diff options
author | Feng Qian <fqian@google.com> | 2009-06-17 12:12:20 -0700 |
---|---|---|
committer | Feng Qian <fqian@google.com> | 2009-06-17 12:12:20 -0700 |
commit | 5f1ab04193ad0130ca8204aadaceae083aca9881 (patch) | |
tree | 5a92cd389e2cfe7fb67197ce14b38469462379f8 /JavaScriptCore/jit/JITPropertyAccess.cpp | |
parent | 194315e5a908cc8ed67d597010544803eef1ac59 (diff) | |
download | external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.zip external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.tar.gz external_webkit-5f1ab04193ad0130ca8204aadaceae083aca9881.tar.bz2 |
Get WebKit r44544.
Diffstat (limited to 'JavaScriptCore/jit/JITPropertyAccess.cpp')
-rw-r--r-- | JavaScriptCore/jit/JITPropertyAccess.cpp | 587 |
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 |