From d549443ef1330431d10b71999421b11291b12508 Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Mon, 22 Apr 2013 12:06:46 -0400 Subject: [PATCH] Bug 857838 - Fix script-pc calculatins when iterating on baseline frames. r=jandem --- js/src/ion/BaselineBailouts.cpp | 7 +++ js/src/ion/BaselineJIT.cpp | 85 ++++++++++++++++++++++++++++++-- js/src/ion/BaselineJIT.h | 4 ++ js/src/ion/IonFrames.cpp | 21 +++++++- js/src/ion/IonMacroAssembler.cpp | 3 +- 5 files changed, 113 insertions(+), 7 deletions(-) diff --git a/js/src/ion/BaselineBailouts.cpp b/js/src/ion/BaselineBailouts.cpp index 6f59d9f6a91..b139a4b813e 100644 --- a/js/src/ion/BaselineBailouts.cpp +++ b/js/src/ion/BaselineBailouts.cpp @@ -1184,6 +1184,13 @@ ion::FinishBailoutToBaseline(BaselineBailoutInfo *bailoutInfo) IonSpew(IonSpew_BaselineBailouts, " Done restoring frames"); + // Check that we can get the current script's PC. +#ifdef DEBUG + jsbytecode *pc; + cx->stack.currentScript(&pc); + IonSpew(IonSpew_BaselineBailouts, " Got pc=%p", pc); +#endif + uint32_t numFrames = bailoutInfo->numFrames; JS_ASSERT(numFrames > 0); BailoutKind bailoutKind = bailoutInfo->bailoutKind; diff --git a/js/src/ion/BaselineJIT.cpp b/js/src/ion/BaselineJIT.cpp index af0708875bb..b97a8c823ae 100644 --- a/js/src/ion/BaselineJIT.cpp +++ b/js/src/ion/BaselineJIT.cpp @@ -388,8 +388,8 @@ BaselineScript::pcMappingReader(size_t indexEntry) return CompactBufferReader(dataStart, dataEnd); } -ICEntry & -BaselineScript::icEntryFromReturnOffset(CodeOffsetLabel returnOffset) +ICEntry * +BaselineScript::maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset) { size_t bottom = 0; size_t top = numICEntries(); @@ -402,8 +402,21 @@ BaselineScript::icEntryFromReturnOffset(CodeOffsetLabel returnOffset) top = mid; mid = (bottom + top) / 2; } - JS_ASSERT(icEntry(mid).returnOffset().offset() == returnOffset.offset()); - return icEntry(mid); + if (mid >= numICEntries()) + return NULL; + + if (icEntry(mid).returnOffset().offset() != returnOffset.offset()) + return NULL; + + return &icEntry(mid); +} + +ICEntry & +BaselineScript::icEntryFromReturnOffset(CodeOffsetLabel returnOffset) +{ + ICEntry *result = maybeICEntryFromReturnOffset(returnOffset); + JS_ASSERT(result); + return *result; } uint8_t * @@ -468,10 +481,20 @@ BaselineScript::icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntr return icEntryFromPCOffset(pcOffset); } +ICEntry * +BaselineScript::maybeICEntryFromReturnAddress(uint8_t *returnAddr) +{ + JS_ASSERT(returnAddr > method_->raw()); + JS_ASSERT(returnAddr < method_->raw() + method_->instructionsSize()); + CodeOffsetLabel offset(returnAddr - method_->raw()); + return maybeICEntryFromReturnOffset(offset); +} + ICEntry & BaselineScript::icEntryFromReturnAddress(uint8_t *returnAddr) { JS_ASSERT(returnAddr > method_->raw()); + JS_ASSERT(returnAddr < method_->raw() + method_->instructionsSize()); CodeOffsetLabel offset(returnAddr - method_->raw()); return icEntryFromReturnOffset(offset); } @@ -581,6 +604,60 @@ BaselineScript::nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotI return NULL; } +jsbytecode * +BaselineScript::pcForReturnOffset(JSScript *script, uint32_t nativeOffset) +{ + JS_ASSERT(script->baselineScript() == this); + JS_ASSERT(nativeOffset < method_->instructionsSize()); + + // Look for the first PCMappingIndexEntry with native offset > the native offset we are + // interested in. + uint32_t i = 1; + for (; i < numPCMappingIndexEntries(); i++) { + if (pcMappingIndexEntry(i).nativeOffset > nativeOffset) + break; + } + + // Go back an entry to search forward from. + JS_ASSERT(i > 0); + i--; + + PCMappingIndexEntry &entry = pcMappingIndexEntry(i); + JS_ASSERT(nativeOffset >= entry.nativeOffset); + + CompactBufferReader reader(pcMappingReader(i)); + jsbytecode *curPC = script->code + entry.pcOffset; + uint32_t curNativeOffset = entry.nativeOffset; + + JS_ASSERT(curPC >= script->code); + JS_ASSERT(curNativeOffset <= nativeOffset); + + while (true) { + // If the high bit is set, the native offset relative to the + // previous pc != 0 and comes next. + uint8_t b = reader.readByte(); + if (b & 0x80) + curNativeOffset += reader.readUnsigned(); + + if (curNativeOffset == nativeOffset) + return curPC; + + curPC += GetBytecodeLength(curPC); + } + + JS_NOT_REACHED("Invalid pc"); + return NULL; +} + +jsbytecode * +BaselineScript::pcForReturnAddress(JSScript *script, uint8_t *nativeAddress) +{ + JS_ASSERT(script->baselineScript() == this); + JS_ASSERT(nativeAddress >= method_->raw()); + JS_ASSERT(nativeAddress < method_->raw() + method_->instructionsSize()); + return pcForReturnOffset(script, uint32_t(nativeAddress - method_->raw())); +} + void BaselineScript::toggleDebugTraps(RawScript script, jsbytecode *pc) { diff --git a/js/src/ion/BaselineJIT.h b/js/src/ion/BaselineJIT.h index 33244f8ca2e..545cab7bf0d 100644 --- a/js/src/ion/BaselineJIT.h +++ b/js/src/ion/BaselineJIT.h @@ -211,9 +211,11 @@ struct BaselineScript } ICEntry &icEntry(size_t index); + ICEntry *maybeICEntryFromReturnOffset(CodeOffsetLabel returnOffset); ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset); ICEntry &icEntryFromPCOffset(uint32_t pcOffset); ICEntry &icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry); + ICEntry *maybeICEntryFromReturnAddress(uint8_t *returnAddr); ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr); uint8_t *returnAddressForIC(const ICEntry &ent); @@ -235,6 +237,8 @@ struct BaselineScript void copyPCMappingEntries(const CompactBufferWriter &entries); uint8_t *nativeCodeForPC(JSScript *script, jsbytecode *pc, PCMappingSlotInfo *slotInfo = NULL); + jsbytecode *pcForReturnOffset(JSScript *script, uint32_t nativeOffset); + jsbytecode *pcForReturnAddress(JSScript *script, uint8_t *nativeAddress); // Toggle debug traps (used for breakpoints and step mode) in the script. // If |pc| is NULL, toggle traps for all ops in the script. Else, only diff --git a/js/src/ion/IonFrames.cpp b/js/src/ion/IonFrames.cpp index 92c66373743..efa67b9d884 100644 --- a/js/src/ion/IonFrames.cpp +++ b/js/src/ion/IonFrames.cpp @@ -193,8 +193,25 @@ IonFrameIterator::baselineScriptAndPc(JSScript **scriptRes, jsbytecode **pcRes) if (scriptRes) *scriptRes = script; uint8_t *retAddr = returnAddressToFp(); - if (pcRes) - *pcRes = script->baselineScript()->icEntryFromReturnAddress(retAddr).pc(script); + if (pcRes) { + // If the return address is into the prologue entry addr, then assume PC 0. + if (retAddr == script->baselineScript()->prologueEntryAddr()) { + *pcRes = 0; + return; + } + + // The return address _may_ be a return from a callVM or IC chain call done for + // some op. + ICEntry *icEntry = script->baselineScript()->maybeICEntryFromReturnAddress(retAddr); + if (icEntry) { + *pcRes = icEntry->pc(script); + return; + } + + // If not, the return address _must_ be the start address of an op, which can + // be computed from the pc mapping table. + *pcRes = script->baselineScript()->pcForReturnAddress(script, retAddr); + } } Value * diff --git a/js/src/ion/IonMacroAssembler.cpp b/js/src/ion/IonMacroAssembler.cpp index c0488428a90..9fd2a8bd976 100644 --- a/js/src/ion/IonMacroAssembler.cpp +++ b/js/src/ion/IonMacroAssembler.cpp @@ -847,7 +847,8 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo) load32(Address(temp, BaselineFrame::reverseOffsetOfFrameSize()), temp); makeFrameDescriptor(temp, IonFrame_BaselineJS); push(temp); - push(Imm32(0)); // Fake return address. + loadPtr(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)), temp); + push(temp); enterFakeExitFrame(); // If monitorStub is non-null, handle resumeAddr appropriately.