+2008-10-17 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ - speed up transitions that resize the property storage a fair bit
+
+ ~3% speedup on v8 RayTrace benchmark, ~1% on DeltaBlue
+
+ * VM/CTI.cpp:
+ (JSC::resizePropertyStorage): renamed from transitionObject, and reduced to just resize
+ the object's property storage with one inline call.
+ (JSC::CTI::privateCompilePutByIdTransition): Use a separate function for property storage
+ resize, but still do all the rest of the work in assembly in that case, and pass the known
+ compile-time constants of old and new size rather than structureIDs, saving a bunch of
+ redundant memory access.
+ * kjs/JSObject.cpp:
+ (JSC::JSObject::allocatePropertyStorage): Just call the inline version.
+ * kjs/JSObject.h:
+ (JSC::JSObject::allocatePropertyStorageInline): Inline version of allocatePropertyStorage
+ * masm/X86Assembler.h:
+ (JSC::X86Assembler::):
+ (JSC::X86Assembler::pushl_i32): Add code to assmeble push of a constant; code originally by Cameron Zwarich.
+
2008-10-17 Cameron Zwarich <zwarich@apple.com>
Reviewed by Maciej Stachowiak.
extern "C" {
-static JSValue* transitionObject(StructureID* newStructureID, size_t cachedOffset, JSObject* baseObject, JSValue* value)
-{
- baseObject->transitionTo(newStructureID);
- baseObject->putDirectOffset(cachedOffset, value);
- return baseObject;
-}
+ static JSValue* resizePropertyStorage(JSObject* baseObject, size_t oldSize, size_t newSize)
+ {
+ baseObject->allocatePropertyStorageInline(oldSize, newSize);
+ return baseObject;
+ }
}
m_jit.link(successCases[i], m_jit.label());
X86Assembler::JmpSrc callTarget;
- // Fast case, don't need to do any heavy lifting, so don't bother making a call.
- if (!transitionWillNeedStorageRealloc(oldStructureID, newStructureID)) {
- // Assumes m_refCount can be decremented easily, refcount decrement is safe as
- // codeblock should ensure oldStructureID->m_refCount > 0
- m_jit.subl_i8m(1, reinterpret_cast<void*>(oldStructureID));
- m_jit.addl_i8m(1, reinterpret_cast<void*>(newStructureID));
- m_jit.movl_i32m(reinterpret_cast<uint32_t>(newStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
-
- // write the value
- m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
- m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
- } else {
- // Slow case transition -- we're going to need to quite a bit of work,
- // so just make a call
+
+ // emit a call only if storage realloc is needed
+ if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID)) {
m_jit.pushl_r(X86::edx);
- m_jit.pushl_r(X86::eax);
- m_jit.movl_i32r(cachedOffset, X86::eax);
- m_jit.pushl_r(X86::eax);
- m_jit.movl_i32r(reinterpret_cast<uint32_t>(newStructureID), X86::eax);
+ m_jit.pushl_i32(newStructureID->propertyStorageCapacity());
+ m_jit.pushl_i32(oldStructureID->propertyStorageCapacity());
m_jit.pushl_r(X86::eax);
callTarget = m_jit.emitCall();
- m_jit.addl_i32r(4 * sizeof(void*), X86::esp);
+ m_jit.addl_i32r(3 * sizeof(void*), X86::esp);
+ m_jit.popl_r(X86::edx);
}
+
+ // Assumes m_refCount can be decremented easily, refcount decrement is safe as
+ // codeblock should ensure oldStructureID->m_refCount > 0
+ m_jit.subl_i8m(1, reinterpret_cast<void*>(oldStructureID));
+ m_jit.addl_i8m(1, reinterpret_cast<void*>(newStructureID));
+ m_jit.movl_i32m(reinterpret_cast<uint32_t>(newStructureID), OBJECT_OFFSET(JSCell, m_structureID), X86::eax);
+
+ // write the value
+ m_jit.movl_mr(OBJECT_OFFSET(JSObject, m_propertyStorage), X86::eax, X86::eax);
+ m_jit.movl_rm(X86::edx, cachedOffset * sizeof(JSValue*), X86::eax);
+
m_jit.ret();
X86Assembler::JmpSrc failureJump;
X86Assembler::link(code, failureJump, reinterpret_cast<void*>(Machine::cti_op_put_by_id_fail));
if (transitionWillNeedStorageRealloc(oldStructureID, newStructureID))
- X86Assembler::link(code, callTarget, reinterpret_cast<void*>(transitionObject));
+ X86Assembler::link(code, callTarget, reinterpret_cast<void*>(resizePropertyStorage));
m_codeBlock->getStubInfo(returnAddress).stubRoutine = code;
virtual bool isNotAnObjectErrorStub() const { return false; }
void allocatePropertyStorage(size_t oldSize, size_t newSize);
+ void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
bool usingInlineStorage() const { return m_propertyStorage == m_inlineStorage; }
static const size_t inlineStorageCapacity = 2;
asCell()->put(exec, propertyName, value);
}
+ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
+{
+ ASSERT(newSize > oldSize);
+
+ JSValue** oldPropertStorage = m_propertyStorage;
+ m_propertyStorage = new JSValue*[newSize];
+
+ for (unsigned i = 0; i < oldSize; ++i)
+ m_propertyStorage[i] = oldPropertStorage[i];
+
+ if (oldPropertStorage != m_inlineStorage)
+ delete [] oldPropertStorage;
+}
+
} // namespace JSC
#endif // JSObject_h