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