Chromium Code Reviews| Index: src/code-stub-assembler.cc |
| diff --git a/src/code-stub-assembler.cc b/src/code-stub-assembler.cc |
| index 0fff014eb50e8fe0337f123aedadb0f218505ab4..8d74ae654f45e79f7efaaab56efff1e3f3817ebe 100644 |
| --- a/src/code-stub-assembler.cc |
| +++ b/src/code-stub-assembler.cc |
| @@ -1478,8 +1478,47 @@ 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; |
| +} |
| + |
| +Node* CodeStubAssembler::PossiblyGrowElementsCapacity( |
| + ParameterMode mode, ElementsKind kind, Node* array, Node* length, |
| + Node* elements, Node* growth, Label* fits, Label* bailout) { |
| + Node* capacity = TaggedToParameter(LoadFixedArrayBaseLength(elements), mode); |
| + Node* new_length = |
| + IntPtrOrSmiAdd(WordToParameter(growth, mode), length, mode); |
| + GotoIfNot(IntPtrOrSmiGreaterThan(new_length, capacity, mode), fits); |
| + Node* new_capacity = CalculateNewElementsCapacity(new_length, mode); |
| + return GrowElementsCapacity(array, elements, kind, kind, capacity, |
| + new_capacity, mode, bailout); |
| +} |
| + |
| +Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, |
| CodeStubArguments& args, |
| Variable& arg_index, |
| Label* bailout) { |
| @@ -1492,20 +1531,14 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context, |
| TaggedToParameter(LoadJSArrayLength(array), mode)); |
| Variable var_elements(this, 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)); |
| + var_elements.Bind(PossiblyGrowElementsCapacity( |
| + mode, kind, array, var_length.value(), var_elements.value(), growth, |
| + &fits, &pre_bailout)); |
| Goto(&fits); |
| Bind(&fits); |
| Node* elements = var_elements.value(); |
| @@ -1516,22 +1549,8 @@ Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* context, |
| 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); |
| @@ -1556,6 +1575,72 @@ 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); |
| + } |
| +} |
| + |
| +Node* CodeStubAssembler::BuildAppendJSArray(ElementsKind kind, Node* array, |
| + Node* value, Label* bailout) { |
| + Comment("BuildAppendJSArray: %s", ElementsKindToString(kind)); |
| + Label success(this); |
| + Variable var_tagged_length(this, MachineRepresentation::kTagged); |
|
jgruber
2017/04/19 10:25:28
Nit: VARIABLE(var_x, ...) instead of Variable var_
mvstanton
2017/04/23 09:00:09
Done.
|
| + ParameterMode mode = OptimalParameterMode(); |
| + Variable var_length(this, OptimalParameterRepresentation(), |
| + TaggedToParameter(LoadJSArrayLength(array), mode)); |
| + Variable var_elements(this, MachineRepresentation::kTagged, |
| + LoadElements(array)); |
| + |
| + // Resize the capacity of the fixed array if it doesn't fit. |
| + Label fits(this, &var_elements); |
| + Node* growth = IntPtrOrSmiConstant(1, mode); |
| + var_elements.Bind(PossiblyGrowElementsCapacity( |
| + mode, kind, array, var_length.value(), var_elements.value(), growth, |
| + &fits, bailout)); |
| + /* |
| + Node* new_length = IntPtrOrSmiAdd(growth, var_length.value(), mode); |
|
jgruber
2017/04/19 10:25:28
Nit: Leftover code?
mvstanton
2017/04/23 09:00:09
Done.
|
| + 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* elements = var_elements.value(); |
| + |
| + // Push each argument onto the end of the array now that there is enough |
| + // capacity. |
| + TryStoreArrayElement(kind, mode, bailout, elements, var_length.value(), |
| + value); |
| + Increment(var_length, 1, mode); |
| + |
| + { |
| + Node* length = ParameterToTagged(var_length.value(), mode); |
| + var_tagged_length.Bind(length); |
|
jgruber
2017/04/19 10:25:28
Nit: var_tagged_length and the success label aren'
mvstanton
2017/04/23 09:00:09
Good idea, thanks!
|
| + StoreObjectFieldNoWriteBarrier(array, JSArray::kLengthOffset, length); |
| + Goto(&success); |
| + } |
| + |
| + Bind(&success); |
| + return var_tagged_length.value(); |
| +} |
| + |
| Node* CodeStubAssembler::AllocateHeapNumber(MutableMode mode) { |
| Node* result = Allocate(HeapNumber::kSize, kNone); |
| Heap::RootListIndex heap_map_index = |
| @@ -8369,6 +8454,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(), |