OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 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 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
94 | 94 |
95 bool is_illegal() const { return type_ == ILLEGAL; } | 95 bool is_illegal() const { return type_ == ILLEGAL; } |
96 | 96 |
97 private: | 97 private: |
98 ArmCodeGenerator* cgen_; | 98 ArmCodeGenerator* cgen_; |
99 Expression* expression_; | 99 Expression* expression_; |
100 Type type_; | 100 Type type_; |
101 }; | 101 }; |
102 | 102 |
103 | 103 |
104 // ----------------------------------------------------------------------------- | 104 // ------------------------------------------------------------------------- |
105 // Code generation state | 105 // Code generation state |
106 | 106 |
| 107 // The state is passed down the AST by the code generator. It is passed |
| 108 // implicitly (in a member variable) to the non-static code generator member |
| 109 // functions, and explicitly (as an argument) to the static member functions |
| 110 // and the AST node member functions. |
| 111 // |
| 112 // The state is threaded through the call stack. Constructing a state |
| 113 // implicitly pushes it on the owning code generator's stack of states, and |
| 114 // destroying one implicitly pops it. |
| 115 |
107 class CodeGenState BASE_EMBEDDED { | 116 class CodeGenState BASE_EMBEDDED { |
108 public: | 117 public: |
109 enum AccessType { | 118 enum AccessType { |
110 UNDEFINED, | 119 UNDEFINED, |
111 LOAD, | 120 LOAD, |
112 LOAD_TYPEOF_EXPR | 121 LOAD_TYPEOF_EXPR |
113 }; | 122 }; |
114 | 123 |
115 CodeGenState() | 124 // Create an initial code generator state. Destroying the initial state |
116 : access_(UNDEFINED), | 125 // leaves the code generator with a NULL state. |
117 ref_(NULL), | 126 CodeGenState(ArmCodeGenerator* owner); |
118 true_target_(NULL), | |
119 false_target_(NULL) { | |
120 } | |
121 | 127 |
122 CodeGenState(AccessType access, | 128 // Create a code generator state based on a code generator's current |
123 Reference* ref, | 129 // state. The new state has its own access type and pair of branch |
| 130 // labels, and no reference. |
| 131 CodeGenState(ArmCodeGenerator* owner, |
| 132 AccessType access, |
124 Label* true_target, | 133 Label* true_target, |
125 Label* false_target) | 134 Label* false_target); |
126 : access_(access), | 135 |
127 ref_(ref), | 136 // Create a code generator state based on a code generator's current |
128 true_target_(true_target), | 137 // state. The new state has an access type of LOAD, its own reference, |
129 false_target_(false_target) { | 138 // and inherits the pair of branch labels of the current state. |
130 } | 139 CodeGenState(ArmCodeGenerator* owner, Reference* ref); |
| 140 |
| 141 // Destroy a code generator state and restore the owning code generator's |
| 142 // previous state. |
| 143 ~CodeGenState(); |
131 | 144 |
132 AccessType access() const { return access_; } | 145 AccessType access() const { return access_; } |
133 Reference* ref() const { return ref_; } | 146 Reference* ref() const { return ref_; } |
134 Label* true_target() const { return true_target_; } | 147 Label* true_target() const { return true_target_; } |
135 Label* false_target() const { return false_target_; } | 148 Label* false_target() const { return false_target_; } |
136 | 149 |
137 private: | 150 private: |
| 151 ArmCodeGenerator* owner_; |
138 AccessType access_; | 152 AccessType access_; |
139 Reference* ref_; | 153 Reference* ref_; |
140 Label* true_target_; | 154 Label* true_target_; |
141 Label* false_target_; | 155 Label* false_target_; |
| 156 CodeGenState* previous_; |
142 }; | 157 }; |
143 | 158 |
144 | 159 |
145 // ----------------------------------------------------------------------------- | 160 // ----------------------------------------------------------------------------- |
146 // ArmCodeGenerator | 161 // ArmCodeGenerator |
147 | 162 |
148 class ArmCodeGenerator: public CodeGenerator { | 163 class ArmCodeGenerator: public CodeGenerator { |
149 public: | 164 public: |
150 static Handle<Code> MakeCode(FunctionLiteral* fun, | 165 static Handle<Code> MakeCode(FunctionLiteral* fun, |
151 Handle<Script> script, | 166 Handle<Script> script, |
152 bool is_eval); | 167 bool is_eval); |
153 | 168 |
154 MacroAssembler* masm() { return masm_; } | 169 MacroAssembler* masm() { return masm_; } |
155 | 170 |
| 171 CodeGenState* state() { return state_; } |
| 172 void set_state(CodeGenState* state) { state_ = state; } |
| 173 |
156 private: | 174 private: |
157 // Assembler | 175 // Assembler |
158 MacroAssembler* masm_; // to generate code | 176 MacroAssembler* masm_; // to generate code |
159 | 177 |
160 // Code generation state | 178 // Code generation state |
161 Scope* scope_; | 179 Scope* scope_; |
162 Condition cc_reg_; | 180 Condition cc_reg_; |
163 CodeGenState* state_; | 181 CodeGenState* state_; |
164 int break_stack_height_; | 182 int break_stack_height_; |
165 | 183 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
236 // look like an explicit property access, instead of an access | 254 // look like an explicit property access, instead of an access |
237 // through the context chain. | 255 // through the context chain. |
238 void LoadTypeofExpression(Expression* x); | 256 void LoadTypeofExpression(Expression* x); |
239 | 257 |
240 | 258 |
241 // References | 259 // References |
242 | 260 |
243 // Generate code to fetch the value of a reference. The reference is | 261 // Generate code to fetch the value of a reference. The reference is |
244 // expected to be on top of the expression stack. It is left in place and | 262 // expected to be on top of the expression stack. It is left in place and |
245 // its value is pushed on top of it. | 263 // its value is pushed on top of it. |
246 void GetValue(Reference* ref); | 264 void GetValue(Reference* ref) { |
| 265 ASSERT(!has_cc()); |
| 266 ASSERT(!ref->is_illegal()); |
| 267 CodeGenState new_state(this, ref); |
| 268 Visit(ref->expression()); |
| 269 } |
247 | 270 |
248 // Generate code to store a value in a reference. The stored value is | 271 // Generate code to store a value in a reference. The stored value is |
249 // expected on top of the expression stack, with the reference immediately | 272 // expected on top of the expression stack, with the reference immediately |
250 // below it. The expression stack is left unchanged. | 273 // below it. The expression stack is left unchanged. |
251 void SetValue(Reference* ref) { | 274 void SetValue(Reference* ref) { |
252 ASSERT(!has_cc()); | 275 ASSERT(!has_cc()); |
253 ASSERT(!ref->is_illegal()); | 276 ASSERT(!ref->is_illegal()); |
254 ref->expression()->GenerateStoreCode(masm_, scope_, ref, NOT_CONST_INIT); | 277 ref->expression()->GenerateStoreCode(masm_, scope_, ref, NOT_CONST_INIT); |
255 } | 278 } |
256 | 279 |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
334 | 357 |
335 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | 358 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); |
336 | 359 |
337 friend class Reference; | 360 friend class Reference; |
338 friend class Property; | 361 friend class Property; |
339 friend class VariableProxy; | 362 friend class VariableProxy; |
340 friend class Slot; | 363 friend class Slot; |
341 }; | 364 }; |
342 | 365 |
343 | 366 |
| 367 // ------------------------------------------------------------------------- |
| 368 // CodeGenState implementation. |
| 369 |
| 370 CodeGenState::CodeGenState(ArmCodeGenerator* owner) |
| 371 : owner_(owner), |
| 372 access_(UNDEFINED), |
| 373 ref_(NULL), |
| 374 true_target_(NULL), |
| 375 false_target_(NULL), |
| 376 previous_(NULL) { |
| 377 owner_->set_state(this); |
| 378 } |
| 379 |
| 380 |
| 381 CodeGenState::CodeGenState(ArmCodeGenerator* owner, |
| 382 AccessType access, |
| 383 Label* true_target, |
| 384 Label* false_target) |
| 385 : owner_(owner), |
| 386 access_(access), |
| 387 ref_(NULL), |
| 388 true_target_(true_target), |
| 389 false_target_(false_target), |
| 390 previous_(owner->state()) { |
| 391 owner_->set_state(this); |
| 392 } |
| 393 |
| 394 |
| 395 CodeGenState::CodeGenState(ArmCodeGenerator* owner, Reference* ref) |
| 396 : owner_(owner), |
| 397 access_(LOAD), |
| 398 ref_(ref), |
| 399 true_target_(owner->state()->true_target_), |
| 400 false_target_(owner->state()->false_target_), |
| 401 previous_(owner->state()) { |
| 402 owner_->set_state(this); |
| 403 } |
| 404 |
| 405 |
| 406 CodeGenState::~CodeGenState() { |
| 407 ASSERT(owner_->state() == this); |
| 408 owner_->set_state(previous_); |
| 409 } |
| 410 |
| 411 |
344 // ----------------------------------------------------------------------------- | 412 // ----------------------------------------------------------------------------- |
345 // ArmCodeGenerator implementation | 413 // ArmCodeGenerator implementation |
346 | 414 |
347 #define __ masm_-> | 415 #define __ masm_-> |
348 | 416 |
349 | 417 |
350 Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit, | 418 Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit, |
351 Handle<Script> script, | 419 Handle<Script> script, |
352 bool is_eval) { | 420 bool is_eval) { |
353 #ifdef ENABLE_DISASSEMBLER | 421 #ifdef ENABLE_DISASSEMBLER |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 // fp: frame pointer | 517 // fp: frame pointer |
450 // sp: stack pointer | 518 // sp: stack pointer |
451 // pp: caller's parameter pointer | 519 // pp: caller's parameter pointer |
452 // cp: callee's context | 520 // cp: callee's context |
453 | 521 |
454 void ArmCodeGenerator::GenCode(FunctionLiteral* fun) { | 522 void ArmCodeGenerator::GenCode(FunctionLiteral* fun) { |
455 Scope* scope = fun->scope(); | 523 Scope* scope = fun->scope(); |
456 ZoneList<Statement*>* body = fun->body(); | 524 ZoneList<Statement*>* body = fun->body(); |
457 | 525 |
458 // Initialize state. | 526 // Initialize state. |
459 { CodeGenState state; | 527 { CodeGenState state(this); |
460 state_ = &state; | |
461 scope_ = scope; | 528 scope_ = scope; |
462 cc_reg_ = al; | 529 cc_reg_ = al; |
463 | 530 |
464 // Entry | 531 // Entry |
465 // stack: function, receiver, arguments, return address | 532 // stack: function, receiver, arguments, return address |
466 // r0: number of arguments | 533 // r0: number of arguments |
467 // sp: stack pointer | 534 // sp: stack pointer |
468 // fp: frame pointer | 535 // fp: frame pointer |
469 // pp: caller's parameter pointer | 536 // pp: caller's parameter pointer |
470 // cp: callee's context | 537 // cp: callee's context |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
602 if (should_trace) { | 669 if (should_trace) { |
603 // Push a valid value as the parameter. The runtime call only uses | 670 // Push a valid value as the parameter. The runtime call only uses |
604 // it as the return value to indicate non-failure. | 671 // it as the return value to indicate non-failure. |
605 __ mov(r0, Operand(Smi::FromInt(0))); | 672 __ mov(r0, Operand(Smi::FromInt(0))); |
606 __ push(r0); | 673 __ push(r0); |
607 __ CallRuntime(Runtime::kDebugTrace, 1); | 674 __ CallRuntime(Runtime::kDebugTrace, 1); |
608 } | 675 } |
609 #endif | 676 #endif |
610 VisitStatements(body); | 677 VisitStatements(body); |
611 } | 678 } |
612 | |
613 state_ = NULL; | |
614 } | 679 } |
615 | 680 |
616 // exit | 681 // exit |
617 // r0: result | 682 // r0: result |
618 // sp: stack pointer | 683 // sp: stack pointer |
619 // fp: frame pointer | 684 // fp: frame pointer |
620 // pp: parameter pointer | 685 // pp: parameter pointer |
621 // cp: callee's context | 686 // cp: callee's context |
622 __ mov(r0, Operand(Factory::undefined_value())); | 687 __ mov(r0, Operand(Factory::undefined_value())); |
623 | 688 |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
710 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 775 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
711 void ArmCodeGenerator::LoadCondition(Expression* x, | 776 void ArmCodeGenerator::LoadCondition(Expression* x, |
712 CodeGenState::AccessType access, | 777 CodeGenState::AccessType access, |
713 Label* true_target, | 778 Label* true_target, |
714 Label* false_target, | 779 Label* false_target, |
715 bool force_cc) { | 780 bool force_cc) { |
716 ASSERT(access == CodeGenState::LOAD || | 781 ASSERT(access == CodeGenState::LOAD || |
717 access == CodeGenState::LOAD_TYPEOF_EXPR); | 782 access == CodeGenState::LOAD_TYPEOF_EXPR); |
718 ASSERT(!has_cc() && !is_referenced()); | 783 ASSERT(!has_cc() && !is_referenced()); |
719 | 784 |
720 CodeGenState* old_state = state_; | 785 { CodeGenState new_state(this, access, true_target, false_target); |
721 CodeGenState new_state(access, NULL, true_target, false_target); | 786 Visit(x); |
722 state_ = &new_state; | 787 } |
723 Visit(x); | |
724 state_ = old_state; | |
725 if (force_cc && !has_cc()) { | 788 if (force_cc && !has_cc()) { |
726 // Convert the TOS value to a boolean in the condition code register. | 789 // Convert the TOS value to a boolean in the condition code register. |
727 ToBoolean(true_target, false_target); | 790 ToBoolean(true_target, false_target); |
728 } | 791 } |
729 ASSERT(has_cc() || !force_cc); | 792 ASSERT(has_cc() || !force_cc); |
730 } | 793 } |
731 | 794 |
732 | 795 |
733 void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { | 796 void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { |
734 ASSERT(access == CodeGenState::LOAD || | 797 ASSERT(access == CodeGenState::LOAD || |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
862 if (size <= 0) { | 925 if (size <= 0) { |
863 // Do nothing. No popping is necessary. | 926 // Do nothing. No popping is necessary. |
864 } else { | 927 } else { |
865 __ pop(r0); | 928 __ pop(r0); |
866 __ add(sp, sp, Operand(size * kPointerSize)); | 929 __ add(sp, sp, Operand(size * kPointerSize)); |
867 __ push(r0); | 930 __ push(r0); |
868 } | 931 } |
869 } | 932 } |
870 | 933 |
871 | 934 |
872 void ArmCodeGenerator::GetValue(Reference* ref) { | |
873 ASSERT(!has_cc()); | |
874 ASSERT(!ref->is_illegal()); | |
875 CodeGenState* old_state = state_; | |
876 CodeGenState new_state(CodeGenState::LOAD, ref, true_target(), | |
877 false_target()); | |
878 state_ = &new_state; | |
879 Visit(ref->expression()); | |
880 state_ = old_state; | |
881 } | |
882 | |
883 | |
884 void Property::GenerateStoreCode(MacroAssembler* masm, | 935 void Property::GenerateStoreCode(MacroAssembler* masm, |
885 Scope* scope, | 936 Scope* scope, |
886 Reference* ref, | 937 Reference* ref, |
887 InitState init_state) { | 938 InitState init_state) { |
888 Comment cmnt(masm, "[ Store to Property"); | 939 Comment cmnt(masm, "[ Store to Property"); |
889 masm->RecordPosition(position()); | 940 masm->RecordPosition(position()); |
890 ArmCodeGenerator::SetReferenceProperty(masm, ref, key()); | 941 ArmCodeGenerator::SetReferenceProperty(masm, ref, key()); |
891 } | 942 } |
892 | 943 |
893 | 944 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
946 masm->CallRuntime(Runtime::kStoreContextSlot, 3); | 997 masm->CallRuntime(Runtime::kStoreContextSlot, 3); |
947 } | 998 } |
948 // Storing a variable must keep the (new) value on the expression | 999 // Storing a variable must keep the (new) value on the expression |
949 // stack. This is necessary for compiling assignment expressions. | 1000 // stack. This is necessary for compiling assignment expressions. |
950 masm->push(r0); | 1001 masm->push(r0); |
951 | 1002 |
952 } else { | 1003 } else { |
953 ASSERT(var()->mode() != Variable::DYNAMIC); | 1004 ASSERT(var()->mode() != Variable::DYNAMIC); |
954 | 1005 |
955 Label exit; | 1006 Label exit; |
956 bool may_skip_write = false; | |
957 if (init_state == CONST_INIT) { | 1007 if (init_state == CONST_INIT) { |
958 ASSERT(var()->mode() == Variable::CONST); | 1008 ASSERT(var()->mode() == Variable::CONST); |
959 // Only the first const initialization must be executed (the slot | 1009 // Only the first const initialization must be executed (the slot |
960 // still contains 'the hole' value). When the assignment is executed, | 1010 // still contains 'the hole' value). When the assignment is executed, |
961 // the code is identical to a normal store (see below). | 1011 // the code is identical to a normal store (see below). |
962 Comment cmnt(masm, "[ Init const"); | 1012 Comment cmnt(masm, "[ Init const"); |
963 masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); | 1013 masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); |
964 masm->cmp(r2, Operand(Factory::the_hole_value())); | 1014 masm->cmp(r2, Operand(Factory::the_hole_value())); |
965 masm->b(ne, &exit); | 1015 masm->b(ne, &exit); |
966 may_skip_write = true; | |
967 } | 1016 } |
968 | 1017 |
969 // We must execute the store. | 1018 // We must execute the store. |
970 // r2 may be loaded with context; used below in RecordWrite. | 1019 // r2 may be loaded with context; used below in RecordWrite. |
971 // Storing a variable must keep the (new) value on the stack. This is | 1020 // Storing a variable must keep the (new) value on the stack. This is |
972 // necessary for compiling assignment expressions. | 1021 // necessary for compiling assignment expressions. |
973 // | 1022 // |
974 // Note: We will reach here even with var()->mode() == Variable::CONST | 1023 // Note: We will reach here even with var()->mode() == Variable::CONST |
975 // because of const declarations which will initialize consts to 'the | 1024 // because of const declarations which will initialize consts to 'the |
976 // hole' value and by doing so, end up calling this code. r2 may be | 1025 // hole' value and by doing so, end up calling this code. r2 may be |
977 // loaded with context; used below in RecordWrite. | 1026 // loaded with context; used below in RecordWrite. |
978 masm->pop(r0); | 1027 masm->pop(r0); |
979 masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); | 1028 masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); |
980 masm->push(r0); | 1029 masm->push(r0); |
981 | 1030 |
982 if (type() == Slot::CONTEXT) { | 1031 if (type() == Slot::CONTEXT) { |
983 // Skip write barrier if the written value is a smi. | 1032 // Skip write barrier if the written value is a smi. |
984 masm->tst(r0, Operand(kSmiTagMask)); | 1033 masm->tst(r0, Operand(kSmiTagMask)); |
985 masm->b(eq, &exit); | 1034 masm->b(eq, &exit); |
986 may_skip_write = true; | |
987 // r2 is loaded with context when calling SlotOperand above. | 1035 // r2 is loaded with context when calling SlotOperand above. |
988 int offset = FixedArray::kHeaderSize + index() * kPointerSize; | 1036 int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
989 masm->mov(r3, Operand(offset)); | 1037 masm->mov(r3, Operand(offset)); |
990 masm->RecordWrite(r2, r3, r1); | 1038 masm->RecordWrite(r2, r3, r1); |
991 } | 1039 } |
992 // If we definitely did not jump over the assignment, we do not need to | 1040 // If we definitely did not jump over the assignment, we do not need to |
993 // bind the exit label. Doing so can defeat peephole optimization. | 1041 // bind the exit label. Doing so can defeat peephole optimization. |
994 if (may_skip_write) masm->bind(&exit); | 1042 if (init_state == CONST_INIT || type() == Slot::CONTEXT) { |
| 1043 masm->bind(&exit); |
| 1044 } |
995 } | 1045 } |
996 } | 1046 } |
997 | 1047 |
998 | 1048 |
999 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 1049 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
1000 // register to a boolean in the condition code register. The code | 1050 // register to a boolean in the condition code register. The code |
1001 // may jump to 'false_target' in case the register converts to 'false'. | 1051 // may jump to 'false_target' in case the register converts to 'false'. |
1002 void ArmCodeGenerator::ToBoolean(Label* true_target, | 1052 void ArmCodeGenerator::ToBoolean(Label* true_target, |
1003 Label* false_target) { | 1053 Label* false_target) { |
1004 // Note: The generated code snippet does not change stack variables. | 1054 // Note: The generated code snippet does not change stack variables. |
(...skipping 3613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4618 bool is_eval) { | 4668 bool is_eval) { |
4619 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); | 4669 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); |
4620 if (!code.is_null()) { | 4670 if (!code.is_null()) { |
4621 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 4671 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
4622 } | 4672 } |
4623 return code; | 4673 return code; |
4624 } | 4674 } |
4625 | 4675 |
4626 | 4676 |
4627 } } // namespace v8::internal | 4677 } } // namespace v8::internal |
OLD | NEW |