Replace jsFunctionVPtr compares with a type check on the Structure.
authorbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Sep 2011 19:59:39 +0000 (19:59 +0000)
committerbarraclough@apple.com <barraclough@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 21 Sep 2011 19:59:39 +0000 (19:59 +0000)
https://bugs.webkit.org/show_bug.cgi?id=68557

Reviewed by Oliver Hunt.

This will permit calls to still optimize to subclasses of JSFunction
that have the correct type (but a different C++ vptr).

This patch stops passing the globalData into numerous functions.

* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGGraph.h:
(JSC::DFG::Graph::isFunctionConstant):
(JSC::DFG::Graph::valueOfFunctionConstant):
* dfg/DFGJITCompiler.h:
(JSC::DFG::JITCompiler::isFunctionConstant):
(JSC::DFG::JITCompiler::valueOfFunctionConstant):
* dfg/DFGOperations.cpp:
* interpreter/Interpreter.cpp:
(JSC::Interpreter::privateExecute):
* jit/JIT.h:
* jit/JITCall.cpp:
(JSC::JIT::compileOpCallVarargs):
(JSC::JIT::compileOpCallSlowCase):
* jit/JITCall32_64.cpp:
(JSC::JIT::compileOpCallVarargs):
(JSC::JIT::compileOpCallSlowCase):
* jit/JITInlineMethods.h:
(JSC::JIT::emitJumpIfNotType):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
* runtime/Executable.h:
(JSC::isHostFunction):
* runtime/JSFunction.h:
(JSC::JSFunction::createStructure):
* runtime/JSObject.cpp:
(JSC::JSObject::put):
(JSC::JSObject::putWithAttributes):
* runtime/JSObject.h:
(JSC::getJSFunction):
(JSC::JSObject::putDirect):
(JSC::JSObject::putDirectWithoutTransition):
* runtime/JSType.h:

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

16 files changed:
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/dfg/DFGByteCodeParser.cpp
Source/JavaScriptCore/dfg/DFGGraph.h
Source/JavaScriptCore/dfg/DFGJITCompiler.h
Source/JavaScriptCore/dfg/DFGOperations.cpp
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/jit/JIT.h
Source/JavaScriptCore/jit/JITCall.cpp
Source/JavaScriptCore/jit/JITCall32_64.cpp
Source/JavaScriptCore/jit/JITInlineMethods.h
Source/JavaScriptCore/jit/JITStubs.cpp
Source/JavaScriptCore/runtime/Executable.h
Source/JavaScriptCore/runtime/JSFunction.h
Source/JavaScriptCore/runtime/JSObject.cpp
Source/JavaScriptCore/runtime/JSObject.h
Source/JavaScriptCore/runtime/JSType.h

