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 bool CreateLazyScriptsForCompartment(JSContext* cx) { AutoObjectVector lazyFunctions(cx); // Find all live root lazy functions in the compartment: those which // have not been compiled, which have a source object, indicating that // they have a parent, and which do not have an uncompiled enclosing // script. The last condition is so that we don't compile lazy scripts // whose enclosing scripts failed to compile, indicating that the lazy // script did not escape the script. // // Note that while we ideally iterate over LazyScripts, LazyScripts do not // currently stand in 1-1 relation with JSScripts; JSFunctions with the // same LazyScript may create different JSScripts due to relazification of // clones. See bug 1105306. for (gc::ZoneCellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) { JSObject* obj = i.get<JSObject>(); if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) { JSFunction* fun = &obj->as<JSFunction>(); if (fun->isInterpretedLazy()) { LazyScript* lazy = fun->lazyScriptOrNull(); if (lazy && lazy->sourceObject() && !lazy->maybeScript() && !lazy->hasUncompiledEnclosingScript()) { if (!lazyFunctions.append(fun)) return false; } } } } // Create scripts for each lazy function, updating the list of functions to // process with any newly exposed inner functions in created scripts. // A function cannot be delazified until its outer script exists. for (size_t i = 0; i < lazyFunctions.length(); i++) { JSFunction* fun = &lazyFunctions[i]->as<JSFunction>(); // lazyFunctions may have been populated with multiple functions for // a lazy script. if (!fun->isInterpretedLazy()) continue; LazyScript* lazy = fun->lazyScript(); bool lazyScriptHadNoScript = !lazy->maybeScript(); JSScript* script = fun->getOrCreateScript(cx); if (!script) return false; if (lazyScriptHadNoScript && !AddInnerLazyFunctionsFromScript(script, lazyFunctions)) return false; } return true; }
static void MarkFunctionsWithinEvalScript(JSScript *script) { // Mark top level functions in an eval script as being within an eval and, // if applicable, inside a with statement. if (!script->hasObjects()) return; ObjectArray *objects = script->objects(); size_t start = script->innerObjectsStart(); for (size_t i = start; i < objects->length; i++) { JSObject *obj = objects->vector[i]; if (obj->is<JSFunction>()) { JSFunction *fun = &obj->as<JSFunction>(); if (fun->hasScript()) fun->nonLazyScript()->setDirectlyInsideEval(); else if (fun->isInterpretedLazy()) fun->lazyScript()->setDirectlyInsideEval(); } } }
static bool CreateLazyScriptsForCompartment(JSContext* cx) { AutoObjectVector lazyFunctions(cx); if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION)) return false; // Methods, for instance {get method() {}}, are extended functions that can // be relazified, so we need to handle those as well. if (!AddLazyFunctionsForCompartment(cx, lazyFunctions, AllocKind::FUNCTION_EXTENDED)) return false; // Create scripts for each lazy function, updating the list of functions to // process with any newly exposed inner functions in created scripts. // A function cannot be delazified until its outer script exists. for (size_t i = 0; i < lazyFunctions.length(); i++) { JSFunction* fun = &lazyFunctions[i]->as<JSFunction>(); // lazyFunctions may have been populated with multiple functions for // a lazy script. if (!fun->isInterpretedLazy()) continue; LazyScript* lazy = fun->lazyScript(); bool lazyScriptHadNoScript = !lazy->maybeScript(); JSScript* script = fun->getOrCreateScript(cx); if (!script) return false; if (lazyScriptHadNoScript && !AddInnerLazyFunctionsFromScript(script, lazyFunctions)) return false; } return true; }