Getting the instruction stream for a code block should not require two loads
authorfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Feb 2012 02:07:34 +0000 (02:07 +0000)
committerfpizlo@apple.com <fpizlo@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 27 Feb 2012 02:07:34 +0000 (02:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=79608

Reviewed by Sam Weinig.

Introduced the RefCountedArray class, which contains a single inline pointer
to a ref-counted non-resizeable vector backing store. This satisfies the
requirements of CodeBlock, which desires the ability to share instruction
streams with other CodeBlocks. It also reduces the number of loads required
for getting the instruction stream by one.

This patch also gets rid of the bytecode discarding logic, since we don't
use it anymore and it's unlikely to ever work right with DFG or LLInt. And
I didn't feel like porting dead code to use RefCountedArray.

* GNUmakefile.list.am:
* JavaScriptCore.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::instructionOffsetForNth):
(JSC::CodeBlock::dump):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::handlerForBytecodeOffset):
(JSC::CodeBlock::lineNumberForBytecodeOffset):
(JSC::CodeBlock::expressionRangeForBytecodeOffset):
(JSC::CodeBlock::shrinkToFit):
* bytecode/CodeBlock.h:
(CodeBlock):
(JSC::CodeBlock::numberOfInstructions):
(JSC::CodeBlock::instructions):
(JSC::CodeBlock::instructionCount):
(JSC::CodeBlock::valueProfileForBytecodeOffset):
(JSC):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::Label::setLocation):
(JSC):
(JSC::BytecodeGenerator::generate):
(JSC::BytecodeGenerator::newLabel):
* bytecompiler/BytecodeGenerator.h:
(JSC):
(BytecodeGenerator):
(JSC::BytecodeGenerator::instructions):
* bytecompiler/Label.h:
(JSC::Label::Label):
(Label):
* dfg/DFGByteCodeCache.h:
(JSC::DFG::ByteCodeCache::~ByteCodeCache):
(JSC::DFG::ByteCodeCache::get):
* jit/JITExceptions.cpp:
(JSC::genericThrow):
* llint/LowLevelInterpreter32_64.asm:
* runtime/Executable.cpp:
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::codeBlockWithBytecodeFor):
(JSC::FunctionExecutable::produceCodeBlockFor):
* wtf/RefCountedArray.h: Added.
(WTF):
(RefCountedArray):
(WTF::RefCountedArray::RefCountedArray):
(WTF::RefCountedArray::operator=):
(WTF::RefCountedArray::~RefCountedArray):
(WTF::RefCountedArray::size):
(WTF::RefCountedArray::data):
(WTF::RefCountedArray::begin):
(WTF::RefCountedArray::end):
(WTF::RefCountedArray::at):
(WTF::RefCountedArray::operator[]):
(Header):
(WTF::RefCountedArray::Header::size):
(WTF::RefCountedArray::Header::payload):
(WTF::RefCountedArray::Header::fromPayload):
* wtf/Platform.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@108943 268f45cc-cd09-0410-ab3c-d52691b4dbfc

14 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/GNUmakefile.list.am
Source/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj
Source/JavaScriptCore/bytecode/CodeBlock.cpp
Source/JavaScriptCore/bytecode/CodeBlock.h
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp
Source/JavaScriptCore/bytecompiler/BytecodeGenerator.h
Source/JavaScriptCore/bytecompiler/Label.h
Source/JavaScriptCore/dfg/DFGByteCodeCache.h
Source/JavaScriptCore/jit/JITExceptions.cpp
Source/JavaScriptCore/llint/LowLevelInterpreter32_64.asm
Source/JavaScriptCore/runtime/Executable.cpp
Source/JavaScriptCore/wtf/Platform.h
Source/JavaScriptCore/wtf/RefCountedArray.h [new file with mode: 0644]

