From 66ec29980888951e00d4d4c6b4996b04291fb95a Mon Sep 17 00:00:00 2001 From: "mstarzinger@chromium.org" Date: Wed, 23 Apr 2014 12:48:32 +0000 Subject: [PATCH] Fix ToObject and Object.isSealed in four Array builtins. R=mvstanton@chromium.org TEST=mjsunit/regress/regress-builtinbust-6 Review URL: https://codereview.chromium.org/240223006 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@20909 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- src/array.js | 75 +++++++++++++-------------- test/mjsunit/regress/regress-builtinbust-6.js | 37 +++++++++++++ 2 files changed, 72 insertions(+), 40 deletions(-) create mode 100644 test/mjsunit/regress/regress-builtinbust-6.js diff --git a/src/array.js b/src/array.js index a233c63..104fe3f 100644 --- a/src/array.js +++ b/src/array.js @@ -415,24 +415,20 @@ function ObservedArrayPop(n) { function ArrayPop() { CHECK_OBJECT_COERCIBLE(this, "Array.prototype.pop"); - var n = TO_UINT32(this.length); + var array = TO_OBJECT_INLINE(this); + var n = TO_UINT32(array.length); if (n == 0) { - this.length = n; + array.length = n; return; } - if (ObjectIsSealed(this)) { - throw MakeTypeError("array_functions_change_sealed", - ["Array.prototype.pop"]); - } - - if (%IsObserved(this)) - return ObservedArrayPop.call(this, n); + if (%IsObserved(array)) + return ObservedArrayPop.call(array, n); n--; - var value = this[n]; - Delete(this, ToName(n), true); - this.length = n; + var value = array[n]; + Delete(array, ToName(n), true); + array.length = n; return value; } @@ -461,24 +457,21 @@ function ObservedArrayPush() { function ArrayPush() { CHECK_OBJECT_COERCIBLE(this, "Array.prototype.push"); - var n = TO_UINT32(this.length); - var m = %_ArgumentsLength(); - if (%IsObserved(this)) return ObservedArrayPush.apply(this, arguments); + var array = TO_OBJECT_INLINE(this); + var n = TO_UINT32(array.length); + var m = %_ArgumentsLength(); + for (var i = 0; i < m; i++) { // Use SetProperty rather than a direct keyed store to ensure that the store // site doesn't become poisened with an elements transition KeyedStoreIC. - // - // TODO(danno): Using %SetProperty is a temporary workaround. The spec says - // that ToObject needs to be called for primitive values (and - // Runtime_SetProperty seem to ignore them). - %SetProperty(this, i+n, %_Arguments(i), 0, kStrictMode); + %SetProperty(array, i+n, %_Arguments(i), 0, kStrictMode); } var new_length = n + m; - this.length = new_length; + array.length = new_length; return new_length; } @@ -596,30 +589,31 @@ function ObservedArrayShift(len) { function ArrayShift() { CHECK_OBJECT_COERCIBLE(this, "Array.prototype.shift"); - var len = TO_UINT32(this.length); + var array = TO_OBJECT_INLINE(this); + var len = TO_UINT32(array.length); if (len === 0) { - this.length = 0; + array.length = 0; return; } - if (ObjectIsSealed(this)) { + if (ObjectIsSealed(array)) { throw MakeTypeError("array_functions_change_sealed", ["Array.prototype.shift"]); } - if (%IsObserved(this)) - return ObservedArrayShift.call(this, len); + if (%IsObserved(array)) + return ObservedArrayShift.call(array, len); - var first = this[0]; + var first = array[0]; - if (IS_ARRAY(this)) { - SmartMove(this, 0, 1, len, 0); + if (IS_ARRAY(array)) { + SmartMove(array, 0, 1, len, 0); } else { - SimpleMove(this, 0, 1, len, 0); + SimpleMove(array, 0, 1, len, 0); } - this.length = len - 1; + array.length = len - 1; return first; } @@ -647,25 +641,26 @@ function ObservedArrayUnshift() { function ArrayUnshift(arg1) { // length == 1 CHECK_OBJECT_COERCIBLE(this, "Array.prototype.unshift"); - var len = TO_UINT32(this.length); - var num_arguments = %_ArgumentsLength(); - var is_sealed = ObjectIsSealed(this); - if (%IsObserved(this)) return ObservedArrayUnshift.apply(this, arguments); - if (IS_ARRAY(this) && !is_sealed) { - SmartMove(this, 0, 0, len, num_arguments); + 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) { + SmartMove(array, 0, 0, len, num_arguments); } else { - SimpleMove(this, 0, 0, len, num_arguments); + SimpleMove(array, 0, 0, len, num_arguments); } for (var i = 0; i < num_arguments; i++) { - this[i] = %_Arguments(i); + array[i] = %_Arguments(i); } var new_length = len + num_arguments; - this.length = new_length; + array.length = new_length; return new_length; } diff --git a/test/mjsunit/regress/regress-builtinbust-6.js b/test/mjsunit/regress/regress-builtinbust-6.js new file mode 100644 index 0000000..771f80a --- /dev/null +++ b/test/mjsunit/regress/regress-builtinbust-6.js @@ -0,0 +1,37 @@ +// Copyright 2014 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Test that Array builtins can be called on primitive values. +var values = [ 23, 4.2, true, false, 0/0 ]; +for (var i = 0; i < values.length; ++i) { + var v = values[i]; + Array.prototype.pop.call(v); + Array.prototype.push.call(v); + Array.prototype.shift.call(v); + Array.prototype.unshift.call(v); +} + +// Test that ToObject on primitive values is only called once. +var length_receiver, element_receiver; +function length() { length_receiver = this; return 1; } +function element() { element_receiver = this; return "x"; } +Object.defineProperty(Number.prototype, "length", { get:length, set:length }); +Object.defineProperty(Number.prototype, "0", { get:element, set:element }); +Object.defineProperty(Number.prototype, "1", { get:element, set:element }); + +assertDoesNotThrow("Array.prototype.pop.call(23)"); +assertEquals(new Number(23), length_receiver); +assertSame(length_receiver, element_receiver); + +assertDoesNotThrow("Array.prototype.push.call(42, 'y')"); +assertEquals(new Number(42), length_receiver); +assertSame(length_receiver, element_receiver); + +assertDoesNotThrow("Array.prototype.shift.call(65)"); +assertEquals(new Number(65), length_receiver); +assertSame(length_receiver, element_receiver); + +assertDoesNotThrow("Array.prototype.unshift.call(99, 'z')"); +assertEquals(new Number(99), length_receiver); +assertSame(length_receiver, element_receiver); -- 2.7.4