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 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 | 100 |
101 bool is_illegal() const { return type_ == ILLEGAL; } | 101 bool is_illegal() const { return type_ == ILLEGAL; } |
102 | 102 |
103 private: | 103 private: |
104 Ia32CodeGenerator* cgen_; | 104 Ia32CodeGenerator* cgen_; |
105 Expression* expression_; | 105 Expression* expression_; |
106 Type type_; | 106 Type type_; |
107 }; | 107 }; |
108 | 108 |
109 | 109 |
110 // ----------------------------------------------------------------------------- | 110 // ------------------------------------------------------------------------- |
111 // Code generation state | 111 // Code generation state |
112 | 112 |
| 113 // The state is passed down the AST by the code generator. It is passed |
| 114 // implicitly (in a member variable) to the non-static code generator member |
| 115 // functions, and explicitly (as an argument) to the static member functions |
| 116 // and the AST node member functions. |
| 117 // |
| 118 // The state is threaded through the call stack. Constructing a state |
| 119 // implicitly pushes it on the owning code generator's stack of states, and |
| 120 // destroying one implicitly pops it. |
| 121 |
113 class CodeGenState BASE_EMBEDDED { | 122 class CodeGenState BASE_EMBEDDED { |
114 public: | 123 public: |
115 enum AccessType { | 124 enum AccessType { |
116 UNDEFINED, | 125 UNDEFINED, |
117 LOAD, | 126 LOAD, |
118 LOAD_TYPEOF_EXPR | 127 LOAD_TYPEOF_EXPR |
119 }; | 128 }; |
120 | 129 |
121 CodeGenState() | 130 // Create an initial code generator state. Destroying the initial state |
122 : access_(UNDEFINED), | 131 // leaves the code generator with a NULL state. |
123 ref_(NULL), | 132 CodeGenState(Ia32CodeGenerator* owner); |
124 true_target_(NULL), | |
125 false_target_(NULL) { | |
126 } | |
127 | 133 |
128 CodeGenState(AccessType access, | 134 // Create a code generator state based on a code generator's current |
129 Reference* ref, | 135 // state. The new state has its own access type and pair of branch |
| 136 // labels, and no reference. |
| 137 CodeGenState(Ia32CodeGenerator* owner, |
| 138 AccessType access, |
130 Label* true_target, | 139 Label* true_target, |
131 Label* false_target) | 140 Label* false_target); |
132 : access_(access), | 141 |
133 ref_(ref), | 142 // Create a code generator state based on a code generator's current |
134 true_target_(true_target), | 143 // state. The new state has an access type of LOAD, its own reference, |
135 false_target_(false_target) { | 144 // and inherits the pair of branch labels of the current state. |
136 } | 145 CodeGenState(Ia32CodeGenerator* owner, Reference* ref); |
| 146 |
| 147 // Destroy a code generator state and restore the owning code generator's |
| 148 // previous state. |
| 149 ~CodeGenState(); |
137 | 150 |
138 AccessType access() const { return access_; } | 151 AccessType access() const { return access_; } |
139 Reference* ref() const { return ref_; } | 152 Reference* ref() const { return ref_; } |
140 Label* true_target() const { return true_target_; } | 153 Label* true_target() const { return true_target_; } |
141 Label* false_target() const { return false_target_; } | 154 Label* false_target() const { return false_target_; } |
142 | 155 |
143 private: | 156 private: |
| 157 Ia32CodeGenerator* owner_; |
144 AccessType access_; | 158 AccessType access_; |
145 Reference* ref_; | 159 Reference* ref_; |
146 Label* true_target_; | 160 Label* true_target_; |
147 Label* false_target_; | 161 Label* false_target_; |
| 162 CodeGenState* previous_; |
148 }; | 163 }; |
149 | 164 |
150 | 165 |
151 // ----------------------------------------------------------------------------- | 166 // ----------------------------------------------------------------------------- |
152 // Ia32CodeGenerator | 167 // Ia32CodeGenerator |
153 | 168 |
154 class Ia32CodeGenerator: public CodeGenerator { | 169 class Ia32CodeGenerator: public CodeGenerator { |
155 public: | 170 public: |
156 static Handle<Code> MakeCode(FunctionLiteral* fun, | 171 static Handle<Code> MakeCode(FunctionLiteral* fun, |
157 Handle<Script> script, | 172 Handle<Script> script, |
158 bool is_eval); | 173 bool is_eval); |
159 | 174 |
160 MacroAssembler* masm() { return masm_; } | 175 MacroAssembler* masm() { return masm_; } |
161 | 176 |
| 177 CodeGenState* state() { return state_; } |
| 178 void set_state(CodeGenState* state) { state_ = state; } |
| 179 |
162 private: | 180 private: |
163 // Assembler | 181 // Assembler |
164 MacroAssembler* masm_; // to generate code | 182 MacroAssembler* masm_; // to generate code |
165 | 183 |
166 // Code generation state | 184 // Code generation state |
167 Scope* scope_; | 185 Scope* scope_; |
168 Condition cc_reg_; | 186 Condition cc_reg_; |
169 CodeGenState* state_; | 187 CodeGenState* state_; |
170 bool is_inside_try_; | 188 bool is_inside_try_; |
171 int break_stack_height_; | 189 int break_stack_height_; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 // non-existing properties of the global object, so we must make it | 262 // non-existing properties of the global object, so we must make it |
245 // look like an explicit property access, instead of an access | 263 // look like an explicit property access, instead of an access |
246 // through the context chain. | 264 // through the context chain. |
247 void LoadTypeofExpression(Expression* x); | 265 void LoadTypeofExpression(Expression* x); |
248 | 266 |
249 // References | 267 // References |
250 | 268 |
251 // Generate code to fetch the value of a reference. The reference is | 269 // Generate code to fetch the value of a reference. The reference is |
252 // expected to be on top of the expression stack. It is left in place and | 270 // expected to be on top of the expression stack. It is left in place and |
253 // its value is pushed on top of it. | 271 // its value is pushed on top of it. |
254 void GetValue(Reference* ref); | 272 void GetValue(Reference* ref) { |
| 273 ASSERT(!has_cc()); |
| 274 ASSERT(!ref->is_illegal()); |
| 275 CodeGenState new_state(this, ref); |
| 276 Visit(ref->expression()); |
| 277 } |
255 | 278 |
256 // Generate code to store a value in a reference. The stored value is | 279 // Generate code to store a value in a reference. The stored value is |
257 // expected on top of the expression stack, with the reference immediately | 280 // expected on top of the expression stack, with the reference immediately |
258 // below it. The expression stack is left unchanged. | 281 // below it. The expression stack is left unchanged. |
259 void SetValue(Reference* ref) { | 282 void SetValue(Reference* ref) { |
260 ASSERT(!has_cc()); | 283 ASSERT(!has_cc()); |
261 ASSERT(!ref->is_illegal()); | 284 ASSERT(!ref->is_illegal()); |
262 ref->expression()->GenerateStoreCode(masm_, scope_, ref, NOT_CONST_INIT); | 285 ref->expression()->GenerateStoreCode(masm_, scope_, ref, NOT_CONST_INIT); |
263 } | 286 } |
264 | 287 |
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
349 | 372 |
350 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | 373 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); |
351 | 374 |
352 friend class Reference; | 375 friend class Reference; |
353 friend class Property; | 376 friend class Property; |
354 friend class VariableProxy; | 377 friend class VariableProxy; |
355 friend class Slot; | 378 friend class Slot; |
356 }; | 379 }; |
357 | 380 |
358 | 381 |
| 382 // ------------------------------------------------------------------------- |
| 383 // CodeGenState implementation. |
| 384 |
| 385 CodeGenState::CodeGenState(Ia32CodeGenerator* owner) |
| 386 : owner_(owner), |
| 387 access_(UNDEFINED), |
| 388 ref_(NULL), |
| 389 true_target_(NULL), |
| 390 false_target_(NULL), |
| 391 previous_(NULL) { |
| 392 owner_->set_state(this); |
| 393 } |
| 394 |
| 395 |
| 396 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, |
| 397 AccessType access, |
| 398 Label* true_target, |
| 399 Label* false_target) |
| 400 : owner_(owner), |
| 401 access_(access), |
| 402 ref_(NULL), |
| 403 true_target_(true_target), |
| 404 false_target_(false_target), |
| 405 previous_(owner->state()) { |
| 406 owner_->set_state(this); |
| 407 } |
| 408 |
| 409 |
| 410 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, Reference* ref) |
| 411 : owner_(owner), |
| 412 access_(LOAD), |
| 413 ref_(ref), |
| 414 true_target_(owner->state()->true_target_), |
| 415 false_target_(owner->state()->false_target_), |
| 416 previous_(owner->state()) { |
| 417 owner_->set_state(this); |
| 418 } |
| 419 |
| 420 |
| 421 CodeGenState::~CodeGenState() { |
| 422 ASSERT(owner_->state() == this); |
| 423 owner_->set_state(previous_); |
| 424 } |
| 425 |
| 426 |
359 // ----------------------------------------------------------------------------- | 427 // ----------------------------------------------------------------------------- |
360 // Ia32CodeGenerator implementation | 428 // Ia32CodeGenerator implementation |
361 | 429 |
362 #define __ masm_-> | 430 #define __ masm_-> |
363 | 431 |
364 | 432 |
365 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, | 433 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, |
366 Handle<Script> script, | 434 Handle<Script> script, |
367 bool is_eval) { | 435 bool is_eval) { |
368 #ifdef ENABLE_DISASSEMBLER | 436 #ifdef ENABLE_DISASSEMBLER |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
467 | 535 |
468 | 536 |
469 void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { | 537 void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { |
470 // Record the position for debugging purposes. | 538 // Record the position for debugging purposes. |
471 __ RecordPosition(fun->start_position()); | 539 __ RecordPosition(fun->start_position()); |
472 | 540 |
473 Scope* scope = fun->scope(); | 541 Scope* scope = fun->scope(); |
474 ZoneList<Statement*>* body = fun->body(); | 542 ZoneList<Statement*>* body = fun->body(); |
475 | 543 |
476 // Initialize state. | 544 // Initialize state. |
477 { CodeGenState state; | 545 { CodeGenState state(this); |
478 state_ = &state; | |
479 scope_ = scope; | 546 scope_ = scope; |
480 cc_reg_ = no_condition; | 547 cc_reg_ = no_condition; |
481 | 548 |
482 // Entry | 549 // Entry |
483 // stack: function, receiver, arguments, return address | 550 // stack: function, receiver, arguments, return address |
484 // esp: stack pointer | 551 // esp: stack pointer |
485 // ebp: frame pointer | 552 // ebp: frame pointer |
486 // edi: caller's parameter pointer | 553 // edi: caller's parameter pointer |
487 // esi: callee's context | 554 // esi: callee's context |
488 | 555 |
(...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
652 VisitStatements(body); | 719 VisitStatements(body); |
653 | 720 |
654 // Generate a return statement if necessary. | 721 // Generate a return statement if necessary. |
655 if (body->is_empty() || body->last()->AsReturnStatement() == NULL) { | 722 if (body->is_empty() || body->last()->AsReturnStatement() == NULL) { |
656 Literal undefined(Factory::undefined_value()); | 723 Literal undefined(Factory::undefined_value()); |
657 ReturnStatement statement(&undefined); | 724 ReturnStatement statement(&undefined); |
658 statement.set_statement_pos(fun->end_position()); | 725 statement.set_statement_pos(fun->end_position()); |
659 VisitReturnStatement(&statement); | 726 VisitReturnStatement(&statement); |
660 } | 727 } |
661 } | 728 } |
662 | |
663 state_ = NULL; | |
664 } | 729 } |
665 | 730 |
666 // Code generation state must be reset. | 731 // Code generation state must be reset. |
667 scope_ = NULL; | 732 scope_ = NULL; |
668 ASSERT(!has_cc()); | 733 ASSERT(!has_cc()); |
669 ASSERT(state_ == NULL); | 734 ASSERT(state_ == NULL); |
670 } | 735 } |
671 | 736 |
672 | 737 |
673 Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm, | 738 Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm, |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
733 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 798 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
734 void Ia32CodeGenerator::LoadCondition(Expression* x, | 799 void Ia32CodeGenerator::LoadCondition(Expression* x, |
735 CodeGenState::AccessType access, | 800 CodeGenState::AccessType access, |
736 Label* true_target, | 801 Label* true_target, |
737 Label* false_target, | 802 Label* false_target, |
738 bool force_cc) { | 803 bool force_cc) { |
739 ASSERT(access == CodeGenState::LOAD || | 804 ASSERT(access == CodeGenState::LOAD || |
740 access == CodeGenState::LOAD_TYPEOF_EXPR); | 805 access == CodeGenState::LOAD_TYPEOF_EXPR); |
741 ASSERT(!has_cc() && !is_referenced()); | 806 ASSERT(!has_cc() && !is_referenced()); |
742 | 807 |
743 CodeGenState* old_state = state_; | 808 { CodeGenState new_state(this, access, true_target, false_target); |
744 CodeGenState new_state(access, NULL, true_target, false_target); | 809 Visit(x); |
745 state_ = &new_state; | 810 } |
746 Visit(x); | |
747 state_ = old_state; | |
748 if (force_cc && !has_cc()) { | 811 if (force_cc && !has_cc()) { |
749 ToBoolean(true_target, false_target); | 812 ToBoolean(true_target, false_target); |
750 } | 813 } |
751 ASSERT(has_cc() || !force_cc); | 814 ASSERT(has_cc() || !force_cc); |
752 } | 815 } |
753 | 816 |
754 | 817 |
755 void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { | 818 void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { |
756 ASSERT(access == CodeGenState::LOAD || | 819 ASSERT(access == CodeGenState::LOAD || |
757 access == CodeGenState::LOAD_TYPEOF_EXPR); | 820 access == CodeGenState::LOAD_TYPEOF_EXPR); |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
885 __ pop(eax); | 948 __ pop(eax); |
886 __ mov(TOS, eax); | 949 __ mov(TOS, eax); |
887 } else { | 950 } else { |
888 __ pop(eax); | 951 __ pop(eax); |
889 __ add(Operand(esp), Immediate(size * kPointerSize)); | 952 __ add(Operand(esp), Immediate(size * kPointerSize)); |
890 __ push(eax); | 953 __ push(eax); |
891 } | 954 } |
892 } | 955 } |
893 | 956 |
894 | 957 |
895 void Ia32CodeGenerator::GetValue(Reference* ref) { | |
896 ASSERT(!has_cc()); | |
897 ASSERT(ref->type() != Reference::ILLEGAL); | |
898 CodeGenState* old_state = state_; | |
899 CodeGenState new_state(CodeGenState::LOAD, ref, true_target(), | |
900 false_target()); | |
901 state_ = &new_state; | |
902 Visit(ref->expression()); | |
903 state_ = old_state; | |
904 } | |
905 | |
906 | |
907 void Property::GenerateStoreCode(MacroAssembler* masm, | 958 void Property::GenerateStoreCode(MacroAssembler* masm, |
908 Scope* scope, | 959 Scope* scope, |
909 Reference* ref, | 960 Reference* ref, |
910 InitState init_state) { | 961 InitState init_state) { |
911 Comment cmnt(masm, "[ Store to Property"); | 962 Comment cmnt(masm, "[ Store to Property"); |
912 masm->RecordPosition(position()); | 963 masm->RecordPosition(position()); |
913 Ia32CodeGenerator::SetReferenceProperty(masm, ref, key()); | 964 Ia32CodeGenerator::SetReferenceProperty(masm, ref, key()); |
914 } | 965 } |
915 | 966 |
916 | 967 |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
968 masm->CallRuntime(Runtime::kStoreContextSlot, 3); | 1019 masm->CallRuntime(Runtime::kStoreContextSlot, 3); |
969 } | 1020 } |
970 // Storing a variable must keep the (new) value on the expression | 1021 // Storing a variable must keep the (new) value on the expression |
971 // stack. This is necessary for compiling assignment expressions. | 1022 // stack. This is necessary for compiling assignment expressions. |
972 masm->push(eax); | 1023 masm->push(eax); |
973 | 1024 |
974 } else { | 1025 } else { |
975 ASSERT(var()->mode() != Variable::DYNAMIC); | 1026 ASSERT(var()->mode() != Variable::DYNAMIC); |
976 | 1027 |
977 Label exit; | 1028 Label exit; |
978 bool may_skip_write = false; | |
979 if (init_state == CONST_INIT) { | 1029 if (init_state == CONST_INIT) { |
980 ASSERT(var()->mode() == Variable::CONST); | 1030 ASSERT(var()->mode() == Variable::CONST); |
981 // Only the first const initialization must be executed (the slot | 1031 // Only the first const initialization must be executed (the slot |
982 // still contains 'the hole' value). When the assignment is executed, | 1032 // still contains 'the hole' value). When the assignment is executed, |
983 // the code is identical to a normal store (see below). | 1033 // the code is identical to a normal store (see below). |
984 Comment cmnt(masm, "[ Init const"); | 1034 Comment cmnt(masm, "[ Init const"); |
985 masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); | 1035 masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); |
986 masm->cmp(eax, Factory::the_hole_value()); | 1036 masm->cmp(eax, Factory::the_hole_value()); |
987 masm->j(not_equal, &exit); | 1037 masm->j(not_equal, &exit); |
988 may_skip_write = true; | |
989 } | 1038 } |
990 | 1039 |
991 // We must execute the store. | 1040 // We must execute the store. |
992 // Storing a variable must keep the (new) value on the stack. This is | 1041 // Storing a variable must keep the (new) value on the stack. This is |
993 // necessary for compiling assignment expressions. ecx may be loaded | 1042 // necessary for compiling assignment expressions. ecx may be loaded |
994 // with context; used below in RecordWrite. | 1043 // with context; used below in RecordWrite. |
995 // | 1044 // |
996 // Note: We will reach here even with node->var()->mode() == | 1045 // Note: We will reach here even with node->var()->mode() == |
997 // Variable::CONST because of const declarations which will initialize | 1046 // Variable::CONST because of const declarations which will initialize |
998 // consts to 'the hole' value and by doing so, end up calling this | 1047 // consts to 'the hole' value and by doing so, end up calling this |
999 // code. | 1048 // code. |
1000 masm->pop(eax); | 1049 masm->pop(eax); |
1001 masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax); | 1050 masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax); |
1002 masm->push(eax); // RecordWrite may destroy the value in eax. | 1051 masm->push(eax); // RecordWrite may destroy the value in eax. |
1003 if (type() == Slot::CONTEXT) { | 1052 if (type() == Slot::CONTEXT) { |
1004 // ecx is loaded with context when calling SlotOperand above. | 1053 // ecx is loaded with context when calling SlotOperand above. |
1005 int offset = FixedArray::kHeaderSize + index() * kPointerSize; | 1054 int offset = FixedArray::kHeaderSize + index() * kPointerSize; |
1006 masm->RecordWrite(ecx, offset, eax, ebx); | 1055 masm->RecordWrite(ecx, offset, eax, ebx); |
1007 } | 1056 } |
1008 // If we definitely did not jump over the assignment, we do not need to | 1057 // If we definitely did not jump over the assignment, we do not need to |
1009 // bind the exit label. Doing so can defeat peephole optimization. | 1058 // bind the exit label. Doing so can defeat peephole optimization. |
1010 if (may_skip_write) masm->bind(&exit); | 1059 if (init_state == CONST_INIT) masm->bind(&exit); |
1011 } | 1060 } |
1012 } | 1061 } |
1013 | 1062 |
1014 | 1063 |
1015 #undef __ | 1064 #undef __ |
1016 #define __ masm-> | 1065 #define __ masm-> |
1017 | 1066 |
1018 class ToBooleanStub: public CodeStub { | 1067 class ToBooleanStub: public CodeStub { |
1019 public: | 1068 public: |
1020 ToBooleanStub() { } | 1069 ToBooleanStub() { } |
(...skipping 4427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5448 bool is_eval) { | 5497 bool is_eval) { |
5449 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | 5498 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); |
5450 if (!code.is_null()) { | 5499 if (!code.is_null()) { |
5451 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 5500 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
5452 } | 5501 } |
5453 return code; | 5502 return code; |
5454 } | 5503 } |
5455 | 5504 |
5456 | 5505 |
5457 } } // namespace v8::internal | 5506 } } // namespace v8::internal |
OLD | NEW |