index 4e472ce..772f4dc 100644 (file)
@@ -1,3 +1,50 @@
+2011-09-21  Gavin Barraclough  <barraclough@apple.com>
+
+        Replace jsFunctionVPtr compares with a type check on the Structure.
+        https://bugs.webkit.org/show_bug.cgi?id=68557
+
+        Reviewed by Oliver Hunt.
+
+        This will permit calls to still optimize to subclasses of JSFunction
+        that have the correct type (but a different C++ vptr).
+
+        This patch stops passing the globalData into numerous functions.
+
+        * dfg/DFGByteCodeParser.cpp:
+        (JSC::DFG::ByteCodeParser::parseBlock):
+        * dfg/DFGGraph.h:
+        (JSC::DFG::Graph::isFunctionConstant):
+        (JSC::DFG::Graph::valueOfFunctionConstant):
+        * dfg/DFGJITCompiler.h:
+        (JSC::DFG::JITCompiler::isFunctionConstant):
+        (JSC::DFG::JITCompiler::valueOfFunctionConstant):
+        * dfg/DFGOperations.cpp:
+        * interpreter/Interpreter.cpp:
+        (JSC::Interpreter::privateExecute):
+        * jit/JIT.h:
+        * jit/JITCall.cpp:
+        (JSC::JIT::compileOpCallVarargs):
+        (JSC::JIT::compileOpCallSlowCase):
+        * jit/JITCall32_64.cpp:
+        (JSC::JIT::compileOpCallVarargs):
+        (JSC::JIT::compileOpCallSlowCase):
+        * jit/JITInlineMethods.h:
+        (JSC::JIT::emitJumpIfNotType):
+        * jit/JITStubs.cpp:
+        (JSC::DEFINE_STUB_FUNCTION):
+        * runtime/Executable.h:
+        (JSC::isHostFunction):
+        * runtime/JSFunction.h:
+        (JSC::JSFunction::createStructure):
+        * runtime/JSObject.cpp:
+        (JSC::JSObject::put):
+        (JSC::JSObject::putWithAttributes):
+        * runtime/JSObject.h:
+        (JSC::getJSFunction):
+        (JSC::JSObject::putDirect):
+        (JSC::JSObject::putDirectWithoutTransition):
+        * runtime/JSType.h:
+
 2011-09-21  Geoffrey Garen  <ggaren@apple.com>
 
         Removed WTFTHREADDATA_MULTITHREADED, making it always true
