author | Sean Stangl <sstangl@mozilla.com> |
Mon, 01 Oct 2012 16:59:11 -0700 | |
changeset 108797 | f625a0dc10524e71789677b09189eed777078333 |
parent 108796 | c2c611cc8df4b44d2d9b33b1ec8e8ca7866af8ca |
child 108798 | 377cda004bd74736636556724ce69bf27d9c31b6 |
push id | 15700 |
push user | sean.stangl@gmail.com |
push date | Mon, 01 Oct 2012 23:59:30 +0000 |
treeherder | mozilla-inbound@f625a0dc1052 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | pierron |
bugs | 794679 |
milestone | 18.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/ion/IonFrames.cpp +++ b/js/src/ion/IonFrames.cpp @@ -11,16 +11,18 @@ #include "jsscript.h" #include "jsfun.h" #include "IonCompartment.h" #include "IonFrames-inl.h" #include "IonFrameIterator-inl.h" #include "Safepoints.h" #include "IonSpewer.h" #include "IonMacroAssembler.h" +#include "PcScriptCache.h" +#include "PcScriptCache-inl.h" #include "gc/Marking.h" #include "SnapshotReader.h" #include "Safepoints.h" #include "VMFunctions.h" using namespace js; using namespace js::ion; @@ -673,25 +675,47 @@ ion::AutoTempAllocatorRooter::trace(JSTr } void ion::GetPcScript(JSContext *cx, MutableHandleScript scriptRes, jsbytecode **pcRes) { JS_ASSERT(cx->fp()->beginsIonActivation()); IonSpew(IonSpew_Snapshots, "Recover PC & Script from the last frame."); - // Recover the innermost inlined frame. - IonFrameIterator it(cx->runtime->ionTop); - ++it; + JSRuntime *rt = cx->runtime; + + // Recover the return address. + IonFrameIterator it(rt->ionTop); + uint8_t *retAddr = it.returnAddress(); + uint32_t hash = PcScriptCache::Hash(retAddr); + JS_ASSERT(retAddr != NULL); + + // Lazily initialize the cache. The allocation may safely fail and will not GC. + if (JS_UNLIKELY(rt->ionPcScriptCache == NULL)) { + rt->ionPcScriptCache = (PcScriptCache *)js_malloc(sizeof(struct PcScriptCache)); + if (rt->ionPcScriptCache) + rt->ionPcScriptCache->clear(rt->gcNumber); + } + + // Attempt to lookup address in cache. + if (rt->ionPcScriptCache && rt->ionPcScriptCache->get(rt, hash, retAddr, scriptRes, pcRes)) + return; + + // Lookup failed: undertake expensive process to recover the innermost inlined frame. + ++it; // Skip exit frame. InlineFrameIterator ifi(&it); // Set the result. scriptRes.set(ifi.script()); if (pcRes) *pcRes = ifi.pc(); + + // Add entry to cache. + if (rt->ionPcScriptCache) + rt->ionPcScriptCache->add(hash, retAddr, ifi.pc(), ifi.script()); } void OsiIndex::fixUpOffset(MacroAssembler &masm) { callPointDisplacement_ = masm.actualOffset(callPointDisplacement_); }
new file mode 100644 --- /dev/null +++ b/js/src/ion/PcScriptCache-inl.h @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef pcscriptcache_inl_h__ +#define pcscriptcache_inl_h__ + +#include "PcScriptCache.h" + +namespace js { +namespace ion { + +// Get a value from the cache. May perform lazy allocation. +bool +PcScriptCache::get(JSRuntime *rt, uint32_t hash, uint8_t *addr, + MutableHandleScript scriptRes, jsbytecode **pcRes) +{ + // If a GC occurred, lazily clear the cache now. + if (gcNumber != rt->gcNumber) { + clear(rt->gcNumber); + return false; + } + + if (entries[hash].returnAddress != addr) + return false; + + scriptRes.set(entries[hash].script); + if (pcRes) + *pcRes = entries[hash].pc; + + return true; +} + +} // namespace ion +} // namespace js + +#endif // pcscriptcache_inl_h__
new file mode 100644 --- /dev/null +++ b/js/src/ion/PcScriptCache.h @@ -0,0 +1,64 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: set ts=4 sw=4 et tw=99: + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef pcscriptcache_h__ +#define pcscriptcache_h__ + +// Defines a fixed-size hash table solely for the purpose of caching ion::GetPcScript(). +// One cache is attached to each JSRuntime; it functions as if cleared on GC. + +struct JSRuntime; + +namespace js { +namespace ion { + +struct PcScriptCacheEntry +{ + uint8_t *returnAddress; // Key into the hash table. + jsbytecode *pc; // Cached PC. + JSScript *script; // Cached script. +}; + +struct PcScriptCache +{ + static const uint32_t Length = 73; + + // GC number at the time the cache was filled or created. + // Storing and checking against this number allows us to not bother + // clearing this cache on every GC -- only when actually necessary. + uint64_t gcNumber; + + // List of cache entries. + PcScriptCacheEntry entries[Length]; + + void clear(uint64_t gcNumber) { + for (uint32_t i = 0; i < Length; i++) + entries[i].returnAddress = NULL; + this->gcNumber = gcNumber; + } + + // Get a value from the cache. May perform lazy allocation. + // Defined in PcScriptCache-inl.h. + bool get(JSRuntime *rt, uint32_t hash, uint8_t *addr, + MutableHandleScript scriptRes, jsbytecode **pcRes); + + void add(uint32_t hash, uint8_t *addr, jsbytecode *pc, JSScript *script) { + entries[hash].returnAddress = addr; + entries[hash].pc = pc; + entries[hash].script = script; + } + + static uint32_t Hash(uint8_t *addr) { + uint32_t key = (uint32_t)((uintptr_t)addr); + return ((key >> 3) * 2654435761) % Length; + } +}; + +} // namespace ion +} // namespace js + +#endif // pcscriptcache_h__
--- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -854,16 +854,17 @@ JSRuntime::JSRuntime() noGCOrAllocationCheck(0), #endif inOOMReport(0), jitHardening(false), ionTop(NULL), ionJSContext(NULL), ionStackLimit(0), ionActivation(NULL), + ionPcScriptCache(NULL), ionReturnOverride_(MagicValue(JS_ARG_POISON)) { /* Initialize infallibly first, so we can goto bad and JS_DestroyRuntime. */ JS_INIT_CLIST(&contextList); JS_INIT_CLIST(&debuggerList); PodZero(&debugHooks); PodZero(&atomState); @@ -1001,16 +1002,19 @@ JSRuntime::~JSRuntime() #endif js_delete(bumpAlloc_); js_delete(mathCache_); #ifdef JS_METHODJIT js_delete(jaegerRuntime_); #endif js_delete(execAlloc_); /* Delete after jaegerRuntime_. */ + + if (ionPcScriptCache) + js_delete(ionPcScriptCache); } #ifdef JS_THREADSAFE void JSRuntime::setOwnerThread() { JS_ASSERT(ownerThread_ == (void *)0xc1ea12); /* "clear" */ JS_ASSERT(requestDepth == 0);
--- a/js/src/jscntxt.h +++ b/js/src/jscntxt.h @@ -28,16 +28,18 @@ #include "ds/LifoAlloc.h" #include "gc/Statistics.h" #include "js/HashTable.h" #include "js/Vector.h" #include "vm/Stack.h" #include "vm/SPSProfiler.h" +#include "ion/PcScriptCache.h" + #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable:4100) /* Silence unreferenced formal parameter warnings */ #pragma warning(push) #pragma warning(disable:4355) /* Silence warning about "this" used in base member initializer list */ #endif JS_BEGIN_EXTERN_C @@ -942,16 +944,19 @@ struct JSRuntime : js::RuntimeFriendFiel void resetIonStackLimit() { ionStackLimit = nativeStackLimit; } // This points to the most recent Ion activation running on the thread. js::ion::IonActivation *ionActivation; + // Cache for ion::GetPcScript(). + js::ion::PcScriptCache *ionPcScriptCache; + private: // In certain cases, we want to optimize certain opcodes to typed instructions, // to avoid carrying an extra register to feed into an unbox. Unfortunately, // that's not always possible. For example, a GetPropertyCacheT could return a // typed double, but if it takes its out-of-line path, it could return an // object, and trigger invalidation. The invalidation bailout will consider the // return value to be a double, and create a garbage Value. //