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 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
50 // Reference support | 50 // Reference support |
51 | 51 |
52 // A reference is a C++ stack-allocated object that keeps an ECMA | 52 // A reference is a C++ stack-allocated object that keeps an ECMA |
53 // reference on the execution stack while in scope. For variables | 53 // reference on the execution stack while in scope. For variables |
54 // the reference is empty, indicating that it isn't necessary to | 54 // the reference is empty, indicating that it isn't necessary to |
55 // store state on the stack for keeping track of references to those. | 55 // store state on the stack for keeping track of references to those. |
56 // For properties, we keep either one (named) or two (indexed) values | 56 // For properties, we keep either one (named) or two (indexed) values |
57 // on the execution stack to represent the reference. | 57 // on the execution stack to represent the reference. |
58 | 58 |
59 enum InitState { CONST_INIT, NOT_CONST_INIT }; | 59 enum InitState { CONST_INIT, NOT_CONST_INIT }; |
60 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; | |
60 | 61 |
61 class Reference BASE_EMBEDDED { | 62 class Reference BASE_EMBEDDED { |
62 public: | 63 public: |
63 // The values of the types is important, see size(). | 64 // The values of the types is important, see size(). |
64 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; | 65 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; |
65 Reference(Ia32CodeGenerator* cgen, Expression* expression); | 66 Reference(Ia32CodeGenerator* cgen, Expression* expression); |
66 ~Reference(); | 67 ~Reference(); |
67 | 68 |
68 Expression* expression() const { return expression_; } | 69 Expression* expression() const { return expression_; } |
69 Type type() const { return type_; } | 70 Type type() const { return type_; } |
70 void set_type(Type value) { | 71 void set_type(Type value) { |
71 ASSERT(type_ == ILLEGAL); | 72 ASSERT(type_ == ILLEGAL); |
72 type_ = value; | 73 type_ = value; |
73 } | 74 } |
74 | 75 |
75 // The size of the reference or -1 if the reference is illegal. | 76 // The size of the reference or -1 if the reference is illegal. |
76 int size() const { return type_; } | 77 int size() const { return type_; } |
77 | 78 |
78 bool is_illegal() const { return type_ == ILLEGAL; } | 79 bool is_illegal() const { return type_ == ILLEGAL; } |
79 bool is_slot() const { return type_ == SLOT; } | 80 bool is_slot() const { return type_ == SLOT; } |
80 bool is_property() const { return type_ == NAMED || type_ == KEYED; } | 81 bool is_property() const { return type_ == NAMED || type_ == KEYED; } |
81 | 82 |
83 // Return the name. Only valid for named property references. | |
84 Handle<String> GetName(); | |
85 | |
86 // Generate code to push the value of the reference on top of the | |
87 // expression stack. The reference is expected to be already on top of | |
88 // the expression stack, and it is left in place with its value above it. | |
89 void GetValue(TypeofState typeof_state); | |
90 | |
91 // Generate code to store the value on top of the expression stack in the | |
92 // reference. The reference is expected to be immediately below the value | |
93 // on the expression stack. The stored value is left in place (with the | |
94 // reference intact below it) to support chained assignments. | |
82 void SetValue(InitState init_state); | 95 void SetValue(InitState init_state); |
83 | 96 |
84 private: | 97 private: |
85 Ia32CodeGenerator* cgen_; | 98 Ia32CodeGenerator* cgen_; |
86 Expression* expression_; | 99 Expression* expression_; |
87 Type type_; | 100 Type type_; |
88 }; | 101 }; |
89 | 102 |
90 | 103 |
91 // ------------------------------------------------------------------------- | 104 // ------------------------------------------------------------------------- |
92 // Code generation state | 105 // Code generation state |
93 | 106 |
94 // The state is passed down the AST by the code generator (and back up, in | 107 // The state is passed down the AST by the code generator (and back up, in |
95 // the form of the state of the label pair). It is threaded through the | 108 // the form of the state of the label pair). It is threaded through the |
96 // call stack. Constructing a state implicitly pushes it on the owning code | 109 // call stack. Constructing a state implicitly pushes it on the owning code |
97 // generator's stack of states, and destroying one implicitly pops it. | 110 // generator's stack of states, and destroying one implicitly pops it. |
98 | 111 |
99 class CodeGenState BASE_EMBEDDED { | 112 class CodeGenState BASE_EMBEDDED { |
100 public: | 113 public: |
101 enum AccessType { | |
102 UNDEFINED, | |
103 LOAD, | |
104 LOAD_TYPEOF_EXPR | |
105 }; | |
106 | |
107 // Create an initial code generator state. Destroying the initial state | 114 // Create an initial code generator state. Destroying the initial state |
108 // leaves the code generator with a NULL state. | 115 // leaves the code generator with a NULL state. |
109 explicit CodeGenState(Ia32CodeGenerator* owner); | 116 explicit CodeGenState(Ia32CodeGenerator* owner); |
110 | 117 |
111 // Create a code generator state based on a code generator's current | 118 // Create a code generator state based on a code generator's current |
112 // state. The new state has its own access type and pair of branch | 119 // state. The new state has its own typeof state and pair of branch |
113 // labels, and no reference. | 120 // labels. |
114 CodeGenState(Ia32CodeGenerator* owner, | 121 CodeGenState(Ia32CodeGenerator* owner, |
115 AccessType access, | 122 TypeofState typeof_state, |
116 Label* true_target, | 123 Label* true_target, |
117 Label* false_target); | 124 Label* false_target); |
118 | 125 |
119 // Create a code generator state based on a code generator's current | |
120 // state. The new state has an access type of LOAD, its own reference, | |
121 // and inherits the pair of branch labels of the current state. | |
122 CodeGenState(Ia32CodeGenerator* owner, Reference* ref); | |
123 | |
124 // Destroy a code generator state and restore the owning code generator's | 126 // Destroy a code generator state and restore the owning code generator's |
125 // previous state. | 127 // previous state. |
126 ~CodeGenState(); | 128 ~CodeGenState(); |
127 | 129 |
128 AccessType access() const { return access_; } | 130 TypeofState typeof_state() const { return typeof_state_; } |
129 Reference* ref() const { return ref_; } | |
130 Label* true_target() const { return true_target_; } | 131 Label* true_target() const { return true_target_; } |
131 Label* false_target() const { return false_target_; } | 132 Label* false_target() const { return false_target_; } |
132 | 133 |
133 private: | 134 private: |
134 Ia32CodeGenerator* owner_; | 135 Ia32CodeGenerator* owner_; |
135 AccessType access_; | 136 TypeofState typeof_state_; |
136 Reference* ref_; | |
137 Label* true_target_; | 137 Label* true_target_; |
138 Label* false_target_; | 138 Label* false_target_; |
139 CodeGenState* previous_; | 139 CodeGenState* previous_; |
140 }; | 140 }; |
141 | 141 |
142 | 142 |
143 // ----------------------------------------------------------------------------- | 143 // ----------------------------------------------------------------------------- |
144 // Ia32CodeGenerator | 144 // Ia32CodeGenerator |
145 | 145 |
146 class Ia32CodeGenerator: public CodeGenerator { | 146 class Ia32CodeGenerator: public CodeGenerator { |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
178 | 178 |
179 // Main code generation function | 179 // Main code generation function |
180 void GenCode(FunctionLiteral* fun); | 180 void GenCode(FunctionLiteral* fun); |
181 | 181 |
182 // The following are used by class Reference. | 182 // The following are used by class Reference. |
183 void LoadReference(Reference* ref); | 183 void LoadReference(Reference* ref); |
184 void UnloadReference(Reference* ref); | 184 void UnloadReference(Reference* ref); |
185 | 185 |
186 // State | 186 // State |
187 bool has_cc() const { return cc_reg_ >= 0; } | 187 bool has_cc() const { return cc_reg_ >= 0; } |
188 CodeGenState::AccessType access() const { return state_->access(); } | 188 TypeofState typeof_state() const { return state_->typeof_state(); } |
189 Reference* ref() const { return state_->ref(); } | |
190 bool is_referenced() const { return state_->ref() != NULL; } | |
191 Label* true_target() const { return state_->true_target(); } | 189 Label* true_target() const { return state_->true_target(); } |
192 Label* false_target() const { return state_->false_target(); } | 190 Label* false_target() const { return state_->false_target(); } |
193 | 191 |
194 // Expressions | 192 // Expressions |
195 Operand GlobalObject() const { | 193 Operand GlobalObject() const { |
196 return ContextOperand(esi, Context::GLOBAL_INDEX); | 194 return ContextOperand(esi, Context::GLOBAL_INDEX); |
197 } | 195 } |
198 | 196 |
199 // Support functions for accessing parameters. | 197 // Support functions for accessing parameters. |
200 Operand ParameterOperand(int index) const { | 198 Operand ParameterOperand(int index) const { |
201 int num_parameters = scope()->num_parameters(); | 199 int num_parameters = scope()->num_parameters(); |
202 ASSERT(-2 <= index && index < num_parameters); | 200 ASSERT(-2 <= index && index < num_parameters); |
203 return Operand(ebp, (1 + num_parameters - index) * kPointerSize); | 201 return Operand(ebp, (1 + num_parameters - index) * kPointerSize); |
204 } | 202 } |
205 | 203 |
206 Operand ReceiverOperand() const { return ParameterOperand(-1); } | 204 Operand ReceiverOperand() const { return ParameterOperand(-1); } |
207 | 205 |
208 Operand FunctionOperand() const { | 206 Operand FunctionOperand() const { |
209 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); | 207 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); |
210 } | 208 } |
211 | 209 |
212 Operand ContextOperand(Register context, int index) const { | 210 Operand ContextOperand(Register context, int index) const { |
213 return Operand(context, Context::SlotOffset(index)); | 211 return Operand(context, Context::SlotOffset(index)); |
214 } | 212 } |
215 | 213 |
216 Operand SlotOperand(Slot* slot, Register tmp); | 214 Operand SlotOperand(Slot* slot, Register tmp); |
217 | 215 |
218 void LoadCondition(Expression* x, | 216 void LoadCondition(Expression* x, |
219 CodeGenState::AccessType access, | 217 TypeofState typeof_state, |
220 Label* true_target, | 218 Label* true_target, |
221 Label* false_target, | 219 Label* false_target, |
222 bool force_cc); | 220 bool force_cc); |
223 void Load(Expression* x, | 221 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); |
224 CodeGenState::AccessType access = CodeGenState::LOAD); | |
225 void LoadGlobal(); | 222 void LoadGlobal(); |
226 | 223 |
224 // Read a value from a slot and leave it on top of the expression stack. | |
225 void LoadFromSlot(Slot* slot, TypeofState typeof_state); | |
226 | |
227 // Special code for typeof expressions: Unfortunately, we must | 227 // Special code for typeof expressions: Unfortunately, we must |
228 // be careful when loading the expression in 'typeof' | 228 // be careful when loading the expression in 'typeof' |
229 // expressions. We are not allowed to throw reference errors for | 229 // expressions. We are not allowed to throw reference errors for |
230 // non-existing properties of the global object, so we must make it | 230 // non-existing properties of the global object, so we must make it |
231 // look like an explicit property access, instead of an access | 231 // look like an explicit property access, instead of an access |
232 // through the context chain. | 232 // through the context chain. |
233 void LoadTypeofExpression(Expression* x); | 233 void LoadTypeofExpression(Expression* x); |
234 | 234 |
235 // References | |
236 | |
237 // Generate code to fetch the value of a reference. The reference is | |
238 // expected to be on top of the expression stack. It is left in place and | |
239 // its value is pushed on top of it. | |
240 void GetValue(Reference* ref) { | |
241 ASSERT(!has_cc()); | |
242 ASSERT(!ref->is_illegal()); | |
243 CodeGenState new_state(this, ref); | |
244 Visit(ref->expression()); | |
245 } | |
246 | |
247 // Generate code to fetch a value from a property of a reference. The | |
248 // reference is expected on top of the expression stack. It is left in | |
249 // place and its value is pushed on top of it. | |
250 void GetReferenceProperty(Expression* key); | |
251 | |
252 void ToBoolean(Label* true_target, Label* false_target); | 235 void ToBoolean(Label* true_target, Label* false_target); |
253 | 236 |
254 void GenericBinaryOperation( | 237 void GenericBinaryOperation( |
255 Token::Value op, | 238 Token::Value op, |
256 const OverwriteMode overwrite_mode = NO_OVERWRITE); | 239 const OverwriteMode overwrite_mode = NO_OVERWRITE); |
257 void Comparison(Condition cc, bool strict = false); | 240 void Comparison(Condition cc, bool strict = false); |
258 | 241 |
259 // Inline small integer literals. To prevent long attacker-controlled byte | 242 // Inline small integer literals. To prevent long attacker-controlled byte |
260 // sequences, we only inline small Smi:s. | 243 // sequences, we only inline small Smi:s. |
261 static const int kMaxSmiInlinedBits = 16; | 244 static const int kMaxSmiInlinedBits = 16; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
333 friend class VariableProxy; | 316 friend class VariableProxy; |
334 friend class Slot; | 317 friend class Slot; |
335 }; | 318 }; |
336 | 319 |
337 | 320 |
338 // ------------------------------------------------------------------------- | 321 // ------------------------------------------------------------------------- |
339 // CodeGenState implementation. | 322 // CodeGenState implementation. |
340 | 323 |
341 CodeGenState::CodeGenState(Ia32CodeGenerator* owner) | 324 CodeGenState::CodeGenState(Ia32CodeGenerator* owner) |
342 : owner_(owner), | 325 : owner_(owner), |
343 access_(UNDEFINED), | 326 typeof_state_(NOT_INSIDE_TYPEOF), |
344 ref_(NULL), | |
345 true_target_(NULL), | 327 true_target_(NULL), |
346 false_target_(NULL), | 328 false_target_(NULL), |
347 previous_(NULL) { | 329 previous_(NULL) { |
348 owner_->set_state(this); | 330 owner_->set_state(this); |
349 } | 331 } |
350 | 332 |
351 | 333 |
352 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, | 334 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, |
353 AccessType access, | 335 TypeofState typeof_state, |
354 Label* true_target, | 336 Label* true_target, |
355 Label* false_target) | 337 Label* false_target) |
356 : owner_(owner), | 338 : owner_(owner), |
357 access_(access), | 339 typeof_state_(typeof_state), |
358 ref_(NULL), | |
359 true_target_(true_target), | 340 true_target_(true_target), |
360 false_target_(false_target), | 341 false_target_(false_target), |
361 previous_(owner->state()) { | 342 previous_(owner->state()) { |
362 owner_->set_state(this); | 343 owner_->set_state(this); |
363 } | 344 } |
364 | 345 |
365 | 346 |
366 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, Reference* ref) | |
367 : owner_(owner), | |
368 access_(LOAD), | |
369 ref_(ref), | |
370 true_target_(owner->state()->true_target_), | |
371 false_target_(owner->state()->false_target_), | |
372 previous_(owner->state()) { | |
373 owner_->set_state(this); | |
374 } | |
375 | |
376 | |
377 CodeGenState::~CodeGenState() { | 347 CodeGenState::~CodeGenState() { |
378 ASSERT(owner_->state() == this); | 348 ASSERT(owner_->state() == this); |
379 owner_->set_state(previous_); | 349 owner_->set_state(previous_); |
380 } | 350 } |
381 | 351 |
382 | 352 |
383 // ----------------------------------------------------------------------------- | 353 // ----------------------------------------------------------------------------- |
384 // Ia32CodeGenerator implementation | 354 // Ia32CodeGenerator implementation |
385 | 355 |
386 #define __ masm_-> | 356 #define __ masm_-> |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
752 } | 722 } |
753 } | 723 } |
754 | 724 |
755 | 725 |
756 // Loads a value on TOS. If it is a boolean value, the result may have been | 726 // Loads a value on TOS. If it is a boolean value, the result may have been |
757 // (partially) translated into branches, or it may have set the condition code | 727 // (partially) translated into branches, or it may have set the condition code |
758 // register. If force_cc is set, the value is forced to set the condition code | 728 // register. If force_cc is set, the value is forced to set the condition code |
759 // register and no value is pushed. If the condition code register was set, | 729 // register and no value is pushed. If the condition code register was set, |
760 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 730 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
761 void Ia32CodeGenerator::LoadCondition(Expression* x, | 731 void Ia32CodeGenerator::LoadCondition(Expression* x, |
762 CodeGenState::AccessType access, | 732 TypeofState typeof_state, |
763 Label* true_target, | 733 Label* true_target, |
764 Label* false_target, | 734 Label* false_target, |
765 bool force_cc) { | 735 bool force_cc) { |
766 ASSERT(access == CodeGenState::LOAD || | 736 ASSERT(!has_cc()); |
767 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
768 ASSERT(!has_cc() && !is_referenced()); | |
769 | 737 |
770 { CodeGenState new_state(this, access, true_target, false_target); | 738 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
771 Visit(x); | 739 Visit(x); |
772 } | 740 } |
773 if (force_cc && !has_cc()) { | 741 if (force_cc && !has_cc()) { |
774 ToBoolean(true_target, false_target); | 742 ToBoolean(true_target, false_target); |
775 } | 743 } |
776 ASSERT(has_cc() || !force_cc); | 744 ASSERT(has_cc() || !force_cc); |
777 } | 745 } |
778 | 746 |
779 | 747 |
780 void Ia32CodeGenerator::Load(Expression* x, CodeGenState::AccessType access) { | 748 void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
781 ASSERT(access == CodeGenState::LOAD || | |
782 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
783 | |
784 Label true_target; | 749 Label true_target; |
785 Label false_target; | 750 Label false_target; |
786 LoadCondition(x, access, &true_target, &false_target, false); | 751 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
787 | 752 |
788 if (has_cc()) { | 753 if (has_cc()) { |
789 // convert cc_reg_ into a bool | 754 // convert cc_reg_ into a bool |
790 | 755 |
791 Label loaded, materialize_true; | 756 Label loaded, materialize_true; |
792 __ j(cc_reg_, &materialize_true); | 757 __ j(cc_reg_, &materialize_true); |
793 __ push(Immediate(Factory::false_value())); | 758 __ push(Immediate(Factory::false_value())); |
794 __ jmp(&loaded); | 759 __ jmp(&loaded); |
795 __ bind(&materialize_true); | 760 __ bind(&materialize_true); |
796 __ push(Immediate(Factory::true_value())); | 761 __ push(Immediate(Factory::true_value())); |
(...skipping 28 matching lines...) Expand all Loading... | |
825 ASSERT(!has_cc()); | 790 ASSERT(!has_cc()); |
826 } | 791 } |
827 | 792 |
828 | 793 |
829 void Ia32CodeGenerator::LoadGlobal() { | 794 void Ia32CodeGenerator::LoadGlobal() { |
830 __ push(GlobalObject()); | 795 __ push(GlobalObject()); |
831 } | 796 } |
832 | 797 |
833 | 798 |
834 // TODO(1241834): Get rid of this function in favor of just using Load, now | 799 // TODO(1241834): Get rid of this function in favor of just using Load, now |
835 // that we have the LOAD_TYPEOF_EXPR access type. => Need to handle | 800 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
836 // global variables w/o reference errors elsewhere. | 801 // variables w/o reference errors elsewhere. |
837 void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { | 802 void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { |
838 Variable* variable = x->AsVariableProxy()->AsVariable(); | 803 Variable* variable = x->AsVariableProxy()->AsVariable(); |
839 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 804 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
840 // NOTE: This is somewhat nasty. We force the compiler to load | 805 // NOTE: This is somewhat nasty. We force the compiler to load |
841 // the variable as if through '<global>.<variable>' to make sure we | 806 // the variable as if through '<global>.<variable>' to make sure we |
842 // do not get reference errors. | 807 // do not get reference errors. |
843 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 808 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
844 Literal key(variable->name()); | 809 Literal key(variable->name()); |
845 // TODO(1241834): Fetch the position from the variable instead of using | 810 // TODO(1241834): Fetch the position from the variable instead of using |
846 // no position. | 811 // no position. |
847 Property property(&global, &key, RelocInfo::kNoPosition); | 812 Property property(&global, &key, RelocInfo::kNoPosition); |
848 Load(&property); | 813 Load(&property); |
849 } else { | 814 } else { |
850 Load(x, CodeGenState::LOAD_TYPEOF_EXPR); | 815 Load(x, INSIDE_TYPEOF); |
851 } | 816 } |
852 } | 817 } |
853 | 818 |
854 | 819 |
855 Reference::Reference(Ia32CodeGenerator* cgen, Expression* expression) | 820 Reference::Reference(Ia32CodeGenerator* cgen, Expression* expression) |
856 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 821 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
857 cgen->LoadReference(this); | 822 cgen->LoadReference(this); |
858 } | 823 } |
859 | 824 |
860 | 825 |
861 Reference::~Reference() { | 826 Reference::~Reference() { |
862 cgen_->UnloadReference(this); | 827 cgen_->UnloadReference(this); |
863 } | 828 } |
864 | 829 |
865 | 830 |
866 void Ia32CodeGenerator::LoadReference(Reference* ref) { | 831 void Ia32CodeGenerator::LoadReference(Reference* ref) { |
832 Comment cmnt(masm_, "[ LoadReference"); | |
867 Expression* e = ref->expression(); | 833 Expression* e = ref->expression(); |
868 Property* property = e->AsProperty(); | 834 Property* property = e->AsProperty(); |
869 Variable* var = e->AsVariableProxy()->AsVariable(); | 835 Variable* var = e->AsVariableProxy()->AsVariable(); |
870 | 836 |
871 if (property != NULL) { | 837 if (property != NULL) { |
872 // The expression is either a property or a variable proxy that rewrites | 838 // The expression is either a property or a variable proxy that rewrites |
873 // to a property. | 839 // to a property. |
874 Load(property->obj()); | 840 Load(property->obj()); |
875 // We use a named reference if the key is a literal symbol, unless it is | 841 // We use a named reference if the key is a literal symbol, unless it is |
876 // a string that can be legally parsed as an integer. This is because | 842 // a string that can be legally parsed as an integer. This is because |
(...skipping 21 matching lines...) Expand all Loading... | |
898 } | 864 } |
899 } else { | 865 } else { |
900 // Anything else is a runtime error. | 866 // Anything else is a runtime error. |
901 Load(e); | 867 Load(e); |
902 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 868 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
903 } | 869 } |
904 } | 870 } |
905 | 871 |
906 | 872 |
907 void Ia32CodeGenerator::UnloadReference(Reference* ref) { | 873 void Ia32CodeGenerator::UnloadReference(Reference* ref) { |
908 // Pop n references on the stack while preserving TOS | 874 // Pop a reference from the stack while preserving TOS. |
909 Comment cmnt(masm_, "[ UnloadReference"); | 875 Comment cmnt(masm_, "[ UnloadReference"); |
910 int size = ref->size(); | 876 int size = ref->size(); |
911 if (size <= 0) { | 877 if (size <= 0) { |
912 // Do nothing. No popping is necessary. | 878 // Do nothing. No popping is necessary. |
913 } else if (size == 1) { | 879 } else if (size == 1) { |
914 __ pop(eax); | 880 __ pop(eax); |
915 __ mov(TOS, eax); | 881 __ mov(TOS, eax); |
916 } else { | 882 } else { |
917 __ pop(eax); | 883 __ pop(eax); |
918 __ add(Operand(esp), Immediate(size * kPointerSize)); | 884 __ add(Operand(esp), Immediate(size * kPointerSize)); |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
978 ToBooleanStub stub; | 944 ToBooleanStub stub; |
979 __ CallStub(&stub); | 945 __ CallStub(&stub); |
980 // Convert result (eax) to condition code. | 946 // Convert result (eax) to condition code. |
981 __ test(eax, Operand(eax)); | 947 __ test(eax, Operand(eax)); |
982 | 948 |
983 ASSERT(not_equal == not_zero); | 949 ASSERT(not_equal == not_zero); |
984 cc_reg_ = not_equal; | 950 cc_reg_ = not_equal; |
985 } | 951 } |
986 | 952 |
987 | 953 |
988 void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { | |
989 ASSERT(!ref()->is_illegal()); | |
990 | |
991 // TODO(1241834): Make sure that this it is safe to ignore the distinction | |
992 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance | |
993 // that reference errors can be thrown below, we must distinguish between | |
994 // the two kinds of loads (typeof expression loads must not throw a | |
995 // reference error). | |
996 if (ref()->type() == Reference::NAMED) { | |
997 // Compute the name of the property. | |
998 Literal* literal = key->AsLiteral(); | |
999 Handle<String> name(String::cast(*literal->handle())); | |
1000 | |
1001 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
1002 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | |
1003 // Setup the name register. | |
1004 __ Set(ecx, Immediate(name)); | |
1005 if (var != NULL) { | |
1006 ASSERT(var->is_global()); | |
1007 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
1008 } else { | |
1009 __ call(ic, RelocInfo::CODE_TARGET); | |
1010 } | |
1011 } else { | |
1012 // Access keyed property. | |
1013 ASSERT(ref()->type() == Reference::KEYED); | |
1014 | |
1015 // Call IC code. | |
1016 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
1017 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | |
1018 if (var != NULL) { | |
1019 ASSERT(var->is_global()); | |
1020 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
1021 } else { | |
1022 __ call(ic, RelocInfo::CODE_TARGET); | |
1023 } | |
1024 } | |
1025 __ push(eax); // IC call leaves result in eax, push it out | |
1026 } | |
1027 | |
1028 | |
1029 class FloatingPointHelper : public AllStatic { | 954 class FloatingPointHelper : public AllStatic { |
1030 public: | 955 public: |
1031 // Code pattern for loading floating point values. Input values must | 956 // Code pattern for loading floating point values. Input values must |
1032 // be either smi or heap number objects (fp values). Requirements: | 957 // be either smi or heap number objects (fp values). Requirements: |
1033 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as | 958 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as |
1034 // floating point numbers on FPU stack. | 959 // floating point numbers on FPU stack. |
1035 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); | 960 static void LoadFloatOperands(MacroAssembler* masm, Register scratch); |
1036 // Test if operands are smi or number objects (fp). Requirements: | 961 // Test if operands are smi or number objects (fp). Requirements: |
1037 // operand_1 in eax, operand_2 in edx; falls through on float | 962 // operand_1 in eax, operand_2 in edx; falls through on float |
1038 // operands, jumps to the non_float label otherwise. | 963 // operands, jumps to the non_float label otherwise. |
(...skipping 630 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1669 Major MajorKey() { return CallFunction; } | 1594 Major MajorKey() { return CallFunction; } |
1670 int MinorKey() { return argc_; } | 1595 int MinorKey() { return argc_; } |
1671 }; | 1596 }; |
1672 | 1597 |
1673 | 1598 |
1674 // Call the function just below TOS on the stack with the given | 1599 // Call the function just below TOS on the stack with the given |
1675 // arguments. The receiver is the TOS. | 1600 // arguments. The receiver is the TOS. |
1676 void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1601 void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
1677 int position) { | 1602 int position) { |
1678 // Push the arguments ("left-to-right") on the stack. | 1603 // Push the arguments ("left-to-right") on the stack. |
1679 for (int i = 0; i < args->length(); i++) Load(args->at(i)); | 1604 for (int i = 0; i < args->length(); i++) { |
1605 Load(args->at(i)); | |
1606 } | |
iposva
2008/10/07 19:43:31
Thanks!
| |
1680 | 1607 |
1681 // Record the position for debugging purposes. | 1608 // Record the position for debugging purposes. |
1682 __ RecordPosition(position); | 1609 __ RecordPosition(position); |
1683 | 1610 |
1684 // Use the shared code stub to call the function. | 1611 // Use the shared code stub to call the function. |
1685 CallFunctionStub call_function(args->length()); | 1612 CallFunctionStub call_function(args->length()); |
1686 __ CallStub(&call_function); | 1613 __ CallStub(&call_function); |
1687 | 1614 |
1688 // Restore context and pop function from the stack. | 1615 // Restore context and pop function from the stack. |
1689 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1616 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1814 // parts of the if statement are present or not. | 1741 // parts of the if statement are present or not. |
1815 bool has_then_stm = node->HasThenStatement(); | 1742 bool has_then_stm = node->HasThenStatement(); |
1816 bool has_else_stm = node->HasElseStatement(); | 1743 bool has_else_stm = node->HasElseStatement(); |
1817 | 1744 |
1818 RecordStatementPosition(node); | 1745 RecordStatementPosition(node); |
1819 Label exit; | 1746 Label exit; |
1820 if (has_then_stm && has_else_stm) { | 1747 if (has_then_stm && has_else_stm) { |
1821 Label then; | 1748 Label then; |
1822 Label else_; | 1749 Label else_; |
1823 // if (cond) | 1750 // if (cond) |
1824 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); | 1751 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
1825 Branch(false, &else_); | 1752 Branch(false, &else_); |
1826 // then | 1753 // then |
1827 __ bind(&then); | 1754 __ bind(&then); |
1828 Visit(node->then_statement()); | 1755 Visit(node->then_statement()); |
1829 __ jmp(&exit); | 1756 __ jmp(&exit); |
1830 // else | 1757 // else |
1831 __ bind(&else_); | 1758 __ bind(&else_); |
1832 Visit(node->else_statement()); | 1759 Visit(node->else_statement()); |
1833 | 1760 |
1834 } else if (has_then_stm) { | 1761 } else if (has_then_stm) { |
1835 ASSERT(!has_else_stm); | 1762 ASSERT(!has_else_stm); |
1836 Label then; | 1763 Label then; |
1837 // if (cond) | 1764 // if (cond) |
1838 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &exit, true); | 1765 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); |
1839 Branch(false, &exit); | 1766 Branch(false, &exit); |
1840 // then | 1767 // then |
1841 __ bind(&then); | 1768 __ bind(&then); |
1842 Visit(node->then_statement()); | 1769 Visit(node->then_statement()); |
1843 | 1770 |
1844 } else if (has_else_stm) { | 1771 } else if (has_else_stm) { |
1845 ASSERT(!has_then_stm); | 1772 ASSERT(!has_then_stm); |
1846 Label else_; | 1773 Label else_; |
1847 // if (!cond) | 1774 // if (!cond) |
1848 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &else_, true); | 1775 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); |
1849 Branch(true, &exit); | 1776 Branch(true, &exit); |
1850 // else | 1777 // else |
1851 __ bind(&else_); | 1778 __ bind(&else_); |
1852 Visit(node->else_statement()); | 1779 Visit(node->else_statement()); |
1853 | 1780 |
1854 } else { | 1781 } else { |
1855 ASSERT(!has_then_stm && !has_else_stm); | 1782 ASSERT(!has_then_stm && !has_else_stm); |
1856 // if (cond) | 1783 // if (cond) |
1857 LoadCondition(node->condition(), CodeGenState::LOAD, &exit, &exit, false); | 1784 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); |
1858 if (has_cc()) { | 1785 if (has_cc()) { |
1859 cc_reg_ = no_condition; | 1786 cc_reg_ = no_condition; |
1860 } else { | 1787 } else { |
1861 // No cc value set up, that means the boolean was pushed. | 1788 // No cc value set up, that means the boolean was pushed. |
1862 // Pop it again, since it is not going to be used. | 1789 // Pop it again, since it is not going to be used. |
1863 __ pop(eax); | 1790 __ pop(eax); |
1864 } | 1791 } |
1865 } | 1792 } |
1866 | 1793 |
1867 // end | 1794 // end |
(...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2132 | 2059 |
2133 // cond | 2060 // cond |
2134 __ bind(&entry); | 2061 __ bind(&entry); |
2135 switch (info) { | 2062 switch (info) { |
2136 case ALWAYS_TRUE: | 2063 case ALWAYS_TRUE: |
2137 __ jmp(&loop); | 2064 __ jmp(&loop); |
2138 break; | 2065 break; |
2139 case ALWAYS_FALSE: | 2066 case ALWAYS_FALSE: |
2140 break; | 2067 break; |
2141 case DONT_KNOW: | 2068 case DONT_KNOW: |
2142 LoadCondition(node->cond(), CodeGenState::LOAD, &loop, | 2069 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop, |
2143 node->break_target(), true); | 2070 node->break_target(), true); |
2144 Branch(true, &loop); | 2071 Branch(true, &loop); |
2145 break; | 2072 break; |
2146 } | 2073 } |
2147 | 2074 |
2148 // exit | 2075 // exit |
2149 __ bind(node->break_target()); | 2076 __ bind(node->break_target()); |
2150 } | 2077 } |
2151 | 2078 |
2152 | 2079 |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2601 void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral( | 2528 void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral( |
2602 FunctionBoilerplateLiteral* node) { | 2529 FunctionBoilerplateLiteral* node) { |
2603 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2530 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
2604 InstantiateBoilerplate(node->boilerplate()); | 2531 InstantiateBoilerplate(node->boilerplate()); |
2605 } | 2532 } |
2606 | 2533 |
2607 | 2534 |
2608 void Ia32CodeGenerator::VisitConditional(Conditional* node) { | 2535 void Ia32CodeGenerator::VisitConditional(Conditional* node) { |
2609 Comment cmnt(masm_, "[ Conditional"); | 2536 Comment cmnt(masm_, "[ Conditional"); |
2610 Label then, else_, exit; | 2537 Label then, else_, exit; |
2611 LoadCondition(node->condition(), CodeGenState::LOAD, &then, &else_, true); | 2538 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
2612 Branch(false, &else_); | 2539 Branch(false, &else_); |
2613 __ bind(&then); | 2540 __ bind(&then); |
2614 Load(node->then_expression(), access()); | 2541 Load(node->then_expression(), typeof_state()); |
2615 __ jmp(&exit); | 2542 __ jmp(&exit); |
2616 __ bind(&else_); | 2543 __ bind(&else_); |
2617 Load(node->else_expression(), access()); | 2544 Load(node->else_expression(), typeof_state()); |
2618 __ bind(&exit); | 2545 __ bind(&exit); |
2619 } | 2546 } |
2620 | 2547 |
2621 | 2548 |
2622 void Ia32CodeGenerator::VisitSlot(Slot* node) { | 2549 void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
2623 ASSERT(access() != CodeGenState::UNDEFINED); | 2550 if (slot->type() == Slot::LOOKUP) { |
2624 Comment cmnt(masm_, "[ Slot"); | 2551 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
2625 | |
2626 if (node->type() == Slot::LOOKUP) { | |
2627 ASSERT(node->var()->mode() == Variable::DYNAMIC); | |
2628 | 2552 |
2629 // For now, just do a runtime call. | 2553 // For now, just do a runtime call. |
2630 __ push(Operand(esi)); | 2554 __ push(esi); |
2631 __ push(Immediate(node->var()->name())); | 2555 __ push(Immediate(slot->var()->name())); |
2632 | 2556 |
2633 if (access() == CodeGenState::LOAD) { | 2557 if (typeof_state == INSIDE_TYPEOF) { |
2558 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
2559 } else { | |
2634 __ CallRuntime(Runtime::kLoadContextSlot, 2); | 2560 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
2635 } else { | |
2636 ASSERT(access() == CodeGenState::LOAD_TYPEOF_EXPR); | |
2637 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
2638 } | 2561 } |
2639 __ push(eax); | 2562 __ push(eax); |
2640 | 2563 |
2641 } else { | 2564 } else { |
2642 // Note: We would like to keep the assert below, but it fires because of | 2565 // Note: We would like to keep the assert below, but it fires because of |
2643 // some nasty code in LoadTypeofExpression() which should be removed... | 2566 // some nasty code in LoadTypeofExpression() which should be removed... |
2644 // ASSERT(node->var()->mode() != Variable::DYNAMIC); | 2567 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); |
2645 | 2568 if (slot->var()->mode() == Variable::CONST) { |
2646 if (node->var()->mode() == Variable::CONST) { | |
2647 // Const slots may contain 'the hole' value (the constant hasn't been | 2569 // Const slots may contain 'the hole' value (the constant hasn't been |
2648 // initialized yet) which needs to be converted into the 'undefined' | 2570 // initialized yet) which needs to be converted into the 'undefined' |
2649 // value. | 2571 // value. |
2650 Comment cmnt(masm_, "[ Load const"); | 2572 Comment cmnt(masm_, "[ Load const"); |
2651 Label L; | 2573 Label exit; |
2652 __ mov(eax, SlotOperand(node, ecx)); | 2574 __ mov(eax, SlotOperand(slot, ecx)); |
2653 __ cmp(eax, Factory::the_hole_value()); | 2575 __ cmp(eax, Factory::the_hole_value()); |
2654 __ j(not_equal, &L); | 2576 __ j(not_equal, &exit); |
2655 __ mov(eax, Factory::undefined_value()); | 2577 __ mov(eax, Factory::undefined_value()); |
2656 __ bind(&L); | 2578 __ bind(&exit); |
2657 __ push(eax); | 2579 __ push(eax); |
2658 } else { | 2580 } else { |
2659 __ push(SlotOperand(node, ecx)); | 2581 __ push(SlotOperand(slot, ecx)); |
2660 } | 2582 } |
2661 } | 2583 } |
2662 } | 2584 } |
2663 | 2585 |
2664 | 2586 |
2587 void Ia32CodeGenerator::VisitSlot(Slot* node) { | |
2588 Comment cmnt(masm_, "[ Slot"); | |
2589 LoadFromSlot(node, typeof_state()); | |
2590 } | |
2591 | |
2592 | |
2665 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2593 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
2666 Comment cmnt(masm_, "[ VariableProxy"); | 2594 Comment cmnt(masm_, "[ VariableProxy"); |
2667 Variable* var_node = node->var(); | 2595 Variable* var = node->var(); |
2668 | 2596 Expression* expr = var->rewrite(); |
2669 Expression* expr = var_node->rewrite(); | |
2670 if (expr != NULL) { | 2597 if (expr != NULL) { |
2671 Visit(expr); | 2598 Visit(expr); |
2672 } else { | 2599 } else { |
2673 ASSERT(var_node->is_global()); | 2600 ASSERT(var->is_global()); |
2674 if (is_referenced()) { | 2601 Reference ref(this, node); |
2675 if (var_node->AsProperty() != NULL) { | 2602 ref.GetValue(typeof_state()); |
2676 __ RecordPosition(var_node->AsProperty()->position()); | |
2677 } | |
2678 GetReferenceProperty(new Literal(var_node->name())); | |
2679 } else { | |
2680 Reference property(this, node); | |
2681 GetValue(&property); | |
2682 } | |
2683 } | 2603 } |
2684 } | 2604 } |
2685 | 2605 |
2686 | 2606 |
2687 void Ia32CodeGenerator::VisitLiteral(Literal* node) { | 2607 void Ia32CodeGenerator::VisitLiteral(Literal* node) { |
2688 Comment cmnt(masm_, "[ Literal"); | 2608 Comment cmnt(masm_, "[ Literal"); |
2689 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 2609 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
2690 // To prevent long attacker-controlled byte sequences in code, larger | 2610 // To prevent long attacker-controlled byte sequences in code, larger |
2691 // Smis are loaded in two steps. | 2611 // Smis are loaded in two steps. |
2692 int bits = reinterpret_cast<int>(*node->handle()); | 2612 int bits = reinterpret_cast<int>(*node->handle()); |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2935 RecordStatementPosition(node); | 2855 RecordStatementPosition(node); |
2936 Reference target(this, node->target()); | 2856 Reference target(this, node->target()); |
2937 if (target.is_illegal()) return; | 2857 if (target.is_illegal()) return; |
2938 | 2858 |
2939 if (node->op() == Token::ASSIGN || | 2859 if (node->op() == Token::ASSIGN || |
2940 node->op() == Token::INIT_VAR || | 2860 node->op() == Token::INIT_VAR || |
2941 node->op() == Token::INIT_CONST) { | 2861 node->op() == Token::INIT_CONST) { |
2942 Load(node->value()); | 2862 Load(node->value()); |
2943 | 2863 |
2944 } else { | 2864 } else { |
2945 GetValue(&target); | 2865 target.GetValue(NOT_INSIDE_TYPEOF); |
2946 Literal* literal = node->value()->AsLiteral(); | 2866 Literal* literal = node->value()->AsLiteral(); |
2947 if (IsInlineSmi(literal)) { | 2867 if (IsInlineSmi(literal)) { |
2948 SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE); | 2868 SmiOperation(node->binary_op(), literal->handle(), false, NO_OVERWRITE); |
2949 } else { | 2869 } else { |
2950 Load(node->value()); | 2870 Load(node->value()); |
2951 GenericBinaryOperation(node->binary_op()); | 2871 GenericBinaryOperation(node->binary_op()); |
2952 } | 2872 } |
2953 } | 2873 } |
2954 | 2874 |
2955 Variable* var = node->target()->AsVariableProxy()->AsVariable(); | 2875 Variable* var = node->target()->AsVariableProxy()->AsVariable(); |
(...skipping 20 matching lines...) Expand all Loading... | |
2976 | 2896 |
2977 Load(node->exception()); | 2897 Load(node->exception()); |
2978 __ RecordPosition(node->position()); | 2898 __ RecordPosition(node->position()); |
2979 __ CallRuntime(Runtime::kThrow, 1); | 2899 __ CallRuntime(Runtime::kThrow, 1); |
2980 __ push(eax); | 2900 __ push(eax); |
2981 } | 2901 } |
2982 | 2902 |
2983 | 2903 |
2984 void Ia32CodeGenerator::VisitProperty(Property* node) { | 2904 void Ia32CodeGenerator::VisitProperty(Property* node) { |
2985 Comment cmnt(masm_, "[ Property"); | 2905 Comment cmnt(masm_, "[ Property"); |
2986 | 2906 Reference property(this, node); |
2987 if (is_referenced()) { | 2907 property.GetValue(typeof_state()); |
2988 __ RecordPosition(node->position()); | |
2989 GetReferenceProperty(node->key()); | |
2990 } else { | |
2991 Reference property(this, node); | |
2992 __ RecordPosition(node->position()); | |
2993 GetValue(&property); | |
2994 } | |
2995 } | 2908 } |
2996 | 2909 |
2997 | 2910 |
2998 void Ia32CodeGenerator::VisitCall(Call* node) { | 2911 void Ia32CodeGenerator::VisitCall(Call* node) { |
2999 Comment cmnt(masm_, "[ Call"); | 2912 Comment cmnt(masm_, "[ Call"); |
3000 | 2913 |
3001 ZoneList<Expression*>* args = node->arguments(); | 2914 ZoneList<Expression*>* args = node->arguments(); |
3002 | 2915 |
3003 RecordStatementPosition(node); | 2916 RecordStatementPosition(node); |
3004 | 2917 |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3083 // Overwrite the function on the stack with the result. | 2996 // Overwrite the function on the stack with the result. |
3084 __ mov(TOS, eax); | 2997 __ mov(TOS, eax); |
3085 | 2998 |
3086 } else { | 2999 } else { |
3087 // ------------------------------------------- | 3000 // ------------------------------------------- |
3088 // JavaScript example: 'array[index](1, 2, 3)' | 3001 // JavaScript example: 'array[index](1, 2, 3)' |
3089 // ------------------------------------------- | 3002 // ------------------------------------------- |
3090 | 3003 |
3091 // Load the function to call from the property through a reference. | 3004 // Load the function to call from the property through a reference. |
3092 Reference ref(this, property); | 3005 Reference ref(this, property); |
3093 GetValue(&ref); | 3006 ref.GetValue(NOT_INSIDE_TYPEOF); |
3094 | 3007 |
3095 // Pass receiver to called function. | 3008 // Pass receiver to called function. |
3096 // The reference's size is non-negative. | 3009 // The reference's size is non-negative. |
3097 __ push(Operand(esp, ref.size() * kPointerSize)); | 3010 __ push(Operand(esp, ref.size() * kPointerSize)); |
3098 | 3011 |
3099 // Call the function. | 3012 // Call the function. |
3100 CallWithArguments(args, node->position()); | 3013 CallWithArguments(args, node->position()); |
3101 } | 3014 } |
3102 | 3015 |
3103 } else { | 3016 } else { |
(...skipping 345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3449 } | 3362 } |
3450 } | 3363 } |
3451 | 3364 |
3452 | 3365 |
3453 void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 3366 void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
3454 Comment cmnt(masm_, "[ UnaryOperation"); | 3367 Comment cmnt(masm_, "[ UnaryOperation"); |
3455 | 3368 |
3456 Token::Value op = node->op(); | 3369 Token::Value op = node->op(); |
3457 | 3370 |
3458 if (op == Token::NOT) { | 3371 if (op == Token::NOT) { |
3459 LoadCondition(node->expression(), CodeGenState::LOAD, | 3372 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
3460 false_target(), true_target(), true); | 3373 false_target(), true_target(), true); |
3461 cc_reg_ = NegateCondition(cc_reg_); | 3374 cc_reg_ = NegateCondition(cc_reg_); |
3462 | 3375 |
3463 } else if (op == Token::DELETE) { | 3376 } else if (op == Token::DELETE) { |
3464 Property* property = node->expression()->AsProperty(); | 3377 Property* property = node->expression()->AsProperty(); |
3465 if (property != NULL) { | 3378 if (property != NULL) { |
3466 Load(property->obj()); | 3379 Load(property->obj()); |
3467 Load(property->key()); | 3380 Load(property->key()); |
3468 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); | 3381 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); |
3469 __ push(eax); | 3382 __ push(eax); |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3670 bool is_increment = node->op() == Token::INC; | 3583 bool is_increment = node->op() == Token::INC; |
3671 | 3584 |
3672 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3585 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
3673 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3586 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
3674 | 3587 |
3675 // Postfix: Make room for the result. | 3588 // Postfix: Make room for the result. |
3676 if (is_postfix) __ push(Immediate(0)); | 3589 if (is_postfix) __ push(Immediate(0)); |
3677 | 3590 |
3678 { Reference target(this, node->expression()); | 3591 { Reference target(this, node->expression()); |
3679 if (target.is_illegal()) return; | 3592 if (target.is_illegal()) return; |
3680 GetValue(&target); | 3593 target.GetValue(NOT_INSIDE_TYPEOF); |
3681 | 3594 |
3682 int result_offset = target.size() * kPointerSize; | 3595 int result_offset = target.size() * kPointerSize; |
3683 CountOperationDeferred* deferred = | 3596 CountOperationDeferred* deferred = |
3684 new CountOperationDeferred(this, is_postfix, | 3597 new CountOperationDeferred(this, is_postfix, |
3685 is_increment, result_offset); | 3598 is_increment, result_offset); |
3686 | 3599 |
3687 __ pop(eax); // Load TOS into eax for calculations below | 3600 __ pop(eax); // Load TOS into eax for calculations below |
3688 | 3601 |
3689 // Postfix: Store the old value as the result. | 3602 // Postfix: Store the old value as the result. |
3690 if (is_postfix) __ mov(Operand(esp, result_offset), eax); | 3603 if (is_postfix) __ mov(Operand(esp, result_offset), eax); |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3725 | 3638 |
3726 // NOTE: If the left hand side produces a materialized value (not in | 3639 // NOTE: If the left hand side produces a materialized value (not in |
3727 // the CC register), we force the right hand side to do the | 3640 // the CC register), we force the right hand side to do the |
3728 // same. This is necessary because we may have to branch to the exit | 3641 // same. This is necessary because we may have to branch to the exit |
3729 // after evaluating the left hand side (due to the shortcut | 3642 // after evaluating the left hand side (due to the shortcut |
3730 // semantics), but the compiler must (statically) know if the result | 3643 // semantics), but the compiler must (statically) know if the result |
3731 // of compiling the binary operation is materialized or not. | 3644 // of compiling the binary operation is materialized or not. |
3732 | 3645 |
3733 if (op == Token::AND) { | 3646 if (op == Token::AND) { |
3734 Label is_true; | 3647 Label is_true; |
3735 LoadCondition(node->left(), CodeGenState::LOAD, &is_true, | 3648 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true, |
3736 false_target(), false); | 3649 false_target(), false); |
3737 if (has_cc()) { | 3650 if (has_cc()) { |
3738 Branch(false, false_target()); | 3651 Branch(false, false_target()); |
3739 | 3652 |
3740 // Evaluate right side expression. | 3653 // Evaluate right side expression. |
3741 __ bind(&is_true); | 3654 __ bind(&is_true); |
3742 LoadCondition(node->right(), CodeGenState::LOAD, true_target(), | 3655 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), |
3743 false_target(), false); | 3656 false_target(), false); |
3744 | 3657 |
3745 } else { | 3658 } else { |
3746 Label pop_and_continue, exit; | 3659 Label pop_and_continue, exit; |
3747 | 3660 |
3748 // Avoid popping the result if it converts to 'false' using the | 3661 // Avoid popping the result if it converts to 'false' using the |
3749 // standard ToBoolean() conversion as described in ECMA-262, | 3662 // standard ToBoolean() conversion as described in ECMA-262, |
3750 // section 9.2, page 30. | 3663 // section 9.2, page 30. |
3751 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3664 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
3752 __ mov(eax, TOS); | 3665 __ mov(eax, TOS); |
3753 __ push(eax); | 3666 __ push(eax); |
3754 ToBoolean(&pop_and_continue, &exit); | 3667 ToBoolean(&pop_and_continue, &exit); |
3755 Branch(false, &exit); | 3668 Branch(false, &exit); |
3756 | 3669 |
3757 // Pop the result of evaluating the first part. | 3670 // Pop the result of evaluating the first part. |
3758 __ bind(&pop_and_continue); | 3671 __ bind(&pop_and_continue); |
3759 __ pop(eax); | 3672 __ pop(eax); |
3760 | 3673 |
3761 // Evaluate right side expression. | 3674 // Evaluate right side expression. |
3762 __ bind(&is_true); | 3675 __ bind(&is_true); |
3763 Load(node->right()); | 3676 Load(node->right()); |
3764 | 3677 |
3765 // Exit (always with a materialized value). | 3678 // Exit (always with a materialized value). |
3766 __ bind(&exit); | 3679 __ bind(&exit); |
3767 } | 3680 } |
3768 | 3681 |
3769 } else if (op == Token::OR) { | 3682 } else if (op == Token::OR) { |
3770 Label is_false; | 3683 Label is_false; |
3771 LoadCondition(node->left(), CodeGenState::LOAD, true_target(), | 3684 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), |
3772 &is_false, false); | 3685 &is_false, false); |
3773 if (has_cc()) { | 3686 if (has_cc()) { |
3774 Branch(true, true_target()); | 3687 Branch(true, true_target()); |
3775 | 3688 |
3776 // Evaluate right side expression. | 3689 // Evaluate right side expression. |
3777 __ bind(&is_false); | 3690 __ bind(&is_false); |
3778 LoadCondition(node->right(), CodeGenState::LOAD, true_target(), | 3691 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), |
3779 false_target(), false); | 3692 false_target(), false); |
3780 | 3693 |
3781 } else { | 3694 } else { |
3782 Label pop_and_continue, exit; | 3695 Label pop_and_continue, exit; |
3783 | 3696 |
3784 // Avoid popping the result if it converts to 'true' using the | 3697 // Avoid popping the result if it converts to 'true' using the |
3785 // standard ToBoolean() conversion as described in ECMA-262, | 3698 // standard ToBoolean() conversion as described in ECMA-262, |
3786 // section 9.2, page 30. | 3699 // section 9.2, page 30. |
3787 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. | 3700 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. |
3788 __ mov(eax, TOS); | 3701 __ mov(eax, TOS); |
(...skipping 294 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4083 // call instruction to support patching the exit code in the | 3996 // call instruction to support patching the exit code in the |
4084 // debugger. See VisitReturnStatement for the full return sequence. | 3997 // debugger. See VisitReturnStatement for the full return sequence. |
4085 __ mov(esp, Operand(ebp)); | 3998 __ mov(esp, Operand(ebp)); |
4086 __ pop(ebp); | 3999 __ pop(ebp); |
4087 } | 4000 } |
4088 | 4001 |
4089 | 4002 |
4090 #undef __ | 4003 #undef __ |
4091 #define __ masm-> | 4004 #define __ masm-> |
4092 | 4005 |
4006 Handle<String> Reference::GetName() { | |
4007 ASSERT(type_ == NAMED); | |
4008 Property* property = expression_->AsProperty(); | |
4009 if (property == NULL) { | |
4010 // Global variable reference treated as a named property reference. | |
4011 VariableProxy* proxy = expression_->AsVariableProxy(); | |
4012 ASSERT(proxy->AsVariable() != NULL); | |
4013 ASSERT(proxy->AsVariable()->is_global()); | |
4014 return proxy->name(); | |
4015 } else { | |
4016 MacroAssembler* masm = cgen_->masm(); | |
4017 __ RecordPosition(property->position()); | |
4018 Literal* raw_name = property->key()->AsLiteral(); | |
4019 ASSERT(raw_name != NULL); | |
4020 return Handle<String>(String::cast(*raw_name->handle())); | |
4021 } | |
4022 } | |
4023 | |
4024 | |
4025 void Reference::GetValue(TypeofState typeof_state) { | |
4026 ASSERT(!is_illegal()); | |
4027 ASSERT(!cgen_->has_cc()); | |
4028 MacroAssembler* masm = cgen_->masm(); | |
4029 switch (type_) { | |
4030 case SLOT: { | |
4031 Comment cmnt(masm, "[ Load from Slot"); | |
4032 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | |
4033 ASSERT(slot != NULL); | |
4034 cgen_->LoadFromSlot(slot, typeof_state); | |
4035 break; | |
4036 } | |
4037 | |
4038 case NAMED: { | |
4039 // TODO(1241834): Make sure that this it is safe to ignore the | |
4040 // distinction between expressions in a typeof and not in a typeof. If | |
4041 // there is a chance that reference errors can be thrown below, we | |
4042 // must distinguish between the two kinds of loads (typeof expression | |
4043 // loads must not throw a reference error). | |
4044 Comment cmnt(masm, "[ Load from named Property"); | |
4045 Handle<String> name(GetName()); | |
4046 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | |
4047 // Setup the name register. | |
4048 __ mov(ecx, name); | |
4049 | |
4050 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
4051 if (var != NULL) { | |
4052 ASSERT(var->is_global()); | |
4053 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
4054 } else { | |
4055 __ call(ic, RelocInfo::CODE_TARGET); | |
4056 } | |
4057 __ push(eax); // IC call leaves result in eax, push it out | |
4058 break; | |
4059 } | |
4060 | |
4061 case KEYED: { | |
4062 // TODO(1241834): Make sure that this it is safe to ignore the | |
4063 // distinction between expressions in a typeof and not in a typeof. | |
4064 Comment cmnt(masm, "[ Load from keyed Property"); | |
4065 Property* property = expression_->AsProperty(); | |
4066 ASSERT(property != NULL); | |
4067 __ RecordPosition(property->position()); | |
4068 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | |
4069 | |
4070 Variable* var = expression_->AsVariableProxy()->AsVariable(); | |
4071 if (var != NULL) { | |
4072 ASSERT(var->is_global()); | |
4073 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); | |
4074 } else { | |
4075 __ call(ic, RelocInfo::CODE_TARGET); | |
4076 } | |
4077 __ push(eax); // IC call leaves result in eax, push it out | |
4078 break; | |
4079 } | |
4080 | |
4081 default: | |
4082 UNREACHABLE(); | |
4083 } | |
4084 } | |
4085 | |
4086 | |
4093 void Reference::SetValue(InitState init_state) { | 4087 void Reference::SetValue(InitState init_state) { |
4094 ASSERT(!is_illegal()); | 4088 ASSERT(!is_illegal()); |
4095 ASSERT(!cgen_->has_cc()); | 4089 ASSERT(!cgen_->has_cc()); |
4096 MacroAssembler* masm = cgen_->masm(); | 4090 MacroAssembler* masm = cgen_->masm(); |
4097 switch (type_) { | 4091 switch (type_) { |
4098 case SLOT: { | 4092 case SLOT: { |
4099 Comment cmnt(masm, "[ Store to Slot"); | 4093 Comment cmnt(masm, "[ Store to Slot"); |
4100 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); | 4094 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot(); |
4101 ASSERT(slot != NULL); | 4095 ASSERT(slot != NULL); |
4102 if (slot->type() == Slot::LOOKUP) { | 4096 if (slot->type() == Slot::LOOKUP) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4165 // If we definitely did not jump over the assignment, we do not need | 4159 // If we definitely did not jump over the assignment, we do not need |
4166 // to bind the exit label. Doing so can defeat peephole | 4160 // to bind the exit label. Doing so can defeat peephole |
4167 // optimization. | 4161 // optimization. |
4168 if (init_state == CONST_INIT) __ bind(&exit); | 4162 if (init_state == CONST_INIT) __ bind(&exit); |
4169 } | 4163 } |
4170 break; | 4164 break; |
4171 } | 4165 } |
4172 | 4166 |
4173 case NAMED: { | 4167 case NAMED: { |
4174 Comment cmnt(masm, "[ Store to named Property"); | 4168 Comment cmnt(masm, "[ Store to named Property"); |
4175 Property* property = expression_->AsProperty(); | |
4176 Handle<String> name; | |
4177 if (property == NULL) { | |
4178 // Global variable reference treated as named property access. | |
4179 VariableProxy* proxy = expression_->AsVariableProxy(); | |
4180 ASSERT(proxy->AsVariable() != NULL); | |
4181 ASSERT(proxy->AsVariable()->is_global()); | |
4182 name = proxy->name(); | |
4183 } else { | |
4184 Literal* raw_name = property->key()->AsLiteral(); | |
4185 ASSERT(raw_name != NULL); | |
4186 name = Handle<String>(String::cast(*raw_name->handle())); | |
4187 __ RecordPosition(property->position()); | |
4188 } | |
4189 | |
4190 // Call the appropriate IC code. | 4169 // Call the appropriate IC code. |
4170 Handle<String> name(GetName()); | |
4191 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | 4171 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); |
4192 // TODO(1222589): Make the IC grab the values from the stack. | 4172 // TODO(1222589): Make the IC grab the values from the stack. |
4193 __ pop(eax); | 4173 __ pop(eax); |
4194 // Setup the name register. | 4174 // Setup the name register. |
4195 __ mov(ecx, name); | 4175 __ mov(ecx, name); |
4196 __ call(ic, RelocInfo::CODE_TARGET); | 4176 __ call(ic, RelocInfo::CODE_TARGET); |
4197 __ push(eax); // IC call leaves result in eax, push it out | 4177 __ push(eax); // IC call leaves result in eax, push it out |
4198 break; | 4178 break; |
4199 } | 4179 } |
4200 | 4180 |
(...skipping 1121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5322 bool is_eval) { | 5302 bool is_eval) { |
5323 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | 5303 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); |
5324 if (!code.is_null()) { | 5304 if (!code.is_null()) { |
5325 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 5305 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
5326 } | 5306 } |
5327 return code; | 5307 return code; |
5328 } | 5308 } |
5329 | 5309 |
5330 | 5310 |
5331 } } // namespace v8::internal | 5311 } } // namespace v8::internal |
OLD | NEW |