Skip to content

Commit

Permalink
bootstrap: delay the instantiation of maps in per-context scripts
Browse files Browse the repository at this point in the history
Instantiating maps renders the snapshot non-rehashable
(v8 currently fails silently during `CreateBlob()`).
Then the hash seed would always be the same and not
recomputed if custom V8 snapshot is enabled. This patch
delays the instantiation of the maps in domexception.js
and make it lazy.

PR-URL: nodejs/node#27371
Reviewed-By: Anna Henningsen <[email protected]>
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: Ruben Bridgewater <[email protected]>
  • Loading branch information
joyeecheung authored and danbev committed Apr 26, 2019
1 parent 5ab65cf commit 08a9c4a
Showing 1 changed file with 51 additions and 31 deletions.
82 changes: 51 additions & 31 deletions lib/internal/per_context/domexception.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,28 @@ class ERR_INVALID_THIS extends TypeError {
get code() { return 'ERR_INVALID_THIS'; }
}

const internalsMap = new SafeWeakMap();
let internalsMap;
let nameToCodeMap;
let isInitialized = false;

const nameToCodeMap = new SafeMap();
// We need to instantiate the maps lazily because they render
// the snapshot non-rehashable.
// https://bugs.chromium.org/p/v8/issues/detail?id=6593
function ensureInitialized() {
if (isInitialized) {
return;
}
internalsMap = new SafeWeakMap();
nameToCodeMap = new SafeMap();
forEachCode((name, codeName, value) => {
nameToCodeMap.set(name, value);
});
isInitialized = true;
}

class DOMException extends Error {
constructor(message = '', name = 'Error') {
ensureInitialized();
super();
internalsMap.set(this, {
message: `${message}`,
Expand All @@ -29,6 +45,7 @@ class DOMException extends Error {
}

get name() {
ensureInitialized();
const internals = internalsMap.get(this);
if (internals === undefined) {
throw new ERR_INVALID_THIS('DOMException');
Expand All @@ -37,6 +54,7 @@ class DOMException extends Error {
}

get message() {
ensureInitialized();
const internals = internalsMap.get(this);
if (internals === undefined) {
throw new ERR_INVALID_THIS('DOMException');
Expand All @@ -45,6 +63,7 @@ class DOMException extends Error {
}

get code() {
ensureInitialized();
const internals = internalsMap.get(this);
if (internals === undefined) {
throw new ERR_INVALID_THIS('DOMException');
Expand All @@ -61,39 +80,40 @@ Object.defineProperties(DOMException.prototype, {
code: { enumerable: true, configurable: true }
});

for (const [name, codeName, value] of [
['IndexSizeError', 'INDEX_SIZE_ERR', 1],
['DOMStringSizeError', 'DOMSTRING_SIZE_ERR', 2],
['HierarchyRequestError', 'HIERARCHY_REQUEST_ERR', 3],
['WrongDocumentError', 'WRONG_DOCUMENT_ERR', 4],
['InvalidCharacterError', 'INVALID_CHARACTER_ERR', 5],
['NoDataAllowedError', 'NO_DATA_ALLOWED_ERR', 6],
['NoModificationAllowedError', 'NO_MODIFICATION_ALLOWED_ERR', 7],
['NotFoundError', 'NOT_FOUND_ERR', 8],
['NotSupportedError', 'NOT_SUPPORTED_ERR', 9],
['InUseAttributeError', 'INUSE_ATTRIBUTE_ERR', 10],
['InvalidStateError', 'INVALID_STATE_ERR', 11],
['SyntaxError', 'SYNTAX_ERR', 12],
['InvalidModificationError', 'INVALID_MODIFICATION_ERR', 13],
['NamespaceError', 'NAMESPACE_ERR', 14],
['InvalidAccessError', 'INVALID_ACCESS_ERR', 15],
['ValidationError', 'VALIDATION_ERR', 16],
['TypeMismatchError', 'TYPE_MISMATCH_ERR', 17],
['SecurityError', 'SECURITY_ERR', 18],
['NetworkError', 'NETWORK_ERR', 19],
['AbortError', 'ABORT_ERR', 20],
['URLMismatchError', 'URL_MISMATCH_ERR', 21],
['QuotaExceededError', 'QUOTA_EXCEEDED_ERR', 22],
['TimeoutError', 'TIMEOUT_ERR', 23],
['InvalidNodeTypeError', 'INVALID_NODE_TYPE_ERR', 24],
['DataCloneError', 'DATA_CLONE_ERR', 25]
function forEachCode(fn) {
fn('IndexSizeError', 'INDEX_SIZE_ERR', 1);
fn('DOMStringSizeError', 'DOMSTRING_SIZE_ERR', 2);
fn('HierarchyRequestError', 'HIERARCHY_REQUEST_ERR', 3);
fn('WrongDocumentError', 'WRONG_DOCUMENT_ERR', 4);
fn('InvalidCharacterError', 'INVALID_CHARACTER_ERR', 5);
fn('NoDataAllowedError', 'NO_DATA_ALLOWED_ERR', 6);
fn('NoModificationAllowedError', 'NO_MODIFICATION_ALLOWED_ERR', 7);
fn('NotFoundError', 'NOT_FOUND_ERR', 8);
fn('NotSupportedError', 'NOT_SUPPORTED_ERR', 9);
fn('InUseAttributeError', 'INUSE_ATTRIBUTE_ERR', 10);
fn('InvalidStateError', 'INVALID_STATE_ERR', 11);
fn('SyntaxError', 'SYNTAX_ERR', 12);
fn('InvalidModificationError', 'INVALID_MODIFICATION_ERR', 13);
fn('NamespaceError', 'NAMESPACE_ERR', 14);
fn('InvalidAccessError', 'INVALID_ACCESS_ERR', 15);
fn('ValidationError', 'VALIDATION_ERR', 16);
fn('TypeMismatchError', 'TYPE_MISMATCH_ERR', 17);
fn('SecurityError', 'SECURITY_ERR', 18);
fn('NetworkError', 'NETWORK_ERR', 19);
fn('AbortError', 'ABORT_ERR', 20);
fn('URLMismatchError', 'URL_MISMATCH_ERR', 21);
fn('QuotaExceededError', 'QUOTA_EXCEEDED_ERR', 22);
fn('TimeoutError', 'TIMEOUT_ERR', 23);
fn('InvalidNodeTypeError', 'INVALID_NODE_TYPE_ERR', 24);
fn('DataCloneError', 'DATA_CLONE_ERR', 25);
// There are some more error names, but since they don't have codes assigned,
// we don't need to care about them.
]) {
}

forEachCode((name, codeName, value) => {
const desc = { enumerable: true, value };
Object.defineProperty(DOMException, codeName, desc);
Object.defineProperty(DOMException.prototype, codeName, desc);
nameToCodeMap.set(name, value);
}
});

exports.DOMException = DOMException;

0 comments on commit 08a9c4a

Please sign in to comment.