Source code

Revision control

Copy as Markdown

Other Tools

load(libdir + 'evalInFrame.js');
class B {
#priv() {
return 12;
}
#privF = () => { return 12; }
callPriv() {
return this.#priv();
}
callPrivF() {
return this.#privF();
}
#val = 'constructed';
set #x(x) {
this.#val = x + ' haha';
}
get #x() {
return this.#val;
}
ef(str) {
return evalInFrame(0, str);
}
layerEf(str) {
// Nested functions here result in computeEffectiveScope traversing
// more than one environment, necessitating more hops.
function tester(o) {
let a = 10;
function interior(o) {
let b = a;
return evalInFrame(0, str.replace("this", "o"));
};
return interior(o);
}
return tester(this);
}
moreLayerEf(str) {
// Nested functions here result in computeEffectiveScope traversing
// more than one environment, necessitating more hops.
function tester(o) {
let a = 0;
function interior(o) {
let b = a;
return (() => {
let k = o;
let replace = str.replace("this", "k");
print(replace);
return evalInFrame(b, replace);
})();
};
return interior(o);
}
return tester(this);
}
callFunc(f) {
return f();
}
static #smethod() {
return 14;
}
static #unusedmethod() {
return 19;
}
static get #unusedgetter() {
return 10;
}
static setter = undefined;
static set #unusedsetter(x) { this.setter = x }
static f() {
return this.#smethod();
}
static seval(str) {
return eval(str);
}
static sef(str) {
return evalInFrame(0, str);
}
static sLayerEf(str) {
// Nested functions here result in computeEffectiveScope traversing
// more than one environment, necessitating more hops.
function tester(o) {
let a = 10;
function interior(o) {
if (a == 10) {
let b = 10 - a;
return evalInFrame(b, str.replace("this", "o"));
}
};
return interior(o);
}
return tester(this);
}
}
var b = new B();
assertEq(b.ef("this.callPriv()"), 12);
assertEq(b.ef("this.callPrivF()"), 12);
// Private fields don't need brand checking and should succeed.
assertEq(b.ef("this.#val"), 'constructed')
// PrivF is a field, not a method, and so isn't brand checked like a method.
assertEq(b.ef(`this.callFunc(() => { return this.#privF() })`), 12);
assertEq(b.ef(`this.#privF()`), 12);
// Accesors are stored like fields, and so successfully execute, as they don't
// need brand checking.
assertEq(b.ef(`this.#x = 'Bye'; this.#x`), 'Bye haha');
assertEq(b.ef(`var x = () => { this.#x = 'Hi'; return this.#x}; x()`), 'Hi haha');
// // Private methods require very special brand checking.
assertEq(b.ef(`this.#priv()`), 12);
assertEq(b.ef(`let hello;
let f = () => {
hello = this.#priv();
assertEq(hello, 12);
};
f();
hello`), 12);
assertEq(b.layerEf(`this.#priv()`), 12);
assertEq(b.moreLayerEf(`this.#priv()`), 12);
if ('dis' in this) {
// Ensure disassembly of GetAliasedDebugVar wroks.
assertEq(b.ef(`dis(); this.#priv()`), 12);
}
assertEq(b.ef(`var x = () => { return this.#priv(); }; x()`), 12);
assertEq(b.ef(`function x(o) { function y(o) { return o.#priv(); }; return y(o); } x(this)`), 12);
assertEq(B.f(), 14);
assertEq(B.sef(`this.#smethod()`), 14);
assertEq(B.sLayerEf(`this.#smethod()`), 14);
assertEq(B.sef("this.#unusedmethod()"), 19);
assertEq(B.sef("this.#unusedgetter"), 10);
B.sef("this.#unusedsetter = 13");
assertEq(B.setter, 13);
// Test case variant from Arai.
class C {
#priv() {
return 12;
}
efInFunction(str) {
return (() => {
let self = this;
return evalInFrame(0, str);
})();
}
}
c = new C;
assertEq(c.efInFunction(`self.#priv()`), 12);
// JIT testing
assertEq(b.ef(`
let result;
let f = () => {
result = this.#priv();
assertEq(result, 12);
};
for (let i = 0; i < 1000; i++) {
f();
}
result
`), 12);
assertEq(b.ef("function f(o) { return o.callPriv() }; for (let i = 0; i < 1000; i++) { f(this); } f(this)"), 12);
assertEq(b.ef("function f(o) { return o.callPrivF() }; for (let i = 0; i < 1000; i++) { f(this); } f(this)"), 12);
assertEq(b.ef(`function x(o) { function y(o) { return o.#priv(); }; return y(o); } x(this)`), 12);
assertEq(B.sef(`function f(o) { return o.#smethod() }; for (let i = 0; i < 1000; i ++) { f(this); }; f(this)`), 14);
assertEq(b.ef(`
var x = () => {
return (() => {
return (() => {
let a;
return (() => {
let b = a;
return this.#priv();
})();
})();
})();
};
x()
`), 12);