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

Side by Side Diff: src/ia32/full-codegen-ia32.cc

Issue 1989012: Add complete implementation of full compiler for the ia32 architecture... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 10 years, 7 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/full-codegen.cc ('k') | src/x64/full-codegen-x64.cc » ('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 2010 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 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
72 __ mov(eax, Immediate(Factory::undefined_value())); 72 __ mov(eax, Immediate(Factory::undefined_value()));
73 for (int i = 0; i < locals_count; i++) { 73 for (int i = 0; i < locals_count; i++) {
74 __ push(eax); 74 __ push(eax);
75 } 75 }
76 } 76 }
77 } 77 }
78 78
79 bool function_in_register = true; 79 bool function_in_register = true;
80 80
81 // Possibly allocate a local context. 81 // Possibly allocate a local context.
82 if (scope()->num_heap_slots() > 0) { 82 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
83 if (heap_slots > 0) {
83 Comment cmnt(masm_, "[ Allocate local context"); 84 Comment cmnt(masm_, "[ Allocate local context");
84 // Argument to NewContext is the function, which is still in edi. 85 // Argument to NewContext is the function, which is still in edi.
85 __ push(edi); 86 __ push(edi);
86 __ CallRuntime(Runtime::kNewContext, 1); 87 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
88 FastNewContextStub stub(heap_slots);
89 __ CallStub(&stub);
90 } else {
91 __ CallRuntime(Runtime::kNewContext, 1);
92 }
87 function_in_register = false; 93 function_in_register = false;
88 // Context is returned in both eax and esi. It replaces the context 94 // Context is returned in both eax and esi. It replaces the context
89 // passed to us. It's saved in the stack and kept live in esi. 95 // passed to us. It's saved in the stack and kept live in esi.
90 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); 96 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
91 97
92 // Copy parameters into context if necessary. 98 // Copy parameters into context if necessary.
93 int num_parameters = scope()->num_parameters(); 99 int num_parameters = scope()->num_parameters();
94 for (int i = 0; i < num_parameters; i++) { 100 for (int i = 0; i < num_parameters; i++) {
95 Slot* slot = scope()->parameter(i)->slot(); 101 Slot* slot = scope()->parameter(i)->slot();
96 if (slot != NULL && slot->type() == Slot::CONTEXT) { 102 if (slot != NULL && slot->type() == Slot::CONTEXT) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
133 __ CallStub(&stub); 139 __ CallStub(&stub);
134 __ mov(ecx, eax); // Duplicate result. 140 __ mov(ecx, eax); // Duplicate result.
135 Move(arguments->slot(), eax, ebx, edx); 141 Move(arguments->slot(), eax, ebx, edx);
136 Slot* dot_arguments_slot = 142 Slot* dot_arguments_slot =
137 scope()->arguments_shadow()->AsVariable()->slot(); 143 scope()->arguments_shadow()->AsVariable()->slot();
138 Move(dot_arguments_slot, ecx, ebx, edx); 144 Move(dot_arguments_slot, ecx, ebx, edx);
139 } 145 }
140 } 146 }
141 147
142 { Comment cmnt(masm_, "[ Declarations"); 148 { Comment cmnt(masm_, "[ Declarations");
143 VisitDeclarations(scope()->declarations()); 149 // For named function expressions, declare the function name as a
150 // constant.
151 if (scope()->is_function_scope() && scope()->function() != NULL) {
152 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
153 }
154 // Visit all the explicit declarations unless there is an illegal
155 // redeclaration.
156 if (scope()->HasIllegalRedeclaration()) {
157 scope()->VisitIllegalRedeclaration(this);
158 } else {
159 VisitDeclarations(scope()->declarations());
160 }
144 } 161 }
145 162
146 { Comment cmnt(masm_, "[ Stack check"); 163 { Comment cmnt(masm_, "[ Stack check");
147 Label ok; 164 Label ok;
148 ExternalReference stack_limit = 165 ExternalReference stack_limit =
149 ExternalReference::address_of_stack_limit(); 166 ExternalReference::address_of_stack_limit();
150 __ cmp(esp, Operand::StaticVariable(stack_limit)); 167 __ cmp(esp, Operand::StaticVariable(stack_limit));
151 __ j(above_equal, &ok, taken); 168 __ j(above_equal, &ok, taken);
152 StackCheckStub stub; 169 StackCheckStub stub;
153 __ CallStub(&stub); 170 __ CallStub(&stub);
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 __ mov(result_register(), reg); 435 __ mov(result_register(), reg);
419 __ mov(Operand(esp, 0), result_register()); 436 __ mov(Operand(esp, 0), result_register());
420 break; 437 break;
421 } 438 }
422 DoTest(context); 439 DoTest(context);
423 break; 440 break;
424 } 441 }
425 } 442 }
426 443
427 444
445 void FullCodeGenerator::PrepareTest(Label* materialize_true,
446 Label* materialize_false,
447 Label** if_true,
448 Label** if_false) {
449 switch (context_) {
450 case Expression::kUninitialized:
451 UNREACHABLE();
452 break;
453 case Expression::kEffect:
454 // In an effect context, the true and the false case branch to the
455 // same label.
456 *if_true = *if_false = materialize_true;
457 break;
458 case Expression::kValue:
459 *if_true = materialize_true;
460 *if_false = materialize_false;
461 break;
462 case Expression::kTest:
463 *if_true = true_label_;
464 *if_false = false_label_;
465 break;
466 case Expression::kValueTest:
467 *if_true = materialize_true;
468 *if_false = false_label_;
469 break;
470 case Expression::kTestValue:
471 *if_true = true_label_;
472 *if_false = materialize_false;
473 break;
474 }
475 }
476
477
428 void FullCodeGenerator::Apply(Expression::Context context, 478 void FullCodeGenerator::Apply(Expression::Context context,
429 Label* materialize_true, 479 Label* materialize_true,
430 Label* materialize_false) { 480 Label* materialize_false) {
431 switch (context) { 481 switch (context) {
432 case Expression::kUninitialized: 482 case Expression::kUninitialized:
433 483
434 case Expression::kEffect: 484 case Expression::kEffect:
435 ASSERT_EQ(materialize_true, materialize_false); 485 ASSERT_EQ(materialize_true, materialize_false);
436 __ bind(materialize_true); 486 __ bind(materialize_true);
437 break; 487 break;
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
483 case kStack: 533 case kStack:
484 __ push(Immediate(Factory::false_value())); 534 __ push(Immediate(Factory::false_value()));
485 break; 535 break;
486 } 536 }
487 __ jmp(false_label_); 537 __ jmp(false_label_);
488 break; 538 break;
489 } 539 }
490 } 540 }
491 541
492 542
543 // Convert constant control flow (true or false) to the result expected for
544 // a given expression context.
545 void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
546 switch (context) {
547 case Expression::kUninitialized:
548 UNREACHABLE();
549 break;
550 case Expression::kEffect:
551 break;
552 case Expression::kValue: {
553 Handle<Object> value =
554 flag ? Factory::true_value() : Factory::false_value();
555 switch (location_) {
556 case kAccumulator:
557 __ mov(result_register(), value);
558 break;
559 case kStack:
560 __ push(Immediate(value));
561 break;
562 }
563 break;
564 }
565 case Expression::kTest:
566 __ jmp(flag ? true_label_ : false_label_);
567 break;
568 case Expression::kTestValue:
569 switch (location_) {
570 case kAccumulator:
571 // If value is false it's needed.
572 if (!flag) __ mov(result_register(), Factory::false_value());
573 break;
574 case kStack:
575 // If value is false it's needed.
576 if (!flag) __ push(Immediate(Factory::false_value()));
577 break;
578 }
579 __ jmp(flag ? true_label_ : false_label_);
580 break;
581 case Expression::kValueTest:
582 switch (location_) {
583 case kAccumulator:
584 // If value is true it's needed.
585 if (flag) __ mov(result_register(), Factory::true_value());
586 break;
587 case kStack:
588 // If value is true it's needed.
589 if (flag) __ push(Immediate(Factory::true_value()));
590 break;
591 }
592 __ jmp(flag ? true_label_ : false_label_);
593 break;
594 }
595 }
596
597
493 void FullCodeGenerator::DoTest(Expression::Context context) { 598 void FullCodeGenerator::DoTest(Expression::Context context) {
494 // The value to test is in the accumulator. If the value might be needed 599 // The value to test is in the accumulator. If the value might be needed
495 // on the stack (value/test and test/value contexts with a stack location 600 // on the stack (value/test and test/value contexts with a stack location
496 // desired), then the value is already duplicated on the stack. 601 // desired), then the value is already duplicated on the stack.
497 ASSERT_NE(NULL, true_label_); 602 ASSERT_NE(NULL, true_label_);
498 ASSERT_NE(NULL, false_label_); 603 ASSERT_NE(NULL, false_label_);
499 604
500 // In value/test and test/value expression contexts with stack as the 605 // In value/test and test/value expression contexts with stack as the
501 // desired location, there is already an extra value on the stack. Use a 606 // desired location, there is already an extra value on the stack. Use a
502 // label to discard it if unneeded. 607 // label to discard it if unneeded.
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
658 MemOperand location = EmitSlotSearch(dst, scratch1); 763 MemOperand location = EmitSlotSearch(dst, scratch1);
659 __ mov(location, src); 764 __ mov(location, src);
660 // Emit the write barrier code if the location is in the heap. 765 // Emit the write barrier code if the location is in the heap.
661 if (dst->type() == Slot::CONTEXT) { 766 if (dst->type() == Slot::CONTEXT) {
662 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize; 767 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
663 __ RecordWrite(scratch1, offset, src, scratch2); 768 __ RecordWrite(scratch1, offset, src, scratch2);
664 } 769 }
665 } 770 }
666 771
667 772
668 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 773 void FullCodeGenerator::EmitDeclaration(Variable* variable,
774 Variable::Mode mode,
775 FunctionLiteral* function) {
669 Comment cmnt(masm_, "[ Declaration"); 776 Comment cmnt(masm_, "[ Declaration");
670 Variable* var = decl->proxy()->var(); 777 ASSERT(variable != NULL); // Must have been resolved.
671 ASSERT(var != NULL); // Must have been resolved. 778 Slot* slot = variable->slot();
672 Slot* slot = var->slot(); 779 Property* prop = variable->AsProperty();
673 Property* prop = var->AsProperty();
674
675 if (slot != NULL) { 780 if (slot != NULL) {
676 switch (slot->type()) { 781 switch (slot->type()) {
677 case Slot::PARAMETER: 782 case Slot::PARAMETER:
678 case Slot::LOCAL: 783 case Slot::LOCAL:
679 if (decl->mode() == Variable::CONST) { 784 if (mode == Variable::CONST) {
680 __ mov(Operand(ebp, SlotOffset(slot)), 785 __ mov(Operand(ebp, SlotOffset(slot)),
681 Immediate(Factory::the_hole_value())); 786 Immediate(Factory::the_hole_value()));
682 } else if (decl->fun() != NULL) { 787 } else if (function != NULL) {
683 VisitForValue(decl->fun(), kAccumulator); 788 VisitForValue(function, kAccumulator);
684 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); 789 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
685 } 790 }
686 break; 791 break;
687 792
688 case Slot::CONTEXT: 793 case Slot::CONTEXT:
689 // We bypass the general EmitSlotSearch because we know more about 794 // We bypass the general EmitSlotSearch because we know more about
690 // this specific context. 795 // this specific context.
691 796
692 // The variable in the decl always resides in the current context. 797 // The variable in the decl always resides in the current context.
693 ASSERT_EQ(0, scope()->ContextChainLength(var->scope())); 798 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
694 if (FLAG_debug_code) { 799 if (FLAG_debug_code) {
695 // Check if we have the correct context pointer. 800 // Check if we have the correct context pointer.
696 __ mov(ebx, 801 __ mov(ebx,
697 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX)); 802 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
698 __ cmp(ebx, Operand(esi)); 803 __ cmp(ebx, Operand(esi));
699 __ Check(equal, "Unexpected declaration in current context."); 804 __ Check(equal, "Unexpected declaration in current context.");
700 } 805 }
701 if (decl->mode() == Variable::CONST) { 806 if (mode == Variable::CONST) {
702 __ mov(eax, Immediate(Factory::the_hole_value())); 807 __ mov(eax, Immediate(Factory::the_hole_value()));
703 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax); 808 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), eax);
704 // No write barrier since the hole value is in old space. 809 // No write barrier since the hole value is in old space.
705 } else if (decl->fun() != NULL) { 810 } else if (function != NULL) {
706 VisitForValue(decl->fun(), kAccumulator); 811 VisitForValue(function, kAccumulator);
707 __ mov(CodeGenerator::ContextOperand(esi, slot->index()), 812 __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
708 result_register()); 813 result_register());
709 int offset = Context::SlotOffset(slot->index()); 814 int offset = Context::SlotOffset(slot->index());
710 __ mov(ebx, esi); 815 __ mov(ebx, esi);
711 __ RecordWrite(ebx, offset, result_register(), ecx); 816 __ RecordWrite(ebx, offset, result_register(), ecx);
712 } 817 }
713 break; 818 break;
714 819
715 case Slot::LOOKUP: { 820 case Slot::LOOKUP: {
716 __ push(esi); 821 __ push(esi);
717 __ push(Immediate(var->name())); 822 __ push(Immediate(variable->name()));
718 // Declaration nodes are always introduced in one of two modes. 823 // Declaration nodes are always introduced in one of two modes.
719 ASSERT(decl->mode() == Variable::VAR || 824 ASSERT(mode == Variable::VAR ||
720 decl->mode() == Variable::CONST); 825 mode == Variable::CONST);
721 PropertyAttributes attr = 826 PropertyAttributes attr =
722 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY; 827 (mode == Variable::VAR) ? NONE : READ_ONLY;
723 __ push(Immediate(Smi::FromInt(attr))); 828 __ push(Immediate(Smi::FromInt(attr)));
724 // Push initial value, if any. 829 // Push initial value, if any.
725 // Note: For variables we must not push an initial value (such as 830 // Note: For variables we must not push an initial value (such as
726 // 'undefined') because we may have a (legal) redeclaration and we 831 // 'undefined') because we may have a (legal) redeclaration and we
727 // must not destroy the current value. 832 // must not destroy the current value.
728 if (decl->mode() == Variable::CONST) { 833 if (mode == Variable::CONST) {
729 __ push(Immediate(Factory::the_hole_value())); 834 __ push(Immediate(Factory::the_hole_value()));
730 } else if (decl->fun() != NULL) { 835 } else if (function != NULL) {
731 VisitForValue(decl->fun(), kStack); 836 VisitForValue(function, kStack);
732 } else { 837 } else {
733 __ push(Immediate(Smi::FromInt(0))); // No initial value! 838 __ push(Immediate(Smi::FromInt(0))); // No initial value!
734 } 839 }
735 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 840 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
736 break; 841 break;
737 } 842 }
738 } 843 }
739 844
740 } else if (prop != NULL) { 845 } else if (prop != NULL) {
741 if (decl->fun() != NULL || decl->mode() == Variable::CONST) { 846 if (function != NULL || mode == Variable::CONST) {
742 // We are declaring a function or constant that rewrites to a 847 // We are declaring a function or constant that rewrites to a
743 // property. Use (keyed) IC to set the initial value. 848 // property. Use (keyed) IC to set the initial value.
744 VisitForValue(prop->obj(), kStack); 849 VisitForValue(prop->obj(), kStack);
745 if (decl->fun() != NULL) { 850 if (function != NULL) {
746 VisitForValue(prop->key(), kStack); 851 VisitForValue(prop->key(), kStack);
747 VisitForValue(decl->fun(), kAccumulator); 852 VisitForValue(function, kAccumulator);
748 __ pop(ecx); 853 __ pop(ecx);
749 } else { 854 } else {
750 VisitForValue(prop->key(), kAccumulator); 855 VisitForValue(prop->key(), kAccumulator);
751 __ mov(ecx, result_register()); 856 __ mov(ecx, result_register());
752 __ mov(result_register(), Factory::the_hole_value()); 857 __ mov(result_register(), Factory::the_hole_value());
753 } 858 }
754 __ pop(edx); 859 __ pop(edx);
755 860
756 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 861 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
757 __ call(ic, RelocInfo::CODE_TARGET); 862 __ call(ic, RelocInfo::CODE_TARGET);
758 // Absence of a test eax instruction following the call 863 // Absence of a test eax instruction following the call
759 // indicates that none of the load was inlined. 864 // indicates that none of the load was inlined.
760 __ nop(); 865 __ nop();
761 } 866 }
762 } 867 }
763 } 868 }
764 869
765 870
871 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
872 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
873 }
874
875
766 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 876 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
767 // Call the runtime to declare the globals. 877 // Call the runtime to declare the globals.
768 __ push(esi); // The context is the first argument. 878 __ push(esi); // The context is the first argument.
769 __ push(Immediate(pairs)); 879 __ push(Immediate(pairs));
770 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); 880 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
771 __ CallRuntime(Runtime::kDeclareGlobals, 3); 881 __ CallRuntime(Runtime::kDeclareGlobals, 3);
772 // Return value is ignored. 882 // Return value is ignored.
773 } 883 }
774 884
775 885
776 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) { 886 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
777 Comment cmnt(masm_, "[ FunctionLiteral"); 887 Comment cmnt(masm_, "[ SwitchStatement");
778 888 Breakable nested_statement(this, stmt);
779 // Build the shared function info and instantiate the function based 889 SetStatementPosition(stmt);
780 // on it. 890 // Keep the switch value on the stack until a case matches.
781 Handle<SharedFunctionInfo> function_info = 891 VisitForValue(stmt->tag(), kStack);
782 Compiler::BuildFunctionInfo(expr, script(), this); 892
783 if (HasStackOverflow()) return; 893 ZoneList<CaseClause*>* clauses = stmt->cases();
784 894 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
785 // Create a new closure. 895
786 __ push(esi); 896 Label next_test; // Recycled for each test.
787 __ push(Immediate(function_info)); 897 // Compile all the tests with branches to their bodies.
788 __ CallRuntime(Runtime::kNewClosure, 2); 898 for (int i = 0; i < clauses->length(); i++) {
899 CaseClause* clause = clauses->at(i);
900 // The default is not a test, but remember it as final fall through.
901 if (clause->is_default()) {
902 default_clause = clause;
903 continue;
904 }
905
906 Comment cmnt(masm_, "[ Case comparison");
907 __ bind(&next_test);
908 next_test.Unuse();
909
910 // Compile the label expression.
911 VisitForValue(clause->label(), kAccumulator);
912
913 // Perform the comparison as if via '==='. The comparison stub expects
914 // the smi vs. smi case to be handled before it is called.
915 Label slow_case;
916 __ mov(edx, Operand(esp, 0)); // Switch value.
917 __ mov(ecx, edx);
918 __ or_(ecx, Operand(eax));
919 __ test(ecx, Immediate(kSmiTagMask));
920 __ j(not_zero, &slow_case, not_taken);
921 __ cmp(edx, Operand(eax));
922 __ j(not_equal, &next_test);
923 __ Drop(1); // Switch value is no longer needed.
924 __ jmp(clause->body_target()->entry_label());
925
926 __ bind(&slow_case);
927 CompareStub stub(equal, true);
928 __ CallStub(&stub);
929 __ test(eax, Operand(eax));
930 __ j(not_equal, &next_test);
931 __ Drop(1); // Switch value is no longer needed.
932 __ jmp(clause->body_target()->entry_label());
933 }
934
935 // Discard the test value and jump to the default if present, otherwise to
936 // the end of the statement.
937 __ bind(&next_test);
938 __ Drop(1); // Switch value is no longer needed.
939 if (default_clause == NULL) {
940 __ jmp(nested_statement.break_target());
941 } else {
942 __ jmp(default_clause->body_target()->entry_label());
943 }
944
945 // Compile all the case bodies.
946 for (int i = 0; i < clauses->length(); i++) {
947 Comment cmnt(masm_, "[ Case body");
948 CaseClause* clause = clauses->at(i);
949 __ bind(clause->body_target()->entry_label());
950 VisitStatements(clause->statements());
951 }
952
953 __ bind(nested_statement.break_target());
954 }
955
956
957 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
958 Comment cmnt(masm_, "[ ForInStatement");
959 SetStatementPosition(stmt);
960
961 Label loop, exit;
962 ForIn loop_statement(this, stmt);
963 increment_loop_depth();
964
965 // Get the object to enumerate over. Both SpiderMonkey and JSC
966 // ignore null and undefined in contrast to the specification; see
967 // ECMA-262 section 12.6.4.
968 VisitForValue(stmt->enumerable(), kAccumulator);
969 __ cmp(eax, Factory::undefined_value());
970 __ j(equal, &exit);
971 __ cmp(eax, Factory::null_value());
972 __ j(equal, &exit);
973
974 // Convert the object to a JS object.
975 Label convert, done_convert;
976 __ test(eax, Immediate(kSmiTagMask));
977 __ j(zero, &convert);
978 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
979 __ j(above_equal, &done_convert);
980 __ bind(&convert);
981 __ push(eax);
982 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
983 __ bind(&done_convert);
984 __ push(eax);
985
986 // TODO(kasperl): Check cache validity in generated code. This is a
987 // fast case for the JSObject::IsSimpleEnum cache validity
988 // checks. If we cannot guarantee cache validity, call the runtime
989 // system to check cache validity or get the property names in a
990 // fixed array.
991
992 // Get the set of properties to enumerate.
993 __ push(eax); // Duplicate the enumerable object on the stack.
994 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
995
996 // If we got a map from the runtime call, we can do a fast
997 // modification check. Otherwise, we got a fixed array, and we have
998 // to do a slow check.
999 Label fixed_array;
1000 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
1001 __ j(not_equal, &fixed_array);
1002
1003 // We got a map in register eax. Get the enumeration cache from it.
1004 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
1005 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
1006 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1007
1008 // Setup the four remaining stack slots.
1009 __ push(eax); // Map.
1010 __ push(edx); // Enumeration cache.
1011 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
1012 __ SmiTag(eax);
1013 __ push(eax); // Enumeration cache length (as smi).
1014 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1015 __ jmp(&loop);
1016
1017 // We got a fixed array in register eax. Iterate through that.
1018 __ bind(&fixed_array);
1019 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
1020 __ push(eax);
1021 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
1022 __ SmiTag(eax);
1023 __ push(eax); // Fixed array length (as smi).
1024 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1025
1026 // Generate code for doing the condition check.
1027 __ bind(&loop);
1028 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1029 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
1030 __ j(above_equal, loop_statement.break_target());
1031
1032 // Get the current entry of the array into register ebx.
1033 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1034 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1035
1036 // Get the expected map from the stack or a zero map in the
1037 // permanent slow case into register edx.
1038 __ mov(edx, Operand(esp, 3 * kPointerSize));
1039
1040 // Check if the expected map still matches that of the enumerable.
1041 // If not, we have to filter the key.
1042 Label update_each;
1043 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1044 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
1045 __ j(equal, &update_each);
1046
1047 // Convert the entry to a string or null if it isn't a property
1048 // anymore. If the property has been removed while iterating, we
1049 // just skip it.
1050 __ push(ecx); // Enumerable.
1051 __ push(ebx); // Current entry.
1052 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1053 __ cmp(eax, Factory::null_value());
1054 __ j(equal, loop_statement.continue_target());
1055 __ mov(ebx, Operand(eax));
1056
1057 // Update the 'each' property or variable from the possibly filtered
1058 // entry in register ebx.
1059 __ bind(&update_each);
1060 __ mov(result_register(), ebx);
1061 // Perform the assignment as if via '='.
1062 EmitAssignment(stmt->each());
1063
1064 // Generate code for the body of the loop.
1065 Label stack_limit_hit, stack_check_done;
1066 Visit(stmt->body());
1067
1068 __ StackLimitCheck(&stack_limit_hit);
1069 __ bind(&stack_check_done);
1070
1071 // Generate code for the going to the next element by incrementing
1072 // the index (smi) stored on top of the stack.
1073 __ bind(loop_statement.continue_target());
1074 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1075 __ jmp(&loop);
1076
1077 // Slow case for the stack limit check.
1078 StackCheckStub stack_check_stub;
1079 __ bind(&stack_limit_hit);
1080 __ CallStub(&stack_check_stub);
1081 __ jmp(&stack_check_done);
1082
1083 // Remove the pointers stored on the stack.
1084 __ bind(loop_statement.break_target());
1085 __ add(Operand(esp), Immediate(5 * kPointerSize));
1086
1087 // Exit and decrement the loop depth.
1088 __ bind(&exit);
1089 decrement_loop_depth();
1090 }
1091
1092
1093 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
1094 // Use the fast case closure allocation code that allocates in new
1095 // space for nested functions that don't need literals cloning.
1096 if (scope()->is_function_scope() && info->num_literals() == 0) {
1097 FastNewClosureStub stub;
1098 __ push(Immediate(info));
1099 __ CallStub(&stub);
1100 } else {
1101 __ push(esi);
1102 __ push(Immediate(info));
1103 __ CallRuntime(Runtime::kNewClosure, 2);
1104 }
789 Apply(context_, eax); 1105 Apply(context_, eax);
790 } 1106 }
791 1107
792 1108
793 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 1109 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
794 Comment cmnt(masm_, "[ VariableProxy"); 1110 Comment cmnt(masm_, "[ VariableProxy");
795 EmitVariableLoad(expr->var(), context_); 1111 EmitVariableLoad(expr->var(), context_);
796 } 1112 }
797 1113
798 1114
(...skipping 24 matching lines...) Expand all
823 Comment cmnt(masm_, "Lookup slot"); 1139 Comment cmnt(masm_, "Lookup slot");
824 __ push(esi); // Context. 1140 __ push(esi); // Context.
825 __ push(Immediate(var->name())); 1141 __ push(Immediate(var->name()));
826 __ CallRuntime(Runtime::kLoadContextSlot, 2); 1142 __ CallRuntime(Runtime::kLoadContextSlot, 2);
827 Apply(context, eax); 1143 Apply(context, eax);
828 1144
829 } else if (slot != NULL) { 1145 } else if (slot != NULL) {
830 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT) 1146 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
831 ? "Context slot" 1147 ? "Context slot"
832 : "Stack slot"); 1148 : "Stack slot");
833 Apply(context, slot); 1149 if (var->mode() == Variable::CONST) {
1150 // Constants may be the hole value if they have not been initialized.
1151 // Unhole them.
1152 Label done;
1153 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1154 __ mov(eax, slot_operand);
1155 __ cmp(eax, Factory::the_hole_value());
1156 __ j(not_equal, &done);
1157 __ mov(eax, Factory::undefined_value());
1158 __ bind(&done);
1159 Apply(context, eax);
1160 } else {
1161 Apply(context, slot);
1162 }
834 1163
835 } else { 1164 } else {
836 Comment cmnt(masm_, "Rewritten parameter"); 1165 Comment cmnt(masm_, "Rewritten parameter");
837 ASSERT_NOT_NULL(property); 1166 ASSERT_NOT_NULL(property);
838 // Rewritten parameter accesses are of the form "slot[literal]". 1167 // Rewritten parameter accesses are of the form "slot[literal]".
839 1168
840 // Assert that the object is in a slot. 1169 // Assert that the object is in a slot.
841 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable(); 1170 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
842 ASSERT_NOT_NULL(object_var); 1171 ASSERT_NOT_NULL(object_var);
843 Slot* object_slot = object_var->slot(); 1172 Slot* object_slot = object_var->slot();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
959 if (result_saved) { 1288 if (result_saved) {
960 ApplyTOS(context_); 1289 ApplyTOS(context_);
961 } else { 1290 } else {
962 Apply(context_, eax); 1291 Apply(context_, eax);
963 } 1292 }
964 } 1293 }
965 1294
966 1295
967 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) { 1296 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
968 Comment cmnt(masm_, "[ ArrayLiteral"); 1297 Comment cmnt(masm_, "[ ArrayLiteral");
1298
1299 ZoneList<Expression*>* subexprs = expr->values();
1300 int length = subexprs->length();
1301
969 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset)); 1302 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
970 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset)); 1303 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
971 __ push(Immediate(Smi::FromInt(expr->literal_index()))); 1304 __ push(Immediate(Smi::FromInt(expr->literal_index())));
972 __ push(Immediate(expr->constant_elements())); 1305 __ push(Immediate(expr->constant_elements()));
973 if (expr->depth() > 1) { 1306 if (expr->depth() > 1) {
974 __ CallRuntime(Runtime::kCreateArrayLiteral, 3); 1307 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
1308 } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
1309 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
975 } else { 1310 } else {
976 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3); 1311 FastCloneShallowArrayStub stub(length);
1312 __ CallStub(&stub);
977 } 1313 }
978 1314
979 bool result_saved = false; // Is the result saved to the stack? 1315 bool result_saved = false; // Is the result saved to the stack?
980 1316
981 // Emit code to evaluate all the non-constant subexpressions and to store 1317 // Emit code to evaluate all the non-constant subexpressions and to store
982 // them into the newly cloned array. 1318 // them into the newly cloned array.
983 ZoneList<Expression*>* subexprs = expr->values(); 1319 for (int i = 0; i < length; i++) {
984 for (int i = 0, len = subexprs->length(); i < len; i++) {
985 Expression* subexpr = subexprs->at(i); 1320 Expression* subexpr = subexprs->at(i);
986 // If the subexpression is a literal or a simple materialized literal it 1321 // If the subexpression is a literal or a simple materialized literal it
987 // is already set in the cloned array. 1322 // is already set in the cloned array.
988 if (subexpr->AsLiteral() != NULL || 1323 if (subexpr->AsLiteral() != NULL ||
989 CompileTimeValue::IsCompileTimeValue(subexpr)) { 1324 CompileTimeValue::IsCompileTimeValue(subexpr)) {
990 continue; 1325 continue;
991 } 1326 }
992 1327
993 if (!result_saved) { 1328 if (!result_saved) {
994 __ push(eax); 1329 __ push(eax);
(...skipping 14 matching lines...) Expand all
1009 if (result_saved) { 1344 if (result_saved) {
1010 ApplyTOS(context_); 1345 ApplyTOS(context_);
1011 } else { 1346 } else {
1012 Apply(context_, eax); 1347 Apply(context_, eax);
1013 } 1348 }
1014 } 1349 }
1015 1350
1016 1351
1017 void FullCodeGenerator::VisitAssignment(Assignment* expr) { 1352 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1018 Comment cmnt(masm_, "[ Assignment"); 1353 Comment cmnt(masm_, "[ Assignment");
1019 ASSERT(expr->op() != Token::INIT_CONST); 1354 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1355 // on the left-hand side.
1356 if (!expr->target()->IsValidLeftHandSide()) {
1357 VisitForEffect(expr->target());
1358 return;
1359 }
1360
1020 // Left-hand side can only be a property, a global or a (parameter or local) 1361 // Left-hand side can only be a property, a global or a (parameter or local)
1021 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 1362 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1022 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 1363 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1023 LhsKind assign_type = VARIABLE; 1364 LhsKind assign_type = VARIABLE;
1024 Property* prop = expr->target()->AsProperty(); 1365 Property* prop = expr->target()->AsProperty();
1025 if (prop != NULL) { 1366 if (prop != NULL) {
1026 assign_type = 1367 assign_type =
1027 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 1368 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1028 } 1369 }
1029 1370
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 location_ = saved_location; 1429 location_ = saved_location;
1089 } 1430 }
1090 1431
1091 // Record source position before possible IC call. 1432 // Record source position before possible IC call.
1092 SetSourcePosition(expr->position()); 1433 SetSourcePosition(expr->position());
1093 1434
1094 // Store the value. 1435 // Store the value.
1095 switch (assign_type) { 1436 switch (assign_type) {
1096 case VARIABLE: 1437 case VARIABLE:
1097 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(), 1438 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1439 expr->op(),
1098 context_); 1440 context_);
1099 break; 1441 break;
1100 case NAMED_PROPERTY: 1442 case NAMED_PROPERTY:
1101 EmitNamedPropertyAssignment(expr); 1443 EmitNamedPropertyAssignment(expr);
1102 break; 1444 break;
1103 case KEYED_PROPERTY: 1445 case KEYED_PROPERTY:
1104 EmitKeyedPropertyAssignment(expr); 1446 EmitKeyedPropertyAssignment(expr);
1105 break; 1447 break;
1106 } 1448 }
1107 } 1449 }
(...skipping 22 matching lines...) Expand all
1130 __ push(result_register()); 1472 __ push(result_register());
1131 GenericBinaryOpStub stub(op, 1473 GenericBinaryOpStub stub(op,
1132 NO_OVERWRITE, 1474 NO_OVERWRITE,
1133 NO_GENERIC_BINARY_FLAGS, 1475 NO_GENERIC_BINARY_FLAGS,
1134 TypeInfo::Unknown()); 1476 TypeInfo::Unknown());
1135 __ CallStub(&stub); 1477 __ CallStub(&stub);
1136 Apply(context, eax); 1478 Apply(context, eax);
1137 } 1479 }
1138 1480
1139 1481
1482 void FullCodeGenerator::EmitAssignment(Expression* expr) {
1483 // Invalid left-hand sides are rewritten to have a 'throw
1484 // ReferenceError' on the left-hand side.
1485 if (!expr->IsValidLeftHandSide()) {
1486 VisitForEffect(expr);
1487 return;
1488 }
1489
1490 // Left-hand side can only be a property, a global or a (parameter or local)
1491 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1492 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1493 LhsKind assign_type = VARIABLE;
1494 Property* prop = expr->AsProperty();
1495 if (prop != NULL) {
1496 assign_type = (prop->key()->IsPropertyName())
1497 ? NAMED_PROPERTY
1498 : KEYED_PROPERTY;
1499 }
1500
1501 switch (assign_type) {
1502 case VARIABLE: {
1503 Variable* var = expr->AsVariableProxy()->var();
1504 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
1505 break;
1506 }
1507 case NAMED_PROPERTY: {
1508 __ push(eax); // Preserve value.
1509 VisitForValue(prop->obj(), kAccumulator);
1510 __ mov(edx, eax);
1511 __ pop(eax); // Restore value.
1512 __ mov(ecx, prop->key()->AsLiteral()->handle());
1513 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1514 __ call(ic, RelocInfo::CODE_TARGET);
1515 __ nop(); // Signal no inlined code.
1516 break;
1517 }
1518 case KEYED_PROPERTY: {
1519 __ push(eax); // Preserve value.
1520 VisitForValue(prop->obj(), kStack);
1521 VisitForValue(prop->key(), kAccumulator);
1522 __ mov(ecx, eax);
1523 __ pop(edx);
1524 __ pop(eax); // Restore value.
1525 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1526 __ call(ic, RelocInfo::CODE_TARGET);
1527 __ nop(); // Signal no inlined code.
1528 break;
1529 }
1530 }
1531 }
1532
1533
1140 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1534 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1535 Token::Value op,
1141 Expression::Context context) { 1536 Expression::Context context) {
1142 // Three main cases: global variables, lookup slots, and all other 1537 // Left-hand sides that rewrite to explicit property accesses do not reach
1143 // types of slots. Left-hand-side parameters that rewrite to 1538 // here.
1144 // explicit property accesses do not reach here.
1145 ASSERT(var != NULL); 1539 ASSERT(var != NULL);
1146 ASSERT(var->is_global() || var->slot() != NULL); 1540 ASSERT(var->is_global() || var->slot() != NULL);
1147 1541
1148 Slot* slot = var->slot();
1149 if (var->is_global()) { 1542 if (var->is_global()) {
1150 ASSERT(!var->is_this()); 1543 ASSERT(!var->is_this());
1151 // Assignment to a global variable. Use inline caching for the 1544 // Assignment to a global variable. Use inline caching for the
1152 // assignment. Right-hand-side value is passed in eax, variable name in 1545 // assignment. Right-hand-side value is passed in eax, variable name in
1153 // ecx, and the global object on the stack. 1546 // ecx, and the global object on the stack.
1154 __ mov(ecx, var->name()); 1547 __ mov(ecx, var->name());
1155 __ mov(edx, CodeGenerator::GlobalObject()); 1548 __ mov(edx, CodeGenerator::GlobalObject());
1156 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 1549 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1157 __ call(ic, RelocInfo::CODE_TARGET); 1550 __ call(ic, RelocInfo::CODE_TARGET);
1158 __ nop(); 1551 __ nop();
1159 Apply(context, eax);
1160 1552
1161 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 1553 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1162 __ push(result_register()); // Value. 1554 // Perform the assignment for non-const variables and for initialization
1163 __ push(esi); // Context. 1555 // of const variables. Const assignments are simply skipped.
1164 __ push(Immediate(var->name())); 1556 Label done;
1165 __ CallRuntime(Runtime::kStoreContextSlot, 3); 1557 Slot* slot = var->slot();
1166 Apply(context, eax);
1167
1168 } else if (slot != NULL) {
1169 switch (slot->type()) { 1558 switch (slot->type()) {
1559 case Slot::PARAMETER:
1170 case Slot::LOCAL: 1560 case Slot::LOCAL:
1171 case Slot::PARAMETER: 1561 if (op == Token::INIT_CONST) {
1172 __ mov(Operand(ebp, SlotOffset(slot)), result_register()); 1562 // Detect const reinitialization by checking for the hole value.
1563 __ mov(edx, Operand(ebp, SlotOffset(slot)));
1564 __ cmp(edx, Factory::the_hole_value());
1565 __ j(not_equal, &done);
1566 }
1567 // Perform the assignment.
1568 __ mov(Operand(ebp, SlotOffset(slot)), eax);
1173 break; 1569 break;
1174 1570
1175 case Slot::CONTEXT: { 1571 case Slot::CONTEXT: {
1176 MemOperand target = EmitSlotSearch(slot, ecx); 1572 MemOperand target = EmitSlotSearch(slot, ecx);
1177 __ mov(target, result_register()); 1573 if (op == Token::INIT_CONST) {
1178 1574 // Detect const reinitialization by checking for the hole value.
1179 // RecordWrite may destroy all its register arguments. 1575 __ mov(edx, target);
1180 __ mov(edx, result_register()); 1576 __ cmp(edx, Factory::the_hole_value());
1577 __ j(not_equal, &done);
1578 }
1579 // Perform the assignment and issue the write barrier.
1580 __ mov(target, eax);
1581 // The value of the assignment is in eax. RecordWrite clobbers its
1582 // register arguments.
1583 __ mov(edx, eax);
1181 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1584 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1182 __ RecordWrite(ecx, offset, edx, ebx); 1585 __ RecordWrite(ecx, offset, edx, ebx);
1183 break; 1586 break;
1184 } 1587 }
1185 1588
1186 case Slot::LOOKUP: 1589 case Slot::LOOKUP:
1187 UNREACHABLE(); 1590 // Call the runtime for the assignment. The runtime will ignore
1591 // const reinitialization.
1592 __ push(eax); // Value.
1593 __ push(esi); // Context.
1594 __ push(Immediate(var->name()));
1595 if (op == Token::INIT_CONST) {
1596 // The runtime will ignore const redeclaration.
1597 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1598 } else {
1599 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1600 }
1188 break; 1601 break;
1189 } 1602 }
1190 Apply(context, result_register()); 1603 __ bind(&done);
1604 }
1191 1605
1192 } else { 1606 Apply(context, eax);
1193 // Variables rewritten as properties are not treated as variables in
1194 // assignments.
1195 UNREACHABLE();
1196 }
1197 } 1607 }
1198 1608
1199 1609
1200 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1610 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1201 // Assignment to a property, using a named store IC. 1611 // Assignment to a property, using a named store IC.
1202 Property* prop = expr->target()->AsProperty(); 1612 Property* prop = expr->target()->AsProperty();
1203 ASSERT(prop != NULL); 1613 ASSERT(prop != NULL);
1204 ASSERT(prop->key()->AsLiteral() != NULL); 1614 ASSERT(prop->key()->AsLiteral() != NULL);
1205 1615
1206 // If the assignment starts a block of assignments to the same object, 1616 // If the assignment starts a block of assignments to the same object,
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after
1320 1730
1321 void FullCodeGenerator::EmitCallWithStub(Call* expr) { 1731 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1322 // Code common for calls using the call stub. 1732 // Code common for calls using the call stub.
1323 ZoneList<Expression*>* args = expr->arguments(); 1733 ZoneList<Expression*>* args = expr->arguments();
1324 int arg_count = args->length(); 1734 int arg_count = args->length();
1325 for (int i = 0; i < arg_count; i++) { 1735 for (int i = 0; i < arg_count; i++) {
1326 VisitForValue(args->at(i), kStack); 1736 VisitForValue(args->at(i), kStack);
1327 } 1737 }
1328 // Record source position for debugger. 1738 // Record source position for debugger.
1329 SetSourcePosition(expr->position()); 1739 SetSourcePosition(expr->position());
1330 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE); 1740 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1741 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1331 __ CallStub(&stub); 1742 __ CallStub(&stub);
1332 // Restore context register. 1743 // Restore context register.
1333 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); 1744 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1334 DropAndApply(1, context_, eax); 1745 DropAndApply(1, context_, eax);
1335 } 1746 }
1336 1747
1337 1748
1338 void FullCodeGenerator::VisitCall(Call* expr) { 1749 void FullCodeGenerator::VisitCall(Call* expr) {
1339 Comment cmnt(masm_, "[ Call"); 1750 Comment cmnt(masm_, "[ Call");
1340 Expression* fun = expr->expression(); 1751 Expression* fun = expr->expression();
1341 Variable* var = fun->AsVariableProxy()->AsVariable(); 1752 Variable* var = fun->AsVariableProxy()->AsVariable();
1342 1753
1343 if (var != NULL && var->is_possibly_eval()) { 1754 if (var != NULL && var->is_possibly_eval()) {
1344 // Call to the identifier 'eval'. 1755 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1345 UNREACHABLE(); 1756 // resolve the function we need to call and the receiver of the
1757 // call. Then we call the resolved function using the given
1758 // arguments.
1759 VisitForValue(fun, kStack);
1760 __ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
1761
1762 // Push the arguments.
1763 ZoneList<Expression*>* args = expr->arguments();
1764 int arg_count = args->length();
1765 for (int i = 0; i < arg_count; i++) {
1766 VisitForValue(args->at(i), kStack);
1767 }
1768
1769 // Push copy of the function - found below the arguments.
1770 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
1771
1772 // Push copy of the first argument or undefined if it doesn't exist.
1773 if (arg_count > 0) {
1774 __ push(Operand(esp, arg_count * kPointerSize));
1775 } else {
1776 __ push(Immediate(Factory::undefined_value()));
1777 }
1778
1779 // Push the receiver of the enclosing function and do runtime call.
1780 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
1781 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1782
1783 // The runtime call returns a pair of values in eax (function) and
1784 // edx (receiver). Touch up the stack with the right values.
1785 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
1786 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
1787
1788 // Record source position for debugger.
1789 SetSourcePosition(expr->position());
1790 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1791 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1792 __ CallStub(&stub);
1793 // Restore context register.
1794 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1795 DropAndApply(1, context_, eax);
1346 } else if (var != NULL && !var->is_this() && var->is_global()) { 1796 } else if (var != NULL && !var->is_this() && var->is_global()) {
1347 // Push global object as receiver for the call IC. 1797 // Push global object as receiver for the call IC.
1348 __ push(CodeGenerator::GlobalObject()); 1798 __ push(CodeGenerator::GlobalObject());
1349 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT); 1799 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1350 } else if (var != NULL && var->slot() != NULL && 1800 } else if (var != NULL && var->slot() != NULL &&
1351 var->slot()->type() == Slot::LOOKUP) { 1801 var->slot()->type() == Slot::LOOKUP) {
1352 // Call to a lookup slot. 1802 // Call to a lookup slot (dynamically introduced variable). Call the
1353 UNREACHABLE(); 1803 // runtime to find the function to call (returned in eax) and the object
1804 // holding it (returned in edx).
1805 __ push(context_register());
1806 __ push(Immediate(var->name()));
1807 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1808 __ push(eax); // Function.
1809 __ push(edx); // Receiver.
1810 EmitCallWithStub(expr);
1354 } else if (fun->AsProperty() != NULL) { 1811 } else if (fun->AsProperty() != NULL) {
1355 // Call to an object property. 1812 // Call to an object property.
1356 Property* prop = fun->AsProperty(); 1813 Property* prop = fun->AsProperty();
1357 Literal* key = prop->key()->AsLiteral(); 1814 Literal* key = prop->key()->AsLiteral();
1358 if (key != NULL && key->handle()->IsSymbol()) { 1815 if (key != NULL && key->handle()->IsSymbol()) {
1359 // Call to a named property, use call IC. 1816 // Call to a named property, use call IC.
1360 VisitForValue(prop->obj(), kStack); 1817 VisitForValue(prop->obj(), kStack);
1361 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET); 1818 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1362 } else { 1819 } else {
1363 // Call to a keyed property, use keyed load IC followed by function 1820 // Call to a keyed property, use keyed load IC followed by function
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
1440 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize)); 1897 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1441 1898
1442 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall)); 1899 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1443 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL); 1900 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1444 1901
1445 // Replace function on TOS with result in eax, or pop it. 1902 // Replace function on TOS with result in eax, or pop it.
1446 DropAndApply(1, context_, eax); 1903 DropAndApply(1, context_, eax);
1447 } 1904 }
1448 1905
1449 1906
1907 void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
1908 Handle<String> name = expr->name();
1909 if (strcmp("_IsSmi", *name->ToCString()) == 0) {
1910 EmitIsSmi(expr->arguments());
1911 } else if (strcmp("_IsNonNegativeSmi", *name->ToCString()) == 0) {
1912 EmitIsNonNegativeSmi(expr->arguments());
1913 } else if (strcmp("_IsObject", *name->ToCString()) == 0) {
1914 EmitIsObject(expr->arguments());
1915 } else if (strcmp("_IsUndetectableObject", *name->ToCString()) == 0) {
1916 EmitIsUndetectableObject(expr->arguments());
1917 } else if (strcmp("_IsFunction", *name->ToCString()) == 0) {
1918 EmitIsFunction(expr->arguments());
1919 } else if (strcmp("_IsArray", *name->ToCString()) == 0) {
1920 EmitIsArray(expr->arguments());
1921 } else if (strcmp("_IsRegExp", *name->ToCString()) == 0) {
1922 EmitIsRegExp(expr->arguments());
1923 } else if (strcmp("_IsConstructCall", *name->ToCString()) == 0) {
1924 EmitIsConstructCall(expr->arguments());
1925 } else if (strcmp("_ObjectEquals", *name->ToCString()) == 0) {
1926 EmitObjectEquals(expr->arguments());
1927 } else if (strcmp("_Arguments", *name->ToCString()) == 0) {
1928 EmitArguments(expr->arguments());
1929 } else if (strcmp("_ArgumentsLength", *name->ToCString()) == 0) {
1930 EmitArgumentsLength(expr->arguments());
1931 } else if (strcmp("_ClassOf", *name->ToCString()) == 0) {
1932 EmitClassOf(expr->arguments());
1933 } else if (strcmp("_Log", *name->ToCString()) == 0) {
1934 EmitLog(expr->arguments());
1935 } else if (strcmp("_RandomHeapNumber", *name->ToCString()) == 0) {
1936 EmitRandomHeapNumber(expr->arguments());
1937 } else if (strcmp("_SubString", *name->ToCString()) == 0) {
1938 EmitSubString(expr->arguments());
1939 } else if (strcmp("_RegExpExec", *name->ToCString()) == 0) {
1940 EmitRegExpExec(expr->arguments());
1941 } else if (strcmp("_ValueOf", *name->ToCString()) == 0) {
1942 EmitValueOf(expr->arguments());
1943 } else if (strcmp("_SetValueOf", *name->ToCString()) == 0) {
1944 EmitSetValueOf(expr->arguments());
1945 } else if (strcmp("_NumberToString", *name->ToCString()) == 0) {
1946 EmitNumberToString(expr->arguments());
1947 } else if (strcmp("_CharFromCode", *name->ToCString()) == 0) {
1948 EmitCharFromCode(expr->arguments());
1949 } else if (strcmp("_FastCharCodeAt", *name->ToCString()) == 0) {
1950 EmitFastCharCodeAt(expr->arguments());
1951 } else if (strcmp("_StringAdd", *name->ToCString()) == 0) {
1952 EmitStringAdd(expr->arguments());
1953 } else if (strcmp("_StringCompare", *name->ToCString()) == 0) {
1954 EmitStringCompare(expr->arguments());
1955 } else if (strcmp("_MathPow", *name->ToCString()) == 0) {
1956 EmitMathPow(expr->arguments());
1957 } else if (strcmp("_MathSin", *name->ToCString()) == 0) {
1958 EmitMathSin(expr->arguments());
1959 } else if (strcmp("_MathCos", *name->ToCString()) == 0) {
1960 EmitMathCos(expr->arguments());
1961 } else if (strcmp("_MathSqrt", *name->ToCString()) == 0) {
1962 EmitMathSqrt(expr->arguments());
1963 } else if (strcmp("_CallFunction", *name->ToCString()) == 0) {
1964 EmitCallFunction(expr->arguments());
1965 } else if (strcmp("_RegExpConstructResult", *name->ToCString()) == 0) {
1966 EmitRegExpConstructResult(expr->arguments());
1967 } else if (strcmp("_SwapElements", *name->ToCString()) == 0) {
1968 EmitSwapElements(expr->arguments());
1969 } else if (strcmp("_GetFromCache", *name->ToCString()) == 0) {
1970 EmitGetFromCache(expr->arguments());
1971 } else {
1972 UNREACHABLE();
1973 }
1974 }
1975
1976
1977 void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1978 ASSERT(args->length() == 1);
1979
1980 VisitForValue(args->at(0), kAccumulator);
1981
1982 Label materialize_true, materialize_false;
1983 Label* if_true = NULL;
1984 Label* if_false = NULL;
1985 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1986
1987 __ test(eax, Immediate(kSmiTagMask));
1988 __ j(zero, if_true);
1989 __ jmp(if_false);
1990
1991 Apply(context_, if_true, if_false);
1992 }
1993
1994
1995 void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1996 ASSERT(args->length() == 1);
1997
1998 VisitForValue(args->at(0), kAccumulator);
1999
2000 Label materialize_true, materialize_false;
2001 Label* if_true = NULL;
2002 Label* if_false = NULL;
2003 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2004
2005 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
2006 __ j(zero, if_true);
2007 __ jmp(if_false);
2008
2009 Apply(context_, if_true, if_false);
2010 }
2011
2012
2013 void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2014 ASSERT(args->length() == 1);
2015
2016 VisitForValue(args->at(0), kAccumulator);
2017
2018 Label materialize_true, materialize_false;
2019 Label* if_true = NULL;
2020 Label* if_false = NULL;
2021 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2022
2023 __ test(eax, Immediate(kSmiTagMask));
2024 __ j(zero, if_false);
2025 __ cmp(eax, Factory::null_value());
2026 __ j(equal, if_true);
2027 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2028 // Undetectable objects behave like undefined when tested with typeof.
2029 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2030 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2031 __ j(not_zero, if_false);
2032 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2033 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2034 __ j(less, if_false);
2035 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
2036 __ j(less_equal, if_true);
2037 __ jmp(if_false);
2038
2039 Apply(context_, if_true, if_false);
2040 }
2041
2042
2043 void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2044 ASSERT(args->length() == 1);
2045
2046 VisitForValue(args->at(0), kAccumulator);
2047
2048 Label materialize_true, materialize_false;
2049 Label* if_true = NULL;
2050 Label* if_false = NULL;
2051 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2052
2053 __ test(eax, Immediate(kSmiTagMask));
2054 __ j(zero, if_false);
2055 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2056 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2057 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
2058 __ j(not_zero, if_true);
2059 __ jmp(if_false);
2060
2061 Apply(context_, if_true, if_false);
2062 }
2063
2064
2065 void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2066 ASSERT(args->length() == 1);
2067
2068 VisitForValue(args->at(0), kAccumulator);
2069
2070 Label materialize_true, materialize_false;
2071 Label* if_true = NULL;
2072 Label* if_false = NULL;
2073 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2074
2075 __ test(eax, Immediate(kSmiTagMask));
2076 __ j(zero, if_false);
2077 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2078 __ j(equal, if_true);
2079 __ jmp(if_false);
2080
2081 Apply(context_, if_true, if_false);
2082 }
2083
2084
2085 void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2086 ASSERT(args->length() == 1);
2087
2088 VisitForValue(args->at(0), kAccumulator);
2089
2090 Label materialize_true, materialize_false;
2091 Label* if_true = NULL;
2092 Label* if_false = NULL;
2093 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2094
2095 __ test(eax, Immediate(kSmiTagMask));
2096 __ j(equal, if_false);
2097 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
2098 __ j(equal, if_true);
2099 __ jmp(if_false);
2100
2101 Apply(context_, if_true, if_false);
2102 }
2103
2104
2105 void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2106 ASSERT(args->length() == 1);
2107
2108 VisitForValue(args->at(0), kAccumulator);
2109
2110 Label materialize_true, materialize_false;
2111 Label* if_true = NULL;
2112 Label* if_false = NULL;
2113 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2114
2115 __ test(eax, Immediate(kSmiTagMask));
2116 __ j(equal, if_false);
2117 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
2118 __ j(equal, if_true);
2119 __ jmp(if_false);
2120
2121 Apply(context_, if_true, if_false);
2122 }
2123
2124
2125
2126 void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2127 ASSERT(args->length() == 0);
2128
2129 Label materialize_true, materialize_false;
2130 Label* if_true = NULL;
2131 Label* if_false = NULL;
2132 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2133
2134 // Get the frame pointer for the calling frame.
2135 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2136
2137 // Skip the arguments adaptor frame if it exists.
2138 Label check_frame_marker;
2139 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2140 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2141 __ j(not_equal, &check_frame_marker);
2142 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2143
2144 // Check the marker in the calling frame.
2145 __ bind(&check_frame_marker);
2146 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2147 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
2148 __ j(equal, if_true);
2149 __ jmp(if_false);
2150
2151 Apply(context_, if_true, if_false);
2152 }
2153
2154
2155 void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2156 ASSERT(args->length() == 2);
2157
2158 // Load the two objects into registers and perform the comparison.
2159 VisitForValue(args->at(0), kStack);
2160 VisitForValue(args->at(1), kAccumulator);
2161
2162 Label materialize_true, materialize_false;
2163 Label* if_true = NULL;
2164 Label* if_false = NULL;
2165 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2166
2167 __ pop(ebx);
2168 __ cmp(eax, Operand(ebx));
2169 __ j(equal, if_true);
2170 __ jmp(if_false);
2171
2172 Apply(context_, if_true, if_false);
2173 }
2174
2175
2176 void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2177 ASSERT(args->length() == 1);
2178
2179 // ArgumentsAccessStub expects the key in edx and the formal
2180 // parameter count in eax.
2181 VisitForValue(args->at(0), kAccumulator);
2182 __ mov(edx, eax);
2183 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2184 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2185 __ CallStub(&stub);
2186 Apply(context_, eax);
2187 }
2188
2189
2190 void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2191 ASSERT(args->length() == 0);
2192
2193 Label exit;
2194 // Get the number of formal parameters.
2195 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2196
2197 // Check if the calling frame is an arguments adaptor frame.
2198 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2199 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2200 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2201 __ j(not_equal, &exit);
2202
2203 // Arguments adaptor case: Read the arguments length from the
2204 // adaptor frame.
2205 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2206
2207 __ bind(&exit);
2208 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
2209 Apply(context_, eax);
2210 }
2211
2212
2213 void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2214 ASSERT(args->length() == 1);
2215 Label done, null, function, non_function_constructor;
2216
2217 VisitForValue(args->at(0), kAccumulator);
2218
2219 // If the object is a smi, we return null.
2220 __ test(eax, Immediate(kSmiTagMask));
2221 __ j(zero, &null);
2222
2223 // Check that the object is a JS object but take special care of JS
2224 // functions to make sure they have 'Function' as their class.
2225 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
2226 __ movzx_b(ebx, FieldOperand(eax, Map::kInstanceTypeOffset));
2227 __ cmp(ebx, FIRST_JS_OBJECT_TYPE);
2228 __ j(less, &null);
2229
2230 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2231 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2232 // LAST_JS_OBJECT_TYPE.
2233 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2234 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
2235 __ cmp(ebx, JS_FUNCTION_TYPE);
2236 __ j(equal, &function);
2237
2238 // Check if the constructor in the map is a function.
2239 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2240 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2241 __ j(not_equal, &non_function_constructor);
2242
2243 // eax now contains the constructor function. Grab the
2244 // instance class name from there.
2245 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2246 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2247 __ jmp(&done);
2248
2249 // Functions have class 'Function'.
2250 __ bind(&function);
2251 __ mov(eax, Factory::function_class_symbol());
2252 __ jmp(&done);
2253
2254 // Objects with a non-function constructor have class 'Object'.
2255 __ bind(&non_function_constructor);
2256 __ mov(eax, Factory::Object_symbol());
2257 __ jmp(&done);
2258
2259 // Non-JS objects have class null.
2260 __ bind(&null);
2261 __ mov(eax, Factory::null_value());
2262
2263 // All done.
2264 __ bind(&done);
2265
2266 Apply(context_, eax);
2267 }
2268
2269
2270 void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2271 // Conditionally generate a log call.
2272 // Args:
2273 // 0 (literal string): The type of logging (corresponds to the flags).
2274 // This is used to determine whether or not to generate the log call.
2275 // 1 (string): Format string. Access the string at argument index 2
2276 // with '%2s' (see Logger::LogRuntime for all the formats).
2277 // 2 (array): Arguments to the format string.
2278 ASSERT_EQ(args->length(), 3);
2279 #ifdef ENABLE_LOGGING_AND_PROFILING
2280 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2281 VisitForValue(args->at(1), kStack);
2282 VisitForValue(args->at(2), kStack);
2283 __ CallRuntime(Runtime::kLog, 2);
2284 }
2285 #endif
2286 // Finally, we're expected to leave a value on the top of the stack.
2287 __ mov(eax, Factory::undefined_value());
2288 Apply(context_, eax);
2289 }
2290
2291
2292 void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2293 ASSERT(args->length() == 0);
2294
2295 Label slow_allocate_heapnumber;
2296 Label heapnumber_allocated;
2297
2298 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2299 __ jmp(&heapnumber_allocated);
2300
2301 __ bind(&slow_allocate_heapnumber);
2302 // To allocate a heap number, and ensure that it is not a smi, we
2303 // call the runtime function FUnaryMinus on 0, returning the double
2304 // -0.0. A new, distinct heap number is returned each time.
2305 __ push(Immediate(Smi::FromInt(0)));
2306 __ CallRuntime(Runtime::kNumberUnaryMinus, 1);
2307 __ mov(edi, eax);
2308
2309 __ bind(&heapnumber_allocated);
2310
2311 __ PrepareCallCFunction(0, ebx);
2312 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2313
2314 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2315 // by computing:
2316 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2317 // This is implemented on both SSE2 and FPU.
2318 if (CpuFeatures::IsSupported(SSE2)) {
2319 CpuFeatures::Scope fscope(SSE2);
2320 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2321 __ movd(xmm1, Operand(ebx));
2322 __ movd(xmm0, Operand(eax));
2323 __ cvtss2sd(xmm1, xmm1);
2324 __ pxor(xmm0, xmm1);
2325 __ subsd(xmm0, xmm1);
2326 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2327 } else {
2328 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2329 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2330 Immediate(0x41300000));
2331 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2332 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2333 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2334 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2335 __ fsubp(1);
2336 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2337 }
2338 __ mov(eax, edi);
2339 Apply(context_, eax);
2340 }
2341
2342
2343 void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2344 // Load the arguments on the stack and call the stub.
2345 SubStringStub stub;
2346 ASSERT(args->length() == 3);
2347 VisitForValue(args->at(0), kStack);
2348 VisitForValue(args->at(1), kStack);
2349 VisitForValue(args->at(2), kStack);
2350 __ CallStub(&stub);
2351 Apply(context_, eax);
2352 }
2353
2354
2355 void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2356 // Load the arguments on the stack and call the stub.
2357 RegExpExecStub stub;
2358 ASSERT(args->length() == 4);
2359 VisitForValue(args->at(0), kStack);
2360 VisitForValue(args->at(1), kStack);
2361 VisitForValue(args->at(2), kStack);
2362 VisitForValue(args->at(3), kStack);
2363 __ CallStub(&stub);
2364 Apply(context_, eax);
2365 }
2366
2367
2368 void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2369 ASSERT(args->length() == 1);
2370
2371 VisitForValue(args->at(0), kAccumulator); // Load the object.
2372
2373 Label done;
2374 // If the object is a smi return the object.
2375 __ test(eax, Immediate(kSmiTagMask));
2376 __ j(zero, &done);
2377 // If the object is not a value type, return the object.
2378 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2379 __ j(not_equal, &done);
2380 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2381
2382 __ bind(&done);
2383 Apply(context_, eax);
2384 }
2385
2386
2387 void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2388 // Load the arguments on the stack and call the runtime function.
2389 ASSERT(args->length() == 2);
2390 VisitForValue(args->at(0), kStack);
2391 VisitForValue(args->at(1), kStack);
2392 __ CallRuntime(Runtime::kMath_pow, 2);
2393 Apply(context_, eax);
2394 }
2395
2396
2397 void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2398 ASSERT(args->length() == 2);
2399
2400 VisitForValue(args->at(0), kStack); // Load the object.
2401 VisitForValue(args->at(1), kAccumulator); // Load the value.
2402 __ pop(ebx); // eax = value. ebx = object.
2403
2404 Label done;
2405 // If the object is a smi, return the value.
2406 __ test(ebx, Immediate(kSmiTagMask));
2407 __ j(zero, &done);
2408
2409 // If the object is not a value type, return the value.
2410 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2411 __ j(not_equal, &done);
2412
2413 // Store the value.
2414 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2415 // Update the write barrier. Save the value as it will be
2416 // overwritten by the write barrier code and is needed afterward.
2417 __ mov(edx, eax);
2418 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2419
2420 __ bind(&done);
2421 Apply(context_, eax);
2422 }
2423
2424
2425 void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2426 ASSERT_EQ(args->length(), 1);
2427
2428 // Load the argument on the stack and call the stub.
2429 VisitForValue(args->at(0), kStack);
2430
2431 NumberToStringStub stub;
2432 __ CallStub(&stub);
2433 Apply(context_, eax);
2434 }
2435
2436
2437 void FullCodeGenerator::EmitCharFromCode(ZoneList<Expression*>* args) {
2438 ASSERT(args->length() == 1);
2439
2440 VisitForValue(args->at(0), kAccumulator);
2441
2442 Label slow_case, done;
2443 // Fast case of Heap::LookupSingleCharacterStringFromCode.
2444 ASSERT(kSmiTag == 0);
2445 ASSERT(kSmiShiftSize == 0);
2446 ASSERT(IsPowerOf2(String::kMaxAsciiCharCode + 1));
2447 __ test(eax,
2448 Immediate(kSmiTagMask |
2449 ((~String::kMaxAsciiCharCode) << kSmiTagSize)));
2450 __ j(not_zero, &slow_case);
2451 __ Set(ebx, Immediate(Factory::single_character_string_cache()));
2452 ASSERT(kSmiTag == 0);
2453 ASSERT(kSmiTagSize == 1);
2454 ASSERT(kSmiShiftSize == 0);
2455 // At this point code register contains smi tagged ascii char code.
2456 __ mov(ebx, FieldOperand(ebx,
2457 eax, times_half_pointer_size,
2458 FixedArray::kHeaderSize));
2459 __ cmp(ebx, Factory::undefined_value());
2460 __ j(equal, &slow_case);
2461 __ mov(eax, ebx);
2462 __ jmp(&done);
2463
2464 __ bind(&slow_case);
2465 __ push(eax);
2466 __ CallRuntime(Runtime::kCharFromCode, 1);
2467
2468 __ bind(&done);
2469 Apply(context_, eax);
2470 }
2471
2472
2473 void FullCodeGenerator::EmitFastCharCodeAt(ZoneList<Expression*>* args) {
2474 // TODO(fsc): Port the complete implementation from the classic back-end.
2475 // Move the undefined value into the result register, which will
2476 // trigger the slow case.
2477 __ Set(eax, Immediate(Factory::undefined_value()));
2478 Apply(context_, eax);
2479 }
2480
2481 void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2482 ASSERT_EQ(2, args->length());
2483
2484 VisitForValue(args->at(0), kStack);
2485 VisitForValue(args->at(1), kStack);
2486
2487 StringAddStub stub(NO_STRING_ADD_FLAGS);
2488 __ CallStub(&stub);
2489 Apply(context_, eax);
2490 }
2491
2492
2493 void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2494 ASSERT_EQ(2, args->length());
2495
2496 VisitForValue(args->at(0), kStack);
2497 VisitForValue(args->at(1), kStack);
2498
2499 StringCompareStub stub;
2500 __ CallStub(&stub);
2501 Apply(context_, eax);
2502 }
2503
2504
2505 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2506 // Load the argument on the stack and call the stub.
2507 TranscendentalCacheStub stub(TranscendentalCache::SIN);
2508 ASSERT(args->length() == 1);
2509 VisitForValue(args->at(0), kStack);
2510 __ CallStub(&stub);
2511 Apply(context_, eax);
2512 }
2513
2514
2515 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2516 // Load the argument on the stack and call the stub.
2517 TranscendentalCacheStub stub(TranscendentalCache::COS);
2518 ASSERT(args->length() == 1);
2519 VisitForValue(args->at(0), kStack);
2520 __ CallStub(&stub);
2521 Apply(context_, eax);
2522 }
2523
2524
2525 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2526 // Load the argument on the stack and call the runtime function.
2527 ASSERT(args->length() == 1);
2528 VisitForValue(args->at(0), kStack);
2529 __ CallRuntime(Runtime::kMath_sqrt, 1);
2530 Apply(context_, eax);
2531 }
2532
2533
2534 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2535 ASSERT(args->length() >= 2);
2536
2537 int arg_count = args->length() - 2; // For receiver and function.
2538 VisitForValue(args->at(0), kStack); // Receiver.
2539 for (int i = 0; i < arg_count; i++) {
2540 VisitForValue(args->at(i + 1), kStack);
2541 }
2542 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
2543
2544 // InvokeFunction requires function in edi. Move it in there.
2545 if (!result_register().is(edi)) __ mov(edi, result_register());
2546 ParameterCount count(arg_count);
2547 __ InvokeFunction(edi, count, CALL_FUNCTION);
2548 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2549 Apply(context_, eax);
2550 }
2551
2552
2553 void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2554 ASSERT(args->length() == 3);
2555 VisitForValue(args->at(0), kStack);
2556 VisitForValue(args->at(1), kStack);
2557 VisitForValue(args->at(2), kStack);
2558 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2559 Apply(context_, eax);
2560 }
2561
2562
2563 void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2564 ASSERT(args->length() == 3);
2565 VisitForValue(args->at(0), kStack);
2566 VisitForValue(args->at(1), kStack);
2567 VisitForValue(args->at(2), kStack);
2568 __ CallRuntime(Runtime::kSwapElements, 3);
2569 Apply(context_, eax);
2570 }
2571
2572
2573 void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2574 ASSERT_EQ(2, args->length());
2575
2576 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2577 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2578
2579 Handle<FixedArray> jsfunction_result_caches(
2580 Top::global_context()->jsfunction_result_caches());
2581 if (jsfunction_result_caches->length() <= cache_id) {
2582 __ Abort("Attempt to use undefined cache.");
2583 __ mov(eax, Factory::undefined_value());
2584 Apply(context_, eax);
2585 return;
2586 }
2587
2588 VisitForValue(args->at(1), kAccumulator);
2589
2590 Register key = eax;
2591 Register cache = ebx;
2592 Register tmp = ecx;
2593 __ mov(cache, CodeGenerator::ContextOperand(esi, Context::GLOBAL_INDEX));
2594 __ mov(cache,
2595 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
2596 __ mov(cache,
2597 CodeGenerator::ContextOperand(
2598 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
2599 __ mov(cache,
2600 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2601
2602 Label done, not_found;
2603 // tmp now holds finger offset as a smi.
2604 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2605 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
2606 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
2607 __ j(not_equal, &not_found);
2608
2609 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
2610 __ jmp(&done);
2611
2612 __ bind(&not_found);
2613 // Call runtime to perform the lookup.
2614 __ push(cache);
2615 __ push(key);
2616 __ CallRuntime(Runtime::kGetFromCache, 2);
2617
2618 __ bind(&done);
2619 Apply(context_, eax);
2620 }
2621
2622
1450 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 2623 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2624 Handle<String> name = expr->name();
2625 if (name->length() > 0 && name->Get(0) == '_') {
2626 Comment cmnt(masm_, "[ InlineRuntimeCall");
2627 EmitInlineRuntimeCall(expr);
2628 return;
2629 }
2630
1451 Comment cmnt(masm_, "[ CallRuntime"); 2631 Comment cmnt(masm_, "[ CallRuntime");
1452 ZoneList<Expression*>* args = expr->arguments(); 2632 ZoneList<Expression*>* args = expr->arguments();
1453 2633
1454 if (expr->is_jsruntime()) { 2634 if (expr->is_jsruntime()) {
1455 // Prepare for calling JS runtime function. 2635 // Prepare for calling JS runtime function.
1456 __ mov(eax, CodeGenerator::GlobalObject()); 2636 __ mov(eax, CodeGenerator::GlobalObject());
1457 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset)); 2637 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
1458 } 2638 }
1459 2639
1460 // Push the arguments ("left-to-right"). 2640 // Push the arguments ("left-to-right").
(...skipping 13 matching lines...) Expand all
1474 } else { 2654 } else {
1475 // Call the C runtime function. 2655 // Call the C runtime function.
1476 __ CallRuntime(expr->function(), arg_count); 2656 __ CallRuntime(expr->function(), arg_count);
1477 } 2657 }
1478 Apply(context_, eax); 2658 Apply(context_, eax);
1479 } 2659 }
1480 2660
1481 2661
1482 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 2662 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1483 switch (expr->op()) { 2663 switch (expr->op()) {
2664 case Token::DELETE: {
2665 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2666 Property* prop = expr->expression()->AsProperty();
2667 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2668 if (prop == NULL && var == NULL) {
2669 // Result of deleting non-property, non-variable reference is true.
2670 // The subexpression may have side effects.
2671 VisitForEffect(expr->expression());
2672 Apply(context_, true);
2673 } else if (var != NULL &&
2674 !var->is_global() &&
2675 var->slot() != NULL &&
2676 var->slot()->type() != Slot::LOOKUP) {
2677 // Result of deleting non-global, non-dynamic variables is false.
2678 // The subexpression does not have side effects.
2679 Apply(context_, false);
2680 } else {
2681 // Property or variable reference. Call the delete builtin with
2682 // object and property name as arguments.
2683 if (prop != NULL) {
2684 VisitForValue(prop->obj(), kStack);
2685 VisitForValue(prop->key(), kStack);
2686 } else if (var->is_global()) {
2687 __ push(CodeGenerator::GlobalObject());
2688 __ push(Immediate(var->name()));
2689 } else {
2690 // Non-global variable. Call the runtime to look up the context
2691 // where the variable was introduced.
2692 __ push(context_register());
2693 __ push(Immediate(var->name()));
2694 __ CallRuntime(Runtime::kLookupContext, 2);
2695 __ push(eax);
2696 __ push(Immediate(var->name()));
2697 }
2698 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
2699 Apply(context_, eax);
2700 }
2701 break;
2702 }
2703
1484 case Token::VOID: { 2704 case Token::VOID: {
1485 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 2705 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1486 VisitForEffect(expr->expression()); 2706 VisitForEffect(expr->expression());
1487 switch (context_) { 2707 switch (context_) {
1488 case Expression::kUninitialized: 2708 case Expression::kUninitialized:
1489 UNREACHABLE(); 2709 UNREACHABLE();
1490 break; 2710 break;
1491 case Expression::kEffect: 2711 case Expression::kEffect:
1492 break; 2712 break;
1493 case Expression::kValue: 2713 case Expression::kValue:
(...skipping 20 matching lines...) Expand all
1514 case Expression::kTest: 2734 case Expression::kTest:
1515 case Expression::kValueTest: 2735 case Expression::kValueTest:
1516 __ jmp(false_label_); 2736 __ jmp(false_label_);
1517 break; 2737 break;
1518 } 2738 }
1519 break; 2739 break;
1520 } 2740 }
1521 2741
1522 case Token::NOT: { 2742 case Token::NOT: {
1523 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 2743 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1524 Label materialize_true, materialize_false, done; 2744 Label materialize_true, materialize_false;
1525 // Initially assume a pure test context. Notice that the labels are 2745 Label* if_true = NULL;
1526 // swapped. 2746 Label* if_false = NULL;
1527 Label* if_true = false_label_; 2747
1528 Label* if_false = true_label_; 2748 // Notice that the labels are swapped.
1529 switch (context_) { 2749 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
1530 case Expression::kUninitialized: 2750
1531 UNREACHABLE();
1532 break;
1533 case Expression::kEffect:
1534 if_true = &done;
1535 if_false = &done;
1536 break;
1537 case Expression::kValue:
1538 if_true = &materialize_false;
1539 if_false = &materialize_true;
1540 break;
1541 case Expression::kTest:
1542 break;
1543 case Expression::kValueTest:
1544 if_false = &materialize_true;
1545 break;
1546 case Expression::kTestValue:
1547 if_true = &materialize_false;
1548 break;
1549 }
1550 VisitForControl(expr->expression(), if_true, if_false); 2751 VisitForControl(expr->expression(), if_true, if_false);
2752
1551 Apply(context_, if_false, if_true); // Labels swapped. 2753 Apply(context_, if_false, if_true); // Labels swapped.
1552 break; 2754 break;
1553 } 2755 }
1554 2756
1555 case Token::TYPEOF: { 2757 case Token::TYPEOF: {
1556 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 2758 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1557 VariableProxy* proxy = expr->expression()->AsVariableProxy(); 2759 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1558 if (proxy != NULL && 2760 if (proxy != NULL &&
1559 !proxy->var()->is_this() && 2761 !proxy->var()->is_this() &&
1560 proxy->var()->is_global()) { 2762 proxy->var()->is_global()) {
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
1636 } 2838 }
1637 2839
1638 default: 2840 default:
1639 UNREACHABLE(); 2841 UNREACHABLE();
1640 } 2842 }
1641 } 2843 }
1642 2844
1643 2845
1644 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) { 2846 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
1645 Comment cmnt(masm_, "[ CountOperation"); 2847 Comment cmnt(masm_, "[ CountOperation");
2848 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
2849 // as the left-hand side.
2850 if (!expr->expression()->IsValidLeftHandSide()) {
2851 VisitForEffect(expr->expression());
2852 return;
2853 }
1646 2854
1647 // Expression can only be a property, a global or a (parameter or local) 2855 // Expression can only be a property, a global or a (parameter or local)
1648 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY. 2856 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1649 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY }; 2857 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1650 LhsKind assign_type = VARIABLE; 2858 LhsKind assign_type = VARIABLE;
1651 Property* prop = expr->expression()->AsProperty(); 2859 Property* prop = expr->expression()->AsProperty();
1652 // In case of a property we use the uninitialized expression context 2860 // In case of a property we use the uninitialized expression context
1653 // of the key to detect a named property. 2861 // of the key to detect a named property.
1654 if (prop != NULL) { 2862 if (prop != NULL) {
1655 assign_type = 2863 assign_type =
1656 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY; 2864 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1657 } 2865 }
1658 2866
1659 // Evaluate expression and get value. 2867 // Evaluate expression and get value.
1660 if (assign_type == VARIABLE) { 2868 if (assign_type == VARIABLE) {
1661 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL); 2869 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1662 Location saved_location = location_; 2870 Location saved_location = location_;
1663 location_ = kAccumulator; 2871 location_ = kAccumulator;
1664 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(), 2872 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1665 Expression::kValue); 2873 Expression::kValue);
1666 location_ = saved_location; 2874 location_ = saved_location;
1667 } else { 2875 } else {
1668 // Reserve space for result of postfix operation. 2876 // Reserve space for result of postfix operation.
1669 if (expr->is_postfix() && context_ != Expression::kEffect) { 2877 if (expr->is_postfix() && context_ != Expression::kEffect) {
1670 __ push(Immediate(Smi::FromInt(0))); 2878 __ push(Immediate(Smi::FromInt(0)));
1671 } 2879 }
1672 if (assign_type == NAMED_PROPERTY) { 2880 if (assign_type == NAMED_PROPERTY) {
1673 // Put the object both on the stack and in the accumulator. 2881 // Put the object both on the stack and in the accumulator.
1674 VisitForValue(prop->obj(), kAccumulator); 2882 VisitForValue(prop->obj(), kAccumulator);
1675 __ push(eax); 2883 __ push(eax);
1676 EmitNamedPropertyLoad(prop); 2884 EmitNamedPropertyLoad(prop);
1677 } else { 2885 } else {
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
1747 NO_OVERWRITE, 2955 NO_OVERWRITE,
1748 NO_GENERIC_BINARY_FLAGS, 2956 NO_GENERIC_BINARY_FLAGS,
1749 TypeInfo::Unknown()); 2957 TypeInfo::Unknown());
1750 stub.GenerateCall(masm(), eax, Smi::FromInt(1)); 2958 stub.GenerateCall(masm(), eax, Smi::FromInt(1));
1751 __ bind(&done); 2959 __ bind(&done);
1752 2960
1753 // Store the value returned in eax. 2961 // Store the value returned in eax.
1754 switch (assign_type) { 2962 switch (assign_type) {
1755 case VARIABLE: 2963 case VARIABLE:
1756 if (expr->is_postfix()) { 2964 if (expr->is_postfix()) {
2965 // Perform the assignment as if via '='.
1757 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 2966 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
2967 Token::ASSIGN,
1758 Expression::kEffect); 2968 Expression::kEffect);
1759 // For all contexts except kEffect: We have the result on 2969 // For all contexts except kEffect: We have the result on
1760 // top of the stack. 2970 // top of the stack.
1761 if (context_ != Expression::kEffect) { 2971 if (context_ != Expression::kEffect) {
1762 ApplyTOS(context_); 2972 ApplyTOS(context_);
1763 } 2973 }
1764 } else { 2974 } else {
2975 // Perform the assignment as if via '='.
1765 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 2976 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
2977 Token::ASSIGN,
1766 context_); 2978 context_);
1767 } 2979 }
1768 break; 2980 break;
1769 case NAMED_PROPERTY: { 2981 case NAMED_PROPERTY: {
1770 __ mov(ecx, prop->key()->AsLiteral()->handle()); 2982 __ mov(ecx, prop->key()->AsLiteral()->handle());
1771 __ pop(edx); 2983 __ pop(edx);
1772 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 2984 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1773 __ call(ic, RelocInfo::CODE_TARGET); 2985 __ call(ic, RelocInfo::CODE_TARGET);
1774 // This nop signals to the IC that there is no inlined code at the call 2986 // This nop signals to the IC that there is no inlined code at the call
1775 // site for it to patch. 2987 // site for it to patch.
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1833 VisitForValue(expr->right(), kAccumulator); 3045 VisitForValue(expr->right(), kAccumulator);
1834 EmitBinaryOp(expr->op(), context_); 3046 EmitBinaryOp(expr->op(), context_);
1835 break; 3047 break;
1836 3048
1837 default: 3049 default:
1838 UNREACHABLE(); 3050 UNREACHABLE();
1839 } 3051 }
1840 } 3052 }
1841 3053
1842 3054
3055 void FullCodeGenerator::EmitNullCompare(bool strict,
3056 Register obj,
3057 Register null_const,
3058 Label* if_true,
3059 Label* if_false,
3060 Register scratch) {
3061 __ cmp(obj, Operand(null_const));
3062 if (strict) {
3063 __ j(equal, if_true);
3064 } else {
3065 __ j(equal, if_true);
3066 __ cmp(obj, Factory::undefined_value());
3067 __ j(equal, if_true);
3068 __ test(obj, Immediate(kSmiTagMask));
3069 __ j(zero, if_false);
3070 // It can be an undetectable object.
3071 __ mov(scratch, FieldOperand(obj, HeapObject::kMapOffset));
3072 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
3073 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
3074 __ j(not_zero, if_true);
3075 }
3076 __ jmp(if_false);
3077 }
3078
3079
1843 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) { 3080 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1844 Comment cmnt(masm_, "[ CompareOperation"); 3081 Comment cmnt(masm_, "[ CompareOperation");
1845 3082
1846 // Always perform the comparison for its control flow. Pack the result 3083 // Always perform the comparison for its control flow. Pack the result
1847 // into the expression's context after the comparison is performed. 3084 // into the expression's context after the comparison is performed.
1848 Label materialize_true, materialize_false, done; 3085
1849 // Initially assume we are in a test context. 3086 Label materialize_true, materialize_false;
1850 Label* if_true = true_label_; 3087 Label* if_true = NULL;
1851 Label* if_false = false_label_; 3088 Label* if_false = NULL;
1852 switch (context_) { 3089 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1853 case Expression::kUninitialized:
1854 UNREACHABLE();
1855 break;
1856 case Expression::kEffect:
1857 if_true = &done;
1858 if_false = &done;
1859 break;
1860 case Expression::kValue:
1861 if_true = &materialize_true;
1862 if_false = &materialize_false;
1863 break;
1864 case Expression::kTest:
1865 break;
1866 case Expression::kValueTest:
1867 if_true = &materialize_true;
1868 break;
1869 case Expression::kTestValue:
1870 if_false = &materialize_false;
1871 break;
1872 }
1873 3090
1874 VisitForValue(expr->left(), kStack); 3091 VisitForValue(expr->left(), kStack);
1875 switch (expr->op()) { 3092 switch (expr->op()) {
1876 case Token::IN: 3093 case Token::IN:
1877 VisitForValue(expr->right(), kStack); 3094 VisitForValue(expr->right(), kStack);
1878 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 3095 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
1879 __ cmp(eax, Factory::true_value()); 3096 __ cmp(eax, Factory::true_value());
1880 __ j(equal, if_true); 3097 __ j(equal, if_true);
1881 __ jmp(if_false); 3098 __ jmp(if_false);
1882 break; 3099 break;
1883 3100
1884 case Token::INSTANCEOF: { 3101 case Token::INSTANCEOF: {
1885 VisitForValue(expr->right(), kStack); 3102 VisitForValue(expr->right(), kStack);
1886 InstanceofStub stub; 3103 InstanceofStub stub;
1887 __ CallStub(&stub); 3104 __ CallStub(&stub);
1888 __ test(eax, Operand(eax)); 3105 __ test(eax, Operand(eax));
1889 __ j(zero, if_true); // The stub returns 0 for true. 3106 __ j(zero, if_true); // The stub returns 0 for true.
1890 __ jmp(if_false); 3107 __ jmp(if_false);
1891 break; 3108 break;
1892 } 3109 }
1893 3110
1894 default: { 3111 default: {
1895 VisitForValue(expr->right(), kAccumulator); 3112 VisitForValue(expr->right(), kAccumulator);
1896 Condition cc = no_condition; 3113 Condition cc = no_condition;
1897 bool strict = false; 3114 bool strict = false;
1898 switch (expr->op()) { 3115 switch (expr->op()) {
1899 case Token::EQ_STRICT: 3116 case Token::EQ_STRICT:
1900 strict = true; 3117 strict = true;
1901 // Fall through 3118 // Fall through
1902 case Token::EQ: 3119 case Token::EQ: {
1903 cc = equal; 3120 cc = equal;
1904 __ pop(edx); 3121 __ pop(edx);
3122 // If either operand is constant null we do a fast compare
3123 // against null.
3124 Literal* right_literal = expr->right()->AsLiteral();
3125 Literal* left_literal = expr->left()->AsLiteral();
3126 if (right_literal != NULL && right_literal->handle()->IsNull()) {
3127 EmitNullCompare(strict, edx, eax, if_true, if_false, ecx);
3128 Apply(context_, if_true, if_false);
3129 return;
3130 } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
3131 EmitNullCompare(strict, eax, edx, if_true, if_false, ecx);
3132 Apply(context_, if_true, if_false);
3133 return;
3134 }
1905 break; 3135 break;
3136 }
1906 case Token::LT: 3137 case Token::LT:
1907 cc = less; 3138 cc = less;
1908 __ pop(edx); 3139 __ pop(edx);
1909 break; 3140 break;
1910 case Token::GT: 3141 case Token::GT:
1911 // Reverse left and right sizes to obtain ECMA-262 conversion order. 3142 // Reverse left and right sizes to obtain ECMA-262 conversion order.
1912 cc = less; 3143 cc = less;
1913 __ mov(edx, result_register()); 3144 __ mov(edx, result_register());
1914 __ pop(eax); 3145 __ pop(eax);
1915 break; 3146 break;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
2005 __ add(Operand(edx), Immediate(masm_->CodeObject())); 3236 __ add(Operand(edx), Immediate(masm_->CodeObject()));
2006 __ mov(Operand(esp, 0), edx); 3237 __ mov(Operand(esp, 0), edx);
2007 // And return. 3238 // And return.
2008 __ ret(0); 3239 __ ret(0);
2009 } 3240 }
2010 3241
2011 3242
2012 #undef __ 3243 #undef __
2013 3244
2014 } } // namespace v8::internal 3245 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/full-codegen.cc ('k') | src/x64/full-codegen-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698