зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1621201: Skip shape guards for immutable lexical environments. r=jandem
Differential Revision: https://phabricator.services.mozilla.com/D221468
This commit is contained in:
Родитель
36b81dbf5d
Коммит
c62100bc74
|
@ -0,0 +1,38 @@
|
|||
this.a = 0;
|
||||
|
||||
function f(y) {
|
||||
// Direct eval to make an extensible environment. Variables lookups within
|
||||
// nested environments are now dynamic.
|
||||
eval("");
|
||||
|
||||
{
|
||||
// Block lexical environment whose shape guard we want to omit.
|
||||
let w = y;
|
||||
|
||||
function g() {
|
||||
// BindName "a" # ENV
|
||||
// Dup # ENV ENV
|
||||
// GetBoundName "a" # ENV ENV.a
|
||||
// GetAliasedVar "w" (hops = 0, slot = 2) # ENV ENV.a w
|
||||
// CheckAliasedLexical "w" (hops = 0, slot = 2) # ENV ENV.a w
|
||||
// Add # ENV (ENV.a += w)
|
||||
// NopIsAssignOp # ENV (ENV.a += w)
|
||||
// SetName "a" # (ENV.a += w)
|
||||
// Pop #
|
||||
a += w;
|
||||
}
|
||||
|
||||
for (var i = 0; i < 150; ++i) {
|
||||
// Introduce a new binding in the global lexical environment which
|
||||
// shadows the global property "a".
|
||||
if (i === 100) {
|
||||
evaluate("let a = 1000");
|
||||
}
|
||||
g();
|
||||
}
|
||||
|
||||
assertEq(a, 1050);
|
||||
assertEq(globalThis.a, 100);
|
||||
}
|
||||
}
|
||||
f(1);
|
|
@ -0,0 +1,43 @@
|
|||
this.a = 0;
|
||||
|
||||
function f(y) {
|
||||
// Direct eval to make an extensible environment. Variables lookups within
|
||||
// nested environments are now dynamic.
|
||||
eval("");
|
||||
|
||||
let w = y;
|
||||
|
||||
// Class with class-body lexical environment whose shape guard we want to omit.
|
||||
class C {
|
||||
// Add a private brand to generate a class-body lexical environment.
|
||||
#private;
|
||||
|
||||
static m() {
|
||||
// BindName "a" # ENV
|
||||
// Dup # ENV ENV
|
||||
// GetBoundName "a" # ENV ENV.a
|
||||
// GetAliasedVar "w" (hops = 2, slot = 2) # ENV ENV.a w
|
||||
// CheckAliasedLexical "w" (hops = 2, slot = 2) # ENV ENV.a w
|
||||
// Add # ENV (ENV.a += w)
|
||||
// NopIsAssignOp # ENV (ENV.a += w)
|
||||
// StrictSetName "a" # (ENV.a += w)
|
||||
// Pop #
|
||||
a += w;
|
||||
}
|
||||
}
|
||||
|
||||
let g = C.m;
|
||||
|
||||
for (var i = 0; i < 150; ++i) {
|
||||
// Introduce a new binding in the global lexical environment which
|
||||
// shadows the global property "a".
|
||||
if (i === 100) {
|
||||
evaluate("let a = 1000");
|
||||
}
|
||||
g();
|
||||
}
|
||||
|
||||
assertEq(a, 1050);
|
||||
assertEq(globalThis.a, 100);
|
||||
}
|
||||
f(1);
|
|
@ -0,0 +1,38 @@
|
|||
this.a = 0;
|
||||
|
||||
function f(y) {
|
||||
// Direct eval to make an extensible environment. Variables lookups within
|
||||
// nested environments are now dynamic.
|
||||
eval("");
|
||||
|
||||
let w = y;
|
||||
|
||||
// Function with NamedLambdaObject environment whose shape guard we want to omit.
|
||||
let g = function lambda() {
|
||||
// Eval to introduce a NamedLambdaObject environment.
|
||||
eval("");
|
||||
|
||||
// BindName "a" # ENV
|
||||
// Dup # ENV ENV
|
||||
// GetBoundName "a" # ENV ENV.a
|
||||
// GetName "w" # ENV ENV.a w
|
||||
// Add # ENV (ENV.a += w)
|
||||
// NopIsAssignOp # ENV (ENV.a += w)
|
||||
// SetName "a" # (ENV.a += w)
|
||||
// Pop #
|
||||
a += w;
|
||||
};
|
||||
|
||||
for (var i = 0; i < 150; ++i) {
|
||||
// Introduce a new binding in the global lexical environment which
|
||||
// shadows the global property "a".
|
||||
if (i === 100) {
|
||||
evaluate("let a = 1000");
|
||||
}
|
||||
g();
|
||||
}
|
||||
|
||||
assertEq(a, 1050);
|
||||
assertEq(globalThis.a, 100);
|
||||
}
|
||||
f(1);
|
|
@ -3592,22 +3592,26 @@ AttachDecision GetNameIRGenerator::tryAttachGlobalNameGetter(ObjOperandId objId,
|
|||
}
|
||||
|
||||
static bool NeedEnvironmentShapeGuard(JSContext* cx, JSObject* envObj) {
|
||||
if (!envObj->is<CallObject>()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can skip a guard on the call object if the script's bindings are
|
||||
// guaranteed to be immutable (and thus cannot introduce shadowing variables).
|
||||
// If the function is a relazified self-hosted function it has no BaseScript
|
||||
// and we pessimistically create the guard.
|
||||
CallObject* callObj = &envObj->as<CallObject>();
|
||||
JSFunction* fun = &callObj->callee();
|
||||
if (!fun->hasBaseScript() || fun->baseScript()->funHasExtensibleScope() ||
|
||||
DebugEnvironments::hasDebugEnvironment(cx, *callObj)) {
|
||||
return true;
|
||||
if (envObj->is<CallObject>()) {
|
||||
auto* callObj = &envObj->as<CallObject>();
|
||||
JSFunction* fun = &callObj->callee();
|
||||
return !fun->hasBaseScript() ||
|
||||
fun->baseScript()->funHasExtensibleScope() ||
|
||||
DebugEnvironments::hasDebugEnvironment(cx, *callObj);
|
||||
}
|
||||
|
||||
return false;
|
||||
// Similar to the call object case, we can also skip a guard if the lexical
|
||||
// environment's bindings are immutable.
|
||||
if (envObj->is<LexicalEnvironmentObject>()) {
|
||||
return envObj->as<LexicalEnvironmentObject>().isExtensible();
|
||||
}
|
||||
|
||||
// Use a shape guard for all other environment objects.
|
||||
return true;
|
||||
}
|
||||
|
||||
AttachDecision GetNameIRGenerator::tryAttachEnvironmentName(ObjOperandId objId,
|
||||
|
|
Загрузка…
Ссылка в новой задаче