Title: [116670] trunk/Source/_javascript_Core
Revision
116670
Author
barraclo...@apple.com
Date
2012-05-10 11:40:29 -0700 (Thu, 10 May 2012)

Log Message

Cache inheritorID on JSFunction
https://bugs.webkit.org/show_bug.cgi?id=85853

Reviewed by Geoff Garen & Filip Pizlo.

An object's prototype is indicated via its structure.  To create an otherwise
empty object with object A as its prototype, we require a structure with its
prototype set to point to A.  We wish to use this same structure for all empty
objects created with a prototype of A, so we presently store this structure as
a property of A, known as the inheritorID.

When a function F is invoked as a constructor, where F has a property 'prototype'
set to point to A, in order to create the 'this' value for the constructor to
use the following steps are taken:
  - the 'prototype' proptery of F is read, via a regular [[Get]] access.
  - the inheritorID internal property of the prototype is read.
  - a new, empty object is constructed with its structure set to point to inheritorID.

There are two drawbacks to the current approach:
  - it requires that every object has an inheritorID field.
  - it requires a [[Get]] access on every constructor call to access the 'prototype' property.

Instead, switch to caching a copy of the inheritorID on the function.  Constructor
calls now only need read the internal property from the callee, saving a [[Get]].
This also means that JSObject::m_inheritorID is no longer commonly read, and in a
future patch we can move to storing this in a more memory efficient fashion.

* _javascript_Core.xcodeproj/project.pbxproj:
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::BytecodeGenerator):
* dfg/DFGAbstractState.cpp:
(JSC::DFG::AbstractState::execute):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGNodeType.h:
(DFG):
* dfg/DFGOperations.cpp:
* dfg/DFGOperations.h:
* dfg/DFGPredictionPropagationPhase.cpp:
(JSC::DFG::PredictionPropagationPhase::propagate):
* dfg/DFGSpeculativeJIT32_64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* dfg/DFGSpeculativeJIT64.cpp:
(JSC::DFG::SpeculativeJIT::compile):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JITInlineMethods.h:
(JSC::JIT::emitAllocateJSFunction):
* jit/JITOpcodes.cpp:
(JSC::JIT::emit_op_create_this):
(JSC::JIT::emitSlow_op_create_this):
* jit/JITOpcodes32_64.cpp:
(JSC::JIT::emit_op_create_this):
(JSC::JIT::emitSlow_op_create_this):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* llint/LLIntSlowPaths.cpp:
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
* llint/LowLevelInterpreter32_64.asm:
* llint/LowLevelInterpreter64.asm:
* runtime/JSFunction.cpp:
(JSC::JSFunction::JSFunction):
(JSC::JSFunction::cacheInheritorID):
(JSC):
(JSC::JSFunction::put):
(JSC::JSFunction::defineOwnProperty):
* runtime/JSFunction.h:
(JSC::JSFunction::cachedInheritorID):
(JSFunction):
(JSC::JSFunction::offsetOfCachedInheritorID):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (116669 => 116670)


