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