Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: src/x64/builtins-x64.cc

Issue 209048: Handle array construction in native code (x64 version) (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 11 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/x64/assembler-x64.h ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 434 matching lines...) Expand 10 before | Expand all | Expand 10 after
445 ParameterCount actual(rax); 445 ParameterCount actual(rax);
446 __ SmiToInteger32(rax, rax); 446 __ SmiToInteger32(rax, rax);
447 __ movq(rdi, Operand(rbp, kFunctionOffset)); 447 __ movq(rdi, Operand(rbp, kFunctionOffset));
448 __ InvokeFunction(rdi, actual, CALL_FUNCTION); 448 __ InvokeFunction(rdi, actual, CALL_FUNCTION);
449 449
450 __ LeaveInternalFrame(); 450 __ LeaveInternalFrame();
451 __ ret(3 * kPointerSize); // remove function, receiver, and arguments 451 __ ret(3 * kPointerSize); // remove function, receiver, and arguments
452 } 452 }
453 453
454 454
455 // Load the built-in Array function from the current context.
456 static void GenerateLoadArrayFunction(MacroAssembler* masm, Register result) {
457 // Load the global context.
458 __ movq(result, Operand(rsi, Context::SlotOffset(Context::GLOBAL_INDEX)));
459 __ movq(result, FieldOperand(result, GlobalObject::kGlobalContextOffset));
460 // Load the Array function from the global context.
461 __ movq(result,
462 Operand(result, Context::SlotOffset(Context::ARRAY_FUNCTION_INDEX)));
463 }
464
465
466 // Number of empty elements to allocate for an empty array.
467 static const int kPreallocatedArrayElements = 4;
468
469
470 // Allocate an empty JSArray. The allocated array is put into the result
471 // register. If the parameter initial_capacity is larger than zero an elements
472 // backing store is allocated with this size and filled with the hole values.
473 // Otherwise the elements backing store is set to the empty FixedArray.
474 static void AllocateEmptyJSArray(MacroAssembler* masm,
475 Register array_function,
476 Register result,
477 Register scratch1,
478 Register scratch2,
479 Register scratch3,
480 int initial_capacity,
481 Label* gc_required) {
482 ASSERT(initial_capacity >= 0);
483
484 // Load the initial map from the array function.
485 __ movq(scratch1, FieldOperand(array_function,
486 JSFunction::kPrototypeOrInitialMapOffset));
487
488 // Allocate the JSArray object together with space for a fixed array with the
489 // requested elements.
490 int size = JSArray::kSize;
491 if (initial_capacity > 0) {
492 size += FixedArray::SizeFor(initial_capacity);
493 }
494 __ AllocateObjectInNewSpace(size,
495 result,
496 scratch2,
497 scratch3,
498 gc_required,
499 TAG_OBJECT);
500
501 // Allocated the JSArray. Now initialize the fields except for the elements
502 // array.
503 // result: JSObject
504 // scratch1: initial map
505 // scratch2: start of next object
506 __ movq(FieldOperand(result, JSObject::kMapOffset), scratch1);
507 __ Move(FieldOperand(result, JSArray::kPropertiesOffset),
508 Factory::empty_fixed_array());
509 // Field JSArray::kElementsOffset is initialized later.
510 __ movq(FieldOperand(result, JSArray::kLengthOffset), Immediate(0));
511
512 // If no storage is requested for the elements array just set the empty
513 // fixed array.
514 if (initial_capacity == 0) {
515 __ Move(FieldOperand(result, JSArray::kElementsOffset),
516 Factory::empty_fixed_array());
517 return;
518 }
519
520 // Calculate the location of the elements array and set elements array member
521 // of the JSArray.
522 // result: JSObject
523 // scratch2: start of next object
524 __ lea(scratch1, Operand(result, JSArray::kSize));
525 __ movq(FieldOperand(result, JSArray::kElementsOffset), scratch1);
526
527 // Initialize the FixedArray and fill it with holes. FixedArray length is not
528 // stored as a smi.
529 // result: JSObject
530 // scratch1: elements array
531 // scratch2: start of next object
532 __ Move(FieldOperand(scratch1, JSObject::kMapOffset),
533 Factory::fixed_array_map());
534 __ movq(FieldOperand(scratch1, Array::kLengthOffset),
535 Immediate(initial_capacity));
536
537 // Fill the FixedArray with the hole value. Inline the code if short.
538 // Reconsider loop unfolding if kPreallocatedArrayElements gets changed.
539 static const int kLoopUnfoldLimit = 4;
540 ASSERT(kPreallocatedArrayElements <= kLoopUnfoldLimit);
541 __ Move(scratch3, Factory::the_hole_value());
542 if (initial_capacity <= kLoopUnfoldLimit) {
543 // Use a scratch register here to have only one reloc info when unfolding
544 // the loop.
545 for (int i = 0; i < initial_capacity; i++) {
546 __ movq(FieldOperand(scratch1,
547 FixedArray::kHeaderSize + i * kPointerSize),
548 scratch3);
549 }
550 } else {
551 Label loop, entry;
552 __ jmp(&entry);
553 __ bind(&loop);
554 __ movq(Operand(scratch1, 0), scratch3);
555 __ addq(scratch1, Immediate(kPointerSize));
556 __ bind(&entry);
557 __ cmpq(scratch1, scratch2);
558 __ j(below, &loop);
559 }
560 }
561
562
563 // Allocate a JSArray with the number of elements stored in a register. The
564 // register array_function holds the built-in Array function and the register
565 // array_size holds the size of the array as a smi. The allocated array is put
566 // into the result register and beginning and end of the FixedArray elements
567 // storage is put into registers elements_array and elements_array_end (see
568 // below for when that is not the case). If the parameter fill_with_holes is
569 // true the allocated elements backing store is filled with the hole values
570 // otherwise it is left uninitialized. When the backing store is filled the
571 // register elements_array is scratched.
572 static void AllocateJSArray(MacroAssembler* masm,
573 Register array_function, // Array function.
574 Register array_size, // As a smi.
575 Register result,
576 Register elements_array,
577 Register elements_array_end,
578 Register scratch,
579 bool fill_with_hole,
580 Label* gc_required) {
581 Label not_empty, allocated;
582
583 // Load the initial map from the array function.
584 __ movq(elements_array,
585 FieldOperand(array_function,
586 JSFunction::kPrototypeOrInitialMapOffset));
587
588 // Check whether an empty sized array is requested.
589 __ testq(array_size, array_size);
590 __ j(not_zero, &not_empty);
591
592 // If an empty array is requested allocate a small elements array anyway. This
593 // keeps the code below free of special casing for the empty array.
594 int size = JSArray::kSize + FixedArray::SizeFor(kPreallocatedArrayElements);
595 __ AllocateObjectInNewSpace(size,
596 result,
597 elements_array_end,
598 scratch,
599 gc_required,
600 TAG_OBJECT);
601 __ jmp(&allocated);
602
603 // Allocate the JSArray object together with space for a FixedArray with the
604 // requested elements.
605 __ bind(&not_empty);
606 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
607 __ AllocateObjectInNewSpace(JSArray::kSize + FixedArray::kHeaderSize,
608 times_half_pointer_size, // array_size is a smi.
609 array_size,
610 result,
611 elements_array_end,
612 scratch,
613 gc_required,
614 TAG_OBJECT);
615
616 // Allocated the JSArray. Now initialize the fields except for the elements
617 // array.
618 // result: JSObject
619 // elements_array: initial map
620 // elements_array_end: start of next object
621 // array_size: size of array (smi)
622 __ bind(&allocated);
623 __ movq(FieldOperand(result, JSObject::kMapOffset), elements_array);
624 __ Move(elements_array, Factory::empty_fixed_array());
625 __ movq(FieldOperand(result, JSArray::kPropertiesOffset), elements_array);
626 // Field JSArray::kElementsOffset is initialized later.
627 __ movq(FieldOperand(result, JSArray::kLengthOffset), array_size);
628
629 // Calculate the location of the elements array and set elements array member
630 // of the JSArray.
631 // result: JSObject
632 // elements_array_end: start of next object
633 // array_size: size of array (smi)
634 __ lea(elements_array, Operand(result, JSArray::kSize));
635 __ movq(FieldOperand(result, JSArray::kElementsOffset), elements_array);
636
637 // Initialize the fixed array. FixedArray length is not stored as a smi.
638 // result: JSObject
639 // elements_array: elements array
640 // elements_array_end: start of next object
641 // array_size: size of array (smi)
642 ASSERT(kSmiTag == 0);
643 __ SmiToInteger64(array_size, array_size);
644 __ Move(FieldOperand(elements_array, JSObject::kMapOffset),
645 Factory::fixed_array_map());
646 Label not_empty_2, fill_array;
647 __ testq(array_size, array_size);
648 __ j(not_zero, &not_empty_2);
649 // Length of the FixedArray is the number of pre-allocated elements even
650 // though the actual JSArray has length 0.
651 __ movq(FieldOperand(elements_array, Array::kLengthOffset),
652 Immediate(kPreallocatedArrayElements));
653 __ jmp(&fill_array);
654 __ bind(&not_empty_2);
655 // For non-empty JSArrays the length of the FixedArray and the JSArray is the
656 // same.
657 __ movq(FieldOperand(elements_array, Array::kLengthOffset), array_size);
658
659 // Fill the allocated FixedArray with the hole value if requested.
660 // result: JSObject
661 // elements_array: elements array
662 // elements_array_end: start of next object
663 __ bind(&fill_array);
664 if (fill_with_hole) {
665 Label loop, entry;
666 __ Move(scratch, Factory::the_hole_value());
667 __ lea(elements_array, Operand(elements_array,
668 FixedArray::kHeaderSize - kHeapObjectTag));
669 __ jmp(&entry);
670 __ bind(&loop);
671 __ movq(Operand(elements_array, 0), scratch);
672 __ addq(elements_array, Immediate(kPointerSize));
673 __ bind(&entry);
674 __ cmpq(elements_array, elements_array_end);
675 __ j(below, &loop);
676 }
677 }
678
679
680 // Create a new array for the built-in Array function. This function allocates
681 // the JSArray object and the FixedArray elements array and initializes these.
682 // If the Array cannot be constructed in native code the runtime is called. This
683 // function assumes the following state:
684 // rdi: constructor (built-in Array function)
685 // rax: argc
686 // rsp[0]: return address
687 // rsp[8]: last argument
688 // This function is used for both construct and normal calls of Array. The only
689 // difference between handling a construct call and a normal call is that for a
690 // construct call the constructor function in rdi needs to be preserved for
691 // entering the generic code. In both cases argc in rax needs to be preserved.
692 // Both registers are preserved by this code so no need to differentiate between
693 // a construct call and a normal call.
694 static void ArrayNativeCode(MacroAssembler* masm,
695 Label *call_generic_code) {
696 Label argc_one_or_more, argc_two_or_more;
697
698 // Check for array construction with zero arguments.
699 __ testq(rax, rax);
700 __ j(not_zero, &argc_one_or_more);
701
702 // Handle construction of an empty array.
703 AllocateEmptyJSArray(masm,
704 rdi,
705 rbx,
706 rcx,
707 rdx,
708 r8,
709 kPreallocatedArrayElements,
710 call_generic_code);
711 __ IncrementCounter(&Counters::array_function_native, 1);
712 __ movq(rax, rbx);
713 __ ret(kPointerSize);
714
715 // Check for one argument. Bail out if argument is not smi or if it is
716 // negative.
717 __ bind(&argc_one_or_more);
718 __ cmpq(rax, Immediate(1));
719 __ j(not_equal, &argc_two_or_more);
720 __ movq(rdx, Operand(rsp, kPointerSize)); // Get the argument from the stack.
721 Condition not_positive_smi = __ CheckNotPositiveSmi(rdx);
722 __ j(not_positive_smi, call_generic_code);
723
724 // Handle construction of an empty array of a certain size. Bail out if size
725 // is to large to actually allocate an elements array.
726 __ JumpIfSmiGreaterEqualsConstant(rdx,
727 JSObject::kInitialMaxFastElementArray,
728 call_generic_code);
729
730 // rax: argc
731 // rdx: array_size (smi)
732 // rdi: constructor
733 // esp[0]: return address
734 // esp[8]: argument
735 AllocateJSArray(masm,
736 rdi,
737 rdx,
738 rbx,
739 rcx,
740 r8,
741 r9,
742 true,
743 call_generic_code);
744 __ IncrementCounter(&Counters::array_function_native, 1);
745 __ movq(rax, rbx);
746 __ ret(2 * kPointerSize);
747
748 // Handle construction of an array from a list of arguments.
749 __ bind(&argc_two_or_more);
750 __ movq(rdx, rax);
751 __ Integer32ToSmi(rdx, rdx); // Convet argc to a smi.
752 // rax: argc
753 // rdx: array_size (smi)
754 // rdi: constructor
755 // esp[0] : return address
756 // esp[8] : last argument
757 AllocateJSArray(masm,
758 rdi,
759 rdx,
760 rbx,
761 rcx,
762 r8,
763 r9,
764 false,
765 call_generic_code);
766 __ IncrementCounter(&Counters::array_function_native, 1);
767
768 // rax: argc
769 // rbx: JSArray
770 // rcx: elements_array
771 // r8: elements_array_end (untagged)
772 // esp[0]: return address
773 // esp[8]: last argument
774
775 // Location of the last argument
776 __ lea(r9, Operand(rsp, kPointerSize));
777
778 // Location of the first array element (Parameter fill_with_holes to
779 // AllocateJSArrayis false, so the FixedArray is returned in rcx).
780 __ lea(rdx, Operand(rcx, FixedArray::kHeaderSize - kHeapObjectTag));
781
782 // rax: argc
783 // rbx: JSArray
784 // rdx: location of the first array element
785 // r9: location of the last argument
786 // esp[0]: return address
787 // esp[8]: last argument
788 Label loop, entry;
789 __ movq(rcx, rax);
790 __ jmp(&entry);
791 __ bind(&loop);
792 __ movq(kScratchRegister, Operand(r9, rcx, times_pointer_size, 0));
793 __ movq(Operand(rdx, 0), kScratchRegister);
794 __ addq(rdx, Immediate(kPointerSize));
795 __ bind(&entry);
796 __ decq(rcx);
797 __ j(greater_equal, &loop);
798
799 // Remove caller arguments from the stack and return.
800 // rax: argc
801 // rbx: JSArray
802 // esp[0]: return address
803 // esp[8]: last argument
804 __ pop(rcx);
805 __ lea(rsp, Operand(rsp, rax, times_pointer_size, 1 * kPointerSize));
806 __ push(rcx);
807 __ movq(rax, rbx);
808 __ ret(0);
809 }
810
811
455 void Builtins::Generate_ArrayCode(MacroAssembler* masm) { 812 void Builtins::Generate_ArrayCode(MacroAssembler* masm) {
456 // Just jump to the generic array code. 813 // ----------- S t a t e -------------
814 // -- rax : argc
815 // -- rsp[0] : return address
816 // -- rsp[8] : last argument
817 // -----------------------------------
818 Label generic_array_code;
819
820 // Get the Array function.
821 GenerateLoadArrayFunction(masm, rdi);
822
823 if (FLAG_debug_code) {
824 // Initial map for the builtin Array function shoud be a map.
825 __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
826 // Will both indicate a NULL and a Smi.
827 ASSERT(kSmiTag == 0);
828 Condition not_smi = __ CheckNotSmi(rbx);
829 __ Assert(not_smi, "Unexpected initial map for Array function");
830 __ CmpObjectType(rbx, MAP_TYPE, rcx);
831 __ Assert(equal, "Unexpected initial map for Array function");
832 }
833
834 // Run the native code for the Array function called as a normal function.
835 ArrayNativeCode(masm, &generic_array_code);
836
837 // Jump to the generic array code in case the specialized code cannot handle
838 // the construction.
839 __ bind(&generic_array_code);
457 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric); 840 Code* code = Builtins::builtin(Builtins::ArrayCodeGeneric);
458 Handle<Code> array_code(code); 841 Handle<Code> array_code(code);
459 __ Jump(array_code, RelocInfo::CODE_TARGET); 842 __ Jump(array_code, RelocInfo::CODE_TARGET);
460 } 843 }
461 844
462 845
463 void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) { 846 void Builtins::Generate_ArrayConstructCode(MacroAssembler* masm) {
464 // Just jump to the generic construct code. 847 // ----------- S t a t e -------------
848 // -- rax : argc
849 // -- rdi : constructor
850 // -- rsp[0] : return address
851 // -- rsp[8] : last argument
852 // -----------------------------------
853 Label generic_constructor;
854
855 if (FLAG_debug_code) {
856 // The array construct code is only set for the builtin Array function which
857 // does always have a map.
858 GenerateLoadArrayFunction(masm, rbx);
859 __ cmpq(rdi, rbx);
860 __ Assert(equal, "Unexpected Array function");
861 // Initial map for the builtin Array function should be a map.
862 __ movq(rbx, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
863 // Will both indicate a NULL and a Smi.
864 ASSERT(kSmiTag == 0);
865 Condition not_smi = __ CheckNotSmi(rbx);
866 __ Assert(not_smi, "Unexpected initial map for Array function");
867 __ CmpObjectType(rbx, MAP_TYPE, rcx);
868 __ Assert(equal, "Unexpected initial map for Array function");
869 }
870
871 // Run the native code for the Array function called as constructor.
872 ArrayNativeCode(masm, &generic_constructor);
873
874 // Jump to the generic construct code in case the specialized code cannot
875 // handle the construction.
876 __ bind(&generic_constructor);
465 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric); 877 Code* code = Builtins::builtin(Builtins::JSConstructStubGeneric);
466 Handle<Code> generic_construct_stub(code); 878 Handle<Code> generic_construct_stub(code);
467 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET); 879 __ Jump(generic_construct_stub, RelocInfo::CODE_TARGET);
468 } 880 }
469 881
470 882
471 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) { 883 void Builtins::Generate_JSConstructCall(MacroAssembler* masm) {
472 // ----------- S t a t e ------------- 884 // ----------- S t a t e -------------
473 // -- rax: number of arguments 885 // -- rax: number of arguments
474 // -- rdi: constructor function 886 // -- rdi: constructor function
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
522 __ movq(kScratchRegister, debug_step_in_fp); 934 __ movq(kScratchRegister, debug_step_in_fp);
523 __ cmpq(Operand(kScratchRegister, 0), Immediate(0)); 935 __ cmpq(Operand(kScratchRegister, 0), Immediate(0));
524 __ j(not_equal, &rt_call); 936 __ j(not_equal, &rt_call);
525 #endif 937 #endif
526 938
527 // Verified that the constructor is a JSFunction. 939 // Verified that the constructor is a JSFunction.
528 // Load the initial map and verify that it is in fact a map. 940 // Load the initial map and verify that it is in fact a map.
529 // rdi: constructor 941 // rdi: constructor
530 __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset)); 942 __ movq(rax, FieldOperand(rdi, JSFunction::kPrototypeOrInitialMapOffset));
531 // Will both indicate a NULL and a Smi 943 // Will both indicate a NULL and a Smi
944 ASSERT(kSmiTag == 0);
532 __ JumpIfSmi(rax, &rt_call); 945 __ JumpIfSmi(rax, &rt_call);
533 // rdi: constructor 946 // rdi: constructor
534 // rax: initial map (if proven valid below) 947 // rax: initial map (if proven valid below)
535 __ CmpObjectType(rax, MAP_TYPE, rbx); 948 __ CmpObjectType(rax, MAP_TYPE, rbx);
536 __ j(not_equal, &rt_call); 949 __ j(not_equal, &rt_call);
537 950
538 // Check that the constructor is not constructing a JSFunction (see comments 951 // Check that the constructor is not constructing a JSFunction (see comments
539 // in Runtime_NewObject in runtime.cc). In which case the initial map's 952 // in Runtime_NewObject in runtime.cc). In which case the initial map's
540 // instance type would be JS_FUNCTION_TYPE. 953 // instance type would be JS_FUNCTION_TYPE.
541 // rdi: constructor 954 // rdi: constructor
(...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after
858 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) { 1271 void Builtins::Generate_JSEntryTrampoline(MacroAssembler* masm) {
859 Generate_JSEntryTrampolineHelper(masm, false); 1272 Generate_JSEntryTrampolineHelper(masm, false);
860 } 1273 }
861 1274
862 1275
863 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) { 1276 void Builtins::Generate_JSConstructEntryTrampoline(MacroAssembler* masm) {
864 Generate_JSEntryTrampolineHelper(masm, true); 1277 Generate_JSEntryTrampolineHelper(masm, true);
865 } 1278 }
866 1279
867 } } // namespace v8::internal 1280 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/x64/assembler-x64.h ('k') | src/x64/macro-assembler-x64.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698