mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 934799 - Part 1: Lazify delazifying lazy scripts in debug mode. (r=jimb)
This commit is contained in:
parent
988e6cea5f
commit
2e736ecad5
@ -141,8 +141,7 @@ CanLazilyParse(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
|
|||||||
{
|
{
|
||||||
return options.canLazilyParse &&
|
return options.canLazilyParse &&
|
||||||
options.compileAndGo &&
|
options.compileAndGo &&
|
||||||
options.sourcePolicy == CompileOptions::SAVE_SOURCE &&
|
options.sourcePolicy == CompileOptions::SAVE_SOURCE;
|
||||||
!cx->compartment()->debugMode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -1788,7 +1788,9 @@ BytecodeEmitter::tellDebuggerAboutCompiledScript(ExclusiveContext *cx)
|
|||||||
|
|
||||||
RootedFunction function(cx, script->function());
|
RootedFunction function(cx, script->function());
|
||||||
CallNewScriptHook(cx->asJSContext(), script, function);
|
CallNewScriptHook(cx->asJSContext(), script, function);
|
||||||
if (!parent) {
|
// Lazy scripts are never top level (despite always being invoked with a
|
||||||
|
// nullptr parent), and so the hook should never be fired.
|
||||||
|
if (emitterMode != LazyFunction && !parent) {
|
||||||
GlobalObject *compileAndGoGlobal = nullptr;
|
GlobalObject *compileAndGoGlobal = nullptr;
|
||||||
if (script->compileAndGo)
|
if (script->compileAndGo)
|
||||||
compileAndGoGlobal = &script->global();
|
compileAndGoGlobal = &script->global();
|
||||||
|
@ -673,20 +673,20 @@ CreateLazyScriptsForCompartment(JSContext *cx)
|
|||||||
{
|
{
|
||||||
AutoObjectVector lazyFunctions(cx);
|
AutoObjectVector lazyFunctions(cx);
|
||||||
|
|
||||||
// Find all root lazy functions in the compartment: those which have not been
|
// Find all live lazy scripts in the compartment, and via them all root
|
||||||
// compiled and which have a source object, indicating that their parent has
|
// lazy functions in the compartment: those which have not been compiled
|
||||||
// been compiled.
|
// and which have a source object, indicating that their parent has been
|
||||||
for (gc::CellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
|
// compiled.
|
||||||
JSObject *obj = i.get<JSObject>();
|
for (gc::CellIter i(cx->zone(), gc::FINALIZE_LAZY_SCRIPT); !i.done(); i.next()) {
|
||||||
if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
|
LazyScript *lazy = i.get<LazyScript>();
|
||||||
JSFunction *fun = &obj->as<JSFunction>();
|
JSFunction *fun = lazy->function();
|
||||||
if (fun->isInterpretedLazy()) {
|
if (fun->compartment() == cx->compartment() &&
|
||||||
LazyScript *lazy = fun->lazyScriptOrNull();
|
lazy->sourceObject() && !lazy->maybeScript())
|
||||||
if (lazy && lazy->sourceObject() && !lazy->maybeScript()) {
|
{
|
||||||
if (!lazyFunctions.append(fun))
|
MOZ_ASSERT(fun->isInterpretedLazy());
|
||||||
return false;
|
MOZ_ASSERT(lazy == fun->lazyScriptOrNull());
|
||||||
}
|
if (!lazyFunctions.append(fun))
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -708,19 +708,16 @@ CreateLazyScriptsForCompartment(JSContext *cx)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repoint any clones of the original functions to their new script.
|
return true;
|
||||||
for (gc::CellIter 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->maybeScript())
|
|
||||||
fun->existingScript();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
JSCompartment::ensureDelazifyScriptsForDebugMode(JSContext *cx)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(cx->compartment() == this);
|
||||||
|
if ((debugModeBits & DebugNeedDelazification) && !CreateLazyScriptsForCompartment(cx))
|
||||||
|
return false;
|
||||||
|
debugModeBits &= ~DebugNeedDelazification;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -728,7 +725,7 @@ bool
|
|||||||
JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidation &invalidate)
|
JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidation &invalidate)
|
||||||
{
|
{
|
||||||
bool enabledBefore = debugMode();
|
bool enabledBefore = debugMode();
|
||||||
bool enabledAfter = (debugModeBits & ~unsigned(DebugFromC)) || b;
|
bool enabledAfter = (debugModeBits & DebugModeFromMask & ~DebugFromC) || b;
|
||||||
|
|
||||||
// Debug mode can be enabled only when no scripts from the target
|
// Debug mode can be enabled only when no scripts from the target
|
||||||
// compartment are on the stack. It would even be incorrect to discard just
|
// compartment are on the stack. It would even be incorrect to discard just
|
||||||
@ -747,11 +744,9 @@ JSCompartment::setDebugModeFromC(JSContext *cx, bool b, AutoDebugModeInvalidatio
|
|||||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
|
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_DEBUG_NOT_IDLE);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (enabledAfter && !CreateLazyScriptsForCompartment(cx))
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
debugModeBits = (debugModeBits & ~unsigned(DebugFromC)) | (b ? DebugFromC : 0);
|
debugModeBits = (debugModeBits & ~DebugFromC) | (b ? DebugFromC : 0);
|
||||||
JS_ASSERT(debugMode() == enabledAfter);
|
JS_ASSERT(debugMode() == enabledAfter);
|
||||||
if (enabledBefore != enabledAfter) {
|
if (enabledBefore != enabledAfter) {
|
||||||
updateForDebugMode(cx->runtime()->defaultFreeOp(), invalidate);
|
updateForDebugMode(cx->runtime()->defaultFreeOp(), invalidate);
|
||||||
@ -801,8 +796,6 @@ JSCompartment::addDebuggee(JSContext *cx,
|
|||||||
Rooted<GlobalObject*> global(cx, globalArg);
|
Rooted<GlobalObject*> global(cx, globalArg);
|
||||||
|
|
||||||
bool wasEnabled = debugMode();
|
bool wasEnabled = debugMode();
|
||||||
if (!wasEnabled && !CreateLazyScriptsForCompartment(cx))
|
|
||||||
return false;
|
|
||||||
if (!debuggees.put(global)) {
|
if (!debuggees.put(global)) {
|
||||||
js_ReportOutOfMemory(cx);
|
js_ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
|
@ -278,7 +278,13 @@ struct JSCompartment
|
|||||||
js::WeakMapBase *gcWeakMapList;
|
js::WeakMapBase *gcWeakMapList;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum { DebugFromC = 1, DebugFromJS = 2 };
|
enum {
|
||||||
|
DebugFromC = 1 << 0,
|
||||||
|
DebugFromJS = 1 << 1,
|
||||||
|
DebugNeedDelazification = 1 << 2
|
||||||
|
};
|
||||||
|
|
||||||
|
static const unsigned DebugModeFromMask = DebugFromC | DebugFromJS;
|
||||||
|
|
||||||
unsigned debugModeBits; // see debugMode() below
|
unsigned debugModeBits; // see debugMode() below
|
||||||
|
|
||||||
@ -356,13 +362,34 @@ struct JSCompartment
|
|||||||
* by Debugger objects. Therefore debugModeBits has the DebugFromC bit set
|
* by Debugger objects. Therefore debugModeBits has the DebugFromC bit set
|
||||||
* if the C API wants debug mode and the DebugFromJS bit set if debuggees
|
* if the C API wants debug mode and the DebugFromJS bit set if debuggees
|
||||||
* is non-empty.
|
* is non-empty.
|
||||||
|
*
|
||||||
|
* When toggling on, DebugNeedDelazification is set to signal that
|
||||||
|
* Debugger methods which depend on seeing all scripts (like findScripts)
|
||||||
|
* need to delazify the scripts in the compartment first.
|
||||||
*/
|
*/
|
||||||
bool debugMode() const { return !!debugModeBits; }
|
bool debugMode() const {
|
||||||
|
return !!(debugModeBits & DebugModeFromMask);
|
||||||
|
}
|
||||||
|
|
||||||
/* True if any scripts from this compartment are on the JS stack. */
|
/* True if any scripts from this compartment are on the JS stack. */
|
||||||
bool hasScriptsOnStack();
|
bool hasScriptsOnStack();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Schedule the compartment to be delazified. Called from
|
||||||
|
* LazyScript::Create.
|
||||||
|
*/
|
||||||
|
void scheduleDelazificationForDebugMode() {
|
||||||
|
debugModeBits |= DebugNeedDelazification;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we scheduled delazification for turning on debug mode, delazify all
|
||||||
|
* scripts.
|
||||||
|
*/
|
||||||
|
bool ensureDelazifyScriptsForDebugMode(JSContext *cx);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/* This is called only when debugMode() has just toggled. */
|
/* This is called only when debugMode() has just toggled. */
|
||||||
void updateForDebugMode(js::FreeOp *fop, js::AutoDebugModeInvalidation &invalidate);
|
void updateForDebugMode(js::FreeOp *fop, js::AutoDebugModeInvalidation &invalidate);
|
||||||
|
|
||||||
|
@ -3043,6 +3043,8 @@ LazyScript::Create(ExclusiveContext *cx, HandleFunction fun,
|
|||||||
if (!res)
|
if (!res)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
|
cx->compartment()->scheduleDelazificationForDebugMode();
|
||||||
|
|
||||||
return new (res) LazyScript(fun, table, numFreeVariables, numInnerFunctions, version,
|
return new (res) LazyScript(fun, table, numFreeVariables, numInnerFunctions, version,
|
||||||
begin, end, lineno, column);
|
begin, end, lineno, column);
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,25 @@ ReportMoreArgsNeeded(JSContext *cx, const char *name, unsigned required)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
EnsureFunctionHasScript(JSContext *cx, JSFunction *fun)
|
||||||
|
{
|
||||||
|
if (fun->isInterpretedLazy()) {
|
||||||
|
AutoCompartment ac(cx, fun);
|
||||||
|
return !!fun->getOrCreateScript(cx);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline JSScript *
|
||||||
|
GetOrCreateFunctionScript(JSContext *cx, JSFunction *fun)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(fun->isInterpreted());
|
||||||
|
if (!EnsureFunctionHasScript(cx, fun))
|
||||||
|
return nullptr;
|
||||||
|
return fun->nonLazyScript();
|
||||||
|
}
|
||||||
|
|
||||||
#define REQUIRE_ARGC(name, n) \
|
#define REQUIRE_ARGC(name, n) \
|
||||||
JS_BEGIN_MACRO \
|
JS_BEGIN_MACRO \
|
||||||
if (argc < (n)) \
|
if (argc < (n)) \
|
||||||
@ -686,6 +705,9 @@ Debugger::wrapDebuggeeValue(JSContext *cx, MutableHandleValue vp)
|
|||||||
if (vp.isObject()) {
|
if (vp.isObject()) {
|
||||||
RootedObject obj(cx, &vp.toObject());
|
RootedObject obj(cx, &vp.toObject());
|
||||||
|
|
||||||
|
if (obj->is<JSFunction>() && !EnsureFunctionHasScript(cx, &obj->as<JSFunction>()))
|
||||||
|
return false;
|
||||||
|
|
||||||
ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj);
|
ObjectWeakMap::AddPtr p = objects.lookupForAdd(obj);
|
||||||
if (p) {
|
if (p) {
|
||||||
vp.setObject(*p->value);
|
vp.setObject(*p->value);
|
||||||
@ -2403,10 +2425,14 @@ class Debugger::ScriptQuery {
|
|||||||
if (!prepareQuery())
|
if (!prepareQuery())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
JSCompartment *singletonComp = nullptr;
|
||||||
|
if (compartments.count() == 1)
|
||||||
|
singletonComp = compartments.all().front();
|
||||||
|
|
||||||
/* Search each compartment for debuggee scripts. */
|
/* Search each compartment for debuggee scripts. */
|
||||||
vector = v;
|
vector = v;
|
||||||
oom = false;
|
oom = false;
|
||||||
IterateScripts(cx->runtime(), nullptr, this, considerScript);
|
IterateScripts(cx->runtime(), singletonComp, this, considerScript);
|
||||||
if (oom) {
|
if (oom) {
|
||||||
js_ReportOutOfMemory(cx);
|
js_ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
@ -2476,10 +2502,21 @@ class Debugger::ScriptQuery {
|
|||||||
/* Indicates whether OOM has occurred while matching. */
|
/* Indicates whether OOM has occurred while matching. */
|
||||||
bool oom;
|
bool oom;
|
||||||
|
|
||||||
|
bool addCompartment(JSCompartment *comp) {
|
||||||
|
{
|
||||||
|
// All scripts in the debuggee compartment must be visible, so
|
||||||
|
// delazify everything.
|
||||||
|
AutoCompartment ac(cx, comp);
|
||||||
|
if (!comp->ensureDelazifyScriptsForDebugMode(cx))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return compartments.put(comp);
|
||||||
|
}
|
||||||
|
|
||||||
/* Arrange for this ScriptQuery to match only scripts that run in |global|. */
|
/* Arrange for this ScriptQuery to match only scripts that run in |global|. */
|
||||||
bool matchSingleGlobal(GlobalObject *global) {
|
bool matchSingleGlobal(GlobalObject *global) {
|
||||||
JS_ASSERT(compartments.count() == 0);
|
JS_ASSERT(compartments.count() == 0);
|
||||||
if (!compartments.put(global->compartment())) {
|
if (!addCompartment(global->compartment())) {
|
||||||
js_ReportOutOfMemory(cx);
|
js_ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2494,7 +2531,7 @@ class Debugger::ScriptQuery {
|
|||||||
JS_ASSERT(compartments.count() == 0);
|
JS_ASSERT(compartments.count() == 0);
|
||||||
/* Build our compartment set from the debugger's set of debuggee globals. */
|
/* Build our compartment set from the debugger's set of debuggee globals. */
|
||||||
for (GlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) {
|
for (GlobalObjectSet::Range r = debugger->debuggees.all(); !r.empty(); r.popFront()) {
|
||||||
if (!compartments.put(r.front()->compartment())) {
|
if (!addCompartment(r.front()->compartment())) {
|
||||||
js_ReportOutOfMemory(cx);
|
js_ReportOutOfMemory(cx);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2937,8 +2974,10 @@ DebuggerScript_getChildScripts(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
for (uint32_t i = script->innerObjectsStart(); i < objects->length; i++) {
|
for (uint32_t i = script->innerObjectsStart(); i < objects->length; i++) {
|
||||||
obj = objects->vector[i];
|
obj = objects->vector[i];
|
||||||
if (obj->is<JSFunction>()) {
|
if (obj->is<JSFunction>()) {
|
||||||
fun = static_cast<JSFunction *>(obj.get());
|
fun = &obj->as<JSFunction>();
|
||||||
funScript = fun->nonLazyScript();
|
funScript = GetOrCreateFunctionScript(cx, fun);
|
||||||
|
if (!funScript)
|
||||||
|
return false;
|
||||||
s = dbg->wrapScript(cx, funScript);
|
s = dbg->wrapScript(cx, funScript);
|
||||||
if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
|
if (!s || !js_NewbornArrayPush(cx, result, ObjectValue(*s)))
|
||||||
return false;
|
return false;
|
||||||
@ -4659,14 +4698,9 @@ DebuggerObject_getParameterNames(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
result->ensureDenseInitializedLength(cx, 0, fun->nargs);
|
result->ensureDenseInitializedLength(cx, 0, fun->nargs);
|
||||||
|
|
||||||
if (fun->isInterpreted()) {
|
if (fun->isInterpreted()) {
|
||||||
RootedScript script(cx);
|
RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
|
||||||
|
if (!script)
|
||||||
{
|
return false;
|
||||||
AutoCompartment ac(cx, fun);
|
|
||||||
script = fun->getOrCreateScript(cx);
|
|
||||||
if (!script)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
JS_ASSERT(fun->nargs == script->bindings.numArgs());
|
JS_ASSERT(fun->nargs == script->bindings.numArgs());
|
||||||
|
|
||||||
@ -4708,15 +4742,9 @@ DebuggerObject_getScript(JSContext *cx, unsigned argc, Value *vp)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
RootedScript script(cx);
|
RootedScript script(cx, GetOrCreateFunctionScript(cx, fun));
|
||||||
|
if (!script)
|
||||||
{
|
return false;
|
||||||
AutoCompartment ac(cx, obj);
|
|
||||||
|
|
||||||
script = fun->getOrCreateScript(cx);
|
|
||||||
if (!script)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Only hand out debuggee scripts. */
|
/* Only hand out debuggee scripts. */
|
||||||
if (!dbg->observesScript(script)) {
|
if (!dbg->observesScript(script)) {
|
||||||
|
Loading…
Reference in New Issue
Block a user