index 49e55baef5cdd6d0fc2c7a0b846da5a65ba245ce..5309949ea553d58cac807a96cf0f2de75b7e60d4 100644 (file)
@@ -1,3 +1,79 @@
+2012-02-26  Filip Pizlo  <fpizlo@apple.com>
+
+        Getting the instruction stream for a code block should not require two loads
+        https://bugs.webkit.org/show_bug.cgi?id=79608
+
+        Reviewed by Sam Weinig.
+        
+        Introduced the RefCountedArray class, which contains a single inline pointer
+        to a ref-counted non-resizeable vector backing store. This satisfies the
+        requirements of CodeBlock, which desires the ability to share instruction
+        streams with other CodeBlocks. It also reduces the number of loads required
+        for getting the instruction stream by one.
+        
+        This patch also gets rid of the bytecode discarding logic, since we don't
+        use it anymore and it's unlikely to ever work right with DFG or LLInt. And
+        I didn't feel like porting dead code to use RefCountedArray.
+
+        * GNUmakefile.list.am:
+        * JavaScriptCore.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::instructionOffsetForNth):
+        (JSC::CodeBlock::dump):
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::finalizeUnconditionally):
+        (JSC::CodeBlock::handlerForBytecodeOffset):
+        (JSC::CodeBlock::lineNumberForBytecodeOffset):
+        (JSC::CodeBlock::expressionRangeForBytecodeOffset):
+        (JSC::CodeBlock::shrinkToFit):
+        * bytecode/CodeBlock.h:
+        (CodeBlock):
+        (JSC::CodeBlock::numberOfInstructions):
+        (JSC::CodeBlock::instructions):
+        (JSC::CodeBlock::instructionCount):
+        (JSC::CodeBlock::valueProfileForBytecodeOffset):
+        (JSC):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::Label::setLocation):
+        (JSC):
+        (JSC::BytecodeGenerator::generate):
+        (JSC::BytecodeGenerator::newLabel):
+        * bytecompiler/BytecodeGenerator.h:
+        (JSC):
+        (BytecodeGenerator):
+        (JSC::BytecodeGenerator::instructions):
+        * bytecompiler/Label.h:
+        (JSC::Label::Label):
+        (Label):
+        * dfg/DFGByteCodeCache.h:
+        (JSC::DFG::ByteCodeCache::~ByteCodeCache):
+        (JSC::DFG::ByteCodeCache::get):
+        * jit/JITExceptions.cpp:
+        (JSC::genericThrow):
+        * llint/LowLevelInterpreter32_64.asm:
+        * runtime/Executable.cpp:
+        (JSC::EvalExecutable::compileInternal):
+        (JSC::ProgramExecutable::compileInternal):
+        (JSC::FunctionExecutable::codeBlockWithBytecodeFor):
+        (JSC::FunctionExecutable::produceCodeBlockFor):
+        * wtf/RefCountedArray.h: Added.
+        (WTF):
+        (RefCountedArray):
+        (WTF::RefCountedArray::RefCountedArray):
+        (WTF::RefCountedArray::operator=):
+        (WTF::RefCountedArray::~RefCountedArray):
+        (WTF::RefCountedArray::size):
+        (WTF::RefCountedArray::data):
+        (WTF::RefCountedArray::begin):
+        (WTF::RefCountedArray::end):
+        (WTF::RefCountedArray::at):
+        (WTF::RefCountedArray::operator[]):
+        (Header):
+        (WTF::RefCountedArray::Header::size):
+        (WTF::RefCountedArray::Header::payload):
+        (WTF::RefCountedArray::Header::fromPayload):
+        * wtf/Platform.h:
+
 2012-02-26  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         StringLiteral and NumericLiteral are allowed as ObjectLiteral getter / setter name
index 898703afa1dc92e252fb0ce434c42b44971b2983..1eea784e2c98a082e1fb7920b915936543d34af7 100644 (file)
@@ -583,6 +583,7 @@ javascriptcore_sources += \
        Source/JavaScriptCore/wtf/ByteArray.h \
        Source/JavaScriptCore/wtf/CheckedArithmetic.h \
        Source/JavaScriptCore/wtf/CheckedBoolean.h \
+       Source/JavaScriptCore/wtf/RefCountedArray.h \
        Source/JavaScriptCore/wtf/Compiler.h \
        Source/JavaScriptCore/wtf/Complex.h \
        Source/JavaScriptCore/wtf/CryptographicallyRandomNumber.cpp \
index 2794ec96d4cec10f1fe11cce94e1308edcad5fdd..0d643c7780b0248ab60d0f1e3db642125800fdb5 100644 (file)
                0FB5467914F5C46B002C2989 /* LazyOperandValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */; };
                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467D14F5CFD6002C2989 /* MethodOfGettingAValueProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */; };