--- trunk/Source/_javascript_Core/ChangeLog	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/ChangeLog	2012-05-10 18:40:29 UTC (rev 116670)
@@ -1,3 +1,81 @@
+2012-05-10  Gavin Barraclough  <barraclo...@apple.com>
+
+        Cache inheritorID on JSFunction
+        https://bugs.webkit.org/show_bug.cgi?id=85853
+
+        Reviewed by Geoff Garen & Filip Pizlo.
+
+        An object's prototype is indicated via its structure.  To create an otherwise
+        empty object with object A as its prototype, we require a structure with its
+        prototype set to point to A.  We wish to use this same structure for all empty
+        objects created with a prototype of A, so we presently store this structure as
+        a property of A, known as the inheritorID.
+
+        When a function F is invoked as a constructor, where F has a property 'prototype'
+        set to point to A, in order to create the 'this' value for the constructor to
+        use the following steps are taken:
+          - the 'prototype' proptery of F is read, via a regular [[Get]] access.
+          - the inheritorID internal property of the prototype is read.
+          - a new, empty object is constructed with its structure set to point to inheritorID.
+
+        There are two drawbacks to the current approach:
+          - it requires that every object has an inheritorID field.
+          - it requires a [[Get]] access on every constructor call to access the 'prototype' property.
+
+        Instead, switch to caching a copy of the inheritorID on the function.  Constructor
+        calls now only need read the internal property from the callee, saving a [[Get]].
+        This also means that JSObject::m_inheritorID is no longer commonly read, and in a
+        future patch we can move to storing this in a more memory efficient fashion.
+
+        * _javascript_Core.xcodeproj/project.pbxproj:
+        * bytecode/CodeBlock.cpp:
+        (JSC::CodeBlock::dump):
+        * bytecode/Opcode.h:
+        (JSC):
+        (JSC::padOpcodeName):
+        * bytecompiler/BytecodeGenerator.cpp:
+        (JSC::BytecodeGenerator::BytecodeGenerator):
+        * dfg/DFGAbstractState.cpp:
+        (JSC::DFG::AbstractState::execute):
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGNodeType.h:
+        (DFG):
+        * dfg/DFGOperations.cpp:
+        * dfg/DFGOperations.h:
+        * dfg/DFGPredictionPropagationPhase.cpp:
+        (JSC::DFG::PredictionPropagationPhase::propagate):
+        * dfg/DFGSpeculativeJIT32_64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * dfg/DFGSpeculativeJIT64.cpp:
+        (JSC::DFG::SpeculativeJIT::compile):
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JITInlineMethods.h:
+        (JSC::JIT::emitAllocateJSFunction):
+        * jit/JITOpcodes.cpp:
+        (JSC::JIT::emit_op_create_this):
+        (JSC::JIT::emitSlow_op_create_this):
+        * jit/JITOpcodes32_64.cpp:
+        (JSC::JIT::emit_op_create_this):
+        (JSC::JIT::emitSlow_op_create_this):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * llint/LLIntSlowPaths.cpp:
+        (JSC::LLInt::LLINT_SLOW_PATH_DECL):
+        * llint/LowLevelInterpreter32_64.asm:
+        * llint/LowLevelInterpreter64.asm:
+        * runtime/JSFunction.cpp:
+        (JSC::JSFunction::JSFunction):
+        (JSC::JSFunction::cacheInheritorID):
+        (JSC):
+        (JSC::JSFunction::put):
+        (JSC::JSFunction::defineOwnProperty):
+        * runtime/JSFunction.h:
+        (JSC::JSFunction::cachedInheritorID):
+        (JSFunction):
+        (JSC::JSFunction::offsetOfCachedInheritorID):
+
 2012-05-10  Michael Saboff  <msab...@apple.com>
 
         Enh: Hash Const JSString in Backing Stores to Save Memory

Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (116669 => 116670)


--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj	2012-05-10 18:40:29 UTC (rev 116670)
@@ -1041,6 +1041,9 @@
 		86880F4C14353B2100B08D42 /* DFGSpeculativeJIT64.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = DFGSpeculativeJIT64.cpp; path = dfg/DFGSpeculativeJIT64.cpp; sourceTree = "<group>"; };
 		869D04AE1193B54D00803475 /* CachedTranscendentalFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedTranscendentalFunction.h; sourceTree = "<group>"; };
 		869EBCB60E8C6D4A008722CC /* ResultType.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResultType.h; sourceTree = "<group>"; };
+		86A054461556451B00445157 /* LowLevelInterpreter.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter.asm; path = llint/LowLevelInterpreter.asm; sourceTree = "<group>"; };
+		86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter32_64.asm; path = llint/LowLevelInterpreter32_64.asm; sourceTree = "<group>"; };
+		86A054481556451B00445157 /* LowLevelInterpreter64.asm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.asm.asm; name = LowLevelInterpreter64.asm; path = llint/LowLevelInterpreter64.asm; sourceTree = "<group>"; };
 		86A90ECF0EE7D51F00AB350D /* JITArithmetic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITArithmetic.cpp; sourceTree = "<group>"; };
 		86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; };
 		86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerARMv7.h; sourceTree = "<group>"; };
@@ -1430,7 +1433,6 @@
 				45E12D8806A49B0F00E9DF84 /* jsc.cpp */,
 				A767FF9F14F4502900789059 /* JSCTypedArrayStubs.h */,
 				F68EBB8C0255D4C601FF60F7 /* config.h */,
