2008-09-23 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Sep 2008 00:27:18 +0000 (00:27 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 24 Sep 2008 00:27:18 +0000 (00:27 +0000)
        Reviewed by Darin Adler.

        Changed the layout of the call frame from

        { header, parameters, locals | constants, temporaries }

        to

        { parameters, header | locals, constants, temporaries }

        This simplifies function entry+exit, and enables a number of future
        optimizations.

        13.5% speedup on empty call benchmark for bytecode; 23.6% speedup on
        empty call benchmark for CTI.

        SunSpider says no change. SunSpider --v8 says 1% faster.

        * VM/CTI.cpp:

        Added a bit of abstraction for calculating whether a register is a
        constant, since this patch changes that calculation:
        (JSC::CTI::isConstant):
        (JSC::CTI::getConstant):
        (JSC::CTI::emitGetArg):
        (JSC::CTI::emitGetPutArg):
        (JSC::CTI::getConstantImmediateNumericArg):

        Updated for changes to callframe header location:
        (JSC::CTI::emitPutToCallFrameHeader):
        (JSC::CTI::emitGetFromCallFrameHeader):
        (JSC::CTI::printOpcodeOperandTypes):

        Renamed to spite Oliver:
        (JSC::CTI::emitInitRegister):

        Added an abstraction for emitting a call through a register, so that
        calls through registers generate exception info, too:
        (JSC::CTI::emitCall):

        Updated to match the new callframe header layout, and to support calls
        through registers, which have no destination address:
        (JSC::CTI::compileOpCall):
        (JSC::CTI::privateCompileMainPass):
        (JSC::CTI::privateCompileSlowCases):
        (JSC::CTI::privateCompile):

        * VM/CTI.h:

        More of the above:
        (JSC::CallRecord::CallRecord):

        * VM/CodeBlock.cpp:

        Updated for new register layout:
        (JSC::registerName):
        (JSC::CodeBlock::dump):

        * VM/CodeBlock.h:

        Updated CodeBlock to track slightly different information about the
        register frame, and tweaked the style of an ASSERT_NOT_REACHED.
        (JSC::CodeBlock::CodeBlock):
        (JSC::CodeBlock::getStubInfo):

        * VM/CodeGenerator.cpp:

        Added some abstraction around constant register allocation, since this
        patch changes it, changed codegen to account for the new callframe
        layout, and added abstraction around register fetching code
        that used to assume that all local registers lived at negative indices,
        since vars now live at positive indices:
        (JSC::CodeGenerator::generate):
        (JSC::CodeGenerator::addVar):
        (JSC::CodeGenerator::addGlobalVar):
        (JSC::CodeGenerator::allocateConstants):
        (JSC::CodeGenerator::CodeGenerator):
        (JSC::CodeGenerator::addParameter):
        (JSC::CodeGenerator::registerFor):
        (JSC::CodeGenerator::constRegisterFor):
        (JSC::CodeGenerator::newRegister):
        (JSC::CodeGenerator::newTemporary):
        (JSC::CodeGenerator::highestUsedRegister):
        (JSC::CodeGenerator::addConstant):

        ASSERT that our caller referenced the registers it passed to us.
        Otherwise, we might overwrite them with parameters:
        (JSC::CodeGenerator::emitCall):
        (JSC::CodeGenerator::emitConstruct):

        * VM/CodeGenerator.h:

        Added some abstraction for getting a RegisterID for a given index,
        since the rules are a little weird:
        (JSC::CodeGenerator::registerFor):

        * VM/Machine.cpp:

        Utility function to transform a machine return PC to a virtual machine
        return VPC, for the sake of stack unwinding, since both PCs are stored
        in the same location now:
        (JSC::vPCForPC):

        Tweaked to account for new call frame:
        (JSC::Machine::initializeCallFrame):

        Tweaked to account for registerOffset supplied by caller:
        (JSC::slideRegisterWindowForCall):

        Tweaked to account for new register layout:
        (JSC::scopeChainForCall):
        (JSC::Machine::callEval):
        (JSC::Machine::dumpRegisters):
        (JSC::Machine::unwindCallFrame):
        (JSC::Machine::execute):

        Changed op_call and op_construct to implement the new calling convention:
        (JSC::Machine::privateExecute):

        Tweaked to account for the new register layout:
        (JSC::Machine::retrieveArguments):
        (JSC::Machine::retrieveCaller):
        (JSC::Machine::retrieveLastCaller):
        (JSC::Machine::callFrame):
        (JSC::Machine::getArgumentsData):

        Changed CTI call helpers to implement the new calling convention:
        (JSC::Machine::cti_op_call_JSFunction):
        (JSC::Machine::cti_op_call_NotJSFunction):
        (JSC::Machine::cti_op_ret_activation):
        (JSC::Machine::cti_op_ret_profiler):
        (JSC::Machine::cti_op_construct_JSConstruct):
        (JSC::Machine::cti_op_construct_NotJSConstruct):
        (JSC::Machine::cti_op_call_eval):

        * VM/Machine.h:

        * VM/Opcode.h:

        Renamed op_initialise_locals to op_init, because this opcode
        doesn't initialize all locals, and it doesn't initialize only locals.
        Also, to spite Oliver.

        * VM/RegisterFile.h:

        New call frame enumeration values:
        (JSC::RegisterFile::):

        Simplified the calculation of whether a RegisterID is a temporary,
        since we can no longer assume that all positive non-constant registers
        are temporaries:
        * VM/RegisterID.h:
        (JSC::RegisterID::RegisterID):
        (JSC::RegisterID::setTemporary):
        (JSC::RegisterID::isTemporary):

        Renamed firstArgumentIndex to firstParameterIndex because the assumption
        that this variable pertained to the actual arguments supplied by the
        caller caused me to write some buggy code:
        * kjs/Arguments.cpp:
        (JSC::ArgumentsData::ArgumentsData):
        (JSC::Arguments::Arguments):
        (JSC::Arguments::fillArgList):
        (JSC::Arguments::getOwnPropertySlot):
        (JSC::Arguments::put):

        Updated for new call frame layout:
        * kjs/DebuggerCallFrame.cpp:
        (JSC::DebuggerCallFrame::functionName):
        (JSC::DebuggerCallFrame::type):
        * kjs/DebuggerCallFrame.h:

        Changed the activation object to account for the fact that a call frame
        header now sits between parameters and local variables. This change
        requires all variable objects to do their own marking, since they
        now use their register storage differently:
        * kjs/JSActivation.cpp:
        (JSC::JSActivation::mark):
        (JSC::JSActivation::copyRegisters):
        (JSC::JSActivation::createArgumentsObject):
        * kjs/JSActivation.h:

        Updated global object to use the new interfaces required by the change
        to JSActivation above:
        * kjs/JSGlobalObject.cpp:
        (JSC::JSGlobalObject::reset):
        (JSC::JSGlobalObject::mark):
        (JSC::JSGlobalObject::copyGlobalsFrom):
        (JSC::JSGlobalObject::copyGlobalsTo):
        * kjs/JSGlobalObject.h:
        (JSC::JSGlobalObject::addStaticGlobals):

        Updated static scope object to use the new interfaces required by the
        change to JSActivation above:
        * kjs/JSStaticScopeObject.cpp:
        (JSC::JSStaticScopeObject::mark):
        (JSC::JSStaticScopeObject::~JSStaticScopeObject):
        * kjs/JSStaticScopeObject.h:
        (JSC::JSStaticScopeObject::JSStaticScopeObject):
        (JSC::JSStaticScopeObject::d):

        Updated variable object to use the new interfaces required by the
        change to JSActivation above:
        * kjs/JSVariableObject.cpp:
        (JSC::JSVariableObject::copyRegisterArray):
        (JSC::JSVariableObject::setRegisters):
        * kjs/JSVariableObject.h:

        Changed the bit twiddling in symbol table not to assume that all indices
        are negative, since they can be positive now:
        * kjs/SymbolTable.h:
        (JSC::SymbolTableEntry::SymbolTableEntry):
        (JSC::SymbolTableEntry::isNull):
        (JSC::SymbolTableEntry::getIndex):
        (JSC::SymbolTableEntry::getAttributes):
        (JSC::SymbolTableEntry::setAttributes):
        (JSC::SymbolTableEntry::isReadOnly):
        (JSC::SymbolTableEntry::pack):
        (JSC::SymbolTableEntry::isValidIndex):

        Changed call and construct nodes to ref their functions and/or bases,
        so that emitCall/emitConstruct doesn't overwrite them with parameters.
        Also, updated for rename to registerFor:
        * kjs/nodes.cpp:
        (JSC::ResolveNode::emitCode):
        (JSC::NewExprNode::emitCode):
        (JSC::EvalFunctionCallNode::emitCode):
        (JSC::FunctionCallValueNode::emitCode):
        (JSC::FunctionCallResolveNode::emitCode):
        (JSC::FunctionCallBracketNode::emitCode):
        (JSC::FunctionCallDotNode::emitCode):
        (JSC::PostfixResolveNode::emitCode):
        (JSC::DeleteResolveNode::emitCode):
        (JSC::TypeOfResolveNode::emitCode):
        (JSC::PrefixResolveNode::emitCode):
        (JSC::ReadModifyResolveNode::emitCode):
        (JSC::AssignResolveNode::emitCode):
        (JSC::ConstDeclNode::emitCodeSingle):
        (JSC::ForInNode::emitCode):

        Added abstraction for getting exception info out of a call through a
        register:
        * masm/X86Assembler.h:
        (JSC::X86Assembler::emitCall):

        Removed duplicate #if:
        * wtf/Platform.h:

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

27 files changed:
JavaScriptCore/ChangeLog
JavaScriptCore/JavaScriptCore.exp
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CTI.h
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeBlock.h
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/CodeGenerator.h
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/Opcode.h
JavaScriptCore/VM/RegisterFile.h
JavaScriptCore/VM/RegisterID.h
JavaScriptCore/kjs/Arguments.cpp
JavaScriptCore/kjs/DebuggerCallFrame.cpp
JavaScriptCore/kjs/DebuggerCallFrame.h
JavaScriptCore/kjs/JSActivation.cpp
JavaScriptCore/kjs/JSActivation.h
JavaScriptCore/kjs/JSGlobalObject.cpp
JavaScriptCore/kjs/JSGlobalObject.h
JavaScriptCore/kjs/JSStaticScopeObject.cpp
JavaScriptCore/kjs/JSStaticScopeObject.h
JavaScriptCore/kjs/JSVariableObject.cpp
JavaScriptCore/kjs/JSVariableObject.h
JavaScriptCore/kjs/SymbolTable.h
JavaScriptCore/kjs/nodes.cpp
JavaScriptCore/masm/X86Assembler.h

index 5ea196f..16c36ee 100644 (file)
@@ -1,3 +1,253 @@
+2008-09-23  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Darin Adler.
+        
+        Changed the layout of the call frame from
+        
+        { header, parameters, locals | constants, temporaries }
+        
+        to
+        
+        { parameters, header | locals, constants, temporaries }
+        
+        This simplifies function entry+exit, and enables a number of future
+        optimizations.
+        
+        13.5% speedup on empty call benchmark for bytecode; 23.6% speedup on
+        empty call benchmark for CTI.
+        
+        SunSpider says no change. SunSpider --v8 says 1% faster.
+
+        * VM/CTI.cpp:
+        
+        Added a bit of abstraction for calculating whether a register is a
+        constant, since this patch changes that calculation:
+        (JSC::CTI::isConstant):
+        (JSC::CTI::getConstant):
+        (JSC::CTI::emitGetArg):
+        (JSC::CTI::emitGetPutArg):
+        (JSC::CTI::getConstantImmediateNumericArg):
+
+        Updated for changes to callframe header location:
+        (JSC::CTI::emitPutToCallFrameHeader):
+        (JSC::CTI::emitGetFromCallFrameHeader):
+        (JSC::CTI::printOpcodeOperandTypes):
+        
+        Renamed to spite Oliver:
+        (JSC::CTI::emitInitRegister):
+        
+        Added an abstraction for emitting a call through a register, so that
+        calls through registers generate exception info, too:
+        (JSC::CTI::emitCall):
+
+        Updated to match the new callframe header layout, and to support calls
+        through registers, which have no destination address:
+        (JSC::CTI::compileOpCall):
+        (JSC::CTI::privateCompileMainPass):
+        (JSC::CTI::privateCompileSlowCases):
+        (JSC::CTI::privateCompile):
+
+        * VM/CTI.h:
+
+        More of the above:
+        (JSC::CallRecord::CallRecord):
+
+        * VM/CodeBlock.cpp:
+
+        Updated for new register layout:
+        (JSC::registerName):
+        (JSC::CodeBlock::dump):
+
+        * VM/CodeBlock.h:
+        
+        Updated CodeBlock to track slightly different information about the
+        register frame, and tweaked the style of an ASSERT_NOT_REACHED.
+        (JSC::CodeBlock::CodeBlock):
+        (JSC::CodeBlock::getStubInfo):
+
+        * VM/CodeGenerator.cpp:
+        
+        Added some abstraction around constant register allocation, since this
+        patch changes it, changed codegen to account for the new callframe
+        layout, and added abstraction around register fetching code
+        that used to assume that all local registers lived at negative indices,
+        since vars now live at positive indices:
+        (JSC::CodeGenerator::generate):
+        (JSC::CodeGenerator::addVar):
+        (JSC::CodeGenerator::addGlobalVar):
+        (JSC::CodeGenerator::allocateConstants):
+        (JSC::CodeGenerator::CodeGenerator):
+        (JSC::CodeGenerator::addParameter):
+        (JSC::CodeGenerator::registerFor):
+        (JSC::CodeGenerator::constRegisterFor):
+        (JSC::CodeGenerator::newRegister):
+        (JSC::CodeGenerator::newTemporary):
+        (JSC::CodeGenerator::highestUsedRegister):
+        (JSC::CodeGenerator::addConstant):
+        
+        ASSERT that our caller referenced the registers it passed to us.
+        Otherwise, we might overwrite them with parameters:
+        (JSC::CodeGenerator::emitCall):
+        (JSC::CodeGenerator::emitConstruct):
+
+        * VM/CodeGenerator.h:
+        
+        Added some abstraction for getting a RegisterID for a given index,
+        since the rules are a little weird:
+        (JSC::CodeGenerator::registerFor):
+
+        * VM/Machine.cpp:
+
+        Utility function to transform a machine return PC to a virtual machine
+        return VPC, for the sake of stack unwinding, since both PCs are stored
+        in the same location now:
+        (JSC::vPCForPC):
+
+        Tweaked to account for new call frame:
+        (JSC::Machine::initializeCallFrame):
+        
+        Tweaked to account for registerOffset supplied by caller:
+        (JSC::slideRegisterWindowForCall):
+
+        Tweaked to account for new register layout:
+        (JSC::scopeChainForCall):
+        (JSC::Machine::callEval):
+        (JSC::Machine::dumpRegisters):
+        (JSC::Machine::unwindCallFrame):
+        (JSC::Machine::execute):
+
+        Changed op_call and op_construct to implement the new calling convention:
+        (JSC::Machine::privateExecute):
+
+        Tweaked to account for the new register layout:
+        (JSC::Machine::retrieveArguments):
+        (JSC::Machine::retrieveCaller):
+        (JSC::Machine::retrieveLastCaller):
+        (JSC::Machine::callFrame):
+        (JSC::Machine::getArgumentsData):
+
+        Changed CTI call helpers to implement the new calling convention:
+        (JSC::Machine::cti_op_call_JSFunction):
+        (JSC::Machine::cti_op_call_NotJSFunction):
+        (JSC::Machine::cti_op_ret_activation):
+        (JSC::Machine::cti_op_ret_profiler):
+        (JSC::Machine::cti_op_construct_JSConstruct):
+        (JSC::Machine::cti_op_construct_NotJSConstruct):
+        (JSC::Machine::cti_op_call_eval):
+
+        * VM/Machine.h:
+
+        * VM/Opcode.h:
+        
+        Renamed op_initialise_locals to op_init, because this opcode
+        doesn't initialize all locals, and it doesn't initialize only locals.
+        Also, to spite Oliver.
+        
+        * VM/RegisterFile.h:
+        
+        New call frame enumeration values:
+        (JSC::RegisterFile::):
+
+        Simplified the calculation of whether a RegisterID is a temporary,
+        since we can no longer assume that all positive non-constant registers
+        are temporaries:
+        * VM/RegisterID.h:
+        (JSC::RegisterID::RegisterID):
+        (JSC::RegisterID::setTemporary):
+        (JSC::RegisterID::isTemporary):
+
+        Renamed firstArgumentIndex to firstParameterIndex because the assumption
+        that this variable pertained to the actual arguments supplied by the
+        caller caused me to write some buggy code:
+        * kjs/Arguments.cpp:
+        (JSC::ArgumentsData::ArgumentsData):
+        (JSC::Arguments::Arguments):
+        (JSC::Arguments::fillArgList):
+        (JSC::Arguments::getOwnPropertySlot):
+        (JSC::Arguments::put):
+
+        Updated for new call frame layout:
+        * kjs/DebuggerCallFrame.cpp:
+        (JSC::DebuggerCallFrame::functionName):
+        (JSC::DebuggerCallFrame::type):
+        * kjs/DebuggerCallFrame.h:
+
+        Changed the activation object to account for the fact that a call frame
+        header now sits between parameters and local variables. This change
+        requires all variable objects to do their own marking, since they
+        now use their register storage differently:
+        * kjs/JSActivation.cpp:
+        (JSC::JSActivation::mark):
+        (JSC::JSActivation::copyRegisters):
+        (JSC::JSActivation::createArgumentsObject):
+        * kjs/JSActivation.h:
+
+        Updated global object to use the new interfaces required by the change
+        to JSActivation above:
+        * kjs/JSGlobalObject.cpp:
+        (JSC::JSGlobalObject::reset):
+        (JSC::JSGlobalObject::mark):
+        (JSC::JSGlobalObject::copyGlobalsFrom):
+        (JSC::JSGlobalObject::copyGlobalsTo):
+        * kjs/JSGlobalObject.h:
+        (JSC::JSGlobalObject::addStaticGlobals):
+
+        Updated static scope object to use the new interfaces required by the 
+        change to JSActivation above:
+        * kjs/JSStaticScopeObject.cpp:
+        (JSC::JSStaticScopeObject::mark):
+        (JSC::JSStaticScopeObject::~JSStaticScopeObject):
+        * kjs/JSStaticScopeObject.h:
+        (JSC::JSStaticScopeObject::JSStaticScopeObject):
+        (JSC::JSStaticScopeObject::d):
+
+        Updated variable object to use the new interfaces required by the 
+        change to JSActivation above:
+        * kjs/JSVariableObject.cpp:
+        (JSC::JSVariableObject::copyRegisterArray):
+        (JSC::JSVariableObject::setRegisters):
+        * kjs/JSVariableObject.h:
+
+        Changed the bit twiddling in symbol table not to assume that all indices
+        are negative, since they can be positive now:
+        * kjs/SymbolTable.h:
+        (JSC::SymbolTableEntry::SymbolTableEntry):
+        (JSC::SymbolTableEntry::isNull):
+        (JSC::SymbolTableEntry::getIndex):
+        (JSC::SymbolTableEntry::getAttributes):
+        (JSC::SymbolTableEntry::setAttributes):
+        (JSC::SymbolTableEntry::isReadOnly):
+        (JSC::SymbolTableEntry::pack):
+        (JSC::SymbolTableEntry::isValidIndex):
+
+        Changed call and construct nodes to ref their functions and/or bases,
+        so that emitCall/emitConstruct doesn't overwrite them with parameters.
+        Also, updated for rename to registerFor:
+        * kjs/nodes.cpp:
+        (JSC::ResolveNode::emitCode):
+        (JSC::NewExprNode::emitCode):
+        (JSC::EvalFunctionCallNode::emitCode):
+        (JSC::FunctionCallValueNode::emitCode):
+        (JSC::FunctionCallResolveNode::emitCode):
+        (JSC::FunctionCallBracketNode::emitCode):
+        (JSC::FunctionCallDotNode::emitCode):
+        (JSC::PostfixResolveNode::emitCode):
+        (JSC::DeleteResolveNode::emitCode):
+        (JSC::TypeOfResolveNode::emitCode):
+        (JSC::PrefixResolveNode::emitCode):
+        (JSC::ReadModifyResolveNode::emitCode):
+        (JSC::AssignResolveNode::emitCode):
+        (JSC::ConstDeclNode::emitCodeSingle):
+        (JSC::ForInNode::emitCode):
+
+        Added abstraction for getting exception info out of a call through a
+        register:
+        * masm/X86Assembler.h:
+        (JSC::X86Assembler::emitCall):
+        
+        Removed duplicate #if:
+        * wtf/Platform.h:
+
 2008-09-23  Kevin McCullough  <kmccullough@apple.com>
 
         Reviewed by Darin.
index e140b8c..7043e41 100644 (file)
@@ -153,9 +153,9 @@ __ZN3JSC14constructArrayEPNS_9ExecStateERKNS_7ArgListE
 __ZN3JSC15JSWrapperObject4markEv
 __ZN3JSC16InternalFunction4infoE
 __ZN3JSC16InternalFunctionC2EPNS_9ExecStateEN3WTF10PassRefPtrINS_11StructureIDEEERKNS_10IdentifierE
+__ZN3JSC16JSVariableObject12setRegistersEPNS_8RegisterES2_m
 __ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE
 __ZN3JSC16JSVariableObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE
-__ZN3JSC16JSVariableObject16setRegisterArrayEPNS_8RegisterEm
 __ZN3JSC16ParserRefCounted3refEv
 __ZN3JSC16ParserRefCounted5derefEv
 __ZN3JSC17PropertyNameArray3addEPNS_7UString3RepE
index 29abd50..80003a1 100644 (file)
@@ -106,12 +106,22 @@ extern "C"
 #endif
 
 
+ALWAYS_INLINE bool CTI::isConstant(int src)
+{
+    return src >= m_codeBlock->numVars && src < m_codeBlock->numVars + m_codeBlock->numConstants;
+}
+
+ALWAYS_INLINE JSValue* CTI::getConstant(ExecState* exec, int src)
+{
+    return m_codeBlock->constantRegisters[src - m_codeBlock->numVars].jsValue(exec);
+}
+
 // get arg puts an arg from the SF register array into a h/w register
 ALWAYS_INLINE void CTI::emitGetArg(unsigned src, X86Assembler::RegisterID dst)
 {
     // TODO: we want to reuse values that are already in registers if we can - add a register allocator!
-    if (src < m_codeBlock->constantRegisters.size()) {
-        JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
+    if (isConstant(src)) {
+        JSValue* js = getConstant(m_exec, src);
         m_jit.movl_i32r(reinterpret_cast<unsigned>(js), dst);
     } else
         m_jit.movl_mr(src * sizeof(Register), X86::edi, dst);
@@ -120,8 +130,8 @@ ALWAYS_INLINE void CTI::emitGetArg(unsigned src, X86Assembler::RegisterID dst)
 // get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function.
 ALWAYS_INLINE void CTI::emitGetPutArg(unsigned src, unsigned offset, X86Assembler::RegisterID scratch)
 {
-    if (src < m_codeBlock->constantRegisters.size()) {
-        JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
+    if (isConstant(src)) {
+        JSValue* js = getConstant(m_exec, src);
         m_jit.movl_i32m(reinterpret_cast<unsigned>(js), offset + sizeof(void*), X86::esp);
     } else {
         m_jit.movl_mr(src * sizeof(Register), X86::edi, scratch);
@@ -142,8 +152,8 @@ ALWAYS_INLINE void CTI::emitPutArgConstant(unsigned value, unsigned offset)
 
 ALWAYS_INLINE JSValue* CTI::getConstantImmediateNumericArg(unsigned src)
 {
-    if (src < m_codeBlock->constantRegisters.size()) {
-        JSValue* js = m_codeBlock->constantRegisters[src].jsValue(m_exec);
+    if (isConstant(src)) {
+        JSValue* js = getConstant(m_exec, src);
         return JSImmediate::isNumber(js) ? js : 0;
     }
     return 0;
@@ -166,12 +176,12 @@ ALWAYS_INLINE void CTI::emitGetCTIParam(unsigned name, X86Assembler::RegisterID
 
 ALWAYS_INLINE void CTI::emitPutToCallFrameHeader(X86Assembler::RegisterID from, RegisterFile::CallFrameHeaderEntry entry)
 {
-    m_jit.movl_rm(from, -((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - entry) * sizeof(Register), X86::edi);
+    m_jit.movl_rm(from, entry * sizeof(Register), X86::edi);
 }
 
 ALWAYS_INLINE void CTI::emitGetFromCallFrameHeader(RegisterFile::CallFrameHeaderEntry entry, X86Assembler::RegisterID to)
 {
-    m_jit.movl_mr(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - entry) * sizeof(Register), X86::edi, to);
+    m_jit.movl_mr(entry * sizeof(Register), X86::edi, to);
 }
 
 ALWAYS_INLINE void CTI::emitPutResult(unsigned dst, X86Assembler::RegisterID from)
@@ -180,7 +190,7 @@ ALWAYS_INLINE void CTI::emitPutResult(unsigned dst, X86Assembler::RegisterID fro
     // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
 }
 
-ALWAYS_INLINE void CTI::emitInitialiseRegister(unsigned dst)
+ALWAYS_INLINE void CTI::emitInitRegister(unsigned dst)
 {
     m_jit.movl_i32m(reinterpret_cast<unsigned>(jsUndefined()), dst * sizeof(Register), X86::edi);
     // FIXME: #ifndef NDEBUG, Write the correct m_type to the register.
@@ -220,8 +230,8 @@ ALWAYS_INLINE void CTI::emitDebugExceptionCheck()
 void CTI::printOpcodeOperandTypes(unsigned src1, unsigned src2)
 {
     char which1 = '*';
-    if (src1 < m_codeBlock->constantRegisters.size()) {
-        JSValue* js = m_codeBlock->constantRegisters[src1].jsValue(m_exec);
+    if (isConstant(src1)) {
+        JSValue* js = getConstant(m_exec, src1);
         which1 = 
             JSImmediate::isImmediate(js) ?
                 (JSImmediate::isNumber(js) ? 'i' :
@@ -234,8 +244,8 @@ void CTI::printOpcodeOperandTypes(unsigned src1, unsigned src2)
             'k');
     }
     char which2 = '*';
-    if (src2 < m_codeBlock->constantRegisters.size()) {
-        JSValue* js = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
+    if (isConstant(src2)) {
+        JSValue* js = getConstant(m_exec, src2);
         which2 = 
             JSImmediate::isImmediate(js) ?
                 (JSImmediate::isNumber(js) ? 'i' :
@@ -253,6 +263,15 @@ void CTI::printOpcodeOperandTypes(unsigned src1, unsigned src2)
 
 #endif
 
+ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCall(unsigned opcodeIndex, X86::RegisterID r)
+{
+    X86Assembler::JmpSrc call = m_jit.emitCall(r);
+    m_calls.append(CallRecord(call, opcodeIndex));
+    emitDebugExceptionCheck();
+
+    return call;
+}
+
 ALWAYS_INLINE X86Assembler::JmpSrc CTI::emitCall(unsigned opcodeIndex, CTIHelper_j helper)
 {
 #if ENABLE(SAMPLING_TOOL)
@@ -431,22 +450,30 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType
     int dst = instruction[i + 1].u.operand;
     int firstArg = instruction[i + 4].u.operand;
     int argCount = instruction[i + 5].u.operand;
+    int registerOffset = instruction[i + 6].u.operand;
+
+    if (type == OpCallEval)
+        emitGetPutArg(instruction[i + 3].u.operand, 16, X86::ecx);
 
     if (type == OpConstruct) {
-        emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 16);
-        emitPutArgConstant(argCount, 12);
+        emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 20);
+        emitPutArgConstant(argCount, 16);
+        emitPutArgConstant(registerOffset, 12);
         emitPutArgConstant(firstArg, 8);
         emitGetPutArg(instruction[i + 3].u.operand, 4, X86::ecx);
     } else {
-        emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 16);
-        emitPutArgConstant(argCount, 12);
-        emitPutArgConstant(firstArg, 8);
-        // FIXME: should this be loaded dynamically off m_exec?
+        emitPutArgConstant(reinterpret_cast<unsigned>(instruction + i), 12);
+        emitPutArgConstant(argCount, 8);
+        emitPutArgConstant(registerOffset, 4);
+
         int thisVal = instruction[i + 3].u.operand;
         if (thisVal == missingThisObjectMarker()) {
-            emitPutArgConstant(reinterpret_cast<unsigned>(m_exec->globalThisValue()), 4);
-        } else
-            emitGetPutArg(thisVal, 4, X86::ecx);
+            // FIXME: should this be loaded dynamically off m_exec?
+            m_jit.movl_i32m(reinterpret_cast<unsigned>(m_exec->globalThisValue()), firstArg * sizeof(Register), X86::edi);
+        } else {
+            emitGetArg(thisVal, X86::ecx);
+            emitPutResult(firstArg, X86::ecx);
+        }
     }
 
     X86Assembler::JmpSrc wasEval;
@@ -459,28 +486,14 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType
 
         m_jit.cmpl_i32r(reinterpret_cast<unsigned>(JSImmediate::impossibleValue()), X86::eax);
         wasEval = m_jit.emitUnlinkedJne();
-    
-        // this reloads the first arg into ecx (checked just below).
+
+        // this sets up the first arg to op_cti_call (func), and explicitly leaves the value in ecx (checked just below).
         emitGetArg(instruction[i + 2].u.operand, X86::ecx);
     } else {
-        // this sets up the first arg, and explicitly leaves the value in ecx (checked just below).
-        emitGetArg(instruction[i + 2].u.operand, X86::ecx);
-        emitPutArg(X86::ecx, 0);
+        // this sets up the first arg to op_cti_call (func), and explicitly leaves the value in ecx (checked just below).
+        emitGetPutArg(instruction[i + 2].u.operand, 0, X86::ecx);
     }
 
-    // initializeCallFrame!
-    m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::CallerCodeBlock) * sizeof(Register), X86::edi);
-    m_jit.movl_i32m(reinterpret_cast<unsigned>(instruction + i), (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::ReturnVPC) * sizeof(Register), X86::edi);
-    emitGetCTIParam(CTI_ARGS_scopeChain, X86::edx);
-    m_jit.movl_rm(X86::edx, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::CallerScopeChain) * sizeof(Register), X86::edi);
-    m_jit.movl_rm(X86::edi, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::CallerRegisters) * sizeof(Register), X86::edi);
-    m_jit.movl_i32m(dst, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::ReturnValueRegister) * sizeof(Register), X86::edi);
-    m_jit.movl_i32m(firstArg, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::ArgumentStartRegister) * sizeof(Register), X86::edi);
-    m_jit.movl_i32m(argCount, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::ArgumentCount) * sizeof(Register), X86::edi);
-    m_jit.movl_rm(X86::ecx, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::Callee) * sizeof(Register), X86::edi);
-    m_jit.movl_i32m(0, (firstArg - RegisterFile::CallFrameHeaderSize + RegisterFile::OptionalCalleeActivation) * sizeof(Register), X86::edi);
-    // CTIReturnEIP (set in callee)
-
     // Fast check for JS function.
     m_jit.testl_i32r(JSImmediate::TagMask, X86::ecx);
     X86Assembler::JmpSrc isNotObject = m_jit.emitUnlinkedJne();
@@ -490,27 +503,32 @@ void CTI::compileOpCall(Instruction* instruction, unsigned i, CompileOpCallType
 
     // This handles host functions
     emitCall(i, ((type == OpConstruct) ? Machine::cti_op_construct_NotJSConstruct : Machine::cti_op_call_NotJSFunction));
-    emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
-    
+
     X86Assembler::JmpSrc wasNotJSFunction = m_jit.emitUnlinkedJmp();
     m_jit.link(isJSFunction, m_jit.label());
 
     // This handles JSFunctions
     emitCall(i, ((type == OpConstruct) ? Machine::cti_op_construct_JSConstruct : Machine::cti_op_call_JSFunction));
+
+    // Initialize the parts of the call frame that have not already been initialized.
+    emitGetCTIParam(CTI_ARGS_r, X86::edi);
+    m_jit.movl_i32m(reinterpret_cast<unsigned>(m_codeBlock), RegisterFile::CallerCodeBlock * sizeof(Register), X86::edi);
+    m_jit.movl_i32m(dst, RegisterFile::ReturnValueRegister * sizeof(Register), X86::edi);
+
     // Check the ctiCode has been generated - if not, this is handled in a slow case.
     m_jit.testl_rr(X86::eax, X86::eax);
     m_slowCases.append(SlowCaseEntry(m_jit.emitUnlinkedJe(), i));
-    m_jit.call_r(X86::eax);
+    emitCall(i, X86::eax);
     
     // In the interpreter the following actions are performed by op_ret:
-    
-    // Store the scope chain - returned by op_ret in %edx (see below) - to ExecState::m_scopeChain and CTI_ARGS_scopeChain on the stack.
+
+    // Restore ExecState::m_scopeChain and CTI_ARGS_scopeChain. NOTE: After
+    // op_ret, %edx holds the caller's scope chain.
     emitGetCTIParam(CTI_ARGS_exec, X86::ecx);
     emitPutCTIParam(X86::edx, CTI_ARGS_scopeChain);
     m_jit.movl_rm(X86::edx, OBJECT_OFFSET(ExecState, m_scopeChain), X86::ecx);
     // Restore ExecState::m_callFrame.
-    m_jit.leal_mr(-(m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) * sizeof(Register), X86::edi, X86::edx);
-    m_jit.movl_rm(X86::edx, OBJECT_OFFSET(ExecState, m_callFrame), X86::ecx);
+    m_jit.movl_rm(X86::edi, OBJECT_OFFSET(ExecState, m_callFrame), X86::ecx);
     // Restore CTI_ARGS_codeBlock.
     emitPutCTIParam(m_codeBlock, CTI_ARGS_codeBlock);
 
@@ -593,13 +611,6 @@ void CTI::emitSlowScriptCheck(unsigned opcodeIndex)
 
 void CTI::privateCompileMainPass()
 {
-    if (m_codeBlock->codeType == FunctionCode) {
-        for (int i = -m_codeBlock->numVars; i < 0; i++)
-            emitInitialiseRegister(i);
-    }
-    for (size_t i = 0; i < m_codeBlock->constantRegisters.size(); ++i)
-        emitInitialiseRegister(i);
-
     Instruction* instruction = m_codeBlock->instructions.begin();
     unsigned instructionCount = m_codeBlock->instructions.size();
 
@@ -617,8 +628,8 @@ void CTI::privateCompileMainPass()
         switch (m_machine->getOpcodeID(instruction[i].u.opcode)) {
         case op_mov: {
             unsigned src = instruction[i + 2].u.operand;
-            if (src < m_codeBlock->constantRegisters.size())
-                m_jit.movl_i32r(reinterpret_cast<unsigned>(m_codeBlock->constantRegisters[src].jsValue(m_exec)), X86::edx);
+            if (isConstant(src))
+                m_jit.movl_i32r(reinterpret_cast<unsigned>(getConstant(m_exec, src)), X86::edx);
             else
                 emitGetArg(src, X86::edx);
             emitPutResult(instruction[i + 1].u.operand, X86::edx);
@@ -629,8 +640,8 @@ void CTI::privateCompileMainPass()
             unsigned dst = instruction[i + 1].u.operand;
             unsigned src1 = instruction[i + 2].u.operand;
             unsigned src2 = instruction[i + 3].u.operand;
-            if (src2 < m_codeBlock->constantRegisters.size()) {
-                JSValue* value = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
+            if (isConstant(src2)) {
+                JSValue* value = getConstant(m_exec, src2);
                 if (JSImmediate::isNumber(value)) {
                     emitGetArg(src1, X86::eax);
                     emitJumpSlowCaseIfNotImmNum(X86::eax, i);
@@ -640,7 +651,7 @@ void CTI::privateCompileMainPass()
                     i += 4;
                     break;
                 }
-            } else if (!(src1 < m_codeBlock->constantRegisters.size())) {
+            } else if (!isConstant(src1)) {
                 emitGetArg(src1, X86::eax);
                 emitGetArg(src2, X86::edx);
                 emitJumpSlowCaseIfNotImmNums(X86::eax, X86::edx, i);
@@ -665,7 +676,7 @@ void CTI::privateCompileMainPass()
 #if ENABLE(SAMPLING_TOOL)
             m_jit.movl_i32m(-1, &currentOpcodeID);
 #endif
-            m_jit.pushl_m(-((m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) - RegisterFile::CTIReturnEIP) * sizeof(Register), X86::edi);
+            m_jit.pushl_m(RegisterFile::ReturnPC * sizeof(Register), X86::edi);
             m_jit.ret();
             i += 2;
             break;
@@ -872,14 +883,14 @@ void CTI::privateCompileMainPass()
             unsigned dst = instruction[i + 1].u.operand;
             unsigned src1 = instruction[i + 2].u.operand;
             unsigned src2 = instruction[i + 3].u.operand;
-            if (src1 < m_codeBlock->constantRegisters.size() || src2 < m_codeBlock->constantRegisters.size()) {
+            if (isConstant(src1) || isConstant(src2)) {
                 unsigned constant = src1;
                 unsigned nonconstant = src2;
-                if (!(src1 < m_codeBlock->constantRegisters.size())) {
+                if (!isConstant(src1)) {
                     constant = src2;
                     nonconstant = src1;
                 }
-                JSValue* value = m_codeBlock->constantRegisters[constant].jsValue(m_exec);
+                JSValue* value = getConstant(m_exec, constant);
                 if (JSImmediate::isNumber(value)) {
                     emitGetArg(nonconstant, X86::eax);
                     emitJumpSlowCaseIfNotImmNum(X86::eax, i);
@@ -915,7 +926,7 @@ void CTI::privateCompileMainPass()
         }
         case op_call: {
             compileOpCall(instruction, i);
-            i += 6;
+            i += 7;
             break;
         }
         case op_get_global_var: {
@@ -962,7 +973,7 @@ void CTI::privateCompileMainPass()
         }
         case op_ret: {
             // Check for an activation - if there is one, jump to the hook below.
-            m_jit.cmpl_i32m(0, -(m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize - RegisterFile::OptionalCalleeActivation) * sizeof(Register), X86::edi);
+            m_jit.cmpl_i32m(0, RegisterFile::OptionalCalleeActivation * sizeof(Register), X86::edi);
             X86Assembler::JmpSrc activation = m_jit.emitUnlinkedJne();
             X86Assembler::JmpDst activated = m_jit.label();
 
@@ -979,11 +990,11 @@ void CTI::privateCompileMainPass()
             // Return the result in %eax, and the caller scope chain in %edx (this is read from the callee call frame,
             // but is only assigned to ExecState::m_scopeChain if returning to a JSFunction).
             emitGetArg(instruction[i + 1].u.operand, X86::eax);
-            m_jit.movl_mr(-(m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize - RegisterFile::CallerScopeChain) * sizeof(Register), X86::edi, X86::edx);
+            m_jit.movl_mr(RegisterFile::CallerScopeChain * sizeof(Register), X86::edi, X86::edx);
             // Restore the machine return addess from the callframe, roll the callframe back to the caller callframe,
             // and preserve a copy of r on the stack at CTI_ARGS_r. 
-            m_jit.movl_mr(-(m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize - RegisterFile::CTIReturnEIP) * sizeof(Register), X86::edi, X86::ecx);
-            m_jit.movl_mr(-(m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize - RegisterFile::CallerRegisters) * sizeof(Register), X86::edi, X86::edi);
+            m_jit.movl_mr(RegisterFile::ReturnPC * sizeof(Register), X86::edi, X86::ecx);
+            m_jit.movl_mr(RegisterFile::CallerRegisters * sizeof(Register), X86::edi, X86::edi);
             emitPutCTIParam(X86::edi, CTI_ARGS_r);
 
             m_jit.pushl_r(X86::ecx);
@@ -1021,7 +1032,7 @@ void CTI::privateCompileMainPass()
         }
         case op_construct: {
             compileOpCall(instruction, i, OpConstruct);
-            i += 6;
+            i += 7;
             break;
         }
         case op_construct_verify: {
@@ -1449,7 +1460,7 @@ void CTI::privateCompileMainPass()
         }
         case op_call_eval: {
             compileOpCall(instruction, i, OpCallEval);
-            i += 6;
+            i += 7;
             break;
         }
         case op_throw: {
@@ -1713,8 +1724,15 @@ void CTI::privateCompileMainPass()
             i += 3;
             break;
         }
-        case op_initialise_locals: {
-            i++;
+        case op_init: {
+            // Even though CTI doesn't use them, we initialize our constant
+            // registers to zap stale pointers, to avoid unnecessarily prolonging
+            // object lifetime and increasing GC pressure.
+            size_t count = m_codeBlock->numVars + m_codeBlock->constantRegisters.size();
+            for (size_t j = 0; j < count; ++j)
+                emitInitRegister(j);
+
+            i+= 1;
             break;
         }
         case op_get_array_length:
@@ -1765,8 +1783,8 @@ void CTI::privateCompileSlowCases()
         case op_add: {
             unsigned dst = instruction[i + 1].u.operand;
             unsigned src2 = instruction[i + 3].u.operand;
-            if (src2 < m_codeBlock->constantRegisters.size()) {
-                JSValue* value = m_codeBlock->constantRegisters[src2].jsValue(m_exec);
+            if (isConstant(src2)) {
+                JSValue* value = getConstant(m_exec, src2);
                 if (JSImmediate::isNumber(value)) {
                     X86Assembler::JmpSrc notImm = iter->from;
                     m_jit.link((++iter)->from, m_jit.label());
@@ -1781,7 +1799,7 @@ void CTI::privateCompileSlowCases()
                 }
             }
 
-            ASSERT(!(static_cast<unsigned>(instruction[i + 2].u.operand) < m_codeBlock->constantRegisters.size()));
+            ASSERT(!isConstant(instruction[i + 2].u.operand));
 
             X86Assembler::JmpSrc notImm = iter->from;
             m_jit.link((++iter)->from, m_jit.label());
@@ -2196,24 +2214,24 @@ void CTI::privateCompileSlowCases()
 
             // We jump to this slow case if the ctiCode for the codeBlock has not yet been generated; compile it now.
             emitCall(i, Machine::cti_vm_compile);
-            m_jit.call_r(X86::eax);
-            
+            emitCall(i, X86::eax);
+
             // Instead of checking for 0 we could initialize the CodeBlock::ctiCode to point to a trampoline that would trigger the translation.
 
             // In the interpreter the following actions are performed by op_ret:
-            
-            // Store the scope chain - returned by op_ret in %edx (see below) - to ExecState::m_scopeChain and CTI_ARGS_scopeChain on the stack.
+
+            // Restore ExecState::m_scopeChain and CTI_ARGS_scopeChain. NOTE: After
+            // op_ret, %edx holds the caller's scope chain.
             emitGetCTIParam(CTI_ARGS_exec, X86::ecx);
             emitPutCTIParam(X86::edx, CTI_ARGS_scopeChain);
             m_jit.movl_rm(X86::edx, OBJECT_OFFSET(ExecState, m_scopeChain), X86::ecx);
             // Restore ExecState::m_callFrame.
-            m_jit.leal_mr(-(m_codeBlock->numLocals + RegisterFile::CallFrameHeaderSize) * sizeof(Register), X86::edi, X86::edx);
-            m_jit.movl_rm(X86::edx, OBJECT_OFFSET(ExecState, m_callFrame), X86::ecx);
+            m_jit.movl_rm(X86::edi, OBJECT_OFFSET(ExecState, m_callFrame), X86::ecx);
             // Restore CTI_ARGS_codeBlock.
             emitPutCTIParam(m_codeBlock, CTI_ARGS_codeBlock);
 
             emitPutResult(instruction[i + 1].u.operand);
-            i += 6;
+            i += 7;
             break;
         }
 
@@ -2233,7 +2251,7 @@ void CTI::privateCompile()
     // Could use a popl_m, but would need to offset the following instruction if so.
     m_jit.popl_r(X86::ecx);
     emitGetCTIParam(CTI_ARGS_r, X86::edi); // edi := r
-    emitPutToCallFrameHeader(X86::ecx, RegisterFile::CTIReturnEIP);
+    emitPutToCallFrameHeader(X86::ecx, RegisterFile::ReturnPC);
 
     // Lazy copy of the scopeChain
     X86Assembler::JmpSrc callToUpdateScopeChain;
@@ -2282,11 +2300,9 @@ void CTI::privateCompile()
     for (Vector<HandlerInfo>::iterator iter = m_codeBlock->exceptionHandlers.begin(); iter != m_codeBlock->exceptionHandlers.end(); ++iter)
          iter->nativeCode = m_jit.getRelocatedAddress(code, m_labels[iter->target]);
 
-    // FIXME: There doesn't seem to be a way to hint to a hashmap that it should make a certain capacity available;
-    // could be faster if we could do something like this:
-    // m_codeBlock->ctiReturnAddressVPCMap.grow(m_calls.size());
     for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) {
-        X86Assembler::link(code, iter->from, iter->to);
+        if (iter->to)
+            X86Assembler::link(code, iter->from, iter->to);
         m_codeBlock->ctiReturnAddressVPCMap.add(m_jit.getRelocatedAddress(code, iter->from), iter->opcodeIndex);
     }
 
index 156e4ee..e5bbd41 100644 (file)
@@ -76,6 +76,7 @@
 #define ARG_src2 ((JSValue*)((ARGS)[2]))
 #define ARG_src3 ((JSValue*)((ARGS)[3]))
 #define ARG_src4 ((JSValue*)((ARGS)[4]))
+#define ARG_src5 ((JSValue*)((ARGS)[5]))
 #define ARG_id1 ((Identifier*)((ARGS)[1]))
 #define ARG_id2 ((Identifier*)((ARGS)[2]))
 #define ARG_id3 ((Identifier*)((ARGS)[3]))
@@ -84,6 +85,7 @@
 #define ARG_int2 ((int)((ARGS)[2]))
 #define ARG_int3 ((int)((ARGS)[3]))
 #define ARG_int4 ((int)((ARGS)[4]))
+#define ARG_int5 ((int)((ARGS)[5]))
 #define ARG_func1 ((FuncDeclNode*)((ARGS)[1]))
 #define ARG_funcexp1 ((FuncExprNode*)((ARGS)[1]))
 #define ARG_registers1 ((Register*)((ARGS)[1]))
@@ -94,6 +96,7 @@
 #define ARG_instr3 ((Instruction*)((ARGS)[3]))
 #define ARG_instr4 ((Instruction*)((ARGS)[4]))
 #define ARG_instr5 ((Instruction*)((ARGS)[5]))
+#define ARG_instr6 ((Instruction*)((ARGS)[6]))
 
 #define CTI_RETURN_ADDRESS ((ARGS)[-1])
 
@@ -161,6 +164,13 @@ namespace JSC {
             , opcodeIndex(i)
         {
         }
+
+        CallRecord(X86Assembler::JmpSrc f, unsigned i)
+            : from(f)
+            , to(0)
+            , opcodeIndex(i)
+        {
+        }
     };
 
     struct JmpTable {
@@ -322,6 +332,10 @@ namespace JSC {
 
     private:
         CTI(Machine*, ExecState*, CodeBlock*);
+        
+        bool isConstant(int src);
+        JSValue* CTI::getConstant(ExecState*, int src);
+
         void privateCompileMainPass();
         void privateCompileLinkPass();
         void privateCompileSlowCases();
@@ -347,7 +361,7 @@ namespace JSC {
         void emitPutArgConstant(unsigned value, unsigned offset);
         void emitPutResult(unsigned dst, X86Assembler::RegisterID from = X86::eax);
 
-        void emitInitialiseRegister(unsigned dst);
+        void emitInitRegister(unsigned dst);
 
         void emitPutCTIParam(void* value, unsigned name);
         void emitPutCTIParam(X86Assembler::RegisterID from, unsigned name);
@@ -376,6 +390,7 @@ namespace JSC {
 
         void emitDebugExceptionCheck();
 
+        X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, X86::RegisterID);
         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_j);
         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_p);
         X86Assembler::JmpSrc emitCall(unsigned opcodeIndex, CTIHelper_b);
index af3b354..e336619 100644 (file)
@@ -64,13 +64,10 @@ static UString valueToSourceString(ExecState* exec, JSValue* val)
 
 static CString registerName(int r)
 {
-    if (r < 0)
-        return (UString("lr") + UString::from(-r)).UTF8String(); 
-        
     if (r == missingThisObjectMarker())
         return "<null>";
 
-    return (UString("tr") + UString::from(r)).UTF8String();
+    return (UString("r") + UString::from(r)).UTF8String();
 }
 
 static CString constantName(ExecState* exec, int k, JSValue* value)
@@ -233,10 +230,10 @@ void CodeBlock::dump(ExecState* exec) const
         if (exec->machine()->isOpcode(it->u.opcode))
             ++instructionCount;
 
-    printf("%lu instructions; %lu bytes at %p; %d locals (%d parameters); %d temporaries\n\n",
+    printf("%lu instructions; %lu bytes at %p; %d parameter(s); %d callee register(s)\n\n",
         static_cast<unsigned long>(instructionCount),
         static_cast<unsigned long>(instructions.size() * sizeof(Instruction)),
-        this, numLocals, numParameters, numTemporaries);
+        this, numParameters, numCalleeRegisters);
     
     for (Vector<Instruction>::const_iterator it = begin; it != end; ++it)
         dump(exec, begin, it);
@@ -254,7 +251,7 @@ void CodeBlock::dump(ExecState* exec) const
         printf("\nConstants:\n");
         size_t i = 0;
         do {
-            printf("  tr%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, constantRegisters[i].jsValue(exec)).ascii());
+            printf("   r%u = %s\n", static_cast<unsigned>(i), valueToSourceString(exec, constantRegisters[i].jsValue(exec)).ascii());
             ++i;
         } while (i < constantRegisters.size());
     }
@@ -351,8 +348,8 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
 {
     int location = it - begin;
     switch (exec->machine()->getOpcodeID(it->u.opcode)) {
-        case op_initialise_locals: {
-            printf("[%4d] initialise_locals\n", location);
+        case op_init: {
+            printf("[%4d] init\n", location);
             break;
         }
         case op_unexpected_load: {
@@ -779,7 +776,8 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int r2 = (++it)->u.operand;
             int tempCount = (++it)->u.operand;
             int argCount = (++it)->u.operand;
-            printf("[%4d] call\t\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
+            int registerOffset = (++it)->u.operand;
+            printf("[%4d] call\t\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
             break;
         }
         case op_call_eval: {
@@ -788,7 +786,8 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int r2 = (++it)->u.operand;
             int tempCount = (++it)->u.operand;
             int argCount = (++it)->u.operand;
-            printf("[%4d] call_eval\t\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
+            int registerOffset = (++it)->u.operand;
+            printf("[%4d] call_eval\t\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
             break;
         }
         case op_ret: {
@@ -802,7 +801,8 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             int r2 = (++it)->u.operand;
             int tempCount = (++it)->u.operand;
             int argCount = (++it)->u.operand;
-            printf("[%4d] construct\t %s, %s, %s, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount);
+            int registerOffset = (++it)->u.operand;
+            printf("[%4d] construct\t %s, %s, %s, %d, %d, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), tempCount, argCount, registerOffset);
             break;
         }
         case op_construct_verify: {
index be3b662..9c90f9e 100644 (file)
@@ -186,10 +186,10 @@ namespace JSC {
 #if ENABLE(CTI)
             , ctiCode(0)
 #endif
-            , numTemporaries(0)
+            , numCalleeRegisters(0)
+            , numConstants(0)
             , numVars(0)
             , numParameters(0)
-            , numLocals(0)
             , needsFullScopeChain(ownerNode_->usesEval() || ownerNode_->needsClosure())
             , usesEval(ownerNode_->usesEval())
             , codeType(codeType_)
@@ -217,15 +217,10 @@ namespace JSC {
         StructureStubInfo& getStubInfo(void* returnAddress)
         {
             // FIXME: would a binary chop be faster here?
-            for (unsigned i = 0; i < structureIDInstructions.size(); ++i) {
+            for (unsigned i = 0; ; ++i) {
                 if (structureIDInstructions[i].callReturnLocation == returnAddress)
                     return structureIDInstructions[i];
             }
-            
-            ASSERT_NOT_REACHED();
-            // keep the compiler happy.
-            static StructureStubInfo duff(0);
-            return duff;
         }
 
         ScopeNode* ownerNode;
@@ -234,11 +229,15 @@ namespace JSC {
         void* ctiCode;
 #endif
 
+        int numCalleeRegisters;
+
+        // NOTE: numConstants holds the number of constant registers allocated
+        // by the code generator, not the number of constant registers used.
+        // (Duplicate constants are uniqued during code generation, and spare
+        // constant registers may be allocated.)
         int numConstants;
-        int numTemporaries;
         int numVars;
         int numParameters;
-        int numLocals;
         int thisRegister;
         bool needsFullScopeChain;
         bool usesEval;
index 12cce6e..5500375 100644 (file)
@@ -129,8 +129,8 @@ void CodeGenerator::setDumpsGeneratedCode(bool dumpsGeneratedCode)
 
 void CodeGenerator::generate()
 {
-    m_codeBlock->numLocals = m_codeBlock->numVars + m_codeBlock->numParameters;
     m_codeBlock->thisRegister = m_thisRegister.index();
+
     if (m_shouldEmitDebugHooks)
         m_codeBlock->needsFullScopeChain = true;
 
@@ -152,40 +152,50 @@ void CodeGenerator::generate()
 
 bool CodeGenerator::addVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
 {
-    int index = m_nextVar;
+    int index = m_calleeRegisters.size();
     SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
     pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
 
-    if (!result.second)
-        index = result.first->second.getIndex();
-    else {
-        --m_nextVar;
-        ++m_codeBlock->numVars;
-
-        m_locals.append(index);
+    if (!result.second) {
+        r0 = &registerFor(result.first->second.getIndex());
+        return false;
     }
 
-    r0 = &m_locals[localsIndex(index)];
-    return result.second;
+    ++m_codeBlock->numVars;
+    r0 = newRegister();
+    return true;
 }
 
 bool CodeGenerator::addGlobalVar(const Identifier& ident, bool isConstant, RegisterID*& r0)
 {
-    int index = m_nextVar;
+    int index = m_nextGlobal;
     SymbolTableEntry newEntry(index, isConstant ? ReadOnly : 0);
     pair<SymbolTable::iterator, bool> result = symbolTable().add(ident.ustring().rep(), newEntry);
 
     if (!result.second)
         index = result.first->second.getIndex();
     else {
-        --m_nextVar;
-        m_locals.append(index + m_globalVarStorageOffset);
+        --m_nextGlobal;
+        m_globals.append(index + m_globalVarStorageOffset);
     }
 
-    r0 = &m_locals[localsIndex(index)];
+    r0 = &registerFor(index);
     return result.second;
 }
 
+void CodeGenerator::allocateConstants(size_t count)
+{
+    m_codeBlock->numConstants = count;
+    if (!count)
+        return;
+    
+    m_nextConstant = m_calleeRegisters.size();
+
+    for (size_t i = 0; i < count; ++i)
+        newRegister();
+    m_lastConstant = &m_calleeRegisters.last();
+}
+
 CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, CodeBlock* codeBlock, VarStack& varStack, FunctionStack& functionStack)
     : m_shouldEmitDebugHooks(!!debugger)
     , m_scopeChain(&scopeChain)
@@ -197,36 +207,36 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
     , m_dynamicScopeDepth(0)
     , m_codeType(GlobalCode)
     , m_continueDepth(0)
-    , m_nextVar(-1)
+    , m_nextGlobal(-1)
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
+    emitOpcode(op_init);
     codeBlock->globalData = m_globalData;
 
     // FIXME: Move code that modifies the global object to Machine::execute.
     
-    m_codeBlock->numConstants = programNode->neededConstants();
-    m_codeBlock->numVars = 1; // Allocate space for "this"
+    m_codeBlock->numParameters = 1; // Allocate space for "this"
 
     JSGlobalObject* globalObject = scopeChain.globalObject();
     ExecState* exec = globalObject->globalExec();
     RegisterFile* registerFile = &exec->globalData().machine->registerFile();
     
     // Shift register indexes in generated code to elide registers allocated by intermediate stack frames.
-    m_globalVarStorageOffset = -1 - RegisterFile::CallFrameHeaderSize - registerFile->size();
+    m_globalVarStorageOffset = -RegisterFile::CallFrameHeaderSize - m_codeBlock->numParameters - registerFile->size();
 
     // Add previously defined symbols to bookkeeping.
-    m_locals.resize(symbolTable->size());
+    m_globals.resize(symbolTable->size());
     SymbolTable::iterator end = symbolTable->end();
     for (SymbolTable::iterator it = symbolTable->begin(); it != end; ++it)
-        m_locals[localsIndex(it->second.getIndex())].setIndex(it->second.getIndex() + m_globalVarStorageOffset);
+        registerFor(it->second.getIndex()).setIndex(it->second.getIndex() + m_globalVarStorageOffset);
         
     BatchedTransitionOptimizer optimizer(globalObject);
 
     bool canOptimizeNewGlobals = symbolTable->size() + functionStack.size() + varStack.size() < registerFile->maxGlobals();
     if (canOptimizeNewGlobals) {
         // Shift new symbols so they get stored prior to existing symbols.
-        m_nextVar -= symbolTable->size();
+        m_nextGlobal -= symbolTable->size();
 
         for (size_t i = 0; i < functionStack.size(); ++i) {
             FuncDeclNode* funcDecl = functionStack[i].get();
@@ -234,10 +244,15 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
             emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl);
         }
 
-        for (size_t i = 0; i < varStack.size(); ++i) {
+        Vector<RegisterID*, 32> newVars;
+        for (size_t i = 0; i < varStack.size(); ++i)
             if (!globalObject->hasProperty(exec, varStack[i].first))
-                emitLoad(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant), jsUndefined());
-        }
+                newVars.append(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant));
+
+        allocateConstants(programNode->neededConstants());
+
+        for (size_t i = 0; i < newVars.size(); ++i)
+            emitLoad(newVars[i], jsUndefined());
     } else {
         for (size_t i = 0; i < functionStack.size(); ++i) {
             FuncDeclNode* funcDecl = functionStack[i].get();
@@ -251,6 +266,8 @@ CodeGenerator::CodeGenerator(ProgramNode* programNode, const Debugger* debugger,
                 attributes |= ReadOnly;
             globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes);
         }
+
+        allocateConstants(programNode->neededConstants());
     }
 }
 
@@ -264,15 +281,12 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     , m_dynamicScopeDepth(0)
     , m_codeType(FunctionCode)
     , m_continueDepth(0)
-    , m_nextVar(-1)
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
-    emitOpcode(op_initialise_locals);
+    emitOpcode(op_init);
     codeBlock->globalData = m_globalData;
 
-    m_codeBlock->numConstants = functionBody->neededConstants();
-
     const Node::FunctionStack& functionStack = functionBody->functionStack();
     for (size_t i = 0; i < functionStack.size(); ++i) {
         FuncDeclNode* funcDecl = functionStack[i].get();
@@ -291,8 +305,8 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     }
 
     Vector<Identifier>& parameters = functionBody->parameters();
-    m_nextParameter = m_nextVar - parameters.size(); // parameters are allocated prior to vars
-    m_locals.resize(localsIndex(m_nextParameter) + 1); // localsIndex of 0 => m_locals size of 1
+    m_nextParameter = -RegisterFile::CallFrameHeaderSize - parameters.size() - 1;
+    m_parameters.resize(1 + parameters.size()); // reserve space for "this"
 
     // Add "this" as a parameter
     m_thisRegister.setIndex(m_nextParameter);
@@ -301,6 +315,8 @@ CodeGenerator::CodeGenerator(FunctionBodyNode* functionBody, const Debugger* deb
     
     for (size_t i = 0; i < parameters.size(); ++i)
         addParameter(parameters[i]);
+
+    allocateConstants(functionBody->neededConstants());
 }
 
 CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const ScopeChain& scopeChain, SymbolTable* symbolTable, EvalCodeBlock* codeBlock)
@@ -317,27 +333,23 @@ CodeGenerator::CodeGenerator(EvalNode* evalNode, const Debugger* debugger, const
     , m_globalData(&scopeChain.globalObject()->globalExec()->globalData())
     , m_lastOpcodeID(op_end)
 {
-    emitOpcode(op_initialise_locals);
+    emitOpcode(op_init);
     codeBlock->globalData = m_globalData;
+    m_codeBlock->numParameters = 1; // Allocate space for "this"
 
-    m_codeBlock->numConstants = evalNode->neededConstants();
-    m_codeBlock->numVars = 1; // Allocate space for "this"
-}
-
-CodeGenerator::~CodeGenerator()
-{
+    allocateConstants(evalNode->neededConstants());
 }
 
 RegisterID* CodeGenerator::addParameter(const Identifier& ident)
 {
-    // Parameters overwrite var declarations, but not function declarations,
-    // in the symbol table.
+    // Parameters overwrite var declarations, but not function declarations.
     RegisterID* result = 0;
     UString::Rep* rep = ident.ustring().rep();
     if (!m_functions.contains(rep)) {
         symbolTable().set(rep, m_nextParameter);
-        m_locals[localsIndex(m_nextParameter)].setIndex(m_nextParameter);
-        result = &(m_locals[localsIndex(m_nextParameter)]);
+        RegisterID& parameter = registerFor(m_nextParameter);
+        parameter.setIndex(m_nextParameter);
+        result = &parameter;
     }
 
     // To maintain the calling convention, we have to allocate unique space for
@@ -347,7 +359,7 @@ RegisterID* CodeGenerator::addParameter(const Identifier& ident)
     return result;
 }
 
-RegisterID* CodeGenerator::registerForLocal(const Identifier& ident)
+RegisterID* CodeGenerator::registerFor(const Identifier& ident)
 {
     if (m_codeType == FunctionCode && ident == propertyNames().arguments)
         m_codeBlock->needsFullScopeChain = true;
@@ -362,10 +374,10 @@ RegisterID* CodeGenerator::registerForLocal(const Identifier& ident)
     if (entry.isNull())
         return 0;
 
-    return &m_locals[localsIndex(entry.getIndex())];
+    return &registerFor(entry.getIndex());
 }
 
-RegisterID* CodeGenerator::registerForLocalConstInit(const Identifier& ident)
+RegisterID* CodeGenerator::constRegisterFor(const Identifier& ident)
 {
     if (m_codeType == EvalCode)
         return 0;
@@ -373,7 +385,7 @@ RegisterID* CodeGenerator::registerForLocalConstInit(const Identifier& ident)
     SymbolTableEntry entry = symbolTable().get(ident.ustring().rep());
     ASSERT(!entry.isNull());
 
-    return &m_locals[localsIndex(entry.getIndex())];
+    return &registerFor(entry.getIndex());
 }
 
 bool CodeGenerator::isLocal(const Identifier& ident)
@@ -389,23 +401,30 @@ bool CodeGenerator::isLocalConstant(const Identifier& ident)
     return symbolTable().get(ident.ustring().rep()).isReadOnly();
 }
 
+RegisterID* CodeGenerator::newRegister()
+{
+    m_calleeRegisters.append(m_calleeRegisters.size());
+    m_codeBlock->numCalleeRegisters = max<int>(m_codeBlock->numCalleeRegisters, m_calleeRegisters.size());
+    return &m_calleeRegisters.last();
+}
+
 RegisterID* CodeGenerator::newTemporary()
 {
     // Reclaim free register IDs.
-    while (m_temporaries.size() && !m_temporaries.last().refCount())
-        m_temporaries.removeLast();
-
-    // Allocate new register ID.
-    m_temporaries.append(m_temporaries.size() + m_codeBlock->numConstants);
-    m_codeBlock->numTemporaries = max<int>(m_codeBlock->numTemporaries, m_temporaries.size());
-    return &m_temporaries.last();
+    while (m_calleeRegisters.size() && !m_calleeRegisters.last().refCount())
+        m_calleeRegisters.removeLast();
+        
+    RegisterID* result = newRegister();
+    result->setTemporary();
+    return result;
 }
 
 RegisterID* CodeGenerator::highestUsedRegister()
 {
-    while (m_temporaries.size() < static_cast<unsigned>(m_codeBlock->numTemporaries))
-        m_temporaries.append(m_temporaries.size());
-    return &m_temporaries.last();
+    size_t count = m_codeBlock->numCalleeRegisters;
+    while (m_calleeRegisters.size() < count)
+        newRegister();
+    return &m_calleeRegisters.last();
 }
 
 PassRefPtr<LabelID> CodeGenerator::newLabel()
@@ -579,16 +598,17 @@ unsigned CodeGenerator::addConstant(const Identifier& ident)
 
 RegisterID* CodeGenerator::addConstant(JSValue* v)
 {
-    pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(v, m_codeBlock->constantRegisters.size());
+    pair<JSValueMap::iterator, bool> result = m_jsValueMap.add(v, m_nextConstant);
     if (result.second) {
-        m_constants.append(m_codeBlock->constantRegisters.size());
-        m_constants.last().makeConstant();
+        RegisterID& constant = m_calleeRegisters[m_nextConstant];
+        
+        ++m_nextConstant;
+
         m_codeBlock->constantRegisters.append(v);
-        ASSERT(m_codeBlock->constantRegisters.size() <= (unsigned) m_codeBlock->numConstants);
-        return &m_constants.last();
+        return &constant;
     }
 
-    return &m_constants[result.first->second];
+    return &registerFor(result.first->second);
 }
 
 unsigned CodeGenerator::addUnexpectedConstant(JSValue* v)
@@ -1089,18 +1109,9 @@ RegisterID* CodeGenerator::emitCallEval(RegisterID* dst, RegisterID* func, Regis
 RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, RegisterID* func, RegisterID* base, ArgumentsNode* argumentsNode, unsigned divot, unsigned startOffset, unsigned endOffset)
 {
     ASSERT(opcodeID == op_call || opcodeID == op_call_eval);
+    ASSERT(func->refCount());
+    ASSERT(!base || base->refCount());
     
-    // Ordinarily, we might ref "func" and "base", to avoid allocating new
-    // temporaries in the same registers. In this case, though, we actually
-    // want the call frame we allocate to overlap "func" and "base", if they're
-    // not otherwise referenced. op_call will read "func" and "base" before
-    // writing out the call frame, so this is safe.
-
-    // Reserve space for call frame.
-    Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
-    for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
-        callFrame.append(newTemporary());
-
     // Generate code for arguments.
     Vector<RefPtr<RegisterID>, 16> argv;
     argv.append(newTemporary()); // reserve space for "this"
@@ -1109,6 +1120,11 @@ RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Register
         emitNode(argv.last().get(), n);
     }
 
+    // Reserve space for call frame.
+    Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
+    for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
+        callFrame.append(newTemporary());
+
     emitExpressionInfo(divot, startOffset, endOffset);
     emitOpcode(opcodeID);
     instructions().append(dst->index());
@@ -1116,6 +1132,7 @@ RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Register
     instructions().append(base ? base->index() : missingThisObjectMarker()); // We encode the "this" value in the instruction stream, to avoid an explicit instruction for copying or loading it.
     instructions().append(argv[0]->index()); // argv
     instructions().append(argv.size()); // argc
+    instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
     return dst;
 }
 
@@ -1130,13 +1147,10 @@ RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, Argu
 {
     ASSERT(func->refCount());
 
-    // Reserve space for prototype
+    // Load prototype.
+    emitExpressionInfo(divot, startOffset, endOffset);
     RefPtr<RegisterID> funcProto = newTemporary();
-
-    // Reserve space for call frame.
-    Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
-    for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
-        callFrame.append(newTemporary());
+    emitGetById(funcProto.get(), func, globalExec()->propertyNames().prototype);
 
     // Generate code for arguments.
     Vector<RefPtr<RegisterID>, 16> argv;
@@ -1146,8 +1160,10 @@ RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, Argu
         emitNode(argv.last().get(), n);
     }
 
-    emitExpressionInfo(divot, startOffset, endOffset);
-    emitGetById(funcProto.get(), func, globalExec()->propertyNames().prototype);
+    // Reserve space for call frame.
+    Vector<RefPtr<RegisterID>, RegisterFile::CallFrameHeaderSize> callFrame;
+    for (int i = 0; i < RegisterFile::CallFrameHeaderSize; ++i)
+        callFrame.append(newTemporary());
 
     emitExpressionInfo(divot, startOffset, endOffset);
     emitOpcode(op_construct);
@@ -1156,7 +1172,8 @@ RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, Argu
     instructions().append(funcProto->index());
     instructions().append(argv[0]->index()); // argv
     instructions().append(argv.size()); // argc
-    
+    instructions().append(argv[0]->index() + argv.size() + RegisterFile::CallFrameHeaderSize); // registerOffset
+
     emitOpcode(op_construct_verify);
     instructions().append(dst->index());
     instructions().append(argv[0]->index());
index 8bc9b31..fc7f5d5 100644 (file)
@@ -79,20 +79,19 @@ namespace JSC {
         CodeGenerator(FunctionBodyNode*, const Debugger*, const ScopeChain&, SymbolTable*, CodeBlock*);
         CodeGenerator(EvalNode*, const Debugger*, const ScopeChain&, SymbolTable*, EvalCodeBlock*);
 
-        ~CodeGenerator();
-
         JSGlobalData* globalData() const { return m_globalData; }
         const CommonIdentifiers& propertyNames() const { return *m_globalData->propertyNames; }
 
         void generate();
 
         // Returns the register corresponding to a local variable, or 0 if no
-        // such register exists. Registers returned by registerForLocal do not
+        // such register exists. Registers returned by registerFor do not
         // require explicit reference counting.
-        RegisterID* registerForLocal(const Identifier&);
-        // Behaves as registerForLocal does, but ignores dynamic scope as
+        RegisterID* registerFor(const Identifier&);
+
+        // Behaves as registerFor does, but ignores dynamic scope as
         // dynamic scope should not interfere with const initialisation
-        RegisterID* registerForLocalConstInit(const Identifier&);
+        RegisterID* constRegisterFor(const Identifier&);
 
         // Searches the scope chain in an attempt to  statically locate the requested
         // property.  Returns false if for any reason the property cannot be safely
@@ -352,9 +351,8 @@ namespace JSC {
         typedef HashMap<UString::Rep*, JSString*, IdentifierRepHash> IdentifierStringMap;
 
         RegisterID* emitCall(OpcodeID, RegisterID*, RegisterID*, RegisterID*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
-
-        // Maps a register index in the symbol table to a RegisterID index in m_locals.
-        int localsIndex(int registerIndex) { return -registerIndex - 1; }
+        
+        RegisterID* newRegister();
 
         // Returns the RegisterID corresponding to ident.
         RegisterID* addVar(const Identifier& ident, bool isConstant)
@@ -377,6 +375,21 @@ namespace JSC {
         bool addGlobalVar(const Identifier&, bool isConstant, RegisterID*&);
 
         RegisterID* addParameter(const Identifier&);
+        
+        void allocateConstants(size_t);
+
+        RegisterID& registerFor(int index)
+        {
+            if (index >= 0)
+                return m_calleeRegisters[index];
+
+            if (m_parameters.size()) {
+                ASSERT(!m_globals.size());
+                return m_parameters[index + m_parameters.size() + RegisterFile::CallFrameHeaderSize];
+            }
+
+            return m_globals[-index - 1];
+        }
 
         unsigned addConstant(FuncDeclNode*);
         unsigned addConstant(FuncExprNode*);
@@ -403,9 +416,10 @@ namespace JSC {
 
         HashSet<RefPtr<UString::Rep>, IdentifierRepHash> m_functions;
         RegisterID m_thisRegister;
-        SegmentedVector<RegisterID, 512> m_locals;
-        SegmentedVector<RegisterID, 512> m_constants;
-        SegmentedVector<RegisterID, 512> m_temporaries;
+        RefPtr<RegisterID> m_lastConstant;
+        SegmentedVector<RegisterID, 512> m_calleeRegisters;
+        SegmentedVector<RegisterID, 512> m_parameters;
+        SegmentedVector<RegisterID, 512> m_globals;
         SegmentedVector<LabelID, 512> m_labels;
         int m_finallyDepth;
         int m_dynamicScopeDepth;
@@ -416,8 +430,9 @@ namespace JSC {
         Vector<ControlFlowContext> m_scopeContextStack;
         Vector<SwitchInfo> m_switchContextStack;
 
-        int m_nextVar;
+        int m_nextGlobal;
         int m_nextParameter;
+        int m_nextConstant;
 
         int m_globalVarStorageOffset;
 
index fb44620..702f6c5 100644 (file)
@@ -83,6 +83,27 @@ static void* op_throw_end_indirect;
 static void* op_call_indirect;
 #endif
 
+#if ENABLE(CTI)
+
+ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock* codeBlock, void* pc)
+{
+    if (pc >= codeBlock->instructions.begin() && pc < codeBlock->instructions.end())
+        return static_cast<Instruction*>(pc);
+
+    ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(pc));
+    unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(pc);
+    return codeBlock->instructions.begin() + vPCIndex;
+}
+
+#else // #ENABLE(CTI)
+
+ALWAYS_INLINE static Instruction* vPCForPC(CodeBlock*, void* pc)
+{
+    return static_cast<Instruction*>(pc);
+}
+
+#endif // #ENABLE(CTI)
+
 // Returns the depth of the scope chain within a given call frame.
 static int depth(CodeBlock* codeBlock, ScopeChain& sc)
 {
@@ -498,23 +519,21 @@ Opcode Machine::getOpcode(OpcodeID id)
     #endif
 }
 
-ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
+ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argc, JSValue* function)
 {
     callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
-    callFrame[RegisterFile::ReturnVPC] = vPC + 1;
     callFrame[RegisterFile::CallerScopeChain] = scopeChain;
     callFrame[RegisterFile::CallerRegisters] = r;
+    callFrame[RegisterFile::ReturnPC] = vPC + 1;
     callFrame[RegisterFile::ReturnValueRegister] = returnValueRegister;
-    callFrame[RegisterFile::ArgumentStartRegister] = argv; // original argument vector (for the sake of the "arguments" object)
     callFrame[RegisterFile::ArgumentCount] = argc; // original argument count (for the sake of the "arguments" object)
     callFrame[RegisterFile::Callee] = function;
     callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
 }
 
-ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, int argv, int argc, JSValue*& exceptionValue)
+ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* newCodeBlock, RegisterFile* registerFile, Register* registerBase, Register* r, size_t registerOffset, int argc, JSValue*& exceptionValue)
 {
-    size_t registerOffset = argv + newCodeBlock->numLocals;
-    size_t size = r - registerBase + registerOffset + newCodeBlock->numConstants + newCodeBlock->numTemporaries;
+    size_t size = r - registerBase + registerOffset + newCodeBlock->numCalleeRegisters;
 
     if (argc == newCodeBlock->numParameters) { // correct number of arguments
         if (!registerFile->grow(size)) {
@@ -523,20 +542,22 @@ ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* n
         }
         r += registerOffset;
     } else if (argc < newCodeBlock->numParameters) { // too few arguments -- fill in the blanks
+        size_t omittedArgCount = newCodeBlock->numParameters - argc;
+        registerOffset += omittedArgCount;
+        size += omittedArgCount;
         if (!registerFile->grow(size)) {
             exceptionValue = createStackOverflowError(exec);
             return r;
         }
         r += registerOffset;
 
-        int omittedArgCount = newCodeBlock->numParameters - argc;
-        Register* endOfParams = r - newCodeBlock->numVars;
-        for (Register* it = endOfParams - omittedArgCount; it != endOfParams; ++it)
-            (*it) = jsUndefined();
-    } else { // too many arguments -- copy return info and expected arguments, leaving the extra arguments behind
-        int shift = argc + RegisterFile::CallFrameHeaderSize;
-        registerOffset += shift;
-        size += shift;
+        Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
+        for (size_t i = 0; i < omittedArgCount; ++i)
+            argv[i] = jsUndefined();
+    } else { // too many arguments -- copy expected arguments, leaving the extra arguments behind
+        size_t numParameters = newCodeBlock->numParameters;
+        registerOffset += numParameters;
+        size += numParameters;
 
         if (!registerFile->grow(size)) {
             exceptionValue = createStackOverflowError(exec);
@@ -544,18 +565,9 @@ ALWAYS_INLINE Register* slideRegisterWindowForCall(ExecState* exec, CodeBlock* n
         }
         r += registerOffset;
 
-        Register* it = r - newCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize - shift;
-        Register* end = it + RegisterFile::CallFrameHeaderSize + newCodeBlock->numParameters;
-        for ( ; it != end; ++it)
-            *(it + shift) = *it;
-    }
-    
-    // initialize local variable slots
-#if ENABLE(CTI)
-    if (!newCodeBlock->ctiCode)
-#endif
-    {
-
+        Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argc;
+        for (size_t i = 0; i < numParameters; ++i)
+            argv[i + argc] = argv[i];
     }
 
     return r;
@@ -565,7 +577,7 @@ ALWAYS_INLINE ScopeChainNode* scopeChainForCall(ExecState* exec, FunctionBodyNod
 {
     if (newCodeBlock->needsFullScopeChain) {
         JSActivation* activation = new (exec) JSActivation(exec, functionBodyNode, r);
-        r[RegisterFile::OptionalCalleeActivation - RegisterFile::CallFrameHeaderSize - newCodeBlock->numLocals] = activation;
+        r[RegisterFile::OptionalCalleeActivation] = activation;
 
         return callDataScopeChain->copy()->push(activation);
     }
@@ -601,7 +613,7 @@ NEVER_INLINE JSValue* Machine::callEval(ExecState* exec, CodeBlock* callingCodeB
 
     JSValue* result = 0;
     if (evalNode)
-        result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + argc, scopeChain, &exceptionValue);
+        result = exec->globalData().machine->execute(evalNode.get(), exec, thisObj, r - registerFile->base() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue);
 
     if (*profiler)
         (*profiler)->didExecute(exec, scopeChain->globalObject()->evalFunction());
@@ -683,46 +695,58 @@ void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFi
         printf("----------------------------------------------------\n");
     }
     
-    it = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+    it = r - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters;
+    printf("[this]                     | %10p | %10p \n", it, (*it).v()); ++it;
+    end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
+    if (it != end) {
+        do {
+            printf("[param]                    | %10p | %10p \n", it, (*it).v());
+            ++it;
+        } while (it != end);
+    }
+    printf("----------------------------------------------------\n");
+
     printf("[CallerCodeBlock]          | %10p | %10p \n", it, (*it).v()); ++it;
-    printf("[ReturnVPC]                | %10p | %10p \n", it, (*it).v()); ++it;
     printf("[CallerScopeChain]         | %10p | %10p \n", it, (*it).v()); ++it;
-    printf("[CallerRegisterOffset]     | %10p | %10p \n", it, (*it).v()); ++it;
+    printf("[CallerRegisters]          | %10p | %10p \n", it, (*it).v()); ++it;
+    printf("[ReturnPC]                 | %10p | %10p \n", it, (*it).v()); ++it;
     printf("[ReturnValueRegister]      | %10p | %10p \n", it, (*it).v()); ++it;
-    printf("[ArgumentStartRegister]    | %10p | %10p \n", it, (*it).v()); ++it;
     printf("[ArgumentCount]            | %10p | %10p \n", it, (*it).v()); ++it;
     printf("[Callee]                   | %10p | %10p \n", it, (*it).v()); ++it;
     printf("[OptionalCalleeActivation] | %10p | %10p \n", it, (*it).v()); ++it;
     printf("----------------------------------------------------\n");
 
-    printf("[this]                     | %10p | %10p \n", it, (*it).v()); ++it;
-    end = it + max(codeBlock->numParameters - 1, 0); // - 1 to skip "this"
+    int registerCount = 0;
+
+    end = it + codeBlock->numVars;
     if (it != end) {
         do {
-            printf("[param]                    | %10p | %10p \n", it, (*it).v());
+            printf("[r%2d]                      | %10p | %10p \n", registerCount, it, (*it).v());
             ++it;
+            ++registerCount;
         } while (it != end);
     }
     printf("----------------------------------------------------\n");
 
-    if (codeBlock->codeType != GlobalCode) {
-        end = it + codeBlock->numVars;
-        if (it != end) {
-            do {
-                printf("[var]                      | %10p | %10p \n", it, (*it).v());
-                ++it;
-            } while (it != end);
-        printf("----------------------------------------------------\n");
-        }
+    end = it + codeBlock->numConstants;
+    if (it != end) {
+        do {
+            printf("[r%2d]                      | %10p | %10p \n", registerCount, it, (*it).v());
+            ++it;
+            ++registerCount;
+        } while (it != end);
     }
+    printf("----------------------------------------------------\n");
 
-    end = it + codeBlock->numTemporaries;
+    end = it + codeBlock->numCalleeRegisters - codeBlock->numConstants - codeBlock->numVars;
     if (it != end) {
         do {
-            printf("[temp]                     | %10p | %10p \n", it, (*it).v());
+            printf("[r%2d]                      | %10p | %10p \n", registerCount, it, (*it).v());
             ++it;
+            ++registerCount;
         } while (it != end);
     }
+    printf("----------------------------------------------------\n");
 }
 
 #endif
@@ -745,19 +769,18 @@ bool Machine::isOpcode(Opcode opcode)
 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r)
 {
     CodeBlock* oldCodeBlock = codeBlock;
-    Register* callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
 
     if (Debugger* debugger = exec->dynamicGlobalObject()->debugger()) {
         DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, exceptionValue);
-        if (callFrame[RegisterFile::Callee].jsValue(exec))
+        if (r[RegisterFile::Callee].jsValue(exec))
             debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
         else
             debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->lastLine());
     }
 
     if (Profiler* profiler = *Profiler::enabledProfilerReference()) {
-        if (callFrame[RegisterFile::Callee].jsValue(exec))
-            profiler->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
+        if (r[RegisterFile::Callee].jsValue(exec))
+            profiler->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
         else
             profiler->didExecute(exec, codeBlock->ownerNode->sourceURL(), codeBlock->ownerNode->lineNo());
     }
@@ -766,19 +789,19 @@ NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionVa
         scopeChain->deref();
 
     // If this call frame created an activation, tear it off.
-    if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+    if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
         ASSERT(activation->isActivationObject());
         activation->copyRegisters();
     }
     
-    codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
+    codeBlock = r[RegisterFile::CallerCodeBlock].codeBlock();
     if (!codeBlock)
         return false;
 
-    scopeChain = callFrame[RegisterFile::CallerScopeChain].scopeChain();
-    r = callFrame[RegisterFile::CallerRegisters].r();
-    exec->m_callFrame = r - oldCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
-    vPC = callFrame[RegisterFile::ReturnVPC].vPC();
+    scopeChain = r[RegisterFile::CallerScopeChain].scopeChain();
+    vPC = vPCForPC(codeBlock, r[RegisterFile::ReturnPC].v());
+    r = r[RegisterFile::CallerRegisters].r();
+    exec->m_callFrame = r;
 
     return true;
 }
@@ -862,7 +885,7 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
     CodeBlock* codeBlock = &programNode->byteCode(scopeChain);
 
     size_t oldSize = m_registerFile.size();
-    size_t newSize = oldSize + RegisterFile::CallFrameHeaderSize + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries;
+    size_t newSize = oldSize + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->numCalleeRegisters;
     if (!m_registerFile.grow(newSize)) {
         *exception = createStackOverflowError(exec);
         return 0;
@@ -872,16 +895,9 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
     JSGlobalObject* globalObject = exec->dynamicGlobalObject();
     globalObject->copyGlobalsTo(m_registerFile);
 
-    Register* callFrame = m_registerFile.base() + oldSize;
-
-    // a 0 codeBlock indicates a built-in caller
-    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
-
-    Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
+    Register* r = m_registerFile.base() + oldSize + codeBlock->numParameters + RegisterFile::CallFrameHeaderSize;
     r[codeBlock->thisRegister] = thisObj;
-
-    for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
-        r[i] = codeBlock->constantRegisters[i];
+    initializeCallFrame(r, 0, 0, 0, 0, 0, 0, 0);
 
     if (codeBlock->needsFullScopeChain)
         scopeChain = scopeChain->copy();
@@ -921,36 +937,32 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, J
         return 0;
     }
 
-    int argv = RegisterFile::CallFrameHeaderSize;
-    int argc = args.size() + 1; // implicit "this" parameter
-
     size_t oldSize = m_registerFile.size();
-    if (!m_registerFile.grow(oldSize + RegisterFile::CallFrameHeaderSize + argc)) {
+    int argc = 1 + args.size(); // implicit "this" parameter
+
+    if (!m_registerFile.grow(oldSize + argc)) {
         *exception = createStackOverflowError(exec);
         return 0;
     }
 
-    Register* callFrame = m_registerFile.base() + oldSize;
-
-    // put args in place, including "this"
-    Register* dst = callFrame + RegisterFile::CallFrameHeaderSize;
-    (*dst) = thisObj;
+    Register* argv = m_registerFile.base() + oldSize;
+    size_t dst = 0;
+    argv[dst] = thisObj;
 
     ArgList::const_iterator end = args.end();
     for (ArgList::const_iterator it = args.begin(); it != end; ++it)
-        (*++dst) = *it;
-
-    // a 0 codeBlock indicates a built-in caller
-    initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
+        argv[++dst] = *it;
 
     CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
-    Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
-    if (*exception) {
+    Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), argv, argc + RegisterFile::CallFrameHeaderSize, argc, *exception);
+    if (UNLIKELY(*exception != 0)) {
         m_registerFile.shrink(oldSize);
         return 0;
     }
+    // a 0 codeBlock indicates a built-in caller
+    initializeCallFrame(r, 0, 0, 0, argv, 0, argc, function);
 
-    ExecState newExec(exec, &m_registerFile, scopeChain, callFrame);
+    ExecState newExec(exec, &m_registerFile, scopeChain, r);
 
     Profiler** profiler = Profiler::enabledProfilerReference();
     if (*profiler)
@@ -973,6 +985,11 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, J
     return result;
 }
 
+JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
+{
+    return execute(evalNode, exec, thisObj, m_registerFile.size() + evalNode->byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception);
+}
+
 JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception)
 {
     if (m_reentryDepth >= MaxReentryDepth) {
@@ -1015,22 +1032,17 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
     }
 
     size_t oldSize = m_registerFile.size();
-    size_t newSize = registerOffset + codeBlock->numVars + codeBlock->numConstants + codeBlock->numTemporaries + RegisterFile::CallFrameHeaderSize;
+    size_t newSize = registerOffset + codeBlock->numCalleeRegisters;
     if (!m_registerFile.grow(newSize)) {
         *exception = createStackOverflowError(exec);
         return 0;
     }
 
-    Register* callFrame = m_registerFile.base() + registerOffset;
+    Register* r = m_registerFile.base() + registerOffset;
 
     // a 0 codeBlock indicates a built-in caller
-    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
-
-    Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
     r[codeBlock->thisRegister] = thisObj;
-
-    for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
-        r[i] = codeBlock->constantRegisters[i];
+    initializeCallFrame(r, 0, 0, 0, 0, 0, 0, 0);
 
     if (codeBlock->needsFullScopeChain)
         scopeChain = scopeChain->copy();
@@ -3179,6 +3191,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         int thisVal = (++vPC)->u.operand;
         int firstArg = (++vPC)->u.operand;
         int argCount = (++vPC)->u.operand;
+        ++vPC; // registerOffset
 
         JSValue* funcVal = r[func].jsValue(exec);
         JSValue* baseVal = r[thisVal].jsValue(exec);
@@ -3198,7 +3211,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         // We didn't find the blessed version of eval, so reset vPC and process
         // this instruction as a normal function call, supplying the proper 'this'
         // value.
-        vPC -= 5;
+        vPC -= 6;
         r[thisVal] = baseVal->toThisObject(exec);
 
 #if HAVE(COMPUTED_GOTO)
@@ -3210,7 +3223,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         // fall through to op_call
     }
     BEGIN_OPCODE(op_call) {
-        /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n)
+        /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n)
 
            Perform a function call. Specifically, call register func
            with a "this" value of register thisVal, and put the result
@@ -3251,31 +3264,32 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         int thisVal = (++vPC)->u.operand;
         int firstArg = (++vPC)->u.operand;
         int argCount = (++vPC)->u.operand;
+        int registerOffset = (++vPC)->u.operand;
 
         JSValue* v = r[func].jsValue(exec);
 
         CallData callData;
         CallType callType = v->getCallData(callData);
 
-        if (*enabledProfilerReference)
-            (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
-
-        Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-        initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
-        exec->m_callFrame = callFrame;
-
         if (callType == CallTypeJS) {
-
             ScopeChainNode* callDataScopeChain = callData.js.scopeChain;
             FunctionBodyNode* functionBodyNode = callData.js.functionBody;
             CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
 
             r[firstArg] = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
+            
+            Register* savedR = r;
 
-            r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
+            r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, registerOffset, argCount, exceptionValue);
             if (UNLIKELY(exceptionValue != 0))
                 goto vm_throw;
 
+            initializeCallFrame(r, codeBlock, vPC, scopeChain, savedR, dst, argCount, v);
+            exec->m_callFrame = r;
+    
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
+
             codeBlock = newCodeBlock;
             setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
             vPC = codeBlock->instructions.begin();
@@ -3283,7 +3297,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 #if DUMP_OPCODE_STATS
             OpcodeStats::resetLastInstruction();
 #endif
-            
+
             NEXT_OPCODE;
         }
 
@@ -3291,10 +3305,16 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             JSValue* thisValue = thisVal == missingThisObjectMarker() ? exec->globalThisValue() : r[thisVal].jsValue(exec);
             ArgList args(r + firstArg + 1, argCount - 1);
 
+            initializeCallFrame(r + registerOffset, codeBlock, vPC, scopeChain, r, dst, argCount, v);
+            exec->m_callFrame = r + registerOffset;
+
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
+
             MACHINE_SAMPLING_callingHostFunction();
 
             JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(v), thisValue, args);
-            exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+            exec->m_callFrame = r;
             VM_CHECK_EXCEPTION();
 
             r[dst] = returnValue;
@@ -3309,7 +3329,6 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         ASSERT(callType == CallTypeNone);
 
         exceptionValue = createNotAFunctionError(exec, v, vPC, codeBlock);
-        exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
         goto vm_throw;
     }
     BEGIN_OPCODE(op_ret) {
@@ -3324,44 +3343,47 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
            
         int result = (++vPC)->u.operand;
 
-        Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
-        if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
+        if (JSActivation* activation = static_cast<JSActivation*>(r[RegisterFile::OptionalCalleeActivation].jsValue(exec))) {
             ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation);
             ASSERT(activation->isActivationObject());
             activation->copyRegisters();
         }
 
         if (*enabledProfilerReference)
-            (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
+            (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(r[RegisterFile::Callee].jsValue(exec)));
 
         if (codeBlock->needsFullScopeChain)
             scopeChain->deref();
 
         JSValue* returnValue = r[result].jsValue(exec);
 
-        codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
+        codeBlock = r[RegisterFile::CallerCodeBlock].codeBlock();
         if (!codeBlock)
             return returnValue;
 
-        vPC = callFrame[RegisterFile::ReturnVPC].vPC();
-        setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
-        r = callFrame[RegisterFile::CallerRegisters].r();
-        exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
-        int dst = callFrame[RegisterFile::ReturnValueRegister].i();
+        vPC = r[RegisterFile::ReturnPC].vPC();
+        setScopeChain(exec, scopeChain, r[RegisterFile::CallerScopeChain].scopeChain());
+        int dst = r[RegisterFile::ReturnValueRegister].i();
+        r = r[RegisterFile::CallerRegisters].r();
+        exec->m_callFrame = r;
         r[dst] = returnValue;
 
         NEXT_OPCODE;
     }
-    BEGIN_OPCODE(op_initialise_locals) {
-        for (Register* it = r - codeBlock->numVars + (codeBlock->codeType == EvalCode); it < r; ++it)
-            (*it) = jsUndefined();
-        for (size_t i = 0; i < codeBlock->constantRegisters.size(); ++i)
-            r[i] = codeBlock->constantRegisters[i];
+    BEGIN_OPCODE(op_init) {
+        size_t i = 0;
+
+        for (size_t count = codeBlock->numVars; i < count; ++i)
+            r[i] = jsUndefined();
+
+        for (size_t count = codeBlock->constantRegisters.size(), j = 0; j < count; ++i, ++j)
+            r[i] = codeBlock->constantRegisters[j];
+
         ++vPC;
         NEXT_OPCODE;
     }
     BEGIN_OPCODE(op_construct) {
-        /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n)
+        /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n)
 
            Invoke register "constr" as a constructor. For JS
            functions, the calling convention is exactly as for the
@@ -3380,18 +3402,16 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         int constrProto = (++vPC)->u.operand;
         int firstArg = (++vPC)->u.operand;
         int argCount = (++vPC)->u.operand;
+        int registerOffset = (++vPC)->u.operand;
 
-        JSValue* constrVal = r[constr].jsValue(exec);
+        JSValue* v = r[constr].jsValue(exec);
 
         ConstructData constructData;
-        ConstructType constructType = constrVal->getConstructData(constructData);
-
-        // Removing this line of code causes a measurable regression on squirrelfish.
-        JSObject* constructor = static_cast<JSObject*>(constrVal);
+        ConstructType constructType = v->getConstructData(constructData);
 
         if (constructType == ConstructTypeJS) {
             if (*enabledProfilerReference)
-                (*enabledProfilerReference)->willExecute(exec, constructor);
+                (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
 
             StructureID* structure;
             JSValue* prototype = r[constrProto].jsValue(exec);
@@ -3407,36 +3427,48 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
             r[firstArg] = newObject; // "this" value
 
-            Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-            initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
-            exec->m_callFrame = callFrame;
+            Register* savedR = r;
 
-            r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
-            if (exceptionValue)
+            r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, registerOffset, argCount, exceptionValue);
+            if (UNLIKELY(exceptionValue != 0))
                 goto vm_throw;
 
+            initializeCallFrame(r, codeBlock, vPC, scopeChain, savedR, dst, argCount, v);
+            exec->m_callFrame = r;
+    
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
+
             codeBlock = newCodeBlock;
             setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r));
             vPC = codeBlock->instructions.begin();
 
+#if DUMP_OPCODE_STATS
+            OpcodeStats::resetLastInstruction();
+#endif
+
             NEXT_OPCODE;
         }
 
         if (constructType == ConstructTypeHost) {
-            if (*enabledProfilerReference)
-                (*enabledProfilerReference)->willExecute(exec, constructor);
-
             ArgList args(r + firstArg + 1, argCount - 1);
 
+            initializeCallFrame(r + registerOffset, codeBlock, vPC, scopeChain, r, dst, argCount, v);
+            exec->m_callFrame = r + registerOffset;
+
+            if (*enabledProfilerReference)
+                (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
+
             MACHINE_SAMPLING_callingHostFunction();
 
-            JSValue* returnValue = constructData.native.function(exec, constructor, args);
+            JSValue* returnValue = constructData.native.function(exec, static_cast<JSObject*>(v), args);
+            exec->m_callFrame = r;
 
             VM_CHECK_EXCEPTION();
             r[dst] = returnValue;
 
             if (*enabledProfilerReference)
-                (*enabledProfilerReference)->didExecute(exec, constructor);
+                (*enabledProfilerReference)->didExecute(exec, static_cast<JSObject*>(v));
 
             ++vPC;
             NEXT_OPCODE;
@@ -3444,7 +3476,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
 
         ASSERT(constructType == ConstructTypeNone);
 
-        exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
+        exceptionValue = createNotAConstructorError(exec, v, vPC, codeBlock);
         goto vm_throw;
     }
     BEGIN_OPCODE(op_construct_verify) {
@@ -3776,8 +3808,7 @@ JSValue* Machine::retrieveArguments(ExecState* exec, JSFunction* function) const
 
     JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
     if (!activation) {
-        CodeBlock* codeBlock = &function->m_body->generatedByteCode();
-        activation = new (exec) JSActivation(exec, function->m_body, callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numLocals);
+        activation = new (exec) JSActivation(exec, function->m_body, callFrame);
         callFrame[RegisterFile::OptionalCalleeActivation] = activation;
     }
 
@@ -3794,7 +3825,7 @@ JSValue* Machine::retrieveCaller(ExecState* exec, InternalFunction* function) co
     if (!callerCodeBlock)
         return jsNull();
 
-    Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+    Register* callerCallFrame = callFrame[RegisterFile::CallerRegisters].r();
     if (JSValue* caller = callerCallFrame[RegisterFile::Callee].jsValue(exec))
         return caller;
 
@@ -3815,7 +3846,7 @@ void Machine::retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId
     if (!callerCodeBlock)
         return;
 
-    Instruction* vPC = callFrame[RegisterFile::ReturnVPC].vPC();
+    Instruction* vPC = vPCForPC(callerCodeBlock, callFrame[RegisterFile::ReturnPC].v());
     lineNumber = callerCodeBlock->lineNumberForVPC(vPC - 1);
     sourceId = callerCodeBlock->ownerNode->sourceId();
     sourceURL = callerCodeBlock->ownerNode->sourceURL();
@@ -3846,17 +3877,26 @@ Register* Machine::callFrame(ExecState* exec, InternalFunction* function) const
             continue;
         }
         
-        callFrame = callFrame[RegisterFile::CallerRegisters].r() - callerCodeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+        callFrame = callFrame[RegisterFile::CallerRegisters].r();
     }
 }
 
-void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, Register*& argv, int& argc)
+void Machine::getArgumentsData(Register* callFrame, JSFunction*& function, int& firstParameterIndex, Register*& argv, int& argc)
 {
     function = static_cast<JSFunction*>(callFrame[RegisterFile::Callee].getJSValue());
     ASSERT(function->inherits(&JSFunction::info));
+    
+    CodeBlock* codeBlock = &function->m_body->generatedByteCode();
+    int numParameters = codeBlock->numParameters;
+    argc = callFrame[RegisterFile::ArgumentCount].i();
 
-    argv = callFrame[RegisterFile::CallerRegisters].r() + callFrame[RegisterFile::ArgumentStartRegister].i() + 1; //  + 1 to skip "this"
-    argc = callFrame[RegisterFile::ArgumentCount].i() - 1; // - 1 to skip "this"
+    if (argc <= numParameters)
+        argv = callFrame - RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this"
+    else
+        argv = callFrame - RegisterFile::CallFrameHeaderSize - numParameters - argc + 1; // + 1 to skip "this"
+
+    argc -= 1; // - 1 to skip "this"
+    firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this"
 }
 
 #if ENABLE(CTI)
@@ -4369,20 +4409,16 @@ void* Machine::cti_op_call_JSFunction(CTI_ARGS)
     RegisterFile* registerFile = ARG_registerFile;
     Register* r = ARG_r;
 
-    JSValue* exceptionValue = 0;
     Register* registerBase = registerFile->base();
     
     JSValue* funcVal = ARG_src1;
-    JSValue* thisValue = ARG_src2;
-    int firstArg = ARG_int3;
-    int argCount = ARG_int4;
+    int registerOffset = ARG_int2;
+    int argCount = ARG_int3;
 
-    // In the JIT code before entering this function we wil have checked the vptr,
-    // and know this is an object of type JSFunction.
 #ifndef NDEBUG
     CallData callData;
-#endif
     ASSERT(funcVal->getCallData(callData) == CallTypeJS);
+#endif
 
     if (*ARG_profilerReference)
         (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
@@ -4391,15 +4427,23 @@ void* Machine::cti_op_call_JSFunction(CTI_ARGS)
     FunctionBodyNode* functionBodyNode = static_cast<JSFunction*>(funcVal)->m_body.get();
 
     CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
+    
+    Register* savedR = r;
 
-    r[firstArg] = thisValue;
+    JSValue* exceptionValue = 0;
+    r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, registerOffset, argCount, exceptionValue);
+    JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
 
-    Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-    exec->m_callFrame = callFrame;
+    // RegisterFile::CallerCodeBlock is set by caller
+    r[RegisterFile::CallerScopeChain] = ARG_scopeChain;
+    r[RegisterFile::CallerRegisters] = savedR;
+    // RegisterFile::ReturnPC is set by callee
+    // RegisterFile::ReturnValueRegister is set by caller
+    r[RegisterFile::ArgumentCount] = argCount; // original argument count (for the sake of the "arguments" object)
+    r[RegisterFile::Callee] = funcVal;
+    r[RegisterFile::OptionalCalleeActivation] = nullJSValue;
 
-    r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
-    JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
-    
+    exec->m_callFrame = r;
     exec->m_scopeChain = callDataScopeChain;
 
     ARG_setScopeChain(callDataScopeChain);
@@ -4433,12 +4477,8 @@ void Machine::cti_vm_updateScopeChain(CTI_ARGS)
 JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
 {
     ExecState* exec = ARG_exec;
-    Register* r = ARG_r;
 
     JSValue* funcVal = ARG_src1;
-    JSValue* thisValue = ARG_src2;
-    int firstArg = ARG_int3;
-    int argCount = ARG_int4;
 
     CallData callData;
     CallType callType = funcVal->getCallData(callData);
@@ -4446,31 +4486,34 @@ JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
     ASSERT(callType != CallTypeJS);
 
     if (callType == CallTypeHost) {
-        Register* oldCallFrame = exec->m_callFrame;
-        Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-        exec->m_callFrame = callFrame;
+        int registerOffset = ARG_int2;
+        int argCount = ARG_int3;
+        Register* r = ARG_r + registerOffset;
+        
+        initializeCallFrame(r, ARG_codeBlock, ARG_instr4, ARG_scopeChain, ARG_r, 0, argCount, funcVal);
+        exec->m_callFrame = r;
 
         if (*ARG_profilerReference)
             (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal));
 
-        ArgList argList(r + firstArg + 1, argCount - 1);
+        Register* argv = r - RegisterFile::CallFrameHeaderSize - argCount;
+        ArgList argList(argv + 1, argCount - 1);
 
         CTI_MACHINE_SAMPLING_callingHostFunction();
 
-        JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(funcVal), thisValue, argList);
-        exec->m_callFrame = oldCallFrame;
+        JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(funcVal), argv[0].jsValue(exec), argList);
         VM_CHECK_EXCEPTION(JSValue*);
 
         if (*ARG_profilerReference)
             (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(funcVal));
 
+        exec->m_callFrame = ARG_r;
         return returnValue;
-
     }
 
     ASSERT(callType == CallTypeNone);
 
-    exec->setException(createNotAFunctionError(exec, funcVal, ARG_instr5, ARG_codeBlock));
+    exec->setException(createNotAFunctionError(exec, funcVal, ARG_instr4, ARG_codeBlock));
     VM_CHECK_EXCEPTION_AT_END();
     return 0;
 }
@@ -4478,7 +4521,7 @@ JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
 void Machine::cti_op_ret_activation(CTI_ARGS)
 {
     ExecState* exec = ARG_exec;
-    Register* callFrame = ARG_r - ARG_codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+    Register* callFrame = ARG_r;
 
     JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec));
     ASSERT(activation);
@@ -4492,7 +4535,7 @@ void Machine::cti_op_ret_profiler(CTI_ARGS)
 {
     ExecState* exec = ARG_exec;
 
-    Register* callFrame = ARG_r - ARG_codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
+    Register* callFrame = ARG_r;
     ASSERT(*ARG_profilerReference);
     (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec)));
 }
@@ -4543,26 +4586,21 @@ void* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
     ExecState* exec = ARG_exec;
     RegisterFile* registerFile = ARG_registerFile;
     Register* r = ARG_r;
-    ScopeChainNode* scopeChain = ARG_scopeChain;
 
-    JSValue* exceptionValue = 0;
     Register* registerBase = registerFile->base();
     
     JSValue* constrVal = ARG_src1;
     JSValue* constrProtoVal = ARG_src2;
     int firstArg = ARG_int3;
-    int argCount = ARG_int4;
+    int registerOffset = ARG_int4;
+    int argCount = ARG_int5;
 
-    ConstructData constructData;
 #ifndef NDEBUG
-    ConstructType constructType =
+    ConstructData constructData;
+    ASSERT(constrVal->getConstructData(constructData) == ConstructTypeJS);
 #endif
-        constrVal->getConstructData(constructData);
-
-    // Removing this line of code causes a measurable regression on sunspider.
-    JSObject* constructor = static_cast<JSObject*>(constrVal);
 
-    ASSERT(constructType == ConstructTypeJS);
+    JSFunction* constructor = static_cast<JSFunction*>(constrVal);
 
     if (*ARG_profilerReference)
         (*ARG_profilerReference)->willExecute(exec, constructor);
@@ -4571,21 +4609,31 @@ void* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
     if (constrProtoVal->isObject())
         structure = static_cast<JSObject*>(constrProtoVal)->inheritorID();
     else
-        structure = scopeChain->globalObject()->emptyObjectStructure();
+        structure = ARG_scopeChain->globalObject()->emptyObjectStructure();
     JSObject* newObject = new (exec) JSObject(structure);
 
-    ScopeChainNode* callDataScopeChain = constructData.js.scopeChain;
-    FunctionBodyNode* functionBodyNode = constructData.js.functionBody;
+    ScopeChainNode* callDataScopeChain = constructor->m_scopeChain.node();
+    FunctionBodyNode* functionBodyNode = constructor->m_body.get();
     CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain);
 
     r[firstArg] = newObject; // "this" value
 
-    Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-    exec->m_callFrame = callFrame;
+    Register* savedR = r;
 
-    r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
+    JSValue* exceptionValue = 0;
+    r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, registerOffset, argCount, exceptionValue);
     JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
 
+    // RegisterFile::CallerCodeBlock is set by caller
+    r[RegisterFile::CallerScopeChain] = ARG_scopeChain;
+    r[RegisterFile::CallerRegisters] = savedR;
+    // RegisterFile::ReturnPC is set by callee
+    // RegisterFile::ReturnValueRegister is set by caller
+    r[RegisterFile::ArgumentCount] = argCount; // original argument count (for the sake of the "arguments" object)
+    r[RegisterFile::Callee] = constructor;
+    r[RegisterFile::OptionalCalleeActivation] = nullJSValue;
+
+    exec->m_callFrame = r;
     exec->m_scopeChain = callDataScopeChain;
 
     ARG_setScopeChain(callDataScopeChain);
@@ -4601,21 +4649,14 @@ JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
 
     JSValue* constrVal = ARG_src1;
     int firstArg = ARG_int3;
-    int argCount = ARG_int4;
+    int argCount = ARG_int5;
 
     ConstructData constructData;
     ConstructType constructType = constrVal->getConstructData(constructData);
 
-    // Removing this line of code causes a measurable regression on squirrelfish.
     JSObject* constructor = static_cast<JSObject*>(constrVal);
 
-    ASSERT(constructType != ConstructTypeJS);
-
     if (constructType == ConstructTypeHost) {
-        Register* oldCallFrame = exec->m_callFrame;
-        Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-        exec->m_callFrame = callFrame;
-
         if (*ARG_profilerReference)
             (*ARG_profilerReference)->willExecute(exec, constructor);
 
@@ -4624,7 +4665,6 @@ JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
         CTI_MACHINE_SAMPLING_callingHostFunction();
 
         JSValue* returnValue = constructData.native.function(exec, constructor, argList);
-        exec->m_callFrame = oldCallFrame;
         VM_CHECK_EXCEPTION(JSValue*);
 
         if (*ARG_profilerReference)
@@ -4635,7 +4675,7 @@ JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
 
     ASSERT(constructType == ConstructTypeNone);
 
-    exec->setException(createNotAConstructorError(exec, constrVal, ARG_instr5, ARG_codeBlock));
+    exec->setException(createNotAConstructorError(exec, constrVal, ARG_instr6, ARG_codeBlock));
     VM_CHECK_EXCEPTION_AT_END();
     return 0;
 }
@@ -5193,16 +5233,16 @@ JSValue* Machine::cti_op_call_eval(CTI_ARGS)
     ScopeChainNode* scopeChain = ARG_scopeChain;
 
     Machine* machine = exec->machine();
-    JSValue* exceptionValue = 0;
     
     JSValue* funcVal = ARG_src1;
-    JSValue* baseVal = ARG_src2;
-    int firstArg = ARG_int3;
-    int argCount = ARG_int4;
+    int registerOffset = ARG_int2;
+    int argCount = ARG_int3;
+    JSValue* baseVal = ARG_src5;
 
     if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) {
         JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec));
-        JSValue* result = machine->callEval(exec, codeBlock, thisObject, scopeChain, registerFile,  r, firstArg, argCount, exceptionValue);
+        JSValue* exceptionValue = 0;
+        JSValue* result = machine->callEval(exec, codeBlock, thisObject, scopeChain, registerFile,  r, registerOffset - RegisterFile::CallFrameHeaderSize - argCount, argCount, exceptionValue);
         JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue);
         return result;
     }
index 3cf1813..5bb4d64 100644 (file)
@@ -90,16 +90,13 @@ namespace JSC {
         
         JSValue* execute(ProgramNode*, ExecState*, ScopeChainNode*, JSObject* thisObj, JSValue** exception);
         JSValue* execute(FunctionBodyNode*, ExecState*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue** exception);
-        JSValue* execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception)
-        {
-            return execute(evalNode, exec, thisObj, m_registerFile.size(), scopeChain, exception);
-        }
+        JSValue* execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue** exception);
 
         JSValue* retrieveArguments(ExecState*, JSFunction*) const;
         JSValue* retrieveCaller(ExecState*, InternalFunction*) const;
         void retrieveLastCaller(ExecState* exec, int& lineNumber, int& sourceId, UString& sourceURL, JSValue*& function) const;
 
-        void getArgumentsData(Register* callFrame, JSFunction*&, Register*& argv, int& argc);
+        void getArgumentsData(Register* callFrame, JSFunction*&, int& firstParameterIndex, Register*& argv, int& argc);
         void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; }
         
         void startTimeoutCheck()
