From 7def95526e1565e4c1de604b9fd02f68d76c5318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bargull?= Date: Thu, 21 Jul 2022 09:38:55 +0000 Subject: [PATCH] Bug 1761989 - Part 1: Remove species lookup from InitializeTypedArrayFromTypedArray. r=mgaudet Implement the changes from and . The next patches will perform further clean-ups. Differential Revision: https://phabricator.services.mozilla.com/D152262 --- js/src/tests/jstests.list | 3 - .../constructor-ArrayBuffer-species-wrap.js | 16 +--- .../constructor-ArrayBuffer-species.js | 38 +-------- ...tructor-typedarray-species-other-global.js | 80 +++---------------- js/src/vm/TypedArrayObject.cpp | 72 +---------------- 5 files changed, 21 insertions(+), 188 deletions(-) diff --git a/js/src/tests/jstests.list b/js/src/tests/jstests.list index a341b7a28b596..9adc75005dab1 100644 --- a/js/src/tests/jstests.list +++ b/js/src/tests/jstests.list @@ -606,9 +606,6 @@ fails-if(!xulRuntime.shell) script test262/language/statements/class/subclass-bu # https://bugzilla.mozilla.org/show_bug.cgi?id=1648202 skip script test262/built-ins/RegExp/named-groups/non-unicode-property-names-valid.js -# https://bugzilla.mozilla.org/show_bug.cgi?id=1761989 -skip script test262/built-ins/TypedArrayConstructors/ctors/no-species.js - ########################################################### # Tests disabled due to issues in test262 importer script # diff --git a/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js index 67a50fc9158de..d454804f94a7b 100644 --- a/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js +++ b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species-wrap.js @@ -8,52 +8,44 @@ for (let ctor of typedArrayConstructors) { for (let ctor2 of typedArrayConstructors) { let b = new ctor2(a); assertEq(Object.getPrototypeOf(b).constructor, ctor2); - assertEq(Object.getPrototypeOf(b.buffer).constructor, g.ArrayBuffer); + assertEq(Object.getPrototypeOf(b.buffer).constructor, ArrayBuffer); } } // Only ArrayBuffer from different global. -let called = false; let origSpecies = Object.getOwnPropertyDescriptor(ArrayBuffer, Symbol.species); let modSpecies = { get() { - called = true; - return g.ArrayBuffer; + throw new Error("unexpected @@species access"); } }; for (let ctor of typedArrayConstructors) { let a = new ctor([1, 2, 3, 4, 5]); for (let ctor2 of typedArrayConstructors) { - called = false; Object.defineProperty(ArrayBuffer, Symbol.species, modSpecies); let b = new ctor2(a); Object.defineProperty(ArrayBuffer, Symbol.species, origSpecies); - assertEq(called, true); assertEq(Object.getPrototypeOf(b).constructor, ctor2); - assertEq(Object.getPrototypeOf(b.buffer).constructor, g.ArrayBuffer); + assertEq(Object.getPrototypeOf(b.buffer).constructor, ArrayBuffer); } } // Only TypedArray from different global. g.otherArrayBuffer = ArrayBuffer; g.eval(` -var called = false; var origSpecies = Object.getOwnPropertyDescriptor(ArrayBuffer, Symbol.species); var modSpecies = { get() { - called = true; - return otherArrayBuffer; + throw new Error("unexpected @@species access"); } }; `); for (let ctor of typedArrayConstructors) { let a = g.eval(`new ${ctor.name}([1, 2, 3, 4, 5]);`); for (let ctor2 of typedArrayConstructors) { - g.called = false; g.eval(`Object.defineProperty(ArrayBuffer, Symbol.species, modSpecies);`); let b = new ctor2(a); g.eval(`Object.defineProperty(ArrayBuffer, Symbol.species, origSpecies);`); - assertEq(g.called, true); assertEq(Object.getPrototypeOf(b).constructor, ctor2); assertEq(Object.getPrototypeOf(b.buffer).constructor, ArrayBuffer); } diff --git a/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js index 4ff5118485939..aa7830df6754c 100644 --- a/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js +++ b/js/src/tests/non262/TypedArray/constructor-ArrayBuffer-species.js @@ -1,49 +1,17 @@ -let logs = []; for (let ctor of typedArrayConstructors) { let arr = new ctor([1, 2, 3, 4, 5, 6, 7, 8]); - let ctorObj = {}; - - let proxyProto = new Proxy({}, { - get(that, name) { - logs.push("get proto." + String(name)); - if (name == "constructor") - return ctorObj; - throw new Error("unexpected prop access"); - } - }); - arr.buffer.constructor = { get [Symbol.species]() { - logs.push("get @@species"); - let C = new Proxy(function(...args) { - logs.push("call ctor"); - return new ArrayBuffer(...args); - }, { - get(that, name) { - logs.push("get ctor." + String(name)); - if (name == "prototype") { - return proxyProto; - } - throw new Error("unexpected prop access"); - } - }); - return C; + throw new Error("unexpected @@species access"); } }; for (let ctor2 of typedArrayConstructors) { - logs.length = 0; let arr2 = new ctor2(arr); - assertDeepEq(logs, ["get @@species", "get ctor.prototype"]); - - logs.length = 0; - assertEq(Object.getPrototypeOf(arr2.buffer), proxyProto); - assertDeepEq(logs, []); - logs.length = 0; - assertEq(arr2.buffer.constructor, ctorObj); - assertDeepEq(logs, ["get proto.constructor"]); + assertEq(Object.getPrototypeOf(arr2.buffer), ArrayBuffer.prototype); + assertEq(arr2.buffer.constructor, ArrayBuffer); } } diff --git a/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js b/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js index a622d9c94b4df..872f46408a3c8 100644 --- a/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js +++ b/js/src/tests/non262/TypedArray/constructor-typedarray-species-other-global.js @@ -5,85 +5,29 @@ const thisGlobal = this; const otherGlobal = newGlobal(); -const ta_i32 = otherGlobal.eval("new Int32Array(0)"); -function assertBufferPrototypeFrom(newTypedArray, prototype) { - var typedArrayName = newTypedArray.constructor.name; +const typedArrays = [otherGlobal.eval("new Int32Array(0)")]; - assertEq(Object.getPrototypeOf(newTypedArray), thisGlobal[typedArrayName].prototype); - assertEq(Object.getPrototypeOf(newTypedArray.buffer), prototype); -} - -const EMPTY = {}; - -// Test SpeciesConstructor() implementation selects the correct (fallback) constructor. -const testCases = [ - // Create the array buffer from the species constructor. - { constructor: EMPTY, prototype: otherGlobal.ArrayBuffer.prototype }, - - // Use %ArrayBuffer% from this global if constructor is undefined. - { constructor: undefined, prototype: ArrayBuffer.prototype }, - - // Use %ArrayBuffer% from this global if species is undefined. - { constructor: {[Symbol.species]: undefined}, prototype: ArrayBuffer.prototype }, - - // Use %ArrayBuffer% from this global if species is null. - { constructor: {[Symbol.species]: null}, prototype: ArrayBuffer.prototype }, -]; - -for (let { constructor, prototype } of testCases) { - if (constructor !== EMPTY) { - ta_i32.buffer.constructor = constructor; - } - - // Same element type. - assertBufferPrototypeFrom(new Int32Array(ta_i32), prototype); - - // Different element type. - assertBufferPrototypeFrom(new Int16Array(ta_i32), prototype); -} - - -// Also ensure TypeErrors are thrown from the correct global. -const errorTestCases = [ - // Constructor property is neither undefined nor an object. - { constructor: null }, - { constructor: 123 }, - - // Species property is neither undefined/null nor a constructor function. - { constructor: { [Symbol.species]: 123 } }, - { constructor: { [Symbol.species]: [] } }, - { constructor: { [Symbol.species]: () => {} } }, -]; - -for (let { constructor } of errorTestCases) { - ta_i32.buffer.constructor = constructor; - - // Same element type. - assertThrowsInstanceOf(() => new Int32Array(ta_i32), TypeError); - - // Different element type. - assertThrowsInstanceOf(() => new Int32Array(ta_i32), TypeError); -} - - -// TypedArrays using SharedArrayBuffers never call the SpeciesConstructor operation. if (this.SharedArrayBuffer) { - const ta_i32_shared = otherGlobal.eval("new Int32Array(new SharedArrayBuffer(0))"); + typedArrays.push(otherGlobal.eval("new Int32Array(new SharedArrayBuffer(0))")); +} - Object.defineProperty(ta_i32_shared.buffer, "constructor", { +for (let typedArray of typedArrays) { + // Ensure the "constructor" property isn't accessed. + Object.defineProperty(typedArray.buffer, "constructor", { get() { throw new Error("constructor property accessed"); } }); - // Same element type. - assertBufferPrototypeFrom(new Int32Array(ta_i32_shared), ArrayBuffer.prototype); + for (let ctor of typedArrayConstructors) { + let newTypedArray = new ctor(typedArray); - // Different element type. - assertBufferPrototypeFrom(new Int16Array(ta_i32_shared), ArrayBuffer.prototype); + assertEq(Object.getPrototypeOf(newTypedArray), ctor.prototype); + assertEq(Object.getPrototypeOf(newTypedArray.buffer), ArrayBuffer.prototype); + assertEq(newTypedArray.buffer.constructor, ArrayBuffer); + } } - if (typeof reportCompare === "function") reportCompare(0, 0); diff --git a/js/src/vm/TypedArrayObject.cpp b/js/src/vm/TypedArrayObject.cpp index 0aa321b6c8a62..754e9fee5f1c8 100644 --- a/js/src/vm/TypedArrayObject.cpp +++ b/js/src/vm/TypedArrayObject.cpp @@ -352,8 +352,6 @@ static TypedArrayObject* NewTypedArrayObject(JSContext* cx, return &obj->as(); } -enum class SpeciesConstructorOverride { None, ArrayBuffer }; - template class TypedArrayObjectTemplate : public TypedArrayObject { friend class TypedArrayObject; @@ -1141,67 +1139,6 @@ template return true; } -static bool IsArrayBufferSpecies(JSContext* cx, JSFunction* species) { - return IsSelfHostedFunctionWithName(species, cx->names().ArrayBufferSpecies); -} - -static JSObject* GetBufferSpeciesConstructor( - JSContext* cx, Handle typedArray, bool isWrapped, - SpeciesConstructorOverride override) { - RootedObject defaultCtor( - cx, GlobalObject::getOrCreateArrayBufferConstructor(cx, cx->global())); - if (!defaultCtor) { - return nullptr; - } - - // Use the current global's ArrayBuffer if the override is set. - if (override == SpeciesConstructorOverride::ArrayBuffer) { - return defaultCtor; - } - - RootedObject obj(cx, typedArray->bufferEither()); - if (!obj) { - MOZ_ASSERT(!isWrapped); - - // The buffer was never exposed to content code, so if - // 1. %ArrayBufferPrototype%.constructor == %ArrayBuffer%, and - // 2. %ArrayBuffer%[@@species] == ArrayBufferSpecies - // we don't have to reify the buffer object and can simply return the - // default array buffer constructor. - - JSObject* proto = - GlobalObject::getOrCreateArrayBufferPrototype(cx, cx->global()); - if (!proto) { - return nullptr; - } - - Value ctor; - bool found; - if (GetOwnPropertyPure(cx, proto, NameToId(cx->names().constructor), &ctor, - &found) && - ctor.isObject() && &ctor.toObject() == defaultCtor) { - jsid speciesId = PropertyKey::Symbol(cx->wellKnownSymbols().species); - JSFunction* getter; - if (GetOwnGetterPure(cx, defaultCtor, speciesId, &getter) && getter && - IsArrayBufferSpecies(cx, getter)) { - return defaultCtor; - } - } - - if (!TypedArrayObject::ensureHasBuffer(cx, typedArray)) { - return nullptr; - } - - obj.set(typedArray->bufferEither()); - } else { - if (isWrapped && !cx->compartment()->wrap(cx, &obj)) { - return nullptr; - } - } - - return SpeciesConstructor(cx, obj, defaultCtor, IsArrayBufferSpecies); -} - template /* static */ TypedArrayObject* TypedArrayObjectTemplate::fromArray( JSContext* cx, HandleObject other, HandleObject proto /* = nullptr */) { @@ -1271,13 +1208,8 @@ template // Steps 10-15 (skipped). // Steps 16-17. - bool isShared = srcArray->isSharedMemory(); - SpeciesConstructorOverride override = - isShared ? SpeciesConstructorOverride::ArrayBuffer - : SpeciesConstructorOverride::None; - RootedObject bufferCtor( - cx, GetBufferSpeciesConstructor(cx, srcArray, isWrapped, override)); + cx, GlobalObject::getOrCreateArrayBufferConstructor(cx, cx->global())); if (!bufferCtor) { return nullptr; } @@ -1316,7 +1248,7 @@ template // Steps 19.c-f or 24.1.1.4 steps 5-7. MOZ_ASSERT(!obj->isSharedMemory()); - if (isShared) { + if (srcArray->isSharedMemory()) { if (!ElementSpecific::setFromTypedArray(obj, srcArray, 0)) { return nullptr; }