-				0F46809C14BA7F4D00BFE272 /* llint */,
 				1432EBD70A34CAD400717B9F /* API */,
 				9688CB120ED12B4E001D649F /* assembler */,
 				969A078F0ED1D3AE00F1F681 /* bytecode */,
@@ -1440,6 +1442,7 @@
 				142E312A134FF0A600AFADB5 /* heap */,
 				1429D77A0ED20D7300B89619 /* interpreter */,
 				1429D92C0ED22D7000B89619 /* jit */,
+				0F46809C14BA7F4D00BFE272 /* llint */,
 				7E39D8370EC3A388003AF11A /* parser */,
 				95AB831A0DA42C6900BC83F3 /* profiler */,
 				7EF6E0BB0EB7A1EC0079AFAF /* runtime */,
@@ -1489,6 +1492,9 @@
 				0F46809F14BA7F8200BFE272 /* LLIntSlowPaths.cpp */,
 				0F4680A014BA7F8200BFE272 /* LLIntSlowPaths.h */,
 				0F4680A114BA7F8200BFE272 /* LLIntOffsetsExtractor.cpp */,
+				86A054461556451B00445157 /* LowLevelInterpreter.asm */,
+				86A054471556451B00445157 /* LowLevelInterpreter32_64.asm */,
+				86A054481556451B00445157 /* LowLevelInterpreter64.asm */,
 			);
 			name = llint;
 			sourceTree = "<group>";

Modified: trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/bytecode/CodeBlock.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -519,8 +519,7 @@
         }
         case op_create_this: {
             int r0 = (++it)->u.operand;
-            int r1 = (++it)->u.operand;
-            dataLog("[%4d] create_this %s %s\n", location, registerName(exec, r0).data(), registerName(exec, r1).data());
+            dataLog("[%4d] create_this %s\n", location, registerName(exec, r0).data());
             break;
         }
         case op_convert_this: {

Modified: trunk/Source/_javascript_Core/bytecode/Opcode.h (116669 => 116670)


--- trunk/Source/_javascript_Core/bytecode/Opcode.h	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/bytecode/Opcode.h	2012-05-10 18:40:29 UTC (rev 116670)
@@ -42,7 +42,7 @@
         macro(op_create_activation, 2) \
         macro(op_init_lazy_reg, 2) \
         macro(op_create_arguments, 2) \
-        macro(op_create_this, 3) \
+        macro(op_create_this, 2) \
         macro(op_get_callee, 2) \
         macro(op_convert_this, 2) \
         \

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -442,17 +442,8 @@
     preserveLastVar();
 
     if (isConstructor()) {
-        RefPtr<RegisterID> func = newTemporary();
-        RefPtr<RegisterID> funcProto = newTemporary();
-
-        emitOpcode(op_get_callee);
-        instructions().append(func->index());
-        // Load prototype.
-        emitGetById(funcProto.get(), func.get(), globalData()->propertyNames->prototype);
-
         emitOpcode(op_create_this);
         instructions().append(m_thisRegister.index());
-        instructions().append(funcProto->index());
     } else if (!codeBlock->isStrictMode() && (functionBody->usesThis() || codeBlock->usesEval() || m_shouldEmitDebugHooks)) {
         emitOpcode(op_convert_this);
         instructions().append(m_thisRegister.index());

Modified: trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/dfg/DFGAbstractState.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -774,19 +774,16 @@
         destination.merge(PredictObjectOther);
         break;
     }
-            
+
     case CreateThis: {
-        Node& child = m_graph[node.child1()];
         AbstractValue& source = forNode(node.child1());
         AbstractValue& destination = forNode(nodeIndex);
             
-        if (child.shouldSpeculateFinalObject())
-            source.filter(PredictFinalObject);
-            
+        source.filter(PredictFunction);
         destination.set(PredictFinalObject);
         break;
     }
-            
+
     case NewObject:
         forNode(nodeIndex).set(m_codeBlock->globalObjectFor(node.codeOrigin)->emptyObjectStructure());
         m_haveStructures = true;

Modified: trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/dfg/DFGByteCodeParser.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -1534,8 +1534,10 @@
         }
 
         case op_create_this: {
-            NodeIndex op1 = get(currentInstruction[2].u.operand);
-            set(currentInstruction[1].u.operand, addToGraph(CreateThis, op1));
+            if (m_inlineStackTop->m_inlineCallFrame)
+                set(currentInstruction[1].u.operand, addToGraph(CreateThis, getDirect(m_inlineStackTop->m_calleeVR)));
+            else
+                set(currentInstruction[1].u.operand, addToGraph(CreateThis, addToGraph(GetCallee)));
             NEXT_OPCODE(op_create_this);
         }
             

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -209,41 +209,19 @@
     return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
 }
 
