diff options
author | Ryan Dahl <ry@tinyclouds.org> | 2011-06-29 17:26:51 +0200 |
---|---|---|
committer | Ryan Dahl <ry@tinyclouds.org> | 2011-06-29 17:26:51 +0200 |
commit | 33af2720f26c2b25bc7f75ce7eb454ff99db6d35 (patch) | |
tree | 9a38f0c96420edf503eebd6325dd8d2d8249f653 /deps/v8/src/array.js | |
parent | 6afdca885adeeeed9eef8cbb01c3d97af0bc084d (diff) | |
download | node-33af2720f26c2b25bc7f75ce7eb454ff99db6d35.tar.gz |
Upgrade V8 to 3.4.8
Diffstat (limited to 'deps/v8/src/array.js')
-rw-r--r-- | deps/v8/src/array.js | 189 |
1 files changed, 163 insertions, 26 deletions
diff --git a/deps/v8/src/array.js b/deps/v8/src/array.js index 0753f1e2a..34ebd4e22 100644 --- a/deps/v8/src/array.js +++ b/deps/v8/src/array.js @@ -33,7 +33,7 @@ // Global list of arrays visited during toString, toLocaleString and // join invocations. -var visited_arrays = new $Array(); +var visited_arrays = new InternalArray(); // Gets a sorted array of array keys. Useful for operations on sparse @@ -67,13 +67,32 @@ function GetSortedArrayKeys(array, intervals) { } +function SparseJoinWithSeparator(array, len, convert, separator) { + var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); + var totalLength = 0; + var elements = new InternalArray(keys.length * 2); + var previousKey = -1; + for (var i = 0; i < keys.length; i++) { + var key = keys[i]; + if (key != previousKey) { // keys may contain duplicates. + var e = array[key]; + if (!IS_STRING(e)) e = convert(e); + elements[i * 2] = key; + elements[i * 2 + 1] = e; + previousKey = key; + } + } + return %SparseJoinWithSeparator(elements, len, separator); +} + + // Optimized for sparse arrays if separator is ''. function SparseJoin(array, len, convert) { var keys = GetSortedArrayKeys(array, %GetArrayKeys(array, len)); var last_key = -1; var keys_length = keys.length; - var elements = new $Array(keys_length); + var elements = new InternalArray(keys_length); var elements_length = 0; for (var i = 0; i < keys_length; i++) { @@ -110,8 +129,12 @@ function Join(array, length, separator, convert) { // Attempt to convert the elements. try { - if (UseSparseVariant(array, length, is_array) && (separator.length == 0)) { - return SparseJoin(array, length, convert); + if (UseSparseVariant(array, length, is_array)) { + if (separator.length == 0) { + return SparseJoin(array, length, convert); + } else { + return SparseJoinWithSeparator(array, length, convert, separator); + } } // Fast case for one-element arrays. @@ -122,17 +145,15 @@ function Join(array, length, separator, convert) { } // Construct an array for the elements. - var elements = new $Array(length); + var elements = new InternalArray(length); // We pull the empty separator check outside the loop for speed! if (separator.length == 0) { var elements_length = 0; for (var i = 0; i < length; i++) { var e = array[i]; - if (!IS_UNDEFINED(e)) { - if (!IS_STRING(e)) e = convert(e); - elements[elements_length++] = e; - } + if (!IS_STRING(e)) e = convert(e); + elements[elements_length++] = e; } elements.length = elements_length; var result = %_FastAsciiArrayJoin(elements, ''); @@ -140,7 +161,7 @@ function Join(array, length, separator, convert) { return %StringBuilderConcat(elements, elements_length, ''); } // Non-empty separator case. - // If the first element is a number then use the heuristic that the + // If the first element is a number then use the heuristic that the // remaining elements are also likely to be numbers. if (!IS_NUMBER(array[0])) { for (var i = 0; i < length; i++) { @@ -148,18 +169,19 @@ function Join(array, length, separator, convert) { if (!IS_STRING(e)) e = convert(e); elements[i] = e; } - } else { + } else { for (var i = 0; i < length; i++) { var e = array[i]; - if (IS_NUMBER(e)) elements[i] = %_NumberToString(e); - else { - if (!IS_STRING(e)) e = convert(e); + if (IS_NUMBER(e)) { + e = %_NumberToString(e); + } else if (!IS_STRING(e)) { + e = convert(e); + } elements[i] = e; - } } - } + } var result = %_FastAsciiArrayJoin(elements, separator); - if (!IS_UNDEFINED(result)) return result; + if (!IS_UNDEFINED(result)) return result; return %StringBuilderJoin(elements, length, separator); } finally { @@ -171,7 +193,7 @@ function Join(array, length, separator, convert) { function ConvertToString(x) { - // Assumes x is a non-string. + // Assumes x is a non-string. if (IS_NUMBER(x)) return %_NumberToString(x); if (IS_BOOLEAN(x)) return x ? 'true' : 'false'; return (IS_NULL_OR_UNDEFINED(x)) ? '' : %ToString(%DefaultString(x)); @@ -241,7 +263,7 @@ function SmartSlice(array, start_i, del_count, len, deleted_elements) { // special array operations to handle sparse arrays in a sensible fashion. function SmartMove(array, start_i, del_count, len, num_additional_args) { // Move data to new array. - var new_array = new $Array(len - del_count + num_additional_args); + var new_array = new InternalArray(len - del_count + num_additional_args); var intervals = %GetArrayKeys(array, len); var length = intervals.length; for (var k = 0; k < length; k++) { @@ -375,6 +397,11 @@ function ArrayToLocaleString() { function ArrayJoin(separator) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.join"]); + } + if (IS_UNDEFINED(separator)) { separator = ','; } else if (!IS_STRING(separator)) { @@ -391,6 +418,11 @@ function ArrayJoin(separator) { // Removes the last element from the array and returns it. See // ECMA-262, section 15.4.4.6. function ArrayPop() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.pop"]); + } + var n = TO_UINT32(this.length); if (n == 0) { this.length = n; @@ -407,6 +439,11 @@ function ArrayPop() { // Appends the arguments to the end of the array and returns the new // length of the array. See ECMA-262, section 15.4.4.7. function ArrayPush() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.push"]); + } + var n = TO_UINT32(this.length); var m = %_ArgumentsLength(); for (var i = 0; i < m; i++) { @@ -418,8 +455,13 @@ function ArrayPush() { function ArrayConcat(arg1) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.concat"]); + } + var arg_count = %_ArgumentsLength(); - var arrays = new $Array(1 + arg_count); + var arrays = new InternalArray(1 + arg_count); arrays[0] = this; for (var i = 0; i < arg_count; i++) { arrays[i + 1] = %_Arguments(i); @@ -474,6 +516,11 @@ function SparseReverse(array, len) { function ArrayReverse() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.reverse"]); + } + var j = TO_UINT32(this.length) - 1; if (UseSparseVariant(this, j, IS_ARRAY(this))) { @@ -505,6 +552,11 @@ function ArrayReverse() { function ArrayShift() { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.shift"]); + } + var len = TO_UINT32(this.length); if (len === 0) { @@ -526,6 +578,11 @@ function ArrayShift() { function ArrayUnshift(arg1) { // length == 1 + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.unshift"]); + } + var len = TO_UINT32(this.length); var num_arguments = %_ArgumentsLength(); @@ -545,6 +602,11 @@ function ArrayUnshift(arg1) { // length == 1 function ArraySlice(start, end) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.slice"]); + } + var len = TO_UINT32(this.length); var start_i = TO_INTEGER(start); var end_i = len; @@ -569,7 +631,9 @@ function ArraySlice(start, end) { if (end_i < start_i) return result; - if (IS_ARRAY(this)) { + if (IS_ARRAY(this) && + (end_i > 1000) && + (%EstimateNumberOfElements(this) < end_i)) { SmartSlice(this, start_i, end_i - start_i, len, result); } else { SimpleSlice(this, start_i, end_i - start_i, len, result); @@ -582,6 +646,11 @@ function ArraySlice(start, end) { function ArraySplice(start, delete_count) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.splice"]); + } + var num_arguments = %_ArgumentsLength(); var len = TO_UINT32(this.length); @@ -653,6 +722,11 @@ function ArraySplice(start, delete_count) { function ArraySort(comparefn) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.sort"]); + } + // In-place QuickSort algorithm. // For short (length <= 22) arrays, insertion sort is used for efficiency. @@ -914,6 +988,11 @@ function ArraySort(comparefn) { // preserving the semantics, since the calls to the receiver function can add // or delete elements from the array. function ArrayFilter(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.filter"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -925,7 +1004,9 @@ function ArrayFilter(f, receiver) { for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - if (f.call(receiver, current, i, this)) result[result_length++] = current; + if (f.call(receiver, current, i, this)) { + result[result_length++] = current; + } } } return result; @@ -933,6 +1014,11 @@ function ArrayFilter(f, receiver) { function ArrayForEach(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.forEach"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -951,6 +1037,11 @@ function ArrayForEach(f, receiver) { // Executes the function once for each element present in the // array until it finds one where callback returns true. function ArraySome(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.some"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -968,6 +1059,11 @@ function ArraySome(f, receiver) { function ArrayEvery(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.every"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } @@ -984,24 +1080,36 @@ function ArrayEvery(f, receiver) { } function ArrayMap(f, receiver) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.map"]); + } + if (!IS_FUNCTION(f)) { throw MakeTypeError('called_non_callable', [ f ]); } // Pull out the length so that modifications to the length in the // loop will not affect the looping. var length = TO_UINT32(this.length); - var result = new $Array(length); + var result = new $Array(); + var accumulator = new InternalArray(length); for (var i = 0; i < length; i++) { var current = this[i]; if (!IS_UNDEFINED(current) || i in this) { - result[i] = f.call(receiver, current, i, this); + accumulator[i] = f.call(receiver, current, i, this); } } + %MoveArrayContents(accumulator, result); return result; } function ArrayIndexOf(element, index) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.indexOf"]); + } + var length = TO_UINT32(this.length); if (length == 0) return -1; if (IS_UNDEFINED(index)) { @@ -1059,6 +1167,11 @@ function ArrayIndexOf(element, index) { function ArrayLastIndexOf(element, index) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.lastIndexOf"]); + } + var length = TO_UINT32(this.length); if (length == 0) return -1; if (%_ArgumentsLength() < 2) { @@ -1112,6 +1225,11 @@ function ArrayLastIndexOf(element, index) { function ArrayReduce(callback, current) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.reduce"]); + } + if (!IS_FUNCTION(callback)) { throw MakeTypeError('called_non_callable', [callback]); } @@ -1134,13 +1252,18 @@ function ArrayReduce(callback, current) { for (; i < length; i++) { var element = this[i]; if (!IS_UNDEFINED(element) || i in this) { - current = callback.call(null, current, element, i, this); + current = callback.call(void 0, current, element, i, this); } } return current; } function ArrayReduceRight(callback, current) { + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { + throw MakeTypeError("called_on_null_or_undefined", + ["Array.prototype.reduceRight"]); + } + if (!IS_FUNCTION(callback)) { throw MakeTypeError('called_non_callable', [callback]); } @@ -1160,7 +1283,7 @@ function ArrayReduceRight(callback, current) { for (; i >= 0; i--) { var element = this[i]; if (!IS_UNDEFINED(element) || i in this) { - current = callback.call(null, current, element, i, this); + current = callback.call(void 0, current, element, i, this); } } return current; @@ -1225,6 +1348,20 @@ function SetupArray() { )); %FinishArrayPrototypeSetup($Array.prototype); + + // The internal Array prototype doesn't need to be fancy, since it's never + // exposed to user code, so no hidden prototypes or DONT_ENUM attributes + // are necessary. + // The null __proto__ ensures that we never inherit any user created + // getters or setters from, e.g., Object.prototype. + InternalArray.prototype.__proto__ = null; + // Adding only the functions that are actually used, and a toString. + InternalArray.prototype.join = getFunction("join", ArrayJoin); + InternalArray.prototype.pop = getFunction("pop", ArrayPop); + InternalArray.prototype.push = getFunction("push", ArrayPush); + InternalArray.prototype.toString = function() { + return "Internal Array, length " + this.length; + }; } |