[typedarray] Implement TypedArray.p.sort using Torque.
This CL implements TypedArray.p.sort in Torque. The Torque version works basically the same as the existing JS builtin: When no comparison function is provided, the C++ fast path builtin is used. Otherwise a quicksort written in Torque is used, with a InsertionSort fallback for smaller arrays. The JS quicksort implementation also containes a more elaborate third pivot calculation for larger arrays. This is currently not done. Reported benchmark results are only for those, where a custom comparison function is provided. The numbers for the C++ path stayed the same. Benchmark Current (JS) Torque Speedup IntTypes 83.9 263.7 3.1 BigIntTypes 32.1 54.6 1.7 FloatTypes 99.3 138.7 1.4 R=danno@chromium.org, jgruber@chromium.org Bug: v8:7382 Cq-Include-Trybots: luci.v8.try:v8_linux_noi18n_rel_ng Change-Id: I7abe7ceff525bab24f302d2f06b5961cca770d24 Reviewed-on: https://chromium-review.googlesource.com/1021691 Commit-Queue: Simon Zünd <szuend@google.com> Reviewed-by: Daniel Clifford <danno@chromium.org> Reviewed-by: Peter Marshall <petermarshall@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Cr-Commit-Position: refs/heads/master@{#52776}
This commit is contained in:
parent
2393710a27
commit
3ea1ad234c
5
BUILD.gn
5
BUILD.gn
@ -865,6 +865,7 @@ action("run_torque") {
|
||||
inputs = [
|
||||
"src/builtins/base.tq",
|
||||
"src/builtins/array.tq",
|
||||
"src/builtins/typed-array.tq",
|
||||
]
|
||||
|
||||
outputs = [
|
||||
@ -873,6 +874,8 @@ action("run_torque") {
|
||||
"$target_gen_dir/builtins-array-from-dsl-gen.h",
|
||||
"$target_gen_dir/builtins-base-from-dsl-gen.cc",
|
||||
"$target_gen_dir/builtins-base-from-dsl-gen.h",
|
||||
"$target_gen_dir/builtins-typed-array-from-dsl-gen.cc",
|
||||
"$target_gen_dir/builtins-typed-array-from-dsl-gen.h",
|
||||
]
|
||||
|
||||
args = [
|
||||
@ -883,6 +886,7 @@ action("run_torque") {
|
||||
rebase_path("$target_gen_dir", root_build_dir),
|
||||
rebase_path("src/builtins/base.tq", root_build_dir),
|
||||
rebase_path("src/builtins/array.tq", root_build_dir),
|
||||
rebase_path("src/builtins/typed-array.tq", root_build_dir),
|
||||
]
|
||||
}
|
||||
|
||||
@ -1196,6 +1200,7 @@ v8_source_set("v8_initializers") {
|
||||
sources = [
|
||||
"$target_gen_dir/builtins-array-from-dsl-gen.cc",
|
||||
"$target_gen_dir/builtins-base-from-dsl-gen.cc",
|
||||
"$target_gen_dir/builtins-typed-array-from-dsl-gen.cc",
|
||||
|
||||
### gcmole(all) ###
|
||||
"src/builtins/builtins-arguments-gen.cc",
|
||||
|
@ -2919,6 +2919,8 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
|
||||
Builtins::kTypedArrayPrototypeSlice, 2, false);
|
||||
SimpleInstallFunction(prototype, "some", Builtins::kTypedArrayPrototypeSome,
|
||||
1, false);
|
||||
SimpleInstallFunction(prototype, "sort", Builtins::kTypedArrayPrototypeSort,
|
||||
1, false);
|
||||
SimpleInstallFunction(prototype, "subarray",
|
||||
Builtins::kTypedArrayPrototypeSubArray, 2, false);
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ type float64 generates 'TNode<Float64T>';
|
||||
type bit generates 'TNode<BoolT>';
|
||||
|
||||
type int31 extends int32 generates 'TNode<Int32T>';
|
||||
type RawPtr generates 'TNode<RawPtrT>';
|
||||
type Number extends Object generates 'TNode<Number>';
|
||||
type Smi extends Number generates 'TNode<Smi>';
|
||||
type HeapObject extends Object generates 'TNode<HeapObject>';
|
||||
@ -29,12 +30,16 @@ type FixedArray extends FixedArrayBase generates 'TNode<FixedArray>';
|
||||
type FixedDoubleArray extends FixedArrayBase generates
|
||||
'TNode<FixedDoubleArray>';
|
||||
|
||||
type JSArrayBuffer extends Object generates 'TNode<JSArrayBuffer>';
|
||||
type JSArrayBufferView extends Object generates 'TNode<JSArrayBufferView>';
|
||||
type JSTypedArray extends JSArrayBufferView generates 'TNode<JSTypedArray>';
|
||||
|
||||
type const_int32 generates 'int32_t';
|
||||
type const_int31 extends const_int32 generates 'int32_t';
|
||||
type const_float64 generates 'double';
|
||||
|
||||
type InstanceType extends int32 generates 'TNode<Int32T>';
|
||||
type ElementsKind generates 'ElementsKind';
|
||||
type ElementsKind extends const_int32 generates 'ElementsKind';
|
||||
type LanguageMode extends Smi;
|
||||
type ExtractFixedArrayFlags;
|
||||
|
||||
@ -49,6 +54,18 @@ const HOLEY_ELEMENTS: ElementsKind = 'HOLEY_ELEMENTS';
|
||||
const PACKED_DOUBLE_ELEMENTS: ElementsKind = 'PACKED_DOUBLE_ELEMENTS';
|
||||
const HOLEY_DOUBLE_ELEMENTS: ElementsKind = 'HOLEY_DOUBLE_ELEMENTS';
|
||||
|
||||
const UINT8_ELEMENTS: ElementsKind = 'UINT8_ELEMENTS';
|
||||
const INT8_ELEMENTS: ElementsKind = 'INT8_ELEMENTS';
|
||||
const UINT16_ELEMENTS: ElementsKind = 'UINT16_ELEMENTS';
|
||||
const INT16_ELEMENTS: ElementsKind = 'INT16_ELEMENTS';
|
||||
const UINT32_ELEMENTS: ElementsKind = 'UINT32_ELEMENTS';
|
||||
const INT32_ELEMENTS: ElementsKind = 'INT32_ELEMENTS';
|
||||
const FLOAT32_ELEMENTS: ElementsKind = 'FLOAT32_ELEMENTS';
|
||||
const FLOAT64_ELEMENTS: ElementsKind = 'FLOAT64_ELEMENTS';
|
||||
const UINT8_CLAMPED_ELEMENTS: ElementsKind = 'UINT8_CLAMPED_ELEMENTS';
|
||||
const BIGUINT64_ELEMENTS: ElementsKind = 'BIGUINT64_ELEMENTS';
|
||||
const BIGINT64_ELEMENTS: ElementsKind = 'BIGINT64_ELEMENTS';
|
||||
|
||||
const kOperationLessThan: CompareOperator = 'Operation::kLessThan';
|
||||
const kOperationLessThanEqual: CompareOperator = 'Operation::kLessThanEqual';
|
||||
const kOperationGreaterThan: CompareOperator = 'Operation::kGreaterThan';
|
||||
@ -69,6 +86,12 @@ const kHasProperty: HasPropertyFlag = 'kHasProperty';
|
||||
|
||||
const kMaxSafeInteger: const_float64 = 'kMaxSafeInteger';
|
||||
|
||||
const kNotTypedArray: MessageTemplate = 'MessageTemplate::kNotTypedArray';
|
||||
const kDetachedOperation: MessageTemplate =
|
||||
'MessageTemplate::kDetachedOperation';
|
||||
const kBadSortComparisonFunction: MessageTemplate =
|
||||
'MessageTemplate::kBadSortComparisonFunction';
|
||||
|
||||
const hole: Object = 'TheHoleConstant()';
|
||||
const null: Oddball = 'NullConstant()';
|
||||
const undefined: Oddball = 'UndefinedConstant()';
|
||||
@ -89,10 +112,13 @@ extern macro Print(String, Object);
|
||||
extern macro DebugBreak();
|
||||
extern macro ToInteger_Inline(Context, Object): Number;
|
||||
extern macro ToLength_Inline(Context, Object): Number;
|
||||
extern macro ToNumber_Inline(Context, Object): Number;
|
||||
extern macro ToString_Inline(Context, Object): String;
|
||||
extern macro GetProperty(Context, Object, Object): Object;
|
||||
extern macro HasProperty(HeapObject, Object, Context, HasPropertyFlag): Oddball;
|
||||
extern macro ThrowRangeError(Context, MessageTemplate): never;
|
||||
extern macro ThrowTypeError(Context, MessageTemplate): never;
|
||||
extern macro ThrowTypeError(Context, MessageTemplate, Object): never;
|
||||
extern macro ArraySpeciesCreate(Context, Object, Number): Object;
|
||||
extern macro EnsureArrayPushable(Map): int32 labels Bailout;
|
||||
|
||||
@ -127,6 +153,8 @@ extern operator '>' macro IntPtrGreaterThan(intptr, intptr): bit;
|
||||
extern operator '<=' macro IntPtrLessThanOrEqual(intptr, intptr): bit;
|
||||
extern operator '>=' macro IntPtrGreaterThanOrEqual(intptr, intptr): bit;
|
||||
|
||||
extern operator '==' macro Float64Equal(float64, float64): bit;
|
||||
|
||||
extern operator
|
||||
'<' macro BranchIfNumberLessThan(Number, Number): never labels True, False;
|
||||
extern operator
|
||||
@ -143,9 +171,11 @@ extern operator '!=' macro WordNotEqual(Object, Object): bit;
|
||||
|
||||
extern operator '+' macro SmiAdd(Smi, Smi): Smi;
|
||||
extern operator '-' macro SmiSub(Smi, Smi): Smi;
|
||||
extern operator '>>>' macro SmiShr(Smi, const_int31): Smi;
|
||||
|
||||
extern operator '+' macro IntPtrAdd(intptr, intptr): intptr;
|
||||
extern operator '-' macro IntPtrSub(intptr, intptr): intptr;
|
||||
extern operator '>>>' macro WordShr(intptr, intptr): intptr;
|
||||
|
||||
extern operator '+' macro NumberAdd(Number, Number): Number;
|
||||
extern operator '-' macro NumberSub(Number, Number): Number;
|
||||
@ -194,6 +224,7 @@ extern operator 'convert<>' macro TruncateWordToWord32(intptr): int32;
|
||||
extern operator 'convert<>' macro SmiTag(intptr): Smi;
|
||||
extern operator 'convert<>' macro SmiUntag(Smi): intptr;
|
||||
|
||||
|
||||
extern macro BranchIfFastJSArray(Object, Context): never labels True, False;
|
||||
extern macro BranchIfNotFastJSArray(Object, Context): never labels True, False;
|
||||
|
||||
@ -203,11 +234,18 @@ extern macro IsArraySpeciesProtectorCellInvalid(): bit;
|
||||
extern macro IsTypedArraySpeciesProtectorCellInvalid(): bit;
|
||||
extern macro IsPromiseSpeciesProtectorCellInvalid(): bit;
|
||||
|
||||
extern operator
|
||||
'.buffer' macro LoadTypedArrayBuffer(JSTypedArray): JSArrayBuffer;
|
||||
|
||||
extern operator '.data_ptr' macro LoadDataPtr(JSTypedArray): RawPtr;
|
||||
|
||||
extern operator '.elements_kind' macro LoadMapElementsKind(Map): int32;
|
||||
extern operator '.elements_kind' macro LoadElementsKind(JSTypedArray): int32;
|
||||
|
||||
extern operator '.elements' macro LoadElements(Object): FixedArrayBase;
|
||||
extern operator '.elements=' macro StoreElements(Object, FixedArrayBase);
|
||||
|
||||
extern operator '.length' macro LoadTypedArrayLength(JSTypedArray): Smi;
|
||||
extern operator '.length' macro LoadJSArrayLength(JSArray): Number;
|
||||
extern operator '.length=' macro StoreJSArrayLength(JSArray, Smi);
|
||||
|
||||
@ -251,3 +289,13 @@ macro HasPropertyObject(
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
extern macro IsCallable(Object): bit;
|
||||
extern macro IsDetachedBuffer(JSArrayBuffer): bit;
|
||||
|
||||
type ParameterMode;
|
||||
const kSmiParameters: ParameterMode = 'ParameterMode::SMI_PARAMETERS';
|
||||
extern macro LoadFixedTypedArrayElementAsTagged(
|
||||
RawPtr, Smi, ElementsKind, ParameterMode): Object;
|
||||
extern macro StoreFixedTypedArrayElementFromTagged(
|
||||
Context, RawPtr, Smi, Object, ElementsKind, ParameterMode);
|
||||
|
@ -1196,6 +1196,27 @@ void TypedArrayBuiltinsAssembler::DispatchTypedArrayByElementsKind(
|
||||
BIND(&next);
|
||||
}
|
||||
|
||||
TNode<BoolT> TypedArrayBuiltinsAssembler::NumberIsNaN(TNode<Number> value) {
|
||||
Label is_heapnumber(this), done(this);
|
||||
TVARIABLE(BoolT, result);
|
||||
|
||||
GotoIf(TaggedIsNotSmi(value), &is_heapnumber);
|
||||
result = Int32FalseConstant();
|
||||
Goto(&done);
|
||||
|
||||
BIND(&is_heapnumber);
|
||||
{
|
||||
CSA_ASSERT(this, IsHeapNumber(value));
|
||||
|
||||
TNode<Float64T> value_f = LoadHeapNumberValue(CAST(value));
|
||||
result = Float64NotEqual(value_f, value_f);
|
||||
Goto(&done);
|
||||
}
|
||||
|
||||
BIND(&done);
|
||||
return result.value();
|
||||
}
|
||||
|
||||
// ES #sec-get-%typedarray%.prototype.set
|
||||
TF_BUILTIN(TypedArrayPrototypeSet, TypedArrayBuiltinsAssembler) {
|
||||
TNode<Context> context = CAST(Parameter(BuiltinDescriptor::kContext));
|
||||
|
@ -71,6 +71,15 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
// Returns the byte size of an element for a TypedArray elements kind.
|
||||
TNode<IntPtrT> GetTypedArrayElementSize(TNode<Word32T> elements_kind);
|
||||
|
||||
TNode<Smi> LoadTypedArrayLength(TNode<JSTypedArray> typed_array) {
|
||||
return LoadObjectField<Smi>(typed_array, JSTypedArray::kLengthOffset);
|
||||
}
|
||||
|
||||
TNode<JSArrayBuffer> LoadTypedArrayBuffer(TNode<JSTypedArray> typed_array) {
|
||||
return LoadObjectField<JSArrayBuffer>(typed_array,
|
||||
JSTypedArray::kBufferOffset);
|
||||
}
|
||||
|
||||
TNode<Object> GetDefaultConstructor(TNode<Context> context,
|
||||
TNode<JSTypedArray> exemplar);
|
||||
|
||||
@ -126,6 +135,14 @@ class TypedArrayBuiltinsAssembler : public CodeStubAssembler {
|
||||
|
||||
void DispatchTypedArrayByElementsKind(
|
||||
TNode<Word32T> elements_kind, const TypedArraySwitchCase& case_function);
|
||||
|
||||
// Returns true iff number is NaN.
|
||||
// TOOD(szuend): Remove when UncheckedCasts are supported in Torque.
|
||||
TNode<BoolT> NumberIsNaN(TNode<Number> number);
|
||||
|
||||
// Always CSA_ASSERTs false.
|
||||
// TODO(szuend): Remove when Unreachable is supported in Torque.
|
||||
void AssertUnreachable() { CSA_ASSERT(this, Int32FalseConstant()); }
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
304
src/builtins/typed-array.tq
Normal file
304
src/builtins/typed-array.tq
Normal file
@ -0,0 +1,304 @@
|
||||
// Copyright 2018 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
module typed_array {
|
||||
extern runtime TypedArraySortFast(Context, Object): JSTypedArray;
|
||||
|
||||
type MethodName;
|
||||
const kTypedArrayProtoSort: MethodName = '\"%TypedArray%.prototype.sort\"';
|
||||
extern macro ValidateTypedArray(Context, Object, MethodName): JSTypedArray;
|
||||
|
||||
extern macro AssertUnreachable();
|
||||
extern macro NumberIsNaN(Number): bit;
|
||||
|
||||
macro CallCompareWithDetachedCheck(
|
||||
context: Context, array: JSTypedArray, comparefn: Callable, a: Object,
|
||||
b: Object): Number labels Detached {
|
||||
// a. Let v be ? ToNumber(? Call(comparefn, undefined, x, y)).
|
||||
let v: Number =
|
||||
ToNumber_Inline(context, Call(context, comparefn, undefined, a, b));
|
||||
|
||||
// b. If IsDetachedBuffer(buffer) is true, throw a TypeError exception.
|
||||
if (IsDetachedBuffer(array.buffer)) goto Detached;
|
||||
|
||||
// c. If v is NaN, return +0.
|
||||
if (NumberIsNaN(v)) return 0;
|
||||
|
||||
// d. return v.
|
||||
return v;
|
||||
}
|
||||
|
||||
// Wrapped CSA macro for better readability. Ideally we want to map this
|
||||
// as the array operator "[]".
|
||||
macro Load(backing_store: RawPtr, index: Smi, kind: ElementsKind): Object {
|
||||
return LoadFixedTypedArrayElementAsTagged(
|
||||
backing_store, index, kind, kSmiParameters);
|
||||
}
|
||||
|
||||
// Wrapped array store CSA macro for better readability.
|
||||
macro Store(
|
||||
context: Context, backing_store: RawPtr, index: Smi, value: Object,
|
||||
kind: ElementsKind) {
|
||||
StoreFixedTypedArrayElementFromTagged(
|
||||
context, backing_store, index, value, kind, kSmiParameters);
|
||||
}
|
||||
|
||||
// InsertionSort is used for smaller arrays.
|
||||
macro TypedArrayInsertionSort(
|
||||
context: Context, array: JSTypedArray, kind: ElementsKind, from_arg: Smi,
|
||||
to_arg: Smi, comparefn: Callable)
|
||||
labels Detached {
|
||||
let from: Smi = from_arg;
|
||||
let to: Smi = to_arg;
|
||||
|
||||
let backing_store: RawPtr = array.data_ptr;
|
||||
if (IsDetachedBuffer(array.buffer)) goto Detached;
|
||||
|
||||
for (let i: Smi = from + 1; i < to; ++i) {
|
||||
let element: Object = Load(backing_store, i, kind);
|
||||
let j: Smi = i - 1;
|
||||
for (; j >= from; --j) {
|
||||
let tmp: Object = Load(backing_store, j, kind);
|
||||
let order: Number = CallCompareWithDetachedCheck(
|
||||
context, array, comparefn, tmp, element) otherwise Detached;
|
||||
backing_store = array.data_ptr; // Force reload.
|
||||
if (order > 0) {
|
||||
Store(context, backing_store, j + 1, tmp, kind);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
Store(context, backing_store, j + 1, element, kind);
|
||||
}
|
||||
}
|
||||
|
||||
macro TypedArrayQuickSortImpl(
|
||||
context: Context, array: JSTypedArray, kind: ElementsKind, from_arg: Smi,
|
||||
to_arg: Smi, comparefn: Callable)
|
||||
labels Detached {
|
||||
let from: Smi = from_arg;
|
||||
let to: Smi = to_arg;
|
||||
|
||||
while (to - from > 1) {
|
||||
if (to - from <= 10) {
|
||||
// TODO(szuend): Investigate InsertionSort removal.
|
||||
// Currently it does not make any difference when the
|
||||
// benchmarks are run locally.
|
||||
TypedArrayInsertionSort(context, array, kind, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(szuend): Check if a more involved third_index calculation is
|
||||
// worth it for very large arrays.
|
||||
let third_index: Smi = from + ((to - from) >>> 1);
|
||||
|
||||
// TODO(szuend): Investigate possible performance impact by caching the
|
||||
// backing_store ptr for off-heap buffers.
|
||||
let backing_store: RawPtr = array.data_ptr;
|
||||
if (IsDetachedBuffer(array.buffer)) goto Detached;
|
||||
|
||||
// Find a pivot as the median of first, last and middle element.
|
||||
let v0: Object = Load(backing_store, from, kind);
|
||||
let v1: Object = Load(backing_store, to - 1, kind);
|
||||
let v2: Object = Load(backing_store, third_index, kind);
|
||||
|
||||
let c01: Number = CallCompareWithDetachedCheck(
|
||||
context, array, comparefn, v0, v1) otherwise Detached;
|
||||
if (c01 > 0) {
|
||||
// v1 < v0, so swap them.
|
||||
let tmp: Object = v0;
|
||||
v0 = v1;
|
||||
v1 = tmp;
|
||||
}
|
||||
// v0 <= v1.
|
||||
let c02: Number = CallCompareWithDetachedCheck(
|
||||
context, array, comparefn, v0, v2) otherwise Detached;
|
||||
if (c02 >= 0) {
|
||||
// v2 <= v0 <= v1.
|
||||
let tmp: Object = v0;
|
||||
v0 = v2;
|
||||
v2 = v1;
|
||||
v1 = tmp;
|
||||
} else {
|
||||
// v0 <= v1 && v0 < v2.
|
||||
let c12: Number = CallCompareWithDetachedCheck(
|
||||
context, array, comparefn, v1, v2) otherwise Detached;
|
||||
if (c12 > 0) {
|
||||
// v0 <= v2 < v1.
|
||||
let tmp: Object = v1;
|
||||
v1 = v2;
|
||||
v2 = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// v0 <= v1 <= v2.
|
||||
backing_store = array.data_ptr; // Force reload.
|
||||
Store(context, backing_store, from, v0, kind);
|
||||
Store(context, backing_store, to - 1, v2, kind);
|
||||
|
||||
let pivot: Object = v1;
|
||||
let low_end: Smi = from + 1; // Upper bound of elems lower than pivot.
|
||||
let high_start: Smi = to - 1; // Lower bound of elems greater than pivot.
|
||||
|
||||
let low_end_value: Object = Load(backing_store, low_end, kind);
|
||||
Store(context, backing_store, third_index, low_end_value, kind);
|
||||
Store(context, backing_store, low_end, pivot, kind);
|
||||
|
||||
// From low_end to idx are elements equal to pivot.
|
||||
// From idx to high_start are elements that haven"t been compared yet.
|
||||
for (let idx: Smi = low_end + 1; idx < high_start; idx++) {
|
||||
let element: Object = Load(backing_store, idx, kind);
|
||||
let order: Number = CallCompareWithDetachedCheck(
|
||||
context, array, comparefn, element, pivot) otherwise Detached;
|
||||
|
||||
backing_store = array.data_ptr; // Force reload.
|
||||
if (order < 0) {
|
||||
low_end_value = Load(backing_store, low_end, kind);
|
||||
Store(context, backing_store, idx, low_end_value, kind);
|
||||
Store(context, backing_store, low_end, element, kind);
|
||||
low_end++;
|
||||
} else if (order > 0) {
|
||||
let break_for: bit = no;
|
||||
|
||||
while (order > 0) {
|
||||
high_start--;
|
||||
if (high_start == idx) {
|
||||
break_for = yes;
|
||||
break;
|
||||
}
|
||||
|
||||
let top_elem: Object = Load(backing_store, high_start, kind);
|
||||
order = CallCompareWithDetachedCheck(
|
||||
context, array, comparefn, top_elem, pivot) otherwise Detached;
|
||||
backing_store = array.data_ptr; // Force reload.
|
||||
}
|
||||
|
||||
if (break_for) {
|
||||
break;
|
||||
}
|
||||
|
||||
let high_start_value: Object = Load(backing_store, high_start, kind);
|
||||
Store(context, backing_store, idx, high_start_value, kind);
|
||||
Store(context, backing_store, high_start, element, kind);
|
||||
|
||||
if (order < 0) {
|
||||
element = Load(backing_store, idx, kind);
|
||||
|
||||
low_end_value = Load(backing_store, low_end, kind);
|
||||
Store(context, backing_store, idx, low_end_value, kind);
|
||||
Store(context, backing_store, low_end, element, kind);
|
||||
low_end++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((to - high_start) < (low_end - from)) {
|
||||
TypedArrayQuickSort(context, array, high_start, to, comparefn);
|
||||
to = low_end;
|
||||
} else {
|
||||
TypedArrayQuickSort(context, array, from, low_end, comparefn);
|
||||
from = high_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
builtin TypedArrayQuickSort(
|
||||
context: Context, array: JSTypedArray, from: Smi, to: Smi,
|
||||
comparefn: Callable): JSTypedArray {
|
||||
let element_kind: int32 = array.elements_kind;
|
||||
|
||||
try {
|
||||
if (element_kind == convert<int32>(UINT8_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, UINT8_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(INT8_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, INT8_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(UINT16_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, UINT16_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(INT16_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, INT16_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(UINT32_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, UINT32_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(INT32_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, INT32_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(UINT8_CLAMPED_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, UINT8_CLAMPED_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(FLOAT32_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, FLOAT32_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(FLOAT64_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, FLOAT64_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(BIGUINT64_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, BIGUINT64_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
} else if (element_kind == convert<int32>(BIGINT64_ELEMENTS)) {
|
||||
TypedArrayQuickSortImpl(
|
||||
context, array, BIGINT64_ELEMENTS, from, to, comparefn)
|
||||
otherwise Detached;
|
||||
}
|
||||
}
|
||||
label Detached {
|
||||
ThrowTypeError(
|
||||
context, kDetachedOperation, '%TypedArray%.prototype.sort');
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
// https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.sort
|
||||
javascript builtin TypedArrayPrototypeSort(
|
||||
context: Context, receiver: Object, ...arguments): JSTypedArray {
|
||||
// 1. If comparefn is not undefined and IsCallable(comparefn) is false,
|
||||
// throw a TypeError exception.
|
||||
let comparefn_obj: Object = arguments.length > 0 ? arguments[0] : undefined;
|
||||
if (comparefn_obj != undefined &&
|
||||
(TaggedIsSmi(comparefn_obj) || !IsCallable(comparefn_obj))) {
|
||||
ThrowTypeError(context, kBadSortComparisonFunction, comparefn_obj);
|
||||
}
|
||||
|
||||
// 2. Let obj be the this value.
|
||||
let obj: Object = receiver;
|
||||
|
||||
// 3. Let buffer be ? ValidateTypedArray(obj).
|
||||
// ValidateTypedArray currently returns the array, not the ViewBuffer.
|
||||
let array: JSTypedArray =
|
||||
ValidateTypedArray(context, obj, kTypedArrayProtoSort);
|
||||
|
||||
// Default sorting is done in C++ using std::sort
|
||||
if (comparefn_obj == undefined) {
|
||||
return TypedArraySortFast(context, obj);
|
||||
}
|
||||
|
||||
// 4. Let len be obj.[[ArrayLength]].
|
||||
let len: Smi = array.length;
|
||||
|
||||
try {
|
||||
let comparefn: Callable =
|
||||
cast<Callable>(comparefn_obj) otherwise CastError;
|
||||
TypedArrayQuickSort(context, array, 0, len, comparefn);
|
||||
}
|
||||
label CastError {
|
||||
// TODO(szuend): Replace with Unreachable() when its supported in Torque.
|
||||
AssertUnreachable();
|
||||
}
|
||||
return array;
|
||||
}
|
||||
}
|
@ -394,6 +394,11 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
|
||||
template <class... TArgs>
|
||||
TNode<Object> Call(TNode<Context> context, TNode<Object> callable,
|
||||
TNode<Object> receiver, TArgs... args) {
|
||||
if (IsUndefinedConstant(receiver) || IsNullConstant(receiver)) {
|
||||
return UncheckedCast<Object>(CallJS(
|
||||
CodeFactory::Call(isolate(), ConvertReceiverMode::kNullOrUndefined),
|
||||
context, callable, receiver, args...));
|
||||
}
|
||||
return UncheckedCast<Object>(CallJS(CodeFactory::Call(isolate()), context,
|
||||
callable, receiver, args...));
|
||||
}
|
||||
|
@ -422,6 +422,16 @@ bool CodeAssembler::ToIntPtrConstant(Node* node, intptr_t& out_value) {
|
||||
return m.HasValue();
|
||||
}
|
||||
|
||||
bool CodeAssembler::IsUndefinedConstant(TNode<Object> node) {
|
||||
compiler::HeapObjectMatcher m(node);
|
||||
return m.Is(isolate()->factory()->undefined_value());
|
||||
}
|
||||
|
||||
bool CodeAssembler::IsNullConstant(TNode<Object> node) {
|
||||
compiler::HeapObjectMatcher m(node);
|
||||
return m.Is(isolate()->factory()->null_value());
|
||||
}
|
||||
|
||||
Node* CodeAssembler::Parameter(int value) {
|
||||
return raw_assembler()->Parameter(value);
|
||||
}
|
||||
|
@ -406,6 +406,7 @@ class SloppyTNode : public TNode<T> {
|
||||
V(Float32GreaterThan, BoolT, Float32T, Float32T) \
|
||||
V(Float32GreaterThanOrEqual, BoolT, Float32T, Float32T) \
|
||||
V(Float64Equal, BoolT, Float64T, Float64T) \
|
||||
V(Float64NotEqual, BoolT, Float64T, Float64T) \
|
||||
V(Float64LessThan, BoolT, Float64T, Float64T) \
|
||||
V(Float64LessThanOrEqual, BoolT, Float64T, Float64T) \
|
||||
V(Float64GreaterThan, BoolT, Float64T, Float64T) \
|
||||
@ -699,6 +700,9 @@ class V8_EXPORT_PRIVATE CodeAssembler {
|
||||
bool ToSmiConstant(Node* node, Smi*& out_value);
|
||||
bool ToIntPtrConstant(Node* node, intptr_t& out_value);
|
||||
|
||||
bool IsUndefinedConstant(TNode<Object> node);
|
||||
bool IsNullConstant(TNode<Object> node);
|
||||
|
||||
TNode<Int32T> Signed(TNode<Word32T> x) { return UncheckedCast<Int32T>(x); }
|
||||
TNode<IntPtrT> Signed(TNode<WordT> x) { return UncheckedCast<IntPtrT>(x); }
|
||||
TNode<Uint32T> Unsigned(TNode<Word32T> x) {
|
||||
|
@ -14,7 +14,6 @@
|
||||
// array.js has to come before typedarray.js for this to work
|
||||
var ArrayToString = utils.ImportNow("ArrayToString");
|
||||
var InnerArrayJoin;
|
||||
var InnerArraySort;
|
||||
var InnerArrayToLocaleString;
|
||||
|
||||
macro TYPED_ARRAYS(FUNCTION)
|
||||
@ -45,7 +44,6 @@ var GlobalTypedArray = %object_get_prototype_of(GlobalUint8Array);
|
||||
|
||||
utils.Import(function(from) {
|
||||
InnerArrayJoin = from.InnerArrayJoin;
|
||||
InnerArraySort = from.InnerArraySort;
|
||||
InnerArrayToLocaleString = from.InnerArrayToLocaleString;
|
||||
});
|
||||
|
||||
@ -59,26 +57,6 @@ function ValidateTypedArray(array, methodName) {
|
||||
throw %make_type_error(kDetachedOperation, methodName);
|
||||
}
|
||||
|
||||
// ES6 draft 05-18-15, section 22.2.3.25
|
||||
DEFINE_METHOD(
|
||||
GlobalTypedArray.prototype,
|
||||
sort(comparefn) {
|
||||
ValidateTypedArray(this, "%TypedArray%.prototype.sort");
|
||||
|
||||
if (!IS_UNDEFINED(comparefn) && !IS_CALLABLE(comparefn)) {
|
||||
throw %make_type_error(kBadSortComparisonFunction, comparefn);
|
||||
}
|
||||
|
||||
var length = %_TypedArrayGetLength(this);
|
||||
|
||||
if (IS_UNDEFINED(comparefn)) {
|
||||
return %TypedArraySortFast(this);
|
||||
}
|
||||
|
||||
return InnerArraySort(this, length, comparefn);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// ES6 section 22.2.3.27
|
||||
DEFINE_METHOD(
|
||||
|
@ -136,8 +136,6 @@
|
||||
'built-ins/TypedArray/prototype/reduceRight/BigInt/callbackfn-detachbuffer': [FAIL],
|
||||
'built-ins/TypedArray/prototype/some/callbackfn-detachbuffer': [FAIL],
|
||||
'built-ins/TypedArray/prototype/some/BigInt/callbackfn-detachbuffer': [FAIL],
|
||||
'built-ins/TypedArray/prototype/sort/detached-buffer-comparefn': [FAIL],
|
||||
'built-ins/TypedArray/prototype/sort/BigInt/detached-buffer-comparefn': [FAIL],
|
||||
# DataView functions should also throw on detached buffers
|
||||
'built-ins/ArrayBuffer/prototype/byteLength/detached-buffer': [FAIL],
|
||||
'built-ins/DataView/detached-buffer': [FAIL],
|
||||
|
@ -28,6 +28,8 @@ group("v8_run_gcmole") {
|
||||
"$target_gen_dir/../../builtins-array-from-dsl-gen.h",
|
||||
"$target_gen_dir/../../builtins-base-from-dsl-gen.cc",
|
||||
"$target_gen_dir/../../builtins-base-from-dsl-gen.h",
|
||||
"$target_gen_dir/../../builtins-typed-array-from-dsl-gen.cc",
|
||||
"$target_gen_dir/../../builtins-typed-array-from-dsl-gen.h",
|
||||
]
|
||||
|
||||
deps = [
|
||||
|
@ -172,33 +172,33 @@ KNOWN_MAPS = {
|
||||
("RO_SPACE", 0x02921): (173, "Tuple2Map"),
|
||||
("RO_SPACE", 0x02999): (171, "ScriptMap"),
|
||||
("RO_SPACE", 0x02a01): (163, "InterceptorInfoMap"),
|
||||
("RO_SPACE", 0x06891): (154, "AccessorInfoMap"),
|
||||
("RO_SPACE", 0x06aa1): (153, "AccessCheckInfoMap"),
|
||||
("RO_SPACE", 0x06b09): (155, "AccessorPairMap"),
|
||||
("RO_SPACE", 0x06b71): (156, "AliasedArgumentsEntryMap"),
|
||||
("RO_SPACE", 0x06bd9): (157, "AllocationMementoMap"),
|
||||
("RO_SPACE", 0x06c41): (158, "AllocationSiteMap"),
|
||||
("RO_SPACE", 0x06ca9): (159, "AsyncGeneratorRequestMap"),
|
||||
("RO_SPACE", 0x06d11): (160, "ContextExtensionMap"),
|
||||
("RO_SPACE", 0x06d79): (161, "DebugInfoMap"),
|
||||
("RO_SPACE", 0x06de1): (162, "FunctionTemplateInfoMap"),
|
||||
("RO_SPACE", 0x06e49): (164, "InterpreterDataMap"),
|
||||
("RO_SPACE", 0x06eb1): (165, "ModuleInfoEntryMap"),
|
||||
("RO_SPACE", 0x06f19): (166, "ModuleMap"),
|
||||
("RO_SPACE", 0x06f81): (167, "ObjectTemplateInfoMap"),
|
||||
("RO_SPACE", 0x06fe9): (168, "PromiseCapabilityMap"),
|
||||
("RO_SPACE", 0x07051): (169, "PromiseReactionMap"),
|
||||
("RO_SPACE", 0x070b9): (170, "PrototypeInfoMap"),
|
||||
("RO_SPACE", 0x07121): (172, "StackFrameInfoMap"),
|
||||
("RO_SPACE", 0x07189): (174, "Tuple3Map"),
|
||||
("RO_SPACE", 0x071f1): (175, "WasmCompiledModuleMap"),
|
||||
("RO_SPACE", 0x07259): (176, "WasmDebugInfoMap"),
|
||||
("RO_SPACE", 0x072c1): (177, "WasmSharedModuleDataMap"),
|
||||
("RO_SPACE", 0x07329): (178, "CallableTaskMap"),
|
||||
("RO_SPACE", 0x07391): (179, "CallbackTaskMap"),
|
||||
("RO_SPACE", 0x073f9): (180, "PromiseFulfillReactionJobTaskMap"),
|
||||
("RO_SPACE", 0x07461): (181, "PromiseRejectReactionJobTaskMap"),
|
||||
("RO_SPACE", 0x074c9): (182, "PromiseResolveThenableJobTaskMap"),
|
||||
("RO_SPACE", 0x068c9): (154, "AccessorInfoMap"),
|
||||
("RO_SPACE", 0x06ad9): (153, "AccessCheckInfoMap"),
|
||||
("RO_SPACE", 0x06b41): (155, "AccessorPairMap"),
|
||||
("RO_SPACE", 0x06ba9): (156, "AliasedArgumentsEntryMap"),
|
||||
("RO_SPACE", 0x06c11): (157, "AllocationMementoMap"),
|
||||
("RO_SPACE", 0x06c79): (158, "AllocationSiteMap"),
|
||||
("RO_SPACE", 0x06ce1): (159, "AsyncGeneratorRequestMap"),
|
||||
("RO_SPACE", 0x06d49): (160, "ContextExtensionMap"),
|
||||
("RO_SPACE", 0x06db1): (161, "DebugInfoMap"),
|
||||
("RO_SPACE", 0x06e19): (162, "FunctionTemplateInfoMap"),
|
||||
("RO_SPACE", 0x06e81): (164, "InterpreterDataMap"),
|
||||
("RO_SPACE", 0x06ee9): (165, "ModuleInfoEntryMap"),
|
||||
("RO_SPACE", 0x06f51): (166, "ModuleMap"),
|
||||
("RO_SPACE", 0x06fb9): (167, "ObjectTemplateInfoMap"),
|
||||
("RO_SPACE", 0x07021): (168, "PromiseCapabilityMap"),
|
||||
("RO_SPACE", 0x07089): (169, "PromiseReactionMap"),
|
||||
("RO_SPACE", 0x070f1): (170, "PrototypeInfoMap"),
|
||||
("RO_SPACE", 0x07159): (172, "StackFrameInfoMap"),
|
||||
("RO_SPACE", 0x071c1): (174, "Tuple3Map"),
|
||||
("RO_SPACE", 0x07229): (175, "WasmCompiledModuleMap"),
|
||||
("RO_SPACE", 0x07291): (176, "WasmDebugInfoMap"),
|
||||
("RO_SPACE", 0x072f9): (177, "WasmSharedModuleDataMap"),
|
||||
("RO_SPACE", 0x07361): (178, "CallableTaskMap"),
|
||||
("RO_SPACE", 0x073c9): (179, "CallbackTaskMap"),
|
||||
("RO_SPACE", 0x07431): (180, "PromiseFulfillReactionJobTaskMap"),
|
||||
("RO_SPACE", 0x07499): (181, "PromiseRejectReactionJobTaskMap"),
|
||||
("RO_SPACE", 0x07501): (182, "PromiseResolveThenableJobTaskMap"),
|
||||
("MAP_SPACE", 0x02201): (138, "FreeSpaceMap"),
|
||||
("MAP_SPACE", 0x02259): (152, "OnePointerFillerMap"),
|
||||
("MAP_SPACE", 0x022b1): (152, "TwoPointerFillerMap"),
|
||||
|
Loading…
Reference in New Issue
Block a user