-inline JSCell* createThis(ExecState* exec, JSCell* prototype, JSFunction* constructor)
+JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* constructor)
 {
+    JSGlobalData* globalData = &exec->globalData();
+    NativeCallFrameTracer tracer(globalData, exec);
+
 #if !ASSERT_DISABLED
     ConstructData constructData;
-    ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
+    ASSERT(jsCast<JSFunction*>(constructor)->methodTable()->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS);
 #endif
     
-    JSGlobalData& globalData = exec->globalData();
-    NativeCallFrameTracer tracer(&globalData, exec);
-
-    Structure* structure;
-    if (prototype->isObject())
-        structure = asObject(prototype)->inheritorID(globalData);
-    else
-        structure = constructor->scope()->globalObject->emptyObjectStructure();
-    
-    return constructEmptyObject(exec, structure);
+    return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->cachedInheritorID(exec));
 }
 
-JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype)
-{
-    JSGlobalData* globalData = &exec->globalData();
-    NativeCallFrameTracer tracer(globalData, exec);
-
-    return createThis(exec, prototype, jsCast<JSFunction*>(exec->callee()));
-}
-
-JSCell* DFG_OPERATION operationCreateThisInlined(ExecState* exec, JSCell* prototype, JSCell* constructor)
-{
-    JSGlobalData* globalData = &exec->globalData();
-    NativeCallFrameTracer tracer(globalData, exec);
-    
-    return createThis(exec, prototype, jsCast<JSFunction*>(constructor));
-}
-
 JSCell* DFG_OPERATION operationNewObject(ExecState* exec)
 {
     JSGlobalData* globalData = &exec->globalData();

Modified: trunk/Source/_javascript_Core/dfg/DFGOperations.h (116669 => 116670)


--- trunk/Source/_javascript_Core/dfg/DFGOperations.h	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/dfg/DFGOperations.h	2012-05-10 18:40:29 UTC (rev 116670)
@@ -97,8 +97,7 @@
 
 // These routines are provide callbacks out to C++ implementations of operations too complex to JIT.
 JSCell* DFG_OPERATION operationNewObject(ExecState*);
-JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* encodedOp1);
-JSCell* DFG_OPERATION operationCreateThisInlined(ExecState*, JSCell* encodedOp1, JSCell* constructor);
+JSCell* DFG_OPERATION operationCreateThis(ExecState*, JSCell* constructor);
 EncodedJSValue DFG_OPERATION operationConvertThis(ExecState*, EncodedJSValue encodedOp1);
 EncodedJSValue DFG_OPERATION operationValueAdd(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);
 EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState*, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2);

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT32_64.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -3029,32 +3029,17 @@
         // then we speculate because we want to get recompiled if it isn't (since
         // otherwise we'd start taking slow path a lot).
         
-        SpeculateCellOperand proto(this, node.child1());
+        SpeculateCellOperand callee(this, node.child1());
         GPRTemporary result(this);
         GPRTemporary scratch(this);
         
