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 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
44 // Reference support | 44 // Reference support |
45 | 45 |
46 // A reference is a C++ stack-allocated object that keeps an ECMA | 46 // A reference is a C++ stack-allocated object that keeps an ECMA |
47 // reference on the execution stack while in scope. For variables | 47 // reference on the execution stack while in scope. For variables |
48 // the reference is empty, indicating that it isn't necessary to | 48 // the reference is empty, indicating that it isn't necessary to |
49 // store state on the stack for keeping track of references to those. | 49 // store state on the stack for keeping track of references to those. |
50 // For properties, we keep either one (named) or two (indexed) values | 50 // For properties, we keep either one (named) or two (indexed) values |
51 // on the execution stack to represent the reference. | 51 // on the execution stack to represent the reference. |
52 | 52 |
53 enum InitState { CONST_INIT, NOT_CONST_INIT }; | 53 enum InitState { CONST_INIT, NOT_CONST_INIT }; |
54 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; | |
54 | 55 |
55 class Reference BASE_EMBEDDED { | 56 class Reference BASE_EMBEDDED { |
56 public: | 57 public: |
57 // The values of the types is important, see size(). | 58 // The values of the types is important, see size(). |
58 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; | 59 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; |
59 Reference(ArmCodeGenerator* cgen, Expression* expression); | 60 Reference(ArmCodeGenerator* cgen, Expression* expression); |
60 ~Reference(); | 61 ~Reference(); |
61 | 62 |
62 Expression* expression() const { return expression_; } | 63 Expression* expression() const { return expression_; } |
63 Type type() const { return type_; } | 64 Type type() const { return type_; } |
64 void set_type(Type value) { | 65 void set_type(Type value) { |
65 ASSERT(type_ == ILLEGAL); | 66 ASSERT(type_ == ILLEGAL); |
66 type_ = value; | 67 type_ = value; |
67 } | 68 } |
68 // The size of the reference or -1 if the reference is illegal. | 69 // The size of the reference or -1 if the reference is illegal. |
69 int size() const { return type_; } | 70 int size() const { return type_; } |
70 | 71 |
71 bool is_illegal() const { return type_ == ILLEGAL; } | 72 bool is_illegal() const { return type_ == ILLEGAL; } |
72 bool is_slot() const { return type_ == SLOT; } | 73 bool is_slot() const { return type_ == SLOT; } |
73 bool is_property() const { return type_ == NAMED || type_ == KEYED; } | 74 bool is_property() const { return type_ == NAMED || type_ == KEYED; } |
74 | 75 |
76 // Return the name. Only valid for named property references. | |
77 Handle<String> GetName(); | |
78 | |
79 // Generate code to push the value of the reference on top of the | |
80 // expression stack. The reference is expected to be already on top of | |
81 // the expression stack, and it is left in place with its value above it. | |
82 void GetValue(TypeofState typeof_state); | |
83 | |
84 // Generate code to store the value on top of the expression stack in the | |
85 // reference. The reference is expected to be immediately below the value | |
86 // on the expression stack. The stored value is left in place (with the | |
87 // reference intact below it) to support chained assignments. | |
75 void SetValue(InitState init_state); | 88 void SetValue(InitState init_state); |
76 | 89 |
77 private: | 90 private: |
78 ArmCodeGenerator* cgen_; | 91 ArmCodeGenerator* cgen_; |
79 Expression* expression_; | 92 Expression* expression_; |
80 Type type_; | 93 Type type_; |
81 }; | 94 }; |
82 | 95 |
83 | 96 |
84 // ------------------------------------------------------------------------- | 97 // ------------------------------------------------------------------------- |
85 // Code generation state | 98 // Code generation state |
86 | 99 |
87 // The state is passed down the AST by the code generator (and back up, in | 100 // The state is passed down the AST by the code generator (and back up, in |
88 // the form of the state of the label pair). It is threaded through the | 101 // the form of the state of the label pair). It is threaded through the |
89 // call stack. Constructing a state implicitly pushes it on the owning code | 102 // call stack. Constructing a state implicitly pushes it on the owning code |
90 // generator's stack of states, and destroying one implicitly pops it. | 103 // generator's stack of states, and destroying one implicitly pops it. |
91 | 104 |
92 class CodeGenState BASE_EMBEDDED { | 105 class CodeGenState BASE_EMBEDDED { |
93 public: | 106 public: |
94 enum AccessType { | |
95 UNDEFINED, | |
96 LOAD, | |
97 LOAD_TYPEOF_EXPR | |
98 }; | |
99 | |
100 // Create an initial code generator state. Destroying the initial state | 107 // Create an initial code generator state. Destroying the initial state |
101 // leaves the code generator with a NULL state. | 108 // leaves the code generator with a NULL state. |
102 explicit CodeGenState(ArmCodeGenerator* owner); | 109 explicit CodeGenState(ArmCodeGenerator* owner); |
103 | 110 |
104 // Create a code generator state based on a code generator's current | 111 // Create a code generator state based on a code generator's current |
105 // state. The new state has its own access type and pair of branch | 112 // state. The new state has its own typeof state and pair of branch |
106 // labels, and no reference. | 113 // labels. |
107 CodeGenState(ArmCodeGenerator* owner, | 114 CodeGenState(ArmCodeGenerator* owner, |
108 AccessType access, | 115 TypeofState typeof_state, |
109 Label* true_target, | 116 Label* true_target, |
110 Label* false_target); | 117 Label* false_target); |
111 | 118 |
112 // Create a code generator state based on a code generator's current | |
113 // state. The new state has an access type of LOAD, its own reference, | |
114 // and inherits the pair of branch labels of the current state. | |
115 CodeGenState(ArmCodeGenerator* owner, Reference* ref); | |
116 | |
117 // Destroy a code generator state and restore the owning code generator's | 119 // Destroy a code generator state and restore the owning code generator's |
118 // previous state. | 120 // previous state. |
119 ~CodeGenState(); | 121 ~CodeGenState(); |
120 | 122 |
121 AccessType access() const { return access_; } | 123 TypeofState typeof_state() const { return typeof_state_; } |
122 Reference* ref() const { return ref_; } | |
123 Label* true_target() const { return true_target_; } | 124 Label* true_target() const { return true_target_; } |
124 Label* false_target() const { return false_target_; } | 125 Label* false_target() const { return false_target_; } |
125 | 126 |
126 private: | 127 private: |
127 ArmCodeGenerator* owner_; | 128 ArmCodeGenerator* owner_; |
128 AccessType access_; | 129 TypeofState typeof_state_; |
129 Reference* ref_; | |
130 Label* true_target_; | 130 Label* true_target_; |
131 Label* false_target_; | 131 Label* false_target_; |
132 CodeGenState* previous_; | 132 CodeGenState* previous_; |
133 }; | 133 }; |
134 | 134 |
135 | 135 |
136 // ----------------------------------------------------------------------------- | 136 // ----------------------------------------------------------------------------- |
137 // ArmCodeGenerator | 137 // ArmCodeGenerator |
138 | 138 |
139 class ArmCodeGenerator: public CodeGenerator { | 139 class ArmCodeGenerator: public CodeGenerator { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
171 | 171 |
172 // Main code generation function | 172 // Main code generation function |
173 void GenCode(FunctionLiteral* fun); | 173 void GenCode(FunctionLiteral* fun); |
174 | 174 |
175 // The following are used by class Reference. | 175 // The following are used by class Reference. |
176 void LoadReference(Reference* ref); | 176 void LoadReference(Reference* ref); |
177 void UnloadReference(Reference* ref); | 177 void UnloadReference(Reference* ref); |
178 | 178 |
179 // State | 179 // State |
180 bool has_cc() const { return cc_reg_ != al; } | 180 bool has_cc() const { return cc_reg_ != al; } |
181 CodeGenState::AccessType access() const { return state_->access(); } | 181 TypeofState typeof_state() const { return state_->typeof_state(); } |
182 Reference* ref() const { return state_->ref(); } | |
183 bool is_referenced() const { return state_->ref() != NULL; } | |
184 Label* true_target() const { return state_->true_target(); } | 182 Label* true_target() const { return state_->true_target(); } |
185 Label* false_target() const { return state_->false_target(); } | 183 Label* false_target() const { return state_->false_target(); } |
186 | 184 |
187 | 185 |
188 // Expressions | 186 // Expressions |
189 MemOperand GlobalObject() const { | 187 MemOperand GlobalObject() const { |
190 return ContextOperand(cp, Context::GLOBAL_INDEX); | 188 return ContextOperand(cp, Context::GLOBAL_INDEX); |
191 } | 189 } |
192 | 190 |
193 MemOperand ContextOperand(Register context, int index) const { | 191 MemOperand ContextOperand(Register context, int index) const { |
194 return MemOperand(context, Context::SlotOffset(index)); | 192 return MemOperand(context, Context::SlotOffset(index)); |
195 } | 193 } |
196 | 194 |
197 MemOperand ParameterOperand(int index) const { | 195 MemOperand ParameterOperand(int index) const { |
198 int num_parameters = scope()->num_parameters(); | 196 int num_parameters = scope()->num_parameters(); |
199 // index -2 corresponds to the activated closure, -1 corresponds | 197 // index -2 corresponds to the activated closure, -1 corresponds |
200 // to the receiver | 198 // to the receiver |
201 ASSERT(-2 <= index && index < num_parameters); | 199 ASSERT(-2 <= index && index < num_parameters); |
202 int offset = (1 + num_parameters - index) * kPointerSize; | 200 int offset = (1 + num_parameters - index) * kPointerSize; |
203 return MemOperand(fp, offset); | 201 return MemOperand(fp, offset); |
204 } | 202 } |
205 | 203 |
206 MemOperand FunctionOperand() const { | 204 MemOperand FunctionOperand() const { |
207 return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset); | 205 return MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset); |
208 } | 206 } |
209 | 207 |
210 MemOperand SlotOperand(Slot* slot, Register tmp); | 208 MemOperand SlotOperand(Slot* slot, Register tmp); |
211 | 209 |
212 void LoadCondition(Expression* x, CodeGenState::AccessType access, | 210 void LoadCondition(Expression* x, |
213 Label* true_target, Label* false_target, bool force_cc); | 211 TypeofState typeof_state, |
214 void Load(Expression* x, | 212 Label* true_target, |
215 CodeGenState::AccessType access = CodeGenState::LOAD); | 213 Label* false_target, |
214 bool force_cc); | |
215 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); | |
216 void LoadGlobal(); | 216 void LoadGlobal(); |
217 | 217 |
218 // Read a value from a slot and leave it on top of the expression stack. | |
219 void LoadFromSlot(Slot* slot, TypeofState typeof_state); | |
220 | |
218 // Special code for typeof expressions: Unfortunately, we must | 221 // Special code for typeof expressions: Unfortunately, we must |
219 // be careful when loading the expression in 'typeof' | 222 // be careful when loading the expression in 'typeof' |
220 // expressions. We are not allowed to throw reference errors for | 223 // expressions. We are not allowed to throw reference errors for |
221 // non-existing properties of the global object, so we must make it | 224 // non-existing properties of the global object, so we must make it |
222 // look like an explicit property access, instead of an access | 225 // look like an explicit property access, instead of an access |
223 // through the context chain. | 226 // through the context chain. |
224 void LoadTypeofExpression(Expression* x); | 227 void LoadTypeofExpression(Expression* x); |
225 | 228 |
226 | |
227 // References | |
228 | |
229 // Generate code to fetch the value of a reference. The reference is | |
230 // expected to be on top of the expression stack. It is left in place and | |
231 // its value is pushed on top of it. | |
232 void GetValue(Reference* ref) { | |
233 ASSERT(!has_cc()); | |
234 ASSERT(!ref->is_illegal()); | |
235 CodeGenState new_state(this, ref); | |
236 Visit(ref->expression()); | |
237 } | |
238 | |
239 // Generate code to fetch a value from a property of a reference. The | |
240 // reference is expected on top of the expression stack. It is left in | |
241 // place and its value is pushed on top of it. | |
242 void GetReferenceProperty(Expression* key); | |
243 | |
244 void ToBoolean(Label* true_target, Label* false_target); | 229 void ToBoolean(Label* true_target, Label* false_target); |
245 | 230 |
246 void GenericBinaryOperation(Token::Value op); | 231 void GenericBinaryOperation(Token::Value op); |
247 void Comparison(Condition cc, bool strict = false); | 232 void Comparison(Condition cc, bool strict = false); |
248 | 233 |
249 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); | 234 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); |
250 | 235 |
251 void CallWithArguments(ZoneList<Expression*>* arguments, int position); | 236 void CallWithArguments(ZoneList<Expression*>* arguments, int position); |
252 | 237 |
253 // Declare global variables and functions in the given array of | 238 // Declare global variables and functions in the given array of |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
302 friend class VariableProxy; | 287 friend class VariableProxy; |
303 friend class Slot; | 288 friend class Slot; |
304 }; | 289 }; |
305 | 290 |
306 | 291 |
307 // ------------------------------------------------------------------------- | 292 // ------------------------------------------------------------------------- |
308 // CodeGenState implementation. | 293 // CodeGenState implementation. |
309 | 294 |
310 CodeGenState::CodeGenState(ArmCodeGenerator* owner) | 295 CodeGenState::CodeGenState(ArmCodeGenerator* owner) |
311 : owner_(owner), | 296 : owner_(owner), |
312 access_(UNDEFINED), | 297 typeof_state_(NOT_INSIDE_TYPEOF), |
313 ref_(NULL), | |
314 true_target_(NULL), | 298 true_target_(NULL), |
315 false_target_(NULL), | 299 false_target_(NULL), |
316 previous_(NULL) { | 300 previous_(NULL) { |
317 owner_->set_state(this); | 301 owner_->set_state(this); |
318 } | 302 } |
319 | 303 |
320 | 304 |
321 CodeGenState::CodeGenState(ArmCodeGenerator* owner, | 305 CodeGenState::CodeGenState(ArmCodeGenerator* owner, |
322 AccessType access, | 306 TypeofState typeof_state, |
323 Label* true_target, | 307 Label* true_target, |
324 Label* false_target) | 308 Label* false_target) |
325 : owner_(owner), | 309 : owner_(owner), |
326 access_(access), | 310 typeof_state_(typeof_state), |
327 ref_(NULL), | |
328 true_target_(true_target), | 311 true_target_(true_target), |
329 false_target_(false_target), | 312 false_target_(false_target), |
330 previous_(owner->state()) { | 313 previous_(owner->state()) { |
331 owner_->set_state(this); | 314 owner_->set_state(this); |
332 } | 315 } |
333 | 316 |
334 | 317 |
335 CodeGenState::CodeGenState(ArmCodeGenerator* owner, Reference* ref) | |
336 : owner_(owner), | |
337 access_(LOAD), | |
338 ref_(ref), | |
339 true_target_(owner->state()->true_target_), | |
340 false_target_(owner->state()->false_target_), | |
341 previous_(owner->state()) { | |
342 owner_->set_state(this); | |
343 } | |
344 | |
345 | |
346 CodeGenState::~CodeGenState() { | 318 CodeGenState::~CodeGenState() { |
347 ASSERT(owner_->state() == this); | 319 ASSERT(owner_->state() == this); |
348 owner_->set_state(previous_); | 320 owner_->set_state(previous_); |
349 } | 321 } |
350 | 322 |
351 | 323 |
352 // ----------------------------------------------------------------------------- | 324 // ----------------------------------------------------------------------------- |
353 // ArmCodeGenerator implementation | 325 // ArmCodeGenerator implementation |
354 | 326 |
355 #define __ masm_-> | 327 #define __ masm_-> |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
701 } | 673 } |
702 } | 674 } |
703 | 675 |
704 | 676 |
705 // Loads a value on the stack. If it is a boolean value, the result may have | 677 // Loads a value on the stack. If it is a boolean value, the result may have |
706 // been (partially) translated into branches, or it may have set the condition | 678 // been (partially) translated into branches, or it may have set the condition |
707 // code register. If force_cc is set, the value is forced to set the condition | 679 // code register. If force_cc is set, the value is forced to set the condition |
708 // code register and no value is pushed. If the condition code register was set, | 680 // code register and no value is pushed. If the condition code register was set, |
709 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 681 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
710 void ArmCodeGenerator::LoadCondition(Expression* x, | 682 void ArmCodeGenerator::LoadCondition(Expression* x, |
711 CodeGenState::AccessType access, | 683 TypeofState typeof_state, |
712 Label* true_target, | 684 Label* true_target, |
713 Label* false_target, | 685 Label* false_target, |
714 bool force_cc) { | 686 bool force_cc) { |
715 ASSERT(access == CodeGenState::LOAD || | 687 ASSERT(!has_cc()); |
716 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
717 ASSERT(!has_cc() && !is_referenced()); | |
718 | 688 |
719 { CodeGenState new_state(this, access, true_target, false_target); | 689 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
720 Visit(x); | 690 Visit(x); |
721 } | 691 } |
722 if (force_cc && !has_cc()) { | 692 if (force_cc && !has_cc()) { |
723 // Convert the TOS value to a boolean in the condition code register. | 693 // Convert the TOS value to a boolean in the condition code register. |
724 ToBoolean(true_target, false_target); | 694 ToBoolean(true_target, false_target); |
725 } | 695 } |
726 ASSERT(has_cc() || !force_cc); | 696 ASSERT(has_cc() || !force_cc); |
727 } | 697 } |
728 | 698 |
729 | 699 |
730 void ArmCodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { | 700 void ArmCodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
731 ASSERT(access == CodeGenState::LOAD || | |
732 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
733 | |
734 Label true_target; | 701 Label true_target; |
735 Label false_target; | 702 Label false_target; |
736 LoadCondition(x, access, &true_target, &false_target, false); | 703 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
737 | 704 |
738 if (has_cc()) { | 705 if (has_cc()) { |
739 // convert cc_reg_ into a bool | 706 // convert cc_reg_ into a bool |
740 Label loaded, materialize_true; | 707 Label loaded, materialize_true; |
741 __ b(cc_reg_, &materialize_true); | 708 __ b(cc_reg_, &materialize_true); |
742 __ mov(r0, Operand(Factory::false_value())); | 709 __ mov(r0, Operand(Factory::false_value())); |
743 __ push(r0); | 710 __ push(r0); |
744 __ b(&loaded); | 711 __ b(&loaded); |
745 __ bind(&materialize_true); | 712 __ bind(&materialize_true); |
746 __ mov(r0, Operand(Factory::true_value())); | 713 __ mov(r0, Operand(Factory::true_value())); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
779 } | 746 } |
780 | 747 |
781 | 748 |
782 void ArmCodeGenerator::LoadGlobal() { | 749 void ArmCodeGenerator::LoadGlobal() { |
783 __ ldr(r0, GlobalObject()); | 750 __ ldr(r0, GlobalObject()); |
784 __ push(r0); | 751 __ push(r0); |
785 } | 752 } |
786 | 753 |
787 | 754 |
788 // TODO(1241834): Get rid of this function in favor of just using Load, now | 755 // TODO(1241834): Get rid of this function in favor of just using Load, now |
789 // that we have the LOAD_TYPEOF_EXPR access type. => Need to handle | 756 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
790 // global variables w/o reference errors elsewhere. | 757 // variables w/o reference errors elsewhere. |
791 void ArmCodeGenerator::LoadTypeofExpression(Expression* x) { | 758 void ArmCodeGenerator::LoadTypeofExpression(Expression* x) { |
792 Variable* variable = x->AsVariableProxy()->AsVariable(); | 759 Variable* variable = x->AsVariableProxy()->AsVariable(); |
793 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 760 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
794 // NOTE: This is somewhat nasty. We force the compiler to load | 761 // NOTE: This is somewhat nasty. We force the compiler to load |
795 // the variable as if through '<global>.<variable>' to make sure we | 762 // the variable as if through '<global>.<variable>' to make sure we |
796 // do not get reference errors. | 763 // do not get reference errors. |
797 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 764 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
798 Literal key(variable->name()); | 765 Literal key(variable->name()); |
799 // TODO(1241834): Fetch the position from the variable instead of using | 766 // TODO(1241834): Fetch the position from the variable instead of using |
800 // no position. | 767 // no position. |
801 Property property(&global, &key, RelocInfo::kNoPosition); | 768 Property property(&global, &key, RelocInfo::kNoPosition); |
802 Load(&property); | 769 Load(&property); |
803 } else { | 770 } else { |
804 Load(x, CodeGenState::LOAD_TYPEOF_EXPR); | 771 Load(x, INSIDE_TYPEOF); |
805 } | 772 } |
806 } | 773 } |
807 | 774 |
808 | 775 |
809 Reference::Reference(ArmCodeGenerator* cgen, Expression* expression) | 776 Reference::Reference(ArmCodeGenerator* cgen, Expression* expression) |
810 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 777 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
811 cgen->LoadReference(this); | 778 cgen->LoadReference(this); |
812 } | 779 } |
813 | 780 |
814 | 781 |
815 Reference::~Reference() { | 782 Reference::~Reference() { |
816 cgen_->UnloadReference(this); | 783 cgen_->UnloadReference(this); |
817 } | 784 } |
818 | 785 |
819 | 786 |
820 void ArmCodeGenerator::LoadReference(Reference* ref) { | 787 void ArmCodeGenerator::LoadReference(Reference* ref) { |
788 Comment cmnt(masm_, "[ LoadReference"); | |
821 Expression* e = ref->expression(); | 789 Expression* e = ref->expression(); |
822 Property* property = e->AsProperty(); | 790 Property* property = e->AsProperty(); |
823 Variable* var = e->AsVariableProxy()->AsVariable(); | 791 Variable* var = e->AsVariableProxy()->AsVariable(); |
824 | 792 |
825 if (property != NULL) { | 793 if (property != NULL) { |
826 // The expression is either a property or a variable proxy that rewrites | 794 // The expression is either a property or a variable proxy that rewrites |
827 // to a property. | 795 // to a property. |
828 Load(property->obj()); | 796 Load(property->obj()); |
829 // We use a named reference if the key is a literal symbol, unless it is | 797 // We use a named reference if the key is a literal symbol, unless it is |
830 // a string that can be legally parsed as an integer. This is because | 798 // a string that can be legally parsed as an integer. This is because |
(...skipping 21 matching lines...) Expand all Loading... | |
852 } | 820 } |
853 } else { | 821 } else { |
854 // Anything else is a runtime error. | 822 // Anything else is a runtime error. |
855 Load(e); | 823 Load(e); |
856 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 824 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
857 } | 825 } |
858 } | 826 } |
859 | 827 |
860 | 828 |
861 void ArmCodeGenerator::UnloadReference(Reference* ref) { | 829 void ArmCodeGenerator::UnloadReference(Reference* ref) { |
830 Comment cmnt(masm_, "[ UnloadReference"); | |
862 int size = ref->size(); | 831 int size = ref->size(); |
863 if (size <= 0) { | 832 if (size <= 0) { |
864 // Do nothing. No popping is necessary. | 833 // Do nothing. No popping is necessary. |
865 } else { | 834 } else { |
866 __ pop(r0); | 835 __ pop(r0); |
867 __ add(sp, sp, Operand(size * kPointerSize)); | 836 __ add(sp, sp, Operand(size * kPointerSize)); |
868 __ push(r0); | 837 __ push(r0); |
869 } | 838 } |
870 } | 839 } |
871 | 840 |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
987 #ifdef DEBUG | 956 #ifdef DEBUG |
988 void Print() { | 957 void Print() { |
989 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", | 958 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n", |
990 static_cast<int>(kind_), | 959 static_cast<int>(kind_), |
991 argc_); | 960 argc_); |
992 } | 961 } |
993 #endif | 962 #endif |
994 }; | 963 }; |
995 | 964 |
996 | 965 |
997 void ArmCodeGenerator::GetReferenceProperty(Expression* key) { | |
998 ASSERT(!ref()->is_illegal()); | |
999 | |
1000 // TODO(1241834): Make sure that this it is safe to ignore the distinction | |
1001 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance | |
1002 // that reference errors can be thrown below, we must distinguish between | |
1003 // the two kinds of loads (typeof expression loads must not throw a | |
1004 // reference error). | |
1005 if (ref()->type() == Reference::NAMED) { | |
1006 // Compute the name of the property. | |
1007 Literal* literal = key->AsLiteral(); | |
1008 Handle<String> name(String::cast(*literal->handle())); | |
1009 | |
1010 // Call the appropriate IC code. | |
1011 // Setup the name register. | |
1012 __ mov(r2, Operand(name)); | |
1013 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
1014 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | |
1015 if (var != NULL) { | |
1016 ASSERT(var->is_global()); | |
1017 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
1018 } else { | |
1019 __ Call(ic, RelocInfo::CODE_TARGET); | |
1020 } | |
1021 | |
1022 } else { | |
1023 // Access keyed property. | |
1024 ASSERT(ref()->type() == Reference::KEYED); | |
1025 | |
1026 // TODO(1224671): Implement inline caching for keyed loads as on ia32. | |
1027 GetPropertyStub stub; | |
1028 __ CallStub(&stub); | |
1029 } | |
1030 __ push(r0); | |
1031 } | |
1032 | |
1033 | |
1034 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { | 966 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { |
1035 // sp[0] : y | 967 // sp[0] : y |
1036 // sp[1] : x | 968 // sp[1] : x |
1037 // result : r0 | 969 // result : r0 |
1038 | 970 |
1039 // Stub is entered with a call: 'return address' is in lr. | 971 // Stub is entered with a call: 'return address' is in lr. |
1040 switch (op) { | 972 switch (op) { |
1041 case Token::ADD: // fall through. | 973 case Token::ADD: // fall through. |
1042 case Token::SUB: // fall through. | 974 case Token::SUB: // fall through. |
1043 case Token::MUL: | 975 case Token::MUL: |
(...skipping 476 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1520 bool has_else_stm = node->HasElseStatement(); | 1452 bool has_else_stm = node->HasElseStatement(); |
1521 | 1453 |
1522 if (FLAG_debug_info) RecordStatementPosition(node); | 1454 if (FLAG_debug_info) RecordStatementPosition(node); |
1523 | 1455 |
1524 Label exit; | 1456 Label exit; |
1525 if (has_then_stm && has_else_stm) { | 1457 if (has_then_stm && has_else_stm) { |
1526 Comment cmnt(masm_, "[ IfThenElse"); | 1458 Comment cmnt(masm_, "[ IfThenElse"); |
1527 Label then; | 1459 Label then; |
1528 Label else_; | 1460 Label else_; |
1529 // if (cond) | 1461 // if (cond) |
1530 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); | 1462 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
1531 Branch(false, &else_); | 1463 Branch(false, &else_); |
1532 // then | 1464 // then |
1533 __ bind(&then); | 1465 __ bind(&then); |
1534 Visit(node->then_statement()); | 1466 Visit(node->then_statement()); |
1535 __ b(&exit); | 1467 __ b(&exit); |
1536 // else | 1468 // else |
1537 __ bind(&else_); | 1469 __ bind(&else_); |
1538 Visit(node->else_statement()); | 1470 Visit(node->else_statement()); |
1539 | 1471 |
1540 } else if (has_then_stm) { | 1472 } else if (has_then_stm) { |
1541 Comment cmnt(masm_, "[ IfThen"); | 1473 Comment cmnt(masm_, "[ IfThen"); |
1542 ASSERT(!has_else_stm); | 1474 ASSERT(!has_else_stm); |
1543 Label then; | 1475 Label then; |
1544 // if (cond) | 1476 // if (cond) |
1545 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true); | 1477 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); |
1546 Branch(false, &exit); | 1478 Branch(false, &exit); |
1547 // then | 1479 // then |
1548 __ bind(&then); | 1480 __ bind(&then); |
1549 Visit(node->then_statement()); | 1481 Visit(node->then_statement()); |
1550 | 1482 |
1551 } else if (has_else_stm) { | 1483 } else if (has_else_stm) { |
1552 Comment cmnt(masm_, "[ IfElse"); | 1484 Comment cmnt(masm_, "[ IfElse"); |
1553 ASSERT(!has_then_stm); | 1485 ASSERT(!has_then_stm); |
1554 Label else_; | 1486 Label else_; |
1555 // if (!cond) | 1487 // if (!cond) |
1556 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true); | 1488 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); |
1557 Branch(true, &exit); | 1489 Branch(true, &exit); |
1558 // else | 1490 // else |
1559 __ bind(&else_); | 1491 __ bind(&else_); |
1560 Visit(node->else_statement()); | 1492 Visit(node->else_statement()); |
1561 | 1493 |
1562 } else { | 1494 } else { |
1563 Comment cmnt(masm_, "[ If"); | 1495 Comment cmnt(masm_, "[ If"); |
1564 ASSERT(!has_then_stm && !has_else_stm); | 1496 ASSERT(!has_then_stm && !has_else_stm); |
1565 // if (cond) | 1497 // if (cond) |
1566 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false); | 1498 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
1567 if (has_cc()) { | 1499 if (has_cc()) { |
1568 cc_reg_ = al; | 1500 cc_reg_ = al; |
1569 } else { | 1501 } else { |
1570 __ pop(r0); // __ Pop(no_reg) | 1502 __ pop(r0); // __ Pop(no_reg) |
1571 } | 1503 } |
1572 } | 1504 } |
1573 | 1505 |
1574 // end | 1506 // end |
1575 __ bind(&exit); | 1507 __ bind(&exit); |
1576 } | 1508 } |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1799 switch (info) { | 1731 switch (info) { |
1800 case ALWAYS_TRUE: | 1732 case ALWAYS_TRUE: |
1801 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1733 CheckStack(); // TODO(1222600): ignore if body contains calls. |
1802 __ b(&loop); | 1734 __ b(&loop); |
1803 break; | 1735 break; |
1804 case ALWAYS_FALSE: | 1736 case ALWAYS_FALSE: |
1805 break; | 1737 break; |
1806 case DONT_KNOW: | 1738 case DONT_KNOW: |
1807 CheckStack(); // TODO(1222600): ignore if body contains calls. | 1739 CheckStack(); // TODO(1222600): ignore if body contains calls. |
1808 LoadCondition(node->cond(), | 1740 LoadCondition(node->cond(), |
1809 CodeGenState::LOAD, | 1741 NOT_INSIDE_TYPEOF, |
1810 &loop, | 1742 &loop, |
1811 node->break_target(), | 1743 node->break_target(), |
1812 true); | 1744 true); |
1813 Branch(true, &loop); | 1745 Branch(true, &loop); |
1814 break; | 1746 break; |
1815 } | 1747 } |
1816 | 1748 |
1817 // exit | 1749 // exit |
1818 __ bind(node->break_target()); | 1750 __ bind(node->break_target()); |
1819 } | 1751 } |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1965 | 1897 |
1966 | 1898 |
1967 __ bind(&end_del_check); | 1899 __ bind(&end_del_check); |
1968 | 1900 |
1969 // Store the entry in the 'each' expression and take another spin in the loop. | 1901 // Store the entry in the 'each' expression and take another spin in the loop. |
1970 // r3: i'th entry of the enum cache (or string there of) | 1902 // r3: i'th entry of the enum cache (or string there of) |
1971 __ push(r3); // push entry | 1903 __ push(r3); // push entry |
1972 { Reference each(this, node->each()); | 1904 { Reference each(this, node->each()); |
1973 if (!each.is_illegal()) { | 1905 if (!each.is_illegal()) { |
1974 if (each.size() > 0) { | 1906 if (each.size() > 0) { |
1975 // Reference's size is positive. | |
1976 __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); | 1907 __ ldr(r0, MemOperand(sp, kPointerSize * each.size())); |
1977 __ push(r0); | 1908 __ push(r0); |
1978 } | 1909 } |
1979 // If the reference was to a slot we rely on the convenient property | 1910 // If the reference was to a slot we rely on the convenient property |
1980 // that it doesn't matter whether a value (eg, r3 pushed above) is | 1911 // that it doesn't matter whether a value (eg, r3 pushed above) is |
1981 // right on top of or right underneath a zero-sized reference. | 1912 // right on top of or right underneath a zero-sized reference. |
1982 each.SetValue(NOT_CONST_INIT); | 1913 each.SetValue(NOT_CONST_INIT); |
1983 if (each.size() > 0) { | 1914 if (each.size() > 0) { |
1984 // It's safe to pop the value lying on top of the reference before | 1915 // It's safe to pop the value lying on top of the reference before |
1985 // unloading the reference itself (which preserves the top of stack, | 1916 // unloading the reference itself (which preserves the top of stack, |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2266 void ArmCodeGenerator::VisitFunctionBoilerplateLiteral( | 2197 void ArmCodeGenerator::VisitFunctionBoilerplateLiteral( |
2267 FunctionBoilerplateLiteral* node) { | 2198 FunctionBoilerplateLiteral* node) { |
2268 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2199 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
2269 InstantiateBoilerplate(node->boilerplate()); | 2200 InstantiateBoilerplate(node->boilerplate()); |
2270 } | 2201 } |
2271 | 2202 |
2272 | 2203 |
2273 void ArmCodeGenerator::VisitConditional(Conditional* node) { | 2204 void ArmCodeGenerator::VisitConditional(Conditional* node) { |
2274 Comment cmnt(masm_, "[ Conditional"); | 2205 Comment cmnt(masm_, "[ Conditional"); |
2275 Label then, else_, exit; | 2206 Label then, else_, exit; |
2276 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); | 2207 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
2277 Branch(false, &else_); | 2208 Branch(false, &else_); |
2278 __ bind(&then); | 2209 __ bind(&then); |
2279 Load(node->then_expression(), access()); | 2210 Load(node->then_expression(), typeof_state()); |
2280 __ b(&exit); | 2211 __ b(&exit); |
2281 __ bind(&else_); | 2212 __ bind(&else_); |
2282 Load(node->else_expression(), access()); | 2213 Load(node->else_expression(), typeof_state()); |
2283 __ bind(&exit); | 2214 __ bind(&exit); |
2284 } | 2215 } |
2285 | 2216 |
2286 | 2217 |
2287 void ArmCodeGenerator::VisitSlot(Slot* node) { | 2218 void ArmCodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
2288 ASSERT(access() != CodeGenState::UNDEFINED); | 2219 if (slot->type() == Slot::LOOKUP) { |
2289 Comment cmnt(masm_, "[ Slot"); | 2220 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
2290 | |
2291 if (node->type() == Slot::LOOKUP) { | |
2292 ASSERT(node->var()->mode() == Variable::DYNAMIC); | |
2293 | 2221 |
2294 // For now, just do a runtime call. | 2222 // For now, just do a runtime call. |
2295 __ push(cp); | 2223 __ push(cp); |
2296 __ mov(r0, Operand(node->var()->name())); | 2224 __ mov(r0, Operand(slot->var()->name())); |
2297 __ push(r0); | 2225 __ push(r0); |
2298 | 2226 |
2299 if (access() == CodeGenState::LOAD) { | 2227 if (typeof_state == INSIDE_TYPEOF) { |
2228 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
2229 } else { | |
2300 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2230 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
2301 } else { | |
2302 ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR); | |
2303 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
2304 } | 2231 } |
2305 __ push(r0); | 2232 __ push(r0); |
2306 | 2233 |
2307 } else { | 2234 } else { |
2308 // Note: We would like to keep the assert below, but it fires because of | 2235 // Note: We would like to keep the assert below, but it fires because of |
2309 // some nasty code in LoadTypeofExpression() which should be removed... | 2236 // some nasty code in LoadTypeofExpression() which should be removed... |
2310 // ASSERT(node->var()->mode() != Variable::DYNAMIC); | 2237 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
2311 | 2238 |
2312 // Special handling for locals allocated in registers. | 2239 // Special handling for locals allocated in registers. |
2313 __ ldr(r0, SlotOperand(node, r2)); | 2240 __ ldr(r0, SlotOperand(slot, r2)); |
2314 __ push(r0); | 2241 __ push(r0); |
2315 if (node->var()->mode() == Variable::CONST) { | 2242 if (slot->var()->mode() == Variable::CONST) { |
2316 // Const slots may contain 'the hole' value (the constant hasn't been | 2243 // Const slots may contain 'the hole' value (the constant hasn't been |
2317 // initialized yet) which needs to be converted into the 'undefined' | 2244 // initialized yet) which needs to be converted into the 'undefined' |
2318 // value. | 2245 // value. |
2319 Comment cmnt(masm_, "[ Unhole const"); | 2246 Comment cmnt(masm_, "[ Unhole const"); |
2320 __ pop(r0); | 2247 __ pop(r0); |
2321 __ cmp(r0, Operand(Factory::the_hole_value())); | 2248 __ cmp(r0, Operand(Factory::the_hole_value())); |
2322 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); | 2249 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
2323 __ push(r0); | 2250 __ push(r0); |
2324 } | 2251 } |
2325 } | 2252 } |
2326 } | 2253 } |
2327 | 2254 |
2328 | 2255 |
2256 void ArmCodeGenerator::VisitSlot(Slot* node) { | |
2257 Comment cmnt(masm_, "[ Slot"); | |
2258 LoadFromSlot(node, typeof_state()); | |
2259 } | |
2260 | |
2261 | |
2329 void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2262 void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) { |
2330 Comment cmnt(masm_, "[ VariableProxy"); | 2263 Comment cmnt(masm_, "[ VariableProxy"); |
2331 Variable* var_node = node->var(); | 2264 Variable* var = node->var(); |
2332 | 2265 Expression* expr = var->rewrite(); |
2333 Expression* expr = var_node->rewrite(); | |
2334 if (expr != NULL) { | 2266 if (expr != NULL) { |
2335 Visit(expr); | 2267 Visit(expr); |
2336 } else { | 2268 } else { |
2337 ASSERT(var_node->is_global()); | 2269 ASSERT(var->is_global()); |
2338 if (is_referenced()) { | 2270 Reference ref(this, node); |
2339 if (var_node->AsProperty() != NULL) { | 2271 ref.GetValue(typeof_state()); |
2340 __ RecordPosition(var_node->AsProperty()->position()); | |
2341 } | |
2342 GetReferenceProperty(new Literal(var_node->name())); | |
2343 } else { | |
2344 Reference property(this, node); | |
2345 GetValue(&property); | |
2346 } | |
2347 } | 2272 } |
2348 } | 2273 } |
2349 | 2274 |
2350 | 2275 |
2351 void ArmCodeGenerator::VisitLiteral(Literal* node) { | 2276 void ArmCodeGenerator::VisitLiteral(Literal* node) { |
2352 Comment cmnt(masm_, "[ Literal"); | 2277 Comment cmnt(masm_, "[ Literal"); |
2353 __ mov(r0, Operand(node->handle())); | 2278 __ mov(r0, Operand(node->handle())); |
2354 __ push(r0); | 2279 __ push(r0); |
2355 } | 2280 } |
2356 | 2281 |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2549 | 2474 |
2550 Reference target(this, node->target()); | 2475 Reference target(this, node->target()); |
2551 if (target.is_illegal()) return; | 2476 if (target.is_illegal()) return; |
2552 | 2477 |
2553 if (node->op() == Token::ASSIGN || | 2478 if (node->op() == Token::ASSIGN || |
2554 node->op() == Token::INIT_VAR || | 2479 node->op() == Token::INIT_VAR || |
2555 node->op() == Token::INIT_CONST) { | 2480 node->op() == Token::INIT_CONST) { |
2556 Load(node->value()); | 2481 Load(node->value()); |
2557 | 2482 |
2558 } else { | 2483 } else { |
2559 GetValue(&target); | 2484 target.GetValue(NOT_INSIDE_TYPEOF); |
2560 Literal* literal = node->value()->AsLiteral(); | 2485 Literal* literal = node->value()->AsLiteral(); |
2561 if (literal != NULL && literal->handle()->IsSmi()) { | 2486 if (literal != NULL && literal->handle()->IsSmi()) { |
2562 SmiOperation(node->binary_op(), literal->handle(), false); | 2487 SmiOperation(node->binary_op(), literal->handle(), false); |
2563 __ push(r0); | 2488 __ push(r0); |
2564 | 2489 |
2565 } else { | 2490 } else { |
2566 Load(node->value()); | 2491 Load(node->value()); |
2567 GenericBinaryOperation(node->binary_op()); | 2492 GenericBinaryOperation(node->binary_op()); |
2568 __ push(r0); | 2493 __ push(r0); |
2569 } | 2494 } |
(...skipping 24 matching lines...) Expand all Loading... | |
2594 | 2519 |
2595 Load(node->exception()); | 2520 Load(node->exception()); |
2596 __ RecordPosition(node->position()); | 2521 __ RecordPosition(node->position()); |
2597 __ CallRuntime(Runtime::kThrow, 1); | 2522 __ CallRuntime(Runtime::kThrow, 1); |
2598 __ push(r0); | 2523 __ push(r0); |
2599 } | 2524 } |
2600 | 2525 |
2601 | 2526 |
2602 void ArmCodeGenerator::VisitProperty(Property* node) { | 2527 void ArmCodeGenerator::VisitProperty(Property* node) { |
2603 Comment cmnt(masm_, "[ Property"); | 2528 Comment cmnt(masm_, "[ Property"); |
2604 | 2529 Reference property(this, node); |
2605 if (is_referenced()) { | 2530 property.GetValue(typeof_state()); |
2606 __ RecordPosition(node->position()); | |
2607 GetReferenceProperty(node->key()); | |
2608 } else { | |
2609 Reference property(this, node); | |
2610 __ RecordPosition(node->position()); | |
2611 GetValue(&property); | |
2612 } | |
2613 } | 2531 } |
2614 | 2532 |
2615 | 2533 |
2616 void ArmCodeGenerator::VisitCall(Call* node) { | 2534 void ArmCodeGenerator::VisitCall(Call* node) { |
2617 Comment cmnt(masm_, "[ Call"); | 2535 Comment cmnt(masm_, "[ Call"); |
2618 | 2536 |
2619 ZoneList<Expression*>* args = node->arguments(); | 2537 ZoneList<Expression*>* args = node->arguments(); |
2620 | 2538 |
2621 if (FLAG_debug_info) RecordStatementPosition(node); | 2539 if (FLAG_debug_info) RecordStatementPosition(node); |
2622 // Standard function call. | 2540 // Standard function call. |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2706 | 2624 |
2707 __ push(r0); // push after get rid of function from the stack | 2625 __ push(r0); // push after get rid of function from the stack |
2708 | 2626 |
2709 } else { | 2627 } else { |
2710 // ------------------------------------------- | 2628 // ------------------------------------------- |
2711 // JavaScript example: 'array[index](1, 2, 3)' | 2629 // JavaScript example: 'array[index](1, 2, 3)' |
2712 // ------------------------------------------- | 2630 // ------------------------------------------- |
2713 | 2631 |
2714 // Load the function to call from the property through a reference. | 2632 // Load the function to call from the property through a reference. |
2715 Reference ref(this, property); | 2633 Reference ref(this, property); |
2716 GetValue(&ref); // receiver | 2634 ref.GetValue(NOT_INSIDE_TYPEOF); // receiver |
2717 | 2635 |
2718 // Pass receiver to called function. | 2636 // Pass receiver to called function. |
2719 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); | 2637 __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize)); |
2720 __ push(r0); | 2638 __ push(r0); |
2721 // Call the function. | 2639 // Call the function. |
2722 CallWithArguments(args, node->position()); | 2640 CallWithArguments(args, node->position()); |
2723 __ push(r0); | 2641 __ push(r0); |
2724 } | 2642 } |
2725 | 2643 |
2726 } else { | 2644 } else { |
(...skipping 223 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2950 } | 2868 } |
2951 | 2869 |
2952 | 2870 |
2953 void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2871 void ArmCodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
2954 Comment cmnt(masm_, "[ UnaryOperation"); | 2872 Comment cmnt(masm_, "[ UnaryOperation"); |
2955 | 2873 |
2956 Token::Value op = node->op(); | 2874 Token::Value op = node->op(); |
2957 | 2875 |
2958 if (op == Token::NOT) { | 2876 if (op == Token::NOT) { |
2959 LoadCondition(node->expression(), | 2877 LoadCondition(node->expression(), |
2960 CodeGenState::LOAD, | 2878 NOT_INSIDE_TYPEOF, |
2961 false_target(), | 2879 false_target(), |
2962 true_target(), | 2880 true_target(), |
2963 true); | 2881 true); |
2964 cc_reg_ = NegateCondition(cc_reg_); | 2882 cc_reg_ = NegateCondition(cc_reg_); |
2965 | 2883 |
2966 } else if (op == Token::DELETE) { | 2884 } else if (op == Token::DELETE) { |
2967 Property* property = node->expression()->AsProperty(); | 2885 Property* property = node->expression()->AsProperty(); |
2968 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); | 2886 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); |
2969 if (property != NULL) { | 2887 if (property != NULL) { |
2970 Load(property->obj()); | 2888 Load(property->obj()); |
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3085 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3003 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
3086 | 3004 |
3087 // Postfix: Make room for the result. | 3005 // Postfix: Make room for the result. |
3088 if (is_postfix) { | 3006 if (is_postfix) { |
3089 __ mov(r0, Operand(0)); | 3007 __ mov(r0, Operand(0)); |
3090 __ push(r0); | 3008 __ push(r0); |
3091 } | 3009 } |
3092 | 3010 |
3093 { Reference target(this, node->expression()); | 3011 { Reference target(this, node->expression()); |
3094 if (target.is_illegal()) return; | 3012 if (target.is_illegal()) return; |
3095 GetValue(&target); | 3013 target.GetValue(NOT_INSIDE_TYPEOF); |
3096 __ pop(r0); | 3014 __ pop(r0); |
3097 | 3015 |
3098 Label slow, exit; | 3016 Label slow, exit; |
3099 | 3017 |
3100 // Load the value (1) into register r1. | 3018 // Load the value (1) into register r1. |
3101 __ mov(r1, Operand(Smi::FromInt(1))); | 3019 __ mov(r1, Operand(Smi::FromInt(1))); |
3102 | 3020 |
3103 // Check for smi operand. | 3021 // Check for smi operand. |
3104 __ tst(r0, Operand(kSmiTagMask)); | 3022 __ tst(r0, Operand(kSmiTagMask)); |
3105 __ b(ne, &slow); | 3023 __ b(ne, &slow); |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3167 // NOTE: If the left hand side produces a materialized value (not in | 3085 // NOTE: If the left hand side produces a materialized value (not in |
3168 // the CC register), we force the right hand side to do the | 3086 // the CC register), we force the right hand side to do the |
3169 // same. This is necessary because we may have to branch to the exit | 3087 // same. This is necessary because we may have to branch to the exit |
3170 // after evaluating the left hand side (due to the shortcut | 3088 // after evaluating the left hand side (due to the shortcut |
3171 // semantics), but the compiler must (statically) know if the result | 3089 // semantics), but the compiler must (statically) know if the result |
3172 // of compiling the binary operation is materialized or not. | 3090 // of compiling the binary operation is materialized or not. |
3173 | 3091 |
3174 if (op == Token::AND) { | 3092 if (op == Token::AND) { |
3175 Label is_true; | 3093 Label is_true; |
3176 LoadCondition(node->left(), | 3094 LoadCondition(node->left(), |
3177 CodeGenState::LOAD, | 3095 NOT_INSIDE_TYPEOF, |
3178 &is_true, | 3096 &is_true, |
3179 false_target(), | 3097 false_target(), |
3180 false); | 3098 false); |
3181 if (has_cc()) { | 3099 if (has_cc()) { |
3182 Branch(false, false_target()); | 3100 Branch(false, false_target()); |
3183 | 3101 |
3184 // Evaluate right side expression. | 3102 // Evaluate right side expression. |
3185 __ bind(&is_true); | 3103 __ bind(&is_true); |
3186 LoadCondition(node->right(), | 3104 LoadCondition(node->right(), |
3187 CodeGenState::LOAD, | 3105 NOT_INSIDE_TYPEOF, |
3188 true_target(), | 3106 true_target(), |
3189 false_target(), | 3107 false_target(), |
3190 false); | 3108 false); |
3191 | 3109 |
3192 } else { | 3110 } else { |
3193 Label pop_and_continue, exit; | 3111 Label pop_and_continue, exit; |
3194 | 3112 |
3195 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top | 3113 __ ldr(r0, MemOperand(sp, 0)); // dup the stack top |
3196 __ push(r0); | 3114 __ push(r0); |
3197 // Avoid popping the result if it converts to 'false' using the | 3115 // Avoid popping the result if it converts to 'false' using the |
(...skipping 10 matching lines...) Expand all Loading... | |
3208 __ bind(&is_true); | 3126 __ bind(&is_true); |
3209 Load(node->right()); | 3127 Load(node->right()); |
3210 | 3128 |
3211 // Exit (always with a materialized value). | 3129 // Exit (always with a materialized value). |
3212 __ bind(&exit); | 3130 __ bind(&exit); |
3213 } | 3131 } |
3214 | 3132 |
3215 } else if (op == Token::OR) { | 3133 } else if (op == Token::OR) { |
3216 Label is_false; | 3134 Label is_false; |
3217 LoadCondition(node->left(), | 3135 LoadCondition(node->left(), |
3218 CodeGenState::LOAD, | 3136 NOT_INSIDE_TYPEOF, |
3219 true_target(), | 3137 true_target(), |
3220 &is_false, | 3138 &is_false, |
3221 false); | 3139 false); |
3222 if (has_cc()) { | 3140 if (has_cc()) { |
3223 Branch(true, true_target()); | 3141 Branch(true, true_target()); |
3224 | 3142 |
3225 // Evaluate right side expression. | 3143 // Evaluate right side expression. |
3226 __ bind(&is_false); | 3144 __ bind(&is_false); |
3227 LoadCondition(node->right(), | 3145 LoadCondition(node->right(), |
3228 CodeGenState::LOAD, | 3146 NOT_INSIDE_TYPEOF, |
3229 true_target(), | 3147 true_target(), |
3230 false_target(), | 3148 false_target(), |
3231 false); | 3149 false); |
3232 | 3150 |
3233 } else { | 3151 } else { |
3234 Label pop_and_continue, exit; | 3152 Label pop_and_continue, exit; |
3235 | 3153 |
3236 __ ldr(r0, MemOperand(sp, 0)); | 3154 __ ldr(r0, MemOperand(sp, 0)); |
3237 __ push(r0); | 3155 __ push(r0); |
3238 // Avoid popping the result if it converts to 'true' using the | 3156 // Avoid popping the result if it converts to 'true' using the |
(...skipping 271 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3510 // Drop the execution stack down to the frame pointer and restore the caller | 3428 // Drop the execution stack down to the frame pointer and restore the caller |
3511 // frame pointer and return address. | 3429 // frame pointer and return address. |
3512 __ mov(sp, fp); | 3430 __ mov(sp, fp); |
3513 __ ldm(ia_w, sp, fp.bit() | lr.bit()); | 3431 __ ldm(ia_w, sp, fp.bit() | lr.bit()); |
3514 } | 3432 } |
3515 | 3433 |
3516 | 3434 |
3517 #undef __ | 3435 #undef __ |
3518 #define __ masm-> | 3436 #define __ masm-> |
3519 | 3437 |
3438 Handle<String> Reference::GetName() { | |
3439 ASSERT(type_ == NAMED); | |
3440 Property* property = expression_->AsProperty(); | |
3441 if (property == NULL) { | |
3442 // Global variable reference treated as a named property reference. | |
3443 VariableProxy* proxy = expression_->AsVariableProxy(); | |
3444 ASSERT(proxy->AsVariable() != NULL); | |
3445 ASSERT(proxy->AsVariable()->is_global()); | |
3446 return proxy->name(); | |
3447 } else { | |
3448 Literal* raw_name = property->key()->AsLiteral(); | |
3449 ASSERT(raw_name != NULL); | |
3450 return Handle<String>(String::cast(*raw_name->handle())); | |
3451 } | |
3452 } | |
3453 | |
3454 | |
3455 void Reference::GetValue(TypeofState typeof_state) { | |
3456 ASSERT(!is_illegal()); | |
3457 ASSERT(!cgen_->has_cc()); | |
3458 MacroAssembler* masm = cgen_->masm(); | |
3459 Property* property = expression_->AsProperty(); | |
3460 if (property != NULL) { | |
3461 __ RecordPosition(property->position()); | |
3462 } | |
3463 | |
3464 switch (type_) { | |
3465 case SLOT: { | |
3466 Comment cmnt(masm, "[ Load from Slot"); | |
3467 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | |
3468 ASSERT(slot != NULL); | |
3469 cgen_->LoadFromSlot(slot, typeof_state); | |
3470 break; | |
3471 } | |
3472 | |
3473 case NAMED: { | |
3474 // TODO(1241834): Make sure that this it is safe to ignore the | |
3475 // distinction between expressions ina typeof and not in a typeof. If | |
iposva
2008/10/07 19:43:31
ina -> in a
| |
3476 // there is a chance that reference errors can be thrown below, we | |
3477 // must distinguish between the two kinds of loads (typeof expression | |
3478 // loads must not throw a reference error). | |
3479 Comment cmnt(masm, "[ Load from named Property"); | |
3480 // Setup the name register. | |
3481 Handle<String> name(GetName()); | |
3482 __ mov(r2, Operand(name)); | |
3483 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
3484 | |
3485 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
3486 if (var != NULL) { | |
3487 ASSERT(var->is_global()); | |
3488 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
3489 } else { | |
3490 __ Call(ic, RelocInfo::CODE_TARGET); | |
3491 } | |
3492 __ push(r0); | |
3493 break; | |
3494 } | |
3495 | |
3496 case KEYED: { | |
3497 // TODO(1241834): Make sure that this it is safe to ignore the | |
3498 // distinction between expressions ina typeof and not in a typeof. | |
iposva
2008/10/07 19:43:31
ina -> in a
| |
3499 Comment cmnt(masm, "[ Load from keyed Property"); | |
3500 ASSERT(property != NULL); | |
3501 // TODO(1224671): Implement inline caching for keyed loads as on ia32. | |
3502 GetPropertyStub stub; | |
3503 __ CallStub(&stub); | |
3504 __ push(r0); | |
3505 break; | |
3506 } | |
3507 | |
3508 default: | |
3509 UNREACHABLE(); | |
3510 } | |
3511 } | |
3512 | |
3513 | |
3520 void Reference::SetValue(InitState init_state) { | 3514 void Reference::SetValue(InitState init_state) { |
3521 ASSERT(!is_illegal()); | 3515 ASSERT(!is_illegal()); |
3522 ASSERT(!cgen_->has_cc()); | 3516 ASSERT(!cgen_->has_cc()); |
3523 MacroAssembler* masm = cgen_->masm(); | 3517 MacroAssembler* masm = cgen_->masm(); |
3518 Property* property = expression_->AsProperty(); | |
3519 if (property != NULL) { | |
3520 __ RecordPosition(property->position()); | |
3521 } | |
3522 | |
3524 switch (type_) { | 3523 switch (type_) { |
3525 case SLOT: { | 3524 case SLOT: { |
3526 Comment cmnt(masm, "[ Store to Slot"); | 3525 Comment cmnt(masm, "[ Store to Slot"); |
3527 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 3526 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
3528 ASSERT(slot != NULL); | 3527 ASSERT(slot != NULL); |
3529 if (slot->type() == Slot::LOOKUP) { | 3528 if (slot->type() == Slot::LOOKUP) { |
3530 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 3529 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
3531 | 3530 |
3532 // For now, just do a runtime call. | 3531 // For now, just do a runtime call. |
3533 __ push(cp); | 3532 __ push(cp); |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3599 // optimization. | 3598 // optimization. |
3600 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { | 3599 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) { |
3601 __ bind(&exit); | 3600 __ bind(&exit); |
3602 } | 3601 } |
3603 } | 3602 } |
3604 break; | 3603 break; |
3605 } | 3604 } |
3606 | 3605 |
3607 case NAMED: { | 3606 case NAMED: { |
3608 Comment cmnt(masm, "[ Store to named Property"); | 3607 Comment cmnt(masm, "[ Store to named Property"); |
3609 Property* property = expression_->AsProperty(); | |
3610 Handle<String> name; | |
3611 if (property == NULL) { | |
3612 // Global variable reference treated as named property access. | |
3613 VariableProxy* proxy = expression_->AsVariableProxy(); | |
3614 ASSERT(proxy->AsVariable() != NULL); | |
3615 ASSERT(proxy->AsVariable()->is_global()); | |
3616 name = proxy->name(); | |
3617 } else { | |
3618 Literal* raw_name = property->key()->AsLiteral(); | |
3619 ASSERT(raw_name != NULL); | |
3620 name = Handle<String>(String::cast(*raw_name->handle())); | |
3621 __ RecordPosition(property->position()); | |
3622 } | |
3623 | |
3624 // Call the appropriate IC code. | 3608 // Call the appropriate IC code. |
3625 __ pop(r0); // value | 3609 __ pop(r0); // value |
3626 // Setup the name register. | 3610 // Setup the name register. |
3611 Handle<String> name(GetName()); | |
3627 __ mov(r2, Operand(name)); | 3612 __ mov(r2, Operand(name)); |
3628 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 3613 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
3629 __ Call(ic, RelocInfo::CODE_TARGET); | 3614 __ Call(ic, RelocInfo::CODE_TARGET); |
3630 __ push(r0); | 3615 __ push(r0); |
3631 break; | 3616 break; |
3632 } | 3617 } |
3633 | 3618 |
3634 case KEYED: { | 3619 case KEYED: { |
3635 Comment cmnt(masm, "[ Store to keyed Property"); | 3620 Comment cmnt(masm, "[ Store to keyed Property"); |
3636 Property* property = expression_->AsProperty(); | 3621 Property* property = expression_->AsProperty(); |
(...skipping 895 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4532 bool is_eval) { | 4517 bool is_eval) { |
4533 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); | 4518 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); |
4534 if (!code.is_null()) { | 4519 if (!code.is_null()) { |
4535 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 4520 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
4536 } | 4521 } |
4537 return code; | 4522 return code; |
4538 } | 4523 } |
4539 | 4524 |
4540 | 4525 |
4541 } } // namespace v8::internal | 4526 } } // namespace v8::internal |
OLD | NEW |