| Index: src/array.js
|
| diff --git a/src/array.js b/src/array.js
|
| index a3674e837d3ade7a59e7ddc159ff77b6b745ebd5..dcfcde51393cbe1d7fc4258c794c73ad01505a21 100644
|
| --- a/src/array.js
|
| +++ b/src/array.js
|
| @@ -395,6 +395,23 @@ function ArrayJoin(separator) {
|
| }
|
|
|
|
|
| +function ObservedArrayPop(n) {
|
| + n--;
|
| + var value = this[n];
|
| +
|
| + EnqueueSpliceRecord(this, n, [value], 1, 0);
|
| +
|
| + try {
|
| + BeginPerformSplice(this);
|
| + delete this[n];
|
| + this.length = n;
|
| + } finally {
|
| + EndPerformSplice(this);
|
| + }
|
| +
|
| + return value;
|
| +}
|
| +
|
| // Removes the last element from the array and returns it. See
|
| // ECMA-262, section 15.4.4.6.
|
| function ArrayPop() {
|
| @@ -408,6 +425,10 @@ function ArrayPop() {
|
| this.length = n;
|
| return;
|
| }
|
| +
|
| + if (%IsObserved(this))
|
| + return ObservedArrayPop.call(this, n);
|
| +
|
| n--;
|
| var value = this[n];
|
| delete this[n];
|
| @@ -424,7 +445,6 @@ function ObservedArrayPush() {
|
|
|
| try {
|
| BeginPerformSplice(this);
|
| -
|
| for (var i = 0; i < m; i++) {
|
| this[i+n] = %_Arguments(i);
|
| }
|
| @@ -558,6 +578,22 @@ function ArrayReverse() {
|
| }
|
|
|
|
|
| +function ObservedArrayShift(len) {
|
| + var first = this[0];
|
| +
|
| + EnqueueSpliceRecord(this, 0, [first], 1, 0);
|
| +
|
| + try {
|
| + BeginPerformSplice(this);
|
| + SimpleMove(this, 0, 1, len, 0);
|
| + this.length = len - 1;
|
| + } finally {
|
| + EndPerformSplice(this);
|
| + }
|
| +
|
| + return first;
|
| +}
|
| +
|
| function ArrayShift() {
|
| if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
|
| throw MakeTypeError("called_on_null_or_undefined",
|
| @@ -571,9 +607,12 @@ function ArrayShift() {
|
| return;
|
| }
|
|
|
| + if (%IsObserved(this))
|
| + return ObservedArrayShift.call(this, len);
|
| +
|
| var first = this[0];
|
|
|
| - if (IS_ARRAY(this) && !%IsObserved(this)) {
|
| + if (IS_ARRAY(this)) {
|
| SmartMove(this, 0, 1, len, 0);
|
| } else {
|
| SimpleMove(this, 0, 1, len, 0);
|
| @@ -584,6 +623,25 @@ function ArrayShift() {
|
| return first;
|
| }
|
|
|
| +function ObservedArrayUnshift() {
|
| + var len = TO_UINT32(this.length);
|
| + var num_arguments = %_ArgumentsLength();
|
| +
|
| + EnqueueSpliceRecord(this, 0, [], 0, num_arguments);
|
| +
|
| + try {
|
| + BeginPerformSplice(this);
|
| + SimpleMove(this, 0, 0, len, num_arguments);
|
| + for (var i = 0; i < num_arguments; i++) {
|
| + this[i] = %_Arguments(i);
|
| + }
|
| + this.length = len + num_arguments;
|
| + } finally {
|
| + EndPerformSplice(this);
|
| + }
|
| +
|
| + return len + num_arguments;
|
| +}
|
|
|
| function ArrayUnshift(arg1) { // length == 1
|
| if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
|
| @@ -591,10 +649,13 @@ function ArrayUnshift(arg1) { // length == 1
|
| ["Array.prototype.unshift"]);
|
| }
|
|
|
| + if (%IsObserved(this))
|
| + return ObservedArrayUnshift.apply(this, arguments);
|
| +
|
| var len = TO_UINT32(this.length);
|
| var num_arguments = %_ArgumentsLength();
|
|
|
| - if (IS_ARRAY(this) && !%IsObserved(this)) {
|
| + if (IS_ARRAY(this)) {
|
| SmartMove(this, 0, 0, len, num_arguments);
|
| } else {
|
| SimpleMove(this, 0, 0, len, num_arguments);
|
| @@ -655,52 +716,100 @@ 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);
|
| - var start_i = TO_INTEGER(start);
|
| -
|
| +function ComputeSpliceStartIndex(start_i, len) {
|
| if (start_i < 0) {
|
| start_i += len;
|
| - if (start_i < 0) start_i = 0;
|
| - } else {
|
| - if (start_i > len) start_i = len;
|
| + return start_i < 0 ? 0 : start_i;
|
| }
|
|
|
| + return start_i > len ? len : start_i;
|
| +}
|
| +
|
| +
|
| +function ComputeSpliceDeleteCount(delete_count, num_arguments, len, start_i) {
|
| // SpiderMonkey, TraceMonkey and JSC treat the case where no delete count is
|
| // given as a request to delete all the elements from the start.
|
| // And it differs from the case of undefined delete count.
|
| // This does not follow ECMA-262, but we do the same for
|
| // compatibility.
|
| var del_count = 0;
|
| - if (num_arguments == 1) {
|
| - del_count = len - start_i;
|
| - } else {
|
| - del_count = TO_INTEGER(delete_count);
|
| - if (del_count < 0) del_count = 0;
|
| - if (del_count > len - start_i) del_count = len - start_i;
|
| - }
|
| + if (num_arguments == 1)
|
| + return len - start_i;
|
| +
|
| + del_count = TO_INTEGER(delete_count);
|
| + if (del_count < 0)
|
| + return 0;
|
| +
|
| + if (del_count > len - start_i)
|
| + return len - start_i;
|
| +
|
| + return del_count;
|
| +}
|
|
|
| +
|
| +function ObservedArraySplice(start, delete_count) {
|
| + var num_arguments = %_ArgumentsLength();
|
| + var len = TO_UINT32(this.length);
|
| + var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
|
| + var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
|
| + start_i);
|
| var deleted_elements = [];
|
| deleted_elements.length = del_count;
|
| + var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
|
| +
|
| + try {
|
| + BeginPerformSplice(this);
|
|
|
| - // Number of elements to add.
|
| - var num_additional_args = 0;
|
| - if (num_arguments > 2) {
|
| - num_additional_args = num_arguments - 2;
|
| + SimpleSlice(this, start_i, del_count, len, deleted_elements);
|
| + SimpleMove(this, start_i, del_count, len, num_elements_to_add);
|
| +
|
| + // Insert the arguments into the resulting array in
|
| + // place of the deleted elements.
|
| + var i = start_i;
|
| + var arguments_index = 2;
|
| + var arguments_length = %_ArgumentsLength();
|
| + while (arguments_index < arguments_length) {
|
| + this[i++] = %_Arguments(arguments_index++);
|
| + }
|
| + this.length = len - del_count + num_elements_to_add;
|
| +
|
| + } finally {
|
| + EndPerformSplice(this);
|
| + if (deleted_elements.length || num_elements_to_add) {
|
| + EnqueueSpliceRecord(this,
|
| + start_i,
|
| + deleted_elements.slice(),
|
| + deleted_elements.length,
|
| + num_elements_to_add);
|
| + }
|
| }
|
|
|
| - var use_simple_splice = true;
|
| + // Return the deleted elements.
|
| + return deleted_elements;
|
| +}
|
| +
|
| +
|
| +function ArraySplice(start, delete_count) {
|
| + if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
|
| + throw MakeTypeError("called_on_null_or_undefined",
|
| + ["Array.prototype.splice"]);
|
| + }
|
|
|
| + if (%IsObserved(this))
|
| + return ObservedArraySplice.apply(this, arguments);
|
| +
|
| + var num_arguments = %_ArgumentsLength();
|
| + var len = TO_UINT32(this.length);
|
| + var start_i = ComputeSpliceStartIndex(TO_INTEGER(start), len);
|
| + var del_count = ComputeSpliceDeleteCount(delete_count, num_arguments, len,
|
| + start_i);
|
| + var deleted_elements = [];
|
| + deleted_elements.length = del_count;
|
| + var num_elements_to_add = num_arguments > 2 ? num_arguments - 2 : 0;
|
| +
|
| + var use_simple_splice = true;
|
| if (IS_ARRAY(this) &&
|
| - !%IsObserved(this) &&
|
| - num_additional_args !== del_count) {
|
| + 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.
|
| @@ -712,10 +821,10 @@ function ArraySplice(start, delete_count) {
|
|
|
| if (use_simple_splice) {
|
| SimpleSlice(this, start_i, del_count, len, deleted_elements);
|
| - SimpleMove(this, start_i, del_count, len, num_additional_args);
|
| + SimpleMove(this, start_i, del_count, len, num_elements_to_add);
|
| } else {
|
| SmartSlice(this, start_i, del_count, len, deleted_elements);
|
| - SmartMove(this, start_i, del_count, len, num_additional_args);
|
| + SmartMove(this, start_i, del_count, len, num_elements_to_add);
|
| }
|
|
|
| // Insert the arguments into the resulting array in
|
| @@ -726,7 +835,7 @@ function ArraySplice(start, delete_count) {
|
| while (arguments_index < arguments_length) {
|
| this[i++] = %_Arguments(arguments_index++);
|
| }
|
| - this.length = len - del_count + num_additional_args;
|
| + this.length = len - del_count + num_elements_to_add;
|
|
|
| // Return the deleted elements.
|
| return deleted_elements;
|
|
|