OLD | NEW |
---|---|
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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.h" | 5 #include "src/builtins/builtins.h" |
6 | 6 |
7 #include "src/api-arguments.h" | 7 #include "src/api-arguments.h" |
8 #include "src/api-natives.h" | 8 #include "src/api-natives.h" |
9 #include "src/api.h" | 9 #include "src/api.h" |
10 #include "src/base/ieee754.h" | 10 #include "src/base/ieee754.h" |
(...skipping 325 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
336 assembler->Return(assembler->BooleanConstant(true)); | 336 assembler->Return(assembler->BooleanConstant(true)); |
337 | 337 |
338 assembler->Bind(&return_false); | 338 assembler->Bind(&return_false); |
339 assembler->Return(assembler->BooleanConstant(false)); | 339 assembler->Return(assembler->BooleanConstant(false)); |
340 | 340 |
341 assembler->Bind(&call_runtime); | 341 assembler->Bind(&call_runtime); |
342 assembler->Return( | 342 assembler->Return( |
343 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); | 343 assembler->CallRuntime(Runtime::kArrayIsArray, context, object)); |
344 } | 344 } |
345 | 345 |
346 void Builtins::Generate_ArrayIncludes(CodeStubAssembler* assembler) { | |
347 typedef compiler::Node Node; | |
348 typedef CodeStubAssembler::Label Label; | |
349 typedef CodeStubAssembler::Variable Variable; | |
350 | |
351 Node* array = assembler->Parameter(0); | |
352 Node* search_element = assembler->Parameter(1); | |
353 Node* start_from = assembler->Parameter(2); | |
354 Node* context = assembler->Parameter(3 + 2); | |
355 | |
356 Node* int32_zero = assembler->Int32Constant(0); | |
357 Node* int32_one = assembler->Int32Constant(1); | |
358 | |
359 Node* the_hole = assembler->TheHoleConstant(); | |
360 Node* undefined = assembler->UndefinedConstant(); | |
361 Node* heap_number_map = assembler->HeapNumberMapConstant(); | |
362 | |
363 Variable len(assembler, MachineRepresentation::kWord32), | |
364 k(assembler, MachineRepresentation::kWord32), | |
365 n(assembler, MachineRepresentation::kWord32); | |
366 | |
367 Label init_k(assembler), return_true(assembler), return_false(assembler), | |
368 call_runtime(assembler); | |
369 | |
370 { | |
371 // Take slow path if not a JSArray, if retrieving elements requires | |
372 // traversing prototype, or if access checks are required. | |
373 Label init_len(assembler); | |
374 assembler->BranchIfFastJSArray(array, context, &init_len, &call_runtime); | |
375 | |
376 assembler->Bind(&init_len); | |
377 len.Bind(assembler->SmiToWord( | |
378 assembler->LoadObjectField(array, JSArray::kLengthOffset))); | |
379 | |
380 assembler->GotoUnless(assembler->Word32Equal(len.value(), int32_zero), | |
381 &init_k); | |
382 assembler->Return(assembler->BooleanConstant(false)); | |
383 } | |
384 | |
385 assembler->Bind(&init_k); | |
386 { | |
387 Label done(assembler), init_k_smi(assembler), init_k_heap_num(assembler), | |
388 init_k_zero(assembler), init_k_n(assembler); | |
389 Callable call_to_integer = CodeFactory::ToInteger(assembler->isolate()); | |
390 Node* tagged_n = assembler->CallStub(call_to_integer, context, start_from); | |
391 | |
392 assembler->Branch(assembler->WordIsSmi(tagged_n), &init_k_smi, | |
393 &init_k_heap_num); | |
394 | |
395 assembler->Bind(&init_k_smi); | |
396 { | |
397 n.Bind(assembler->SmiToWord32(tagged_n)); | |
398 assembler->Goto(&init_k_n); | |
399 } | |
400 | |
401 assembler->Bind(&init_k_heap_num); | |
402 { | |
403 Label abort(assembler); | |
404 Node* fp_len = assembler->ChangeInt32ToFloat64(len.value()); | |
405 Node* fp_n = assembler->LoadHeapNumberValue(tagged_n); | |
406 assembler->GotoIf(assembler->Float64GreaterThanOrEqual(fp_n, fp_len), | |
407 &abort); | |
408 n.Bind(assembler->TruncateFloat64ToWord32(fp_n)); | |
409 assembler->Goto(&init_k_n); | |
410 | |
411 assembler->Bind(&abort); | |
412 assembler->Return(assembler->BooleanConstant(false)); | |
413 } | |
414 | |
415 assembler->Bind(&init_k_n); | |
416 { | |
417 Label if_positive(assembler), if_negative(assembler), done(assembler); | |
418 assembler->Branch(assembler->Int32LessThan(n.value(), int32_zero), | |
419 &if_negative, &if_positive); | |
420 | |
421 assembler->Bind(&if_positive); | |
422 { | |
423 k.Bind(n.value()); | |
424 assembler->Goto(&done); | |
425 } | |
426 | |
427 assembler->Bind(&if_negative); | |
428 { | |
429 k.Bind(assembler->Int32Add(len.value(), n.value())); | |
430 assembler->Branch(assembler->Int32LessThan(k.value(), int32_zero), | |
431 &init_k_zero, &done); | |
432 } | |
433 | |
434 assembler->Bind(&init_k_zero); | |
435 { | |
436 k.Bind(int32_zero); | |
437 assembler->Goto(&done); | |
438 } | |
439 | |
440 assembler->Bind(&done); | |
441 } | |
442 } | |
443 | |
444 int32_t element_kinds[] = { | |
445 FAST_SMI_ELEMENTS, FAST_HOLEY_SMI_ELEMENTS, FAST_ELEMENTS, | |
446 FAST_HOLEY_ELEMENTS, FAST_DOUBLE_ELEMENTS, FAST_HOLEY_DOUBLE_ELEMENTS, | |
447 }; | |
448 | |
449 Label if_smiorobjects(assembler), if_packed_doubles(assembler), | |
450 if_holey_doubles(assembler); | |
451 Label* element_kind_handlers[] = {&if_smiorobjects, &if_smiorobjects, | |
452 &if_smiorobjects, &if_smiorobjects, | |
453 &if_packed_doubles, &if_holey_doubles}; | |
454 | |
455 Node* map = assembler->LoadMap(array); | |
456 Node* bit_field2 = assembler->LoadMapBitField2(map); | |
457 Node* elements_kind = | |
458 assembler->BitFieldDecode<Map::ElementsKindBits>(bit_field2); | |
459 Node* elements = assembler->LoadElements(array); | |
460 assembler->Switch(elements_kind, &return_false, element_kinds, | |
461 element_kind_handlers, arraysize(element_kinds)); | |
462 | |
463 assembler->Bind(&if_smiorobjects); | |
caitp
2016/07/17 03:26:47
There are lots of different tight loops here, to b
Benedikt Meurer
2016/07/17 06:03:18
Awesome, I think this is the maximum you can get o
caitp
2016/07/18 22:10:23
I had looked at adding a JSBuiltinReducer for Arra
| |
464 { | |
465 Label ident_loop(assembler, &k), heap_num_loop(assembler), | |
466 string_loop(assembler, &k), simd_loop(assembler), | |
467 undef_loop(assembler, &k); | |
468 | |
469 assembler->GotoIf(assembler->WordIsSmi(search_element), &ident_loop); | |
470 assembler->GotoIf(assembler->WordEqual(search_element, undefined), | |
471 &undef_loop); | |
472 Node* map = assembler->LoadMap(search_element); | |
473 assembler->GotoIf(assembler->WordEqual(map, heap_number_map), | |
474 &heap_num_loop); | |
475 Node* search_type = assembler->LoadMapInstanceType(map); | |
476 assembler->GotoIf( | |
477 assembler->Int32LessThan( | |
478 search_type, assembler->Int32Constant(FIRST_NONSTRING_TYPE)), | |
479 &string_loop); | |
480 assembler->GotoIf( | |
481 assembler->WordEqual(search_type, | |
482 assembler->Int32Constant(SIMD128_VALUE_TYPE)), | |
483 &simd_loop); | |
484 assembler->Goto(&ident_loop); | |
485 | |
486 assembler->Bind(&ident_loop); | |
487 { | |
488 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
489 &return_false); | |
490 Node* element_k = assembler->LoadFixedArrayElement(elements, k.value()); | |
491 assembler->GotoIf(assembler->WordEqual(element_k, search_element), | |
492 &return_true); | |
493 | |
494 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
495 assembler->Goto(&ident_loop); | |
496 } | |
497 | |
498 assembler->Bind(&undef_loop); | |
499 { | |
500 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
501 &return_false); | |
502 Node* element_k = assembler->LoadFixedArrayElement(elements, k.value()); | |
503 assembler->GotoIf(assembler->WordEqual(element_k, undefined), | |
504 &return_true); | |
505 assembler->GotoIf(assembler->WordEqual(element_k, the_hole), | |
506 &return_true); | |
507 | |
508 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
509 assembler->Goto(&undef_loop); | |
510 } | |
511 | |
512 assembler->Bind(&heap_num_loop); | |
513 { | |
514 Label nan_loop(assembler, &k), not_nan_loop(assembler, &k); | |
515 Node* search_num = assembler->LoadHeapNumberValue(search_element); | |
516 assembler->BranchIfFloat64IsNaN(search_num, &nan_loop, ¬_nan_loop); | |
517 | |
518 assembler->Bind(¬_nan_loop); | |
519 { | |
520 Label continue_loop(assembler); | |
521 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
522 &return_false); | |
523 Node* element_k = assembler->LoadFixedArrayElement(elements, k.value()); | |
524 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); | |
525 assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), | |
526 heap_number_map), | |
527 &continue_loop); | |
528 assembler->BranchIfFloat64Equal( | |
529 search_num, assembler->LoadHeapNumberValue(element_k), &return_true, | |
530 &continue_loop); | |
531 | |
532 assembler->Bind(&continue_loop); | |
533 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
534 assembler->Goto(¬_nan_loop); | |
535 } | |
536 | |
537 assembler->Bind(&nan_loop); | |
538 { | |
539 Label continue_loop(assembler); | |
540 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
541 &return_false); | |
542 Node* element_k = assembler->LoadFixedArrayElement(elements, k.value()); | |
543 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); | |
544 assembler->GotoIf(assembler->WordNotEqual(assembler->LoadMap(element_k), | |
545 heap_number_map), | |
546 &continue_loop); | |
547 assembler->BranchIfFloat64IsNaN( | |
548 assembler->LoadHeapNumberValue(element_k), &return_true, | |
549 &continue_loop); | |
550 | |
551 assembler->Bind(&continue_loop); | |
552 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
553 assembler->Goto(&nan_loop); | |
554 } | |
555 } | |
556 | |
557 assembler->Bind(&string_loop); | |
558 { | |
559 Label continue_loop(assembler); | |
560 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
561 &return_false); | |
562 Node* element_k = assembler->LoadFixedArrayElement(elements, k.value()); | |
563 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); | |
564 assembler->GotoUnless(assembler->Int32LessThan( | |
565 assembler->LoadMapInstanceType(element_k), | |
566 assembler->Int32Constant(FIRST_NONSTRING_TYPE)), | |
567 &continue_loop); | |
568 | |
569 Callable callable = CodeFactory::StringEqual(assembler->isolate()); | |
570 Node* result = | |
571 assembler->CallStub(callable, context, search_element, element_k); | |
572 assembler->Branch( | |
573 assembler->WordEqual(assembler->BooleanConstant(true), result), | |
574 &return_true, &continue_loop); | |
575 | |
576 assembler->Bind(&continue_loop); | |
577 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
578 assembler->Goto(&string_loop); | |
579 } | |
580 | |
581 assembler->Bind(&simd_loop); | |
582 { | |
583 Label continue_loop(assembler, &k), loop_body(assembler, &k); | |
584 Node* map = assembler->LoadMap(search_element); | |
585 | |
586 assembler->Goto(&loop_body); | |
587 assembler->Bind(&loop_body); | |
588 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
589 &return_false); | |
590 | |
591 Node* element_k = assembler->LoadFixedArrayElement(elements, k.value()); | |
592 assembler->GotoIf(assembler->WordIsSmi(element_k), &continue_loop); | |
593 | |
594 Node* map_k = assembler->LoadMap(element_k); | |
595 assembler->BranchIfSimd128Equal(search_element, map, element_k, map_k, | |
596 &return_true, &continue_loop); | |
597 | |
598 assembler->Bind(&continue_loop); | |
599 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
600 assembler->Goto(&loop_body); | |
601 } | |
602 } | |
603 | |
604 assembler->Bind(&if_packed_doubles); | |
605 { | |
606 Label nan_loop(assembler, &k), not_nan_loop(assembler, &k), | |
607 hole_loop(assembler, &k); | |
608 assembler->GotoIf(assembler->WordIsSmi(search_element), &return_false); | |
609 assembler->GotoIf(assembler->WordNotEqual( | |
610 assembler->LoadMap(search_element), heap_number_map), | |
611 &return_false); | |
612 | |
613 Node* search_num = assembler->LoadHeapNumberValue(search_element); | |
614 | |
615 assembler->BranchIfFloat64IsNaN(search_num, &nan_loop, ¬_nan_loop); | |
616 | |
617 // Search for HeapNumber | |
618 assembler->Bind(¬_nan_loop); | |
619 { | |
620 Label continue_loop(assembler); | |
621 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
622 &return_false); | |
623 Node* element_k = assembler->LoadFixedDoubleArrayElement( | |
624 elements, k.value(), MachineType::Float64()); | |
625 assembler->BranchIfFloat64Equal(element_k, search_num, &return_true, | |
626 &continue_loop); | |
627 assembler->Bind(&continue_loop); | |
628 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
629 assembler->Goto(¬_nan_loop); | |
630 } | |
631 | |
632 // Search for NaN | |
633 assembler->Bind(&nan_loop); | |
634 { | |
635 Label continue_loop(assembler); | |
636 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
637 &return_false); | |
638 Node* element_k = assembler->LoadFixedDoubleArrayElement( | |
639 elements, k.value(), MachineType::Float64()); | |
640 assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); | |
641 assembler->Bind(&continue_loop); | |
642 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
643 assembler->Goto(&nan_loop); | |
644 } | |
645 } | |
646 | |
647 assembler->Bind(&if_holey_doubles); | |
648 { | |
649 Label nan_loop(assembler, &k), not_nan_loop(assembler, &k), | |
650 hole_loop(assembler, &k); | |
651 assembler->GotoIf(assembler->WordIsSmi(search_element), &return_false); | |
652 assembler->GotoIf(assembler->WordEqual(search_element, undefined), | |
653 &hole_loop); | |
654 assembler->GotoIf(assembler->WordNotEqual( | |
655 assembler->LoadMap(search_element), heap_number_map), | |
656 &return_false); | |
657 | |
658 Node* search_num = assembler->LoadHeapNumberValue(search_element); | |
659 | |
660 assembler->BranchIfFloat64IsNaN(search_num, &nan_loop, ¬_nan_loop); | |
661 | |
662 // Search for HeapNumber | |
663 assembler->Bind(¬_nan_loop); | |
664 { | |
665 Label continue_loop(assembler); | |
666 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
667 &return_false); | |
668 | |
669 if (kPointerSize == kDoubleSize) { | |
670 Node* element = assembler->LoadFixedDoubleArrayElement( | |
671 elements, k.value(), MachineType::Uint64()); | |
672 Node* the_hole = assembler->Int64Constant(kHoleNanInt64); | |
673 assembler->GotoIf(assembler->Word64Equal(element, the_hole), | |
674 &continue_loop); | |
675 } else { | |
676 Node* element_upper = assembler->LoadFixedDoubleArrayElement( | |
677 elements, k.value(), MachineType::Uint32(), | |
678 kIeeeDoubleExponentWordOffset); | |
679 assembler->GotoIf( | |
680 assembler->Word32Equal(element_upper, | |
681 assembler->Int32Constant(kHoleNanUpper32)), | |
682 &continue_loop); | |
683 } | |
684 | |
685 Node* element_k = assembler->LoadFixedDoubleArrayElement( | |
686 elements, k.value(), MachineType::Float64()); | |
687 assembler->BranchIfFloat64Equal(element_k, search_num, &return_true, | |
688 &continue_loop); | |
689 assembler->Bind(&continue_loop); | |
690 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
691 assembler->Goto(¬_nan_loop); | |
692 } | |
693 | |
694 // Search for NaN | |
695 assembler->Bind(&nan_loop); | |
696 { | |
697 Label continue_loop(assembler); | |
698 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
699 &return_false); | |
700 | |
701 if (kPointerSize == kDoubleSize) { | |
702 Node* element = assembler->LoadFixedDoubleArrayElement( | |
703 elements, k.value(), MachineType::Uint64()); | |
704 Node* the_hole = assembler->Int64Constant(kHoleNanInt64); | |
705 assembler->GotoIf(assembler->Word64Equal(element, the_hole), | |
706 &continue_loop); | |
707 } else { | |
708 Node* element_upper = assembler->LoadFixedDoubleArrayElement( | |
709 elements, k.value(), MachineType::Uint32(), | |
710 kIeeeDoubleExponentWordOffset); | |
711 assembler->GotoIf( | |
712 assembler->Word32Equal(element_upper, | |
713 assembler->Int32Constant(kHoleNanUpper32)), | |
714 &continue_loop); | |
715 } | |
716 | |
717 Node* element_k = assembler->LoadFixedDoubleArrayElement( | |
718 elements, k.value(), MachineType::Float64()); | |
719 assembler->BranchIfFloat64IsNaN(element_k, &return_true, &continue_loop); | |
720 assembler->Bind(&continue_loop); | |
721 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
722 assembler->Goto(&nan_loop); | |
723 } | |
724 | |
725 // Search for the Hole | |
726 assembler->Bind(&hole_loop); | |
727 { | |
728 assembler->GotoUnless(assembler->Int32LessThan(k.value(), len.value()), | |
729 &return_false); | |
730 | |
731 if (kPointerSize == kDoubleSize) { | |
732 Node* element = assembler->LoadFixedDoubleArrayElement( | |
733 elements, k.value(), MachineType::Uint64()); | |
734 Node* the_hole = assembler->Int64Constant(kHoleNanInt64); | |
735 assembler->GotoIf(assembler->Word64Equal(element, the_hole), | |
736 &return_true); | |
737 } else { | |
738 Node* element_upper = assembler->LoadFixedDoubleArrayElement( | |
739 elements, k.value(), MachineType::Uint32(), | |
740 kIeeeDoubleExponentWordOffset); | |
741 assembler->GotoIf( | |
742 assembler->Word32Equal(element_upper, | |
743 assembler->Int32Constant(kHoleNanUpper32)), | |
744 &return_true); | |
745 } | |
746 | |
747 k.Bind(assembler->Int32Add(k.value(), int32_one)); | |
748 assembler->Goto(&hole_loop); | |
749 } | |
750 } | |
751 | |
752 assembler->Bind(&return_true); | |
753 assembler->Return(assembler->BooleanConstant(true)); | |
754 | |
755 assembler->Bind(&return_false); | |
756 assembler->Return(assembler->BooleanConstant(false)); | |
757 | |
758 assembler->Bind(&call_runtime); | |
759 assembler->Return(assembler->CallRuntime(Runtime::kArrayIncludes_Slow, | |
760 context, array, search_element, | |
761 start_from)); | |
762 } | |
763 | |
346 void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) { | 764 void Builtins::Generate_ObjectHasOwnProperty(CodeStubAssembler* assembler) { |
347 typedef compiler::Node Node; | 765 typedef compiler::Node Node; |
348 typedef CodeStubAssembler::Label Label; | 766 typedef CodeStubAssembler::Label Label; |
349 typedef CodeStubAssembler::Variable Variable; | 767 typedef CodeStubAssembler::Variable Variable; |
350 | 768 |
351 Node* object = assembler->Parameter(0); | 769 Node* object = assembler->Parameter(0); |
352 Node* key = assembler->Parameter(1); | 770 Node* key = assembler->Parameter(1); |
353 Node* context = assembler->Parameter(4); | 771 Node* context = assembler->Parameter(4); |
354 | 772 |
355 Label call_runtime(assembler), return_true(assembler), | 773 Label call_runtime(assembler), return_true(assembler), |
(...skipping 6567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
6923 #define DEFINE_BUILTIN_ACCESSOR(Name, ...) \ | 7341 #define DEFINE_BUILTIN_ACCESSOR(Name, ...) \ |
6924 Handle<Code> Builtins::Name() { \ | 7342 Handle<Code> Builtins::Name() { \ |
6925 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \ | 7343 Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \ |
6926 return Handle<Code>(code_address); \ | 7344 return Handle<Code>(code_address); \ |
6927 } | 7345 } |
6928 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR) | 7346 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR) |
6929 #undef DEFINE_BUILTIN_ACCESSOR | 7347 #undef DEFINE_BUILTIN_ACCESSOR |
6930 | 7348 |
6931 } // namespace internal | 7349 } // namespace internal |
6932 } // namespace v8 | 7350 } // namespace v8 |
OLD | NEW |