2008-09-15 Geoffrey Garen <ggaren@apple.com>
authorggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Sep 2008 23:37:31 +0000 (23:37 +0000)
committerggaren@apple.com <ggaren@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Mon, 15 Sep 2008 23:37:31 +0000 (23:37 +0000)
        Reviewed by Sam Weinig.

        Removed the CalledAsConstructor flag from the call frame header. Now,
        we use an explicit opcode at the call site to fix up constructor results.

        SunSpider says 0.4% faster.

        cti_op_construct_verify is an out-of-line function call for now, but we
        can fix that once StructureID holds type information like isObject.

        * VM/CTI.cpp:
        (JSC::CTI::privateCompileMainPass): Codegen for the new opcode.

        * VM/CodeBlock.cpp:
        (JSC::CodeBlock::dump):

        * VM/CodeGenerator.cpp: Codegen for the new opcode. Also...
        (JSC::CodeGenerator::emitCall): ... don't test for known non-zero value.
        (JSC::CodeGenerator::emitConstruct): ... ditto.

        * VM/Machine.cpp: No more CalledAsConstructor
        (JSC::Machine::privateExecute): Implementation for the new opcode.
        (JSC::Machine::cti_op_ret): The speedup: no need to check whether we were
        called as a constructor.
        (JSC::Machine::cti_op_construct_verify): Implementation for the new opcode.
        * VM/Machine.h:

        * VM/Opcode.h: Declare new opcode.

        * VM/RegisterFile.h:
        (JSC::RegisterFile::): No more CalledAsConstructor

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

JavaScriptCore/ChangeLog
JavaScriptCore/VM/CTI.cpp
JavaScriptCore/VM/CodeBlock.cpp
JavaScriptCore/VM/CodeGenerator.cpp
JavaScriptCore/VM/Machine.cpp
JavaScriptCore/VM/Machine.h
JavaScriptCore/VM/Opcode.h
JavaScriptCore/VM/RegisterFile.h

index 03c4c1a..dce1e29 100644 (file)
@@ -1,3 +1,37 @@
+2008-09-15  Geoffrey Garen  <ggaren@apple.com>
+
+        Reviewed by Sam Weinig.
+        
+        Removed the CalledAsConstructor flag from the call frame header. Now,
+        we use an explicit opcode at the call site to fix up constructor results.
+
+        SunSpider says 0.4% faster.
+        
+        cti_op_construct_verify is an out-of-line function call for now, but we
+        can fix that once StructureID holds type information like isObject.
+
+        * VM/CTI.cpp:
+        (JSC::CTI::privateCompileMainPass): Codegen for the new opcode.
+
+        * VM/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+
+        * VM/CodeGenerator.cpp: Codegen for the new opcode. Also...
+        (JSC::CodeGenerator::emitCall): ... don't test for known non-zero value.
+        (JSC::CodeGenerator::emitConstruct): ... ditto.
+
+        * VM/Machine.cpp: No more CalledAsConstructor
+        (JSC::Machine::privateExecute): Implementation for the new opcode.
+        (JSC::Machine::cti_op_ret): The speedup: no need to check whether we were
+        called as a constructor.
+        (JSC::Machine::cti_op_construct_verify): Implementation for the new opcode.
+        * VM/Machine.h:
+
+        * VM/Opcode.h: Declare new opcode.
+
+        * VM/RegisterFile.h:
+        (JSC::RegisterFile::): No more CalledAsConstructor
+
 2008-09-15  Gavin Barraclough  <barraclough@apple.com>
 
         Reviewed by Geoff Garen.
index b556019..5dd3c25 100644 (file)
@@ -834,6 +834,13 @@ void CTI::privateCompileMainPass()
             i += 6;
             break;
         }
+        case op_construct_verify: {
+            emitPutArgConstant(instruction[i + 1].u.operand, 0);
+            emitPutArgConstant(instruction[i + 2].u.operand, 4);
+            emitCall(i, Machine::cti_op_construct_verify);
+            i += 3;
+            break;
+        }
         case op_get_by_val: {
             emitGetArg(instruction[i + 2].u.operand, X86::eax);
             emitGetArg(instruction[i + 3].u.operand, X86::edx);
index c6d869a..7bff4b2 100644 (file)
@@ -789,6 +789,12 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator&
             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);
             break;
         }