+               0FB5469014FADA7B002C2989 /* RefCountedArray.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FB5468E14FADA6F002C2989 /* RefCountedArray.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FBC0AE71496C7C400D4FBDD /* DFGExitProfile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */; };
                0FBC0AE81496C7C700D4FBDD /* DFGExitProfile.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FBD7E691447999600481315 /* CodeOrigin.h in Headers */ = {isa = PBXBuildFile; fileRef = 0FBD7E671447998F00481315 /* CodeOrigin.h */; settings = {ATTRIBUTES = (Private, ); }; };
                0FB5467814F5C468002C2989 /* LazyOperandValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LazyOperandValueProfile.cpp; sourceTree = "<group>"; };
                0FB5467A14F5C7D4002C2989 /* MethodOfGettingAValueProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MethodOfGettingAValueProfile.h; sourceTree = "<group>"; };
                0FB5467C14F5CFD3002C2989 /* MethodOfGettingAValueProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MethodOfGettingAValueProfile.cpp; sourceTree = "<group>"; };
+               0FB5468E14FADA6F002C2989 /* RefCountedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefCountedArray.h; sourceTree = "<group>"; };
                0FBC0AE41496C7C100D4FBDD /* DFGExitProfile.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DFGExitProfile.cpp; sourceTree = "<group>"; };
                0FBC0AE51496C7C100D4FBDD /* DFGExitProfile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DFGExitProfile.h; sourceTree = "<group>"; };
                0FBD7E671447998F00481315 /* CodeOrigin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CodeOrigin.h; sourceTree = "<group>"; };
                                A7A1F7AB0F252B3C00E184E2 /* ByteArray.h */,
                                A7BC0C81140608B000B1BB71 /* CheckedArithmetic.h */,
                                C2D9CA1214BCC04600304B46 /* CheckedBoolean.h */,
+                               0FB5468E14FADA6F002C2989 /* RefCountedArray.h */,
                                BC66BAE213F4928F00C23FAE /* Compiler.h */,
                                FDA15C1612B03028003A583A /* Complex.h */,
                                97941A7C1302A098004A3447 /* CryptographicallyRandomNumber.cpp */,
                                1497209114EB831500FEB1B7 /* PassWeak.h in Headers */,
                                0FB5467714F59B5C002C2989 /* LazyOperandValueProfile.h in Headers */,
                                0FB5467B14F5C7E1002C2989 /* MethodOfGettingAValueProfile.h in Headers */,
+                               0FB5469014FADA7B002C2989 /* RefCountedArray.h in Headers */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index ab89ad9652fd2f16a7ffe5a12c42f1b2849eb4cd..30f13051fa753e1376916be0f191575759ed2452 100644 (file)
@@ -226,7 +226,7 @@ static bool isPropertyAccess(OpcodeID opcodeID)
     }
 }
 
