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(), |