v8/test/mjsunit/es6/home-object-in-context.js
Marja Hölttä 31d2bb8670 Reland2 [super] Store home object in Context instead of JSFunction
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}
2021-01-29 09:19:23 +00:00

197 lines
4.8 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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());
})();