2022-05-16 11:04:00 +00:00
|
|
|
// Copyright 2022 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.
|
|
|
|
|
|
|
|
class A {
|
|
|
|
constructor(arg) {
|
|
|
|
return arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class B extends A {
|
|
|
|
#b = 1; // ACCESS_CHECK -> DATA
|
|
|
|
constructor(arg) {
|
|
|
|
super(arg);
|
|
|
|
}
|
|
|
|
static setField(obj) {
|
|
|
|
obj.#b = 'b'; // KeyedStoreIC
|
|
|
|
}
|
|
|
|
static getField(obj) {
|
|
|
|
return obj.#b;
|
|
|
|
}
|
2022-07-05 16:30:02 +00:00
|
|
|
static hasField(obj) {
|
|
|
|
return #b in obj;
|
|
|
|
}
|
2022-05-16 11:04:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class C extends A {
|
|
|
|
#c; // DefineKeyedOwnIC: ACCESS_CHECK -> NOT_FOUND
|
|
|
|
constructor(arg) {
|
|
|
|
super(arg);
|
|
|
|
}
|
|
|
|
static setField(obj) {
|
|
|
|
obj.#c = 'c'; // KeyedStoreIC
|
|
|
|
}
|
|
|
|
static getField(obj) {
|
|
|
|
return obj.#c;
|
|
|
|
}
|
2022-07-05 16:30:02 +00:00
|
|
|
static hasField(obj) {
|
|
|
|
return #c in obj;
|
|
|
|
}
|
2022-05-16 11:04:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let d = 0;
|
|
|
|
class D extends A {
|
|
|
|
get #d() { return d; }
|
2022-07-05 16:30:02 +00:00
|
|
|
set #d(val) { d = val; }
|
2022-05-16 11:04:00 +00:00
|
|
|
constructor(arg) {
|
|
|
|
super(arg); // KeyedStoreIC for private brand
|
|
|
|
}
|
|
|
|
static setAccessor(obj) {
|
|
|
|
obj.#d = 'd'; // KeyedLoadIC for private brand
|
|
|
|
}
|
|
|
|
static getAccessor(obj) {
|
|
|
|
return obj.#d; // KeyedLoadIC for private brand
|
|
|
|
}
|
2022-07-05 16:30:02 +00:00
|
|
|
static hasAccessor(obj) {
|
|
|
|
return #d in obj;
|
|
|
|
}
|
2022-05-16 11:04:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class E extends A {
|
|
|
|
#e() { return 0; }
|
|
|
|
constructor(arg) {
|
|
|
|
super(arg); // KeyedStoreIC for private brand
|
|
|
|
}
|
|
|
|
static setMethod(obj) {
|
|
|
|
obj.#e = 'e'; // KeyedLoadIC for private brand
|
|
|
|
}
|
|
|
|
static getMethod(obj) {
|
|
|
|
return obj.#e; // KeyedLoadIC for private brand
|
|
|
|
}
|
2022-07-05 16:30:02 +00:00
|
|
|
static hasMethod(obj) {
|
|
|
|
return #e in obj;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkHasAccess(object) {
|
|
|
|
assertThrows(() => B.setField(globalProxy), TypeError, /Cannot write private member #b to an object whose class did not declare it/);
|
|
|
|
assertThrows(() => B.getField(globalProxy), TypeError, /Cannot read private member #b from an object whose class did not declare it/);
|
|
|
|
assertFalse(B.hasField(globalProxy));
|
|
|
|
|
|
|
|
new B(globalProxy);
|
|
|
|
assertEquals(B.getField(globalProxy), 1);
|
|
|
|
B.setField(globalProxy);
|
|
|
|
assertEquals(B.getField(globalProxy), 'b'); // Fast case
|
|
|
|
B.setField(globalProxy); // Fast case
|
|
|
|
assertEquals(B.getField(globalProxy), 'b'); // Fast case
|
|
|
|
assertThrows(() => new B(globalProxy), TypeError, /Cannot initialize #b twice on the same object/);
|
|
|
|
assertTrue(B.hasField(globalProxy));
|
|
|
|
assertTrue(B.hasField(globalProxy)); // Fast case
|
|
|
|
|
|
|
|
assertThrows(() => C.setField(globalProxy), TypeError, /Cannot write private member #c to an object whose class did not declare it/);
|
|
|
|
assertThrows(() => C.getField(globalProxy), TypeError, /Cannot read private member #c from an object whose class did not declare it/);
|
|
|
|
assertFalse(C.hasField(globalProxy));
|
|
|
|
|
|
|
|
new C(globalProxy);
|
|
|
|
assertEquals(C.getField(globalProxy), undefined);
|
|
|
|
C.setField(globalProxy);
|
|
|
|
assertEquals(C.getField(globalProxy), 'c'); // Fast case
|
|
|
|
C.setField(globalProxy); // Fast case
|
|
|
|
assertEquals(C.getField(globalProxy), 'c'); // Fast case
|
|
|
|
assertThrows(() => new C(globalProxy), TypeError, /Cannot initialize #c twice on the same object/);
|
|
|
|
assertTrue(C.hasField(globalProxy));
|
|
|
|
assertTrue(C.hasField(globalProxy)); // Fast case
|
|
|
|
|
|
|
|
assertThrows(() => D.setAccessor(globalProxy), TypeError, /Receiver must be an instance of class D/);
|
|
|
|
assertThrows(() => D.getAccessor(globalProxy), TypeError, /Receiver must be an instance of class D/);
|
|
|
|
assertFalse(D.hasAccessor(globalProxy));
|
|
|
|
|
|
|
|
new D(globalProxy);
|
|
|
|
assertEquals(D.getAccessor(globalProxy), 0);
|
|
|
|
D.setAccessor(globalProxy);
|
|
|
|
assertEquals(D.getAccessor(globalProxy), 'd'); // Fast case
|
|
|
|
D.setAccessor(globalProxy); // Fast case
|
|
|
|
assertEquals(D.getAccessor(globalProxy), 'd'); // Fast case
|
|
|
|
assertThrows(() => new D(globalProxy), TypeError, /Cannot initialize private methods of class D twice on the same object/);
|
|
|
|
assertTrue(D.hasAccessor(globalProxy));
|
|
|
|
assertTrue(D.hasAccessor(globalProxy)); // Fast case
|
|
|
|
|
|
|
|
assertThrows(() => E.setMethod(globalProxy), TypeError, /Receiver must be an instance of class E/);
|
|
|
|
assertThrows(() => E.getMethod(globalProxy), TypeError, /Receiver must be an instance of class E/);
|
|
|
|
assertFalse(E.hasMethod(globalProxy));
|
|
|
|
|
|
|
|
new E(globalProxy);
|
|
|
|
assertEquals(E.getMethod(globalProxy)(), 0);
|
|
|
|
assertThrows(() => E.setMethod(globalProxy), TypeError, /Private method '#e' is not writable/);
|
|
|
|
assertEquals(E.getMethod(globalProxy)(), 0); // Fast case
|
|
|
|
assertThrows(() => new E(globalProxy), TypeError, /Cannot initialize private methods of class E twice on the same object/);
|
|
|
|
assertTrue(E.hasMethod(globalProxy));
|
|
|
|
assertTrue(E.hasMethod(globalProxy)); // Fast case
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkNoAccess(object, message) {
|
|
|
|
assertThrows(() => new B(object), Error, message);
|
|
|
|
assertThrows(() => new C(object), Error, message);
|
|
|
|
assertThrows(() => new D(object), Error, message);
|
|
|
|
assertThrows(() => new E(object), Error, message);
|
|
|
|
assertThrows(() => B.setField(object), Error, message);
|
|
|
|
assertThrows(() => B.getField(object), Error, message);
|
|
|
|
assertThrows(() => B.hasField(object), Error, message);
|
|
|
|
assertThrows(() => C.setField(object), Error, message);
|
|
|
|
assertThrows(() => C.getField(object), Error, message);
|
|
|
|
assertThrows(() => C.hasField(object), Error, message);
|
|
|
|
assertThrows(() => D.setAccessor(object), Error, message);
|
|
|
|
assertThrows(() => D.getAccessor(object), Error, message);
|
|
|
|
assertThrows(() => D.hasAccessor(object), Error, message);
|
|
|
|
assertThrows(() => E.setMethod(object), Error, message);
|
|
|
|
assertThrows(() => E.getMethod(object), Error, message);
|
|
|
|
assertThrows(() => E.hasMethod(object), Error, message);
|
|
|
|
}
|
|
|
|
|
|
|
|
function checkNoAccessNoThrow(object) {
|
|
|
|
// The failed access check callback is supposed to throw.
|
|
|
|
// If it doesn't the behavior is quite quirky.
|
|
|
|
// This only documents the current behavior.
|
|
|
|
new B(object);
|
|
|
|
new C(object);
|
|
|
|
new D(object);
|
|
|
|
new E(object);
|
|
|
|
B.setField(object);
|
|
|
|
assertEquals(undefined, B.getField(object));
|
|
|
|
assertFalse(B.hasField(object));
|
|
|
|
C.setField(object);
|
|
|
|
assertEquals(undefined, C.getField(object));
|
|
|
|
assertFalse(C.hasField(object));
|
|
|
|
D.setAccessor(object)
|
|
|
|
assertEquals("d", D.getAccessor(object));
|
|
|
|
assertFalse(D.hasAccessor(object));
|
|
|
|
assertThrows(() => E.setMethod(object), TypeError, /Private method '#e' is not writable/);
|
|
|
|
assertEquals(0, E.getMethod(object)());
|
|
|
|
assertFalse(E.hasMethod(object));
|
2022-05-16 11:04:00 +00:00
|
|
|
}
|