index cc49177..2d8b195 100644 (file)
@@ -1305,7 +1305,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
             
         case op_call: {
             NodeIndex callTarget = get(currentInstruction[1].u.operand);
-            if (m_graph.isFunctionConstant(m_codeBlock, *m_globalData, callTarget)) {
+            if (m_graph.isFunctionConstant(m_codeBlock, callTarget)) {
                 int argCount = currentInstruction[2].u.operand;
                 int registerOffset = currentInstruction[3].u.operand;
                 int firstArg = registerOffset - argCount - RegisterFile::CallFrameHeaderSize;
@@ -1320,7 +1320,7 @@ bool ByteCodeParser::parseBlock(unsigned limit)
                     usesResult = true;
                 }
                 
-                DFG::Intrinsic intrinsic = m_graph.valueOfFunctionConstant(m_codeBlock, *m_globalData, callTarget)->executable()->intrinsic();
+                DFG::Intrinsic intrinsic = m_graph.valueOfFunctionConstant(m_codeBlock, callTarget)->executable()->intrinsic();
                 
                 if (handleIntrinsic(usesResult, resultOperand, intrinsic, firstArg, lastArg)) {
                     // NEXT_OPCODE() has to be inside braces.
index 7bf0036..d69d671 100644 (file)
@@ -271,11 +271,11 @@ public:
     {
         return at(nodeIndex).isBooleanConstant(codeBlock);
     }
-    bool isFunctionConstant(CodeBlock* codeBlock, JSGlobalData& globalData, NodeIndex nodeIndex)
+    bool isFunctionConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
     {
         if (!isJSConstant(nodeIndex))
             return false;
-        if (!getJSFunction(globalData, valueOfJSConstant(codeBlock, nodeIndex)))
+        if (!getJSFunction(valueOfJSConstant(codeBlock, nodeIndex)))
             return false;
         return true;
     }
@@ -298,9 +298,9 @@ public:
     {
         return valueOfJSConstantNode(codeBlock, nodeIndex).getBoolean();
     }
-    JSFunction* valueOfFunctionConstant(CodeBlock* codeBlock, JSGlobalData& globalData, NodeIndex nodeIndex)
+    JSFunction* valueOfFunctionConstant(CodeBlock* codeBlock, NodeIndex nodeIndex)
     {
-        JSCell* function = getJSFunction(globalData, valueOfJSConstant(codeBlock, nodeIndex));
+        JSCell* function = getJSFunction(valueOfJSConstant(codeBlock, nodeIndex));
         ASSERT(function);
         return asFunction(function);
     }
index e8db501..c6e1d36 100644 (file)
@@ -251,13 +251,13 @@ public:
     bool isDoubleConstant(NodeIndex nodeIndex) { return graph().isDoubleConstant(codeBlock(), nodeIndex); }
     bool isNumberConstant(NodeIndex nodeIndex) { return graph().isNumberConstant(codeBlock(), nodeIndex); }
     bool isBooleanConstant(NodeIndex nodeIndex) { return graph().isBooleanConstant(codeBlock(), nodeIndex); }
-    bool isFunctionConstant(NodeIndex nodeIndex) { return graph().isFunctionConstant(codeBlock(), *globalData(), nodeIndex); }
+    bool isFunctionConstant(NodeIndex nodeIndex) { return graph().isFunctionConstant(codeBlock(), nodeIndex); }
     // Helper methods get constant values from nodes.
     JSValue valueOfJSConstant(NodeIndex nodeIndex) { return graph().valueOfJSConstant(codeBlock(), nodeIndex); }
     int32_t valueOfInt32Constant(NodeIndex nodeIndex) { return graph().valueOfInt32Constant(codeBlock(), nodeIndex); }
     double valueOfNumberConstant(NodeIndex nodeIndex) { return graph().valueOfNumberConstant(codeBlock(), nodeIndex); }
     bool valueOfBooleanConstant(NodeIndex nodeIndex) { return graph().valueOfBooleanConstant(codeBlock(), nodeIndex); }
-    JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) { return graph().valueOfFunctionConstant(codeBlock(), *globalData(), nodeIndex); }
+    JSFunction* valueOfFunctionConstant(NodeIndex nodeIndex) { return graph().valueOfFunctionConstant(codeBlock(), nodeIndex); }
 
     // These methods JIT generate dynamic, debug-only checks - akin to ASSERTs.
 #if ENABLE(DFG_JIT_ASSERT)
index 2d72b78..4ee86bc 100644 (file)
@@ -519,7 +519,7 @@ inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, Code
     ExecState* exec = execCallee->callerFrame();
     JSGlobalData* globalData = &exec->globalData();
     JSValue calleeAsValue = execCallee->calleeAsValue();
-    JSCell* calleeAsFunctionCell = getJSFunction(*globalData, calleeAsValue);
+    JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
     if (!calleeAsFunctionCell)
         return handleHostCall(execCallee, calleeAsValue, kind);
     JSFunction* callee = asFunction(calleeAsFunctionCell);
@@ -568,9 +568,8 @@ void* operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddre
 inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
 {
     ExecState* exec = execCallee->callerFrame();
-    JSGlobalData* globalData = &exec->globalData();
     JSValue calleeAsValue = execCallee->calleeAsValue();
-    JSCell* calleeAsFunctionCell = getJSFunction(*globalData, calleeAsValue);
+    JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
     if (UNLIKELY(!calleeAsFunctionCell))
         return handleHostCall(execCallee, calleeAsValue, kind);
     
index b32a010..9f0aa30 100644 (file)
@@ -4169,7 +4169,7 @@ skip_id_custom_self:
         ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsFullScopeChain() || callFrame->r(codeBlock->activationRegister()).jsValue());
         JSValue funcVal = callFrame->r(func).jsValue();
 
-        if (isHostFunction(callFrame->globalData(), funcVal, globalFuncEval)) {
+        if (isHostFunction(funcVal, globalFuncEval)) {
             Register* newCallFrame = callFrame->registers() + registerOffset;
             Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
 
index 13ee57a..0761811 100644 (file)
@@ -312,6 +312,7 @@ namespace JSC {
         void emitLoadDouble(unsigned index, FPRegisterID value);
         void emitLoadInt32ToDouble(unsigned index, FPRegisterID value);
         Jump emitJumpIfNotObject(RegisterID structureReg);
+        Jump emitJumpIfNotType(RegisterID baseReg, RegisterID scratchReg, JSType);
 
         void testPrototype(JSValue, JumpList& failureCases);
 
index 50b8d1c..7f7fcd5 100644 (file)
@@ -75,7 +75,7 @@ void JIT::compileOpCallVarargs(Instruction* instruction)
 
     // Check for JSFunctions.
     emitJumpSlowCaseIfNotJSCell(regT0);
-    addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
+    addSlowCase(emitJumpIfNotType(regT0, regT3, JSFunctionType));
 
     // Speculatively roll the callframe, assuming argCount will match the arity.
     mul32(TrustedImm32(sizeof(Register)), regT2, regT2);
@@ -171,7 +171,7 @@ void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>:
 
     // Fast check for JS function.
     Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0);
-    Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
+    Jump callLinkFailNotJSFunction = emitJumpIfNotType(regT0, regT3, JSFunctionType);
 
     // Speculatively roll the callframe, assuming argCount will match the arity.
     storePtr(callFrameRegister, Address(callFrameRegister, (RegisterFile::CallerFrame + registerOffset) * static_cast<int>(sizeof(Register))));
index 0ca2e0b..ae4630b 100644 (file)
@@ -72,7 +72,7 @@ void JIT::compileOpCallVarargs(Instruction* instruction)
     addPtr(Imm32(registerOffset), regT2, regT3); // registerOffset
 
     emitJumpSlowCaseIfNotJSCell(callee, regT1);
-    addSlowCase(branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr)));
+    addSlowCase(emitJumpIfNotType(regT0, regT1, JSFunctionType));
 
     // Speculatively roll the callframe, assuming argCount will match the arity.
     mul32(TrustedImm32(sizeof(Register)), regT3, regT3);
@@ -256,7 +256,7 @@ void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>:
 
     // Fast check for JS function.
     Jump callLinkFailNotObject = branch32(NotEqual, regT1, TrustedImm32(JSValue::CellTag));
-    Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), TrustedImmPtr(m_globalData->jsFunctionVPtr));
+    Jump callLinkFailNotJSFunction = emitJumpIfNotType(regT0, regT1, JSFunctionType);
 
     // Speculatively roll the callframe, assuming argCount will match the arity.
     store32(TrustedImm32(JSValue::CellTag), tagFor(RegisterFile::CallerFrame + registerOffset, callFrameRegister));
