41ef63df21
With bytecode flushing and lazy feedback allocation, we need to call %PrepareForOptimization before we call %OptimizeFunctionOnNextCall Bug: v8:8801, v8:8394 Change-Id: I81918f174b2f97cbaa8b8ef2e459080c2581f535 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1588415 Commit-Queue: Mythri Alle <mythria@chromium.org> Commit-Queue: Ross McIlroy <rmcilroy@chromium.org> Reviewed-by: Ross McIlroy <rmcilroy@chromium.org> Cr-Commit-Position: refs/heads/master@{#61122}
1293 lines
30 KiB
JavaScript
1293 lines
30 KiB
JavaScript
// Copyright 2014 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.
|
|
|
|
// Flags: --allow-natives-syntax
|
|
|
|
(function TestBasics() {
|
|
var C = class C {}
|
|
assertEquals(typeof C, 'function');
|
|
assertEquals(C.__proto__, Function.prototype);
|
|
assertEquals(Object.prototype, Object.getPrototypeOf(C.prototype));
|
|
assertEquals(Function.prototype, Object.getPrototypeOf(C));
|
|
assertEquals('C', C.name);
|
|
|
|
class D {}
|
|
assertEquals(typeof D, 'function');
|
|
assertEquals(D.__proto__, Function.prototype);
|
|
assertEquals(Object.prototype, Object.getPrototypeOf(D.prototype));
|
|
assertEquals(Function.prototype, Object.getPrototypeOf(D));
|
|
assertEquals('D', D.name);
|
|
|
|
class D2 { constructor() {} }
|
|
assertEquals('D2', D2.name);
|
|
|
|
var E = class {}
|
|
assertEquals('E', E.name);
|
|
|
|
var F = class { constructor() {} };
|
|
assertEquals('F', F.name);
|
|
|
|
var literal = { E: class {} };
|
|
assertEquals('E', literal.E.name);
|
|
|
|
literal = { E: class F {} };
|
|
assertEquals('F', literal.E.name);
|
|
|
|
literal = { __proto__: class {} };
|
|
assertEquals('', literal.__proto__.name);
|
|
assertEquals(
|
|
undefined, Object.getOwnPropertyDescriptor(literal.__proto__, 'name'));
|
|
|
|
literal = { __proto__: class F {} };
|
|
assertEquals('F', literal.__proto__.name);
|
|
assertNotEquals(
|
|
undefined, Object.getOwnPropertyDescriptor(literal.__proto__, 'name'));
|
|
|
|
class G {};
|
|
literal = { __proto__: G };
|
|
assertEquals('G', literal.__proto__.name);
|
|
|
|
var H = class { static name() { return 'A'; } };
|
|
literal = { __proto__ : H };
|
|
assertEquals('A', literal.__proto__.name());
|
|
|
|
literal = {
|
|
__proto__: class {
|
|
static name() { return 'A'; }
|
|
}
|
|
};
|
|
assertEquals('A', literal.__proto__.name());
|
|
})();
|
|
|
|
|
|
(function TestBasicsExtends() {
|
|
class C extends null {}
|
|
assertEquals(typeof C, 'function');
|
|
assertEquals(C.__proto__, Function.prototype);
|
|
assertEquals(null, Object.getPrototypeOf(C.prototype));
|
|
|
|
class D extends C {}
|
|
assertEquals(typeof D, 'function');
|
|
assertEquals(D.__proto__, C);
|
|
assertEquals(C.prototype, Object.getPrototypeOf(D.prototype));
|
|
})();
|
|
|
|
|
|
(function TestSideEffectInExtends() {
|
|
var calls = 0;
|
|
class C {}
|
|
class D extends (calls++, C) {}
|
|
assertEquals(1, calls);
|
|
assertEquals(typeof D, 'function');
|
|
assertEquals(D.__proto__, C);
|
|
assertEquals(C.prototype, Object.getPrototypeOf(D.prototype));
|
|
})();
|
|
|
|
|
|
(function TestInvalidExtends() {
|
|
assertThrows(function() {
|
|
class C extends 42 {}
|
|
}, TypeError);
|
|
|
|
assertThrows(function() {
|
|
// Function but its .prototype is not null or a function.
|
|
class C extends Math.abs {}
|
|
}, TypeError);
|
|
|
|
assertThrows(function() {
|
|
Math.abs.prototype = 42;
|
|
class C extends Math.abs {}
|
|
}, TypeError);
|
|
delete Math.abs.prototype;
|
|
|
|
assertThrows(function() {
|
|
function* g() {}
|
|
class C extends g {}
|
|
}, TypeError);
|
|
})();
|
|
|
|
|
|
(function TestConstructorProperty() {
|
|
class C {}
|
|
assertEquals(C, C.prototype.constructor);
|
|
var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor');
|
|
assertTrue(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertTrue(descr.writable);
|
|
})();
|
|
|
|
|
|
(function TestPrototypeProperty() {
|
|
class C {}
|
|
var descr = Object.getOwnPropertyDescriptor(C, 'prototype');
|
|
assertFalse(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertFalse(descr.writable);
|
|
})();
|
|
|
|
|
|
(function TestConstructor() {
|
|
var count = 0;
|
|
class C {
|
|
constructor() {
|
|
assertEquals(Object.getPrototypeOf(this), C.prototype);
|
|
count++;
|
|
}
|
|
}
|
|
assertEquals(C, C.prototype.constructor);
|
|
var descr = Object.getOwnPropertyDescriptor(C.prototype, 'constructor');
|
|
assertTrue(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertTrue(descr.writable);
|
|
|
|
var c = new C();
|
|
assertEquals(1, count);
|
|
assertEquals(Object.getPrototypeOf(c), C.prototype);
|
|
})();
|
|
|
|
|
|
(function TestImplicitConstructor() {
|
|
class C {}
|
|
var c = new C();
|
|
assertEquals(Object.getPrototypeOf(c), C.prototype);
|
|
})();
|
|
|
|
|
|
(function TestConstructorStrict() {
|
|
class C {
|
|
constructor() {
|
|
assertThrows(function() {
|
|
nonExistingBinding = 42;
|
|
}, ReferenceError);
|
|
}
|
|
}
|
|
new C();
|
|
})();
|
|
|
|
|
|
(function TestSuperInConstructor() {
|
|
var calls = 0;
|
|
class B {}
|
|
B.prototype.x = 42;
|
|
|
|
class C extends B {
|
|
constructor() {
|
|
super();
|
|
calls++;
|
|
assertEquals(42, super.x);
|
|
}
|
|
}
|
|
|
|
new C;
|
|
assertEquals(1, calls);
|
|
})();
|
|
|
|
|
|
(function TestStrictMode() {
|
|
class C {}
|
|
|
|
with ({a: 1}) {
|
|
assertEquals(1, a);
|
|
}
|
|
|
|
assertThrows('class C extends function B() { with ({}); return B; }() {}',
|
|
SyntaxError);
|
|
|
|
var D = class extends function() {
|
|
this.args = arguments;
|
|
} {};
|
|
assertThrows(function() {
|
|
Object.getPrototypeOf(D).arguments;
|
|
}, TypeError);
|
|
var e = new D();
|
|
assertThrows(() => e.args.callee, TypeError);
|
|
assertEquals(undefined, Object.getOwnPropertyDescriptor(e.args, 'caller'));
|
|
assertFalse('caller' in e.args);
|
|
})();
|
|
|
|
|
|
(function TestToString() {
|
|
class C {}
|
|
assertEquals('class C {}', C.toString());
|
|
|
|
class D { constructor() { 42; } }
|
|
assertEquals('class D { constructor() { 42; } }', D.toString());
|
|
|
|
class E { x() { 42; } }
|
|
assertEquals('class E { x() { 42; } }', E.toString());
|
|
})();
|
|
|
|
|
|
function assertMethodDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertTrue(descr.writable);
|
|
assertEquals('function', typeof descr.value);
|
|
assertFalse('prototype' in descr.value);
|
|
assertEquals(name, descr.value.name);
|
|
}
|
|
|
|
|
|
function assertGetterDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertEquals('function', typeof descr.get);
|
|
assertFalse('prototype' in descr.get);
|
|
assertEquals(undefined, descr.set);
|
|
assertEquals("get " + name, descr.get.name);
|
|
}
|
|
|
|
|
|
function assertSetterDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertEquals(undefined, descr.get);
|
|
assertEquals('function', typeof descr.set);
|
|
assertFalse('prototype' in descr.set);
|
|
assertEquals("set " + name, descr.set.name);
|
|
}
|
|
|
|
|
|
function assertAccessorDescriptor(object, name) {
|
|
var descr = Object.getOwnPropertyDescriptor(object, name);
|
|
assertTrue(descr.configurable);
|
|
assertFalse(descr.enumerable);
|
|
assertEquals('function', typeof descr.get);
|
|
assertEquals('function', typeof descr.set);
|
|
assertFalse('prototype' in descr.get);
|
|
assertFalse('prototype' in descr.set);
|
|
assertEquals("get " + name, descr.get.name);
|
|
assertEquals("set " + name, descr.set.name);
|
|
}
|
|
|
|
|
|
(function TestMethods() {
|
|
class C {
|
|
method() { return 1; }
|
|
static staticMethod() { return 2; }
|
|
method2() { return 3; }
|
|
static staticMethod2() { return 4; }
|
|
}
|
|
|
|
assertMethodDescriptor(C.prototype, 'method');
|
|
assertMethodDescriptor(C.prototype, 'method2');
|
|
assertMethodDescriptor(C, 'staticMethod');
|
|
assertMethodDescriptor(C, 'staticMethod2');
|
|
|
|
assertEquals(1, new C().method());
|
|
assertEquals(2, C.staticMethod());
|
|
assertEquals(3, new C().method2());
|
|
assertEquals(4, C.staticMethod2());
|
|
})();
|
|
|
|
|
|
(function TestGetters() {
|
|
class C {
|
|
get x() { return 1; }
|
|
static get staticX() { return 2; }
|
|
get y() { return 3; }
|
|
static get staticY() { return 4; }
|
|
}
|
|
|
|
assertGetterDescriptor(C.prototype, 'x');
|
|
assertGetterDescriptor(C.prototype, 'y');
|
|
assertGetterDescriptor(C, 'staticX');
|
|
assertGetterDescriptor(C, 'staticY');
|
|
|
|
assertEquals(1, new C().x);
|
|
assertEquals(2, C.staticX);
|
|
assertEquals(3, new C().y);
|
|
assertEquals(4, C.staticY);
|
|
})();
|
|
|
|
|
|
|
|
(function TestSetters() {
|
|
var x, staticX, y, staticY;
|
|
class C {
|
|
set x(v) { x = v; }
|
|
static set staticX(v) { staticX = v; }
|
|
set y(v) { y = v; }
|
|
static set staticY(v) { staticY = v; }
|
|
}
|
|
|
|
assertSetterDescriptor(C.prototype, 'x');
|
|
assertSetterDescriptor(C.prototype, 'y');
|
|
assertSetterDescriptor(C, 'staticX');
|
|
assertSetterDescriptor(C, 'staticY');
|
|
|
|
assertEquals(1, new C().x = 1);
|
|
assertEquals(1, x);
|
|
assertEquals(2, C.staticX = 2);
|
|
assertEquals(2, staticX);
|
|
assertEquals(3, new C().y = 3);
|
|
assertEquals(3, y);
|
|
assertEquals(4, C.staticY = 4);
|
|
assertEquals(4, staticY);
|
|
})();
|
|
|
|
|
|
(function TestSideEffectsInPropertyDefine() {
|
|
function B() {}
|
|
B.prototype = {
|
|
constructor: B,
|
|
set m(v) {
|
|
throw Error();
|
|
}
|
|
};
|
|
|
|
class C extends B {
|
|
m() { return 1; }
|
|
}
|
|
|
|
assertEquals(1, new C().m());
|
|
})();
|
|
|
|
|
|
(function TestAccessors() {
|
|
class C {
|
|
constructor(x) {
|
|
this._x = x;
|
|
}
|
|
|
|
get x() { return this._x; }
|
|
set x(v) { this._x = v; }
|
|
|
|
static get staticX() { return this._x; }
|
|
static set staticX(v) { this._x = v; }
|
|
}
|
|
|
|
assertAccessorDescriptor(C.prototype, 'x');
|
|
assertAccessorDescriptor(C, 'staticX');
|
|
|
|
var c = new C(1);
|
|
c._x = 1;
|
|
assertEquals(1, c.x);
|
|
c.x = 2;
|
|
assertEquals(2, c._x);
|
|
|
|
C._x = 3;
|
|
assertEquals(3, C.staticX);
|
|
C._x = 4;
|
|
assertEquals(4, C.staticX );
|
|
})();
|
|
|
|
|
|
(function TestProto() {
|
|
class C {
|
|
__proto__() { return 1; }
|
|
}
|
|
assertMethodDescriptor(C.prototype, '__proto__');
|
|
assertEquals(1, new C().__proto__());
|
|
})();
|
|
|
|
|
|
(function TestProtoStatic() {
|
|
class C {
|
|
static __proto__() { return 1; }
|
|
}
|
|
assertMethodDescriptor(C, '__proto__');
|
|
assertEquals(1, C.__proto__());
|
|
})();
|
|
|
|
|
|
(function TestProtoAccessor() {
|
|
class C {
|
|
get __proto__() { return this._p; }
|
|
set __proto__(v) { this._p = v; }
|
|
}
|
|
assertAccessorDescriptor(C.prototype, '__proto__');
|
|
var c = new C();
|
|
c._p = 1;
|
|
assertEquals(1, c.__proto__);
|
|
c.__proto__ = 2;
|
|
assertEquals(2, c.__proto__);
|
|
})();
|
|
|
|
|
|
(function TestStaticProtoAccessor() {
|
|
class C {
|
|
static get __proto__() { return this._p; }
|
|
static set __proto__(v) { this._p = v; }
|
|
}
|
|
assertAccessorDescriptor(C, '__proto__');
|
|
C._p = 1;
|
|
assertEquals(1, C.__proto__);
|
|
C.__proto__ = 2;
|
|
assertEquals(2, C.__proto__);
|
|
})();
|
|
|
|
|
|
(function TestSettersOnProto() {
|
|
function Base() {}
|
|
Base.prototype = {
|
|
set constructor(_) {
|
|
assertUnreachable();
|
|
},
|
|
set m(_) {
|
|
assertUnreachable();
|
|
}
|
|
};
|
|
Object.defineProperty(Base, 'staticM', {
|
|
set: function() {
|
|
assertUnreachable();
|
|
}
|
|
});
|
|
|
|
class C extends Base {
|
|
m() {
|
|
return 1;
|
|
}
|
|
static staticM() {
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
assertEquals(1, new C().m());
|
|
assertEquals(2, C.staticM());
|
|
})();
|
|
|
|
|
|
(function TestConstructableButNoPrototype() {
|
|
var Base = function() {}.bind();
|
|
assertThrows(function() {
|
|
class C extends Base {}
|
|
}, TypeError);
|
|
})();
|
|
|
|
|
|
(function TestPrototypeGetter() {
|
|
var calls = 0;
|
|
var Base = function() {}.bind();
|
|
Object.defineProperty(Base, 'prototype', {
|
|
get: function() {
|
|
calls++;
|
|
return null;
|
|
},
|
|
configurable: true
|
|
});
|
|
class C extends Base {}
|
|
assertEquals(1, calls);
|
|
|
|
calls = 0;
|
|
Object.defineProperty(Base, 'prototype', {
|
|
get: function() {
|
|
calls++;
|
|
return 42;
|
|
},
|
|
configurable: true
|
|
});
|
|
assertThrows(function() {
|
|
class C extends Base {}
|
|
}, TypeError);
|
|
assertEquals(1, calls);
|
|
})();
|
|
|
|
|
|
(function TestPrototypeSetter() {
|
|
var Base = function() {}.bind();
|
|
Object.defineProperty(Base, 'prototype', {
|
|
set: function() {
|
|
assertUnreachable();
|
|
}
|
|
});
|
|
assertThrows(function() {
|
|
class C extends Base {}
|
|
}, TypeError);
|
|
})();
|
|
|
|
|
|
(function TestSuperInMethods() {
|
|
class B {
|
|
method() {
|
|
return 1;
|
|
}
|
|
get x() {
|
|
return 2;
|
|
}
|
|
}
|
|
class C extends B {
|
|
method() {
|
|
assertEquals(2, super.x);
|
|
return super.method();
|
|
}
|
|
}
|
|
assertEquals(1, new C().method());
|
|
})();
|
|
|
|
|
|
(function TestSuperInGetter() {
|
|
class B {
|
|
method() {
|
|
return 1;
|
|
}
|
|
get x() {
|
|
return 2;
|
|
}
|
|
}
|
|
class C extends B {
|
|
get y() {
|
|
assertEquals(2, super.x);
|
|
return super.method();
|
|
}
|
|
}
|
|
assertEquals(1, new C().y);
|
|
})();
|
|
|
|
|
|
(function TestSuperInSetter() {
|
|
class B {
|
|
method() {
|
|
return 1;
|
|
}
|
|
get x() {
|
|
return 2;
|
|
}
|
|
}
|
|
class C extends B {
|
|
set y(v) {
|
|
assertEquals(3, v);
|
|
assertEquals(2, super.x);
|
|
assertEquals(1, super.method());
|
|
}
|
|
}
|
|
assertEquals(3, new C().y = 3);
|
|
})();
|
|
|
|
|
|
(function TestSuperInStaticMethods() {
|
|
class B {
|
|
static method() {
|
|
return 1;
|
|
}
|
|
static get x() {
|
|
return 2;
|
|
}
|
|
}
|
|
class C extends B {
|
|
static method() {
|
|
assertEquals(2, super.x);
|
|
return super.method();
|
|
}
|
|
}
|
|
assertEquals(1, C.method());
|
|
})();
|
|
|
|
|
|
(function TestSuperInStaticGetter() {
|
|
class B {
|
|
static method() {
|
|
return 1;
|
|
}
|
|
static get x() {
|
|
return 2;
|
|
}
|
|
}
|
|
class C extends B {
|
|
static get x() {
|
|
assertEquals(2, super.x);
|
|
return super.method();
|
|
}
|
|
}
|
|
assertEquals(1, C.x);
|
|
})();
|
|
|
|
|
|
(function TestSuperInStaticSetter() {
|
|
class B {
|
|
static method() {
|
|
return 1;
|
|
}
|
|
static get x() {
|
|
return 2;
|
|
}
|
|
}
|
|
class C extends B {
|
|
static set x(v) {
|
|
assertEquals(3, v);
|
|
assertEquals(2, super.x);
|
|
assertEquals(1, super.method());
|
|
}
|
|
}
|
|
assertEquals(3, C.x = 3);
|
|
})();
|
|
|
|
|
|
(function TestNumericPropertyNames() {
|
|
class B {
|
|
1() { return 1; }
|
|
get 2() { return 2; }
|
|
set 3(_) {}
|
|
|
|
static 4() { return 4; }
|
|
static get 5() { return 5; }
|
|
static set 6(_) {}
|
|
|
|
2147483649() { return 2147483649; }
|
|
get 2147483650() { return 2147483650; }
|
|
set 2147483651(_) {}
|
|
|
|
static 2147483652() { return 2147483652; }
|
|
static get 2147483653() { return 2147483653; }
|
|
static set 2147483654(_) {}
|
|
|
|
4294967294() { return 4294967294; }
|
|
4294967295() { return 4294967295; }
|
|
static 4294967294() { return 4294967294; }
|
|
static 4294967295() { return 4294967295; }
|
|
}
|
|
|
|
assertMethodDescriptor(B.prototype, '1');
|
|
assertGetterDescriptor(B.prototype, '2');
|
|
assertSetterDescriptor(B.prototype, '3');
|
|
assertMethodDescriptor(B.prototype, '2147483649');
|
|
assertGetterDescriptor(B.prototype, '2147483650');
|
|
assertSetterDescriptor(B.prototype, '2147483651');
|
|
assertMethodDescriptor(B.prototype, '4294967294');
|
|
assertMethodDescriptor(B.prototype, '4294967295');
|
|
|
|
assertMethodDescriptor(B, '4');
|
|
assertGetterDescriptor(B, '5');
|
|
assertSetterDescriptor(B, '6');
|
|
assertMethodDescriptor(B, '2147483652');
|
|
assertGetterDescriptor(B, '2147483653');
|
|
assertSetterDescriptor(B, '2147483654');
|
|
assertMethodDescriptor(B, '4294967294');
|
|
assertMethodDescriptor(B, '4294967295');
|
|
|
|
class C extends B {
|
|
1() { return super[1](); }
|
|
get 2() { return super[2]; }
|
|
|
|
static 4() { return super[4](); }
|
|
static get 5() { return super[5]; }
|
|
|
|
2147483649() { return super[2147483649](); }
|
|
get 2147483650() { return super[2147483650]; }
|
|
|
|
static 2147483652() { return super[2147483652](); }
|
|
static get 2147483653() { return super[2147483653]; }
|
|
|
|
}
|
|
|
|
assertEquals(1, new C()[1]());
|
|
assertEquals(2, new C()[2]);
|
|
assertEquals(2147483649, new C()[2147483649]());
|
|
assertEquals(2147483650, new C()[2147483650]);
|
|
assertEquals(4, C[4]());
|
|
assertEquals(5, C[5]);
|
|
assertEquals(2147483652, C[2147483652]());
|
|
assertEquals(2147483653, C[2147483653]);
|
|
})();
|
|
|
|
|
|
(function TestDefaultConstructorNoCrash() {
|
|
// Regression test for https://code.google.com/p/v8/issues/detail?id=3661
|
|
class C {}
|
|
assertThrows(function () {C();}, TypeError);
|
|
assertThrows(function () {C(1);}, TypeError);
|
|
assertTrue(new C() instanceof C);
|
|
assertTrue(new C(1) instanceof C);
|
|
})();
|
|
|
|
|
|
(function TestConstructorCall(){
|
|
var realmIndex = Realm.create();
|
|
var otherTypeError = Realm.eval(realmIndex, "TypeError");
|
|
var A = Realm.eval(realmIndex, '"use strict"; class A {}; A');
|
|
var instance = new A();
|
|
var constructor = instance.constructor;
|
|
var otherTypeError = Realm.eval(realmIndex, 'TypeError');
|
|
if (otherTypeError === TypeError) {
|
|
throw Error('Should not happen!');
|
|
}
|
|
|
|
// ES6 9.2.1[[Call]] throws a TypeError in the caller context/Realm when the
|
|
// called function is a classConstructor
|
|
assertThrows(function() { Realm.eval(realmIndex, "A()") }, otherTypeError);
|
|
assertThrows(function() { instance.constructor() }, TypeError);
|
|
assertThrows(function() { A() }, TypeError);
|
|
|
|
// ES6 9.3.1 call() first activates the callee context before invoking the
|
|
// method. The TypeError from the constructor is thus thrown in the other
|
|
// Realm.
|
|
assertThrows(function() { Realm.eval(realmIndex, "A.call()") },
|
|
otherTypeError);
|
|
assertThrows(function() { constructor.call() }, otherTypeError);
|
|
assertThrows(function() { A.call() }, otherTypeError);
|
|
})();
|
|
|
|
|
|
(function TestConstructorCallOptimized() {
|
|
class A { };
|
|
|
|
function invoke_constructor() { A() }
|
|
function call_constructor() { A.call() }
|
|
function apply_constructor() { A.apply() }
|
|
%PrepareFunctionForOptimization(invoke_constructor);
|
|
%PrepareFunctionForOptimization(call_constructor);
|
|
%PrepareFunctionForOptimization(apply_constructor);
|
|
|
|
for (var i=0; i<3; i++) {
|
|
assertThrows(invoke_constructor);
|
|
assertThrows(call_constructor);
|
|
assertThrows(apply_constructor);
|
|
}
|
|
// Make sure we still check for class constructors when calling optimized
|
|
// code.
|
|
%OptimizeFunctionOnNextCall(invoke_constructor);
|
|
assertThrows(invoke_constructor);
|
|
%OptimizeFunctionOnNextCall(call_constructor);
|
|
assertThrows(call_constructor);
|
|
%OptimizeFunctionOnNextCall(apply_constructor);
|
|
assertThrows(apply_constructor);
|
|
})();
|
|
|
|
|
|
(function TestDefaultConstructor() {
|
|
var calls = 0;
|
|
class Base {
|
|
constructor() {
|
|
calls++;
|
|
}
|
|
}
|
|
class Derived extends Base {}
|
|
var object = new Derived;
|
|
assertEquals(1, calls);
|
|
|
|
calls = 0;
|
|
assertThrows(function() { Derived(); }, TypeError);
|
|
assertEquals(0, calls);
|
|
})();
|
|
|
|
|
|
(function TestDefaultConstructorArguments() {
|
|
var args, self;
|
|
class Base {
|
|
constructor() {
|
|
self = this;
|
|
args = arguments;
|
|
}
|
|
}
|
|
class Derived extends Base {}
|
|
|
|
new Derived;
|
|
assertEquals(0, args.length);
|
|
|
|
new Derived(0, 1, 2);
|
|
assertEquals(3, args.length);
|
|
assertTrue(self instanceof Derived);
|
|
|
|
var arr = new Array(100);
|
|
var obj = {};
|
|
assertThrows(function() {Derived.apply(obj, arr);}, TypeError);
|
|
})();
|
|
|
|
|
|
(function TestDefaultConstructorArguments2() {
|
|
var args;
|
|
class Base {
|
|
constructor(x, y) {
|
|
args = arguments;
|
|
}
|
|
}
|
|
class Derived extends Base {}
|
|
|
|
new Derived;
|
|
assertEquals(0, args.length);
|
|
|
|
new Derived(1);
|
|
assertEquals(1, args.length);
|
|
assertEquals(1, args[0]);
|
|
|
|
new Derived(1, 2, 3);
|
|
assertEquals(3, args.length);
|
|
assertEquals(1, args[0]);
|
|
assertEquals(2, args[1]);
|
|
assertEquals(3, args[2]);
|
|
})();
|
|
|
|
|
|
(function TestNameBindingConst() {
|
|
assertThrows('class C { constructor() { C = 42; } }; new C();', TypeError);
|
|
assertThrows('new (class C { constructor() { C = 42; } })', TypeError);
|
|
assertThrows('class C { m() { C = 42; } }; new C().m()', TypeError);
|
|
assertThrows('new (class C { m() { C = 42; } }).m()', TypeError);
|
|
assertThrows('class C { get x() { C = 42; } }; new C().x', TypeError);
|
|
assertThrows('(new (class C { get x() { C = 42; } })).x', TypeError);
|
|
assertThrows('class C { set x(_) { C = 42; } }; new C().x = 15;', TypeError);
|
|
assertThrows('(new (class C { set x(_) { C = 42; } })).x = 15;', TypeError);
|
|
})();
|
|
|
|
|
|
(function TestNameBinding() {
|
|
var C2;
|
|
class C {
|
|
constructor() {
|
|
C2 = C;
|
|
}
|
|
m() {
|
|
C2 = C;
|
|
}
|
|
get x() {
|
|
C2 = C;
|
|
}
|
|
set x(_) {
|
|
C2 = C;
|
|
}
|
|
}
|
|
new C();
|
|
assertEquals(C, C2);
|
|
|
|
C2 = undefined;
|
|
new C().m();
|
|
assertEquals(C, C2);
|
|
|
|
C2 = undefined;
|
|
new C().x;
|
|
assertEquals(C, C2);
|
|
|
|
C2 = undefined;
|
|
new C().x = 1;
|
|
assertEquals(C, C2);
|
|
})();
|
|
|
|
|
|
(function TestNameBindingExpression() {
|
|
var C3;
|
|
var C = class C2 {
|
|
constructor() {
|
|
assertEquals(C2, C);
|
|
C3 = C2;
|
|
}
|
|
m() {
|
|
assertEquals(C2, C);
|
|
C3 = C2;
|
|
}
|
|
get x() {
|
|
assertEquals(C2, C);
|
|
C3 = C2;
|
|
}
|
|
set x(_) {
|
|
assertEquals(C2, C);
|
|
C3 = C2;
|
|
}
|
|
}
|
|
new C();
|
|
assertEquals(C, C3);
|
|
|
|
C3 = undefined;
|
|
new C().m();
|
|
assertEquals(C, C3);
|
|
|
|
C3 = undefined;
|
|
new C().x;
|
|
assertEquals(C, C3);
|
|
|
|
C3 = undefined;
|
|
new C().x = 1;
|
|
assertEquals(C, C3);
|
|
})();
|
|
|
|
|
|
(function TestNameBindingInExtendsExpression() {
|
|
assertThrows(function() {
|
|
class x extends x {}
|
|
}, ReferenceError);
|
|
|
|
assertThrows(function() {
|
|
(class x extends x {});
|
|
}, ReferenceError);
|
|
|
|
assertThrows(function() {
|
|
var x = (class x extends x {});
|
|
}, ReferenceError);
|
|
})();
|
|
|
|
|
|
(function TestThisAccessRestriction() {
|
|
class Base {}
|
|
(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
var y;
|
|
super();
|
|
}
|
|
}; new C();
|
|
}());
|
|
assertThrows(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
super(this.x);
|
|
}
|
|
}; new C();
|
|
}, ReferenceError);
|
|
assertThrows(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
super(this);
|
|
}
|
|
}; new C();
|
|
}, ReferenceError);
|
|
assertThrows(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
super.method();
|
|
super(this);
|
|
}
|
|
}; new C();
|
|
}, ReferenceError);
|
|
assertThrows(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
super(super.method());
|
|
}
|
|
}; new C();
|
|
}, ReferenceError);
|
|
assertThrows(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
super(super());
|
|
}
|
|
}; new C();
|
|
}, ReferenceError);
|
|
assertThrows(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
super(1, 2, Object.getPrototypeOf(this));
|
|
}
|
|
}; new C();
|
|
}, ReferenceError);
|
|
(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
{ super(1, 2); }
|
|
}
|
|
}; new C();
|
|
}());
|
|
(function() {
|
|
class C extends Base {
|
|
constructor() {
|
|
if (1) super();
|
|
}
|
|
}; new C();
|
|
}());
|
|
|
|
class C1 extends Object {
|
|
constructor() {
|
|
'use strict';
|
|
super();
|
|
}
|
|
};
|
|
new C1();
|
|
|
|
class C2 extends Object {
|
|
constructor() {
|
|
; 'use strict';;;;;
|
|
super();
|
|
}
|
|
};
|
|
new C2();
|
|
|
|
class C3 extends Object {
|
|
constructor() {
|
|
; 'use strict';;;;;
|
|
// This is a comment.
|
|
super();
|
|
}
|
|
};
|
|
new C3();
|
|
}());
|
|
|
|
|
|
function testClassRestrictedProperties(C) {
|
|
assertEquals(false, C.hasOwnProperty("arguments"));
|
|
assertThrows(function() { return C.arguments; }, TypeError);
|
|
assertThrows(function() { C.arguments = {}; }, TypeError);
|
|
|
|
assertEquals(false, C.hasOwnProperty("caller"));
|
|
assertThrows(function() { return C.caller; }, TypeError);
|
|
assertThrows(function() { C.caller = {}; }, TypeError);
|
|
|
|
assertEquals(false, (new C).method.hasOwnProperty("arguments"));
|
|
assertThrows(function() { return new C().method.arguments; }, TypeError);
|
|
assertThrows(function() { new C().method.arguments = {}; }, TypeError);
|
|
|
|
assertEquals(false, (new C).method.hasOwnProperty("caller"));
|
|
assertThrows(function() { return new C().method.caller; }, TypeError);
|
|
assertThrows(function() { new C().method.caller = {}; }, TypeError);
|
|
}
|
|
|
|
|
|
(function testRestrictedPropertiesStrict() {
|
|
"use strict";
|
|
class ClassWithDefaultConstructor {
|
|
method() {}
|
|
}
|
|
class Class {
|
|
constructor() {}
|
|
method() {}
|
|
}
|
|
class DerivedClassWithDefaultConstructor extends Class {}
|
|
class DerivedClass extends Class { constructor() { super(); } }
|
|
|
|
testClassRestrictedProperties(ClassWithDefaultConstructor);
|
|
testClassRestrictedProperties(Class);
|
|
testClassRestrictedProperties(DerivedClassWithDefaultConstructor);
|
|
testClassRestrictedProperties(DerivedClass);
|
|
testClassRestrictedProperties(class { method() {} });
|
|
testClassRestrictedProperties(class { constructor() {} method() {} });
|
|
testClassRestrictedProperties(class extends Class { });
|
|
testClassRestrictedProperties(
|
|
class extends Class { constructor() { super(); } });
|
|
})();
|
|
|
|
|
|
(function testRestrictedPropertiesSloppy() {
|
|
class ClassWithDefaultConstructor {
|
|
method() {}
|
|
}
|
|
class Class {
|
|
constructor() {}
|
|
method() {}
|
|
}
|
|
class DerivedClassWithDefaultConstructor extends Class {}
|
|
class DerivedClass extends Class { constructor() { super(); } }
|
|
|
|
testClassRestrictedProperties(ClassWithDefaultConstructor);
|
|
testClassRestrictedProperties(Class);
|
|
testClassRestrictedProperties(DerivedClassWithDefaultConstructor);
|
|
testClassRestrictedProperties(DerivedClass);
|
|
testClassRestrictedProperties(class { method() {} });
|
|
testClassRestrictedProperties(class { constructor() {} method() {} });
|
|
testClassRestrictedProperties(class extends Class { });
|
|
testClassRestrictedProperties(
|
|
class extends Class { constructor() { super(); } });
|
|
})();
|
|
|
|
|
|
(function testReturnFromClassLiteral() {
|
|
|
|
function usingYieldInBody() {
|
|
function* foo() {
|
|
class C {
|
|
[yield]() {}
|
|
}
|
|
}
|
|
var g = foo();
|
|
g.next();
|
|
return g.return(42).value;
|
|
}
|
|
assertEquals(42, usingYieldInBody());
|
|
|
|
function usingYieldInExtends() {
|
|
function* foo() {
|
|
class C extends (yield) {};
|
|
}
|
|
var g = foo();
|
|
g.next();
|
|
return g.return(42).value;
|
|
}
|
|
assertEquals(42, usingYieldInExtends());
|
|
|
|
})();
|
|
|
|
|
|
(function testLargeClassesMethods() {
|
|
const kLimit = 2000;
|
|
let evalString = "(function(i) { " +
|
|
"let clazz = class { " +
|
|
" constructor(i) { this.value = i; } ";
|
|
for (let i = 0; i < 2000; i++) {
|
|
evalString += "property"+i+"() { return "+i+"; }; "
|
|
}
|
|
evalString += "};" +
|
|
" return new clazz(i); })";
|
|
|
|
let fn = eval(evalString);
|
|
%PrepareFunctionForOptimization(fn);
|
|
assertEquals(fn(1).value, 1);
|
|
assertEquals(fn(2).value, 2);
|
|
assertEquals(fn(3).value, 3);
|
|
%OptimizeFunctionOnNextCall(fn);
|
|
assertEquals(fn(4).value, 4);
|
|
|
|
let instance = fn(1);
|
|
assertEquals(Object.getOwnPropertyNames(instance).length, 1);
|
|
assertEquals(Object.getOwnPropertyNames(instance.__proto__).length,
|
|
kLimit + 1);
|
|
|
|
// Call all instance functions.
|
|
for (let i = 0; i < kLimit; i++) {
|
|
const key = "property" + i;
|
|
assertEquals(instance[key](), i);
|
|
}
|
|
})();
|
|
|
|
|
|
(function testLargeClassesStaticMethods() {
|
|
const kLimit = 2000;
|
|
let evalString = "(function(i) { " +
|
|
"let clazz = class { " +
|
|
" constructor(i) { this.value = i; } ";
|
|
for (let i = 0; i < kLimit; i++) {
|
|
evalString += "static property"+i+"() { return "+i+" }; "
|
|
}
|
|
evalString += "};" +
|
|
" return new clazz(i); })";
|
|
|
|
let fn = eval(evalString);
|
|
|
|
%PrepareFunctionForOptimization(fn);
|
|
assertEquals(fn(1).value, 1);
|
|
assertEquals(fn(2).value, 2);
|
|
assertEquals(fn(3).value, 3);
|
|
%OptimizeFunctionOnNextCall(fn);
|
|
assertEquals(fn(4).value, 4);
|
|
|
|
let instance = fn(1);
|
|
assertEquals(Object.getOwnPropertyNames(instance).length, 1);
|
|
assertEquals(instance.value, 1);
|
|
instance.value = 10;
|
|
assertEquals(instance.value, 10);
|
|
|
|
// kLimit + nof default properties (length, prototype, name).
|
|
assertEquals(Object.getOwnPropertyNames(instance.constructor).length,
|
|
kLimit + 3);
|
|
|
|
// Call all static properties.
|
|
for (let i = 0; i < kLimit; i++) {
|
|
const key = "property" + i;
|
|
assertEquals(instance.constructor[key](), i);
|
|
}
|
|
})();
|
|
|
|
|
|
(function testLargeClassesProperties(){
|
|
const kLimit = 2000;
|
|
let evalString = "(function(i) { " +
|
|
"let clazz = class { " +
|
|
" constructor(i) { this.value = i;";
|
|
for (let i = 0; i < kLimit ; i++) {
|
|
evalString += "this.property"+i +" = "+i+"; "
|
|
}
|
|
evalString += "}};" +
|
|
" return (new clazz(i)); })";
|
|
|
|
let fn = eval(evalString);
|
|
%PrepareFunctionForOptimization(fn);
|
|
assertEquals(fn(1).value, 1);
|
|
assertEquals(fn(2).value, 2);
|
|
assertEquals(fn(3).value, 3);
|
|
%OptimizeFunctionOnNextCall(fn);
|
|
assertEquals(fn(4).value, 4);
|
|
|
|
let instance = fn(1);
|
|
assertEquals(Object.getOwnPropertyNames(instance).length, kLimit+1);
|
|
|
|
// Get and set all properties.
|
|
for (let i = 0; i < kLimit; i++) {
|
|
const key = "property" + i;
|
|
assertEquals(instance[key], i);
|
|
const value = "value"+i;
|
|
instance[key] = value;
|
|
assertEquals(instance[key], value);
|
|
}
|
|
})();
|
|
|
|
var b = 'b';
|
|
|
|
(function TestOverwritingInstanceAccessors() {
|
|
var C, desc;
|
|
C = class {
|
|
[b]() { return 'B'; };
|
|
get b() { return 'get B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C.prototype, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals('get B', desc.get());
|
|
assertEquals(undefined, desc.set);
|
|
|
|
C = class {
|
|
[b]() { return 'B'; };
|
|
set b(v) { return 'set B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C.prototype, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals(undefined, desc.get);
|
|
assertEquals('set B', desc.set());
|
|
|
|
C = class {
|
|
set b(v) { return 'get B'; };
|
|
[b]() { return 'B'; };
|
|
get b() { return 'get B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C.prototype, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals('get B', desc.get());
|
|
assertEquals(undefined, desc.set);
|
|
|
|
C = class {
|
|
get b() { return 'get B'; };
|
|
[b]() { return 'B'; };
|
|
set b(v) { return 'set B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C.prototype, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals(undefined, desc.get);
|
|
assertEquals('set B', desc.set());
|
|
})();
|
|
|
|
(function TestOverwritingStaticAccessors() {
|
|
var C, desc;
|
|
C = class {
|
|
static [b]() { return 'B'; };
|
|
static get b() { return 'get B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals('get B', desc.get());
|
|
assertEquals(undefined, desc.set);
|
|
|
|
C = class {
|
|
static [b]() { return 'B'; };
|
|
static set b(v) { return 'set B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals(undefined, desc.get);
|
|
assertEquals('set B', desc.set());
|
|
|
|
C = class {
|
|
static set b(v) { return 'get B'; };
|
|
static [b]() { return 'B'; };
|
|
static get b() { return 'get B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals('get B', desc.get());
|
|
assertEquals(undefined, desc.set);
|
|
|
|
C = class {
|
|
static get b() { return 'get B'; };
|
|
static [b]() { return 'B'; };
|
|
static set b(v) { return 'set B'; };
|
|
};
|
|
desc = Object.getOwnPropertyDescriptor(C, 'b');
|
|
assertFalse(desc.enumerable);
|
|
assertTrue(desc.configurable);
|
|
assertEquals(undefined, desc.get);
|
|
assertEquals('set B', desc.set());
|
|
})();
|