'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);