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 { |
| (...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_); | |
| 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); | |
|
Camillo Bruni
2017/04/11 13:16:06
drive-by-comment: Could you upgrade your implement
| |
| 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 |