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

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

Issue 6614010: [Isolates] Merge 6700:7030 from bleeding_edge to isolates. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/isolates/
Patch Set: '' Created 9 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/arm/deoptimizer-arm.cc ('k') | src/arm/ic-arm.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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 27 matching lines...) Expand all
38 #include "scopes.h" 38 #include "scopes.h"
39 #include "stub-cache.h" 39 #include "stub-cache.h"
40 40
41 #include "arm/code-stubs-arm.h" 41 #include "arm/code-stubs-arm.h"
42 42
43 namespace v8 { 43 namespace v8 {
44 namespace internal { 44 namespace internal {
45 45
46 #define __ ACCESS_MASM(masm_) 46 #define __ ACCESS_MASM(masm_)
47 47
48
49 // A patch site is a location in the code which it is possible to patch. This
50 // class has a number of methods to emit the code which is patchable and the
51 // method EmitPatchInfo to record a marker back to the patchable code. This
52 // marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit
53 // immediate value is used) is the delta from the pc to the first instruction of
54 // the patchable code.
55 class JumpPatchSite BASE_EMBEDDED {
56 public:
57 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
58 #ifdef DEBUG
59 info_emitted_ = false;
60 #endif
61 }
62
63 ~JumpPatchSite() {
64 ASSERT(patch_site_.is_bound() == info_emitted_);
65 }
66
67 // When initially emitting this ensure that a jump is always generated to skip
68 // the inlined smi code.
69 void EmitJumpIfNotSmi(Register reg, Label* target) {
70 ASSERT(!patch_site_.is_bound() && !info_emitted_);
71 __ bind(&patch_site_);
72 __ cmp(reg, Operand(reg));
73 // Don't use b(al, ...) as that might emit the constant pool right after the
74 // branch. After patching when the branch is no longer unconditional
75 // execution can continue into the constant pool.
76 __ b(eq, target); // Always taken before patched.
77 }
78
79 // When initially emitting this ensure that a jump is never generated to skip
80 // the inlined smi code.
81 void EmitJumpIfSmi(Register reg, Label* target) {
82 ASSERT(!patch_site_.is_bound() && !info_emitted_);
83 __ bind(&patch_site_);
84 __ cmp(reg, Operand(reg));
85 __ b(ne, target); // Never taken before patched.
86 }
87
88 void EmitPatchInfo() {
89 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
90 Register reg;
91 reg.set_code(delta_to_patch_site / kOff12Mask);
92 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
93 #ifdef DEBUG
94 info_emitted_ = true;
95 #endif
96 }
97
98 bool is_bound() const { return patch_site_.is_bound(); }
99
100 private:
101 MacroAssembler* masm_;
102 Label patch_site_;
103 #ifdef DEBUG
104 bool info_emitted_;
105 #endif
106 };
107
108
48 // Generate code for a JS function. On entry to the function the receiver 109 // Generate code for a JS function. On entry to the function the receiver
49 // and arguments have been pushed on the stack left to right. The actual 110 // and arguments have been pushed on the stack left to right. The actual
50 // argument count matches the formal parameter count expected by the 111 // argument count matches the formal parameter count expected by the
51 // function. 112 // function.
52 // 113 //
53 // The live registers are: 114 // The live registers are:
54 // o r1: the JS function object being called (ie, ourselves) 115 // o r1: the JS function object being called (ie, ourselves)
55 // o cp: our context 116 // o cp: our context
56 // o fp: our caller's frame pointer 117 // o fp: our caller's frame pointer
57 // o sp: stack pointer 118 // o sp: stack pointer
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 // stack frame was an arguments adapter frame. 212 // stack frame was an arguments adapter frame.
152 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 213 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
153 __ CallStub(&stub); 214 __ CallStub(&stub);
154 // Duplicate the value; move-to-slot operation might clobber registers. 215 // Duplicate the value; move-to-slot operation might clobber registers.
155 __ mov(r3, r0); 216 __ mov(r3, r0);
156 Move(arguments->AsSlot(), r0, r1, r2); 217 Move(arguments->AsSlot(), r0, r1, r2);
157 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot(); 218 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
158 Move(dot_arguments_slot, r3, r1, r2); 219 Move(dot_arguments_slot, r3, r1, r2);
159 } 220 }
160 221
161 { Comment cmnt(masm_, "[ Declarations");
162 // For named function expressions, declare the function name as a
163 // constant.
164 if (scope()->is_function_scope() && scope()->function() != NULL) {
165 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
166 }
167 // Visit all the explicit declarations unless there is an illegal
168 // redeclaration.
169 if (scope()->HasIllegalRedeclaration()) {
170 scope()->VisitIllegalRedeclaration(this);
171 } else {
172 VisitDeclarations(scope()->declarations());
173 }
174 }
175
176 if (FLAG_trace) { 222 if (FLAG_trace) {
177 __ CallRuntime(Runtime::kTraceEnter, 0); 223 __ CallRuntime(Runtime::kTraceEnter, 0);
178 } 224 }
179 225
180 // Check the stack for overflow or break request. 226 // Visit the declarations and body unless there is an illegal
181 { Comment cmnt(masm_, "[ Stack check"); 227 // redeclaration.
182 PrepareForBailout(info->function(), NO_REGISTERS); 228 if (scope()->HasIllegalRedeclaration()) {
183 Label ok; 229 Comment cmnt(masm_, "[ Declarations");
184 __ LoadRoot(ip, Heap::kStackLimitRootIndex); 230 scope()->VisitIllegalRedeclaration(this);
185 __ cmp(sp, Operand(ip)); 231
186 __ b(hs, &ok); 232 } else {
187 StackCheckStub stub; 233 { Comment cmnt(masm_, "[ Declarations");
188 __ CallStub(&stub); 234 // For named function expressions, declare the function name as a
189 __ bind(&ok); 235 // constant.
236 if (scope()->is_function_scope() && scope()->function() != NULL) {
237 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
238 }
239 VisitDeclarations(scope()->declarations());
240 }
241
242 { Comment cmnt(masm_, "[ Stack check");
243 PrepareForBailout(info->function(), NO_REGISTERS);
244 Label ok;
245 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
246 __ cmp(sp, Operand(ip));
247 __ b(hs, &ok);
248 StackCheckStub stub;
249 __ CallStub(&stub);
250 __ bind(&ok);
251 }
252
253 { Comment cmnt(masm_, "[ Body");
254 ASSERT(loop_depth() == 0);
255 VisitStatements(function()->body());
256 ASSERT(loop_depth() == 0);
257 }
190 } 258 }
191 259
192 { Comment cmnt(masm_, "[ Body"); 260 // Always emit a 'return undefined' in case control fell off the end of
193 ASSERT(loop_depth() == 0); 261 // the body.
194 VisitStatements(function()->body());
195 ASSERT(loop_depth() == 0);
196 }
197
198 { Comment cmnt(masm_, "[ return <undefined>;"); 262 { Comment cmnt(masm_, "[ return <undefined>;");
199 // Emit a 'return undefined' in case control fell off the end of the
200 // body.
201 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 263 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
202 } 264 }
203 EmitReturnSequence(); 265 EmitReturnSequence();
204 266
205 // Force emit the constant pool, so it doesn't get emitted in the middle 267 // Force emit the constant pool, so it doesn't get emitted in the middle
206 // of the stack check table. 268 // of the stack check table.
207 masm()->CheckConstPool(true, false); 269 masm()->CheckConstPool(true, false);
208 } 270 }
209 271
210 272
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 #ifdef DEBUG 332 #ifdef DEBUG
271 // Check that the size of the code used for returning is large enough 333 // Check that the size of the code used for returning is large enough
272 // for the debugger's requirements. 334 // for the debugger's requirements.
273 ASSERT(Assembler::kJSReturnSequenceInstructions <= 335 ASSERT(Assembler::kJSReturnSequenceInstructions <=
274 masm_->InstructionsGeneratedSince(&check_exit_codesize)); 336 masm_->InstructionsGeneratedSince(&check_exit_codesize));
275 #endif 337 #endif
276 } 338 }
277 } 339 }
278 340
279 341
280 FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
281 Token::Value op, Expression* left, Expression* right) {
282 ASSERT(ShouldInlineSmiCase(op));
283 return kNoConstants;
284 }
285
286
287 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const { 342 void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
288 } 343 }
289 344
290 345
291 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const { 346 void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
292 codegen()->Move(result_register(), slot); 347 codegen()->Move(result_register(), slot);
293 } 348 }
294 349
295 350
296 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const { 351 void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 if (true_label_ != fall_through_) __ b(true_label_); 550 if (true_label_ != fall_through_) __ b(true_label_);
496 } else { 551 } else {
497 if (false_label_ != fall_through_) __ b(false_label_); 552 if (false_label_ != fall_through_) __ b(false_label_);
498 } 553 }
499 } 554 }
500 555
501 556
502 void FullCodeGenerator::DoTest(Label* if_true, 557 void FullCodeGenerator::DoTest(Label* if_true,
503 Label* if_false, 558 Label* if_false,
504 Label* fall_through) { 559 Label* fall_through) {
505 // Call the runtime to find the boolean value of the source and then 560 if (Isolate::Current()->cpu_features()->IsSupported(VFP3)) {
506 // translate it into control flow to the pair of labels. 561 CpuFeatures::Scope scope(VFP3);
507 __ push(result_register()); 562 // Emit the inlined tests assumed by the stub.
508 __ CallRuntime(Runtime::kToBool, 1); 563 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
509 __ LoadRoot(ip, Heap::kTrueValueRootIndex); 564 __ cmp(result_register(), ip);
510 __ cmp(r0, ip); 565 __ b(eq, if_false);
511 Split(eq, if_true, if_false, fall_through); 566 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
567 __ cmp(result_register(), ip);
568 __ b(eq, if_true);
569 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
570 __ cmp(result_register(), ip);
571 __ b(eq, if_false);
572 STATIC_ASSERT(kSmiTag == 0);
573 __ tst(result_register(), result_register());
574 __ b(eq, if_false);
575 __ JumpIfSmi(result_register(), if_true);
576
577 // Call the ToBoolean stub for all other cases.
578 ToBooleanStub stub(result_register());
579 __ CallStub(&stub);
580 __ tst(result_register(), result_register());
581 } else {
582 // Call the runtime to find the boolean value of the source and then
583 // translate it into control flow to the pair of labels.
584 __ push(result_register());
585 __ CallRuntime(Runtime::kToBool, 1);
586 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
587 __ cmp(r0, ip);
588 }
589
590 // The stub returns nonzero for true.
591 Split(ne, if_true, if_false, fall_through);
512 } 592 }
513 593
514 594
515 void FullCodeGenerator::Split(Condition cond, 595 void FullCodeGenerator::Split(Condition cond,
516 Label* if_true, 596 Label* if_true,
517 Label* if_false, 597 Label* if_false,
518 Label* fall_through) { 598 Label* fall_through) {
519 if (if_false == fall_through) { 599 if (if_false == fall_through) {
520 __ b(cond, if_true); 600 __ b(cond, if_true);
521 } else if (if_true == fall_through) { 601 } else if (if_true == fall_through) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
616 } else if (function != NULL) { 696 } else if (function != NULL) {
617 VisitForAccumulatorValue(function); 697 VisitForAccumulatorValue(function);
618 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); 698 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
619 } 699 }
620 break; 700 break;
621 701
622 case Slot::CONTEXT: 702 case Slot::CONTEXT:
623 // We bypass the general EmitSlotSearch because we know more about 703 // We bypass the general EmitSlotSearch because we know more about
624 // this specific context. 704 // this specific context.
625 705
626 // The variable in the decl always resides in the current context. 706 // The variable in the decl always resides in the current function
707 // context.
627 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope())); 708 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
628 if (FLAG_debug_code) { 709 if (FLAG_debug_code) {
629 // Check if we have the correct context pointer. 710 // Check that we're not inside a 'with'.
630 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX)); 711 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
631 __ cmp(r1, cp); 712 __ cmp(r1, cp);
632 __ Check(eq, "Unexpected declaration in current context."); 713 __ Check(eq, "Unexpected declaration in current context.");
633 } 714 }
634 if (mode == Variable::CONST) { 715 if (mode == Variable::CONST) {
635 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex); 716 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
636 __ str(ip, ContextOperand(cp, slot->index())); 717 __ str(ip, ContextOperand(cp, slot->index()));
637 // No write barrier since the_hole_value is in old space. 718 // No write barrier since the_hole_value is in old space.
638 } else if (function != NULL) { 719 } else if (function != NULL) {
639 VisitForAccumulatorValue(function); 720 VisitForAccumulatorValue(function);
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 VisitForAccumulatorValue(function); 769 VisitForAccumulatorValue(function);
689 __ pop(r2); 770 __ pop(r2);
690 } else { 771 } else {
691 __ mov(r2, r0); 772 __ mov(r2, r0);
692 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex); 773 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
693 } 774 }
694 ASSERT(prop->key()->AsLiteral() != NULL && 775 ASSERT(prop->key()->AsLiteral() != NULL &&
695 prop->key()->AsLiteral()->handle()->IsSmi()); 776 prop->key()->AsLiteral()->handle()->IsSmi());
696 __ mov(r1, Operand(prop->key()->AsLiteral()->handle())); 777 __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
697 778
698 Handle<Code> ic(isolate()->builtins()->builtin( 779 Handle<Code> ic(isolate()->builtins()->builtin(is_strict()
699 Builtins::KeyedStoreIC_Initialize)); 780 ? Builtins::KeyedStoreIC_Initialize_Strict
781 : Builtins::KeyedStoreIC_Initialize));
700 EmitCallIC(ic, RelocInfo::CODE_TARGET); 782 EmitCallIC(ic, RelocInfo::CODE_TARGET);
701 // Value in r0 is ignored (declarations are statements). 783 // Value in r0 is ignored (declarations are statements).
702 } 784 }
703 } 785 }
704 } 786 }
705 787
706 788
707 void FullCodeGenerator::VisitDeclaration(Declaration* decl) { 789 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
708 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun()); 790 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
709 } 791 }
710 792
711 793
712 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 794 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
713 // Call the runtime to declare the globals. 795 // Call the runtime to declare the globals.
714 // The context is the first argument. 796 // The context is the first argument.
715 __ mov(r1, Operand(pairs)); 797 __ mov(r2, Operand(pairs));
716 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0))); 798 __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
717 __ Push(cp, r1, r0); 799 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
718 __ CallRuntime(Runtime::kDeclareGlobals, 3); 800 __ Push(cp, r2, r1, r0);
801 __ CallRuntime(Runtime::kDeclareGlobals, 4);
719 // Return value is ignored. 802 // Return value is ignored.
720 } 803 }
721 804
722 805
723 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) { 806 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
724 Comment cmnt(masm_, "[ SwitchStatement"); 807 Comment cmnt(masm_, "[ SwitchStatement");
725 Breakable nested_statement(this, stmt); 808 Breakable nested_statement(this, stmt);
726 SetStatementPosition(stmt); 809 SetStatementPosition(stmt);
810
727 // Keep the switch value on the stack until a case matches. 811 // Keep the switch value on the stack until a case matches.
728 VisitForStackValue(stmt->tag()); 812 VisitForStackValue(stmt->tag());
729
730 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS); 813 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
731 814
732 ZoneList<CaseClause*>* clauses = stmt->cases(); 815 ZoneList<CaseClause*>* clauses = stmt->cases();
733 CaseClause* default_clause = NULL; // Can occur anywhere in the list. 816 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
734 817
735 Label next_test; // Recycled for each test. 818 Label next_test; // Recycled for each test.
736 // Compile all the tests with branches to their bodies. 819 // Compile all the tests with branches to their bodies.
737 for (int i = 0; i < clauses->length(); i++) { 820 for (int i = 0; i < clauses->length(); i++) {
738 CaseClause* clause = clauses->at(i); 821 CaseClause* clause = clauses->at(i);
739 clause->body_target()->entry_label()->Unuse(); 822 clause->body_target()->entry_label()->Unuse();
740 823
741 // The default is not a test, but remember it as final fall through. 824 // The default is not a test, but remember it as final fall through.
742 if (clause->is_default()) { 825 if (clause->is_default()) {
743 default_clause = clause; 826 default_clause = clause;
744 continue; 827 continue;
745 } 828 }
746 829
747 Comment cmnt(masm_, "[ Case comparison"); 830 Comment cmnt(masm_, "[ Case comparison");
748 __ bind(&next_test); 831 __ bind(&next_test);
749 next_test.Unuse(); 832 next_test.Unuse();
750 833
751 // Compile the label expression. 834 // Compile the label expression.
752 VisitForAccumulatorValue(clause->label()); 835 VisitForAccumulatorValue(clause->label());
753 836
754 // Perform the comparison as if via '==='. 837 // Perform the comparison as if via '==='.
755 __ ldr(r1, MemOperand(sp, 0)); // Switch value. 838 __ ldr(r1, MemOperand(sp, 0)); // Switch value.
756 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT); 839 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
840 JumpPatchSite patch_site(masm_);
757 if (inline_smi_code) { 841 if (inline_smi_code) {
758 Label slow_case; 842 Label slow_case;
759 __ orr(r2, r1, r0); 843 __ orr(r2, r1, r0);
760 __ tst(r2, Operand(kSmiTagMask)); 844 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
761 __ b(ne, &slow_case); 845
762 __ cmp(r1, r0); 846 __ cmp(r1, r0);
763 __ b(ne, &next_test); 847 __ b(ne, &next_test);
764 __ Drop(1); // Switch value is no longer needed. 848 __ Drop(1); // Switch value is no longer needed.
765 __ b(clause->body_target()->entry_label()); 849 __ b(clause->body_target()->entry_label());
766 __ bind(&slow_case); 850 __ bind(&slow_case);
767 } 851 }
768 852
769 CompareFlags flags = inline_smi_code 853 // Record position before stub call for type feedback.
770 ? NO_SMI_COMPARE_IN_STUB 854 SetSourcePosition(clause->position());
771 : NO_COMPARE_FLAGS; 855 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
772 CompareStub stub(eq, true, flags, r1, r0); 856 EmitCallIC(ic, &patch_site);
773 __ CallStub(&stub); 857 __ cmp(r0, Operand(0));
774 __ cmp(r0, Operand(0, RelocInfo::NONE));
775 __ b(ne, &next_test); 858 __ b(ne, &next_test);
776 __ Drop(1); // Switch value is no longer needed. 859 __ Drop(1); // Switch value is no longer needed.
777 __ b(clause->body_target()->entry_label()); 860 __ b(clause->body_target()->entry_label());
778 } 861 }
779 862
780 // Discard the test value and jump to the default if present, otherwise to 863 // Discard the test value and jump to the default if present, otherwise to
781 // the end of the statement. 864 // the end of the statement.
782 __ bind(&next_test); 865 __ bind(&next_test);
783 __ Drop(1); // Switch value is no longer needed. 866 __ Drop(1); // Switch value is no longer needed.
784 if (default_clause == NULL) { 867 if (default_clause == NULL) {
(...skipping 23 matching lines...) Expand all
808 ForIn loop_statement(this, stmt); 891 ForIn loop_statement(this, stmt);
809 increment_loop_depth(); 892 increment_loop_depth();
810 893
811 // Get the object to enumerate over. Both SpiderMonkey and JSC 894 // Get the object to enumerate over. Both SpiderMonkey and JSC
812 // ignore null and undefined in contrast to the specification; see 895 // ignore null and undefined in contrast to the specification; see
813 // ECMA-262 section 12.6.4. 896 // ECMA-262 section 12.6.4.
814 VisitForAccumulatorValue(stmt->enumerable()); 897 VisitForAccumulatorValue(stmt->enumerable());
815 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 898 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
816 __ cmp(r0, ip); 899 __ cmp(r0, ip);
817 __ b(eq, &exit); 900 __ b(eq, &exit);
818 __ LoadRoot(ip, Heap::kNullValueRootIndex); 901 Register null_value = r5;
819 __ cmp(r0, ip); 902 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
903 __ cmp(r0, null_value);
820 __ b(eq, &exit); 904 __ b(eq, &exit);
821 905
822 // Convert the object to a JS object. 906 // Convert the object to a JS object.
823 Label convert, done_convert; 907 Label convert, done_convert;
824 __ JumpIfSmi(r0, &convert); 908 __ JumpIfSmi(r0, &convert);
825 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE); 909 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
826 __ b(hs, &done_convert); 910 __ b(hs, &done_convert);
827 __ bind(&convert); 911 __ bind(&convert);
828 __ push(r0); 912 __ push(r0);
829 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS); 913 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
830 __ bind(&done_convert); 914 __ bind(&done_convert);
831 __ push(r0); 915 __ push(r0);
832 916
833 // BUG(867): Check cache validity in generated code. This is a fast 917 // Check cache validity in generated code. This is a fast case for
834 // case for the JSObject::IsSimpleEnum cache validity checks. If we 918 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
835 // cannot guarantee cache validity, call the runtime system to check 919 // guarantee cache validity, call the runtime system to check cache
836 // cache validity or get the property names in a fixed array. 920 // validity or get the property names in a fixed array.
921 Label next, call_runtime;
922 // Preload a couple of values used in the loop.
923 Register empty_fixed_array_value = r6;
924 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
925 Register empty_descriptor_array_value = r7;
926 __ LoadRoot(empty_descriptor_array_value,
927 Heap::kEmptyDescriptorArrayRootIndex);
928 __ mov(r1, r0);
929 __ bind(&next);
930
931 // Check that there are no elements. Register r1 contains the
932 // current JS object we've reached through the prototype chain.
933 __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
934 __ cmp(r2, empty_fixed_array_value);
935 __ b(ne, &call_runtime);
936
937 // Check that instance descriptors are not empty so that we can
938 // check for an enum cache. Leave the map in r2 for the subsequent
939 // prototype load.
940 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
941 __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOffset));
942 __ cmp(r3, empty_descriptor_array_value);
943 __ b(eq, &call_runtime);
944
945 // Check that there is an enum cache in the non-empty instance
946 // descriptors (r3). This is the case if the next enumeration
947 // index field does not contain a smi.
948 __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumerationIndexOffset));
949 __ JumpIfSmi(r3, &call_runtime);
950
951 // For all objects but the receiver, check that the cache is empty.
952 Label check_prototype;
953 __ cmp(r1, r0);
954 __ b(eq, &check_prototype);
955 __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheBridgeCacheOffset));
956 __ cmp(r3, empty_fixed_array_value);
957 __ b(ne, &call_runtime);
958
959 // Load the prototype from the map and loop if non-null.
960 __ bind(&check_prototype);
961 __ ldr(r1, FieldMemOperand(r2, Map::kPrototypeOffset));
962 __ cmp(r1, null_value);
963 __ b(ne, &next);
964
965 // The enum cache is valid. Load the map of the object being
966 // iterated over and use the cache for the iteration.
967 Label use_cache;
968 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
969 __ b(&use_cache);
837 970
838 // Get the set of properties to enumerate. 971 // Get the set of properties to enumerate.
972 __ bind(&call_runtime);
839 __ push(r0); // Duplicate the enumerable object on the stack. 973 __ push(r0); // Duplicate the enumerable object on the stack.
840 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 974 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
841 975
842 // If we got a map from the runtime call, we can do a fast 976 // If we got a map from the runtime call, we can do a fast
843 // modification check. Otherwise, we got a fixed array, and we have 977 // modification check. Otherwise, we got a fixed array, and we have
844 // to do a slow check. 978 // to do a slow check.
845 Label fixed_array; 979 Label fixed_array;
846 __ mov(r2, r0); 980 __ mov(r2, r0);
847 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset)); 981 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
848 __ LoadRoot(ip, Heap::kMetaMapRootIndex); 982 __ LoadRoot(ip, Heap::kMetaMapRootIndex);
849 __ cmp(r1, ip); 983 __ cmp(r1, ip);
850 __ b(ne, &fixed_array); 984 __ b(ne, &fixed_array);
851 985
852 // We got a map in register r0. Get the enumeration cache from it. 986 // We got a map in register r0. Get the enumeration cache from it.
987 __ bind(&use_cache);
853 __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset)); 988 __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset));
854 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset)); 989 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
855 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset)); 990 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
856 991
857 // Setup the four remaining stack slots. 992 // Setup the four remaining stack slots.
858 __ push(r0); // Map. 993 __ push(r0); // Map.
859 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset)); 994 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset));
860 __ mov(r0, Operand(Smi::FromInt(0))); 995 __ mov(r0, Operand(Smi::FromInt(0)));
861 // Push enumeration cache, enumeration cache length (as smi) and zero. 996 // Push enumeration cache, enumeration cache length (as smi) and zero.
862 __ Push(r2, r1, r0); 997 __ Push(r2, r1, r0);
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
931 1066
932 // Exit and decrement the loop depth. 1067 // Exit and decrement the loop depth.
933 __ bind(&exit); 1068 __ bind(&exit);
934 decrement_loop_depth(); 1069 decrement_loop_depth();
935 } 1070 }
936 1071
937 1072
938 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info, 1073 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
939 bool pretenure) { 1074 bool pretenure) {
940 // Use the fast case closure allocation code that allocates in new 1075 // Use the fast case closure allocation code that allocates in new
941 // space for nested functions that don't need literals cloning. 1076 // space for nested functions that don't need literals cloning. If
942 if (scope()->is_function_scope() && 1077 // we're running with the --always-opt or the --prepare-always-opt
1078 // flag, we need to use the runtime function so that the new function
1079 // we are creating here gets a chance to have its code optimized and
1080 // doesn't just get a copy of the existing unoptimized code.
1081 if (!FLAG_always_opt &&
1082 !FLAG_prepare_always_opt &&
1083 scope()->is_function_scope() &&
943 info->num_literals() == 0 && 1084 info->num_literals() == 0 &&
944 !pretenure) { 1085 !pretenure) {
945 FastNewClosureStub stub; 1086 FastNewClosureStub stub;
946 __ mov(r0, Operand(info)); 1087 __ mov(r0, Operand(info));
947 __ push(r0); 1088 __ push(r0);
948 __ CallStub(&stub); 1089 __ CallStub(&stub);
949 } else { 1090 } else {
950 __ mov(r0, Operand(info)); 1091 __ mov(r0, Operand(info));
951 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex 1092 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
952 : Heap::kFalseValueRootIndex); 1093 : Heap::kFalseValueRootIndex);
953 __ Push(cp, r0, r1); 1094 __ Push(cp, r0, r1);
954 __ CallRuntime(Runtime::kNewClosure, 3); 1095 __ CallRuntime(Runtime::kNewClosure, 3);
955 } 1096 }
956 context()->Plug(r0); 1097 context()->Plug(r0);
957 } 1098 }
958 1099
959 1100
960 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) { 1101 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
961 Comment cmnt(masm_, "[ VariableProxy"); 1102 Comment cmnt(masm_, "[ VariableProxy");
962 EmitVariableLoad(expr->var()); 1103 EmitVariableLoad(expr->var());
963 } 1104 }
964 1105
965 1106
966 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions( 1107 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
967 Slot* slot, 1108 Slot* slot,
968 Label* slow) { 1109 Label* slow) {
969 ASSERT(slot->type() == Slot::CONTEXT); 1110 ASSERT(slot->type() == Slot::CONTEXT);
970 Register current = cp; 1111 Register context = cp;
971 Register next = r3; 1112 Register next = r3;
972 Register temp = r4; 1113 Register temp = r4;
973 1114
974 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) { 1115 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
975 if (s->num_heap_slots() > 0) { 1116 if (s->num_heap_slots() > 0) {
976 if (s->calls_eval()) { 1117 if (s->calls_eval()) {
977 // Check that extension is NULL. 1118 // Check that extension is NULL.
978 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); 1119 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
979 __ tst(temp, temp); 1120 __ tst(temp, temp);
980 __ b(ne, slow); 1121 __ b(ne, slow);
981 } 1122 }
982 __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX)); 1123 __ ldr(next, ContextOperand(context, Context::CLOSURE_INDEX));
983 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset)); 1124 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
984 // Walk the rest of the chain without clobbering cp. 1125 // Walk the rest of the chain without clobbering cp.
985 current = next; 1126 context = next;
986 } 1127 }
987 } 1128 }
988 // Check that last extension is NULL. 1129 // Check that last extension is NULL.
989 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX)); 1130 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
990 __ tst(temp, temp); 1131 __ tst(temp, temp);
991 __ b(ne, slow); 1132 __ b(ne, slow);
992 __ ldr(temp, ContextOperand(current, Context::FCONTEXT_INDEX)); 1133
993 return ContextOperand(temp, slot->index()); 1134 // This function is used only for loads, not stores, so it's safe to
1135 // return an cp-based operand (the write barrier cannot be allowed to
1136 // destroy the cp register).
1137 return ContextOperand(context, slot->index());
994 } 1138 }
995 1139
996 1140
997 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase( 1141 void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
998 Slot* slot, 1142 Slot* slot,
999 TypeofState typeof_state, 1143 TypeofState typeof_state,
1000 Label* slow, 1144 Label* slow,
1001 Label* done) { 1145 Label* done) {
1002 // Generate fast-case code for variables that might be shadowed by 1146 // Generate fast-case code for variables that might be shadowed by
1003 // eval-introduced variables. Eval is used a lot without 1147 // eval-introduced variables. Eval is used a lot without
(...skipping 183 matching lines...) Expand 10 before | Expand all | Expand 10 after
1187 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1331 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1188 context()->Plug(r0); 1332 context()->Plug(r0);
1189 } 1333 }
1190 } 1334 }
1191 1335
1192 1336
1193 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) { 1337 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1194 Comment cmnt(masm_, "[ RegExpLiteral"); 1338 Comment cmnt(masm_, "[ RegExpLiteral");
1195 Label materialized; 1339 Label materialized;
1196 // Registers will be used as follows: 1340 // Registers will be used as follows:
1341 // r5 = materialized value (RegExp literal)
1197 // r4 = JS function, literals array 1342 // r4 = JS function, literals array
1198 // r3 = literal index 1343 // r3 = literal index
1199 // r2 = RegExp pattern 1344 // r2 = RegExp pattern
1200 // r1 = RegExp flags 1345 // r1 = RegExp flags
1201 // r0 = temp + materialized value (RegExp literal) 1346 // r0 = RegExp literal clone
1202 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1347 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1203 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset)); 1348 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
1204 int literal_offset = 1349 int literal_offset =
1205 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize; 1350 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1206 __ ldr(r0, FieldMemOperand(r4, literal_offset)); 1351 __ ldr(r5, FieldMemOperand(r4, literal_offset));
1207 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex); 1352 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1208 __ cmp(r0, ip); 1353 __ cmp(r5, ip);
1209 __ b(ne, &materialized); 1354 __ b(ne, &materialized);
1210 1355
1211 // Create regexp literal using runtime function. 1356 // Create regexp literal using runtime function.
1212 // Result will be in r0. 1357 // Result will be in r0.
1213 __ mov(r3, Operand(Smi::FromInt(expr->literal_index()))); 1358 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1214 __ mov(r2, Operand(expr->pattern())); 1359 __ mov(r2, Operand(expr->pattern()));
1215 __ mov(r1, Operand(expr->flags())); 1360 __ mov(r1, Operand(expr->flags()));
1216 __ Push(r4, r3, r2, r1); 1361 __ Push(r4, r3, r2, r1);
1217 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 1362 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1363 __ mov(r5, r0);
1218 1364
1219 __ bind(&materialized); 1365 __ bind(&materialized);
1220 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize; 1366 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1221 __ push(r0); 1367 Label allocated, runtime_allocate;
1368 __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
1369 __ jmp(&allocated);
1370
1371 __ bind(&runtime_allocate);
1372 __ push(r5);
1222 __ mov(r0, Operand(Smi::FromInt(size))); 1373 __ mov(r0, Operand(Smi::FromInt(size)));
1223 __ push(r0); 1374 __ push(r0);
1224 __ CallRuntime(Runtime::kAllocateInNewSpace, 1); 1375 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1376 __ pop(r5);
1225 1377
1378 __ bind(&allocated);
1226 // After this, registers are used as follows: 1379 // After this, registers are used as follows:
1227 // r0: Newly allocated regexp. 1380 // r0: Newly allocated regexp.
1228 // r1: Materialized regexp. 1381 // r5: Materialized regexp.
1229 // r2: temp. 1382 // r2: temp.
1230 __ pop(r1); 1383 __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
1231 __ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
1232 context()->Plug(r0); 1384 context()->Plug(r0);
1233 } 1385 }
1234 1386
1235 1387
1236 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) { 1388 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1237 Comment cmnt(masm_, "[ ObjectLiteral"); 1389 Comment cmnt(masm_, "[ ObjectLiteral");
1238 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset)); 1390 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1239 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset)); 1391 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1240 __ mov(r2, Operand(Smi::FromInt(expr->literal_index()))); 1392 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1241 __ mov(r1, Operand(expr->constant_properties())); 1393 __ mov(r1, Operand(expr->constant_properties()));
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1288 break; 1440 break;
1289 } 1441 }
1290 // Fall through. 1442 // Fall through.
1291 case ObjectLiteral::Property::PROTOTYPE: 1443 case ObjectLiteral::Property::PROTOTYPE:
1292 // Duplicate receiver on stack. 1444 // Duplicate receiver on stack.
1293 __ ldr(r0, MemOperand(sp)); 1445 __ ldr(r0, MemOperand(sp));
1294 __ push(r0); 1446 __ push(r0);
1295 VisitForStackValue(key); 1447 VisitForStackValue(key);
1296 VisitForStackValue(value); 1448 VisitForStackValue(value);
1297 if (property->emit_store()) { 1449 if (property->emit_store()) {
1298 __ CallRuntime(Runtime::kSetProperty, 3); 1450 __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1451 __ push(r0);
1452 __ CallRuntime(Runtime::kSetProperty, 4);
1299 } else { 1453 } else {
1300 __ Drop(3); 1454 __ Drop(3);
1301 } 1455 }
1302 break; 1456 break;
1303 case ObjectLiteral::Property::GETTER: 1457 case ObjectLiteral::Property::GETTER:
1304 case ObjectLiteral::Property::SETTER: 1458 case ObjectLiteral::Property::SETTER:
1305 // Duplicate receiver on stack. 1459 // Duplicate receiver on stack.
1306 __ ldr(r0, MemOperand(sp)); 1460 __ ldr(r0, MemOperand(sp));
1307 __ push(r0); 1461 __ push(r0);
1308 VisitForStackValue(key); 1462 VisitForStackValue(key);
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1468 } 1622 }
1469 } 1623 }
1470 1624
1471 // For property compound assignments we need another deoptimization 1625 // For property compound assignments we need another deoptimization
1472 // point after the property load. 1626 // point after the property load.
1473 if (property != NULL) { 1627 if (property != NULL) {
1474 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG); 1628 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
1475 } 1629 }
1476 1630
1477 Token::Value op = expr->binary_op(); 1631 Token::Value op = expr->binary_op();
1478 ConstantOperand constant = ShouldInlineSmiCase(op) 1632 __ push(r0); // Left operand goes on the stack.
1479 ? GetConstantOperand(op, expr->target(), expr->value()) 1633 VisitForAccumulatorValue(expr->value());
1480 : kNoConstants;
1481 ASSERT(constant == kRightConstant || constant == kNoConstants);
1482 if (constant == kNoConstants) {
1483 __ push(r0); // Left operand goes on the stack.
1484 VisitForAccumulatorValue(expr->value());
1485 }
1486 1634
1487 OverwriteMode mode = expr->value()->ResultOverwriteAllowed() 1635 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1488 ? OVERWRITE_RIGHT 1636 ? OVERWRITE_RIGHT
1489 : NO_OVERWRITE; 1637 : NO_OVERWRITE;
1490 SetSourcePosition(expr->position() + 1); 1638 SetSourcePosition(expr->position() + 1);
1491 AccumulatorValueContext context(this); 1639 AccumulatorValueContext context(this);
1492 if (ShouldInlineSmiCase(op)) { 1640 if (ShouldInlineSmiCase(op)) {
1493 EmitInlineSmiBinaryOp(expr, 1641 EmitInlineSmiBinaryOp(expr,
1494 op, 1642 op,
1495 mode, 1643 mode,
1496 expr->target(), 1644 expr->target(),
1497 expr->value(), 1645 expr->value());
1498 constant);
1499 } else { 1646 } else {
1500 EmitBinaryOp(op, mode); 1647 EmitBinaryOp(op, mode);
1501 } 1648 }
1502 1649
1503 // Deoptimization point in case the binary operation may have side effects. 1650 // Deoptimization point in case the binary operation may have side effects.
1504 PrepareForBailout(expr->binary_operation(), TOS_REG); 1651 PrepareForBailout(expr->binary_operation(), TOS_REG);
1505 } else { 1652 } else {
1506 VisitForAccumulatorValue(expr->value()); 1653 VisitForAccumulatorValue(expr->value());
1507 } 1654 }
1508 1655
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1543 // Call keyed load IC. It has arguments key and receiver in r0 and r1. 1690 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
1544 Handle<Code> ic(isolate()->builtins()->builtin( 1691 Handle<Code> ic(isolate()->builtins()->builtin(
1545 Builtins::KeyedLoadIC_Initialize)); 1692 Builtins::KeyedLoadIC_Initialize));
1546 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1693 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1547 } 1694 }
1548 1695
1549 1696
1550 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr, 1697 void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1551 Token::Value op, 1698 Token::Value op,
1552 OverwriteMode mode, 1699 OverwriteMode mode,
1553 Expression* left, 1700 Expression* left_expr,
1554 Expression* right, 1701 Expression* right_expr) {
1555 ConstantOperand constant) { 1702 Label done, smi_case, stub_call;
1556 ASSERT(constant == kNoConstants); // Only handled case. 1703
1557 EmitBinaryOp(op, mode); 1704 Register scratch1 = r2;
1705 Register scratch2 = r3;
1706
1707 // Get the arguments.
1708 Register left = r1;
1709 Register right = r0;
1710 __ pop(left);
1711
1712 // Perform combined smi check on both operands.
1713 __ orr(scratch1, left, Operand(right));
1714 STATIC_ASSERT(kSmiTag == 0);
1715 JumpPatchSite patch_site(masm_);
1716 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1717
1718 __ bind(&stub_call);
1719 TypeRecordingBinaryOpStub stub(op, mode);
1720 EmitCallIC(stub.GetCode(), &patch_site);
1721 __ jmp(&done);
1722
1723 __ bind(&smi_case);
1724 // Smi case. This code works the same way as the smi-smi case in the type
1725 // recording binary operation stub, see
1726 // TypeRecordingBinaryOpStub::GenerateSmiSmiOperation for comments.
1727 switch (op) {
1728 case Token::SAR:
1729 __ b(&stub_call);
1730 __ GetLeastBitsFromSmi(scratch1, right, 5);
1731 __ mov(right, Operand(left, ASR, scratch1));
1732 __ bic(right, right, Operand(kSmiTagMask));
1733 break;
1734 case Token::SHL: {
1735 __ b(&stub_call);
1736 __ SmiUntag(scratch1, left);
1737 __ GetLeastBitsFromSmi(scratch2, right, 5);
1738 __ mov(scratch1, Operand(scratch1, LSL, scratch2));
1739 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
1740 __ b(mi, &stub_call);
1741 __ SmiTag(right, scratch1);
1742 break;
1743 }
1744 case Token::SHR: {
1745 __ b(&stub_call);
1746 __ SmiUntag(scratch1, left);
1747 __ GetLeastBitsFromSmi(scratch2, right, 5);
1748 __ mov(scratch1, Operand(scratch1, LSR, scratch2));
1749 __ tst(scratch1, Operand(0xc0000000));
1750 __ b(ne, &stub_call);
1751 __ SmiTag(right, scratch1);
1752 break;
1753 }
1754 case Token::ADD:
1755 __ add(scratch1, left, Operand(right), SetCC);
1756 __ b(vs, &stub_call);
1757 __ mov(right, scratch1);
1758 break;
1759 case Token::SUB:
1760 __ sub(scratch1, left, Operand(right), SetCC);
1761 __ b(vs, &stub_call);
1762 __ mov(right, scratch1);
1763 break;
1764 case Token::MUL: {
1765 __ SmiUntag(ip, right);
1766 __ smull(scratch1, scratch2, left, ip);
1767 __ mov(ip, Operand(scratch1, ASR, 31));
1768 __ cmp(ip, Operand(scratch2));
1769 __ b(ne, &stub_call);
1770 __ tst(scratch1, Operand(scratch1));
1771 __ mov(right, Operand(scratch1), LeaveCC, ne);
1772 __ b(ne, &done);
1773 __ add(scratch2, right, Operand(left), SetCC);
1774 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
1775 __ b(mi, &stub_call);
1776 break;
1777 }
1778 case Token::BIT_OR:
1779 __ orr(right, left, Operand(right));
1780 break;
1781 case Token::BIT_AND:
1782 __ and_(right, left, Operand(right));
1783 break;
1784 case Token::BIT_XOR:
1785 __ eor(right, left, Operand(right));
1786 break;
1787 default:
1788 UNREACHABLE();
1789 }
1790
1791 __ bind(&done);
1792 context()->Plug(r0);
1558 } 1793 }
1559 1794
1560 1795
1561 void FullCodeGenerator::EmitBinaryOp(Token::Value op, 1796 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1562 OverwriteMode mode) { 1797 OverwriteMode mode) {
1563 __ pop(r1); 1798 __ pop(r1);
1564 if (op == Token::ADD || 1799 TypeRecordingBinaryOpStub stub(op, mode);
1565 op == Token::SUB || 1800 EmitCallIC(stub.GetCode(), NULL);
1566 op == Token::MUL ||
1567 op == Token::DIV ||
1568 op == Token::MOD ||
1569 op == Token::BIT_OR ||
1570 op == Token::BIT_AND ||
1571 op == Token::BIT_XOR) {
1572 TypeRecordingBinaryOpStub stub(op, mode);
1573 __ CallStub(&stub);
1574 } else {
1575 GenericBinaryOpStub stub(op, mode, r1, r0);
1576 __ CallStub(&stub);
1577 }
1578 context()->Plug(r0); 1801 context()->Plug(r0);
1579 } 1802 }
1580 1803
1581 1804
1582 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) { 1805 void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
1583 // Invalid left-hand sides are rewritten to have a 'throw 1806 // Invalid left-hand sides are rewritten to have a 'throw
1584 // ReferenceError' on the left-hand side. 1807 // ReferenceError' on the left-hand side.
1585 if (!expr->IsValidLeftHandSide()) { 1808 if (!expr->IsValidLeftHandSide()) {
1586 VisitForEffect(expr); 1809 VisitForEffect(expr);
1587 return; 1810 return;
(...skipping 17 matching lines...) Expand all
1605 EmitVariableAssignment(var, Token::ASSIGN); 1828 EmitVariableAssignment(var, Token::ASSIGN);
1606 break; 1829 break;
1607 } 1830 }
1608 case NAMED_PROPERTY: { 1831 case NAMED_PROPERTY: {
1609 __ push(r0); // Preserve value. 1832 __ push(r0); // Preserve value.
1610 VisitForAccumulatorValue(prop->obj()); 1833 VisitForAccumulatorValue(prop->obj());
1611 __ mov(r1, r0); 1834 __ mov(r1, r0);
1612 __ pop(r0); // Restore value. 1835 __ pop(r0); // Restore value.
1613 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 1836 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1614 Handle<Code> ic(isolate()->builtins()->builtin( 1837 Handle<Code> ic(isolate()->builtins()->builtin(
1615 Builtins::StoreIC_Initialize)); 1838 is_strict() ? Builtins::StoreIC_Initialize_Strict
1839 : Builtins::StoreIC_Initialize));
1616 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1840 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1617 break; 1841 break;
1618 } 1842 }
1619 case KEYED_PROPERTY: { 1843 case KEYED_PROPERTY: {
1620 __ push(r0); // Preserve value. 1844 __ push(r0); // Preserve value.
1621 VisitForStackValue(prop->obj()); 1845 if (prop->is_synthetic()) {
1622 VisitForAccumulatorValue(prop->key()); 1846 ASSERT(prop->obj()->AsVariableProxy() != NULL);
1623 __ mov(r1, r0); 1847 ASSERT(prop->key()->AsLiteral() != NULL);
1624 __ pop(r2); 1848 { AccumulatorValueContext for_object(this);
1849 EmitVariableLoad(prop->obj()->AsVariableProxy()->var());
1850 }
1851 __ mov(r2, r0);
1852 __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
1853 } else {
1854 VisitForStackValue(prop->obj());
1855 VisitForAccumulatorValue(prop->key());
1856 __ mov(r1, r0);
1857 __ pop(r2);
1858 }
1625 __ pop(r0); // Restore value. 1859 __ pop(r0); // Restore value.
1626 Handle<Code> ic(isolate()->builtins()->builtin( 1860 Handle<Code> ic(isolate()->builtins()->builtin(
1627 Builtins::KeyedStoreIC_Initialize)); 1861 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
1862 : Builtins::KeyedStoreIC_Initialize));
1628 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1863 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1629 break; 1864 break;
1630 } 1865 }
1631 } 1866 }
1632 PrepareForBailoutForId(bailout_ast_id, TOS_REG); 1867 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1633 context()->Plug(r0); 1868 context()->Plug(r0);
1634 } 1869 }
1635 1870
1636 1871
1637 void FullCodeGenerator::EmitVariableAssignment(Variable* var, 1872 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
1638 Token::Value op) { 1873 Token::Value op) {
1639 // Left-hand sides that rewrite to explicit property accesses do not reach 1874 // Left-hand sides that rewrite to explicit property accesses do not reach
1640 // here. 1875 // here.
1641 ASSERT(var != NULL); 1876 ASSERT(var != NULL);
1642 ASSERT(var->is_global() || var->AsSlot() != NULL); 1877 ASSERT(var->is_global() || var->AsSlot() != NULL);
1643 1878
1644 if (var->is_global()) { 1879 if (var->is_global()) {
1645 ASSERT(!var->is_this()); 1880 ASSERT(!var->is_this());
1646 // Assignment to a global variable. Use inline caching for the 1881 // Assignment to a global variable. Use inline caching for the
1647 // assignment. Right-hand-side value is passed in r0, variable name in 1882 // assignment. Right-hand-side value is passed in r0, variable name in
1648 // r2, and the global object in r1. 1883 // r2, and the global object in r1.
1649 __ mov(r2, Operand(var->name())); 1884 __ mov(r2, Operand(var->name()));
1650 __ ldr(r1, GlobalObjectOperand()); 1885 __ ldr(r1, GlobalObjectOperand());
1651 Handle<Code> ic(isolate()->builtins()->builtin( 1886 Handle<Code> ic(isolate()->builtins()->builtin(
1652 Builtins::StoreIC_Initialize)); 1887 is_strict() ? Builtins::StoreIC_Initialize_Strict
1653 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1888 : Builtins::StoreIC_Initialize));
1889 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
1654 1890
1655 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) { 1891 } else if (op == Token::INIT_CONST) {
1656 // Perform the assignment for non-const variables and for initialization 1892 // Like var declarations, const declarations are hoisted to function
1657 // of const variables. Const assignments are simply skipped. 1893 // scope. However, unlike var initializers, const initializers are able
1658 Label done; 1894 // to drill a hole to that function context, even from inside a 'with'
1895 // context. We thus bypass the normal static scope lookup.
1896 Slot* slot = var->AsSlot();
1897 Label skip;
1898 switch (slot->type()) {
1899 case Slot::PARAMETER:
1900 // No const parameters.
1901 UNREACHABLE();
1902 break;
1903 case Slot::LOCAL:
1904 // Detect const reinitialization by checking for the hole value.
1905 __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1906 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1907 __ cmp(r1, ip);
1908 __ b(ne, &skip);
1909 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1910 break;
1911 case Slot::CONTEXT: {
1912 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
1913 __ ldr(r2, ContextOperand(r1, slot->index()));
1914 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1915 __ cmp(r2, ip);
1916 __ b(ne, &skip);
1917 __ str(r0, ContextOperand(r1, slot->index()));
1918 int offset = Context::SlotOffset(slot->index());
1919 __ mov(r3, r0); // Preserve the stored value in r0.
1920 __ RecordWrite(r1, Operand(offset), r3, r2);
1921 break;
1922 }
1923 case Slot::LOOKUP:
1924 __ push(r0);
1925 __ mov(r0, Operand(slot->var()->name()));
1926 __ Push(cp, r0); // Context and name.
1927 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1928 break;
1929 }
1930 __ bind(&skip);
1931
1932 } else if (var->mode() != Variable::CONST) {
1933 // Perform the assignment for non-const variables. Const assignments
1934 // are simply skipped.
1659 Slot* slot = var->AsSlot(); 1935 Slot* slot = var->AsSlot();
1660 switch (slot->type()) { 1936 switch (slot->type()) {
1661 case Slot::PARAMETER: 1937 case Slot::PARAMETER:
1662 case Slot::LOCAL: 1938 case Slot::LOCAL:
1663 if (op == Token::INIT_CONST) {
1664 // Detect const reinitialization by checking for the hole value.
1665 __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1666 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1667 __ cmp(r1, ip);
1668 __ b(ne, &done);
1669 }
1670 // Perform the assignment. 1939 // Perform the assignment.
1671 __ str(result_register(), MemOperand(fp, SlotOffset(slot))); 1940 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1672 break; 1941 break;
1673 1942
1674 case Slot::CONTEXT: { 1943 case Slot::CONTEXT: {
1675 MemOperand target = EmitSlotSearch(slot, r1); 1944 MemOperand target = EmitSlotSearch(slot, r1);
1676 if (op == Token::INIT_CONST) {
1677 // Detect const reinitialization by checking for the hole value.
1678 __ ldr(r2, target);
1679 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1680 __ cmp(r2, ip);
1681 __ b(ne, &done);
1682 }
1683 // Perform the assignment and issue the write barrier. 1945 // Perform the assignment and issue the write barrier.
1684 __ str(result_register(), target); 1946 __ str(result_register(), target);
1685 // RecordWrite may destroy all its register arguments. 1947 // RecordWrite may destroy all its register arguments.
1686 __ mov(r3, result_register()); 1948 __ mov(r3, result_register());
1687 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 1949 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1688 __ RecordWrite(r1, Operand(offset), r2, r3); 1950 __ RecordWrite(r1, Operand(offset), r2, r3);
1689 break; 1951 break;
1690 } 1952 }
1691 1953
1692 case Slot::LOOKUP: 1954 case Slot::LOOKUP:
1693 // Call the runtime for the assignment. The runtime will ignore 1955 // Call the runtime for the assignment.
1694 // const reinitialization.
1695 __ push(r0); // Value. 1956 __ push(r0); // Value.
1696 __ mov(r0, Operand(slot->var()->name())); 1957 __ mov(r1, Operand(slot->var()->name()));
1697 __ Push(cp, r0); // Context and name. 1958 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
1698 if (op == Token::INIT_CONST) { 1959 __ Push(cp, r1, r0); // Context, name, strict mode.
1699 // The runtime will ignore const redeclaration. 1960 __ CallRuntime(Runtime::kStoreContextSlot, 4);
1700 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1701 } else {
1702 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1703 }
1704 break; 1961 break;
1705 } 1962 }
1706 __ bind(&done);
1707 } 1963 }
1708 } 1964 }
1709 1965
1710 1966
1711 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) { 1967 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1712 // Assignment to a property, using a named store IC. 1968 // Assignment to a property, using a named store IC.
1713 Property* prop = expr->target()->AsProperty(); 1969 Property* prop = expr->target()->AsProperty();
1714 ASSERT(prop != NULL); 1970 ASSERT(prop != NULL);
1715 ASSERT(prop->key()->AsLiteral() != NULL); 1971 ASSERT(prop->key()->AsLiteral() != NULL);
1716 1972
(...skipping 13 matching lines...) Expand all
1730 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 1986 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1731 // Load receiver to r1. Leave a copy in the stack if needed for turning the 1987 // Load receiver to r1. Leave a copy in the stack if needed for turning the
1732 // receiver into fast case. 1988 // receiver into fast case.
1733 if (expr->ends_initialization_block()) { 1989 if (expr->ends_initialization_block()) {
1734 __ ldr(r1, MemOperand(sp)); 1990 __ ldr(r1, MemOperand(sp));
1735 } else { 1991 } else {
1736 __ pop(r1); 1992 __ pop(r1);
1737 } 1993 }
1738 1994
1739 Handle<Code> ic(isolate()->builtins()->builtin( 1995 Handle<Code> ic(isolate()->builtins()->builtin(
1740 Builtins::StoreIC_Initialize)); 1996 is_strict() ? Builtins::StoreIC_Initialize_Strict
1997 : Builtins::StoreIC_Initialize));
1741 EmitCallIC(ic, RelocInfo::CODE_TARGET); 1998 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1742 1999
1743 // If the assignment ends an initialization block, revert to fast case. 2000 // If the assignment ends an initialization block, revert to fast case.
1744 if (expr->ends_initialization_block()) { 2001 if (expr->ends_initialization_block()) {
1745 __ push(r0); // Result of assignment, saved even if not needed. 2002 __ push(r0); // Result of assignment, saved even if not needed.
1746 // Receiver is under the result value. 2003 // Receiver is under the result value.
1747 __ ldr(ip, MemOperand(sp, kPointerSize)); 2004 __ ldr(ip, MemOperand(sp, kPointerSize));
1748 __ push(ip); 2005 __ push(ip);
1749 __ CallRuntime(Runtime::kToFastProperties, 1); 2006 __ CallRuntime(Runtime::kToFastProperties, 1);
1750 __ pop(r0); 2007 __ pop(r0);
(...skipping 24 matching lines...) Expand all
1775 __ pop(r1); // Key. 2032 __ pop(r1); // Key.
1776 // Load receiver to r2. Leave a copy in the stack if needed for turning the 2033 // Load receiver to r2. Leave a copy in the stack if needed for turning the
1777 // receiver into fast case. 2034 // receiver into fast case.
1778 if (expr->ends_initialization_block()) { 2035 if (expr->ends_initialization_block()) {
1779 __ ldr(r2, MemOperand(sp)); 2036 __ ldr(r2, MemOperand(sp));
1780 } else { 2037 } else {
1781 __ pop(r2); 2038 __ pop(r2);
1782 } 2039 }
1783 2040
1784 Handle<Code> ic(isolate()->builtins()->builtin( 2041 Handle<Code> ic(isolate()->builtins()->builtin(
1785 Builtins::KeyedStoreIC_Initialize)); 2042 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
2043 : Builtins::KeyedStoreIC_Initialize));
1786 EmitCallIC(ic, RelocInfo::CODE_TARGET); 2044 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1787 2045
1788 // If the assignment ends an initialization block, revert to fast case. 2046 // If the assignment ends an initialization block, revert to fast case.
1789 if (expr->ends_initialization_block()) { 2047 if (expr->ends_initialization_block()) {
1790 __ push(r0); // Result of assignment, saved even if not needed. 2048 __ push(r0); // Result of assignment, saved even if not needed.
1791 // Receiver is under the result value. 2049 // Receiver is under the result value.
1792 __ ldr(ip, MemOperand(sp, kPointerSize)); 2050 __ ldr(ip, MemOperand(sp, kPointerSize));
1793 __ push(ip); 2051 __ push(ip);
1794 __ CallRuntime(Runtime::kToFastProperties, 1); 2052 __ CallRuntime(Runtime::kToFastProperties, 1);
1795 __ pop(r0); 2053 __ pop(r0);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1892 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 2150 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1893 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2151 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1894 __ CallStub(&stub); 2152 __ CallStub(&stub);
1895 RecordJSReturnSite(expr); 2153 RecordJSReturnSite(expr);
1896 // Restore context register. 2154 // Restore context register.
1897 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset)); 2155 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1898 context()->DropAndPlug(1, r0); 2156 context()->DropAndPlug(1, r0);
1899 } 2157 }
1900 2158
1901 2159
2160 void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2161 int arg_count) {
2162 // Push copy of the first argument or undefined if it doesn't exist.
2163 if (arg_count > 0) {
2164 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
2165 } else {
2166 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
2167 }
2168 __ push(r1);
2169
2170 // Push the receiver of the enclosing function and do runtime call.
2171 __ ldr(r1, MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
2172 __ push(r1);
2173 // Push the strict mode flag.
2174 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
2175 __ push(r1);
2176
2177 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2178 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2179 : Runtime::kResolvePossiblyDirectEval, 4);
2180 }
2181
2182
1902 void FullCodeGenerator::VisitCall(Call* expr) { 2183 void FullCodeGenerator::VisitCall(Call* expr) {
1903 #ifdef DEBUG 2184 #ifdef DEBUG
1904 // We want to verify that RecordJSReturnSite gets called on all paths 2185 // We want to verify that RecordJSReturnSite gets called on all paths
1905 // through this function. Avoid early returns. 2186 // through this function. Avoid early returns.
1906 expr->return_is_recorded_ = false; 2187 expr->return_is_recorded_ = false;
1907 #endif 2188 #endif
1908 2189
1909 Comment cmnt(masm_, "[ Call"); 2190 Comment cmnt(masm_, "[ Call");
1910 Expression* fun = expr->expression(); 2191 Expression* fun = expr->expression();
1911 Variable* var = fun->AsVariableProxy()->AsVariable(); 2192 Variable* var = fun->AsVariableProxy()->AsVariable();
1912 2193
1913 if (var != NULL && var->is_possibly_eval()) { 2194 if (var != NULL && var->is_possibly_eval()) {
1914 // In a call to eval, we first call %ResolvePossiblyDirectEval to 2195 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1915 // resolve the function we need to call and the receiver of the 2196 // resolve the function we need to call and the receiver of the
1916 // call. Then we call the resolved function using the given 2197 // call. Then we call the resolved function using the given
1917 // arguments. 2198 // arguments.
1918 ZoneList<Expression*>* args = expr->arguments(); 2199 ZoneList<Expression*>* args = expr->arguments();
1919 int arg_count = args->length(); 2200 int arg_count = args->length();
1920 2201
1921 { PreservePositionScope pos_scope(masm()->positions_recorder()); 2202 { PreservePositionScope pos_scope(masm()->positions_recorder());
1922 VisitForStackValue(fun); 2203 VisitForStackValue(fun);
1923 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex); 2204 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
1924 __ push(r2); // Reserved receiver slot. 2205 __ push(r2); // Reserved receiver slot.
1925 2206
1926 // Push the arguments. 2207 // Push the arguments.
1927 for (int i = 0; i < arg_count; i++) { 2208 for (int i = 0; i < arg_count; i++) {
1928 VisitForStackValue(args->at(i)); 2209 VisitForStackValue(args->at(i));
1929 } 2210 }
1930 2211
1931 // Push copy of the function - found below the arguments. 2212 // If we know that eval can only be shadowed by eval-introduced
2213 // variables we attempt to load the global eval function directly
2214 // in generated code. If we succeed, there is no need to perform a
2215 // context lookup in the runtime system.
2216 Label done;
2217 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2218 Label slow;
2219 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2220 NOT_INSIDE_TYPEOF,
2221 &slow);
2222 // Push the function and resolve eval.
2223 __ push(r0);
2224 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2225 __ jmp(&done);
2226 __ bind(&slow);
2227 }
2228
2229 // Push copy of the function (found below the arguments) and
2230 // resolve eval.
1932 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2231 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
1933 __ push(r1); 2232 __ push(r1);
1934 2233 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
1935 // Push copy of the first argument or undefined if it doesn't exist. 2234 if (done.is_linked()) {
1936 if (arg_count > 0) { 2235 __ bind(&done);
1937 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
1938 __ push(r1);
1939 } else {
1940 __ push(r2);
1941 } 2236 }
1942 2237
1943 // Push the receiver of the enclosing function and do runtime call.
1944 __ ldr(r1,
1945 MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
1946 __ push(r1);
1947 // Push the strict mode flag.
1948 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
1949 __ push(r1);
1950 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 4);
1951
1952 // The runtime call returns a pair of values in r0 (function) and 2238 // The runtime call returns a pair of values in r0 (function) and
1953 // r1 (receiver). Touch up the stack with the right values. 2239 // r1 (receiver). Touch up the stack with the right values.
1954 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize)); 2240 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
1955 __ str(r1, MemOperand(sp, arg_count * kPointerSize)); 2241 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
1956 } 2242 }
1957 2243
1958 // Record source position for debugger. 2244 // Record source position for debugger.
1959 SetSourcePosition(expr->position()); 2245 SetSourcePosition(expr->position());
1960 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP; 2246 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1961 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE); 2247 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
(...skipping 795 matching lines...) Expand 10 before | Expand all | Expand 10 after
2757 VisitForStackValue(args->at(0)); 3043 VisitForStackValue(args->at(0));
2758 VisitForStackValue(args->at(1)); 3044 VisitForStackValue(args->at(1));
2759 3045
2760 StringCompareStub stub; 3046 StringCompareStub stub;
2761 __ CallStub(&stub); 3047 __ CallStub(&stub);
2762 context()->Plug(r0); 3048 context()->Plug(r0);
2763 } 3049 }
2764 3050
2765 3051
2766 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) { 3052 void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2767 // Load the argument on the stack and call the runtime. 3053 // Load the argument on the stack and call the stub.
3054 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3055 TranscendentalCacheStub::TAGGED);
2768 ASSERT(args->length() == 1); 3056 ASSERT(args->length() == 1);
2769 VisitForStackValue(args->at(0)); 3057 VisitForStackValue(args->at(0));
2770 __ CallRuntime(Runtime::kMath_sin, 1); 3058 __ CallStub(&stub);
2771 context()->Plug(r0); 3059 context()->Plug(r0);
2772 } 3060 }
2773 3061
2774 3062
2775 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) { 3063 void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2776 // Load the argument on the stack and call the runtime. 3064 // Load the argument on the stack and call the stub.
3065 TranscendentalCacheStub stub(TranscendentalCache::COS,
3066 TranscendentalCacheStub::TAGGED);
2777 ASSERT(args->length() == 1); 3067 ASSERT(args->length() == 1);
2778 VisitForStackValue(args->at(0)); 3068 VisitForStackValue(args->at(0));
2779 __ CallRuntime(Runtime::kMath_cos, 1); 3069 __ CallStub(&stub);
3070 context()->Plug(r0);
3071 }
3072
3073
3074 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3075 // Load the argument on the stack and call the stub.
3076 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3077 TranscendentalCacheStub::TAGGED);
3078 ASSERT(args->length() == 1);
3079 VisitForStackValue(args->at(0));
3080 __ CallStub(&stub);
2780 context()->Plug(r0); 3081 context()->Plug(r0);
2781 } 3082 }
2782 3083
2783 3084
2784 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) { 3085 void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2785 // Load the argument on the stack and call the runtime function. 3086 // Load the argument on the stack and call the runtime function.
2786 ASSERT(args->length() == 1); 3087 ASSERT(args->length() == 1);
2787 VisitForStackValue(args->at(0)); 3088 VisitForStackValue(args->at(0));
2788 __ CallRuntime(Runtime::kMath_sqrt, 1); 3089 __ CallRuntime(Runtime::kMath_sqrt, 1);
2789 context()->Plug(r0); 3090 context()->Plug(r0);
2790 } 3091 }
2791 3092
2792
2793 void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
2794 // Load the argument on the stack and call the runtime function.
2795 ASSERT(args->length() == 1);
2796 VisitForStackValue(args->at(0));
2797 __ CallRuntime(Runtime::kMath_log, 1);
2798 context()->Plug(r0);
2799 }
2800
2801 3093
2802 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) { 3094 void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2803 ASSERT(args->length() >= 2); 3095 ASSERT(args->length() >= 2);
2804 3096
2805 int arg_count = args->length() - 2; // For receiver and function. 3097 int arg_count = args->length() - 2; // For receiver and function.
2806 VisitForStackValue(args->at(0)); // Receiver. 3098 VisitForStackValue(args->at(0)); // Receiver.
2807 for (int i = 0; i < arg_count; i++) { 3099 for (int i = 0; i < arg_count; i++) {
2808 VisitForStackValue(args->at(i + 1)); 3100 VisitForStackValue(args->at(i + 1));
2809 } 3101 }
2810 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function. 3102 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
(...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after
2946 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 3238 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2947 Split(eq, if_true, if_false, fall_through); 3239 Split(eq, if_true, if_false, fall_through);
2948 3240
2949 context()->Plug(if_true, if_false); 3241 context()->Plug(if_true, if_false);
2950 } 3242 }
2951 3243
2952 3244
2953 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) { 3245 void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
2954 ASSERT(args->length() == 1); 3246 ASSERT(args->length() == 1);
2955 VisitForAccumulatorValue(args->at(0)); 3247 VisitForAccumulatorValue(args->at(0));
3248
3249 if (FLAG_debug_code) {
3250 __ AbortIfNotString(r0);
3251 }
3252
2956 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset)); 3253 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
2957 __ IndexFromHash(r0, r0); 3254 __ IndexFromHash(r0, r0);
3255
2958 context()->Plug(r0); 3256 context()->Plug(r0);
2959 } 3257 }
2960 3258
2961 3259
2962 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) { 3260 void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
3261 Label bailout, done, one_char_separator, long_separator,
3262 non_trivial_array, not_size_one_array, loop,
3263 empty_separator_loop, one_char_separator_loop,
3264 one_char_separator_loop_entry, long_separator_loop;
3265
3266 ASSERT(args->length() == 2);
3267 VisitForStackValue(args->at(1));
3268 VisitForAccumulatorValue(args->at(0));
3269
3270 // All aliases of the same register have disjoint lifetimes.
3271 Register array = r0;
3272 Register elements = no_reg; // Will be r0.
3273 Register result = no_reg; // Will be r0.
3274 Register separator = r1;
3275 Register array_length = r2;
3276 Register result_pos = no_reg; // Will be r2
3277 Register string_length = r3;
3278 Register string = r4;
3279 Register element = r5;
3280 Register elements_end = r6;
3281 Register scratch1 = r7;
3282 Register scratch2 = r9;
3283
3284 // Separator operand is on the stack.
3285 __ pop(separator);
3286
3287 // Check that the array is a JSArray.
3288 __ JumpIfSmi(array, &bailout);
3289 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
3290 __ b(ne, &bailout);
3291
3292 // Check that the array has fast elements.
3293 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitField2Offset));
3294 __ tst(scratch2, Operand(1 << Map::kHasFastElements));
3295 __ b(eq, &bailout);
3296
3297 // If the array has length zero, return the empty string.
3298 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3299 __ SmiUntag(array_length, SetCC);
3300 __ b(ne, &non_trivial_array);
3301 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
3302 __ b(&done);
3303
3304 __ bind(&non_trivial_array);
3305
3306 // Get the FixedArray containing array's elements.
3307 elements = array;
3308 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3309 array = no_reg; // End of array's live range.
3310
3311 // Check that all array elements are sequential ASCII strings, and
3312 // accumulate the sum of their lengths, as a smi-encoded value.
3313 __ mov(string_length, Operand(0));
3314 __ add(element,
3315 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3316 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3317 // Loop condition: while (element < elements_end).
3318 // Live values in registers:
3319 // elements: Fixed array of strings.
3320 // array_length: Length of the fixed array of strings (not smi)
3321 // separator: Separator string
3322 // string_length: Accumulated sum of string lengths (smi).
3323 // element: Current array element.
3324 // elements_end: Array end.
3325 if (FLAG_debug_code) {
3326 __ cmp(array_length, Operand(0));
3327 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin");
3328 }
3329 __ bind(&loop);
3330 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3331 __ JumpIfSmi(string, &bailout);
3332 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
3333 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3334 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3335 __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
3336 __ add(string_length, string_length, Operand(scratch1));
3337 __ b(vs, &bailout);
3338 __ cmp(element, elements_end);
3339 __ b(lt, &loop);
3340
3341 // If array_length is 1, return elements[0], a string.
3342 __ cmp(array_length, Operand(1));
3343 __ b(ne, &not_size_one_array);
3344 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
3345 __ b(&done);
3346
3347 __ bind(&not_size_one_array);
3348
3349 // Live values in registers:
3350 // separator: Separator string
3351 // array_length: Length of the array.
3352 // string_length: Sum of string lengths (smi).
3353 // elements: FixedArray of strings.
3354
3355 // Check that the separator is a flat ASCII string.
3356 __ JumpIfSmi(separator, &bailout);
3357 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
3358 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3359 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3360
3361 // Add (separator length times array_length) - separator length to the
3362 // string_length to get the length of the result string. array_length is not
3363 // smi but the other values are, so the result is a smi
3364 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3365 __ sub(string_length, string_length, Operand(scratch1));
3366 __ smull(scratch2, ip, array_length, scratch1);
3367 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3368 // zero.
3369 __ cmp(ip, Operand(0));
3370 __ b(ne, &bailout);
3371 __ tst(scratch2, Operand(0x80000000));
3372 __ b(ne, &bailout);
3373 __ add(string_length, string_length, Operand(scratch2));
3374 __ b(vs, &bailout);
3375 __ SmiUntag(string_length);
3376
3377 // Get first element in the array to free up the elements register to be used
3378 // for the result.
3379 __ add(element,
3380 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3381 result = elements; // End of live range for elements.
3382 elements = no_reg;
3383 // Live values in registers:
3384 // element: First array element
3385 // separator: Separator string
3386 // string_length: Length of result string (not smi)
3387 // array_length: Length of the array.
3388 __ AllocateAsciiString(result,
3389 string_length,
3390 scratch1,
3391 scratch2,
3392 elements_end,
3393 &bailout);
3394 // Prepare for looping. Set up elements_end to end of the array. Set
3395 // result_pos to the position of the result where to write the first
3396 // character.
3397 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3398 result_pos = array_length; // End of live range for array_length.
3399 array_length = no_reg;
3400 __ add(result_pos,
3401 result,
3402 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3403
3404 // Check the length of the separator.
3405 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3406 __ cmp(scratch1, Operand(Smi::FromInt(1)));
3407 __ b(eq, &one_char_separator);
3408 __ b(gt, &long_separator);
3409
3410 // Empty separator case
3411 __ bind(&empty_separator_loop);
3412 // Live values in registers:
3413 // result_pos: the position to which we are currently copying characters.
3414 // element: Current array element.
3415 // elements_end: Array end.
3416
3417 // Copy next array element to the result.
3418 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3419 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3420 __ SmiUntag(string_length);
3421 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3422 __ CopyBytes(string, result_pos, string_length, scratch1);
3423 __ cmp(element, elements_end);
3424 __ b(lt, &empty_separator_loop); // End while (element < elements_end).
3425 ASSERT(result.is(r0));
3426 __ b(&done);
3427
3428 // One-character separator case
3429 __ bind(&one_char_separator);
3430 // Replace separator with its ascii character value.
3431 __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
3432 // Jump into the loop after the code that copies the separator, so the first
3433 // element is not preceded by a separator
3434 __ jmp(&one_char_separator_loop_entry);
3435
3436 __ bind(&one_char_separator_loop);
3437 // Live values in registers:
3438 // result_pos: the position to which we are currently copying characters.
3439 // element: Current array element.
3440 // elements_end: Array end.
3441 // separator: Single separator ascii char (in lower byte).
3442
3443 // Copy the separator character to the result.
3444 __ strb(separator, MemOperand(result_pos, 1, PostIndex));
3445
3446 // Copy next array element to the result.
3447 __ bind(&one_char_separator_loop_entry);
3448 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3449 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3450 __ SmiUntag(string_length);
3451 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3452 __ CopyBytes(string, result_pos, string_length, scratch1);
3453 __ cmp(element, elements_end);
3454 __ b(lt, &one_char_separator_loop); // End while (element < elements_end).
3455 ASSERT(result.is(r0));
3456 __ b(&done);
3457
3458 // Long separator case (separator is more than one character). Entry is at the
3459 // label long_separator below.
3460 __ bind(&long_separator_loop);
3461 // Live values in registers:
3462 // result_pos: the position to which we are currently copying characters.
3463 // element: Current array element.
3464 // elements_end: Array end.
3465 // separator: Separator string.
3466
3467 // Copy the separator to the result.
3468 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset));
3469 __ SmiUntag(string_length);
3470 __ add(string,
3471 separator,
3472 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3473 __ CopyBytes(string, result_pos, string_length, scratch1);
3474
3475 __ bind(&long_separator);
3476 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3477 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3478 __ SmiUntag(string_length);
3479 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3480 __ CopyBytes(string, result_pos, string_length, scratch1);
3481 __ cmp(element, elements_end);
3482 __ b(lt, &long_separator_loop); // End while (element < elements_end).
3483 ASSERT(result.is(r0));
3484 __ b(&done);
3485
3486 __ bind(&bailout);
2963 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex); 3487 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
3488 __ bind(&done);
2964 context()->Plug(r0); 3489 context()->Plug(r0);
2965 return;
2966 } 3490 }
2967 3491
2968 3492
2969 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) { 3493 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
2970 Handle<String> name = expr->name(); 3494 Handle<String> name = expr->name();
2971 if (name->length() > 0 && name->Get(0) == '_') { 3495 if (name->length() > 0 && name->Get(0) == '_') {
2972 Comment cmnt(masm_, "[ InlineRuntimeCall"); 3496 Comment cmnt(masm_, "[ InlineRuntimeCall");
2973 EmitInlineRuntimeCall(expr); 3497 EmitInlineRuntimeCall(expr);
2974 return; 3498 return;
2975 } 3499 }
(...skipping 29 matching lines...) Expand all
3005 context()->Plug(r0); 3529 context()->Plug(r0);
3006 } 3530 }
3007 3531
3008 3532
3009 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) { 3533 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3010 switch (expr->op()) { 3534 switch (expr->op()) {
3011 case Token::DELETE: { 3535 case Token::DELETE: {
3012 Comment cmnt(masm_, "[ UnaryOperation (DELETE)"); 3536 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3013 Property* prop = expr->expression()->AsProperty(); 3537 Property* prop = expr->expression()->AsProperty();
3014 Variable* var = expr->expression()->AsVariableProxy()->AsVariable(); 3538 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
3015 if (prop == NULL && var == NULL) { 3539
3016 // Result of deleting non-property, non-variable reference is true. 3540 if (prop != NULL) {
3017 // The subexpression may have side effects. 3541 if (prop->is_synthetic()) {
3018 VisitForEffect(expr->expression()); 3542 // Result of deleting parameters is false, even when they rewrite
3019 context()->Plug(true); 3543 // to accesses on the arguments object.
3020 } else if (var != NULL && 3544 context()->Plug(false);
3021 !var->is_global() && 3545 } else {
3022 var->AsSlot() != NULL &&
3023 var->AsSlot()->type() != Slot::LOOKUP) {
3024 // Result of deleting non-global, non-dynamic variables is false.
3025 // The subexpression does not have side effects.
3026 context()->Plug(false);
3027 } else {
3028 // Property or variable reference. Call the delete builtin with
3029 // object and property name as arguments.
3030 if (prop != NULL) {
3031 VisitForStackValue(prop->obj()); 3546 VisitForStackValue(prop->obj());
3032 VisitForStackValue(prop->key()); 3547 VisitForStackValue(prop->key());
3548 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
3549 __ push(r1);
3033 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 3550 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
3034 } else if (var->is_global()) { 3551 context()->Plug(r0);
3035 __ ldr(r1, GlobalObjectOperand()); 3552 }
3036 __ mov(r0, Operand(var->name())); 3553 } else if (var != NULL) {
3037 __ Push(r1, r0); 3554 // Delete of an unqualified identifier is disallowed in strict mode
3555 // but "delete this" is.
3556 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
3557 if (var->is_global()) {
3558 __ ldr(r2, GlobalObjectOperand());
3559 __ mov(r1, Operand(var->name()));
3560 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
3561 __ Push(r2, r1, r0);
3038 __ InvokeBuiltin(Builtins::DELETE, CALL_JS); 3562 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
3563 context()->Plug(r0);
3564 } else if (var->AsSlot() != NULL &&
3565 var->AsSlot()->type() != Slot::LOOKUP) {
3566 // Result of deleting non-global, non-dynamic variables is false.
3567 // The subexpression does not have side effects.
3568 context()->Plug(false);
3039 } else { 3569 } else {
3040 // Non-global variable. Call the runtime to delete from the 3570 // Non-global variable. Call the runtime to try to delete from the
3041 // context where the variable was introduced. 3571 // context where the variable was introduced.
3042 __ push(context_register()); 3572 __ push(context_register());
3043 __ mov(r2, Operand(var->name())); 3573 __ mov(r2, Operand(var->name()));
3044 __ push(r2); 3574 __ push(r2);
3045 __ CallRuntime(Runtime::kDeleteContextSlot, 2); 3575 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3576 context()->Plug(r0);
3046 } 3577 }
3047 context()->Plug(r0); 3578 } else {
3579 // Result of deleting non-property, non-variable reference is true.
3580 // The subexpression may have side effects.
3581 VisitForEffect(expr->expression());
3582 context()->Plug(true);
3048 } 3583 }
3049 break; 3584 break;
3050 } 3585 }
3051 3586
3052 case Token::VOID: { 3587 case Token::VOID: {
3053 Comment cmnt(masm_, "[ UnaryOperation (VOID)"); 3588 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3054 VisitForEffect(expr->expression()); 3589 VisitForEffect(expr->expression());
3055 context()->Plug(Heap::kUndefinedValueRootIndex); 3590 context()->Plug(Heap::kUndefinedValueRootIndex);
3056 break; 3591 break;
3057 } 3592 }
3058 3593
3059 case Token::NOT: { 3594 case Token::NOT: {
3060 Comment cmnt(masm_, "[ UnaryOperation (NOT)"); 3595 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
3061 Label materialize_true, materialize_false; 3596 if (context()->IsEffect()) {
3062 Label* if_true = NULL; 3597 // Unary NOT has no side effects so it's only necessary to visit the
3063 Label* if_false = NULL; 3598 // subexpression. Match the optimizing compiler by not branching.
3064 Label* fall_through = NULL; 3599 VisitForEffect(expr->expression());
3600 } else {
3601 Label materialize_true, materialize_false;
3602 Label* if_true = NULL;
3603 Label* if_false = NULL;
3604 Label* fall_through = NULL;
3065 3605
3066 // Notice that the labels are swapped. 3606 // Notice that the labels are swapped.
3067 context()->PrepareTest(&materialize_true, &materialize_false, 3607 context()->PrepareTest(&materialize_true, &materialize_false,
3068 &if_false, &if_true, &fall_through); 3608 &if_false, &if_true, &fall_through);
3069 if (context()->IsTest()) ForwardBailoutToChild(expr); 3609 if (context()->IsTest()) ForwardBailoutToChild(expr);
3070 VisitForControl(expr->expression(), if_true, if_false, fall_through); 3610 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3071 context()->Plug(if_false, if_true); // Labels swapped. 3611 context()->Plug(if_false, if_true); // Labels swapped.
3612 }
3072 break; 3613 break;
3073 } 3614 }
3074 3615
3075 case Token::TYPEOF: { 3616 case Token::TYPEOF: {
3076 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)"); 3617 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3077 { StackValueContext context(this); 3618 { StackValueContext context(this);
3078 VisitForTypeofValue(expr->expression()); 3619 VisitForTypeofValue(expr->expression());
3079 } 3620 }
3080 __ CallRuntime(Runtime::kTypeof, 1); 3621 __ CallRuntime(Runtime::kTypeof, 1);
3081 context()->Plug(r0); 3622 context()->Plug(r0);
(...skipping 11 matching lines...) Expand all
3093 __ bind(&no_conversion); 3634 __ bind(&no_conversion);
3094 context()->Plug(result_register()); 3635 context()->Plug(result_register());
3095 break; 3636 break;
3096 } 3637 }
3097 3638
3098 case Token::SUB: { 3639 case Token::SUB: {
3099 Comment cmt(masm_, "[ UnaryOperation (SUB)"); 3640 Comment cmt(masm_, "[ UnaryOperation (SUB)");
3100 bool can_overwrite = expr->expression()->ResultOverwriteAllowed(); 3641 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3101 UnaryOverwriteMode overwrite = 3642 UnaryOverwriteMode overwrite =
3102 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE; 3643 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
3103 GenericUnaryOpStub stub(Token::SUB, 3644 GenericUnaryOpStub stub(Token::SUB, overwrite, NO_UNARY_FLAGS);
3104 overwrite,
3105 NO_UNARY_FLAGS);
3106 // GenericUnaryOpStub expects the argument to be in the 3645 // GenericUnaryOpStub expects the argument to be in the
3107 // accumulator register r0. 3646 // accumulator register r0.
3108 VisitForAccumulatorValue(expr->expression()); 3647 VisitForAccumulatorValue(expr->expression());
3109 __ CallStub(&stub); 3648 __ CallStub(&stub);
3110 context()->Plug(r0); 3649 context()->Plug(r0);
3111 break; 3650 break;
3112 } 3651 }
3113 3652
3114 case Token::BIT_NOT: { 3653 case Token::BIT_NOT: {
3115 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)"); 3654 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
(...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after
3228 case KEYED_PROPERTY: 3767 case KEYED_PROPERTY:
3229 __ str(r0, MemOperand(sp, 2 * kPointerSize)); 3768 __ str(r0, MemOperand(sp, 2 * kPointerSize));
3230 break; 3769 break;
3231 } 3770 }
3232 } 3771 }
3233 } 3772 }
3234 3773
3235 3774
3236 // Inline smi case if we are in a loop. 3775 // Inline smi case if we are in a loop.
3237 Label stub_call, done; 3776 Label stub_call, done;
3777 JumpPatchSite patch_site(masm_);
3778
3238 int count_value = expr->op() == Token::INC ? 1 : -1; 3779 int count_value = expr->op() == Token::INC ? 1 : -1;
3239 if (ShouldInlineSmiCase(expr->op())) { 3780 if (ShouldInlineSmiCase(expr->op())) {
3240 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC); 3781 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
3241 __ b(vs, &stub_call); 3782 __ b(vs, &stub_call);
3242 // We could eliminate this smi check if we split the code at 3783 // We could eliminate this smi check if we split the code at
3243 // the first smi check before calling ToNumber. 3784 // the first smi check before calling ToNumber.
3244 __ JumpIfSmi(r0, &done); 3785 patch_site.EmitJumpIfSmi(r0, &done);
3786
3245 __ bind(&stub_call); 3787 __ bind(&stub_call);
3246 // Call stub. Undo operation first. 3788 // Call stub. Undo operation first.
3247 __ sub(r0, r0, Operand(Smi::FromInt(count_value))); 3789 __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
3248 } 3790 }
3249 __ mov(r1, Operand(Smi::FromInt(count_value))); 3791 __ mov(r1, Operand(Smi::FromInt(count_value)));
3250 3792
3251 // Record position before stub call. 3793 // Record position before stub call.
3252 SetSourcePosition(expr->position()); 3794 SetSourcePosition(expr->position());
3253 3795
3254 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0); 3796 TypeRecordingBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
3255 __ CallStub(&stub); 3797 EmitCallIC(stub.GetCode(), &patch_site);
3256 __ bind(&done); 3798 __ bind(&done);
3257 3799
3258 // Store the value returned in r0. 3800 // Store the value returned in r0.
3259 switch (assign_type) { 3801 switch (assign_type) {
3260 case VARIABLE: 3802 case VARIABLE:
3261 if (expr->is_postfix()) { 3803 if (expr->is_postfix()) {
3262 { EffectContext context(this); 3804 { EffectContext context(this);
3263 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 3805 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3264 Token::ASSIGN); 3806 Token::ASSIGN);
3265 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3807 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3266 context.Plug(r0); 3808 context.Plug(r0);
3267 } 3809 }
3268 // For all contexts except EffectConstant We have the result on 3810 // For all contexts except EffectConstant We have the result on
3269 // top of the stack. 3811 // top of the stack.
3270 if (!context()->IsEffect()) { 3812 if (!context()->IsEffect()) {
3271 context()->PlugTOS(); 3813 context()->PlugTOS();
3272 } 3814 }
3273 } else { 3815 } else {
3274 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(), 3816 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3275 Token::ASSIGN); 3817 Token::ASSIGN);
3276 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3818 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3277 context()->Plug(r0); 3819 context()->Plug(r0);
3278 } 3820 }
3279 break; 3821 break;
3280 case NAMED_PROPERTY: { 3822 case NAMED_PROPERTY: {
3281 __ mov(r2, Operand(prop->key()->AsLiteral()->handle())); 3823 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
3282 __ pop(r1); 3824 __ pop(r1);
3283 Handle<Code> ic(isolate()->builtins()->builtin( 3825 Handle<Code> ic(isolate()->builtins()->builtin(
3284 Builtins::StoreIC_Initialize)); 3826 is_strict() ? Builtins::StoreIC_Initialize_Strict
3827 : Builtins::StoreIC_Initialize));
3285 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3828 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3286 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3829 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3287 if (expr->is_postfix()) { 3830 if (expr->is_postfix()) {
3288 if (!context()->IsEffect()) { 3831 if (!context()->IsEffect()) {
3289 context()->PlugTOS(); 3832 context()->PlugTOS();
3290 } 3833 }
3291 } else { 3834 } else {
3292 context()->Plug(r0); 3835 context()->Plug(r0);
3293 } 3836 }
3294 break; 3837 break;
3295 } 3838 }
3296 case KEYED_PROPERTY: { 3839 case KEYED_PROPERTY: {
3297 __ pop(r1); // Key. 3840 __ pop(r1); // Key.
3298 __ pop(r2); // Receiver. 3841 __ pop(r2); // Receiver.
3299 Handle<Code> ic(isolate()->builtins()->builtin( 3842 Handle<Code> ic(isolate()->builtins()->builtin(
3300 Builtins::KeyedStoreIC_Initialize)); 3843 is_strict() ? Builtins::KeyedStoreIC_Initialize_Strict
3844 : Builtins::KeyedStoreIC_Initialize));
3301 EmitCallIC(ic, RelocInfo::CODE_TARGET); 3845 EmitCallIC(ic, RelocInfo::CODE_TARGET);
3302 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG); 3846 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3303 if (expr->is_postfix()) { 3847 if (expr->is_postfix()) {
3304 if (!context()->IsEffect()) { 3848 if (!context()->IsEffect()) {
3305 context()->PlugTOS(); 3849 context()->PlugTOS();
3306 } 3850 }
3307 } else { 3851 } else {
3308 context()->Plug(r0); 3852 context()->Plug(r0);
3309 } 3853 }
3310 break; 3854 break;
(...skipping 216 matching lines...) Expand 10 before | Expand all | Expand 10 after
3527 cond = ge; 4071 cond = ge;
3528 __ pop(r1); 4072 __ pop(r1);
3529 break; 4073 break;
3530 case Token::IN: 4074 case Token::IN:
3531 case Token::INSTANCEOF: 4075 case Token::INSTANCEOF:
3532 default: 4076 default:
3533 UNREACHABLE(); 4077 UNREACHABLE();
3534 } 4078 }
3535 4079
3536 bool inline_smi_code = ShouldInlineSmiCase(op); 4080 bool inline_smi_code = ShouldInlineSmiCase(op);
4081 JumpPatchSite patch_site(masm_);
3537 if (inline_smi_code) { 4082 if (inline_smi_code) {
3538 Label slow_case; 4083 Label slow_case;
3539 __ orr(r2, r0, Operand(r1)); 4084 __ orr(r2, r0, Operand(r1));
3540 __ JumpIfNotSmi(r2, &slow_case); 4085 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
3541 __ cmp(r1, r0); 4086 __ cmp(r1, r0);
3542 Split(cond, if_true, if_false, NULL); 4087 Split(cond, if_true, if_false, NULL);
3543 __ bind(&slow_case); 4088 __ bind(&slow_case);
3544 } 4089 }
3545 CompareFlags flags = inline_smi_code 4090
3546 ? NO_SMI_COMPARE_IN_STUB 4091 // Record position and call the compare IC.
3547 : NO_COMPARE_FLAGS; 4092 SetSourcePosition(expr->position());
3548 CompareStub stub(cond, strict, flags, r1, r0); 4093 Handle<Code> ic = CompareIC::GetUninitialized(op);
3549 __ CallStub(&stub); 4094 EmitCallIC(ic, &patch_site);
3550 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false); 4095 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3551 __ cmp(r0, Operand(0, RelocInfo::NONE)); 4096 __ cmp(r0, Operand(0));
3552 Split(cond, if_true, if_false, fall_through); 4097 Split(cond, if_true, if_false, fall_through);
3553 } 4098 }
3554 } 4099 }
3555 4100
3556 // Convert the result of the comparison into one expected for this 4101 // Convert the result of the comparison into one expected for this
3557 // expression's context. 4102 // expression's context.
3558 context()->Plug(if_true, if_false); 4103 context()->Plug(if_true, if_false);
3559 } 4104 }
3560 4105
3561 4106
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
3604 4149
3605 4150
3606 Register FullCodeGenerator::context_register() { 4151 Register FullCodeGenerator::context_register() {
3607 return cp; 4152 return cp;
3608 } 4153 }
3609 4154
3610 4155
3611 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) { 4156 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
3612 ASSERT(mode == RelocInfo::CODE_TARGET || 4157 ASSERT(mode == RelocInfo::CODE_TARGET ||
3613 mode == RelocInfo::CODE_TARGET_CONTEXT); 4158 mode == RelocInfo::CODE_TARGET_CONTEXT);
4159 switch (ic->kind()) {
4160 case Code::LOAD_IC:
4161 __ IncrementCounter(COUNTERS->named_load_full(), 1, r1, r2);
4162 break;
4163 case Code::KEYED_LOAD_IC:
4164 __ IncrementCounter(COUNTERS->keyed_load_full(), 1, r1, r2);
4165 break;
4166 case Code::STORE_IC:
4167 __ IncrementCounter(COUNTERS->named_store_full(), 1, r1, r2);
4168 break;
4169 case Code::KEYED_STORE_IC:
4170 __ IncrementCounter(COUNTERS->keyed_store_full(), 1, r1, r2);
4171 default:
4172 break;
4173 }
4174
3614 __ Call(ic, mode); 4175 __ Call(ic, mode);
3615 } 4176 }
3616 4177
3617 4178
4179 void FullCodeGenerator::EmitCallIC(Handle<Code> ic, JumpPatchSite* patch_site) {
4180 switch (ic->kind()) {
4181 case Code::LOAD_IC:
4182 __ IncrementCounter(COUNTERS->named_load_full(), 1, r1, r2);
4183 break;
4184 case Code::KEYED_LOAD_IC:
4185 __ IncrementCounter(COUNTERS->keyed_load_full(), 1, r1, r2);
4186 break;
4187 case Code::STORE_IC:
4188 __ IncrementCounter(COUNTERS->named_store_full(), 1, r1, r2);
4189 break;
4190 case Code::KEYED_STORE_IC:
4191 __ IncrementCounter(COUNTERS->keyed_store_full(), 1, r1, r2);
4192 default:
4193 break;
4194 }
4195
4196 __ Call(ic, RelocInfo::CODE_TARGET);
4197 if (patch_site != NULL && patch_site->is_bound()) {
4198 patch_site->EmitPatchInfo();
4199 } else {
4200 __ nop(); // Signals no inlined code.
4201 }
4202 }
4203
4204
3618 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) { 4205 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3619 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset); 4206 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3620 __ str(value, MemOperand(fp, frame_offset)); 4207 __ str(value, MemOperand(fp, frame_offset));
3621 } 4208 }
3622 4209
3623 4210
3624 void FullCodeGenerator::LoadContextField(Register dst, int context_index) { 4211 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3625 __ ldr(dst, ContextOperand(cp, context_index)); 4212 __ ldr(dst, ContextOperand(cp, context_index));
3626 } 4213 }
3627 4214
(...skipping 24 matching lines...) Expand all
3652 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value. 4239 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
3653 __ add(pc, r1, Operand(masm_->CodeObject())); 4240 __ add(pc, r1, Operand(masm_->CodeObject()));
3654 } 4241 }
3655 4242
3656 4243
3657 #undef __ 4244 #undef __
3658 4245
3659 } } // namespace v8::internal 4246 } } // namespace v8::internal
3660 4247
3661 #endif // V8_TARGET_ARCH_ARM 4248 #endif // V8_TARGET_ARCH_ARM
OLDNEW
« no previous file with comments | « src/arm/deoptimizer-arm.cc ('k') | src/arm/ic-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698