-static unsigned instructionOffsetForNth(ExecState* exec, const Vector<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
+static unsigned instructionOffsetForNth(ExecState* exec, const RefCountedArray<Instruction>& instructions, int nth, bool (*predicate)(OpcodeID))
 {
     size_t i = 0;
     while (i < instructions.size()) {
@@ -347,18 +347,13 @@ void CodeBlock::printStructures(const Instruction* vPC) const
 
 void CodeBlock::dump(ExecState* exec) const
 {
-    if (!m_instructions) {
-        dataLog("No instructions available.\n");
-        return;
-    }
-
     size_t instructionCount = 0;
 
     for (size_t i = 0; i < instructions().size(); i += opcodeLengths[exec->interpreter()->getOpcodeID(instructions()[i].u.opcode)])
         ++instructionCount;
 
     dataLog("%lu m_instructions; %lu bytes at %p; %d parameter(s); %d callee register(s); %d variable(s)\n\n",
-        static_cast<unsigned long>(instructionCount),
+        static_cast<unsigned long>(instructions().size()),
         static_cast<unsigned long>(instructions().size() * sizeof(Instruction)),
         this, m_numParameters, m_numCalleeRegisters, m_numVars);
 
@@ -1424,11 +1419,9 @@ CodeBlock::CodeBlock(CopyParsedBlockTag, CodeBlock& other, SymbolTable* symTab)
     , m_numVars(other.m_numVars)
     , m_numCapturedVars(other.m_numCapturedVars)
     , m_isConstructor(other.m_isConstructor)
-    , m_shouldDiscardBytecode(false)
     , m_ownerExecutable(*other.m_globalData, other.m_ownerExecutable.get(), other.m_ownerExecutable.get())
     , m_globalData(other.m_globalData)
     , m_instructions(other.m_instructions)
-    , m_instructionCount(other.m_instructionCount)
     , m_thisRegister(other.m_thisRegister)
     , m_argumentsRegister(other.m_argumentsRegister)
     , m_activationRegister(other.m_activationRegister)
@@ -1484,12 +1477,9 @@ CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, JSGlo
     , m_numCalleeRegisters(0)
     , m_numVars(0)
     , m_isConstructor(isConstructor)
-    , m_shouldDiscardBytecode(false)
     , m_numParameters(0)
     , m_ownerExecutable(globalObject->globalData(), ownerExecutable, ownerExecutable)
     , m_globalData(0)
-    , m_instructions(adoptRef(new Instructions))
-    , m_instructionCount(0)
     , m_argumentsRegister(-1)
     , m_needsFullScopeChain(ownerExecutable->needsActivation())
     , m_usesEval(ownerExecutable->usesEval())
@@ -1903,12 +1893,6 @@ void CodeBlock::finalizeUnconditionally()
         }
     }
 #endif
-
-    // Handle the bytecode discarding chore.
-    if (m_shouldDiscardBytecode) {
-        discardBytecode();
-        m_shouldDiscardBytecode = false;
-    }
 }
 
 void CodeBlock::stronglyVisitStrongReferences(SlotVisitor& visitor)
@@ -1980,7 +1964,7 @@ void CodeBlock::stronglyVisitWeakReferences(SlotVisitor& visitor)
 
 HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
 {
-    ASSERT(bytecodeOffset < m_instructionCount);
+    ASSERT(bytecodeOffset < instructions().size());
 
     if (!m_rareData)
         return 0;
@@ -1998,7 +1982,7 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset)
 
 int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
 {
-    ASSERT(bytecodeOffset < m_instructionCount);
+    ASSERT(bytecodeOffset < instructions().size());
 
     if (!m_rareData)
         return m_ownerExecutable->source().firstLine();
@@ -2022,7 +2006,7 @@ int CodeBlock::lineNumberForBytecodeOffset(unsigned bytecodeOffset)
 
 void CodeBlock::expressionRangeForBytecodeOffset(unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset)
 {
-    ASSERT(bytecodeOffset < m_instructionCount);
+    ASSERT(bytecodeOffset < instructions().size());
 
     if (!m_rareData) {
         startOffset = 0;
@@ -2102,8 +2086,6 @@ bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset)
 
 void CodeBlock::shrinkToFit()
 {
-    instructions().shrinkToFit();
-
 #if ENABLE(CLASSIC_INTERPRETER)
     m_propertyAccessInstructions.shrinkToFit();
     m_globalResolveInstructions.shrinkToFit();
index 195aa62ca05fa9c8561074c47a7508bb2a3d66c8..f7bb651c153f6d4346ad3d127ff5f60ccfa97350 100644 (file)
@@ -61,6 +61,7 @@
 #include "UString.h"
 #include "UnconditionalFinalizer.h"
 #include "ValueProfile.h"
+#include <wtf/RefCountedArray.h>
 #include <wtf/FastAllocBase.h>
 #include <wtf/PassOwnPtr.h>
 #include <wtf/RefPtr.h>
@@ -127,8 +128,6 @@ namespace JSC {
         }
 #endif
         
-        bool canProduceCopyWithBytecode() { return hasInstructions(); }
-
         void visitAggregate(SlotVisitor&);
 
         static void dumpStatistics();
@@ -341,20 +340,13 @@ namespace JSC {
         void setIsNumericCompareFunction(bool isNumericCompareFunction) { m_isNumericCompareFunction = isNumericCompareFunction; }
         bool isNumericCompareFunction() { return m_isNumericCompareFunction; }
 
-        bool hasInstructions() const { return !!m_instructions; }
-        unsigned numberOfInstructions() const { return !m_instructions ? 0 : m_instructions->m_instructions.size(); }
-        Vector<Instruction>& instructions() { return m_instructions->m_instructions; }
-        const Vector<Instruction>& instructions() const { return m_instructions->m_instructions; }
-        void discardBytecode() { m_instructions.clear(); }
-        void discardBytecodeLater()
-        {
-            m_shouldDiscardBytecode = true;
-        }
+        unsigned numberOfInstructions() const { return m_instructions.size(); }
+        RefCountedArray<Instruction>& instructions() { return m_instructions; }
+        const RefCountedArray<Instruction>& instructions() const { return m_instructions; }
         
         bool usesOpcode(OpcodeID);
 
-        unsigned instructionCount() { return m_instructionCount; }
-        void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; }
+        unsigned instructionCount() { return m_instructions.size(); }
 
 #if ENABLE(JIT)
         void setJITCode(const JITCode& code, MacroAssemblerCodePtr codeWithArityCheck)
@@ -541,11 +533,10 @@ namespace JSC {
         {
             ValueProfile* result = WTF::genericBinarySearch<ValueProfile, int, getValueProfileBytecodeOffset>(m_valueProfiles, m_valueProfiles.size(), bytecodeOffset);
             ASSERT(result->m_bytecodeOffset != -1);
-            ASSERT(!hasInstructions()
-                   || instructions()[bytecodeOffset + opcodeLength(
-                           m_globalData->interpreter->getOpcodeID(
-                               instructions()[
-                                   bytecodeOffset].u.opcode)) - 1].u.profile == result);
+            ASSERT(instructions()[bytecodeOffset + opcodeLength(
+                       m_globalData->interpreter->getOpcodeID(
+                           instructions()[
+                               bytecodeOffset].u.opcode)) - 1].u.profile == result);
             return result;
         }
         PredictedType valueProfilePredictionForBytecodeOffset(int bytecodeOffset)
@@ -1047,9 +1038,6 @@ namespace JSC {
         int m_numCapturedVars;
         bool m_isConstructor;
 
-        // This is public because otherwise we would have many friends.
-        bool m_shouldDiscardBytecode;
-
     protected:
 #if ENABLE(JIT)
         virtual void jitCompileImpl(JSGlobalData&) = 0;
@@ -1115,11 +1103,7 @@ namespace JSC {
         WriteBarrier<ScriptExecutable> m_ownerExecutable;
         JSGlobalData* m_globalData;
 
-        struct Instructions : public RefCounted<Instructions> {
-            Vector<Instruction> m_instructions;
-        };
-        RefPtr<Instructions> m_instructions;
-        unsigned m_instructionCount;
+        RefCountedArray<Instruction> m_instructions;
 
         int m_thisRegister;
         int m_argumentsRegister;
@@ -1379,27 +1363,6 @@ namespace JSC {
 #endif
     };
 
-    // Use this if you want to copy a code block and you're paranoid about a GC
-    // happening.
-    class BytecodeDestructionBlocker {
-    public:
-        BytecodeDestructionBlocker(CodeBlock* codeBlock)
-            : m_codeBlock(codeBlock)
-            , m_oldValueOfShouldDiscardBytecode(codeBlock->m_shouldDiscardBytecode)
-        {
-            codeBlock->m_shouldDiscardBytecode = false;
-        }
-        
-        ~BytecodeDestructionBlocker()
-        {
-            m_codeBlock->m_shouldDiscardBytecode = m_oldValueOfShouldDiscardBytecode;
-        }
-        
-    private:
-        CodeBlock* m_codeBlock;
-        bool m_oldValueOfShouldDiscardBytecode;
-    };
-
     inline CodeBlock* baselineCodeBlockForOriginAndBaselineCodeBlock(const CodeOrigin& codeOrigin, CodeBlock* baselineCodeBlock)
     {
         if (codeOrigin.inlineCallFrame) {
index 6fa0ce96b91303084e7067d75882aa6d188c876e..4a6f4653eab892fc6da0db93cb49cb1571a6adfb 100644 (file)
@@ -119,6 +119,15 @@ namespace JSC {
     expected by the callee.
 */
 
+void Label::setLocation(unsigned location)
+{
+    m_location = location;
+    
+    unsigned size = m_unresolvedJumps.size();
+    for (unsigned i = 0; i < size; ++i)
+        m_generator->m_instructions[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first;
+}
+
 #ifndef NDEBUG
 void ResolveResult::checkValidity()
 {
@@ -171,8 +180,8 @@ JSObject* BytecodeGenerator::generate()
     m_codeBlock->setThisRegister(m_thisRegister.index());
 
     m_scopeNode->emitBytecode(*this);
-
-    m_codeBlock->setInstructionCount(m_codeBlock->instructions().size());
+    
+    m_codeBlock->instructions() = RefCountedArray<Instruction>(m_instructions);
 
     if (s_dumpsGeneratedCode)
         m_codeBlock->dump(m_scopeChain->globalObject->globalExec());
@@ -607,7 +616,7 @@ PassRefPtr<Label> BytecodeGenerator::newLabel()
         m_labels.removeLast();
 
     // Allocate new label ID.
-    m_labels.append(m_codeBlock);
+    m_labels.append(this);
     return &m_labels.last();
 }
 
index d61b42b76bdda9d3119b8db8a78957a5f9d67c68..c44812c7e85bc5490f3c7aad42e32fea02417840 100644 (file)
@@ -48,6 +48,7 @@
 namespace JSC {
 
     class Identifier;
+    class Label;
     class ScopeChainNode;
 
     class CallArguments {
@@ -532,6 +533,8 @@ namespace JSC {
         ScopeChainNode* scopeChain() const { return m_scopeChain.get(); }
 
     private:
+        friend class Label;
+        
         void emitOpcode(OpcodeID);
         ValueProfile* emitProfiledOpcode(OpcodeID);
         void retrieveLastBinaryOp(int& dstIndex, int& src1Index, int& src2Index);
@@ -611,7 +614,7 @@ namespace JSC {
 
         RegisterID* emitInitLazyRegister(RegisterID*);
 
-        Vector<Instruction>& instructions() { return m_codeBlock->instructions(); }
+        Vector<Instruction>& instructions() { return m_instructions; }
         SymbolTable& symbolTable() { return *m_symbolTable; }
 
         bool shouldOptimizeLocals()
@@ -644,6 +647,8 @@ namespace JSC {
         void createArgumentsIfNecessary();
         void createActivationIfNecessary();
         RegisterID* createLazyRegisterIfNecessary(RegisterID*);
+        
+        Vector<Instruction> m_instructions;
 
         bool m_shouldEmitDebugHooks;
         bool m_shouldEmitProfileHooks;
index 8cab1dbc00dc9ec623b37a20a86c484cc7122f88..21fa46309a2f2875a28da6483bb4a56fe1ee0dad 100644 (file)
@@ -39,21 +39,14 @@ namespace JSC {
 
     class Label {
     public:
-        explicit Label(CodeBlock* codeBlock)
+        explicit Label(BytecodeGenerator* generator)
             : m_refCount(0)
             , m_location(invalidLocation)
-            , m_codeBlock(codeBlock)
+            , m_generator(generator)
         {
         }
 
-        void setLocation(unsigned location)
-        {
-            m_location = location;
-
-            unsigned size = m_unresolvedJumps.size();
-            for (unsigned i = 0; i < size; ++i)
-                m_codeBlock->instructions()[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first;
-        }
+        void setLocation(unsigned);
 
         int bind(int opcode, int offset) const
         {
@@ -81,7 +74,7 @@ namespace JSC {
 
         int m_refCount;
         unsigned m_location;
-        CodeBlock* m_codeBlock;
+        BytecodeGenerator* m_generator;
         mutable JumpVector m_unresolvedJumps;
     };
 
index fd3b5147f81080d4e2bec2076e64bd902cbe07a8..f6a745c66587133b12cbd44ff3a929a93c1ba107 100644 (file)
@@ -138,7 +138,6 @@ public:
                 delete iter->second.codeBlock;
                 continue;
             }
-            iter->second.codeBlock->m_shouldDiscardBytecode = iter->second.oldValueOfShouldDiscardBytecode;
         }
     }
     
@@ -155,7 +154,6 @@ public:
         value.codeBlock = key.executable()->codeBlockWithBytecodeFor(key.kind());
         if (value.codeBlock) {
             value.owned = false;
-            value.oldValueOfShouldDiscardBytecode = value.codeBlock->m_shouldDiscardBytecode;
         } else {
             // Nope, so try to parse one.
             JSObject* exception;
@@ -171,13 +169,6 @@ public:
             value.codeBlock = 0;
         }
         
-        // If we're about to return a code block, make sure that we're not going
-        // to be discarding its bytecode if a GC were to happen during DFG
-        // compilation. That's unlikely, but it's good to thoroughly enjoy this
-        // kind of paranoia.
-        if (!!value.codeBlock)
-            value.codeBlock->m_shouldDiscardBytecode = false;
-        
         m_map.add(key, value);
         
         return value.codeBlock;
index 2edd3408f51bf599cf8c5cb9a421b9161d847b8b..ab1180716087be55f95ee6da1f5add0ae764977d 100644 (file)
@@ -48,8 +48,7 @@ ExceptionHandler genericThrow(JSGlobalData* globalData, ExecState* callFrame, JS
     Instruction* catchPCForInterpreter = 0;
     if (handler) {
         catchRoutine = handler->nativeCode.executableAddress();
-        if (callFrame->codeBlock()->hasInstructions())
-            catchPCForInterpreter = &callFrame->codeBlock()->instructions()[handler->target];
+        catchPCForInterpreter = &callFrame->codeBlock()->instructions()[handler->target];
     } else
         catchRoutine = FunctionPtr(ctiOpThrowNotCaught).value();
     
index ba49fe365e5afe027fcb81d8af7baf949775e704..2c3aa7d6070dfec10311eacc2c964d7c163a9368 100644 (file)
@@ -443,8 +443,7 @@ macro prologue(codeBlockGetter, codeBlockSetter, osrSlowPath, traceSlowPath)
     codeBlockSetter(t1)
     
     # Set up the PC.
-    loadp CodeBlock::m_instructions[t1], t0
-    loadp CodeBlock::Instructions::m_instructions + VectorBufferOffset[t0], PC
+    loadp CodeBlock::m_instructions[t1], PC
 end
 
 # Expects that CodeBlock is in t1, which is what prologue() leaves behind.
@@ -503,8 +502,7 @@ macro functionArityCheck(doneLabel, slow_path)
 .continue:
     # Reload CodeBlock and PC, since the slow_path clobbered it.
     loadp CodeBlock[cfr], t1
-    loadp CodeBlock::m_instructions[t1], t0
-    loadp CodeBlock::Instructions::m_instructions + VectorBufferOffset[t0], PC
+    loadp CodeBlock::m_instructions[t1], PC
     jmp doneLabel
 end
 
index 25ddf764a96245de6978febe1ff4d6a322080d25..a85089ac98b33ea36e458a5a15c453e100b28fdd 100644 (file)
@@ -210,8 +210,7 @@ JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scope
     JSGlobalData* globalData = &exec->globalData();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
     
-    if (!!m_evalCodeBlock && m_evalCodeBlock->canProduceCopyWithBytecode()) {
-        BytecodeDestructionBlocker blocker(m_evalCodeBlock.get());
+    if (!!m_evalCodeBlock) {
         OwnPtr<EvalCodeBlock> newCodeBlock = adoptPtr(new EvalCodeBlock(CodeBlock::CopyParsedBlock, *m_evalCodeBlock));
         newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_evalCodeBlock.release()));
         m_evalCodeBlock = newCodeBlock.release();
@@ -346,8 +345,7 @@ JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* sc
     JSGlobalData* globalData = &exec->globalData();
     JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
     
-    if (!!m_programCodeBlock && m_programCodeBlock->canProduceCopyWithBytecode()) {
-        BytecodeDestructionBlocker blocker(m_programCodeBlock.get());
+    if (!!m_programCodeBlock) {
         OwnPtr<ProgramCodeBlock> newCodeBlock = adoptPtr(new ProgramCodeBlock(CodeBlock::CopyParsedBlock, *m_programCodeBlock));
         newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_programCodeBlock.release()));
         m_programCodeBlock = newCodeBlock.release();
@@ -494,18 +492,13 @@ void FunctionExecutable::jitCompileForConstruct(JSGlobalData& globalData)
 
 FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind)
 {
-    FunctionCodeBlock* codeBlock = baselineCodeBlockFor(kind);
-    if (codeBlock->canProduceCopyWithBytecode())
-        return codeBlock;
-    return 0;
+    return baselineCodeBlockFor(kind);
 }
 
 PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(ScopeChainNode* scopeChainNode, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception)
 {
-    if (!!codeBlockFor(specializationKind) && codeBlockFor(specializationKind)->canProduceCopyWithBytecode()) {
-        BytecodeDestructionBlocker blocker(codeBlockFor(specializationKind).get());
+    if (!!codeBlockFor(specializationKind))
         return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind)));
-    }
     
     exception = 0;
     JSGlobalData* globalData = scopeChainNode->globalData;
index 76b11fe88e4982a45c8c7bfbc5c754f4a0be20d1..794db09dbc1325273d8d8897608932f0c9bc37b6 100644 (file)
 #define ENABLE_JIT 0
 #endif
 
-/* The JIT is enabled by default on all x86, x64-64, ARM & MIPS platforms. */
+/* The JIT is enabled by default on all x86, x86-64, ARM & MIPS platforms. */
 #if !defined(ENABLE_JIT) \
     && (CPU(X86) || CPU(X86_64) || CPU(ARM) || CPU(MIPS)) \
     && (OS(DARWIN) || !COMPILER(GCC) || GCC_VERSION_AT_LEAST(4, 1, 0)) \
diff --git a/Source/JavaScriptCore/wtf/RefCountedArray.h b/Source/JavaScriptCore/wtf/RefCountedArray.h
new file mode 100644 (file)
index 0000000..a5ae862
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
+ */
+
+#ifndef RefCountedArray_h
+#define RefCountedArray_h
+
+#include <wtf/FastMalloc.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/Vector.h>
+
+// This implements a reference counted array for POD** values, which is optimized for:
+// - An empty array only uses one word.
+// - A copy of the array only uses one word (i.e. assignment means aliasing).
+// - The vector can't grow beyond 2^32-1 elements.
+// - In all other regards this has similar space usage to a Vector.
+//
+// ** This could be modified to support non-POD values quite easily. It just
+//    hasn't been, so far, because there has been no need. Moreover, even now,
+//    it's used for things that aren't quite POD according to the official
+//    defintion, such as JSC::Instruction.
+
+namespace WTF {
+
+template<typename T>
+class RefCountedArray {
+public:
+    RefCountedArray()
+        : m_data(0)
+    {
+    }
+    
+    RefCountedArray(const RefCountedArray& other)
+        : m_data(other.m_data)
+    {
+        if (m_data)
+            Header::fromPayload(m_data)->refCount++;
+    }
+    
+    explicit RefCountedArray(const Vector<T>& other)
+    {
+        if (other.isEmpty()) {
+            m_data = 0;
+            return;
+        }
+        
+        m_data = (static_cast<Header*>(fastMalloc(Header::size() + sizeof(T) * other.size())))->payload();
+        Header::fromPayload(m_data)->refCount = 1;
+        Header::fromPayload(m_data)->length = other.size();
+        ASSERT(Header::fromPayload(m_data)->length == other.size());
+        memcpy(m_data, other.begin(), sizeof(T) * other.size());
+    }
+    
+    RefCountedArray& operator=(const RefCountedArray& other)
+    {
+        T* oldData = m_data;
+        m_data = other.m_data;
+        if (m_data)
+            Header::fromPayload(m_data)->refCount++;
+        
+        if (!oldData)
+            return *this;
+        if (--Header::fromPayload(oldData)->refCount)
+            return *this;
+        fastFree(Header::fromPayload(oldData));
+        return *this;
+    }
+    
+    ~RefCountedArray()
+    {
+        if (!m_data)
+            return;
+        if (--Header::fromPayload(m_data)->refCount)
+            return;
+        fastFree(Header::fromPayload(m_data));
+    }
+    
+    size_t size() const
+    {
+        if (!m_data)
+            return 0;
+        return Header::fromPayload(m_data)->length;
+    }
+    
+    T* data() { return m_data; }
+    T* begin() { return m_data; }
+    T* end()
+    {
+        if (!m_data)
+            return 0;
+        return m_data + Header::fromPayload(m_data)->length;
+    }
+    
+    const T* data() const { return m_data; }
+    const T* begin() const { return m_data; }
+    const T* end() const { return const_cast<RefCountedArray*>(this)->end(); }
+    
+    T& at(size_t i)
+    {
+        ASSERT(i < size());
+        return begin()[i];
+    }
+    
+    const T& at(size_t i) const
+    {
+        ASSERT(i < size());
+        return begin()[i];
+    }
+    
+    T& operator[](size_t i) { return at(i); }
+    const T& operator[](size_t i) const { return at(i); }
+    
+private:
+    struct Header {
+        unsigned refCount;
+        unsigned length;
+        
+        static size_t size()
+        {
+            return (sizeof(Header) + 7) & ~7;
+        }
+        
+        T* payload()
+        {
+            char* result = reinterpret_cast<char*>(this) + size();
+            ASSERT(!(bitwise_cast<uintptr_t>(result) & 7));
+            return reinterpret_cast<T*>(result);
+        }
+        
+        static Header* fromPayload(T* payload)
+        {
+            return reinterpret_cast<Header*>(reinterpret_cast<char*>(payload) - size());
+        }
+    };
+    
+    T* m_data;
+};
+
+} // namespace WTF
+
+using WTF::RefCountedArray;
+
+#endif // RefCountedArray_h
+