Commit b38285cd authored by barraclough@apple.com's avatar 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:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@95666 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent b57c3443
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
......@@ -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.
......
......@@ -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);
}
......
......@@ -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)
......
......@@ -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);
......
......@@ -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;
......
......@@ -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);
......
......@@ -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))));
......
......@@ -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));
......
......@@ -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)
{
......
......@@ -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;
......
......@@ -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;
......
......@@ -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();
......
......@@ -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)
......
......@@ -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);
......
......@@ -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
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment