Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6)

Side by Side Diff: src/codegen-ia32.cc

Issue 6527: Move code generation for storing to a reference out of the AST nodes, and... (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: '' Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-arm.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
49 // ----------------------------------------------------------------------------- 49 // -----------------------------------------------------------------------------
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 };
60
59 class Reference BASE_EMBEDDED { 61 class Reference BASE_EMBEDDED {
60 public: 62 public:
61 // The values of the types is important, see size(). 63 // The values of the types is important, see size().
62 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; 64 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 };
63 Reference(Ia32CodeGenerator* cgen, Expression* expression); 65 Reference(Ia32CodeGenerator* cgen, Expression* expression);
64 ~Reference(); 66 ~Reference();
65 67
66 Expression* expression() const { return expression_; } 68 Expression* expression() const { return expression_; }
67 Type type() const { return type_; } 69 Type type() const { return type_; }
68 void set_type(Type value) { 70 void set_type(Type value) {
69 ASSERT(type_ == ILLEGAL); 71 ASSERT(type_ == ILLEGAL);
70 type_ = value; 72 type_ = value;
71 } 73 }
72 74
73 // The size of the reference or -1 if the reference is illegal. 75 // The size of the reference or -1 if the reference is illegal.
74 int size() const { return type_; } 76 int size() const { return type_; }
75 77
76 bool is_illegal() const { return type_ == ILLEGAL; } 78 bool is_illegal() const { return type_ == ILLEGAL; }
77 bool is_slot() const { return type_ == SLOT; } 79 bool is_slot() const { return type_ == SLOT; }
78 bool is_property() const { return type_ == NAMED || type_ == KEYED; } 80 bool is_property() const { return type_ == NAMED || type_ == KEYED; }
79 81
82 void SetValue(InitState init_state);
83
80 private: 84 private:
81 Ia32CodeGenerator* cgen_; 85 Ia32CodeGenerator* cgen_;
82 Expression* expression_; 86 Expression* expression_;
83 Type type_; 87 Type type_;
84 }; 88 };
85 89
86 90
87 // ------------------------------------------------------------------------- 91 // -------------------------------------------------------------------------
88 // Code generation state 92 // Code generation state
89 93
90 // The state is passed down the AST by the code generator. It is passed 94 // The state is passed down the AST by the code generator (and back up, in
91 // implicitly (in a member variable) to the non-static code generator member 95 // the form of the state of the label pair). It is threaded through the
92 // functions, and explicitly (as an argument) to the static member functions 96 // call stack. Constructing a state implicitly pushes it on the owning code
93 // and the AST node member functions. 97 // generator's stack of states, and destroying one implicitly pops it.
94 //
95 // The state is threaded through the call stack. Constructing a state
96 // implicitly pushes it on the owning code generator's stack of states, and
97 // destroying one implicitly pops it.
98 98
99 class CodeGenState BASE_EMBEDDED { 99 class CodeGenState BASE_EMBEDDED {
100 public: 100 public:
101 enum AccessType { 101 enum AccessType {
102 UNDEFINED, 102 UNDEFINED,
103 LOAD, 103 LOAD,
104 LOAD_TYPEOF_EXPR 104 LOAD_TYPEOF_EXPR
105 }; 105 };
106 106
107 // Create an initial code generator state. Destroying the initial state 107 // Create an initial code generator state. Destroying the initial state
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
189 Reference* ref() const { return state_->ref(); } 189 Reference* ref() const { return state_->ref(); }
190 bool is_referenced() const { return state_->ref() != NULL; } 190 bool is_referenced() const { return state_->ref() != NULL; }
191 Label* true_target() const { return state_->true_target(); } 191 Label* true_target() const { return state_->true_target(); }
192 Label* false_target() const { return state_->false_target(); } 192 Label* false_target() const { return state_->false_target(); }
193 193
194 // Expressions 194 // Expressions
195 Operand GlobalObject() const { 195 Operand GlobalObject() const {
196 return ContextOperand(esi, Context::GLOBAL_INDEX); 196 return ContextOperand(esi, Context::GLOBAL_INDEX);
197 } 197 }
198 198
199 // Support functions for accessing parameters. Static versions can 199 // Support functions for accessing parameters.
200 // require some code generator state to be passed in as arguments. 200 Operand ParameterOperand(int index) const {
201 static Operand ParameterOperand(const CodeGenerator* cgen, int index) { 201 int num_parameters = scope()->num_parameters();
202 int num_parameters = cgen->scope()->num_parameters();
203 ASSERT(-2 <= index && index < num_parameters); 202 ASSERT(-2 <= index && index < num_parameters);
204 return Operand(ebp, (1 + num_parameters - index) * kPointerSize); 203 return Operand(ebp, (1 + num_parameters - index) * kPointerSize);
205 } 204 }
206 205
207 Operand ParameterOperand(int index) const {
208 return ParameterOperand(this, index);
209 }
210
211 Operand ReceiverOperand() const { return ParameterOperand(-1); } 206 Operand ReceiverOperand() const { return ParameterOperand(-1); }
212 207
213 Operand FunctionOperand() const { 208 Operand FunctionOperand() const {
214 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); 209 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset);
215 } 210 }
216 211
217 static Operand ContextOperand(Register context, int index) { 212 Operand ContextOperand(Register context, int index) const {
218 return Operand(context, Context::SlotOffset(index)); 213 return Operand(context, Context::SlotOffset(index));
219 } 214 }
220 215
221 static Operand SlotOperand(CodeGenerator* cgen, 216 Operand SlotOperand(Slot* slot, Register tmp);
Kasper Lund 2008/10/07 11:02:11 I guess there's a good reason why this isn't const
222 Slot* slot,
223 Register tmp);
224
225 Operand SlotOperand(Slot* slot, Register tmp) {
226 return SlotOperand(this, slot, tmp);
227 }
228 217
229 void LoadCondition(Expression* x, 218 void LoadCondition(Expression* x,
230 CodeGenState::AccessType access, 219 CodeGenState::AccessType access,
231 Label* true_target, 220 Label* true_target,
232 Label* false_target, 221 Label* false_target,
233 bool force_cc); 222 bool force_cc);
234 void Load(Expression* x, 223 void Load(Expression* x,
235 CodeGenState::AccessType access = CodeGenState::LOAD); 224 CodeGenState::AccessType access = CodeGenState::LOAD);
236 void LoadGlobal(); 225 void LoadGlobal();
237 226
(...skipping 10 matching lines...) Expand all
248 // Generate code to fetch the value of a reference. The reference is 237 // Generate code to fetch the value of a reference. The reference is
249 // expected to be on top of the expression stack. It is left in place and 238 // expected to be on top of the expression stack. It is left in place and
250 // its value is pushed on top of it. 239 // its value is pushed on top of it.
251 void GetValue(Reference* ref) { 240 void GetValue(Reference* ref) {
252 ASSERT(!has_cc()); 241 ASSERT(!has_cc());
253 ASSERT(!ref->is_illegal()); 242 ASSERT(!ref->is_illegal());
254 CodeGenState new_state(this, ref); 243 CodeGenState new_state(this, ref);
255 Visit(ref->expression()); 244 Visit(ref->expression());
256 } 245 }
257 246
258 // Generate code to store a value in a reference. The stored value is
259 // expected on top of the expression stack, with the reference immediately
260 // below it. The expression stack is left unchanged.
261 void SetValue(Reference* ref) {
262 ASSERT(!has_cc());
263 ASSERT(!ref->is_illegal());
264 ref->expression()->GenerateStoreCode(this, ref, NOT_CONST_INIT);
265 }
266
267 // Same as SetValue, used to set the initial value of a constant.
268 void InitConst(Reference* ref) {
269 ASSERT(!has_cc());
270 ASSERT(!ref->is_illegal());
271 ref->expression()->GenerateStoreCode(this, ref, CONST_INIT);
272 }
273
274 // Generate code to fetch a value from a property of a reference. The 247 // Generate code to fetch a value from a property of a reference. The
275 // reference is expected on top of the expression stack. It is left in 248 // reference is expected on top of the expression stack. It is left in
276 // place and its value is pushed on top of it. 249 // place and its value is pushed on top of it.
277 void GetReferenceProperty(Expression* key); 250 void GetReferenceProperty(Expression* key);
278 251
279 // Generate code to store a value in a property of a reference. The
280 // stored value is expected on top of the expression stack, with the
281 // reference immediately below it. The expression stack is left
282 // unchanged.
283 static void SetReferenceProperty(CodeGenerator* cgen,
284 Reference* ref,
285 Expression* key);
286
287 void ToBoolean(Label* true_target, Label* false_target); 252 void ToBoolean(Label* true_target, Label* false_target);
288 253
289 void GenericBinaryOperation( 254 void GenericBinaryOperation(
290 Token::Value op, 255 Token::Value op,
291 const OverwriteMode overwrite_mode = NO_OVERWRITE); 256 const OverwriteMode overwrite_mode = NO_OVERWRITE);
292 void Comparison(Condition cc, bool strict = false); 257 void Comparison(Condition cc, bool strict = false);
293 258
294 // Inline small integer literals. To prevent long attacker-controlled byte 259 // Inline small integer literals. To prevent long attacker-controlled byte
295 // sequences, we only inline small Smi:s. 260 // sequences, we only inline small Smi:s.
296 static const int kMaxSmiInlinedBits = 16; 261 static const int kMaxSmiInlinedBits = 16;
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after
666 // representing slots take up no space on the expression stack 631 // representing slots take up no space on the expression stack
667 // (ie, it doesn't matter that the stored value is actually below 632 // (ie, it doesn't matter that the stored value is actually below
668 // the reference). 633 // the reference).
669 // 634 //
670 // If the newly-allocated argument object is not already on 635 // If the newly-allocated argument object is not already on
671 // the stack, we rely on the property that loading a 636 // the stack, we rely on the property that loading a
672 // zero-sized reference will not clobber the ecx register. 637 // zero-sized reference will not clobber the ecx register.
673 if (!arguments_object_saved) { 638 if (!arguments_object_saved) {
674 __ push(ecx); 639 __ push(ecx);
675 } 640 }
676 SetValue(&arguments_ref); 641 arguments_ref.SetValue(NOT_CONST_INIT);
677 } 642 }
678 SetValue(&shadow_ref); 643 shadow_ref.SetValue(NOT_CONST_INIT);
679 } 644 }
680 __ pop(eax); // Value is no longer needed. 645 __ pop(eax); // Value is no longer needed.
681 } 646 }
682 647
683 // Generate code to 'execute' declarations and initialize 648 // Generate code to 'execute' declarations and initialize
684 // functions (source elements). In case of an illegal 649 // functions (source elements). In case of an illegal
685 // redeclaration we need to handle that instead of processing the 650 // redeclaration we need to handle that instead of processing the
686 // declarations. 651 // declarations.
687 if (scope->HasIllegalRedeclaration()) { 652 if (scope->HasIllegalRedeclaration()) {
688 Comment cmnt(masm_, "[ illegal redeclarations"); 653 Comment cmnt(masm_, "[ illegal redeclarations");
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
727 } 692 }
728 } 693 }
729 694
730 // Code generation state must be reset. 695 // Code generation state must be reset.
731 scope_ = NULL; 696 scope_ = NULL;
732 ASSERT(!has_cc()); 697 ASSERT(!has_cc());
733 ASSERT(state_ == NULL); 698 ASSERT(state_ == NULL);
734 } 699 }
735 700
736 701
702 Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
703 // Currently, this assertion will fail if we try to assign to
704 // a constant variable that is constant because it is read-only
705 // (such as the variable referring to a named function expression).
706 // We need to implement assignments to read-only variables.
707 // Ideally, we should do this during AST generation (by converting
708 // such assignments into expression statements); however, in general
709 // we may not be able to make the decision until past AST generation,
710 // that is when the entire program is known.
711 ASSERT(slot != NULL);
712 int index = slot->index();
713 switch (slot->type()) {
714 case Slot::PARAMETER:
715 return ParameterOperand(index);
716
717 case Slot::LOCAL: {
718 ASSERT(0 <= index && index < scope()->num_stack_slots());
719 const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset;
720 return Operand(ebp, kLocal0Offset - index * kPointerSize);
721 }
722
723 case Slot::CONTEXT: {
724 // Follow the context chain if necessary.
725 ASSERT(!tmp.is(esi)); // do not overwrite context register
726 Register context = esi;
727 int chain_length = scope()->ContextChainLength(slot->var()->scope());
728 for (int i = chain_length; i-- > 0;) {
729 // Load the closure.
730 // (All contexts, even 'with' contexts, have a closure,
731 // and it is the same for all contexts inside a function.
732 // There is no need to go to the function context first.)
733 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
734 // Load the function context (which is the incoming, outer context).
735 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset));
736 context = tmp;
737 }
738 // We may have a 'with' context now. Get the function context.
739 // (In fact this mov may never be the needed, since the scope analysis
740 // may not permit a direct context access in this case and thus we are
741 // always at a function context. However it is safe to dereference be-
742 // cause the function context of a function context is itself. Before
743 // deleting this mov we should try to create a counter-example first,
744 // though...)
745 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
746 return ContextOperand(tmp, index);
747 }
748
749 default:
750 UNREACHABLE();
751 return Operand(eax);
752 }
753 }
754
755
737 // Loads a value on TOS. If it is a boolean value, the result may have been 756 // Loads a value on TOS. If it is a boolean value, the result may have been
738 // (partially) translated into branches, or it may have set the condition code 757 // (partially) translated into branches, or it may have set the condition code
739 // register. If force_cc is set, the value is forced to set the condition code 758 // register. If force_cc is set, the value is forced to set the condition code
740 // register and no value is pushed. If the condition code register was set, 759 // register and no value is pushed. If the condition code register was set,
741 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. 760 // has_cc() is true and cc_reg_ contains the condition to test for 'true'.
742 void Ia32CodeGenerator::LoadCondition(Expression* x, 761 void Ia32CodeGenerator::LoadCondition(Expression* x,
743 CodeGenState::AccessType access, 762 CodeGenState::AccessType access,
744 Label* true_target, 763 Label* true_target,
745 Label* false_target, 764 Label* false_target,
746 bool force_cc) { 765 bool force_cc) {
(...skipping 1009 matching lines...) Expand 10 before | Expand all | Expand 10 after
1756 val = new Literal(Factory::the_hole_value()); 1775 val = new Literal(Factory::the_hole_value());
1757 } else { 1776 } else {
1758 val = node->fun(); // NULL if we don't have a function 1777 val = node->fun(); // NULL if we don't have a function
1759 } 1778 }
1760 1779
1761 if (val != NULL) { 1780 if (val != NULL) {
1762 // Set initial value. 1781 // Set initial value.
1763 Reference target(this, node->proxy()); 1782 Reference target(this, node->proxy());
1764 ASSERT(target.is_slot()); 1783 ASSERT(target.is_slot());
1765 Load(val); 1784 Load(val);
1766 SetValue(&target); 1785 target.SetValue(NOT_CONST_INIT);
1767 // Get rid of the assigned value (declarations are statements). It's 1786 // Get rid of the assigned value (declarations are statements). It's
1768 // safe to pop the value lying on top of the reference before unloading 1787 // safe to pop the value lying on top of the reference before unloading
1769 // the reference itself (which preserves the top of stack) because we 1788 // the reference itself (which preserves the top of stack) because we
1770 // know that it is a zero-sized reference. 1789 // know that it is a zero-sized reference.
1771 __ pop(eax); // Pop(no_reg); 1790 __ pop(eax); // Pop(no_reg);
1772 } 1791 }
1773 } 1792 }
1774 1793
1775 1794
1776 void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { 1795 void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
(...skipping 506 matching lines...) Expand 10 before | Expand all | Expand 10 after
2283 // edx: i'th entry of the enum cache (or string there of) 2302 // edx: i'th entry of the enum cache (or string there of)
2284 __ push(ebx); 2303 __ push(ebx);
2285 { Reference each(this, node->each()); 2304 { Reference each(this, node->each());
2286 if (!each.is_illegal()) { 2305 if (!each.is_illegal()) {
2287 if (each.size() > 0) { 2306 if (each.size() > 0) {
2288 __ push(Operand(esp, kPointerSize * each.size())); 2307 __ push(Operand(esp, kPointerSize * each.size()));
2289 } 2308 }
2290 // If the reference was to a slot we rely on the convenient property 2309 // If the reference was to a slot we rely on the convenient property
2291 // that it doesn't matter whether a value (eg, ebx pushed above) is 2310 // that it doesn't matter whether a value (eg, ebx pushed above) is
2292 // right on top of or right underneath a zero-sized reference. 2311 // right on top of or right underneath a zero-sized reference.
2293 SetValue(&each); 2312 each.SetValue(NOT_CONST_INIT);
2294 if (each.size() > 0) { 2313 if (each.size() > 0) {
2295 // It's safe to pop the value lying on top of the reference before 2314 // It's safe to pop the value lying on top of the reference before
2296 // unloading the reference itself (which preserves the top of stack, 2315 // unloading the reference itself (which preserves the top of stack,
2297 // ie, now the topmost value of the non-zero sized reference), since 2316 // ie, now the topmost value of the non-zero sized reference), since
2298 // we will discard the top of stack after unloading the reference 2317 // we will discard the top of stack after unloading the reference
2299 // anyway. 2318 // anyway.
2300 __ pop(eax); 2319 __ pop(eax);
2301 } 2320 }
2302 } 2321 }
2303 } 2322 }
(...skipping 23 matching lines...) Expand all
2327 __ call(&try_block); 2346 __ call(&try_block);
2328 // --- Catch block --- 2347 // --- Catch block ---
2329 __ push(eax); 2348 __ push(eax);
2330 2349
2331 // Store the caught exception in the catch variable. 2350 // Store the caught exception in the catch variable.
2332 { Reference ref(this, node->catch_var()); 2351 { Reference ref(this, node->catch_var());
2333 ASSERT(ref.is_slot()); 2352 ASSERT(ref.is_slot());
2334 // Load the exception to the top of the stack. Here we make use of the 2353 // Load the exception to the top of the stack. Here we make use of the
2335 // convenient property that it doesn't matter whether a value is 2354 // convenient property that it doesn't matter whether a value is
2336 // immediately on top of or underneath a zero-sized reference. 2355 // immediately on top of or underneath a zero-sized reference.
2337 SetValue(&ref); 2356 ref.SetValue(NOT_CONST_INIT);
2338 } 2357 }
2339 2358
2340 // Remove the exception from the stack. 2359 // Remove the exception from the stack.
2341 __ pop(edx); 2360 __ pop(edx);
2342 2361
2343 VisitStatements(node->catch_block()->statements()); 2362 VisitStatements(node->catch_block()->statements());
2344 __ jmp(&exit); 2363 __ jmp(&exit);
2345 2364
2346 2365
2347 // --- Try block --- 2366 // --- Try block ---
(...skipping 589 matching lines...) Expand 10 before | Expand all | Expand 10 after
2937 if (var != NULL && 2956 if (var != NULL &&
2938 var->mode() == Variable::CONST && 2957 var->mode() == Variable::CONST &&
2939 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) { 2958 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
2940 // Assignment ignored - leave the value on the stack. 2959 // Assignment ignored - leave the value on the stack.
2941 } else { 2960 } else {
2942 __ RecordPosition(node->position()); 2961 __ RecordPosition(node->position());
2943 if (node->op() == Token::INIT_CONST) { 2962 if (node->op() == Token::INIT_CONST) {
2944 // Dynamic constant initializations must use the function context 2963 // Dynamic constant initializations must use the function context
2945 // and initialize the actual constant declared. Dynamic variable 2964 // and initialize the actual constant declared. Dynamic variable
2946 // initializations are simply assignments and use SetValue. 2965 // initializations are simply assignments and use SetValue.
2947 InitConst(&target); 2966 target.SetValue(CONST_INIT);
2948 } else { 2967 } else {
2949 SetValue(&target); 2968 target.SetValue(NOT_CONST_INIT);
2950 } 2969 }
2951 } 2970 }
2952 } 2971 }
2953 2972
2954 2973
2955 void Ia32CodeGenerator::VisitThrow(Throw* node) { 2974 void Ia32CodeGenerator::VisitThrow(Throw* node) {
2956 Comment cmnt(masm_, "[ Throw"); 2975 Comment cmnt(masm_, "[ Throw");
2957 2976
2958 Load(node->exception()); 2977 Load(node->exception());
2959 __ RecordPosition(node->position()); 2978 __ RecordPosition(node->position());
(...skipping 720 matching lines...) Expand 10 before | Expand all | Expand 10 after
3680 // If the count operation didn't overflow and the result is a 3699 // If the count operation didn't overflow and the result is a
3681 // valid smi, we're done. Otherwise, we jump to the deferred 3700 // valid smi, we're done. Otherwise, we jump to the deferred
3682 // slow-case code. 3701 // slow-case code.
3683 __ j(overflow, deferred->enter(), not_taken); 3702 __ j(overflow, deferred->enter(), not_taken);
3684 __ test(eax, Immediate(kSmiTagMask)); 3703 __ test(eax, Immediate(kSmiTagMask));
3685 __ j(not_zero, deferred->enter(), not_taken); 3704 __ j(not_zero, deferred->enter(), not_taken);
3686 3705
3687 // Store the new value in the target if not const. 3706 // Store the new value in the target if not const.
3688 __ bind(deferred->exit()); 3707 __ bind(deferred->exit());
3689 __ push(eax); // Push the new value to TOS 3708 __ push(eax); // Push the new value to TOS
3690 if (!is_const) SetValue(&target); 3709 if (!is_const) target.SetValue(NOT_CONST_INIT);
3691 } 3710 }
3692 3711
3693 // Postfix: Discard the new value and use the old. 3712 // Postfix: Discard the new value and use the old.
3694 if (is_postfix) __ pop(eax); 3713 if (is_postfix) __ pop(eax);
3695 } 3714 }
3696 3715
3697 3716
3698 void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { 3717 void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
3699 Comment cmnt(masm_, "[ BinaryOperation"); 3718 Comment cmnt(masm_, "[ BinaryOperation");
3700 Token::Value op = node->op(); 3719 Token::Value op = node->op();
(...skipping 363 matching lines...) Expand 10 before | Expand all | Expand 10 after
4064 // call instruction to support patching the exit code in the 4083 // call instruction to support patching the exit code in the
4065 // debugger. See VisitReturnStatement for the full return sequence. 4084 // debugger. See VisitReturnStatement for the full return sequence.
4066 __ mov(esp, Operand(ebp)); 4085 __ mov(esp, Operand(ebp));
4067 __ pop(ebp); 4086 __ pop(ebp);
4068 } 4087 }
4069 4088
4070 4089
4071 #undef __ 4090 #undef __
4072 #define __ masm-> 4091 #define __ masm->
4073 4092
4074 Operand Ia32CodeGenerator::SlotOperand(CodeGenerator* cgen, 4093 void Reference::SetValue(InitState init_state) {
4075 Slot* slot, 4094 ASSERT(!is_illegal());
4076 Register tmp) { 4095 ASSERT(!cgen_->has_cc());
4077 // Currently, this assertion will fail if we try to assign to 4096 MacroAssembler* masm = cgen_->masm();
4078 // a constant variable that is constant because it is read-only 4097 switch (type_) {
4079 // (such as the variable referring to a named function expression). 4098 case SLOT: {
4080 // We need to implement assignments to read-only variables. 4099 Comment cmnt(masm, "[ Store to Slot");
4081 // Ideally, we should do this during AST generation (by converting 4100 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
4082 // such assignments into expression statements); however, in general 4101 ASSERT(slot != NULL);
4083 // we may not be able to make the decision until past AST generation, 4102 if (slot->type() == Slot::LOOKUP) {
4084 // that is when the entire program is known. 4103 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
4085 ASSERT(slot != NULL);
4086 int index = slot->index();
4087 switch (slot->type()) {
4088 case Slot::PARAMETER: return ParameterOperand(cgen, index);
4089 4104
4090 case Slot::LOCAL: { 4105 // For now, just do a runtime call.
4091 ASSERT(0 <= index && index < cgen->scope()->num_stack_slots()); 4106 __ push(esi);
4092 const int kLocal0Offset = JavaScriptFrameConstants::kLocal0Offset; 4107 __ push(Immediate(slot->var()->name()));
4093 return Operand(ebp, kLocal0Offset - index * kPointerSize); 4108
4109 if (init_state == CONST_INIT) {
4110 // Same as the case for a normal store, but ignores attribute
4111 // (e.g. READ_ONLY) of context slot so that we can initialize
4112 // const properties (introduced via eval("const foo = (some
4113 // expr);")). Also, uses the current function context instead of
4114 // the top context.
4115 //
4116 // Note that we must declare the foo upon entry of eval(), via a
4117 // context slot declaration, but we cannot initialize it at the
4118 // same time, because the const declaration may be at the end of
4119 // the eval code (sigh...) and the const variable may have been
4120 // used before (where its value is 'undefined'). Thus, we can only
4121 // do the initialization when we actually encounter the expression
4122 // and when the expression operands are defined and valid, and
4123 // thus we need the split into 2 operations: declaration of the
4124 // context slot followed by initialization.
4125 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
4126 } else {
4127 __ CallRuntime(Runtime::kStoreContextSlot, 3);
4128 }
4129 // Storing a variable must keep the (new) value on the expression
4130 // stack. This is necessary for compiling chained assignment
4131 // expressions.
4132 __ push(eax);
4133
4134 } else {
4135 ASSERT(slot->var()->mode() != Variable::DYNAMIC);
4136
4137 Label exit;
4138 if (init_state == CONST_INIT) {
4139 ASSERT(slot->var()->mode() == Variable::CONST);
4140 // Only the first const initialization must be executed (the slot
4141 // still contains 'the hole' value). When the assignment is
4142 // executed, the code is identical to a normal store (see below).
4143 Comment cmnt(masm, "[ Init const");
4144 __ mov(eax, cgen_->SlotOperand(slot, ecx));
4145 __ cmp(eax, Factory::the_hole_value());
4146 __ j(not_equal, &exit);
4147 }
4148
4149 // We must execute the store. Storing a variable must keep the
4150 // (new) value on the stack. This is necessary for compiling
4151 // assignment expressions.
4152 //
4153 // Note: We will reach here even with slot->var()->mode() ==
4154 // Variable::CONST because of const declarations which will
4155 // initialize consts to 'the hole' value and by doing so, end up
4156 // calling this code.
4157 __ pop(eax);
4158 __ mov(cgen_->SlotOperand(slot, ecx), eax);
4159 __ push(eax); // RecordWrite may destroy the value in eax.
4160 if (slot->type() == Slot::CONTEXT) {
4161 // ecx is loaded with context when calling SlotOperand above.
4162 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
4163 __ RecordWrite(ecx, offset, eax, ebx);
4164 }
4165 // If we definitely did not jump over the assignment, we do not need
4166 // to bind the exit label. Doing so can defeat peephole
4167 // optimization.
4168 if (init_state == CONST_INIT) __ bind(&exit);
4169 }
4170 break;
4094 } 4171 }
4095 4172
4096 case Slot::CONTEXT: { 4173 case NAMED: {
4097 MacroAssembler* masm = cgen->masm(); 4174 Comment cmnt(masm, "[ Store to named Property");
4098 // Follow the context chain if necessary. 4175 Property* property = expression_->AsProperty();
4099 ASSERT(!tmp.is(esi)); // do not overwrite context register 4176 Handle<String> name;
4100 Register context = esi; 4177 if (property == NULL) {
4101 int chain_length = 4178 // Global variable reference treated as named property access.
4102 cgen->scope()->ContextChainLength(slot->var()->scope()); 4179 VariableProxy* proxy = expression_->AsVariableProxy();
4103 for (int i = chain_length; i-- > 0;) { 4180 ASSERT(proxy->AsVariable() != NULL);
4104 // Load the closure. 4181 ASSERT(proxy->AsVariable()->is_global());
4105 // (All contexts, even 'with' contexts, have a closure, 4182 name = proxy->name();
4106 // and it is the same for all contexts inside a function. 4183 } else {
4107 // There is no need to go to the function context first.) 4184 Literal* raw_name = property->key()->AsLiteral();
4108 __ mov(tmp, ContextOperand(context, Context::CLOSURE_INDEX)); 4185 ASSERT(raw_name != NULL);
4109 // Load the function context (which is the incoming, outer context). 4186 name = Handle<String>(String::cast(*raw_name->handle()));
4110 __ mov(tmp, FieldOperand(tmp, JSFunction::kContextOffset)); 4187 __ RecordPosition(property->position());
4111 context = tmp;
4112 } 4188 }
4113 // We may have a 'with' context now. Get the function context. 4189
4114 // (In fact this mov may never be the needed, since the scope analysis 4190 // Call the appropriate IC code.
4115 // may not permit a direct context access in this case and thus we are 4191 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
4116 // always at a function context. However it is safe to dereference be- 4192 // TODO(1222589): Make the IC grab the values from the stack.
4117 // cause the function context of a function context is itself. Before 4193 __ pop(eax);
4118 // deleting this mov we should try to create a counter-example first, 4194 // Setup the name register.
4119 // though...) 4195 __ mov(ecx, name);
4120 __ mov(tmp, ContextOperand(context, Context::FCONTEXT_INDEX)); 4196 __ call(ic, RelocInfo::CODE_TARGET);
4121 return ContextOperand(tmp, index); 4197 __ push(eax); // IC call leaves result in eax, push it out
4198 break;
4199 }
4200
4201 case KEYED: {
4202 Comment cmnt(masm, "[ Store to keyed Property");
4203 Property* property = expression_->AsProperty();
4204 ASSERT(property != NULL);
4205 __ RecordPosition(property->position());
4206 // Call IC code.
4207 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
4208 // TODO(1222589): Make the IC grab the values from the stack.
4209 __ pop(eax);
4210 __ call(ic, RelocInfo::CODE_TARGET);
4211 __ push(eax); // IC call leaves result in eax, push it out
4212 break;
4122 } 4213 }
4123 4214
4124 default: 4215 default:
4125 UNREACHABLE(); 4216 UNREACHABLE();
4126 return Operand(eax);
4127 } 4217 }
4128 } 4218 }
4129 4219
4130
4131 void Property::GenerateStoreCode(CodeGenerator* cgen,
4132 Reference* ref,
4133 InitState init_state) {
4134 MacroAssembler* masm = cgen->masm();
4135 Comment cmnt(masm, "[ Store to Property");
4136 __ RecordPosition(position());
4137 Ia32CodeGenerator::SetReferenceProperty(cgen, ref, key());
4138 }
4139
4140
4141 void VariableProxy::GenerateStoreCode(CodeGenerator* cgen,
4142 Reference* ref,
4143 InitState init_state) {
4144 MacroAssembler* masm = cgen->masm();
4145 Comment cmnt(masm, "[ Store to VariableProxy");
4146 Variable* node = var();
4147
4148 Expression* expr = node->rewrite();
4149 if (expr != NULL) {
4150 expr->GenerateStoreCode(cgen, ref, init_state);
4151 } else {
4152 ASSERT(node->is_global());
4153 if (node->AsProperty() != NULL) {
4154 __ RecordPosition(node->AsProperty()->position());
4155 }
4156 Expression* key = new Literal(node->name());
4157 Ia32CodeGenerator::SetReferenceProperty(cgen, ref, key);
4158 }
4159 }
4160
4161
4162 void Slot::GenerateStoreCode(CodeGenerator* cgen,
4163 Reference* ref,
4164 InitState init_state) {
4165 MacroAssembler* masm = cgen->masm();
4166 Comment cmnt(masm, "[ Store to Slot");
4167
4168 if (type() == Slot::LOOKUP) {
4169 ASSERT(var()->mode() == Variable::DYNAMIC);
4170
4171 // For now, just do a runtime call.
4172 __ push(esi);
4173 __ push(Immediate(var()->name()));
4174
4175 if (init_state == CONST_INIT) {
4176 // Same as the case for a normal store, but ignores attribute
4177 // (e.g. READ_ONLY) of context slot so that we can initialize const
4178 // properties (introduced via eval("const foo = (some expr);")). Also,
4179 // uses the current function context instead of the top context.
4180 //
4181 // Note that we must declare the foo upon entry of eval(), via a
4182 // context slot declaration, but we cannot initialize it at the same
4183 // time, because the const declaration may be at the end of the eval
4184 // code (sigh...) and the const variable may have been used before
4185 // (where its value is 'undefined'). Thus, we can only do the
4186 // initialization when we actually encounter the expression and when
4187 // the expression operands are defined and valid, and thus we need the
4188 // split into 2 operations: declaration of the context slot followed
4189 // by initialization.
4190 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
4191 } else {
4192 __ CallRuntime(Runtime::kStoreContextSlot, 3);
4193 }
4194 // Storing a variable must keep the (new) value on the expression
4195 // stack. This is necessary for compiling assignment expressions.
4196 __ push(eax);
4197
4198 } else {
4199 ASSERT(var()->mode() != Variable::DYNAMIC);
4200
4201 Label exit;
4202 if (init_state == CONST_INIT) {
4203 ASSERT(var()->mode() == Variable::CONST);
4204 // Only the first const initialization must be executed (the slot
4205 // still contains 'the hole' value). When the assignment is executed,
4206 // the code is identical to a normal store (see below).
4207 Comment cmnt(masm, "[ Init const");
4208 __ mov(eax, Ia32CodeGenerator::SlotOperand(cgen, this, ecx));
4209 __ cmp(eax, Factory::the_hole_value());
4210 __ j(not_equal, &exit);
4211 }
4212
4213 // We must execute the store.
4214 // Storing a variable must keep the (new) value on the stack. This is
4215 // necessary for compiling assignment expressions. ecx may be loaded
4216 // with context; used below in RecordWrite.
4217 //
4218 // Note: We will reach here even with node->var()->mode() ==
4219 // Variable::CONST because of const declarations which will initialize
4220 // consts to 'the hole' value and by doing so, end up calling this
4221 // code.
4222 __ pop(eax);
4223 __ mov(Ia32CodeGenerator::SlotOperand(cgen, this, ecx), eax);
4224 __ push(eax); // RecordWrite may destroy the value in eax.
4225 if (type() == Slot::CONTEXT) {
4226 // ecx is loaded with context when calling SlotOperand above.
4227 int offset = FixedArray::kHeaderSize + index() * kPointerSize;
4228 __ RecordWrite(ecx, offset, eax, ebx);
4229 }
4230 // If we definitely did not jump over the assignment, we do not need to
4231 // bind the exit label. Doing so can defeat peephole optimization.
4232 if (init_state == CONST_INIT) __ bind(&exit);
4233 }
4234 }
4235
4236 4220
4237 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined). 4221 // NOTE: The stub does not handle the inlined cases (Smis, Booleans, undefined).
4238 void ToBooleanStub::Generate(MacroAssembler* masm) { 4222 void ToBooleanStub::Generate(MacroAssembler* masm) {
4239 Label false_result, true_result, not_string; 4223 Label false_result, true_result, not_string;
4240 __ mov(eax, Operand(esp, 1 * kPointerSize)); 4224 __ mov(eax, Operand(esp, 1 * kPointerSize));
4241 4225
4242 // 'null' => false. 4226 // 'null' => false.
4243 __ cmp(eax, Factory::null_value()); 4227 __ cmp(eax, Factory::null_value());
4244 __ j(equal, &false_result); 4228 __ j(equal, &false_result);
4245 4229
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
4284 // Return 1/0 for true/false in eax. 4268 // Return 1/0 for true/false in eax.
4285 __ bind(&true_result); 4269 __ bind(&true_result);
4286 __ mov(eax, 1); 4270 __ mov(eax, 1);
4287 __ ret(1 * kPointerSize); 4271 __ ret(1 * kPointerSize);
4288 __ bind(&false_result); 4272 __ bind(&false_result);
4289 __ mov(eax, 0); 4273 __ mov(eax, 0);
4290 __ ret(1 * kPointerSize); 4274 __ ret(1 * kPointerSize);
4291 } 4275 }
4292 4276
4293 4277
4294 void Ia32CodeGenerator::SetReferenceProperty(CodeGenerator* cgen,
4295 Reference* ref,
4296 Expression* key) {
4297 ASSERT(!ref->is_illegal());
4298 MacroAssembler* masm = cgen->masm();
4299
4300 if (ref->type() == Reference::NAMED) {
4301 // Compute the name of the property.
4302 Literal* literal = key->AsLiteral();
4303 Handle<String> name(String::cast(*literal->handle()));
4304
4305 // Call the appropriate IC code.
4306 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
4307 // TODO(1222589): Make the IC grab the values from the stack.
4308 __ pop(eax);
4309 // Setup the name register.
4310 __ Set(ecx, Immediate(name));
4311 __ call(ic, RelocInfo::CODE_TARGET);
4312 } else {
4313 // Access keyed property.
4314 ASSERT(ref->type() == Reference::KEYED);
4315
4316 // Call IC code.
4317 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
4318 // TODO(1222589): Make the IC grab the values from the stack.
4319 __ pop(eax);
4320 __ call(ic, RelocInfo::CODE_TARGET);
4321 }
4322 __ push(eax); // IC call leaves result in eax, push it out
4323 }
4324
4325
4326 void GenericBinaryOpStub::Generate(MacroAssembler* masm) { 4278 void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
4327 Label call_runtime; 4279 Label call_runtime;
4328 __ mov(eax, Operand(esp, 1 * kPointerSize)); // Get y. 4280 __ mov(eax, Operand(esp, 1 * kPointerSize)); // Get y.
4329 __ mov(edx, Operand(esp, 2 * kPointerSize)); // Get x. 4281 __ mov(edx, Operand(esp, 2 * kPointerSize)); // Get x.
4330 4282
4331 // 1. Smi case. 4283 // 1. Smi case.
4332 switch (op_) { 4284 switch (op_) {
4333 case Token::ADD: { 4285 case Token::ADD: {
4334 // eax: y. 4286 // eax: y.
4335 // edx: x. 4287 // edx: x.
(...skipping 1034 matching lines...) Expand 10 before | Expand all | Expand 10 after
5370 bool is_eval) { 5322 bool is_eval) {
5371 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); 5323 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval);
5372 if (!code.is_null()) { 5324 if (!code.is_null()) {
5373 Counters::total_compiled_code_size.Increment(code->instruction_size()); 5325 Counters::total_compiled_code_size.Increment(code->instruction_size());
5374 } 5326 }
5375 return code; 5327 return code;
5376 } 5328 }
5377 5329
5378 5330
5379 } } // namespace v8::internal 5331 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-arm.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698