blob: 2097163d62cb4e72fa36980ccb2b952d78f8fccf [file] [log] [blame]
"use strict";
var createCustomGetterObject = $vm.createCustomGetterObject;
function assert(a) {
if (!a)
throw new Error("Bad!");
}
var Base = class Base {
constructor() { this._name = "Name"; }
get name() { return this._name; } // If this instead returns a static: return "Foo" things somewhat work.
set name(x) { this._name = x; }
};
var Subclass = class Subclass extends Base {
get name() { return super.name; }
};
function getterName(instance) {
return instance.name;
}
noInline(getterName);
function getterValue(instance) {
return instance.value;
}
noInline(getterValue);
const runTimes = 10000;
// Base case
var instance = new Subclass;
for (let i = 0; i < runTimes; i++)
assert(getterName(instance) == "Name");
// Polymorphic case
class PolymorphicSubclass {
get value() { return super.value; }
};
let numPolymorphicClasses = 4;
let subclasses = new Array(numPolymorphicClasses);
for (let i = 0; i < numPolymorphicClasses; i++) {
let BaseCode = `
(class Base${i} {
get value() { return this._value; }
});
`;
let Base = eval(BaseCode);
subclasses[i] = new PolymorphicSubclass();
subclasses[i]._value = i;
Object.setPrototypeOf(subclasses[i], Base.prototype);
}
for (let i = 0; i < runTimes; i++) {
let index = i % numPolymorphicClasses;
let value = getterValue(subclasses[index]);
assert(value == index);
}
// Megamorphic case
let nClasses = 1000;
class MegamorphicSubclass {
get value() { return super.value; }
};
subclasses = new Array(nClasses);
for (let i = 0; i < nClasses; i++) {
let BaseCode = `
(class Base${i + 4} {
get value() { return this._value; }
});
`;
let Base = eval(BaseCode);
subclasses[i] = new MegamorphicSubclass();
subclasses[i]._value = i;
Object.setPrototypeOf(subclasses[i], Base.prototype);
}
for (let i = 0; i < runTimes; i++) {
let index = i % nClasses;
let value = getterValue(subclasses[index]);
assert(value == index);
}
// CustomGetter case
let customGetter = createCustomGetterObject();
Object.setPrototypeOf(customGetter, Object.prototype);
let subObj = {
__proto__: customGetter,
get value () {
return super.customGetterAccessor;
}
}
for (let i = 0; i < runTimes; i++) {
let value = getterValue(subObj);
assert(value == 100);
}
subObj.shouldThrow = true;
for (let i = 0; i < runTimes; i++) {
try {
getterValue(subObj);
assert(false);
} catch(e) {
assert(e instanceof TypeError);
};
}
// CustomValue case
customGetter = createCustomGetterObject();
Object.setPrototypeOf(customGetter, Object.prototype);
subObj = {
__proto__: customGetter,
get value () {
return super.customGetter;
}
}
for (let i = 0; i < runTimes; i++) {
let value = getterValue(subObj);
assert(value == 100);
}
subObj.shouldThrow = true;
for (let i = 0; i < runTimes; i++) {
let value = getterValue(subObj);
assert(value == 100);
}
// Exception handling case
class BaseException {
constructor() { this._name = "Name"; }
get name() {
if (this.shouldThrow)
throw new Error("Forced Exception");
return this._name;
}
};
class SubclassException extends BaseException {
get name() { return super.name; }
};
let eObj = new SubclassException;
for (let i = 0; i < runTimes; i++)
assert(getterName(eObj) == "Name");
eObj.shouldThrow = true;
for (let i = 0; i < runTimes; i++) {
try {
getterValue(eObj);
assert(false);
} catch(e) {
eObj.shouldThrow = false;
assert(getterName(eObj) == "Name");
};
}
// In getter exception handling
class BaseExceptionComplex {
constructor() { this._name = "Name"; }
foo () {
if (this.shouldThrow)
throw new Error("Forced Exception");
}
get name() {
this.foo();
return this._name;
}
};
class SubclassExceptionComplex extends BaseExceptionComplex {
get name() {
try {
return super.name;
} catch(e) {
this.shouldThrow = false;
return super.name;
}
}
};
eObj = new SubclassExceptionComplex;
for (let i = 0; i < runTimes; i++)
assert(getterName(eObj) == "Name");
eObj.shouldThrow = true;
for (let i = 0; i < runTimes; i++)
assert(getterName(eObj) == "Name");