@@ -239,7 +236,7 @@ namespace JSC {
         NEVER_INLINE JSValue* callEval(ExecState* exec, CodeBlock* callingCodeBlock, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile*, Register* r, int argv, int argc, JSValue*& exceptionValue);
         JSValue* execute(EvalNode*, ExecState*, JSObject* thisObj, int registerOffset, ScopeChainNode*, JSValue** exception);
 
-        ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argv, int argc, JSValue* function);
+        ALWAYS_INLINE static void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argc, JSValue* function);
 
         ALWAYS_INLINE void setScopeChain(ExecState* exec, ScopeChainNode*&, ScopeChainNode*);
         NEVER_INLINE void debug(ExecState*, const CodeBlock*, ScopeChainNode*, Register*, DebugHookID, int firstLine, int lastLine);
index 46ac05c..9388709 100644 (file)
@@ -40,7 +40,7 @@ namespace JSC {
 #define DUMP_OPCODE_STATS 0
 
     #define FOR_EACH_OPCODE_ID(macro) \
-        macro(op_initialise_locals) \
+        macro(op_init) \
         macro(op_unexpected_load) \
         macro(op_new_object) \
         macro(op_new_array) \
index 7e3b6a1..da7773a 100644 (file)
@@ -90,20 +90,19 @@ namespace JSC {
     class RegisterFile : Noncopyable {
     public:
         enum CallFrameHeaderEntry {
-            CallerCodeBlock = 0,
-            ReturnVPC,
-            CallerScopeChain,
-            CallerRegisters,
-            ReturnValueRegister,
-            ArgumentStartRegister,
-            ArgumentCount,
-            Callee,
-            OptionalCalleeActivation,
-            CTIReturnEIP,
-            CallFrameHeaderSize
+            CallFrameHeaderSize = 8,
+
+            CallerCodeBlock = -8,
+            CallerScopeChain = -7,
+            CallerRegisters = -6,
+            ReturnPC = -5,
+            ReturnValueRegister = -4,
+            ArgumentCount = -3,
+            Callee = -2,
+            OptionalCalleeActivation = -1,
         };
 
-        enum { ProgramCodeThisRegister = - 1 };
+        enum { ProgramCodeThisRegister = -CallFrameHeaderSize - 1 };
 
         enum { DefaultCapacity = 2 * 1024 * 1024 / sizeof(Register) };
         enum { DefaultMaxGlobals = 8 * 1024 };
index ec7de19..bff653b 100644 (file)
@@ -39,7 +39,7 @@ namespace JSC {
     public:
         RegisterID()
             : m_refCount(0)
-            , m_isConstant(false)
+            , m_isTemporary(false)
 #ifndef NDEBUG
             , m_didSetIndex(false)
 #endif
@@ -49,7 +49,7 @@ namespace JSC {
         explicit RegisterID(int index)
             : m_refCount(0)
             , m_index(index)
-            , m_isConstant(false)
+            , m_isTemporary(false)
 #ifndef NDEBUG
             , m_didSetIndex(true)
 #endif
@@ -65,9 +65,9 @@ namespace JSC {
             m_index = index;
         }
 
-        void makeConstant()
+        void setTemporary()
         {
-            m_isConstant = true;
+            m_isTemporary = true;
         }
 
         int index() const
@@ -78,7 +78,7 @@ namespace JSC {
 
         bool isTemporary()
         {
-            return m_index >= 0 && !m_isConstant;
+            return m_isTemporary;
         }
 
         void ref()
@@ -101,7 +101,7 @@ namespace JSC {
 
         int m_refCount;
         int m_index;
-        bool m_isConstant;
+        bool m_isTemporary;
 #ifndef NDEBUG
         bool m_didSetIndex;
 #endif
index 7b67a3a..98130b4 100644 (file)
@@ -38,10 +38,10 @@ ASSERT_CLASS_FITS_IN_CELL(Arguments);
 const ClassInfo Arguments::info = { "Arguments", 0, 0, 0 };
 
 struct ArgumentsData : Noncopyable {
-    ArgumentsData(JSActivation* activation, unsigned numParameters, unsigned firstArgumentIndex, unsigned numArguments, JSFunction* callee)
+    ArgumentsData(JSActivation* activation, unsigned numParameters, int firstParameterIndex, unsigned numArguments, JSFunction* callee)
         : activation(activation)
         , numParameters(numParameters)
-        , firstArgumentIndex(firstArgumentIndex)
+        , firstParameterIndex(firstParameterIndex)
         , numArguments(numArguments)
         , extraArguments(0)
         , callee(callee)
@@ -53,7 +53,7 @@ struct ArgumentsData : Noncopyable {
     JSActivation* activation;
 
     unsigned numParameters;
-    unsigned firstArgumentIndex;
+    int firstParameterIndex;
     unsigned numArguments;
     Register* extraArguments;
     OwnArrayPtr<bool> deletedArguments;
@@ -65,9 +65,9 @@ struct ArgumentsData : Noncopyable {
 };
 
 // ECMA 10.1.8
-Arguments::Arguments(ExecState* exec, JSFunction* function, JSActivation* activation, int firstArgumentIndex, Register* argv, int argc)
+Arguments::Arguments(ExecState* exec, JSFunction* function, JSActivation* activation, int firstParameterIndex, Register* argv, int argc)
     : JSObject(exec->lexicalGlobalObject()->argumentsStructure())
-    , d(new ArgumentsData(activation, function->numParameters(), firstArgumentIndex, argc, function))
+    , d(new ArgumentsData(activation, function->numParameters(), firstParameterIndex, argc, function))
 {
     ASSERT(activation);
   
@@ -118,14 +118,14 @@ void Arguments::fillArgList(ExecState* exec, ArgList& args)
         }
 
         if (d->numParameters == d->numArguments) {
-            args.initialize(&d->activation->registerAt(d->firstArgumentIndex), d->numArguments);
+            args.initialize(&d->activation->registerAt(d->firstParameterIndex), d->numArguments);
             return;
         }
 
         unsigned parametersLength = min(d->numParameters, d->numArguments);
         unsigned i = 0;
         for (; i < parametersLength; ++i)
-            args.append(d->activation->uncheckedSymbolTableGetValue(d->firstArgumentIndex + i));
+            args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
         for (; i < d->numArguments; ++i)
             args.append(d->extraArguments[i - d->numParameters].getJSValue());
         return;
@@ -135,7 +135,7 @@ void Arguments::fillArgList(ExecState* exec, ArgList& args)
     unsigned i = 0;
     for (; i < parametersLength; ++i) {
         if (!d->deletedArguments[i])
-            args.append(d->activation->uncheckedSymbolTableGetValue(d->firstArgumentIndex + i));
+            args.append(d->activation->uncheckedSymbolTableGetValue(d->firstParameterIndex + i));
         else
             args.append(get(exec, i));
     }
@@ -151,7 +151,7 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& sl
 {
     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTableGet(d->firstArgumentIndex + i, slot);
+            d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
         else
             slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
         return true;
@@ -166,7 +166,7 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa
     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTableGet(d->firstArgumentIndex + i, slot);
+            d->activation->uncheckedSymbolTableGet(d->firstParameterIndex + i, slot);
         else
             slot.setValue(d->extraArguments[i - d->numParameters].getJSValue());
         return true;
@@ -189,7 +189,7 @@ void Arguments::put(ExecState* exec, unsigned i, JSValue* value, PutPropertySlot
 {
     if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTablePut(d->firstArgumentIndex + i, value);
+            d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
         else
             d->extraArguments[i - d->numParameters] = value;
         return;
@@ -204,7 +204,7 @@ void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* va
     unsigned i = propertyName.toArrayIndex(&isArrayIndex);
     if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) {
         if (i < d->numParameters)
-            d->activation->uncheckedSymbolTablePut(d->firstArgumentIndex + i, value);
+            d->activation->uncheckedSymbolTablePut(d->firstParameterIndex + i, value);
         else
             d->extraArguments[i - d->numParameters] = value;
         return;
index 43b5e49..707e458 100644 (file)
 
 namespace JSC {
 
-Register* DebuggerCallFrame::callFrame() const
-{
-    return m_registers - m_codeBlock->numLocals - RegisterFile::CallFrameHeaderSize;
-}
-
 const UString* DebuggerCallFrame::functionName() const
 {
     if (!m_codeBlock)
         return 0;
 
-    JSFunction* function = static_cast<JSFunction*>(callFrame()[RegisterFile::Callee].getJSValue());
+    JSFunction* function = static_cast<JSFunction*>(m_registers[RegisterFile::Callee].getJSValue());
     if (!function)
         return 0;
     return &function->name(m_exec);
@@ -54,7 +49,7 @@ const UString* DebuggerCallFrame::functionName() const
 
 DebuggerCallFrame::Type DebuggerCallFrame::type() const
 {
-    if (callFrame()[RegisterFile::Callee].getJSValue())
+    if (m_registers[RegisterFile::Callee].getJSValue())
         return FunctionType;
 
     return ProgramType;
index 6a2a88b..665d4e6 100644 (file)
@@ -67,8 +67,6 @@ namespace JSC {
         JSValue* exception() const { return m_exception; }
 
     private:
-        Register* callFrame() const;
-
         ExecState* m_exec;
         JSGlobalObject* m_dynamicGlobalObject;
         const CodeBlock* m_codeBlock;
index ab597b8..0f12759 100644 (file)
@@ -51,13 +51,57 @@ JSActivation::~JSActivation()
     delete d();
 }
 
+void JSActivation::mark()
+{
+    Base::mark();
+    
+    if (d()->argumentsObject)
+        d()->argumentsObject->mark();
+
+    Register* registerArray = d()->registerArray.get();
+    if (!registerArray)
+        return;
+
+    size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
+
+    size_t i = 0;
+    size_t count = numParametersMinusThis; 
+    for ( ; i < count; ++i) {
+        Register& r = registerArray[i];
+        if (!r.marked())
+            r.mark();
+    }
+
+    size_t numVars = d()->functionBody->generatedByteCode().numVars;
+
+    // Skip the call frame, which sits between the parameters and vars.
+    i += RegisterFile::CallFrameHeaderSize;
+    count += RegisterFile::CallFrameHeaderSize + numVars;
+
+    for ( ; i < count; ++i) {
+        Register& r = registerArray[i];
+        if (!r.marked())
+            r.mark();
+    }
+}
+
 void JSActivation::copyRegisters()
 {
-    int numLocals = d()->functionBody->generatedByteCode().numLocals;
+    ASSERT(!d()->registerArray);
+    ASSERT(!d()->registerArraySize);
+
+    size_t numParametersMinusThis = d()->functionBody->generatedByteCode().numParameters - 1;
+    size_t numVars = d()->functionBody->generatedByteCode().numVars;
+    size_t numLocals = numVars + numParametersMinusThis;
+
     if (!numLocals)
         return;
 
-    copyRegisterArray(d()->registers - numLocals, numLocals);
+    int registerOffset = numParametersMinusThis + RegisterFile::CallFrameHeaderSize;
+    size_t registerArraySize = numLocals + RegisterFile::CallFrameHeaderSize;
+
+    Register* registerArray = copyRegisterArray(d()->registers - registerOffset, registerArraySize);
+    setRegisters(registerArray + registerOffset, registerArray, registerArraySize);
 }
 
 bool JSActivation::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
@@ -126,14 +170,6 @@ JSObject* JSActivation::toThisObject(ExecState* exec) const
     return exec->globalThisValue();
 }
 
-void JSActivation::mark()
-{
-    Base::mark();
-    
-    if (d()->argumentsObject)
-        d()->argumentsObject->mark();
-}
-
 bool JSActivation::isActivationObject() const
 {
     return true;
@@ -163,15 +199,13 @@ PropertySlot::GetValueFunc JSActivation::getArgumentsGetter()
 
 Arguments* JSActivation::createArgumentsObject(ExecState* exec)
 {
-    Register* callFrame = d()->registers - d()->functionBody->generatedByteCode().numLocals - RegisterFile::CallFrameHeaderSize;
-
     JSFunction* function;
     Register* argv;
     int argc;
-    exec->machine()->getArgumentsData(callFrame, function, argv, argc);
+    int firstParameterIndex;
+    exec->machine()->getArgumentsData(d()->registers, function, firstParameterIndex, argv, argc);
 
-    int firstArgumentIndex = -d()->functionBody->generatedByteCode().numLocals + 1;
-    return new (exec) Arguments(exec, function, this, firstArgumentIndex, argv, argc);
+    return new (exec) Arguments(exec, function, this, firstParameterIndex, argv, argc);
 }
 
 } // namespace JSC
index cc73690..f40bf47 100644 (file)
@@ -44,6 +44,8 @@ namespace JSC {
         JSActivation(ExecState* exec, PassRefPtr<FunctionBodyNode>, Register*);
         virtual ~JSActivation();
         
+        virtual void mark();
+
         virtual bool isActivationObject() const;
         virtual bool isDynamicScope() const;
 
@@ -71,8 +73,6 @@ namespace JSC {
 
         virtual JSObject* toThisObject(ExecState*) const;
 
-        virtual void mark();
-        
         void copyRegisters();
         
         virtual const ClassInfo* classInfo() const { return &info; }
index b8f8734..d9f3ad5 100644 (file)
@@ -202,7 +202,7 @@ void JSGlobalObject::reset(JSValue* prototype)
 
     ASSERT(!hasCustomProperties());
     symbolTable().clear();
-    setRegisterArray(0, 0);
+    setRegisters(0, 0, 0);
 
     ExecState* exec = d()->globalExec.get();
 
@@ -396,6 +396,17 @@ void JSGlobalObject::mark()
 
     // No need to mark the other structures, because their prototypes are all
     // guaranteed to be referenced elsewhere.
+
+    Register* registerArray = d()->registerArray.get();
+    if (!registerArray)
+        return;
+
+    size_t size = d()->registerArraySize;
+    for (size_t i = 0; i < size; ++i) {
+        Register& r = registerArray[i];
+        if (!r.marked())
+            r.mark();
+    }
 }
 
 JSGlobalObject* JSGlobalObject::toGlobalObject(ExecState*) const
@@ -423,7 +434,9 @@ void JSGlobalObject::copyGlobalsFrom(RegisterFile& registerFile)
         d()->registers = 0;
         return;
     }
-    copyRegisterArray(registerFile.lastGlobal(), numGlobals);
+    
+    Register* registerArray = copyRegisterArray(registerFile.lastGlobal(), numGlobals);
+    setRegisters(registerArray + numGlobals, registerArray, numGlobals);
 }
 
 void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile)
@@ -437,10 +450,8 @@ void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile)
 
     if (d()->registerArray) {
         memcpy(registerFile.base() - d()->registerArraySize, d()->registerArray.get(), d()->registerArraySize * sizeof(Register));
-        setRegisterArray(0, 0);
+        setRegisters(registerFile.base(), 0, 0);
     }
-
-    d()->registers = registerFile.base();
 }
 
 void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData)
index ef100e5..14140d2 100644 (file)
@@ -156,6 +156,8 @@ namespace JSC {
     public:
         virtual ~JSGlobalObject();
 
+        virtual void mark();
+
         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
         virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&);
@@ -224,8 +226,6 @@ namespace JSC {
         
         ScopeChain& globalScopeChain() { return d()->globalScopeChain; }
 
-        virtual void mark();
-
         virtual bool isGlobalObject() const { return true; }
         virtual JSGlobalObject* toGlobalObject(ExecState*) const;
 
@@ -274,13 +274,14 @@ namespace JSC {
 
     inline void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
     {
-        size_t registerArraySize = d()->registerArraySize;
-        Register* registerArray = new Register[registerArraySize + count];
+        size_t oldSize = d()->registerArraySize;
+        size_t newSize = oldSize + count;
+        Register* registerArray = new Register[newSize];
         if (d()->registerArray)
-            memcpy(registerArray + count, d()->registerArray.get(), registerArraySize * sizeof(Register));
-        setRegisterArray(registerArray, registerArraySize + count);
+            memcpy(registerArray + count, d()->registerArray.get(), oldSize * sizeof(Register));
+        setRegisters(registerArray + newSize, registerArray, newSize);
 
-        for (int i = 0, index = -static_cast<int>(registerArraySize) - 1; i < count; ++i, --index) {
+        for (int i = 0, index = -static_cast<int>(oldSize) - 1; i < count; ++i, --index) {
             GlobalPropertyInfo& global = globals[i];
             ASSERT(global.attributes & DontDelete);
             SymbolTableEntry newEntry(index, global.attributes);
index 1e37826..0698250 100644 (file)
@@ -31,6 +31,14 @@ namespace JSC {
 
 ASSERT_CLASS_FITS_IN_CELL(JSStaticScopeObject);
 
+void JSStaticScopeObject::mark()
+{
+    JSVariableObject::mark();
+    
+    if (!d()->registerStore.marked())
+        d()->registerStore.mark();
+}
+
 JSObject* JSStaticScopeObject::toThisObject(ExecState* exec) const
 {
     return exec->globalThisValue();
@@ -59,8 +67,8 @@ bool JSStaticScopeObject::isDynamicScope() const
 
 JSStaticScopeObject::~JSStaticScopeObject()
 {
-    ASSERT(d);
-    delete static_cast<JSStaticScopeObjectData*>(d);
+    ASSERT(d());
+    delete d();
 }
 
 inline bool JSStaticScopeObject::getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot& slot)
index 8b8025f..a78c2f5 100644 (file)
@@ -47,17 +47,20 @@ namespace JSC{
         JSStaticScopeObject(ExecState* exec, const Identifier& ident, JSValue* value, unsigned attributes)
             : JSVariableObject(exec->globalData().nullProtoStructureID, new JSStaticScopeObjectData())
         {
-            JSStaticScopeObjectData* data = static_cast<JSStaticScopeObjectData*>(d);
-            data->registerStore = value;
+            d()->registerStore = value;
             symbolTable().add(ident.ustring().rep(), SymbolTableEntry(-1, attributes));
         }
         virtual ~JSStaticScopeObject();
+        virtual void mark();
         bool isDynamicScope() const;
         virtual JSObject* toThisObject(ExecState*) const;
         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
         virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&, bool& slotIsWriteable);
         virtual void put(ExecState*, const Identifier&, JSValue*, PutPropertySlot&);
         void putWithAttributes(ExecState*, const Identifier&, JSValue*, unsigned attributes);
+
+    private:
+        JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); }
     };
 
 }
index d6a1f84..8efb9ab 100644 (file)
@@ -63,40 +63,25 @@ bool JSVariableObject::getPropertyAttributes(ExecState* exec, const Identifier&
     return JSObject::getPropertyAttributes(exec, propertyName, attributes);
 }
 
-void JSVariableObject::mark()
-{
-    JSObject::mark();
-
-    if (!d->registerArray)
-        return;
-    
-    Register* end = d->registerArray.get() + d->registerArraySize;
-    for (Register* it = d->registerArray.get(); it != end; ++it)
-        if (!(*it).marked())
-            (*it).mark();
-}
-
 bool JSVariableObject::isVariableObject() const
 {
     return true;
 }
 
-void JSVariableObject::copyRegisterArray(Register* src, size_t count)
+Register* JSVariableObject::copyRegisterArray(Register* src, size_t count)
 {
-    ASSERT(!d->registerArray);
-
     Register* registerArray = new Register[count];
     memcpy(registerArray, src, count * sizeof(Register));
 
-    setRegisterArray(registerArray, count);
+    return registerArray;
 }
 
-void JSVariableObject::setRegisterArray(Register* registerArray, size_t count)
+void JSVariableObject::setRegisters(Register* r, Register* registerArray, size_t count)
 {
     if (registerArray != d->registerArray.get())
         d->registerArray.set(registerArray);
     d->registerArraySize = count;
-    d->registers = registerArray + count;
+    d->registers = r;
 }
 
 } // namespace JSC
index 1263b41..20b225b 100644 (file)
@@ -48,7 +48,6 @@ namespace JSC {
 
         virtual bool deleteProperty(ExecState*, const Identifier&);
         virtual void getPropertyNames(ExecState*, PropertyNameArray&);
-        virtual void mark();
         
         virtual bool isVariableObject() const;
         virtual bool isDynamicScope() const = 0;
@@ -71,7 +70,7 @@ namespace JSC {
             }
 
             SymbolTable* symbolTable; // Maps name -> offset from "r" in register file.
-            Register* registers; // Pointers to the register past the end of local storage. (Local storage indexes are negative.)
+            Register* registers; // "r" in the register file.
             OwnArrayPtr<Register> registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file.
             size_t registerArraySize;
 
@@ -91,8 +90,8 @@ namespace JSC {
         {
         }
 
-        void copyRegisterArray(Register* src, size_t count);
-        void setRegisterArray(Register* registerArray, size_t count);
+        Register* copyRegisterArray(Register* src, size_t count);
+        void setRegisters(Register* r, Register* registerArray, size_t count);
 
         bool symbolTableGet(const Identifier&, PropertySlot&);
         bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable);
index 1434074..d730d58 100644 (file)
@@ -38,83 +38,84 @@ namespace JSC {
     static ALWAYS_INLINE int missingSymbolMarker() { return std::numeric_limits<int>::max(); }
 
     // The bit twiddling in this class assumes that every register index is a
-    // reasonably small negative number, and therefore has its high two bits set.
+    // reasonably small positive or negative number, and therefore has its high
+    // four bits all set or all unset.
 
     struct SymbolTableEntry {
         SymbolTableEntry()
-            : rawValue(0)
+            : m_bits(0)
         {
         }
-        
+
         SymbolTableEntry(int index)
         {
-            ASSERT(index & 0x80000000);
-            ASSERT(index & 0x40000000);
-
-            rawValue = index & ~0x80000000 & ~0x40000000;
+            ASSERT(isValidIndex(index));
+            pack(index, false, false);
         }
-        
+
         SymbolTableEntry(int index, unsigned attributes)
         {
-            ASSERT(index & 0x80000000);
-            ASSERT(index & 0x40000000);
-
-            rawValue = index;
-            
-            if (!(attributes & ReadOnly))
-                rawValue &= ~0x80000000;
-            
-            if (!(attributes & DontEnum))
-                rawValue &= ~0x40000000;
+            ASSERT(isValidIndex(index));
+            pack(index, attributes & ReadOnly, attributes & DontEnum);
         }
-
+        
         bool isNull() const
         {
-            return !rawValue;
+            return !m_bits;
         }
 
         int getIndex() const
         {
-            ASSERT(!isNull());
-            return rawValue | 0x80000000 | 0x40000000;
+            return m_bits >> FlagBits;
         }
 
         unsigned getAttributes() const
         {
             unsigned attributes = 0;
-            
-            if (rawValue & 0x80000000)
+            if (m_bits & ReadOnlyFlag)
                 attributes |= ReadOnly;
-            
-            if (rawValue & 0x40000000)
+            if (m_bits & DontEnumFlag)
                 attributes |= DontEnum;
-            
             return attributes;
         }
 
         void setAttributes(unsigned attributes)
         {
-            rawValue = getIndex();
-            
-            if (!(attributes & ReadOnly))
-                rawValue &= ~0x80000000;
-            
-            if (!(attributes & DontEnum))
-                rawValue &= ~0x40000000;
+            pack(getIndex(), attributes & ReadOnly, attributes & DontEnum);
         }
 
         bool isReadOnly() const
         {
-            return rawValue & 0x80000000;
+            return m_bits & ReadOnlyFlag;
+        }
+
+    private:
+        static const unsigned ReadOnlyFlag = 0x1;
+        static const unsigned DontEnumFlag = 0x2;
+        static const unsigned NotNullFlag = 0x4;
+        static const unsigned FlagBits = 3;
+
+        void pack(int index, bool readOnly, bool dontEnum)
+        {
+            m_bits = (index << FlagBits) | NotNullFlag;
+            if (readOnly)
+                m_bits |= ReadOnlyFlag;
+            if (dontEnum)
+                m_bits |= DontEnumFlag;
+        }
+        
+        bool isValidIndex(int index)
+        {
+            return ((index << FlagBits) >> FlagBits) == index;
         }
 
-        int rawValue;
+        int m_bits;
     };
 
     struct SymbolTableIndexHashTraits {
         typedef SymbolTableEntry TraitType;
         static SymbolTableEntry emptyValue() { return SymbolTableEntry(); }
-        static const bool emptyValueIsZero = false;
+        static const bool emptyValueIsZero = true;
         static const bool needsDestruction = false;
     };
 
index 4333a41..90fcd96 100644 (file)
@@ -286,7 +286,7 @@ bool ResolveNode::isPure(CodeGenerator& generator) const
 
 RegisterID* ResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident)) {
+    if (RegisterID* local = generator.registerFor(m_ident)) {
         if (dst == ignoredResult())
             return 0;
         return generator.moveToDestinationIfNeeded(dst, local);
@@ -404,43 +404,43 @@ RegisterID* ArgumentListNode::emitCode(CodeGenerator& generator, RegisterID* dst
 
 RegisterID* NewExprNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
-    return generator.emitConstruct(generator.finalDestination(dst, r0.get()), r0.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
+    RefPtr<RegisterID> func = generator.emitNode(m_expr.get());
+    return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* EvalFunctionCallNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.tempDestination(dst);
-    RegisterID* func = generator.newTemporary();
-    generator.emitResolveWithBase(base.get(), func, generator.propertyNames().eval);
-    return generator.emitCallEval(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
+    RefPtr<RegisterID> func = generator.newTemporary();
+    generator.emitResolveWithBase(base.get(), func.get(), generator.propertyNames().eval);
+    return generator.emitCallEval(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    RegisterID* func = generator.emitNode(m_expr.get());
-    return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
+    RefPtr<RegisterID> func = generator.emitNode(m_expr.get());
+    return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident))
-        return generator.emitCall(generator.finalDestination(dst), local, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
+    if (RefPtr<RegisterID> local = generator.registerFor(m_ident))
+        return generator.emitCall(generator.finalDestination(dst), local.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
 
     int index = 0;
     size_t depth = 0;
     JSValue* globalObject = 0;
     if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) {
-        RegisterID* func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
-        return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
+        RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
+        return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
     }
 
     RefPtr<RegisterID> base = generator.tempDestination(dst);
-    RegisterID* func = generator.newTemporary();
+    RefPtr<RegisterID> func = generator.newTemporary();
     int identifierStart = m_divot - m_startOffset;
     generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0);
-    generator.emitResolveFunction(base.get(), func, m_ident);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
+    generator.emitResolveFunction(base.get(), func.get(), m_ident);
+    return generator.emitCall(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
@@ -448,16 +448,16 @@ RegisterID* FunctionCallBracketNode::emitCode(CodeGenerator& generator, Register
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     RegisterID* property = generator.emitNode(m_subscript.get());
     generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
-    RegisterID* function = generator.emitGetByVal(generator.newTemporary(), base.get(), property);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
+    RefPtr<RegisterID> function = generator.emitGetByVal(generator.newTemporary(), base.get(), property);
+    return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 RegisterID* FunctionCallDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
     RefPtr<RegisterID> base = generator.emitNode(m_base.get());
     generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
-    RegisterID* function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
-    return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
+    RefPtr<RegisterID> function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
+    return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
 }
 
 // ------------------------------ PostfixResolveNode ----------------------------------
@@ -474,7 +474,7 @@ static RegisterID* emitPostIncOrDec(CodeGenerator& generator, RegisterID* dst, R
 
 RegisterID* PostfixResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident)) {
+    if (RegisterID* local = generator.registerFor(m_ident)) {
         if (generator.isLocalConstant(m_ident)) {
             if (dst == ignoredResult())
                 return 0;
@@ -574,7 +574,7 @@ RegisterID* PostfixErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
 
 RegisterID* DeleteResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (generator.registerForLocal(m_ident))
+    if (generator.registerFor(m_ident))
         return generator.emitUnexpectedLoad(generator.finalDestination(dst), false);
 
     generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
@@ -629,7 +629,7 @@ RegisterID* VoidNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* TypeOfResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident)) {
+    if (RegisterID* local = generator.registerFor(m_ident)) {
         if (dst == ignoredResult())
             return 0;
         return generator.emitTypeOf(generator.finalDestination(dst), local);
@@ -658,7 +658,7 @@ RegisterID* TypeOfValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 
 RegisterID* PrefixResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident)) {
+    if (RegisterID* local = generator.registerFor(m_ident)) {
         if (generator.isLocalConstant(m_ident)) {
             if (dst == ignoredResult())
                 return 0;
@@ -893,7 +893,7 @@ static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generat
 
 RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident)) {
+    if (RegisterID* local = generator.registerFor(m_ident)) {
         if (generator.isLocalConstant(m_ident)) {
             RegisterID* src2 = generator.emitNode(m_right.get());
             return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator);
@@ -937,7 +937,7 @@ RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID
 
 RegisterID* AssignResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
 {
-    if (RegisterID* local = generator.registerForLocal(m_ident)) {
+    if (RegisterID* local = generator.registerFor(m_ident)) {
         if (generator.isLocalConstant(m_ident))
             return generator.emitNode(dst, m_right.get());
         
@@ -1047,7 +1047,7 @@ ConstDeclNode::ConstDeclNode(JSGlobalData* globalData, const Identifier& ident,
 
 RegisterID* ConstDeclNode::emitCodeSingle(CodeGenerator& generator)
 {
-    if (RegisterID* local = generator.registerForLocalConstInit(m_ident)) {
+    if (RegisterID* local = generator.constRegisterFor(m_ident)) {
         if (!m_init)
             return local;
 
@@ -1338,7 +1338,7 @@ RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
     RegisterID* propertyName;
     if (m_lexpr->isResolveNode()) {
         const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
-        propertyName = generator.registerForLocal(ident);
+        propertyName = generator.registerFor(ident);
         if (!propertyName) {
             propertyName = generator.newTemporary();
             RefPtr<RegisterID> protect = propertyName;
index b0df2fc..a224497 100644 (file)
@@ -678,12 +678,6 @@ public:
         emitModRm_opm(GROUP5_OP_JMPN, base, offset);
     }
     
-    void call_r(RegisterID dst)
-    {
-        m_buffer->putByte(OP_GROUP5_Ev);
-        emitModRm_opr(GROUP5_OP_CALLN, dst);
-    }
-
     // Opaque label types
     
     class JmpSrc {
@@ -728,6 +722,13 @@ public:
         return JmpSrc(m_buffer->getOffset());
     }
     
+    JmpSrc emitCall(RegisterID dst)
+    {
+        m_buffer->putByte(OP_GROUP5_Ev);
+        emitModRm_opr(GROUP5_OP_CALLN, dst);
+        return JmpSrc(m_buffer->getOffset());
+    }
+
     JmpDst label()
     {
         return JmpDst(m_buffer->getOffset());