From 95b07ea1e4fc2dd2b74be22167c081cad3d726c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Fri, 6 Mar 2020 17:01:41 +0100 Subject: [PATCH] lib: add TypedArray to the primordials This also makes it possible to use Symbol methods and getters. --- lib/buffer.js | 18 ++++--------- lib/internal/per_context/primordials.js | 33 ++++++++++++++++------- lib/internal/util/inspect.js | 19 +++++-------- lib/internal/util/types.js | 36 +++++++++---------------- 4 files changed, 48 insertions(+), 58 deletions(-) diff --git a/lib/buffer.js b/lib/buffer.js index a818f41a26ed5b..ffb562ad809251 100644 --- a/lib/buffer.js +++ b/lib/buffer.js @@ -34,12 +34,11 @@ const { ObjectCreate, ObjectDefineProperties, ObjectDefineProperty, - ObjectGetOwnPropertyDescriptor, - ObjectGetPrototypeOf, ObjectSetPrototypeOf, SymbolSpecies, SymbolToPrimitive, - Uint8ArrayPrototype, + TypedArrayPrototypeByteLength, + TypedArrayPrototypeFill, } = primordials; const { @@ -107,13 +106,6 @@ const { addBufferPrototypeMethods } = require('internal/buffer'); -const TypedArrayPrototype = ObjectGetPrototypeOf(Uint8ArrayPrototype); - -const TypedArrayProto_byteLength = - ObjectGetOwnPropertyDescriptor(TypedArrayPrototype, - 'byteLength').get; -const TypedArrayFill = TypedArrayPrototype.fill; - FastBuffer.prototype.constructor = Buffer; Buffer.prototype = FastBuffer.prototype; addBufferPrototypeMethods(Buffer.prototype); @@ -581,7 +573,7 @@ Buffer.concat = function concat(list, length) { // Zero-fill the remaining bytes if the specified `length` was more than // the actual total length, i.e. if we have some remaining allocated bytes // there were not initialized. - TypedArrayFill.call(buffer, 0, pos, length); + TypedArrayPrototypeFill(buffer, 0, pos, length); } return buffer; @@ -1020,12 +1012,12 @@ function _fill(buf, value, offset, end, encoding) { if (typeof value === 'number') { // OOB check - const byteLen = TypedArrayProto_byteLength.call(buf); + const byteLen = TypedArrayPrototypeByteLength(buf); const fillLength = end - offset; if (offset > end || fillLength + offset > byteLen) throw new ERR_BUFFER_OUT_OF_BOUNDS(); - TypedArrayFill.call(buf, value, offset, end); + TypedArrayPrototypeFill(buf, value, offset, end); } else { const res = bindingFill(buf, value, offset, end, encoding); if (res < 0) { diff --git a/lib/internal/per_context/primordials.js b/lib/internal/per_context/primordials.js index 09bea0fc7fc523..75ed0fd1b81a67 100644 --- a/lib/internal/per_context/primordials.js +++ b/lib/internal/per_context/primordials.js @@ -65,16 +65,22 @@ function copyPropsRenamedBound(src, dest, prefix) { function copyPrototype(src, dest, prefix) { for (const key of Reflect.ownKeys(src)) { - if (typeof key === 'string') { - const desc = Reflect.getOwnPropertyDescriptor(src, key); - if (typeof desc.value === 'function') { - desc.value = uncurryThis(desc.value); - } - Reflect.defineProperty( - dest, - `${prefix}${key[0].toUpperCase()}${key.slice(1)}`, - desc); + let newKey; + if (typeof key === 'symbol') { + const name = key.description.slice(7); + newKey = `${prefix}Symbol${name[0].toUpperCase()}${name.slice(1)}`; + } else { + newKey = `${prefix}${key[0].toUpperCase()}${key.slice(1)}`; } + const desc = Reflect.getOwnPropertyDescriptor(src, key); + if (typeof desc.value === 'function') { + desc.value = uncurryThis(desc.value); + } else if (typeof desc.get === 'function') { + desc.value = uncurryThis(desc.get); + delete desc.get; + delete desc.set; + } + Reflect.defineProperty(dest, newKey, desc); } } @@ -163,5 +169,14 @@ primordials.SafePromise = makeSafe( copyPrototype(original.prototype, primordials, `${name}Prototype`); }); +// Create copies of objects that are not immediately available on `globalThis`. +[ + ['TypedArray', Object.getPrototypeOf(Uint8Array)] +].forEach(([name, original]) => { + primordials[name] = original; + copyPropsRenamed(original, primordials, name); + copyPrototype(original.prototype, primordials, `${name}Prototype`); +}); + Object.setPrototypeOf(primordials, null); Object.freeze(primordials); diff --git a/lib/internal/util/inspect.js b/lib/internal/util/inspect.js index 1af1e420e55e28..f5afc689da3b82 100644 --- a/lib/internal/util/inspect.js +++ b/lib/internal/util/inspect.js @@ -14,8 +14,8 @@ const { Float32Array, JSONStringify, Map, - MapPrototype, MapPrototypeEntries, + MapPrototypeSize, MathFloor, MathMax, MathMin, @@ -39,13 +39,14 @@ const { RegExp, RegExpPrototypeToString, Set, - SetPrototype, + SetPrototypeSize, SetPrototypeValues, StringPrototypeValueOf, SymbolPrototypeToString, SymbolPrototypeValueOf, SymbolIterator, SymbolToStringTag, + TypedArrayPrototypeLength, Uint16Array, uncurryThis, } = primordials; @@ -120,14 +121,6 @@ const assert = require('internal/assert'); const { NativeModule } = require('internal/bootstrap/loaders'); -const setSizeGetter = uncurryThis( - ObjectGetOwnPropertyDescriptor(SetPrototype, 'size').get); -const mapSizeGetter = uncurryThis( - ObjectGetOwnPropertyDescriptor(MapPrototype, 'size').get); -const typedArraySizeGetter = uncurryThis( - ObjectGetOwnPropertyDescriptor( - ObjectGetPrototypeOf(Uint8Array.prototype), 'length').get); - let hexSlice; const builtInObjects = new Set( @@ -802,7 +795,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { extrasType = kArrayExtrasType; formatter = formatArray; } else if (isSet(value)) { - const size = setSizeGetter(value); + const size = SetPrototypeSize(value); const prefix = getPrefix(constructor, tag, 'Set', `(${size})`); keys = getKeys(value, ctx.showHidden); formatter = constructor !== null ? @@ -812,7 +805,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { return `${prefix}{}`; braces = [`${prefix}{`, '}']; } else if (isMap(value)) { - const size = mapSizeGetter(value); + const size = MapPrototypeSize(value); const prefix = getPrefix(constructor, tag, 'Map', `(${size})`); keys = getKeys(value, ctx.showHidden); formatter = constructor !== null ? @@ -831,7 +824,7 @@ function formatRaw(ctx, value, recurseTimes, typedArray) { // Reconstruct the array information. bound = new constr(value); } - const size = typedArraySizeGetter(value); + const size = TypedArrayPrototypeLength(value); const prefix = getPrefix(constructor, tag, fallback, `(${size})`); braces = [`${prefix}[`, ']']; if (value.length === 0 && keys.length === 0 && !ctx.showHidden) diff --git a/lib/internal/util/types.js b/lib/internal/util/types.js index 676f386a2458d4..8000295c954a9d 100644 --- a/lib/internal/util/types.js +++ b/lib/internal/util/types.js @@ -2,65 +2,55 @@ const { ArrayBufferIsView, - ObjectGetOwnPropertyDescriptor, - ObjectGetPrototypeOf, - SymbolToStringTag, - uncurryThis, + TypedArrayPrototypeSymbolToStringTag, } = primordials; -const TypedArrayPrototype = ObjectGetPrototypeOf(Uint8Array.prototype); - -const TypedArrayProto_toStringTag = - uncurryThis( - ObjectGetOwnPropertyDescriptor(TypedArrayPrototype, - SymbolToStringTag).get); - function isTypedArray(value) { - return TypedArrayProto_toStringTag(value) !== undefined; + return TypedArrayPrototypeSymbolToStringTag(value) !== undefined; } function isUint8Array(value) { - return TypedArrayProto_toStringTag(value) === 'Uint8Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Uint8Array'; } function isUint8ClampedArray(value) { - return TypedArrayProto_toStringTag(value) === 'Uint8ClampedArray'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Uint8ClampedArray'; } function isUint16Array(value) { - return TypedArrayProto_toStringTag(value) === 'Uint16Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Uint16Array'; } function isUint32Array(value) { - return TypedArrayProto_toStringTag(value) === 'Uint32Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Uint32Array'; } function isInt8Array(value) { - return TypedArrayProto_toStringTag(value) === 'Int8Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Int8Array'; } function isInt16Array(value) { - return TypedArrayProto_toStringTag(value) === 'Int16Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Int16Array'; } function isInt32Array(value) { - return TypedArrayProto_toStringTag(value) === 'Int32Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Int32Array'; } function isFloat32Array(value) { - return TypedArrayProto_toStringTag(value) === 'Float32Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Float32Array'; } function isFloat64Array(value) { - return TypedArrayProto_toStringTag(value) === 'Float64Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'Float64Array'; } function isBigInt64Array(value) { - return TypedArrayProto_toStringTag(value) === 'BigInt64Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'BigInt64Array'; } function isBigUint64Array(value) { - return TypedArrayProto_toStringTag(value) === 'BigUint64Array'; + return TypedArrayPrototypeSymbolToStringTag(value) === 'BigUint64Array'; } module.exports = {