f6450b97ec
1) Computed property keys (esp functions in them) shouldn't be inside the object literal scope. 2) I was using an imprecise "maybe uses super" and storing it to preparse data. This won't fly, since it pollutes sister scopes and leads to confusion wrt whether an object literal needs a home object or not. Made it precise (mostly cancelling changes in the original CL). 3) PreParser::NewSuperPropertyReference was creating a VariableProxy for this_function (which made it used) -> inconsistent scopes between parsing and preparsing. 4) MultipleEntryBlockContextScope was messing up the accumulator Original: https://chromium-review.googlesource.com/c/v8/v8/+/2563275 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, chromium:1167918, chromium:1167981, chromium:1167988, chromium:1168055 Change-Id: I4f53f18cc18762c33e53d8c802909b42f1c33538 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2637220 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Marja Hölttä <marja@chromium.org> Cr-Commit-Position: refs/heads/master@{#72169}
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());
|
||
})();
|