summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/jit/JITPropertyAccess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/jit/JITPropertyAccess.cpp')
-rw-r--r--JavaScriptCore/jit/JITPropertyAccess.cpp587
1 files changed, 350 insertions, 237 deletions
diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp
index ce90ee4..3a6f9b3 100644
--- a/JavaScriptCore/jit/JITPropertyAccess.cpp
+++ b/JavaScriptCore/jit/JITPropertyAccess.cpp
@@ -30,6 +30,7 @@
#include "CodeBlock.h"
#include "JITInlineMethods.h"
+#include "JITStubCall.h"
#include "JSArray.h"
#include "JSFunction.h"
#include "Interpreter.h"
@@ -44,59 +45,240 @@ using namespace std;
namespace JSC {
+void JIT::emit_op_get_by_val(Instruction* currentInstruction)
+{
+ emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1);
+ emitJumpSlowCaseIfNotImmediateInteger(regT1);
+#if USE(ALTERNATE_JSIMMEDIATE)
+ // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter.
+ // We check the value as if it was a uint32 against the m_fastAccessCutoff - which will always fail if
+ // number was signed since m_fastAccessCutoff is always less than intmax (since the total allocation
+ // size is always less than 4Gb). As such zero extending wil have been correct (and extending the value
+ // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign
+ // extending since it makes it easier to re-tag the value in the slow case.
+ zeroExtend32ToPtr(regT1, regT1);
+#else
+ emitFastArithImmToInt(regT1);
+#endif
+ emitJumpSlowCaseIfNotJSCell(regT0);
+ addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
+
+ // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff
+ loadPtr(Address(regT0, FIELD_OFFSET(JSArray, m_storage)), regT2);
+ addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, FIELD_OFFSET(JSArray, m_fastAccessCutoff))));
+
+ // Get the value from the vector
+ loadPtr(BaseIndex(regT2, regT1, ScalePtr, FIELD_OFFSET(ArrayStorage, m_vector[0])), regT0);
+ emitPutVirtualRegister(currentInstruction[1].u.operand);
+}
+
+void JIT::emit_op_put_by_val(Instruction* currentInstruction)
+{
+ emitGetVirtualRegisters(currentInstruction[1].u.operand, regT0, currentInstruction[2].u.operand, regT1);
+ emitJumpSlowCaseIfNotImmediateInteger(regT1);
+#if USE(ALTERNATE_JSIMMEDIATE)
+ // See comment in op_get_by_val.
+ zeroExtend32ToPtr(regT1, regT1);
+#else
+ emitFastArithImmToInt(regT1);
+#endif
+ emitJumpSlowCaseIfNotJSCell(regT0);
+ addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)));
+
+ // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff
+ loadPtr(Address(regT0, FIELD_OFFSET(JSArray, m_storage)), regT2);
+ Jump inFastVector = branch32(Below, regT1, Address(regT0, FIELD_OFFSET(JSArray, m_fastAccessCutoff)));
+ // No; oh well, check if the access if within the vector - if so, we may still be okay.
+ addSlowCase(branch32(AboveOrEqual, regT1, Address(regT2, FIELD_OFFSET(ArrayStorage, m_vectorLength))));
+
+ // This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location.
+ // FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff.
+ addSlowCase(branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, FIELD_OFFSET(ArrayStorage, m_vector[0]))));
+
+ // All good - put the value into the array.
+ inFastVector.link(this);
+ emitGetVirtualRegister(currentInstruction[3].u.operand, regT0);
+ storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr, FIELD_OFFSET(ArrayStorage, m_vector[0])));
+}
+
+void JIT::emit_op_put_by_index(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, JITStubs::cti_op_put_by_index);
+ stubCall.addArgument(currentInstruction[1].u.operand, regT2);
+ stubCall.addArgument(Imm32(currentInstruction[2].u.operand));
+ stubCall.addArgument(currentInstruction[3].u.operand, regT2);
+ stubCall.call();
+}
+
+void JIT::emit_op_put_getter(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, JITStubs::cti_op_put_getter);
+ stubCall.addArgument(currentInstruction[1].u.operand, regT2);
+ stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(currentInstruction[3].u.operand, regT2);
+ stubCall.call();
+}
+
+void JIT::emit_op_put_setter(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, JITStubs::cti_op_put_setter);
+ stubCall.addArgument(currentInstruction[1].u.operand, regT2);
+ stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[2].u.operand)));
+ stubCall.addArgument(currentInstruction[3].u.operand, regT2);
+ stubCall.call();
+}
+
+void JIT::emit_op_del_by_id(Instruction* currentInstruction)
+{
+ JITStubCall stubCall(this, JITStubs::cti_op_del_by_id);
+ stubCall.addArgument(currentInstruction[2].u.operand, regT2);
+ stubCall.addArgument(ImmPtr(&m_codeBlock->identifier(currentInstruction[3].u.operand)));
+ stubCall.call(currentInstruction[1].u.operand);
+}
+
+
#if !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
-void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier* ident, unsigned)
+/* ------------------------------ BEGIN: !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */
+
+// Treat these as nops - the call will be handed as a regular get_by_id/op_call pair.
+void JIT::emit_op_method_check(Instruction*) {}
+void JIT::emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&) { ASSERT_NOT_REACHED(); }
+#if ENABLE(JIT_OPTIMIZE_METHOD_CALLS)
+#error "JIT_OPTIMIZE_METHOD_CALLS requires JIT_OPTIMIZE_PROPERTY_ACCESS"
+#endif
+
+void JIT::emit_op_get_by_id(Instruction* currentInstruction)
{
- // As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched.
- // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump
- // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label
- // to jump back to if one of these trampolies finds a match.
+ unsigned resultVReg = currentInstruction[1].u.operand;
+ unsigned baseVReg = currentInstruction[2].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
emitGetVirtualRegister(baseVReg, regT0);
+ JITStubCall stubCall(this, JITStubs::cti_op_get_by_id_generic);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(ImmPtr(ident));
+ stubCall.call(resultVReg);
- emitPutJITStubArg(regT0, 1);
- emitPutJITStubArgConstant(ident, 2);
- emitCTICall(JITStubs::cti_op_get_by_id_generic);
- emitPutVirtualRegister(resultVReg);
+ m_propertyAccessInstructionIndex++;
}
-
-void JIT::compileGetByIdSlowCase(int, int, Identifier*, Vector<SlowCaseEntry>::iterator&, unsigned)
+void JIT::emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&)
{
ASSERT_NOT_REACHED();
}
-void JIT::compilePutByIdHotPath(int baseVReg, Identifier* ident, int valueVReg, unsigned)
+void JIT::emit_op_put_by_id(Instruction* currentInstruction)
{
- // In order to be able to patch both the Structure, and the object offset, we store one pointer,
- // to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
- // such that the Structure & offset are always at the same distance from this.
+ unsigned baseVReg = currentInstruction[1].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[2].u.operand));
+ unsigned valueVReg = currentInstruction[3].u.operand;
emitGetVirtualRegisters(baseVReg, regT0, valueVReg, regT1);
- emitPutJITStubArgConstant(ident, 2);
- emitPutJITStubArg(regT0, 1);
- emitPutJITStubArg(regT1, 3);
- emitCTICall(JITStubs::cti_op_put_by_id_generic);
+ JITStubCall stubCall(this, JITStubs::cti_op_put_by_id_generic);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(regT1);
+ stubCall.call();
+
+ m_propertyAccessInstructionIndex++;
}
-void JIT::compilePutByIdSlowCase(int, Identifier*, int, Vector<SlowCaseEntry>::iterator&, unsigned)
+void JIT::emitSlow_op_put_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&)
{
ASSERT_NOT_REACHED();
}
-#else
+#else // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
+
+/* ------------------------------ BEGIN: ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */
-void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier*, unsigned propertyAccessInstructionIndex)
+#if ENABLE(JIT_OPTIMIZE_METHOD_CALLS)
+
+void JIT::emit_op_method_check(Instruction* currentInstruction)
+{
+ // Assert that the following instruction is a get_by_id.
+ ASSERT(m_interpreter->getOpcodeID((currentInstruction + OPCODE_LENGTH(op_method_check))->u.opcode) == op_get_by_id);
+
+ currentInstruction += OPCODE_LENGTH(op_method_check);
+ unsigned resultVReg = currentInstruction[1].u.operand;
+ unsigned baseVReg = currentInstruction[2].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+ emitGetVirtualRegister(baseVReg, regT0);
+
+ // Do the method check - check the object & its prototype's structure inline (this is the common case).
+ m_methodCallCompilationInfo.append(MethodCallCompilationInfo(m_propertyAccessInstructionIndex));
+ MethodCallCompilationInfo& info = m_methodCallCompilationInfo.last();
+ Jump notCell = emitJumpIfNotJSCell(regT0);
+ Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, FIELD_OFFSET(JSCell, m_structure)), info.structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+ DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(ImmPtr(0), regT1);
+ Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT1, FIELD_OFFSET(JSCell, m_structure)), protoStructureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)));
+
+ // This will be relinked to load the function without doing a load.
+ DataLabelPtr putFunction = moveWithPatch(ImmPtr(0), regT0);
+ Jump match = jump();
+
+ ASSERT(differenceBetween(info.structureToCompare, protoObj) == patchOffsetMethodCheckProtoObj);
+ ASSERT(differenceBetween(info.structureToCompare, protoStructureToCompare) == patchOffsetMethodCheckProtoStruct);
+ ASSERT(differenceBetween(info.structureToCompare, putFunction) == patchOffsetMethodCheckPutFunction);
+
+ // Link the failure cases here.
+ notCell.link(this);
+ structureCheck.link(this);
+ protoStructureCheck.link(this);
+
+ // Do a regular(ish) get_by_id (the slow case will be link to
+ // cti_op_get_by_id_method_check instead of cti_op_get_by_id.
+ compileGetByIdHotPath(resultVReg, baseVReg, ident, m_propertyAccessInstructionIndex++);
+
+ match.link(this);
+ emitPutVirtualRegister(resultVReg);
+
+ // We've already generated the following get_by_id, so make sure it's skipped over.
+ m_bytecodeIndex += OPCODE_LENGTH(op_get_by_id);
+}
+
+void JIT::emitSlow_op_method_check(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ currentInstruction += OPCODE_LENGTH(op_method_check);
+ unsigned resultVReg = currentInstruction[1].u.operand;
+ unsigned baseVReg = currentInstruction[2].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+ compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, m_propertyAccessInstructionIndex++, true);
+
+ // We've already generated the following get_by_id, so make sure it's skipped over.
+ m_bytecodeIndex += OPCODE_LENGTH(op_get_by_id);
+}
+
+#else //!ENABLE(JIT_OPTIMIZE_METHOD_CALLS)
+
+// Treat these as nops - the call will be handed as a regular get_by_id/op_call pair.
+void JIT::emit_op_method_check(Instruction*) {}
+void JIT::emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&) { ASSERT_NOT_REACHED(); }
+
+#endif
+
+void JIT::emit_op_get_by_id(Instruction* currentInstruction)
+{
+ unsigned resultVReg = currentInstruction[1].u.operand;
+ unsigned baseVReg = currentInstruction[2].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+ emitGetVirtualRegister(baseVReg, regT0);
+ compileGetByIdHotPath(resultVReg, baseVReg, ident, m_propertyAccessInstructionIndex++);
+ emitPutVirtualRegister(resultVReg);
+}
+
+void JIT::compileGetByIdHotPath(int, int baseVReg, Identifier*, unsigned propertyAccessInstructionIndex)
{
// As for put_by_id, get_by_id requires the offset of the Structure and the offset of the access to be patched.
// Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump
// to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label
// to jump back to if one of these trampolies finds a match.
- emitGetVirtualRegister(baseVReg, regT0);
-
emitJumpSlowCaseIfNotJSCell(regT0, baseVReg);
Label hotPathBegin(this);
@@ -108,17 +290,28 @@ void JIT::compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier*, unsig
ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetGetByIdStructure);
ASSERT(differenceBetween(hotPathBegin, structureCheck) == patchOffsetGetByIdBranchToSlowCase);
- loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
+ Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, FIELD_OFFSET(JSObject, m_externalStorage)), regT0);
+ Label externalLoadComplete(this);
+ ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetGetByIdExternalLoad);
+ ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthGetByIdExternalLoad);
+
DataLabel32 displacementLabel = loadPtrWithAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0);
ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetGetByIdPropertyMapOffset);
Label putResult(this);
ASSERT(differenceBetween(hotPathBegin, putResult) == patchOffsetGetByIdPutResult);
- emitPutVirtualRegister(resultVReg);
}
+void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
+{
+ unsigned resultVReg = currentInstruction[1].u.operand;
+ unsigned baseVReg = currentInstruction[2].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[3].u.operand));
+
+ compileGetByIdSlowCase(resultVReg, baseVReg, ident, iter, m_propertyAccessInstructionIndex++, false);
+}
-void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex)
+void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex, bool isMethodCheck)
{
// As for the hot path of get_by_id, above, we ensure that we can use an architecture specific offset
// so that we only need track one pointer into the slow case code - we track a pointer to the location
@@ -132,10 +325,10 @@ void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident
#ifndef NDEBUG
Label coldPathBegin(this);
#endif
- emitPutJITStubArg(regT0, 1);
- emitPutJITStubArgConstant(ident, 2);
- Call call = emitCTICall(JITStubs::cti_op_get_by_id);
- emitPutVirtualRegister(resultVReg);
+ JITStubCall stubCall(this, isMethodCheck ? JITStubs::cti_op_get_by_id_method_check : JITStubs::cti_op_get_by_id);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(ImmPtr(ident));
+ Call call = stubCall.call(resultVReg);
ASSERT(differenceBetween(coldPathBegin, call) == patchOffsetGetByIdSlowCaseCall);
@@ -143,8 +336,13 @@ void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident
m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
}
-void JIT::compilePutByIdHotPath(int baseVReg, Identifier*, int valueVReg, unsigned propertyAccessInstructionIndex)
+void JIT::emit_op_put_by_id(Instruction* currentInstruction)
{
+ unsigned baseVReg = currentInstruction[1].u.operand;
+ unsigned valueVReg = currentInstruction[3].u.operand;
+
+ unsigned propertyAccessInstructionIndex = m_propertyAccessInstructionIndex++;
+
// In order to be able to patch both the Structure, and the object offset, we store one pointer,
// to just after the arguments have been loaded into registers 'hotPathBegin', and we generate code
// such that the Structure & offset are always at the same distance from this.
@@ -163,34 +361,64 @@ void JIT::compilePutByIdHotPath(int baseVReg, Identifier*, int valueVReg, unsign
ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetPutByIdStructure);
// Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used.
- loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
+ Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, FIELD_OFFSET(JSObject, m_externalStorage)), regT0);
+ Label externalLoadComplete(this);
+ ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetPutByIdExternalLoad);
+ ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthPutByIdExternalLoad);
+
DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchGetByIdDefaultOffset));
ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetPutByIdPropertyMapOffset);
}
-void JIT::compilePutByIdSlowCase(int baseVReg, Identifier* ident, int, Vector<SlowCaseEntry>::iterator& iter, unsigned propertyAccessInstructionIndex)
+void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter)
{
+ unsigned baseVReg = currentInstruction[1].u.operand;
+ Identifier* ident = &(m_codeBlock->identifier(currentInstruction[2].u.operand));
+
+ unsigned propertyAccessInstructionIndex = m_propertyAccessInstructionIndex++;
+
linkSlowCaseIfNotJSCell(iter, baseVReg);
linkSlowCase(iter);
- emitPutJITStubArgConstant(ident, 2);
- emitPutJITStubArg(regT0, 1);
- emitPutJITStubArg(regT1, 3);
- Call call = emitCTICall(JITStubs::cti_op_put_by_id);
+ JITStubCall stubCall(this, JITStubs::cti_op_put_by_id);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(ImmPtr(ident));
+ stubCall.addArgument(regT1);
+ Call call = stubCall.call();
// Track the location of the call; this will be used to recover patch information.
m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].callReturnLocation = call;
}
-static JSObject* resizePropertyStorage(JSObject* baseObject, int32_t oldSize, int32_t newSize)
+// Compile a store into an object's property storage. May overwrite the
+// value in objectReg.
+void JIT::compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset)
+{
+ int offset = cachedOffset * sizeof(JSValue);
+ if (structure->isUsingInlineStorage())
+ offset += FIELD_OFFSET(JSObject, m_inlineStorage);
+ else
+ loadPtr(Address(base, FIELD_OFFSET(JSObject, m_externalStorage)), base);
+ storePtr(value, Address(base, offset));
+}
+
+// Compile a load from an object's property storage. May overwrite base.
+void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset)
{
- baseObject->allocatePropertyStorage(oldSize, newSize);
- return baseObject;
+ int offset = cachedOffset * sizeof(JSValue);
+ if (structure->isUsingInlineStorage())
+ offset += FIELD_OFFSET(JSObject, m_inlineStorage);
+ else
+ loadPtr(Address(base, FIELD_OFFSET(JSObject, m_externalStorage)), base);
+ loadPtr(Address(base, offset), result);
}
-static inline bool transitionWillNeedStorageRealloc(Structure* oldStructure, Structure* newStructure)
+void JIT::compileGetDirectOffset(JSObject* base, RegisterID result, size_t cachedOffset)
{
- return oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
+ if (base->isUsingInlineStorage())
+ loadPtr(static_cast<void*>(&base->m_inlineStorage[cachedOffset]), result);
+ else
+ loadPtr(static_cast<void*>(&base->m_externalStorage[cachedOffset]), result);
}
void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ProcessorReturnAddress returnAddress)
@@ -201,7 +429,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
failureCases.append(branchPtr(NotEqual, Address(regT0, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(oldStructure)));
JumpList successCases;
- // ecx = baseObject
+ // ecx = baseObject
loadPtr(Address(regT0, FIELD_OFFSET(JSCell, m_structure)), regT2);
// proto(ecx) = baseObject->structure()->prototype()
failureCases.append(branch32(NotEqual, Address(regT2, FIELD_OFFSET(Structure, m_typeInfo) + FIELD_OFFSET(TypeInfo, m_type)), Imm32(ObjectType)));
@@ -211,7 +439,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
// ecx = baseObject->m_structure
for (RefPtr<Structure>* it = chain->head(); *it; ++it) {
// null check the prototype
- successCases.append(branchPtr(Equal, regT2, ImmPtr(JSValuePtr::encode(jsNull()))));
+ successCases.append(branchPtr(Equal, regT2, ImmPtr(JSValue::encode(jsNull()))));
// Check the structure id
failureCases.append(branchPtr(NotEqual, Address(regT2, FIELD_OFFSET(JSCell, m_structure)), ImmPtr(it->get())));
@@ -226,23 +454,21 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
Call callTarget;
// emit a call only if storage realloc is needed
- bool willNeedStorageRealloc = transitionWillNeedStorageRealloc(oldStructure, newStructure);
+ bool willNeedStorageRealloc = oldStructure->propertyStorageCapacity() != newStructure->propertyStorageCapacity();
if (willNeedStorageRealloc) {
- pop(X86::ebx);
-#if PLATFORM(X86_64)
- move(Imm32(newStructure->propertyStorageCapacity()), regT1);
- move(Imm32(oldStructure->propertyStorageCapacity()), X86::esi);
- move(regT0, X86::edi);
- callTarget = call();
-#else
- push(Imm32(newStructure->propertyStorageCapacity()));
- push(Imm32(oldStructure->propertyStorageCapacity()));
- push(regT0);
- callTarget = call();
- addPtr(Imm32(3 * sizeof(void*)), X86::esp);
-#endif
- emitGetJITStubArg(3, regT1);
- push(X86::ebx);
+ // This trampoline was called to like a JIT stub; before we can can call again we need to
+ // remove the return address from the stack, to prevent the stack from becoming misaligned.
+ preverveReturnAddressAfterCall(regT3);
+
+ JITStubCall stubCall(this, JITStubs::cti_op_put_by_id_transition_realloc);
+ stubCall.addArgument(regT0);
+ stubCall.addArgument(Imm32(oldStructure->propertyStorageCapacity()));
+ stubCall.addArgument(Imm32(newStructure->propertyStorageCapacity()));
+ stubCall.addArgument(regT1); // This argument is not used in the stub; we set it up on the stack so that it can be restored, below.
+ stubCall.call(regT0);
+ emitGetJITStubArg(4, regT1);
+
+ restoreReturnAddressBeforeReturn(regT3);
}
// Assumes m_refCount can be decremented easily, refcount decrement is safe as
@@ -252,8 +478,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
storePtr(ImmPtr(newStructure), Address(regT0, FIELD_OFFSET(JSCell, m_structure)));
// write the value
- loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
- storePtr(regT1, Address(regT0, cachedOffset * sizeof(JSValuePtr)));
+ compilePutDirectOffset(regT0, regT1, newStructure, cachedOffset);
ret();
@@ -262,47 +487,74 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure
restoreArgumentReferenceForTrampoline();
Call failureCall = tailRecursiveCall();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
- patchBuffer.link(failureCall, JITStubs::cti_op_put_by_id_fail);
+ patchBuffer.link(failureCall, FunctionPtr(JITStubs::cti_op_put_by_id_fail));
- if (willNeedStorageRealloc)
- patchBuffer.link(callTarget, resizePropertyStorage);
+ if (willNeedStorageRealloc) {
+ ASSERT(m_calls.size() == 1);
+ patchBuffer.link(m_calls[0].from, FunctionPtr(JITStubs::cti_op_put_by_id_transition_realloc));
+ }
- stubInfo->stubRoutine = patchBuffer.entry();
-
- returnAddress.relinkCallerToFunction(code);
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
+ stubInfo->stubRoutine = entryLabel;
+ returnAddress.relinkCallerToTrampoline(entryLabel);
}
void JIT::patchGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ProcessorReturnAddress returnAddress)
{
// We don't want to patch more than once - in future go to cti_op_get_by_id_generic.
// Should probably go to JITStubs::cti_op_get_by_id_fail, but that doesn't do anything interesting right now.
- returnAddress.relinkCallerToFunction(JITStubs::cti_op_get_by_id_self_fail);
+ returnAddress.relinkCallerToFunction(FunctionPtr(JITStubs::cti_op_get_by_id_self_fail));
+
+ int offset = sizeof(JSValue) * cachedOffset;
+
+ // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
+ // and makes the subsequent load's offset automatically correct
+ if (structure->isUsingInlineStorage())
+ stubInfo->hotPathBegin.instructionAtOffset(patchOffsetGetByIdExternalLoad).repatchLoadPtrToLEA();
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetGetByIdStructure).repatch(structure);
- stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset).repatch(cachedOffset * sizeof(JSValuePtr));
+ stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetGetByIdPropertyMapOffset).repatch(offset);
+}
+
+void JIT::patchMethodCallProto(MethodCallLinkInfo& methodCallLinkInfo, JSFunction* callee, Structure* structure, JSObject* proto)
+{
+ ASSERT(!methodCallLinkInfo.cachedStructure);
+ methodCallLinkInfo.cachedStructure = structure;
+ structure->ref();
+
+ methodCallLinkInfo.structureLabel.repatch(structure);
+ methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoObj).repatch(proto);
+ methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckProtoStruct).repatch(proto->structure());
+ methodCallLinkInfo.structureLabel.dataLabelPtrAtOffset(patchOffsetMethodCheckPutFunction).repatch(callee);
}
void JIT::patchPutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ProcessorReturnAddress returnAddress)
{
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
// Should probably go to JITStubs::cti_op_put_by_id_fail, but that doesn't do anything interesting right now.
- returnAddress.relinkCallerToFunction(JITStubs::cti_op_put_by_id_generic);
+ returnAddress.relinkCallerToFunction(FunctionPtr(JITStubs::cti_op_put_by_id_generic));
+
+ int offset = sizeof(JSValue) * cachedOffset;
+
+ // If we're patching to use inline storage, convert the initial load to a lea; this avoids the extra load
+ // and makes the subsequent load's offset automatically correct
+ if (structure->isUsingInlineStorage())
+ stubInfo->hotPathBegin.instructionAtOffset(patchOffsetPutByIdExternalLoad).repatchLoadPtrToLEA();
// Patch the offset into the propoerty map to load from, then patch the Structure to look for.
stubInfo->hotPathBegin.dataLabelPtrAtOffset(patchOffsetPutByIdStructure).repatch(structure);
- stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset).repatch(cachedOffset * sizeof(JSValuePtr));
+ stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset).repatch(offset);
}
void JIT::privateCompilePatchGetArrayLength(ProcessorReturnAddress returnAddress)
{
- StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress);
+ StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress.addressForLookup());
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
- returnAddress.relinkCallerToFunction(JITStubs::cti_op_get_by_id_array_fail);
+ returnAddress.relinkCallerToFunction(FunctionPtr(JITStubs::cti_op_get_by_id_array_fail));
// Check eax is an array
Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr));
@@ -316,8 +568,7 @@ void JIT::privateCompilePatchGetArrayLength(ProcessorReturnAddress returnAddress
emitFastArithIntToImmNoCheck(regT2, regT0);
Jump success = jump();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
@@ -328,7 +579,7 @@ void JIT::privateCompilePatchGetArrayLength(ProcessorReturnAddress returnAddress
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
// Track the stub we have created so that it will be deleted later.
- CodeLocationLabel entryLabel = patchBuffer.entry();
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
@@ -336,42 +587,14 @@ void JIT::privateCompilePatchGetArrayLength(ProcessorReturnAddress returnAddress
jumpLocation.relink(entryLabel);
}
-void JIT::privateCompileGetByIdSelf(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ProcessorReturnAddress returnAddress)
-{
- // Check eax is an object of the right Structure.
- Jump failureCases1 = emitJumpIfNotJSCell(regT0);
- Jump failureCases2 = checkStructure(regT0, structure);
-
- // Checks out okay! - getDirectOffset
- loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
- loadPtr(Address(regT0, cachedOffset * sizeof(JSValuePtr)), regT0);
- ret();
-
- Call failureCases1Call = makeTailRecursiveCall(failureCases1);
- Call failureCases2Call = makeTailRecursiveCall(failureCases2);
-
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
-
- patchBuffer.link(failureCases1Call, JITStubs::cti_op_get_by_id_self_fail);
- patchBuffer.link(failureCases2Call, JITStubs::cti_op_get_by_id_self_fail);
-
- stubInfo->stubRoutine = patchBuffer.entry();
-
- returnAddress.relinkCallerToFunction(code);
-}
-
void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, ProcessorReturnAddress returnAddress, CallFrame* callFrame)
{
-#if USE(CTI_REPATCH_PIC)
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
- returnAddress.relinkCallerToFunction(JITStubs::cti_op_get_by_id_proto_list);
+ returnAddress.relinkCallerToFunction(FunctionPtr(JITStubs::cti_op_get_by_id_proto_list));
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- loadPtr(static_cast<void*>(protoPropertyStorage), regT1);
// Check eax is an object of the right Structure.
Jump failureCases1 = checkStructure(regT0, structure);
@@ -386,12 +609,11 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
#endif
// Checks out okay! - getDirectOffset
- loadPtr(Address(regT1, cachedOffset * sizeof(JSValuePtr)), regT0);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall);
@@ -402,56 +624,21 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
// Track the stub we have created so that it will be deleted later.
- CodeLocationLabel entryLabel = patchBuffer.entry();
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
jumpLocation.relink(entryLabel);
-#else
- // The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
- // referencing the prototype object - let's speculatively load it's table nice and early!)
- JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- loadPtr(protoPropertyStorage, regT1);
-
- // Check eax is an object of the right Structure.
- Jump failureCases1 = emitJumpIfNotJSCell(regT0);
- Jump failureCases2 = checkStructure(regT0, structure);
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
- Jump failureCases3 = branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(prototypeStructure));
-
- // Checks out okay! - getDirectOffset
- loadPtr(Address(regT1, cachedOffset * sizeof(JSValuePtr)), regT0);
-
- ret();
-
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
-
- patchBuffer.link(failureCases1, JITStubs::cti_op_get_by_id_proto_fail);
- patchBuffer.link(failureCases2, JITStubs::cti_op_get_by_id_proto_fail);
- patchBuffer.link(failureCases3, JITStubs::cti_op_get_by_id_proto_fail);
-
- stubInfo->stubRoutine = patchBuffer.entry();
-
- returnAddress.relinkCallerToFunction(code);
-#endif
}
-#if USE(CTI_REPATCH_PIC)
void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, size_t cachedOffset)
{
Jump failureCase = checkStructure(regT0, structure);
- loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
- loadPtr(Address(regT0, cachedOffset * sizeof(JSValuePtr)), regT0);
+ compileGetDirectOffset(regT0, regT0, structure, cachedOffset);
Jump success = jump();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- ASSERT(code);
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel lastProtoBegin = polymorphicStructures->list[currentIndex - 1].stubRoutine;
@@ -463,7 +650,7 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic
// On success return back to the hot patch code, at a point it will perform the store to dest for us.
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
- CodeLocationLabel entryLabel = patchBuffer.entry();
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
structure->ref();
polymorphicStructures->list[currentIndex].set(entryLabel, structure);
@@ -478,8 +665,6 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
// The prototype object definitely exists (if this stub exists the CodeBlock is referencing a Structure that is
// referencing the prototype object - let's speculatively load it's table nice and early!)
JSObject* protoObject = asObject(structure->prototypeForLookup(callFrame));
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- loadPtr(protoPropertyStorage, regT1);
// Check eax is an object of the right Structure.
Jump failureCases1 = checkStructure(regT0, structure);
@@ -494,12 +679,11 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
#endif
// Checks out okay! - getDirectOffset
- loadPtr(Address(regT1, cachedOffset * sizeof(JSValuePtr)), regT0);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
@@ -509,7 +693,7 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi
// On success return back to the hot patch code, at a point it will perform the store to dest for us.
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
- CodeLocationLabel entryLabel = patchBuffer.entry();
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
structure->ref();
prototypeStructure->ref();
@@ -548,13 +732,10 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
}
ASSERT(protoObject);
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- loadPtr(protoPropertyStorage, regT1);
- loadPtr(Address(regT1, cachedOffset * sizeof(JSValuePtr)), regT0);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
CodeLocationLabel lastProtoBegin = prototypeStructures->list[currentIndex - 1].stubRoutine;
@@ -564,7 +745,7 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
// On success return back to the hot patch code, at a point it will perform the store to dest for us.
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
- CodeLocationLabel entryLabel = patchBuffer.entry();
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
// Track the stub we have created so that it will be deleted later.
structure->ref();
@@ -575,13 +756,11 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
jumpLocation.relink(entryLabel);
}
-#endif
void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, size_t cachedOffset, ProcessorReturnAddress returnAddress, CallFrame* callFrame)
{
-#if USE(CTI_REPATCH_PIC)
// We don't want to patch more than once - in future go to cti_op_put_by_id_generic.
- returnAddress.relinkCallerToFunction(JITStubs::cti_op_get_by_id_proto_list);
+ returnAddress.relinkCallerToFunction(FunctionPtr(JITStubs::cti_op_get_by_id_proto_list));
ASSERT(count);
@@ -608,13 +787,10 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
}
ASSERT(protoObject);
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- loadPtr(protoPropertyStorage, regT1);
- loadPtr(Address(regT1, cachedOffset * sizeof(JSValuePtr)), regT0);
+ compileGetDirectOffset(protoObject, regT0, cachedOffset);
Jump success = jump();
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
+ PatchBuffer patchBuffer(this, m_codeBlock->executablePool());
// Use the patch information to link the failure cases back to the original slow case routine.
patchBuffer.link(bucketsOfFail, stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall));
@@ -623,80 +799,17 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str
patchBuffer.link(success, stubInfo->hotPathBegin.labelAtOffset(patchOffsetGetByIdPutResult));
// Track the stub we have created so that it will be deleted later.
- CodeLocationLabel entryLabel = patchBuffer.entry();
+ CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum();
stubInfo->stubRoutine = entryLabel;
// Finally patch the jump to slow case back in the hot path to jump here instead.
CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase);
jumpLocation.relink(entryLabel);
-#else
- ASSERT(count);
-
- JumpList bucketsOfFail;
-
- // Check eax is an object of the right Structure.
- bucketsOfFail.append(emitJumpIfNotJSCell(regT0));
- bucketsOfFail.append(checkStructure(regT0, structure));
-
- Structure* currStructure = structure;
- RefPtr<Structure>* chainEntries = chain->head();
- JSObject* protoObject = 0;
- for (unsigned i = 0; i < count; ++i) {
- protoObject = asObject(currStructure->prototypeForLookup(callFrame));
- currStructure = chainEntries[i].get();
-
- // Check the prototype object's Structure had not changed.
- Structure** prototypeStructureAddress = &(protoObject->m_structure);
-#if PLATFORM(X86_64)
- move(ImmPtr(currStructure), regT3);
- bucketsOfFail.append(branchPtr(NotEqual, regT3, AbsoluteAddress(prototypeStructureAddress)));
-#else
- bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure)));
-#endif
- }
- ASSERT(protoObject);
-
- PropertyStorage* protoPropertyStorage = &protoObject->m_propertyStorage;
- loadPtr(protoPropertyStorage, regT1);
- loadPtr(Address(regT1, cachedOffset * sizeof(JSValuePtr)), regT0);
- ret();
-
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
-
- patchBuffer.link(bucketsOfFail, JITStubs::cti_op_get_by_id_proto_fail);
-
- stubInfo->stubRoutine = patchBuffer.entry();
-
- returnAddress.relinkCallerToFunction(code);
-#endif
}
-void JIT::privateCompilePutByIdReplace(StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ProcessorReturnAddress returnAddress)
-{
- // Check eax is an object of the right Structure.
- Jump failureCases1 = emitJumpIfNotJSCell(regT0);
- Jump failureCases2 = checkStructure(regT0, structure);
-
- // checks out okay! - putDirectOffset
- loadPtr(Address(regT0, FIELD_OFFSET(JSObject, m_propertyStorage)), regT0);
- storePtr(regT1, Address(regT0, cachedOffset * sizeof(JSValuePtr)));
- ret();
-
- Call failureCases1Call = makeTailRecursiveCall(failureCases1);
- Call failureCases2Call = makeTailRecursiveCall(failureCases2);
+/* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */
- void* code = m_assembler.executableCopy(m_codeBlock->executablePool());
- PatchBuffer patchBuffer(code);
-
- patchBuffer.link(failureCases1Call, JITStubs::cti_op_put_by_id_fail);
- patchBuffer.link(failureCases2Call, JITStubs::cti_op_put_by_id_fail);
-
- stubInfo->stubRoutine = patchBuffer.entry();
-
- returnAddress.relinkCallerToFunction(code);
-}
-
-#endif
+#endif // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
} // namespace JSC