}
-function SparseJoinWithSeparator(array, len, convert, separator) {
+function SparseJoinWithSeparatorJS(array, len, convert, separator) {
var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len));
var totalLength = 0;
var elements = new InternalArray(keys.length * 2);
}
-function UseSparseVariant(object, length, is_array) {
- return is_array &&
- length > 1000 &&
- (!%_IsSmi(length) ||
- %EstimateNumberOfElements(object) < (length >> 2));
+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 || %IsObserved(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);
}
// Attempt to convert the elements.
try {
- if (UseSparseVariant(array, length, is_array)) {
+ if (UseSparseVariant(array, length, is_array, length)) {
+ %NormalizeElements(array);
if (separator.length == 0) {
return SparseJoin(array, length, convert);
} else {
- return SparseJoinWithSeparator(array, length, convert, separator);
+ return SparseJoinWithSeparatorJS(array, length, convert, separator);
}
}
elements[elements_length++] = e;
}
elements.length = elements_length;
- var result = %_FastAsciiArrayJoin(elements, '');
+ var result = %_FastOneByteArrayJoin(elements, '');
if (!IS_UNDEFINED(result)) return result;
return %StringBuilderConcat(elements, elements_length, '');
}
elements[i] = e;
}
}
- var result = %_FastAsciiArrayJoin(elements, separator);
+ var result = %_FastOneByteArrayJoin(elements, separator);
if (!IS_UNDEFINED(result)) return result;
return %StringBuilderJoin(elements, length, separator);
function SimpleSlice(array, start_i, del_count, len, deleted_elements) {
for (var i = 0; i < del_count; i++) {
var index = start_i + i;
- // The spec could also be interpreted such that %HasLocalProperty
+ // The spec could also be interpreted such that %HasOwnProperty
// would be the appropriate test. We follow KJS in consulting the
// prototype.
var current = array[index];
var from_index = i + del_count - 1;
var to_index = i + num_additional_args - 1;
// The spec could also be interpreted such that
- // %HasLocalProperty would be the appropriate test. We follow
+ // %HasOwnProperty would be the appropriate test. We follow
// KJS in consulting the prototype.
var current = array[from_index];
if (!IS_UNDEFINED(current) || from_index in array) {
var from_index = i + del_count;
var to_index = i + num_additional_args;
// The spec could also be interpreted such that
- // %HasLocalProperty would be the appropriate test. We follow
+ // %HasOwnProperty would be the appropriate test. We follow
// KJS in consulting the prototype.
var current = array[from_index];
if (!IS_UNDEFINED(current) || from_index in array) {
separator = NonStringToString(separator);
}
- var result = %_FastAsciiArrayJoin(array, separator);
+ var result = %_FastOneByteArrayJoin(array, separator);
if (!IS_UNDEFINED(result)) return result;
return Join(array, length, separator, ConvertToString);
var m = %_ArgumentsLength();
for (var i = 0; i < m; i++) {
- // Use SetProperty rather than a direct keyed store to ensure that the store
- // site doesn't become poisened with an elements transition KeyedStoreIC.
- %SetProperty(array, i+n, %_Arguments(i), 0, kStrictMode);
+ array[i+n] = %_Arguments(i);
}
var new_length = n + m;
// Returns an array containing the array elements of the object followed
// by the array elements of each argument in order. See ECMA-262,
// section 15.4.4.7.
-function ArrayConcat(arg1) { // length == 1
+function ArrayConcatJS(arg1) { // length == 1
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.concat");
var array = ToObject(this);
CHECK_OBJECT_COERCIBLE(this, "Array.prototype.reverse");
var array = TO_OBJECT_INLINE(this);
- var j = TO_UINT32(array.length) - 1;
+ var len = TO_UINT32(array.length);
- if (UseSparseVariant(array, j, IS_ARRAY(array))) {
- SparseReverse(array, j+1);
+ if (UseSparseVariant(array, len, IS_ARRAY(array), len)) {
+ %NormalizeElements(array);
+ SparseReverse(array, len);
return array;
}
+ var j = len - 1;
for (var i = 0; i < j; i++, j--) {
var current_i = array[i];
if (!IS_UNDEFINED(current_i) || i in array) {
var num_arguments = %_ArgumentsLength();
var is_sealed = ObjectIsSealed(array);
- if (IS_ARRAY(array) && !is_sealed) {
+ if (IS_ARRAY(array) && !is_sealed && len > 0) {
SmartMove(array, 0, 0, len, num_arguments);
} else {
SimpleMove(array, 0, 0, len, num_arguments);
if (end_i < start_i) return result;
- if (IS_ARRAY(array) &&
- !%IsObserved(array) &&
- (end_i > 1000) &&
- (%EstimateNumberOfElements(array) < end_i)) {
+ if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {
+ %NormalizeElements(array);
+ %NormalizeElements(result);
SmartSlice(array, start_i, end_i - start_i, len, result);
} else {
SimpleSlice(array, start_i, end_i - start_i, len, result);
["Array.prototype.splice"]);
}
- var use_simple_splice = true;
- if (IS_ARRAY(array) &&
- num_elements_to_add !== del_count) {
- // If we are only deleting/moving a few things near the end of the
- // array then the simple version is going to be faster, because it
- // doesn't touch most of the array.
- var estimated_non_hole_elements = %EstimateNumberOfElements(array);
- if (len > 20 && (estimated_non_hole_elements >> 2) < (len - start_i)) {
- use_simple_splice = false;
- }
+ var changed_elements = del_count;
+ if (num_elements_to_add != del_count) {
+ // If the slice needs to do a actually move elements after the insertion
+ // point, then include those in the estimate of changed elements.
+ changed_elements += len - start_i - del_count;
}
-
- if (use_simple_splice) {
- SimpleSlice(array, start_i, del_count, len, deleted_elements);
- SimpleMove(array, start_i, del_count, len, num_elements_to_add);
- } else {
+ if (UseSparseVariant(array, len, IS_ARRAY(array), changed_elements)) {
+ %NormalizeElements(array);
+ %NormalizeElements(deleted_elements);
SmartSlice(array, start_i, del_count, len, deleted_elements);
SmartMove(array, start_i, del_count, len, num_elements_to_add);
+ } else {
+ SimpleSlice(array, start_i, del_count, len, deleted_elements);
+ SimpleMove(array, start_i, del_count, len, num_elements_to_add);
}
// Insert the arguments into the resulting array in
var t_array = [];
// Use both 'from' and 'to' to determine the pivot candidates.
var increment = 200 + ((to - from) & 15);
- for (var i = from + 1; i < to - 1; i += increment) {
- t_array.push([i, a[i]]);
+ for (var i = from + 1, j = 0; i < to - 1; i += increment, j++) {
+ t_array[j] = [i, a[i]];
}
- t_array.sort(function(a, b) {
- return %_CallFunction(receiver, a[1], b[1], comparefn) } );
+ %_CallFunction(t_array, function(a, b) {
+ return %_CallFunction(receiver, a[1], b[1], comparefn);
+ }, ArraySort);
var third_index = t_array[t_array.length >> 1][0];
return third_index;
}
// It's an interval.
var proto_length = indices;
for (var i = 0; i < proto_length; i++) {
- if (!obj.hasOwnProperty(i) && proto.hasOwnProperty(i)) {
+ if (!HAS_OWN_PROPERTY(obj, i) && HAS_OWN_PROPERTY(proto, i)) {
obj[i] = proto[i];
if (i >= max) { max = i + 1; }
}
} else {
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
- if (!IS_UNDEFINED(index) &&
- !obj.hasOwnProperty(index) && proto.hasOwnProperty(index)) {
+ if (!IS_UNDEFINED(index) && !HAS_OWN_PROPERTY(obj, index)
+ && HAS_OWN_PROPERTY(proto, index)) {
obj[index] = proto[index];
if (index >= max) { max = index + 1; }
}
// It's an interval.
var proto_length = indices;
for (var i = from; i < proto_length; i++) {
- if (proto.hasOwnProperty(i)) {
+ if (HAS_OWN_PROPERTY(proto, i)) {
obj[i] = UNDEFINED;
}
}
for (var i = 0; i < indices.length; i++) {
var index = indices[i];
if (!IS_UNDEFINED(index) && from <= index &&
- proto.hasOwnProperty(index)) {
+ HAS_OWN_PROPERTY(proto, index)) {
obj[index] = UNDEFINED;
}
}
}
// Maintain the invariant num_holes = the number of holes in the original
// array with indices <= first_undefined or > last_defined.
- if (!obj.hasOwnProperty(first_undefined)) {
+ if (!HAS_OWN_PROPERTY(obj, first_undefined)) {
num_holes++;
}
// Find last defined element.
while (first_undefined < last_defined &&
IS_UNDEFINED(obj[last_defined])) {
- if (!obj.hasOwnProperty(last_defined)) {
+ if (!HAS_OWN_PROPERTY(obj, last_defined)) {
num_holes++;
}
last_defined--;
// 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
- // local elements. This is not very efficient, but sorting with
+ // 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
var result = new $Array();
var accumulator = new InternalArray();
var accumulator_length = 0;
- var stepping = %_DebugCallbackSupportsStepping(f);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
receiver = ToObject(receiver);
}
- var stepping = %_DebugCallbackSupportsStepping(f);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
receiver = ToObject(receiver);
}
- var stepping = %_DebugCallbackSupportsStepping(f);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
receiver = ToObject(receiver);
}
- var stepping = %_DebugCallbackSupportsStepping(f);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
var result = new $Array();
var accumulator = new InternalArray(length);
- var stepping = %_DebugCallbackSupportsStepping(f);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
for (var i = 0; i < length; i++) {
if (i in array) {
var element = array[i];
}
var min = index;
var max = length;
- if (UseSparseVariant(this, length, IS_ARRAY(this))) {
+ if (UseSparseVariant(this, length, IS_ARRAY(this), max - min)) {
+ %NormalizeElements(this);
var indices = %GetArrayKeys(this, length);
if (IS_NUMBER(indices)) {
// It's an interval.
}
var min = 0;
var max = index;
- if (UseSparseVariant(this, length, IS_ARRAY(this))) {
+ if (UseSparseVariant(this, length, IS_ARRAY(this), index)) {
+ %NormalizeElements(this);
var indices = %GetArrayKeys(this, index + 1);
if (IS_NUMBER(indices)) {
// It's an interval.
}
var receiver = %GetDefaultReceiver(callback);
- var stepping = %_DebugCallbackSupportsStepping(callback);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(callback);
for (; i < length; i++) {
if (i in array) {
var element = array[i];
}
var receiver = %GetDefaultReceiver(callback);
- var stepping = %_DebugCallbackSupportsStepping(callback);
+ var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(callback);
for (; i >= 0; i--) {
if (i in array) {
var element = array[i];
// Set up non-enumerable constructor property on the Array.prototype
// object.
- %SetProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
+ %AddNamedProperty($Array.prototype, "constructor", $Array, DONT_ENUM);
+
+ // Set up unscopable properties on the Array.prototype object.
+ var unscopables = {
+ __proto__: null,
+ copyWithin: true,
+ entries: true,
+ fill: true,
+ find: true,
+ findIndex: true,
+ keys: true,
+ values: true,
+ };
+ %AddNamedProperty($Array.prototype, symbolUnscopables, unscopables,
+ DONT_ENUM | READ_ONLY);
// Set up non-enumerable functions on the Array object.
InstallFunctions($Array, DONT_ENUM, $Array(
"isArray", ArrayIsArray
));
- var specialFunctions = %SpecialArrayFunctions({});
+ var specialFunctions = %SpecialArrayFunctions();
var getFunction = function(name, jsBuiltin, len) {
var f = jsBuiltin;
"join", getFunction("join", ArrayJoin),
"pop", getFunction("pop", ArrayPop),
"push", getFunction("push", ArrayPush, 1),
- "concat", getFunction("concat", ArrayConcat, 1),
+ "concat", getFunction("concat", ArrayConcatJS, 1),
"reverse", getFunction("reverse", ArrayReverse),
"shift", getFunction("shift", ArrayShift),
"unshift", getFunction("unshift", ArrayUnshift, 1),
// exposed to user code.
// Adding only the functions that are actually used.
SetUpLockedPrototype(InternalArray, $Array(), $Array(
- "concat", getFunction("concat", ArrayConcat),
+ "concat", getFunction("concat", ArrayConcatJS),
"indexOf", getFunction("indexOf", ArrayIndexOf),
"join", getFunction("join", ArrayJoin),
"pop", getFunction("pop", ArrayPop),