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

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

Issue 6697023: Merge 6800:7180 from the bleeding edge branch to the experimental/gc branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 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/codegen-x64.h ('k') | src/x64/codegen-x64-inl.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 2010 the V8 project authors. All rights reserved. 1 // Copyright 2011 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
11 // with the distribution. 11 // with the distribution.
(...skipping 596 matching lines...) Expand 10 before | Expand all | Expand 10 after
608 LoadFromSlotCheckForArguments(variable->AsSlot(), INSIDE_TYPEOF); 608 LoadFromSlotCheckForArguments(variable->AsSlot(), INSIDE_TYPEOF);
609 } else { 609 } else {
610 // Anything else can be handled normally. 610 // Anything else can be handled normally.
611 Load(expr); 611 Load(expr);
612 } 612 }
613 } 613 }
614 614
615 615
616 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() { 616 ArgumentsAllocationMode CodeGenerator::ArgumentsMode() {
617 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION; 617 if (scope()->arguments() == NULL) return NO_ARGUMENTS_ALLOCATION;
618 ASSERT(scope()->arguments_shadow() != NULL); 618
619 // In strict mode there is no need for shadow arguments.
620 ASSERT(scope()->arguments_shadow() != NULL || scope()->is_strict_mode());
619 // We don't want to do lazy arguments allocation for functions that 621 // We don't want to do lazy arguments allocation for functions that
620 // have heap-allocated contexts, because it interfers with the 622 // have heap-allocated contexts, because it interfers with the
621 // uninitialized const tracking in the context objects. 623 // uninitialized const tracking in the context objects.
622 return (scope()->num_heap_slots() > 0) 624 return (scope()->num_heap_slots() > 0 || scope()->is_strict_mode())
623 ? EAGER_ARGUMENTS_ALLOCATION 625 ? EAGER_ARGUMENTS_ALLOCATION
624 : LAZY_ARGUMENTS_ALLOCATION; 626 : LAZY_ARGUMENTS_ALLOCATION;
625 } 627 }
626 628
627 629
628 Result CodeGenerator::StoreArgumentsObject(bool initial) { 630 Result CodeGenerator::StoreArgumentsObject(bool initial) {
629 ArgumentsAllocationMode mode = ArgumentsMode(); 631 ArgumentsAllocationMode mode = ArgumentsMode();
630 ASSERT(mode != NO_ARGUMENTS_ALLOCATION); 632 ASSERT(mode != NO_ARGUMENTS_ALLOCATION);
631 633
632 Comment cmnt(masm_, "[ store arguments object"); 634 Comment cmnt(masm_, "[ store arguments object");
633 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) { 635 if (mode == LAZY_ARGUMENTS_ALLOCATION && initial) {
634 // When using lazy arguments allocation, we store the arguments marker value 636 // When using lazy arguments allocation, we store the arguments marker value
635 // as a sentinel indicating that the arguments object hasn't been 637 // as a sentinel indicating that the arguments object hasn't been
636 // allocated yet. 638 // allocated yet.
637 frame_->Push(Factory::arguments_marker()); 639 frame_->Push(Factory::arguments_marker());
638 } else { 640 } else {
639 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 641 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
640 frame_->PushFunction(); 642 frame_->PushFunction();
641 frame_->PushReceiverSlotAddress(); 643 frame_->PushReceiverSlotAddress();
642 frame_->Push(Smi::FromInt(scope()->num_parameters())); 644 frame_->Push(Smi::FromInt(scope()->num_parameters()));
643 Result result = frame_->CallStub(&stub, 3); 645 Result result = frame_->CallStub(&stub, 3);
644 frame_->Push(&result); 646 frame_->Push(&result);
645 } 647 }
646 648
647 Variable* arguments = scope()->arguments(); 649 Variable* arguments = scope()->arguments();
648 Variable* shadow = scope()->arguments_shadow(); 650 Variable* shadow = scope()->arguments_shadow();
649 ASSERT(arguments != NULL && arguments->AsSlot() != NULL); 651 ASSERT(arguments != NULL && arguments->AsSlot() != NULL);
650 ASSERT(shadow != NULL && shadow->AsSlot() != NULL); 652 ASSERT((shadow != NULL && shadow->AsSlot() != NULL) ||
653 scope()->is_strict_mode());
654
651 JumpTarget done; 655 JumpTarget done;
652 bool skip_arguments = false; 656 bool skip_arguments = false;
653 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) { 657 if (mode == LAZY_ARGUMENTS_ALLOCATION && !initial) {
654 // We have to skip storing into the arguments slot if it has 658 // We have to skip storing into the arguments slot if it has
655 // already been written to. This can happen if the a function 659 // already been written to. This can happen if the a function
656 // has a local variable named 'arguments'. 660 // has a local variable named 'arguments'.
657 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF); 661 LoadFromSlot(arguments->AsSlot(), NOT_INSIDE_TYPEOF);
658 Result probe = frame_->Pop(); 662 Result probe = frame_->Pop();
659 if (probe.is_constant()) { 663 if (probe.is_constant()) {
660 // We have to skip updating the arguments object if it has 664 // We have to skip updating the arguments object if it has
661 // been assigned a proper value. 665 // been assigned a proper value.
662 skip_arguments = !probe.handle()->IsArgumentsMarker(); 666 skip_arguments = !probe.handle()->IsArgumentsMarker();
663 } else { 667 } else {
664 __ CompareRoot(probe.reg(), Heap::kArgumentsMarkerRootIndex); 668 __ CompareRoot(probe.reg(), Heap::kArgumentsMarkerRootIndex);
665 probe.Unuse(); 669 probe.Unuse();
666 done.Branch(not_equal); 670 done.Branch(not_equal);
667 } 671 }
668 } 672 }
669 if (!skip_arguments) { 673 if (!skip_arguments) {
670 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT); 674 StoreToSlot(arguments->AsSlot(), NOT_CONST_INIT);
671 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind(); 675 if (mode == LAZY_ARGUMENTS_ALLOCATION) done.Bind();
672 } 676 }
673 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT); 677 if (shadow != NULL) {
678 StoreToSlot(shadow->AsSlot(), NOT_CONST_INIT);
679 }
674 return frame_->Pop(); 680 return frame_->Pop();
675 } 681 }
676 682
677 //------------------------------------------------------------------------------ 683 //------------------------------------------------------------------------------
678 // CodeGenerator implementation of variables, lookups, and stores. 684 // CodeGenerator implementation of variables, lookups, and stores.
679 685
680 Reference::Reference(CodeGenerator* cgen, 686 Reference::Reference(CodeGenerator* cgen,
681 Expression* expression, 687 Expression* expression,
682 bool persist_after_get) 688 bool persist_after_get)
683 : cgen_(cgen), 689 : cgen_(cgen),
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
757 // The value to convert should be popped from the frame. 763 // The value to convert should be popped from the frame.
758 Result value = frame_->Pop(); 764 Result value = frame_->Pop();
759 value.ToRegister(); 765 value.ToRegister();
760 766
761 if (value.is_number()) { 767 if (value.is_number()) {
762 // Fast case if TypeInfo indicates only numbers. 768 // Fast case if TypeInfo indicates only numbers.
763 if (FLAG_debug_code) { 769 if (FLAG_debug_code) {
764 __ AbortIfNotNumber(value.reg()); 770 __ AbortIfNotNumber(value.reg());
765 } 771 }
766 // Smi => false iff zero. 772 // Smi => false iff zero.
767 __ SmiCompare(value.reg(), Smi::FromInt(0)); 773 __ Cmp(value.reg(), Smi::FromInt(0));
768 if (value.is_smi()) { 774 if (value.is_smi()) {
769 value.Unuse(); 775 value.Unuse();
770 dest->Split(not_zero); 776 dest->Split(not_zero);
771 } else { 777 } else {
772 dest->false_target()->Branch(equal); 778 dest->false_target()->Branch(equal);
773 Condition is_smi = masm_->CheckSmi(value.reg()); 779 Condition is_smi = masm_->CheckSmi(value.reg());
774 dest->true_target()->Branch(is_smi); 780 dest->true_target()->Branch(is_smi);
775 __ xorpd(xmm0, xmm0); 781 __ xorpd(xmm0, xmm0);
776 __ ucomisd(xmm0, FieldOperand(value.reg(), HeapNumber::kValueOffset)); 782 __ ucomisd(xmm0, FieldOperand(value.reg(), HeapNumber::kValueOffset));
777 value.Unuse(); 783 value.Unuse();
778 dest->Split(not_zero); 784 dest->Split(not_zero);
779 } 785 }
780 } else { 786 } else {
781 // Fast case checks. 787 // Fast case checks.
782 // 'false' => false. 788 // 'false' => false.
783 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex); 789 __ CompareRoot(value.reg(), Heap::kFalseValueRootIndex);
784 dest->false_target()->Branch(equal); 790 dest->false_target()->Branch(equal);
785 791
786 // 'true' => true. 792 // 'true' => true.
787 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex); 793 __ CompareRoot(value.reg(), Heap::kTrueValueRootIndex);
788 dest->true_target()->Branch(equal); 794 dest->true_target()->Branch(equal);
789 795
790 // 'undefined' => false. 796 // 'undefined' => false.
791 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex); 797 __ CompareRoot(value.reg(), Heap::kUndefinedValueRootIndex);
792 dest->false_target()->Branch(equal); 798 dest->false_target()->Branch(equal);
793 799
794 // Smi => false iff zero. 800 // Smi => false iff zero.
795 __ SmiCompare(value.reg(), Smi::FromInt(0)); 801 __ Cmp(value.reg(), Smi::FromInt(0));
796 dest->false_target()->Branch(equal); 802 dest->false_target()->Branch(equal);
797 Condition is_smi = masm_->CheckSmi(value.reg()); 803 Condition is_smi = masm_->CheckSmi(value.reg());
798 dest->true_target()->Branch(is_smi); 804 dest->true_target()->Branch(is_smi);
799 805
800 // Call the stub for all other cases. 806 // Call the stub for all other cases.
801 frame_->Push(&value); // Undo the Pop() from above. 807 frame_->Push(&value); // Undo the Pop() from above.
802 ToBooleanStub stub; 808 ToBooleanStub stub;
803 Result temp = frame_->CallStub(&stub, 1); 809 Result temp = frame_->CallStub(&stub, 1);
804 // Convert the result to a condition code. 810 // Convert the result to a condition code.
805 __ testq(temp.reg(), temp.reg()); 811 __ testq(temp.reg(), temp.reg());
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
1027 operands_type); 1033 operands_type);
1028 answer = GenerateGenericBinaryOpStubCall(&stub, &left, &right); 1034 answer = GenerateGenericBinaryOpStubCall(&stub, &left, &right);
1029 } else if (right_is_smi_constant) { 1035 } else if (right_is_smi_constant) {
1030 answer = ConstantSmiBinaryOperation(expr, &left, right.handle(), 1036 answer = ConstantSmiBinaryOperation(expr, &left, right.handle(),
1031 false, overwrite_mode); 1037 false, overwrite_mode);
1032 } else if (left_is_smi_constant) { 1038 } else if (left_is_smi_constant) {
1033 answer = ConstantSmiBinaryOperation(expr, &right, left.handle(), 1039 answer = ConstantSmiBinaryOperation(expr, &right, left.handle(),
1034 true, overwrite_mode); 1040 true, overwrite_mode);
1035 } else { 1041 } else {
1036 // Set the flags based on the operation, type and loop nesting level. 1042 // Set the flags based on the operation, type and loop nesting level.
1037 // Bit operations always assume they likely operate on Smis. Still only 1043 // Bit operations always assume they likely operate on smis. Still only
1038 // generate the inline Smi check code if this operation is part of a loop. 1044 // generate the inline Smi check code if this operation is part of a loop.
1039 // For all other operations only inline the Smi check code for likely smis 1045 // For all other operations only inline the Smi check code for likely smis
1040 // if the operation is part of a loop. 1046 // if the operation is part of a loop.
1041 if (loop_nesting() > 0 && 1047 if (loop_nesting() > 0 &&
1042 (Token::IsBitOp(op) || 1048 (Token::IsBitOp(op) ||
1043 operands_type.IsInteger32() || 1049 operands_type.IsInteger32() ||
1044 expr->type()->IsLikelySmi())) { 1050 expr->type()->IsLikelySmi())) {
1045 answer = LikelySmiBinaryOperation(expr, &left, &right, overwrite_mode); 1051 answer = LikelySmiBinaryOperation(expr, &left, &right, overwrite_mode);
1046 } else { 1052 } else {
1047 GenericBinaryOpStub stub(op, 1053 GenericBinaryOpStub stub(op,
(...skipping 1051 matching lines...) Expand 10 before | Expand all | Expand 10 after
2099 is_string.Bind(&left_side); 2105 is_string.Bind(&left_side);
2100 // left_side is a sequential ASCII string. 2106 // left_side is a sequential ASCII string.
2101 ASSERT(left_side.reg().is(left_reg)); 2107 ASSERT(left_side.reg().is(left_reg));
2102 right_side = Result(right_val); 2108 right_side = Result(right_val);
2103 Result temp2 = allocator_->Allocate(); 2109 Result temp2 = allocator_->Allocate();
2104 ASSERT(temp2.is_valid()); 2110 ASSERT(temp2.is_valid());
2105 // Test string equality and comparison. 2111 // Test string equality and comparison.
2106 if (cc == equal) { 2112 if (cc == equal) {
2107 Label comparison_done; 2113 Label comparison_done;
2108 __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset), 2114 __ SmiCompare(FieldOperand(left_side.reg(), String::kLengthOffset),
2109 Smi::FromInt(1)); 2115 Smi::FromInt(1));
2110 __ j(not_equal, &comparison_done); 2116 __ j(not_equal, &comparison_done);
2111 uint8_t char_value = 2117 uint8_t char_value =
2112 static_cast<uint8_t>(String::cast(*right_val)->Get(0)); 2118 static_cast<uint8_t>(String::cast(*right_val)->Get(0));
2113 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize), 2119 __ cmpb(FieldOperand(left_side.reg(), SeqAsciiString::kHeaderSize),
2114 Immediate(char_value)); 2120 Immediate(char_value));
2115 __ bind(&comparison_done); 2121 __ bind(&comparison_done);
2116 } else { 2122 } else {
2117 __ movq(temp2.reg(), 2123 __ movq(temp2.reg(),
2118 FieldOperand(left_side.reg(), String::kLengthOffset)); 2124 FieldOperand(left_side.reg(), String::kLengthOffset));
2119 __ SmiSubConstant(temp2.reg(), temp2.reg(), Smi::FromInt(1)); 2125 __ SmiSubConstant(temp2.reg(), temp2.reg(), Smi::FromInt(1));
(...skipping 165 matching lines...) Expand 10 before | Expand all | Expand 10 after
2285 // Since one side is a constant Smi, conversion order does not matter. 2291 // Since one side is a constant Smi, conversion order does not matter.
2286 if (left_side_constant_smi) { 2292 if (left_side_constant_smi) {
2287 Result* temp = left_side; 2293 Result* temp = left_side;
2288 left_side = right_side; 2294 left_side = right_side;
2289 right_side = temp; 2295 right_side = temp;
2290 cc = ReverseCondition(cc); 2296 cc = ReverseCondition(cc);
2291 // This may re-introduce greater or less_equal as the value of cc. 2297 // This may re-introduce greater or less_equal as the value of cc.
2292 // CompareStub and the inline code both support all values of cc. 2298 // CompareStub and the inline code both support all values of cc.
2293 } 2299 }
2294 // Implement comparison against a constant Smi, inlining the case 2300 // Implement comparison against a constant Smi, inlining the case
2295 // where both sides are Smis. 2301 // where both sides are smis.
2296 left_side->ToRegister(); 2302 left_side->ToRegister();
2297 Register left_reg = left_side->reg(); 2303 Register left_reg = left_side->reg();
2298 Smi* constant_smi = Smi::cast(*right_side->handle()); 2304 Smi* constant_smi = Smi::cast(*right_side->handle());
2299 2305
2300 if (left_side->is_smi()) { 2306 if (left_side->is_smi()) {
2301 if (FLAG_debug_code) { 2307 if (FLAG_debug_code) {
2302 __ AbortIfNotSmi(left_reg); 2308 __ AbortIfNotSmi(left_reg);
2303 } 2309 }
2304 // Test smi equality and comparison by signed int comparison. 2310 // Test smi equality and comparison by signed int comparison.
2305 // Both sides are smis, so we can use an Immediate.
2306 __ SmiCompare(left_reg, constant_smi); 2311 __ SmiCompare(left_reg, constant_smi);
2307 left_side->Unuse(); 2312 left_side->Unuse();
2308 right_side->Unuse(); 2313 right_side->Unuse();
2309 dest->Split(cc); 2314 dest->Split(cc);
2310 } else { 2315 } else {
2311 // Only the case where the left side could possibly be a non-smi is left. 2316 // Only the case where the left side could possibly be a non-smi is left.
2312 JumpTarget is_smi; 2317 JumpTarget is_smi;
2313 if (cc == equal) { 2318 if (cc == equal) {
2314 // We can do the equality comparison before the smi check. 2319 // We can do the equality comparison before the smi check.
2315 __ SmiCompare(left_reg, constant_smi); 2320 __ Cmp(left_reg, constant_smi);
2316 dest->true_target()->Branch(equal); 2321 dest->true_target()->Branch(equal);
2317 Condition left_is_smi = masm_->CheckSmi(left_reg); 2322 Condition left_is_smi = masm_->CheckSmi(left_reg);
2318 dest->false_target()->Branch(left_is_smi); 2323 dest->false_target()->Branch(left_is_smi);
2319 } else { 2324 } else {
2320 // Do the smi check, then the comparison. 2325 // Do the smi check, then the comparison.
2321 Condition left_is_smi = masm_->CheckSmi(left_reg); 2326 Condition left_is_smi = masm_->CheckSmi(left_reg);
2322 is_smi.Branch(left_is_smi, left_side, right_side); 2327 is_smi.Branch(left_is_smi, left_side, right_side);
2323 } 2328 }
2324 2329
2325 // Jump or fall through to here if we are comparing a non-smi to a 2330 // Jump or fall through to here if we are comparing a non-smi to a
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after
2566 __ movq(rdi, Operand(rsp, 2 * kPointerSize)); 2571 __ movq(rdi, Operand(rsp, 2 * kPointerSize));
2567 is_smi = masm_->CheckSmi(rdi); 2572 is_smi = masm_->CheckSmi(rdi);
2568 __ j(is_smi, &build_args); 2573 __ j(is_smi, &build_args);
2569 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx); 2574 __ CmpObjectType(rdi, JS_FUNCTION_TYPE, rcx);
2570 __ j(not_equal, &build_args); 2575 __ j(not_equal, &build_args);
2571 2576
2572 // Copy the arguments to this function possibly from the 2577 // Copy the arguments to this function possibly from the
2573 // adaptor frame below it. 2578 // adaptor frame below it.
2574 Label invoke, adapted; 2579 Label invoke, adapted;
2575 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 2580 __ movq(rdx, Operand(rbp, StandardFrameConstants::kCallerFPOffset));
2576 __ SmiCompare(Operand(rdx, StandardFrameConstants::kContextOffset), 2581 __ Cmp(Operand(rdx, StandardFrameConstants::kContextOffset),
2577 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 2582 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
2578 __ j(equal, &adapted); 2583 __ j(equal, &adapted);
2579 2584
2580 // No arguments adaptor frame. Copy fixed number of arguments. 2585 // No arguments adaptor frame. Copy fixed number of arguments.
2581 __ Set(rax, scope()->num_parameters()); 2586 __ Set(rax, scope()->num_parameters());
2582 for (int i = 0; i < scope()->num_parameters(); i++) { 2587 for (int i = 0; i < scope()->num_parameters(); i++) {
2583 __ push(frame_->ParameterAt(i)); 2588 __ push(frame_->ParameterAt(i));
2584 } 2589 }
2585 __ jmp(&invoke); 2590 __ jmp(&invoke);
2586 2591
2587 // Arguments adaptor frame present. Copy arguments from there, but 2592 // Arguments adaptor frame present. Copy arguments from there, but
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after
2744 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 2749 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
2745 // Call the runtime to declare the globals. The inevitable call 2750 // Call the runtime to declare the globals. The inevitable call
2746 // will sync frame elements to memory anyway, so we do it eagerly to 2751 // will sync frame elements to memory anyway, so we do it eagerly to
2747 // allow us to push the arguments directly into place. 2752 // allow us to push the arguments directly into place.
2748 frame_->SyncRange(0, frame_->element_count() - 1); 2753 frame_->SyncRange(0, frame_->element_count() - 1);
2749 2754
2750 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT); 2755 __ movq(kScratchRegister, pairs, RelocInfo::EMBEDDED_OBJECT);
2751 frame_->EmitPush(rsi); // The context is the first argument. 2756 frame_->EmitPush(rsi); // The context is the first argument.
2752 frame_->EmitPush(kScratchRegister); 2757 frame_->EmitPush(kScratchRegister);
2753 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0)); 2758 frame_->EmitPush(Smi::FromInt(is_eval() ? 1 : 0));
2754 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 3); 2759 frame_->EmitPush(Smi::FromInt(strict_mode_flag()));
2760 Result ignored = frame_->CallRuntime(Runtime::kDeclareGlobals, 4);
2755 // Return value is ignored. 2761 // Return value is ignored.
2756 } 2762 }
2757 2763
2758 2764
2759 void CodeGenerator::VisitDeclaration(Declaration* node) { 2765 void CodeGenerator::VisitDeclaration(Declaration* node) {
2760 Comment cmnt(masm_, "[ Declaration"); 2766 Comment cmnt(masm_, "[ Declaration");
2761 Variable* var = node->proxy()->var(); 2767 Variable* var = node->proxy()->var();
2762 ASSERT(var != NULL); // must have been resolved 2768 ASSERT(var != NULL); // must have been resolved
2763 Slot* slot = var->AsSlot(); 2769 Slot* slot = var->AsSlot();
2764 2770
(...skipping 1082 matching lines...) Expand 10 before | Expand all | Expand 10 after
3847 __ cmpq(rcx, rdx); 3853 __ cmpq(rcx, rdx);
3848 end_del_check.Branch(equal); 3854 end_del_check.Branch(equal);
3849 3855
3850 // Convert the entry to a string (or null if it isn't a property anymore). 3856 // Convert the entry to a string (or null if it isn't a property anymore).
3851 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable 3857 frame_->EmitPush(frame_->ElementAt(4)); // push enumerable
3852 frame_->EmitPush(rbx); // push entry 3858 frame_->EmitPush(rbx); // push entry
3853 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2); 3859 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2);
3854 __ movq(rbx, rax); 3860 __ movq(rbx, rax);
3855 3861
3856 // If the property has been removed while iterating, we just skip it. 3862 // If the property has been removed while iterating, we just skip it.
3857 __ SmiCompare(rbx, Smi::FromInt(0)); 3863 __ Cmp(rbx, Smi::FromInt(0));
3858 node->continue_target()->Branch(equal); 3864 node->continue_target()->Branch(equal);
3859 3865
3860 end_del_check.Bind(); 3866 end_del_check.Bind();
3861 // Store the entry in the 'each' expression and take another spin in the 3867 // Store the entry in the 'each' expression and take another spin in the
3862 // loop. rdx: i'th entry of the enum cache (or string there of) 3868 // loop. rdx: i'th entry of the enum cache (or string there of)
3863 frame_->EmitPush(rbx); 3869 frame_->EmitPush(rbx);
3864 { Reference each(this, node->each()); 3870 { Reference each(this, node->each());
3865 // Loading a reference may leave the frame in an unspilled state. 3871 // Loading a reference may leave the frame in an unspilled state.
3866 frame_->SpillAll(); 3872 frame_->SpillAll();
3867 if (!each.is_illegal()) { 3873 if (!each.is_illegal()) {
(...skipping 734 matching lines...) Expand 10 before | Expand all | Expand 10 after
4602 // context slot declaration, but we cannot initialize it at the same 4608 // context slot declaration, but we cannot initialize it at the same
4603 // time, because the const declaration may be at the end of the eval 4609 // time, because the const declaration may be at the end of the eval
4604 // code (sigh...) and the const variable may have been used before 4610 // code (sigh...) and the const variable may have been used before
4605 // (where its value is 'undefined'). Thus, we can only do the 4611 // (where its value is 'undefined'). Thus, we can only do the
4606 // initialization when we actually encounter the expression and when 4612 // initialization when we actually encounter the expression and when
4607 // the expression operands are defined and valid, and thus we need the 4613 // the expression operands are defined and valid, and thus we need the
4608 // split into 2 operations: declaration of the context slot followed 4614 // split into 2 operations: declaration of the context slot followed
4609 // by initialization. 4615 // by initialization.
4610 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3); 4616 value = frame_->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
4611 } else { 4617 } else {
4612 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 3); 4618 frame_->Push(Smi::FromInt(strict_mode_flag()));
4619 value = frame_->CallRuntime(Runtime::kStoreContextSlot, 4);
4613 } 4620 }
4614 // Storing a variable must keep the (new) value on the expression 4621 // Storing a variable must keep the (new) value on the expression
4615 // stack. This is necessary for compiling chained assignment 4622 // stack. This is necessary for compiling chained assignment
4616 // expressions. 4623 // expressions.
4617 frame_->Push(&value); 4624 frame_->Push(&value);
4618 } else { 4625 } else {
4619 ASSERT(!slot->var()->is_dynamic()); 4626 ASSERT(!slot->var()->is_dynamic());
4620 4627
4621 JumpTarget exit; 4628 JumpTarget exit;
4622 if (init_state == CONST_INIT) { 4629 if (init_state == CONST_INIT) {
(...skipping 292 matching lines...) Expand 10 before | Expand all | Expand 10 after
4915 break; 4922 break;
4916 } 4923 }
4917 // Fall through 4924 // Fall through
4918 } 4925 }
4919 case ObjectLiteral::Property::PROTOTYPE: { 4926 case ObjectLiteral::Property::PROTOTYPE: {
4920 // Duplicate the object as an argument to the runtime call. 4927 // Duplicate the object as an argument to the runtime call.
4921 frame_->Dup(); 4928 frame_->Dup();
4922 Load(property->key()); 4929 Load(property->key());
4923 Load(property->value()); 4930 Load(property->value());
4924 if (property->emit_store()) { 4931 if (property->emit_store()) {
4932 frame_->Push(Smi::FromInt(NONE)); // PropertyAttributes
4925 // Ignore the result. 4933 // Ignore the result.
4926 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 3); 4934 Result ignored = frame_->CallRuntime(Runtime::kSetProperty, 4);
4927 } else { 4935 } else {
4928 frame_->Drop(3); 4936 frame_->Drop(3);
4929 } 4937 }
4930 break; 4938 break;
4931 } 4939 }
4932 case ObjectLiteral::Property::SETTER: { 4940 case ObjectLiteral::Property::SETTER: {
4933 // Duplicate the object as an argument to the runtime call. 4941 // Duplicate the object as an argument to the runtime call.
4934 frame_->Dup(); 4942 frame_->Dup();
4935 Load(property->key()); 4943 Load(property->key());
4936 frame_->Push(Smi::FromInt(1)); 4944 frame_->Push(Smi::FromInt(1));
(...skipping 1257 matching lines...) Expand 10 before | Expand all | Expand 10 after
6194 6202
6195 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) { 6203 void CodeGenerator::GenerateIsConstructCall(ZoneList<Expression*>* args) {
6196 ASSERT(args->length() == 0); 6204 ASSERT(args->length() == 0);
6197 6205
6198 // Get the frame pointer for the calling frame. 6206 // Get the frame pointer for the calling frame.
6199 Result fp = allocator()->Allocate(); 6207 Result fp = allocator()->Allocate();
6200 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 6208 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset));
6201 6209
6202 // Skip the arguments adaptor frame if it exists. 6210 // Skip the arguments adaptor frame if it exists.
6203 Label check_frame_marker; 6211 Label check_frame_marker;
6204 __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset), 6212 __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
6205 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 6213 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
6206 __ j(not_equal, &check_frame_marker); 6214 __ j(not_equal, &check_frame_marker);
6207 __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset)); 6215 __ movq(fp.reg(), Operand(fp.reg(), StandardFrameConstants::kCallerFPOffset));
6208 6216
6209 // Check the marker in the calling frame. 6217 // Check the marker in the calling frame.
6210 __ bind(&check_frame_marker); 6218 __ bind(&check_frame_marker);
6211 __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset), 6219 __ Cmp(Operand(fp.reg(), StandardFrameConstants::kMarkerOffset),
6212 Smi::FromInt(StackFrame::CONSTRUCT)); 6220 Smi::FromInt(StackFrame::CONSTRUCT));
6213 fp.Unuse(); 6221 fp.Unuse();
6214 destination()->Split(equal); 6222 destination()->Split(equal);
6215 } 6223 }
6216 6224
6217 6225
6218 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { 6226 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
6219 ASSERT(args->length() == 0); 6227 ASSERT(args->length() == 0);
6220 6228
6221 Result fp = allocator_->Allocate(); 6229 Result fp = allocator_->Allocate();
6222 Result result = allocator_->Allocate(); 6230 Result result = allocator_->Allocate();
6223 ASSERT(fp.is_valid() && result.is_valid()); 6231 ASSERT(fp.is_valid() && result.is_valid());
6224 6232
6225 Label exit; 6233 Label exit;
6226 6234
6227 // Get the number of formal parameters. 6235 // Get the number of formal parameters.
6228 __ Move(result.reg(), Smi::FromInt(scope()->num_parameters())); 6236 __ Move(result.reg(), Smi::FromInt(scope()->num_parameters()));
6229 6237
6230 // Check if the calling frame is an arguments adaptor frame. 6238 // Check if the calling frame is an arguments adaptor frame.
6231 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset)); 6239 __ movq(fp.reg(), Operand(rbp, StandardFrameConstants::kCallerFPOffset));
6232 __ SmiCompare(Operand(fp.reg(), StandardFrameConstants::kContextOffset), 6240 __ Cmp(Operand(fp.reg(), StandardFrameConstants::kContextOffset),
6233 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)); 6241 Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR));
6234 __ j(not_equal, &exit); 6242 __ j(not_equal, &exit);
6235 6243
6236 // Arguments adaptor case: Read the arguments length from the 6244 // Arguments adaptor case: Read the arguments length from the
6237 // adaptor frame. 6245 // adaptor frame.
6238 __ movq(result.reg(), 6246 __ movq(result.reg(),
6239 Operand(fp.reg(), ArgumentsAdaptorFrameConstants::kLengthOffset)); 6247 Operand(fp.reg(), ArgumentsAdaptorFrameConstants::kLengthOffset));
6240 6248
6241 __ bind(&exit); 6249 __ bind(&exit);
6242 result.set_type_info(TypeInfo::Smi()); 6250 result.set_type_info(TypeInfo::Smi());
6243 if (FLAG_debug_code) { 6251 if (FLAG_debug_code) {
(...skipping 538 matching lines...) Expand 10 before | Expand all | Expand 10 after
6782 frame_->Spill(index1.reg()); 6790 frame_->Spill(index1.reg());
6783 frame_->Spill(index2.reg()); 6791 frame_->Spill(index2.reg());
6784 6792
6785 DeferredSwapElements* deferred = new DeferredSwapElements(object.reg(), 6793 DeferredSwapElements* deferred = new DeferredSwapElements(object.reg(),
6786 index1.reg(), 6794 index1.reg(),
6787 index2.reg()); 6795 index2.reg());
6788 6796
6789 // Fetch the map and check if array is in fast case. 6797 // Fetch the map and check if array is in fast case.
6790 // Check that object doesn't require security checks and 6798 // Check that object doesn't require security checks and
6791 // has no indexed interceptor. 6799 // has no indexed interceptor.
6792 __ CmpObjectType(object.reg(), FIRST_JS_OBJECT_TYPE, tmp1.reg()); 6800 __ CmpObjectType(object.reg(), JS_ARRAY_TYPE, tmp1.reg());
6793 deferred->Branch(below); 6801 deferred->Branch(not_equal);
6794 __ testb(FieldOperand(tmp1.reg(), Map::kBitFieldOffset), 6802 __ testb(FieldOperand(tmp1.reg(), Map::kBitFieldOffset),
6795 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask)); 6803 Immediate(KeyedLoadIC::kSlowCaseBitFieldMask));
6796 deferred->Branch(not_zero); 6804 deferred->Branch(not_zero);
6797 6805
6798 // Check the object's elements are in fast case and writable. 6806 // Check the object's elements are in fast case and writable.
6799 __ movq(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset)); 6807 __ movq(tmp1.reg(), FieldOperand(object.reg(), JSObject::kElementsOffset));
6800 __ CompareRoot(FieldOperand(tmp1.reg(), HeapObject::kMapOffset), 6808 __ CompareRoot(FieldOperand(tmp1.reg(), HeapObject::kMapOffset),
6801 Heap::kFixedArrayMapRootIndex); 6809 Heap::kFixedArrayMapRootIndex);
6802 deferred->Branch(not_equal); 6810 deferred->Branch(not_equal);
6803 6811
(...skipping 21 matching lines...) Expand all
6825 FixedArray::kHeaderSize)); 6833 FixedArray::kHeaderSize));
6826 6834
6827 // Swap elements. 6835 // Swap elements.
6828 __ movq(object.reg(), Operand(index1.reg(), 0)); 6836 __ movq(object.reg(), Operand(index1.reg(), 0));
6829 __ movq(tmp2.reg(), Operand(index2.reg(), 0)); 6837 __ movq(tmp2.reg(), Operand(index2.reg(), 0));
6830 __ movq(Operand(index2.reg(), 0), object.reg()); 6838 __ movq(Operand(index2.reg(), 0), object.reg());
6831 __ movq(Operand(index1.reg(), 0), tmp2.reg()); 6839 __ movq(Operand(index1.reg(), 0), tmp2.reg());
6832 6840
6833 Label done; 6841 Label done;
6834 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done); 6842 __ InNewSpace(tmp1.reg(), tmp2.reg(), equal, &done);
6835 // Possible optimization: do a check that both values are Smis 6843 // Possible optimization: do a check that both values are smis
6836 // (or them and test against Smi mask.) 6844 // (or them and test against Smi mask.)
6837 6845
6838 __ movq(tmp2.reg(), tmp1.reg()); 6846 __ movq(tmp2.reg(), tmp1.reg());
6839 __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg(), kDontSaveFPRegs); 6847 __ RecordWriteHelper(tmp1.reg(), index1.reg(), object.reg(), kDontSaveFPRegs);
6840 __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg(), kDontSaveFPRegs); 6848 __ RecordWriteHelper(tmp2.reg(), index2.reg(), object.reg(), kDontSaveFPRegs);
6841 __ bind(&done); 6849 __ bind(&done);
6842 6850
6843 deferred->BindExit(); 6851 deferred->BindExit();
6844 frame_->Push(Factory::undefined_value()); 6852 frame_->Push(Factory::undefined_value());
6845 } 6853 }
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
7038 answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2); 7046 answer = frame()->CallRuntime(Runtime::kMath_pow_cfunction, 2);
7039 7047
7040 done.Bind(&answer); 7048 done.Bind(&answer);
7041 frame()->Push(&answer); 7049 frame()->Push(&answer);
7042 } 7050 }
7043 7051
7044 7052
7045 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) { 7053 void CodeGenerator::GenerateMathSin(ZoneList<Expression*>* args) {
7046 ASSERT_EQ(args->length(), 1); 7054 ASSERT_EQ(args->length(), 1);
7047 Load(args->at(0)); 7055 Load(args->at(0));
7048 TranscendentalCacheStub stub(TranscendentalCache::SIN); 7056 TranscendentalCacheStub stub(TranscendentalCache::SIN,
7057 TranscendentalCacheStub::TAGGED);
7049 Result result = frame_->CallStub(&stub, 1); 7058 Result result = frame_->CallStub(&stub, 1);
7050 frame_->Push(&result); 7059 frame_->Push(&result);
7051 } 7060 }
7052 7061
7053 7062
7054 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) { 7063 void CodeGenerator::GenerateMathCos(ZoneList<Expression*>* args) {
7055 ASSERT_EQ(args->length(), 1); 7064 ASSERT_EQ(args->length(), 1);
7056 Load(args->at(0)); 7065 Load(args->at(0));
7057 TranscendentalCacheStub stub(TranscendentalCache::COS); 7066 TranscendentalCacheStub stub(TranscendentalCache::COS,
7067 TranscendentalCacheStub::TAGGED);
7058 Result result = frame_->CallStub(&stub, 1); 7068 Result result = frame_->CallStub(&stub, 1);
7059 frame_->Push(&result); 7069 frame_->Push(&result);
7060 } 7070 }
7061 7071
7062 7072
7063 void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) { 7073 void CodeGenerator::GenerateMathLog(ZoneList<Expression*>* args) {
7064 ASSERT_EQ(args->length(), 1); 7074 ASSERT_EQ(args->length(), 1);
7065 Load(args->at(0)); 7075 Load(args->at(0));
7066 TranscendentalCacheStub stub(TranscendentalCache::LOG); 7076 TranscendentalCacheStub stub(TranscendentalCache::LOG,
7077 TranscendentalCacheStub::TAGGED);
7067 Result result = frame_->CallStub(&stub, 1); 7078 Result result = frame_->CallStub(&stub, 1);
7068 frame_->Push(&result); 7079 frame_->Push(&result);
7069 } 7080 }
7070 7081
7071 7082
7072 // Generates the Math.sqrt method. Please note - this function assumes that 7083 // Generates the Math.sqrt method. Please note - this function assumes that
7073 // the callsite has executed ToNumber on the argument. 7084 // the callsite has executed ToNumber on the argument.
7074 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) { 7085 void CodeGenerator::GenerateMathSqrt(ZoneList<Expression*>* args) {
7075 ASSERT(args->length() == 1); 7086 ASSERT(args->length() == 1);
7076 Load(args->at(0)); 7087 Load(args->at(0));
(...skipping 170 matching lines...) Expand 10 before | Expand all | Expand 10 after
7247 Load(property->key()); 7258 Load(property->key());
7248 frame_->Push(Smi::FromInt(strict_mode_flag())); 7259 frame_->Push(Smi::FromInt(strict_mode_flag()));
7249 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3); 7260 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 3);
7250 frame_->Push(&answer); 7261 frame_->Push(&answer);
7251 return; 7262 return;
7252 } 7263 }
7253 7264
7254 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); 7265 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
7255 if (variable != NULL) { 7266 if (variable != NULL) {
7256 // Delete of an unqualified identifier is disallowed in strict mode 7267 // Delete of an unqualified identifier is disallowed in strict mode
7257 // so this code can only be reached in non-strict mode. 7268 // but "delete this" is.
7258 ASSERT(strict_mode_flag() == kNonStrictMode); 7269 ASSERT(strict_mode_flag() == kNonStrictMode || variable->is_this());
7259 Slot* slot = variable->AsSlot(); 7270 Slot* slot = variable->AsSlot();
7260 if (variable->is_global()) { 7271 if (variable->is_global()) {
7261 LoadGlobal(); 7272 LoadGlobal();
7262 frame_->Push(variable->name()); 7273 frame_->Push(variable->name());
7263 frame_->Push(Smi::FromInt(kNonStrictMode)); 7274 frame_->Push(Smi::FromInt(kNonStrictMode));
7264 Result answer = frame_->InvokeBuiltin(Builtins::DELETE, 7275 Result answer = frame_->InvokeBuiltin(Builtins::DELETE,
7265 CALL_FUNCTION, 3); 7276 CALL_FUNCTION, 3);
7266 frame_->Push(&answer); 7277 frame_->Push(&answer);
7267 return;
7268 7278
7269 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 7279 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
7270 // Call the runtime to delete from the context holding the named 7280 // Call the runtime to delete from the context holding the named
7271 // variable. Sync the virtual frame eagerly so we can push the 7281 // variable. Sync the virtual frame eagerly so we can push the
7272 // arguments directly into place. 7282 // arguments directly into place.
7273 frame_->SyncRange(0, frame_->element_count() - 1); 7283 frame_->SyncRange(0, frame_->element_count() - 1);
7274 frame_->EmitPush(rsi); 7284 frame_->EmitPush(rsi);
7275 frame_->EmitPush(variable->name()); 7285 frame_->EmitPush(variable->name());
7276 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2); 7286 Result answer = frame_->CallRuntime(Runtime::kDeleteContextSlot, 2);
7277 frame_->Push(&answer); 7287 frame_->Push(&answer);
7278 return; 7288 } else {
7289 // Default: Result of deleting non-global, not dynamically
7290 // introduced variables is false.
7291 frame_->Push(Factory::false_value());
7279 } 7292 }
7280
7281 // Default: Result of deleting non-global, not dynamically
7282 // introduced variables is false.
7283 frame_->Push(Factory::false_value());
7284
7285 } else { 7293 } else {
7286 // Default: Result of deleting expressions is true. 7294 // Default: Result of deleting expressions is true.
7287 Load(node->expression()); // may have side-effects 7295 Load(node->expression()); // may have side-effects
7288 frame_->SetElementAt(0, Factory::true_value()); 7296 frame_->SetElementAt(0, Factory::true_value());
7289 } 7297 }
7290 7298
7291 } else if (op == Token::TYPEOF) { 7299 } else if (op == Token::TYPEOF) {
7292 // Special case for loading the typeof expression; see comment on 7300 // Special case for loading the typeof expression; see comment on
7293 // LoadTypeofExpression(). 7301 // LoadTypeofExpression().
7294 LoadTypeofExpression(node->expression()); 7302 LoadTypeofExpression(node->expression());
(...skipping 665 matching lines...) Expand 10 before | Expand all | Expand 10 after
7960 bool CodeGenerator::HasValidEntryRegisters() { 7968 bool CodeGenerator::HasValidEntryRegisters() {
7961 return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0)) 7969 return (allocator()->count(rax) == (frame()->is_used(rax) ? 1 : 0))
7962 && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0)) 7970 && (allocator()->count(rbx) == (frame()->is_used(rbx) ? 1 : 0))
7963 && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0)) 7971 && (allocator()->count(rcx) == (frame()->is_used(rcx) ? 1 : 0))
7964 && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0)) 7972 && (allocator()->count(rdx) == (frame()->is_used(rdx) ? 1 : 0))
7965 && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0)) 7973 && (allocator()->count(rdi) == (frame()->is_used(rdi) ? 1 : 0))
7966 && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0)) 7974 && (allocator()->count(r8) == (frame()->is_used(r8) ? 1 : 0))
7967 && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0)) 7975 && (allocator()->count(r9) == (frame()->is_used(r9) ? 1 : 0))
7968 && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0)) 7976 && (allocator()->count(r11) == (frame()->is_used(r11) ? 1 : 0))
7969 && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0)) 7977 && (allocator()->count(r14) == (frame()->is_used(r14) ? 1 : 0))
7970 && (allocator()->count(r12) == (frame()->is_used(r12) ? 1 : 0)); 7978 && (allocator()->count(r15) == (frame()->is_used(r15) ? 1 : 0));
7971 } 7979 }
7972 #endif 7980 #endif
7973 7981
7974 7982
7975 7983
7976 // Emit a LoadIC call to get the value from receiver and leave it in 7984 // Emit a LoadIC call to get the value from receiver and leave it in
7977 // dst. The receiver register is restored after the call. 7985 // dst. The receiver register is restored after the call.
7978 class DeferredReferenceGetNamedValue: public DeferredCode { 7986 class DeferredReferenceGetNamedValue: public DeferredCode {
7979 public: 7987 public:
7980 DeferredReferenceGetNamedValue(Register dst, 7988 DeferredReferenceGetNamedValue(Register dst,
(...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after
8083 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1); 8091 __ IncrementCounter(&Counters::keyed_load_inline_miss, 1);
8084 8092
8085 if (!dst_.is(rax)) __ movq(dst_, rax); 8093 if (!dst_.is(rax)) __ movq(dst_, rax);
8086 } 8094 }
8087 8095
8088 8096
8089 class DeferredReferenceSetKeyedValue: public DeferredCode { 8097 class DeferredReferenceSetKeyedValue: public DeferredCode {
8090 public: 8098 public:
8091 DeferredReferenceSetKeyedValue(Register value, 8099 DeferredReferenceSetKeyedValue(Register value,
8092 Register key, 8100 Register key,
8093 Register receiver) 8101 Register receiver,
8094 : value_(value), key_(key), receiver_(receiver) { 8102 StrictModeFlag strict_mode)
8103 : value_(value),
8104 key_(key),
8105 receiver_(receiver),
8106 strict_mode_(strict_mode) {
8095 set_comment("[ DeferredReferenceSetKeyedValue"); 8107 set_comment("[ DeferredReferenceSetKeyedValue");
8096 } 8108 }
8097 8109
8098 virtual void Generate(); 8110 virtual void Generate();
8099 8111
8100 Label* patch_site() { return &patch_site_; } 8112 Label* patch_site() { return &patch_site_; }
8101 8113
8102 private: 8114 private:
8103 Register value_; 8115 Register value_;
8104 Register key_; 8116 Register key_;
8105 Register receiver_; 8117 Register receiver_;
8106 Label patch_site_; 8118 Label patch_site_;
8119 StrictModeFlag strict_mode_;
8107 }; 8120 };
8108 8121
8109 8122
8110 void DeferredReferenceSetKeyedValue::Generate() { 8123 void DeferredReferenceSetKeyedValue::Generate() {
8111 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1); 8124 __ IncrementCounter(&Counters::keyed_store_inline_miss, 1);
8112 // Move value, receiver, and key to registers rax, rdx, and rcx, as 8125 // Move value, receiver, and key to registers rax, rdx, and rcx, as
8113 // the IC stub expects. 8126 // the IC stub expects.
8114 // Move value to rax, using xchg if the receiver or key is in rax. 8127 // Move value to rax, using xchg if the receiver or key is in rax.
8115 if (!value_.is(rax)) { 8128 if (!value_.is(rax)) {
8116 if (!receiver_.is(rax) && !key_.is(rax)) { 8129 if (!receiver_.is(rax) && !key_.is(rax)) {
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
8148 __ movq(rcx, key_); 8161 __ movq(rcx, key_);
8149 } 8162 }
8150 } else if (key_.is(rcx)) { 8163 } else if (key_.is(rcx)) {
8151 __ movq(rdx, receiver_); 8164 __ movq(rdx, receiver_);
8152 } else { 8165 } else {
8153 __ movq(rcx, key_); 8166 __ movq(rcx, key_);
8154 __ movq(rdx, receiver_); 8167 __ movq(rdx, receiver_);
8155 } 8168 }
8156 8169
8157 // Call the IC stub. 8170 // Call the IC stub.
8158 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 8171 Handle<Code> ic(Builtins::builtin(
8172 (strict_mode_ == kStrictMode) ? Builtins::KeyedStoreIC_Initialize_Strict
8173 : Builtins::KeyedStoreIC_Initialize));
8159 __ Call(ic, RelocInfo::CODE_TARGET); 8174 __ Call(ic, RelocInfo::CODE_TARGET);
8160 // The delta from the start of the map-compare instructions (initial movq) 8175 // The delta from the start of the map-compare instructions (initial movq)
8161 // to the test instruction. We use masm_-> directly here instead of the 8176 // to the test instruction. We use masm_-> directly here instead of the
8162 // __ macro because the macro sometimes uses macro expansion to turn 8177 // __ macro because the macro sometimes uses macro expansion to turn
8163 // into something that can't return a value. This is encountered 8178 // into something that can't return a value. This is encountered
8164 // when doing generated code coverage tests. 8179 // when doing generated code coverage tests.
8165 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site()); 8180 int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(patch_site());
8166 // Here we use masm_-> instead of the __ macro because this is the 8181 // Here we use masm_-> instead of the __ macro because this is the
8167 // instruction that gets patched and coverage code gets in the way. 8182 // instruction that gets patched and coverage code gets in the way.
8168 masm_->testl(rax, Immediate(-delta_to_patch_site)); 8183 masm_->testl(rax, Immediate(-delta_to_patch_site));
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
8215 DeferredReferenceGetNamedValue* deferred = 8230 DeferredReferenceGetNamedValue* deferred =
8216 new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name); 8231 new DeferredReferenceGetNamedValue(result.reg(), receiver.reg(), name);
8217 8232
8218 // Check that the receiver is a heap object. 8233 // Check that the receiver is a heap object.
8219 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); 8234 __ JumpIfSmi(receiver.reg(), deferred->entry_label());
8220 8235
8221 __ bind(deferred->patch_site()); 8236 __ bind(deferred->patch_site());
8222 // This is the map check instruction that will be patched (so we can't 8237 // This is the map check instruction that will be patched (so we can't
8223 // use the double underscore macro that may insert instructions). 8238 // use the double underscore macro that may insert instructions).
8224 // Initially use an invalid map to force a failure. 8239 // Initially use an invalid map to force a failure.
8225 masm()->Move(kScratchRegister, Factory::null_value()); 8240 masm()->movq(kScratchRegister, Factory::null_value(),
8241 RelocInfo::EMBEDDED_OBJECT);
8226 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), 8242 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
8227 kScratchRegister); 8243 kScratchRegister);
8228 // This branch is always a forwards branch so it's always a fixed 8244 // This branch is always a forwards branch so it's always a fixed
8229 // size which allows the assert below to succeed and patching to work. 8245 // size which allows the assert below to succeed and patching to work.
8230 // Don't use deferred->Branch(...), since that might add coverage code. 8246 // Don't use deferred->Branch(...), since that might add coverage code.
8231 masm()->j(not_equal, deferred->entry_label()); 8247 masm()->j(not_equal, deferred->entry_label());
8232 8248
8233 // The delta from the patch label to the load offset must be 8249 // The delta from the patch label to the load offset must be
8234 // statically known. 8250 // statically known.
8235 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) == 8251 ASSERT(masm()->SizeOfCodeGeneratedSince(deferred->patch_site()) ==
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
8291 Condition is_smi = masm()->CheckSmi(receiver.reg()); 8307 Condition is_smi = masm()->CheckSmi(receiver.reg());
8292 slow.Branch(is_smi, &value, &receiver); 8308 slow.Branch(is_smi, &value, &receiver);
8293 8309
8294 // This is the map check instruction that will be patched. 8310 // This is the map check instruction that will be patched.
8295 // Initially use an invalid map to force a failure. The exact 8311 // Initially use an invalid map to force a failure. The exact
8296 // instruction sequence is important because we use the 8312 // instruction sequence is important because we use the
8297 // kOffsetToStoreInstruction constant for patching. We avoid using 8313 // kOffsetToStoreInstruction constant for patching. We avoid using
8298 // the __ macro for the following two instructions because it 8314 // the __ macro for the following two instructions because it
8299 // might introduce extra instructions. 8315 // might introduce extra instructions.
8300 __ bind(&patch_site); 8316 __ bind(&patch_site);
8301 masm()->Move(kScratchRegister, Factory::null_value()); 8317 masm()->movq(kScratchRegister, Factory::null_value(),
8318 RelocInfo::EMBEDDED_OBJECT);
8302 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset), 8319 masm()->cmpq(FieldOperand(receiver.reg(), HeapObject::kMapOffset),
8303 kScratchRegister); 8320 kScratchRegister);
8304 // This branch is always a forwards branch so it's always a fixed size 8321 // This branch is always a forwards branch so it's always a fixed size
8305 // which allows the assert below to succeed and patching to work. 8322 // which allows the assert below to succeed and patching to work.
8306 slow.Branch(not_equal, &value, &receiver); 8323 slow.Branch(not_equal, &value, &receiver);
8307 8324
8308 // The delta from the patch label to the store offset must be 8325 // The delta from the patch label to the store offset must be
8309 // statically known. 8326 // statically known.
8310 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) == 8327 ASSERT(masm()->SizeOfCodeGeneratedSince(&patch_site) ==
8311 StoreIC::kOffsetToStoreInstruction); 8328 StoreIC::kOffsetToStoreInstruction);
(...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after
8492 bool value_is_constant = result.is_constant(); 8509 bool value_is_constant = result.is_constant();
8493 8510
8494 // Make sure that value, key and receiver are in registers. 8511 // Make sure that value, key and receiver are in registers.
8495 result.ToRegister(); 8512 result.ToRegister();
8496 key.ToRegister(); 8513 key.ToRegister();
8497 receiver.ToRegister(); 8514 receiver.ToRegister();
8498 8515
8499 DeferredReferenceSetKeyedValue* deferred = 8516 DeferredReferenceSetKeyedValue* deferred =
8500 new DeferredReferenceSetKeyedValue(result.reg(), 8517 new DeferredReferenceSetKeyedValue(result.reg(),
8501 key.reg(), 8518 key.reg(),
8502 receiver.reg()); 8519 receiver.reg(),
8520 strict_mode_flag());
8503 8521
8504 // Check that the receiver is not a smi. 8522 // Check that the receiver is not a smi.
8505 __ JumpIfSmi(receiver.reg(), deferred->entry_label()); 8523 __ JumpIfSmi(receiver.reg(), deferred->entry_label());
8506 8524
8507 // Check that the key is a smi. 8525 // Check that the key is a smi.
8508 if (!key.is_smi()) { 8526 if (!key.is_smi()) {
8509 __ JumpIfNotSmi(key.reg(), deferred->entry_label()); 8527 __ JumpIfNotSmi(key.reg(), deferred->entry_label());
8510 } else if (FLAG_debug_code) { 8528 } else if (FLAG_debug_code) {
8511 __ AbortIfNotSmi(key.reg()); 8529 __ AbortIfNotSmi(key.reg());
8512 } 8530 }
8513 8531
8514 // Check that the receiver is a JSArray. 8532 // Check that the receiver is a JSArray.
8515 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister); 8533 __ CmpObjectType(receiver.reg(), JS_ARRAY_TYPE, kScratchRegister);
8516 deferred->Branch(not_equal); 8534 deferred->Branch(not_equal);
8517 8535
8518 // Check that the key is within bounds. Both the key and the length of
8519 // the JSArray are smis. Use unsigned comparison to handle negative keys.
8520 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
8521 key.reg());
8522 deferred->Branch(below_equal);
8523
8524 // Get the elements array from the receiver and check that it is not a 8536 // Get the elements array from the receiver and check that it is not a
8525 // dictionary. 8537 // dictionary.
8526 __ movq(tmp.reg(), 8538 __ movq(tmp.reg(),
8527 FieldOperand(receiver.reg(), JSArray::kElementsOffset)); 8539 FieldOperand(receiver.reg(), JSArray::kElementsOffset));
8528 8540
8529 // Check whether it is possible to omit the write barrier. If the elements 8541 // Check whether it is possible to omit the write barrier. If the elements
8530 // array is in new space or the value written is a smi we can safely update 8542 // array is in new space or the value written is a smi we can safely update
8531 // the elements array without write barrier. 8543 // the elements array without write barrier.
8532 Label in_new_space; 8544 Label in_new_space;
8533 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space); 8545 __ InNewSpace(tmp.reg(), tmp2.reg(), equal, &in_new_space);
8534 if (!value_is_constant) { 8546 if (!value_is_constant) {
8535 __ JumpIfNotSmi(result.reg(), deferred->entry_label()); 8547 __ JumpIfNotSmi(result.reg(), deferred->entry_label());
8536 } 8548 }
8537 8549
8538 __ bind(&in_new_space); 8550 __ bind(&in_new_space);
8539 8551
8540 // Bind the deferred code patch site to be able to locate the fixed 8552 // Bind the deferred code patch site to be able to locate the fixed
8541 // array map comparison. When debugging, we patch this comparison to 8553 // array map comparison. When debugging, we patch this comparison to
8542 // always fail so that we will hit the IC call in the deferred code 8554 // always fail so that we will hit the IC call in the deferred code
8543 // which will allow the debugger to break for fast case stores. 8555 // which will allow the debugger to break for fast case stores.
8544 __ bind(deferred->patch_site()); 8556 __ bind(deferred->patch_site());
8545 // Avoid using __ to ensure the distance from patch_site 8557 // Avoid using __ to ensure the distance from patch_site
8546 // to the map address is always the same. 8558 // to the map address is always the same.
8547 masm()->movq(kScratchRegister, Factory::fixed_array_map(), 8559 masm()->movq(kScratchRegister, Factory::fixed_array_map(),
8548 RelocInfo::EMBEDDED_OBJECT); 8560 RelocInfo::EMBEDDED_OBJECT);
8549 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset), 8561 __ cmpq(FieldOperand(tmp.reg(), HeapObject::kMapOffset),
8550 kScratchRegister); 8562 kScratchRegister);
8551 deferred->Branch(not_equal); 8563 deferred->Branch(not_equal);
8552 8564
8565 // Check that the key is within bounds. Both the key and the length of
8566 // the JSArray are smis (because the fixed array check above ensures the
8567 // elements are in fast case). Use unsigned comparison to handle negative
8568 // keys.
8569 __ SmiCompare(FieldOperand(receiver.reg(), JSArray::kLengthOffset),
8570 key.reg());
8571 deferred->Branch(below_equal);
8572
8553 // Store the value. 8573 // Store the value.
8554 SmiIndex index = 8574 SmiIndex index =
8555 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2); 8575 masm()->SmiToIndex(kScratchRegister, key.reg(), kPointerSizeLog2);
8556 __ movq(FieldOperand(tmp.reg(), 8576 __ movq(FieldOperand(tmp.reg(),
8557 index.reg, 8577 index.reg,
8558 index.scale, 8578 index.scale,
8559 FixedArray::kHeaderSize), 8579 FixedArray::kHeaderSize),
8560 result.reg()); 8580 result.reg());
8561 __ IncrementCounter(&Counters::keyed_store_inline, 1); 8581 __ IncrementCounter(&Counters::keyed_store_inline, 1);
8562 8582
8563 deferred->BindExit(); 8583 deferred->BindExit();
8564 } else { 8584 } else {
8565 result = frame()->CallKeyedStoreIC(); 8585 result = frame()->CallKeyedStoreIC(strict_mode_flag());
8566 // Make sure that we do not have a test instruction after the 8586 // Make sure that we do not have a test instruction after the
8567 // call. A test instruction after the call is used to 8587 // call. A test instruction after the call is used to
8568 // indicate that we have generated an inline version of the 8588 // indicate that we have generated an inline version of the
8569 // keyed store. 8589 // keyed store.
8570 __ nop(); 8590 __ nop();
8571 } 8591 }
8572 ASSERT(frame()->height() == original_height - 3); 8592 ASSERT(frame()->height() == original_height - 3);
8573 return result; 8593 return result;
8574 } 8594 }
8575 8595
(...skipping 258 matching lines...) Expand 10 before | Expand all | Expand 10 after
8834 } 8854 }
8835 8855
8836 #endif 8856 #endif
8837 8857
8838 8858
8839 #undef __ 8859 #undef __
8840 8860
8841 } } // namespace v8::internal 8861 } } // namespace v8::internal
8842 8862
8843 #endif // V8_TARGET_ARCH_X64 8863 #endif // V8_TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « src/x64/codegen-x64.h ('k') | src/x64/codegen-x64-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698