// 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)) {
+ if (!is_array || length < 1000 || %IsObserved(array) ||
+ %HasComplexElements(array)) {
return false;
}
if (!%_IsSmi(length)) {
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
-function SmartSlice(array, start_i, del_count, len, deleted_elements) {
+function SparseSlice(array, start_i, del_count, len, deleted_elements) {
// Move deleted elements to a new array (the return value from splice).
var indices = %GetArrayKeys(array, start_i + del_count);
if (IS_NUMBER(indices)) {
for (var i = start_i; i < limit; ++i) {
var current = array[i];
if (!IS_UNDEFINED(current) || i in array) {
- deleted_elements[i - start_i] = current;
+ %AddElement(deleted_elements, i - start_i, current, NONE);
}
}
} else {
if (key >= start_i) {
var current = array[key];
if (!IS_UNDEFINED(current) || key in array) {
- deleted_elements[key - start_i] = current;
+ %AddElement(deleted_elements, key - start_i, current, NONE);
}
}
}
// This function implements the optimized splice implementation that can use
// special array operations to handle sparse arrays in a sensible fashion.
-function SmartMove(array, start_i, del_count, len, num_additional_args) {
+function SparseMove(array, start_i, del_count, len, num_additional_args) {
+ // Bail out if no moving is necessary.
+ if (num_additional_args === del_count) return;
// Move data to new array.
var new_array = new InternalArray(len - del_count + num_additional_args);
var indices = %GetArrayKeys(array, len);
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 %HasOwnProperty
- // would be the appropriate test. We follow KJS in consulting the
- // prototype.
- var current = array[index];
- if (!IS_UNDEFINED(current) || index in array) {
- deleted_elements[i] = current;
+ if (index in array) {
+ var current = array[index];
+ // The spec requires [[DefineOwnProperty]] here, %AddElement is close
+ // enough (in that it ignores the prototype).
+ %AddElement(deleted_elements, i, current, NONE);
}
}
}
for (var i = len - del_count; i > start_i; i--) {
var from_index = i + del_count - 1;
var to_index = i + num_additional_args - 1;
- // The spec could also be interpreted such that
- // %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) {
- array[to_index] = current;
+ if (from_index in array) {
+ array[to_index] = array[from_index];
} else {
delete array[to_index];
}
for (var i = start_i; i < len - del_count; i++) {
var from_index = i + del_count;
var to_index = i + num_additional_args;
- // The spec could also be interpreted such that
- // %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) {
- array[to_index] = current;
+ if (from_index in array) {
+ array[to_index] = array[from_index];
} else {
delete array[to_index];
}
func = array.join;
}
if (!IS_SPEC_FUNCTION(func)) {
- return %_CallFunction(array, ObjectToString);
+ return %_CallFunction(array, NoSideEffectsObjectToString);
}
return %_CallFunction(array, func);
}
var result = %_FastOneByteArrayJoin(array, separator);
if (!IS_UNDEFINED(result)) return result;
+ // Fast case for one-element arrays.
+ if (length === 1) {
+ var e = array[0];
+ if (IS_STRING(e)) return e;
+ if (IS_NULL_OR_UNDEFINED(e)) return '';
+ return NonStringToString(e);
+ }
+
return Join(array, length, separator, ConvertToString);
}
var first = array[0];
- if (IS_ARRAY(array)) {
- SmartMove(array, 0, 1, len, 0);
+ if (UseSparseVariant(array, len, IS_ARRAY(array), len)) {
+ SparseMove(array, 0, 1, len, 0);
} else {
SimpleMove(array, 0, 1, len, 0);
}
var array = TO_OBJECT_INLINE(this);
var len = TO_UINT32(array.length);
var num_arguments = %_ArgumentsLength();
- var is_sealed = ObjectIsSealed(array);
- if (IS_ARRAY(array) && !is_sealed && len > 0) {
- SmartMove(array, 0, 0, len, num_arguments);
+ if (len > 0 && UseSparseVariant(array, len, IS_ARRAY(array), len) &&
+ !ObjectIsSealed(array)) {
+ SparseMove(array, 0, 0, len, num_arguments);
} else {
SimpleMove(array, 0, 0, len, num_arguments);
}
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);
+ SparseSlice(array, start_i, end_i - start_i, len, result);
} else {
SimpleSlice(array, start_i, end_i - start_i, len, result);
}
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);
+ SparseSlice(array, start_i, del_count, len, deleted_elements);
+ SparseMove(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);
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
+ var needs_wrapper = false;
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
- receiver = ToObject(receiver);
+ } else {
+ needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var result = new $Array();
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
- if (%_CallFunction(receiver, element, i, array, f)) {
+ var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+ if (%_CallFunction(new_receiver, element, i, array, f)) {
accumulator[accumulator_length++] = element;
}
}
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
+ var needs_wrapper = false;
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
- receiver = ToObject(receiver);
+ } else {
+ needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
- %_CallFunction(receiver, element, i, array, f);
+ var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+ %_CallFunction(new_receiver, element, i, array, f);
}
}
}
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
+ var needs_wrapper = false;
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
- receiver = ToObject(receiver);
+ } else {
+ needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
- if (%_CallFunction(receiver, element, i, array, f)) return true;
+ var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+ if (%_CallFunction(new_receiver, element, i, array, f)) return true;
}
}
return false;
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
+ var needs_wrapper = false;
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
- receiver = ToObject(receiver);
+ } else {
+ needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
- if (!%_CallFunction(receiver, element, i, array, f)) return false;
+ var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+ if (!%_CallFunction(new_receiver, element, i, array, f)) return false;
}
}
return true;
if (!IS_SPEC_FUNCTION(f)) {
throw MakeTypeError('called_non_callable', [ f ]);
}
+ var needs_wrapper = false;
if (IS_NULL_OR_UNDEFINED(receiver)) {
receiver = %GetDefaultReceiver(f) || receiver;
- } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
- receiver = ToObject(receiver);
+ } else {
+ needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
}
var result = new $Array();
var element = array[i];
// Prepare break slots for debugger step in.
if (stepping) %DebugPrepareStepInIfStepping(f);
- accumulator[i] = %_CallFunction(receiver, element, i, array, f);
+ var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+ accumulator[i] = %_CallFunction(new_receiver, element, i, array, f);
}
}
%MoveArrayContents(accumulator, result);
var i = 0;
find_initial: if (%_ArgumentsLength() < 2) {
for (; i < length; i++) {
- current = array[i];
- if (!IS_UNDEFINED(current) || i in array) {
- i++;
+ if (i in array) {
+ current = array[i++];
break find_initial;
}
}
var i = length - 1;
find_initial: if (%_ArgumentsLength() < 2) {
for (; i >= 0; i--) {
- current = array[i];
- if (!IS_UNDEFINED(current) || i in array) {
- i--;
+ if (i in array) {
+ current = array[i--];
break find_initial;
}
}