Chromium Code Reviews| 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 |