0
0
mirror of https://github.com/nodejs/node.git synced 2024-11-30 07:27:22 +01:00
nodejs/lib/internal/per_context/primordials.js
Bradley Farias 6ce87c027d policy: minor perf opts and cleanup
PR-URL: https://github.com/nodejs/node/pull/29322
Reviewed-By: James M Snell <jasnell@gmail.com>
2019-09-03 11:12:05 -05:00

121 lines
3.3 KiB
JavaScript

'use strict';
/* eslint-disable no-restricted-globals */
// This file subclasses and stores the JS builtins that come from the VM
// so that Node.js's builtin modules do not need to later look these up from
// the global proxy, which can be mutated by users.
// TODO(joyeecheung): we can restrict access to these globals in builtin
// modules through the JS linter, for example: ban access such as `Object`
// (which falls back to a lookup in the global proxy) in favor of
// `primordials.Object` where `primordials` is a lexical variable passed
// by the native module compiler.
const ReflectApply = Reflect.apply;
const ReflectConstruct = Reflect.construct;
// This function is borrowed from the function with the same name on V8 Extras'
// `utils` object. V8 implements Reflect.apply very efficiently in conjunction
// with the spread syntax, such that no additional special case is needed for
// function calls w/o arguments.
// Refs: https://github.com/v8/v8/blob/d6ead37d265d7215cf9c5f768f279e21bd170212/src/js/prologue.js#L152-L156
function uncurryThis(func) {
return (thisArg, ...args) => ReflectApply(func, thisArg, args);
}
primordials.uncurryThis = uncurryThis;
function copyProps(src, dest) {
for (const key of Reflect.ownKeys(src)) {
if (!Reflect.getOwnPropertyDescriptor(dest, key)) {
Reflect.defineProperty(
dest,
key,
Reflect.getOwnPropertyDescriptor(src, key));
}
}
}
function copyPrototype(src, dest) {
for (const key of Reflect.ownKeys(src)) {
if (!Reflect.getOwnPropertyDescriptor(dest, key)) {
const desc = Reflect.getOwnPropertyDescriptor(src, key);
if (typeof desc.value === 'function') {
desc.value = uncurryThis(desc.value);
}
Reflect.defineProperty(dest, key, desc);
}
}
}
function makeSafe(unsafe, safe) {
copyProps(unsafe.prototype, safe.prototype);
copyProps(unsafe, safe);
Object.setPrototypeOf(safe.prototype, null);
Object.freeze(safe.prototype);
Object.freeze(safe);
return safe;
}
// Subclass the constructors because we need to use their prototype
// methods later.
primordials.SafeMap = makeSafe(
Map,
class SafeMap extends Map {}
);
primordials.SafeWeakMap = makeSafe(
WeakMap,
class SafeWeakMap extends WeakMap {}
);
primordials.SafeSet = makeSafe(
Set,
class SafeSet extends Set {}
);
primordials.SafePromise = makeSafe(
Promise,
class SafePromise extends Promise {}
);
// Create copies of the namespace objects
[
'JSON',
'Math',
'Reflect'
].forEach((name) => {
const target = primordials[name] = Object.create(null);
copyProps(global[name], target);
});
// Create copies of intrinsic objects
[
'Array',
'BigInt',
'Boolean',
'Date',
'Error',
'Function',
'Map',
'Number',
'Object',
'RegExp',
'Set',
'String',
'Symbol',
].forEach((name) => {
const original = global[name];
const target = primordials[name] = Object.setPrototypeOf({
[name]: function(...args) {
return new.target ?
ReflectConstruct(original, args, new.target) :
ReflectApply(original, this, args);
}
}[name], null);
copyProps(original, target);
const proto = primordials[name + 'Prototype'] = Object.create(null);
copyPrototype(original.prototype, proto);
});
Object.setPrototypeOf(primordials, null);
Object.freeze(primordials);