| Index: src/code-stub-assembler.cc
 | 
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc
 | 
| index 2a01133efebfa3a32c666a872b0b90a25db3470a..5d4531f6937674a04926f75000ba95da6ce8385c 100644
 | 
| --- a/src/code-stub-assembler.cc
 | 
| +++ b/src/code-stub-assembler.cc
 | 
| @@ -1523,8 +1523,53 @@ Node* CodeStubAssembler::StoreFixedDoubleArrayElement(
 | 
|    return StoreNoWriteBarrier(rep, object, offset, value);
 | 
|  }
 | 
|  
 | 
| -Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
 | 
| -                                            Node* array,
 | 
| +Node* CodeStubAssembler::EnsureArrayPushable(Node* receiver, Label* bailout) {
 | 
| +  // Disallow pushing onto prototypes. It might be the JSArray prototype.
 | 
| +  // Disallow pushing onto non-extensible objects.
 | 
| +  Comment("Disallow pushing onto prototypes");
 | 
| +  Node* map = LoadMap(receiver);
 | 
| +  Node* bit_field2 = LoadMapBitField2(map);
 | 
| +  int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) |
 | 
| +             (1 << Map::kIsExtensible);
 | 
| +  Node* test = Word32And(bit_field2, Int32Constant(mask));
 | 
| +  GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)), bailout);
 | 
| +
 | 
| +  // Disallow pushing onto arrays in dictionary named property mode. We need
 | 
| +  // to figure out whether the length property is still writable.
 | 
| +  Comment("Disallow pushing onto arrays in dictionary named property mode");
 | 
| +  GotoIf(IsDictionaryMap(map), bailout);
 | 
| +
 | 
| +  // Check whether the length property is writable. The length property is the
 | 
| +  // only default named property on arrays. It's nonconfigurable, hence is
 | 
| +  // guaranteed to stay the first property.
 | 
| +  Node* descriptors = LoadMapDescriptors(map);
 | 
| +  Node* details =
 | 
| +      LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0));
 | 
| +  GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), bailout);
 | 
| +
 | 
| +  Node* kind = DecodeWord32<Map::ElementsKindBits>(bit_field2);
 | 
| +  return kind;
 | 
| +}
 | 
| +
 | 
| +void CodeStubAssembler::PossiblyGrowElementsCapacity(
 | 
| +    ParameterMode mode, ElementsKind kind, Node* array, Node* length,
 | 
| +    Variable* var_elements, Node* growth, Label* bailout) {
 | 
| +  Label fits(this, var_elements);
 | 
| +  Node* capacity =
 | 
| +      TaggedToParameter(LoadFixedArrayBaseLength(var_elements->value()), mode);
 | 
| +  // length and growth nodes are already in a ParameterMode appropriate
 | 
| +  // representation.
 | 
| +  Node* new_length = IntPtrOrSmiAdd(growth, length, mode);
 | 
| +  GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), &fits);
 | 
| +  Node* new_capacity = CalculateNewElementsCapacity(new_length, mode);
 | 
| +  var_elements->Bind(GrowElementsCapacity(array, var_elements->value(), kind,
 | 
| +                                          kind, capacity, new_capacity, mode,
 | 
| +                                          bailout));
 | 
| +  Goto(&fits);
 | 
| +  BIND(&fits);
 | 
| +}
 | 
| +
 | 
| +Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array,
 | 
|                                              CodeStubArguments& args,
 | 
|                                              Variable& arg_index,
 | 
|                                              Label* bailout) {
 | 
| @@ -1536,46 +1581,22 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
 | 
|    VARIABLE(var_length, OptimalParameterRepresentation(),
 | 
|             TaggedToParameter(LoadJSArrayLength(array), mode));
 | 
|    VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array));
 | 
| -  Node* capacity =
 | 
| -      TaggedToParameter(LoadFixedArrayBaseLength(var_elements.value()), mode);
 | 
|  
 | 
|    // Resize the capacity of the fixed array if it doesn't fit.
 | 
| -  Label fits(this, &var_elements);
 | 
|    Node* first = arg_index.value();
 | 
| -  Node* growth = IntPtrSub(args.GetLength(), first);
 | 
| -  Node* new_length =
 | 
| -      IntPtrOrSmiAdd(WordToParameter(growth, mode), var_length.value(), mode);
 | 
| -  GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), &fits);
 | 
| -  Node* new_capacity = CalculateNewElementsCapacity(new_length, mode);
 | 
| -  var_elements.Bind(GrowElementsCapacity(array, var_elements.value(), kind,
 | 
| -                                         kind, capacity, new_capacity, mode,
 | 
| -                                         &pre_bailout));
 | 
| -  Goto(&fits);
 | 
| -  BIND(&fits);
 | 
| -  Node* elements = var_elements.value();
 | 
| +  Node* growth = WordToParameter(IntPtrSub(args.GetLength(), first), mode);
 | 
| +  PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(),
 | 
| +                               &var_elements, growth, &pre_bailout);
 | 
|  
 | 
|    // Push each argument onto the end of the array now that there is enough
 | 
|    // capacity.
 | 
|    CodeStubAssembler::VariableList push_vars({&var_length}, zone());
 | 
