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 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
102 | 102 |
103 | 103 |
104 // ----------------------------------------------------------------------------- | 104 // ----------------------------------------------------------------------------- |
105 // Code generation state | 105 // Code generation state |
106 | 106 |
107 class CodeGenState BASE_EMBEDDED { | 107 class CodeGenState BASE_EMBEDDED { |
108 public: | 108 public: |
109 enum AccessType { | 109 enum AccessType { |
110 UNDEFINED, | 110 UNDEFINED, |
111 LOAD, | 111 LOAD, |
112 LOAD_TYPEOF_EXPR, | 112 LOAD_TYPEOF_EXPR |
113 STORE, | |
114 INIT_CONST | |
115 }; | 113 }; |
116 | 114 |
117 CodeGenState() | 115 CodeGenState() |
118 : access_(UNDEFINED), | 116 : access_(UNDEFINED), |
119 ref_(NULL), | 117 ref_(NULL), |
120 true_target_(NULL), | 118 true_target_(NULL), |
121 false_target_(NULL) { | 119 false_target_(NULL) { |
122 } | 120 } |
123 | 121 |
124 CodeGenState(AccessType access, | 122 CodeGenState(AccessType access, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
174 bool is_eval); | 172 bool is_eval); |
175 | 173 |
176 virtual ~ArmCodeGenerator() { delete masm_; } | 174 virtual ~ArmCodeGenerator() { delete masm_; } |
177 | 175 |
178 // Main code generation function | 176 // Main code generation function |
179 void GenCode(FunctionLiteral* fun); | 177 void GenCode(FunctionLiteral* fun); |
180 | 178 |
181 // The following are used by class Reference. | 179 // The following are used by class Reference. |
182 void LoadReference(Reference* ref); | 180 void LoadReference(Reference* ref); |
183 void UnloadReference(Reference* ref); | 181 void UnloadReference(Reference* ref); |
184 friend class Reference; | |
185 | 182 |
186 // State | 183 // State |
187 bool has_cc() const { return cc_reg_ != al; } | 184 bool has_cc() const { return cc_reg_ != al; } |
188 CodeGenState::AccessType access() const { return state_->access(); } | 185 CodeGenState::AccessType access() const { return state_->access(); } |
189 Reference* ref() const { return state_->ref(); } | 186 Reference* ref() const { return state_->ref(); } |
190 bool is_referenced() const { return state_->ref() != NULL; } | 187 bool is_referenced() const { return state_->ref() != NULL; } |
191 Label* true_target() const { return state_->true_target(); } | 188 Label* true_target() const { return state_->true_target(); } |
192 Label* false_target() const { return state_->false_target(); } | 189 Label* false_target() const { return state_->false_target(); } |
193 | 190 |
194 | 191 |
195 // Expressions | 192 // Expressions |
196 MemOperand GlobalObject() const { | 193 MemOperand GlobalObject() const { |
197 return ContextOperand(cp, Context::GLOBAL_INDEX); | 194 return ContextOperand(cp, Context::GLOBAL_INDEX); |
198 } | 195 } |
199 | 196 |
200 MemOperand ContextOperand(Register context, int index) const { | 197 static MemOperand ContextOperand(Register context, int index) { |
201 return MemOperand(context, Context::SlotOffset(index)); | 198 return MemOperand(context, Context::SlotOffset(index)); |
202 } | 199 } |
203 | 200 |
204 MemOperand ParameterOperand(int index) const { | 201 static MemOperand ParameterOperand(Scope* scope, int index) { |
205 // index -2 corresponds to the activated closure, -1 corresponds | 202 // index -2 corresponds to the activated closure, -1 corresponds |
206 // to the receiver | 203 // to the receiver |
207 ASSERT(-2 <= index && index < scope_->num_parameters()); | 204 ASSERT(-2 <= index && index < scope->num_parameters()); |
208 int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize; | 205 int offset = JavaScriptFrameConstants::kParam0Offset - index * kPointerSize; |
209 return MemOperand(pp, offset); | 206 return MemOperand(pp, offset); |
210 } | 207 } |
211 | 208 |
209 MemOperand ParameterOperand(int index) const { | |
210 return ParameterOperand(scope_, index); | |
211 } | |
212 | |
212 MemOperand FunctionOperand() const { return ParameterOperand(-2); } | 213 MemOperand FunctionOperand() const { return ParameterOperand(-2); } |
213 | 214 |
214 MemOperand SlotOperand(Slot* slot, Register tmp); | 215 static MemOperand SlotOperand(MacroAssembler* masm, |
216 Scope* scope, | |
217 Slot* slot, | |
218 Register tmp); | |
219 | |
220 MemOperand SlotOperand(Slot* slot, Register tmp) { | |
221 return SlotOperand(masm_, scope_, slot, tmp); | |
222 } | |
215 | 223 |
216 void LoadCondition(Expression* x, CodeGenState::AccessType access, | 224 void LoadCondition(Expression* x, CodeGenState::AccessType access, |
217 Label* true_target, Label* false_target, bool force_cc); | 225 Label* true_target, Label* false_target, bool force_cc); |
218 void Load(Expression* x, | 226 void Load(Expression* x, |
219 CodeGenState::AccessType access = CodeGenState::LOAD); | 227 CodeGenState::AccessType access = CodeGenState::LOAD); |
220 void LoadGlobal(); | 228 void LoadGlobal(); |
221 | 229 |
222 // Special code for typeof expressions: Unfortunately, we must | 230 // Special code for typeof expressions: Unfortunately, we must |
223 // be careful when loading the expression in 'typeof' | 231 // be careful when loading the expression in 'typeof' |
224 // expressions. We are not allowed to throw reference errors for | 232 // expressions. We are not allowed to throw reference errors for |
225 // non-existing properties of the global object, so we must make it | 233 // non-existing properties of the global object, so we must make it |
226 // look like an explicit property access, instead of an access | 234 // look like an explicit property access, instead of an access |
227 // through the context chain. | 235 // through the context chain. |
228 void LoadTypeofExpression(Expression* x); | 236 void LoadTypeofExpression(Expression* x); |
229 | 237 |
238 | |
230 // References | 239 // References |
231 void AccessReference(Reference* ref, CodeGenState::AccessType access); | |
232 | 240 |
233 void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); } | 241 // Generate code to fetch the value of a reference. The reference is |
234 void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); } | 242 // expected to be on top of the expression stack. It is left in place and |
235 void InitConst(Reference* ref) { | 243 // its value is pushed on top of it. |
236 AccessReference(ref, CodeGenState::INIT_CONST); | 244 void GetValue(Reference* ref); |
245 | |
246 // Generate code to store a value in a reference. The stored value is | |
247 // expected on top of the expression stack, with the reference immediately | |
248 // below it. The expression stack is left unchanged. | |
249 void SetValue(Reference* ref) { | |
250 ASSERT(!has_cc()); | |
251 ASSERT(!ref->is_illegal()); | |
252 ref->expression()->GenerateStoreCode(masm_, scope_, ref, false); | |
237 } | 253 } |
238 | 254 |
239 void ToBoolean(Label* true_target, Label* false_target); | 255 // Generate code to store a value in a reference. The stored value is |
256 // expected on top of the expression stack, with the reference immediately | |
257 // below it. The expression stack is left unchanged. | |
258 void InitConst(Reference* ref) { | |
259 ASSERT(!has_cc()); | |
260 ASSERT(!ref->is_illegal()); | |
261 ref->expression()->GenerateStoreCode(masm_, scope_, ref, true); | |
262 } | |
263 | |
264 // Generate code to fetch a value from a property of a reference. The | |
265 // reference is expected on top of the expression stack. It is left in | |
266 // place and its value is pushed on top of it. | |
267 void GetReferenceProperty(Expression* key); | |
268 | |
269 // Generate code to store a value in a property of a reference. The | |
270 // stored value is expected on top of the expression stack, with the | |
271 // reference immediately below it. The expression stack is left | |
272 // unchanged. | |
273 static void SetReferenceProperty(MacroAssembler* masm, | |
274 Reference* ref, | |
275 Expression* key); | |
240 | 276 |
241 | 277 |
242 // Access property from the reference (must be at the TOS). | 278 void ToBoolean(Label* true_target, Label* false_target); |
243 void AccessReferenceProperty(Expression* key, | |
244 CodeGenState::AccessType access); | |
245 | 279 |
246 void GenericBinaryOperation(Token::Value op); | 280 void GenericBinaryOperation(Token::Value op); |
247 void Comparison(Condition cc, bool strict = false); | 281 void Comparison(Condition cc, bool strict = false); |
248 | 282 |
249 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); | 283 void SmiOperation(Token::Value op, Handle<Object> value, bool reversed); |
250 | 284 |
251 void CallWithArguments(ZoneList<Expression*>* arguments, int position); | 285 void CallWithArguments(ZoneList<Expression*>* arguments, int position); |
252 | 286 |
253 // Declare global variables and functions in the given array of | 287 // Declare global variables and functions in the given array of |
254 // name/value pairs. | 288 // name/value pairs. |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
290 | 324 |
291 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); | 325 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); |
292 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); | 326 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); |
293 | 327 |
294 virtual void GenerateValueOf(ZoneList<Expression*>* args); | 328 virtual void GenerateValueOf(ZoneList<Expression*>* args); |
295 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); | 329 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); |
296 | 330 |
297 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); | 331 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); |
298 | 332 |
299 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | 333 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); |
334 | |
335 friend class Reference; | |
336 friend class Property; | |
337 friend class VariableProxy; | |
338 friend class Slot; | |
300 }; | 339 }; |
301 | 340 |
302 | 341 |
303 // ----------------------------------------------------------------------------- | 342 // ----------------------------------------------------------------------------- |
304 // ArmCodeGenerator implementation | 343 // ArmCodeGenerator implementation |
305 | 344 |
306 #define __ masm_-> | 345 #define __ masm_-> |
307 | 346 |
308 | 347 |
309 Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit, | 348 Handle<Code> ArmCodeGenerator::MakeCode(FunctionLiteral* flit, |
(...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
592 | 631 |
593 ExitJSFrame(); | 632 ExitJSFrame(); |
594 | 633 |
595 // Code generation state must be reset. | 634 // Code generation state must be reset. |
596 scope_ = NULL; | 635 scope_ = NULL; |
597 ASSERT(!has_cc()); | 636 ASSERT(!has_cc()); |
598 ASSERT(state_ == NULL); | 637 ASSERT(state_ == NULL); |
599 } | 638 } |
600 | 639 |
601 | 640 |
602 MemOperand ArmCodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 641 MemOperand ArmCodeGenerator::SlotOperand(MacroAssembler* masm, |
642 Scope* scope, | |
643 Slot* slot, | |
644 Register tmp) { | |
603 // Currently, this assertion will fail if we try to assign to | 645 // Currently, this assertion will fail if we try to assign to |
604 // a constant variable that is constant because it is read-only | 646 // a constant variable that is constant because it is read-only |
605 // (such as the variable referring to a named function expression). | 647 // (such as the variable referring to a named function expression). |
606 // We need to implement assignments to read-only variables. | 648 // We need to implement assignments to read-only variables. |
607 // Ideally, we should do this during AST generation (by converting | 649 // Ideally, we should do this during AST generation (by converting |
608 // such assignments into expression statements); however, in general | 650 // such assignments into expression statements); however, in general |
609 // we may not be able to make the decision until past AST generation, | 651 // we may not be able to make the decision until past AST generation, |
610 // that is when the entire program is known. | 652 // that is when the entire program is known. |
611 ASSERT(slot != NULL); | 653 ASSERT(slot != NULL); |
612 int index = slot->index(); | 654 int index = slot->index(); |
613 switch (slot->type()) { | 655 switch (slot->type()) { |
614 case Slot::PARAMETER: | 656 case Slot::PARAMETER: |
615 return ParameterOperand(index); | 657 return ParameterOperand(scope, index); |
616 | 658 |
617 case Slot::LOCAL: { | 659 case Slot::LOCAL: { |
618 ASSERT(0 <= index && | 660 ASSERT(0 <= index && |
619 index < scope_->num_stack_slots() && | 661 index < scope->num_stack_slots() && |
620 index >= 0); | 662 index >= 0); |
621 int local_offset = JavaScriptFrameConstants::kLocal0Offset - | 663 int local_offset = JavaScriptFrameConstants::kLocal0Offset - |
622 index * kPointerSize; | 664 index * kPointerSize; |
623 return MemOperand(fp, local_offset); | 665 return MemOperand(fp, local_offset); |
624 } | 666 } |
625 | 667 |
626 case Slot::CONTEXT: { | 668 case Slot::CONTEXT: { |
627 // Follow the context chain if necessary. | 669 // Follow the context chain if necessary. |
628 ASSERT(!tmp.is(cp)); // do not overwrite context register | 670 ASSERT(!tmp.is(cp)); // do not overwrite context register |
629 Register context = cp; | 671 Register context = cp; |
630 int chain_length = scope_->ContextChainLength(slot->var()->scope()); | 672 int chain_length = scope->ContextChainLength(slot->var()->scope()); |
631 for (int i = chain_length; i-- > 0;) { | 673 for (int i = chain_length; i-- > 0;) { |
632 // Load the closure. | 674 // Load the closure. |
633 // (All contexts, even 'with' contexts, have a closure, | 675 // (All contexts, even 'with' contexts, have a closure, |
634 // and it is the same for all contexts inside a function. | 676 // and it is the same for all contexts inside a function. |
635 // There is no need to go to the function context first.) | 677 // There is no need to go to the function context first.) |
636 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); | 678 masm->ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
637 // Load the function context (which is the incoming, outer context). | 679 // Load the function context (which is the incoming, outer context). |
638 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); | 680 masm->ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset)); |
639 context = tmp; | 681 context = tmp; |
640 } | 682 } |
641 // We may have a 'with' context now. Get the function context. | 683 // We may have a 'with' context now. Get the function context. |
642 // (In fact this mov may never be the needed, since the scope analysis | 684 // (In fact this mov may never be the needed, since the scope analysis |
643 // may not permit a direct context access in this case and thus we are | 685 // may not permit a direct context access in this case and thus we are |
644 // always at a function context. However it is safe to dereference be- | 686 // always at a function context. However it is safe to dereference be- |
645 // cause the function context of a function context is itself. Before | 687 // cause the function context of a function context is itself. Before |
646 // deleting this mov we should try to create a counter-example first, | 688 // deleting this mov we should try to create a counter-example first, |
647 // though...) | 689 // though...) |
648 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 690 masm->ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
649 return ContextOperand(tmp, index); | 691 return ContextOperand(tmp, index); |
650 } | 692 } |
651 | 693 |
652 default: | 694 default: |
653 UNREACHABLE(); | 695 UNREACHABLE(); |
654 return MemOperand(r0, 0); | 696 return MemOperand(r0, 0); |
655 } | 697 } |
656 } | 698 } |
657 | 699 |
658 | 700 |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
815 if (size <= 0) { | 857 if (size <= 0) { |
816 // Do nothing. No popping is necessary. | 858 // Do nothing. No popping is necessary. |
817 } else { | 859 } else { |
818 __ pop(r0); | 860 __ pop(r0); |
819 __ add(sp, sp, Operand(size * kPointerSize)); | 861 __ add(sp, sp, Operand(size * kPointerSize)); |
820 __ push(r0); | 862 __ push(r0); |
821 } | 863 } |
822 } | 864 } |
823 | 865 |
824 | 866 |
825 void ArmCodeGenerator::AccessReference(Reference* ref, | 867 void ArmCodeGenerator::GetValue(Reference* ref) { |
826 CodeGenState::AccessType access) { | |
827 ASSERT(!has_cc()); | 868 ASSERT(!has_cc()); |
828 ASSERT(ref->type() != Reference::ILLEGAL); | 869 ASSERT(!ref->is_illegal()); |
829 CodeGenState* old_state = state_; | 870 CodeGenState* old_state = state_; |
830 CodeGenState new_state(access, ref, true_target(), false_target()); | 871 CodeGenState new_state(CodeGenState::LOAD, ref, true_target(), |
872 false_target()); | |
831 state_ = &new_state; | 873 state_ = &new_state; |
832 Visit(ref->expression()); | 874 Visit(ref->expression()); |
833 state_ = old_state; | 875 state_ = old_state; |
834 } | 876 } |
835 | 877 |
836 | 878 |
879 void Property::GenerateStoreCode(MacroAssembler* masm, | |
880 Scope* scope, | |
881 Reference* ref, | |
882 bool is_const_init) { | |
883 Comment cmnt(masm, "[ Store to Property"); | |
884 masm->RecordPosition(position()); | |
885 ArmCodeGenerator::SetReferenceProperty(masm, ref, key()); | |
886 } | |
887 | |
888 | |
889 void VariableProxy::GenerateStoreCode(MacroAssembler* masm, | |
890 Scope* scope, | |
891 Reference* ref, | |
892 bool is_const_init) { | |
893 Comment cmnt(masm, "[ Store to VariableProxy"); | |
894 Variable* node = var(); | |
895 | |
896 Expression* expr = node->rewrite(); | |
897 if (expr != NULL) { | |
898 expr->GenerateStoreCode(masm, scope, ref, is_const_init); | |
899 } else { | |
900 ASSERT(node->is_global()); | |
901 if (node->AsProperty() != NULL) { | |
902 masm->RecordPosition(node->AsProperty()->position()); | |
903 } | |
904 ArmCodeGenerator::SetReferenceProperty(masm, ref, | |
905 new Literal(node->name())); | |
906 } | |
907 } | |
908 | |
909 | |
910 void Slot::GenerateStoreCode(MacroAssembler* masm, | |
911 Scope* scope, | |
912 Reference* ref, | |
913 bool is_const_init) { | |
914 Comment cmnt(masm, "[ Store to Slot"); | |
915 | |
916 if (type() == Slot::LOOKUP) { | |
917 ASSERT(var()->mode() == Variable::DYNAMIC); | |
918 | |
919 // For now, just do a runtime call. | |
920 masm->push(cp); | |
921 masm->mov(r0, Operand(var()->name())); | |
922 masm->push(r0); | |
923 | |
924 if (is_const_init) { | |
925 // Same as the case for a normal store, but ignores attribute | |
926 // (e.g. READ_ONLY) of context slot so that we can initialize const | |
927 // properties (introduced via eval("const foo = (some expr);")). Also, | |
928 // uses the current function context instead of the top context. | |
929 // | |
930 // Note that we must declare the foo upon entry of eval(), via a | |
931 // context slot declaration, but we cannot initialize it at the same | |
932 // time, because the const declaration may be at the end of the eval | |
933 // code (sigh...) and the const variable may have been used before | |
934 // (where its value is 'undefined'). Thus, we can only do the | |
935 // initialization when we actually encounter the expression and when | |
936 // the expression operands are defined and valid, and thus we need the | |
937 // split into 2 operations: declaration of the context slot followed | |
938 // by initialization. | |
939 masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
940 } else { | |
941 masm->CallRuntime(Runtime::kStoreContextSlot, 3); | |
942 } | |
943 // Storing a variable must keep the (new) value on the expression | |
944 // stack. This is necessary for compiling assignment expressions. | |
945 masm->push(r0); | |
946 | |
947 } else { | |
948 ASSERT(var()->mode() != Variable::DYNAMIC); | |
949 | |
950 Label exit; | |
951 if (is_const_init) { | |
952 ASSERT(var()->mode() == Variable::CONST); | |
953 // Only the first const initialization must be executed (the slot | |
954 // still contains 'the hole' value). When the assignment is executed, | |
955 // the code is identical to a normal store (see below). | |
956 Comment cmnt(masm, "[ Init const"); | |
957 masm->ldr(r2, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); | |
958 masm->cmp(r2, Operand(Factory::the_hole_value())); | |
959 masm->b(ne, &exit); | |
960 } | |
961 | |
962 // We must execute the store. | |
963 // r2 may be loaded with context; used below in RecordWrite. | |
964 // Storing a variable must keep the (new) value on the stack. This is | |
965 // necessary for compiling assignment expressions. | |
966 // | |
967 // Note: We will reach here even with var()->mode() == Variable::CONST | |
968 // because of const declarations which will initialize consts to 'the | |
969 // hole' value and by doing so, end up calling this code. r2 may be | |
970 // loaded with context; used below in RecordWrite. | |
971 masm->pop(r0); | |
972 masm->str(r0, ArmCodeGenerator::SlotOperand(masm, scope, this, r2)); | |
973 masm->push(r0); | |
974 | |
975 if (type() == Slot::CONTEXT) { | |
976 // Skip write barrier if the written value is a smi. | |
977 masm->tst(r0, Operand(kSmiTagMask)); | |
978 masm->b(eq, &exit); | |
979 // r2 is loaded with context when calling SlotOperand above. | |
980 int offset = FixedArray::kHeaderSize + index() * kPointerSize; | |
981 masm->mov(r3, Operand(offset)); | |
982 masm->RecordWrite(r2, r3, r1); | |
983 } | |
984 masm->bind(&exit); | |
985 } | |
986 } | |
987 | |
988 | |
837 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given | 989 // ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given |
838 // register to a boolean in the condition code register. The code | 990 // register to a boolean in the condition code register. The code |
839 // may jump to 'false_target' in case the register converts to 'false'. | 991 // may jump to 'false_target' in case the register converts to 'false'. |
840 void ArmCodeGenerator::ToBoolean(Label* true_target, | 992 void ArmCodeGenerator::ToBoolean(Label* true_target, |
841 Label* false_target) { | 993 Label* false_target) { |
842 // Note: The generated code snippet does not change stack variables. | 994 // Note: The generated code snippet does not change stack variables. |
843 // Only the condition code should be set. | 995 // Only the condition code should be set. |
844 __ pop(r0); | 996 __ pop(r0); |
845 | 997 |
846 // Fast case checks | 998 // Fast case checks |
(...skipping 982 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1829 __ push(r0); | 1981 __ push(r0); |
1830 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); | 1982 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1); |
1831 } | 1983 } |
1832 } | 1984 } |
1833 | 1985 |
1834 | 1986 |
1835 #undef __ | 1987 #undef __ |
1836 #define __ masm_-> | 1988 #define __ masm_-> |
1837 | 1989 |
1838 | 1990 |
1839 void ArmCodeGenerator::AccessReferenceProperty( | 1991 void ArmCodeGenerator::GetReferenceProperty(Expression* key) { |
1840 Expression* key, | |
1841 CodeGenState::AccessType access) { | |
1842 Reference::Type type = ref()->type(); | 1992 Reference::Type type = ref()->type(); |
1843 ASSERT(type != Reference::ILLEGAL); | 1993 ASSERT(!ref()->is_illegal()); |
1844 | 1994 |
1845 // TODO(1241834): Make sure that this is sufficient. If there is a chance | 1995 // TODO(1241834): Make sure that this it is safe to ignore the distinction |
1846 // that reference errors can be thrown below, we must distinguish | 1996 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance |
1847 // between the 2 kinds of loads (typeof expression loads must not | 1997 // that reference errors can be thrown below, we must distinguish between |
1848 // throw a reference error). | 1998 // the two kinds of loads (typeof expression loads must not throw a |
1849 bool is_load = (access == CodeGenState::LOAD || | 1999 // reference error). |
1850 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
1851 | |
1852 if (type == Reference::NAMED) { | 2000 if (type == Reference::NAMED) { |
1853 // Compute the name of the property. | 2001 // Compute the name of the property. |
1854 Literal* literal = key->AsLiteral(); | 2002 Literal* literal = key->AsLiteral(); |
1855 Handle<String> name(String::cast(*literal->handle())); | 2003 Handle<String> name(String::cast(*literal->handle())); |
1856 | 2004 |
1857 // Call the appropriate IC code. | 2005 // Call the appropriate IC code. |
1858 if (is_load) { | 2006 // Setup the name register. |
1859 // Setup the name register. | 2007 __ mov(r2, Operand(name)); |
1860 __ mov(r2, Operand(name)); | 2008 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1861 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 2009 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
1862 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | 2010 if (var != NULL) { |
1863 if (var != NULL) { | 2011 ASSERT(var->is_global()); |
1864 ASSERT(var->is_global()); | 2012 __ Call(ic, code_target_context); |
1865 __ Call(ic, code_target_context); | |
1866 } else { | |
1867 __ Call(ic, code_target); | |
1868 } | |
1869 | |
1870 } else { | 2013 } else { |
1871 __ pop(r0); // value | |
1872 // Setup the name register. | |
1873 __ mov(r2, Operand(name)); | |
1874 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
1875 __ Call(ic, code_target); | 2014 __ Call(ic, code_target); |
1876 } | 2015 } |
1877 | 2016 |
1878 } else { | 2017 } else { |
1879 // Access keyed property. | 2018 // Access keyed property. |
1880 ASSERT(type == Reference::KEYED); | 2019 ASSERT(type == Reference::KEYED); |
1881 | 2020 |
1882 if (is_load) { | 2021 // TODO(1224671): Implement inline caching for keyed loads as on ia32. |
1883 // TODO(1224671): Implement inline caching for keyed loads as on ia32. | 2022 GetPropertyStub stub; |
1884 GetPropertyStub stub; | 2023 __ CallStub(&stub); |
1885 __ CallStub(&stub); | |
1886 | |
1887 } else { | |
1888 __ pop(r0); // value | |
1889 SetPropertyStub stub; | |
1890 __ CallStub(&stub); | |
1891 } | |
1892 } | 2024 } |
1893 __ push(r0); | 2025 __ push(r0); |
1894 } | 2026 } |
1895 | 2027 |
1896 | 2028 |
2029 void ArmCodeGenerator::SetReferenceProperty(MacroAssembler* masm, | |
2030 Reference* ref, | |
2031 Expression* key) { | |
2032 Reference::Type type = ref->type(); | |
2033 ASSERT(!ref->is_illegal()); | |
iposva
2008/09/10 18:01:44
Nit: Don't you want to assert before accessing any
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Changed. Illegal references have a type, so it's
| |
2034 | |
2035 if (type == Reference::NAMED) { | |
2036 // Compute the name of the property. | |
2037 Literal* literal = key->AsLiteral(); | |
2038 Handle<String> name(String::cast(*literal->handle())); | |
2039 | |
2040 // Call the appropriate IC code. | |
2041 masm->pop(r0); // value | |
2042 // Setup the name register. | |
2043 masm->mov(r2, Operand(name)); | |
2044 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
2045 masm->Call(ic, code_target); | |
2046 | |
2047 } else { | |
2048 // Access keyed property. | |
2049 ASSERT(type == Reference::KEYED); | |
2050 | |
2051 masm->pop(r0); // value | |
2052 SetPropertyStub stub; | |
2053 masm->CallStub(&stub); | |
2054 } | |
2055 masm->push(r0); | |
2056 } | |
2057 | |
2058 | |
1897 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { | 2059 void ArmCodeGenerator::GenericBinaryOperation(Token::Value op) { |
1898 // sp[0] : y | 2060 // sp[0] : y |
1899 // sp[1] : x | 2061 // sp[1] : x |
1900 // result : r0 | 2062 // result : r0 |
1901 | 2063 |
1902 // Stub is entered with a call: 'return address' is in lr. | 2064 // Stub is entered with a call: 'return address' is in lr. |
1903 switch (op) { | 2065 switch (op) { |
1904 case Token::ADD: // fall through. | 2066 case Token::ADD: // fall through. |
1905 case Token::SUB: // fall through. | 2067 case Token::SUB: // fall through. |
1906 case Token::MUL: | 2068 case Token::MUL: |
(...skipping 1202 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3109 __ bind(&then); | 3271 __ bind(&then); |
3110 Load(node->then_expression(), access()); | 3272 Load(node->then_expression(), access()); |
3111 __ b(&exit); | 3273 __ b(&exit); |
3112 __ bind(&else_); | 3274 __ bind(&else_); |
3113 Load(node->else_expression(), access()); | 3275 Load(node->else_expression(), access()); |
3114 __ bind(&exit); | 3276 __ bind(&exit); |
3115 } | 3277 } |
3116 | 3278 |
3117 | 3279 |
3118 void ArmCodeGenerator::VisitSlot(Slot* node) { | 3280 void ArmCodeGenerator::VisitSlot(Slot* node) { |
3281 ASSERT(access() != CodeGenState::UNDEFINED); | |
3119 Comment cmnt(masm_, "[ Slot"); | 3282 Comment cmnt(masm_, "[ Slot"); |
3120 | 3283 |
3121 if (node->type() == Slot::LOOKUP) { | 3284 if (node->type() == Slot::LOOKUP) { |
3122 ASSERT(node->var()->mode() == Variable::DYNAMIC); | 3285 ASSERT(node->var()->mode() == Variable::DYNAMIC); |
3123 | 3286 |
3124 // For now, just do a runtime call. | 3287 // For now, just do a runtime call. |
3125 __ push(cp); | 3288 __ push(cp); |
3126 __ mov(r0, Operand(node->var()->name())); | 3289 __ mov(r0, Operand(node->var()->name())); |
3127 __ push(r0); | 3290 __ push(r0); |
3128 | 3291 |
3129 switch (access()) { | 3292 if (access() == CodeGenState::LOAD) { |
3130 case CodeGenState::UNDEFINED: | 3293 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
3131 UNREACHABLE(); | 3294 } else { |
3132 break; | 3295 // CodeGenState::LOAD_TYPEOF_EXPR. |
iposva
2008/09/10 18:01:44
Please assert that the CodeGenState is LOAD_TYPEOF
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done. Earlier assert already ruled out UNDEFINED,
| |
3133 | 3296 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
3134 case CodeGenState::LOAD: | |
3135 __ CallRuntime(Runtime::kLoadContextSlot, 2); | |
3136 __ push(r0); | |
3137 break; | |
3138 | |
3139 case CodeGenState::LOAD_TYPEOF_EXPR: | |
3140 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
3141 __ push(r0); | |
3142 break; | |
3143 | |
3144 case CodeGenState::STORE: | |
3145 // Storing a variable must keep the (new) value on the stack. This | |
3146 // is necessary for compiling assignment expressions. | |
3147 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
3148 __ push(r0); | |
3149 // result (TOS) is the value that was stored | |
3150 break; | |
3151 | |
3152 case CodeGenState::INIT_CONST: | |
3153 // Same as STORE but ignores attribute (e.g. READ_ONLY) of | |
3154 // context slot so that we can initialize const properties | |
3155 // (introduced via eval("const foo = (some expr);")). Also, | |
3156 // uses the current function context instead of the top | |
3157 // context. | |
3158 // | |
3159 // Note that we must declare the foo upon entry of eval(), | |
3160 // via a context slot declaration, but we cannot initialize | |
3161 // it at the same time, because the const declaration may | |
3162 // be at the end of the eval code (sigh...) and the const | |
3163 // variable may have been used before (where its value is | |
3164 // 'undefined'). Thus, we can only do the initialization | |
3165 // when we actually encounter the expression and when the | |
3166 // expression operands are defined and valid, and thus we | |
3167 // need the split into 2 operations: declaration of the | |
3168 // context slot followed by initialization. | |
3169 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
3170 __ push(r0); | |
3171 break; | |
3172 } | 3297 } |
3298 __ push(r0); | |
3173 | 3299 |
3174 } else { | 3300 } else { |
3175 // Note: We would like to keep the assert below, but it fires because | 3301 // Note: We would like to keep the assert below, but it fires because of |
3176 // of some nasty code in LoadTypeofExpression() which should be removed... | 3302 // some nasty code in LoadTypeofExpression() which should be removed... |
3177 // ASSERT(node->var()->mode() != Variable::DYNAMIC); | 3303 // ASSERT(node->var()->mode() != Variable::DYNAMIC); |
3178 | 3304 |
3179 switch (access()) { | 3305 // Special handling for locals allocated in registers. |
3180 case CodeGenState::UNDEFINED: | 3306 __ ldr(r0, SlotOperand(node, r2)); |
3181 UNREACHABLE(); | 3307 __ push(r0); |
3182 break; | 3308 if (node->var()->mode() == Variable::CONST) { |
3183 | 3309 // Const slots may contain 'the hole' value (the constant hasn't been |
3184 case CodeGenState::LOAD: // fall through | 3310 // initialized yet) which needs to be converted into the 'undefined' |
3185 case CodeGenState::LOAD_TYPEOF_EXPR: | 3311 // value. |
3186 // Special handling for locals allocated in registers. | 3312 Comment cmnt(masm_, "[ Unhole const"); |
3187 __ ldr(r0, SlotOperand(node, r2)); | 3313 __ pop(r0); |
3188 __ push(r0); | 3314 __ cmp(r0, Operand(Factory::the_hole_value())); |
3189 if (node->var()->mode() == Variable::CONST) { | 3315 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); |
3190 // Const slots may contain 'the hole' value (the constant hasn't | 3316 __ push(r0); |
3191 // been initialized yet) which needs to be converted into the | |
3192 // 'undefined' value. | |
3193 Comment cmnt(masm_, "[ Unhole const"); | |
3194 __ pop(r0); | |
3195 __ cmp(r0, Operand(Factory::the_hole_value())); | |
3196 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq); | |
3197 __ push(r0); | |
3198 } | |
3199 break; | |
3200 | |
3201 case CodeGenState::INIT_CONST: { | |
3202 ASSERT(node->var()->mode() == Variable::CONST); | |
3203 // Only the first const initialization must be executed (the slot | |
3204 // still contains 'the hole' value). When the assignment is executed, | |
3205 // the code is identical to a normal store (see below). | |
3206 { Comment cmnt(masm_, "[ Init const"); | |
3207 Label L; | |
3208 __ ldr(r2, SlotOperand(node, r2)); | |
3209 __ cmp(r2, Operand(Factory::the_hole_value())); | |
3210 __ b(ne, &L); | |
3211 // We must execute the store. | |
3212 // r2 may be loaded with context; used below in RecordWrite. | |
3213 __ ldr(r0, MemOperand(sp, 0)); | |
3214 __ str(r0, SlotOperand(node, r2)); | |
3215 if (node->type() == Slot::CONTEXT) { | |
3216 // Skip write barrier if the written value is a smi. | |
3217 Label exit; | |
3218 __ tst(r0, Operand(kSmiTagMask)); | |
3219 __ b(eq, &exit); | |
3220 // r2 is loaded with context when calling SlotOperand above. | |
3221 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; | |
3222 __ mov(r3, Operand(offset)); | |
3223 __ RecordWrite(r2, r3, r1); | |
3224 __ bind(&exit); | |
3225 } | |
3226 __ bind(&L); | |
3227 } | |
3228 break; | |
3229 } | |
3230 | |
3231 case CodeGenState::STORE: { | |
3232 // Storing a variable must keep the (new) value on the stack. This | |
3233 // is necessary for compiling assignment expressions. | |
3234 // Special handling for locals allocated in registers. | |
3235 // | |
3236 // Note: We will reach here even with node->var()->mode() == | |
3237 // Variable::CONST because of const declarations which will | |
3238 // initialize consts to 'the hole' value and by doing so, end | |
3239 // up calling this code. | |
3240 // r2 may be loaded with context; used below in RecordWrite. | |
3241 __ pop(r0); | |
3242 __ str(r0, SlotOperand(node, r2)); | |
3243 __ push(r0); | |
3244 if (node->type() == Slot::CONTEXT) { | |
3245 // Skip write barrier if the written value is a smi. | |
3246 Label exit; | |
3247 __ tst(r0, Operand(kSmiTagMask)); | |
3248 __ b(eq, &exit); | |
3249 // r2 is loaded with context when calling SlotOperand above. | |
3250 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; | |
3251 __ mov(r3, Operand(offset)); | |
3252 __ RecordWrite(r2, r3, r1); | |
3253 __ bind(&exit); | |
3254 } | |
3255 break; | |
3256 } | |
3257 } | 3317 } |
3258 } | 3318 } |
3259 } | 3319 } |
3260 | 3320 |
3261 | 3321 |
3262 void ArmCodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) { | 3322 void ArmCodeGenerator::VisitVariableProxy(VariableProxy* node) { |
3263 Comment cmnt(masm_, "[ VariableProxy"); | 3323 Comment cmnt(masm_, "[ VariableProxy"); |
3264 Variable* node = proxy_node->var(); | 3324 Variable* var_node = node->var(); |
3265 | 3325 |
3266 Expression* x = node->rewrite(); | 3326 Expression* expr = var_node->rewrite(); |
3267 if (x != NULL) { | 3327 if (expr != NULL) { |
3268 Visit(x); | 3328 Visit(expr); |
3269 return; | 3329 } else { |
3270 } | 3330 ASSERT(var_node->is_global()); |
3271 | 3331 if (is_referenced()) { |
3272 ASSERT(node->is_global()); | 3332 if (var_node->AsProperty() != NULL) { |
3273 if (is_referenced()) { | 3333 __ RecordPosition(var_node->AsProperty()->position()); |
3274 if (node->AsProperty() != NULL) { | 3334 } |
3275 __ RecordPosition(node->AsProperty()->position()); | 3335 GetReferenceProperty(new Literal(var_node->name())); |
3336 } else { | |
3337 Reference property(this, node); | |
3338 GetValue(&property); | |
3276 } | 3339 } |
3277 AccessReferenceProperty(new Literal(node->name()), access()); | |
3278 | |
3279 } else { | |
3280 // All stores are through references. | |
3281 ASSERT(access() != CodeGenState::STORE); | |
3282 Reference property(this, proxy_node); | |
3283 GetValue(&property); | |
3284 } | 3340 } |
3285 } | 3341 } |
3286 | 3342 |
3287 | 3343 |
3288 void ArmCodeGenerator::VisitLiteral(Literal* node) { | 3344 void ArmCodeGenerator::VisitLiteral(Literal* node) { |
3289 Comment cmnt(masm_, "[ Literal"); | 3345 Comment cmnt(masm_, "[ Literal"); |
3290 __ mov(r0, Operand(node->handle())); | 3346 __ mov(r0, Operand(node->handle())); |
3291 __ push(r0); | 3347 __ push(r0); |
3292 } | 3348 } |
3293 | 3349 |
(...skipping 240 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3534 | 3590 |
3535 Load(node->exception()); | 3591 Load(node->exception()); |
3536 __ RecordPosition(node->position()); | 3592 __ RecordPosition(node->position()); |
3537 __ CallRuntime(Runtime::kThrow, 1); | 3593 __ CallRuntime(Runtime::kThrow, 1); |
3538 __ push(r0); | 3594 __ push(r0); |
3539 } | 3595 } |
3540 | 3596 |
3541 | 3597 |
3542 void ArmCodeGenerator::VisitProperty(Property* node) { | 3598 void ArmCodeGenerator::VisitProperty(Property* node) { |
3543 Comment cmnt(masm_, "[ Property"); | 3599 Comment cmnt(masm_, "[ Property"); |
3600 | |
3544 if (is_referenced()) { | 3601 if (is_referenced()) { |
3545 __ RecordPosition(node->position()); | 3602 __ RecordPosition(node->position()); |
3546 AccessReferenceProperty(node->key(), access()); | 3603 GetReferenceProperty(node->key()); |
3547 | |
3548 } else { | 3604 } else { |
3549 // All stores are through references. | |
3550 ASSERT(access() != CodeGenState::STORE); | |
3551 Reference property(this, node); | 3605 Reference property(this, node); |
3552 __ RecordPosition(node->position()); | 3606 __ RecordPosition(node->position()); |
3553 GetValue(&property); | 3607 GetValue(&property); |
3554 } | 3608 } |
3555 } | 3609 } |
3556 | 3610 |
3557 | 3611 |
3558 void ArmCodeGenerator::VisitCall(Call* node) { | 3612 void ArmCodeGenerator::VisitCall(Call* node) { |
3559 Comment cmnt(masm_, "[ Call"); | 3613 Comment cmnt(masm_, "[ Call"); |
3560 | 3614 |
(...skipping 1089 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
4650 bool is_eval) { | 4704 bool is_eval) { |
4651 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); | 4705 Handle<Code> code = ArmCodeGenerator::MakeCode(fun, script, is_eval); |
4652 if (!code.is_null()) { | 4706 if (!code.is_null()) { |
4653 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 4707 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
4654 } | 4708 } |
4655 return code; | 4709 return code; |
4656 } | 4710 } |
4657 | 4711 |
4658 | 4712 |
4659 } } // namespace v8::internal | 4713 } } // namespace v8::internal |
OLD | NEW |