Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2017 the V8 project authors. All rights reserved. | 1 // Copyright 2017 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/builtins/builtins-utils-gen.h" | 5 #include "src/builtins/builtins-utils-gen.h" |
| 6 #include "src/builtins/builtins.h" | 6 #include "src/builtins/builtins.h" |
| 7 #include "src/code-stub-assembler.h" | 7 #include "src/code-stub-assembler.h" |
| 8 | 8 |
| 9 namespace v8 { | 9 namespace v8 { |
| 10 namespace internal { | 10 namespace internal { |
| 11 | 11 |
| 12 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { | 12 class ArrayBuiltinCodeStubAssembler : public CodeStubAssembler { |
| 13 public: | 13 public: |
| 14 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) | 14 explicit ArrayBuiltinCodeStubAssembler(compiler::CodeAssemblerState* state) |
| 15 : CodeStubAssembler(state), | 15 : CodeStubAssembler(state), |
| 16 k_(this, MachineRepresentation::kTagged, SmiConstant(0)), | 16 k_(this, MachineRepresentation::kTagged, SmiConstant(0)), |
| 17 a_(this, MachineRepresentation::kTagged, SmiConstant(0)), | 17 a_(this, MachineRepresentation::kTagged, SmiConstant(0)), |
| 18 to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {} | 18 to_(this, MachineRepresentation::kTagged, SmiConstant(0)) {} |
| 19 | 19 |
| 20 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)> | 20 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm)> |
| 21 BuiltinResultGenerator; | 21 BuiltinResultGenerator; |
| 22 | 22 |
| 23 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> | 23 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> |
| 24 BuiltinResultIndexInitializer; | 24 BuiltinResultIndexInitializer; |
| 25 | 25 |
| 26 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, | 26 typedef std::function<Node*(ArrayBuiltinCodeStubAssembler* masm, |
| 27 Node* k_value, Node* k)> | 27 ElementsKind o_kind, Node* k_value, Node* k)> |
| 28 CallResultProcessor; | 28 CallResultProcessor; |
| 29 | 29 |
| 30 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> | 30 typedef std::function<void(ArrayBuiltinCodeStubAssembler* masm)> |
| 31 PostLoopAction; | 31 PostLoopAction; |
| 32 | 32 |
| 33 Node* ForEachResultGenerator() { return UndefinedConstant(); } | 33 Node* ForEachResultGenerator() { return UndefinedConstant(); } |
| 34 | 34 |
| 35 Node* ForEachProcessor(Node* k_value, Node* k) { | 35 Node* ForEachProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
| 36 CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), | 36 CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), this_arg(), |
| 37 k_value, k, o()); | 37 k_value, k, o()); |
| 38 return a(); | 38 return a(); |
| 39 } | 39 } |
| 40 | 40 |
| 41 Node* SomeResultGenerator() { return FalseConstant(); } | 41 Node* SomeResultGenerator() { return FalseConstant(); } |
| 42 | 42 |
| 43 Node* SomeProcessor(Node* k_value, Node* k) { | 43 Node* SomeProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
| 44 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | 44 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
| 45 this_arg(), k_value, k, o()); | 45 this_arg(), k_value, k, o()); |
| 46 Label false_continue(this), return_true(this); | 46 Label false_continue(this), return_true(this); |
| 47 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); | 47 BranchIfToBooleanIsTrue(value, &return_true, &false_continue); |
| 48 Bind(&return_true); | 48 Bind(&return_true); |
| 49 Return(TrueConstant()); | 49 Return(TrueConstant()); |
| 50 Bind(&false_continue); | 50 Bind(&false_continue); |
| 51 return a(); | 51 return a(); |
| 52 } | 52 } |
| 53 | 53 |
| 54 Node* EveryResultGenerator() { return TrueConstant(); } | 54 Node* EveryResultGenerator() { return TrueConstant(); } |
| 55 | 55 |
| 56 Node* EveryProcessor(Node* k_value, Node* k) { | 56 Node* EveryProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
| 57 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | 57 Node* value = CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
| 58 this_arg(), k_value, k, o()); | 58 this_arg(), k_value, k, o()); |
| 59 Label true_continue(this), return_false(this); | 59 Label true_continue(this), return_false(this); |
| 60 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); | 60 BranchIfToBooleanIsTrue(value, &true_continue, &return_false); |
| 61 Bind(&return_false); | 61 Bind(&return_false); |
| 62 Return(FalseConstant()); | 62 Return(FalseConstant()); |
| 63 Bind(&true_continue); | 63 Bind(&true_continue); |
| 64 return a(); | 64 return a(); |
| 65 } | 65 } |
| 66 | 66 |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 91 // 9. Else initialValue is not present, | 91 // 9. Else initialValue is not present, |
| 92 Bind(&no_initial_value); | 92 Bind(&no_initial_value); |
| 93 | 93 |
| 94 // a. Let kPresent be false. | 94 // a. Let kPresent be false. |
| 95 a.Bind(TheHoleConstant()); | 95 a.Bind(TheHoleConstant()); |
| 96 Goto(&done); | 96 Goto(&done); |
| 97 Bind(&done); | 97 Bind(&done); |
| 98 return a.value(); | 98 return a.value(); |
| 99 } | 99 } |
| 100 | 100 |
| 101 Node* ReduceProcessor(Node* k_value, Node* k) { | 101 Node* ReduceProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
| 102 Variable result(this, MachineRepresentation::kTagged); | 102 Variable result(this, MachineRepresentation::kTagged); |
| 103 Label done(this, {&result}), initial(this); | 103 Label done(this, {&result}), initial(this); |
| 104 GotoIf(WordEqual(a(), TheHoleConstant()), &initial); | 104 GotoIf(WordEqual(a(), TheHoleConstant()), &initial); |
| 105 result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), | 105 result.Bind(CallJS(CodeFactory::Call(isolate()), context(), callbackfn(), |
| 106 UndefinedConstant(), a(), k_value, k, o())); | 106 UndefinedConstant(), a(), k_value, k, o())); |
| 107 Goto(&done); | 107 Goto(&done); |
| 108 | 108 |
| 109 Bind(&initial); | 109 Bind(&initial); |
| 110 result.Bind(k_value); | 110 result.Bind(k_value); |
| 111 Goto(&done); | 111 Goto(&done); |
| 112 | 112 |
| 113 Bind(&done); | 113 Bind(&done); |
| 114 return result.value(); | 114 return result.value(); |
| 115 } | 115 } |
| 116 | 116 |
| 117 void ReducePostLoopAction() { | 117 void ReducePostLoopAction() { |
| 118 Label ok(this); | 118 Label ok(this); |
| 119 GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok); | 119 GotoIf(WordNotEqual(a(), TheHoleConstant()), &ok); |
| 120 CallRuntime(Runtime::kThrowTypeError, context(), | 120 CallRuntime(Runtime::kThrowTypeError, context(), |
| 121 SmiConstant(MessageTemplate::kReduceNoInitial)); | 121 SmiConstant(MessageTemplate::kReduceNoInitial)); |
| 122 Unreachable(); | 122 Unreachable(); |
| 123 Bind(&ok); | 123 Bind(&ok); |
| 124 } | 124 } |
| 125 | 125 |
| 126 Node* FilterResultGenerator() { | 126 Node* FilterResultGenerator() { |
| 127 // 7. Let A be ArraySpeciesCreate(O, 0). | 127 // 7. Let A be ArraySpeciesCreate(O, 0). |
| 128 return ArraySpeciesCreate(context(), o(), SmiConstant(0)); | 128 return ArraySpeciesCreate(context(), o(), SmiConstant(0)); |
| 129 } | 129 } |
| 130 | 130 |
| 131 Node* FilterProcessor(Node* k_value, Node* k) { | 131 Node* FilterProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
| 132 // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)). | 132 // ii. Let selected be ToBoolean(? Call(callbackfn, T, kValue, k, O)). |
| 133 Node* selected = CallJS(CodeFactory::Call(isolate()), context(), | 133 Node* selected = CallJS(CodeFactory::Call(isolate()), context(), |
| 134 callbackfn(), this_arg(), k_value, k, o()); | 134 callbackfn(), this_arg(), k_value, k, o()); |
| 135 Label true_continue(this, &to_), false_continue(this); | 135 Label true_continue(this, &to_), false_continue(this); |
| 136 BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue); | 136 BranchIfToBooleanIsTrue(selected, &true_continue, &false_continue); |
| 137 Bind(&true_continue); | 137 Bind(&true_continue); |
| 138 // iii. If selected is true, then... | |
| 139 { | 138 { |
| 139 // iii. If selected is true, then... | |
| 140 Label after_work(this, &to_); | |
| 141 if (o_kind < DICTIONARY_ELEMENTS) { | |
|
danno
2017/04/03 15:35:27
Please use the predicates in elements-kind.h, e.g.
mvstanton
2017/04/06 08:57:36
Per our discussion, I'll just remove the o_kind pa
| |
| 142 Node* kind = nullptr; | |
| 143 | |
| 144 // If a() is a JSArray, we can have a fast path. | |
| 145 Label fast(this); | |
| 146 Label runtime(this); | |
| 147 Label object_push_pre(this), object_push(this), double_push(this); | |
|
danno
2017/04/03 15:35:27
I think you can make this slightly better. Since y
mvstanton
2017/04/06 08:57:36
Right, because of the vagaries of what can happen
| |
| 148 BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS, | |
| 149 &fast, &runtime); | |
| 150 | |
| 151 Bind(&fast); | |
| 152 { | |
| 153 kind = EnsureArrayPushable(a(), &runtime); | |
| 154 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | |
| 155 &object_push_pre); | |
| 156 | |
| 157 BuildAppendJSArray(FAST_SMI_ELEMENTS, a(), k_value, &runtime); | |
| 158 Goto(&after_work); | |
| 159 } | |
| 160 | |
| 161 Bind(&object_push_pre); | |
| 162 { | |
| 163 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
| 164 &double_push, &object_push); | |
| 165 } | |
| 166 | |
| 167 Bind(&object_push); | |
| 168 { | |
| 169 BuildAppendJSArray(FAST_ELEMENTS, a(), k_value, &runtime); | |
| 170 Goto(&after_work); | |
| 171 } | |
| 172 | |
| 173 Bind(&double_push); | |
| 174 { | |
| 175 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, a(), k_value, &runtime); | |
| 176 Goto(&after_work); | |
| 177 } | |
| 178 | |
| 179 Bind(&runtime); | |
| 180 } | |
| 181 | |
| 140 // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). | 182 // 1. Perform ? CreateDataPropertyOrThrow(A, ToString(to), kValue). |
| 141 CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(), | 183 CallRuntime(Runtime::kCreateDataProperty, context(), a(), to_.value(), |
| 142 k_value); | 184 k_value); |
| 185 Goto(&after_work); | |
| 143 | 186 |
| 144 // 2. Increase to by 1. | 187 Bind(&after_work); |
| 145 to_.Bind(NumberInc(to_.value())); | 188 { |
| 146 Goto(&false_continue); | 189 // 2. Increase to by 1. |
| 190 to_.Bind(NumberInc(to_.value())); | |
| 191 Goto(&false_continue); | |
| 192 } | |
| 147 } | 193 } |
| 148 Bind(&false_continue); | 194 Bind(&false_continue); |
| 149 return a(); | 195 return a(); |
| 150 } | 196 } |
| 151 | 197 |
| 152 Node* MapResultGenerator() { | 198 Node* MapResultGenerator() { |
| 153 // 5. Let A be ? ArraySpeciesCreate(O, len). | 199 // 5. Let A be ? ArraySpeciesCreate(O, len). |
| 154 return ArraySpeciesCreate(context(), o(), len_); | 200 return ArraySpeciesCreate(context(), o(), len_); |
| 155 } | 201 } |
| 156 | 202 |
| 157 Node* MapProcessor(Node* k_value, Node* k) { | 203 Node* MapProcessor(ElementsKind o_kind, Node* k_value, Node* k) { |
| 158 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. | 204 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. |
| 159 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). | 205 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). |
| 160 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), | 206 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), |
| 161 callbackfn(), this_arg(), k_value, k, o()); | 207 callbackfn(), this_arg(), k_value, k, o()); |
| 162 | 208 |
| 209 Label finished(this); | |
| 210 if (o_kind < DICTIONARY_ELEMENTS) { | |
| 211 Node* kind = nullptr; | |
| 212 Node* elements = nullptr; | |
| 213 | |
| 214 // If a() is a JSArray, we can have a fast path. | |
| 215 // mode is SMI_PARAMETERS because k has tagged representation. | |
| 216 ParameterMode mode = SMI_PARAMETERS; | |
| 217 Label fast(this); | |
| 218 Label runtime(this); | |
| 219 Label object_push_pre(this), object_push(this), double_push(this); | |
| 220 BranchIfFastJSArray(a(), context(), FastJSArrayAccessMode::ANY_ACCESS, | |
| 221 &fast, &runtime); | |
| 222 | |
| 223 Bind(&fast); | |
| 224 { | |
| 225 kind = EnsureArrayPushable(a(), &runtime); | |
| 226 elements = LoadElements(a()); | |
| 227 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | |
|
danno
2017/04/03 15:35:27
Consider adding/using existing predicates in code-
mvstanton
2017/04/06 08:57:36
I use a "greater than" metaphor to avoid multiple
| |
| 228 &object_push_pre); | |
| 229 | |
| 230 TryStoreArrayElement(FAST_SMI_ELEMENTS, mode, &runtime, elements, k, | |
| 231 mappedValue); | |
| 232 Goto(&finished); | |
| 233 } | |
| 234 | |
| 235 Bind(&object_push_pre); | |
| 236 { | |
| 237 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | |
| 238 &double_push, &object_push); | |
| 239 } | |
| 240 | |
| 241 Bind(&object_push); | |
| 242 { | |
| 243 TryStoreArrayElement(FAST_ELEMENTS, mode, &runtime, elements, k, | |
| 244 mappedValue); | |
| 245 Goto(&finished); | |
| 246 } | |
| 247 | |
| 248 Bind(&double_push); | |
| 249 { | |
| 250 TryStoreArrayElement(FAST_DOUBLE_ELEMENTS, mode, &runtime, elements, k, | |
| 251 mappedValue); | |
| 252 Goto(&finished); | |
| 253 } | |
| 254 | |
| 255 Bind(&runtime); | |
| 256 } | |
| 257 | |
| 163 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). | 258 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). |
| 164 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); | 259 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); |
| 260 Goto(&finished); | |
| 261 | |
| 262 Bind(&finished); | |
| 165 return a(); | 263 return a(); |
| 166 } | 264 } |
| 167 | 265 |
| 168 void NullPostLoopAction() {} | 266 void NullPostLoopAction() {} |
| 169 | 267 |
| 170 protected: | 268 protected: |
| 171 Node* context() { return context_; } | 269 Node* context() { return context_; } |
| 172 Node* receiver() { return receiver_; } | 270 Node* receiver() { return receiver_; } |
| 173 Node* new_target() { return new_target_; } | 271 Node* new_target() { return new_target_; } |
| 174 Node* o() { return o_; } | 272 Node* o() { return o_; } |
| (...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 413 | 511 |
| 414 // d. If kPresent is true, then | 512 // d. If kPresent is true, then |
| 415 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); | 513 GotoIf(WordNotEqual(k_present, TrueConstant()), &done_element); |
| 416 | 514 |
| 417 // i. Let kValue be Get(O, Pk). | 515 // i. Let kValue be Get(O, Pk). |
| 418 // ii. ReturnIfAbrupt(kValue). | 516 // ii. ReturnIfAbrupt(kValue). |
| 419 Node* k_value = GetProperty(context(), o(), k()); | 517 Node* k_value = GetProperty(context(), o(), k()); |
| 420 | 518 |
| 421 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). | 519 // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). |
| 422 // iv. ReturnIfAbrupt(funcResult). | 520 // iv. ReturnIfAbrupt(funcResult). |
| 423 a_.Bind(processor(this, k_value, k())); | 521 a_.Bind(processor(this, DICTIONARY_ELEMENTS, k_value, k())); |
|
danno
2017/04/03 15:35:27
Although I know what you mean here, the elements m
| |
| 424 Goto(&done_element); | 522 Goto(&done_element); |
| 425 | 523 |
| 426 Bind(&done_element); | 524 Bind(&done_element); |
| 427 | 525 |
| 428 if (direction == ForEachDirection::kForward) { | 526 if (direction == ForEachDirection::kForward) { |
| 429 // e. Increase k by 1. | 527 // e. Increase k by 1. |
| 430 k_.Bind(NumberInc(k())); | 528 k_.Bind(NumberInc(k())); |
| 431 } else { | 529 } else { |
| 432 // e. Decrease k by 1. | 530 // e. Decrease k by 1. |
| 433 k_.Bind(NumberDec(k())); | 531 k_.Bind(NumberDec(k())); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 466 Node* elements = LoadElements(o_); | 564 Node* elements = LoadElements(o_); |
| 467 Node* base_ptr = | 565 Node* base_ptr = |
| 468 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | 566 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
| 469 Node* external_ptr = | 567 Node* external_ptr = |
| 470 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | 568 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
| 471 MachineType::Pointer()); | 569 MachineType::Pointer()); |
| 472 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); | 570 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); |
| 473 Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, | 571 Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, |
| 474 SMI_PARAMETERS); | 572 SMI_PARAMETERS); |
| 475 k_.Bind(index); | 573 k_.Bind(index); |
| 476 a_.Bind(processor(this, value, index)); | 574 a_.Bind(processor(this, kind, value, index)); |
| 477 }; | 575 }; |
| 478 BuildFastLoop(list, SmiConstant(0), len_, body, 1, | 576 BuildFastLoop(list, SmiConstant(0), len_, body, 1, |
| 479 ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost); | 577 ParameterMode::SMI_PARAMETERS, IndexAdvanceMode::kPost); |
| 480 } | 578 } |
| 481 | 579 |
| 482 void VisitAllFastElementsOneKind(ElementsKind kind, | 580 void VisitAllFastElementsOneKind(ElementsKind kind, |
| 483 const CallResultProcessor& processor, | 581 const CallResultProcessor& processor, |
| 484 Label* array_changed, ParameterMode mode, | 582 Label* array_changed, ParameterMode mode, |
| 485 ForEachDirection direction) { | 583 ForEachDirection direction) { |
| 486 Comment("begin VisitAllFastElementsOneKind"); | 584 Comment("begin VisitAllFastElementsOneKind"); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 522 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); | 620 Node* offset = ElementOffsetFromIndex(index, kind, mode, base_size); |
| 523 Node* value = nullptr; | 621 Node* value = nullptr; |
| 524 if (kind == FAST_ELEMENTS) { | 622 if (kind == FAST_ELEMENTS) { |
| 525 value = LoadObjectField(elements, offset); | 623 value = LoadObjectField(elements, offset); |
| 526 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); | 624 GotoIf(WordEqual(value, TheHoleConstant()), &hole_element); |
| 527 } else { | 625 } else { |
| 528 Node* double_value = | 626 Node* double_value = |
| 529 LoadDoubleWithHoleCheck(elements, offset, &hole_element); | 627 LoadDoubleWithHoleCheck(elements, offset, &hole_element); |
| 530 value = AllocateHeapNumberWithValue(double_value); | 628 value = AllocateHeapNumberWithValue(double_value); |
| 531 } | 629 } |
| 532 a_.Bind(processor(this, value, k())); | 630 a_.Bind(processor(this, kind, value, k())); |
| 533 Goto(&one_element_done); | 631 Goto(&one_element_done); |
| 534 | 632 |
| 535 Bind(&hole_element); | 633 Bind(&hole_element); |
| 536 // Check if o's prototype change unexpectedly has elements after the | 634 // Check if o's prototype change unexpectedly has elements after the |
| 537 // callback in the case of a hole. | 635 // callback in the case of a hole. |
| 538 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, | 636 BranchIfPrototypesHaveNoElements(o_map, &one_element_done, |
| 539 array_changed); | 637 array_changed); |
| 540 | 638 |
| 541 Bind(&one_element_done); | 639 Bind(&one_element_done); |
| 542 }, | 640 }, |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 625 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); | 723 CodeStubArguments args(this, ChangeInt32ToIntPtr(argc)); |
| 626 Node* receiver = args.GetReceiver(); | 724 Node* receiver = args.GetReceiver(); |
| 627 Node* kind = nullptr; | 725 Node* kind = nullptr; |
| 628 | 726 |
| 629 Label fast(this); | 727 Label fast(this); |
| 630 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, | 728 BranchIfFastJSArray(receiver, context, FastJSArrayAccessMode::ANY_ACCESS, |
| 631 &fast, &runtime); | 729 &fast, &runtime); |
| 632 | 730 |
| 633 Bind(&fast); | 731 Bind(&fast); |
| 634 { | 732 { |
| 635 // Disallow pushing onto prototypes. It might be the JSArray prototype. | |
| 636 // Disallow pushing onto non-extensible objects. | |
| 637 Comment("Disallow pushing onto prototypes"); | |
| 638 Node* map = LoadMap(receiver); | |
| 639 Node* bit_field2 = LoadMapBitField2(map); | |
| 640 int mask = static_cast<int>(Map::IsPrototypeMapBits::kMask) | | |
| 641 (1 << Map::kIsExtensible); | |
| 642 Node* test = Word32And(bit_field2, Int32Constant(mask)); | |
| 643 GotoIf(Word32NotEqual(test, Int32Constant(1 << Map::kIsExtensible)), | |
| 644 &runtime); | |
| 645 | |
| 646 // Disallow pushing onto arrays in dictionary named property mode. We need | |
| 647 // to figure out whether the length property is still writable. | |
| 648 Comment("Disallow pushing onto arrays in dictionary named property mode"); | |
| 649 GotoIf(IsDictionaryMap(map), &runtime); | |
| 650 | |
| 651 // Check whether the length property is writable. The length property is the | |
| 652 // only default named property on arrays. It's nonconfigurable, hence is | |
| 653 // guaranteed to stay the first property. | |
| 654 Node* descriptors = LoadMapDescriptors(map); | |
| 655 Node* details = | |
| 656 LoadFixedArrayElement(descriptors, DescriptorArray::ToDetailsIndex(0)); | |
| 657 GotoIf(IsSetSmi(details, PropertyDetails::kAttributesReadOnlyMask), | |
| 658 &runtime); | |
| 659 | |
| 660 arg_index.Bind(IntPtrConstant(0)); | 733 arg_index.Bind(IntPtrConstant(0)); |
| 661 kind = DecodeWord32<Map::ElementsKindBits>(bit_field2); | 734 kind = EnsureArrayPushable(receiver, &runtime); |
| 662 | |
| 663 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), | 735 GotoIf(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_SMI_ELEMENTS)), |
| 664 &object_push_pre); | 736 &object_push_pre); |
| 665 | 737 |
| 666 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, context, receiver, | 738 Node* new_length = BuildAppendJSArray(FAST_SMI_ELEMENTS, receiver, args, |
| 667 args, arg_index, &smi_transition); | 739 arg_index, &smi_transition); |
| 668 args.PopAndReturn(new_length); | 740 args.PopAndReturn(new_length); |
| 669 } | 741 } |
| 670 | 742 |
| 671 // If the argument is not a smi, then use a heavyweight SetProperty to | 743 // If the argument is not a smi, then use a heavyweight SetProperty to |
| 672 // transition the array for only the single next element. If the argument is | 744 // transition the array for only the single next element. If the argument is |
| 673 // a smi, the failure is due to some other reason and we should fall back on | 745 // a smi, the failure is due to some other reason and we should fall back on |
| 674 // the most generic implementation for the rest of the array. | 746 // the most generic implementation for the rest of the array. |
| 675 Bind(&smi_transition); | 747 Bind(&smi_transition); |
| 676 { | 748 { |
| 677 Node* arg = args.AtIndex(arg_index.value()); | 749 Node* arg = args.AtIndex(arg_index.value()); |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 695 } | 767 } |
| 696 | 768 |
| 697 Bind(&object_push_pre); | 769 Bind(&object_push_pre); |
| 698 { | 770 { |
| 699 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), | 771 Branch(Int32GreaterThan(kind, Int32Constant(FAST_HOLEY_ELEMENTS)), |
| 700 &double_push, &object_push); | 772 &double_push, &object_push); |
| 701 } | 773 } |
| 702 | 774 |
| 703 Bind(&object_push); | 775 Bind(&object_push); |
| 704 { | 776 { |
| 705 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, context, receiver, | 777 Node* new_length = BuildAppendJSArray(FAST_ELEMENTS, receiver, args, |
| 706 args, arg_index, &default_label); | 778 arg_index, &default_label); |
| 707 args.PopAndReturn(new_length); | 779 args.PopAndReturn(new_length); |
| 708 } | 780 } |
| 709 | 781 |
| 710 Bind(&double_push); | 782 Bind(&double_push); |
| 711 { | 783 { |
| 712 Node* new_length = | 784 Node* new_length = BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, receiver, args, |
| 713 BuildAppendJSArray(FAST_DOUBLE_ELEMENTS, context, receiver, args, | 785 arg_index, &double_transition); |
| 714 arg_index, &double_transition); | |
| 715 args.PopAndReturn(new_length); | 786 args.PopAndReturn(new_length); |
| 716 } | 787 } |
| 717 | 788 |
| 718 // If the argument is not a double, then use a heavyweight SetProperty to | 789 // If the argument is not a double, then use a heavyweight SetProperty to |
| 719 // transition the array for only the single next element. If the argument is | 790 // transition the array for only the single next element. If the argument is |
| 720 // a double, the failure is due to some other reason and we should fall back | 791 // a double, the failure is due to some other reason and we should fall back |
| 721 // on the most generic implementation for the rest of the array. | 792 // on the most generic implementation for the rest of the array. |
| 722 Bind(&double_transition); | 793 Bind(&double_transition); |
| 723 { | 794 { |
| 724 Node* arg = args.AtIndex(arg_index.value()); | 795 Node* arg = args.AtIndex(arg_index.value()); |
| (...skipping 1392 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2117 { | 2188 { |
| 2118 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 2189 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
| 2119 CallRuntime(Runtime::kThrowTypeError, context, message, | 2190 CallRuntime(Runtime::kThrowTypeError, context, message, |
| 2120 HeapConstant(operation)); | 2191 HeapConstant(operation)); |
| 2121 Unreachable(); | 2192 Unreachable(); |
| 2122 } | 2193 } |
| 2123 } | 2194 } |
| 2124 | 2195 |
| 2125 } // namespace internal | 2196 } // namespace internal |
| 2126 } // namespace v8 | 2197 } // namespace v8 |
| OLD | NEW |