+        case op_construct_verify: {
+            int r0 = (++it)->u.operand;
+            int r1 = (++it)->u.operand;
+            printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str());
+            break;
+        }
         case op_get_pnames: {
             int r0 = (++it)->u.operand;
             int r1 = (++it)->u.operand;
index c4f878a..f33d0c9 100644 (file)
@@ -1080,7 +1080,7 @@ RegisterID* CodeGenerator::emitCall(OpcodeID opcodeID, RegisterID* dst, Register
     instructions().append(dst->index());
     instructions().append(func->index());
     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.size() ? argv[0]->index() : m_temporaries.size()); // argv
+    instructions().append(argv[0]->index()); // argv
     instructions().append(argv.size()); // argc
     return dst;
 }
@@ -1124,8 +1124,13 @@ RegisterID* CodeGenerator::emitConstruct(RegisterID* dst, RegisterID* func, Argu
     instructions().append(dst->index());
     instructions().append(func->index());
     instructions().append(funcProto->index());
-    instructions().append(argv.size() ? argv[0]->index() : m_temporaries.size()); // argv
+    instructions().append(argv[0]->index()); // argv
     instructions().append(argv.size()); // argc
+    
+    emitOpcode(op_construct_verify);
+    instructions().append(dst->index());
+    instructions().append(argv[0]->index());
+
     return dst;
 }
 
index 379dd2e..23af659 100644 (file)
@@ -439,7 +439,7 @@ static bool NEVER_INLINE resolveBaseAndFunc(ExecState* exec, Instruction* vPC, R
     return false;
 }
 
-ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, int calledAsConstructor, JSValue* function)
+ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock* codeBlock, Instruction* vPC, ScopeChainNode* scopeChain, Register* r, int returnValueRegister, int argv, int argc, JSValue* function)
 {
     callFrame[RegisterFile::CallerCodeBlock] = codeBlock;
     callFrame[RegisterFile::ReturnVPC] = vPC + 1;
@@ -448,7 +448,6 @@ ALWAYS_INLINE void Machine::initializeCallFrame(Register* callFrame, CodeBlock*
     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::CalledAsConstructor] = calledAsConstructor;
     callFrame[RegisterFile::Callee] = function;
     callFrame[RegisterFile::OptionalCalleeActivation] = nullJSValue;
 }
@@ -636,7 +635,6 @@ void Machine::dumpRegisters(const CodeBlock* codeBlock, RegisterFile* registerFi
     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("[CalledAsConstructor]      | %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");
@@ -821,7 +819,7 @@ JSValue* Machine::execute(ProgramNode* programNode, ExecState* exec, ScopeChainN
     Register* callFrame = m_registerFile.base() + oldSize;
 
     // a 0 codeBlock indicates a built-in caller
-    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
 
     Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
     r[codeBlock->thisRegister] = thisObj;
@@ -887,7 +885,7 @@ JSValue* Machine::execute(FunctionBodyNode* functionBodyNode, ExecState* exec, J
         (*++dst) = *it;
 
     // a 0 codeBlock indicates a built-in caller
-    initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, 0, function);
+    initializeCallFrame(callFrame, 0, 0, 0, callFrame, 0, argv, argc, function);
 
     CodeBlock* newCodeBlock = &functionBodyNode->byteCode(scopeChain);
     Register* r = slideRegisterWindowForCall(exec, newCodeBlock, &m_registerFile, m_registerFile.base(), callFrame, argv, argc, *exception);
@@ -971,7 +969,7 @@ JSValue* Machine::execute(EvalNode* evalNode, ExecState* exec, JSObject* thisObj
     Register* callFrame = m_registerFile.base() + registerOffset;
 
     // a 0 codeBlock indicates a built-in caller
-    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+    initializeCallFrame(callFrame, 0, 0, 0, 0, 0, 0, 0, 0);
 
     Register* r = callFrame + RegisterFile::CallFrameHeaderSize + codeBlock->numVars;
     r[codeBlock->thisRegister] = thisObj;
@@ -3188,7 +3186,7 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             (*enabledProfilerReference)->willExecute(exec, static_cast<JSObject*>(v));
 
         Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-        initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, 0, v);
+        initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, v);
         exec->m_callFrame = callFrame;
 
         if (callType == CallTypeJS) {
@@ -3265,10 +3263,6 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
             scopeChain->deref();
 
         JSValue* returnValue = r[result].jsValue(exec);
-        if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
-            JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
-            returnValue = thisObject;
-        }
 
         codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
         if (!codeBlock)
@@ -3331,7 +3325,7 @@ 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, 1, constructor);
+            initializeCallFrame(callFrame, codeBlock, vPC, scopeChain, r, dst, firstArg, argCount, constructor);
             exec->m_callFrame = callFrame;
 
             r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
@@ -3370,6 +3364,25 @@ JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFi
         exceptionValue = createNotAConstructorError(exec, constrVal, vPC, codeBlock);
         goto vm_throw;
     }
+    BEGIN_OPCODE(op_construct_verify) {
+        /* construct_verify dst(r) override(r)
+
+           Verifies that register dst holds an object. If not, moves
+           the object in register override to register dst.
+        */
+
+        int dst = vPC[1].u.operand;;
+        if (LIKELY(r[dst].jsValue(exec)->isObject())) {
+            vPC += 3;
+            NEXT_OPCODE;
+        }
+
+        int override = vPC[2].u.operand;
+        r[dst] = r[override];
+
+        vPC += 3;
+        NEXT_OPCODE;
+    }
     BEGIN_OPCODE(op_push_scope) {
         /* push_scope scope(r)
 
@@ -4281,7 +4294,7 @@ void* Machine::cti_op_call_JSFunction(CTI_ARGS)
     r[firstArg] = thisValue;
 
     Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-    machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal);
+    machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, funcVal);
     exec->m_callFrame = callFrame;
 
     r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
@@ -4321,7 +4334,7 @@ JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS)
 
         Register* oldCallFrame = exec->m_callFrame;
         Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-        machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal);
+        machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, funcVal);
         exec->m_callFrame = callFrame;
 
         if (*ARG_profilerReference)
@@ -4371,12 +4384,6 @@ JSValue* Machine::cti_op_ret(CTI_ARGS)
     if (codeBlock->needsFullScopeChain)
         scopeChain->deref();
 
-    JSValue* returnValue = ARG_src1;
-    if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) {
-        JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec);
-        returnValue = thisObject;
-    }
-
     codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock();
     if (codeBlock) {
         machine->setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain());
@@ -4388,7 +4395,7 @@ JSValue* Machine::cti_op_ret(CTI_ARGS)
     ARG_setCodeBlock(codeBlock);
     ARG_setR(r);
 
-    return returnValue;
+    return ARG_src1;
 }
 
 JSValue* Machine::cti_op_new_array(CTI_ARGS)
@@ -4472,7 +4479,7 @@ void* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
     r[firstArg] = newObject; // "this" value
 
     Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-    machine->initializeCallFrame(callFrame, codeBlock, ARG_instr4, scopeChain, r, 0/*dst*/, firstArg, argCount, 1, constructor);
+    machine->initializeCallFrame(callFrame, codeBlock, ARG_instr4, scopeChain, r, 0/*dst*/, firstArg, argCount, constructor);
     exec->m_callFrame = callFrame;
 
     r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue);
@@ -4490,6 +4497,19 @@ void* Machine::cti_op_construct_JSConstruct(CTI_ARGS)
     return codeBlock->ctiCode;
 }
 
+void Machine::cti_op_construct_verify(CTI_ARGS)
+{
+    ExecState* exec = ARG_exec;
+    Register* r = ARG_r;
+    int dst = ARG_int1;
+
+    if (LIKELY(r[dst].jsValue(exec)->isObject()))
+        return;
+    
+    int override = ARG_int2;
+    r[dst] = r[override];
+}
+
 JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
 {
     ExecState* exec = ARG_exec;
@@ -4514,7 +4534,7 @@ JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS)
 
         Register* oldCallFrame = exec->m_callFrame;
         Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize;
-        machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 1, constrVal);
+        machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, constrVal);
         exec->m_callFrame = callFrame;
 
         if (*ARG_profilerReference)
index bcf3105..d145642 100644 (file)
@@ -165,6 +165,7 @@ namespace JSC {
         static JSValue* SFX_CALL cti_op_resolve(CTI_ARGS);
         static void* SFX_CALL cti_op_construct_JSConstruct(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_construct_NotJSConstruct(CTI_ARGS);
+        static void SFX_CALL cti_op_construct_verify(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_get_by_val(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_resolve_func(CTI_ARGS);
         static JSValue* SFX_CALL cti_op_sub(CTI_ARGS);
@@ -239,7 +240,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, int calledAsConstructor, JSValue* function);
+        ALWAYS_INLINE void initializeCallFrame(Register* callFrame, CodeBlock*, Instruction*, ScopeChainNode*, Register* r, int returnValueRegister, int argv, 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 5792e4a..580da83 100644 (file)
@@ -134,6 +134,7 @@ namespace JSC {
         macro(op_ret) \
         \
         macro(op_construct) \
+        macro(op_construct_verify) \
         \
         macro(op_get_pnames) \
         macro(op_next_pname) \
index 0db99bf..7e3b6a1 100644 (file)
@@ -97,7 +97,6 @@ namespace JSC {
             ReturnValueRegister,
             ArgumentStartRegister,
             ArgumentCount,
-            CalledAsConstructor,
             Callee,
             OptionalCalleeActivation,
             CTIReturnEIP,