index 7ef6b29..bee36c4 100644 (file)
@@ -326,6 +326,12 @@ ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotObject(RegisterID structureReg)
     return branch8(Below, Address(structureReg, Structure::typeInfoTypeOffset()), TrustedImm32(ObjectType));
 }
 
+ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotType(RegisterID baseReg, RegisterID scratchReg, JSType type)
+{
+    loadPtr(Address(baseReg, JSCell::structureOffset()), scratchReg);
+    return branch8(NotEqual, Address(scratchReg, Structure::typeInfoTypeOffset()), TrustedImm32(type));
+}
+
 #if ENABLE(SAMPLING_FLAGS)
 ALWAYS_INLINE void JIT::setSamplingFlag(int32_t flag)
 {
index 18e97ef..d0bf758 100644 (file)
@@ -3389,7 +3389,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
     int registerOffset = stackFrame.args[1].int32();
     int argCount = stackFrame.args[2].int32();
 
-    if (!isHostFunction(callFrame->globalData(), funcVal, globalFuncEval))
+    if (!isHostFunction(funcVal, globalFuncEval))
         return JSValue::encode(JSValue());
 
     Register* newCallFrame = callFrame->registers() + registerOffset;
index 07676ae..43a6333 100644 (file)
@@ -620,9 +620,9 @@ namespace JSC {
         return static_cast<NativeExecutable*>(m_executable.get())->function();
     }
 
-    inline bool isHostFunction(JSGlobalData& globalData, JSValue value, NativeFunction nativeFunction)
+    inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
     {
-        JSFunction* function = static_cast<JSFunction*>(getJSFunction(globalData, value));
+        JSFunction* function = static_cast<JSFunction*>(getJSFunction(value));
         if (!function || !function->isHostFunction())
             return false;
         return function->nativeFunction() == nativeFunction;
index 6e47733..67a0ac9 100644 (file)
@@ -119,7 +119,7 @@ namespace JSC {
         static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) 
         {
             ASSERT(globalObject);
-            return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info); 
+            return Structure::create(globalData, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info); 
         }
 
         NativeFunction nativeFunction();
index 070a53e..523721c 100644 (file)
@@ -128,7 +128,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu
     for (JSObject* obj = this; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
         prototype = obj->prototype();
         if (prototype.isNull()) {
-            if (!putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(globalData, value)) && slot.isStrictMode())
+            if (!putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(value)) && slot.isStrictMode())
                 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
             return;
         }
