diff options
author | Matt Mastracci <matthew@mastracci.com> | 2023-07-01 18:00:14 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-07-02 00:00:14 +0000 |
commit | e746b6d80654ba4e4e26370fe6e4f784ce841d92 (patch) | |
tree | 153ffad92a96126b9ab8e906dcdabf7648755931 /core/00_primordials.js | |
parent | b9c0e7cd550ab14fa7da7e33ed87cbeeeb9785a0 (diff) |
refactor(core): Extract deno_core (#19658)
`deno_core` is moving out! You'll find it at
https://github.com/denoland/deno_core/ once this PR lands.
Diffstat (limited to 'core/00_primordials.js')
-rw-r--r-- | core/00_primordials.js | 615 |
1 files changed, 0 insertions, 615 deletions
diff --git a/core/00_primordials.js b/core/00_primordials.js deleted file mode 100644 index 60474e649..000000000 --- a/core/00_primordials.js +++ /dev/null @@ -1,615 +0,0 @@ -// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license. - -// Based on https://github.com/nodejs/node/blob/889ad35d3d41e376870f785b0c1b669cb732013d/lib/internal/per_context/primordials.js -// Copyright Joyent, Inc. and other Node contributors. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the -// "Software"), to deal in the Software without restriction, including -// without limitation the rights to use, copy, modify, merge, publish, -// distribute, sublicense, and/or sell copies of the Software, and to permit -// persons to whom the Software is furnished to do so, subject to the -// following conditions: -// -// The above copyright notice and this permission notice shall be included -// in all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN -// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, -// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE -// USE OR OTHER DEALINGS IN THE SOFTWARE. -// 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. - -// Use of primordials have sometimes a dramatic impact on performance, please -// benchmark all changes made in performance-sensitive areas of the codebase. -// See: https://github.com/nodejs/node/pull/38248 - -// deno-lint-ignore-file prefer-primordials - -"use strict"; - -(() => { - const primordials = {}; - - const { - defineProperty: ReflectDefineProperty, - getOwnPropertyDescriptor: ReflectGetOwnPropertyDescriptor, - ownKeys: ReflectOwnKeys, - } = Reflect; - - // `uncurryThis` is equivalent to `func => Function.prototype.call.bind(func)`. - // It is using `bind.bind(call)` to avoid using `Function.prototype.bind` - // and `Function.prototype.call` after it may have been mutated by users. - const { apply, bind, call } = Function.prototype; - const uncurryThis = bind.bind(call); - primordials.uncurryThis = uncurryThis; - - // `applyBind` is equivalent to `func => Function.prototype.apply.bind(func)`. - // It is using `bind.bind(apply)` to avoid using `Function.prototype.bind` - // and `Function.prototype.apply` after it may have been mutated by users. - const applyBind = bind.bind(apply); - primordials.applyBind = applyBind; - - // Methods that accept a variable number of arguments, and thus it's useful to - // also create `${prefix}${key}Apply`, which uses `Function.prototype.apply`, - // instead of `Function.prototype.call`, and thus doesn't require iterator - // destructuring. - const varargsMethods = [ - // 'ArrayPrototypeConcat' is omitted, because it performs the spread - // on its own for arrays and array-likes with a truthy - // @@isConcatSpreadable symbol property. - "ArrayOf", - "ArrayPrototypePush", - "ArrayPrototypeUnshift", - // 'FunctionPrototypeCall' is omitted, since there's 'ReflectApply' - // and 'FunctionPrototypeApply'. - "MathHypot", - "MathMax", - "MathMin", - "StringPrototypeConcat", - "TypedArrayOf", - ]; - - function getNewKey(key) { - return typeof key === "symbol" - ? `Symbol${key.description[7].toUpperCase()}${key.description.slice(8)}` - : `${key[0].toUpperCase()}${key.slice(1)}`; - } - - function copyAccessor(dest, prefix, key, { enumerable, get, set }) { - ReflectDefineProperty(dest, `${prefix}Get${key}`, { - value: uncurryThis(get), - enumerable, - }); - if (set !== undefined) { - ReflectDefineProperty(dest, `${prefix}Set${key}`, { - value: uncurryThis(set), - enumerable, - }); - } - } - - function copyPropsRenamed(src, dest, prefix) { - for (const key of ReflectOwnKeys(src)) { - const newKey = getNewKey(key); - const desc = ReflectGetOwnPropertyDescriptor(src, key); - if ("get" in desc) { - copyAccessor(dest, prefix, newKey, desc); - } else { - const name = `${prefix}${newKey}`; - ReflectDefineProperty(dest, name, desc); - if (varargsMethods.includes(name)) { - ReflectDefineProperty(dest, `${name}Apply`, { - // `src` is bound as the `this` so that the static `this` points - // to the object it was defined on, - // e.g.: `ArrayOfApply` gets a `this` of `Array`: - value: applyBind(desc.value, src), - }); - } - } - } - } - - function copyPropsRenamedBound(src, dest, prefix) { - for (const key of ReflectOwnKeys(src)) { - const newKey = getNewKey(key); - const desc = ReflectGetOwnPropertyDescriptor(src, key); - if ("get" in desc) { - copyAccessor(dest, prefix, newKey, desc); - } else { - const { value } = desc; - if (typeof value === "function") { - desc.value = value.bind(src); - } - - const name = `${prefix}${newKey}`; - ReflectDefineProperty(dest, name, desc); - if (varargsMethods.includes(name)) { - ReflectDefineProperty(dest, `${name}Apply`, { - value: applyBind(value, src), - }); - } - } - } - } - - function copyPrototype(src, dest, prefix) { - for (const key of ReflectOwnKeys(src)) { - const newKey = getNewKey(key); - const desc = ReflectGetOwnPropertyDescriptor(src, key); - if ("get" in desc) { - copyAccessor(dest, prefix, newKey, desc); - } else { - const { value } = desc; - if (typeof value === "function") { - desc.value = uncurryThis(value); - } - - const name = `${prefix}${newKey}`; - ReflectDefineProperty(dest, name, desc); - if (varargsMethods.includes(name)) { - ReflectDefineProperty(dest, `${name}Apply`, { - value: applyBind(value), - }); - } - } - } - } - - // Create copies of configurable value properties of the global object - [ - "Proxy", - "globalThis", - ].forEach((name) => { - primordials[name] = globalThis[name]; - }); - - // Create copy of isNaN - primordials[isNaN.name] = isNaN; - - // Create copies of URI handling functions - [ - decodeURI, - decodeURIComponent, - encodeURI, - encodeURIComponent, - ].forEach((fn) => { - primordials[fn.name] = fn; - }); - - // Create copies of the namespace objects - [ - "JSON", - "Math", - "Proxy", - "Reflect", - ].forEach((name) => { - copyPropsRenamed(globalThis[name], primordials, name); - }); - - // Create copies of intrinsic objects - [ - "AggregateError", - "Array", - "ArrayBuffer", - "BigInt", - "BigInt64Array", - "BigUint64Array", - "Boolean", - "DataView", - "Date", - "Error", - "EvalError", - "FinalizationRegistry", - "Float32Array", - "Float64Array", - "Function", - "Int16Array", - "Int32Array", - "Int8Array", - "Map", - "Number", - "Object", - "RangeError", - "ReferenceError", - "RegExp", - "Set", - "String", - "Symbol", - "SyntaxError", - "TypeError", - "URIError", - "Uint16Array", - "Uint32Array", - "Uint8Array", - "Uint8ClampedArray", - "WeakMap", - "WeakRef", - "WeakSet", - ].forEach((name) => { - const original = globalThis[name]; - primordials[name] = original; - copyPropsRenamed(original, primordials, name); - copyPrototype(original.prototype, primordials, `${name}Prototype`); - }); - - // Create copies of intrinsic objects that require a valid `this` to call - // static methods. - // Refs: https://www.ecma-international.org/ecma-262/#sec-promise.all - [ - "Promise", - ].forEach((name) => { - const original = globalThis[name]; - primordials[name] = original; - copyPropsRenamedBound(original, primordials, name); - copyPrototype(original.prototype, primordials, `${name}Prototype`); - }); - - // Create copies of abstract intrinsic objects that are not directly exposed - // on the global object. - // Refs: https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object - [ - { name: "TypedArray", original: Reflect.getPrototypeOf(Uint8Array) }, - { - name: "ArrayIterator", - original: { - prototype: Reflect.getPrototypeOf(Array.prototype[Symbol.iterator]()), - }, - }, - { - name: "SetIterator", - original: { - prototype: Reflect.getPrototypeOf(new Set()[Symbol.iterator]()), - }, - }, - { - name: "MapIterator", - original: { - prototype: Reflect.getPrototypeOf(new Map()[Symbol.iterator]()), - }, - }, - { - name: "StringIterator", - original: { - prototype: Reflect.getPrototypeOf(String.prototype[Symbol.iterator]()), - }, - }, - { name: "Generator", original: Reflect.getPrototypeOf(function* () {}) }, - { - name: "AsyncGenerator", - original: Reflect.getPrototypeOf(async function* () {}), - }, - ].forEach(({ name, original }) => { - primordials[name] = original; - // The static %TypedArray% methods require a valid `this`, but can't be bound, - // as they need a subclass constructor as the receiver: - copyPrototype(original, primordials, name); - copyPrototype(original.prototype, primordials, `${name}Prototype`); - }); - - const { - ArrayPrototypeForEach, - ArrayPrototypeJoin, - ArrayPrototypeMap, - FunctionPrototypeCall, - ObjectDefineProperty, - ObjectFreeze, - ObjectPrototypeIsPrototypeOf, - ObjectSetPrototypeOf, - Promise, - PromisePrototype, - PromisePrototypeThen, - SymbolIterator, - TypedArrayPrototypeJoin, - } = primordials; - - // Because these functions are used by `makeSafe`, which is exposed - // on the `primordials` object, it's important to use const references - // to the primordials that they use: - const createSafeIterator = (factory, next) => { - class SafeIterator { - constructor(iterable) { - this._iterator = factory(iterable); - } - next() { - return next(this._iterator); - } - [SymbolIterator]() { - return this; - } - } - ObjectSetPrototypeOf(SafeIterator.prototype, null); - ObjectFreeze(SafeIterator.prototype); - ObjectFreeze(SafeIterator); - return SafeIterator; - }; - - const SafeArrayIterator = createSafeIterator( - primordials.ArrayPrototypeSymbolIterator, - primordials.ArrayIteratorPrototypeNext, - ); - primordials.SafeArrayIterator = SafeArrayIterator; - primordials.SafeSetIterator = createSafeIterator( - primordials.SetPrototypeSymbolIterator, - primordials.SetIteratorPrototypeNext, - ); - primordials.SafeMapIterator = createSafeIterator( - primordials.MapPrototypeSymbolIterator, - primordials.MapIteratorPrototypeNext, - ); - primordials.SafeStringIterator = createSafeIterator( - primordials.StringPrototypeSymbolIterator, - primordials.StringIteratorPrototypeNext, - ); - - const copyProps = (src, dest) => { - ArrayPrototypeForEach(ReflectOwnKeys(src), (key) => { - if (!ReflectGetOwnPropertyDescriptor(dest, key)) { - ReflectDefineProperty( - dest, - key, - ReflectGetOwnPropertyDescriptor(src, key), - ); - } - }); - }; - - /** - * @type {typeof primordials.makeSafe} - */ - const makeSafe = (unsafe, safe) => { - if (SymbolIterator in unsafe.prototype) { - const dummy = new unsafe(); - let next; // We can reuse the same `next` method. - - ArrayPrototypeForEach(ReflectOwnKeys(unsafe.prototype), (key) => { - if (!ReflectGetOwnPropertyDescriptor(safe.prototype, key)) { - const desc = ReflectGetOwnPropertyDescriptor(unsafe.prototype, key); - if ( - typeof desc.value === "function" && - desc.value.length === 0 && - SymbolIterator in (FunctionPrototypeCall(desc.value, dummy) ?? {}) - ) { - const createIterator = uncurryThis(desc.value); - next ??= uncurryThis(createIterator(dummy).next); - const SafeIterator = createSafeIterator(createIterator, next); - desc.value = function () { - return new SafeIterator(this); - }; - } - ReflectDefineProperty(safe.prototype, key, desc); - } - }); - } else { - copyProps(unsafe.prototype, safe.prototype); - } - copyProps(unsafe, safe); - - ObjectSetPrototypeOf(safe.prototype, null); - ObjectFreeze(safe.prototype); - ObjectFreeze(safe); - return safe; - }; - primordials.makeSafe = makeSafe; - - // Subclass the constructors because we need to use their prototype - // methods later. - // Defining the `constructor` is necessary here to avoid the default - // constructor which uses the user-mutable `%ArrayIteratorPrototype%.next`. - primordials.SafeMap = makeSafe( - Map, - class SafeMap extends Map { - constructor(i) { - if (i == null) { - super(); - return; - } - super(new SafeArrayIterator(i)); - } - }, - ); - primordials.SafeWeakMap = makeSafe( - WeakMap, - class SafeWeakMap extends WeakMap { - constructor(i) { - if (i == null) { - super(); - return; - } - super(new SafeArrayIterator(i)); - } - }, - ); - - primordials.SafeSet = makeSafe( - Set, - class SafeSet extends Set { - constructor(i) { - if (i == null) { - super(); - return; - } - super(new SafeArrayIterator(i)); - } - }, - ); - primordials.SafeWeakSet = makeSafe( - WeakSet, - class SafeWeakSet extends WeakSet { - constructor(i) { - if (i == null) { - super(); - return; - } - super(new SafeArrayIterator(i)); - } - }, - ); - - primordials.SafeRegExp = makeSafe( - RegExp, - class SafeRegExp extends RegExp { - constructor(pattern, flags) { - super(pattern, flags); - } - }, - ); - - primordials.SafeFinalizationRegistry = makeSafe( - FinalizationRegistry, - class SafeFinalizationRegistry extends FinalizationRegistry { - constructor(cleanupCallback) { - super(cleanupCallback); - } - }, - ); - - primordials.SafeWeakRef = makeSafe( - WeakRef, - class SafeWeakRef extends WeakRef { - constructor(target) { - super(target); - } - }, - ); - - const SafePromise = makeSafe( - Promise, - class SafePromise extends Promise { - constructor(executor) { - super(executor); - } - }, - ); - - primordials.ArrayPrototypeToString = (thisArray) => - ArrayPrototypeJoin(thisArray); - - primordials.TypedArrayPrototypeToString = (thisArray) => - TypedArrayPrototypeJoin(thisArray); - - primordials.PromisePrototypeCatch = (thisPromise, onRejected) => - PromisePrototypeThen(thisPromise, undefined, onRejected); - - const arrayToSafePromiseIterable = (array) => - new SafeArrayIterator( - ArrayPrototypeMap( - array, - (p) => { - if (ObjectPrototypeIsPrototypeOf(PromisePrototype, p)) { - return new SafePromise((c, d) => PromisePrototypeThen(p, c, d)); - } - return p; - }, - ), - ); - - /** - * Creates a Promise that is resolved with an array of results when all of the - * provided Promises resolve, or rejected when any Promise is rejected. - * @template T - * @param {Array<T | PromiseLike<T>>} values - * @returns {Promise<Awaited<T>[]>} - */ - primordials.SafePromiseAll = (values) => - // Wrapping on a new Promise is necessary to not expose the SafePromise - // prototype to user-land. - new Promise((a, b) => - SafePromise.all(arrayToSafePromiseIterable(values)).then(a, b) - ); - - // NOTE: Uncomment the following functions when you need to use them - - // /** - // * Creates a Promise that is resolved with an array of results when all - // * of the provided Promises resolve or reject. - // * @template T - // * @param {Array<T | PromiseLike<T>>} values - // * @returns {Promise<PromiseSettledResult<T>[]>} - // */ - // primordials.SafePromiseAllSettled = (values) => - // // Wrapping on a new Promise is necessary to not expose the SafePromise - // // prototype to user-land. - // new Promise((a, b) => - // SafePromise.allSettled(arrayToSafePromiseIterable(values)).then(a, b) - // ); - - // /** - // * The any function returns a promise that is fulfilled by the first given - // * promise to be fulfilled, or rejected with an AggregateError containing - // * an array of rejection reasons if all of the given promises are rejected. - // * It resolves all elements of the passed iterable to promises as it runs - // * this algorithm. - // * @template T - // * @param {T} values - // * @returns {Promise<Awaited<T[number]>>} - // */ - // primordials.SafePromiseAny = (values) => - // // Wrapping on a new Promise is necessary to not expose the SafePromise - // // prototype to user-land. - // new Promise((a, b) => - // SafePromise.any(arrayToSafePromiseIterable(values)).then(a, b) - // ); - - // /** - // * Creates a Promise that is resolved or rejected when any of the provided - // * Promises are resolved or rejected. - // * @template T - // * @param {T} values - // * @returns {Promise<Awaited<T[number]>>} - // */ - // primordials.SafePromiseRace = (values) => - // // Wrapping on a new Promise is necessary to not expose the SafePromise - // // prototype to user-land. - // new Promise((a, b) => - // SafePromise.race(arrayToSafePromiseIterable(values)).then(a, b) - // ); - - /** - * Attaches a callback that is invoked when the Promise is settled (fulfilled or - * rejected). The resolved value cannot be modified from the callback. - * Prefer using async functions when possible. - * @param {Promise<any>} thisPromise - * @param {() => void) | undefined | null} onFinally The callback to execute - * when the Promise is settled (fulfilled or rejected). - * @returns A Promise for the completion of the callback. - */ - primordials.SafePromisePrototypeFinally = (thisPromise, onFinally) => - // Wrapping on a new Promise is necessary to not expose the SafePromise - // prototype to user-land. - new Promise((a, b) => - new SafePromise((a, b) => PromisePrototypeThen(thisPromise, a, b)) - .finally(onFinally) - .then(a, b) - ); - - // Create getter and setter for `queueMicrotask`, it hasn't been bound yet. - let queueMicrotask = undefined; - ObjectDefineProperty(primordials, "queueMicrotask", { - get() { - return queueMicrotask; - }, - }); - primordials.setQueueMicrotask = (value) => { - if (queueMicrotask !== undefined) { - throw new Error("queueMicrotask is already defined"); - } - queueMicrotask = value; - }; - - // Renaming from `eval` is necessary because otherwise it would perform direct - // evaluation, allowing user-land access to local variables. - // This is because the identifier `eval` is somewhat treated as a keyword - primordials.indirectEval = eval; - - ObjectSetPrototypeOf(primordials, null); - ObjectFreeze(primordials); - - // Provide bootstrap namespace - globalThis.__bootstrap = { primordials }; -})(); |