Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
[JSC] Add fast path to TypedArray.from
https://bugs.webkit.org/show_bug.cgi?id=239936 Reviewed by Mark Lam, Ross Kirsling and Keith Miller. This patch adds a fast path to TypedArray.from. Similar to what we do with Array, we integrate TypedArray's iterator-protocol WatchpointSet. And now TypedArray has isIteratorProtocolFastAndNonObservable() function which answers whether we can do fast-iteration without user observable behavior withhout using normal generic for-of iterator protocol. The most complicated part of this WatchpointSet is that "length" property of TypedArray. Unlike Array, TypedArray does not have its own "length" property. Instead it has "length" getter in TypedArray.prototype. Thus, we need to ensure the following. 1. Uint8Array instance does not have its own "length" property 2. Uint8Array instance's [[Prototype]] is Uint8Array.prototype 3. Uint8Array.prototype does not have "length" property 4. Uint8Array.prototype's [[Prototype]] is TypedArray.prototype 5. TypedArray.prototype has default "length" getter We set "length" absence ObjectPropertyCondition (OPC) on Uint8Array.prototype. And we also set "length" equivalence OPC on TypedArray.prototype.length. As the same with Array's iterator protocol, we also ensure @@iterator function's absence status on Uint8Array.prototype and TypedArray.prototype too. By installing these watchpoints, we can quickly answer whether this TypedArray instance can get fast iteration. And in TypedArray.from, we use this condition to bypass normal for-of iteration protocol. Also we extend this function to accept normal Array: using Array's iterator protocol WatchpointSet to make it fast for Int32 and Double Arrays. TypedArray.from from TypedArray gets 396.0x faster. And TypedArray.from from Array gets 6.8x faster. ToT Patched typed-array-from-array 913.8926+-1.7045 ^ 133.6719+-0.1703 ^ definitely 6.8368x faster typed-array-from 1183.6522+-2.1020 ^ 2.9890+-0.3176 ^ definitely 396.0042x faster * microbenchmarks/typed-array-from.js: Added. * stress/typed-array-from-array-iterator-protocol.js: Added. (shouldBe): (shouldBeArray): (values.__proto__.next): * stress/typed-array-from.js: Added. (shouldBe): (shouldBeArray): (shouldThrow): (shouldBeArray.TestArray): (Uint8Array.prototype.__proto__.Symbol.iterator): * Source/JavaScriptCore/builtins/BuiltinNames.h: * Source/JavaScriptCore/builtins/TypedArrayConstructor.js: * Source/JavaScriptCore/bytecode/LinkTimeConstant.h: * Source/JavaScriptCore/runtime/JSGlobalObject.cpp: (JSC::JSGlobalObject::init): * Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.cpp: (JSC::isTypedArrayViewConstructor): (JSC::JSC_DEFINE_HOST_FUNCTION): (JSC::JSTypedArrayViewPrototype::finishCreation): * Source/JavaScriptCore/runtime/JSTypedArrayViewPrototype.h: Canonical link: https://commits.webkit.org/252976@main
- Loading branch information
1 parent
1297883
commit 1b440ef
Showing
25 changed files
with
571 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
var a1 = new Array(1024 * 1024 * 1); | ||
a1.fill(99); | ||
for (var i = 0; i < 1e2; ++i) | ||
var a2 = Uint8Array.from(a1); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
var a1 = new Uint8Array(1024 * 1024 * 1); | ||
a1.fill(99); | ||
for (var i = 0; i < 1e2; ++i) | ||
var a2 = Uint8Array.from(a1); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
function shouldThrow(func, errorMessage) { | ||
var errorThrown = false; | ||
var error = null; | ||
try { | ||
func(); | ||
} catch (e) { | ||
errorThrown = true; | ||
error = e; | ||
} | ||
if (!errorThrown) | ||
throw new Error('not thrown'); | ||
if (String(error) !== errorMessage) | ||
throw new Error(`bad error: ${String(error)}`); | ||
} | ||
|
||
shouldThrow(() => { | ||
var a = new Int32Array([0, 1, 2, 3]); | ||
BigInt64Array.from(a); | ||
}, `TypeError: Content types of source and destination typed arrays are different`); | ||
|
||
shouldThrow(() => { | ||
var a = [0, 1, 2, 3]; | ||
BigInt64Array.from(a); | ||
}, `TypeError: Invalid argument type in ToBigInt operation`); | ||
|
||
shouldThrow(() => { | ||
var a = [0.0, 0.1, 0.2, 0.3]; | ||
BigInt64Array.from(a); | ||
}, `TypeError: Invalid argument type in ToBigInt operation`); |
38 changes: 38 additions & 0 deletions
38
JSTests/stress/typed-array-from-array-iterator-protocol.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error('bad value: ' + actual); | ||
} | ||
|
||
function shouldBeArray(actual, expected) { | ||
shouldBe(actual.length, expected.length); | ||
for (var i = 0; i < expected.length; ++i) { | ||
try { | ||
shouldBe(actual[i], expected[i]); | ||
} catch(e) { | ||
print(JSON.stringify(actual)); | ||
throw e; | ||
} | ||
} | ||
} | ||
|
||
{ | ||
let length = 5; | ||
let index = 0; | ||
[].values().__proto__.next = function () { | ||
if (index < length) { | ||
++index; | ||
return { | ||
value: index, | ||
done: false | ||
}; | ||
} | ||
return { | ||
value: null, | ||
done: true | ||
}; | ||
}; | ||
|
||
let a0 = new Uint32Array([0xffffffff, 0xfffffffe, 0xfffffff0, 0xfffff0f0]); | ||
let a1 = Uint8Array.from(a0); | ||
shouldBeArray(a1, [1, 2, 3, 4, 5]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error('bad value: ' + actual); | ||
} | ||
|
||
var array = new Uint8Array(128); | ||
Reflect.defineProperty(Uint8Array.prototype, 'length', { | ||
value: 42 | ||
}); | ||
var result = Uint8Array.from(array); | ||
shouldBe(result.length, 42); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error('bad value: ' + actual); | ||
} | ||
|
||
var array = new Uint8Array(128); | ||
Reflect.defineProperty(array, 'length', { | ||
value: 42 | ||
}); | ||
var result = Uint8Array.from(array); | ||
shouldBe(result.length, 42); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error('bad value: ' + actual); | ||
} | ||
|
||
{ | ||
let a = new Int32Array([0, 1, 2]); | ||
let b = Float64Array.from(a); | ||
shouldBe(b.length, 3); | ||
shouldBe(b[0], 0); | ||
shouldBe(b[1], 1); | ||
shouldBe(b[2], 2); | ||
} | ||
{ | ||
let a = new Float32Array([0, 1, 2]); | ||
let b = Int32Array.from(a); | ||
shouldBe(b.length, 3); | ||
shouldBe(b[0], 0); | ||
shouldBe(b[1], 1); | ||
shouldBe(b[2], 2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error('bad value: ' + actual); | ||
} | ||
|
||
{ | ||
let a = Int32Array.from([0, , , 6]); | ||
shouldBe(a.length, 4); | ||
shouldBe(a[0], 0); | ||
shouldBe(a[1], 0); | ||
shouldBe(a[2], 0); | ||
shouldBe(a[3], 6); | ||
} | ||
{ | ||
let a = Int32Array.from([0.2, , , 6.1]); | ||
shouldBe(a.length, 4); | ||
shouldBe(a[0], 0); | ||
shouldBe(a[1], 0); | ||
shouldBe(a[2], 0); | ||
shouldBe(a[3], 6); | ||
} | ||
{ | ||
let a = Float64Array.from([0, , , 6]); | ||
shouldBe(a.length, 4); | ||
shouldBe(a[0], 0); | ||
shouldBe(Number.isNaN(a[1]), true); | ||
shouldBe(Number.isNaN(a[2]), true); | ||
shouldBe(a[3], 6); | ||
} | ||
{ | ||
let a = Float64Array.from([0.2, , , 6.1]); | ||
shouldBe(a.length, 4); | ||
shouldBe(a[0], 0.2); | ||
shouldBe(Number.isNaN(a[1]), true); | ||
shouldBe(Number.isNaN(a[2]), true); | ||
shouldBe(a[3], 6.1); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
function shouldBe(actual, expected) { | ||
if (actual !== expected) | ||
throw new Error('bad value: ' + actual); | ||
} | ||
|
||
function shouldBeArray(actual, expected) { | ||
shouldBe(actual.length, expected.length); | ||
for (var i = 0; i < expected.length; ++i) { | ||
try { | ||
shouldBe(actual[i], expected[i]); | ||
} catch(e) { | ||
print(JSON.stringify(actual)); | ||
throw e; | ||
} | ||
} | ||
} | ||
|
||
function shouldThrow(func, errorMessage) { | ||
var errorThrown = false; | ||
var error = null; | ||
try { | ||
func(); | ||
} catch (e) { | ||
errorThrown = true; | ||
error = e; | ||
} | ||
if (!errorThrown) | ||
throw new Error('not thrown'); | ||
if (String(error) !== errorMessage) | ||
throw new Error(`bad error: ${String(error)}`); | ||
} | ||
|
||
{ | ||
let a0 = new Uint32Array([0xffffffff, 0xfffffffe, 0xfffffff0, 0xfffff0f0]); | ||
let a1 = Uint8Array.from(a0); | ||
shouldBeArray(a1, [0xff, 0xfe, 0xf0, 0xf0]); | ||
|
||
let a2 = Uint32Array.from(a0); | ||
shouldBeArray(a2, a0); | ||
} | ||
{ | ||
class TestArray extends Uint8Array { | ||
constructor(size) { | ||
super(size); | ||
} | ||
} | ||
|
||
let a0 = new Uint32Array([0xffffffff, 0xfffffffe, 0xfffffff0, 0xfffff0f0]); | ||
let a1 = TestArray.from(a0); | ||
shouldBeArray(a1, [0xff, 0xfe, 0xf0, 0xf0]); | ||
|
||
let a2 = Uint32Array.from(a0); | ||
shouldBeArray(a2, a0); | ||
} | ||
{ | ||
let a0 = new Uint32Array([0xffffffff, 0xfffffffe, 0xfffffff0, 0xfffff0f0]); | ||
class TestArray extends Uint8Array { | ||
constructor(size) { | ||
super(size); | ||
transferArrayBuffer(a0.buffer); | ||
} | ||
} | ||
|
||
let a1 = TestArray.from(a0); | ||
shouldBeArray(a1, [0xff, 0xfe, 0xf0, 0xf0]); // This should pass. When TestArray is created, we should have already collected the data from a0. | ||
|
||
shouldThrow(() => { | ||
Uint32Array.from(a0); | ||
}, `TypeError: Underlying ArrayBuffer has been detached from the view`); | ||
} | ||
|
||
Uint8Array.prototype.__proto__[Symbol.iterator] = function *() { | ||
for (var i = 0; i < this.length; ++i) | ||
yield 42; | ||
}; | ||
|
||
{ | ||
let a0 = new Uint32Array([0xffffffff, 0xfffffffe, 0xfffffff0, 0xfffff0f0]); | ||
let a1 = Uint8Array.from(a0); | ||
shouldBeArray(a1, [42, 42, 42, 42]); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.