+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
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;
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.
{
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;
}
{
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);
}
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)
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);
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);
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;
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);
// 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);
// 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))));
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);
// 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));
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)
{
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;
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;
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();
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;
}
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;
}
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)
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)
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;
}
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);
// The ObjectType value must come before any JSType that is a subclass of JSObject.
ObjectType = 10,
FinalObjectType = 11,
+ JSFunctionType = 12,
};
} // namespace JSC