-        GPRReg protoGPR = proto.gpr();
+        GPRReg calleeGPR = callee.gpr();
         GPRReg resultGPR = result.gpr();
         GPRReg scratchGPR = scratch.gpr();
         
-        proto.use();
-        
+        // Load the inheritorID. If the inheritorID is not set, go to slow path.
+        m_jit.loadPtr(MacroAssembler::Address(calleeGPR, JSFunction::offsetOfCachedInheritorID()), scratchGPR);
         MacroAssembler::JumpList slowPath;
-        
-        // Need to verify that the prototype is an object. If we have reason to believe
-        // that it's a FinalObject then we speculate on that directly. Otherwise we
-        // do the slow (structure-based) check.
-        if (at(node.child1()).shouldSpeculateFinalObject()) {
-            if (!isFinalObjectPrediction(m_state.forNode(node.child1()).m_type))
-                speculationCheck(BadType, JSValueSource::unboxedCell(protoGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSFinalObject::s_info)));
-        } else {
-            m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR);
-            slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));
-        }
-        
-        // Load the inheritorID (the Structure that objects who have protoGPR as the prototype
-        // use to refer to that prototype). If the inheritorID is not set, go to slow path.
-        m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
         
         emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
@@ -3064,15 +3049,12 @@
         slowPath.link(&m_jit);
         
         silentSpillAllRegisters(resultGPR);
-        if (node.codeOrigin.inlineCallFrame)
-            callOperation(operationCreateThisInlined, resultGPR, protoGPR, node.codeOrigin.inlineCallFrame->callee.get());
-        else
-            callOperation(operationCreateThis, resultGPR, protoGPR);
+        callOperation(operationCreateThis, resultGPR, calleeGPR);
         silentFillAllRegisters(resultGPR);
         
         done.link(&m_jit);
         
-        cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+        cellResult(resultGPR, m_compileIndex);
         break;
     }
 

Modified: trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/dfg/DFGSpeculativeJIT64.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -3053,32 +3053,17 @@
         // then we speculate because we want to get recompiled if it isn't (since
         // otherwise we'd start taking slow path a lot).
         
-        SpeculateCellOperand proto(this, node.child1());
+        SpeculateCellOperand callee(this, node.child1());
         GPRTemporary result(this);
         GPRTemporary scratch(this);
         
-        GPRReg protoGPR = proto.gpr();
+        GPRReg calleeGPR = callee.gpr();
         GPRReg resultGPR = result.gpr();
         GPRReg scratchGPR = scratch.gpr();
         
-        proto.use();
-        
+        // Load the inheritorID. If the inheritorID is not set, go to slow path.
+        m_jit.loadPtr(MacroAssembler::Address(calleeGPR, JSFunction::offsetOfCachedInheritorID()), scratchGPR);
         MacroAssembler::JumpList slowPath;
-        
-        // Need to verify that the prototype is an object. If we have reason to believe
-        // that it's a FinalObject then we speculate on that directly. Otherwise we
-        // do the slow (structure-based) check.
-        if (at(node.child1()).shouldSpeculateFinalObject()) {
-            if (!isFinalObjectPrediction(m_state.forNode(node.child1()).m_type))
-                speculationCheck(BadType, JSValueRegs(protoGPR), node.child1(), m_jit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(protoGPR, JSCell::classInfoOffset()), MacroAssembler::TrustedImmPtr(&JSFinalObject::s_info)));
-        } else {
-            m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSCell::structureOffset()), scratchGPR);
-            slowPath.append(m_jit.branch8(MacroAssembler::Below, MacroAssembler::Address(scratchGPR, Structure::typeInfoTypeOffset()), MacroAssembler::TrustedImm32(ObjectType)));
-        }
-        
-        // Load the inheritorID (the Structure that objects who have protoGPR as the prototype
-        // use to refer to that prototype). If the inheritorID is not set, go to slow path.
-        m_jit.loadPtr(MacroAssembler::Address(protoGPR, JSObject::offsetOfInheritorID()), scratchGPR);
         slowPath.append(m_jit.branchTestPtr(MacroAssembler::Zero, scratchGPR));
         
         emitAllocateJSFinalObject(scratchGPR, resultGPR, scratchGPR, slowPath);
