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 12 matching lines...) Expand all Loading... |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #include "v8.h" | 28 #include "v8.h" |
29 | 29 |
30 #include "bootstrapper.h" | 30 #include "bootstrapper.h" |
31 #include "codegen-inl.h" | 31 #include "codegen-inl.h" |
32 #include "debug.h" | 32 #include "debug.h" |
33 #include "prettyprinter.h" | |
34 #include "scopeinfo.h" | |
35 #include "scopes.h" | 33 #include "scopes.h" |
36 #include "runtime.h" | 34 #include "runtime.h" |
37 | 35 |
38 namespace v8 { namespace internal { | 36 namespace v8 { namespace internal { |
39 | 37 |
40 #define TOS (Operand(esp, 0)) | 38 #define TOS (Operand(esp, 0)) |
41 | 39 |
42 | 40 |
43 class Ia32CodeGenerator; | |
44 | |
45 // Mode to overwrite BinaryExpression values. | |
46 enum OverwriteMode { NO_OVERWRITE, OVERWRITE_LEFT, OVERWRITE_RIGHT }; | |
47 | |
48 | |
49 // ----------------------------------------------------------------------------- | |
50 // Reference support | |
51 | |
52 // A reference is a C++ stack-allocated object that keeps an ECMA | |
53 // reference on the execution stack while in scope. For variables | |
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. | |
56 // For properties, we keep either one (named) or two (indexed) values | |
57 // on the execution stack to represent the reference. | |
58 | |
59 enum InitState { CONST_INIT, NOT_CONST_INIT }; | |
60 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF }; | |
61 | |
62 class Reference BASE_EMBEDDED { | |
63 public: | |
64 // The values of the types is important, see size(). | |
65 enum Type { ILLEGAL = -1, SLOT = 0, NAMED = 1, KEYED = 2 }; | |
66 Reference(Ia32CodeGenerator* cgen, Expression* expression); | |
67 ~Reference(); | |
68 | |
69 Expression* expression() const { return expression_; } | |
70 Type type() const { return type_; } | |
71 void set_type(Type value) { | |
72 ASSERT(type_ == ILLEGAL); | |
73 type_ = value; | |
74 } | |
75 | |
76 // The size of the reference or -1 if the reference is illegal. | |
77 int size() const { return type_; } | |
78 | |
79 bool is_illegal() const { return type_ == ILLEGAL; } | |
80 bool is_slot() const { return type_ == SLOT; } | |
81 bool is_property() const { return type_ == NAMED || type_ == KEYED; } | |
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. | |
95 void SetValue(InitState init_state); | |
96 | |
97 private: | |
98 Ia32CodeGenerator* cgen_; | |
99 Expression* expression_; | |
100 Type type_; | |
101 }; | |
102 | |
103 | |
104 // ------------------------------------------------------------------------- | |
105 // Code generation state | |
106 | |
107 // The state is passed down the AST by the code generator (and back up, in | |
108 // the form of the state of the label pair). It is threaded through the | |
109 // call stack. Constructing a state implicitly pushes it on the owning code | |
110 // generator's stack of states, and destroying one implicitly pops it. | |
111 | |
112 class CodeGenState BASE_EMBEDDED { | |
113 public: | |
114 // Create an initial code generator state. Destroying the initial state | |
115 // leaves the code generator with a NULL state. | |
116 explicit CodeGenState(Ia32CodeGenerator* owner); | |
117 | |
118 // Create a code generator state based on a code generator's current | |
119 // state. The new state has its own typeof state and pair of branch | |
120 // labels. | |
121 CodeGenState(Ia32CodeGenerator* owner, | |
122 TypeofState typeof_state, | |
123 Label* true_target, | |
124 Label* false_target); | |
125 | |
126 // Destroy a code generator state and restore the owning code generator's | |
127 // previous state. | |
128 ~CodeGenState(); | |
129 | |
130 TypeofState typeof_state() const { return typeof_state_; } | |
131 Label* true_target() const { return true_target_; } | |
132 Label* false_target() const { return false_target_; } | |
133 | |
134 private: | |
135 Ia32CodeGenerator* owner_; | |
136 TypeofState typeof_state_; | |
137 Label* true_target_; | |
138 Label* false_target_; | |
139 CodeGenState* previous_; | |
140 }; | |
141 | |
142 | |
143 // ----------------------------------------------------------------------------- | |
144 // Ia32CodeGenerator | |
145 | |
146 class Ia32CodeGenerator: public CodeGenerator { | |
147 public: | |
148 static Handle<Code> MakeCode(FunctionLiteral* fun, | |
149 Handle<Script> script, | |
150 bool is_eval); | |
151 | |
152 MacroAssembler* masm() { return masm_; } | |
153 | |
154 Scope* scope() const { return scope_; } | |
155 | |
156 CodeGenState* state() { return state_; } | |
157 void set_state(CodeGenState* state) { state_ = state; } | |
158 | |
159 private: | |
160 // Assembler | |
161 MacroAssembler* masm_; // to generate code | |
162 | |
163 // Code generation state | |
164 Scope* scope_; | |
165 Condition cc_reg_; | |
166 CodeGenState* state_; | |
167 bool is_inside_try_; | |
168 int break_stack_height_; | |
169 | |
170 // Labels | |
171 Label function_return_; | |
172 | |
173 // Construction/destruction | |
174 Ia32CodeGenerator(int buffer_size, | |
175 Handle<Script> script, | |
176 bool is_eval); | |
177 virtual ~Ia32CodeGenerator() { delete masm_; } | |
178 | |
179 // Main code generation function | |
180 void GenCode(FunctionLiteral* fun); | |
181 | |
182 // The following are used by class Reference. | |
183 void LoadReference(Reference* ref); | |
184 void UnloadReference(Reference* ref); | |
185 | |
186 // State | |
187 bool has_cc() const { return cc_reg_ >= 0; } | |
188 TypeofState typeof_state() const { return state_->typeof_state(); } | |
189 Label* true_target() const { return state_->true_target(); } | |
190 Label* false_target() const { return state_->false_target(); } | |
191 | |
192 // Expressions | |
193 Operand GlobalObject() const { | |
194 return ContextOperand(esi, Context::GLOBAL_INDEX); | |
195 } | |
196 | |
197 // Support functions for accessing parameters. | |
198 Operand ParameterOperand(int index) const { | |
199 int num_parameters = scope()->num_parameters(); | |
200 ASSERT(-2 <= index && index < num_parameters); | |
201 return Operand(ebp, (1 + num_parameters - index) * kPointerSize); | |
202 } | |
203 | |
204 Operand ReceiverOperand() const { return ParameterOperand(-1); } | |
205 | |
206 Operand FunctionOperand() const { | |
207 return Operand(ebp, JavaScriptFrameConstants::kFunctionOffset); | |
208 } | |
209 | |
210 Operand ContextOperand(Register context, int index) const { | |
211 return Operand(context, Context::SlotOffset(index)); | |
212 } | |
213 | |
214 Operand SlotOperand(Slot* slot, Register tmp); | |
215 | |
216 void LoadCondition(Expression* x, | |
217 TypeofState typeof_state, | |
218 Label* true_target, | |
219 Label* false_target, | |
220 bool force_cc); | |
221 void Load(Expression* x, TypeofState typeof_state = NOT_INSIDE_TYPEOF); | |
222 void LoadGlobal(); | |
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 | |
228 // be careful when loading the expression in 'typeof' | |
229 // expressions. We are not allowed to throw reference errors for | |
230 // non-existing properties of the global object, so we must make it | |
231 // look like an explicit property access, instead of an access | |
232 // through the context chain. | |
233 void LoadTypeofExpression(Expression* x); | |
234 | |
235 void ToBoolean(Label* true_target, Label* false_target); | |
236 | |
237 void GenericBinaryOperation( | |
238 Token::Value op, | |
239 const OverwriteMode overwrite_mode = NO_OVERWRITE); | |
240 void Comparison(Condition cc, bool strict = false); | |
241 | |
242 // Inline small integer literals. To prevent long attacker-controlled byte | |
243 // sequences, we only inline small Smi:s. | |
244 static const int kMaxSmiInlinedBits = 16; | |
245 bool IsInlineSmi(Literal* literal); | |
246 void SmiComparison(Condition cc, Handle<Object> value, bool strict = false); | |
247 void SmiOperation(Token::Value op, | |
248 Handle<Object> value, | |
249 bool reversed, | |
250 OverwriteMode overwrite_mode); | |
251 | |
252 void CallWithArguments(ZoneList<Expression*>* arguments, int position); | |
253 | |
254 // Declare global variables and functions in the given array of | |
255 // name/value pairs. | |
256 virtual void DeclareGlobals(Handle<FixedArray> pairs); | |
257 | |
258 // Instantiate the function boilerplate. | |
259 void InstantiateBoilerplate(Handle<JSFunction> boilerplate); | |
260 | |
261 // Control flow | |
262 void Branch(bool if_true, Label* L); | |
263 void CheckStack(); | |
264 void CleanStack(int num_bytes); | |
265 | |
266 // Node visitors | |
267 #define DEF_VISIT(type) \ | |
268 virtual void Visit##type(type* node); | |
269 NODE_LIST(DEF_VISIT) | |
270 #undef DEF_VISIT | |
271 | |
272 // Only allow fast-case switch if the range of labels is at most | |
273 // this factor times the number of case labels. | |
274 // Value is derived from comparing the size of code generated by the normal | |
275 // switch code for Smi-labels to the size of a single pointer. If code | |
276 // quality increases this number should be decreased to match. | |
277 static const int kFastSwitchMaxOverheadFactor = 5; | |
278 | |
279 // Minimal number of switch cases required before we allow jump-table | |
280 // optimization. | |
281 static const int kFastSwitchMinCaseCount = 5; | |
282 | |
283 virtual int FastCaseSwitchMaxOverheadFactor(); | |
284 virtual int FastCaseSwitchMinCaseCount(); | |
285 | |
286 // Generate a computed jump with an empty jump table. | |
287 // Binds a label to the start of the jump table. This table must | |
288 // be populated later when the addresses of the targets are known. | |
289 // Used by GenerateFastCaseSwitchStatement. | |
290 virtual void GenerateFastCaseSwitchJumpTable( | |
291 SwitchStatement* node, int min_index, int range, Label *fail_label, | |
292 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels); | |
293 | |
294 void RecordStatementPosition(Node* node); | |
295 | |
296 // Activation frames. | |
297 void EnterJSFrame(); | |
298 void ExitJSFrame(); | |
299 | |
300 virtual void GenerateIsSmi(ZoneList<Expression*>* args); | |
301 virtual void GenerateIsNonNegativeSmi(ZoneList<Expression*>* args); | |
302 virtual void GenerateIsArray(ZoneList<Expression*>* args); | |
303 | |
304 virtual void GenerateArgumentsLength(ZoneList<Expression*>* args); | |
305 virtual void GenerateArgumentsAccess(ZoneList<Expression*>* args); | |
306 | |
307 virtual void GenerateValueOf(ZoneList<Expression*>* args); | |
308 virtual void GenerateSetValueOf(ZoneList<Expression*>* args); | |
309 | |
310 virtual void GenerateFastCharCodeAt(ZoneList<Expression*>* args); | |
311 | |
312 virtual void GenerateObjectEquals(ZoneList<Expression*>* args); | |
313 | |
314 friend class Reference; | |
315 friend class Property; | |
316 friend class VariableProxy; | |
317 friend class Slot; | |
318 }; | |
319 | |
320 | |
321 // ------------------------------------------------------------------------- | 41 // ------------------------------------------------------------------------- |
322 // CodeGenState implementation. | 42 // CodeGenState implementation. |
323 | 43 |
324 CodeGenState::CodeGenState(Ia32CodeGenerator* owner) | 44 CodeGenState::CodeGenState(CodeGenerator* owner) |
325 : owner_(owner), | 45 : owner_(owner), |
326 typeof_state_(NOT_INSIDE_TYPEOF), | 46 typeof_state_(NOT_INSIDE_TYPEOF), |
327 true_target_(NULL), | 47 true_target_(NULL), |
328 false_target_(NULL), | 48 false_target_(NULL), |
329 previous_(NULL) { | 49 previous_(NULL) { |
330 owner_->set_state(this); | 50 owner_->set_state(this); |
331 } | 51 } |
332 | 52 |
333 | 53 |
334 CodeGenState::CodeGenState(Ia32CodeGenerator* owner, | 54 CodeGenState::CodeGenState(CodeGenerator* owner, |
335 TypeofState typeof_state, | 55 TypeofState typeof_state, |
336 Label* true_target, | 56 Label* true_target, |
337 Label* false_target) | 57 Label* false_target) |
338 : owner_(owner), | 58 : owner_(owner), |
339 typeof_state_(typeof_state), | 59 typeof_state_(typeof_state), |
340 true_target_(true_target), | 60 true_target_(true_target), |
341 false_target_(false_target), | 61 false_target_(false_target), |
342 previous_(owner->state()) { | 62 previous_(owner->state()) { |
343 owner_->set_state(this); | 63 owner_->set_state(this); |
344 } | 64 } |
345 | 65 |
346 | 66 |
347 CodeGenState::~CodeGenState() { | 67 CodeGenState::~CodeGenState() { |
348 ASSERT(owner_->state() == this); | 68 ASSERT(owner_->state() == this); |
349 owner_->set_state(previous_); | 69 owner_->set_state(previous_); |
350 } | 70 } |
351 | 71 |
352 | 72 |
353 // ----------------------------------------------------------------------------- | 73 // ----------------------------------------------------------------------------- |
354 // Ia32CodeGenerator implementation | 74 // CodeGenerator implementation |
355 | 75 |
356 #define __ masm_-> | 76 #define __ masm_-> |
357 | 77 |
358 Handle<Code> Ia32CodeGenerator::MakeCode(FunctionLiteral* flit, | 78 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script, |
359 Handle<Script> script, | 79 bool is_eval) |
360 bool is_eval) { | 80 : is_eval_(is_eval), |
361 #ifdef ENABLE_DISASSEMBLER | 81 script_(script), |
362 bool print_code = FLAG_print_code && !Bootstrapper::IsActive(); | 82 deferred_(8), |
363 #endif | |
364 | |
365 #ifdef DEBUG | |
366 bool print_source = false; | |
367 bool print_ast = false; | |
368 const char* ftype; | |
369 | |
370 if (Bootstrapper::IsActive()) { | |
371 print_source = FLAG_print_builtin_source; | |
372 print_ast = FLAG_print_builtin_ast; | |
373 print_code = FLAG_print_builtin_code; | |
374 ftype = "builtin"; | |
375 } else { | |
376 print_source = FLAG_print_source; | |
377 print_ast = FLAG_print_ast; | |
378 ftype = "user-defined"; | |
379 } | |
380 | |
381 if (FLAG_trace_codegen || print_source || print_ast) { | |
382 PrintF("*** Generate code for %s function: ", ftype); | |
383 flit->name()->ShortPrint(); | |
384 PrintF(" ***\n"); | |
385 } | |
386 | |
387 if (print_source) { | |
388 PrintF("--- Source from AST ---\n%s\n", PrettyPrinter().PrintProgram(flit)); | |
389 } | |
390 | |
391 if (print_ast) { | |
392 PrintF("--- AST ---\n%s\n", AstPrinter().PrintProgram(flit)); | |
393 } | |
394 #endif // DEBUG | |
395 | |
396 // Generate code. | |
397 const int initial_buffer_size = 4 * KB; | |
398 Ia32CodeGenerator cgen(initial_buffer_size, script, is_eval); | |
399 cgen.GenCode(flit); | |
400 if (cgen.HasStackOverflow()) { | |
401 ASSERT(!Top::has_pending_exception()); | |
402 return Handle<Code>::null(); | |
403 } | |
404 | |
405 // Process any deferred code. | |
406 cgen.ProcessDeferred(); | |
407 | |
408 // Allocate and install the code. | |
409 CodeDesc desc; | |
410 cgen.masm()->GetCode(&desc); | |
411 ScopeInfo<> sinfo(flit->scope()); | |
412 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION); | |
413 Handle<Code> code = Factory::NewCode(desc, &sinfo, flags); | |
414 | |
415 // Add unresolved entries in the code to the fixup list. | |
416 Bootstrapper::AddFixup(*code, cgen.masm()); | |
417 | |
418 #ifdef ENABLE_DISASSEMBLER | |
419 if (print_code) { | |
420 // Print the source code if available. | |
421 if (!script->IsUndefined() && !script->source()->IsUndefined()) { | |
422 PrintF("--- Raw source ---\n"); | |
423 StringInputBuffer stream(String::cast(script->source())); | |
424 stream.Seek(flit->start_position()); | |
425 // flit->end_position() points to the last character in the stream. We | |
426 // need to compensate by adding one to calculate the length. | |
427 int source_len = flit->end_position() - flit->start_position() + 1; | |
428 for (int i = 0; i < source_len; i++) { | |
429 if (stream.has_more()) PrintF("%c", stream.GetNext()); | |
430 } | |
431 PrintF("\n\n"); | |
432 } | |
433 PrintF("--- Code ---\n"); | |
434 code->Disassemble(); | |
435 } | |
436 #endif // ENABLE_DISASSEMBLER | |
437 | |
438 return code; | |
439 } | |
440 | |
441 | |
442 Ia32CodeGenerator::Ia32CodeGenerator(int buffer_size, | |
443 Handle<Script> script, | |
444 bool is_eval) | |
445 : CodeGenerator(is_eval, script), | |
446 masm_(new MacroAssembler(NULL, buffer_size)), | 83 masm_(new MacroAssembler(NULL, buffer_size)), |
447 scope_(NULL), | 84 scope_(NULL), |
448 cc_reg_(no_condition), | 85 cc_reg_(no_condition), |
449 state_(NULL), | 86 state_(NULL), |
450 is_inside_try_(false), | 87 is_inside_try_(false), |
451 break_stack_height_(0) { | 88 break_stack_height_(0) { |
452 } | 89 } |
453 | 90 |
454 | 91 |
455 // Calling conventions: | 92 // Calling conventions: |
456 // ebp: frame pointer | 93 // ebp: frame pointer |
457 // esp: stack pointer | 94 // esp: stack pointer |
458 // edi: caller's parameter pointer | 95 // edi: caller's parameter pointer |
459 // esi: callee's context | 96 // esi: callee's context |
460 | 97 |
461 void Ia32CodeGenerator::GenCode(FunctionLiteral* fun) { | 98 void CodeGenerator::GenCode(FunctionLiteral* fun) { |
462 // Record the position for debugging purposes. | 99 // Record the position for debugging purposes. |
463 __ RecordPosition(fun->start_position()); | 100 __ RecordPosition(fun->start_position()); |
464 | 101 |
465 Scope* scope = fun->scope(); | 102 Scope* scope = fun->scope(); |
466 ZoneList<Statement*>* body = fun->body(); | 103 ZoneList<Statement*>* body = fun->body(); |
467 | 104 |
468 // Initialize state. | 105 // Initialize state. |
469 { CodeGenState state(this); | 106 { CodeGenState state(this); |
470 scope_ = scope; | 107 scope_ = scope; |
471 cc_reg_ = no_condition; | 108 cc_reg_ = no_condition; |
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
662 } | 299 } |
663 } | 300 } |
664 | 301 |
665 // Code generation state must be reset. | 302 // Code generation state must be reset. |
666 scope_ = NULL; | 303 scope_ = NULL; |
667 ASSERT(!has_cc()); | 304 ASSERT(!has_cc()); |
668 ASSERT(state_ == NULL); | 305 ASSERT(state_ == NULL); |
669 } | 306 } |
670 | 307 |
671 | 308 |
672 Operand Ia32CodeGenerator::SlotOperand(Slot* slot, Register tmp) { | 309 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { |
673 // Currently, this assertion will fail if we try to assign to | 310 // Currently, this assertion will fail if we try to assign to |
674 // a constant variable that is constant because it is read-only | 311 // a constant variable that is constant because it is read-only |
675 // (such as the variable referring to a named function expression). | 312 // (such as the variable referring to a named function expression). |
676 // We need to implement assignments to read-only variables. | 313 // We need to implement assignments to read-only variables. |
677 // Ideally, we should do this during AST generation (by converting | 314 // Ideally, we should do this during AST generation (by converting |
678 // such assignments into expression statements); however, in general | 315 // such assignments into expression statements); however, in general |
679 // we may not be able to make the decision until past AST generation, | 316 // we may not be able to make the decision until past AST generation, |
680 // that is when the entire program is known. | 317 // that is when the entire program is known. |
681 ASSERT(slot != NULL); | 318 ASSERT(slot != NULL); |
682 int index = slot->index(); | 319 int index = slot->index(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 return Operand(eax); | 358 return Operand(eax); |
722 } | 359 } |
723 } | 360 } |
724 | 361 |
725 | 362 |
726 // Loads a value on TOS. If it is a boolean value, the result may have been | 363 // Loads a value on TOS. If it is a boolean value, the result may have been |
727 // (partially) translated into branches, or it may have set the condition code | 364 // (partially) translated into branches, or it may have set the condition code |
728 // register. If force_cc is set, the value is forced to set the condition code | 365 // register. If force_cc is set, the value is forced to set the condition code |
729 // register and no value is pushed. If the condition code register was set, | 366 // register and no value is pushed. If the condition code register was set, |
730 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. | 367 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. |
731 void Ia32CodeGenerator::LoadCondition(Expression* x, | 368 void CodeGenerator::LoadCondition(Expression* x, |
732 TypeofState typeof_state, | 369 TypeofState typeof_state, |
733 Label* true_target, | 370 Label* true_target, |
734 Label* false_target, | 371 Label* false_target, |
735 bool force_cc) { | 372 bool force_cc) { |
736 ASSERT(!has_cc()); | 373 ASSERT(!has_cc()); |
737 | 374 |
738 { CodeGenState new_state(this, typeof_state, true_target, false_target); | 375 { CodeGenState new_state(this, typeof_state, true_target, false_target); |
739 Visit(x); | 376 Visit(x); |
740 } | 377 } |
741 if (force_cc && !has_cc()) { | 378 if (force_cc && !has_cc()) { |
742 ToBoolean(true_target, false_target); | 379 ToBoolean(true_target, false_target); |
743 } | 380 } |
744 ASSERT(has_cc() || !force_cc); | 381 ASSERT(has_cc() || !force_cc); |
745 } | 382 } |
746 | 383 |
747 | 384 |
748 void Ia32CodeGenerator::Load(Expression* x, TypeofState typeof_state) { | 385 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { |
749 Label true_target; | 386 Label true_target; |
750 Label false_target; | 387 Label false_target; |
751 LoadCondition(x, typeof_state, &true_target, &false_target, false); | 388 LoadCondition(x, typeof_state, &true_target, &false_target, false); |
752 | 389 |
753 if (has_cc()) { | 390 if (has_cc()) { |
754 // convert cc_reg_ into a bool | 391 // convert cc_reg_ into a bool |
755 | 392 |
756 Label loaded, materialize_true; | 393 Label loaded, materialize_true; |
757 __ j(cc_reg_, &materialize_true); | 394 __ j(cc_reg_, &materialize_true); |
758 __ push(Immediate(Factory::false_value())); | 395 __ push(Immediate(Factory::false_value())); |
(...skipping 25 matching lines...) Expand all Loading... |
784 __ bind(&false_target); | 421 __ bind(&false_target); |
785 __ push(Immediate(Factory::false_value())); | 422 __ push(Immediate(Factory::false_value())); |
786 } | 423 } |
787 // everything is loaded at this point | 424 // everything is loaded at this point |
788 __ bind(&loaded); | 425 __ bind(&loaded); |
789 } | 426 } |
790 ASSERT(!has_cc()); | 427 ASSERT(!has_cc()); |
791 } | 428 } |
792 | 429 |
793 | 430 |
794 void Ia32CodeGenerator::LoadGlobal() { | 431 void CodeGenerator::LoadGlobal() { |
795 __ push(GlobalObject()); | 432 __ push(GlobalObject()); |
796 } | 433 } |
797 | 434 |
798 | 435 |
799 // TODO(1241834): Get rid of this function in favor of just using Load, now | 436 // TODO(1241834): Get rid of this function in favor of just using Load, now |
800 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global | 437 // that we have the INSIDE_TYPEOF typeof state. => Need to handle global |
801 // variables w/o reference errors elsewhere. | 438 // variables w/o reference errors elsewhere. |
802 void Ia32CodeGenerator::LoadTypeofExpression(Expression* x) { | 439 void CodeGenerator::LoadTypeofExpression(Expression* x) { |
803 Variable* variable = x->AsVariableProxy()->AsVariable(); | 440 Variable* variable = x->AsVariableProxy()->AsVariable(); |
804 if (variable != NULL && !variable->is_this() && variable->is_global()) { | 441 if (variable != NULL && !variable->is_this() && variable->is_global()) { |
805 // NOTE: This is somewhat nasty. We force the compiler to load | 442 // NOTE: This is somewhat nasty. We force the compiler to load |
806 // the variable as if through '<global>.<variable>' to make sure we | 443 // the variable as if through '<global>.<variable>' to make sure we |
807 // do not get reference errors. | 444 // do not get reference errors. |
808 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); | 445 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX); |
809 Literal key(variable->name()); | 446 Literal key(variable->name()); |
810 // TODO(1241834): Fetch the position from the variable instead of using | 447 // TODO(1241834): Fetch the position from the variable instead of using |
811 // no position. | 448 // no position. |
812 Property property(&global, &key, RelocInfo::kNoPosition); | 449 Property property(&global, &key, RelocInfo::kNoPosition); |
813 Load(&property); | 450 Load(&property); |
814 } else { | 451 } else { |
815 Load(x, INSIDE_TYPEOF); | 452 Load(x, INSIDE_TYPEOF); |
816 } | 453 } |
817 } | 454 } |
818 | 455 |
819 | 456 |
820 Reference::Reference(Ia32CodeGenerator* cgen, Expression* expression) | 457 Reference::Reference(CodeGenerator* cgen, Expression* expression) |
821 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { | 458 : cgen_(cgen), expression_(expression), type_(ILLEGAL) { |
822 cgen->LoadReference(this); | 459 cgen->LoadReference(this); |
823 } | 460 } |
824 | 461 |
825 | 462 |
826 Reference::~Reference() { | 463 Reference::~Reference() { |
827 cgen_->UnloadReference(this); | 464 cgen_->UnloadReference(this); |
828 } | 465 } |
829 | 466 |
830 | 467 |
831 void Ia32CodeGenerator::LoadReference(Reference* ref) { | 468 void CodeGenerator::LoadReference(Reference* ref) { |
832 Comment cmnt(masm_, "[ LoadReference"); | 469 Comment cmnt(masm_, "[ LoadReference"); |
833 Expression* e = ref->expression(); | 470 Expression* e = ref->expression(); |
834 Property* property = e->AsProperty(); | 471 Property* property = e->AsProperty(); |
835 Variable* var = e->AsVariableProxy()->AsVariable(); | 472 Variable* var = e->AsVariableProxy()->AsVariable(); |
836 | 473 |
837 if (property != NULL) { | 474 if (property != NULL) { |
838 // The expression is either a property or a variable proxy that rewrites | 475 // The expression is either a property or a variable proxy that rewrites |
839 // to a property. | 476 // to a property. |
840 Load(property->obj()); | 477 Load(property->obj()); |
841 // We use a named reference if the key is a literal symbol, unless it is | 478 // We use a named reference if the key is a literal symbol, unless it is |
(...skipping 21 matching lines...) Expand all Loading... |
863 ref->set_type(Reference::SLOT); | 500 ref->set_type(Reference::SLOT); |
864 } | 501 } |
865 } else { | 502 } else { |
866 // Anything else is a runtime error. | 503 // Anything else is a runtime error. |
867 Load(e); | 504 Load(e); |
868 __ CallRuntime(Runtime::kThrowReferenceError, 1); | 505 __ CallRuntime(Runtime::kThrowReferenceError, 1); |
869 } | 506 } |
870 } | 507 } |
871 | 508 |
872 | 509 |
873 void Ia32CodeGenerator::UnloadReference(Reference* ref) { | 510 void CodeGenerator::UnloadReference(Reference* ref) { |
874 // Pop a reference from the stack while preserving TOS. | 511 // Pop a reference from the stack while preserving TOS. |
875 Comment cmnt(masm_, "[ UnloadReference"); | 512 Comment cmnt(masm_, "[ UnloadReference"); |
876 int size = ref->size(); | 513 int size = ref->size(); |
877 if (size <= 0) { | 514 if (size <= 0) { |
878 // Do nothing. No popping is necessary. | 515 // Do nothing. No popping is necessary. |
879 } else if (size == 1) { | 516 } else if (size == 1) { |
880 __ pop(eax); | 517 __ pop(eax); |
881 __ mov(TOS, eax); | 518 __ mov(TOS, eax); |
882 } else { | 519 } else { |
883 __ pop(eax); | 520 __ pop(eax); |
(...skipping 11 matching lines...) Expand all Loading... |
895 | 532 |
896 private: | 533 private: |
897 Major MajorKey() { return ToBoolean; } | 534 Major MajorKey() { return ToBoolean; } |
898 int MinorKey() { return 0; } | 535 int MinorKey() { return 0; } |
899 }; | 536 }; |
900 | 537 |
901 | 538 |
902 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and | 539 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and |
903 // convert it to a boolean in the condition code register or jump to | 540 // convert it to a boolean in the condition code register or jump to |
904 // 'false_target'/'true_target' as appropriate. | 541 // 'false_target'/'true_target' as appropriate. |
905 void Ia32CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { | 542 void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { |
906 Comment cmnt(masm_, "[ ToBoolean"); | 543 Comment cmnt(masm_, "[ ToBoolean"); |
907 | 544 |
908 // The value to convert should be popped from the stack. | 545 // The value to convert should be popped from the stack. |
909 __ pop(eax); | 546 __ pop(eax); |
910 | 547 |
911 // Fast case checks. | 548 // Fast case checks. |
912 | 549 |
913 // 'false' => false. | 550 // 'false' => false. |
914 __ cmp(eax, Factory::false_value()); | 551 __ cmp(eax, Factory::false_value()); |
915 __ j(equal, false_target); | 552 __ j(equal, false_target); |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1006 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; | 643 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND"; |
1007 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; | 644 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR"; |
1008 case Token::SAR: return "GenericBinaryOpStub_SAR"; | 645 case Token::SAR: return "GenericBinaryOpStub_SAR"; |
1009 case Token::SHL: return "GenericBinaryOpStub_SHL"; | 646 case Token::SHL: return "GenericBinaryOpStub_SHL"; |
1010 case Token::SHR: return "GenericBinaryOpStub_SHR"; | 647 case Token::SHR: return "GenericBinaryOpStub_SHR"; |
1011 default: return "GenericBinaryOpStub"; | 648 default: return "GenericBinaryOpStub"; |
1012 } | 649 } |
1013 } | 650 } |
1014 | 651 |
1015 | 652 |
1016 void Ia32CodeGenerator::GenericBinaryOperation(Token::Value op, | 653 void CodeGenerator::GenericBinaryOperation(Token::Value op, |
1017 OverwriteMode overwrite_mode) { | 654 OverwriteMode overwrite_mode) { |
1018 Comment cmnt(masm_, "[ BinaryOperation"); | 655 Comment cmnt(masm_, "[ BinaryOperation"); |
1019 Comment cmnt_token(masm_, Token::String(op)); | 656 Comment cmnt_token(masm_, Token::String(op)); |
1020 switch (op) { | 657 switch (op) { |
1021 case Token::ADD: | 658 case Token::ADD: |
1022 case Token::SUB: | 659 case Token::SUB: |
1023 case Token::MUL: | 660 case Token::MUL: |
1024 case Token::DIV: | 661 case Token::DIV: |
1025 case Token::MOD: { | 662 case Token::MOD: { |
1026 GenericBinaryOpStub stub(op, overwrite_mode); | 663 GenericBinaryOpStub stub(op, overwrite_mode); |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1263 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_); | 900 GenericBinaryOpStub igostub(Token::SUB, overwrite_mode_); |
1264 __ CallStub(&igostub); | 901 __ CallStub(&igostub); |
1265 } | 902 } |
1266 | 903 |
1267 private: | 904 private: |
1268 Register tos_reg_; | 905 Register tos_reg_; |
1269 OverwriteMode overwrite_mode_; | 906 OverwriteMode overwrite_mode_; |
1270 }; | 907 }; |
1271 | 908 |
1272 | 909 |
1273 void Ia32CodeGenerator::SmiOperation(Token::Value op, | 910 void CodeGenerator::SmiOperation(Token::Value op, |
1274 Handle<Object> value, | 911 Handle<Object> value, |
1275 bool reversed, | 912 bool reversed, |
1276 OverwriteMode overwrite_mode) { | 913 OverwriteMode overwrite_mode) { |
1277 // NOTE: This is an attempt to inline (a bit) more of the code for | 914 // NOTE: This is an attempt to inline (a bit) more of the code for |
1278 // some possible smi operations (like + and -) when (at least) one | 915 // some possible smi operations (like + and -) when (at least) one |
1279 // of the operands is a literal smi. With this optimization, the | 916 // of the operands is a literal smi. With this optimization, the |
1280 // performance of the system is increased by ~15%, and the generated | 917 // performance of the system is increased by ~15%, and the generated |
1281 // code size is increased by ~1% (measured on a combination of | 918 // code size is increased by ~1% (measured on a combination of |
1282 // different benchmarks). | 919 // different benchmarks). |
1283 | 920 |
(...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1469 #ifdef DEBUG | 1106 #ifdef DEBUG |
1470 void Print() { | 1107 void Print() { |
1471 PrintF("CompareStub (cc %d), (strict %s)\n", | 1108 PrintF("CompareStub (cc %d), (strict %s)\n", |
1472 static_cast<int>(cc_), | 1109 static_cast<int>(cc_), |
1473 strict_ ? "true" : "false"); | 1110 strict_ ? "true" : "false"); |
1474 } | 1111 } |
1475 #endif | 1112 #endif |
1476 }; | 1113 }; |
1477 | 1114 |
1478 | 1115 |
1479 void Ia32CodeGenerator::Comparison(Condition cc, bool strict) { | 1116 void CodeGenerator::Comparison(Condition cc, bool strict) { |
1480 // Strict only makes sense for equality comparisons. | 1117 // Strict only makes sense for equality comparisons. |
1481 ASSERT(!strict || cc == equal); | 1118 ASSERT(!strict || cc == equal); |
1482 | 1119 |
1483 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. | 1120 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. |
1484 if (cc == greater || cc == less_equal) { | 1121 if (cc == greater || cc == less_equal) { |
1485 cc = ReverseCondition(cc); | 1122 cc = ReverseCondition(cc); |
1486 __ pop(edx); | 1123 __ pop(edx); |
1487 __ pop(eax); | 1124 __ pop(eax); |
1488 } else { | 1125 } else { |
1489 __ pop(eax); | 1126 __ pop(eax); |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1536 CompareStub stub(cc_, strict_); | 1173 CompareStub stub(cc_, strict_); |
1537 // Setup parameters and call stub. | 1174 // Setup parameters and call stub. |
1538 __ mov(edx, Operand(eax)); | 1175 __ mov(edx, Operand(eax)); |
1539 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); | 1176 __ mov(Operand(eax), Immediate(Smi::FromInt(value_))); |
1540 __ CallStub(&stub); | 1177 __ CallStub(&stub); |
1541 __ cmp(eax, 0); | 1178 __ cmp(eax, 0); |
1542 // "result" is returned in the flags | 1179 // "result" is returned in the flags |
1543 } | 1180 } |
1544 | 1181 |
1545 | 1182 |
1546 void Ia32CodeGenerator::SmiComparison(Condition cc, | 1183 void CodeGenerator::SmiComparison(Condition cc, |
1547 Handle<Object> value, | 1184 Handle<Object> value, |
1548 bool strict) { | 1185 bool strict) { |
1549 // Strict only makes sense for equality comparisons. | 1186 // Strict only makes sense for equality comparisons. |
1550 ASSERT(!strict || cc == equal); | 1187 ASSERT(!strict || cc == equal); |
1551 | 1188 |
1552 int int_value = Smi::cast(*value)->value(); | 1189 int int_value = Smi::cast(*value)->value(); |
1553 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); | 1190 ASSERT(is_intn(int_value, kMaxSmiInlinedBits)); |
1554 | 1191 |
1555 SmiComparisonDeferred* deferred = | 1192 SmiComparisonDeferred* deferred = |
1556 new SmiComparisonDeferred(this, cc, strict, int_value); | 1193 new SmiComparisonDeferred(this, cc, strict, int_value); |
(...skipping 20 matching lines...) Expand all Loading... |
1577 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } | 1214 void Print() { PrintF("CallFunctionStub (args %d)\n", argc_); } |
1578 #endif | 1215 #endif |
1579 | 1216 |
1580 Major MajorKey() { return CallFunction; } | 1217 Major MajorKey() { return CallFunction; } |
1581 int MinorKey() { return argc_; } | 1218 int MinorKey() { return argc_; } |
1582 }; | 1219 }; |
1583 | 1220 |
1584 | 1221 |
1585 // Call the function just below TOS on the stack with the given | 1222 // Call the function just below TOS on the stack with the given |
1586 // arguments. The receiver is the TOS. | 1223 // arguments. The receiver is the TOS. |
1587 void Ia32CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, | 1224 void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args, |
1588 int position) { | 1225 int position) { |
1589 // Push the arguments ("left-to-right") on the stack. | 1226 // Push the arguments ("left-to-right") on the stack. |
1590 for (int i = 0; i < args->length(); i++) { | 1227 for (int i = 0; i < args->length(); i++) { |
1591 Load(args->at(i)); | 1228 Load(args->at(i)); |
1592 } | 1229 } |
1593 | 1230 |
1594 // Record the position for debugging purposes. | 1231 // Record the position for debugging purposes. |
1595 __ RecordPosition(position); | 1232 __ RecordPosition(position); |
1596 | 1233 |
1597 // Use the shared code stub to call the function. | 1234 // Use the shared code stub to call the function. |
1598 CallFunctionStub call_function(args->length()); | 1235 CallFunctionStub call_function(args->length()); |
1599 __ CallStub(&call_function); | 1236 __ CallStub(&call_function); |
1600 | 1237 |
1601 // Restore context and pop function from the stack. | 1238 // Restore context and pop function from the stack. |
1602 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 1239 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
1603 __ mov(TOS, eax); | 1240 __ mov(TOS, eax); |
1604 } | 1241 } |
1605 | 1242 |
1606 | 1243 |
1607 void Ia32CodeGenerator::Branch(bool if_true, Label* L) { | 1244 void CodeGenerator::Branch(bool if_true, Label* L) { |
1608 ASSERT(has_cc()); | 1245 ASSERT(has_cc()); |
1609 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); | 1246 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); |
1610 __ j(cc, L); | 1247 __ j(cc, L); |
1611 cc_reg_ = no_condition; | 1248 cc_reg_ = no_condition; |
1612 } | 1249 } |
1613 | 1250 |
1614 | 1251 |
1615 void Ia32CodeGenerator::CheckStack() { | 1252 void CodeGenerator::CheckStack() { |
1616 if (FLAG_check_stack) { | 1253 if (FLAG_check_stack) { |
1617 Label stack_is_ok; | 1254 Label stack_is_ok; |
1618 StackCheckStub stub; | 1255 StackCheckStub stub; |
1619 ExternalReference stack_guard_limit = | 1256 ExternalReference stack_guard_limit = |
1620 ExternalReference::address_of_stack_guard_limit(); | 1257 ExternalReference::address_of_stack_guard_limit(); |
1621 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); | 1258 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); |
1622 __ j(above_equal, &stack_is_ok, taken); | 1259 __ j(above_equal, &stack_is_ok, taken); |
1623 __ CallStub(&stub); | 1260 __ CallStub(&stub); |
1624 __ bind(&stack_is_ok); | 1261 __ bind(&stack_is_ok); |
1625 } | 1262 } |
1626 } | 1263 } |
1627 | 1264 |
1628 | 1265 |
1629 void Ia32CodeGenerator::VisitBlock(Block* node) { | 1266 void CodeGenerator::VisitBlock(Block* node) { |
1630 Comment cmnt(masm_, "[ Block"); | 1267 Comment cmnt(masm_, "[ Block"); |
1631 RecordStatementPosition(node); | 1268 RecordStatementPosition(node); |
1632 node->set_break_stack_height(break_stack_height_); | 1269 node->set_break_stack_height(break_stack_height_); |
1633 VisitStatements(node->statements()); | 1270 VisitStatements(node->statements()); |
1634 __ bind(node->break_target()); | 1271 __ bind(node->break_target()); |
1635 } | 1272 } |
1636 | 1273 |
1637 | 1274 |
1638 void Ia32CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { | 1275 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { |
1639 __ push(Immediate(pairs)); | 1276 __ push(Immediate(pairs)); |
1640 __ push(Operand(esi)); | 1277 __ push(Operand(esi)); |
1641 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); | 1278 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); |
1642 __ CallRuntime(Runtime::kDeclareGlobals, 3); | 1279 __ CallRuntime(Runtime::kDeclareGlobals, 3); |
1643 // Return value is ignored. | 1280 // Return value is ignored. |
1644 } | 1281 } |
1645 | 1282 |
1646 | 1283 |
1647 void Ia32CodeGenerator::VisitDeclaration(Declaration* node) { | 1284 void CodeGenerator::VisitDeclaration(Declaration* node) { |
1648 Comment cmnt(masm_, "[ Declaration"); | 1285 Comment cmnt(masm_, "[ Declaration"); |
1649 Variable* var = node->proxy()->var(); | 1286 Variable* var = node->proxy()->var(); |
1650 ASSERT(var != NULL); // must have been resolved | 1287 ASSERT(var != NULL); // must have been resolved |
1651 Slot* slot = var->slot(); | 1288 Slot* slot = var->slot(); |
1652 | 1289 |
1653 // If it was not possible to allocate the variable at compile time, | 1290 // If it was not possible to allocate the variable at compile time, |
1654 // we need to "declare" it at runtime to make sure it actually | 1291 // we need to "declare" it at runtime to make sure it actually |
1655 // exists in the local context. | 1292 // exists in the local context. |
1656 if (slot != NULL && slot->type() == Slot::LOOKUP) { | 1293 if (slot != NULL && slot->type() == Slot::LOOKUP) { |
1657 // Variables with a "LOOKUP" slot were introduced as non-locals | 1294 // Variables with a "LOOKUP" slot were introduced as non-locals |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1698 target.SetValue(NOT_CONST_INIT); | 1335 target.SetValue(NOT_CONST_INIT); |
1699 // Get rid of the assigned value (declarations are statements). It's | 1336 // Get rid of the assigned value (declarations are statements). It's |
1700 // safe to pop the value lying on top of the reference before unloading | 1337 // safe to pop the value lying on top of the reference before unloading |
1701 // the reference itself (which preserves the top of stack) because we | 1338 // the reference itself (which preserves the top of stack) because we |
1702 // know that it is a zero-sized reference. | 1339 // know that it is a zero-sized reference. |
1703 __ pop(eax); // Pop(no_reg); | 1340 __ pop(eax); // Pop(no_reg); |
1704 } | 1341 } |
1705 } | 1342 } |
1706 | 1343 |
1707 | 1344 |
1708 void Ia32CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { | 1345 void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) { |
1709 Comment cmnt(masm_, "[ ExpressionStatement"); | 1346 Comment cmnt(masm_, "[ ExpressionStatement"); |
1710 RecordStatementPosition(node); | 1347 RecordStatementPosition(node); |
1711 Expression* expression = node->expression(); | 1348 Expression* expression = node->expression(); |
1712 expression->MarkAsStatement(); | 1349 expression->MarkAsStatement(); |
1713 Load(expression); | 1350 Load(expression); |
1714 __ pop(eax); // remove the lingering expression result from the top of stack | 1351 __ pop(eax); // remove the lingering expression result from the top of stack |
1715 } | 1352 } |
1716 | 1353 |
1717 | 1354 |
1718 void Ia32CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { | 1355 void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) { |
1719 Comment cmnt(masm_, "// EmptyStatement"); | 1356 Comment cmnt(masm_, "// EmptyStatement"); |
1720 // nothing to do | 1357 // nothing to do |
1721 } | 1358 } |
1722 | 1359 |
1723 | 1360 |
1724 void Ia32CodeGenerator::VisitIfStatement(IfStatement* node) { | 1361 void CodeGenerator::VisitIfStatement(IfStatement* node) { |
1725 Comment cmnt(masm_, "[ IfStatement"); | 1362 Comment cmnt(masm_, "[ IfStatement"); |
1726 // Generate different code depending on which | 1363 // Generate different code depending on which |
1727 // parts of the if statement are present or not. | 1364 // parts of the if statement are present or not. |
1728 bool has_then_stm = node->HasThenStatement(); | 1365 bool has_then_stm = node->HasThenStatement(); |
1729 bool has_else_stm = node->HasElseStatement(); | 1366 bool has_else_stm = node->HasElseStatement(); |
1730 | 1367 |
1731 RecordStatementPosition(node); | 1368 RecordStatementPosition(node); |
1732 Label exit; | 1369 Label exit; |
1733 if (has_then_stm && has_else_stm) { | 1370 if (has_then_stm && has_else_stm) { |
1734 Label then; | 1371 Label then; |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1775 // Pop it again, since it is not going to be used. | 1412 // Pop it again, since it is not going to be used. |
1776 __ pop(eax); | 1413 __ pop(eax); |
1777 } | 1414 } |
1778 } | 1415 } |
1779 | 1416 |
1780 // end | 1417 // end |
1781 __ bind(&exit); | 1418 __ bind(&exit); |
1782 } | 1419 } |
1783 | 1420 |
1784 | 1421 |
1785 void Ia32CodeGenerator::CleanStack(int num_bytes) { | 1422 void CodeGenerator::CleanStack(int num_bytes) { |
1786 ASSERT(num_bytes >= 0); | 1423 ASSERT(num_bytes >= 0); |
1787 if (num_bytes > 0) { | 1424 if (num_bytes > 0) { |
1788 __ add(Operand(esp), Immediate(num_bytes)); | 1425 __ add(Operand(esp), Immediate(num_bytes)); |
1789 } | 1426 } |
1790 } | 1427 } |
1791 | 1428 |
1792 | 1429 |
1793 void Ia32CodeGenerator::VisitContinueStatement(ContinueStatement* node) { | 1430 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { |
1794 Comment cmnt(masm_, "[ ContinueStatement"); | 1431 Comment cmnt(masm_, "[ ContinueStatement"); |
1795 RecordStatementPosition(node); | 1432 RecordStatementPosition(node); |
1796 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1433 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
1797 __ jmp(node->target()->continue_target()); | 1434 __ jmp(node->target()->continue_target()); |
1798 } | 1435 } |
1799 | 1436 |
1800 | 1437 |
1801 void Ia32CodeGenerator::VisitBreakStatement(BreakStatement* node) { | 1438 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { |
1802 Comment cmnt(masm_, "[ BreakStatement"); | 1439 Comment cmnt(masm_, "[ BreakStatement"); |
1803 RecordStatementPosition(node); | 1440 RecordStatementPosition(node); |
1804 CleanStack(break_stack_height_ - node->target()->break_stack_height()); | 1441 CleanStack(break_stack_height_ - node->target()->break_stack_height()); |
1805 __ jmp(node->target()->break_target()); | 1442 __ jmp(node->target()->break_target()); |
1806 } | 1443 } |
1807 | 1444 |
1808 | 1445 |
1809 void Ia32CodeGenerator::VisitReturnStatement(ReturnStatement* node) { | 1446 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { |
1810 Comment cmnt(masm_, "[ ReturnStatement"); | 1447 Comment cmnt(masm_, "[ ReturnStatement"); |
1811 RecordStatementPosition(node); | 1448 RecordStatementPosition(node); |
1812 Load(node->expression()); | 1449 Load(node->expression()); |
1813 | 1450 |
1814 // Move the function result into eax | 1451 // Move the function result into eax |
1815 __ pop(eax); | 1452 __ pop(eax); |
1816 | 1453 |
1817 // If we're inside a try statement or the return instruction | 1454 // If we're inside a try statement or the return instruction |
1818 // sequence has been generated, we just jump to that | 1455 // sequence has been generated, we just jump to that |
1819 // point. Otherwise, we generate the return instruction sequence and | 1456 // point. Otherwise, we generate the return instruction sequence and |
(...skipping 17 matching lines...) Expand all Loading... |
1837 __ ret((scope_->num_parameters() + 1) * kPointerSize); | 1474 __ ret((scope_->num_parameters() + 1) * kPointerSize); |
1838 | 1475 |
1839 // Check that the size of the code used for returning matches what is | 1476 // Check that the size of the code used for returning matches what is |
1840 // expected by the debugger. | 1477 // expected by the debugger. |
1841 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, | 1478 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, |
1842 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); | 1479 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); |
1843 } | 1480 } |
1844 } | 1481 } |
1845 | 1482 |
1846 | 1483 |
1847 void Ia32CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { | 1484 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { |
1848 Comment cmnt(masm_, "[ WithEnterStatement"); | 1485 Comment cmnt(masm_, "[ WithEnterStatement"); |
1849 RecordStatementPosition(node); | 1486 RecordStatementPosition(node); |
1850 Load(node->expression()); | 1487 Load(node->expression()); |
1851 __ CallRuntime(Runtime::kPushContext, 1); | 1488 __ CallRuntime(Runtime::kPushContext, 1); |
1852 | 1489 |
1853 if (kDebug) { | 1490 if (kDebug) { |
1854 Label verified_true; | 1491 Label verified_true; |
1855 // Verify eax and esi are the same in debug mode | 1492 // Verify eax and esi are the same in debug mode |
1856 __ cmp(eax, Operand(esi)); | 1493 __ cmp(eax, Operand(esi)); |
1857 __ j(equal, &verified_true); | 1494 __ j(equal, &verified_true); |
1858 __ int3(); | 1495 __ int3(); |
1859 __ bind(&verified_true); | 1496 __ bind(&verified_true); |
1860 } | 1497 } |
1861 | 1498 |
1862 // Update context local. | 1499 // Update context local. |
1863 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 1500 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
1864 } | 1501 } |
1865 | 1502 |
1866 | 1503 |
1867 void Ia32CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { | 1504 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { |
1868 Comment cmnt(masm_, "[ WithExitStatement"); | 1505 Comment cmnt(masm_, "[ WithExitStatement"); |
1869 // Pop context. | 1506 // Pop context. |
1870 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); | 1507 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); |
1871 // Update context local. | 1508 // Update context local. |
1872 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); | 1509 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi); |
1873 } | 1510 } |
1874 | 1511 |
1875 int Ia32CodeGenerator::FastCaseSwitchMaxOverheadFactor() { | 1512 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { |
1876 return kFastSwitchMaxOverheadFactor; | 1513 return kFastSwitchMaxOverheadFactor; |
1877 } | 1514 } |
1878 | 1515 |
1879 int Ia32CodeGenerator::FastCaseSwitchMinCaseCount() { | 1516 int CodeGenerator::FastCaseSwitchMinCaseCount() { |
1880 return kFastSwitchMinCaseCount; | 1517 return kFastSwitchMinCaseCount; |
1881 } | 1518 } |
1882 | 1519 |
1883 // Generate a computed jump to a switch case. | 1520 // Generate a computed jump to a switch case. |
1884 void Ia32CodeGenerator::GenerateFastCaseSwitchJumpTable( | 1521 void CodeGenerator::GenerateFastCaseSwitchJumpTable( |
1885 SwitchStatement* node, int min_index, int range, Label *fail_label, | 1522 SwitchStatement* node, int min_index, int range, Label *fail_label, |
1886 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) { | 1523 SmartPointer<Label*> &case_targets, SmartPointer<Label> &case_labels) { |
1887 // Notice: Internal references, used by both the jmp instruction and | 1524 // Notice: Internal references, used by both the jmp instruction and |
1888 // the table entries, need to be relocated if the buffer grows. This | 1525 // the table entries, need to be relocated if the buffer grows. This |
1889 // prevents the forward use of Labels, since a displacement cannot | 1526 // prevents the forward use of Labels, since a displacement cannot |
1890 // survive relocation, and it also cannot safely be distinguished | 1527 // survive relocation, and it also cannot safely be distinguished |
1891 // from a real address. Instead we put in zero-values as | 1528 // from a real address. Instead we put in zero-values as |
1892 // placeholders, and fill in the addresses after the labels have been | 1529 // placeholders, and fill in the addresses after the labels have been |
1893 // bound. | 1530 // bound. |
1894 | 1531 |
(...skipping 25 matching lines...) Expand all Loading... |
1920 | 1557 |
1921 GenerateFastCaseSwitchCases(node, case_labels); | 1558 GenerateFastCaseSwitchCases(node, case_labels); |
1922 | 1559 |
1923 for (int i = 0, entry_pos = table_start.pos(); | 1560 for (int i = 0, entry_pos = table_start.pos(); |
1924 i < range; i++, entry_pos += sizeof(uint32_t)) { | 1561 i < range; i++, entry_pos += sizeof(uint32_t)) { |
1925 __ WriteInternalReference(entry_pos, *case_targets[i]); | 1562 __ WriteInternalReference(entry_pos, *case_targets[i]); |
1926 } | 1563 } |
1927 } | 1564 } |
1928 | 1565 |
1929 | 1566 |
1930 void Ia32CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { | 1567 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { |
1931 Comment cmnt(masm_, "[ SwitchStatement"); | 1568 Comment cmnt(masm_, "[ SwitchStatement"); |
1932 RecordStatementPosition(node); | 1569 RecordStatementPosition(node); |
1933 node->set_break_stack_height(break_stack_height_); | 1570 node->set_break_stack_height(break_stack_height_); |
1934 | 1571 |
1935 Load(node->tag()); | 1572 Load(node->tag()); |
1936 | 1573 |
1937 if (TryGenerateFastCaseSwitchStatement(node)) { | 1574 if (TryGenerateFastCaseSwitchStatement(node)) { |
1938 return; | 1575 return; |
1939 } | 1576 } |
1940 | 1577 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1987 } else { | 1624 } else { |
1988 // Remove the switch value from the stack. | 1625 // Remove the switch value from the stack. |
1989 __ pop(eax); | 1626 __ pop(eax); |
1990 } | 1627 } |
1991 | 1628 |
1992 __ bind(&fall_through); | 1629 __ bind(&fall_through); |
1993 __ bind(node->break_target()); | 1630 __ bind(node->break_target()); |
1994 } | 1631 } |
1995 | 1632 |
1996 | 1633 |
1997 void Ia32CodeGenerator::VisitLoopStatement(LoopStatement* node) { | 1634 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { |
1998 Comment cmnt(masm_, "[ LoopStatement"); | 1635 Comment cmnt(masm_, "[ LoopStatement"); |
1999 RecordStatementPosition(node); | 1636 RecordStatementPosition(node); |
2000 node->set_break_stack_height(break_stack_height_); | 1637 node->set_break_stack_height(break_stack_height_); |
2001 | 1638 |
2002 // simple condition analysis | 1639 // simple condition analysis |
2003 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; | 1640 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; |
2004 if (node->cond() == NULL) { | 1641 if (node->cond() == NULL) { |
2005 ASSERT(node->type() == LoopStatement::FOR_LOOP); | 1642 ASSERT(node->type() == LoopStatement::FOR_LOOP); |
2006 info = ALWAYS_TRUE; | 1643 info = ALWAYS_TRUE; |
2007 } else { | 1644 } else { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2056 node->break_target(), true); | 1693 node->break_target(), true); |
2057 Branch(true, &loop); | 1694 Branch(true, &loop); |
2058 break; | 1695 break; |
2059 } | 1696 } |
2060 | 1697 |
2061 // exit | 1698 // exit |
2062 __ bind(node->break_target()); | 1699 __ bind(node->break_target()); |
2063 } | 1700 } |
2064 | 1701 |
2065 | 1702 |
2066 void Ia32CodeGenerator::VisitForInStatement(ForInStatement* node) { | 1703 void CodeGenerator::VisitForInStatement(ForInStatement* node) { |
2067 Comment cmnt(masm_, "[ ForInStatement"); | 1704 Comment cmnt(masm_, "[ ForInStatement"); |
2068 RecordStatementPosition(node); | 1705 RecordStatementPosition(node); |
2069 | 1706 |
2070 // We keep stuff on the stack while the body is executing. | 1707 // We keep stuff on the stack while the body is executing. |
2071 // Record it, so that a break/continue crossing this statement | 1708 // Record it, so that a break/continue crossing this statement |
2072 // can restore the stack. | 1709 // can restore the stack. |
2073 const int kForInStackSize = 5 * kPointerSize; | 1710 const int kForInStackSize = 5 * kPointerSize; |
2074 break_stack_height_ += kForInStackSize; | 1711 break_stack_height_ += kForInStackSize; |
2075 node->set_break_stack_height(break_stack_height_); | 1712 node->set_break_stack_height(break_stack_height_); |
2076 | 1713 |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2244 __ bind(node->break_target()); | 1881 __ bind(node->break_target()); |
2245 __ add(Operand(esp), Immediate(5 * kPointerSize)); | 1882 __ add(Operand(esp), Immediate(5 * kPointerSize)); |
2246 | 1883 |
2247 // Exit. | 1884 // Exit. |
2248 __ bind(&exit); | 1885 __ bind(&exit); |
2249 | 1886 |
2250 break_stack_height_ -= kForInStackSize; | 1887 break_stack_height_ -= kForInStackSize; |
2251 } | 1888 } |
2252 | 1889 |
2253 | 1890 |
2254 void Ia32CodeGenerator::VisitTryCatch(TryCatch* node) { | 1891 void CodeGenerator::VisitTryCatch(TryCatch* node) { |
2255 Comment cmnt(masm_, "[ TryCatch"); | 1892 Comment cmnt(masm_, "[ TryCatch"); |
2256 | 1893 |
2257 Label try_block, exit; | 1894 Label try_block, exit; |
2258 | 1895 |
2259 __ call(&try_block); | 1896 __ call(&try_block); |
2260 // --- Catch block --- | 1897 // --- Catch block --- |
2261 __ push(eax); | 1898 __ push(eax); |
2262 | 1899 |
2263 // Store the caught exception in the catch variable. | 1900 // Store the caught exception in the catch variable. |
2264 { Reference ref(this, node->catch_var()); | 1901 { Reference ref(this, node->catch_var()); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2343 Immediate(StackHandlerConstants::kSize - kPointerSize)); | 1980 Immediate(StackHandlerConstants::kSize - kPointerSize)); |
2344 // next_sp popped. | 1981 // next_sp popped. |
2345 __ jmp(shadows[i]->shadowed()); | 1982 __ jmp(shadows[i]->shadowed()); |
2346 } | 1983 } |
2347 } | 1984 } |
2348 | 1985 |
2349 __ bind(&exit); | 1986 __ bind(&exit); |
2350 } | 1987 } |
2351 | 1988 |
2352 | 1989 |
2353 void Ia32CodeGenerator::VisitTryFinally(TryFinally* node) { | 1990 void CodeGenerator::VisitTryFinally(TryFinally* node) { |
2354 Comment cmnt(masm_, "[ TryFinally"); | 1991 Comment cmnt(masm_, "[ TryFinally"); |
2355 | 1992 |
2356 // State: Used to keep track of reason for entering the finally | 1993 // State: Used to keep track of reason for entering the finally |
2357 // block. Should probably be extended to hold information for | 1994 // block. Should probably be extended to hold information for |
2358 // break/continue from within the try block. | 1995 // break/continue from within the try block. |
2359 enum { FALLING, THROWING, JUMPING }; | 1996 enum { FALLING, THROWING, JUMPING }; |
2360 | 1997 |
2361 Label exit, unlink, try_block, finally_block; | 1998 Label exit, unlink, try_block, finally_block; |
2362 | 1999 |
2363 __ call(&try_block); | 2000 __ call(&try_block); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2472 | 2109 |
2473 // Rethrow exception. | 2110 // Rethrow exception. |
2474 __ push(eax); // undo pop from above | 2111 __ push(eax); // undo pop from above |
2475 __ CallRuntime(Runtime::kReThrow, 1); | 2112 __ CallRuntime(Runtime::kReThrow, 1); |
2476 | 2113 |
2477 // Done. | 2114 // Done. |
2478 __ bind(&exit); | 2115 __ bind(&exit); |
2479 } | 2116 } |
2480 | 2117 |
2481 | 2118 |
2482 void Ia32CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { | 2119 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { |
2483 Comment cmnt(masm_, "[ DebuggerStatement"); | 2120 Comment cmnt(masm_, "[ DebuggerStatement"); |
2484 RecordStatementPosition(node); | 2121 RecordStatementPosition(node); |
2485 __ CallRuntime(Runtime::kDebugBreak, 1); | 2122 __ CallRuntime(Runtime::kDebugBreak, 1); |
2486 __ push(eax); | 2123 __ push(eax); |
2487 } | 2124 } |
2488 | 2125 |
2489 | 2126 |
2490 void Ia32CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { | 2127 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { |
2491 ASSERT(boilerplate->IsBoilerplate()); | 2128 ASSERT(boilerplate->IsBoilerplate()); |
2492 | 2129 |
2493 // Push the boilerplate on the stack. | 2130 // Push the boilerplate on the stack. |
2494 __ push(Immediate(boilerplate)); | 2131 __ push(Immediate(boilerplate)); |
2495 | 2132 |
2496 // Create a new closure. | 2133 // Create a new closure. |
2497 __ push(esi); | 2134 __ push(esi); |
2498 __ CallRuntime(Runtime::kNewClosure, 2); | 2135 __ CallRuntime(Runtime::kNewClosure, 2); |
2499 __ push(eax); | 2136 __ push(eax); |
2500 } | 2137 } |
2501 | 2138 |
2502 | 2139 |
2503 void Ia32CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { | 2140 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { |
2504 Comment cmnt(masm_, "[ FunctionLiteral"); | 2141 Comment cmnt(masm_, "[ FunctionLiteral"); |
2505 | 2142 |
2506 // Build the function boilerplate and instantiate it. | 2143 // Build the function boilerplate and instantiate it. |
2507 Handle<JSFunction> boilerplate = BuildBoilerplate(node); | 2144 Handle<JSFunction> boilerplate = BuildBoilerplate(node); |
2508 // Check for stack-overflow exception. | 2145 // Check for stack-overflow exception. |
2509 if (HasStackOverflow()) return; | 2146 if (HasStackOverflow()) return; |
2510 InstantiateBoilerplate(boilerplate); | 2147 InstantiateBoilerplate(boilerplate); |
2511 } | 2148 } |
2512 | 2149 |
2513 | 2150 |
2514 void Ia32CodeGenerator::VisitFunctionBoilerplateLiteral( | 2151 void CodeGenerator::VisitFunctionBoilerplateLiteral( |
2515 FunctionBoilerplateLiteral* node) { | 2152 FunctionBoilerplateLiteral* node) { |
2516 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); | 2153 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); |
2517 InstantiateBoilerplate(node->boilerplate()); | 2154 InstantiateBoilerplate(node->boilerplate()); |
2518 } | 2155 } |
2519 | 2156 |
2520 | 2157 |
2521 void Ia32CodeGenerator::VisitConditional(Conditional* node) { | 2158 void CodeGenerator::VisitConditional(Conditional* node) { |
2522 Comment cmnt(masm_, "[ Conditional"); | 2159 Comment cmnt(masm_, "[ Conditional"); |
2523 Label then, else_, exit; | 2160 Label then, else_, exit; |
2524 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); | 2161 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); |
2525 Branch(false, &else_); | 2162 Branch(false, &else_); |
2526 __ bind(&then); | 2163 __ bind(&then); |
2527 Load(node->then_expression(), typeof_state()); | 2164 Load(node->then_expression(), typeof_state()); |
2528 __ jmp(&exit); | 2165 __ jmp(&exit); |
2529 __ bind(&else_); | 2166 __ bind(&else_); |
2530 Load(node->else_expression(), typeof_state()); | 2167 Load(node->else_expression(), typeof_state()); |
2531 __ bind(&exit); | 2168 __ bind(&exit); |
2532 } | 2169 } |
2533 | 2170 |
2534 | 2171 |
2535 void Ia32CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { | 2172 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { |
2536 if (slot->type() == Slot::LOOKUP) { | 2173 if (slot->type() == Slot::LOOKUP) { |
2537 ASSERT(slot->var()->mode() == Variable::DYNAMIC); | 2174 ASSERT(slot->var()->mode() == Variable::DYNAMIC); |
2538 | 2175 |
2539 // For now, just do a runtime call. | 2176 // For now, just do a runtime call. |
2540 __ push(esi); | 2177 __ push(esi); |
2541 __ push(Immediate(slot->var()->name())); | 2178 __ push(Immediate(slot->var()->name())); |
2542 | 2179 |
2543 if (typeof_state == INSIDE_TYPEOF) { | 2180 if (typeof_state == INSIDE_TYPEOF) { |
2544 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); | 2181 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); |
2545 } else { | 2182 } else { |
(...skipping 17 matching lines...) Expand all Loading... |
2563 __ mov(eax, Factory::undefined_value()); | 2200 __ mov(eax, Factory::undefined_value()); |
2564 __ bind(&exit); | 2201 __ bind(&exit); |
2565 __ push(eax); | 2202 __ push(eax); |
2566 } else { | 2203 } else { |
2567 __ push(SlotOperand(slot, ecx)); | 2204 __ push(SlotOperand(slot, ecx)); |
2568 } | 2205 } |
2569 } | 2206 } |
2570 } | 2207 } |
2571 | 2208 |
2572 | 2209 |
2573 void Ia32CodeGenerator::VisitSlot(Slot* node) { | 2210 void CodeGenerator::VisitSlot(Slot* node) { |
2574 Comment cmnt(masm_, "[ Slot"); | 2211 Comment cmnt(masm_, "[ Slot"); |
2575 LoadFromSlot(node, typeof_state()); | 2212 LoadFromSlot(node, typeof_state()); |
2576 } | 2213 } |
2577 | 2214 |
2578 | 2215 |
2579 void Ia32CodeGenerator::VisitVariableProxy(VariableProxy* node) { | 2216 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { |
2580 Comment cmnt(masm_, "[ VariableProxy"); | 2217 Comment cmnt(masm_, "[ VariableProxy"); |
2581 Variable* var = node->var(); | 2218 Variable* var = node->var(); |
2582 Expression* expr = var->rewrite(); | 2219 Expression* expr = var->rewrite(); |
2583 if (expr != NULL) { | 2220 if (expr != NULL) { |
2584 Visit(expr); | 2221 Visit(expr); |
2585 } else { | 2222 } else { |
2586 ASSERT(var->is_global()); | 2223 ASSERT(var->is_global()); |
2587 Reference ref(this, node); | 2224 Reference ref(this, node); |
2588 ref.GetValue(typeof_state()); | 2225 ref.GetValue(typeof_state()); |
2589 } | 2226 } |
2590 } | 2227 } |
2591 | 2228 |
2592 | 2229 |
2593 void Ia32CodeGenerator::VisitLiteral(Literal* node) { | 2230 void CodeGenerator::VisitLiteral(Literal* node) { |
2594 Comment cmnt(masm_, "[ Literal"); | 2231 Comment cmnt(masm_, "[ Literal"); |
2595 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { | 2232 if (node->handle()->IsSmi() && !IsInlineSmi(node)) { |
2596 // To prevent long attacker-controlled byte sequences in code, larger | 2233 // To prevent long attacker-controlled byte sequences in code, larger |
2597 // Smis are loaded in two steps. | 2234 // Smis are loaded in two steps. |
2598 int bits = reinterpret_cast<int>(*node->handle()); | 2235 int bits = reinterpret_cast<int>(*node->handle()); |
2599 __ mov(eax, bits & 0x0000FFFF); | 2236 __ mov(eax, bits & 0x0000FFFF); |
2600 __ xor_(eax, bits & 0xFFFF0000); | 2237 __ xor_(eax, bits & 0xFFFF0000); |
2601 __ push(eax); | 2238 __ push(eax); |
2602 } else { | 2239 } else { |
2603 __ push(Immediate(node->handle())); | 2240 __ push(Immediate(node->handle())); |
(...skipping 23 matching lines...) Expand all Loading... |
2627 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2264 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
2628 // RegExp pattern (2). | 2265 // RegExp pattern (2). |
2629 __ push(Immediate(node_->pattern())); | 2266 __ push(Immediate(node_->pattern())); |
2630 // RegExp flags (3). | 2267 // RegExp flags (3). |
2631 __ push(Immediate(node_->flags())); | 2268 __ push(Immediate(node_->flags())); |
2632 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); | 2269 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); |
2633 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx | 2270 __ mov(ebx, Operand(eax)); // "caller" expects result in ebx |
2634 } | 2271 } |
2635 | 2272 |
2636 | 2273 |
2637 void Ia32CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { | 2274 void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) { |
2638 Comment cmnt(masm_, "[ RegExp Literal"); | 2275 Comment cmnt(masm_, "[ RegExp Literal"); |
2639 RegExpDeferred* deferred = new RegExpDeferred(this, node); | 2276 RegExpDeferred* deferred = new RegExpDeferred(this, node); |
2640 | 2277 |
2641 // Retrieve the literal array and check the allocated entry. | 2278 // Retrieve the literal array and check the allocated entry. |
2642 | 2279 |
2643 // Load the function of this activation. | 2280 // Load the function of this activation. |
2644 __ mov(ecx, FunctionOperand()); | 2281 __ mov(ecx, FunctionOperand()); |
2645 | 2282 |
2646 // Load the literals array of the function. | 2283 // Load the literals array of the function. |
2647 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2284 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2687 __ push(Operand(ecx)); | 2324 __ push(Operand(ecx)); |
2688 // Literal index (1). | 2325 // Literal index (1). |
2689 __ push(Immediate(Smi::FromInt(node_->literal_index()))); | 2326 __ push(Immediate(Smi::FromInt(node_->literal_index()))); |
2690 // Constant properties (2). | 2327 // Constant properties (2). |
2691 __ push(Immediate(node_->constant_properties())); | 2328 __ push(Immediate(node_->constant_properties())); |
2692 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); | 2329 __ CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3); |
2693 __ mov(ebx, Operand(eax)); | 2330 __ mov(ebx, Operand(eax)); |
2694 } | 2331 } |
2695 | 2332 |
2696 | 2333 |
2697 void Ia32CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { | 2334 void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) { |
2698 Comment cmnt(masm_, "[ ObjectLiteral"); | 2335 Comment cmnt(masm_, "[ ObjectLiteral"); |
2699 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); | 2336 ObjectLiteralDeferred* deferred = new ObjectLiteralDeferred(this, node); |
2700 | 2337 |
2701 // Retrieve the literal array and check the allocated entry. | 2338 // Retrieve the literal array and check the allocated entry. |
2702 | 2339 |
2703 // Load the function of this activation. | 2340 // Load the function of this activation. |
2704 __ mov(ecx, FunctionOperand()); | 2341 __ mov(ecx, FunctionOperand()); |
2705 | 2342 |
2706 // Load the literals array of the function. | 2343 // Load the literals array of the function. |
2707 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2344 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2777 __ CallRuntime(Runtime::kDefineAccessor, 4); | 2414 __ CallRuntime(Runtime::kDefineAccessor, 4); |
2778 // Ignore result. | 2415 // Ignore result. |
2779 break; | 2416 break; |
2780 } | 2417 } |
2781 default: UNREACHABLE(); | 2418 default: UNREACHABLE(); |
2782 } | 2419 } |
2783 } | 2420 } |
2784 } | 2421 } |
2785 | 2422 |
2786 | 2423 |
2787 void Ia32CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { | 2424 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { |
2788 Comment cmnt(masm_, "[ ArrayLiteral"); | 2425 Comment cmnt(masm_, "[ ArrayLiteral"); |
2789 | 2426 |
2790 // Call runtime to create the array literal. | 2427 // Call runtime to create the array literal. |
2791 __ push(Immediate(node->literals())); | 2428 __ push(Immediate(node->literals())); |
2792 // Load the function of this frame. | 2429 // Load the function of this frame. |
2793 __ mov(ecx, FunctionOperand()); | 2430 __ mov(ecx, FunctionOperand()); |
2794 // Load the literals array of the function. | 2431 // Load the literals array of the function. |
2795 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); | 2432 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); |
2796 __ push(ecx); | 2433 __ push(ecx); |
2797 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); | 2434 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); |
(...skipping 23 matching lines...) Expand all Loading... |
2821 int offset = i * kPointerSize + Array::kHeaderSize; | 2458 int offset = i * kPointerSize + Array::kHeaderSize; |
2822 __ mov(FieldOperand(ecx, offset), eax); | 2459 __ mov(FieldOperand(ecx, offset), eax); |
2823 | 2460 |
2824 // Update the write barrier for the array address. | 2461 // Update the write barrier for the array address. |
2825 __ RecordWrite(ecx, offset, eax, ebx); | 2462 __ RecordWrite(ecx, offset, eax, ebx); |
2826 } | 2463 } |
2827 } | 2464 } |
2828 } | 2465 } |
2829 | 2466 |
2830 | 2467 |
2831 bool Ia32CodeGenerator::IsInlineSmi(Literal* literal) { | 2468 bool CodeGenerator::IsInlineSmi(Literal* literal) { |
2832 if (literal == NULL || !literal->handle()->IsSmi()) return false; | 2469 if (literal == NULL || !literal->handle()->IsSmi()) return false; |
2833 int int_value = Smi::cast(*literal->handle())->value(); | 2470 int int_value = Smi::cast(*literal->handle())->value(); |
2834 return is_intn(int_value, kMaxSmiInlinedBits); | 2471 return is_intn(int_value, kMaxSmiInlinedBits); |
2835 } | 2472 } |
2836 | 2473 |
2837 | 2474 |
2838 void Ia32CodeGenerator::VisitAssignment(Assignment* node) { | 2475 void CodeGenerator::VisitAssignment(Assignment* node) { |
2839 Comment cmnt(masm_, "[ Assignment"); | 2476 Comment cmnt(masm_, "[ Assignment"); |
2840 | 2477 |
2841 RecordStatementPosition(node); | 2478 RecordStatementPosition(node); |
2842 Reference target(this, node->target()); | 2479 Reference target(this, node->target()); |
2843 if (target.is_illegal()) return; | 2480 if (target.is_illegal()) return; |
2844 | 2481 |
2845 if (node->op() == Token::ASSIGN || | 2482 if (node->op() == Token::ASSIGN || |
2846 node->op() == Token::INIT_VAR || | 2483 node->op() == Token::INIT_VAR || |
2847 node->op() == Token::INIT_CONST) { | 2484 node->op() == Token::INIT_CONST) { |
2848 Load(node->value()); | 2485 Load(node->value()); |
(...skipping 21 matching lines...) Expand all Loading... |
2870 // and initialize the actual constant declared. Dynamic variable | 2507 // and initialize the actual constant declared. Dynamic variable |
2871 // initializations are simply assignments and use SetValue. | 2508 // initializations are simply assignments and use SetValue. |
2872 target.SetValue(CONST_INIT); | 2509 target.SetValue(CONST_INIT); |
2873 } else { | 2510 } else { |
2874 target.SetValue(NOT_CONST_INIT); | 2511 target.SetValue(NOT_CONST_INIT); |
2875 } | 2512 } |
2876 } | 2513 } |
2877 } | 2514 } |
2878 | 2515 |
2879 | 2516 |
2880 void Ia32CodeGenerator::VisitThrow(Throw* node) { | 2517 void CodeGenerator::VisitThrow(Throw* node) { |
2881 Comment cmnt(masm_, "[ Throw"); | 2518 Comment cmnt(masm_, "[ Throw"); |
2882 | 2519 |
2883 Load(node->exception()); | 2520 Load(node->exception()); |
2884 __ RecordPosition(node->position()); | 2521 __ RecordPosition(node->position()); |
2885 __ CallRuntime(Runtime::kThrow, 1); | 2522 __ CallRuntime(Runtime::kThrow, 1); |
2886 __ push(eax); | 2523 __ push(eax); |
2887 } | 2524 } |
2888 | 2525 |
2889 | 2526 |
2890 void Ia32CodeGenerator::VisitProperty(Property* node) { | 2527 void CodeGenerator::VisitProperty(Property* node) { |
2891 Comment cmnt(masm_, "[ Property"); | 2528 Comment cmnt(masm_, "[ Property"); |
| 2529 |
2892 Reference property(this, node); | 2530 Reference property(this, node); |
2893 property.GetValue(typeof_state()); | 2531 property.GetValue(typeof_state()); |
2894 } | 2532 } |
2895 | 2533 |
2896 | 2534 |
2897 void Ia32CodeGenerator::VisitCall(Call* node) { | 2535 void CodeGenerator::VisitCall(Call* node) { |
2898 Comment cmnt(masm_, "[ Call"); | 2536 Comment cmnt(masm_, "[ Call"); |
2899 | 2537 |
2900 ZoneList<Expression*>* args = node->arguments(); | 2538 ZoneList<Expression*>* args = node->arguments(); |
2901 | 2539 |
2902 RecordStatementPosition(node); | 2540 RecordStatementPosition(node); |
2903 | 2541 |
2904 // Check if the function is a variable or a property. | 2542 // Check if the function is a variable or a property. |
2905 Expression* function = node->expression(); | 2543 Expression* function = node->expression(); |
2906 Variable* var = function->AsVariableProxy()->AsVariable(); | 2544 Variable* var = function->AsVariableProxy()->AsVariable(); |
2907 Property* property = function->AsProperty(); | 2545 Property* property = function->AsProperty(); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3009 | 2647 |
3010 // Pass the global object as the receiver. | 2648 // Pass the global object as the receiver. |
3011 LoadGlobal(); | 2649 LoadGlobal(); |
3012 | 2650 |
3013 // Call the function. | 2651 // Call the function. |
3014 CallWithArguments(args, node->position()); | 2652 CallWithArguments(args, node->position()); |
3015 } | 2653 } |
3016 } | 2654 } |
3017 | 2655 |
3018 | 2656 |
3019 void Ia32CodeGenerator::VisitCallNew(CallNew* node) { | 2657 void CodeGenerator::VisitCallNew(CallNew* node) { |
3020 Comment cmnt(masm_, "[ CallNew"); | 2658 Comment cmnt(masm_, "[ CallNew"); |
3021 | 2659 |
3022 // According to ECMA-262, section 11.2.2, page 44, the function | 2660 // According to ECMA-262, section 11.2.2, page 44, the function |
3023 // expression in new calls must be evaluated before the | 2661 // expression in new calls must be evaluated before the |
3024 // arguments. This is different from ordinary calls, where the | 2662 // arguments. This is different from ordinary calls, where the |
3025 // actual function to call is resolved after the arguments have been | 2663 // actual function to call is resolved after the arguments have been |
3026 // evaluated. | 2664 // evaluated. |
3027 | 2665 |
3028 // Compute function to call and use the global object as the | 2666 // Compute function to call and use the global object as the |
3029 // receiver. | 2667 // receiver. |
(...skipping 15 matching lines...) Expand all Loading... |
3045 | 2683 |
3046 // Call the construct call builtin that handles allocation and | 2684 // Call the construct call builtin that handles allocation and |
3047 // constructor invocation. | 2685 // constructor invocation. |
3048 __ RecordPosition(node->position()); | 2686 __ RecordPosition(node->position()); |
3049 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), | 2687 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), |
3050 RelocInfo::CONSTRUCT_CALL); | 2688 RelocInfo::CONSTRUCT_CALL); |
3051 __ mov(TOS, eax); // discard the function and "push" the newly created object | 2689 __ mov(TOS, eax); // discard the function and "push" the newly created object |
3052 } | 2690 } |
3053 | 2691 |
3054 | 2692 |
3055 void Ia32CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { | 2693 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { |
3056 ASSERT(args->length() == 1); | 2694 ASSERT(args->length() == 1); |
3057 Load(args->at(0)); | 2695 Load(args->at(0)); |
3058 __ pop(eax); | 2696 __ pop(eax); |
3059 __ test(eax, Immediate(kSmiTagMask)); | 2697 __ test(eax, Immediate(kSmiTagMask)); |
3060 cc_reg_ = zero; | 2698 cc_reg_ = zero; |
3061 } | 2699 } |
3062 | 2700 |
3063 | 2701 |
3064 void Ia32CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { | 2702 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) { |
3065 ASSERT(args->length() == 1); | 2703 ASSERT(args->length() == 1); |
3066 Load(args->at(0)); | 2704 Load(args->at(0)); |
3067 __ pop(eax); | 2705 __ pop(eax); |
3068 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); | 2706 __ test(eax, Immediate(kSmiTagMask | 0x80000000)); |
3069 cc_reg_ = zero; | 2707 cc_reg_ = zero; |
3070 } | 2708 } |
3071 | 2709 |
3072 | 2710 |
3073 // This generates code that performs a charCodeAt() call or returns | 2711 // This generates code that performs a charCodeAt() call or returns |
3074 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. | 2712 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. |
3075 // It can handle flat and sliced strings, 8 and 16 bit characters and | 2713 // It can handle flat and sliced strings, 8 and 16 bit characters and |
3076 // cons strings where the answer is found in the left hand branch of the | 2714 // cons strings where the answer is found in the left hand branch of the |
3077 // cons. The slow case will flatten the string, which will ensure that | 2715 // cons. The slow case will flatten the string, which will ensure that |
3078 // the answer is in the left hand side the next time around. | 2716 // the answer is in the left hand side the next time around. |
3079 void Ia32CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { | 2717 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { |
3080 ASSERT(args->length() == 2); | 2718 ASSERT(args->length() == 2); |
3081 | 2719 |
3082 Label slow_case; | 2720 Label slow_case; |
3083 Label end; | 2721 Label end; |
3084 Label not_a_flat_string; | 2722 Label not_a_flat_string; |
3085 Label not_a_cons_string_either; | 2723 Label not_a_cons_string_either; |
3086 Label try_again_with_new_string; | 2724 Label try_again_with_new_string; |
3087 Label ascii_string; | 2725 Label ascii_string; |
3088 Label got_char_code; | 2726 Label got_char_code; |
3089 | 2727 |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3195 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); | 2833 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); |
3196 __ jmp(&try_again_with_new_string); | 2834 __ jmp(&try_again_with_new_string); |
3197 | 2835 |
3198 __ bind(&slow_case); | 2836 __ bind(&slow_case); |
3199 __ push(Immediate(Factory::undefined_value())); | 2837 __ push(Immediate(Factory::undefined_value())); |
3200 | 2838 |
3201 __ bind(&end); | 2839 __ bind(&end); |
3202 } | 2840 } |
3203 | 2841 |
3204 | 2842 |
3205 void Ia32CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { | 2843 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { |
3206 ASSERT(args->length() == 1); | 2844 ASSERT(args->length() == 1); |
3207 Load(args->at(0)); | 2845 Load(args->at(0)); |
3208 Label answer; | 2846 Label answer; |
3209 // We need the CC bits to come out as not_equal in the case where the | 2847 // We need the CC bits to come out as not_equal in the case where the |
3210 // object is a smi. This can't be done with the usual test opcode so | 2848 // object is a smi. This can't be done with the usual test opcode so |
3211 // we copy the object to ecx and do some destructive ops on it that | 2849 // we copy the object to ecx and do some destructive ops on it that |
3212 // result in the right CC bits. | 2850 // result in the right CC bits. |
3213 __ pop(eax); | 2851 __ pop(eax); |
3214 __ mov(ecx, Operand(eax)); | 2852 __ mov(ecx, Operand(eax)); |
3215 __ and_(ecx, kSmiTagMask); | 2853 __ and_(ecx, kSmiTagMask); |
3216 __ xor_(ecx, kSmiTagMask); | 2854 __ xor_(ecx, kSmiTagMask); |
3217 __ j(not_equal, &answer, not_taken); | 2855 __ j(not_equal, &answer, not_taken); |
3218 // It is a heap object - get map. | 2856 // It is a heap object - get map. |
3219 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); | 2857 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); |
3220 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); | 2858 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); |
3221 // Check if the object is a JS array or not. | 2859 // Check if the object is a JS array or not. |
3222 __ cmp(eax, JS_ARRAY_TYPE); | 2860 __ cmp(eax, JS_ARRAY_TYPE); |
3223 __ bind(&answer); | 2861 __ bind(&answer); |
3224 cc_reg_ = equal; | 2862 cc_reg_ = equal; |
3225 } | 2863 } |
3226 | 2864 |
3227 | 2865 |
3228 void Ia32CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { | 2866 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { |
3229 ASSERT(args->length() == 0); | 2867 ASSERT(args->length() == 0); |
3230 | 2868 |
3231 // Seed the result with the formal parameters count, which will be | 2869 // Seed the result with the formal parameters count, which will be |
3232 // used in case no arguments adaptor frame is found below the | 2870 // used in case no arguments adaptor frame is found below the |
3233 // current frame. | 2871 // current frame. |
3234 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 2872 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
3235 | 2873 |
3236 // Call the shared stub to get to the arguments.length. | 2874 // Call the shared stub to get to the arguments.length. |
3237 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); | 2875 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); |
3238 __ CallStub(&stub); | 2876 __ CallStub(&stub); |
3239 __ push(eax); | 2877 __ push(eax); |
3240 } | 2878 } |
3241 | 2879 |
3242 | 2880 |
3243 void Ia32CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { | 2881 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { |
3244 ASSERT(args->length() == 1); | 2882 ASSERT(args->length() == 1); |
3245 Label leave; | 2883 Label leave; |
3246 Load(args->at(0)); // Load the object. | 2884 Load(args->at(0)); // Load the object. |
3247 __ mov(eax, TOS); | 2885 __ mov(eax, TOS); |
3248 // if (object->IsSmi()) return object. | 2886 // if (object->IsSmi()) return object. |
3249 __ test(eax, Immediate(kSmiTagMask)); | 2887 __ test(eax, Immediate(kSmiTagMask)); |
3250 __ j(zero, &leave, taken); | 2888 __ j(zero, &leave, taken); |
3251 // It is a heap object - get map. | 2889 // It is a heap object - get map. |
3252 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); | 2890 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); |
3253 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); | 2891 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); |
3254 // if (!object->IsJSValue()) return object. | 2892 // if (!object->IsJSValue()) return object. |
3255 __ cmp(ecx, JS_VALUE_TYPE); | 2893 __ cmp(ecx, JS_VALUE_TYPE); |
3256 __ j(not_equal, &leave, not_taken); | 2894 __ j(not_equal, &leave, not_taken); |
3257 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); | 2895 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); |
3258 __ mov(TOS, eax); | 2896 __ mov(TOS, eax); |
3259 __ bind(&leave); | 2897 __ bind(&leave); |
3260 } | 2898 } |
3261 | 2899 |
3262 | 2900 |
3263 void Ia32CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { | 2901 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { |
3264 ASSERT(args->length() == 2); | 2902 ASSERT(args->length() == 2); |
3265 Label leave; | 2903 Label leave; |
3266 Load(args->at(0)); // Load the object. | 2904 Load(args->at(0)); // Load the object. |
3267 Load(args->at(1)); // Load the value. | 2905 Load(args->at(1)); // Load the value. |
3268 __ mov(eax, (Operand(esp, kPointerSize))); | 2906 __ mov(eax, (Operand(esp, kPointerSize))); |
3269 __ mov(ecx, TOS); | 2907 __ mov(ecx, TOS); |
3270 // if (object->IsSmi()) return object. | 2908 // if (object->IsSmi()) return object. |
3271 __ test(eax, Immediate(kSmiTagMask)); | 2909 __ test(eax, Immediate(kSmiTagMask)); |
3272 __ j(zero, &leave, taken); | 2910 __ j(zero, &leave, taken); |
3273 // It is a heap object - get map. | 2911 // It is a heap object - get map. |
3274 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); | 2912 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); |
3275 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); | 2913 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); |
3276 // if (!object->IsJSValue()) return object. | 2914 // if (!object->IsJSValue()) return object. |
3277 __ cmp(ebx, JS_VALUE_TYPE); | 2915 __ cmp(ebx, JS_VALUE_TYPE); |
3278 __ j(not_equal, &leave, not_taken); | 2916 __ j(not_equal, &leave, not_taken); |
3279 // Store the value. | 2917 // Store the value. |
3280 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); | 2918 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); |
3281 // Update the write barrier. | 2919 // Update the write barrier. |
3282 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); | 2920 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); |
3283 // Leave. | 2921 // Leave. |
3284 __ bind(&leave); | 2922 __ bind(&leave); |
3285 __ mov(ecx, TOS); | 2923 __ mov(ecx, TOS); |
3286 __ pop(eax); | 2924 __ pop(eax); |
3287 __ mov(TOS, ecx); | 2925 __ mov(TOS, ecx); |
3288 } | 2926 } |
3289 | 2927 |
3290 | 2928 |
3291 void Ia32CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { | 2929 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { |
3292 ASSERT(args->length() == 1); | 2930 ASSERT(args->length() == 1); |
3293 | 2931 |
3294 // Load the key onto the stack and set register eax to the formal | 2932 // Load the key onto the stack and set register eax to the formal |
3295 // parameters count for the currently executing function. | 2933 // parameters count for the currently executing function. |
3296 Load(args->at(0)); | 2934 Load(args->at(0)); |
3297 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); | 2935 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); |
3298 | 2936 |
3299 // Call the shared stub to get to arguments[key]. | 2937 // Call the shared stub to get to arguments[key]. |
3300 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); | 2938 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); |
3301 __ CallStub(&stub); | 2939 __ CallStub(&stub); |
3302 __ mov(TOS, eax); | 2940 __ mov(TOS, eax); |
3303 } | 2941 } |
3304 | 2942 |
3305 | 2943 |
3306 void Ia32CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { | 2944 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { |
3307 ASSERT(args->length() == 2); | 2945 ASSERT(args->length() == 2); |
3308 | 2946 |
3309 // Load the two objects into registers and perform the comparison. | 2947 // Load the two objects into registers and perform the comparison. |
3310 Load(args->at(0)); | 2948 Load(args->at(0)); |
3311 Load(args->at(1)); | 2949 Load(args->at(1)); |
3312 __ pop(eax); | 2950 __ pop(eax); |
3313 __ pop(ecx); | 2951 __ pop(ecx); |
3314 __ cmp(eax, Operand(ecx)); | 2952 __ cmp(eax, Operand(ecx)); |
3315 cc_reg_ = equal; | 2953 cc_reg_ = equal; |
3316 } | 2954 } |
3317 | 2955 |
3318 | 2956 |
3319 void Ia32CodeGenerator::VisitCallRuntime(CallRuntime* node) { | 2957 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { |
3320 if (CheckForInlineRuntimeCall(node)) return; | 2958 if (CheckForInlineRuntimeCall(node)) return; |
3321 | 2959 |
3322 ZoneList<Expression*>* args = node->arguments(); | 2960 ZoneList<Expression*>* args = node->arguments(); |
3323 Comment cmnt(masm_, "[ CallRuntime"); | 2961 Comment cmnt(masm_, "[ CallRuntime"); |
3324 Runtime::Function* function = node->function(); | 2962 Runtime::Function* function = node->function(); |
3325 | 2963 |
3326 if (function == NULL) { | 2964 if (function == NULL) { |
3327 // Prepare stack for calling JS runtime function. | 2965 // Prepare stack for calling JS runtime function. |
3328 __ push(Immediate(node->name())); | 2966 __ push(Immediate(node->name())); |
3329 // Push the builtins object found in the current global object. | 2967 // Push the builtins object found in the current global object. |
(...skipping 13 matching lines...) Expand all Loading... |
3343 // Call the JS runtime function. | 2981 // Call the JS runtime function. |
3344 Handle<Code> stub = ComputeCallInitialize(args->length()); | 2982 Handle<Code> stub = ComputeCallInitialize(args->length()); |
3345 __ Set(eax, Immediate(args->length())); | 2983 __ Set(eax, Immediate(args->length())); |
3346 __ call(stub, RelocInfo::CODE_TARGET); | 2984 __ call(stub, RelocInfo::CODE_TARGET); |
3347 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); | 2985 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset)); |
3348 __ mov(TOS, eax); | 2986 __ mov(TOS, eax); |
3349 } | 2987 } |
3350 } | 2988 } |
3351 | 2989 |
3352 | 2990 |
3353 void Ia32CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { | 2991 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { |
3354 Comment cmnt(masm_, "[ UnaryOperation"); | 2992 Comment cmnt(masm_, "[ UnaryOperation"); |
3355 | 2993 |
3356 Token::Value op = node->op(); | 2994 Token::Value op = node->op(); |
3357 | 2995 |
3358 if (op == Token::NOT) { | 2996 if (op == Token::NOT) { |
3359 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, | 2997 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, |
3360 false_target(), true_target(), true); | 2998 false_target(), true_target(), true); |
3361 cc_reg_ = NegateCondition(cc_reg_); | 2999 cc_reg_ = NegateCondition(cc_reg_); |
3362 | 3000 |
3363 } else if (op == Token::DELETE) { | 3001 } else if (op == Token::DELETE) { |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3552 void CountOperationDeferred::Generate() { | 3190 void CountOperationDeferred::Generate() { |
3553 if (is_postfix_) { | 3191 if (is_postfix_) { |
3554 RevertToNumberStub to_number_stub(is_increment_); | 3192 RevertToNumberStub to_number_stub(is_increment_); |
3555 __ CallStub(&to_number_stub); | 3193 __ CallStub(&to_number_stub); |
3556 } | 3194 } |
3557 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); | 3195 CounterOpStub stub(result_offset_, is_postfix_, is_increment_); |
3558 __ CallStub(&stub); | 3196 __ CallStub(&stub); |
3559 } | 3197 } |
3560 | 3198 |
3561 | 3199 |
3562 void Ia32CodeGenerator::VisitCountOperation(CountOperation* node) { | 3200 void CodeGenerator::VisitCountOperation(CountOperation* node) { |
3563 Comment cmnt(masm_, "[ CountOperation"); | 3201 Comment cmnt(masm_, "[ CountOperation"); |
3564 | 3202 |
3565 bool is_postfix = node->is_postfix(); | 3203 bool is_postfix = node->is_postfix(); |
3566 bool is_increment = node->op() == Token::INC; | 3204 bool is_increment = node->op() == Token::INC; |
3567 | 3205 |
3568 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); | 3206 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); |
3569 bool is_const = (var != NULL && var->mode() == Variable::CONST); | 3207 bool is_const = (var != NULL && var->mode() == Variable::CONST); |
3570 | 3208 |
3571 // Postfix: Make room for the result. | 3209 // Postfix: Make room for the result. |
3572 if (is_postfix) __ push(Immediate(0)); | 3210 if (is_postfix) __ push(Immediate(0)); |
(...skipping 30 matching lines...) Expand all Loading... |
3603 __ bind(deferred->exit()); | 3241 __ bind(deferred->exit()); |
3604 __ push(eax); // Push the new value to TOS | 3242 __ push(eax); // Push the new value to TOS |
3605 if (!is_const) target.SetValue(NOT_CONST_INIT); | 3243 if (!is_const) target.SetValue(NOT_CONST_INIT); |
3606 } | 3244 } |
3607 | 3245 |
3608 // Postfix: Discard the new value and use the old. | 3246 // Postfix: Discard the new value and use the old. |
3609 if (is_postfix) __ pop(eax); | 3247 if (is_postfix) __ pop(eax); |
3610 } | 3248 } |
3611 | 3249 |
3612 | 3250 |
3613 void Ia32CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { | 3251 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { |
3614 Comment cmnt(masm_, "[ BinaryOperation"); | 3252 Comment cmnt(masm_, "[ BinaryOperation"); |
3615 Token::Value op = node->op(); | 3253 Token::Value op = node->op(); |
3616 | 3254 |
3617 // According to ECMA-262 section 11.11, page 58, the binary logical | 3255 // According to ECMA-262 section 11.11, page 58, the binary logical |
3618 // operators must yield the result of one of the two expressions | 3256 // operators must yield the result of one of the two expressions |
3619 // before any ToBoolean() conversions. This means that the value | 3257 // before any ToBoolean() conversions. This means that the value |
3620 // produced by a && or || operator is not necessarily a boolean. | 3258 // produced by a && or || operator is not necessarily a boolean. |
3621 | 3259 |
3622 // NOTE: If the left hand side produces a materialized value (not in | 3260 // NOTE: If the left hand side produces a materialized value (not in |
3623 // the CC register), we force the right hand side to do the | 3261 // the CC register), we force the right hand side to do the |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3725 | 3363 |
3726 } else { | 3364 } else { |
3727 Load(node->left()); | 3365 Load(node->left()); |
3728 Load(node->right()); | 3366 Load(node->right()); |
3729 GenericBinaryOperation(node->op(), overwrite_mode); | 3367 GenericBinaryOperation(node->op(), overwrite_mode); |
3730 } | 3368 } |
3731 } | 3369 } |
3732 } | 3370 } |
3733 | 3371 |
3734 | 3372 |
3735 void Ia32CodeGenerator::VisitThisFunction(ThisFunction* node) { | 3373 void CodeGenerator::VisitThisFunction(ThisFunction* node) { |
3736 __ push(FunctionOperand()); | 3374 __ push(FunctionOperand()); |
3737 } | 3375 } |
3738 | 3376 |
3739 | 3377 |
3740 class InstanceofStub: public CodeStub { | 3378 class InstanceofStub: public CodeStub { |
3741 public: | 3379 public: |
3742 InstanceofStub() { } | 3380 InstanceofStub() { } |
3743 | 3381 |
3744 void Generate(MacroAssembler* masm); | 3382 void Generate(MacroAssembler* masm); |
3745 | 3383 |
3746 private: | 3384 private: |
3747 Major MajorKey() { return Instanceof; } | 3385 Major MajorKey() { return Instanceof; } |
3748 int MinorKey() { return 0; } | 3386 int MinorKey() { return 0; } |
3749 }; | 3387 }; |
3750 | 3388 |
3751 | 3389 |
3752 void Ia32CodeGenerator::VisitCompareOperation(CompareOperation* node) { | 3390 void CodeGenerator::VisitCompareOperation(CompareOperation* node) { |
3753 Comment cmnt(masm_, "[ CompareOperation"); | 3391 Comment cmnt(masm_, "[ CompareOperation"); |
3754 | 3392 |
3755 // Get the expressions from the node. | 3393 // Get the expressions from the node. |
3756 Expression* left = node->left(); | 3394 Expression* left = node->left(); |
3757 Expression* right = node->right(); | 3395 Expression* right = node->right(); |
3758 Token::Value op = node->op(); | 3396 Token::Value op = node->op(); |
3759 | 3397 |
3760 // NOTE: To make null checks efficient, we check if either left or | 3398 // NOTE: To make null checks efficient, we check if either left or |
3761 // right is the literal 'null'. If so, we optimize the code by | 3399 // right is the literal 'null'. If so, we optimize the code by |
3762 // inlining a null check instead of calling the (very) general | 3400 // inlining a null check instead of calling the (very) general |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3951 SmiComparison(cc, right->AsLiteral()->handle(), strict); | 3589 SmiComparison(cc, right->AsLiteral()->handle(), strict); |
3952 return; | 3590 return; |
3953 } | 3591 } |
3954 | 3592 |
3955 Load(left); | 3593 Load(left); |
3956 Load(right); | 3594 Load(right); |
3957 Comparison(cc, strict); | 3595 Comparison(cc, strict); |
3958 } | 3596 } |
3959 | 3597 |
3960 | 3598 |
3961 void Ia32CodeGenerator::RecordStatementPosition(Node* node) { | 3599 void CodeGenerator::RecordStatementPosition(Node* node) { |
3962 if (FLAG_debug_info) { | 3600 if (FLAG_debug_info) { |
3963 int pos = node->statement_pos(); | 3601 int pos = node->statement_pos(); |
3964 if (pos != RelocInfo::kNoPosition) { | 3602 if (pos != RelocInfo::kNoPosition) { |
3965 __ RecordStatementPosition(pos); | 3603 __ RecordStatementPosition(pos); |
3966 } | 3604 } |
3967 } | 3605 } |
3968 } | 3606 } |
3969 | 3607 |
3970 | 3608 |
3971 void Ia32CodeGenerator::EnterJSFrame() { | 3609 void CodeGenerator::EnterJSFrame() { |
3972 __ push(ebp); | 3610 __ push(ebp); |
3973 __ mov(ebp, Operand(esp)); | 3611 __ mov(ebp, Operand(esp)); |
3974 | 3612 |
3975 // Store the context and the function in the frame. | 3613 // Store the context and the function in the frame. |
3976 __ push(esi); | 3614 __ push(esi); |
3977 __ push(edi); | 3615 __ push(edi); |
3978 | 3616 |
3979 // Clear the function slot when generating debug code. | 3617 // Clear the function slot when generating debug code. |
3980 if (FLAG_debug_code) { | 3618 if (FLAG_debug_code) { |
3981 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue))); | 3619 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue))); |
3982 } | 3620 } |
3983 } | 3621 } |
3984 | 3622 |
3985 | 3623 |
3986 void Ia32CodeGenerator::ExitJSFrame() { | 3624 void CodeGenerator::ExitJSFrame() { |
3987 // Record the location of the JS exit code for patching when setting | 3625 // Record the location of the JS exit code for patching when setting |
3988 // break point. | 3626 // break point. |
3989 __ RecordJSReturn(); | 3627 __ RecordJSReturn(); |
3990 | 3628 |
3991 // Avoid using the leave instruction here, because it is too | 3629 // Avoid using the leave instruction here, because it is too |
3992 // short. We need the return sequence to be a least the size of a | 3630 // short. We need the return sequence to be a least the size of a |
3993 // call instruction to support patching the exit code in the | 3631 // call instruction to support patching the exit code in the |
3994 // debugger. See VisitReturnStatement for the full return sequence. | 3632 // debugger. See VisitReturnStatement for the full return sequence. |
3995 __ mov(esp, Operand(ebp)); | 3633 __ mov(esp, Operand(ebp)); |
3996 __ pop(ebp); | 3634 __ pop(ebp); |
(...skipping 1339 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5336 __ ret(2 * kPointerSize); | 4974 __ ret(2 * kPointerSize); |
5337 | 4975 |
5338 // Slow-case: Go through the JavaScript implementation. | 4976 // Slow-case: Go through the JavaScript implementation. |
5339 __ bind(&slow); | 4977 __ bind(&slow); |
5340 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); | 4978 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); |
5341 } | 4979 } |
5342 | 4980 |
5343 | 4981 |
5344 #undef __ | 4982 #undef __ |
5345 | 4983 |
5346 // ----------------------------------------------------------------------------- | |
5347 // CodeGenerator interfaces | |
5348 | |
5349 // MakeCode() is just a wrapper for CodeGenerator::MakeCode() | |
5350 // so we don't have to expose the entire CodeGenerator class in | |
5351 // the .h file. | |
5352 Handle<Code> CodeGenerator::MakeCode(FunctionLiteral* fun, | |
5353 Handle<Script> script, | |
5354 bool is_eval) { | |
5355 Handle<Code> code = Ia32CodeGenerator::MakeCode(fun, script, is_eval); | |
5356 if (!code.is_null()) { | |
5357 Counters::total_compiled_code_size.Increment(code->instruction_size()); | |
5358 } | |
5359 return code; | |
5360 } | |
5361 | |
5362 | |
5363 } } // namespace v8::internal | 4984 } } // namespace v8::internal |
OLD | NEW |