[builtins] Port TypedArray join, toString, and toLocaleString to Torque.
Micro-benchmarks show speed improvements across the various types:
TypedArrays-JoinBigIntTypes 7246 8297 14.50%
TypedArrays-JoinBigIntTypes 7194 8637 20.06%
TypedArrays-JoinBigIntTypes 7258 8586 18.30%
TypedArrays-JoinFloatTypes 24461 28628 17.04%
TypedArrays-JoinFloatTypes 24523 29647 20.89%
TypedArrays-JoinFloatTypes 24419 29327 20.10%
TypedArrays-JoinIntTypes 23378 33928 45.13%
TypedArrays-JoinIntTypes 23333 34034 45.86%
TypedArrays-JoinIntTypes 21653 34000 57.02%
TypedArrays-JoinWithSeparatorBigIntTypes 6620 7339 10.86%
TypedArrays-JoinWithSeparatorBigIntTypes 6566 7579 15.43%
TypedArrays-JoinWithSeparatorBigIntTypes 6631 7481 12.82%
TypedArrays-JoinWithSeparatorFloatTypes 18695 19670 5.22%
TypedArrays-JoinWithSeparatorFloatTypes 18518 20088 8.48%
TypedArrays-JoinWithSeparatorFloatTypes 18482 20193 9.26%
TypedArrays-JoinWithSeparatorIntTypes 17849 21482 20.35%
TypedArrays-JoinWithSeparatorIntTypes 17831 21578 21.01%
TypedArrays-JoinWithSeparatorIntTypes 17937 21578 20.30%
Drive-by: Removed unused CSA helper InternalArrayCreate.
Bug: v8:7624
Change-Id: I8e63815982439cfd2267417d03cd2b71b4b7a812
Reviewed-on: https://chromium-review.googlesource.com/c/1369330
Commit-Queue: Peter Wong <peter.wm.wong@gmail.com>
Reviewed-by: Jakob Gruber <jgruber@chromium.org>
Reviewed-by: Peter Marshall <petermarshall@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58167}
diff --git a/BUILD.gn b/BUILD.gn
index 8bfda8d..c361555 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -724,8 +724,6 @@
"src/js/macros.py",
"src/message-template.h",
"src/js/prologue.js",
- "src/js/array.js",
- "src/js/typedarray.js",
]
outputs = [
diff --git a/src/bootstrapper.cc b/src/bootstrapper.cc
index b5231fb..e614189 100644
--- a/src/bootstrapper.cc
+++ b/src/bootstrapper.cc
@@ -1629,6 +1629,7 @@
*info);
}
+ Handle<JSFunction> array_prototype_to_string_fun;
{ // --- A r r a y ---
Handle<JSFunction> array_function = InstallFunction(
isolate_, global, "Array", JS_ARRAY_TYPE, JSArray::kSize, 0,
@@ -1745,8 +1746,9 @@
Builtins::kArrayReduceRight, 1, false);
SimpleInstallFunction(isolate_, proto, "toLocaleString",
Builtins::kArrayPrototypeToLocaleString, 0, false);
- SimpleInstallFunction(isolate_, proto, "toString",
- Builtins::kArrayPrototypeToString, 0, false);
+ array_prototype_to_string_fun =
+ SimpleInstallFunction(isolate_, proto, "toString",
+ Builtins::kArrayPrototypeToString, 0, false);
}
{ // --- A r r a y I t e r a t o r ---
@@ -3201,6 +3203,8 @@
Builtins::kTypedArrayPrototypeIncludes, 1, false);
SimpleInstallFunction(isolate_, prototype, "indexOf",
Builtins::kTypedArrayPrototypeIndexOf, 1, false);
+ SimpleInstallFunction(isolate_, prototype, "join",
+ Builtins::kTypedArrayPrototypeJoin, 1, false);
SimpleInstallFunction(isolate_, prototype, "lastIndexOf",
Builtins::kTypedArrayPrototypeLastIndexOf, 1, false);
SimpleInstallFunction(isolate_, prototype, "map",
@@ -3221,6 +3225,11 @@
Builtins::kTypedArrayPrototypeSort, 1, false);
SimpleInstallFunction(isolate_, prototype, "subarray",
Builtins::kTypedArrayPrototypeSubArray, 2, false);
+ SimpleInstallFunction(isolate_, prototype, "toLocaleString",
+ Builtins::kTypedArrayPrototypeToLocaleString, 0,
+ false);
+ JSObject::AddProperty(isolate_, prototype, factory->toString_string(),
+ array_prototype_to_string_fun, DONT_ENUM);
}
{ // -- T y p e d A r r a y s
diff --git a/src/builtins/array-join.tq b/src/builtins/array-join.tq
index 4f5cee9..f331f8b 100644
--- a/src/builtins/array-join.tq
+++ b/src/builtins/array-join.tq
@@ -55,6 +55,14 @@
}
}
+ builtin LoadJoinTypedElement<T: type>(
+ context: Context, receiver: JSReceiver, k: Number): Object {
+ const typedArray: JSTypedArray = UnsafeCast<JSTypedArray>(receiver);
+ return typed_array::LoadFixedTypedArrayElementAsTagged(
+ typedArray.data_ptr, UnsafeCast<Smi>(k),
+ typed_array::KindForArrayType<T>(), SMI_PARAMETERS);
+ }
+
transitioning builtin ConvertToLocaleString(
context: Context, element: Object, locales: Object,
options: Object): String {
@@ -80,9 +88,17 @@
// Verifies the current element JSArray accessor can still be safely used
// (see LoadJoinElement<ElementsAccessor>).
- macro CannotUseSameArrayAccessor(implicit context: Context)(
- originalMap: Object, originalLen: Object, receiver: JSReceiver): never
+ macro CannotUseSameArrayAccessor<T: type>(implicit context: Context)(
+ loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map,
+ originalLen: Number): never
+ labels Cannot, Can;
+
+ CannotUseSameArrayAccessor<JSArray>(implicit context: Context)(
+ loadFn: LoadJoinElementFn, receiver: JSReceiver, originalMap: Map,
+ originalLen: Number): never
labels Cannot, Can {
+ if (loadFn == LoadJoinElement<GenericElementsAccessor>) goto Can;
+
const array: JSArray = UnsafeCast<JSArray>(receiver);
if (originalMap != array.map) goto Cannot;
if (originalLen != array.length) goto Cannot;
@@ -90,6 +106,18 @@
goto Can;
}
+ CannotUseSameArrayAccessor<JSTypedArray>(implicit context: Context)(
+ loadFn: LoadJoinElementFn, receiver: JSReceiver, initialMap: Map,
+ initialLen: Number): never
+ labels Cannot, Can {
+ // It is assumed that neither loading a typed array element nor converting a
+ // number to string have side-effects. As such, it safe to use the initial
+ // LoadJoinElement specialization and it cannot change through out the join
+ // call.
+ assert(!IsDetachedBuffer(UnsafeCast<JSTypedArray>(receiver).buffer));
+ goto Can;
+ }
+
// Calculates the running total length of the resulting string. If the
// calculated length exceeds the maximum string length (see
// String::kMaxLength), throws a range error.
@@ -245,15 +273,15 @@
buffer.fixedArray, buffer.index, sep, r);
}
- transitioning macro ArrayJoinImpl(
- context: Context, receiver: JSReceiver, sep: String, lengthNumber: Number,
+ transitioning macro ArrayJoinImpl<T: type>(implicit context: Context)(
+ receiver: JSReceiver, sep: String, lengthNumber: Number,
useToLocaleString: constexpr bool, locales: Object, options: Object,
- initialLoadJoinElement: LoadJoinElementFn): String {
+ initialLoadFn: LoadJoinElementFn): String {
const initialMap: Map = receiver.map;
const len: uintptr = Convert<uintptr>(lengthNumber);
const separatorLength: intptr = sep.length;
let nofSeparators: intptr = 0;
- let loadJoinElements: LoadJoinElementFn = initialLoadJoinElement;
+ let loadFn: LoadJoinElementFn = initialLoadFn;
let buffer: Buffer = BufferInit(len, sep);
// 6. Let k be 0.
@@ -264,20 +292,15 @@
if (k > 0) {
// a. If k > 0, let R be the string-concatenation of R and sep.
nofSeparators = nofSeparators + 1;
-
- // Verify the current LoadJoinElement specialization can safely be
- // used. Otherwise, fall back to generic element access (see
- // LoadJoinElement<GenericElementsAccessor>).
- if (loadJoinElements != LoadJoinElement<GenericElementsAccessor>&&
- CannotUseSameArrayAccessor(initialMap, lengthNumber, receiver))
+ if (CannotUseSameArrayAccessor<T>(
+ loadFn, receiver, initialMap, lengthNumber))
deferred {
- loadJoinElements = LoadJoinElement<GenericElementsAccessor>;
+ loadFn = LoadJoinElement<GenericElementsAccessor>;
}
}
// b. Let element be ? Get(O, ! ToString(k)).
- const element: Object =
- loadJoinElements(context, receiver, Convert<Number>(k++));
+ const element: Object = loadFn(context, receiver, Convert<Number>(k++));
// c. If element is undefined or null, let next be the empty String;
// otherwise, let next be ? ToString(element).
@@ -313,12 +336,16 @@
return BufferJoin(buffer, sep);
}
- transitioning macro ArrayJoin(implicit context: Context)(
+ transitioning macro ArrayJoin<T: type>(implicit context: Context)(
+ useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String,
+ lenNumber: Number, locales: Object, options: Object): Object;
+
+ ArrayJoin<JSArray>(implicit context: Context)(
useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String,
lenNumber: Number, locales: Object, options: Object): Object {
const map: Map = receiver.map;
const kind: ElementsKind = map.elements_kind;
- let loadJoinElements: LoadJoinElementFn;
+ let loadFn: LoadJoinElementFn;
try {
const array: JSArray = Cast<JSArray>(receiver) otherwise IfSlowPath;
@@ -327,9 +354,9 @@
if (IsNoElementsProtectorCellInvalid()) goto IfSlowPath;
if (IsElementsKindLessThanOrEqual(kind, HOLEY_ELEMENTS)) {
- loadJoinElements = LoadJoinElement<FastSmiOrObjectElements>;
+ loadFn = LoadJoinElement<FastSmiOrObjectElements>;
} else if (IsElementsKindLessThanOrEqual(kind, HOLEY_DOUBLE_ELEMENTS)) {
- loadJoinElements = LoadJoinElement<FastDoubleElements>;
+ loadFn = LoadJoinElement<FastDoubleElements>;
} else if (kind == DICTIONARY_ELEMENTS)
deferred {
const dict: NumberDictionary =
@@ -346,7 +373,7 @@
ThrowInvalidStringLength(context);
}
} else {
- loadJoinElements = LoadJoinElement<DictionaryElements>;
+ loadFn = LoadJoinElement<DictionaryElements>;
}
}
else {
@@ -354,11 +381,52 @@
}
}
label IfSlowPath {
- loadJoinElements = LoadJoinElement<GenericElementsAccessor>;
+ loadFn = LoadJoinElement<GenericElementsAccessor>;
}
- return ArrayJoinImpl(
- context, receiver, sep, lenNumber, useToLocaleString, locales, options,
- loadJoinElements);
+ return ArrayJoinImpl<JSArray>(
+ receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn);
+ }
+
+ ArrayJoin<JSTypedArray>(implicit context: Context)(
+ useToLocaleString: constexpr bool, receiver: JSReceiver, sep: String,
+ lenNumber: Number, locales: Object, options: Object): Object {
+ const map: Map = receiver.map;
+ const kind: ElementsKind = map.elements_kind;
+ let loadFn: LoadJoinElementFn;
+
+ if (IsElementsKindGreaterThan(kind, UINT32_ELEMENTS)) {
+ if (kind == INT32_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedInt32Array>;
+ } else if (kind == FLOAT32_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedFloat32Array>;
+ } else if (kind == FLOAT64_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedFloat64Array>;
+ } else if (kind == UINT8_CLAMPED_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedUint8ClampedArray>;
+ } else if (kind == BIGUINT64_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedBigUint64Array>;
+ } else if (kind == BIGINT64_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedBigInt64Array>;
+ } else {
+ unreachable;
+ }
+ } else {
+ if (kind == UINT8_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedUint8Array>;
+ } else if (kind == INT8_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedInt8Array>;
+ } else if (kind == UINT16_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedUint16Array>;
+ } else if (kind == INT16_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedInt16Array>;
+ } else if (kind == UINT32_ELEMENTS) {
+ loadFn = LoadJoinTypedElement<FixedUint32Array>;
+ } else {
+ unreachable;
+ }
+ }
+ return ArrayJoinImpl<JSTypedArray>(
+ receiver, sep, lenNumber, useToLocaleString, locales, options, loadFn);
}
// The Join Stack detects cyclical calls to Array Join builtins
@@ -474,18 +542,10 @@
}
// Main entry point for all builtins using Array Join functionality.
- transitioning macro CycleProtectedArrayJoin(implicit context: Context)(
- useToLocaleString: constexpr bool, receiver: Object, sepObj: Object,
- locales: Object, options: Object): Object {
- // 1. Let O be ? ToObject(this value).
- const o: JSReceiver = ToObject_Inline(context, receiver);
-
- // 2. Let len be ? ToLength(? Get(O, "length")).
- const len: Number = GetLengthProperty(o);
- // Only handle valid array lengths. Although the spec allows larger values,
- // this matches historical V8 behavior.
- if (len > kMaxArrayIndex + 1) ThrowTypeError(context, kInvalidArrayLength);
-
+ transitioning macro CycleProtectedArrayJoin<T: type>(implicit context:
+ Context)(
+ useToLocaleString: constexpr bool, o: JSReceiver, len: Number,
+ sepObj: Object, locales: Object, options: Object): Object {
// 3. If separator is undefined, let sep be the single-element String ",".
// 4. Else, let sep be ? ToString(separator).
let sep: String =
@@ -496,7 +556,7 @@
if (len > 0 && JoinStackPushInline(o)) {
try {
const result: Object =
- ArrayJoin(useToLocaleString, o, sep, len, locales, options);
+ ArrayJoin<T>(useToLocaleString, o, sep, len, locales, options);
JoinStackPopInline(o);
return result;
} catch (e) deferred {
@@ -512,19 +572,42 @@
transitioning javascript builtin
ArrayPrototypeJoin(context: Context, receiver: Object, ...arguments): Object {
const separator: Object = arguments[0];
- return CycleProtectedArrayJoin(
- false, receiver, separator, Undefined, Undefined);
+
+ // 1. Let O be ? ToObject(this value).
+ const o: JSReceiver = ToObject_Inline(context, receiver);
+
+ // 2. Let len be ? ToLength(? Get(O, "length")).
+ const len: Number = GetLengthProperty(o);
+
+ // Only handle valid array lengths. Although the spec allows larger values,
+ // this matches historical V8 behavior.
+ if (len > kMaxArrayIndex + 1) ThrowTypeError(context, kInvalidArrayLength);
+
+ return CycleProtectedArrayJoin<JSArray>(
+ false, o, len, separator, Undefined, Undefined);
}
- // https://tc39.github.io/ecma262/#sec-array.prototype.toLocaleString
+ // https://tc39.github.io/ecma262/#sec-array.prototype.tolocalestring
transitioning javascript builtin ArrayPrototypeToLocaleString(
context: Context, receiver: Object, ...arguments): Object {
const locales: Object = arguments[0];
const options: Object = arguments[1];
- return CycleProtectedArrayJoin(true, receiver, ',', locales, options);
+
+ // 1. Let O be ? ToObject(this value).
+ const o: JSReceiver = ToObject_Inline(context, receiver);
+
+ // 2. Let len be ? ToLength(? Get(O, "length")).
+ const len: Number = GetLengthProperty(o);
+
+ // Only handle valid array lengths. Although the spec allows larger values,
+ // this matches historical V8 behavior.
+ if (len > kMaxArrayIndex + 1) ThrowTypeError(context, kInvalidArrayLength);
+
+ return CycleProtectedArrayJoin<JSArray>(
+ true, o, len, ',', locales, options);
}
- // https://tc39.github.io/ecma262/#sec-array.prototype.toString
+ // https://tc39.github.io/ecma262/#sec-array.prototype.tostring
transitioning javascript builtin ArrayPrototypeToString(
context: Context, receiver: Object, ...arguments): Object {
// 1. Let array be ? ToObject(this value).
@@ -544,4 +627,35 @@
return ObjectToString(context, array);
}
}
+
+ // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.join
+ transitioning javascript builtin TypedArrayPrototypeJoin(
+ context: Context, receiver: Object, ...arguments): Object {
+ const separator: Object = arguments[0];
+
+ // Spec: ValidateTypedArray is applied to the this value prior to evaluating
+ // the algorithm.
+ const typedArray: JSTypedArray = typed_array::ValidateTypedArray(
+ context, receiver, '%TypedArray%.prototype.join');
+ const length: Smi = typedArray.length;
+
+ return CycleProtectedArrayJoin<JSTypedArray>(
+ false, typedArray, length, separator, Undefined, Undefined);
+ }
+
+ // https://tc39.github.io/ecma262/#sec-%typedarray%.prototype.tolocalestring
+ transitioning javascript builtin TypedArrayPrototypeToLocaleString(
+ context: Context, receiver: Object, ...arguments): Object {
+ const locales: Object = arguments[0];
+ const options: Object = arguments[1];
+
+ // Spec: ValidateTypedArray is applied to the this value prior to evaluating
+ // the algorithm.
+ const typedArray: JSTypedArray = typed_array::ValidateTypedArray(
+ context, receiver, '%TypedArray%.prototype.toLocaleString');
+ const length: Smi = typedArray.length;
+
+ return CycleProtectedArrayJoin<JSTypedArray>(
+ true, typedArray, length, ',', locales, options);
+ }
}
diff --git a/src/builtins/base.tq b/src/builtins/base.tq
index 3f10bb2..b145e4a 100644
--- a/src/builtins/base.tq
+++ b/src/builtins/base.tq
@@ -322,7 +322,6 @@
Context, constexpr MessageTemplate, Object, Object, Object): never;
extern macro ArraySpeciesCreate(Context, Object, Number): JSReceiver;
extern macro ArrayCreate(implicit context: Context)(Number): JSArray;
-extern macro InternalArrayCreate(Context, Number): JSArray;
extern macro EnsureArrayPushable(Map): ElementsKind
labels Bailout;
extern macro EnsureArrayLengthWritable(Map) labels Bailout;
@@ -526,6 +525,8 @@
extern macro HeapObjectToJSDataView(HeapObject): JSDataView
labels CastError;
+extern macro HeapObjectToJSTypedArray(HeapObject): JSTypedArray
+ labels CastError;
extern macro TaggedToHeapObject(Object): HeapObject
labels CastError;
extern macro TaggedToSmi(Object): Smi
@@ -578,6 +579,12 @@
return HeapObjectToJSDataView(o) otherwise CastError;
}
+CastHeapObject<JSTypedArray>(o: HeapObject): JSTypedArray
+ labels CastError {
+ if (IsJSTypedArray(o)) return %RawObjectCast<JSTypedArray>(o);
+ goto CastError;
+}
+
CastHeapObject<Callable>(o: HeapObject): Callable
labels CastError {
return HeapObjectToCallable(o) otherwise CastError;
@@ -1180,6 +1187,7 @@
extern macro IsMap(HeapObject): bool;
extern macro IsJSFunction(HeapObject): bool;
extern macro IsJSObject(HeapObject): bool;
+extern macro IsJSTypedArray(HeapObject): bool;
extern macro IsNumberDictionary(HeapObject): bool;
extern macro IsFixedTypedArray(HeapObject): bool;
extern macro IsContext(HeapObject): bool;
diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
index c676cf4..0d57139 100644
--- a/src/code-stub-assembler.cc
+++ b/src/code-stub-assembler.cc
@@ -12928,14 +12928,6 @@
return Construct(context, constructor, len);
}
-TNode<JSReceiver> CodeStubAssembler::InternalArrayCreate(TNode<Context> context,
- TNode<Number> len) {
- TNode<Context> native_context = LoadNativeContext(context);
- TNode<JSReceiver> constructor = CAST(LoadContextElement(
- native_context, Context::INTERNAL_ARRAY_FUNCTION_INDEX));
- return Construct(context, constructor, len);
-}
-
Node* CodeStubAssembler::IsDetachedBuffer(Node* buffer) {
CSA_ASSERT(this, HasInstanceType(buffer, JS_ARRAY_BUFFER_TYPE));
TNode<Uint32T> buffer_bit_field = LoadJSArrayBufferBitField(CAST(buffer));
diff --git a/src/code-stub-assembler.h b/src/code-stub-assembler.h
index 1369841..998c05a 100644
--- a/src/code-stub-assembler.h
+++ b/src/code-stub-assembler.h
@@ -1516,8 +1516,6 @@
TNode<JSReceiver> ArraySpeciesCreate(TNode<Context> context,
TNode<Object> originalArray,
TNode<Number> len);
- TNode<JSReceiver> InternalArrayCreate(TNode<Context> context,
- TNode<Number> len);
void FillFixedArrayWithValue(ElementsKind kind, Node* array, Node* from_index,
Node* to_index, RootIndex value_root_index,
diff --git a/src/js/array.js b/src/js/array.js
deleted file mode 100644
index 6945ad9..0000000
--- a/src/js/array.js
+++ /dev/null
@@ -1,478 +0,0 @@
-// Copyright 2012 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.
-
-(function(global, utils, extrasUtils) {
-
-"use strict";
-
-%CheckIsBootstrapping();
-
-// -------------------------------------------------------------------
-// Imports
-
-var GlobalArray = global.Array;
-var InternalArray = utils.InternalArray;
-var ObjectToString = global.Object.prototype.toString;
-var iteratorSymbol = utils.ImportNow("iterator_symbol");
-var unscopablesSymbol = utils.ImportNow("unscopables_symbol");
-
-// -------------------------------------------------------------------
-
-macro INVERT_NEG_ZERO(arg)
-((arg) + 0)
-endmacro
-
-function ArraySpeciesCreate(array, length) {
- length = INVERT_NEG_ZERO(length);
- var constructor = %ArraySpeciesConstructor(array);
- return new constructor(length);
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function KeySortCompare(a, b) {
- return a - b;
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function GetSortedArrayKeys(array, indices) {
- if (IS_NUMBER(indices)) {
- // It's an interval
- var limit = indices;
- var keys = new InternalArray();
- for (var i = 0; i < limit; ++i) {
- var e = array[i];
- if (!IS_UNDEFINED(e) || i in array) {
- keys.push(i);
- }
- }
- return keys;
- }
- return InnerArraySort(indices, indices.length, KeySortCompare);
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function SparseJoinWithSeparatorJS(
- array, keys, length, use_locale, separator, locales, options) {
- var keys_length = keys.length;
- var elements = new InternalArray(keys_length * 2);
- for (var i = 0; i < keys_length; i++) {
- var key = keys[i];
- elements[i * 2] = key;
- elements[i * 2 + 1] = ConvertToString(
- use_locale, array[key], locales, options);
- }
- return %SparseJoinWithSeparator(elements, length, separator);
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-// Optimized for sparse arrays if separator is ''.
-function SparseJoin(array, keys, use_locale, locales, options) {
- var keys_length = keys.length;
- var elements = new InternalArray(keys_length);
- for (var i = 0; i < keys_length; i++) {
- elements[i] = ConvertToString(use_locale, array[keys[i]], locales, options);
- }
- return %StringBuilderConcat(elements, keys_length, '');
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function UseSparseVariant(array, length, is_array, touched) {
- // Only use the sparse variant on arrays that are likely to be sparse and the
- // number of elements touched in the operation is relatively small compared to
- // the overall size of the array.
- if (!is_array || length < 1000 || %HasComplexElements(array)) {
- return false;
- }
- if (!%_IsSmi(length)) {
- return true;
- }
- var elements_threshold = length >> 2; // No more than 75% holes
- var estimated_elements = %EstimateNumberOfElements(array);
- return (estimated_elements < elements_threshold) &&
- (touched > estimated_elements * 4);
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function Stack() {
- this.length = 0;
- this.values = new InternalArray();
-}
-
-// Predeclare the instance variables on the prototype. Otherwise setting them in
-// the constructor will leak the instance through settings on Object.prototype.
-Stack.prototype.length = null;
-Stack.prototype.values = null;
-
-function StackPush(stack, value) {
- stack.values[stack.length++] = value;
-}
-
-function StackPop(stack) {
- stack.values[--stack.length] = null
-}
-
-function StackHas(stack, v) {
- var length = stack.length;
- var values = stack.values;
- for (var i = 0; i < length; i++) {
- if (values[i] === v) return true;
- }
- return false;
-}
-
-// Global list of arrays visited during toString, toLocaleString and
-// join invocations.
-var visited_arrays = new Stack();
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function DoJoin(
- array, length, is_array, separator, use_locale, locales, options) {
- if (UseSparseVariant(array, length, is_array, length)) {
- %NormalizeElements(array);
- var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, length));
- if (separator === '') {
- if (keys.length === 0) return '';
- return SparseJoin(array, keys, use_locale, locales, options);
- } else {
- return SparseJoinWithSeparatorJS(
- array, keys, length, use_locale, separator, locales, options);
- }
- }
-
- // Fast case for one-element arrays.
- if (length === 1) {
- return ConvertToString(use_locale, array[0], locales, options);
- }
-
- // Construct an array for the elements.
- var elements = new InternalArray(length);
- for (var i = 0; i < length; i++) {
- elements[i] = ConvertToString(use_locale, array[i], locales, options);
- }
-
- if (separator === '') {
- return %StringBuilderConcat(elements, length, '');
- } else {
- return %StringBuilderJoin(elements, length, separator);
- }
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function Join(array, length, separator, use_locale, locales, options) {
- if (length === 0) return '';
-
- var is_array = IS_ARRAY(array);
-
- if (is_array) {
- // If the array is cyclic, return the empty string for already
- // visited arrays.
- if (StackHas(visited_arrays, array)) return '';
- StackPush(visited_arrays, array);
- }
-
- // Attempt to convert the elements.
- try {
- return DoJoin(
- array, length, is_array, separator, use_locale, locales, options);
- } finally {
- // Make sure to remove the last element of the visited array no
- // matter what happens.
- if (is_array) StackPop(visited_arrays);
- }
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function ConvertToString(use_locale, x, locales, options) {
- if (IS_NULL_OR_UNDEFINED(x)) return '';
- if (use_locale) {
- if (IS_NULL_OR_UNDEFINED(locales)) {
- return TO_STRING(x.toLocaleString());
- } else if (IS_NULL_OR_UNDEFINED(options)) {
- return TO_STRING(x.toLocaleString(locales));
- }
- return TO_STRING(x.toLocaleString(locales, options));
- }
-
- return TO_STRING(x);
-}
-
-
-// -------------------------------------------------------------------
-
-// ecma402 #sup-array.prototype.tolocalestring
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function InnerArrayToLocaleString(array, length, locales, options) {
- return Join(array, TO_LENGTH(length), ',', true, locales, options);
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function InnerArrayJoin(separator, array, length) {
- if (IS_UNDEFINED(separator)) {
- separator = ',';
- } else {
- separator = TO_STRING(separator);
- }
-
- // Fast case for one-element arrays.
- if (length === 1) {
- var e = array[0];
- if (IS_NULL_OR_UNDEFINED(e)) return '';
- return TO_STRING(e);
- }
-
- return Join(array, length, separator, false);
-}
-
-
-
-
-// Oh the humanity... don't remove the following function because js2c for some
-// reason gets symbol minifiation wrong if it's not there. Instead of spending
-// the time fixing js2c (which will go away when all of the internal .js runtime
-// files are gone), just keep this work-around.
-function ArraySliceFallback(start, end) {
- return null;
-}
-
-// TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
-function InnerArraySort(array, length, comparefn) {
- // In-place QuickSort algorithm.
- // For short (length <= 10) arrays, insertion sort is used for efficiency.
-
- if (!IS_CALLABLE(comparefn)) {
- comparefn = function (x, y) {
- if (x === y) return 0;
- if (%_IsSmi(x) && %_IsSmi(y)) {
- return %SmiLexicographicCompare(x, y);
- }
- x = TO_STRING(x);
- y = TO_STRING(y);
- if (x == y) return 0;
- else return x < y ? -1 : 1;
- };
- }
- function InsertionSort(a, from, to) {
- for (var i = from + 1; i < to; i++) {
- var element = a[i];
- for (var j = i - 1; j >= from; j--) {
- var tmp = a[j];
- var order = comparefn(tmp, element);
- if (order > 0) {
- a[j + 1] = tmp;
- } else {
- break;
- }
- }
- a[j + 1] = element;
- }
- };
-
- function GetThirdIndex(a, from, to) {
- var t_array = new InternalArray();
- // Use both 'from' and 'to' to determine the pivot candidates.
- var increment = 200 + ((to - from) & 15);
- var j = 0;
- from += 1;
- to -= 1;
- for (var i = from; i < to; i += increment) {
- t_array[j] = [i, a[i]];
- j++;
- }
- t_array.sort(function(a, b) {
- return comparefn(a[1], b[1]);
- });
- var third_index = t_array[t_array.length >> 1][0];
- return third_index;
- }
-
- function QuickSort(a, from, to) {
- var third_index = 0;
- while (true) {
- // Insertion sort is faster for short arrays.
- if (to - from <= 10) {
- InsertionSort(a, from, to);
- return;
- }
- if (to - from > 1000) {
- third_index = GetThirdIndex(a, from, to);
- } else {
- third_index = from + ((to - from) >> 1);
- }
- // Find a pivot as the median of first, last and middle element.
- var v0 = a[from];
- var v1 = a[to - 1];
- var v2 = a[third_index];
- var c01 = comparefn(v0, v1);
- if (c01 > 0) {
- // v1 < v0, so swap them.
- var tmp = v0;
- v0 = v1;
- v1 = tmp;
- } // v0 <= v1.
- var c02 = comparefn(v0, v2);
- if (c02 >= 0) {
- // v2 <= v0 <= v1.
- var tmp = v0;
- v0 = v2;
- v2 = v1;
- v1 = tmp;
- } else {
- // v0 <= v1 && v0 < v2
- var c12 = comparefn(v1, v2);
- if (c12 > 0) {
- // v0 <= v2 < v1
- var tmp = v1;
- v1 = v2;
- v2 = tmp;
- }
- }
- // v0 <= v1 <= v2
- a[from] = v0;
- a[to - 1] = v2;
- var pivot = v1;
- var low_end = from + 1; // Upper bound of elements lower than pivot.
- var high_start = to - 1; // Lower bound of elements greater than pivot.
- a[third_index] = a[low_end];
- a[low_end] = pivot;
-
- // From low_end to i are elements equal to pivot.
- // From i to high_start are elements that haven't been compared yet.
- partition: for (var i = low_end + 1; i < high_start; i++) {
- var element = a[i];
- var order = comparefn(element, pivot);
- if (order < 0) {
- a[i] = a[low_end];
- a[low_end] = element;
- low_end++;
- } else if (order > 0) {
- do {
- high_start--;
- if (high_start == i) break partition;
- var top_elem = a[high_start];
- order = comparefn(top_elem, pivot);
- } while (order > 0);
- a[i] = a[high_start];
- a[high_start] = element;
- if (order < 0) {
- element = a[i];
- a[i] = a[low_end];
- a[low_end] = element;
- low_end++;
- }
- }
- }
- if (to - high_start < low_end - from) {
- QuickSort(a, high_start, to);
- to = low_end;
- } else {
- QuickSort(a, from, low_end);
- from = high_start;
- }
- }
- };
-
- if (length < 2) return array;
-
- // For compatibility with JSC, we also sort elements inherited from
- // the prototype chain on non-Array objects.
- // We do this by copying them to this object and sorting only
- // own elements. This is not very efficient, but sorting with
- // inherited elements happens very, very rarely, if at all.
- // The specification allows "implementation dependent" behavior
- // if an element on the prototype chain has an element that
- // might interact with sorting.
- //
- // We also move all non-undefined elements to the front of the
- // array and move the undefineds after that. Holes are removed.
- // This happens for Array as well as non-Array objects.
- var num_non_undefined = %PrepareElementsForSort(array, length);
-
- QuickSort(array, 0, num_non_undefined);
-
- return array;
-}
-
-
-// Set up unscopable properties on the Array.prototype object.
-var unscopables = {
- __proto__: null,
- copyWithin: true,
- entries: true,
- fill: true,
- find: true,
- findIndex: true,
- includes: true,
- keys: true,
-};
-
-%ToFastProperties(unscopables);
-
-%AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
- DONT_ENUM | READ_ONLY);
-
-var ArrayIndexOf = GlobalArray.prototype.indexOf;
-var ArrayJoin = GlobalArray.prototype.join;
-var ArrayPop = GlobalArray.prototype.pop;
-var ArrayPush = GlobalArray.prototype.push;
-var ArraySlice = GlobalArray.prototype.slice;
-var ArrayShift = GlobalArray.prototype.shift;
-var ArraySort = GlobalArray.prototype.sort;
-var ArraySplice = GlobalArray.prototype.splice;
-var ArrayToString = GlobalArray.prototype.toString;
-var ArrayUnshift = GlobalArray.prototype.unshift;
-
-// Array prototype functions that return iterators. They are exposed to the
-// public API via Template::SetIntrinsicDataProperty().
-var ArrayEntries = GlobalArray.prototype.entries;
-var ArrayForEach = GlobalArray.prototype.forEach;
-var ArrayKeys = GlobalArray.prototype.keys;
-var ArrayValues = GlobalArray.prototype[iteratorSymbol];
-
-
-// The internal Array prototype doesn't need to be fancy, since it's never
-// exposed to user code.
-// Adding only the functions that are actually used.
-utils.SetUpLockedPrototype(InternalArray, GlobalArray(), [
- "indexOf", ArrayIndexOf,
- "join", ArrayJoin,
- "pop", ArrayPop,
- "push", ArrayPush,
- "shift", ArrayShift,
- "sort", ArraySort,
- "splice", ArraySplice
-]);
-
-// V8 extras get a separate copy of InternalPackedArray. We give them the basic
-// manipulation methods.
-utils.SetUpLockedPrototype(extrasUtils.InternalPackedArray, GlobalArray(), [
- "push", ArrayPush,
- "pop", ArrayPop,
- "shift", ArrayShift,
- "unshift", ArrayUnshift,
- "splice", ArraySplice,
- "slice", ArraySlice
-]);
-
-// -------------------------------------------------------------------
-// Exports
-
-utils.Export(function(to) {
- to.ArrayJoin = ArrayJoin;
- to.ArrayPush = ArrayPush;
- to.ArrayToString = ArrayToString;
- to.ArrayValues = ArrayValues;
- // TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
- to.InnerArrayJoin = InnerArrayJoin;
- // TODO(pwong): Remove once TypedArray.prototype.join() is ported to Torque.
- to.InnerArrayToLocaleString = InnerArrayToLocaleString;
-});
-
-%InstallToContext([
- "array_entries_iterator", ArrayEntries,
- "array_for_each_iterator", ArrayForEach,
- "array_keys_iterator", ArrayKeys,
- "array_values_iterator", ArrayValues,
-]);
-
-});
diff --git a/src/js/prologue.js b/src/js/prologue.js
index d3c3463..ebd669f 100644
--- a/src/js/prologue.js
+++ b/src/js/prologue.js
@@ -68,6 +68,8 @@
%ToFastProperties(prototype);
}
+var GlobalArray = global.Array;
+var InternalArray;
// -----------------------------------------------------------------------
// To be called by bootstrapper
@@ -75,6 +77,81 @@
function PostNatives(utils) {
%CheckIsBootstrapping();
+ // -------------------------------------------------------------------
+ // Array
+
+ InternalArray = utils.InternalArray;
+ var iteratorSymbol = ImportNow("iterator_symbol");
+ var unscopablesSymbol = ImportNow("unscopables_symbol");
+
+ // Set up unscopable properties on the Array.prototype object.
+ var unscopables = {
+ __proto__: null,
+ copyWithin: true,
+ entries: true,
+ fill: true,
+ find: true,
+ findIndex: true,
+ includes: true,
+ keys: true,
+ };
+
+ %ToFastProperties(unscopables);
+
+ %AddNamedProperty(GlobalArray.prototype, unscopablesSymbol, unscopables,
+ DONT_ENUM | READ_ONLY);
+
+ var ArrayIndexOf = GlobalArray.prototype.indexOf;
+ var ArrayJoin = GlobalArray.prototype.join;
+ var ArrayPop = GlobalArray.prototype.pop;
+ var ArrayPush = GlobalArray.prototype.push;
+ var ArraySlice = GlobalArray.prototype.slice;
+ var ArrayShift = GlobalArray.prototype.shift;
+ var ArraySort = GlobalArray.prototype.sort;
+ var ArraySplice = GlobalArray.prototype.splice;
+ var ArrayUnshift = GlobalArray.prototype.unshift;
+
+ // Array prototype functions that return iterators. They are exposed to the
+ // public API via Template::SetIntrinsicDataProperty().
+ var ArrayEntries = GlobalArray.prototype.entries;
+ var ArrayForEach = GlobalArray.prototype.forEach;
+ var ArrayKeys = GlobalArray.prototype.keys;
+ var ArrayValues = GlobalArray.prototype[iteratorSymbol];
+
+
+ // The internal Array prototype doesn't need to be fancy, since it's never
+ // exposed to user code.
+ // Adding only the functions that are actually used.
+ SetUpLockedPrototype(InternalArray, GlobalArray(), [
+ "indexOf", ArrayIndexOf,
+ "join", ArrayJoin,
+ "pop", ArrayPop,
+ "push", ArrayPush,
+ "shift", ArrayShift,
+ "sort", ArraySort,
+ "splice", ArraySplice
+ ]);
+
+ // V8 extras get a separate copy of InternalPackedArray. We give them the basic
+ // manipulation methods.
+ SetUpLockedPrototype(extrasUtils.InternalPackedArray, GlobalArray(), [
+ "push", ArrayPush,
+ "pop", ArrayPop,
+ "shift", ArrayShift,
+ "unshift", ArrayUnshift,
+ "splice", ArraySplice,
+ "slice", ArraySlice
+ ]);
+
+ %InstallToContext([
+ "array_entries_iterator", ArrayEntries,
+ "array_for_each_iterator", ArrayForEach,
+ "array_keys_iterator", ArrayKeys,
+ "array_values_iterator", ArrayValues,
+ ]);
+
+ // -------------------------------------------------------------------
+
for ( ; !IS_UNDEFINED(imports); imports = imports.next) {
imports(exports_container);
}
@@ -94,7 +171,6 @@
utils.Import = Import;
utils.ImportNow = ImportNow;
utils.Export = Export;
-utils.SetUpLockedPrototype = SetUpLockedPrototype;
utils.PostNatives = PostNatives;
%ToFastProperties(utils);
diff --git a/src/js/typedarray.js b/src/js/typedarray.js
deleted file mode 100644
index e1a4f19..0000000
--- a/src/js/typedarray.js
+++ /dev/null
@@ -1,93 +0,0 @@
-// Copyright 2013 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.
-
-(function(global, utils) {
-
-"use strict";
-
-%CheckIsBootstrapping();
-
-// -------------------------------------------------------------------
-// Imports
-
-// array.js has to come before typedarray.js for this to work
-var ArrayToString = utils.ImportNow("ArrayToString");
-var InnerArrayJoin;
-var InnerArrayToLocaleString;
-
-macro TYPED_ARRAYS(FUNCTION)
-FUNCTION(Uint8Array, 1)
-FUNCTION(Int8Array, 1)
-FUNCTION(Uint16Array, 2)
-FUNCTION(Int16Array, 2)
-FUNCTION(Uint32Array, 4)
-FUNCTION(Int32Array, 4)
-FUNCTION(Float32Array, 4)
-FUNCTION(Float64Array, 8)
-FUNCTION(Uint8ClampedArray, 1)
-FUNCTION(BigUint64Array, 8)
-FUNCTION(BigInt64Array, 8)
-endmacro
-
-macro DECLARE_GLOBALS(NAME, SIZE)
-var GlobalNAME = global.NAME;
-endmacro
-
-TYPED_ARRAYS(DECLARE_GLOBALS)
-
-macro IS_TYPEDARRAY(arg)
-(%_IsTypedArray(arg))
-endmacro
-
-var GlobalTypedArray = %object_get_prototype_of(GlobalUint8Array);
-
-utils.Import(function(from) {
- InnerArrayJoin = from.InnerArrayJoin;
- InnerArrayToLocaleString = from.InnerArrayToLocaleString;
-});
-
-// --------------- Typed Arrays ---------------------
-
-// ES6 section 22.2.3.5.1 ValidateTypedArray ( O )
-function ValidateTypedArray(array, methodName) {
- if (!IS_TYPEDARRAY(array)) throw %make_type_error(kNotTypedArray);
-
- if (%ArrayBufferViewWasDetached(array))
- throw %make_type_error(kDetachedOperation, methodName);
-}
-
-
-// ES6 section 22.2.3.27
-// ecma402 #sup-array.prototype.tolocalestring
-DEFINE_METHOD(
- GlobalTypedArray.prototype,
- toLocaleString() {
- ValidateTypedArray(this, "%TypedArray%.prototype.toLocaleString");
-
- var locales = arguments[0];
- var options = arguments[1];
- var length = %TypedArrayGetLength(this);
- return InnerArrayToLocaleString(this, length, locales, options);
- }
-);
-
-
-// ES6 section 22.2.3.14
-DEFINE_METHOD(
- GlobalTypedArray.prototype,
- join(separator) {
- ValidateTypedArray(this, "%TypedArray%.prototype.join");
-
- var length = %TypedArrayGetLength(this);
-
- return InnerArrayJoin(separator, this, length);
- }
-);
-
-// -------------------------------------------------------------------
-
-%AddNamedProperty(GlobalTypedArray.prototype, "toString", ArrayToString,
- DONT_ENUM);
-
-})
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 8026660..ec90ad9 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -4296,9 +4296,9 @@
CHECK_EQ(count_by_type[i::Script::TYPE_WASM], 0);
CHECK_EQ(count_by_type[i::Script::TYPE_INSPECTOR], 0);
- i::Handle<i::Script> native_array_script =
- FindScript(i_isolate, scripts, "native array.js").ToHandleChecked();
- CHECK_EQ(native_array_script->type(), i::Script::TYPE_NATIVE);
+ i::Handle<i::Script> native_prologue_script =
+ FindScript(i_isolate, scripts, "native prologue.js").ToHandleChecked();
+ CHECK_EQ(native_prologue_script->type(), i::Script::TYPE_NATIVE);
i::Handle<i::Script> gc_script =
FindScript(i_isolate, scripts, "v8/gc").ToHandleChecked();