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 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
108 | 108 |
109 | 109 |
110 // ----------------------------------------------------------------------------- | 110 // ----------------------------------------------------------------------------- |
111 // Code generation state | 111 // Code generation state |
112 | 112 |
113 class CodeGenState BASE_EMBEDDED { | 113 class CodeGenState BASE_EMBEDDED { |
114 public: | 114 public: |
115 enum AccessType { | 115 enum AccessType { |
116 UNDEFINED, | 116 UNDEFINED, |
117 LOAD, | 117 LOAD, |
118 LOAD_TYPEOF_EXPR, | 118 LOAD_TYPEOF_EXPR |
119 STORE, | |
120 INIT_CONST | |
121 }; | 119 }; |
122 | 120 |
123 CodeGenState() | 121 CodeGenState() |
124 : access_(UNDEFINED), | 122 : access_(UNDEFINED), |
125 ref_(NULL), | 123 ref_(NULL), |
126 true_target_(NULL), | 124 true_target_(NULL), |
127 false_target_(NULL) { | 125 false_target_(NULL) { |
128 } | 126 } |
129 | 127 |
130 CodeGenState(AccessType access, | 128 CodeGenState(AccessType access, |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 Handle<Script> script, | 178 Handle<Script> script, |
181 bool is_eval); | 179 bool is_eval); |
182 virtual ~Ia32CodeGenerator() { delete masm_; } | 180 virtual ~Ia32CodeGenerator() { delete masm_; } |
183 | 181 |
184 // Main code generation function | 182 // Main code generation function |
185 void GenCode(FunctionLiteral* fun); | 183 void GenCode(FunctionLiteral* fun); |
186 | 184 |
187 // The following are used by class Reference. | 185 // The following are used by class Reference. |
188 void LoadReference(Reference* ref); | 186 void LoadReference(Reference* ref); |
189 void UnloadReference(Reference* ref); | 187 void UnloadReference(Reference* ref); |
190 friend class Reference; | |
191 | 188 |
192 // State | 189 // State |
193 bool has_cc() const { return cc_reg_ >= 0; } | 190 bool has_cc() const { return cc_reg_ >= 0; } |
194 CodeGenState::AccessType access() const { return state_->access(); } | 191 CodeGenState::AccessType access() const { return state_->access(); } |
195 Reference* ref() const { return state_->ref(); } | 192 Reference* ref() const { return state_->ref(); } |
196 bool is_referenced() const { return state_->ref() != NULL; } | 193 bool is_referenced() const { return state_->ref() != NULL; } |
197 Label* true_target() const { return state_->true_target(); } | 194 Label* true_target() const { return state_->true_target(); } |
198 Label* false_target() const { return state_->false_target(); } | 195 Label* false_target() const { return state_->false_target(); } |
199 | 196 |
200 // Expressions | 197 // Expressions |
201 Operand GlobalObject() const { | 198 Operand GlobalObject() const { |
202 return ContextOperand(esi, Context::GLOBAL_INDEX); | 199 return ContextOperand(esi, Context::GLOBAL_INDEX); |
203 } | 200 } |
204 | 201 |
205 // Support functions for accessing parameters. | 202 // Support functions for accessing parameters. Static versions can |
203 // require some code generator state to be passed in as arguments. | |
204 static Operand ParameterOperand(Scope* scope, int index) { | |
205 ASSERT(-2 <= index && index < scope->num_parameters()); | |
206 return Operand(ebp, (1 + scope->num_parameters() - index) * kPointerSize); | |
207 } | |
208 | |
206 Operand ParameterOperand(int index) const { | 209 Operand ParameterOperand(int index) const { |
207 ASSERT(-2 <= index && index < scope_->num_parameters()); | 210 return ParameterOperand(scope_, index); |
208 return Operand(ebp, (1 + scope_->num_parameters() - index) * kPointerSize); | |
209 } | 211 } |
210 | 212 |
211 Operand ReceiverOperand() const { return ParameterOperand(-1); } | 213 Operand ReceiverOperand() const { return ParameterOperand(-1); } |
214 | |
212 Operand FunctionOperand() const { | 215 Operand FunctionOperand() const { |
213 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); | 216 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); |
214 } | 217 } |
215 | 218 |
216 Operand ContextOperand(Register context, int index) const { | 219 static Operand ContextOperand(Register context, int index) { |
217 return Operand(context, Context::SlotOffset(index)); | 220 return Operand(context, Context::SlotOffset(index)); |
218 } | 221 } |
219 | 222 |
220 Operand SlotOperand(Slot* slot, Register tmp); | 223 static Operand SlotOperand(MacroAssembler* masm, |
224 Scope* scope, | |
225 Slot* slot, | |
226 Register tmp); | |
227 | |
228 Operand SlotOperand(Slot* slot, Register tmp) { | |
229 return SlotOperand(masm_, scope_, slot, tmp); | |
230 } | |
221 | 231 |
222 void LoadCondition(Expression* x, | 232 void LoadCondition(Expression* x, |
223 CodeGenState::AccessType access, | 233 CodeGenState::AccessType access, |
224 Label* true_target, | 234 Label* true_target, |
225 Label* false_target, | 235 Label* false_target, |
226 bool force_cc); | 236 bool force_cc); |
227 void Load(Expression* x, | 237 void Load(Expression* x, |
228 CodeGenState::AccessType access = CodeGenState::LOAD); | 238 CodeGenState::AccessType access = CodeGenState::LOAD); |
229 void LoadGlobal(); | 239 void LoadGlobal(); |
230 | 240 |
231 // Special code for typeof expressions: Unfortunately, we must | 241 // Special code for typeof expressions: Unfortunately, we must |
232 // be careful when loading the expression in 'typeof' | 242 // be careful when loading the expression in 'typeof' |
233 // expressions. We are not allowed to throw reference errors for | 243 // expressions. We are not allowed to throw reference errors for |
234 // non-existing properties of the global object, so we must make it | 244 // non-existing properties of the global object, so we must make it |
235 // look like an explicit property access, instead of an access | 245 // look like an explicit property access, instead of an access |
236 // through the context chain. | 246 // through the context chain. |
237 void LoadTypeofExpression(Expression* x); | 247 void LoadTypeofExpression(Expression* x); |
238 | 248 |
239 // References | 249 // References |
240 void AccessReference(Reference* ref, CodeGenState::AccessType access); | |
241 | 250 |
242 void GetValue(Reference* ref) { AccessReference(ref, CodeGenState::LOAD); } | 251 // Generate code to fetch the value of a reference. The reference is |
243 void SetValue(Reference* ref) { AccessReference(ref, CodeGenState::STORE); } | 252 // expected to be on top of the expression stack. It is left in place and |
253 // its value is pushed on top of it. | |
254 void GetValue(Reference* ref); | |
255 | |
256 // Generate code to store a value in a reference. The stored value is | |
257 // expected on top of the expression stack, with the reference immediately | |
258 // below it. The expression stack is left unchanged. | |
259 void SetValue(Reference* ref) { | |
260 ASSERT(!has_cc()); | |
261 ASSERT(!ref->is_illegal()); | |
262 ref->expression()->GenerateStoreCode(masm_, scope_, ref, false); | |
263 } | |
264 | |
265 // Same as SetValue, used to set the initial value of a constant. | |
244 void InitConst(Reference* ref) { | 266 void InitConst(Reference* ref) { |
245 AccessReference(ref, CodeGenState::INIT_CONST); | 267 ASSERT(!has_cc()); |
268 ASSERT(!ref->is_illegal()); | |
269 ref->expression()->GenerateStoreCode(masm_, scope_, ref, true); | |
246 } | 270 } |
247 | 271 |
272 // Generate code to fetch a value from a property of a reference. The | |
273 // reference is expected on top of the expression stack. It is left in | |
274 // place and its value is pushed on top of it. | |
275 void GetReferenceProperty(Expression* key); | |
276 | |
277 // Generate code to store a value in a property of a reference. The | |
278 // stored value is expected on top of the expression stack, with the | |
279 // reference immediately below it. The expression stack is left | |
280 // unchanged. | |
281 static void SetReferenceProperty(MacroAssembler* masm, | |
282 Reference* ref, | |
283 Expression* key); | |
284 | |
248 void ToBoolean(Label* true_target, Label* false_target); | 285 void ToBoolean(Label* true_target, Label* false_target); |
249 | 286 |
250 | |
251 // Access property from the reference (must be at the TOS). | |
252 void AccessReferenceProperty(Expression* key, | |
253 CodeGenState::AccessType access); | |
254 | |
255 void GenericBinaryOperation( | 287 void GenericBinaryOperation( |
256 Token::Value op, | 288 Token::Value op, |
257 const OverwriteMode overwrite_mode = NO_OVERWRITE); | 289 const OverwriteMode overwrite_mode = NO_OVERWRITE); |
258 void Comparison(Condition cc, bool strict = false); | 290 void Comparison(Condition cc, bool strict = false); |
259 | 291 |
260 // Inline small integer literals. To prevent long attacker-controlled byte | 292 // Inline small integer literals. To prevent long attacker-controlled byte |
261 // sequences, we only inline small Smi:s. | 293 // sequences, we only inline small Smi:s. |
262 static const int kMaxSmiInlinedBits = 16; | 294 static const int kMaxSmiInlinedBits = 16; |
263 bool IsInlineSmi(Literal* literal); | 295 bool IsInlineSmi(Literal* literal); |
264 void SmiComparison(Condition cc, Handle<Object> value, bool strict = false); | 296 void SmiComparison(Condition cc, Handle<Object> value, bool strict = false); |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
309 | 341 |
310 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); | 342 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); |
311 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); | 343 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); |
312 | 344 |
313 virtual void GenerateValueOf(ZoneList<Expression*>* args); | 345 virtual void GenerateValueOf(ZoneList<Expression*>* args); |
314 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); | 346 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); |
315 | 347 |
316 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); | 348 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); |
317 | 349 |
318 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | 350 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); |
351 | |
352 friend class Reference; | |
353 friend class Property; | |
354 friend class VariableProxy; | |
355 friend class Slot; | |
319 }; | 356 }; |
320 | 357 |
321 | 358 |
322 // ----------------------------------------------------------------------------- | 359 // ----------------------------------------------------------------------------- |
323 // Ia32CodeGenerator implementation | 360 // Ia32CodeGenerator implementation |
324 | 361 |
325 #define __ masm_-> | 362 #define __ masm_-> |
326 | 363 |
327 | 364 |
328 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, | 365 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, |
(...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
626 state_ = NULL; | 663 state_ = NULL; |
627 } | 664 } |
628 | 665 |
629 // Code generation state must be reset. | 666 // Code generation state must be reset. |
630 scope_ = NULL; | 667 scope_ = NULL; |
631 ASSERT(!has_cc()); | 668 ASSERT(!has_cc()); |
632 ASSERT(state_ == NULL); | 669 ASSERT(state_ == NULL); |
633 } | 670 } |
634 | 671 |
635 | 672 |
636 Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 673 Operand Ia32CodeGenerator::SlotOperand(MacroAssembler* masm, |
674 Scope* scope, | |
675 Slot* slot, | |
676 Register tmp) { | |
637 // Currently, this assertion will fail if we try to assign to | 677 // Currently, this assertion will fail if we try to assign to |
638 // a constant variable that is constant because it is read-only | 678 // a constant variable that is constant because it is read-only |
639 // (such as the variable referring to a named function expression). | 679 // (such as the variable referring to a named function expression). |
640 // We need to implement assignments to read-only variables. | 680 // We need to implement assignments to read-only variables. |
641 // Ideally, we should do this during AST generation (by converting | 681 // Ideally, we should do this during AST generation (by converting |
642 // such assignments into expression statements); however, in general | 682 // such assignments into expression statements); however, in general |
643 // we may not be able to make the decision until past AST generation, | 683 // we may not be able to make the decision until past AST generation, |
644 // that is when the entire program is known. | 684 // that is when the entire program is known. |
645 ASSERT(slot != NULL); | 685 ASSERT(slot != NULL); |
646 int index = slot->index(); | 686 int index = slot->index(); |
647 switch (slot->type()) { | 687 switch (slot->type()) { |
648 case Slot::PARAMETER: return ParameterOperand(index); | 688 case Slot::PARAMETER: return ParameterOperand(scope, index); |
649 | 689 |
650 case Slot::LOCAL: { | 690 case Slot::LOCAL: { |
651 ASSERT(0 <= index && index < scope_->num_stack_slots()); | 691 ASSERT(0 <= index && index < scope->num_stack_slots()); |
652 const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; | 692 const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; |
653 return Operand(ebp, kLocal0Offset - index * kPointerSize); | 693 return Operand(ebp, kLocal0Offset - index * kPointerSize); |
654 } | 694 } |
655 | 695 |
656 case Slot::CONTEXT: { | 696 case Slot::CONTEXT: { |
657 // Follow the context chain if necessary. | 697 // Follow the context chain if necessary. |
658 ASSERT(!tmp.is(esi)); // do not overwrite context register | 698 ASSERT(!tmp.is(esi)); // do not overwrite context register |
659 Register context = esi; | 699 Register context = esi; |
660 int chain_length = scope_->ContextChainLength(slot->var()->scope()); | 700 int chain_length = scope->ContextChainLength(slot->var()->scope()); |
661 for (int i = chain_length; i-- > 0;) { | 701 for (int i = chain_length; i-- > 0;) { |
662 // Load the closure. | 702 // Load the closure. |
663 // (All contexts, even 'with' contexts, have a closure, | 703 // (All contexts, even 'with' contexts, have a closure, |
664 // and it is the same for all contexts inside a function. | 704 // and it is the same for all contexts inside a function. |
665 // There is no need to go to the function context first.) | 705 // There is no need to go to the function context first.) |
666 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); | 706 masm->mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); |
667 // Load the function context (which is the incoming, outer context). | 707 // Load the function context (which is the incoming, outer context). |
668 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); | 708 masm->mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); |
669 context = tmp; | 709 context = tmp; |
670 } | 710 } |
671 // We may have a 'with' context now. Get the function context. | 711 // We may have a 'with' context now. Get the function context. |
672 // (In fact this mov may never be the needed, since the scope analysis | 712 // (In fact this mov may never be the needed, since the scope analysis |
673 // may not permit a direct context access in this case and thus we are | 713 // may not permit a direct context access in this case and thus we are |
674 // always at a function context. However it is safe to dereference be- | 714 // always at a function context. However it is safe to dereference be- |
675 // cause the function context of a function context is itself. Before | 715 // cause the function context of a function context is itself. Before |
676 // deleting this mov we should try to create a counter-example first, | 716 // deleting this mov we should try to create a counter-example first, |
677 // though...) | 717 // though...) |
678 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); | 718 masm->mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); |
679 return ContextOperand(tmp, index); | 719 return ContextOperand(tmp, index); |
680 } | 720 } |
681 | 721 |
682 default: | 722 default: |
683 UNREACHABLE(); | 723 UNREACHABLE(); |
684 return Operand(eax); | 724 return Operand(eax); |
685 } | 725 } |
686 } | 726 } |
687 | 727 |
688 | 728 |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
845 __ pop(eax); | 885 __ pop(eax); |
846 __ mov(TOS, eax); | 886 __ mov(TOS, eax); |
847 } else { | 887 } else { |
848 __ pop(eax); | 888 __ pop(eax); |
849 __ add(Operand(esp), Immediate(size * kPointerSize)); | 889 __ add(Operand(esp), Immediate(size * kPointerSize)); |
850 __ push(eax); | 890 __ push(eax); |
851 } | 891 } |
852 } | 892 } |
853 | 893 |
854 | 894 |
855 void Ia32CodeGenerator::AccessReference(Reference* ref, | 895 void Ia32CodeGenerator::GetValue(Reference* ref) { |
856 CodeGenState::AccessType access) { | |
857 ASSERT(!has_cc()); | 896 ASSERT(!has_cc()); |
858 ASSERT(ref->type() != Reference::ILLEGAL); | 897 ASSERT(ref->type() != Reference::ILLEGAL); |
859 CodeGenState* old_state = state_; | 898 CodeGenState* old_state = state_; |
860 CodeGenState new_state(access, ref, true_target(), false_target()); | 899 CodeGenState new_state(CodeGenState::LOAD, ref, true_target(), |
900 false_target()); | |
861 state_ = &new_state; | 901 state_ = &new_state; |
862 Visit(ref->expression()); | 902 Visit(ref->expression()); |
863 state_ = old_state; | 903 state_ = old_state; |
864 } | 904 } |
865 | 905 |
866 | 906 |
907 void Property::GenerateStoreCode(MacroAssembler* masm, | |
908 Scope* scope, | |
909 Reference* ref, | |
910 bool is_const_init) { | |
911 Comment cmnt(masm, "[ Store to Property"); | |
912 masm->RecordPosition(position()); | |
913 Ia32CodeGenerator::SetReferenceProperty(masm, ref, key()); | |
914 } | |
915 | |
916 | |
917 void VariableProxy::GenerateStoreCode(MacroAssembler* masm, | |
918 Scope* scope, | |
919 Reference* ref, | |
920 bool is_const_init) { | |
921 | |
922 Comment cmnt(masm, "[ Store to VariableProxy"); | |
923 Variable* node = var(); | |
924 | |
925 Expression* expr = node->rewrite(); | |
926 if (expr != NULL) { | |
927 expr->GenerateStoreCode(masm, scope, ref, is_const_init); | |
928 } else { | |
929 ASSERT(node->is_global()); | |
930 if (node->AsProperty() != NULL) { | |
931 masm->RecordPosition(node->AsProperty()->position()); | |
932 } | |
933 Ia32CodeGenerator::SetReferenceProperty(masm, ref, | |
934 new Literal(node->name())); | |
935 } | |
936 } | |
937 | |
938 | |
939 void Slot::GenerateStoreCode(MacroAssembler* masm, | |
940 Scope* scope, | |
941 Reference* ref, | |
942 bool is_const_init) { | |
943 Comment cmnt(masm, "[ Store to Slot"); | |
944 | |
945 if (type() == Slot::LOOKUP) { | |
946 ASSERT(var()->mode() == Variable::DYNAMIC); | |
947 | |
948 // For now, just do a runtime call. | |
949 masm->push(Operand(esi)); | |
950 masm->push(Immediate(var()->name())); | |
951 | |
952 if (is_const_init) { | |
953 // Same as the case for a normal store, but ignores attribute | |
954 // (e.g. READ_ONLY) of context slot so that we can initialize const | |
955 // properties (introduced via eval("const foo = (some expr);")). Also, | |
956 // uses the current function context instead of the top context. | |
957 // | |
958 // Note that we must declare the foo upon entry of eval(), via a | |
959 // context slot declaration, but we cannot initialize it at the same | |
960 // time, because the const declaration may be at the end of the eval | |
961 // code (sigh...) and the const variable may have been used before | |
962 // (where its value is 'undefined'). Thus, we can only do the | |
963 // initialization when we actually encounter the expression and when | |
964 // the expression operands are defined and valid, and thus we need the | |
965 // split into 2 operations: declaration of the context slot followed | |
966 // by initialization. | |
967 masm->CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
968 } else { | |
969 masm->CallRuntime(Runtime::kStoreContextSlot, 3); | |
970 } | |
971 // Storing a variable must keep the (new) value on the expression | |
972 // stack. This is necessary for compiling assignment expressions. | |
973 masm->push(eax); | |
974 | |
975 } else { | |
976 ASSERT(var()->mode() != Variable::DYNAMIC); | |
977 | |
978 Label exit; | |
979 if (is_const_init) { | |
980 ASSERT(var()->mode() == Variable::CONST); | |
981 // Only the first const initialization must be executed (the slot | |
982 // still contains 'the hole' value). When the assignment is executed, | |
983 // the code is identical to a normal store (see below). | |
984 Comment cmnt(masm, "[ Init const"); | |
985 masm->mov(eax, Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx)); | |
986 masm->cmp(eax, Factory::the_hole_value()); | |
987 masm->j(not_equal, &exit); | |
988 } | |
989 | |
990 // We must execute the store. | |
991 // Storing a variable must keep the (new) value on the stack. This is | |
992 // necessary for compiling assignment expressions. ecx may be loaded | |
993 // with context; used below in RecordWrite. | |
994 // | |
995 // Note: We will reach here even with node->var()->mode() == | |
996 // Variable::CONST because of const declarations which will initialize | |
997 // consts to 'the hole' value and by doing so, end up calling this | |
998 // code. | |
999 masm->pop(eax); | |
1000 masm->mov(Ia32CodeGenerator::SlotOperand(masm, scope, this, ecx), eax); | |
1001 masm->push(eax); // RecordWrite may destroy the value in eax. | |
1002 if (type() == Slot::CONTEXT) { | |
1003 // ecx is loaded with context when calling SlotOperand above. | |
1004 int offset = FixedArray::kHeaderSize + index() * kPointerSize; | |
1005 masm->RecordWrite(ecx, offset, eax, ebx); | |
1006 } | |
1007 masm->bind(&exit); | |
1008 } | |
1009 } | |
1010 | |
1011 | |
867 #undef __ | 1012 #undef __ |
868 #define __ masm-> | 1013 #define __ masm-> |
869 | 1014 |
870 class ToBooleanStub: public CodeStub { | 1015 class ToBooleanStub: public CodeStub { |
871 public: | 1016 public: |
872 ToBooleanStub() { } | 1017 ToBooleanStub() { } |
873 | 1018 |
874 void Generate(MacroAssembler* masm); | 1019 void Generate(MacroAssembler* masm); |
875 | 1020 |
876 private: | 1021 private: |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
984 ToBooleanStub stub; | 1129 ToBooleanStub stub; |
985 __ CallStub(&stub); | 1130 __ CallStub(&stub); |
986 // Convert result (eax) to condition code. | 1131 // Convert result (eax) to condition code. |
987 __ test(eax, Operand(eax)); | 1132 __ test(eax, Operand(eax)); |
988 | 1133 |
989 ASSERT(not_equal == not_zero); | 1134 ASSERT(not_equal == not_zero); |
990 cc_reg_ = not_equal; | 1135 cc_reg_ = not_equal; |
991 } | 1136 } |
992 | 1137 |
993 | 1138 |
994 void Ia32CodeGenerator::AccessReferenceProperty( | 1139 void Ia32CodeGenerator::GetReferenceProperty(Expression* key) { |
995 Expression* key, | |
996 CodeGenState::AccessType access) { | |
997 Reference::Type type = ref()->type(); | 1140 Reference::Type type = ref()->type(); |
998 ASSERT(type != Reference::ILLEGAL); | 1141 ASSERT(!ref()->is_illegal()); |
iposva
2008/09/10 18:01:44
Same nit as on ARM: Don't you want to assert befor
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done.
| |
999 | 1142 |
1000 // TODO(1241834): Make sure that this is sufficient. If there is a chance | 1143 // TODO(1241834): Make sure that this it is safe to ignore the distinction |
1001 // that reference errors can be thrown below, we must distinguish | 1144 // between access types LOAD and LOAD_TYPEOF_EXPR. If there is a chance |
1002 // between the 2 kinds of loads (typeof expression loads must not | 1145 // that reference errors can be thrown below, we must distinguish between |
1003 // throw a reference error). | 1146 // the two kinds of loads (typeof expression loads must not throw a |
1004 bool is_load = (access == CodeGenState::LOAD || | 1147 // reference error). |
1005 access == CodeGenState::LOAD_TYPEOF_EXPR); | |
1006 | |
1007 if (type == Reference::NAMED) { | 1148 if (type == Reference::NAMED) { |
1008 // Compute the name of the property. | 1149 // Compute the name of the property. |
1009 Literal* literal = key->AsLiteral(); | 1150 Literal* literal = key->AsLiteral(); |
1010 Handle<String> name(String::cast(*literal->handle())); | 1151 Handle<String> name(String::cast(*literal->handle())); |
1011 | 1152 |
1012 // Call the appropriate IC code. | 1153 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); |
1013 if (is_load) { | 1154 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
1014 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); | 1155 // Setup the name register. |
1015 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | 1156 __ Set(ecx, Immediate(name)); |
1016 // Setup the name register. | 1157 if (var != NULL) { |
1017 __ Set(ecx, Immediate(name)); | 1158 ASSERT(var->is_global()); |
1018 if (var != NULL) { | 1159 __ call(ic, code_target_context); |
1019 ASSERT(var->is_global()); | |
1020 __ call(ic, code_target_context); | |
1021 } else { | |
1022 __ call(ic, code_target); | |
1023 } | |
1024 } else { | 1160 } else { |
1025 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
1026 // TODO(1222589): Make the IC grab the values from the stack. | |
1027 __ pop(eax); | |
1028 // Setup the name register. | |
1029 __ Set(ecx, Immediate(name)); | |
1030 __ call(ic, code_target); | 1161 __ call(ic, code_target); |
1031 } | 1162 } |
1032 } else { | 1163 } else { |
1033 // Access keyed property. | 1164 // Access keyed property. |
1034 ASSERT(type == Reference::KEYED); | 1165 ASSERT(type == Reference::KEYED); |
1035 | 1166 |
1036 if (is_load) { | 1167 // Call IC code. |
1037 // Call IC code. | 1168 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); |
1038 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); | 1169 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); |
1039 Variable* var = ref()->expression()->AsVariableProxy()->AsVariable(); | 1170 if (var != NULL) { |
1040 if (var != NULL) { | 1171 ASSERT(var->is_global()); |
1041 ASSERT(var->is_global()); | 1172 __ call(ic, code_target_context); |
1042 __ call(ic, code_target_context); | |
1043 } else { | |
1044 __ call(ic, code_target); | |
1045 } | |
1046 } else { | 1173 } else { |
1047 // Call IC code. | |
1048 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | |
1049 // TODO(1222589): Make the IC grab the values from the stack. | |
1050 __ pop(eax); | |
1051 __ call(ic, code_target); | 1174 __ call(ic, code_target); |
1052 } | 1175 } |
1053 } | 1176 } |
1054 __ push(eax); // IC call leaves result in eax, push it out | 1177 __ push(eax); // IC call leaves result in eax, push it out |
1055 } | 1178 } |
1056 | 1179 |
1057 | 1180 |
1181 void Ia32CodeGenerator::SetReferenceProperty(MacroAssembler* masm, | |
1182 Reference* ref, | |
1183 Expression* key) { | |
1184 Reference::Type type = ref->type(); | |
1185 ASSERT(!ref->is_illegal()); | |
1186 | |
1187 if (type == Reference::NAMED) { | |
1188 // Compute the name of the property. | |
1189 Literal* literal = key->AsLiteral(); | |
1190 Handle<String> name(String::cast(*literal->handle())); | |
1191 | |
1192 // Call the appropriate IC code. | |
1193 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); | |
1194 // TODO(1222589): Make the IC grab the values from the stack. | |
1195 masm->pop(eax); | |
1196 // Setup the name register. | |
1197 masm->Set(ecx, Immediate(name)); | |
1198 masm->call(ic, code_target); | |
1199 } else { | |
1200 // Access keyed property. | |
1201 ASSERT(type == Reference::KEYED); | |
1202 | |
1203 // Call IC code. | |
1204 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); | |
1205 // TODO(1222589): Make the IC grab the values from the stack. | |
1206 masm->pop(eax); | |
1207 masm->call(ic, code_target); | |
1208 } | |
1209 masm->push(eax); // IC call leaves result in eax, push it out | |
1210 } | |
1211 | |
1212 | |
1058 #undef __ | 1213 #undef __ |
1059 #define __ masm-> | 1214 #define __ masm-> |
1060 | 1215 |
1061 | 1216 |
1062 class FloatingPointHelper : public AllStatic { | 1217 class FloatingPointHelper : public AllStatic { |
1063 public: | 1218 public: |
1064 // Code pattern for loading floating point values. Input values must | 1219 // Code pattern for loading floating point values. Input values must |
1065 // be either smi or heap number objects (fp values). Requirements: | 1220 // be either smi or heap number objects (fp values). Requirements: |
1066 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as | 1221 // operand_1 on TOS+1 , operand_2 on TOS+2; Returns operands as |
1067 // floating point numbers on FPU stack. | 1222 // floating point numbers on FPU stack. |
(...skipping 2250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3318 __ bind(&then); | 3473 __ bind(&then); |
3319 Load(node->then_expression(), access()); | 3474 Load(node->then_expression(), access()); |
3320 __ jmp(&exit); | 3475 __ jmp(&exit); |
3321 __ bind(&else_); | 3476 __ bind(&else_); |
3322 Load(node->else_expression(), access()); | 3477 Load(node->else_expression(), access()); |
3323 __ bind(&exit); | 3478 __ bind(&exit); |
3324 } | 3479 } |
3325 | 3480 |
3326 | 3481 |
3327 void Ia32CodeGenerator::VisitSlot(Slot* node) { | 3482 void Ia32CodeGenerator::VisitSlot(Slot* node) { |
3483 ASSERT(access() != CodeGenState::UNDEFINED); | |
3328 Comment cmnt(masm_, "[ Slot"); | 3484 Comment cmnt(masm_, "[ Slot"); |
3329 | 3485 |
3330 if (node->type() == Slot::LOOKUP) { | 3486 if (node->type() == Slot::LOOKUP) { |
3331 ASSERT(node->var()->mode() == Variable::DYNAMIC); | 3487 ASSERT(node->var()->mode() == Variable::DYNAMIC); |
3332 | 3488 |
3333 // For now, just do a runtime call. | 3489 // For now, just do a runtime call. |
3334 __ push(Operand(esi)); | 3490 __ push(Operand(esi)); |
3335 __ push(Immediate(node->var()->name())); | 3491 __ push(Immediate(node->var()->name())); |
3336 | 3492 |
3337 switch (access()) { | 3493 if (access() == CodeGenState::LOAD) { |
3338 case CodeGenState::UNDEFINED: | 3494 __ CallRuntime(Runtime::kLoadContextSlot, 2); |
3339 UNREACHABLE(); | 3495 } else { |
3340 break; | 3496 // CodeGenState::LOAD_TYPEOF_EXPR. |
iposva
2008/09/10 18:01:44
Same comment as on ARM: Please assert that the Cod
Kevin Millikin (Chromium)
2008/09/11 07:15:55
Done.
| |
3341 | 3497 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
3342 case CodeGenState::LOAD: | |
3343 __ CallRuntime(Runtime::kLoadContextSlot, 2); | |
3344 __ push(eax); | |
3345 // result (TOS) is the value that was loaded | |
3346 break; | |
3347 | |
3348 case CodeGenState::LOAD_TYPEOF_EXPR: | |
3349 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | |
3350 __ push(eax); | |
3351 // result (TOS) is the value that was loaded | |
3352 break; | |
3353 | |
3354 case CodeGenState::STORE: | |
3355 // Storing a variable must keep the (new) value on the | |
3356 // stack. This is necessary for compiling assignment | |
3357 // expressions. | |
3358 __ CallRuntime(Runtime::kStoreContextSlot, 3); | |
3359 __ push(eax); | |
3360 // result (TOS) is the value that was stored | |
3361 break; | |
3362 | |
3363 case CodeGenState::INIT_CONST: | |
3364 // Same as STORE but ignores attribute (e.g. READ_ONLY) of | |
3365 // context slot so that we can initialize const properties | |
3366 // (introduced via eval("const foo = (some expr);")). Also, | |
3367 // uses the current function context instead of the top | |
3368 // context. | |
3369 // | |
3370 // Note that we must declare the foo upon entry of eval(), | |
3371 // via a context slot declaration, but we cannot initialize | |
3372 // it at the same time, because the const declaration may | |
3373 // be at the end of the eval code (sigh...) and the const | |
3374 // variable may have been used before (where its value is | |
3375 // 'undefined'). Thus, we can only do the initialization | |
3376 // when we actually encounter the expression and when the | |
3377 // expression operands are defined and valid, and thus we | |
3378 // need the split into 2 operations: declaration of the | |
3379 // context slot followed by initialization. | |
3380 // | |
3381 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); | |
3382 __ push(eax); | |
3383 break; | |
3384 } | 3498 } |
3499 __ push(eax); | |
3385 | 3500 |
3386 } else { | 3501 } else { |
3387 // Note: We would like to keep the assert below, but it fires because | 3502 // Note: We would like to keep the assert below, but it fires because of |
3388 // of some nasty code in LoadTypeofExpression() which should be removed... | 3503 // some nasty code in LoadTypeofExpression() which should be removed... |
3389 // ASSERT(node->var()->mode() != Variable::DYNAMIC); | 3504 // ASSERT(node->var()->mode() != Variable::DYNAMIC); |
3390 | 3505 |
3391 switch (access()) { | 3506 if (node->var()->mode() == Variable::CONST) { |
3392 case CodeGenState::UNDEFINED: | 3507 // Const slots may contain 'the hole' value (the constant hasn't been |
3393 UNREACHABLE(); | 3508 // initialized yet) which needs to be converted into the 'undefined' |
3394 break; | 3509 // value. |
3395 | 3510 Comment cmnt(masm_, "[ Load const"); |
3396 case CodeGenState::LOAD: // fall through | 3511 Label L; |
3397 case CodeGenState::LOAD_TYPEOF_EXPR: | 3512 __ mov(eax, SlotOperand(node, ecx)); |
3398 if (node->var()->mode() == Variable::CONST) { | 3513 __ cmp(eax, Factory::the_hole_value()); |
3399 // Const slots may contain 'the hole' value (the constant hasn't | 3514 __ j(not_equal, &L); |
3400 // been initialized yet) which needs to be converted into the | 3515 __ mov(eax, Factory::undefined_value()); |
3401 // 'undefined' value. | 3516 __ bind(&L); |
3402 Comment cmnt(masm_, "[ Load const"); | 3517 __ push(eax); |
3403 Label L; | 3518 } else { |
3404 __ mov(eax, SlotOperand(node, ecx)); | 3519 __ push(SlotOperand(node, ecx)); |
3405 __ cmp(eax, Factory::the_hole_value()); | |
3406 __ j(not_equal, &L); | |
3407 __ mov(eax, Factory::undefined_value()); | |
3408 __ bind(&L); | |
3409 __ push(eax); | |
3410 } else { | |
3411 __ push(SlotOperand(node, ecx)); | |
3412 } | |
3413 break; | |
3414 | |
3415 case CodeGenState::INIT_CONST: | |
3416 ASSERT(node->var()->mode() == Variable::CONST); | |
3417 // Only the first const initialization must be executed (the slot | |
3418 // still contains 'the hole' value). When the assignment is executed, | |
3419 // the code is identical to a normal store (see below). | |
3420 { Comment cmnt(masm_, "[ Init const"); | |
3421 Label L; | |
3422 __ mov(eax, SlotOperand(node, ecx)); | |
3423 __ cmp(eax, Factory::the_hole_value()); | |
3424 __ j(not_equal, &L); | |
3425 // We must execute the store. | |
3426 __ mov(eax, TOS); | |
3427 __ mov(SlotOperand(node, ecx), eax); | |
3428 if (node->type() == Slot::CONTEXT) { | |
3429 // ecx is loaded with context when calling SlotOperand above. | |
3430 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; | |
3431 __ RecordWrite(ecx, offset, eax, ebx); | |
3432 } | |
3433 __ bind(&L); | |
3434 } | |
3435 break; | |
3436 | |
3437 case CodeGenState::STORE: | |
3438 // Storing a variable must keep the (new) value on the stack. This | |
3439 // is necessary for compiling assignment expressions. | |
3440 // ecx may be loaded with context; used below in RecordWrite. | |
3441 // | |
3442 // Note: We will reach here even with node->var()->mode() == | |
3443 // Variable::CONST because of const declarations which will | |
3444 // initialize consts to 'the hole' value and by doing so, end | |
3445 // up calling this code. | |
3446 __ pop(eax); | |
3447 __ mov(SlotOperand(node, ecx), eax); | |
3448 __ push(eax); // RecordWrite may destroy the value in eax. | |
3449 if (node->type() == Slot::CONTEXT) { | |
3450 // ecx is loaded with context when calling SlotOperand above. | |
3451 int offset = FixedArray::kHeaderSize + node->index() * kPointerSize; | |
3452 __ RecordWrite(ecx, offset, eax, ebx); | |
3453 } | |
3454 break; | |
3455 } | 3520 } |
3456 } | 3521 } |
3457 } | 3522 } |
3458 | 3523 |
3459 | 3524 |
3460 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* proxy_node) { | 3525 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
3461 Comment cmnt(masm_, "[ VariableProxy"); | 3526 Comment cmnt(masm_, "[ VariableProxy"); |
3462 Variable* node = proxy_node->var(); | 3527 Variable* var_node = node->var(); |
3463 | 3528 |
3464 Expression* x = node->rewrite(); | 3529 Expression* expr = var_node->rewrite(); |
3465 if (x != NULL) { | 3530 if (expr != NULL) { |
3466 Visit(x); | 3531 Visit(expr); |
3467 return; | 3532 } else { |
3468 } | 3533 ASSERT(var_node->is_global()); |
3469 | 3534 if (is_referenced()) { |
3470 ASSERT(node->is_global()); | 3535 if (var_node->AsProperty() != NULL) { |
3471 if (is_referenced()) { | 3536 __ RecordPosition(var_node->AsProperty()->position()); |
3472 if (node->AsProperty() != NULL) { | 3537 } |
3473 __ RecordPosition(node->AsProperty()->position()); | 3538 GetReferenceProperty(new Literal(var_node->name())); |
3539 } else { | |
3540 Reference property(this, node); | |
3541 GetValue(&property); | |
3474 } | 3542 } |
3475 AccessReferenceProperty(new Literal(node->name()), access()); | |
3476 | |
3477 } else { | |
3478 // All stores are through references. | |
3479 ASSERT(access() != CodeGenState::STORE); | |
3480 Reference property(this, proxy_node); | |
3481 GetValue(&property); | |
3482 } | 3543 } |
3483 } | 3544 } |
3484 | 3545 |
3485 | 3546 |
3486 void Ia32CodeGenerator::VisitLiteral(Literal* node) { | 3547 void Ia32CodeGenerator::VisitLiteral(Literal* node) { |
3487 Comment cmnt(masm_, "[ Literal"); | 3548 Comment cmnt(masm_, "[ Literal"); |
3488 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 3549 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
3489 // To prevent long attacker-controlled byte sequences in code, larger | 3550 // To prevent long attacker-controlled byte sequences in code, larger |
3490 // Smis are loaded in two steps. | 3551 // Smis are loaded in two steps. |
3491 int bits = reinterpret_cast<int>(*node->handle()); | 3552 int bits = reinterpret_cast<int>(*node->handle()); |
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3777 __ CallRuntime(Runtime::kThrow, 1); | 3838 __ CallRuntime(Runtime::kThrow, 1); |
3778 __ push(eax); | 3839 __ push(eax); |
3779 } | 3840 } |
3780 | 3841 |
3781 | 3842 |
3782 void Ia32CodeGenerator::VisitProperty(Property* node) { | 3843 void Ia32CodeGenerator::VisitProperty(Property* node) { |
3783 Comment cmnt(masm_, "[ Property"); | 3844 Comment cmnt(masm_, "[ Property"); |
3784 | 3845 |
3785 if (is_referenced()) { | 3846 if (is_referenced()) { |
3786 __ RecordPosition(node->position()); | 3847 __ RecordPosition(node->position()); |
3787 AccessReferenceProperty(node->key(), access()); | 3848 GetReferenceProperty(node->key()); |
3788 } else { | 3849 } else { |
3789 // All stores are through references. | |
3790 ASSERT(access() != CodeGenState::STORE); | |
3791 Reference property(this, node); | 3850 Reference property(this, node); |
3792 __ RecordPosition(node->position()); | 3851 __ RecordPosition(node->position()); |
3793 GetValue(&property); | 3852 GetValue(&property); |
3794 } | 3853 } |
3795 } | 3854 } |
3796 | 3855 |
3797 | 3856 |
3798 void Ia32CodeGenerator::VisitCall(Call* node) { | 3857 void Ia32CodeGenerator::VisitCall(Call* node) { |
3799 Comment cmnt(masm_, "[ Call"); | 3858 Comment cmnt(masm_, "[ Call"); |
3800 | 3859 |
(...skipping 1585 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
5386 bool is_eval) { | 5445 bool is_eval) { |
5387 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | 5446 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); |
5388 if (!code.is_null()) { | 5447 if (!code.is_null()) { |
5389 Counters::total_compiled_code_size.Increment(code->instruction_size()); | 5448 Counters::total_compiled_code_size.Increment(code->instruction_size()); |
5390 } | 5449 } |
5391 return code; | 5450 return code; |
5392 } | 5451 } |
5393 | 5452 |
5394 | 5453 |
5395 } } // namespace v8::internal | 5454 } } // namespace v8::internal |
OLD | NEW |