Skip to content

Commit

Permalink
Make wrapper instanciation lazy
Browse files Browse the repository at this point in the history
  • Loading branch information
pmdartus committed Jan 20, 2020
1 parent 7c8037f commit bb4a763
Show file tree
Hide file tree
Showing 6 changed files with 1,360 additions and 1,108 deletions.
6 changes: 3 additions & 3 deletions lib/constructs/attribute.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ class Attribute {
throw new TypeError("Illegal invocation");
}
`;
let getterBody = `return utils.tryWrapperForImpl(${objName}[impl]["${this.idl.name}"]);`;
let setterBody = `${objName}[impl]["${this.idl.name}"] = V;`;
let getterBody = `return utils.tryWrapperForImpl(${objName}[implSymbol]["${this.idl.name}"]);`;
let setterBody = `${objName}[implSymbol]["${this.idl.name}"] = V;`;
if (conversions[this.idl.idlType.idlType]) {
getterBody = `return ${objName}[impl]["${this.idl.name}"];`;
getterBody = `return ${objName}[implSymbol]["${this.idl.name}"];`;
}

const addMethod = this.static ?
Expand Down
121 changes: 64 additions & 57 deletions lib/constructs/interface.js
Original file line number Diff line number Diff line change
Expand Up @@ -404,7 +404,7 @@ class Interface {
value: function next() {
const internal = this[utils.iterInternalSymbol];
const { target, kind, index } = internal;
const values = Array.from(target[impl]);
const values = Array.from(target[implSymbol]);
const len = values.length;
if (index >= len) {
return { value: undefined, done: true };
Expand Down Expand Up @@ -498,8 +498,11 @@ class Interface {
}

generateRequires() {
this.requires.addRaw("impl", "utils.implSymbol");
this.requires.addRaw("ctorRegistry", "utils.ctorRegistrySymbol");
this.requires.addRaw("implSymbol", "utils.implSymbol");
this.requires.addRaw("wrapperSymbol", "utils.wrapperSymbol");
this.requires.addRaw("ctorRegistrySymbol", "utils.ctorRegistrySymbol");
this.requires.addRaw("globalObjectSymbol", "utils.globalObjectSymbol");
this.requires.addRaw("createWrapperSymbol", "utils.createWrapperSymbol");

if (this.idl.inheritance !== null) {
this.requires.add(this.idl.inheritance);
Expand Down Expand Up @@ -534,7 +537,7 @@ class Interface {
exports._mixedIntoPredicates = [];
exports.is = function is(obj) {
if (obj) {
if (utils.hasOwn(obj, impl) && obj[impl] instanceof Impl.implementation) {
if (utils.hasOwn(obj, implSymbol) && obj[implSymbol] instanceof Impl.implementation) {
return true;
}
for (const isMixedInto of exports._mixedIntoPredicates) {
Expand Down Expand Up @@ -595,10 +598,10 @@ class Interface {
}
if (unsupportedValue) {
const func = this.indexedGetter.name ? `.${this.indexedGetter.name}` : "[utils.indexedGet]";
const value = indexedValue || `${O}[impl]${func}(${index})`;
const value = indexedValue || `${O}[implSymbol]${func}(${index})`;
return `${value} !== ${unsupportedValue}`;
}
return `${O}[impl][utils.supportsPropertyIndex](${index})`;
return `${O}[implSymbol][utils.supportsPropertyIndex](${index})`;
};

const supportsPropertyName = (O, P, namedValue) => {
Expand All @@ -608,10 +611,10 @@ class Interface {
}
if (unsupportedValue) {
const func = this.namedGetter.name ? `.${this.namedGetter.name}` : "[utils.namedGet]";
const value = namedValue || `${O}[impl]${func}(${P})`;
const value = namedValue || `${O}[implSymbol]${func}(${P})`;
return `${value} !== ${unsupportedValue}`;
}
return `${O}[impl][utils.supportsPropertyName](${P})`;
return `${O}[implSymbol][utils.supportsPropertyName](${P})`;
};

// "named property visibility algorithm"
Expand Down Expand Up @@ -648,14 +651,14 @@ class Interface {
str += `
const creating = !(${supportsPropertyIndex(O, "index")});
if (creating) {
${O}[impl][utils.indexedSetNew](index, indexedValue);
${O}[implSymbol][utils.indexedSetNew](index, indexedValue);
} else {
${O}[impl][utils.indexedSetExisting](index, indexedValue);
${O}[implSymbol][utils.indexedSetExisting](index, indexedValue);
}
`;
} else {
str += `
${O}[impl].${this.indexedSetter.name}(index, indexedValue);
${O}[implSymbol].${this.indexedSetter.name}(index, indexedValue);
`;
}

Expand All @@ -679,14 +682,14 @@ class Interface {
str += `
const creating = !(${supportsPropertyName(O, P)});
if (creating) {
${O}[impl][utils.namedSetNew](${P}, namedValue);
${O}[implSymbol][utils.namedSetNew](${P}, namedValue);
} else {
${O}[impl][utils.namedSetExisting](${P}, namedValue);
${O}[implSymbol][utils.namedSetExisting](${P}, namedValue);
}
`;
} else {
str += `
${O}[impl].${this.namedSetter.name}(${P}, namedValue);
${O}[implSymbol].${this.namedSetter.name}(${P}, namedValue);
`;
}

Expand Down Expand Up @@ -749,14 +752,14 @@ class Interface {
`;
if (this.supportsIndexedProperties) {
this.str += `
for (const key of target[impl][utils.supportedPropertyIndices]) {
for (const key of target[implSymbol][utils.supportedPropertyIndices]) {
keys.add(\`\${key}\`);
}
`;
}
if (this.supportsNamedProperties) {
this.str += `
for (const key of target[impl][utils.supportedPropertyNames]) {
for (const key of target[implSymbol][utils.supportedPropertyNames]) {
if (${namedPropertyVisible("key", "target", true)}) {
keys.add(\`\${key}\`);
}
Expand Down Expand Up @@ -789,10 +792,10 @@ class Interface {
let preamble = "";
let condition;
if (utils.getExtAttr(this.indexedGetter.extAttrs, "WebIDL2JSValueAsUnsupported")) {
this.str += `const indexedValue = target[impl]${func}(index);`;
this.str += `const indexedValue = target[implSymbol]${func}(index);`;
condition = supportsPropertyIndex("target", "index", "indexedValue");
} else {
preamble = `const indexedValue = target[impl]${func}(index);`;
preamble = `const indexedValue = target[implSymbol]${func}(index);`;
condition = supportsPropertyIndex("target", "index");
}

Expand All @@ -817,13 +820,13 @@ class Interface {
const conditions = [];
if (utils.getExtAttr(this.namedGetter.extAttrs, "WebIDL2JSValueAsUnsupported")) {
this.str += `
const namedValue = target[impl]${func}(P);
const namedValue = target[implSymbol]${func}(P);
`;
conditions.push(supportsPropertyName("target", "index", "namedValue"));
conditions.push(namedPropertyVisible("P", "target", true));
} else {
preamble = `
const namedValue = target[impl]${func}(P);
const namedValue = target[implSymbol]${func}(P);
`;
conditions.push(namedPropertyVisible("P", "target", false));
}
Expand Down Expand Up @@ -899,10 +902,10 @@ class Interface {
let preamble = "";
let condition;
if (utils.getExtAttr(this.indexedGetter.extAttrs, "WebIDL2JSValueAsUnsupported")) {
this.str += `const indexedValue = target[impl]${func}(index);`;
this.str += `const indexedValue = target[implSymbol]${func}(index);`;
condition = supportsPropertyIndex("target", "index", "indexedValue");
} else {
preamble = `const indexedValue = target[impl]${func}(index);`;
preamble = `const indexedValue = target[implSymbol]${func}(index);`;
condition = supportsPropertyIndex("target", "index");
}

Expand Down Expand Up @@ -1068,11 +1071,11 @@ class Interface {
const func = this.namedDeleter.name ? `.${this.namedDeleter.name}` : "[utils.namedDelete]";
if (this.namedDeleter.idlType.idlType === "bool") {
this.str += `
return target[impl]${func}(P);
return target[implSymbol]${func}(P);
`;
} else {
this.str += `
target[impl]${func}(P);
target[implSymbol]${func}(P);
return true;
`;
}
Expand Down Expand Up @@ -1100,59 +1103,63 @@ class Interface {

generateIface() {
this.str += `
exports.create = function create(globalObject, constructorArgs, privateData) {
if (globalObject[ctorRegistry] === undefined) {
function createWrapper(impl) {
const globalObject = impl[globalObjectSymbol];
if (globalObject[ctorRegistrySymbol] === undefined) {
throw new Error('Internal error: invalid global object');
}
const ctor = globalObject[ctorRegistry]["${this.name}"];
const ctor = globalObject[ctorRegistrySymbol]["${this.name}"];
if (ctor === undefined) {
throw new Error('Internal error: constructor ${this.name} is not installed on the passed global object');
}
let obj = Object.create(ctor.prototype);
obj = exports.setup(obj, globalObject, constructorArgs, privateData);
return obj;
};
exports.createImpl = function createImpl(globalObject, constructorArgs, privateData) {
const obj = exports.create(globalObject, constructorArgs, privateData);
return utils.implForWrapper(obj);
};
exports._internalSetup = function _internalSetup(obj) {
let wrapper = Object.create(ctor.prototype);
exports._internalSetup(wrapper);
`;

if (this.idl.inheritance) {
if (this.isLegacyPlatformObj) {
this.str += `
${this.idl.inheritance}._internalSetup(obj);
wrapper = new Proxy(wrapper, proxyHandler);
`;
}

this.generateOnInstance();

this.str += `
impl[wrapperSymbol] = wrapper;
wrapper[implSymbol] = impl;
return wrapper;
};
exports.create = function create(globalObject, constructorArgs, privateData) {
const impl = exports.createImpl(globalObject, constructorArgs, privateData);
return utils.wrapperForImpl(impl);
};
exports.setup = function setup(obj, globalObject, constructorArgs = [], privateData = {}) {
privateData.wrapper = obj;
exports.createImpl = function createImpl(globalObject, constructorArgs = [], privateData = {}) {
const impl = new Impl.implementation(globalObject, constructorArgs, privateData);
exports._internalSetup(obj);
Object.defineProperty(obj, impl, {
value: new Impl.implementation(globalObject, constructorArgs, privateData),
configurable: true
});
impl[wrapperSymbol] = null;
impl[globalObjectSymbol] = globalObject;
impl[createWrapperSymbol] = createWrapper;
return impl;
};
exports.setup = function setup(wrapper, globalObject, constructorArgs = [], privateData = {}) {
const impl = exports.createImpl(globalObject, constructorArgs, privateData);
impl[wrapperSymbol] = wrapper;
wrapper[implSymbol] = impl;
return wrapper;
};
exports._internalSetup = function _internalSetup(obj) {
`;

if (this.isLegacyPlatformObj) {
if (this.idl.inheritance) {
this.str += `
obj = new Proxy(obj, proxyHandler);
${this.idl.inheritance}._internalSetup(obj);
`;
}
this.generateOnInstance();

this.str += `
obj[impl][utils.wrapperSymbol] = obj;
if (Impl.init) {
Impl.init(obj[impl], privateData);
}
return obj;
};
`;
}
Expand Down Expand Up @@ -1438,10 +1445,10 @@ class Interface {
this.generateOffInstanceAfterClass();

this.str += `
if (globalObject[ctorRegistry] === undefined) {
globalObject[ctorRegistry] = Object.create(null);
if (globalObject[ctorRegistrySymbol] === undefined) {
globalObject[ctorRegistrySymbol] = Object.create(null);
}
globalObject[ctorRegistry]["${name}"] = ${name};
globalObject[ctorRegistrySymbol]["${name}"] = ${name};
Object.defineProperty(globalObject, "${name}", {
configurable: true,
Expand Down
2 changes: 1 addition & 1 deletion lib/constructs/operation.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ class Operation {
`;
}

const callOn = this.static ? "Impl.implementation" : "this[impl]";
const callOn = this.static ? "Impl.implementation" : "this[implSymbol]";
// In case of stringifiers, use the named implementation function rather than hardcoded "toString".
// All overloads will have the same name, so pick the first one.
const implFunc = this.idls[0].name || this.name;
Expand Down
15 changes: 14 additions & 1 deletion lib/output/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ function hasOwn(obj, prop) {

const wrapperSymbol = Symbol("wrapper");
const implSymbol = Symbol("impl");
const globalObjectSymbol = Symbol("global object");
const createWrapperSymbol = Symbol("create wrapper");
const sameObjectCaches = Symbol("SameObject caches");
const ctorRegistrySymbol = Symbol.for("[webidl2js] constructor registry");

Expand All @@ -28,7 +30,16 @@ function getSameObject(wrapper, prop, creator) {
}

function wrapperForImpl(impl) {
return impl ? impl[wrapperSymbol] : null;
if (!impl) {
return null;
}

const wrapper = impl[wrapperSymbol];
if (wrapper === undefined || wrapper !== null) {
return wrapper;
}

return impl[createWrapperSymbol](impl);
}

function implForWrapper(wrapper) {
Expand Down Expand Up @@ -91,6 +102,8 @@ module.exports = exports = {
hasOwn,
wrapperSymbol,
implSymbol,
globalObjectSymbol,
createWrapperSymbol,
getSameObject,
ctorRegistrySymbol,
wrapperForImpl,
Expand Down
18 changes: 9 additions & 9 deletions lib/reflector.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@

module.exports.boolean = {
get(objName, attrName) {
return `return this[impl].hasAttributeNS(null, "${attrName}");`;
return `return this[implSymbol].hasAttributeNS(null, "${attrName}");`;
},
set(objName, attrName) {
return `
if (V) {
this[impl].setAttributeNS(null, "${attrName}", "");
this[implSymbol].setAttributeNS(null, "${attrName}", "");
} else {
this[impl].removeAttributeNS(null, "${attrName}");
this[implSymbol].removeAttributeNS(null, "${attrName}");
}
`;
}
Expand All @@ -18,35 +18,35 @@ module.exports.boolean = {
module.exports.DOMString = {
get(objName, attrName) {
return `
const value = this[impl].getAttributeNS(null, "${attrName}");
const value = this[implSymbol].getAttributeNS(null, "${attrName}");
return value === null ? "" : value;
`;
},
set(objName, attrName) {
return `this[impl].setAttributeNS(null, "${attrName}", V);`;
return `this[implSymbol].setAttributeNS(null, "${attrName}", V);`;
}
};

module.exports.long = {
get(objName, attrName) {
return `
const value = parseInt(this[impl].getAttributeNS(null, "${attrName}"));
const value = parseInt(this[implSymbol].getAttributeNS(null, "${attrName}"));
return isNaN(value) || value < -2147483648 || value > 2147483647 ? 0 : value
`;
},
set(objName, attrName) {
return `this[impl].setAttributeNS(null, "${attrName}", String(V));`;
return `this[implSymbol].setAttributeNS(null, "${attrName}", String(V));`;
}
};

module.exports["unsigned long"] = {
get(objName, attrName) {
return `
const value = parseInt(this[impl].getAttributeNS(null, "${attrName}"));
const value = parseInt(this[implSymbol].getAttributeNS(null, "${attrName}"));
return isNaN(value) || value < 0 || value > 2147483647 ? 0 : value
`;
},
set(objName, attrName) {
return `this[impl].setAttributeNS(null, "${attrName}", String(V > 2147483647 ? 0 : V));`;
return `this[implSymbol].setAttributeNS(null, "${attrName}", String(V > 2147483647 ? 0 : V));`;
}
};
Loading

0 comments on commit bb4a763

Please sign in to comment.