@@ -171,7 +171,7 @@ void JSObject::put(ExecState* exec, const Identifier& propertyName, JSValue valu
             break;
     }
     
-    if (!putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(globalData, value)) && slot.isStrictMode())
+    if (!putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(value)) && slot.isStrictMode())
         throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
     return;
 }
@@ -184,13 +184,13 @@ void JSObject::put(ExecState* exec, unsigned propertyName, JSValue value)
 
 void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
 {
-    putDirectInternal(*globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(*globalData, value));
+    putDirectInternal(*globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(value));
 }
 
 void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
     PutPropertySlot slot;
-    putDirectInternal(*globalData, propertyName, value, attributes, true, slot, getJSFunction(*globalData, value));
+    putDirectInternal(*globalData, propertyName, value, attributes, true, slot, getJSFunction(value));
 }
 
 void JSObject::putWithAttributes(JSGlobalData* globalData, unsigned propertyName, JSValue value, unsigned attributes)
@@ -201,14 +201,14 @@ void JSObject::putWithAttributes(JSGlobalData* globalData, unsigned propertyName
 void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
 {
     JSGlobalData& globalData = exec->globalData();
-    putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
+    putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(value));
 }
 
 void JSObject::putWithAttributes(ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
     PutPropertySlot slot;
     JSGlobalData& globalData = exec->globalData();
-    putDirectInternal(globalData, propertyName, value, attributes, true, slot, getJSFunction(globalData, value));
+    putDirectInternal(globalData, propertyName, value, attributes, true, slot, getJSFunction(value));
 }
 
 void JSObject::putWithAttributes(ExecState* exec, unsigned propertyName, JSValue value, unsigned attributes)
index 513590c..052b19e 100644 (file)
@@ -39,9 +39,9 @@
 
 namespace JSC {
 
-    inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
+    inline JSCell* getJSFunction(JSValue value)
     {
-        if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
+        if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType))
             return value.asCell();
         return 0;
     }
@@ -702,24 +702,24 @@ inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& prop
     ASSERT(value);
     ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
 
-    return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
+    return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(value));
 }
 
 inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
     PutPropertySlot slot;
-    putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
+    putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(value));
 }
 
 inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
 {
-    return putDirectInternal(globalData, propertyName, value, 0, false, slot, getJSFunction(globalData, value));
+    return putDirectInternal(globalData, propertyName, value, 0, false, slot, getJSFunction(value));
 }
 
 inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
 {
     size_t currentCapacity = structure()->propertyStorageCapacity();
-    size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(globalData, value));
+    size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
     if (currentCapacity != structure()->propertyStorageCapacity())
         allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
     putDirectOffset(globalData, offset, value);
index f99e3f1..2e186dd 100644 (file)
@@ -40,6 +40,7 @@ enum JSType {
     // The ObjectType value must come before any JSType that is a subclass of JSObject.
     ObjectType          = 10,
     FinalObjectType     = 11,
+    JSFunctionType      = 12,
 };
 
 } // namespace JSC