@@ -3088,15 +3073,12 @@
         slowPath.link(&m_jit);
         
         silentSpillAllRegisters(resultGPR);
-        if (node.codeOrigin.inlineCallFrame)
-            callOperation(operationCreateThisInlined, resultGPR, protoGPR, node.codeOrigin.inlineCallFrame->callee.get());
-        else
-            callOperation(operationCreateThis, resultGPR, protoGPR);
+        callOperation(operationCreateThis, resultGPR, calleeGPR);
         silentFillAllRegisters(resultGPR);
         
         done.link(&m_jit);
         
-        cellResult(resultGPR, m_compileIndex, UseChildrenCalledExplicitly);
+        cellResult(resultGPR, m_compileIndex);
         break;
     }
 

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -4809,7 +4809,6 @@
         */
 
         int thisRegister = vPC[1].u.operand;
-        int protoRegister = vPC[2].u.operand;
 
         JSFunction* constructor = jsCast<JSFunction*>(callFrame->callee());
 #if !ASSERT_DISABLED
@@ -4817,12 +4816,7 @@
         ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
 #endif
 
-        Structure* structure;
-        JSValue proto = callFrame->r(protoRegister).jsValue();
-        if (proto.isObject())
-            structure = asObject(proto)->inheritorID(callFrame->globalData());
-        else
-            structure = constructor->scope()->globalObject->emptyObjectStructure();
+        Structure* structure = constructor->cachedInheritorID(callFrame);
         callFrame->uncheckedR(thisRegister) = constructEmptyObject(callFrame, structure);
 
         vPC += OPCODE_LENGTH(op_create_this);

Modified: trunk/Source/_javascript_Core/jit/JITInlineMethods.h (116669 => 116670)


--- trunk/Source/_javascript_Core/jit/JITInlineMethods.h	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/jit/JITInlineMethods.h	2012-05-10 18:40:29 UTC (rev 116670)
@@ -448,6 +448,9 @@
     // store the function's executable member
     storePtr(TrustedImmPtr(executable), Address(result, JSFunction::offsetOfExecutable()));
 
+    // clear the function's inheritorID
+    storePtr(TrustedImmPtr(0), Address(result, JSFunction::offsetOfCachedInheritorID()));
+
     // store the function's name
     ASSERT(executable->nameValue());
     int functionNameOffset = sizeof(JSValue) * m_codeBlock->globalObject()->functionNameOffset();

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -1272,33 +1272,22 @@
 
 void JIT::emit_op_create_this(Instruction* currentInstruction)
 {
-    emitGetVirtualRegister(currentInstruction[2].u.operand, regT2);
-    emitJumpSlowCaseIfNotJSCell(regT2, currentInstruction[2].u.operand);
-    loadPtr(Address(regT2, JSCell::structureOffset()), regT1);
-    addSlowCase(emitJumpIfNotObject(regT1));
-    
-    // now we know that the prototype is an object, but we don't know if it's got an
-    // inheritor ID
-    
-    loadPtr(Address(regT2, JSObject::offsetOfInheritorID()), regT2);
+    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
+    loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2);
     addSlowCase(branchTestPtr(Zero, regT2));
     
     // now regT2 contains the inheritorID, which is the structure that the newly
     // allocated object will have.
     
     emitAllocateJSFinalObject(regT2, regT0, regT1);
-    
     emitPutVirtualRegister(currentInstruction[1].u.operand);
 }
 
 void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); // not a cell
-    linkSlowCase(iter); // not an object
     linkSlowCase(iter); // doesn't have an inheritor ID
     linkSlowCase(iter); // allocation failed
     JITStubCall stubCall(this, cti_op_create_this);
