| // Copyright 2019 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. |
| |
| namespace array { |
| extern builtin ArrayShift(Context, JSFunction, JSAny, int32): JSAny; |
| |
| macro TryFastArrayShift(implicit context: Context)(receiver: JSAny): JSAny |
| labels Slow, Runtime { |
| const array: FastJSArray = Cast<FastJSArray>(receiver) otherwise Slow; |
| let witness = NewFastJSArrayWitness(array); |
| |
| witness.EnsureArrayPushable() otherwise Slow; |
| |
| if (array.length == 0) { |
| return Undefined; |
| } |
| |
| const newLength = array.length - 1; |
| |
| // Check that we're not supposed to right-trim the backing store, as |
| // implemented in elements.cc:ElementsAccessorBase::SetLengthImpl. |
| if ((newLength + newLength + kMinAddedElementsCapacity) < |
| array.elements.length) { |
| goto Runtime; |
| } |
| |
| // Check that we're not supposed to left-trim the backing store, as |
| // implemented in elements.cc:FastElementsAccessor::MoveElements. |
| if (newLength > kMaxCopyElements) goto Runtime; |
| |
| const result = witness.LoadElementOrUndefined(0); |
| witness.ChangeLength(newLength); |
| witness.MoveElements(0, 1, Convert<intptr>(newLength)); |
| witness.StoreHole(newLength); |
| return result; |
| } |
| |
| transitioning macro GenericArrayShift(implicit context: Context)( |
| receiver: JSAny): JSAny { |
| // 1. Let O be ? ToObject(this value). |
| const object: JSReceiver = ToObject_Inline(context, receiver); |
| |
| // 2. Let len be ? ToLength(? Get(O, "length")). |
| const length: Number = GetLengthProperty(object); |
| |
| // 3. If len is zero, then |
| if (length == 0) { |
| // a. Perform ? Set(O, "length", 0, true). |
| SetProperty(object, kLengthString, Convert<Smi>(0)); |
| // b. Return undefined. |
| return Undefined; |
| } |
| |
| // 4. Let first be ? Get(O, "0"). |
| const first = GetProperty(object, Convert<Smi>(0)); |
| // 5. Let k be 1. |
| let k: Number = 1; |
| // 6. Repeat, while k < len |
| while (k < length) { |
| // a. Let from be ! ToString(k). |
| const from: Number = k; |
| |
| // b. Let to be ! ToString(k - 1). |
| const to: Number = k - 1; |
| |
| // c. Let fromPresent be ? HasProperty(O, from). |
| const fromPresent: Boolean = HasProperty(object, from); |
| |
| // d. If fromPresent is true, then |
| if (fromPresent == True) { |
| // i. Let fromVal be ? Get(O, from). |
| const fromValue: JSAny = GetProperty(object, from); |
| |
| // ii. Perform ? Set(O, to, fromValue, true). |
| SetProperty(object, to, fromValue); |
| } else { |
| // i. Perform ? DeletePropertyOrThrow(O, to). |
| DeleteProperty(object, to, LanguageMode::kStrict); |
| } |
| |
| // f. Increase k by 1. |
| k++; |
| } |
| |
| // 7. Perform ? DeletePropertyOrThrow(O, ! ToString(len - 1)). |
| DeleteProperty(object, length - 1, LanguageMode::kStrict); |
| |
| // 8. Perform ? Set(O, "length", len - 1, true). |
| SetProperty(object, kLengthString, length - 1); |
| |
| // 9. Return first. |
| return first; |
| } |
| |
| // https://tc39.github.io/ecma262/#sec-array.prototype.shift |
| transitioning javascript builtin ArrayPrototypeShift( |
| js-implicit context: NativeContext, receiver: JSAny)(...arguments): JSAny { |
| try { |
| return TryFastArrayShift(receiver) otherwise Slow, Runtime; |
| } label Slow { |
| return GenericArrayShift(receiver); |
| } label Runtime { |
| tail ArrayShift( |
| context, LoadTargetFromFrame(), Undefined, |
| Convert<int32>(arguments.length)); |
| } |
| } |
| } |