Bug 1552766: Handle optimised out this when reporting missing bindings. r=jimb

In addition to normal bindings, which always use a proper identifier name, the
|this| binding can also be optimised out for arrow functions. The |this|
binding is stored in a binding named ".this", which, because it doesn't match
the IdentifierName syntax, triggered an assertion when generating its printable
representation. Workaround this assertion by special-casing ".this" when
reporting optimised out bindings.

Differential Revision: https://phabricator.services.mozilla.com/D47238

--HG--
extra : moz-landing-system : lando
This commit is contained in:
André Bargull 2019-10-07 13:43:55 +00:00
parent 3b9287f8d2
commit 14b2bea568
2 changed files with 54 additions and 10 deletions

View File

@ -0,0 +1,38 @@
var g = newGlobal({newCompartment: true});
var dbg = new Debugger(g);
g.eval(`
function f() {
// |this| in arrow-functions refers to the |this| binding in outer functions.
// So when |frame.eval("this")| is executed, the outer |this| binding should
// be returned, unless it has been optimised out.
(() => {})();
// Ensure a |this| binding is created for |f|.
return this;
}
`);
var errors = [];
function enterFrame(frame) {
// Disable the handler so we don't call it recursively through |frame.eval|.
dbg.onEnterFrame = undefined;
// Store the error when resolving |this| was unsuccessful.
var r = frame.eval("this");
if (r.throw) {
errors.push(r.throw);
}
// Re-enable the handler.
dbg.onEnterFrame = enterFrame;
};
dbg.onEnterFrame = enterFrame;
g.f();
assertEq(errors.length, 1);
assertEq(errors[0].unsafeDereference().toString(),
"Error: variable `this' has been optimized out");

View File

@ -1426,14 +1426,6 @@ void LiveEnvironmentVal::staticAsserts() {
namespace {
static void ReportOptimizedOut(JSContext* cx, HandleId id) {
if (UniqueChars printable =
IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsIdentifier)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_OPTIMIZED_OUT, printable.get());
}
}
/*
* DebugEnvironmentProxy is the handler for DebugEnvironmentProxy proxy
* objects. Having a custom handler (rather than trying to reuse js::Wrapper)
@ -1962,6 +1954,20 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler {
return true;
}
static void reportOptimizedOut(JSContext* cx, HandleId id) {
if (isThis(cx, id)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_OPTIMIZED_OUT, "this");
return;
}
if (UniqueChars printable =
IdToPrintableUTF8(cx, id, IdToPrintableBehavior::IdIsIdentifier)) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_DEBUG_OPTIMIZED_OUT, printable.get());
}
}
public:
static const char family;
static const DebugEnvironmentProxyHandler singleton;
@ -2077,7 +2083,7 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler {
case ACCESS_GENERIC:
return JS_GetOwnPropertyDescriptorById(cx, env, id, desc);
case ACCESS_LOST:
ReportOptimizedOut(cx, id);
reportOptimizedOut(cx, id);
return false;
default:
MOZ_CRASH("bad AccessResult");
@ -2157,7 +2163,7 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler {
}
return true;
case ACCESS_LOST:
ReportOptimizedOut(cx, id);
reportOptimizedOut(cx, id);
return false;
default:
MOZ_CRASH("bad AccessResult");