31d2bb8670
Fix 1: Track Scope::needs_home_object and Scope::uses_super_property accurately. When "eval" is seen, figure out whether it can access "super" and if yes, set the corresponding home object as needed. Fix 2: The object literal scope shouldn't be entered for things inside spreads. Original: https://chromium-review.googlesource.com/c/v8/v8/+/2563275 Previous reland: https://chromium-review.googlesource.com/c/v8/v8/+/2637220 This saves memory (the home object doesn't need to be stored for each method, but only once per class) and hopefully makes the home object a constant in the optimized code. Detailed documentation of the changes: https://docs.google.com/document/d/1ZVXcoQdf9IdMsnRI9iyUjyq9NDoEyx9nA3XqMgwflMs/edit?usp=sharing Bug: v8:9237 Bug: chromium:1167918 Bug: chromium:1167981 Bug: chromium:1167988 Bug: chromium:1168055 Bug: chromium:1171195 Bug: chromium:1171600 Change-Id: I9686e0d90cd0c1128757eca440a88748897ee91e Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2655509 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/master@{#72422}
197 lines
4.8 KiB
JavaScript
197 lines
4.8 KiB
JavaScript
// Copyright 2021 the V8 project authors. All rights reserved.
|
||
// Use of this source code is governed by a BSD-style license that can be
|
||
// found in the LICENSE file.
|
||
|
||
(function TestSuperInObjectLiteralMethod() {
|
||
let my_proto = {
|
||
__proto__ : {'x': 'right' },
|
||
m() { return super.x; }
|
||
};
|
||
let o = {__proto__: my_proto};
|
||
assertEquals('right', o.m());
|
||
})();
|
||
|
||
(function TestSuperInObjectLiteralGetter() {
|
||
let my_proto = {
|
||
__proto__ : {'x': 'right' },
|
||
get p() { return super.x; }
|
||
};
|
||
let o = {__proto__: my_proto};
|
||
assertEquals('right', o.p);
|
||
})();
|
||
|
||
(function TestSuperInObjectLiteralSetter() {
|
||
let read_value;
|
||
let my_proto = {
|
||
__proto__ : {'x': 'right' },
|
||
set p(x) { read_value = super.x; }
|
||
};
|
||
let o = {__proto__: my_proto};
|
||
o.p = 'whatever';
|
||
assertEquals('right', read_value);
|
||
})();
|
||
|
||
(function TestSuperInObjectLiteralProperty() {
|
||
class OuterBase {};
|
||
OuterBase.prototype.x = 'right';
|
||
class Outer extends OuterBase {
|
||
m2() {
|
||
let my_proto = {
|
||
__proto__ : {'x': 'wrong' },
|
||
m: () => super.x,
|
||
};
|
||
let o = {__proto__: my_proto};
|
||
return o.m();
|
||
}
|
||
}
|
||
assertEquals('right', (new Outer()).m2());
|
||
})();
|
||
|
||
(function TestMethodScopes() {
|
||
let object = { // object literal 1 starts
|
||
__proto__: { // object literal 2 starts
|
||
method1() { return 'right'; }
|
||
}, // object literal 2 ends
|
||
method2() {
|
||
return super.method1();
|
||
}
|
||
}; // object literal 1 ends
|
||
assertEquals('right', object.method2());
|
||
})();
|
||
|
||
(function TestEvalInObjectLiteral() {
|
||
let o = {__proto__: {x: 'right'},
|
||
x: 'wrong',
|
||
m() {
|
||
let r = 0;
|
||
eval('r = super.x;');
|
||
return r;
|
||
}
|
||
};
|
||
|
||
assertEquals('right', o.m());
|
||
})();
|
||
|
||
(function TestEvalInMethod() {
|
||
class A {};
|
||
A.prototype.x = 'right';
|
||
|
||
class B extends A {
|
||
m() {
|
||
let r;
|
||
eval('r = super.x;');
|
||
return r;
|
||
}
|
||
};
|
||
B.prototype.x = 'wrong';
|
||
|
||
let b = new B();
|
||
assertEquals('right', b.m());
|
||
})();
|
||
|
||
(function TestSuperInsidePropertyInitializer() {
|
||
class OuterBase {}
|
||
OuterBase.prototype.prop = 'wrong';
|
||
OuterBase.prop = 'wrong';
|
||
|
||
class Outer extends OuterBase {
|
||
m() {
|
||
class A { }
|
||
A.prototype.prop = 'right';
|
||
|
||
class B extends A {
|
||
x = () => { return super.prop; };
|
||
}
|
||
|
||
B.prototype.prop = 'wrong';
|
||
return (new B()).x();
|
||
}
|
||
}
|
||
Outer.prototype.prop = 'wrong';
|
||
Outer.prop = 'wrong';
|
||
|
||
assertEquals('right', (new Outer()).m());
|
||
})();
|
||
|
||
(function TestSuperInsideStaticPropertyInitializer() {
|
||
class OuterBase {}
|
||
OuterBase.prototype.prop = 'wrong';
|
||
OuterBase.prop = 'wrong';
|
||
|
||
class Outer extends OuterBase {
|
||
m() {
|
||
class A { }
|
||
A.prop = 'right';
|
||
A.prototype.prop = 'wrong';
|
||
class B extends A {
|
||
static x = super.prop;
|
||
}
|
||
B.prop = 'wrong';
|
||
B.prototype.prop = 'wrong';
|
||
return B.x;
|
||
}
|
||
}
|
||
Outer.prototype.prop = 'wrong';
|
||
Outer.prop = 'wrong';
|
||
|
||
assertEquals('right', (new Outer).m());
|
||
})();
|
||
|
||
(function TestSuperInsideStaticPropertyInitializer2() {
|
||
class A extends class {
|
||
a() { return 'wrong'; }
|
||
} {
|
||
m() {
|
||
class C extends class {
|
||
static a() { return 'right'; }
|
||
} {
|
||
static static_prop = super.a;
|
||
};
|
||
return C.static_prop;
|
||
}
|
||
};
|
||
assertEquals('right', (new A()).m()());
|
||
})();
|
||
|
||
(function TestSuperInsideExtends() {
|
||
class C extends class {
|
||
static a = 'right';
|
||
} {
|
||
static m = class D extends new Proxy(function f() {},
|
||
{get:(t, k) => {
|
||
if (k == "prototype") {
|
||
return Function.prototype;
|
||
}
|
||
return super.a;
|
||
}
|
||
}) {}
|
||
};
|
||
assertEquals('right', C.m.a);
|
||
})();
|
||
|
||
// Same as the previous test but without a Proxy.
|
||
(function TestSuperInsideExtends2() {
|
||
function f(x) {
|
||
function A() { }
|
||
A.x = x;
|
||
return A;
|
||
}
|
||
|
||
class B {};
|
||
B.a = 'right';
|
||
|
||
// How to write "super" inside the extends clause? The "class extends value"
|
||
// needs to be a constructor.
|
||
class C extends B {
|
||
static m = class D extends f({m2: () => { return super.a;}}) { }
|
||
}
|
||
|
||
// C.m is a class. Its "parent class" is a function (returned by f). C.m.x
|
||
// binds to the parent's x, which is whatever we passed as a param to f.
|
||
// In this case, it's an object which has a property m2.
|
||
|
||
// Since m2 is an arrow function, and not a method, "super" inside it
|
||
// doesn't bind to the object where m2 is defined, but outside.
|
||
assertEquals('right', C.m.x.m2());
|
||
})();
|