summaryrefslogtreecommitdiff
path: root/deps/v8/src/array.js
diff options
context:
space:
mode:
authorRyan Dahl <ry@tinyclouds.org>2011-06-29 17:26:51 +0200
committerRyan Dahl <ry@tinyclouds.org>2011-06-29 17:26:51 +0200
commit33af2720f26c2b25bc7f75ce7eb454ff99db6d35 (patch)
tree9a38f0c96420edf503eebd6325dd8d2d8249f653 /deps/v8/src/array.js
parent6afdca885adeeeed9eef8cbb01c3d97af0bc084d (diff)
downloadnode-33af2720f26c2b25bc7f75ce7eb454ff99db6d35.tar.gz
Upgrade V8 to 3.4.8
Diffstat (limited to 'deps/v8/src/array.js')
-rw-r--r--deps/v8/src/array.js189
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;
+ };
}