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):
git-svn-id: http://svn.webkit.org/repository/webkit/trunk@92498 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/ChangeLog b/Source/JavaScriptCore/ChangeLog
index 774fd32..8f81bf0 100644
--- a/Source/JavaScriptCore/ChangeLog
+++ b/Source/JavaScriptCore/ChangeLog
@@ -1,3 +1,39 @@
+2011-08-05 Oliver Hunt <oliver@apple.com>
+
+ 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 <levin@chromium.org>
CStringBuffer should have thread safety checks turned on.
diff --git a/Source/JavaScriptCore/jit/JIT.cpp b/Source/JavaScriptCore/jit/JIT.cpp
index c60cc57..a454167 100644
--- a/Source/JavaScriptCore/jit/JIT.cpp
+++ b/Source/JavaScriptCore/jit/JIT.cpp
@@ -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)
diff --git a/Source/JavaScriptCore/jit/JIT.h b/Source/JavaScriptCore/jit/JIT.h
index 4ed2d38..85c4b0a 100644
--- a/Source/JavaScriptCore/jit/JIT.h
+++ b/Source/JavaScriptCore/jit/JIT.h
@@ -49,6 +49,7 @@
namespace JSC {
class CodeBlock;
+ class FunctionExecutable;
class JIT;
class JSPropertyNameIterator;
class Interpreter;
@@ -299,9 +300,10 @@
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);
diff --git a/Source/JavaScriptCore/jit/JITInlineMethods.h b/Source/JavaScriptCore/jit/JITInlineMethods.h
index 724de3a..7445994 100644
--- a/Source/JavaScriptCore/jit/JITInlineMethods.h
+++ b/Source/JavaScriptCore/jit/JITInlineMethods.h
@@ -374,29 +374,60 @@
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)
diff --git a/Source/JavaScriptCore/jit/JITOpcodes.cpp b/Source/JavaScriptCore/jit/JITOpcodes.cpp
index b0d0cf7..84ad192 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes.cpp
@@ -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,11 +1614,59 @@
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)
diff --git a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
index 713c6f9..abdb6f5 100644
--- a/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
+++ b/Source/JavaScriptCore/jit/JITOpcodes32_64.cpp
@@ -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;
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index cdfad94..006a7db 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -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;