diff options
author | Ben Murdoch <benm@google.com> | 2010-08-11 14:44:44 +0100 |
---|---|---|
committer | Ben Murdoch <benm@google.com> | 2010-08-12 19:15:41 +0100 |
commit | dd8bb3de4f353a81954234999f1fea748aee2ea9 (patch) | |
tree | 729b52bf09294f0d6c67cd5ea80aee1b727b7bd8 /JavaScriptCore/jit/JITPropertyAccess.cpp | |
parent | f3d41ba51d86bf719c7a65ab5297aea3c17e2d98 (diff) | |
download | external_webkit-dd8bb3de4f353a81954234999f1fea748aee2ea9.zip external_webkit-dd8bb3de4f353a81954234999f1fea748aee2ea9.tar.gz external_webkit-dd8bb3de4f353a81954234999f1fea748aee2ea9.tar.bz2 |
Merge WebKit at r65072 : Initial merge by git.
Change-Id: Ibcf418498376b2660aacb7f8d46ea7085ef91585
Diffstat (limited to 'JavaScriptCore/jit/JITPropertyAccess.cpp')
-rw-r--r-- | JavaScriptCore/jit/JITPropertyAccess.cpp | 149 |
1 files changed, 87 insertions, 62 deletions
diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp index 10dcd3f..6b2a2fe 100644 --- a/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -77,7 +77,10 @@ JIT::CodePtr JIT::stringGetByValStubGenerator(JSGlobalData* globalData, Executab jit.move(Imm32(0), regT0); jit.ret(); - LinkBuffer patchBuffer(&jit, pool); + LinkBuffer patchBuffer(&jit, pool, 0); + // We can't run without the JIT trampolines! + if (!patchBuffer.allocationSuccessful()) + CRASH(); return patchBuffer.finalizeCode().m_code; } @@ -103,10 +106,10 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) emitJumpSlowCaseIfNotJSCell(regT0, base); addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2); addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); - loadPtr(BaseIndex(regT2, regT1, ScalePtr), regT0); + loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); addSlowCase(branchTestPtr(Zero, regT0)); emitPutVirtualRegister(dst); @@ -214,21 +217,21 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT2); - Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr)); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2); + Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); Label storeResult(this); emitGetVirtualRegister(value, regT0); - storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr)); + storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); Jump end = jump(); empty.link(this); - add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector)-OBJECT_OFFSETOF(ArrayStorage, m_vector))); - branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))).linkTo(storeResult, this); + add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this); move(regT1, regT0); add32(Imm32(1), regT0); - store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector))); + store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))); jump().linkTo(storeResult, this); end.link(this); @@ -581,28 +584,35 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res } } -void JIT::testPrototype(Structure* structure, JumpList& failureCases) +void JIT::testPrototype(JSValue prototype, JumpList& failureCases) { - if (structure->m_prototype.isNull()) + if (prototype.isNull()) return; - move(ImmPtr(&asCell(structure->m_prototype)->m_structure), regT2); - move(ImmPtr(asCell(structure->m_prototype)->m_structure), regT3); - failureCases.append(branchPtr(NotEqual, Address(regT2), regT3)); + // We have a special case for X86_64 here because X86 instructions that take immediate values + // only take 32 bit immediate values, wheras the pointer constants we are using here are 64 bit + // values. In the non X86_64 case, the generated code is slightly more efficient because it uses + // two less instructions and doesn't require any scratch registers. +#if CPU(X86_64) + move(ImmPtr(asCell(prototype)->structure()), regT3); + failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), regT3)); +#else + failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(prototype)->m_structure), ImmPtr(asCell(prototype)->structure()))); +#endif } -void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) +bool JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress, bool direct) { JumpList failureCases; // Check eax is an object of the right Structure. failureCases.append(emitJumpIfNotJSCell(regT0)); failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure))); - testPrototype(oldStructure, failureCases); + testPrototype(oldStructure->storedPrototype(), failureCases); // ecx = baseObject->m_structure if (!direct) { for (RefPtr<Structure>* it = chain->head(); *it; ++it) - testPrototype(it->get(), failureCases); + testPrototype((*it)->storedPrototype(), failureCases); } Call callTarget; @@ -642,7 +652,9 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure restoreArgumentReferenceForTrampoline(); Call failureCall = tailRecursiveCall(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; patchBuffer.link(failureCall, FunctionPtr(direct ? cti_op_put_by_id_direct_fail : cti_op_put_by_id_fail)); @@ -652,9 +664,10 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure } CodeLocationLabel entryLabel = patchBuffer.finalizeCodeAddendum(); - stubInfo->stubRoutine = entryLabel; RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relinkCallerToTrampoline(returnAddress, entryLabel); + stubInfo->initPutByIdTransition(oldStructure, newStructure, chain, entryLabel); + return true; } void JIT::patchGetByIdSelf(CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, size_t cachedOffset, ReturnAddressPtr returnAddress) @@ -717,22 +730,22 @@ void JIT::patchPutByIdReplace(CodeBlock* codeBlock, StructureStubInfo* stubInfo, repatchBuffer.repatch(stubInfo->hotPathBegin.dataLabel32AtOffset(patchOffsetPutByIdPropertyMapOffset), offset); } -void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) +bool JIT::privateCompilePatchGetArrayLength(StructureStubInfo* stubInfo, ReturnAddressPtr returnAddress) { - StructureStubInfo* stubInfo = &m_codeBlock->getStubInfo(returnAddress); - // Check eax is an array Jump failureCases1 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr)); // Checks out okay! - get the length from the storage - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_vector)), regT3); - load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)-OBJECT_OFFSETOF(ArrayStorage, m_vector)), regT2); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3); + load32(Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length)), regT2); Jump failureCases2 = branch32(Above, regT2, Imm32(JSImmediate::maxImmediateInt)); emitFastArithIntToImmNoCheck(regT2, regT0); Jump success = jump(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -744,7 +757,6 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) // Track the stub we have created so that it will be deleted later. 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); @@ -753,9 +765,11 @@ void JIT::privateCompilePatchGetArrayLength(ReturnAddressPtr returnAddress) // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_array_fail)); + stubInfo->stubRoutine = entryLabel; + return true; } -void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) +bool JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) { // 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!) @@ -795,7 +809,9 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str } else compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; // Use the patch information to link the failure cases back to the original slow case routine. CodeLocationLabel slowCaseBegin = stubInfo->callReturnLocation.labelAtOffset(-patchOffsetGetByIdSlowCaseCall); @@ -813,7 +829,6 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str } // Track the stub we have created so that it will be deleted later. 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); @@ -822,10 +837,15 @@ void JIT::privateCompileGetByIdProto(StructureStubInfo* stubInfo, Structure* str // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); + stubInfo->initGetByIdProto(structure, prototypeStructure, entryLabel); + return true; } -void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* polymorphicStructures, int currentIndex, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) +bool JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Structure* structure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset) { + PolymorphicAccessStructureList* polymorphicStructures = stubInfo->u.getByIdSelfList.structureList; + int currentIndex = stubInfo->u.getByIdSelfList.listSize; + Jump failureCase = checkStructure(regT0, structure); bool needsStubLink = false; if (slot.cachedPropertyType() == PropertySlot::Getter) { @@ -852,7 +872,9 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic compileGetDirectOffset(regT0, regT0, structure, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -880,10 +902,15 @@ void JIT::privateCompileGetByIdSelfList(StructureStubInfo* stubInfo, Polymorphic CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); + stubInfo->u.getByIdSelfList.listSize++; + return true; } -void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) +bool JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) { + PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList; + int currentIndex = stubInfo->u.getByIdProtoList.listSize; + // 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)); @@ -923,7 +950,9 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi Jump success = jump(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -950,10 +979,15 @@ void JIT::privateCompileGetByIdProtoList(StructureStubInfo* stubInfo, Polymorphi CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); + stubInfo->u.getByIdProtoList.listSize++; + return true; } -void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, PolymorphicAccessStructureList* prototypeStructures, int currentIndex, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) +bool JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, CallFrame* callFrame) { + PolymorphicAccessStructureList* prototypeStructures = stubInfo->u.getByIdProtoList.structureList; + int currentIndex = stubInfo->u.getByIdProtoList.listSize; + ASSERT(count); JumpList bucketsOfFail; @@ -962,20 +996,12 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi bucketsOfFail.append(baseObjectCheck); Structure* currStructure = structure; - RefPtr<Structure>* chainEntries = chain->head(); + RefPtr<Structure>* it = chain->head(); JSObject* protoObject = 0; - for (unsigned i = 0; i < count; ++i) { + for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(callFrame)); - currStructure = chainEntries[i].get(); - - // Check the prototype object's Structure had not changed. - Structure** prototypeStructureAddress = &(protoObject->m_structure); -#if CPU(X86_64) - move(ImmPtr(currStructure), regT3); - bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3)); -#else - bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure))); -#endif + currStructure = it->get(); + testPrototype(protoObject, bucketsOfFail); } ASSERT(protoObject); @@ -1000,7 +1026,9 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -1028,9 +1056,11 @@ void JIT::privateCompileGetByIdChainList(StructureStubInfo* stubInfo, Polymorphi CodeLocationJump jumpLocation = stubInfo->hotPathBegin.jumpAtOffset(patchOffsetGetByIdBranchToSlowCase); RepatchBuffer repatchBuffer(m_codeBlock); repatchBuffer.relink(jumpLocation, entryLabel); + stubInfo->u.getByIdProtoList.listSize++; + return true; } -void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) +bool JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* structure, StructureChain* chain, size_t count, const Identifier& ident, const PropertySlot& slot, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame) { ASSERT(count); @@ -1040,20 +1070,12 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str bucketsOfFail.append(checkStructure(regT0, structure)); Structure* currStructure = structure; - RefPtr<Structure>* chainEntries = chain->head(); + RefPtr<Structure>* it = chain->head(); JSObject* protoObject = 0; - for (unsigned i = 0; i < count; ++i) { + for (unsigned i = 0; i < count; ++i, ++it) { protoObject = asObject(currStructure->prototypeForLookup(callFrame)); - currStructure = chainEntries[i].get(); - - // Check the prototype object's Structure had not changed. - Structure** prototypeStructureAddress = &(protoObject->m_structure); -#if CPU(X86_64) - move(ImmPtr(currStructure), regT3); - bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), regT3)); -#else - bucketsOfFail.append(branchPtr(NotEqual, AbsoluteAddress(prototypeStructureAddress), ImmPtr(currStructure))); -#endif + currStructure = it->get(); + testPrototype(protoObject, bucketsOfFail); } ASSERT(protoObject); @@ -1078,7 +1100,9 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str compileGetDirectOffset(protoObject, regT1, regT0, cachedOffset); Jump success = jump(); - LinkBuffer patchBuffer(this, m_codeBlock->executablePool()); + LinkBuffer patchBuffer(this, m_codeBlock->executablePool(), 0); + if (!patchBuffer.allocationSuccessful()) + return false; if (needsStubLink) { for (Vector<CallRecord>::iterator iter = m_calls.begin(); iter != m_calls.end(); ++iter) { @@ -1095,7 +1119,6 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str // Track the stub we have created so that it will be deleted later. 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); @@ -1104,6 +1127,8 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str // We don't want to patch more than once - in future go to cti_op_put_by_id_generic. repatchBuffer.relinkCallerToFunction(returnAddress, FunctionPtr(cti_op_get_by_id_proto_list)); + stubInfo->initGetByIdChain(structure, chain, entryLabel); + return true; } /* ------------------------------ END: !ENABLE / ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) ------------------------------ */ |