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

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

Issue 8961: Merge change list off bleeding_edge into toiger branch. (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: Created 12 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/codegen-ia32.h ('k') | src/globals.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 20 matching lines...) Expand all
31 #include "codegen-inl.h" 31 #include "codegen-inl.h"
32 #include "debug.h" 32 #include "debug.h"
33 #include "scopes.h" 33 #include "scopes.h"
34 #include "runtime.h" 34 #include "runtime.h"
35 35
36 namespace v8 { namespace internal { 36 namespace v8 { namespace internal {
37 37
38 #define __ masm_-> 38 #define __ masm_->
39 39
40 // ------------------------------------------------------------------------- 40 // -------------------------------------------------------------------------
41 // VirtualFrame implementation.
42
43 VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
44 ASSERT(cgen->scope() != NULL);
45
46 masm_ = cgen->masm();
47 frame_local_count_ = cgen->scope()->num_stack_slots();
48 parameter_count_ = cgen->scope()->num_parameters();
49 }
50
51
52 void VirtualFrame::Enter() {
53 Comment cmnt(masm_, "[ Enter JS frame");
54 __ push(ebp);
55 __ mov(ebp, Operand(esp));
56
57 // Store the context and the function in the frame.
58 __ push(esi);
59 __ push(edi);
60
61 // Clear the function slot when generating debug code.
62 if (FLAG_debug_code) {
63 __ Set(edi, Immediate(reinterpret_cast<int>(kZapValue)));
64 }
65 }
66
67
68 void VirtualFrame::Exit() {
69 Comment cmnt(masm_, "[ Exit JS frame");
70 // Record the location of the JS exit code for patching when setting
71 // break point.
72 __ RecordJSReturn();
73
74 // Avoid using the leave instruction here, because it is too
75 // short. We need the return sequence to be a least the size of a
76 // call instruction to support patching the exit code in the
77 // debugger. See VisitReturnStatement for the full return sequence.
78 __ mov(esp, Operand(ebp));
79 __ pop(ebp);
80 }
81
82
83 void VirtualFrame::AllocateLocals() {
84 if (frame_local_count_ > 0) {
85 Comment cmnt(masm_, "[ Allocate space for locals");
86 __ Set(eax, Immediate(Factory::undefined_value()));
87 for (int i = 0; i < frame_local_count_; i++) {
88 __ push(eax);
89 }
90 }
91 }
92
93
94 void VirtualFrame::Drop(int count) {
95 ASSERT(count >= 0);
96 if (count > 0) {
97 __ add(Operand(esp), Immediate(count * kPointerSize));
98 }
99 }
100
101
102 void VirtualFrame::Pop() {
103 __ add(Operand(esp), Immediate(kPointerSize));
104 }
105
106
107 void VirtualFrame::Pop(Register reg) {
108 __ pop(reg);
109 }
110
111
112 void VirtualFrame::Pop(Operand operand) {
113 __ pop(operand);
114 }
115
116
117 void VirtualFrame::Push(Register reg) {
118 __ push(reg);
119 }
120
121
122 void VirtualFrame::Push(Operand operand) {
123 __ push(operand);
124 }
125
126
127 void VirtualFrame::Push(Immediate immediate) {
128 __ push(immediate);
129 }
130
131
132 // -------------------------------------------------------------------------
133 // CodeGenState implementation. 41 // CodeGenState implementation.
134 42
135 CodeGenState::CodeGenState(CodeGenerator* owner) 43 CodeGenState::CodeGenState(CodeGenerator* owner)
136 : owner_(owner), 44 : owner_(owner),
137 typeof_state_(NOT_INSIDE_TYPEOF), 45 typeof_state_(NOT_INSIDE_TYPEOF),
138 true_target_(NULL), 46 true_target_(NULL),
139 false_target_(NULL), 47 false_target_(NULL),
140 previous_(NULL) { 48 previous_(NULL) {
141 owner_->set_state(this); 49 owner_->set_state(this);
142 } 50 }
143 51
144 52
145 CodeGenState::CodeGenState(CodeGenerator* owner, 53 CodeGenState::CodeGenState(CodeGenerator* owner,
146 TypeofState typeof_state, 54 TypeofState typeof_state,
147 Label* true_target, 55 JumpTarget* true_target,
148 Label* false_target) 56 JumpTarget* false_target)
149 : owner_(owner), 57 : owner_(owner),
150 typeof_state_(typeof_state), 58 typeof_state_(typeof_state),
151 true_target_(true_target), 59 true_target_(true_target),
152 false_target_(false_target), 60 false_target_(false_target),
153 previous_(owner->state()) { 61 previous_(owner->state()) {
154 owner_->set_state(this); 62 owner_->set_state(this);
155 } 63 }
156 64
157 65
158 CodeGenState::~CodeGenState() { 66 CodeGenState::~CodeGenState() {
(...skipping 10 matching lines...) Expand all
169 : is_eval_(is_eval), 77 : is_eval_(is_eval),
170 script_(script), 78 script_(script),
171 deferred_(8), 79 deferred_(8),
172 masm_(new MacroAssembler(NULL, buffer_size)), 80 masm_(new MacroAssembler(NULL, buffer_size)),
173 scope_(NULL), 81 scope_(NULL),
174 frame_(NULL), 82 frame_(NULL),
175 cc_reg_(no_condition), 83 cc_reg_(no_condition),
176 state_(NULL), 84 state_(NULL),
177 is_inside_try_(false), 85 is_inside_try_(false),
178 break_stack_height_(0), 86 break_stack_height_(0),
179 loop_nesting_(0) { 87 loop_nesting_(0),
88 function_return_is_shadowed_(false) {
180 } 89 }
181 90
182 91
183 // Calling conventions: 92 // Calling conventions:
184 // ebp: frame pointer 93 // ebp: frame pointer
185 // esp: stack pointer 94 // esp: stack pointer
186 // edi: caller's parameter pointer 95 // edi: caller's parameter pointer
187 // esi: callee's context 96 // esi: callee's context
188 97
189 void CodeGenerator::GenCode(FunctionLiteral* fun) { 98 void CodeGenerator::GenCode(FunctionLiteral* fun) {
190 // Record the position for debugging purposes. 99 // Record the position for debugging purposes.
191 __ RecordPosition(fun->start_position()); 100 __ RecordPosition(fun->start_position());
192 101
193 ZoneList<Statement*>* body = fun->body(); 102 ZoneList<Statement*>* body = fun->body();
194 103
195 // Initialize state. 104 // Initialize state.
196 ASSERT(scope_ == NULL); 105 ASSERT(scope_ == NULL);
197 scope_ = fun->scope(); 106 scope_ = fun->scope();
198 ASSERT(frame_ == NULL); 107 ASSERT(frame_ == NULL);
199 VirtualFrame virtual_frame(this); 108 set_frame(new VirtualFrame(this));
200 frame_ = &virtual_frame;
201 cc_reg_ = no_condition; 109 cc_reg_ = no_condition;
110 function_return_.set_code_generator(this);
111 function_return_is_shadowed_ = false;
202 { 112 {
203 CodeGenState state(this); 113 CodeGenState state(this);
204 114
205 // Entry 115 // Entry
206 // stack: function, receiver, arguments, return address 116 // stack: function, receiver, arguments, return address
207 // esp: stack pointer 117 // esp: stack pointer
208 // ebp: frame pointer 118 // ebp: frame pointer
209 // edi: caller's parameter pointer 119 // edi: caller's parameter pointer
210 // esi: callee's context 120 // esi: callee's context
211 121
(...skipping 20 matching lines...) Expand all
232 // The arguments object pointer needs to be saved in ecx, since we need 142 // The arguments object pointer needs to be saved in ecx, since we need
233 // to store arguments into the context. 143 // to store arguments into the context.
234 if (scope_->arguments() != NULL) { 144 if (scope_->arguments() != NULL) {
235 ASSERT(scope_->arguments_shadow() != NULL); 145 ASSERT(scope_->arguments_shadow() != NULL);
236 Comment cmnt(masm_, "[ allocate arguments object"); 146 Comment cmnt(masm_, "[ allocate arguments object");
237 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT); 147 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
238 __ lea(eax, frame_->Receiver()); 148 __ lea(eax, frame_->Receiver());
239 frame_->Push(frame_->Function()); 149 frame_->Push(frame_->Function());
240 frame_->Push(eax); 150 frame_->Push(eax);
241 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters()))); 151 frame_->Push(Immediate(Smi::FromInt(scope_->num_parameters())));
242 __ CallStub(&stub); 152 frame_->CallStub(&stub, 3);
243 __ mov(ecx, Operand(eax)); 153 __ mov(ecx, Operand(eax));
244 arguments_object_allocated = true; 154 arguments_object_allocated = true;
245 } 155 }
246 156
247 // Allocate space for locals and initialize them. 157 // Allocate space for locals and initialize them.
248 frame_->AllocateLocals(); 158 frame_->AllocateLocals();
249 159
250 if (scope_->num_heap_slots() > 0) { 160 if (scope_->num_heap_slots() > 0) {
251 Comment cmnt(masm_, "[ allocate local context"); 161 Comment cmnt(masm_, "[ allocate local context");
252 // Save the arguments object pointer, if any. 162 // Save the arguments object pointer, if any.
253 if (arguments_object_allocated && !arguments_object_saved) { 163 if (arguments_object_allocated && !arguments_object_saved) {
254 frame_->Push(ecx); 164 frame_->Push(ecx);
255 arguments_object_saved = true; 165 arguments_object_saved = true;
256 } 166 }
257 // Allocate local context. 167 // Allocate local context.
258 // Get outer context and create a new context based on it. 168 // Get outer context and create a new context based on it.
259 frame_->Push(frame_->Function()); 169 frame_->Push(frame_->Function());
260 __ CallRuntime(Runtime::kNewContext, 1); // eax holds the result 170 frame_->CallRuntime(Runtime::kNewContext, 1); // eax holds the result
261 171
262 if (kDebug) { 172 if (kDebug) {
263 Label verified_true; 173 JumpTarget verified_true(this);
264 // Verify eax and esi are the same in debug mode 174 // Verify eax and esi are the same in debug mode
265 __ cmp(eax, Operand(esi)); 175 __ cmp(eax, Operand(esi));
266 __ j(equal, &verified_true); 176 verified_true.Branch(equal);
267 __ int3(); 177 __ int3();
268 __ bind(&verified_true); 178 verified_true.Bind();
269 } 179 }
270 180
271 // Update context local. 181 // Update context local.
272 __ mov(frame_->Context(), esi); 182 __ mov(frame_->Context(), esi);
273 // Restore the arguments array pointer, if any. 183 // Restore the arguments array pointer, if any.
274 } 184 }
275 185
276 // TODO(1241774): Improve this code: 186 // TODO(1241774): Improve this code:
277 // 1) only needed if we have a context 187 // 1) only needed if we have a context
278 // 2) no need to recompute context ptr every single time 188 // 2) no need to recompute context ptr every single time
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after
350 scope_->VisitIllegalRedeclaration(this); 260 scope_->VisitIllegalRedeclaration(this);
351 } else { 261 } else {
352 Comment cmnt(masm_, "[ declarations"); 262 Comment cmnt(masm_, "[ declarations");
353 ProcessDeclarations(scope_->declarations()); 263 ProcessDeclarations(scope_->declarations());
354 // Bail out if a stack-overflow exception occurred when 264 // Bail out if a stack-overflow exception occurred when
355 // processing declarations. 265 // processing declarations.
356 if (HasStackOverflow()) return; 266 if (HasStackOverflow()) return;
357 } 267 }
358 268
359 if (FLAG_trace) { 269 if (FLAG_trace) {
360 __ CallRuntime(Runtime::kTraceEnter, 0); 270 frame_->CallRuntime(Runtime::kTraceEnter, 0);
361 // Ignore the return value. 271 // Ignore the return value.
362 } 272 }
363 CheckStack(); 273 CheckStack();
364 274
365 // Compile the body of the function in a vanilla state. Don't 275 // Compile the body of the function in a vanilla state. Don't
366 // bother compiling all the code if the scope has an illegal 276 // bother compiling all the code if the scope has an illegal
367 // redeclaration. 277 // redeclaration.
368 if (!scope_->HasIllegalRedeclaration()) { 278 if (!scope_->HasIllegalRedeclaration()) {
369 Comment cmnt(masm_, "[ function body"); 279 Comment cmnt(masm_, "[ function body");
370 #ifdef DEBUG 280 #ifdef DEBUG
371 bool is_builtin = Bootstrapper::IsActive(); 281 bool is_builtin = Bootstrapper::IsActive();
372 bool should_trace = 282 bool should_trace =
373 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls; 283 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
374 if (should_trace) { 284 if (should_trace) {
375 __ CallRuntime(Runtime::kDebugTrace, 0); 285 frame_->CallRuntime(Runtime::kDebugTrace, 0);
376 // Ignore the return value. 286 // Ignore the return value.
377 } 287 }
378 #endif 288 #endif
379 VisitStatements(body); 289 VisitStatements(body);
380 290
381 // Generate a return statement if necessary. 291 // Generate a return statement if necessary. A NULL frame indicates
382 if (body->is_empty() || body->last()->AsReturnStatement() == NULL) { 292 // that control flow leaves the body on all paths and cannot fall
293 // through.
294 if (frame_ != NULL) {
383 Literal undefined(Factory::undefined_value()); 295 Literal undefined(Factory::undefined_value());
384 ReturnStatement statement(&undefined); 296 ReturnStatement statement(&undefined);
385 statement.set_statement_pos(fun->end_position()); 297 statement.set_statement_pos(fun->end_position());
386 VisitReturnStatement(&statement); 298 VisitReturnStatement(&statement);
387 } 299 }
388 } 300 }
389 } 301 }
390 302
391 // Code generation state must be reset. 303 // Code generation state must be reset.
304 ASSERT(!function_return_is_shadowed_);
305 function_return_.Unuse();
392 scope_ = NULL; 306 scope_ = NULL;
393 frame_ = NULL; 307 delete_frame();
394 ASSERT(!has_cc()); 308 ASSERT(!has_cc());
395 ASSERT(state_ == NULL); 309 ASSERT(state_ == NULL);
396 } 310 }
397 311
398 312
399 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) { 313 Operand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
400 // Currently, this assertion will fail if we try to assign to 314 // Currently, this assertion will fail if we try to assign to
401 // a constant variable that is constant because it is read-only 315 // a constant variable that is constant because it is read-only
402 // (such as the variable referring to a named function expression). 316 // (such as the variable referring to a named function expression).
403 // We need to implement assignments to read-only variables. 317 // We need to implement assignments to read-only variables.
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
447 } 361 }
448 362
449 363
450 // Loads a value on TOS. If it is a boolean value, the result may have been 364 // Loads a value on TOS. If it is a boolean value, the result may have been
451 // (partially) translated into branches, or it may have set the condition code 365 // (partially) translated into branches, or it may have set the condition code
452 // register. If force_cc is set, the value is forced to set the condition code 366 // register. If force_cc is set, the value is forced to set the condition code
453 // register and no value is pushed. If the condition code register was set, 367 // register and no value is pushed. If the condition code register was set,
454 // has_cc() is true and cc_reg_ contains the condition to test for 'true'. 368 // has_cc() is true and cc_reg_ contains the condition to test for 'true'.
455 void CodeGenerator::LoadCondition(Expression* x, 369 void CodeGenerator::LoadCondition(Expression* x,
456 TypeofState typeof_state, 370 TypeofState typeof_state,
457 Label* true_target, 371 JumpTarget* true_target,
458 Label* false_target, 372 JumpTarget* false_target,
459 bool force_cc) { 373 bool force_cc) {
460 ASSERT(!has_cc()); 374 ASSERT(!has_cc());
461 375
462 { CodeGenState new_state(this, typeof_state, true_target, false_target); 376 { CodeGenState new_state(this, typeof_state, true_target, false_target);
463 Visit(x); 377 Visit(x);
464 } 378 }
465 if (force_cc && !has_cc()) { 379
380 if (force_cc && frame_ != NULL && !has_cc()) {
466 ToBoolean(true_target, false_target); 381 ToBoolean(true_target, false_target);
467 } 382 }
468 ASSERT(has_cc() || !force_cc); 383
384 ASSERT(!force_cc || frame_ == NULL || has_cc());
469 } 385 }
470 386
471 387
472 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) { 388 void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
473 Label true_target; 389 JumpTarget true_target(this);
474 Label false_target; 390 JumpTarget false_target(this);
475 LoadCondition(x, typeof_state, &true_target, &false_target, false); 391 LoadCondition(x, typeof_state, &true_target, &false_target, false);
476 392
477 if (has_cc()) { 393 if (has_cc()) {
394 ASSERT(frame_ != NULL);
478 // convert cc_reg_ into a bool 395 // convert cc_reg_ into a bool
479 396
480 Label loaded, materialize_true; 397 JumpTarget loaded(this);
481 __ j(cc_reg_, &materialize_true); 398 JumpTarget materialize_true(this);
399 materialize_true.Branch(cc_reg_);
482 frame_->Push(Immediate(Factory::false_value())); 400 frame_->Push(Immediate(Factory::false_value()));
483 __ jmp(&loaded); 401 loaded.Jump();
484 __ bind(&materialize_true); 402 materialize_true.Bind();
485 frame_->Push(Immediate(Factory::true_value())); 403 frame_->Push(Immediate(Factory::true_value()));
486 __ bind(&loaded); 404 loaded.Bind();
487 cc_reg_ = no_condition; 405 cc_reg_ = no_condition;
488 } 406 }
489 407
490 if (true_target.is_linked() || false_target.is_linked()) { 408 if (true_target.is_linked() || false_target.is_linked()) {
491 // we have at least one condition value 409 // we have at least one condition value
492 // that has been "translated" into a branch, 410 // that has been "translated" into a branch,
493 // thus it needs to be loaded explicitly again 411 // thus it needs to be loaded explicitly again
494 Label loaded; 412 JumpTarget loaded(this);
495 __ jmp(&loaded); // don't lose current TOS 413 if (frame_ != NULL) {
414 loaded.Jump(); // don't lose current TOS
415 }
496 bool both = true_target.is_linked() && false_target.is_linked(); 416 bool both = true_target.is_linked() && false_target.is_linked();
497 // reincarnate "true", if necessary 417 // reincarnate "true", if necessary
498 if (true_target.is_linked()) { 418 if (true_target.is_linked()) {
499 __ bind(&true_target); 419 true_target.Bind();
500 frame_->Push(Immediate(Factory::true_value())); 420 frame_->Push(Immediate(Factory::true_value()));
501 } 421 }
502 // if both "true" and "false" need to be reincarnated, 422 // if both "true" and "false" need to be reincarnated,
503 // jump across code for "false" 423 // jump across code for "false"
504 if (both) 424 if (both) {
505 __ jmp(&loaded); 425 loaded.Jump();
426 }
506 // reincarnate "false", if necessary 427 // reincarnate "false", if necessary
507 if (false_target.is_linked()) { 428 if (false_target.is_linked()) {
508 __ bind(&false_target); 429 false_target.Bind();
509 frame_->Push(Immediate(Factory::false_value())); 430 frame_->Push(Immediate(Factory::false_value()));
510 } 431 }
511 // everything is loaded at this point 432 // everything is loaded at this point
512 __ bind(&loaded); 433 loaded.Bind();
513 } 434 }
514 ASSERT(!has_cc()); 435 ASSERT(!has_cc());
515 } 436 }
516 437
517 438
518 void CodeGenerator::LoadGlobal() { 439 void CodeGenerator::LoadGlobal() {
519 frame_->Push(GlobalObject()); 440 frame_->Push(GlobalObject());
520 } 441 }
521 442
522 443
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
588 if (var->is_global()) { 509 if (var->is_global()) {
589 LoadGlobal(); 510 LoadGlobal();
590 ref->set_type(Reference::NAMED); 511 ref->set_type(Reference::NAMED);
591 } else { 512 } else {
592 ASSERT(var->slot() != NULL); 513 ASSERT(var->slot() != NULL);
593 ref->set_type(Reference::SLOT); 514 ref->set_type(Reference::SLOT);
594 } 515 }
595 } else { 516 } else {
596 // Anything else is a runtime error. 517 // Anything else is a runtime error.
597 Load(e); 518 Load(e);
598 __ CallRuntime(Runtime::kThrowReferenceError, 1); 519 frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
599 } 520 }
600 } 521 }
601 522
602 523
603 void CodeGenerator::UnloadReference(Reference* ref) { 524 void CodeGenerator::UnloadReference(Reference* ref) {
604 // Pop a reference from the stack while preserving TOS. 525 // Pop a reference from the stack while preserving TOS.
605 Comment cmnt(masm_, "[ UnloadReference"); 526 Comment cmnt(masm_, "[ UnloadReference");
606 int size = ref->size(); 527 int size = ref->size();
607 if (size <= 0) { 528 if (size <= 0) {
608 // Do nothing. No popping is necessary. 529 // Do nothing. No popping is necessary.
(...skipping 16 matching lines...) Expand all
625 546
626 private: 547 private:
627 Major MajorKey() { return ToBoolean; } 548 Major MajorKey() { return ToBoolean; }
628 int MinorKey() { return 0; } 549 int MinorKey() { return 0; }
629 }; 550 };
630 551
631 552
632 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and 553 // ECMA-262, section 9.2, page 30: ToBoolean(). Pop the top of stack and
633 // convert it to a boolean in the condition code register or jump to 554 // convert it to a boolean in the condition code register or jump to
634 // 'false_target'/'true_target' as appropriate. 555 // 'false_target'/'true_target' as appropriate.
635 void CodeGenerator::ToBoolean(Label* true_target, Label* false_target) { 556 void CodeGenerator::ToBoolean(JumpTarget* true_target, JumpTarget* false_target) {
636 Comment cmnt(masm_, "[ ToBoolean"); 557 Comment cmnt(masm_, "[ ToBoolean");
637 558
638 // The value to convert should be popped from the stack. 559 // The value to convert should be popped from the stack.
639 frame_->Pop(eax); 560 frame_->Pop(eax);
640 561
641 // Fast case checks. 562 // Fast case checks.
642 563
643 // 'false' => false. 564 // 'false' => false.
644 __ cmp(eax, Factory::false_value()); 565 __ cmp(eax, Factory::false_value());
645 __ j(equal, false_target); 566 false_target->Branch(equal);
646 567
647 // 'true' => true. 568 // 'true' => true.
648 __ cmp(eax, Factory::true_value()); 569 __ cmp(eax, Factory::true_value());
649 __ j(equal, true_target); 570 true_target->Branch(equal);
650 571
651 // 'undefined' => false. 572 // 'undefined' => false.
652 __ cmp(eax, Factory::undefined_value()); 573 __ cmp(eax, Factory::undefined_value());
653 __ j(equal, false_target); 574 false_target->Branch(equal);
654 575
655 // Smi => false iff zero. 576 // Smi => false iff zero.
656 ASSERT(kSmiTag == 0); 577 ASSERT(kSmiTag == 0);
657 __ test(eax, Operand(eax)); 578 __ test(eax, Operand(eax));
658 __ j(zero, false_target); 579 false_target->Branch(zero);
659 __ test(eax, Immediate(kSmiTagMask)); 580 __ test(eax, Immediate(kSmiTagMask));
660 __ j(zero, true_target); 581 true_target->Branch(zero);
661 582
662 // Call the stub for all other cases. 583 // Call the stub for all other cases.
663 frame_->Push(eax); // Undo the pop(eax) from above. 584 frame_->Push(eax); // Undo the pop(eax) from above.
664 ToBooleanStub stub; 585 ToBooleanStub stub;
665 __ CallStub(&stub); 586 frame_->CallStub(&stub, 1);
666 // Convert result (eax) to condition code. 587 // Convert result (eax) to condition code.
667 __ test(eax, Operand(eax)); 588 __ test(eax, Operand(eax));
668 589
669 ASSERT(not_equal == not_zero); 590 ASSERT(not_equal == not_zero);
670 cc_reg_ = not_equal; 591 cc_reg_ = not_equal;
671 } 592 }
672 593
673 594
674 class FloatingPointHelper : public AllStatic { 595 class FloatingPointHelper : public AllStatic {
675 public: 596 public:
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
836 deferred->GenerateInlineCode(); 757 deferred->GenerateInlineCode();
837 // Put result back on the stack. It seems somewhat weird to let 758 // Put result back on the stack. It seems somewhat weird to let
838 // the deferred code jump back before the assignment to the frame 759 // the deferred code jump back before the assignment to the frame
839 // top, but this is just to let the peephole optimizer get rid of 760 // top, but this is just to let the peephole optimizer get rid of
840 // more code. 761 // more code.
841 __ bind(deferred->exit()); 762 __ bind(deferred->exit());
842 __ mov(frame_->Top(), eax); 763 __ mov(frame_->Top(), eax);
843 } else { 764 } else {
844 // Call the stub and push the result to the stack. 765 // Call the stub and push the result to the stack.
845 GenericBinaryOpStub stub(op, overwrite_mode, flags); 766 GenericBinaryOpStub stub(op, overwrite_mode, flags);
846 __ CallStub(&stub); 767 frame_->CallStub(&stub, 2);
847 frame_->Push(eax); 768 frame_->Push(eax);
848 } 769 }
849 } 770 }
850 771
851 772
852 class DeferredInlinedSmiOperation: public DeferredCode { 773 class DeferredInlinedSmiOperation: public DeferredCode {
853 public: 774 public:
854 DeferredInlinedSmiOperation(CodeGenerator* generator, 775 DeferredInlinedSmiOperation(CodeGenerator* generator,
855 Token::Value op, int value, 776 Token::Value op, int value,
856 OverwriteMode overwrite_mode) : 777 OverwriteMode overwrite_mode) :
(...skipping 351 matching lines...) Expand 10 before | Expand all | Expand 10 after
1208 if (cc == greater || cc == less_equal) { 1129 if (cc == greater || cc == less_equal) {
1209 cc = ReverseCondition(cc); 1130 cc = ReverseCondition(cc);
1210 frame_->Pop(edx); 1131 frame_->Pop(edx);
1211 frame_->Pop(eax); 1132 frame_->Pop(eax);
1212 } else { 1133 } else {
1213 frame_->Pop(eax); 1134 frame_->Pop(eax);
1214 frame_->Pop(edx); 1135 frame_->Pop(edx);
1215 } 1136 }
1216 1137
1217 // Check for the smi case. 1138 // Check for the smi case.
1218 Label is_smi, done; 1139 JumpTarget is_smi(this);
1140 JumpTarget done(this);
1219 __ mov(ecx, Operand(eax)); 1141 __ mov(ecx, Operand(eax));
1220 __ or_(ecx, Operand(edx)); 1142 __ or_(ecx, Operand(edx));
1221 __ test(ecx, Immediate(kSmiTagMask)); 1143 __ test(ecx, Immediate(kSmiTagMask));
1222 __ j(zero, &is_smi, taken); 1144 is_smi.Branch(zero, taken);
1223 1145
1224 // When non-smi, call out to the compare stub. "parameters" setup by 1146 // When non-smi, call out to the compare stub. "parameters" setup by
1225 // calling code in edx and eax and "result" is returned in the flags. 1147 // calling code in edx and eax and "result" is returned in the flags.
1226 CompareStub stub(cc, strict); 1148 CompareStub stub(cc, strict);
1227 __ CallStub(&stub); 1149 frame_->CallStub(&stub, 0);
1228 if (cc == equal) { 1150 if (cc == equal) {
1229 __ test(eax, Operand(eax)); 1151 __ test(eax, Operand(eax));
1230 } else { 1152 } else {
1231 __ cmp(eax, 0); 1153 __ cmp(eax, 0);
1232 } 1154 }
1233 __ jmp(&done); 1155 done.Jump();
1234 1156
1235 // Test smi equality by pointer comparison. 1157 // Test smi equality by pointer comparison.
1236 __ bind(&is_smi); 1158 is_smi.Bind();
1237 __ cmp(edx, Operand(eax)); 1159 __ cmp(edx, Operand(eax));
1238 // Fall through to |done|. 1160 // Fall through to |done|.
1239 1161
1240 __ bind(&done); 1162 done.Bind();
1241 cc_reg_ = cc; 1163 cc_reg_ = cc;
1242 } 1164 }
1243 1165
1244 1166
1245 class SmiComparisonDeferred: public DeferredCode { 1167 class SmiComparisonDeferred: public DeferredCode {
1246 public: 1168 public:
1247 SmiComparisonDeferred(CodeGenerator* generator, 1169 SmiComparisonDeferred(CodeGenerator* generator,
1248 Condition cc, 1170 Condition cc,
1249 bool strict, 1171 bool strict,
1250 int value) 1172 int value)
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
1317 // Push the arguments ("left-to-right") on the stack. 1239 // Push the arguments ("left-to-right") on the stack.
1318 for (int i = 0; i < args->length(); i++) { 1240 for (int i = 0; i < args->length(); i++) {
1319 Load(args->at(i)); 1241 Load(args->at(i));
1320 } 1242 }
1321 1243
1322 // Record the position for debugging purposes. 1244 // Record the position for debugging purposes.
1323 __ RecordPosition(position); 1245 __ RecordPosition(position);
1324 1246
1325 // Use the shared code stub to call the function. 1247 // Use the shared code stub to call the function.
1326 CallFunctionStub call_function(args->length()); 1248 CallFunctionStub call_function(args->length());
1327 __ CallStub(&call_function); 1249 frame_->CallStub(&call_function, args->length() + 1);
1328 1250
1329 // Restore context and pop function from the stack. 1251 // Restore context and pop function from the stack.
1330 __ mov(esi, frame_->Context()); 1252 __ mov(esi, frame_->Context());
1331 __ mov(frame_->Top(), eax); 1253 __ mov(frame_->Top(), eax);
1332 } 1254 }
1333 1255
1334 1256
1335 void CodeGenerator::Branch(bool if_true, Label* L) { 1257 void CodeGenerator::Branch(bool if_true, JumpTarget* target) {
1336 ASSERT(has_cc()); 1258 ASSERT(has_cc());
1337 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_); 1259 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
1338 __ j(cc, L); 1260 target->Branch(cc);
1339 cc_reg_ = no_condition; 1261 cc_reg_ = no_condition;
1340 } 1262 }
1341 1263
1342 1264
1343 void CodeGenerator::CheckStack() { 1265 void CodeGenerator::CheckStack() {
1344 if (FLAG_check_stack) { 1266 if (FLAG_check_stack) {
1345 Label stack_is_ok; 1267 JumpTarget stack_is_ok(this);
1346 StackCheckStub stub; 1268 StackCheckStub stub;
1347 ExternalReference stack_guard_limit = 1269 ExternalReference stack_guard_limit =
1348 ExternalReference::address_of_stack_guard_limit(); 1270 ExternalReference::address_of_stack_guard_limit();
1349 __ cmp(esp, Operand::StaticVariable(stack_guard_limit)); 1271 __ cmp(esp, Operand::StaticVariable(stack_guard_limit));
1350 __ j(above_equal, &stack_is_ok, taken); 1272 stack_is_ok.Branch(above_equal, taken);
1351 __ CallStub(&stub); 1273 frame_->CallStub(&stub, 0);
1352 __ bind(&stack_is_ok); 1274 stack_is_ok.Bind();
1275 }
1276 }
1277
1278
1279 void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
1280 for (int i = 0; frame_ != NULL && i < statements->length(); i++) {
1281 Visit(statements->at(i));
1353 } 1282 }
1354 } 1283 }
1355 1284
1356 1285
1357 void CodeGenerator::VisitBlock(Block* node) { 1286 void CodeGenerator::VisitBlock(Block* node) {
1358 Comment cmnt(masm_, "[ Block"); 1287 Comment cmnt(masm_, "[ Block");
1359 RecordStatementPosition(node); 1288 RecordStatementPosition(node);
1360 node->set_break_stack_height(break_stack_height_); 1289 node->set_break_stack_height(break_stack_height_);
1290 node->break_target()->set_code_generator(this);
1361 VisitStatements(node->statements()); 1291 VisitStatements(node->statements());
1362 __ bind(node->break_target()); 1292 if (node->break_target()->is_linked()) {
1293 node->break_target()->Bind();
1294 }
1363 } 1295 }
1364 1296
1365 1297
1366 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) { 1298 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
1367 frame_->Push(Immediate(pairs)); 1299 frame_->Push(Immediate(pairs));
1368 frame_->Push(esi); 1300 frame_->Push(esi);
1369 frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0))); 1301 frame_->Push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
1370 __ CallRuntime(Runtime::kDeclareGlobals, 3); 1302 frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
1371 // Return value is ignored. 1303 // Return value is ignored.
1372 } 1304 }
1373 1305
1374 1306
1375 void CodeGenerator::VisitDeclaration(Declaration* node) { 1307 void CodeGenerator::VisitDeclaration(Declaration* node) {
1376 Comment cmnt(masm_, "[ Declaration"); 1308 Comment cmnt(masm_, "[ Declaration");
1377 Variable* var = node->proxy()->var(); 1309 Variable* var = node->proxy()->var();
1378 ASSERT(var != NULL); // must have been resolved 1310 ASSERT(var != NULL); // must have been resolved
1379 Slot* slot = var->slot(); 1311 Slot* slot = var->slot();
1380 1312
(...skipping 15 matching lines...) Expand all
1396 // Note: For variables we must not push an initial value (such as 1328 // Note: For variables we must not push an initial value (such as
1397 // 'undefined') because we may have a (legal) redeclaration and we 1329 // 'undefined') because we may have a (legal) redeclaration and we
1398 // must not destroy the current value. 1330 // must not destroy the current value.
1399 if (node->mode() == Variable::CONST) { 1331 if (node->mode() == Variable::CONST) {
1400 frame_->Push(Immediate(Factory::the_hole_value())); 1332 frame_->Push(Immediate(Factory::the_hole_value()));
1401 } else if (node->fun() != NULL) { 1333 } else if (node->fun() != NULL) {
1402 Load(node->fun()); 1334 Load(node->fun());
1403 } else { 1335 } else {
1404 frame_->Push(Immediate(0)); // no initial value! 1336 frame_->Push(Immediate(0)); // no initial value!
1405 } 1337 }
1406 __ CallRuntime(Runtime::kDeclareContextSlot, 4); 1338 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4);
1407 // Ignore the return value (declarations are statements). 1339 // Ignore the return value (declarations are statements).
1408 return; 1340 return;
1409 } 1341 }
1410 1342
1411 ASSERT(!var->is_global()); 1343 ASSERT(!var->is_global());
1412 1344
1413 // If we have a function or a constant, we need to initialize the variable. 1345 // If we have a function or a constant, we need to initialize the variable.
1414 Expression* val = NULL; 1346 Expression* val = NULL;
1415 if (node->mode() == Variable::CONST) { 1347 if (node->mode() == Variable::CONST) {
1416 val = new Literal(Factory::the_hole_value()); 1348 val = new Literal(Factory::the_hole_value());
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1451 1383
1452 1384
1453 void CodeGenerator::VisitIfStatement(IfStatement* node) { 1385 void CodeGenerator::VisitIfStatement(IfStatement* node) {
1454 Comment cmnt(masm_, "[ IfStatement"); 1386 Comment cmnt(masm_, "[ IfStatement");
1455 // Generate different code depending on which 1387 // Generate different code depending on which
1456 // parts of the if statement are present or not. 1388 // parts of the if statement are present or not.
1457 bool has_then_stm = node->HasThenStatement(); 1389 bool has_then_stm = node->HasThenStatement();
1458 bool has_else_stm = node->HasElseStatement(); 1390 bool has_else_stm = node->HasElseStatement();
1459 1391
1460 RecordStatementPosition(node); 1392 RecordStatementPosition(node);
1461 Label exit; 1393 JumpTarget exit(this);
1462 if (has_then_stm && has_else_stm) { 1394 if (has_then_stm && has_else_stm) {
1463 Label then; 1395 JumpTarget then(this);
1464 Label else_; 1396 JumpTarget else_(this);
1465 // if (cond) 1397 // if (cond)
1466 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); 1398 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
1467 Branch(false, &else_); 1399 if (frame_ != NULL) {
1400 // A NULL frame here indicates that the code for the condition cannot
1401 // fall-through, i.e. it causes unconditional branchs to targets.
1402 Branch(false, &else_);
1403 }
1468 // then 1404 // then
1469 __ bind(&then); 1405 if (frame_ != NULL || then.is_linked()) {
1470 Visit(node->then_statement()); 1406 // If control flow can reach the then part via fall-through from the
1471 __ jmp(&exit); 1407 // test or a branch to the target, compile it.
1408 then.Bind();
1409 Visit(node->then_statement());
1410 }
1411 if (frame_ != NULL) {
1412 // A NULL frame here indicates that control did not fall out of the
1413 // then statement, it escaped on all branches. In that case, a jump
1414 // to the exit label would be dead code (and impossible, because we
1415 // don't have a current virtual frame to set at the exit label).
1416 exit.Jump();
1417 }
1472 // else 1418 // else
1473 __ bind(&else_); 1419 if (else_.is_linked()) {
1474 Visit(node->else_statement()); 1420 // Control flow for if-then-else does not fall-through to the else
1421 // part, it can only reach here via jump if at all.
1422 else_.Bind();
1423 Visit(node->else_statement());
1424 }
1475 1425
1476 } else if (has_then_stm) { 1426 } else if (has_then_stm) {
1477 ASSERT(!has_else_stm); 1427 ASSERT(!has_else_stm);
1478 Label then; 1428 JumpTarget then(this);
1479 // if (cond) 1429 // if (cond)
1480 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true); 1430 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &exit, true);
1481 Branch(false, &exit); 1431 if (frame_ != NULL) {
1432 Branch(false, &exit);
1433 }
1482 // then 1434 // then
1483 __ bind(&then); 1435 if (frame_ != NULL || then.is_linked()) {
1484 Visit(node->then_statement()); 1436 then.Bind();
1437 Visit(node->then_statement());
1438 }
1485 1439
1486 } else if (has_else_stm) { 1440 } else if (has_else_stm) {
1487 ASSERT(!has_then_stm); 1441 ASSERT(!has_then_stm);
1488 Label else_; 1442 JumpTarget else_(this);
1489 // if (!cond) 1443 // if (!cond)
1490 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true); 1444 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &else_, true);
1491 Branch(true, &exit); 1445 if (frame_ != NULL) {
1446 Branch(true, &exit);
1447 }
1492 // else 1448 // else
1493 __ bind(&else_); 1449 if (frame_ != NULL || else_.is_linked()) {
1494 Visit(node->else_statement()); 1450 else_.Bind();
1451 Visit(node->else_statement());
1452 }
1495 1453
1496 } else { 1454 } else {
1497 ASSERT(!has_then_stm && !has_else_stm); 1455 ASSERT(!has_then_stm && !has_else_stm);
1498 // if (cond) 1456 // if (cond)
1499 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false); 1457 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &exit, &exit, false);
1500 if (has_cc()) { 1458 if (frame_ != NULL) {
1501 cc_reg_ = no_condition; 1459 if (has_cc()) {
1502 } else { 1460 cc_reg_ = no_condition;
1503 // No cc value set up, that means the boolean was pushed. 1461 } else {
1504 // Pop it again, since it is not going to be used. 1462 // No cc value set up, that means the boolean was pushed.
1505 frame_->Pop(); 1463 // Pop it again, since it is not going to be used.
1464 frame_->Pop();
1465 }
1506 } 1466 }
1507 } 1467 }
1508 1468
1509 // end 1469 // end
1510 __ bind(&exit); 1470 if (exit.is_linked()) {
1471 exit.Bind();
1472 }
1511 } 1473 }
1512 1474
1513 1475
1514 void CodeGenerator::CleanStack(int num_bytes) { 1476 void CodeGenerator::CleanStack(int num_bytes) {
1515 ASSERT(num_bytes % kPointerSize == 0); 1477 ASSERT(num_bytes % kPointerSize == 0);
1516 frame_->Drop(num_bytes / kPointerSize); 1478 frame_->Drop(num_bytes / kPointerSize);
1517 } 1479 }
1518 1480
1519 1481
1520 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) { 1482 void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
1521 Comment cmnt(masm_, "[ ContinueStatement"); 1483 Comment cmnt(masm_, "[ ContinueStatement");
1522 RecordStatementPosition(node); 1484 RecordStatementPosition(node);
1523 CleanStack(break_stack_height_ - node->target()->break_stack_height()); 1485 CleanStack(break_stack_height_ - node->target()->break_stack_height());
1524 __ jmp(node->target()->continue_target()); 1486 node->target()->continue_target()->Jump();
1525 } 1487 }
1526 1488
1527 1489
1528 void CodeGenerator::VisitBreakStatement(BreakStatement* node) { 1490 void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
1529 Comment cmnt(masm_, "[ BreakStatement"); 1491 Comment cmnt(masm_, "[ BreakStatement");
1530 RecordStatementPosition(node); 1492 RecordStatementPosition(node);
1531 CleanStack(break_stack_height_ - node->target()->break_stack_height()); 1493 CleanStack(break_stack_height_ - node->target()->break_stack_height());
1532 __ jmp(node->target()->break_target()); 1494 node->target()->break_target()->Jump();
1533 } 1495 }
1534 1496
1535 1497
1536 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) { 1498 void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
1537 Comment cmnt(masm_, "[ ReturnStatement"); 1499 Comment cmnt(masm_, "[ ReturnStatement");
1538 RecordStatementPosition(node); 1500 RecordStatementPosition(node);
1539 Load(node->expression()); 1501 Load(node->expression());
1540 1502
1541 // Move the function result into eax 1503 // Move the function result into eax
1542 frame_->Pop(eax); 1504 frame_->Pop(eax);
1543 1505
1544 // If we're inside a try statement or the return instruction 1506 // If we're inside a try statement or the return instruction
1545 // sequence has been generated, we just jump to that 1507 // sequence has been generated, we just jump to that
1546 // point. Otherwise, we generate the return instruction sequence and 1508 // point. Otherwise, we generate the return instruction sequence and
1547 // bind the function return label. 1509 // bind the function return label.
1548 if (is_inside_try_ || function_return_.is_bound()) { 1510 if (is_inside_try_ || function_return_.is_bound()) {
1549 __ jmp(&function_return_); 1511 function_return_.Jump();
1550 } else { 1512 } else {
1551 __ bind(&function_return_); 1513 function_return_.Bind();
1552 if (FLAG_trace) { 1514 if (FLAG_trace) {
1553 frame_->Push(eax); // undo the pop(eax) from above 1515 frame_->Push(eax); // undo the pop(eax) from above
1554 __ CallRuntime(Runtime::kTraceExit, 1); 1516 frame_->CallRuntime(Runtime::kTraceExit, 1);
1555 } 1517 }
1556 1518
1557 // Add a label for checking the size of the code used for returning. 1519 // Add a label for checking the size of the code used for returning.
1558 Label check_exit_codesize; 1520 Label check_exit_codesize;
1559 __ bind(&check_exit_codesize); 1521 __ bind(&check_exit_codesize);
1560 1522
1561 // Leave the frame and return popping the arguments and the 1523 // Leave the frame and return popping the arguments and the
1562 // receiver. 1524 // receiver.
1563 frame_->Exit(); 1525 frame_->Exit();
1564 __ ret((scope_->num_parameters() + 1) * kPointerSize); 1526 __ ret((scope_->num_parameters() + 1) * kPointerSize);
1527 delete_frame();
1565 1528
1566 // Check that the size of the code used for returning matches what is 1529 // Check that the size of the code used for returning matches what is
1567 // expected by the debugger. 1530 // expected by the debugger.
1568 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength, 1531 ASSERT_EQ(Debug::kIa32JSReturnSequenceLength,
1569 __ SizeOfCodeGeneratedSince(&check_exit_codesize)); 1532 __ SizeOfCodeGeneratedSince(&check_exit_codesize));
1570 } 1533 }
1571 } 1534 }
1572 1535
1573 1536
1574 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) { 1537 void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
1575 Comment cmnt(masm_, "[ WithEnterStatement"); 1538 Comment cmnt(masm_, "[ WithEnterStatement");
1576 RecordStatementPosition(node); 1539 RecordStatementPosition(node);
1577 Load(node->expression()); 1540 Load(node->expression());
1578 __ CallRuntime(Runtime::kPushContext, 1); 1541 frame_->CallRuntime(Runtime::kPushContext, 1);
1579 1542
1580 if (kDebug) { 1543 if (kDebug) {
1581 Label verified_true; 1544 JumpTarget verified_true(this);
1582 // Verify eax and esi are the same in debug mode 1545 // Verify eax and esi are the same in debug mode
1583 __ cmp(eax, Operand(esi)); 1546 __ cmp(eax, Operand(esi));
1584 __ j(equal, &verified_true); 1547 verified_true.Branch(equal);
1585 __ int3(); 1548 __ int3();
1586 __ bind(&verified_true); 1549 verified_true.Bind();
1587 } 1550 }
1588 1551
1589 // Update context local. 1552 // Update context local.
1590 __ mov(frame_->Context(), esi); 1553 __ mov(frame_->Context(), esi);
1591 } 1554 }
1592 1555
1593 1556
1594 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) { 1557 void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
1595 Comment cmnt(masm_, "[ WithExitStatement"); 1558 Comment cmnt(masm_, "[ WithExitStatement");
1596 // Pop context. 1559 // Pop context.
1597 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX)); 1560 __ mov(esi, ContextOperand(esi, Context::PREVIOUS_INDEX));
1598 // Update context local. 1561 // Update context local.
1599 __ mov(frame_->Context(), esi); 1562 __ mov(frame_->Context(), esi);
1600 } 1563 }
1601 1564
1565
1602 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() { 1566 int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
1603 return kFastSwitchMaxOverheadFactor; 1567 return kFastSwitchMaxOverheadFactor;
1604 } 1568 }
1605 1569
1570
1606 int CodeGenerator::FastCaseSwitchMinCaseCount() { 1571 int CodeGenerator::FastCaseSwitchMinCaseCount() {
1607 return kFastSwitchMinCaseCount; 1572 return kFastSwitchMinCaseCount;
1608 } 1573 }
1609 1574
1575
1610 // Generate a computed jump to a switch case. 1576 // Generate a computed jump to a switch case.
1611 void CodeGenerator::GenerateFastCaseSwitchJumpTable( 1577 void CodeGenerator::GenerateFastCaseSwitchJumpTable(
1612 SwitchStatement* node, 1578 SwitchStatement* node,
1613 int min_index, 1579 int min_index,
1614 int range, 1580 int range,
1615 Label* fail_label, 1581 JumpTarget* fail_label,
1616 Vector<Label*> case_targets, 1582 Vector<JumpTarget*> case_targets,
1617 Vector<Label> case_labels) { 1583 Vector<JumpTarget> case_labels) {
1618 // Notice: Internal references, used by both the jmp instruction and 1584 // Notice: Internal references, used by both the jmp instruction and
1619 // the table entries, need to be relocated if the buffer grows. This 1585 // the table entries, need to be relocated if the buffer grows. This
1620 // prevents the forward use of Labels, since a displacement cannot 1586 // prevents the forward use of Labels, since a displacement cannot
1621 // survive relocation, and it also cannot safely be distinguished 1587 // survive relocation, and it also cannot safely be distinguished
1622 // from a real address. Instead we put in zero-values as 1588 // from a real address. Instead we put in zero-values as
1623 // placeholders, and fill in the addresses after the labels have been 1589 // placeholders, and fill in the addresses after the labels have been
1624 // bound. 1590 // bound.
1625 1591
1626 frame_->Pop(eax); // supposed smi 1592 frame_->Pop(eax); // supposed smi
1627 // check range of value, if outside [0..length-1] jump to default/end label. 1593 // check range of value, if outside [0..length-1] jump to default/end label.
1628 ASSERT(kSmiTagSize == 1 && kSmiTag == 0); 1594 ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
1629 if (min_index != 0) { 1595 if (min_index != 0) {
1630 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize)); 1596 __ sub(Operand(eax), Immediate(min_index << kSmiTagSize));
1631 } 1597 }
1632 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi 1598 __ test(eax, Immediate(0x80000000 | kSmiTagMask)); // negative or not Smi
1633 __ j(not_equal, fail_label, not_taken); 1599 fail_label->Branch(not_equal, not_taken);
1634 __ cmp(eax, range << kSmiTagSize); 1600 __ cmp(eax, range << kSmiTagSize);
1635 __ j(greater_equal, fail_label, not_taken); 1601 fail_label->Branch(greater_equal, not_taken);
1636 1602
1637 // 0 is placeholder. 1603 // 0 is placeholder.
1638 __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE)); 1604 __ jmp(Operand(eax, times_2, 0x0, RelocInfo::INTERNAL_REFERENCE));
1639 // calculate address to overwrite later with actual address of table. 1605 // calculate address to overwrite later with actual address of table.
1640 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t); 1606 int32_t jump_table_ref = __ pc_offset() - sizeof(int32_t);
1641 1607
1642 __ Align(4); 1608 __ Align(4);
1643 Label table_start; 1609 JumpTarget table_start(this);
1644 __ bind(&table_start); 1610 table_start.Bind();
1645 __ WriteInternalReference(jump_table_ref, table_start); 1611 __ WriteInternalReference(jump_table_ref, *table_start.label());
1646 1612
1647 for (int i = 0; i < range; i++) { 1613 for (int i = 0; i < range; i++) {
1648 // table entry, 0 is placeholder for case address 1614 // table entry, 0 is placeholder for case address
1649 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE); 1615 __ dd(0x0, RelocInfo::INTERNAL_REFERENCE);
1650 } 1616 }
1651 1617
1652 GenerateFastCaseSwitchCases(node, case_labels); 1618 GenerateFastCaseSwitchCases(node, case_labels, &table_start);
1653 1619
1654 for (int i = 0, entry_pos = table_start.pos(); 1620 for (int i = 0, entry_pos = table_start.label()->pos();
1655 i < range; i++, entry_pos += sizeof(uint32_t)) { 1621 i < range;
1656 __ WriteInternalReference(entry_pos, *case_targets[i]); 1622 i++, entry_pos += sizeof(uint32_t)) {
1623 __ WriteInternalReference(entry_pos, *case_targets[i]->label());
1657 } 1624 }
1658 } 1625 }
1659 1626
1660 1627
1661 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) { 1628 void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
1662 Comment cmnt(masm_, "[ SwitchStatement"); 1629 Comment cmnt(masm_, "[ SwitchStatement");
1663 RecordStatementPosition(node); 1630 RecordStatementPosition(node);
1664 node->set_break_stack_height(break_stack_height_); 1631 node->set_break_stack_height(break_stack_height_);
1632 node->break_target()->set_code_generator(this);
1665 1633
1666 Load(node->tag()); 1634 Load(node->tag());
1667 1635
1668 if (TryGenerateFastCaseSwitchStatement(node)) { 1636 if (TryGenerateFastCaseSwitchStatement(node)) {
1669 return; 1637 return;
1670 } 1638 }
1671 1639
1672 Label next, fall_through, default_case; 1640 JumpTarget next_test(this);
1641 JumpTarget fall_through(this);
1642 JumpTarget default_entry(this);
1643 JumpTarget default_exit(this);
1644
1673 ZoneList<CaseClause*>* cases = node->cases(); 1645 ZoneList<CaseClause*>* cases = node->cases();
1674 int length = cases->length(); 1646 int length = cases->length();
1647 CaseClause* default_clause = NULL;
1675 1648
1676 for (int i = 0; i < length; i++) { 1649 for (int i = 0; i < length; i++) {
1677 CaseClause* clause = cases->at(i); 1650 CaseClause* clause = cases->at(i);
1678 Comment cmnt(masm_, "[ case clause");
1679 1651
1680 if (clause->is_default()) { 1652 if (clause->is_default()) {
1681 // Continue matching cases. The program will execute the default case's 1653 default_clause = clause;
1682 // statements if it does not match any of the cases. 1654 } else {
1683 __ jmp(&next); 1655 Comment cmnt(masm_, "[ Case clause");
1684 1656
1685 // Bind the default case label, so we can branch to it when we 1657 // Compile the test.
1686 // have compared against all other cases. 1658 next_test.Bind();
1687 ASSERT(default_case.is_unused()); // at most one default clause 1659 next_test.Unuse();
1688 __ bind(&default_case); 1660 // Duplicate TOS.
1689 } else {
1690 __ bind(&next);
1691 next.Unuse();
1692 __ mov(eax, frame_->Top()); 1661 __ mov(eax, frame_->Top());
1693 frame_->Push(eax); // duplicate TOS 1662 frame_->Push(eax);
1694 Load(clause->label()); 1663 Load(clause->label());
1695 Comparison(equal, true); 1664 Comparison(equal, true);
1696 Branch(false, &next); 1665 Branch(false, &next_test);
1666
1667 // Before entering the body, remove the switch value from the stack.
1668 frame_->Pop();
1669
1670 // Label the body so that fall through is enabled.
1671 if (i > 0 && cases->at(i - 1)->is_default()) {
1672 default_exit.Bind();
1673 } else {
1674 fall_through.Bind();
1675 fall_through.Unuse();
1676 }
1677 VisitStatements(clause->statements());
1678
1679 // If control flow can fall through from the body jump to the
1680 // next body or end of the statement.
1681 if (frame_ != NULL) {
1682 if (i < length - 1 && cases->at(i + 1)->is_default()) {
1683 default_entry.Jump();
1684 } else {
1685 fall_through.Jump();
1686 }
1687 }
1697 } 1688 }
1698
1699 // Entering the case statement for the first time. Remove the switch value
1700 // from the stack.
1701 frame_->Pop(eax);
1702
1703 // Generate code for the body.
1704 // This is also the target for the fall through from the previous case's
1705 // statements which has to skip over the matching code and the popping of
1706 // the switch value.
1707 __ bind(&fall_through);
1708 fall_through.Unuse();
1709 VisitStatements(clause->statements());
1710 __ jmp(&fall_through);
1711 } 1689 }
1712 1690
1713 __ bind(&next); 1691 // The final test removes the switch value.
1714 // Reached the end of the case statements without matching any of the cases. 1692 next_test.Bind();
1715 if (default_case.is_bound()) { 1693 frame_->Pop();
1716 // A default case exists -> execute its statements. 1694
1717 __ jmp(&default_case); 1695 // If there is a default clause, compile it.
1718 } else { 1696 if (default_clause != NULL) {
1719 // Remove the switch value from the stack. 1697 Comment cmnt(masm_, "[ Default clause");
1720 frame_->Pop(); 1698 default_entry.Bind();
1699 VisitStatements(default_clause->statements());
1700 // If control flow can fall out of the default and there is a case after
1701 // it, jump to that case's body.
1702 if (frame_ != NULL && default_exit.is_bound()) {
1703 default_exit.Jump();
1704 }
1721 } 1705 }
1722 1706
1723 __ bind(&fall_through); 1707 if (fall_through.is_linked()) {
1724 __ bind(node->break_target()); 1708 fall_through.Bind();
1709 }
1710
1711 if (node->break_target()->is_linked()) {
1712 node->break_target()->Bind();
1713 }
1725 } 1714 }
1726 1715
1727 1716
1728 void CodeGenerator::VisitLoopStatement(LoopStatement* node) { 1717 void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
1729 Comment cmnt(masm_, "[ LoopStatement"); 1718 Comment cmnt(masm_, "[ LoopStatement");
1730 RecordStatementPosition(node); 1719 RecordStatementPosition(node);
1731 node->set_break_stack_height(break_stack_height_); 1720 node->set_break_stack_height(break_stack_height_);
1721 node->break_target()->set_code_generator(this);
1722 node->continue_target()->set_code_generator(this);
1732 1723
1733 // simple condition analysis 1724 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
1725 // known result for the test expression, with no side effects.
1734 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW; 1726 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
1735 if (node->cond() == NULL) { 1727 if (node->cond() == NULL) {
1736 ASSERT(node->type() == LoopStatement::FOR_LOOP); 1728 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1737 info = ALWAYS_TRUE; 1729 info = ALWAYS_TRUE;
1738 } else { 1730 } else {
1739 Literal* lit = node->cond()->AsLiteral(); 1731 Literal* lit = node->cond()->AsLiteral();
1740 if (lit != NULL) { 1732 if (lit != NULL) {
1741 if (lit->IsTrue()) { 1733 if (lit->IsTrue()) {
1742 info = ALWAYS_TRUE; 1734 info = ALWAYS_TRUE;
1743 } else if (lit->IsFalse()) { 1735 } else if (lit->IsFalse()) {
1744 info = ALWAYS_FALSE; 1736 info = ALWAYS_FALSE;
1745 } 1737 }
1746 } 1738 }
1747 } 1739 }
1748 1740
1749 Label loop, entry; 1741 switch (node->type()) {
1742 case LoopStatement::DO_LOOP: {
1743 JumpTarget body(this);
1750 1744
1751 // init 1745 IncrementLoopNesting();
1752 if (node->init() != NULL) { 1746 // Label the body.
1753 ASSERT(node->type() == LoopStatement::FOR_LOOP); 1747 if (info == ALWAYS_TRUE) {
1754 Visit(node->init()); 1748 node->continue_target()->Bind();
1755 } 1749 } else if (info == ALWAYS_FALSE) {
1756 if (node->type() != LoopStatement::DO_LOOP && info != ALWAYS_TRUE) { 1750 // There is no need, we will never jump back.
1757 __ jmp(&entry); 1751 } else {
1758 } 1752 ASSERT(info == DONT_KNOW);
1753 body.Bind();
1754 }
1755 CheckStack(); // TODO(1222600): ignore if body contains calls.
1756 Visit(node->body());
1759 1757
1760 IncrementLoopNesting(); 1758 if (info == ALWAYS_TRUE) {
1759 if (frame_ != NULL) {
1760 // If control flow can fall off the end of the body, jump back to
1761 // the top.
1762 node->continue_target()->Jump();
1763 }
1764 } else if (info == ALWAYS_FALSE) {
1765 // If we have a continue in the body, we only have to bind its jump
1766 // target.
1767 if (node->continue_target()->is_linked()) {
1768 node->continue_target()->Bind();
1769 }
1770 } else {
1771 ASSERT(info == DONT_KNOW);
1772 // We have to compile the test expression if we don't know its value
1773 // and it can be reached by control flow falling out of the body or
1774 // via continue.
1775 if (frame_ != NULL || node->continue_target()->is_linked()) {
1776 node->continue_target()->Bind();
1777 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
1778 &body, node->break_target(), true);
1779 if (frame_ != NULL) {
1780 // A NULL frame here indicates that control flow did not fall
1781 // out of the test expression.
1782 Branch(true, &body);
1783 }
1784 }
1785 }
1786 break;
1787 }
1761 1788
1762 // body 1789 case LoopStatement::WHILE_LOOP: {
1763 __ bind(&loop);
1764 CheckStack(); // TODO(1222600): ignore if body contains calls.
1765 Visit(node->body());
1766 1790
1767 // next 1791 JumpTarget body(this);
1768 __ bind(node->continue_target());
1769 if (node->next() != NULL) {
1770 // Record source position of the statement as this code which is after the
1771 // code for the body actually belongs to the loop statement and not the
1772 // body.
1773 RecordStatementPosition(node);
1774 __ RecordPosition(node->statement_pos());
1775 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1776 Visit(node->next());
1777 }
1778 1792
1779 // cond 1793 IncrementLoopNesting();
1780 __ bind(&entry); 1794 // Generate the loop header.
1781 switch (info) { 1795 if (info == ALWAYS_TRUE) {
1782 case ALWAYS_TRUE: 1796 // Merely label the body with the continue target.
1783 __ jmp(&loop); 1797 node->continue_target()->Bind();
1798 } else if (info == ALWAYS_FALSE) {
1799 // There is no need to even compile the test or body.
1800 break;
1801 } else {
1802 // Compile the test labeled with the continue target and label the
1803 // body with the body target.
1804 ASSERT(info == DONT_KNOW);
1805 node->continue_target()->Bind();
1806 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
1807 &body, node->break_target(), true);
1808 if (frame_ != NULL) {
1809 // A NULL frame indicates that control did not fall out of the
1810 // test expression.
1811 Branch(false, node->break_target());
1812 }
1813 if (frame_ != NULL || body.is_linked()) {
1814 body.Bind();
1815 }
1816 }
1817 if (frame_ != NULL) {
1818 CheckStack(); // TODO(1222600): ignore if body contains calls.
1819 Visit(node->body());
1820
1821 // If control flow can fall out of the body, jump back to the top.
1822 if (frame_ != NULL) {
1823 node->continue_target()->Jump();
1824 }
1825 }
1784 break; 1826 break;
1785 case ALWAYS_FALSE: 1827 }
1828
1829 case LoopStatement::FOR_LOOP: {
1830 JumpTarget loop(this);
1831 JumpTarget body(this);
1832 if (node->init() != NULL) {
1833 Visit(node->init());
1834 }
1835
1836 IncrementLoopNesting();
1837 // There is no need to compile the test or body.
1838 if (info == ALWAYS_FALSE) break;
1839
1840 // If there is no update statement, label the top of the loop with the
1841 // continue target, otherwise with the loop target.
1842 if (node->next() == NULL) {
1843 node->continue_target()->Bind();
1844 } else {
1845 loop.Bind();
1846 }
1847
1848 // If the test is always true, there is no need to compile it.
1849 if (info == DONT_KNOW) {
1850 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF,
1851 &body, node->break_target(), true);
1852 if (frame_ != NULL) {
1853 Branch(false, node->break_target());
1854 }
1855 if (frame_ != NULL || body.is_linked()) {
1856 body.Bind();
1857 }
1858 }
1859
1860 if (frame_ != NULL) {
1861 CheckStack(); // TODO(1222600): ignore if body contains calls.
1862 Visit(node->body());
1863
1864 if (node->next() == NULL) {
1865 // If there is no update statement and control flow can fall out
1866 // of the loop, jump directly to the continue label.
1867 if (frame_ != NULL) {
1868 node->continue_target()->Jump();
1869 }
1870 } else {
1871 // If there is an update statement and control flow can reach it
1872 // via falling out of the body of the loop or continuing, we
1873 // compile the update statement.
1874 if (frame_ != NULL || node->continue_target()->is_linked()) {
1875 node->continue_target()->Bind();
1876 // Record source position of the statement as this code which is
1877 // after the code for the body actually belongs to the loop
1878 // statement and not the body.
1879 RecordStatementPosition(node);
1880 __ RecordPosition(node->statement_pos());
1881 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1882 Visit(node->next());
1883 loop.Jump();
1884 }
1885 }
1886 }
1786 break; 1887 break;
1787 case DONT_KNOW: 1888 }
1788 LoadCondition(node->cond(), NOT_INSIDE_TYPEOF, &loop,
1789 node->break_target(), true);
1790 Branch(true, &loop);
1791 break;
1792 } 1889 }
1793 1890
1794 DecrementLoopNesting(); 1891 DecrementLoopNesting();
1795 1892 if (node->break_target()->is_linked()) {
1796 // exit 1893 node->break_target()->Bind();
1797 __ bind(node->break_target()); 1894 }
1798 } 1895 }
1799 1896
1800 1897
1801 void CodeGenerator::VisitForInStatement(ForInStatement* node) { 1898 void CodeGenerator::VisitForInStatement(ForInStatement* node) {
1802 Comment cmnt(masm_, "[ ForInStatement"); 1899 Comment cmnt(masm_, "[ ForInStatement");
1803 RecordStatementPosition(node); 1900 RecordStatementPosition(node);
1804 1901
1805 // We keep stuff on the stack while the body is executing. 1902 // We keep stuff on the stack while the body is executing.
1806 // Record it, so that a break/continue crossing this statement 1903 // Record it, so that a break/continue crossing this statement
1807 // can restore the stack. 1904 // can restore the stack.
1808 const int kForInStackSize = 5 * kPointerSize; 1905 const int kForInStackSize = 5 * kPointerSize;
1809 break_stack_height_ += kForInStackSize; 1906 break_stack_height_ += kForInStackSize;
1810 node->set_break_stack_height(break_stack_height_); 1907 node->set_break_stack_height(break_stack_height_);
1908 node->break_target()->set_code_generator(this);
1909 node->continue_target()->set_code_generator(this);
1811 1910
1812 Label loop, next, entry, cleanup, exit, primitive, jsobject; 1911 JumpTarget entry(this);
1813 Label end_del_check, fixed_array; 1912 JumpTarget cleanup(this);
1913 JumpTarget exit(this);
1914 JumpTarget primitive(this);
1915 JumpTarget jsobject(this);
1916 JumpTarget end_del_check(this);
1917 JumpTarget fixed_array(this);
1814 1918
1815 // Get the object to enumerate over (converted to JSObject). 1919 // Get the object to enumerate over (converted to JSObject).
1816 Load(node->enumerable()); 1920 Load(node->enumerable());
1817 1921
1818 // Both SpiderMonkey and kjs ignore null and undefined in contrast 1922 // Both SpiderMonkey and kjs ignore null and undefined in contrast
1819 // to the specification. 12.6.4 mandates a call to ToObject. 1923 // to the specification. 12.6.4 mandates a call to ToObject.
1820 frame_->Pop(eax); 1924 frame_->Pop(eax);
1821 1925
1822 // eax: value to be iterated over 1926 // eax: value to be iterated over
1823 __ cmp(eax, Factory::undefined_value()); 1927 __ cmp(eax, Factory::undefined_value());
1824 __ j(equal, &exit); 1928 exit.Branch(equal);
1825 __ cmp(eax, Factory::null_value()); 1929 __ cmp(eax, Factory::null_value());
1826 __ j(equal, &exit); 1930 exit.Branch(equal);
1827 1931
1828 // Stack layout in body: 1932 // Stack layout in body:
1829 // [iteration counter (smi)] <- slot 0 1933 // [iteration counter (smi)] <- slot 0
1830 // [length of array] <- slot 1 1934 // [length of array] <- slot 1
1831 // [FixedArray] <- slot 2 1935 // [FixedArray] <- slot 2
1832 // [Map or 0] <- slot 3 1936 // [Map or 0] <- slot 3
1833 // [Object] <- slot 4 1937 // [Object] <- slot 4
1834 1938
1835 // Check if enumerable is already a JSObject 1939 // Check if enumerable is already a JSObject
1836 // eax: value to be iterated over 1940 // eax: value to be iterated over
1837 __ test(eax, Immediate(kSmiTagMask)); 1941 __ test(eax, Immediate(kSmiTagMask));
1838 __ j(zero, &primitive); 1942 primitive.Branch(zero);
1839 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 1943 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
1840 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 1944 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
1841 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 1945 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
1842 __ j(above_equal, &jsobject); 1946 jsobject.Branch(above_equal);
1843 1947
1844 __ bind(&primitive); 1948 primitive.Bind();
1845 frame_->Push(eax); 1949 frame_->Push(eax);
1846 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION); 1950 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION, 1);
1847 // function call returns the value in eax, which is where we want it below 1951 // function call returns the value in eax, which is where we want it below
1848 1952
1849 1953
1850 __ bind(&jsobject); 1954 jsobject.Bind();
1851 1955
1852 // Get the set of properties (as a FixedArray or Map). 1956 // Get the set of properties (as a FixedArray or Map).
1853 // eax: value to be iterated over 1957 // eax: value to be iterated over
1854 frame_->Push(eax); // push the object being iterated over (slot 4) 1958 frame_->Push(eax); // push the object being iterated over (slot 4)
1855 1959
1856 frame_->Push(eax); // push the Object (slot 4) for the runtime call 1960 frame_->Push(eax); // push the Object (slot 4) for the runtime call
1857 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1); 1961 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1858 1962
1859 // If we got a Map, we can do a fast modification check. 1963 // If we got a Map, we can do a fast modification check.
1860 // Otherwise, we got a FixedArray, and we have to do a slow check. 1964 // Otherwise, we got a FixedArray, and we have to do a slow check.
1861 // eax: map or fixed array (result from call to 1965 // eax: map or fixed array (result from call to
1862 // Runtime::kGetPropertyNamesFast) 1966 // Runtime::kGetPropertyNamesFast)
1863 __ mov(edx, Operand(eax)); 1967 __ mov(edx, Operand(eax));
1864 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 1968 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
1865 __ cmp(ecx, Factory::meta_map()); 1969 __ cmp(ecx, Factory::meta_map());
1866 __ j(not_equal, &fixed_array); 1970 fixed_array.Branch(not_equal);
1867 1971
1868 // Get enum cache 1972 // Get enum cache
1869 // eax: map (result from call to Runtime::kGetPropertyNamesFast) 1973 // eax: map (result from call to Runtime::kGetPropertyNamesFast)
1870 __ mov(ecx, Operand(eax)); 1974 __ mov(ecx, Operand(eax));
1871 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset)); 1975 __ mov(ecx, FieldOperand(ecx, Map::kInstanceDescriptorsOffset));
1872 // Get the bridge array held in the enumeration index field. 1976 // Get the bridge array held in the enumeration index field.
1873 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset)); 1977 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
1874 // Get the cache from the bridge array. 1978 // Get the cache from the bridge array.
1875 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset)); 1979 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1876 1980
1877 frame_->Push(eax); // <- slot 3 1981 frame_->Push(eax); // <- slot 3
1878 frame_->Push(edx); // <- slot 2 1982 frame_->Push(edx); // <- slot 2
1879 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset)); 1983 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
1880 __ shl(eax, kSmiTagSize); 1984 __ shl(eax, kSmiTagSize);
1881 frame_->Push(eax); // <- slot 1 1985 frame_->Push(eax); // <- slot 1
1882 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 1986 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0
1883 __ jmp(&entry); 1987 entry.Jump();
1884 1988
1885 1989
1886 __ bind(&fixed_array); 1990 fixed_array.Bind();
1887 1991
1888 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast) 1992 // eax: fixed array (result from call to Runtime::kGetPropertyNamesFast)
1889 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3 1993 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 3
1890 frame_->Push(eax); // <- slot 2 1994 frame_->Push(eax); // <- slot 2
1891 1995
1892 // Push the length of the array and the initial index onto the stack. 1996 // Push the length of the array and the initial index onto the stack.
1893 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset)); 1997 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
1894 __ shl(eax, kSmiTagSize); 1998 __ shl(eax, kSmiTagSize);
1895 frame_->Push(eax); // <- slot 1 1999 frame_->Push(eax); // <- slot 1
1896 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0 2000 frame_->Push(Immediate(Smi::FromInt(0))); // <- slot 0
1897 __ jmp(&entry);
1898
1899 // Body.
1900 __ bind(&loop);
1901 Visit(node->body());
1902
1903 // Next.
1904 __ bind(node->continue_target());
1905 __ bind(&next);
1906 frame_->Pop(eax);
1907 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
1908 frame_->Push(eax);
1909 2001
1910 // Condition. 2002 // Condition.
1911 __ bind(&entry); 2003 entry.Bind();
1912 2004
1913 __ mov(eax, frame_->Element(0)); // load the current count 2005 __ mov(eax, frame_->Element(0)); // load the current count
1914 __ cmp(eax, frame_->Element(1)); // compare to the array length 2006 __ cmp(eax, frame_->Element(1)); // compare to the array length
1915 __ j(above_equal, &cleanup); 2007 cleanup.Branch(above_equal);
1916 2008
1917 // Get the i'th entry of the array. 2009 // Get the i'th entry of the array.
1918 __ mov(edx, frame_->Element(2)); 2010 __ mov(edx, frame_->Element(2));
1919 __ mov(ebx, Operand(edx, eax, times_2, 2011 __ mov(ebx, Operand(edx, eax, times_2,
1920 FixedArray::kHeaderSize - kHeapObjectTag)); 2012 FixedArray::kHeaderSize - kHeapObjectTag));
1921 2013
1922 // Get the expected map from the stack or a zero map in the 2014 // Get the expected map from the stack or a zero map in the
1923 // permanent slow case eax: current iteration count ebx: i'th entry 2015 // permanent slow case eax: current iteration count ebx: i'th entry
1924 // of the enum cache 2016 // of the enum cache
1925 __ mov(edx, frame_->Element(3)); 2017 __ mov(edx, frame_->Element(3));
1926 // Check if the expected map still matches that of the enumerable. 2018 // Check if the expected map still matches that of the enumerable.
1927 // If not, we have to filter the key. 2019 // If not, we have to filter the key.
1928 // eax: current iteration count 2020 // eax: current iteration count
1929 // ebx: i'th entry of the enum cache 2021 // ebx: i'th entry of the enum cache
1930 // edx: expected map value 2022 // edx: expected map value
1931 __ mov(ecx, frame_->Element(4)); 2023 __ mov(ecx, frame_->Element(4));
1932 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset)); 2024 __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
1933 __ cmp(ecx, Operand(edx)); 2025 __ cmp(ecx, Operand(edx));
1934 __ j(equal, &end_del_check); 2026 end_del_check.Branch(equal);
1935 2027
1936 // Convert the entry to a string (or null if it isn't a property anymore). 2028 // Convert the entry to a string (or null if it isn't a property anymore).
1937 frame_->Push(frame_->Element(4)); // push enumerable 2029 frame_->Push(frame_->Element(4)); // push enumerable
1938 frame_->Push(ebx); // push entry 2030 frame_->Push(ebx); // push entry
1939 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION); 2031 frame_->InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION, 2);
1940 __ mov(ebx, Operand(eax)); 2032 __ mov(ebx, Operand(eax));
1941 2033
1942 // If the property has been removed while iterating, we just skip it. 2034 // If the property has been removed while iterating, we just skip it.
1943 __ cmp(ebx, Factory::null_value()); 2035 __ cmp(ebx, Factory::null_value());
1944 __ j(equal, &next); 2036 node->continue_target()->Branch(equal);
1945 2037
1946 2038 end_del_check.Bind();
1947 __ bind(&end_del_check);
1948
1949 // Store the entry in the 'each' expression and take another spin in the loop. 2039 // Store the entry in the 'each' expression and take another spin in the loop.
1950 // edx: i'th entry of the enum cache (or string there of) 2040 // edx: i'th entry of the enum cache (or string there of)
1951 frame_->Push(ebx); 2041 frame_->Push(ebx);
1952 { Reference each(this, node->each()); 2042 { Reference each(this, node->each());
1953 if (!each.is_illegal()) { 2043 if (!each.is_illegal()) {
1954 if (each.size() > 0) { 2044 if (each.size() > 0) {
1955 frame_->Push(frame_->Element(each.size())); 2045 frame_->Push(frame_->Element(each.size()));
1956 } 2046 }
1957 // If the reference was to a slot we rely on the convenient property 2047 // If the reference was to a slot we rely on the convenient property
1958 // that it doesn't matter whether a value (eg, ebx pushed above) is 2048 // that it doesn't matter whether a value (eg, ebx pushed above) is
1959 // right on top of or right underneath a zero-sized reference. 2049 // right on top of or right underneath a zero-sized reference.
1960 each.SetValue(NOT_CONST_INIT); 2050 each.SetValue(NOT_CONST_INIT);
1961 if (each.size() > 0) { 2051 if (each.size() > 0) {
1962 // It's safe to pop the value lying on top of the reference before 2052 // It's safe to pop the value lying on top of the reference before
1963 // unloading the reference itself (which preserves the top of stack, 2053 // unloading the reference itself (which preserves the top of stack,
1964 // ie, now the topmost value of the non-zero sized reference), since 2054 // ie, now the topmost value of the non-zero sized reference), since
1965 // we will discard the top of stack after unloading the reference 2055 // we will discard the top of stack after unloading the reference
1966 // anyway. 2056 // anyway.
1967 frame_->Pop(); 2057 frame_->Pop();
1968 } 2058 }
1969 } 2059 }
1970 } 2060 }
1971 // Discard the i'th entry pushed above or else the remainder of the 2061 // Discard the i'th entry pushed above or else the remainder of the
1972 // reference, whichever is currently on top of the stack. 2062 // reference, whichever is currently on top of the stack.
1973 frame_->Pop(); 2063 frame_->Pop();
2064
2065 // Body.
1974 CheckStack(); // TODO(1222600): ignore if body contains calls. 2066 CheckStack(); // TODO(1222600): ignore if body contains calls.
1975 __ jmp(&loop); 2067 Visit(node->body());
2068
2069 // Next.
2070 node->continue_target()->Bind();
2071 frame_->Pop(eax);
2072 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
2073 frame_->Push(eax);
2074 entry.Jump();
1976 2075
1977 // Cleanup. 2076 // Cleanup.
1978 __ bind(&cleanup); 2077 cleanup.Bind();
1979 __ bind(node->break_target()); 2078 node->break_target()->Bind();
1980 frame_->Drop(5); 2079 frame_->Drop(5);
1981 2080
1982 // Exit. 2081 // Exit.
1983 __ bind(&exit); 2082 exit.Bind();
1984 2083
1985 break_stack_height_ -= kForInStackSize; 2084 break_stack_height_ -= kForInStackSize;
1986 } 2085 }
1987 2086
1988 2087
1989 void CodeGenerator::VisitTryCatch(TryCatch* node) { 2088 void CodeGenerator::VisitTryCatch(TryCatch* node) {
1990 Comment cmnt(masm_, "[ TryCatch"); 2089 Comment cmnt(masm_, "[ TryCatch");
1991 2090
1992 Label try_block, exit; 2091 JumpTarget try_block(this);
2092 JumpTarget exit(this);
1993 2093
1994 __ call(&try_block); 2094 try_block.Call();
1995 // --- Catch block --- 2095 // --- Catch block ---
1996 frame_->Push(eax); 2096 frame_->Push(eax);
1997 2097
1998 // Store the caught exception in the catch variable. 2098 // Store the caught exception in the catch variable.
1999 { Reference ref(this, node->catch_var()); 2099 { Reference ref(this, node->catch_var());
2000 ASSERT(ref.is_slot()); 2100 ASSERT(ref.is_slot());
2001 // Load the exception to the top of the stack. Here we make use of the 2101 // Load the exception to the top of the stack. Here we make use of the
2002 // convenient property that it doesn't matter whether a value is 2102 // convenient property that it doesn't matter whether a value is
2003 // immediately on top of or underneath a zero-sized reference. 2103 // immediately on top of or underneath a zero-sized reference.
2004 ref.SetValue(NOT_CONST_INIT); 2104 ref.SetValue(NOT_CONST_INIT);
2005 } 2105 }
2006 2106
2007 // Remove the exception from the stack. 2107 // Remove the exception from the stack.
2008 frame_->Pop(); 2108 frame_->Pop();
2009 2109
2010 VisitStatements(node->catch_block()->statements()); 2110 VisitStatements(node->catch_block()->statements());
2011 __ jmp(&exit); 2111 if (frame_ != NULL) {
2112 exit.Jump();
2113 }
2012 2114
2013 2115
2014 // --- Try block --- 2116 // --- Try block ---
2015 __ bind(&try_block); 2117 try_block.Bind();
2016 2118
2017 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER); 2119 frame_->PushTryHandler(TRY_CATCH_HANDLER);
2018 // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS 2120 int handler_height = frame_->height();
2019 frame_->Push(eax); //
2020 2121
2021 // Shadow the labels for all escapes from the try block, including 2122 // Shadow the labels for all escapes from the try block, including
2022 // returns. During shadowing, the original label is hidden as the 2123 // returns. During shadowing, the original label is hidden as the
2023 // LabelShadow and operations on the original actually affect the 2124 // LabelShadow and operations on the original actually affect the
2024 // shadowing label. 2125 // shadowing label.
2025 // 2126 //
2026 // We should probably try to unify the escaping labels and the return 2127 // We should probably try to unify the escaping labels and the return
2027 // label. 2128 // label.
2028 int nof_escapes = node->escaping_labels()->length(); 2129 int nof_escapes = node->escaping_targets()->length();
2029 List<LabelShadow*> shadows(1 + nof_escapes); 2130 List<ShadowTarget*> shadows(1 + nof_escapes);
2030 shadows.Add(new LabelShadow(&function_return_)); 2131 shadows.Add(new ShadowTarget(&function_return_));
2031 for (int i = 0; i < nof_escapes; i++) { 2132 for (int i = 0; i < nof_escapes; i++) {
2032 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); 2133 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
2033 } 2134 }
2135 bool function_return_was_shadowed = function_return_is_shadowed_;
2136 function_return_is_shadowed_ = true;
2034 2137
2035 // Generate code for the statements in the try block. 2138 // Generate code for the statements in the try block.
2036 bool was_inside_try = is_inside_try_; 2139 bool was_inside_try = is_inside_try_;
2037 is_inside_try_ = true; 2140 is_inside_try_ = true;
2038 VisitStatements(node->try_block()->statements()); 2141 VisitStatements(node->try_block()->statements());
2039 is_inside_try_ = was_inside_try; 2142 is_inside_try_ = was_inside_try;
2040 2143
2041 // Stop the introduced shadowing and count the number of required unlinks. 2144 // Stop the introduced shadowing and count the number of required unlinks.
2042 // After shadowing stops, the original labels are unshadowed and the 2145 // After shadowing stops, the original labels are unshadowed and the
2043 // LabelShadows represent the formerly shadowing labels. 2146 // LabelShadows represent the formerly shadowing labels.
2044 int nof_unlinks = 0; 2147 int nof_unlinks = 0;
2045 for (int i = 0; i <= nof_escapes; i++) { 2148 for (int i = 0; i <= nof_escapes; i++) {
2046 shadows[i]->StopShadowing(); 2149 shadows[i]->StopShadowing();
2047 if (shadows[i]->is_linked()) nof_unlinks++; 2150 if (shadows[i]->is_linked()) nof_unlinks++;
2048 } 2151 }
2152 function_return_is_shadowed_ = function_return_was_shadowed;
2049 2153
2050 // Get an external reference to the handler address. 2154 // Get an external reference to the handler address.
2051 ExternalReference handler_address(Top::k_handler_address); 2155 ExternalReference handler_address(Top::k_handler_address);
2052 2156
2053 // Make sure that there's nothing left on the stack above the 2157 // Make sure that there's nothing left on the stack above the
2054 // handler structure. 2158 // handler structure.
2055 if (FLAG_debug_code) { 2159 if (FLAG_debug_code) {
2056 __ mov(eax, Operand::StaticVariable(handler_address)); 2160 __ mov(eax, Operand::StaticVariable(handler_address));
2057 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement)); 2161 __ lea(eax, Operand(eax, StackHandlerConstants::kAddressDisplacement));
2058 __ cmp(esp, Operand(eax)); 2162 __ cmp(esp, Operand(eax));
2059 __ Assert(equal, "stack pointer should point to top handler"); 2163 __ Assert(equal, "stack pointer should point to top handler");
2060 } 2164 }
2061 2165
2062 // Unlink from try chain. 2166 // If we can fall off the end of the try block, unlink from try chain.
2063 frame_->Pop(eax); 2167 if (frame_ != NULL) {
2064 __ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp 2168 frame_->Pop(eax);
2065 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2169 __ mov(Operand::StaticVariable(handler_address), eax); // TOS == next_sp
2066 // next_sp popped. 2170 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2067 if (nof_unlinks > 0) __ jmp(&exit); 2171 // next_sp popped.
2172 if (nof_unlinks > 0) {
2173 exit.Jump();
2174 }
2175 }
2068 2176
2069 // Generate unlink code for the (formerly) shadowing labels that have been 2177 // Generate unlink code for the (formerly) shadowing labels that have been
2070 // jumped to. 2178 // jumped to.
2071 for (int i = 0; i <= nof_escapes; i++) { 2179 for (int i = 0; i <= nof_escapes; i++) {
2072 if (shadows[i]->is_linked()) { 2180 if (shadows[i]->is_linked()) {
2073 // Unlink from try chain; be careful not to destroy the TOS. 2181 // Unlink from try chain; be careful not to destroy the TOS.
2074 __ bind(shadows[i]); 2182 shadows[i]->Bind();
2075 2183
2076 // Reload sp from the top handler, because some statements that we 2184 // Reload sp from the top handler, because some statements that we
2077 // break from (eg, for...in) may have left stuff on the stack. 2185 // break from (eg, for...in) may have left stuff on the stack.
2078 __ mov(edx, Operand::StaticVariable(handler_address)); 2186 __ mov(edx, Operand::StaticVariable(handler_address));
2079 const int kNextOffset = StackHandlerConstants::kNextOffset + 2187 const int kNextOffset = StackHandlerConstants::kNextOffset +
2080 StackHandlerConstants::kAddressDisplacement; 2188 StackHandlerConstants::kAddressDisplacement;
2081 __ lea(esp, Operand(edx, kNextOffset)); 2189 __ lea(esp, Operand(edx, kNextOffset));
2190 frame_->Forget(frame_->height() - handler_height);
2082 2191
2083 frame_->Pop(Operand::StaticVariable(handler_address)); 2192 frame_->Pop(Operand::StaticVariable(handler_address));
2084 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2193 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2085 // next_sp popped. 2194 // next_sp popped.
2086 __ jmp(shadows[i]->original_label()); 2195 JumpTarget* original_target = shadows[i]->original_target();
2196 original_target->Jump();
2087 } 2197 }
2088 } 2198 }
2089 2199
2090 __ bind(&exit); 2200 exit.Bind();
2091 } 2201 }
2092 2202
2093 2203
2094 void CodeGenerator::VisitTryFinally(TryFinally* node) { 2204 void CodeGenerator::VisitTryFinally(TryFinally* node) {
2095 Comment cmnt(masm_, "[ TryFinally"); 2205 Comment cmnt(masm_, "[ TryFinally");
2096 2206
2097 // State: Used to keep track of reason for entering the finally 2207 // State: Used to keep track of reason for entering the finally
2098 // block. Should probably be extended to hold information for 2208 // block. Should probably be extended to hold information for
2099 // break/continue from within the try block. 2209 // break/continue from within the try block.
2100 enum { FALLING, THROWING, JUMPING }; 2210 enum { FALLING, THROWING, JUMPING };
2101 2211
2102 Label exit, unlink, try_block, finally_block; 2212 JumpTarget exit(this);
2213 JumpTarget unlink(this);
2214 JumpTarget try_block(this);
2215 JumpTarget finally_block(this);
2103 2216
2104 __ call(&try_block); 2217 try_block.Call();
2105 2218
2106 frame_->Push(eax); 2219 frame_->Push(eax);
2107 // In case of thrown exceptions, this is where we continue. 2220 // In case of thrown exceptions, this is where we continue.
2108 __ Set(ecx, Immediate(Smi::FromInt(THROWING))); 2221 __ Set(ecx, Immediate(Smi::FromInt(THROWING)));
2109 __ jmp(&finally_block); 2222 finally_block.Jump();
2110 2223
2111 2224
2112 // --- Try block --- 2225 // --- Try block ---
2113 __ bind(&try_block); 2226 try_block.Bind();
2114 2227
2115 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER); 2228 frame_->PushTryHandler(TRY_FINALLY_HANDLER);
2116 // TODO(1222589): remove the reliance of PushTryHandler on a cached TOS 2229 int handler_height = frame_->height();
2117 frame_->Push(eax);
2118 2230
2119 // Shadow the labels for all escapes from the try block, including 2231 // Shadow the labels for all escapes from the try block, including
2120 // returns. During shadowing, the original label is hidden as the 2232 // returns. During shadowing, the original label is hidden as the
2121 // LabelShadow and operations on the original actually affect the 2233 // LabelShadow and operations on the original actually affect the
2122 // shadowing label. 2234 // shadowing label.
2123 // 2235 //
2124 // We should probably try to unify the escaping labels and the return 2236 // We should probably try to unify the escaping labels and the return
2125 // label. 2237 // label.
2126 int nof_escapes = node->escaping_labels()->length(); 2238 int nof_escapes = node->escaping_targets()->length();
2127 List<LabelShadow*> shadows(1 + nof_escapes); 2239 List<ShadowTarget*> shadows(1 + nof_escapes);
2128 shadows.Add(new LabelShadow(&function_return_)); 2240 shadows.Add(new ShadowTarget(&function_return_));
2129 for (int i = 0; i < nof_escapes; i++) { 2241 for (int i = 0; i < nof_escapes; i++) {
2130 shadows.Add(new LabelShadow(node->escaping_labels()->at(i))); 2242 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
2131 } 2243 }
2244 bool function_return_was_shadowed = function_return_is_shadowed_;
2245 function_return_is_shadowed_ = true;
2132 2246
2133 // Generate code for the statements in the try block. 2247 // Generate code for the statements in the try block.
2134 bool was_inside_try = is_inside_try_; 2248 bool was_inside_try = is_inside_try_;
2135 is_inside_try_ = true; 2249 is_inside_try_ = true;
2136 VisitStatements(node->try_block()->statements()); 2250 VisitStatements(node->try_block()->statements());
2137 is_inside_try_ = was_inside_try; 2251 is_inside_try_ = was_inside_try;
2138 2252
2139 // Stop the introduced shadowing and count the number of required unlinks. 2253 // Stop the introduced shadowing and count the number of required unlinks.
2140 // After shadowing stops, the original labels are unshadowed and the 2254 // After shadowing stops, the original labels are unshadowed and the
2141 // LabelShadows represent the formerly shadowing labels. 2255 // LabelShadows represent the formerly shadowing labels.
2142 int nof_unlinks = 0; 2256 int nof_unlinks = 0;
2143 for (int i = 0; i <= nof_escapes; i++) { 2257 for (int i = 0; i <= nof_escapes; i++) {
2144 shadows[i]->StopShadowing(); 2258 shadows[i]->StopShadowing();
2145 if (shadows[i]->is_linked()) nof_unlinks++; 2259 if (shadows[i]->is_linked()) nof_unlinks++;
2146 } 2260 }
2261 function_return_is_shadowed_ = function_return_was_shadowed;
2147 2262
2148 // Set the state on the stack to FALLING. 2263 // If we can fall off the end of the try block, set the state on the stack
2149 frame_->Push(Immediate(Factory::undefined_value())); // fake TOS 2264 // to FALLING.
2150 __ Set(ecx, Immediate(Smi::FromInt(FALLING))); 2265 if (frame_ != NULL) {
2151 if (nof_unlinks > 0) __ jmp(&unlink); 2266 frame_->Push(Immediate(Factory::undefined_value())); // fake TOS
2267 __ Set(ecx, Immediate(Smi::FromInt(FALLING)));
2268 if (nof_unlinks > 0) {
2269 unlink.Jump();
2270 }
2271 }
2152 2272
2153 // Generate code to set the state for the (formerly) shadowing labels that 2273 // Generate code to set the state for the (formerly) shadowing labels that
2154 // have been jumped to. 2274 // have been jumped to.
2155 for (int i = 0; i <= nof_escapes; i++) { 2275 for (int i = 0; i <= nof_escapes; i++) {
2156 if (shadows[i]->is_linked()) { 2276 if (shadows[i]->is_linked()) {
2157 __ bind(shadows[i]); 2277 shadows[i]->Bind();
2158 if (shadows[i]->original_label() == &function_return_) { 2278 if (shadows[i]->original_target() == &function_return_) {
2159 // If this label shadowed the function return, materialize the 2279 // If this label shadowed the function return, materialize the
2160 // return value on the stack. 2280 // return value on the stack.
2161 frame_->Push(eax); 2281 frame_->Push(eax);
2162 } else { 2282 } else {
2163 // Fake TOS for labels that shadowed breaks and continues. 2283 // Fake TOS for labels that shadowed breaks and continues.
2164 frame_->Push(Immediate(Factory::undefined_value())); 2284 frame_->Push(Immediate(Factory::undefined_value()));
2165 } 2285 }
2166 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i))); 2286 __ Set(ecx, Immediate(Smi::FromInt(JUMPING + i)));
2167 __ jmp(&unlink); 2287 unlink.Jump();
2168 } 2288 }
2169 } 2289 }
2170 2290
2171 // Unlink from try chain; be careful not to destroy the TOS. 2291 // Unlink from try chain; be careful not to destroy the TOS.
2172 __ bind(&unlink); 2292 unlink.Bind();
2173 // Reload sp from the top handler, because some statements that we 2293 // Reload sp from the top handler, because some statements that we
2174 // break from (eg, for...in) may have left stuff on the stack. 2294 // break from (eg, for...in) may have left stuff on the stack.
2175 // Preserve the TOS in a register across stack manipulation. 2295 // Preserve the TOS in a register across stack manipulation.
2176 frame_->Pop(eax); 2296 frame_->Pop(eax);
2177 ExternalReference handler_address(Top::k_handler_address); 2297 ExternalReference handler_address(Top::k_handler_address);
2178 __ mov(edx, Operand::StaticVariable(handler_address)); 2298 __ mov(edx, Operand::StaticVariable(handler_address));
2179 const int kNextOffset = StackHandlerConstants::kNextOffset + 2299 const int kNextOffset = StackHandlerConstants::kNextOffset +
2180 StackHandlerConstants::kAddressDisplacement; 2300 StackHandlerConstants::kAddressDisplacement;
2181 __ lea(esp, Operand(edx, kNextOffset)); 2301 __ lea(esp, Operand(edx, kNextOffset));
2302 frame_->Forget(frame_->height() - handler_height);
2182 2303
2183 frame_->Pop(Operand::StaticVariable(handler_address)); 2304 frame_->Pop(Operand::StaticVariable(handler_address));
2184 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1); 2305 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
2185 // Next_sp popped. 2306 // Next_sp popped.
2186 // Preserve the TOS in a register across stack manipulation. 2307 // Preserve the TOS in a register across stack manipulation.
2187 frame_->Push(eax); 2308 frame_->Push(eax);
2188 2309
2189 // --- Finally block --- 2310 // --- Finally block ---
2190 __ bind(&finally_block); 2311 finally_block.Bind();
2191 2312
2192 // Push the state on the stack. 2313 // Push the state on the stack.
2193 frame_->Push(ecx); 2314 frame_->Push(ecx);
2194 2315
2195 // We keep two elements on the stack - the (possibly faked) result 2316 // We keep two elements on the stack - the (possibly faked) result
2196 // and the state - while evaluating the finally block. Record it, so 2317 // and the state - while evaluating the finally block. Record it, so
2197 // that a break/continue crossing this statement can restore the 2318 // that a break/continue crossing this statement can restore the
2198 // stack. 2319 // stack.
2199 const int kFinallyStackSize = 2 * kPointerSize; 2320 const int kFinallyStackSize = 2 * kPointerSize;
2200 break_stack_height_ += kFinallyStackSize; 2321 break_stack_height_ += kFinallyStackSize;
2201 2322
2202 // Generate code for the statements in the finally block. 2323 // Generate code for the statements in the finally block.
2203 VisitStatements(node->finally_block()->statements()); 2324 VisitStatements(node->finally_block()->statements());
2204 2325
2205 // Restore state and return value or faked TOS.
2206 frame_->Pop(ecx);
2207 frame_->Pop(eax);
2208 break_stack_height_ -= kFinallyStackSize; 2326 break_stack_height_ -= kFinallyStackSize;
2327 if (frame_ != NULL) {
2328 // Restore state and return value or faked TOS.
2329 frame_->Pop(ecx);
2330 frame_->Pop(eax);
2209 2331
2210 // Generate code to jump to the right destination for all used (formerly) 2332 // Generate code to jump to the right destination for all used
2211 // shadowing labels. 2333 // (formerly) shadowing labels.
2212 for (int i = 0; i <= nof_escapes; i++) { 2334 for (int i = 0; i <= nof_escapes; i++) {
2213 if (shadows[i]->is_bound()) { 2335 if (shadows[i]->is_bound()) {
2214 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i))); 2336 __ cmp(Operand(ecx), Immediate(Smi::FromInt(JUMPING + i)));
2215 __ j(equal, shadows[i]->original_label()); 2337 shadows[i]->original_target()->Branch(equal);
2338 }
2216 } 2339 }
2340
2341 // Check if we need to rethrow the exception.
2342 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING)));
2343 exit.Branch(not_equal);
2344
2345 // Rethrow exception.
2346 frame_->Push(eax); // undo pop from above
2347 frame_->CallRuntime(Runtime::kReThrow, 1);
2348
2349 // Done.
2350 exit.Bind();
2217 } 2351 }
2218
2219 // Check if we need to rethrow the exception.
2220 __ cmp(Operand(ecx), Immediate(Smi::FromInt(THROWING)));
2221 __ j(not_equal, &exit);
2222
2223 // Rethrow exception.
2224 frame_->Push(eax); // undo pop from above
2225 __ CallRuntime(Runtime::kReThrow, 1);
2226
2227 // Done.
2228 __ bind(&exit);
2229 } 2352 }
2230 2353
2231 2354
2232 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) { 2355 void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
2233 Comment cmnt(masm_, "[ DebuggerStatement"); 2356 Comment cmnt(masm_, "[ DebuggerStatement");
2234 RecordStatementPosition(node); 2357 RecordStatementPosition(node);
2235 __ CallRuntime(Runtime::kDebugBreak, 0); 2358 frame_->CallRuntime(Runtime::kDebugBreak, 0);
2236 // Ignore the return value. 2359 // Ignore the return value.
2237 } 2360 }
2238 2361
2239 2362
2240 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) { 2363 void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
2241 ASSERT(boilerplate->IsBoilerplate()); 2364 ASSERT(boilerplate->IsBoilerplate());
2242 2365
2243 // Push the boilerplate on the stack. 2366 // Push the boilerplate on the stack.
2244 frame_->Push(Immediate(boilerplate)); 2367 frame_->Push(Immediate(boilerplate));
2245 2368
2246 // Create a new closure. 2369 // Create a new closure.
2247 frame_->Push(esi); 2370 frame_->Push(esi);
2248 __ CallRuntime(Runtime::kNewClosure, 2); 2371 frame_->CallRuntime(Runtime::kNewClosure, 2);
2249 frame_->Push(eax); 2372 frame_->Push(eax);
2250 } 2373 }
2251 2374
2252 2375
2253 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) { 2376 void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
2254 Comment cmnt(masm_, "[ FunctionLiteral"); 2377 Comment cmnt(masm_, "[ FunctionLiteral");
2255 2378
2256 // Build the function boilerplate and instantiate it. 2379 // Build the function boilerplate and instantiate it.
2257 Handle<JSFunction> boilerplate = BuildBoilerplate(node); 2380 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
2258 // Check for stack-overflow exception. 2381 // Check for stack-overflow exception.
2259 if (HasStackOverflow()) return; 2382 if (HasStackOverflow()) return;
2260 InstantiateBoilerplate(boilerplate); 2383 InstantiateBoilerplate(boilerplate);
2261 } 2384 }
2262 2385
2263 2386
2264 void CodeGenerator::VisitFunctionBoilerplateLiteral( 2387 void CodeGenerator::VisitFunctionBoilerplateLiteral(
2265 FunctionBoilerplateLiteral* node) { 2388 FunctionBoilerplateLiteral* node) {
2266 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral"); 2389 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
2267 InstantiateBoilerplate(node->boilerplate()); 2390 InstantiateBoilerplate(node->boilerplate());
2268 } 2391 }
2269 2392
2270 2393
2271 void CodeGenerator::VisitConditional(Conditional* node) { 2394 void CodeGenerator::VisitConditional(Conditional* node) {
2272 Comment cmnt(masm_, "[ Conditional"); 2395 Comment cmnt(masm_, "[ Conditional");
2273 Label then, else_, exit; 2396 JumpTarget then(this);
2397 JumpTarget else_(this);
2398 JumpTarget exit(this);
2274 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true); 2399 LoadCondition(node->condition(), NOT_INSIDE_TYPEOF, &then, &else_, true);
2275 Branch(false, &else_); 2400 if (frame_ != NULL) {
2276 __ bind(&then); 2401 Branch(false, &else_);
2277 Load(node->then_expression(), typeof_state()); 2402 }
2278 __ jmp(&exit); 2403 if (frame_ != NULL || then.is_linked()) {
2279 __ bind(&else_); 2404 then.Bind();
2280 Load(node->else_expression(), typeof_state()); 2405 Load(node->then_expression(), typeof_state());
2281 __ bind(&exit); 2406 exit.Jump();
2407 }
2408 if (else_.is_linked()) {
2409 else_.Bind();
2410 Load(node->else_expression(), typeof_state());
2411 }
2412 exit.Bind();
2282 } 2413 }
2283 2414
2284 2415
2285 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) { 2416 void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
2286 if (slot->type() == Slot::LOOKUP) { 2417 if (slot->type() == Slot::LOOKUP) {
2287 ASSERT(slot->var()->mode() == Variable::DYNAMIC); 2418 ASSERT(slot->var()->mode() == Variable::DYNAMIC);
2288 2419
2289 // For now, just do a runtime call. 2420 // For now, just do a runtime call.
2290 frame_->Push(esi); 2421 frame_->Push(esi);
2291 frame_->Push(Immediate(slot->var()->name())); 2422 frame_->Push(Immediate(slot->var()->name()));
2292 2423
2293 if (typeof_state == INSIDE_TYPEOF) { 2424 if (typeof_state == INSIDE_TYPEOF) {
2294 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2); 2425 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
2295 } else { 2426 } else {
2296 __ CallRuntime(Runtime::kLoadContextSlot, 2); 2427 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
2297 } 2428 }
2298 frame_->Push(eax); 2429 frame_->Push(eax);
2299 2430
2300 } else { 2431 } else {
2301 // Note: We would like to keep the assert below, but it fires because of 2432 // Note: We would like to keep the assert below, but it fires because of
2302 // some nasty code in LoadTypeofExpression() which should be removed... 2433 // some nasty code in LoadTypeofExpression() which should be removed...
2303 // ASSERT(slot->var()->mode() != Variable::DYNAMIC); 2434 // ASSERT(slot->var()->mode() != Variable::DYNAMIC);
2304 if (slot->var()->mode() == Variable::CONST) { 2435 if (slot->var()->mode() == Variable::CONST) {
2305 // Const slots may contain 'the hole' value (the constant hasn't been 2436 // Const slots may contain 'the hole' value (the constant hasn't been
2306 // initialized yet) which needs to be converted into the 'undefined' 2437 // initialized yet) which needs to be converted into the 'undefined'
2307 // value. 2438 // value.
2308 Comment cmnt(masm_, "[ Load const"); 2439 Comment cmnt(masm_, "[ Load const");
2309 Label exit; 2440 JumpTarget exit(this);
2310 __ mov(eax, SlotOperand(slot, ecx)); 2441 __ mov(eax, SlotOperand(slot, ecx));
2311 __ cmp(eax, Factory::the_hole_value()); 2442 __ cmp(eax, Factory::the_hole_value());
2312 __ j(not_equal, &exit); 2443 exit.Branch(not_equal);
2313 __ mov(eax, Factory::undefined_value()); 2444 __ mov(eax, Factory::undefined_value());
2314 __ bind(&exit); 2445 exit.Bind();
2315 frame_->Push(eax); 2446 frame_->Push(eax);
2316 } else { 2447 } else {
2317 frame_->Push(SlotOperand(slot, ecx)); 2448 frame_->Push(SlotOperand(slot, ecx));
2318 } 2449 }
2319 } 2450 }
2320 } 2451 }
2321 2452
2322 2453
2323 void CodeGenerator::VisitSlot(Slot* node) { 2454 void CodeGenerator::VisitSlot(Slot* node) {
2324 Comment cmnt(masm_, "[ Slot"); 2455 Comment cmnt(masm_, "[ Slot");
2325 LoadFromSlot(node, typeof_state()); 2456 LoadFromSlot(node, typeof_state());
2326 } 2457 }
2327 2458
2328 2459
2329 void CodeGenerator::VisitVariableProxy(VariableProxy* node) { 2460 void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
2330 Comment cmnt(masm_, "[ VariableProxy"); 2461 Comment cmnt(masm_, "[ VariableProxy");
2331 Variable* var = node->var(); 2462 Variable* var = node->var();
2332 Expression* expr = var->rewrite(); 2463 Expression* expr = var->rewrite();
2333 if (expr != NULL) { 2464 if (expr != NULL) {
2465 // We have to be wary of calling Visit directly on expressions. Because
2466 // of special casing comparisons of the form typeof<expr> === "string",
2467 // we can return from a call from Visit (to a comparison or a unary
2468 // operation) without a virtual frame; which will probably crash if we
2469 // try to emit frame code before reestablishing a frame. Here we're
2470 // safe as long as variable proxies can't rewrite into typeof
2471 // comparisons or unary logical not expressions.
2334 Visit(expr); 2472 Visit(expr);
2473 ASSERT(frame_ != NULL);
2335 } else { 2474 } else {
2336 ASSERT(var->is_global()); 2475 ASSERT(var->is_global());
2337 Reference ref(this, node); 2476 Reference ref(this, node);
2338 ref.GetValue(typeof_state()); 2477 ref.GetValue(typeof_state());
2339 } 2478 }
2340 } 2479 }
2341 2480
2342 2481
2343 void CodeGenerator::VisitLiteral(Literal* node) { 2482 void CodeGenerator::VisitLiteral(Literal* node) {
2344 Comment cmnt(masm_, "[ Literal"); 2483 Comment cmnt(masm_, "[ Literal");
(...skipping 16 matching lines...) Expand all
2361 : DeferredCode(generator), node_(node) { 2500 : DeferredCode(generator), node_(node) {
2362 set_comment("[ RegExpDeferred"); 2501 set_comment("[ RegExpDeferred");
2363 } 2502 }
2364 virtual void Generate(); 2503 virtual void Generate();
2365 private: 2504 private:
2366 RegExpLiteral* node_; 2505 RegExpLiteral* node_;
2367 }; 2506 };
2368 2507
2369 2508
2370 void RegExpDeferred::Generate() { 2509 void RegExpDeferred::Generate() {
2371 // If the entry is undefined we call the runtime system to computed 2510 // If the entry is undefined we call the runtime system to compute the
2372 // the literal. 2511 // literal.
2373 2512
2374 // Literal array (0). 2513 // Literal array (0).
2375 __ push(ecx); 2514 __ push(ecx);
2376 // Literal index (1). 2515 // Literal index (1).
2377 __ push(Immediate(Smi::FromInt(node_->literal_index()))); 2516 __ push(Immediate(Smi::FromInt(node_->literal_index())));
2378 // RegExp pattern (2). 2517 // RegExp pattern (2).
2379 __ push(Immediate(node_->pattern())); 2518 __ push(Immediate(node_->pattern()));
2380 // RegExp flags (3). 2519 // RegExp flags (3).
2381 __ push(Immediate(node_->flags())); 2520 __ push(Immediate(node_->flags()));
2382 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4); 2521 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
2463 2602
2464 // Check whether we need to materialize the object literal boilerplate. 2603 // Check whether we need to materialize the object literal boilerplate.
2465 // If so, jump to the deferred code. 2604 // If so, jump to the deferred code.
2466 __ cmp(ebx, Factory::undefined_value()); 2605 __ cmp(ebx, Factory::undefined_value());
2467 __ j(equal, deferred->enter(), not_taken); 2606 __ j(equal, deferred->enter(), not_taken);
2468 __ bind(deferred->exit()); 2607 __ bind(deferred->exit());
2469 2608
2470 // Push the literal. 2609 // Push the literal.
2471 frame_->Push(ebx); 2610 frame_->Push(ebx);
2472 // Clone the boilerplate object. 2611 // Clone the boilerplate object.
2473 __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1); 2612 frame_->CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
2474 // Push the new cloned literal object as the result. 2613 // Push the new cloned literal object as the result.
2475 frame_->Push(eax); 2614 frame_->Push(eax);
2476 2615
2477 2616
2478 for (int i = 0; i < node->properties()->length(); i++) { 2617 for (int i = 0; i < node->properties()->length(); i++) {
2479 ObjectLiteral::Property* property = node->properties()->at(i); 2618 ObjectLiteral::Property* property = node->properties()->at(i);
2480 switch (property->kind()) { 2619 switch (property->kind()) {
2481 case ObjectLiteral::Property::CONSTANT: break; 2620 case ObjectLiteral::Property::CONSTANT: break;
2482 case ObjectLiteral::Property::COMPUTED: { 2621 case ObjectLiteral::Property::COMPUTED: {
2483 Handle<Object> key(property->key()->handle()); 2622 Handle<Object> key(property->key()->handle());
2484 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 2623 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
2485 if (key->IsSymbol()) { 2624 if (key->IsSymbol()) {
2486 __ mov(eax, frame_->Top()); 2625 __ mov(eax, frame_->Top());
2487 frame_->Push(eax); 2626 frame_->Push(eax);
2488 Load(property->value()); 2627 Load(property->value());
2489 frame_->Pop(eax); 2628 frame_->Pop(eax);
2490 __ Set(ecx, Immediate(key)); 2629 __ Set(ecx, Immediate(key));
2491 __ call(ic, RelocInfo::CODE_TARGET); 2630 frame_->CallCode(ic, RelocInfo::CODE_TARGET, 0);
2492 frame_->Pop(); 2631 frame_->Pop();
2493 // Ignore result. 2632 // Ignore result.
2494 break; 2633 break;
2495 } 2634 }
2496 // Fall through 2635 // Fall through
2497 } 2636 }
2498 case ObjectLiteral::Property::PROTOTYPE: { 2637 case ObjectLiteral::Property::PROTOTYPE: {
2499 __ mov(eax, frame_->Top()); 2638 __ mov(eax, frame_->Top());
2500 frame_->Push(eax); 2639 frame_->Push(eax);
2501 Load(property->key()); 2640 Load(property->key());
2502 Load(property->value()); 2641 Load(property->value());
2503 __ CallRuntime(Runtime::kSetProperty, 3); 2642 frame_->CallRuntime(Runtime::kSetProperty, 3);
2504 // Ignore result. 2643 // Ignore result.
2505 break; 2644 break;
2506 } 2645 }
2507 case ObjectLiteral::Property::SETTER: { 2646 case ObjectLiteral::Property::SETTER: {
2508 // Duplicate the resulting object on the stack. The runtime 2647 // Duplicate the resulting object on the stack. The runtime
2509 // function will pop the three arguments passed in. 2648 // function will pop the three arguments passed in.
2510 __ mov(eax, frame_->Top()); 2649 __ mov(eax, frame_->Top());
2511 frame_->Push(eax); 2650 frame_->Push(eax);
2512 Load(property->key()); 2651 Load(property->key());
2513 frame_->Push(Immediate(Smi::FromInt(1))); 2652 frame_->Push(Immediate(Smi::FromInt(1)));
2514 Load(property->value()); 2653 Load(property->value());
2515 __ CallRuntime(Runtime::kDefineAccessor, 4); 2654 frame_->CallRuntime(Runtime::kDefineAccessor, 4);
2516 // Ignore result. 2655 // Ignore result.
2517 break; 2656 break;
2518 } 2657 }
2519 case ObjectLiteral::Property::GETTER: { 2658 case ObjectLiteral::Property::GETTER: {
2520 // Duplicate the resulting object on the stack. The runtime 2659 // Duplicate the resulting object on the stack. The runtime
2521 // function will pop the three arguments passed in. 2660 // function will pop the three arguments passed in.
2522 __ mov(eax, frame_->Top()); 2661 __ mov(eax, frame_->Top());
2523 frame_->Push(eax); 2662 frame_->Push(eax);
2524 Load(property->key()); 2663 Load(property->key());
2525 frame_->Push(Immediate(Smi::FromInt(0))); 2664 frame_->Push(Immediate(Smi::FromInt(0)));
2526 Load(property->value()); 2665 Load(property->value());
2527 __ CallRuntime(Runtime::kDefineAccessor, 4); 2666 frame_->CallRuntime(Runtime::kDefineAccessor, 4);
2528 // Ignore result. 2667 // Ignore result.
2529 break; 2668 break;
2530 } 2669 }
2531 default: UNREACHABLE(); 2670 default: UNREACHABLE();
2532 } 2671 }
2533 } 2672 }
2534 } 2673 }
2535 2674
2536 2675
2537 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) { 2676 void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
2538 Comment cmnt(masm_, "[ ArrayLiteral"); 2677 Comment cmnt(masm_, "[ ArrayLiteral");
2539 2678
2540 // Call runtime to create the array literal. 2679 // Call runtime to create the array literal.
2541 frame_->Push(Immediate(node->literals())); 2680 frame_->Push(Immediate(node->literals()));
2542 // Load the function of this frame. 2681 // Load the function of this frame.
2543 __ mov(ecx, frame_->Function()); 2682 __ mov(ecx, frame_->Function());
2544 // Load the literals array of the function. 2683 // Load the literals array of the function.
2545 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset)); 2684 __ mov(ecx, FieldOperand(ecx, JSFunction::kLiteralsOffset));
2546 frame_->Push(ecx); 2685 frame_->Push(ecx);
2547 __ CallRuntime(Runtime::kCreateArrayLiteral, 2); 2686 frame_->CallRuntime(Runtime::kCreateArrayLiteral, 2);
2548 2687
2549 // Push the resulting array literal on the stack. 2688 // Push the resulting array literal on the stack.
2550 frame_->Push(eax); 2689 frame_->Push(eax);
2551 2690
2552 // Generate code to set the elements in the array that are not 2691 // Generate code to set the elements in the array that are not
2553 // literals. 2692 // literals.
2554 for (int i = 0; i < node->values()->length(); i++) { 2693 for (int i = 0; i < node->values()->length(); i++) {
2555 Expression* value = node->values()->at(i); 2694 Expression* value = node->values()->at(i);
2556 2695
2557 // If value is literal the property value is already 2696 // If value is literal the property value is already
(...skipping 24 matching lines...) Expand all
2582 if (literal == NULL || !literal->handle()->IsSmi()) return false; 2721 if (literal == NULL || !literal->handle()->IsSmi()) return false;
2583 int int_value = Smi::cast(*literal->handle())->value(); 2722 int int_value = Smi::cast(*literal->handle())->value();
2584 return is_intn(int_value, kMaxSmiInlinedBits); 2723 return is_intn(int_value, kMaxSmiInlinedBits);
2585 } 2724 }
2586 2725
2587 2726
2588 void CodeGenerator::VisitAssignment(Assignment* node) { 2727 void CodeGenerator::VisitAssignment(Assignment* node) {
2589 Comment cmnt(masm_, "[ Assignment"); 2728 Comment cmnt(masm_, "[ Assignment");
2590 2729
2591 RecordStatementPosition(node); 2730 RecordStatementPosition(node);
2592 Reference target(this, node->target()); 2731 { Reference target(this, node->target());
2593 if (target.is_illegal()) return; 2732 if (target.is_illegal()) {
2733 // Fool the virtual frame into thinking that we left the assignment's
2734 // value on the frame.
2735 frame_->Push(Immediate(Smi::FromInt(0)));
2736 return;
2737 }
2594 2738
2595 if (node->op() == Token::ASSIGN || 2739 if (node->op() == Token::ASSIGN ||
2596 node->op() == Token::INIT_VAR || 2740 node->op() == Token::INIT_VAR ||
2597 node->op() == Token::INIT_CONST) { 2741 node->op() == Token::INIT_CONST) {
2598 Load(node->value()); 2742 Load(node->value());
2599 2743
2744 } else {
2745 target.GetValue(NOT_INSIDE_TYPEOF);
2746 Literal* literal = node->value()->AsLiteral();
2747 if (IsInlineSmi(literal)) {
2748 SmiOperation(node->binary_op(), node->type(), literal->handle(), false,
2749 NO_OVERWRITE);
2750 } else {
2751 Load(node->value());
2752 GenericBinaryOperation(node->binary_op(), node->type());
2753 }
2754 }
2755
2756 Variable* var = node->target()->AsVariableProxy()->AsVariable();
2757 if (var != NULL &&
2758 var->mode() == Variable::CONST &&
2759 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
2760 // Assignment ignored - leave the value on the stack.
2600 } else { 2761 } else {
2601 target.GetValue(NOT_INSIDE_TYPEOF); 2762 __ RecordPosition(node->position());
2602 Literal* literal = node->value()->AsLiteral(); 2763 if (node->op() == Token::INIT_CONST) {
2603 if (IsInlineSmi(literal)) { 2764 // Dynamic constant initializations must use the function context
2604 SmiOperation(node->binary_op(), node->type(), literal->handle(), false, 2765 // and initialize the actual constant declared. Dynamic variable
2605 NO_OVERWRITE); 2766 // initializations are simply assignments and use SetValue.
2606 } else { 2767 target.SetValue(CONST_INIT);
2607 Load(node->value()); 2768 } else {
2608 GenericBinaryOperation(node->binary_op(), node->type()); 2769 target.SetValue(NOT_CONST_INIT);
2609 } 2770 }
2610 }
2611
2612 Variable* var = node->target()->AsVariableProxy()->AsVariable();
2613 if (var != NULL &&
2614 var->mode() == Variable::CONST &&
2615 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
2616 // Assignment ignored - leave the value on the stack.
2617 } else {
2618 __ RecordPosition(node->position());
2619 if (node->op() == Token::INIT_CONST) {
2620 // Dynamic constant initializations must use the function context
2621 // and initialize the actual constant declared. Dynamic variable
2622 // initializations are simply assignments and use SetValue.
2623 target.SetValue(CONST_INIT);
2624 } else {
2625 target.SetValue(NOT_CONST_INIT);
2626 } 2771 }
2627 } 2772 }
2628 } 2773 }
2629 2774
2630 2775
2631 void CodeGenerator::VisitThrow(Throw* node) { 2776 void CodeGenerator::VisitThrow(Throw* node) {
2632 Comment cmnt(masm_, "[ Throw"); 2777 Comment cmnt(masm_, "[ Throw");
2633 2778
2634 Load(node->exception()); 2779 Load(node->exception());
2635 __ RecordPosition(node->position()); 2780 __ RecordPosition(node->position());
2636 __ CallRuntime(Runtime::kThrow, 1); 2781 frame_->CallRuntime(Runtime::kThrow, 1);
2637 frame_->Push(eax); 2782 frame_->Push(eax);
2638 } 2783 }
2639 2784
2640 2785
2641 void CodeGenerator::VisitProperty(Property* node) { 2786 void CodeGenerator::VisitProperty(Property* node) {
2642 Comment cmnt(masm_, "[ Property"); 2787 Comment cmnt(masm_, "[ Property");
2643
2644 Reference property(this, node); 2788 Reference property(this, node);
2645 property.GetValue(typeof_state()); 2789 property.GetValue(typeof_state());
2646 } 2790 }
2647 2791
2648 2792
2649 void CodeGenerator::VisitCall(Call* node) { 2793 void CodeGenerator::VisitCall(Call* node) {
2650 Comment cmnt(masm_, "[ Call"); 2794 Comment cmnt(masm_, "[ Call");
2651 2795
2652 ZoneList<Expression*>* args = node->arguments(); 2796 ZoneList<Expression*>* args = node->arguments();
2653 2797
(...skipping 27 matching lines...) Expand all
2681 LoadGlobal(); 2825 LoadGlobal();
2682 2826
2683 // Load the arguments. 2827 // Load the arguments.
2684 for (int i = 0; i < args->length(); i++) { 2828 for (int i = 0; i < args->length(); i++) {
2685 Load(args->at(i)); 2829 Load(args->at(i));
2686 } 2830 }
2687 2831
2688 // Setup the receiver register and call the IC initialization code. 2832 // Setup the receiver register and call the IC initialization code.
2689 Handle<Code> stub = ComputeCallInitialize(args->length()); 2833 Handle<Code> stub = ComputeCallInitialize(args->length());
2690 __ RecordPosition(node->position()); 2834 __ RecordPosition(node->position());
2691 __ call(stub, RelocInfo::CODE_TARGET_CONTEXT); 2835 frame_->CallCode(stub, RelocInfo::CODE_TARGET_CONTEXT, args->length() + 1);
2692 __ mov(esi, frame_->Context()); 2836 __ mov(esi, frame_->Context());
2693 2837
2694 // Overwrite the function on the stack with the result. 2838 // Overwrite the function on the stack with the result.
2695 __ mov(frame_->Top(), eax); 2839 __ mov(frame_->Top(), eax);
2696 2840
2697 } else if (var != NULL && var->slot() != NULL && 2841 } else if (var != NULL && var->slot() != NULL &&
2698 var->slot()->type() == Slot::LOOKUP) { 2842 var->slot()->type() == Slot::LOOKUP) {
2699 // ---------------------------------- 2843 // ----------------------------------
2700 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj 2844 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
2701 // ---------------------------------- 2845 // ----------------------------------
2702 2846
2703 // Load the function 2847 // Load the function
2704 frame_->Push(esi); 2848 frame_->Push(esi);
2705 frame_->Push(Immediate(var->name())); 2849 frame_->Push(Immediate(var->name()));
2706 __ CallRuntime(Runtime::kLoadContextSlot, 2); 2850 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
2707 // eax: slot value; edx: receiver 2851 // eax: slot value; edx: receiver
2708 2852
2709 // Load the receiver. 2853 // Load the receiver.
2710 frame_->Push(eax); 2854 frame_->Push(eax);
2711 frame_->Push(edx); 2855 frame_->Push(edx);
2712 2856
2713 // Call the function. 2857 // Call the function.
2714 CallWithArguments(args, node->position()); 2858 CallWithArguments(args, node->position());
2715 2859
2716 } else if (property != NULL) { 2860 } else if (property != NULL) {
2717 // Check if the key is a literal string. 2861 // Check if the key is a literal string.
2718 Literal* literal = property->key()->AsLiteral(); 2862 Literal* literal = property->key()->AsLiteral();
2719 2863
2720 if (literal != NULL && literal->handle()->IsSymbol()) { 2864 if (literal != NULL && literal->handle()->IsSymbol()) {
2721 // ------------------------------------------------------------------ 2865 // ------------------------------------------------------------------
2722 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)' 2866 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
2723 // ------------------------------------------------------------------ 2867 // ------------------------------------------------------------------
2724 2868
2725 // Push the name of the function and the receiver onto the stack. 2869 // Push the name of the function and the receiver onto the stack.
2726 frame_->Push(Immediate(literal->handle())); 2870 frame_->Push(Immediate(literal->handle()));
2727 Load(property->obj()); 2871 Load(property->obj());
2728 2872
2729 // Load the arguments. 2873 // Load the arguments.
2730 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2874 for (int i = 0; i < args->length(); i++) Load(args->at(i));
2731 2875
2732 // Call the IC initialization code. 2876 // Call the IC initialization code.
2733 Handle<Code> stub = ComputeCallInitialize(args->length()); 2877 Handle<Code> stub = ComputeCallInitialize(args->length());
2734 __ RecordPosition(node->position()); 2878 __ RecordPosition(node->position());
2735 __ call(stub, RelocInfo::CODE_TARGET); 2879 frame_->CallCode(stub, RelocInfo::CODE_TARGET, args->length() + 1);
2736 __ mov(esi, frame_->Context()); 2880 __ mov(esi, frame_->Context());
2737 2881
2738 // Overwrite the function on the stack with the result. 2882 // Overwrite the function on the stack with the result.
2739 __ mov(frame_->Top(), eax); 2883 __ mov(frame_->Top(), eax);
2740 2884
2741 } else { 2885 } else {
2742 // ------------------------------------------- 2886 // -------------------------------------------
2743 // JavaScript example: 'array[index](1, 2, 3)' 2887 // JavaScript example: 'array[index](1, 2, 3)'
2744 // ------------------------------------------- 2888 // -------------------------------------------
2745 2889
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
2782 // evaluated. 2926 // evaluated.
2783 2927
2784 // Compute function to call and use the global object as the 2928 // Compute function to call and use the global object as the
2785 // receiver. There is no need to use the global proxy here because 2929 // receiver. There is no need to use the global proxy here because
2786 // it will always be replaced with a newly allocated object. 2930 // it will always be replaced with a newly allocated object.
2787 Load(node->expression()); 2931 Load(node->expression());
2788 LoadGlobal(); 2932 LoadGlobal();
2789 2933
2790 // Push the arguments ("left-to-right") on the stack. 2934 // Push the arguments ("left-to-right") on the stack.
2791 ZoneList<Expression*>* args = node->arguments(); 2935 ZoneList<Expression*>* args = node->arguments();
2792 for (int i = 0; i < args->length(); i++) Load(args->at(i)); 2936 for (int i = 0; i < args->length(); i++) {
2937 Load(args->at(i));
2938 }
2793 2939
2794 // Constructors are called with the number of arguments in register 2940 // Constructors are called with the number of arguments in register
2795 // eax for now. Another option would be to have separate construct 2941 // eax for now. Another option would be to have separate construct
2796 // call trampolines per different arguments counts encountered. 2942 // call trampolines per different arguments counts encountered.
2797 __ Set(eax, Immediate(args->length())); 2943 __ Set(eax, Immediate(args->length()));
2798 2944
2799 // Load the function into temporary function slot as per calling 2945 // Load the function into temporary function slot as per calling
2800 // convention. 2946 // convention.
2801 __ mov(edi, frame_->Element(args->length() + 1)); 2947 __ mov(edi, frame_->Element(args->length() + 1));
2802 2948
2803 // Call the construct call builtin that handles allocation and 2949 // Call the construct call builtin that handles allocation and
2804 // constructor invocation. 2950 // constructor invocation.
2805 __ RecordPosition(node->position()); 2951 __ RecordPosition(node->position());
2806 __ call(Handle<Code>(Builtins::builtin(Builtins::JSConstructCall)), 2952 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
2807 RelocInfo::CONSTRUCT_CALL); 2953 frame_->CallCode(ic, RelocInfo::CONSTRUCT_CALL, args->length() + 1);
2808 // Discard the function and "push" the newly created object. 2954 // Discard the function and "push" the newly created object.
2809 __ mov(frame_->Top(), eax); 2955 __ mov(frame_->Top(), eax);
2810 } 2956 }
2811 2957
2812 2958
2813 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) { 2959 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
2814 ASSERT(args->length() == 1); 2960 ASSERT(args->length() == 1);
2815 Load(args->at(0)); 2961 Load(args->at(0));
2816 frame_->Pop(eax); 2962 frame_->Pop(eax);
2817 __ test(eax, Immediate(kSmiTagMask)); 2963 __ test(eax, Immediate(kSmiTagMask));
(...skipping 12 matching lines...) Expand all
2830 2976
2831 // This generates code that performs a charCodeAt() call or returns 2977 // This generates code that performs a charCodeAt() call or returns
2832 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt. 2978 // undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
2833 // It can handle flat and sliced strings, 8 and 16 bit characters and 2979 // It can handle flat and sliced strings, 8 and 16 bit characters and
2834 // cons strings where the answer is found in the left hand branch of the 2980 // cons strings where the answer is found in the left hand branch of the
2835 // cons. The slow case will flatten the string, which will ensure that 2981 // cons. The slow case will flatten the string, which will ensure that
2836 // the answer is in the left hand side the next time around. 2982 // the answer is in the left hand side the next time around.
2837 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) { 2983 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
2838 ASSERT(args->length() == 2); 2984 ASSERT(args->length() == 2);
2839 2985
2840 Label slow_case; 2986 JumpTarget slow_case(this);
2841 Label end; 2987 JumpTarget end(this);
2842 Label not_a_flat_string; 2988 JumpTarget not_a_flat_string(this);
2843 Label not_a_cons_string_either; 2989 JumpTarget not_a_cons_string_either(this);
2844 Label try_again_with_new_string; 2990 JumpTarget try_again_with_new_string(this);
2845 Label ascii_string; 2991 JumpTarget ascii_string(this);
2846 Label got_char_code; 2992 JumpTarget got_char_code(this);
2847 2993
2848 // Load the string into eax. 2994 // Load the string into eax.
2849 Load(args->at(0)); 2995 Load(args->at(0));
2850 frame_->Pop(eax); 2996 frame_->Pop(eax);
2851 // If the receiver is a smi return undefined. 2997 // If the receiver is a smi return undefined.
2852 ASSERT(kSmiTag == 0); 2998 ASSERT(kSmiTag == 0);
2853 __ test(eax, Immediate(kSmiTagMask)); 2999 __ test(eax, Immediate(kSmiTagMask));
2854 __ j(zero, &slow_case, not_taken); 3000 slow_case.Branch(zero, not_taken);
2855 3001
2856 // Load the index into ebx. 3002 // Load the index into ebx.
2857 Load(args->at(1)); 3003 Load(args->at(1));
2858 frame_->Pop(ebx); 3004 frame_->Pop(ebx);
2859 3005
2860 // Check for negative or non-smi index. 3006 // Check for negative or non-smi index.
2861 ASSERT(kSmiTag == 0); 3007 ASSERT(kSmiTag == 0);
2862 __ test(ebx, Immediate(kSmiTagMask | 0x80000000)); 3008 __ test(ebx, Immediate(kSmiTagMask | 0x80000000));
2863 __ j(not_zero, &slow_case, not_taken); 3009 slow_case.Branch(not_zero, not_taken);
2864 // Get rid of the smi tag on the index. 3010 // Get rid of the smi tag on the index.
2865 __ sar(ebx, kSmiTagSize); 3011 __ sar(ebx, kSmiTagSize);
2866 3012
2867 __ bind(&try_again_with_new_string); 3013 try_again_with_new_string.Bind();
2868 // Get the type of the heap object into edi. 3014 // Get the type of the heap object into edi.
2869 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 3015 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
2870 __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset)); 3016 __ movzx_b(edi, FieldOperand(edx, Map::kInstanceTypeOffset));
2871 // We don't handle non-strings. 3017 // We don't handle non-strings.
2872 __ test(edi, Immediate(kIsNotStringMask)); 3018 __ test(edi, Immediate(kIsNotStringMask));
2873 __ j(not_zero, &slow_case, not_taken); 3019 slow_case.Branch(not_zero, not_taken);
2874 3020
2875 // Here we make assumptions about the tag values and the shifts needed. 3021 // Here we make assumptions about the tag values and the shifts needed.
2876 // See the comment in objects.h. 3022 // See the comment in objects.h.
2877 ASSERT(kLongStringTag == 0); 3023 ASSERT(kLongStringTag == 0);
2878 ASSERT(kMediumStringTag + String::kLongLengthShift == 3024 ASSERT(kMediumStringTag + String::kLongLengthShift ==
2879 String::kMediumLengthShift); 3025 String::kMediumLengthShift);
2880 ASSERT(kShortStringTag + String::kLongLengthShift == 3026 ASSERT(kShortStringTag + String::kLongLengthShift ==
2881 String::kShortLengthShift); 3027 String::kShortLengthShift);
2882 __ mov(ecx, Operand(edi)); 3028 __ mov(ecx, Operand(edi));
2883 __ and_(ecx, kStringSizeMask); 3029 __ and_(ecx, kStringSizeMask);
2884 __ add(Operand(ecx), Immediate(String::kLongLengthShift)); 3030 __ add(Operand(ecx), Immediate(String::kLongLengthShift));
2885 // Get the length field. 3031 // Get the length field.
2886 __ mov(edx, FieldOperand(eax, String::kLengthOffset)); 3032 __ mov(edx, FieldOperand(eax, String::kLengthOffset));
2887 __ shr(edx); // ecx is implicit operand. 3033 __ shr(edx); // ecx is implicit operand.
2888 // edx is now the length of the string. 3034 // edx is now the length of the string.
2889 3035
2890 // Check for index out of range. 3036 // Check for index out of range.
2891 __ cmp(ebx, Operand(edx)); 3037 __ cmp(ebx, Operand(edx));
2892 __ j(greater_equal, &slow_case, not_taken); 3038 slow_case.Branch(greater_equal, not_taken);
2893 3039
2894 // We need special handling for non-flat strings. 3040 // We need special handling for non-flat strings.
2895 ASSERT(kSeqStringTag == 0); 3041 ASSERT(kSeqStringTag == 0);
2896 __ test(edi, Immediate(kStringRepresentationMask)); 3042 __ test(edi, Immediate(kStringRepresentationMask));
2897 __ j(not_zero, &not_a_flat_string, not_taken); 3043 not_a_flat_string.Branch(not_zero, not_taken);
2898 3044
2899 // Check for 1-byte or 2-byte string. 3045 // Check for 1-byte or 2-byte string.
2900 __ test(edi, Immediate(kStringEncodingMask)); 3046 __ test(edi, Immediate(kStringEncodingMask));
2901 __ j(not_zero, &ascii_string, taken); 3047 ascii_string.Branch(not_zero, taken);
2902 3048
2903 // 2-byte string. 3049 // 2-byte string.
2904 // Load the 2-byte character code. 3050 // Load the 2-byte character code.
2905 __ movzx_w(eax, 3051 __ movzx_w(eax,
2906 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize)); 3052 FieldOperand(eax, ebx, times_2, SeqTwoByteString::kHeaderSize));
2907 __ jmp(&got_char_code); 3053 got_char_code.Jump();
2908 3054
2909 // ASCII string. 3055 // ASCII string.
2910 __ bind(&ascii_string); 3056 ascii_string.Bind();
2911 // Load the byte. 3057 // Load the byte.
2912 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize)); 3058 __ movzx_b(eax, FieldOperand(eax, ebx, times_1, SeqAsciiString::kHeaderSize));
2913 3059
2914 __ bind(&got_char_code); 3060 got_char_code.Bind();
2915 ASSERT(kSmiTag == 0); 3061 ASSERT(kSmiTag == 0);
2916 __ shl(eax, kSmiTagSize); 3062 __ shl(eax, kSmiTagSize);
2917 frame_->Push(eax); 3063 frame_->Push(eax);
2918 __ jmp(&end); 3064 end.Jump();
2919 3065
2920 // Handle non-flat strings. 3066 // Handle non-flat strings.
2921 __ bind(&not_a_flat_string); 3067 not_a_flat_string.Bind();
2922 __ and_(edi, kStringRepresentationMask); 3068 __ and_(edi, kStringRepresentationMask);
2923 __ cmp(edi, kConsStringTag); 3069 __ cmp(edi, kConsStringTag);
2924 __ j(not_equal, &not_a_cons_string_either, not_taken); 3070 not_a_cons_string_either.Branch(not_equal, not_taken);
2925 3071
2926 // ConsString. 3072 // ConsString.
2927 // Get the first of the two strings. 3073 // Get the first of the two strings.
2928 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset)); 3074 __ mov(eax, FieldOperand(eax, ConsString::kFirstOffset));
2929 __ jmp(&try_again_with_new_string); 3075 try_again_with_new_string.Jump();
2930 3076
2931 __ bind(&not_a_cons_string_either); 3077 not_a_cons_string_either.Bind();
2932 __ cmp(edi, kSlicedStringTag); 3078 __ cmp(edi, kSlicedStringTag);
2933 __ j(not_equal, &slow_case, not_taken); 3079 slow_case.Branch(not_equal, not_taken);
2934 3080
2935 // SlicedString. 3081 // SlicedString.
2936 // Add the offset to the index. 3082 // Add the offset to the index.
2937 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset)); 3083 __ add(ebx, FieldOperand(eax, SlicedString::kStartOffset));
2938 __ j(overflow, &slow_case); 3084 slow_case.Branch(overflow);
2939 // Get the underlying string. 3085 // Get the underlying string.
2940 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset)); 3086 __ mov(eax, FieldOperand(eax, SlicedString::kBufferOffset));
2941 __ jmp(&try_again_with_new_string); 3087 try_again_with_new_string.Jump();
2942 3088
2943 __ bind(&slow_case); 3089 slow_case.Bind();
2944 frame_->Push(Immediate(Factory::undefined_value())); 3090 frame_->Push(Immediate(Factory::undefined_value()));
2945 3091
2946 __ bind(&end); 3092 end.Bind();
2947 } 3093 }
2948 3094
2949 3095
2950 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) { 3096 void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
2951 ASSERT(args->length() == 1); 3097 ASSERT(args->length() == 1);
2952 Load(args->at(0)); 3098 Load(args->at(0));
2953 Label answer; 3099 JumpTarget answer(this);
2954 // We need the CC bits to come out as not_equal in the case where the 3100 // We need the CC bits to come out as not_equal in the case where the
2955 // object is a smi. This can't be done with the usual test opcode so 3101 // object is a smi. This can't be done with the usual test opcode so
2956 // we copy the object to ecx and do some destructive ops on it that 3102 // we copy the object to ecx and do some destructive ops on it that
2957 // result in the right CC bits. 3103 // result in the right CC bits.
2958 frame_->Pop(eax); 3104 frame_->Pop(eax);
2959 __ mov(ecx, Operand(eax)); 3105 __ mov(ecx, Operand(eax));
2960 __ and_(ecx, kSmiTagMask); 3106 __ and_(ecx, kSmiTagMask);
2961 __ xor_(ecx, kSmiTagMask); 3107 __ xor_(ecx, kSmiTagMask);
2962 __ j(not_equal, &answer, not_taken); 3108 answer.Branch(not_equal, not_taken);
2963 // It is a heap object - get map. 3109 // It is a heap object - get map.
2964 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset)); 3110 __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
2965 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset)); 3111 __ movzx_b(eax, FieldOperand(eax, Map::kInstanceTypeOffset));
2966 // Check if the object is a JS array or not. 3112 // Check if the object is a JS array or not.
2967 __ cmp(eax, JS_ARRAY_TYPE); 3113 __ cmp(eax, JS_ARRAY_TYPE);
2968 __ bind(&answer); 3114 answer.Bind();
2969 cc_reg_ = equal; 3115 cc_reg_ = equal;
2970 } 3116 }
2971 3117
2972 3118
2973 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) { 3119 void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
2974 ASSERT(args->length() == 0); 3120 ASSERT(args->length() == 0);
2975 3121
2976 // Seed the result with the formal parameters count, which will be 3122 // Seed the result with the formal parameters count, which will be
2977 // used in case no arguments adaptor frame is found below the 3123 // used in case no arguments adaptor frame is found below the
2978 // current frame. 3124 // current frame.
2979 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); 3125 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters())));
2980 3126
2981 // Call the shared stub to get to the arguments.length. 3127 // Call the shared stub to get to the arguments.length.
2982 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH); 3128 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
2983 __ CallStub(&stub); 3129 frame_->CallStub(&stub, 0);
2984 frame_->Push(eax); 3130 frame_->Push(eax);
2985 } 3131 }
2986 3132
2987 3133
2988 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) { 3134 void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
2989 ASSERT(args->length() == 1); 3135 ASSERT(args->length() == 1);
2990 Label leave; 3136 JumpTarget leave(this);
2991 Load(args->at(0)); // Load the object. 3137 Load(args->at(0)); // Load the object.
2992 __ mov(eax, frame_->Top()); 3138 __ mov(eax, frame_->Top());
2993 // if (object->IsSmi()) return object. 3139 // if (object->IsSmi()) return object.
2994 __ test(eax, Immediate(kSmiTagMask)); 3140 __ test(eax, Immediate(kSmiTagMask));
2995 __ j(zero, &leave, taken); 3141 leave.Branch(zero, taken);
2996 // It is a heap object - get map. 3142 // It is a heap object - get map.
2997 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset)); 3143 __ mov(ecx, FieldOperand(eax, HeapObject::kMapOffset));
2998 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 3144 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
2999 // if (!object->IsJSValue()) return object. 3145 // if (!object->IsJSValue()) return object.
3000 __ cmp(ecx, JS_VALUE_TYPE); 3146 __ cmp(ecx, JS_VALUE_TYPE);
3001 __ j(not_equal, &leave, not_taken); 3147 leave.Branch(not_equal, not_taken);
3002 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset)); 3148 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3003 __ mov(frame_->Top(), eax); 3149 __ mov(frame_->Top(), eax);
3004 __ bind(&leave); 3150 leave.Bind();
3005 } 3151 }
3006 3152
3007 3153
3008 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) { 3154 void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
3009 ASSERT(args->length() == 2); 3155 ASSERT(args->length() == 2);
3010 Label leave; 3156 JumpTarget leave(this);
3011 Load(args->at(0)); // Load the object. 3157 Load(args->at(0)); // Load the object.
3012 Load(args->at(1)); // Load the value. 3158 Load(args->at(1)); // Load the value.
3013 __ mov(eax, frame_->Element(1)); 3159 __ mov(eax, frame_->Element(1));
3014 __ mov(ecx, frame_->Top()); 3160 __ mov(ecx, frame_->Top());
3015 // if (object->IsSmi()) return object. 3161 // if (object->IsSmi()) return object.
3016 __ test(eax, Immediate(kSmiTagMask)); 3162 __ test(eax, Immediate(kSmiTagMask));
3017 __ j(zero, &leave, taken); 3163 leave.Branch(zero, taken);
3018 // It is a heap object - get map. 3164 // It is a heap object - get map.
3019 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset)); 3165 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
3020 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset)); 3166 __ movzx_b(ebx, FieldOperand(ebx, Map::kInstanceTypeOffset));
3021 // if (!object->IsJSValue()) return object. 3167 // if (!object->IsJSValue()) return object.
3022 __ cmp(ebx, JS_VALUE_TYPE); 3168 __ cmp(ebx, JS_VALUE_TYPE);
3023 __ j(not_equal, &leave, not_taken); 3169 leave.Branch(not_equal, not_taken);
3024 // Store the value. 3170 // Store the value.
3025 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx); 3171 __ mov(FieldOperand(eax, JSValue::kValueOffset), ecx);
3026 // Update the write barrier. 3172 // Update the write barrier.
3027 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx); 3173 __ RecordWrite(eax, JSValue::kValueOffset, ecx, ebx);
3028 // Leave. 3174 // Leave.
3029 __ bind(&leave); 3175 leave.Bind();
3030 __ mov(ecx, frame_->Top()); 3176 __ mov(ecx, frame_->Top());
3031 frame_->Pop(); 3177 frame_->Pop();
3032 __ mov(frame_->Top(), ecx); 3178 __ mov(frame_->Top(), ecx);
3033 } 3179 }
3034 3180
3035 3181
3036 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) { 3182 void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
3037 ASSERT(args->length() == 1); 3183 ASSERT(args->length() == 1);
3038 3184
3039 // Load the key onto the stack and set register eax to the formal 3185 // Load the key onto the stack and set register eax to the formal
3040 // parameters count for the currently executing function. 3186 // parameters count for the currently executing function.
3041 Load(args->at(0)); 3187 Load(args->at(0));
3042 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters()))); 3188 __ Set(eax, Immediate(Smi::FromInt(scope_->num_parameters())));
3043 3189
3044 // Call the shared stub to get to arguments[key]. 3190 // Call the shared stub to get to arguments[key].
3045 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT); 3191 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3046 __ CallStub(&stub); 3192 frame_->CallStub(&stub, 0);
3047 __ mov(frame_->Top(), eax); 3193 __ mov(frame_->Top(), eax);
3048 } 3194 }
3049 3195
3050 3196
3051 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) { 3197 void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
3052 ASSERT(args->length() == 2); 3198 ASSERT(args->length() == 2);
3053 3199
3054 // Load the two objects into registers and perform the comparison. 3200 // Load the two objects into registers and perform the comparison.
3055 Load(args->at(0)); 3201 Load(args->at(0));
3056 Load(args->at(1)); 3202 Load(args->at(1));
3057 frame_->Pop(eax); 3203 frame_->Pop(eax);
3058 frame_->Pop(ecx); 3204 frame_->Pop(ecx);
3059 __ cmp(eax, Operand(ecx)); 3205 __ cmp(eax, Operand(ecx));
3060 cc_reg_ = equal; 3206 cc_reg_ = equal;
3061 } 3207 }
3062 3208
3063 3209
3064 void CodeGenerator::VisitCallRuntime(CallRuntime* node) { 3210 void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
3065 if (CheckForInlineRuntimeCall(node)) return; 3211 if (CheckForInlineRuntimeCall(node)) {
3212 return;
3213 }
3066 3214
3067 ZoneList<Expression*>* args = node->arguments(); 3215 ZoneList<Expression*>* args = node->arguments();
3068 Comment cmnt(masm_, "[ CallRuntime"); 3216 Comment cmnt(masm_, "[ CallRuntime");
3069 Runtime::Function* function = node->function(); 3217 Runtime::Function* function = node->function();
3070 3218
3071 if (function == NULL) { 3219 if (function == NULL) {
3072 // Prepare stack for calling JS runtime function. 3220 // Prepare stack for calling JS runtime function.
3073 frame_->Push(Immediate(node->name())); 3221 frame_->Push(Immediate(node->name()));
3074 // Push the builtins object found in the current global object. 3222 // Push the builtins object found in the current global object.
3075 __ mov(edx, GlobalObject()); 3223 __ mov(edx, GlobalObject());
3076 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset)); 3224 frame_->Push(FieldOperand(edx, GlobalObject::kBuiltinsOffset));
3077 } 3225 }
3078 3226
3079 // Push the arguments ("left-to-right"). 3227 // Push the arguments ("left-to-right").
3080 for (int i = 0; i < args->length(); i++) 3228 for (int i = 0; i < args->length(); i++) {
3081 Load(args->at(i)); 3229 Load(args->at(i));
3230 }
3082 3231
3083 if (function != NULL) { 3232 if (function == NULL) {
3084 // Call the C runtime function.
3085 __ CallRuntime(function, args->length());
3086 frame_->Push(eax);
3087 } else {
3088 // Call the JS runtime function. 3233 // Call the JS runtime function.
3089 Handle<Code> stub = ComputeCallInitialize(args->length()); 3234 Handle<Code> stub = ComputeCallInitialize(args->length());
3090 __ Set(eax, Immediate(args->length())); 3235 __ Set(eax, Immediate(args->length()));
3091 __ call(stub, RelocInfo::CODE_TARGET); 3236 frame_->CallCode(stub, RelocInfo::CODE_TARGET, args->length() + 1);
3092 __ mov(esi, frame_->Context()); 3237 __ mov(esi, frame_->Context());
3093 __ mov(frame_->Top(), eax); 3238 __ mov(frame_->Top(), eax);
3239 } else {
3240 // Call the C runtime function.
3241 frame_->CallRuntime(function, args->length());
3242 frame_->Push(eax);
3094 } 3243 }
3095 } 3244 }
3096 3245
3097 3246
3098 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) { 3247 void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
3248 // Note that because of NOT and an optimization in comparison of a typeof
3249 // expression to a literal string, this function can fail to leave a value
3250 // on top of the frame or in the cc register.
3099 Comment cmnt(masm_, "[ UnaryOperation"); 3251 Comment cmnt(masm_, "[ UnaryOperation");
3100 3252
3101 Token::Value op = node->op(); 3253 Token::Value op = node->op();
3102 3254
3103 if (op == Token::NOT) { 3255 if (op == Token::NOT) {
3104 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF, 3256 LoadCondition(node->expression(), NOT_INSIDE_TYPEOF,
3105 false_target(), true_target(), true); 3257 false_target(), true_target(), true);
3106 cc_reg_ = NegateCondition(cc_reg_); 3258 cc_reg_ = NegateCondition(cc_reg_);
3107 3259
3108 } else if (op == Token::DELETE) { 3260 } else if (op == Token::DELETE) {
3109 Property* property = node->expression()->AsProperty(); 3261 Property* property = node->expression()->AsProperty();
3110 if (property != NULL) { 3262 if (property != NULL) {
3111 Load(property->obj()); 3263 Load(property->obj());
3112 Load(property->key()); 3264 Load(property->key());
3113 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3265 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
3114 frame_->Push(eax); 3266 frame_->Push(eax);
3115 return; 3267 return;
3116 } 3268 }
3117 3269
3118 Variable* variable = node->expression()->AsVariableProxy()->AsVariable(); 3270 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
3119 if (variable != NULL) { 3271 if (variable != NULL) {
3120 Slot* slot = variable->slot(); 3272 Slot* slot = variable->slot();
3121 if (variable->is_global()) { 3273 if (variable->is_global()) {
3122 LoadGlobal(); 3274 LoadGlobal();
3123 frame_->Push(Immediate(variable->name())); 3275 frame_->Push(Immediate(variable->name()));
3124 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3276 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
3125 frame_->Push(eax); 3277 frame_->Push(eax);
3126 return; 3278 return;
3127 3279
3128 } else if (slot != NULL && slot->type() == Slot::LOOKUP) { 3280 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
3129 // lookup the context holding the named variable 3281 // lookup the context holding the named variable
3130 frame_->Push(esi); 3282 frame_->Push(esi);
3131 frame_->Push(Immediate(variable->name())); 3283 frame_->Push(Immediate(variable->name()));
3132 __ CallRuntime(Runtime::kLookupContext, 2); 3284 frame_->CallRuntime(Runtime::kLookupContext, 2);
3133 // eax: context 3285 // eax: context
3134 frame_->Push(eax); 3286 frame_->Push(eax);
3135 frame_->Push(Immediate(variable->name())); 3287 frame_->Push(Immediate(variable->name()));
3136 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION); 3288 frame_->InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION, 2);
3137 frame_->Push(eax); 3289 frame_->Push(eax);
3138 return; 3290 return;
3139 } 3291 }
3140 3292
3141 // Default: Result of deleting non-global, not dynamically 3293 // Default: Result of deleting non-global, not dynamically
3142 // introduced variables is false. 3294 // introduced variables is false.
3143 frame_->Push(Immediate(Factory::false_value())); 3295 frame_->Push(Immediate(Factory::false_value()));
3144 3296
3145 } else { 3297 } else {
3146 // Default: Result of deleting expressions is true. 3298 // Default: Result of deleting expressions is true.
3147 Load(node->expression()); // may have side-effects 3299 Load(node->expression()); // may have side-effects
3148 __ Set(frame_->Top(), Immediate(Factory::true_value())); 3300 __ Set(frame_->Top(), Immediate(Factory::true_value()));
3149 } 3301 }
3150 3302
3151 } else if (op == Token::TYPEOF) { 3303 } else if (op == Token::TYPEOF) {
3152 // Special case for loading the typeof expression; see comment on 3304 // Special case for loading the typeof expression; see comment on
3153 // LoadTypeofExpression(). 3305 // LoadTypeofExpression().
3154 LoadTypeofExpression(node->expression()); 3306 LoadTypeofExpression(node->expression());
3155 __ CallRuntime(Runtime::kTypeof, 1); 3307 frame_->CallRuntime(Runtime::kTypeof, 1);
3156 frame_->Push(eax); 3308 frame_->Push(eax);
3157 3309
3158 } else { 3310 } else {
3159 Load(node->expression()); 3311 Load(node->expression());
3160 switch (op) { 3312 switch (op) {
3161 case Token::NOT: 3313 case Token::NOT:
3162 case Token::DELETE: 3314 case Token::DELETE:
3163 case Token::TYPEOF: 3315 case Token::TYPEOF:
3164 UNREACHABLE(); // handled above 3316 UNREACHABLE(); // handled above
3165 break; 3317 break;
3166 3318
3167 case Token::SUB: { 3319 case Token::SUB: {
3168 UnarySubStub stub; 3320 UnarySubStub stub;
3169 // TODO(1222589): remove dependency of TOS being cached inside stub 3321 // TODO(1222589): remove dependency of TOS being cached inside stub
3170 frame_->Pop(eax); 3322 frame_->Pop(eax);
3171 __ CallStub(&stub); 3323 frame_->CallStub(&stub, 0);
3172 frame_->Push(eax); 3324 frame_->Push(eax);
3173 break; 3325 break;
3174 } 3326 }
3175 3327
3176 case Token::BIT_NOT: { 3328 case Token::BIT_NOT: {
3177 // Smi check. 3329 // Smi check.
3178 Label smi_label; 3330 JumpTarget smi_label(this);
3179 Label continue_label; 3331 JumpTarget continue_label(this);
3180 frame_->Pop(eax); 3332 frame_->Pop(eax);
3181 __ test(eax, Immediate(kSmiTagMask)); 3333 __ test(eax, Immediate(kSmiTagMask));
3182 __ j(zero, &smi_label, taken); 3334 smi_label.Branch(zero, taken);
3183 3335
3184 frame_->Push(eax); // undo popping of TOS 3336 frame_->Push(eax); // undo popping of TOS
3185 __ InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION); 3337 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_FUNCTION, 1);
3186 3338
3187 __ jmp(&continue_label); 3339 continue_label.Jump();
3188 __ bind(&smi_label); 3340 smi_label.Bind();
3189 __ not_(eax); 3341 __ not_(eax);
3190 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag. 3342 __ and_(eax, ~kSmiTagMask); // Remove inverted smi-tag.
3191 __ bind(&continue_label); 3343 continue_label.Bind();
3192 frame_->Push(eax); 3344 frame_->Push(eax);
3193 break; 3345 break;
3194 } 3346 }
3195 3347
3196 case Token::VOID: 3348 case Token::VOID:
3197 __ mov(frame_->Top(), Factory::undefined_value()); 3349 __ mov(frame_->Top(), Factory::undefined_value());
3198 break; 3350 break;
3199 3351
3200 case Token::ADD: { 3352 case Token::ADD: {
3201 // Smi check. 3353 // Smi check.
3202 Label continue_label; 3354 JumpTarget continue_label(this);
3203 frame_->Pop(eax); 3355 frame_->Pop(eax);
3204 __ test(eax, Immediate(kSmiTagMask)); 3356 __ test(eax, Immediate(kSmiTagMask));
3205 __ j(zero, &continue_label); 3357 continue_label.Branch(zero);
3206 3358
3207 frame_->Push(eax); 3359 frame_->Push(eax);
3208 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION); 3360 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION, 1);
3209 3361
3210 __ bind(&continue_label); 3362 continue_label.Bind();
3211 frame_->Push(eax); 3363 frame_->Push(eax);
3212 break; 3364 break;
3213 } 3365 }
3214 3366
3215 default: 3367 default:
3216 UNREACHABLE(); 3368 UNREACHABLE();
3217 } 3369 }
3218 } 3370 }
3219 } 3371 }
3220 3372
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
3312 3464
3313 Variable* var = node->expression()->AsVariableProxy()->AsVariable(); 3465 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
3314 bool is_const = (var != NULL && var->mode() == Variable::CONST); 3466 bool is_const = (var != NULL && var->mode() == Variable::CONST);
3315 3467
3316 // Postfix: Make room for the result. 3468 // Postfix: Make room for the result.
3317 if (is_postfix) { 3469 if (is_postfix) {
3318 frame_->Push(Immediate(0)); 3470 frame_->Push(Immediate(0));
3319 } 3471 }
3320 3472
3321 { Reference target(this, node->expression()); 3473 { Reference target(this, node->expression());
3322 if (target.is_illegal()) return; 3474 if (target.is_illegal()) {
3475 // Spoof the virtual frame to have the expected height (one higher
3476 // than on entry).
3477 if (!is_postfix) {
3478 frame_->Push(Immediate(Smi::FromInt(0)));
3479 }
3480 return;
3481 }
3323 target.GetValue(NOT_INSIDE_TYPEOF); 3482 target.GetValue(NOT_INSIDE_TYPEOF);
3324 3483
3325 CountOperationDeferred* deferred = 3484 CountOperationDeferred* deferred =
3326 new CountOperationDeferred(this, is_postfix, is_increment, 3485 new CountOperationDeferred(this, is_postfix, is_increment,
3327 target.size() * kPointerSize); 3486 target.size() * kPointerSize);
3328 3487
3329 frame_->Pop(eax); // Load TOS into eax for calculations below 3488 frame_->Pop(eax); // Load TOS into eax for calculations below
3330 3489
3331 // Postfix: Store the old value as the result. 3490 // Postfix: Store the old value as the result.
3332 if (is_postfix) { 3491 if (is_postfix) {
(...skipping 21 matching lines...) Expand all
3354 } 3513 }
3355 3514
3356 // Postfix: Discard the new value and use the old. 3515 // Postfix: Discard the new value and use the old.
3357 if (is_postfix) { 3516 if (is_postfix) {
3358 frame_->Pop(); 3517 frame_->Pop();
3359 } 3518 }
3360 } 3519 }
3361 3520
3362 3521
3363 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) { 3522 void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
3523 // Note that due to an optimization in comparison operations (typeof
3524 // compared to a string literal), we can evaluate a binary expression such
3525 // as AND or OR and not leave a value on the frame or in the cc register.
3364 Comment cmnt(masm_, "[ BinaryOperation"); 3526 Comment cmnt(masm_, "[ BinaryOperation");
3365 Token::Value op = node->op(); 3527 Token::Value op = node->op();
3366 3528
3367 // According to ECMA-262 section 11.11, page 58, the binary logical 3529 // According to ECMA-262 section 11.11, page 58, the binary logical
3368 // operators must yield the result of one of the two expressions 3530 // operators must yield the result of one of the two expressions
3369 // before any ToBoolean() conversions. This means that the value 3531 // before any ToBoolean() conversions. This means that the value
3370 // produced by a && or || operator is not necessarily a boolean. 3532 // produced by a && or || operator is not necessarily a boolean.
3371 3533
3372 // NOTE: If the left hand side produces a materialized value (not in 3534 // NOTE: If the left hand side produces a materialized value (not in
3373 // the CC register), we force the right hand side to do the 3535 // the CC register), we force the right hand side to do the
3374 // same. This is necessary because we may have to branch to the exit 3536 // same. This is necessary because we may have to branch to the exit
3375 // after evaluating the left hand side (due to the shortcut 3537 // after evaluating the left hand side (due to the shortcut
3376 // semantics), but the compiler must (statically) know if the result 3538 // semantics), but the compiler must (statically) know if the result
3377 // of compiling the binary operation is materialized or not. 3539 // of compiling the binary operation is materialized or not.
3378 3540
3379 if (op == Token::AND) { 3541 if (op == Token::AND) {
3380 Label is_true; 3542 JumpTarget is_true(this);
3381 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true, 3543 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, &is_true,
3382 false_target(), false); 3544 false_target(), false);
3383 if (has_cc()) { 3545 if (has_cc() || frame_ == NULL) {
3384 Branch(false, false_target()); 3546 if (has_cc()) {
3547 ASSERT(frame_ != NULL);
3548 Branch(false, false_target());
3549 }
3385 3550
3386 // Evaluate right side expression. 3551 if (frame_ != NULL || is_true.is_linked()) {
3387 __ bind(&is_true); 3552 // Evaluate right side expression.
3388 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), 3553 is_true.Bind();
3389 false_target(), false); 3554 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
3390 3555 false_target(), false);
3556 }
3391 } else { 3557 } else {
3392 Label pop_and_continue, exit; 3558 // We have a materialized value on the frame.
3559 JumpTarget pop_and_continue(this);
3560 JumpTarget exit(this);
3393 3561
3394 // Avoid popping the result if it converts to 'false' using the 3562 // Avoid popping the result if it converts to 'false' using the
3395 // standard ToBoolean() conversion as described in ECMA-262, 3563 // standard ToBoolean() conversion as described in ECMA-262, section
3396 // section 9.2, page 30. 3564 // 9.2, page 30.
3397 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. 3565 //
3566 // Duplicate the TOS value. The duplicate will be popped by ToBoolean.
3398 __ mov(eax, frame_->Top()); 3567 __ mov(eax, frame_->Top());
3399 frame_->Push(eax); 3568 frame_->Push(eax);
3400 ToBoolean(&pop_and_continue, &exit); 3569 ToBoolean(&pop_and_continue, &exit);
3401 Branch(false, &exit); 3570 Branch(false, &exit);
3402 3571
3403 // Pop the result of evaluating the first part. 3572 // Pop the result of evaluating the first part.
3404 __ bind(&pop_and_continue); 3573 pop_and_continue.Bind();
3405 frame_->Pop(); 3574 frame_->Pop();
3406 3575
3407 // Evaluate right side expression. 3576 // Evaluate right side expression.
3408 __ bind(&is_true); 3577 is_true.Bind();
3409 Load(node->right()); 3578 Load(node->right());
3410 3579
3411 // Exit (always with a materialized value). 3580 // Exit (always with a materialized value).
3412 __ bind(&exit); 3581 exit.Bind();
3413 } 3582 }
3414 3583
3415 } else if (op == Token::OR) { 3584 } else if (op == Token::OR) {
3416 Label is_false; 3585 JumpTarget is_false(this);
3417 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(), 3586 LoadCondition(node->left(), NOT_INSIDE_TYPEOF, true_target(),
3418 &is_false, false); 3587 &is_false, false);
3419 if (has_cc()) { 3588 if (has_cc() || frame_ == NULL) {
3420 Branch(true, true_target()); 3589 if (has_cc()) {
3590 ASSERT(frame_ != NULL);
3591 Branch(true, true_target());
3592 }
3421 3593
3422 // Evaluate right side expression. 3594 if (frame_ != NULL || is_false.is_linked()) {
3423 __ bind(&is_false); 3595 // Evaluate right side expression.
3424 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(), 3596 is_false.Bind();
3425 false_target(), false); 3597 LoadCondition(node->right(), NOT_INSIDE_TYPEOF, true_target(),
3598 false_target(), false);
3599 }
3426 3600
3427 } else { 3601 } else {
3428 Label pop_and_continue, exit; 3602 // We have a materialized value on the frame.
3603 JumpTarget pop_and_continue(this);
3604 JumpTarget exit(this);
3429 3605
3430 // Avoid popping the result if it converts to 'true' using the 3606 // Avoid popping the result if it converts to 'true' using the
3431 // standard ToBoolean() conversion as described in ECMA-262, 3607 // standard ToBoolean() conversion as described in ECMA-262,
3432 // section 9.2, page 30. 3608 // section 9.2, page 30.
3433 // Duplicate the TOS value. The duplicate will be popped by ToBoolean. 3609 // Duplicate the TOS value. The duplicate will be popped by ToBoolean.
3434 __ mov(eax, frame_->Top()); 3610 __ mov(eax, frame_->Top());
3435 frame_->Push(eax); 3611 frame_->Push(eax);
3436 ToBoolean(&exit, &pop_and_continue); 3612 ToBoolean(&exit, &pop_and_continue);
3437 Branch(true, &exit); 3613 Branch(true, &exit);
3438 3614
3439 // Pop the result of evaluating the first part. 3615 // Pop the result of evaluating the first part.
3440 __ bind(&pop_and_continue); 3616 pop_and_continue.Bind();
3441 frame_->Pop(); 3617 frame_->Pop();
3442 3618
3443 // Evaluate right side expression. 3619 // Evaluate right side expression.
3444 __ bind(&is_false); 3620 is_false.Bind();
3445 Load(node->right()); 3621 Load(node->right());
3446 3622
3447 // Exit (always with a materialized value). 3623 // Exit (always with a materialized value).
3448 __ bind(&exit); 3624 exit.Bind();
3449 } 3625 }
3450 3626
3451 } else { 3627 } else {
3452 // NOTE: The code below assumes that the slow cases (calls to runtime) 3628 // NOTE: The code below assumes that the slow cases (calls to runtime)
3453 // never return a constant/immutable object. 3629 // never return a constant/immutable object.
3454 OverwriteMode overwrite_mode = NO_OVERWRITE; 3630 OverwriteMode overwrite_mode = NO_OVERWRITE;
3455 if (node->left()->AsBinaryOperation() != NULL && 3631 if (node->left()->AsBinaryOperation() != NULL &&
3456 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) { 3632 node->left()->AsBinaryOperation()->ResultOverwriteAllowed()) {
3457 overwrite_mode = OVERWRITE_LEFT; 3633 overwrite_mode = OVERWRITE_LEFT;
3458 } else if (node->right()->AsBinaryOperation() != NULL && 3634 } else if (node->right()->AsBinaryOperation() != NULL &&
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
3513 // runtime routine for checking equality. 3689 // runtime routine for checking equality.
3514 3690
3515 if (op == Token::EQ || op == Token::EQ_STRICT) { 3691 if (op == Token::EQ || op == Token::EQ_STRICT) {
3516 bool left_is_null = 3692 bool left_is_null =
3517 left->AsLiteral() != NULL && left->AsLiteral()->IsNull(); 3693 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
3518 bool right_is_null = 3694 bool right_is_null =
3519 right->AsLiteral() != NULL && right->AsLiteral()->IsNull(); 3695 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
3520 // The 'null' value is only equal to 'null' or 'undefined'. 3696 // The 'null' value is only equal to 'null' or 'undefined'.
3521 if (left_is_null || right_is_null) { 3697 if (left_is_null || right_is_null) {
3522 Load(left_is_null ? right : left); 3698 Load(left_is_null ? right : left);
3523 Label exit, undetectable; 3699 JumpTarget exit(this);
3700 JumpTarget undetectable(this);
3524 frame_->Pop(eax); 3701 frame_->Pop(eax);
3525 __ cmp(eax, Factory::null_value()); 3702 __ cmp(eax, Factory::null_value());
3526 3703
3527 // The 'null' value is only equal to 'undefined' if using 3704 // The 'null' value is only equal to 'undefined' if using
3528 // non-strict comparisons. 3705 // non-strict comparisons.
3529 if (op != Token::EQ_STRICT) { 3706 if (op != Token::EQ_STRICT) {
3530 __ j(equal, &exit); 3707 exit.Branch(equal);
3531 __ cmp(eax, Factory::undefined_value()); 3708 __ cmp(eax, Factory::undefined_value());
3532 3709
3533 // NOTE: it can be an undetectable object. 3710 // NOTE: it can be an undetectable object.
3534 __ j(equal, &exit); 3711 exit.Branch(equal);
3535 __ test(eax, Immediate(kSmiTagMask)); 3712 __ test(eax, Immediate(kSmiTagMask));
3536 3713
3537 __ j(not_equal, &undetectable); 3714 undetectable.Branch(not_equal);
3538 __ jmp(false_target()); 3715 false_target()->Jump();
3539 3716
3540 __ bind(&undetectable); 3717 undetectable.Bind();
3541 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset)); 3718 __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
3542 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); 3719 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3543 __ and_(ecx, 1 << Map::kIsUndetectable); 3720 __ and_(ecx, 1 << Map::kIsUndetectable);
3544 __ cmp(ecx, 1 << Map::kIsUndetectable); 3721 __ cmp(ecx, 1 << Map::kIsUndetectable);
3545 } 3722 }
3546 3723
3547 __ bind(&exit); 3724 exit.Bind();
3548 3725
3549 cc_reg_ = equal; 3726 cc_reg_ = equal;
3550 return; 3727 return;
3551 } 3728 }
3552 } 3729 }
3553 3730
3554 // NOTE: To make typeof testing for natives implemented in 3731 // NOTE: To make typeof testing for natives implemented in
3555 // JavaScript really efficient, we generate special code for 3732 // JavaScript really efficient, we generate special code for
3556 // expressions of the form: 'typeof <expression> == <string>'. 3733 // expressions of the form: 'typeof <expression> == <string>'.
3557 3734
3558 UnaryOperation* operation = left->AsUnaryOperation(); 3735 UnaryOperation* operation = left->AsUnaryOperation();
3559 if ((op == Token::EQ || op == Token::EQ_STRICT) && 3736 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
3560 (operation != NULL && operation->op() == Token::TYPEOF) && 3737 (operation != NULL && operation->op() == Token::TYPEOF) &&
3561 (right->AsLiteral() != NULL && 3738 (right->AsLiteral() != NULL &&
3562 right->AsLiteral()->handle()->IsString())) { 3739 right->AsLiteral()->handle()->IsString())) {
3563 Handle<String> check(String::cast(*right->AsLiteral()->handle())); 3740 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
3564 3741
3565 // Load the operand, move it to register edx, and restore TOS. 3742 // Load the operand, move it to register edx, and restore TOS.
3566 LoadTypeofExpression(operation->expression()); 3743 LoadTypeofExpression(operation->expression());
3567 frame_->Pop(edx); 3744 frame_->Pop(edx);
3568 3745
3569 if (check->Equals(Heap::number_symbol())) { 3746 if (check->Equals(Heap::number_symbol())) {
3570 __ test(edx, Immediate(kSmiTagMask)); 3747 __ test(edx, Immediate(kSmiTagMask));
3571 __ j(zero, true_target()); 3748 true_target()->Branch(zero);
3572 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); 3749 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
3573 __ cmp(edx, Factory::heap_number_map()); 3750 __ cmp(edx, Factory::heap_number_map());
3574 cc_reg_ = equal; 3751 cc_reg_ = equal;
3575 3752
3576 } else if (check->Equals(Heap::string_symbol())) { 3753 } else if (check->Equals(Heap::string_symbol())) {
3577 __ test(edx, Immediate(kSmiTagMask)); 3754 __ test(edx, Immediate(kSmiTagMask));
3578 __ j(zero, false_target()); 3755 false_target()->Branch(zero);
3579 3756
3580 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); 3757 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
3581 3758
3582 // NOTE: it might be an undetectable string object 3759 // NOTE: it might be an undetectable string object
3583 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); 3760 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3584 __ and_(ecx, 1 << Map::kIsUndetectable); 3761 __ and_(ecx, 1 << Map::kIsUndetectable);
3585 __ cmp(ecx, 1 << Map::kIsUndetectable); 3762 __ cmp(ecx, 1 << Map::kIsUndetectable);
3586 __ j(equal, false_target()); 3763 false_target()->Branch(equal);
3587 3764
3588 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset)); 3765 __ movzx_b(ecx, FieldOperand(edx, Map::kInstanceTypeOffset));
3589 __ cmp(ecx, FIRST_NONSTRING_TYPE); 3766 __ cmp(ecx, FIRST_NONSTRING_TYPE);
3590 cc_reg_ = less; 3767 cc_reg_ = less;
3591 3768
3592 } else if (check->Equals(Heap::boolean_symbol())) { 3769 } else if (check->Equals(Heap::boolean_symbol())) {
3593 __ cmp(edx, Factory::true_value()); 3770 __ cmp(edx, Factory::true_value());
3594 __ j(equal, true_target()); 3771 true_target()->Branch(equal);
3595 __ cmp(edx, Factory::false_value()); 3772 __ cmp(edx, Factory::false_value());
3596 cc_reg_ = equal; 3773 cc_reg_ = equal;
3597 3774
3598 } else if (check->Equals(Heap::undefined_symbol())) { 3775 } else if (check->Equals(Heap::undefined_symbol())) {
3599 __ cmp(edx, Factory::undefined_value()); 3776 __ cmp(edx, Factory::undefined_value());
3600 __ j(equal, true_target()); 3777 true_target()->Branch(equal);
3601 3778
3602 __ test(edx, Immediate(kSmiTagMask)); 3779 __ test(edx, Immediate(kSmiTagMask));
3603 __ j(zero, false_target()); 3780 false_target()->Branch(zero);
3604 3781
3605 // NOTE: it can be an undetectable object. 3782 // NOTE: it can be an undetectable object.
3606 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); 3783 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
3607 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset)); 3784 __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
3608 __ and_(ecx, 1 << Map::kIsUndetectable); 3785 __ and_(ecx, 1 << Map::kIsUndetectable);
3609 __ cmp(ecx, 1 << Map::kIsUndetectable); 3786 __ cmp(ecx, 1 << Map::kIsUndetectable);
3610 3787
3611 cc_reg_ = equal; 3788 cc_reg_ = equal;
3612 3789
3613 } else if (check->Equals(Heap::function_symbol())) { 3790 } else if (check->Equals(Heap::function_symbol())) {
3614 __ test(edx, Immediate(kSmiTagMask)); 3791 __ test(edx, Immediate(kSmiTagMask));
3615 __ j(zero, false_target()); 3792 false_target()->Branch(zero);
3616 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset)); 3793 __ mov(edx, FieldOperand(edx, HeapObject::kMapOffset));
3617 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset)); 3794 __ movzx_b(edx, FieldOperand(edx, Map::kInstanceTypeOffset));
3618 __ cmp(edx, JS_FUNCTION_TYPE); 3795 __ cmp(edx, JS_FUNCTION_TYPE);
3619 cc_reg_ = equal; 3796 cc_reg_ = equal;
3620 3797
3621 } else if (check->Equals(Heap::object_symbol())) { 3798 } else if (check->Equals(Heap::object_symbol())) {
3622 __ test(edx, Immediate(kSmiTagMask)); 3799 __ test(edx, Immediate(kSmiTagMask));
3623 __ j(zero, false_target()); 3800 false_target()->Branch(zero);
3624 3801
3625 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset)); 3802 __ mov(ecx, FieldOperand(edx, HeapObject::kMapOffset));
3626 __ cmp(edx, Factory::null_value()); 3803 __ cmp(edx, Factory::null_value());
3627 __ j(equal, true_target()); 3804 true_target()->Branch(equal);
3628 3805
3629 // NOTE: it might be an undetectable object 3806 // NOTE: it might be an undetectable object
3630 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset)); 3807 __ movzx_b(edx, FieldOperand(ecx, Map::kBitFieldOffset));
3631 __ and_(edx, 1 << Map::kIsUndetectable); 3808 __ and_(edx, 1 << Map::kIsUndetectable);
3632 __ cmp(edx, 1 << Map::kIsUndetectable); 3809 __ cmp(edx, 1 << Map::kIsUndetectable);
3633 __ j(equal, false_target()); 3810 false_target()->Branch(equal);
3634 3811
3635 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset)); 3812 __ movzx_b(ecx, FieldOperand(ecx, Map::kInstanceTypeOffset));
3636 __ cmp(ecx, FIRST_JS_OBJECT_TYPE); 3813 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
3637 __ j(less, false_target()); 3814 false_target()->Branch(less);
3638 __ cmp(ecx, LAST_JS_OBJECT_TYPE); 3815 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
3639 cc_reg_ = less_equal; 3816 cc_reg_ = less_equal;
3640 3817
3641 } else { 3818 } else {
3642 // Uncommon case: Typeof testing against a string literal that 3819 // Uncommon case: Typeof testing against a string literal that
3643 // is never returned from the typeof operator. 3820 // is never returned from the typeof operator.
3644 __ jmp(false_target()); 3821 false_target()->Jump();
3822 // TODO(): Can this cause a problem because it is an expression that
3823 // exits without a virtual frame in place?
3645 } 3824 }
3646 return; 3825 return;
3647 } 3826 }
3648 3827
3649 Condition cc = no_condition; 3828 Condition cc = no_condition;
3650 bool strict = false; 3829 bool strict = false;
3651 switch (op) { 3830 switch (op) {
3652 case Token::EQ_STRICT: 3831 case Token::EQ_STRICT:
3653 strict = true; 3832 strict = true;
3654 // Fall through 3833 // Fall through
3655 case Token::EQ: 3834 case Token::EQ:
3656 cc = equal; 3835 cc = equal;
3657 break; 3836 break;
3658 case Token::LT: 3837 case Token::LT:
3659 cc = less; 3838 cc = less;
3660 break; 3839 break;
3661 case Token::GT: 3840 case Token::GT:
3662 cc = greater; 3841 cc = greater;
3663 break; 3842 break;
3664 case Token::LTE: 3843 case Token::LTE:
3665 cc = less_equal; 3844 cc = less_equal;
3666 break; 3845 break;
3667 case Token::GTE: 3846 case Token::GTE:
3668 cc = greater_equal; 3847 cc = greater_equal;
3669 break; 3848 break;
3670 case Token::IN: { 3849 case Token::IN: {
3671 Load(left); 3850 Load(left);
3672 Load(right); 3851 Load(right);
3673 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION); 3852 frame_->InvokeBuiltin(Builtins::IN, CALL_FUNCTION, 2);
3674 frame_->Push(eax); // push the result 3853 frame_->Push(eax); // push the result
3675 return; 3854 return;
3676 } 3855 }
3677 case Token::INSTANCEOF: { 3856 case Token::INSTANCEOF: {
3678 Load(left); 3857 Load(left);
3679 Load(right); 3858 Load(right);
3680 InstanceofStub stub; 3859 InstanceofStub stub;
3681 __ CallStub(&stub); 3860 frame_->CallStub(&stub, 2);
3682 __ test(eax, Operand(eax)); 3861 __ test(eax, Operand(eax));
3683 cc_reg_ = zero; 3862 cc_reg_ = zero;
3684 return; 3863 return;
3685 } 3864 }
3686 default: 3865 default:
3687 UNREACHABLE(); 3866 UNREACHABLE();
3688 } 3867 }
3689 3868
3690 // Optimize for the case where (at least) one of the expressions 3869 // Optimize for the case where (at least) one of the expressions
3691 // is a literal small integer. 3870 // is a literal small integer.
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
3760 // loads must not throw a reference error). 3939 // loads must not throw a reference error).
3761 Comment cmnt(masm, "[ Load from named Property"); 3940 Comment cmnt(masm, "[ Load from named Property");
3762 Handle<String> name(GetName()); 3941 Handle<String> name(GetName());
3763 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize)); 3942 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3764 // Setup the name register. 3943 // Setup the name register.
3765 __ mov(ecx, name); 3944 __ mov(ecx, name);
3766 3945
3767 Variable* var = expression_->AsVariableProxy()->AsVariable(); 3946 Variable* var = expression_->AsVariableProxy()->AsVariable();
3768 if (var != NULL) { 3947 if (var != NULL) {
3769 ASSERT(var->is_global()); 3948 ASSERT(var->is_global());
3770 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); 3949 frame->CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, 0);
3771 } else { 3950 } else {
3772 __ call(ic, RelocInfo::CODE_TARGET); 3951 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0);
3773 } 3952 }
3774 frame->Push(eax); // IC call leaves result in eax, push it out 3953 frame->Push(eax); // IC call leaves result in eax, push it out
3775 break; 3954 break;
3776 } 3955 }
3777 3956
3778 case KEYED: { 3957 case KEYED: {
3779 // TODO(1241834): Make sure that this it is safe to ignore the 3958 // TODO(1241834): Make sure that this it is safe to ignore the
3780 // distinction between expressions in a typeof and not in a typeof. 3959 // distinction between expressions in a typeof and not in a typeof.
3781 Comment cmnt(masm, "[ Load from keyed Property"); 3960 Comment cmnt(masm, "[ Load from keyed Property");
3782 Property* property = expression_->AsProperty(); 3961 Property* property = expression_->AsProperty();
3783 ASSERT(property != NULL); 3962 ASSERT(property != NULL);
3784 __ RecordPosition(property->position()); 3963 __ RecordPosition(property->position());
3785 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize)); 3964 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
3786 3965
3787 Variable* var = expression_->AsVariableProxy()->AsVariable(); 3966 Variable* var = expression_->AsVariableProxy()->AsVariable();
3788 if (var != NULL) { 3967 if (var != NULL) {
3789 ASSERT(var->is_global()); 3968 ASSERT(var->is_global());
3790 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT); 3969 frame->CallCode(ic, RelocInfo::CODE_TARGET_CONTEXT, 0);
3791 } else { 3970 } else {
3792 __ call(ic, RelocInfo::CODE_TARGET); 3971 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0);
3793 } 3972 }
3794 frame->Push(eax); // IC call leaves result in eax, push it out 3973 frame->Push(eax); // IC call leaves result in eax, push it out
3795 break; 3974 break;
3796 } 3975 }
3797 3976
3798 default: 3977 default:
3799 UNREACHABLE(); 3978 UNREACHABLE();
3800 } 3979 }
3801 } 3980 }
3802 3981
(...skipping 24 matching lines...) Expand all
3827 // 4006 //
3828 // Note that we must declare the foo upon entry of eval(), via a 4007 // Note that we must declare the foo upon entry of eval(), via a
3829 // context slot declaration, but we cannot initialize it at the 4008 // context slot declaration, but we cannot initialize it at the
3830 // same time, because the const declaration may be at the end of 4009 // same time, because the const declaration may be at the end of
3831 // the eval code (sigh...) and the const variable may have been 4010 // the eval code (sigh...) and the const variable may have been
3832 // used before (where its value is 'undefined'). Thus, we can only 4011 // used before (where its value is 'undefined'). Thus, we can only
3833 // do the initialization when we actually encounter the expression 4012 // do the initialization when we actually encounter the expression
3834 // and when the expression operands are defined and valid, and 4013 // and when the expression operands are defined and valid, and
3835 // thus we need the split into 2 operations: declaration of the 4014 // thus we need the split into 2 operations: declaration of the
3836 // context slot followed by initialization. 4015 // context slot followed by initialization.
3837 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3); 4016 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
3838 } else { 4017 } else {
3839 __ CallRuntime(Runtime::kStoreContextSlot, 3); 4018 frame->CallRuntime(Runtime::kStoreContextSlot, 3);
3840 } 4019 }
3841 // Storing a variable must keep the (new) value on the expression 4020 // Storing a variable must keep the (new) value on the expression
3842 // stack. This is necessary for compiling chained assignment 4021 // stack. This is necessary for compiling chained assignment
3843 // expressions. 4022 // expressions.
3844 frame->Push(eax); 4023 frame->Push(eax);
3845 4024
3846 } else { 4025 } else {
3847 ASSERT(slot->var()->mode() != Variable::DYNAMIC); 4026 ASSERT(slot->var()->mode() != Variable::DYNAMIC);
3848 4027
3849 Label exit; 4028 JumpTarget exit(cgen_);
3850 if (init_state == CONST_INIT) { 4029 if (init_state == CONST_INIT) {
3851 ASSERT(slot->var()->mode() == Variable::CONST); 4030 ASSERT(slot->var()->mode() == Variable::CONST);
3852 // Only the first const initialization must be executed (the slot 4031 // Only the first const initialization must be executed (the slot
3853 // still contains 'the hole' value). When the assignment is 4032 // still contains 'the hole' value). When the assignment is
3854 // executed, the code is identical to a normal store (see below). 4033 // executed, the code is identical to a normal store (see below).
3855 Comment cmnt(masm, "[ Init const"); 4034 Comment cmnt(masm, "[ Init const");
3856 __ mov(eax, cgen_->SlotOperand(slot, ecx)); 4035 __ mov(eax, cgen_->SlotOperand(slot, ecx));
3857 __ cmp(eax, Factory::the_hole_value()); 4036 __ cmp(eax, Factory::the_hole_value());
3858 __ j(not_equal, &exit); 4037 exit.Branch(not_equal);
3859 } 4038 }
3860 4039
3861 // We must execute the store. Storing a variable must keep the 4040 // We must execute the store. Storing a variable must keep the
3862 // (new) value on the stack. This is necessary for compiling 4041 // (new) value on the stack. This is necessary for compiling
3863 // assignment expressions. 4042 // assignment expressions.
3864 // 4043 //
3865 // Note: We will reach here even with slot->var()->mode() == 4044 // Note: We will reach here even with slot->var()->mode() ==
3866 // Variable::CONST because of const declarations which will 4045 // Variable::CONST because of const declarations which will
3867 // initialize consts to 'the hole' value and by doing so, end up 4046 // initialize consts to 'the hole' value and by doing so, end up
3868 // calling this code. 4047 // calling this code.
3869 frame->Pop(eax); 4048 frame->Pop(eax);
3870 __ mov(cgen_->SlotOperand(slot, ecx), eax); 4049 __ mov(cgen_->SlotOperand(slot, ecx), eax);
3871 frame->Push(eax); // RecordWrite may destroy the value in eax. 4050 frame->Push(eax); // RecordWrite may destroy the value in eax.
3872 if (slot->type() == Slot::CONTEXT) { 4051 if (slot->type() == Slot::CONTEXT) {
3873 // ecx is loaded with context when calling SlotOperand above. 4052 // ecx is loaded with context when calling SlotOperand above.
3874 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize; 4053 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
3875 __ RecordWrite(ecx, offset, eax, ebx); 4054 __ RecordWrite(ecx, offset, eax, ebx);
3876 } 4055 }
3877 // If we definitely did not jump over the assignment, we do not need 4056 // If we definitely did not jump over the assignment, we do not need
3878 // to bind the exit label. Doing so can defeat peephole 4057 // to bind the exit label. Doing so can defeat peephole
3879 // optimization. 4058 // optimization.
3880 if (init_state == CONST_INIT) __ bind(&exit); 4059 if (init_state == CONST_INIT) {
4060 exit.Bind();
4061 }
3881 } 4062 }
3882 break; 4063 break;
3883 } 4064 }
3884 4065
3885 case NAMED: { 4066 case NAMED: {
3886 Comment cmnt(masm, "[ Store to named Property"); 4067 Comment cmnt(masm, "[ Store to named Property");
3887 // Call the appropriate IC code. 4068 // Call the appropriate IC code.
3888 Handle<String> name(GetName()); 4069 Handle<String> name(GetName());
3889 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize)); 4070 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
3890 // TODO(1222589): Make the IC grab the values from the stack. 4071 // TODO(1222589): Make the IC grab the values from the stack.
3891 frame->Pop(eax); 4072 frame->Pop(eax);
3892 // Setup the name register. 4073 // Setup the name register.
3893 __ mov(ecx, name); 4074 __ mov(ecx, name);
3894 __ call(ic, RelocInfo::CODE_TARGET); 4075 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0);
3895 frame->Push(eax); // IC call leaves result in eax, push it out 4076 frame->Push(eax); // IC call leaves result in eax, push it out
3896 break; 4077 break;
3897 } 4078 }
3898 4079
3899 case KEYED: { 4080 case KEYED: {
3900 Comment cmnt(masm, "[ Store to keyed Property"); 4081 Comment cmnt(masm, "[ Store to keyed Property");
3901 Property* property = expression_->AsProperty(); 4082 Property* property = expression_->AsProperty();
3902 ASSERT(property != NULL); 4083 ASSERT(property != NULL);
3903 __ RecordPosition(property->position()); 4084 __ RecordPosition(property->position());
3904 // Call IC code. 4085 // Call IC code.
3905 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize)); 4086 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
3906 // TODO(1222589): Make the IC grab the values from the stack. 4087 // TODO(1222589): Make the IC grab the values from the stack.
3907 frame->Pop(eax); 4088 frame->Pop(eax);
3908 __ call(ic, RelocInfo::CODE_TARGET); 4089 frame->CallCode(ic, RelocInfo::CODE_TARGET, 0);
3909 frame->Push(eax); // IC call leaves result in eax, push it out 4090 frame->Push(eax); // IC call leaves result in eax, push it out
3910 break; 4091 break;
3911 } 4092 }
3912 4093
3913 default: 4094 default:
3914 UNREACHABLE(); 4095 UNREACHABLE();
3915 } 4096 }
3916 } 4097 }
3917 4098
3918 4099
(...skipping 1215 matching lines...) Expand 10 before | Expand all | Expand 10 after
5134 5315
5135 // Slow-case: Go through the JavaScript implementation. 5316 // Slow-case: Go through the JavaScript implementation.
5136 __ bind(&slow); 5317 __ bind(&slow);
5137 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 5318 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
5138 } 5319 }
5139 5320
5140 5321
5141 #undef __ 5322 #undef __
5142 5323
5143 } } // namespace v8::internal 5324 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/codegen-ia32.h ('k') | src/globals.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698