author | Tooru Fujisawa <arai_a@mac.com> |
Thu, 26 Jul 2018 12:36:16 +0900 | |
changeset 428520 | dea04c3e53869104c0e79e6b5ecc4cd9df2f0d17 |
parent 428519 | 1a5bdbbfc37535b866b79015bbe849bf8f6e42bd |
child 428521 | 49f82b7a2cb1991eec2db836efca5762d1e50a06 |
push id | 34337 |
push user | ncsoregi@mozilla.com |
push date | Thu, 26 Jul 2018 21:58:45 +0000 |
treeherder | mozilla-central@8f2f847b2f9d [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | jimb |
bugs | 1434305 |
milestone | 63.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/gc/GC.h +++ b/js/src/gc/GC.h @@ -107,23 +107,28 @@ IterateHeapUnbarrieredForZone(JSContext* /* * Invoke chunkCallback on every in-use chunk. */ extern void IterateChunks(JSContext* cx, void* data, IterateChunkCallback chunkCallback); typedef void (*IterateScriptCallback)(JSRuntime* rt, void* data, JSScript* script, const JS::AutoRequireNoGC& nogc); +typedef void (*IterateLazyScriptCallback)(JSRuntime* rt, void* data, LazyScript* lazyScript, + const JS::AutoRequireNoGC& nogc); /* * Invoke scriptCallback on every in-use script for the given realm or for all * realms if it is null. */ extern void IterateScripts(JSContext* cx, JS::Realm* realm, void* data, IterateScriptCallback scriptCallback); +extern void +IterateLazyScripts(JSContext* cx, JS::Realm* realm, void* data, + IterateLazyScriptCallback lazyScriptCallback); JS::Realm* NewRealm(JSContext* cx, JSPrincipals* principals, const JS::RealmOptions& options); namespace gc { void FinishGC(JSContext* cx);
--- a/js/src/gc/PublicIterators.cpp +++ b/js/src/gc/PublicIterators.cpp @@ -79,38 +79,112 @@ js::IterateChunks(JSContext* cx, void* d { AutoPrepareForTracing prep(cx); AutoLockGC lock(cx->runtime()); for (auto chunk = cx->runtime()->gc.allNonEmptyChunks(lock); !chunk.done(); chunk.next()) chunkCallback(cx->runtime(), data, chunk); } -void -js::IterateScripts(JSContext* cx, Realm* realm, void* data, IterateScriptCallback scriptCallback) +static void +TraverseInnerLazyScriptsForLazyScript(JSContext* cx, void* data, LazyScript* enclosingLazyScript, + IterateLazyScriptCallback lazyScriptCallback, + const JS::AutoRequireNoGC& nogc) +{ + GCPtrFunction* innerFunctions = enclosingLazyScript->innerFunctions(); + for (size_t i = 0, len = enclosingLazyScript->numInnerFunctions(); i < len; i++) { + JSFunction* fun = innerFunctions[i]; + + // LazyScript::CreateForXDR temporarily initializes innerFunctions with + // its own function, but it should be overwritten with correct + // inner functions before getting inserted into parent's innerFunctions. + MOZ_ASSERT(fun != enclosingLazyScript->functionNonDelazifying()); + + if (!fun->isInterpretedLazy()) + return; + + LazyScript* lazyScript = fun->lazyScript(); + MOZ_ASSERT(lazyScript->hasEnclosingScope() || lazyScript->hasEnclosingLazyScript()); + MOZ_ASSERT_IF(lazyScript->hasEnclosingLazyScript(), + lazyScript->enclosingLazyScript() == enclosingLazyScript); + + lazyScriptCallback(cx->runtime(), data, lazyScript, nogc); + + TraverseInnerLazyScriptsForLazyScript(cx, data, lazyScript, lazyScriptCallback, nogc); + } +} + +static inline void +DoScriptCallback(JSContext* cx, void* data, LazyScript* lazyScript, + IterateLazyScriptCallback lazyScriptCallback, + const JS::AutoRequireNoGC& nogc) +{ + // We call the callback only for the LazyScript that: + // (a) its enclosing script has ever been fully compiled and + // itself is delazifyable (handled in this function) + // (b) it is contained in the (a)'s inner function tree + // (handled in TraverseInnerLazyScriptsForLazyScript) + if (!lazyScript->enclosingScriptHasEverBeenCompiled()) + return; + + lazyScriptCallback(cx->runtime(), data, lazyScript, nogc); + + TraverseInnerLazyScriptsForLazyScript(cx, data, lazyScript, lazyScriptCallback, nogc); +} + +static inline void +DoScriptCallback(JSContext* cx, void* data, JSScript* script, + IterateScriptCallback scriptCallback, + const JS::AutoRequireNoGC& nogc) +{ + // We check for presence of script->isUncompleted() because it is + // possible that the script was created and thus exposed to GC, but *not* + // fully initialized from fullyInit{FromEmitter,Trivial} due to errors. + if (script->isUncompleted()) + return; + + scriptCallback(cx->runtime(), data, script, nogc); +} + +template <typename T, typename Callback> +static void +IterateScriptsImpl(JSContext* cx, Realm* realm, void* data, Callback scriptCallback) { MOZ_ASSERT(!cx->suppressGC); AutoEmptyNursery empty(cx); AutoPrepareForTracing prep(cx); JS::AutoSuppressGCAnalysis nogc; if (realm) { Zone* zone = realm->zone(); - for (auto script = zone->cellIter<JSScript>(empty); !script.done(); script.next()) { + for (auto script = zone->cellIter<T>(empty); !script.done(); script.next()) { if (script->realm() == realm) - scriptCallback(cx->runtime(), data, script, nogc); + DoScriptCallback(cx, data, script, scriptCallback, nogc); } } else { for (ZonesIter zone(cx->runtime(), SkipAtoms); !zone.done(); zone.next()) { - for (auto script = zone->cellIter<JSScript>(empty); !script.done(); script.next()) - scriptCallback(cx->runtime(), data, script, nogc); + for (auto script = zone->cellIter<T>(empty); !script.done(); script.next()) + DoScriptCallback(cx, data, script, scriptCallback, nogc); } } } +void +js::IterateScripts(JSContext* cx, Realm* realm, void* data, IterateScriptCallback scriptCallback) +{ + IterateScriptsImpl<JSScript>(cx, realm, data, scriptCallback); +} + +void +js::IterateLazyScripts(JSContext* cx, Realm* realm, void* data, + IterateLazyScriptCallback scriptCallback) +{ + IterateScriptsImpl<LazyScript>(cx, realm, data, scriptCallback); +} + static void IterateGrayObjects(Zone* zone, GCThingCallback cellCallback, void* data) { for (auto kind : ObjectAllocKinds()) { for (GrayObjectIter obj(zone, kind); !obj.done(); obj.next()) { if (obj->asTenured().isMarkedGray()) cellCallback(data, JS::GCCellPtr(obj.get())); }
--- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -4568,21 +4568,17 @@ class MOZ_STACK_CLASS Debugger::ScriptQu } /* * If |script| matches this query, append it to |vector| or place it in * |innermostForRealm|, as appropriate. Set |oom| if an out of memory * condition occurred. */ void consider(JSScript* script, const JS::AutoRequireNoGC& nogc) { - // We check for presence of script->isUncompleted() because it is - // possible that the script was created and thus exposed to GC, but - // *not* fully initialized from fullyInit{FromEmitter,Trivial} due to - // errors. - if (oom || script->selfHosted() || script->isUncompleted()) + if (oom || script->selfHosted()) return; Realm* realm = script->realm(); if (!realms.has(realm)) return; if (urlCString.ptr()) { bool gotFilename = false; if (script->filename() && strcmp(script->filename(), urlCString.ptr()) == 0) gotFilename = true;