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 { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
147 } | 147 } |
148 BIND(&false_continue); | 148 BIND(&false_continue); |
149 return a(); | 149 return a(); |
150 } | 150 } |
151 | 151 |
152 Node* MapResultGenerator() { | 152 Node* MapResultGenerator() { |
153 // 5. Let A be ? ArraySpeciesCreate(O, len). | 153 // 5. Let A be ? ArraySpeciesCreate(O, len). |
154 return ArraySpeciesCreate(context(), o(), len_); | 154 return ArraySpeciesCreate(context(), o(), len_); |
155 } | 155 } |
156 | 156 |
157 Node* TypedArrayMapResultGenerator() { | |
158 // 6. Let A be ? TypedArraySpeciesCreate(O, len). | |
159 Node* A = TypedArraySpeciesCreateByLength(context(), o(), len_); | |
danno
2017/04/24 16:11:16
super nit: elsewhere to conform to the coding styl
| |
160 // In the Spec and our current implementation, the length check is already | |
161 // performed in TypedArraySpeciesCreate. Repeating the check here to | |
162 // keep this invariant local. | |
163 fast_typed_array_target_ = WordAnd( | |
164 WordEqual(LoadInstanceType(LoadElements(o_)), | |
165 LoadInstanceType(LoadElements(A))), | |
166 WordEqual(len_, LoadObjectField(A, JSTypedArray::kLengthOffset))); | |
167 return A; | |
168 } | |
169 | |
157 Node* MapProcessor(Node* k_value, Node* k) { | 170 Node* MapProcessor(Node* k_value, Node* k) { |
158 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. | 171 // i. Let kValue be ? Get(O, Pk). Performed by the caller of MapProcessor. |
159 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). | 172 // ii. Let mappedValue be ? Call(callbackfn, T, kValue, k, O). |
160 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), | 173 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), |
161 callbackfn(), this_arg(), k_value, k, o()); | 174 callbackfn(), this_arg(), k_value, k, o()); |
162 | 175 |
163 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). | 176 // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue). |
164 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); | 177 CallRuntime(Runtime::kCreateDataProperty, context(), a(), k, mappedValue); |
165 return a(); | 178 return a(); |
166 } | 179 } |
167 | 180 |
181 // See tc39.github.io/ecma262/#sec-%typedarray%.prototype.map. | |
182 Node* TypedArrayMapProcessor(Node* k_value, Node* k) { | |
183 // 8. c. Let mappedValue be ? Call(callbackfn, T, « kValue, k, O »). | |
184 Node* mappedValue = CallJS(CodeFactory::Call(isolate()), context(), | |
185 callbackfn(), this_arg(), k_value, k, o()); | |
186 Label fast(this), slow(this), done(this), detached(this, Label::kDeferred); | |
187 | |
188 // 8. d. Perform ? Set(A, Pk, mappedValue, true). | |
189 // Since we know that A is a TypedArray, this always ends up in | |
190 // #sec-integer-indexed-exotic-objects-set-p-v-receiver and then | |
191 // tc39.github.io/ecma262/#sec-integerindexedelementset . | |
192 Branch(fast_typed_array_target_, &fast, &slow); | |
193 | |
194 BIND(&fast); | |
195 // #sec-integerindexedelementset 3. Let numValue be ? ToNumber(value). | |
196 Node* num_value = ToNumber(context(), mappedValue); | |
197 // The only way how this can bailout is because of a detached buffer. | |
198 EmitElementStore( | |
199 a(), k, num_value, false, source_elements_kind_, | |
200 KeyedAccessStoreMode::STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS, | |
201 &detached); | |
202 Goto(&done); | |
203 | |
204 BIND(&slow); | |
205 CallRuntime(Runtime::kSetProperty, context(), a(), k, mappedValue, | |
206 SmiConstant(STRICT)); | |
207 Goto(&done); | |
208 | |
209 BIND(&detached); | |
210 { | |
211 // tc39.github.io/ecma262/#sec-integerindexedelementset | |
212 // 5. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. | |
213 CallRuntime(Runtime::kThrowTypeError, context_, | |
214 SmiConstant(MessageTemplate::kDetachedOperation), | |
215 name_string_); | |
216 Unreachable(); | |
217 } | |
218 | |
219 BIND(&done); | |
220 return a(); | |
221 } | |
222 | |
168 void NullPostLoopAction() {} | 223 void NullPostLoopAction() {} |
169 | 224 |
170 protected: | 225 protected: |
171 Node* context() { return context_; } | 226 Node* context() { return context_; } |
172 Node* receiver() { return receiver_; } | 227 Node* receiver() { return receiver_; } |
173 Node* new_target() { return new_target_; } | 228 Node* new_target() { return new_target_; } |
174 Node* o() { return o_; } | 229 Node* o() { return o_; } |
175 Node* len() { return len_; } | 230 Node* len() { return len_; } |
176 Node* callbackfn() { return callbackfn_; } | 231 Node* callbackfn() { return callbackfn_; } |
177 Node* this_arg() { return this_arg_; } | 232 Node* this_arg() { return this_arg_; } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
288 k_.Bind(initial_k); | 343 k_.Bind(initial_k); |
289 o_ = o; | 344 o_ = o; |
290 len_ = len; | 345 len_ = len; |
291 to_.Bind(to); | 346 to_.Bind(to); |
292 } | 347 } |
293 | 348 |
294 void GenerateIteratingTypedArrayBuiltinBody( | 349 void GenerateIteratingTypedArrayBuiltinBody( |
295 const char* name, const BuiltinResultGenerator& generator, | 350 const char* name, const BuiltinResultGenerator& generator, |
296 const CallResultProcessor& processor, const PostLoopAction& action, | 351 const CallResultProcessor& processor, const PostLoopAction& action, |
297 ForEachDirection direction = ForEachDirection::kForward) { | 352 ForEachDirection direction = ForEachDirection::kForward) { |
298 Node* name_string = | 353 name_string_ = |
299 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name)); | 354 HeapConstant(isolate()->factory()->NewStringFromAsciiChecked(name)); |
300 | 355 |
301 // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray | 356 // ValidateTypedArray: tc39.github.io/ecma262/#sec-validatetypedarray |
302 | 357 |
303 Label throw_not_typed_array(this, Label::kDeferred), | 358 Label throw_not_typed_array(this, Label::kDeferred), |
304 throw_detached(this, Label::kDeferred); | 359 throw_detached(this, Label::kDeferred); |
305 | 360 |
306 GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array); | 361 GotoIf(TaggedIsSmi(receiver_), &throw_not_typed_array); |
307 GotoIfNot(HasInstanceType(receiver_, JS_TYPED_ARRAY_TYPE), | 362 GotoIfNot(HasInstanceType(receiver_, JS_TYPED_ARRAY_TYPE), |
308 &throw_not_typed_array); | 363 &throw_not_typed_array); |
(...skipping 14 matching lines...) Expand all Loading... | |
323 { | 378 { |
324 CallRuntime(Runtime::kThrowTypeError, context_, | 379 CallRuntime(Runtime::kThrowTypeError, context_, |
325 SmiConstant(MessageTemplate::kNotTypedArray)); | 380 SmiConstant(MessageTemplate::kNotTypedArray)); |
326 Unreachable(); | 381 Unreachable(); |
327 } | 382 } |
328 | 383 |
329 BIND(&throw_detached); | 384 BIND(&throw_detached); |
330 { | 385 { |
331 CallRuntime(Runtime::kThrowTypeError, context_, | 386 CallRuntime(Runtime::kThrowTypeError, context_, |
332 SmiConstant(MessageTemplate::kDetachedOperation), | 387 SmiConstant(MessageTemplate::kDetachedOperation), |
333 name_string); | 388 name_string_); |
334 Unreachable(); | 389 Unreachable(); |
335 } | 390 } |
336 | 391 |
337 BIND(&throw_not_callable); | 392 BIND(&throw_not_callable); |
338 { | 393 { |
339 CallRuntime(Runtime::kThrowTypeError, context_, | 394 CallRuntime(Runtime::kThrowTypeError, context_, |
340 SmiConstant(MessageTemplate::kCalledNonCallable), | 395 SmiConstant(MessageTemplate::kCalledNonCallable), |
341 callbackfn_); | 396 callbackfn_); |
342 Unreachable(); | 397 Unreachable(); |
343 } | 398 } |
(...skipping 16 matching lines...) Expand all Loading... | |
360 label_ptrs.push_back(&label); | 415 label_ptrs.push_back(&label); |
361 } | 416 } |
362 | 417 |
363 BIND(&distinguish_types); | 418 BIND(&distinguish_types); |
364 | 419 |
365 if (direction == ForEachDirection::kForward) { | 420 if (direction == ForEachDirection::kForward) { |
366 k_.Bind(SmiConstant(0)); | 421 k_.Bind(SmiConstant(0)); |
367 } else { | 422 } else { |
368 k_.Bind(NumberDec(len())); | 423 k_.Bind(NumberDec(len())); |
369 } | 424 } |
370 a_.Bind(generator(this)); | 425 Node* instance_type = LoadInstanceType(LoadElements(o_)); |
371 Node* elements_type = LoadInstanceType(LoadElements(o_)); | 426 Switch(instance_type, &unexpected_instance_type, instance_types.data(), |
372 Switch(elements_type, &unexpected_instance_type, instance_types.data(), | |
373 label_ptrs.data(), labels.size()); | 427 label_ptrs.data(), labels.size()); |
374 | 428 |
375 for (size_t i = 0; i < labels.size(); ++i) { | 429 for (size_t i = 0; i < labels.size(); ++i) { |
376 BIND(&labels[i]); | 430 BIND(&labels[i]); |
377 Label done(this); | 431 Label done(this); |
432 source_elements_kind_ = ElementsKindForInstanceType( | |
433 static_cast<InstanceType>(instance_types[i])); | |
434 a_.Bind(generator(this)); | |
378 // TODO(tebbi): Silently cancelling the loop on buffer detachment is a | 435 // TODO(tebbi): Silently cancelling the loop on buffer detachment is a |
379 // spec violation. Should go to &detached and throw a TypeError instead. | 436 // spec violation. Should go to &throw_detached_ and throw a TypeError |
380 VisitAllTypedArrayElements( | 437 // instead. |
381 ElementsKindForInstanceType( | 438 VisitAllTypedArrayElements(array_buffer, processor, &done, direction); |
382 static_cast<InstanceType>(instance_types[i])), | |
383 array_buffer, processor, &done, direction); | |
384 Goto(&done); | 439 Goto(&done); |
385 // No exception, return success | 440 // No exception, return success |
386 BIND(&done); | 441 BIND(&done); |
387 action(this); | 442 action(this); |
388 Return(a_.value()); | 443 Return(a_.value()); |
389 } | 444 } |
390 } | 445 } |
391 | 446 |
392 void GenerateIteratingArrayBuiltinLoopContinuation( | 447 void GenerateIteratingArrayBuiltinLoopContinuation( |
393 const CallResultProcessor& processor, const PostLoopAction& action, | 448 const CallResultProcessor& processor, const PostLoopAction& action, |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
452 | 507 |
453 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND) | 508 TYPED_ARRAYS(INSTANCE_TYPE_TO_ELEMENTS_KIND) |
454 #undef INSTANCE_TYPE_TO_ELEMENTS_KIND | 509 #undef INSTANCE_TYPE_TO_ELEMENTS_KIND |
455 | 510 |
456 default: | 511 default: |
457 UNREACHABLE(); | 512 UNREACHABLE(); |
458 return static_cast<ElementsKind>(-1); | 513 return static_cast<ElementsKind>(-1); |
459 } | 514 } |
460 } | 515 } |
461 | 516 |
462 void VisitAllTypedArrayElements(ElementsKind kind, Node* array_buffer, | 517 void VisitAllTypedArrayElements(Node* array_buffer, |
463 const CallResultProcessor& processor, | 518 const CallResultProcessor& processor, |
464 Label* detached, ForEachDirection direction) { | 519 Label* detached, ForEachDirection direction) { |
465 VariableList list({&a_, &k_, &to_}, zone()); | 520 VariableList list({&a_, &k_, &to_}, zone()); |
466 | 521 |
467 FastLoopBody body = [&](Node* index) { | 522 FastLoopBody body = [&](Node* index) { |
468 GotoIf(IsDetachedBuffer(array_buffer), detached); | 523 GotoIf(IsDetachedBuffer(array_buffer), detached); |
469 Node* elements = LoadElements(o_); | 524 Node* elements = LoadElements(o_); |
470 Node* base_ptr = | 525 Node* base_ptr = |
471 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); | 526 LoadObjectField(elements, FixedTypedArrayBase::kBasePointerOffset); |
472 Node* external_ptr = | 527 Node* external_ptr = |
473 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, | 528 LoadObjectField(elements, FixedTypedArrayBase::kExternalPointerOffset, |
474 MachineType::Pointer()); | 529 MachineType::Pointer()); |
475 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); | 530 Node* data_ptr = IntPtrAdd(BitcastTaggedToWord(base_ptr), external_ptr); |
476 Node* value = LoadFixedTypedArrayElementAsTagged(data_ptr, index, kind, | 531 Node* value = LoadFixedTypedArrayElementAsTagged( |
477 SMI_PARAMETERS); | 532 data_ptr, index, source_elements_kind_, SMI_PARAMETERS); |
478 k_.Bind(index); | 533 k_.Bind(index); |
479 a_.Bind(processor(this, value, index)); | 534 a_.Bind(processor(this, value, index)); |
480 }; | 535 }; |
481 Node* start = SmiConstant(0); | 536 Node* start = SmiConstant(0); |
482 Node* end = len_; | 537 Node* end = len_; |
483 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost; | 538 IndexAdvanceMode advance_mode = IndexAdvanceMode::kPost; |
484 int incr = 1; | 539 int incr = 1; |
485 if (direction == ForEachDirection::kReverse) { | 540 if (direction == ForEachDirection::kReverse) { |
486 std::swap(start, end); | 541 std::swap(start, end); |
487 advance_mode = IndexAdvanceMode::kPre; | 542 advance_mode = IndexAdvanceMode::kPre; |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
606 } | 661 } |
607 } | 662 } |
608 | 663 |
609 Node* callbackfn_ = nullptr; | 664 Node* callbackfn_ = nullptr; |
610 Node* o_ = nullptr; | 665 Node* o_ = nullptr; |
611 Node* this_arg_ = nullptr; | 666 Node* this_arg_ = nullptr; |
612 Node* len_ = nullptr; | 667 Node* len_ = nullptr; |
613 Node* context_ = nullptr; | 668 Node* context_ = nullptr; |
614 Node* receiver_ = nullptr; | 669 Node* receiver_ = nullptr; |
615 Node* new_target_ = nullptr; | 670 Node* new_target_ = nullptr; |
671 Node* fast_typed_array_target_ = nullptr; | |
672 Node* name_string_ = nullptr; | |
616 Variable k_; | 673 Variable k_; |
617 Variable a_; | 674 Variable a_; |
618 Variable to_; | 675 Variable to_; |
676 ElementsKind source_elements_kind_ = ElementsKind::NO_ELEMENTS; | |
619 }; | 677 }; |
620 | 678 |
621 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { | 679 TF_BUILTIN(FastArrayPush, CodeStubAssembler) { |
622 VARIABLE(arg_index, MachineType::PointerRepresentation()); | 680 VARIABLE(arg_index, MachineType::PointerRepresentation()); |
623 Label default_label(this, &arg_index); | 681 Label default_label(this, &arg_index); |
624 Label smi_transition(this); | 682 Label smi_transition(this); |
625 Label object_push_pre(this); | 683 Label object_push_pre(this); |
626 Label object_push(this, &arg_index); | 684 Label object_push(this, &arg_index); |
627 Label double_push(this, &arg_index); | 685 Label double_push(this, &arg_index); |
628 Label double_transition(this); | 686 Label double_transition(this); |
(...skipping 474 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1103 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, | 1161 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, |
1104 new_target); | 1162 new_target); |
1105 | 1163 |
1106 GenerateIteratingArrayBuiltinBody( | 1164 GenerateIteratingArrayBuiltinBody( |
1107 "Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator, | 1165 "Array.prototype.map", &ArrayBuiltinCodeStubAssembler::MapResultGenerator, |
1108 &ArrayBuiltinCodeStubAssembler::MapProcessor, | 1166 &ArrayBuiltinCodeStubAssembler::MapProcessor, |
1109 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, | 1167 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction, |
1110 CodeFactory::ArrayMapLoopContinuation(isolate())); | 1168 CodeFactory::ArrayMapLoopContinuation(isolate())); |
1111 } | 1169 } |
1112 | 1170 |
1171 TF_BUILTIN(TypedArrayPrototypeMap, ArrayBuiltinCodeStubAssembler) { | |
1172 Node* context = Parameter(Descriptor::kContext); | |
1173 Node* receiver = Parameter(Descriptor::kReceiver); | |
1174 Node* callbackfn = Parameter(Descriptor::kCallbackFn); | |
1175 Node* this_arg = Parameter(Descriptor::kThisArg); | |
1176 Node* new_target = Parameter(Descriptor::kNewTarget); | |
1177 | |
1178 InitIteratingArrayBuiltinBody(context, receiver, callbackfn, this_arg, | |
1179 new_target); | |
1180 | |
1181 GenerateIteratingTypedArrayBuiltinBody( | |
1182 "%TypedArray%.prototype.map", | |
1183 &ArrayBuiltinCodeStubAssembler::TypedArrayMapResultGenerator, | |
1184 &ArrayBuiltinCodeStubAssembler::TypedArrayMapProcessor, | |
1185 &ArrayBuiltinCodeStubAssembler::NullPostLoopAction); | |
1186 } | |
1187 | |
1113 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { | 1188 TF_BUILTIN(ArrayIsArray, CodeStubAssembler) { |
1114 Node* object = Parameter(Descriptor::kArg); | 1189 Node* object = Parameter(Descriptor::kArg); |
1115 Node* context = Parameter(Descriptor::kContext); | 1190 Node* context = Parameter(Descriptor::kContext); |
1116 | 1191 |
1117 Label call_runtime(this), return_true(this), return_false(this); | 1192 Label call_runtime(this), return_true(this), return_false(this); |
1118 | 1193 |
1119 GotoIf(TaggedIsSmi(object), &return_false); | 1194 GotoIf(TaggedIsSmi(object), &return_false); |
1120 Node* instance_type = LoadInstanceType(object); | 1195 Node* instance_type = LoadInstanceType(object); |
1121 | 1196 |
1122 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), | 1197 GotoIf(Word32Equal(instance_type, Int32Constant(JS_ARRAY_TYPE)), |
(...skipping 1041 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2164 { | 2239 { |
2165 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); | 2240 Node* message = SmiConstant(MessageTemplate::kDetachedOperation); |
2166 CallRuntime(Runtime::kThrowTypeError, context, message, | 2241 CallRuntime(Runtime::kThrowTypeError, context, message, |
2167 HeapConstant(operation)); | 2242 HeapConstant(operation)); |
2168 Unreachable(); | 2243 Unreachable(); |
2169 } | 2244 } |
2170 } | 2245 } |
2171 | 2246 |
2172 } // namespace internal | 2247 } // namespace internal |
2173 } // namespace v8 | 2248 } // namespace v8 |
OLD | NEW |