1'use strict'; 2 3/* eslint-disable no-restricted-globals */ 4 5// This file subclasses and stores the JS builtins that come from the VM 6// so that Node.js's builtin modules do not need to later look these up from 7// the global proxy, which can be mutated by users. 8 9// TODO(joyeecheung): we can restrict access to these globals in builtin 10// modules through the JS linter, for example: ban access such as `Object` 11// (which falls back to a lookup in the global proxy) in favor of 12// `primordials.Object` where `primordials` is a lexical variable passed 13// by the native module compiler. 14 15const ReflectApply = Reflect.apply; 16 17// This function is borrowed from the function with the same name on V8 Extras' 18// `utils` object. V8 implements Reflect.apply very efficiently in conjunction 19// with the spread syntax, such that no additional special case is needed for 20// function calls w/o arguments. 21// Refs: https://github.com/v8/v8/blob/d6ead37d265d7215cf9c5f768f279e21bd170212/src/js/prologue.js#L152-L156 22function uncurryThis(func) { 23 return (thisArg, ...args) => ReflectApply(func, thisArg, args); 24} 25 26primordials.uncurryThis = uncurryThis; 27 28function copyProps(src, dest) { 29 for (const key of Reflect.ownKeys(src)) { 30 if (!Reflect.getOwnPropertyDescriptor(dest, key)) { 31 Reflect.defineProperty( 32 dest, 33 key, 34 Reflect.getOwnPropertyDescriptor(src, key)); 35 } 36 } 37} 38 39function copyPropsRenamed(src, dest, prefix) { 40 for (const key of Reflect.ownKeys(src)) { 41 if (typeof key === 'string') { 42 Reflect.defineProperty( 43 dest, 44 `${prefix}${key[0].toUpperCase()}${key.slice(1)}`, 45 Reflect.getOwnPropertyDescriptor(src, key)); 46 } 47 } 48} 49 50function copyPropsRenamedBound(src, dest, prefix) { 51 for (const key of Reflect.ownKeys(src)) { 52 if (typeof key === 'string') { 53 const desc = Reflect.getOwnPropertyDescriptor(src, key); 54 if (typeof desc.value === 'function') { 55 desc.value = desc.value.bind(src); 56 } 57 Reflect.defineProperty( 58 dest, 59 `${prefix}${key[0].toUpperCase()}${key.slice(1)}`, 60 desc 61 ); 62 } 63 } 64} 65 66function copyPrototype(src, dest, prefix) { 67 for (const key of Reflect.ownKeys(src)) { 68 if (typeof key === 'string') { 69 const desc = Reflect.getOwnPropertyDescriptor(src, key); 70 if (typeof desc.value === 'function') { 71 desc.value = uncurryThis(desc.value); 72 } 73 Reflect.defineProperty( 74 dest, 75 `${prefix}${key[0].toUpperCase()}${key.slice(1)}`, 76 desc); 77 } 78 } 79} 80 81function makeSafe(unsafe, safe) { 82 copyProps(unsafe.prototype, safe.prototype); 83 copyProps(unsafe, safe); 84 Object.setPrototypeOf(safe.prototype, null); 85 Object.freeze(safe.prototype); 86 Object.freeze(safe); 87 return safe; 88} 89 90// Subclass the constructors because we need to use their prototype 91// methods later. 92primordials.SafeMap = makeSafe( 93 Map, 94 class SafeMap extends Map {} 95); 96primordials.SafeWeakMap = makeSafe( 97 WeakMap, 98 class SafeWeakMap extends WeakMap {} 99); 100primordials.SafeSet = makeSafe( 101 Set, 102 class SafeSet extends Set {} 103); 104primordials.SafePromise = makeSafe( 105 Promise, 106 class SafePromise extends Promise {} 107); 108 109// Create copies of the namespace objects 110[ 111 'JSON', 112 'Math', 113 'Reflect' 114].forEach((name) => { 115 copyPropsRenamed(global[name], primordials, name); 116}); 117 118// Create copies of intrinsic objects 119[ 120 'Array', 121 'ArrayBuffer', 122 'BigInt', 123 'BigInt64Array', 124 'BigUint64Array', 125 'Boolean', 126 'Date', 127 'Error', 128 'Float32Array', 129 'Float64Array', 130 'Function', 131 'Int16Array', 132 'Int32Array', 133 'Int8Array', 134 'Map', 135 'Number', 136 'Object', 137 'RegExp', 138 'Set', 139 'String', 140 'Symbol', 141 'Uint16Array', 142 'Uint32Array', 143 'Uint8Array', 144 'Uint8ClampedArray', 145 'WeakMap', 146 'WeakSet', 147].forEach((name) => { 148 const original = global[name]; 149 primordials[name] = original; 150 copyPropsRenamed(original, primordials, name); 151 copyPrototype(original.prototype, primordials, `${name}Prototype`); 152}); 153 154// Create copies of intrinsic objects that require a valid `this` to call 155// static methods. 156// Refs: https://www.ecma-international.org/ecma-262/#sec-promise.all 157[ 158 'Promise', 159].forEach((name) => { 160 const original = global[name]; 161 primordials[name] = original; 162 copyPropsRenamedBound(original, primordials, name); 163 copyPrototype(original.prototype, primordials, `${name}Prototype`); 164}); 165 166Object.setPrototypeOf(primordials, null); 167Object.freeze(primordials); 168