| Index: src/array.js
|
| diff --git a/src/array.js b/src/array.js
|
| index 15cbbf21a6003a3336be6dd6e5f755154c510a28..60a6834198bc421b8c41c076696006680c8b82b6 100644
|
| --- a/src/array.js
|
| +++ b/src/array.js
|
| @@ -86,11 +86,20 @@ function SparseJoin(array, len, convert) {
|
| }
|
|
|
|
|
| -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);
|
| }
|
|
|
|
|
| @@ -107,7 +116,8 @@ function Join(array, length, separator, convert) {
|
|
|
| // 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 {
|
| @@ -518,13 +528,15 @@ function ArrayReverse() {
|
| 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) {
|
| @@ -670,10 +682,9 @@ function ArraySlice(start, end) {
|
|
|
| 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);
|
| @@ -781,24 +792,20 @@ function ArraySplice(start, delete_count) {
|
| ["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
|
| @@ -1283,7 +1290,8 @@ function ArrayIndexOf(element, index) {
|
| }
|
| 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.
|
| @@ -1338,7 +1346,8 @@ function ArrayLastIndexOf(element, index) {
|
| }
|
| 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.
|
|
|