From 299bdcb06ff9460845e7e6e203a6d3b8b643ff1c Mon Sep 17 00:00:00 2001 From: Kannan Vijayan Date: Sun, 3 Mar 2013 12:23:35 -0500 Subject: [PATCH] Bug 845866 - Speed up lookup of IC entries. r=bhackett --- js/src/ion/BaselineInspector.h | 7 ++- js/src/ion/BaselineJIT.cpp | 79 ++++++++++++++++++++++++++-------- js/src/ion/BaselineJIT.h | 1 + 3 files changed, 67 insertions(+), 20 deletions(-) diff --git a/js/src/ion/BaselineInspector.h b/js/src/ion/BaselineInspector.h index cd60ecde38a..f03dedfa602 100644 --- a/js/src/ion/BaselineInspector.h +++ b/js/src/ion/BaselineInspector.h @@ -21,10 +21,11 @@ class BaselineInspector private: JSContext *cx; RootedScript script; + ICEntry *prevLookedUpEntry; public: BaselineInspector(JSContext *cx, RawScript rawScript) - : cx(cx), script(cx, rawScript) + : cx(cx), script(cx, rawScript), prevLookedUpEntry(NULL) { JS_ASSERT(script); } @@ -48,7 +49,9 @@ class BaselineInspector ICEntry &icEntryFromPC(jsbytecode *pc) { JS_ASSERT(hasBaselineScript()); JS_ASSERT(isValidPC(pc)); - return baselineScript()->icEntryFromPCOffset(pc - script->code); + ICEntry &ent = baselineScript()->icEntryFromPCOffset(pc - script->code, prevLookedUpEntry); + prevLookedUpEntry = &ent; + return ent; } public: diff --git a/js/src/ion/BaselineJIT.cpp b/js/src/ion/BaselineJIT.cpp index ad88d23bb38..2a004162737 100644 --- a/js/src/ion/BaselineJIT.cpp +++ b/js/src/ion/BaselineJIT.cpp @@ -391,15 +391,19 @@ BaselineScript::pcMappingReader(size_t indexEntry) ICEntry & BaselineScript::icEntryFromReturnOffset(CodeOffsetLabel returnOffset) { - // FIXME: Change this to something better than linear search (binary probe)? - for (size_t i = 0; i < numICEntries(); i++) { - ICEntry &entry = icEntry(i); - if (entry.returnOffset().offset() == returnOffset.offset()) - return entry; + size_t bottom = 0; + size_t top = numICEntries(); + size_t mid = (bottom + top) / 2; + while (mid < top) { + ICEntry &midEntry = icEntry(mid); + if (midEntry.returnOffset().offset() < returnOffset.offset()) + bottom = mid + 1; + else // if (midEntry.returnOffset().offset() >= returnOffset.offset()) + top = mid; + mid = (bottom + top) / 2; } - - JS_NOT_REACHED("No cache"); - return icEntry(0); + JS_ASSERT(icEntry(mid).returnOffset().offset() == returnOffset.offset()); + return icEntry(mid); } uint8_t * @@ -411,19 +415,58 @@ BaselineScript::returnAddressForIC(const ICEntry &ent) ICEntry & BaselineScript::icEntryFromPCOffset(uint32_t pcOffset) { - // FIXME: Change this to something better than linear search (binary probe)? - for (size_t i = 0; i < numICEntries(); i++) { - ICEntry &entry = icEntry(i); + // Multiple IC entries can have the same PC offset, but this method only looks for + // those which have isForOp() set. + size_t bottom = 0; + size_t top = numICEntries(); + size_t mid = (bottom + top) / 2; + while (mid < top) { + ICEntry &midEntry = icEntry(mid); + if (midEntry.pcOffset() < pcOffset) + bottom = mid + 1; + else if (midEntry.pcOffset() > pcOffset) + top = mid; + else + break; + mid = (bottom + top) / 2; + } + // Found an IC entry with a matching PC offset. Search backward, and then + // forward from this IC entry, looking for one with the same PC offset which + // has isForOp() set. + for (size_t i = mid; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i--) { + if (icEntry(i).isForOp()) + return icEntry(i); + } + for (size_t i = mid+1; i < numICEntries() && icEntry(i).pcOffset() == pcOffset; i++) { + if (icEntry(i).isForOp()) + return icEntry(i); + } + JS_NOT_REACHED("Invalid PC offset for IC entry."); + return icEntry(mid); +} - if (!entry.isForOp()) - continue; - - if (entry.pcOffset() == pcOffset) - return entry; +ICEntry & +BaselineScript::icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry) +{ + // Do a linear forward search from the last queried PC offset, or fallback to a + // binary search if the last offset is too far away. + if (prevLookedUpEntry && pcOffset >= prevLookedUpEntry->pcOffset() && + (pcOffset - prevLookedUpEntry->pcOffset()) <= 10) + { + uint32_t diff = pcOffset - prevLookedUpEntry->pcOffset(); + ICEntry *firstEntry = &icEntry(0); + ICEntry *lastEntry = &icEntry(numICEntries() - 1); + ICEntry *curEntry = prevLookedUpEntry; + while (curEntry >= firstEntry && curEntry <= lastEntry) { + if (curEntry->pcOffset() == pcOffset && curEntry->isForOp()) + break; + curEntry++; + } + JS_ASSERT(curEntry->pcOffset() == pcOffset && curEntry->isForOp()); + return *curEntry; } - JS_NOT_REACHED("No cache"); - return icEntry(0); + return icEntryFromPCOffset(pcOffset); } ICEntry & diff --git a/js/src/ion/BaselineJIT.h b/js/src/ion/BaselineJIT.h index 691424cc96e..45f5e2cad52 100644 --- a/js/src/ion/BaselineJIT.h +++ b/js/src/ion/BaselineJIT.h @@ -231,6 +231,7 @@ struct BaselineScript ICEntry &icEntry(size_t index); ICEntry &icEntryFromReturnOffset(CodeOffsetLabel returnOffset); ICEntry &icEntryFromPCOffset(uint32_t pcOffset); + ICEntry &icEntryFromPCOffset(uint32_t pcOffset, ICEntry *prevLookedUpEntry); ICEntry &icEntryFromReturnAddress(uint8_t *returnAddr); uint8_t *returnAddressForIC(const ICEntry &ent);