Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (92497 => 92498)
--- trunk/Source/_javascript_Core/ChangeLog 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-08-05 20:03:19 UTC (rev 92498)
@@ -1,3 +1,39 @@
+2011-08-05 Oliver Hunt <[email protected]>
+
+ Inline allocation of function objects
+ https://bugs.webkit.org/show_bug.cgi?id=65779
+
+ Reviewed by Gavin Barraclough.
+
+ Inline allocation and initilisation of function objects
+ in generated code. This ended up being a 60-70% improvement
+ in function allocation performance. This improvement shows
+ up as a ~2% improvement in 32bit sunspider and V8, but is a
+ wash on 64-bit.
+
+ We currently don't inline the allocation of named function
+ expressions, as that requires being able to gc allocate a
+ variable object.
+
+ * jit/JIT.cpp:
+ (JSC::JIT::privateCompileSlowCases):
+ * jit/JIT.h:
+ (JSC::JIT::emitStoreCell):
+ * jit/JITInlineMethods.h:
+ (JSC::JIT::emitAllocateBasicJSObject):
+ (JSC::JIT::emitAllocateJSFinalObject):
+ (JSC::JIT::emitAllocateJSFunction):
+ * jit/JITOpcodes.cpp:
+ (JSC::JIT::emit_op_new_func):
+ (JSC::JIT::emitSlow_op_new_func):
+ (JSC::JIT::emit_op_new_func_exp):
+ (JSC::JIT::emitSlow_op_new_func_exp):
+ * jit/JITOpcodes32_64.cpp:
+ Removed duplicate implementation of op_new_func and op_new_func_exp
+ * runtime/JSFunction.h:
+ (JSC::JSFunction::offsetOfScopeChain):
+ (JSC::JSFunction::offsetOfExecutable):
+
2011-08-04 David Levin <[email protected]>
CStringBuffer should have thread safety checks turned on.
Modified: trunk/Source/_javascript_Core/jit/JIT.cpp (92497 => 92498)
--- trunk/Source/_javascript_Core/jit/JIT.cpp 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/jit/JIT.cpp 2011-08-05 20:03:19 UTC (rev 92498)
@@ -431,6 +431,8 @@
#endif
DEFINE_SLOWCASE_OP(op_neq)
DEFINE_SLOWCASE_OP(op_new_object)
+ DEFINE_SLOWCASE_OP(op_new_func)
+ DEFINE_SLOWCASE_OP(op_new_func_exp)
DEFINE_SLOWCASE_OP(op_not)
DEFINE_SLOWCASE_OP(op_nstricteq)
DEFINE_SLOWCASE_OP(op_post_dec)
Modified: trunk/Source/_javascript_Core/jit/JIT.h (92497 => 92498)
--- trunk/Source/_javascript_Core/jit/JIT.h 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/jit/JIT.h 2011-08-05 20:03:19 UTC (rev 92498)
@@ -49,6 +49,7 @@
namespace JSC {
class CodeBlock;
+ class FunctionExecutable;
class JIT;
class JSPropertyNameIterator;
class Interpreter;
@@ -299,10 +300,11 @@
void testPrototype(JSValue, JumpList& failureCases);
void emitWriteBarrier(RegisterID owner, RegisterID scratch);
-
- template<typename T>
- void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch);
+ template<typename ClassType, typename StructureType> void emitAllocateBasicJSObject(StructureType, void* vtable, RegisterID result, RegisterID storagePtr);
+ template<typename T> void emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID storagePtr);
+ void emitAllocateJSFunction(FunctionExecutable*, RegisterID scopeChain, RegisterID result, RegisterID storagePtr);
+
#if USE(JSVALUE32_64)
bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant);
@@ -528,6 +530,10 @@
void emitGetVirtualRegister(int src, RegisterID dst);
void emitGetVirtualRegisters(int src1, RegisterID dst1, int src2, RegisterID dst2);
void emitPutVirtualRegister(unsigned dst, RegisterID from = regT0);
+ void emitStoreCell(unsigned dst, RegisterID payload, bool /* only used in JSValue32_64 */ = false)
+ {
+ emitPutVirtualRegister(dst, payload);
+ }
int32_t getConstantOperandImmediateInt(unsigned src);
@@ -906,6 +912,8 @@
void emitSlow_op_to_jsnumber(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_to_primitive(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitSlow_op_urshift(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_new_func(Instruction*, Vector<SlowCaseEntry>::iterator&);
+ void emitSlow_op_new_func_exp(Instruction*, Vector<SlowCaseEntry>::iterator&);
void emitRightShift(Instruction*, bool isUnsigned);
Modified: trunk/Source/_javascript_Core/jit/JITInlineMethods.h (92497 => 92498)
--- trunk/Source/_javascript_Core/jit/JITInlineMethods.h 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/jit/JITInlineMethods.h 2011-08-05 20:03:19 UTC (rev 92498)
@@ -374,33 +374,64 @@
return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isString() && asString(getConstantOperand(src).asCell())->length() == 1;
}
-template<typename T>
-inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
+template <typename ClassType, typename StructureType> inline void JIT::emitAllocateBasicJSObject(StructureType structure, void* vtable, RegisterID result, RegisterID storagePtr)
{
- NewSpace::SizeClass* sizeClass = &m_globalData->heap.sizeClassFor(sizeof(JSFinalObject));
+ NewSpace::SizeClass* sizeClass = &m_globalData->heap.sizeClassFor(sizeof(ClassType));
loadPtr(&sizeClass->firstFreeCell, result);
addSlowCase(branchTestPtr(Zero, result));
-
+
// remove the object from the free list
- loadPtr(Address(result), scratch);
- storePtr(scratch, &sizeClass->firstFreeCell);
-
+ loadPtr(Address(result), storagePtr);
+ storePtr(storagePtr, &sizeClass->firstFreeCell);
+
// initialize the object's vtable
- storePtr(ImmPtr(m_globalData->jsFinalObjectVPtr), Address(result));
-
+ storePtr(TrustedImmPtr(vtable), Address(result));
+
// initialize the object's structure
storePtr(structure, Address(result, JSCell::structureOffset()));
-
+
// initialize the inheritor ID
- storePtr(ImmPtr(0), Address(result, JSObject::offsetOfInheritorID()));
-
+ storePtr(TrustedImmPtr(0), Address(result, JSObject::offsetOfInheritorID()));
+
// initialize the object's property storage pointer
- addPtr(Imm32(sizeof(JSObject)), result, scratch);
- storePtr(scratch, Address(result, JSObject::offsetOfPropertyStorage()));
+ addPtr(TrustedImm32(sizeof(JSObject)), result, storagePtr);
+ storePtr(storagePtr, Address(result, ClassType::offsetOfPropertyStorage()));
}
+template <typename T> inline void JIT::emitAllocateJSFinalObject(T structure, RegisterID result, RegisterID scratch)
+{
+ emitAllocateBasicJSObject<JSFinalObject>(structure, m_globalData->jsFinalObjectVPtr, result, scratch);
+}
+
+inline void JIT::emitAllocateJSFunction(FunctionExecutable* executable, RegisterID scopeChain, RegisterID result, RegisterID storagePtr)
+{
+ emitAllocateBasicJSObject<JSFunction>(TrustedImmPtr(m_codeBlock->globalObject()->namedFunctionStructure()), m_globalData->jsFunctionVPtr, result, storagePtr);
+
+ // store the function's scope chain
+ storePtr(scopeChain, Address(result, JSFunction::offsetOfScopeChain()));
+
+ // store the function's executable member
+ storePtr(TrustedImmPtr(executable), Address(result, JSFunction::offsetOfExecutable()));
+
+
+ // store the function's global object
+ int globalObjectOffset = sizeof(JSValue) * JSFunction::GlobalObjectSlot;
+ storePtr(TrustedImmPtr(m_codeBlock->globalObject()), Address(regT1, globalObjectOffset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
#if USE(JSVALUE32_64)
+ store32(TrustedImm32(JSValue::CellTag), Address(regT1, globalObjectOffset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+#endif
+ // store the function's name
+ ASSERT(executable->nameValue());
+ int functionNameOffset = sizeof(JSValue) * m_codeBlock->globalObject()->functionNameOffset();
+ storePtr(TrustedImmPtr(executable->nameValue()), Address(regT1, functionNameOffset + OBJECT_OFFSETOF(JSValue, u.asBits.payload)));
+#if USE(JSVALUE32_64)
+ store32(TrustedImm32(JSValue::CellTag), Address(regT1, functionNameOffset + OBJECT_OFFSETOF(JSValue, u.asBits.tag)));
+#endif
+}
+
+#if USE(JSVALUE32_64)
+
inline void JIT::emitLoadTag(unsigned index, RegisterID tag)
{
RegisterID mappedTag;
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes.cpp (92497 => 92498)
--- trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes.cpp 2011-08-05 20:03:19 UTC (rev 92498)
@@ -725,13 +725,6 @@
stubCall.call(currentInstruction[2].u.operand);
}
-void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
-{
- JITStubCall stubCall(this, cti_op_new_func_exp);
- stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
- stubCall.call(currentInstruction[1].u.operand);
-}
-
void JIT::emit_op_jtrue(Instruction* currentInstruction)
{
unsigned target = currentInstruction[2].u.operand;
@@ -1621,13 +1614,61 @@
lazyJump = branchTestPtr(NonZero, addressFor(dst));
#endif
}
+
+ FunctionExecutable* executable = m_codeBlock->functionDecl(currentInstruction[2].u.operand);
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
+ emitAllocateJSFunction(executable, regT2, regT0, regT1);
+
+ emitStoreCell(dst, regT0);
+
+ if (currentInstruction[3].u.operand) {
+#if USE(JSVALUE32_64)
+ unmap();
+#else
+ killLastResultRegister();
+#endif
+ lazyJump.link(this);
+ }
+}
+
+void JIT::emitSlow_op_new_func(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ linkSlowCase(iter);
JITStubCall stubCall(this, cti_op_new_func);
stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand)));
stubCall.call(currentInstruction[1].u.operand);
- if (currentInstruction[3].u.operand)
- lazyJump.link(this);
}
+void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
+{
+ FunctionExecutable* executable = m_codeBlock->functionExpr(currentInstruction[2].u.operand);
+
+ // We only inline the allocation of a anonymous function expressions
+ // If we want to be able to allocate a named function _expression_, we would
+ // need to be able to do inline allocation of a JSStaticScopeObject.
+ if (executable->name().isNull()) {
+ emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT2);
+ emitAllocateJSFunction(executable, regT2, regT0, regT1);
+ emitStoreCell(currentInstruction[1].u.operand, regT0);
+ return;
+ }
+
+ JITStubCall stubCall(this, cti_op_new_func_exp);
+ stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
+void JIT::emitSlow_op_new_func_exp(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ FunctionExecutable* executable = m_codeBlock->functionExpr(currentInstruction[2].u.operand);
+ if (!executable->name().isNull())
+ return;
+ linkSlowCase(iter);
+ JITStubCall stubCall(this, cti_op_new_func_exp);
+ stubCall.addArgument(TrustedImmPtr(executable));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
void JIT::emit_op_new_array(Instruction* currentInstruction)
{
JITStubCall stubCall(this, cti_op_new_array);
Modified: trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp (92497 => 92498)
--- trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/jit/JITOpcodes32_64.cpp 2011-08-05 20:03:19 UTC (rev 92498)
@@ -1118,13 +1118,6 @@
stubCall.call(currentInstruction[2].u.operand);
}
-void JIT::emit_op_new_func_exp(Instruction* currentInstruction)
-{
- JITStubCall stubCall(this, cti_op_new_func_exp);
- stubCall.addArgument(TrustedImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand)));
- stubCall.call(currentInstruction[1].u.operand);
-}
-
void JIT::emit_op_throw(Instruction* currentInstruction)
{
unsigned exception = currentInstruction[1].u.operand;
Modified: trunk/Source/_javascript_Core/runtime/JSFunction.h (92497 => 92498)
--- trunk/Source/_javascript_Core/runtime/JSFunction.h 2011-08-05 19:55:49 UTC (rev 92497)
+++ trunk/Source/_javascript_Core/runtime/JSFunction.h 2011-08-05 20:03:19 UTC (rev 92498)
@@ -110,6 +110,16 @@
virtual ConstructType getConstructData(ConstructData&);
virtual CallType getCallData(CallData&);
+ static inline size_t offsetOfScopeChain()
+ {
+ return OBJECT_OFFSETOF(JSFunction, m_scopeChain);
+ }
+
+ static inline size_t offsetOfExecutable()
+ {
+ return OBJECT_OFFSETOF(JSFunction, m_executable);
+ }
+
protected:
const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;