| +  Node* elements = var_elements.value();
 | 
|    args.ForEach(
 | 
|        push_vars,
 | 
|        [this, kind, mode, elements, &var_length, &pre_bailout](Node* arg) {
 | 
| -        if (IsFastSmiElementsKind(kind)) {
 | 
| -          GotoIf(TaggedIsNotSmi(arg), &pre_bailout);
 | 
| -        } else if (IsFastDoubleElementsKind(kind)) {
 | 
| -          GotoIfNotNumber(arg, &pre_bailout);
 | 
| -        }
 | 
| -        if (IsFastDoubleElementsKind(kind)) {
 | 
| -          Node* double_value = ChangeNumberToFloat64(arg);
 | 
| -          StoreFixedDoubleArrayElement(elements, var_length.value(),
 | 
| -                                       Float64SilenceNaN(double_value), mode);
 | 
| -        } else {
 | 
| -          WriteBarrierMode barrier_mode = IsFastSmiElementsKind(kind)
 | 
| -                                              ? SKIP_WRITE_BARRIER
 | 
| -                                              : UPDATE_WRITE_BARRIER;
 | 
| -          StoreFixedArrayElement(elements, var_length.value(), arg,
 | 
| -                                 barrier_mode, 0, mode);
 | 
| -        }
 | 
| +        TryStoreArrayElement(kind, mode, &pre_bailout, elements,
 | 
| +                             var_length.value(), arg);
 | 
|          Increment(var_length, 1, mode);
 | 
|        },
 | 
|        first, nullptr);
 | 
| @@ -1600,6 +1621,49 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context,
 | 
|    return var_tagged_length.value();
 | 
|  }
 | 
|  
 | 
| +void CodeStubAssembler::TryStoreArrayElement(ElementsKind kind,
 | 
| +                                             ParameterMode mode, Label* bailout,
 | 
| +                                             Node* elements, Node* index,
 | 
| +                                             Node* value) {
 | 
| +  if (IsFastSmiElementsKind(kind)) {
 | 
| +    GotoIf(TaggedIsNotSmi(value), bailout);
 | 
| +  } else if (IsFastDoubleElementsKind(kind)) {
 | 
| +    GotoIfNotNumber(value, bailout);
 | 
| +  }
 | 
| +  if (IsFastDoubleElementsKind(kind)) {
 | 
| +    Node* double_value = ChangeNumberToFloat64(value);
 | 
| +    StoreFixedDoubleArrayElement(elements, index,
 | 
| +                                 Float64SilenceNaN(double_value), mode);
 | 
| +  } else {
 | 
| +    WriteBarrierMode barrier_mode =
 | 
| +        IsFastSmiElementsKind(kind) ? SKIP_WRITE_BARRIER : UPDATE_WRITE_BARRIER;
 | 
| +    StoreFixedArrayElement(elements, index, value, barrier_mode, 0, mode);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array,
 | 
| +                                           Node* value, Label* bailout) {
 | 
| +  Comment("BuildAppendJSArray: %s", ElementsKindToString(kind));
 | 
| +  ParameterMode mode = OptimalParameterMode();
 | 
| +  VARIABLE(var_length, OptimalParameterRepresentation(),
 | 
| +           TaggedToParameter(LoadJSArrayLength(array), mode));
 | 
| +  VARIABLE(var_elements, MachineRepresentation::kTagged, LoadElements(array));
 | 
| +
 | 
| +  // Resize the capacity of the fixed array if it doesn't fit.
 | 
| +  Node* growth = IntPtrOrSmiConstant(1, mode);
 | 
| +  PossiblyGrowElementsCapacity(mode, kind, array, var_length.value(),
 | 
| +                               &var_elements, growth, bailout);
 | 
| +
 | 
| +  // Push each argument onto the end of the array now that there is enough
 | 
| +  // capacity.
 | 
| +  TryStoreArrayElement(kind, mode, bailout, var_elements.value(),
 | 
| +                       var_length.value(), value);
 | 
| +  Increment(var_length, 1, mode);
 | 
| +
 | 
| +  Node* length = ParameterToTagged(var_length.value(), mode);
 | 
| +  StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length);
 | 
| +}
 | 
| +
 | 
|  Node* CodeStubAssembler::AllocateHeapNumber(MutableMode mode) {
 | 
|    Node* result = Allocate(HeapNumber::kSize, kNone);
 | 
|    Heap::RootListIndex heap_map_index =
 | 
| @@ -8485,6 +8549,11 @@ Node* CodeStubAssembler::IsHoleyFastElementsKind(Node* elements_kind) {
 | 
|    return Word32Equal(holey_elements, Int32Constant(1));
 | 
|  }
 | 
|  
 | 
| +Node* CodeStubAssembler::IsElementsKindGreaterThan(
 | 
| +    Node* target_kind, ElementsKind reference_kind) {
 | 
| +  return Int32GreaterThan(target_kind, Int32Constant(reference_kind));
 | 
| +}
 | 
| +
 | 
|  Node* CodeStubAssembler::IsDebugActive() {
 | 
|    Node* is_debug_active = Load(
 | 
|        MachineType::Uint8(),
 | 
| 
 |