Skip to content

Commit bcdbf97

Browse files
isheludkoCommit Bot
authored andcommitted
[builtins] Move %TypedArray%.prototype.sort to typed-array-sort.tq
Bug: v8:4153 Change-Id: I63d2ad673639b28b84e9f594be63cbebd931f636 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1914563 Reviewed-by: Leszek Swirski <leszeks@chromium.org> Commit-Queue: Igor Sheludko <ishell@chromium.org> Cr-Commit-Position: refs/heads/master@{#64968}
1 parent abfbe76 commit bcdbf97

3 files changed

Lines changed: 146 additions & 135 deletions

File tree

BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ torque_files = [
10061006
"src/builtins/typed-array-set.tq",
10071007
"src/builtins/typed-array-slice.tq",
10081008
"src/builtins/typed-array-some.tq",
1009+
"src/builtins/typed-array-sort.tq",
10091010
"src/builtins/typed-array-subarray.tq",
10101011
"src/builtins/typed-array.tq",
10111012
"src/ic/handler-configuration.tq",

src/builtins/typed-array-sort.tq

Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
// Copyright 2019 the V8 project authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include 'src/builtins/builtins-typed-array-gen.h'
6+
7+
namespace typed_array {
8+
const kBuiltinNameSort: constexpr string = '%TypedArray%.prototype.sort';
9+
10+
extern runtime TypedArraySortFast(Context, JSAny): JSTypedArray;
11+
12+
transitioning macro CallCompare(
13+
implicit context: Context, array: JSTypedArray,
14+
comparefn: Callable)(a: JSAny, b: JSAny): Number {
15+
// a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)).
16+
const v: Number =
17+
ToNumber_Inline(Call(context, comparefn, Undefined, a, b));
18+
19+
// b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
20+
if (IsDetachedBuffer(array.buffer)) {
21+
ThrowTypeError(kDetachedOperation, kBuiltinNameSort);
22+
}
23+
24+
// c. If v is NaN, return +0.
25+
if (NumberIsNaN(v)) return 0;
26+
27+
// d. return v.
28+
return v;
29+
}
30+
31+
// Merges two sorted runs [from, middle) and [middle, to)
32+
// from "source" into "target".
33+
transitioning macro
34+
TypedArrayMerge(
35+
implicit context: Context, array: JSTypedArray, comparefn: Callable)(
36+
source: FixedArray, from: uintptr, middle: uintptr, to: uintptr,
37+
target: FixedArray) {
38+
let left: uintptr = from;
39+
let right: uintptr = middle;
40+
41+
for (let targetIndex: uintptr = from; targetIndex < to; ++targetIndex) {
42+
if (left < middle && right >= to) {
43+
// If the left run has elements, but the right does not, we take
44+
// from the left.
45+
target.objects[targetIndex] = source.objects[left++];
46+
} else if (left < middle) {
47+
// If both have elements, we need to compare.
48+
const leftElement = UnsafeCast<JSAny>(source.objects[left]);
49+
const rightElement = UnsafeCast<JSAny>(source.objects[right]);
50+
if (CallCompare(leftElement, rightElement) <= 0) {
51+
target.objects[targetIndex] = leftElement;
52+
left++;
53+
} else {
54+
target.objects[targetIndex] = rightElement;
55+
right++;
56+
}
57+
} else {
58+
// No elements on the left, but the right does, so we take
59+
// from the right.
60+
assert(left == middle);
61+
target.objects[targetIndex] = source.objects[right++];
62+
}
63+
}
64+
}
65+
66+
transitioning builtin
67+
TypedArrayMergeSort(implicit context: Context)(
68+
source: FixedArray, from: uintptr, to: uintptr, target: FixedArray,
69+
array: JSTypedArray, comparefn: Callable): JSAny {
70+
assert(to - from > 1);
71+
const middle: uintptr = from + ((to - from) >>> 1);
72+
73+
// On the next recursion step source becomes target and vice versa.
74+
// This saves the copy of the relevant range from the original
75+
// array into a work array on each recursion step.
76+
if (middle - from > 1) {
77+
TypedArrayMergeSort(target, from, middle, source, array, comparefn);
78+
}
79+
if (to - middle > 1) {
80+
TypedArrayMergeSort(target, middle, to, source, array, comparefn);
81+
}
82+
83+
TypedArrayMerge(source, from, middle, to, target);
84+
85+
return Undefined;
86+
}
87+
88+
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort
89+
transitioning javascript builtin TypedArrayPrototypeSort(
90+
js-implicit context: Context,
91+
receiver: JSAny)(...arguments): JSTypedArray {
92+
// 1. If comparefn is not undefined and IsCallable(comparefn) is false,
93+
// throw a TypeError exception.
94+
const comparefnObj: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
95+
if (comparefnObj != Undefined && !TaggedIsCallable(comparefnObj)) {
96+
ThrowTypeError(kBadSortComparisonFunction, comparefnObj);
97+
}
98+
99+
// 2. Let obj be the this value.
100+
const obj: JSAny = receiver;
101+
102+
// 3. Let buffer be ? ValidateTypedArray(obj).
103+
// ValidateTypedArray currently returns the array, not the ViewBuffer.
104+
const array: JSTypedArray =
105+
ValidateTypedArray(context, obj, kBuiltinNameSort);
106+
107+
// Default sorting is done in C++ using std::sort
108+
if (comparefnObj == Undefined) {
109+
return TypedArraySortFast(context, obj);
110+
}
111+
112+
// 4. Let len be obj.[[ArrayLength]].
113+
const len: uintptr = array.length;
114+
115+
// Arrays of length 1 or less are considered sorted.
116+
if (len < 2) return array;
117+
118+
const comparefn: Callable =
119+
Cast<Callable>(comparefnObj) otherwise unreachable;
120+
const accessor: TypedArrayAccessor =
121+
GetTypedArrayAccessor(array.elements_kind);
122+
123+
// Prepare the two work arrays. All numbers are converted to tagged
124+
// objects first, and merge sorted between the two FixedArrays.
125+
// The result is then written back into the JSTypedArray.
126+
const work1: FixedArray = AllocateZeroedFixedArray(Convert<intptr>(len));
127+
const work2: FixedArray = AllocateZeroedFixedArray(Convert<intptr>(len));
128+
129+
for (let i: uintptr = 0; i < len; ++i) {
130+
const element: Numeric = accessor.LoadNumeric(context, array, i);
131+
work1.objects[i] = element;
132+
work2.objects[i] = element;
133+
}
134+
135+
TypedArrayMergeSort(work2, 0, len, work1, array, comparefn);
136+
137+
// work1 contains the sorted numbers. Write them back.
138+
for (let i: uintptr = 0; i < len; ++i) {
139+
accessor.StoreNumeric(
140+
context, array, i, UnsafeCast<Numeric>(work1.objects[i]));
141+
}
142+
143+
return array;
144+
}
145+
}

src/builtins/typed-array.tq

Lines changed: 0 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ namespace typed_array {
5252
sizeLog2: uintptr;
5353
kind: ElementsKind;
5454
}
55-
extern runtime TypedArraySortFast(Context, JSAny): JSTypedArray;
5655
extern runtime TypedArrayCopyElements(Context, JSTypedArray, Object, Number):
5756
void;
5857
extern macro TypedArrayBuiltinsAssembler::ValidateTypedArray(
@@ -272,138 +271,4 @@ namespace typed_array {
272271
}
273272
return kStoreSucceded;
274273
}
275-
276-
transitioning macro CallCompare(
277-
implicit context: Context, array: JSTypedArray,
278-
comparefn: Callable)(a: JSAny, b: JSAny): Number {
279-
// a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)).
280-
const v: Number =
281-
ToNumber_Inline(Call(context, comparefn, Undefined, a, b));
282-
283-
// b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
284-
if (IsDetachedBuffer(array.buffer)) {
285-
ThrowTypeError(kDetachedOperation, '%TypedArray%.prototype.sort');
286-
}
287-
288-
// c. If v is NaN, return +0.
289-
if (NumberIsNaN(v)) return 0;
290-
291-
// d. return v.
292-
return v;
293-
}
294-
295-
// Merges two sorted runs [from, middle) and [middle, to)
296-
// from "source" into "target".
297-
transitioning macro
298-
TypedArrayMerge(
299-
implicit context: Context, array: JSTypedArray, comparefn: Callable)(
300-
source: FixedArray, from: uintptr, middle: uintptr, to: uintptr,
301-
target: FixedArray) {
302-
let left: uintptr = from;
303-
let right: uintptr = middle;
304-
305-
for (let targetIndex: uintptr = from; targetIndex < to; ++targetIndex) {
306-
if (left < middle && right >= to) {
307-
// If the left run has elements, but the right does not, we take
308-
// from the left.
309-
target.objects[targetIndex] = source.objects[left++];
310-
} else if (left < middle) {
311-
// If both have elements, we need to compare.
312-
const leftElement = UnsafeCast<JSAny>(source.objects[left]);
313-
const rightElement = UnsafeCast<JSAny>(source.objects[right]);
314-
if (CallCompare(leftElement, rightElement) <= 0) {
315-
target.objects[targetIndex] = leftElement;
316-
left++;
317-
} else {
318-
target.objects[targetIndex] = rightElement;
319-
right++;
320-
}
321-
} else {
322-
// No elements on the left, but the right does, so we take
323-
// from the right.
324-
assert(left == middle);
325-
target.objects[targetIndex] = source.objects[right++];
326-
}
327-
}
328-
}
329-
330-
transitioning builtin
331-
TypedArrayMergeSort(implicit context: Context)(
332-
source: FixedArray, from: uintptr, to: uintptr, target: FixedArray,
333-
array: JSTypedArray, comparefn: Callable): JSAny {
334-
assert(to - from > 1);
335-
const middle: uintptr = from + ((to - from) >>> 1);
336-
337-
// On the next recursion step source becomes target and vice versa.
338-
// This saves the copy of the relevant range from the original
339-
// array into a work array on each recursion step.
340-
if (middle - from > 1) {
341-
TypedArrayMergeSort(target, from, middle, source, array, comparefn);
342-
}
343-
if (to - middle > 1) {
344-
TypedArrayMergeSort(target, middle, to, source, array, comparefn);
345-
}
346-
347-
TypedArrayMerge(source, from, middle, to, target);
348-
349-
return Undefined;
350-
}
351-
352-
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort
353-
transitioning javascript builtin TypedArrayPrototypeSort(
354-
js-implicit context: Context,
355-
receiver: JSAny)(...arguments): JSTypedArray {
356-
// 1. If comparefn is not undefined and IsCallable(comparefn) is false,
357-
// throw a TypeError exception.
358-
const comparefnObj: JSAny = arguments.length > 0 ? arguments[0] : Undefined;
359-
if (comparefnObj != Undefined && !TaggedIsCallable(comparefnObj)) {
360-
ThrowTypeError(kBadSortComparisonFunction, comparefnObj);
361-
}
362-
363-
// 2. Let obj be the this value.
364-
const obj: JSAny = receiver;
365-
366-
// 3. Let buffer be ? ValidateTypedArray(obj).
367-
// ValidateTypedArray currently returns the array, not the ViewBuffer.
368-
const array: JSTypedArray =
369-
ValidateTypedArray(context, obj, '%TypedArray%.prototype.sort');
370-
371-
// Default sorting is done in C++ using std::sort
372-
if (comparefnObj == Undefined) {
373-
return TypedArraySortFast(context, obj);
374-
}
375-
376-
// 4. Let len be obj.[[ArrayLength]].
377-
const len: uintptr = array.length;
378-
379-
// Arrays of length 1 or less are considered sorted.
380-
if (len < 2) return array;
381-
382-
const comparefn: Callable =
383-
Cast<Callable>(comparefnObj) otherwise unreachable;
384-
const accessor: TypedArrayAccessor =
385-
GetTypedArrayAccessor(array.elements_kind);
386-
387-
// Prepare the two work arrays. All numbers are converted to tagged
388-
// objects first, and merge sorted between the two FixedArrays.
389-
// The result is then written back into the JSTypedArray.
390-
const work1: FixedArray = AllocateZeroedFixedArray(Convert<intptr>(len));
391-
const work2: FixedArray = AllocateZeroedFixedArray(Convert<intptr>(len));
392-
393-
for (let i: uintptr = 0; i < len; ++i) {
394-
const element: Numeric = accessor.LoadNumeric(context, array, i);
395-
work1.objects[i] = element;
396-
work2.objects[i] = element;
397-
}
398-
399-
TypedArrayMergeSort(work2, 0, len, work1, array, comparefn);
400-
401-
// work1 contains the sorted numbers. Write them back.
402-
for (let i: uintptr = 0; i < len; ++i) {
403-
accessor.StoreNumeric(
404-
context, array, i, UnsafeCast<Numeric>(work1.objects[i]));
405-
}
406-
407-
return array;
408-
}
409274
}

0 commit comments

Comments
 (0)