-    stubCall.addArgument(currentInstruction[2].u.operand, regT1);
     stubCall.call(currentInstruction[1].u.operand);
 }
 

Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -1532,35 +1532,22 @@
 
 void JIT::emit_op_create_this(Instruction* currentInstruction)
 {
-    emitLoad(currentInstruction[2].u.operand, regT1, regT0);
-    emitJumpSlowCaseIfNotJSCell(currentInstruction[2].u.operand, regT1);
-    loadPtr(Address(regT0, JSCell::structureOffset()), regT1);
-    addSlowCase(emitJumpIfNotObject(regT1));
-    
-    // now we know that the prototype is an object, but we don't know if it's got an
-    // inheritor ID
-    
-    loadPtr(Address(regT0, JSObject::offsetOfInheritorID()), regT2);
+    emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT0);
+    loadPtr(Address(regT0, JSFunction::offsetOfCachedInheritorID()), regT2);
     addSlowCase(branchTestPtr(Zero, regT2));
     
     // now regT2 contains the inheritorID, which is the structure that the newly
     // allocated object will have.
     
     emitAllocateJSFinalObject(regT2, regT0, regT1);
-
     emitStoreCell(currentInstruction[1].u.operand, regT0);
 }
 
 void JIT::emitSlow_op_create_this(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
 {
-    linkSlowCaseIfNotJSCell(iter, currentInstruction[2].u.operand); // not a cell
-    linkSlowCase(iter); // not an object
     linkSlowCase(iter); // doesn't have an inheritor ID
     linkSlowCase(iter); // allocation failed
-    unsigned protoRegister = currentInstruction[2].u.operand;
-    emitLoad(protoRegister, regT1, regT0);
     JITStubCall stubCall(this, cti_op_create_this);
-    stubCall.addArgument(regT1, regT0);
     stubCall.call(currentInstruction[1].u.operand);
 }
 

Modified: trunk/Source/_javascript_Core/jit/JITStubs.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/jit/JITStubs.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/jit/JITStubs.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -1286,12 +1286,7 @@
     ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
 #endif
 
-    Structure* structure;
-    JSValue proto = stackFrame.args[0].jsValue();
-    if (proto.isObject())
-        structure = asObject(proto)->inheritorID(*stackFrame.globalData);
-    else
-        structure = constructor->scope()->globalObject->emptyObjectStructure();
+    Structure* structure = constructor->cachedInheritorID(callFrame);
     JSValue result = constructEmptyObject(callFrame, structure);
 
     return JSValue::encode(result);

Modified: trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/llint/LLIntSlowPaths.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -458,13 +458,7 @@
     ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
 #endif
     
-    Structure* structure;
-    JSValue proto = LLINT_OP(2).jsValue();
-    if (proto.isObject())
-        structure = asObject(proto)->inheritorID(globalData);
-    else
-        structure = constructor->scope()->globalObject->emptyObjectStructure();
-    
+    Structure* structure = constructor->cachedInheritorID(exec);
     LLINT_RETURN(constructEmptyObject(exec, structure));
 }
 

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm (116669 => 116670)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter32_64.asm	2012-05-10 18:40:29 UTC (rev 116670)
@@ -343,23 +343,18 @@
 
 _llint_op_create_this:
     traceExecution()
-    loadi 8[PC], t0
-    assertNotConstant(t0)
-    bineq TagOffset[cfr, t0, 8], CellTag, .opCreateThisSlow
-    loadi PayloadOffset[cfr, t0, 8], t0
-    loadp JSCell::m_structure[t0], t1
-    bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow
-    loadp JSObject::m_inheritorID[t0], t2
+    loadp Callee[cfr], t0
+    loadp JSFunction::m_cachedInheritorID[t0], t2
     btpz t2, .opCreateThisSlow
     allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow)
     loadi 4[PC], t1
     storei CellTag, TagOffset[cfr, t1, 8]
     storei t0, PayloadOffset[cfr, t1, 8]
-    dispatch(3)
+    dispatch(2)
 
 .opCreateThisSlow:
     callSlowPath(_llint_slow_path_create_this)
-    dispatch(3)
+    dispatch(2)
 
 
 _llint_op_get_callee:

Modified: trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm (116669 => 116670)


--- trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/llint/LowLevelInterpreter64.asm	2012-05-10 18:40:29 UTC (rev 116670)
@@ -221,22 +221,17 @@
 
 _llint_op_create_this:
     traceExecution()
-    loadis 16[PB, PC, 8], t0
-    assertNotConstant(t0)
-    loadp [cfr, t0, 8], t0
-    btpnz t0, tagMask, .opCreateThisSlow
-    loadp JSCell::m_structure[t0], t1
-    bbb Structure::m_typeInfo + TypeInfo::m_type[t1], ObjectType, .opCreateThisSlow
-    loadp JSObject::m_inheritorID[t0], t2
+    loadp Callee[cfr], t0
+    loadp JSFunction::m_cachedInheritorID[t0], t2
     btpz t2, .opCreateThisSlow
     allocateBasicJSObject(JSFinalObjectSizeClassIndex, JSGlobalData::jsFinalObjectClassInfo, t2, t0, t1, t3, .opCreateThisSlow)
     loadis 8[PB, PC, 8], t1
     storep t0, [cfr, t1, 8]
-    dispatch(3)
+    dispatch(2)
 
 .opCreateThisSlow:
     callSlowPath(_llint_slow_path_create_this)
-    dispatch(3)
+    dispatch(2)
 
 
 _llint_op_get_callee:

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.cpp (116669 => 116670)


--- trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.cpp	2012-05-10 18:40:29 UTC (rev 116670)
@@ -112,6 +112,16 @@
     putDirectOffset(exec->globalData(), scopeChainNode->globalObject->functionNameOffset(), executable->nameValue());
 }
 
+Structure* JSFunction::cacheInheritorID(ExecState* exec)
+{
+    JSValue prototype = get(exec, exec->globalData().propertyNames->prototype);
+    if (prototype.isObject())
+        m_cachedInheritorID.set(exec->globalData(), this, asObject(prototype)->inheritorID(exec->globalData()));
+    else
+        m_cachedInheritorID.set(exec->globalData(), this, globalObject()->emptyObjectStructure());
+    return m_cachedInheritorID.get();
+}
+
 const UString& JSFunction::name(ExecState* exec)
 {
     return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
@@ -332,6 +342,7 @@
         // following the rules set out in ECMA-262 8.12.9.
         PropertySlot slot;
         thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+        thisObject->m_cachedInheritorID.clear();
     }
     if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) {
         // This will trigger the property to be reified, if this is not already the case!
@@ -372,6 +383,7 @@
         // following the rules set out in ECMA-262 8.12.9.
         PropertySlot slot;
         thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+        thisObject->m_cachedInheritorID.clear();
         return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
     }
 

Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (116669 => 116670)


--- trunk/Source/_javascript_Core/runtime/JSFunction.h	2012-05-10 18:39:43 UTC (rev 116669)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h	2012-05-10 18:40:29 UTC (rev 116670)
@@ -121,6 +121,18 @@
             return OBJECT_OFFSETOF(JSFunction, m_executable);
         }
 
+        Structure* cachedInheritorID(ExecState* exec)
+        {
+            if (UNLIKELY(!m_cachedInheritorID))
+                return cacheInheritorID(exec);
+            return m_cachedInheritorID.get();
+        }
+
+        static size_t offsetOfCachedInheritorID()
+        {
+            return OBJECT_OFFSETOF(JSFunction, m_cachedInheritorID);
+        }
+
     protected:
         const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
 
@@ -130,6 +142,8 @@
         void finishCreation(ExecState*, NativeExecutable*, int length, const Identifier& name);
         void finishCreation(ExecState*, FunctionExecutable*, ScopeChainNode*);
 
+        Structure* cacheInheritorID(ExecState*);
+
         static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
         static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
         static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties);
@@ -152,6 +166,7 @@
 
         WriteBarrier<ExecutableBase> m_executable;
         WriteBarrier<ScopeChainNode> m_scopeChain;
+        WriteBarrier<Structure> m_cachedInheritorID;
     };
 
     inline bool JSValue::isFunction() const
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to