• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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