Diff
Modified: trunk/Source/_javascript_Core/ChangeLog (90062 => 90063)
--- trunk/Source/_javascript_Core/ChangeLog 2011-06-29 23:42:03 UTC (rev 90062)
+++ trunk/Source/_javascript_Core/ChangeLog 2011-06-29 23:45:28 UTC (rev 90063)
@@ -1,3 +1,18 @@
+2011-06-29 Filip Pizlo <[email protected]>
+
+ Reviewed by Gavin Barraclough.
+
+ DFG JIT does not do put_by_id transition caching.
+ https://bugs.webkit.org/show_bug.cgi?id=63662
+
+ * dfg/DFGJITCodeGenerator.cpp:
+ (JSC::DFG::JITCodeGenerator::cachedPutById):
+ * dfg/DFGJITCompiler.h:
+ (JSC::DFG::JITCompiler::addPropertyAccess):
+ * dfg/DFGRepatch.cpp:
+ (JSC::DFG::testPrototype):
+ (JSC::DFG::tryCachePutByID):
+
2011-06-29 Geoffrey Garen <[email protected]>
Reviewed by Oliver Hunt.
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.cpp (90062 => 90063)
--- trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.cpp 2011-06-29 23:42:03 UTC (rev 90062)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCodeGenerator.cpp 2011-06-29 23:45:28 UTC (rev 90063)
@@ -370,12 +370,26 @@
void JITCodeGenerator::cachedPutById(GPRReg baseGPR, GPRReg valueGPR, GPRReg scratchGPR, unsigned identifierNumber, PutKind putKind, JITCompiler::Jump slowPathTarget)
{
+ GPRReg slowPathScratch = scratchGPR;
+
+ if (scratchGPR == baseGPR)
+ slowPathScratch = tryAllocate();
+
JITCompiler::DataLabelPtr structureToCompare;
- JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::Equal, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
+ JITCompiler::Jump structureCheck = m_jit.branchPtrWithPatch(JITCompiler::NotEqual, JITCompiler::Address(baseGPR, JSCell::structureOffset()), structureToCompare, JITCompiler::TrustedImmPtr(reinterpret_cast<void*>(-1)));
+ m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
+
+ JITCompiler::Jump done = m_jit.jump();
+
+ structureCheck.link(&m_jit);
+
if (slowPathTarget.isSet())
slowPathTarget.link(&m_jit);
+ JITCompiler::Label slowCase = m_jit.label();
+
silentSpillAllRegisters(InvalidGPRReg, baseGPR, valueGPR);
setupTwoStubArgs<GPRInfo::argumentGPR1, GPRInfo::argumentGPR2>(valueGPR, baseGPR);
m_jit.move(JITCompiler::ImmPtr(identifier(identifierNumber)), GPRInfo::argumentGPR3);
@@ -395,19 +409,19 @@
JITCompiler::Call functionCall = appendCallWithExceptionCheck(optimizedCall);
silentFillAllRegisters(InvalidGPRReg);
- JITCompiler::Jump handledByC = m_jit.jump();
- structureCheck.link(&m_jit);
+ done.link(&m_jit);
+ JITCompiler::Label doneLabel = m_jit.label();
- m_jit.loadPtr(JITCompiler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
- JITCompiler::DataLabel32 storeWithPatch = m_jit.storePtrWithAddressOffsetPatch(valueGPR, JITCompiler::Address(scratchGPR, 0));
-
int8_t checkImmToCall = static_cast<int8_t>(m_jit.differenceBetween(structureToCompare, functionCall));
int8_t callToCheck = static_cast<int8_t>(m_jit.differenceBetween(functionCall, structureCheck));
int8_t callToStore = static_cast<int8_t>(m_jit.differenceBetween(functionCall, storeWithPatch));
+ int8_t callToSlowCase = static_cast<int8_t>(m_jit.differenceBetween(functionCall, slowCase));
+ int8_t callToDone = static_cast<int8_t>(m_jit.differenceBetween(functionCall, doneLabel));
- handledByC.link(&m_jit);
+ m_jit.addPropertyAccess(functionCall, checkImmToCall, callToCheck, callToStore, callToSlowCase, callToDone, static_cast<int8_t>(baseGPR), static_cast<int8_t>(valueGPR), static_cast<int8_t>(slowPathScratch));
- m_jit.addPropertyAccess(functionCall, checkImmToCall, callToCheck, callToStore);
+ if (scratchGPR == baseGPR && slowPathScratch != InvalidGPRReg)
+ unlock(slowPathScratch);
}
#ifndef NDEBUG
Modified: trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h (90062 => 90063)
--- trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h 2011-06-29 23:42:03 UTC (rev 90062)
+++ trunk/Source/_javascript_Core/dfg/DFGJITCompiler.h 2011-06-29 23:45:28 UTC (rev 90063)
@@ -233,7 +233,7 @@
void clearSamplingFlag(int32_t flag);
#endif
- void addPropertyAccess(JITCompiler::Call functionCall, int16_t deltaCheckImmToCall, int16_t deltaCallToStructCheck, int16_t deltaCallToLoadOrStore, int16_t deltaCallToSlowCase = 0, int16_t deltaCallToDone = 0, int8_t baseGPR = 0, int8_t valueGPR = 0, int8_t scratchGPR = 0)
+ void addPropertyAccess(JITCompiler::Call functionCall, int16_t deltaCheckImmToCall, int16_t deltaCallToStructCheck, int16_t deltaCallToLoadOrStore, int16_t deltaCallToSlowCase, int16_t deltaCallToDone, int8_t baseGPR, int8_t valueGPR, int8_t scratchGPR)
{
m_propertyAccesses.append(PropertyAccessRecord(functionCall, deltaCheckImmToCall, deltaCallToStructCheck, deltaCallToLoadOrStore, deltaCallToSlowCase, deltaCallToDone, baseGPR, valueGPR, scratchGPR));
}
Modified: trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp (90062 => 90063)
--- trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp 2011-06-29 23:42:03 UTC (rev 90062)
+++ trunk/Source/_javascript_Core/dfg/DFGRepatch.cpp 2011-06-29 23:45:28 UTC (rev 90063)
@@ -30,6 +30,7 @@
#include "DFGJITCodeGenerator.h"
#include "LinkBuffer.h"
+#include "Operations.h"
#include "RepatchBuffer.h"
namespace JSC { namespace DFG {
@@ -250,6 +251,17 @@
return operationPutByIdNonStrict;
}
+static void testPrototype(MacroAssembler &stubJit, GPRReg scratchGPR, JSValue prototype, MacroAssembler::JumpList& failureCases)
+{
+ if (prototype.isNull())
+ return;
+
+ ASSERT(prototype.isCell());
+
+ stubJit.move(MacroAssembler::TrustedImmPtr(prototype.asCell()), scratchGPR);
+ failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(scratchGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(prototype.asCell()->structure())));
+}
+
static bool tryCachePutByID(ExecState* exec, JSValue baseValue, const Identifier&, const PutPropertySlot& slot, StructureStubInfo& stubInfo, PutKind putKind)
{
CodeBlock* codeBlock = exec->codeBlock();
@@ -259,6 +271,8 @@
return false;
JSCell* baseCell = baseValue.asCell();
Structure* structure = baseCell->structure();
+ Structure* oldStructure = structure->previousID();
+
if (!slot.isCacheable())
return false;
if (structure->isUncacheableDictionary())
@@ -266,9 +280,83 @@
// Optimize self access.
if (slot.base() == baseValue) {
- if (slot.type() == PutPropertySlot::NewProperty)
- return false;
+ if (slot.type() == PutPropertySlot::NewProperty) {
+ if (structure->isDictionary())
+ return false;
+
+ // skip optimizing the case where we need a realloc
+ if (oldStructure->propertyStorageCapacity() != structure->propertyStorageCapacity())
+ return false;
+
+ normalizePrototypeChain(exec, baseCell);
+
+ StructureChain* prototypeChain = structure->prototypeChain(exec);
+
+ GPRReg baseGPR = static_cast<GPRReg>(stubInfo.baseGPR);
+ GPRReg valueGPR = static_cast<GPRReg>(stubInfo.valueGPR);
+ GPRReg scratchGPR = static_cast<GPRReg>(stubInfo.u.unset.scratchGPR);
+ bool needToRestoreScratch = false;
+
+ ASSERT(scratchGPR != baseGPR);
+
+ MacroAssembler stubJit;
+
+ MacroAssembler::JumpList failureCases;
+
+ if (scratchGPR == InvalidGPRReg) {
+ scratchGPR = JITCodeGenerator::selectScratchGPR(baseGPR, valueGPR);
+ stubJit.push(scratchGPR);
+ needToRestoreScratch = true;
+ }
+
+ failureCases.append(stubJit.branchPtr(MacroAssembler::NotEqual, MacroAssembler::Address(baseGPR, JSCell::structureOffset()), MacroAssembler::TrustedImmPtr(oldStructure)));
+
+ testPrototype(stubJit, scratchGPR, oldStructure->storedPrototype(), failureCases);
+
+ if (putKind == NotDirect) {
+ for (WriteBarrier<Structure>* it = prototypeChain->head(); *it; ++it)
+ testPrototype(stubJit, scratchGPR, (*it)->storedPrototype(), failureCases);
+ }
+
+ stubJit.storePtr(MacroAssembler::TrustedImmPtr(structure), MacroAssembler::Address(baseGPR, JSCell::structureOffset()));
+ if (structure->isUsingInlineStorage())
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(baseGPR, JSObject::offsetOfInlineStorage() + slot.cachedOffset() * sizeof(JSValue)));
+ else {
+ stubJit.loadPtr(MacroAssembler::Address(baseGPR, JSObject::offsetOfPropertyStorage()), scratchGPR);
+ stubJit.storePtr(valueGPR, MacroAssembler::Address(scratchGPR, slot.cachedOffset() * sizeof(JSValue)));
+ }
+
+ MacroAssembler::Jump success;
+ MacroAssembler::Jump failure;
+
+ if (needToRestoreScratch) {
+ stubJit.pop(scratchGPR);
+ success = stubJit.jump();
+ failureCases.link(&stubJit);
+ stubJit.pop(scratchGPR);
+ failure = stubJit.jump();
+ } else
+ success = stubJit.jump();
+
+ LinkBuffer patchBuffer(*globalData, &stubJit, codeBlock->executablePool());
+ patchBuffer.link(success, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToDone));
+ if (needToRestoreScratch)
+ patchBuffer.link(failure, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase));
+ else
+ patchBuffer.link(failureCases, stubInfo.callReturnLocation.labelAtOffset(stubInfo.deltaCallToSlowCase));
+
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
+ stubInfo.stubRoutine = entryLabel;
+
+ CodeLocationLabel hotPathBegin = stubInfo.hotPathBegin;
+ RepatchBuffer repatchBuffer(codeBlock);
+ repatchBuffer.relink(stubInfo.callReturnLocation.jumpAtOffset(stubInfo.deltaCallToStructCheck), entryLabel);
+ repatchBuffer.relink(stubInfo.callReturnLocation, appropriatePutByIdFunction(slot, putKind));
+
+ return true;
+ }
+
dfgRepatchByIdSelfAccess(codeBlock, stubInfo, structure, slot.cachedOffset(), appropriatePutByIdFunction(slot, putKind), false);
stubInfo.initPutByIdReplace(*globalData, codeBlock->ownerExecutable(), structure);
return true;