Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / v8 / src / x87 / full-codegen-x87.cc
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #if V8_TARGET_ARCH_X87
8
9 #include "src/code-stubs.h"
10 #include "src/codegen.h"
11 #include "src/compiler.h"
12 #include "src/debug.h"
13 #include "src/full-codegen.h"
14 #include "src/isolate-inl.h"
15 #include "src/parser.h"
16 #include "src/scopes.h"
17 #include "src/stub-cache.h"
18
19 namespace v8 {
20 namespace internal {
21
22 #define __ ACCESS_MASM(masm_)
23
24
25 class JumpPatchSite BASE_EMBEDDED {
26  public:
27   explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
28 #ifdef DEBUG
29     info_emitted_ = false;
30 #endif
31   }
32
33   ~JumpPatchSite() {
34     DCHECK(patch_site_.is_bound() == info_emitted_);
35   }
36
37   void EmitJumpIfNotSmi(Register reg,
38                         Label* target,
39                         Label::Distance distance = Label::kFar) {
40     __ test(reg, Immediate(kSmiTagMask));
41     EmitJump(not_carry, target, distance);  // Always taken before patched.
42   }
43
44   void EmitJumpIfSmi(Register reg,
45                      Label* target,
46                      Label::Distance distance = Label::kFar) {
47     __ test(reg, Immediate(kSmiTagMask));
48     EmitJump(carry, target, distance);  // Never taken before patched.
49   }
50
51   void EmitPatchInfo() {
52     if (patch_site_.is_bound()) {
53       int delta_to_patch_site = masm_->SizeOfCodeGeneratedSince(&patch_site_);
54       DCHECK(is_uint8(delta_to_patch_site));
55       __ test(eax, Immediate(delta_to_patch_site));
56 #ifdef DEBUG
57       info_emitted_ = true;
58 #endif
59     } else {
60       __ nop();  // Signals no inlined code.
61     }
62   }
63
64  private:
65   // jc will be patched with jz, jnc will become jnz.
66   void EmitJump(Condition cc, Label* target, Label::Distance distance) {
67     DCHECK(!patch_site_.is_bound() && !info_emitted_);
68     DCHECK(cc == carry || cc == not_carry);
69     __ bind(&patch_site_);
70     __ j(cc, target, distance);
71   }
72
73   MacroAssembler* masm_;
74   Label patch_site_;
75 #ifdef DEBUG
76   bool info_emitted_;
77 #endif
78 };
79
80
81 // Generate code for a JS function.  On entry to the function the receiver
82 // and arguments have been pushed on the stack left to right, with the
83 // return address on top of them.  The actual argument count matches the
84 // formal parameter count expected by the function.
85 //
86 // The live registers are:
87 //   o edi: the JS function object being called (i.e. ourselves)
88 //   o esi: our context
89 //   o ebp: our caller's frame pointer
90 //   o esp: stack pointer (pointing to return address)
91 //
92 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
93 // frames-x87.h for its layout.
94 void FullCodeGenerator::Generate() {
95   CompilationInfo* info = info_;
96   handler_table_ =
97       isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
98
99   profiling_counter_ = isolate()->factory()->NewCell(
100       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
101   SetFunctionPosition(function());
102   Comment cmnt(masm_, "[ function compiled by full code generator");
103
104   ProfileEntryHookStub::MaybeCallEntryHook(masm_);
105
106 #ifdef DEBUG
107   if (strlen(FLAG_stop_at) > 0 &&
108       info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
109     __ int3();
110   }
111 #endif
112
113   // Sloppy mode functions and builtins need to replace the receiver with the
114   // global proxy when called as functions (without an explicit receiver
115   // object).
116   if (info->strict_mode() == SLOPPY && !info->is_native()) {
117     Label ok;
118     // +1 for return address.
119     int receiver_offset = (info->scope()->num_parameters() + 1) * kPointerSize;
120     __ mov(ecx, Operand(esp, receiver_offset));
121
122     __ cmp(ecx, isolate()->factory()->undefined_value());
123     __ j(not_equal, &ok, Label::kNear);
124
125     __ mov(ecx, GlobalObjectOperand());
126     __ mov(ecx, FieldOperand(ecx, GlobalObject::kGlobalProxyOffset));
127
128     __ mov(Operand(esp, receiver_offset), ecx);
129
130     __ bind(&ok);
131   }
132
133   // Open a frame scope to indicate that there is a frame on the stack.  The
134   // MANUAL indicates that the scope shouldn't actually generate code to set up
135   // the frame (that is done below).
136   FrameScope frame_scope(masm_, StackFrame::MANUAL);
137
138   info->set_prologue_offset(masm_->pc_offset());
139   __ Prologue(info->IsCodePreAgingActive());
140   info->AddNoFrameRange(0, masm_->pc_offset());
141
142   { Comment cmnt(masm_, "[ Allocate locals");
143     int locals_count = info->scope()->num_stack_slots();
144     // Generators allocate locals, if any, in context slots.
145     DCHECK(!info->function()->is_generator() || locals_count == 0);
146     if (locals_count == 1) {
147       __ push(Immediate(isolate()->factory()->undefined_value()));
148     } else if (locals_count > 1) {
149       if (locals_count >= 128) {
150         Label ok;
151         __ mov(ecx, esp);
152         __ sub(ecx, Immediate(locals_count * kPointerSize));
153         ExternalReference stack_limit =
154             ExternalReference::address_of_real_stack_limit(isolate());
155         __ cmp(ecx, Operand::StaticVariable(stack_limit));
156         __ j(above_equal, &ok, Label::kNear);
157         __ InvokeBuiltin(Builtins::STACK_OVERFLOW, CALL_FUNCTION);
158         __ bind(&ok);
159       }
160       __ mov(eax, Immediate(isolate()->factory()->undefined_value()));
161       const int kMaxPushes = 32;
162       if (locals_count >= kMaxPushes) {
163         int loop_iterations = locals_count / kMaxPushes;
164         __ mov(ecx, loop_iterations);
165         Label loop_header;
166         __ bind(&loop_header);
167         // Do pushes.
168         for (int i = 0; i < kMaxPushes; i++) {
169           __ push(eax);
170         }
171         __ dec(ecx);
172         __ j(not_zero, &loop_header, Label::kNear);
173       }
174       int remaining = locals_count % kMaxPushes;
175       // Emit the remaining pushes.
176       for (int i  = 0; i < remaining; i++) {
177         __ push(eax);
178       }
179     }
180   }
181
182   bool function_in_register = true;
183
184   // Possibly allocate a local context.
185   int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
186   if (heap_slots > 0) {
187     Comment cmnt(masm_, "[ Allocate context");
188     bool need_write_barrier = true;
189     // Argument to NewContext is the function, which is still in edi.
190     if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
191       __ push(edi);
192       __ Push(info->scope()->GetScopeInfo());
193       __ CallRuntime(Runtime::kNewGlobalContext, 2);
194     } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
195       FastNewContextStub stub(isolate(), heap_slots);
196       __ CallStub(&stub);
197       // Result of FastNewContextStub is always in new space.
198       need_write_barrier = false;
199     } else {
200       __ push(edi);
201       __ CallRuntime(Runtime::kNewFunctionContext, 1);
202     }
203     function_in_register = false;
204     // Context is returned in eax.  It replaces the context passed to us.
205     // It's saved in the stack and kept live in esi.
206     __ mov(esi, eax);
207     __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), eax);
208
209     // Copy parameters into context if necessary.
210     int num_parameters = info->scope()->num_parameters();
211     for (int i = 0; i < num_parameters; i++) {
212       Variable* var = scope()->parameter(i);
213       if (var->IsContextSlot()) {
214         int parameter_offset = StandardFrameConstants::kCallerSPOffset +
215             (num_parameters - 1 - i) * kPointerSize;
216         // Load parameter from stack.
217         __ mov(eax, Operand(ebp, parameter_offset));
218         // Store it in the context.
219         int context_offset = Context::SlotOffset(var->index());
220         __ mov(Operand(esi, context_offset), eax);
221         // Update the write barrier. This clobbers eax and ebx.
222         if (need_write_barrier) {
223           __ RecordWriteContextSlot(esi,
224                                     context_offset,
225                                     eax,
226                                     ebx);
227         } else if (FLAG_debug_code) {
228           Label done;
229           __ JumpIfInNewSpace(esi, eax, &done, Label::kNear);
230           __ Abort(kExpectedNewSpaceObject);
231           __ bind(&done);
232         }
233       }
234     }
235   }
236
237   Variable* arguments = scope()->arguments();
238   if (arguments != NULL) {
239     // Function uses arguments object.
240     Comment cmnt(masm_, "[ Allocate arguments object");
241     if (function_in_register) {
242       __ push(edi);
243     } else {
244       __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
245     }
246     // Receiver is just before the parameters on the caller's stack.
247     int num_parameters = info->scope()->num_parameters();
248     int offset = num_parameters * kPointerSize;
249     __ lea(edx,
250            Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
251     __ push(edx);
252     __ push(Immediate(Smi::FromInt(num_parameters)));
253     // Arguments to ArgumentsAccessStub:
254     //   function, receiver address, parameter count.
255     // The stub will rewrite receiver and parameter count if the previous
256     // stack frame was an arguments adapter frame.
257     ArgumentsAccessStub::Type type;
258     if (strict_mode() == STRICT) {
259       type = ArgumentsAccessStub::NEW_STRICT;
260     } else if (function()->has_duplicate_parameters()) {
261       type = ArgumentsAccessStub::NEW_SLOPPY_SLOW;
262     } else {
263       type = ArgumentsAccessStub::NEW_SLOPPY_FAST;
264     }
265     ArgumentsAccessStub stub(isolate(), type);
266     __ CallStub(&stub);
267
268     SetVar(arguments, eax, ebx, edx);
269   }
270
271   if (FLAG_trace) {
272     __ CallRuntime(Runtime::kTraceEnter, 0);
273   }
274
275   // Visit the declarations and body unless there is an illegal
276   // redeclaration.
277   if (scope()->HasIllegalRedeclaration()) {
278     Comment cmnt(masm_, "[ Declarations");
279     scope()->VisitIllegalRedeclaration(this);
280
281   } else {
282     PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
283     { Comment cmnt(masm_, "[ Declarations");
284       // For named function expressions, declare the function name as a
285       // constant.
286       if (scope()->is_function_scope() && scope()->function() != NULL) {
287         VariableDeclaration* function = scope()->function();
288         DCHECK(function->proxy()->var()->mode() == CONST ||
289                function->proxy()->var()->mode() == CONST_LEGACY);
290         DCHECK(function->proxy()->var()->location() != Variable::UNALLOCATED);
291         VisitVariableDeclaration(function);
292       }
293       VisitDeclarations(scope()->declarations());
294     }
295
296     { Comment cmnt(masm_, "[ Stack check");
297       PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
298       Label ok;
299       ExternalReference stack_limit
300           = ExternalReference::address_of_stack_limit(isolate());
301       __ cmp(esp, Operand::StaticVariable(stack_limit));
302       __ j(above_equal, &ok, Label::kNear);
303       __ call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
304       __ bind(&ok);
305     }
306
307     { Comment cmnt(masm_, "[ Body");
308       DCHECK(loop_depth() == 0);
309       VisitStatements(function()->body());
310       DCHECK(loop_depth() == 0);
311     }
312   }
313
314   // Always emit a 'return undefined' in case control fell off the end of
315   // the body.
316   { Comment cmnt(masm_, "[ return <undefined>;");
317     __ mov(eax, isolate()->factory()->undefined_value());
318     EmitReturnSequence();
319   }
320 }
321
322
323 void FullCodeGenerator::ClearAccumulator() {
324   __ Move(eax, Immediate(Smi::FromInt(0)));
325 }
326
327
328 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
329   __ mov(ebx, Immediate(profiling_counter_));
330   __ sub(FieldOperand(ebx, Cell::kValueOffset),
331          Immediate(Smi::FromInt(delta)));
332 }
333
334
335 void FullCodeGenerator::EmitProfilingCounterReset() {
336   int reset_value = FLAG_interrupt_budget;
337   __ mov(ebx, Immediate(profiling_counter_));
338   __ mov(FieldOperand(ebx, Cell::kValueOffset),
339          Immediate(Smi::FromInt(reset_value)));
340 }
341
342
343 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
344                                                 Label* back_edge_target) {
345   Comment cmnt(masm_, "[ Back edge bookkeeping");
346   Label ok;
347
348   DCHECK(back_edge_target->is_bound());
349   int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
350   int weight = Min(kMaxBackEdgeWeight,
351                    Max(1, distance / kCodeSizeMultiplier));
352   EmitProfilingCounterDecrement(weight);
353   __ j(positive, &ok, Label::kNear);
354   __ call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
355
356   // Record a mapping of this PC offset to the OSR id.  This is used to find
357   // the AST id from the unoptimized code in order to use it as a key into
358   // the deoptimization input data found in the optimized code.
359   RecordBackEdge(stmt->OsrEntryId());
360
361   EmitProfilingCounterReset();
362
363   __ bind(&ok);
364   PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
365   // Record a mapping of the OSR id to this PC.  This is used if the OSR
366   // entry becomes the target of a bailout.  We don't expect it to be, but
367   // we want it to work if it is.
368   PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
369 }
370
371
372 void FullCodeGenerator::EmitReturnSequence() {
373   Comment cmnt(masm_, "[ Return sequence");
374   if (return_label_.is_bound()) {
375     __ jmp(&return_label_);
376   } else {
377     // Common return label
378     __ bind(&return_label_);
379     if (FLAG_trace) {
380       __ push(eax);
381       __ CallRuntime(Runtime::kTraceExit, 1);
382     }
383     // Pretend that the exit is a backwards jump to the entry.
384     int weight = 1;
385     if (info_->ShouldSelfOptimize()) {
386       weight = FLAG_interrupt_budget / FLAG_self_opt_count;
387     } else {
388       int distance = masm_->pc_offset();
389       weight = Min(kMaxBackEdgeWeight,
390                    Max(1, distance / kCodeSizeMultiplier));
391     }
392     EmitProfilingCounterDecrement(weight);
393     Label ok;
394     __ j(positive, &ok, Label::kNear);
395     __ push(eax);
396     __ call(isolate()->builtins()->InterruptCheck(),
397             RelocInfo::CODE_TARGET);
398     __ pop(eax);
399     EmitProfilingCounterReset();
400     __ bind(&ok);
401 #ifdef DEBUG
402     // Add a label for checking the size of the code used for returning.
403     Label check_exit_codesize;
404     masm_->bind(&check_exit_codesize);
405 #endif
406     SetSourcePosition(function()->end_position() - 1);
407     __ RecordJSReturn();
408     // Do not use the leave instruction here because it is too short to
409     // patch with the code required by the debugger.
410     __ mov(esp, ebp);
411     int no_frame_start = masm_->pc_offset();
412     __ pop(ebp);
413
414     int arguments_bytes = (info_->scope()->num_parameters() + 1) * kPointerSize;
415     __ Ret(arguments_bytes, ecx);
416     // Check that the size of the code used for returning is large enough
417     // for the debugger's requirements.
418     DCHECK(Assembler::kJSReturnSequenceLength <=
419            masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
420     info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
421   }
422 }
423
424
425 void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
426   DCHECK(var->IsStackAllocated() || var->IsContextSlot());
427 }
428
429
430 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
431   DCHECK(var->IsStackAllocated() || var->IsContextSlot());
432   codegen()->GetVar(result_register(), var);
433 }
434
435
436 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
437   DCHECK(var->IsStackAllocated() || var->IsContextSlot());
438   MemOperand operand = codegen()->VarOperand(var, result_register());
439   // Memory operands can be pushed directly.
440   __ push(operand);
441 }
442
443
444 void FullCodeGenerator::TestContext::Plug(Variable* var) const {
445   // For simplicity we always test the accumulator register.
446   codegen()->GetVar(result_register(), var);
447   codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
448   codegen()->DoTest(this);
449 }
450
451
452 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
453   UNREACHABLE();  // Not used on X87.
454 }
455
456
457 void FullCodeGenerator::AccumulatorValueContext::Plug(
458     Heap::RootListIndex index) const {
459   UNREACHABLE();  // Not used on X87.
460 }
461
462
463 void FullCodeGenerator::StackValueContext::Plug(
464     Heap::RootListIndex index) const {
465   UNREACHABLE();  // Not used on X87.
466 }
467
468
469 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
470   UNREACHABLE();  // Not used on X87.
471 }
472
473
474 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
475 }
476
477
478 void FullCodeGenerator::AccumulatorValueContext::Plug(
479     Handle<Object> lit) const {
480   if (lit->IsSmi()) {
481     __ SafeMove(result_register(), Immediate(lit));
482   } else {
483     __ Move(result_register(), Immediate(lit));
484   }
485 }
486
487
488 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
489   if (lit->IsSmi()) {
490     __ SafePush(Immediate(lit));
491   } else {
492     __ push(Immediate(lit));
493   }
494 }
495
496
497 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
498   codegen()->PrepareForBailoutBeforeSplit(condition(),
499                                           true,
500                                           true_label_,
501                                           false_label_);
502   DCHECK(!lit->IsUndetectableObject());  // There are no undetectable literals.
503   if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
504     if (false_label_ != fall_through_) __ jmp(false_label_);
505   } else if (lit->IsTrue() || lit->IsJSObject()) {
506     if (true_label_ != fall_through_) __ jmp(true_label_);
507   } else if (lit->IsString()) {
508     if (String::cast(*lit)->length() == 0) {
509       if (false_label_ != fall_through_) __ jmp(false_label_);
510     } else {
511       if (true_label_ != fall_through_) __ jmp(true_label_);
512     }
513   } else if (lit->IsSmi()) {
514     if (Smi::cast(*lit)->value() == 0) {
515       if (false_label_ != fall_through_) __ jmp(false_label_);
516     } else {
517       if (true_label_ != fall_through_) __ jmp(true_label_);
518     }
519   } else {
520     // For simplicity we always test the accumulator register.
521     __ mov(result_register(), lit);
522     codegen()->DoTest(this);
523   }
524 }
525
526
527 void FullCodeGenerator::EffectContext::DropAndPlug(int count,
528                                                    Register reg) const {
529   DCHECK(count > 0);
530   __ Drop(count);
531 }
532
533
534 void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
535     int count,
536     Register reg) const {
537   DCHECK(count > 0);
538   __ Drop(count);
539   __ Move(result_register(), reg);
540 }
541
542
543 void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
544                                                        Register reg) const {
545   DCHECK(count > 0);
546   if (count > 1) __ Drop(count - 1);
547   __ mov(Operand(esp, 0), reg);
548 }
549
550
551 void FullCodeGenerator::TestContext::DropAndPlug(int count,
552                                                  Register reg) const {
553   DCHECK(count > 0);
554   // For simplicity we always test the accumulator register.
555   __ Drop(count);
556   __ Move(result_register(), reg);
557   codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
558   codegen()->DoTest(this);
559 }
560
561
562 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
563                                             Label* materialize_false) const {
564   DCHECK(materialize_true == materialize_false);
565   __ bind(materialize_true);
566 }
567
568
569 void FullCodeGenerator::AccumulatorValueContext::Plug(
570     Label* materialize_true,
571     Label* materialize_false) const {
572   Label done;
573   __ bind(materialize_true);
574   __ mov(result_register(), isolate()->factory()->true_value());
575   __ jmp(&done, Label::kNear);
576   __ bind(materialize_false);
577   __ mov(result_register(), isolate()->factory()->false_value());
578   __ bind(&done);
579 }
580
581
582 void FullCodeGenerator::StackValueContext::Plug(
583     Label* materialize_true,
584     Label* materialize_false) const {
585   Label done;
586   __ bind(materialize_true);
587   __ push(Immediate(isolate()->factory()->true_value()));
588   __ jmp(&done, Label::kNear);
589   __ bind(materialize_false);
590   __ push(Immediate(isolate()->factory()->false_value()));
591   __ bind(&done);
592 }
593
594
595 void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
596                                           Label* materialize_false) const {
597   DCHECK(materialize_true == true_label_);
598   DCHECK(materialize_false == false_label_);
599 }
600
601
602 void FullCodeGenerator::EffectContext::Plug(bool flag) const {
603 }
604
605
606 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
607   Handle<Object> value = flag
608       ? isolate()->factory()->true_value()
609       : isolate()->factory()->false_value();
610   __ mov(result_register(), value);
611 }
612
613
614 void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
615   Handle<Object> value = flag
616       ? isolate()->factory()->true_value()
617       : isolate()->factory()->false_value();
618   __ push(Immediate(value));
619 }
620
621
622 void FullCodeGenerator::TestContext::Plug(bool flag) const {
623   codegen()->PrepareForBailoutBeforeSplit(condition(),
624                                           true,
625                                           true_label_,
626                                           false_label_);
627   if (flag) {
628     if (true_label_ != fall_through_) __ jmp(true_label_);
629   } else {
630     if (false_label_ != fall_through_) __ jmp(false_label_);
631   }
632 }
633
634
635 void FullCodeGenerator::DoTest(Expression* condition,
636                                Label* if_true,
637                                Label* if_false,
638                                Label* fall_through) {
639   Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
640   CallIC(ic, condition->test_id());
641   __ test(result_register(), result_register());
642   // The stub returns nonzero for true.
643   Split(not_zero, if_true, if_false, fall_through);
644 }
645
646
647 void FullCodeGenerator::Split(Condition cc,
648                               Label* if_true,
649                               Label* if_false,
650                               Label* fall_through) {
651   if (if_false == fall_through) {
652     __ j(cc, if_true);
653   } else if (if_true == fall_through) {
654     __ j(NegateCondition(cc), if_false);
655   } else {
656     __ j(cc, if_true);
657     __ jmp(if_false);
658   }
659 }
660
661
662 MemOperand FullCodeGenerator::StackOperand(Variable* var) {
663   DCHECK(var->IsStackAllocated());
664   // Offset is negative because higher indexes are at lower addresses.
665   int offset = -var->index() * kPointerSize;
666   // Adjust by a (parameter or local) base offset.
667   if (var->IsParameter()) {
668     offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
669   } else {
670     offset += JavaScriptFrameConstants::kLocal0Offset;
671   }
672   return Operand(ebp, offset);
673 }
674
675
676 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
677   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
678   if (var->IsContextSlot()) {
679     int context_chain_length = scope()->ContextChainLength(var->scope());
680     __ LoadContext(scratch, context_chain_length);
681     return ContextOperand(scratch, var->index());
682   } else {
683     return StackOperand(var);
684   }
685 }
686
687
688 void FullCodeGenerator::GetVar(Register dest, Variable* var) {
689   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
690   MemOperand location = VarOperand(var, dest);
691   __ mov(dest, location);
692 }
693
694
695 void FullCodeGenerator::SetVar(Variable* var,
696                                Register src,
697                                Register scratch0,
698                                Register scratch1) {
699   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
700   DCHECK(!scratch0.is(src));
701   DCHECK(!scratch0.is(scratch1));
702   DCHECK(!scratch1.is(src));
703   MemOperand location = VarOperand(var, scratch0);
704   __ mov(location, src);
705
706   // Emit the write barrier code if the location is in the heap.
707   if (var->IsContextSlot()) {
708     int offset = Context::SlotOffset(var->index());
709     DCHECK(!scratch0.is(esi) && !src.is(esi) && !scratch1.is(esi));
710     __ RecordWriteContextSlot(scratch0, offset, src, scratch1);
711   }
712 }
713
714
715 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
716                                                      bool should_normalize,
717                                                      Label* if_true,
718                                                      Label* if_false) {
719   // Only prepare for bailouts before splits if we're in a test
720   // context. Otherwise, we let the Visit function deal with the
721   // preparation to avoid preparing with the same AST id twice.
722   if (!context()->IsTest() || !info_->IsOptimizable()) return;
723
724   Label skip;
725   if (should_normalize) __ jmp(&skip, Label::kNear);
726   PrepareForBailout(expr, TOS_REG);
727   if (should_normalize) {
728     __ cmp(eax, isolate()->factory()->true_value());
729     Split(equal, if_true, if_false, NULL);
730     __ bind(&skip);
731   }
732 }
733
734
735 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
736   // The variable in the declaration always resides in the current context.
737   DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
738   if (generate_debug_code_) {
739     // Check that we're not inside a with or catch context.
740     __ mov(ebx, FieldOperand(esi, HeapObject::kMapOffset));
741     __ cmp(ebx, isolate()->factory()->with_context_map());
742     __ Check(not_equal, kDeclarationInWithContext);
743     __ cmp(ebx, isolate()->factory()->catch_context_map());
744     __ Check(not_equal, kDeclarationInCatchContext);
745   }
746 }
747
748
749 void FullCodeGenerator::VisitVariableDeclaration(
750     VariableDeclaration* declaration) {
751   // If it was not possible to allocate the variable at compile time, we
752   // need to "declare" it at runtime to make sure it actually exists in the
753   // local context.
754   VariableProxy* proxy = declaration->proxy();
755   VariableMode mode = declaration->mode();
756   Variable* variable = proxy->var();
757   bool hole_init = mode == LET || mode == CONST || mode == CONST_LEGACY;
758   switch (variable->location()) {
759     case Variable::UNALLOCATED:
760       globals_->Add(variable->name(), zone());
761       globals_->Add(variable->binding_needs_init()
762                         ? isolate()->factory()->the_hole_value()
763                         : isolate()->factory()->undefined_value(), zone());
764       break;
765
766     case Variable::PARAMETER:
767     case Variable::LOCAL:
768       if (hole_init) {
769         Comment cmnt(masm_, "[ VariableDeclaration");
770         __ mov(StackOperand(variable),
771                Immediate(isolate()->factory()->the_hole_value()));
772       }
773       break;
774
775     case Variable::CONTEXT:
776       if (hole_init) {
777         Comment cmnt(masm_, "[ VariableDeclaration");
778         EmitDebugCheckDeclarationContext(variable);
779         __ mov(ContextOperand(esi, variable->index()),
780                Immediate(isolate()->factory()->the_hole_value()));
781         // No write barrier since the hole value is in old space.
782         PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
783       }
784       break;
785
786     case Variable::LOOKUP: {
787       Comment cmnt(masm_, "[ VariableDeclaration");
788       __ push(esi);
789       __ push(Immediate(variable->name()));
790       // VariableDeclaration nodes are always introduced in one of four modes.
791       DCHECK(IsDeclaredVariableMode(mode));
792       PropertyAttributes attr =
793           IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
794       __ push(Immediate(Smi::FromInt(attr)));
795       // Push initial value, if any.
796       // Note: For variables we must not push an initial value (such as
797       // 'undefined') because we may have a (legal) redeclaration and we
798       // must not destroy the current value.
799       if (hole_init) {
800         __ push(Immediate(isolate()->factory()->the_hole_value()));
801       } else {
802         __ push(Immediate(Smi::FromInt(0)));  // Indicates no initial value.
803       }
804       __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
805       break;
806     }
807   }
808 }
809
810
811 void FullCodeGenerator::VisitFunctionDeclaration(
812     FunctionDeclaration* declaration) {
813   VariableProxy* proxy = declaration->proxy();
814   Variable* variable = proxy->var();
815   switch (variable->location()) {
816     case Variable::UNALLOCATED: {
817       globals_->Add(variable->name(), zone());
818       Handle<SharedFunctionInfo> function =
819           Compiler::BuildFunctionInfo(declaration->fun(), script(), info_);
820       // Check for stack-overflow exception.
821       if (function.is_null()) return SetStackOverflow();
822       globals_->Add(function, zone());
823       break;
824     }
825
826     case Variable::PARAMETER:
827     case Variable::LOCAL: {
828       Comment cmnt(masm_, "[ FunctionDeclaration");
829       VisitForAccumulatorValue(declaration->fun());
830       __ mov(StackOperand(variable), result_register());
831       break;
832     }
833
834     case Variable::CONTEXT: {
835       Comment cmnt(masm_, "[ FunctionDeclaration");
836       EmitDebugCheckDeclarationContext(variable);
837       VisitForAccumulatorValue(declaration->fun());
838       __ mov(ContextOperand(esi, variable->index()), result_register());
839       // We know that we have written a function, which is not a smi.
840       __ RecordWriteContextSlot(esi,
841                                 Context::SlotOffset(variable->index()),
842                                 result_register(),
843                                 ecx,
844                                 EMIT_REMEMBERED_SET,
845                                 OMIT_SMI_CHECK);
846       PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
847       break;
848     }
849
850     case Variable::LOOKUP: {
851       Comment cmnt(masm_, "[ FunctionDeclaration");
852       __ push(esi);
853       __ push(Immediate(variable->name()));
854       __ push(Immediate(Smi::FromInt(NONE)));
855       VisitForStackValue(declaration->fun());
856       __ CallRuntime(Runtime::kDeclareLookupSlot, 4);
857       break;
858     }
859   }
860 }
861
862
863 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
864   Variable* variable = declaration->proxy()->var();
865   DCHECK(variable->location() == Variable::CONTEXT);
866   DCHECK(variable->interface()->IsFrozen());
867
868   Comment cmnt(masm_, "[ ModuleDeclaration");
869   EmitDebugCheckDeclarationContext(variable);
870
871   // Load instance object.
872   __ LoadContext(eax, scope_->ContextChainLength(scope_->GlobalScope()));
873   __ mov(eax, ContextOperand(eax, variable->interface()->Index()));
874   __ mov(eax, ContextOperand(eax, Context::EXTENSION_INDEX));
875
876   // Assign it.
877   __ mov(ContextOperand(esi, variable->index()), eax);
878   // We know that we have written a module, which is not a smi.
879   __ RecordWriteContextSlot(esi,
880                             Context::SlotOffset(variable->index()),
881                             eax,
882                             ecx,
883                             EMIT_REMEMBERED_SET,
884                             OMIT_SMI_CHECK);
885   PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
886
887   // Traverse into body.
888   Visit(declaration->module());
889 }
890
891
892 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
893   VariableProxy* proxy = declaration->proxy();
894   Variable* variable = proxy->var();
895   switch (variable->location()) {
896     case Variable::UNALLOCATED:
897       // TODO(rossberg)
898       break;
899
900     case Variable::CONTEXT: {
901       Comment cmnt(masm_, "[ ImportDeclaration");
902       EmitDebugCheckDeclarationContext(variable);
903       // TODO(rossberg)
904       break;
905     }
906
907     case Variable::PARAMETER:
908     case Variable::LOCAL:
909     case Variable::LOOKUP:
910       UNREACHABLE();
911   }
912 }
913
914
915 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
916   // TODO(rossberg)
917 }
918
919
920 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
921   // Call the runtime to declare the globals.
922   __ push(esi);  // The context is the first argument.
923   __ Push(pairs);
924   __ Push(Smi::FromInt(DeclareGlobalsFlags()));
925   __ CallRuntime(Runtime::kDeclareGlobals, 3);
926   // Return value is ignored.
927 }
928
929
930 void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
931   // Call the runtime to declare the modules.
932   __ Push(descriptions);
933   __ CallRuntime(Runtime::kDeclareModules, 1);
934   // Return value is ignored.
935 }
936
937
938 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
939   Comment cmnt(masm_, "[ SwitchStatement");
940   Breakable nested_statement(this, stmt);
941   SetStatementPosition(stmt);
942
943   // Keep the switch value on the stack until a case matches.
944   VisitForStackValue(stmt->tag());
945   PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
946
947   ZoneList<CaseClause*>* clauses = stmt->cases();
948   CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
949
950   Label next_test;  // Recycled for each test.
951   // Compile all the tests with branches to their bodies.
952   for (int i = 0; i < clauses->length(); i++) {
953     CaseClause* clause = clauses->at(i);
954     clause->body_target()->Unuse();
955
956     // The default is not a test, but remember it as final fall through.
957     if (clause->is_default()) {
958       default_clause = clause;
959       continue;
960     }
961
962     Comment cmnt(masm_, "[ Case comparison");
963     __ bind(&next_test);
964     next_test.Unuse();
965
966     // Compile the label expression.
967     VisitForAccumulatorValue(clause->label());
968
969     // Perform the comparison as if via '==='.
970     __ mov(edx, Operand(esp, 0));  // Switch value.
971     bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
972     JumpPatchSite patch_site(masm_);
973     if (inline_smi_code) {
974       Label slow_case;
975       __ mov(ecx, edx);
976       __ or_(ecx, eax);
977       patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
978
979       __ cmp(edx, eax);
980       __ j(not_equal, &next_test);
981       __ Drop(1);  // Switch value is no longer needed.
982       __ jmp(clause->body_target());
983       __ bind(&slow_case);
984     }
985
986     // Record position before stub call for type feedback.
987     SetSourcePosition(clause->position());
988     Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT);
989     CallIC(ic, clause->CompareId());
990     patch_site.EmitPatchInfo();
991
992     Label skip;
993     __ jmp(&skip, Label::kNear);
994     PrepareForBailout(clause, TOS_REG);
995     __ cmp(eax, isolate()->factory()->true_value());
996     __ j(not_equal, &next_test);
997     __ Drop(1);
998     __ jmp(clause->body_target());
999     __ bind(&skip);
1000
1001     __ test(eax, eax);
1002     __ j(not_equal, &next_test);
1003     __ Drop(1);  // Switch value is no longer needed.
1004     __ jmp(clause->body_target());
1005   }
1006
1007   // Discard the test value and jump to the default if present, otherwise to
1008   // the end of the statement.
1009   __ bind(&next_test);
1010   __ Drop(1);  // Switch value is no longer needed.
1011   if (default_clause == NULL) {
1012     __ jmp(nested_statement.break_label());
1013   } else {
1014     __ jmp(default_clause->body_target());
1015   }
1016
1017   // Compile all the case bodies.
1018   for (int i = 0; i < clauses->length(); i++) {
1019     Comment cmnt(masm_, "[ Case body");
1020     CaseClause* clause = clauses->at(i);
1021     __ bind(clause->body_target());
1022     PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
1023     VisitStatements(clause->statements());
1024   }
1025
1026   __ bind(nested_statement.break_label());
1027   PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1028 }
1029
1030
1031 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
1032   Comment cmnt(masm_, "[ ForInStatement");
1033   int slot = stmt->ForInFeedbackSlot();
1034
1035   SetStatementPosition(stmt);
1036
1037   Label loop, exit;
1038   ForIn loop_statement(this, stmt);
1039   increment_loop_depth();
1040
1041   // Get the object to enumerate over. If the object is null or undefined, skip
1042   // over the loop.  See ECMA-262 version 5, section 12.6.4.
1043   VisitForAccumulatorValue(stmt->enumerable());
1044   __ cmp(eax, isolate()->factory()->undefined_value());
1045   __ j(equal, &exit);
1046   __ cmp(eax, isolate()->factory()->null_value());
1047   __ j(equal, &exit);
1048
1049   PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1050
1051   // Convert the object to a JS object.
1052   Label convert, done_convert;
1053   __ JumpIfSmi(eax, &convert, Label::kNear);
1054   __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ecx);
1055   __ j(above_equal, &done_convert, Label::kNear);
1056   __ bind(&convert);
1057   __ push(eax);
1058   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1059   __ bind(&done_convert);
1060   __ push(eax);
1061
1062   // Check for proxies.
1063   Label call_runtime, use_cache, fixed_array;
1064   STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1065   __ CmpObjectType(eax, LAST_JS_PROXY_TYPE, ecx);
1066   __ j(below_equal, &call_runtime);
1067
1068   // Check cache validity in generated code. This is a fast case for
1069   // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1070   // guarantee cache validity, call the runtime system to check cache
1071   // validity or get the property names in a fixed array.
1072   __ CheckEnumCache(&call_runtime);
1073
1074   __ mov(eax, FieldOperand(eax, HeapObject::kMapOffset));
1075   __ jmp(&use_cache, Label::kNear);
1076
1077   // Get the set of properties to enumerate.
1078   __ bind(&call_runtime);
1079   __ push(eax);
1080   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1081   __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
1082          isolate()->factory()->meta_map());
1083   __ j(not_equal, &fixed_array);
1084
1085
1086   // We got a map in register eax. Get the enumeration cache from it.
1087   Label no_descriptors;
1088   __ bind(&use_cache);
1089
1090   __ EnumLength(edx, eax);
1091   __ cmp(edx, Immediate(Smi::FromInt(0)));
1092   __ j(equal, &no_descriptors);
1093
1094   __ LoadInstanceDescriptors(eax, ecx);
1095   __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheOffset));
1096   __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1097
1098   // Set up the four remaining stack slots.
1099   __ push(eax);  // Map.
1100   __ push(ecx);  // Enumeration cache.
1101   __ push(edx);  // Number of valid entries for the map in the enum cache.
1102   __ push(Immediate(Smi::FromInt(0)));  // Initial index.
1103   __ jmp(&loop);
1104
1105   __ bind(&no_descriptors);
1106   __ add(esp, Immediate(kPointerSize));
1107   __ jmp(&exit);
1108
1109   // We got a fixed array in register eax. Iterate through that.
1110   Label non_proxy;
1111   __ bind(&fixed_array);
1112
1113   // No need for a write barrier, we are storing a Smi in the feedback vector.
1114   __ LoadHeapObject(ebx, FeedbackVector());
1115   __ mov(FieldOperand(ebx, FixedArray::OffsetOfElementAt(slot)),
1116          Immediate(TypeFeedbackInfo::MegamorphicSentinel(isolate())));
1117
1118   __ mov(ebx, Immediate(Smi::FromInt(1)));  // Smi indicates slow check
1119   __ mov(ecx, Operand(esp, 0 * kPointerSize));  // Get enumerated object
1120   STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1121   __ CmpObjectType(ecx, LAST_JS_PROXY_TYPE, ecx);
1122   __ j(above, &non_proxy);
1123   __ Move(ebx, Immediate(Smi::FromInt(0)));  // Zero indicates proxy
1124   __ bind(&non_proxy);
1125   __ push(ebx);  // Smi
1126   __ push(eax);  // Array
1127   __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
1128   __ push(eax);  // Fixed array length (as smi).
1129   __ push(Immediate(Smi::FromInt(0)));  // Initial index.
1130
1131   // Generate code for doing the condition check.
1132   PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1133   __ bind(&loop);
1134   __ mov(eax, Operand(esp, 0 * kPointerSize));  // Get the current index.
1135   __ cmp(eax, Operand(esp, 1 * kPointerSize));  // Compare to the array length.
1136   __ j(above_equal, loop_statement.break_label());
1137
1138   // Get the current entry of the array into register ebx.
1139   __ mov(ebx, Operand(esp, 2 * kPointerSize));
1140   __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1141
1142   // Get the expected map from the stack or a smi in the
1143   // permanent slow case into register edx.
1144   __ mov(edx, Operand(esp, 3 * kPointerSize));
1145
1146   // Check if the expected map still matches that of the enumerable.
1147   // If not, we may have to filter the key.
1148   Label update_each;
1149   __ mov(ecx, Operand(esp, 4 * kPointerSize));
1150   __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
1151   __ j(equal, &update_each, Label::kNear);
1152
1153   // For proxies, no filtering is done.
1154   // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1155   DCHECK(Smi::FromInt(0) == 0);
1156   __ test(edx, edx);
1157   __ j(zero, &update_each);
1158
1159   // Convert the entry to a string or null if it isn't a property
1160   // anymore. If the property has been removed while iterating, we
1161   // just skip it.
1162   __ push(ecx);  // Enumerable.
1163   __ push(ebx);  // Current entry.
1164   __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
1165   __ test(eax, eax);
1166   __ j(equal, loop_statement.continue_label());
1167   __ mov(ebx, eax);
1168
1169   // Update the 'each' property or variable from the possibly filtered
1170   // entry in register ebx.
1171   __ bind(&update_each);
1172   __ mov(result_register(), ebx);
1173   // Perform the assignment as if via '='.
1174   { EffectContext context(this);
1175     EmitAssignment(stmt->each());
1176   }
1177
1178   // Generate code for the body of the loop.
1179   Visit(stmt->body());
1180
1181   // Generate code for going to the next element by incrementing the
1182   // index (smi) stored on top of the stack.
1183   __ bind(loop_statement.continue_label());
1184   __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1185
1186   EmitBackEdgeBookkeeping(stmt, &loop);
1187   __ jmp(&loop);
1188
1189   // Remove the pointers stored on the stack.
1190   __ bind(loop_statement.break_label());
1191   __ add(esp, Immediate(5 * kPointerSize));
1192
1193   // Exit and decrement the loop depth.
1194   PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1195   __ bind(&exit);
1196   decrement_loop_depth();
1197 }
1198
1199
1200 void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1201   Comment cmnt(masm_, "[ ForOfStatement");
1202   SetStatementPosition(stmt);
1203
1204   Iteration loop_statement(this, stmt);
1205   increment_loop_depth();
1206
1207   // var iterator = iterable[Symbol.iterator]();
1208   VisitForEffect(stmt->assign_iterator());
1209
1210   // Loop entry.
1211   __ bind(loop_statement.continue_label());
1212
1213   // result = iterator.next()
1214   VisitForEffect(stmt->next_result());
1215
1216   // if (result.done) break;
1217   Label result_not_done;
1218   VisitForControl(stmt->result_done(),
1219                   loop_statement.break_label(),
1220                   &result_not_done,
1221                   &result_not_done);
1222   __ bind(&result_not_done);
1223
1224   // each = result.value
1225   VisitForEffect(stmt->assign_each());
1226
1227   // Generate code for the body of the loop.
1228   Visit(stmt->body());
1229
1230   // Check stack before looping.
1231   PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
1232   EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
1233   __ jmp(loop_statement.continue_label());
1234
1235   // Exit and decrement the loop depth.
1236   PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1237   __ bind(loop_statement.break_label());
1238   decrement_loop_depth();
1239 }
1240
1241
1242 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1243                                        bool pretenure) {
1244   // Use the fast case closure allocation code that allocates in new
1245   // space for nested functions that don't need literals cloning. If
1246   // we're running with the --always-opt or the --prepare-always-opt
1247   // flag, we need to use the runtime function so that the new function
1248   // we are creating here gets a chance to have its code optimized and
1249   // doesn't just get a copy of the existing unoptimized code.
1250   if (!FLAG_always_opt &&
1251       !FLAG_prepare_always_opt &&
1252       !pretenure &&
1253       scope()->is_function_scope() &&
1254       info->num_literals() == 0) {
1255     FastNewClosureStub stub(isolate(),
1256                             info->strict_mode(),
1257                             info->is_generator());
1258     __ mov(ebx, Immediate(info));
1259     __ CallStub(&stub);
1260   } else {
1261     __ push(esi);
1262     __ push(Immediate(info));
1263     __ push(Immediate(pretenure
1264                       ? isolate()->factory()->true_value()
1265                       : isolate()->factory()->false_value()));
1266     __ CallRuntime(Runtime::kNewClosure, 3);
1267   }
1268   context()->Plug(eax);
1269 }
1270
1271
1272 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1273   Comment cmnt(masm_, "[ VariableProxy");
1274   EmitVariableLoad(expr);
1275 }
1276
1277
1278 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1279                                                       TypeofState typeof_state,
1280                                                       Label* slow) {
1281   Register context = esi;
1282   Register temp = edx;
1283
1284   Scope* s = scope();
1285   while (s != NULL) {
1286     if (s->num_heap_slots() > 0) {
1287       if (s->calls_sloppy_eval()) {
1288         // Check that extension is NULL.
1289         __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1290                Immediate(0));
1291         __ j(not_equal, slow);
1292       }
1293       // Load next context in chain.
1294       __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1295       // Walk the rest of the chain without clobbering esi.
1296       context = temp;
1297     }
1298     // If no outer scope calls eval, we do not need to check more
1299     // context extensions.  If we have reached an eval scope, we check
1300     // all extensions from this point.
1301     if (!s->outer_scope_calls_sloppy_eval() || s->is_eval_scope()) break;
1302     s = s->outer_scope();
1303   }
1304
1305   if (s != NULL && s->is_eval_scope()) {
1306     // Loop up the context chain.  There is no frame effect so it is
1307     // safe to use raw labels here.
1308     Label next, fast;
1309     if (!context.is(temp)) {
1310       __ mov(temp, context);
1311     }
1312     __ bind(&next);
1313     // Terminate at native context.
1314     __ cmp(FieldOperand(temp, HeapObject::kMapOffset),
1315            Immediate(isolate()->factory()->native_context_map()));
1316     __ j(equal, &fast, Label::kNear);
1317     // Check that extension is NULL.
1318     __ cmp(ContextOperand(temp, Context::EXTENSION_INDEX), Immediate(0));
1319     __ j(not_equal, slow);
1320     // Load next context in chain.
1321     __ mov(temp, ContextOperand(temp, Context::PREVIOUS_INDEX));
1322     __ jmp(&next);
1323     __ bind(&fast);
1324   }
1325
1326   // All extension objects were empty and it is safe to use a global
1327   // load IC call.
1328   __ mov(LoadIC::ReceiverRegister(), GlobalObjectOperand());
1329   __ mov(LoadIC::NameRegister(), proxy->var()->name());
1330   if (FLAG_vector_ics) {
1331     __ mov(LoadIC::SlotRegister(),
1332            Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
1333   }
1334
1335   ContextualMode mode = (typeof_state == INSIDE_TYPEOF)
1336       ? NOT_CONTEXTUAL
1337       : CONTEXTUAL;
1338
1339   CallLoadIC(mode);
1340 }
1341
1342
1343 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1344                                                                 Label* slow) {
1345   DCHECK(var->IsContextSlot());
1346   Register context = esi;
1347   Register temp = ebx;
1348
1349   for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1350     if (s->num_heap_slots() > 0) {
1351       if (s->calls_sloppy_eval()) {
1352         // Check that extension is NULL.
1353         __ cmp(ContextOperand(context, Context::EXTENSION_INDEX),
1354                Immediate(0));
1355         __ j(not_equal, slow);
1356       }
1357       __ mov(temp, ContextOperand(context, Context::PREVIOUS_INDEX));
1358       // Walk the rest of the chain without clobbering esi.
1359       context = temp;
1360     }
1361   }
1362   // Check that last extension is NULL.
1363   __ cmp(ContextOperand(context, Context::EXTENSION_INDEX), Immediate(0));
1364   __ j(not_equal, slow);
1365
1366   // This function is used only for loads, not stores, so it's safe to
1367   // return an esi-based operand (the write barrier cannot be allowed to
1368   // destroy the esi register).
1369   return ContextOperand(context, var->index());
1370 }
1371
1372
1373 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1374                                                   TypeofState typeof_state,
1375                                                   Label* slow,
1376                                                   Label* done) {
1377   // Generate fast-case code for variables that might be shadowed by
1378   // eval-introduced variables.  Eval is used a lot without
1379   // introducing variables.  In those cases, we do not want to
1380   // perform a runtime call for all variables in the scope
1381   // containing the eval.
1382   Variable* var = proxy->var();
1383   if (var->mode() == DYNAMIC_GLOBAL) {
1384     EmitLoadGlobalCheckExtensions(proxy, typeof_state, slow);
1385     __ jmp(done);
1386   } else if (var->mode() == DYNAMIC_LOCAL) {
1387     Variable* local = var->local_if_not_shadowed();
1388     __ mov(eax, ContextSlotOperandCheckExtensions(local, slow));
1389     if (local->mode() == LET || local->mode() == CONST ||
1390         local->mode() == CONST_LEGACY) {
1391       __ cmp(eax, isolate()->factory()->the_hole_value());
1392       __ j(not_equal, done);
1393       if (local->mode() == CONST_LEGACY) {
1394         __ mov(eax, isolate()->factory()->undefined_value());
1395       } else {  // LET || CONST
1396         __ push(Immediate(var->name()));
1397         __ CallRuntime(Runtime::kThrowReferenceError, 1);
1398       }
1399     }
1400     __ jmp(done);
1401   }
1402 }
1403
1404
1405 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1406   // Record position before possible IC call.
1407   SetSourcePosition(proxy->position());
1408   Variable* var = proxy->var();
1409
1410   // Three cases: global variables, lookup variables, and all other types of
1411   // variables.
1412   switch (var->location()) {
1413     case Variable::UNALLOCATED: {
1414       Comment cmnt(masm_, "[ Global variable");
1415       __ mov(LoadIC::ReceiverRegister(), GlobalObjectOperand());
1416       __ mov(LoadIC::NameRegister(), var->name());
1417       if (FLAG_vector_ics) {
1418         __ mov(LoadIC::SlotRegister(),
1419                Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
1420       }
1421       CallLoadIC(CONTEXTUAL);
1422       context()->Plug(eax);
1423       break;
1424     }
1425
1426     case Variable::PARAMETER:
1427     case Variable::LOCAL:
1428     case Variable::CONTEXT: {
1429       Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1430                                                : "[ Stack variable");
1431       if (var->binding_needs_init()) {
1432         // var->scope() may be NULL when the proxy is located in eval code and
1433         // refers to a potential outside binding. Currently those bindings are
1434         // always looked up dynamically, i.e. in that case
1435         //     var->location() == LOOKUP.
1436         // always holds.
1437         DCHECK(var->scope() != NULL);
1438
1439         // Check if the binding really needs an initialization check. The check
1440         // can be skipped in the following situation: we have a LET or CONST
1441         // binding in harmony mode, both the Variable and the VariableProxy have
1442         // the same declaration scope (i.e. they are both in global code, in the
1443         // same function or in the same eval code) and the VariableProxy is in
1444         // the source physically located after the initializer of the variable.
1445         //
1446         // We cannot skip any initialization checks for CONST in non-harmony
1447         // mode because const variables may be declared but never initialized:
1448         //   if (false) { const x; }; var y = x;
1449         //
1450         // The condition on the declaration scopes is a conservative check for
1451         // nested functions that access a binding and are called before the
1452         // binding is initialized:
1453         //   function() { f(); let x = 1; function f() { x = 2; } }
1454         //
1455         bool skip_init_check;
1456         if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1457           skip_init_check = false;
1458         } else {
1459           // Check that we always have valid source position.
1460           DCHECK(var->initializer_position() != RelocInfo::kNoPosition);
1461           DCHECK(proxy->position() != RelocInfo::kNoPosition);
1462           skip_init_check = var->mode() != CONST_LEGACY &&
1463               var->initializer_position() < proxy->position();
1464         }
1465
1466         if (!skip_init_check) {
1467           // Let and const need a read barrier.
1468           Label done;
1469           GetVar(eax, var);
1470           __ cmp(eax, isolate()->factory()->the_hole_value());
1471           __ j(not_equal, &done, Label::kNear);
1472           if (var->mode() == LET || var->mode() == CONST) {
1473             // Throw a reference error when using an uninitialized let/const
1474             // binding in harmony mode.
1475             __ push(Immediate(var->name()));
1476             __ CallRuntime(Runtime::kThrowReferenceError, 1);
1477           } else {
1478             // Uninitalized const bindings outside of harmony mode are unholed.
1479             DCHECK(var->mode() == CONST_LEGACY);
1480             __ mov(eax, isolate()->factory()->undefined_value());
1481           }
1482           __ bind(&done);
1483           context()->Plug(eax);
1484           break;
1485         }
1486       }
1487       context()->Plug(var);
1488       break;
1489     }
1490
1491     case Variable::LOOKUP: {
1492       Comment cmnt(masm_, "[ Lookup variable");
1493       Label done, slow;
1494       // Generate code for loading from variables potentially shadowed
1495       // by eval-introduced variables.
1496       EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
1497       __ bind(&slow);
1498       __ push(esi);  // Context.
1499       __ push(Immediate(var->name()));
1500       __ CallRuntime(Runtime::kLoadLookupSlot, 2);
1501       __ bind(&done);
1502       context()->Plug(eax);
1503       break;
1504     }
1505   }
1506 }
1507
1508
1509 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1510   Comment cmnt(masm_, "[ RegExpLiteral");
1511   Label materialized;
1512   // Registers will be used as follows:
1513   // edi = JS function.
1514   // ecx = literals array.
1515   // ebx = regexp literal.
1516   // eax = regexp literal clone.
1517   __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1518   __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
1519   int literal_offset =
1520       FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
1521   __ mov(ebx, FieldOperand(ecx, literal_offset));
1522   __ cmp(ebx, isolate()->factory()->undefined_value());
1523   __ j(not_equal, &materialized, Label::kNear);
1524
1525   // Create regexp literal using runtime function
1526   // Result will be in eax.
1527   __ push(ecx);
1528   __ push(Immediate(Smi::FromInt(expr->literal_index())));
1529   __ push(Immediate(expr->pattern()));
1530   __ push(Immediate(expr->flags()));
1531   __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
1532   __ mov(ebx, eax);
1533
1534   __ bind(&materialized);
1535   int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1536   Label allocated, runtime_allocate;
1537   __ Allocate(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1538   __ jmp(&allocated);
1539
1540   __ bind(&runtime_allocate);
1541   __ push(ebx);
1542   __ push(Immediate(Smi::FromInt(size)));
1543   __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1544   __ pop(ebx);
1545
1546   __ bind(&allocated);
1547   // Copy the content into the newly allocated memory.
1548   // (Unroll copy loop once for better throughput).
1549   for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1550     __ mov(edx, FieldOperand(ebx, i));
1551     __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1552     __ mov(FieldOperand(eax, i), edx);
1553     __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1554   }
1555   if ((size % (2 * kPointerSize)) != 0) {
1556     __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1557     __ mov(FieldOperand(eax, size - kPointerSize), edx);
1558   }
1559   context()->Plug(eax);
1560 }
1561
1562
1563 void FullCodeGenerator::EmitAccessor(Expression* expression) {
1564   if (expression == NULL) {
1565     __ push(Immediate(isolate()->factory()->null_value()));
1566   } else {
1567     VisitForStackValue(expression);
1568   }
1569 }
1570
1571
1572 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1573   Comment cmnt(masm_, "[ ObjectLiteral");
1574
1575   expr->BuildConstantProperties(isolate());
1576   Handle<FixedArray> constant_properties = expr->constant_properties();
1577   int flags = expr->fast_elements()
1578       ? ObjectLiteral::kFastElements
1579       : ObjectLiteral::kNoFlags;
1580   flags |= expr->has_function()
1581       ? ObjectLiteral::kHasFunction
1582       : ObjectLiteral::kNoFlags;
1583   int properties_count = constant_properties->length() / 2;
1584   if (expr->may_store_doubles() || expr->depth() > 1 ||
1585       masm()->serializer_enabled() ||
1586       flags != ObjectLiteral::kFastElements ||
1587       properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
1588     __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1589     __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1590     __ push(Immediate(Smi::FromInt(expr->literal_index())));
1591     __ push(Immediate(constant_properties));
1592     __ push(Immediate(Smi::FromInt(flags)));
1593     __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
1594   } else {
1595     __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1596     __ mov(eax, FieldOperand(edi, JSFunction::kLiteralsOffset));
1597     __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1598     __ mov(ecx, Immediate(constant_properties));
1599     __ mov(edx, Immediate(Smi::FromInt(flags)));
1600     FastCloneShallowObjectStub stub(isolate(), properties_count);
1601     __ CallStub(&stub);
1602   }
1603
1604   // If result_saved is true the result is on top of the stack.  If
1605   // result_saved is false the result is in eax.
1606   bool result_saved = false;
1607
1608   // Mark all computed expressions that are bound to a key that
1609   // is shadowed by a later occurrence of the same key. For the
1610   // marked expressions, no store code is emitted.
1611   expr->CalculateEmitStore(zone());
1612
1613   AccessorTable accessor_table(zone());
1614   for (int i = 0; i < expr->properties()->length(); i++) {
1615     ObjectLiteral::Property* property = expr->properties()->at(i);
1616     if (property->IsCompileTimeValue()) continue;
1617
1618     Literal* key = property->key();
1619     Expression* value = property->value();
1620     if (!result_saved) {
1621       __ push(eax);  // Save result on the stack
1622       result_saved = true;
1623     }
1624     switch (property->kind()) {
1625       case ObjectLiteral::Property::CONSTANT:
1626         UNREACHABLE();
1627       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1628         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
1629         // Fall through.
1630       case ObjectLiteral::Property::COMPUTED:
1631         if (key->value()->IsInternalizedString()) {
1632           if (property->emit_store()) {
1633             VisitForAccumulatorValue(value);
1634             DCHECK(StoreIC::ValueRegister().is(eax));
1635             __ mov(StoreIC::NameRegister(), Immediate(key->value()));
1636             __ mov(StoreIC::ReceiverRegister(), Operand(esp, 0));
1637             CallStoreIC(key->LiteralFeedbackId());
1638             PrepareForBailoutForId(key->id(), NO_REGISTERS);
1639           } else {
1640             VisitForEffect(value);
1641           }
1642           break;
1643         }
1644         __ push(Operand(esp, 0));  // Duplicate receiver.
1645         VisitForStackValue(key);
1646         VisitForStackValue(value);
1647         if (property->emit_store()) {
1648           __ push(Immediate(Smi::FromInt(SLOPPY)));  // Strict mode
1649           __ CallRuntime(Runtime::kSetProperty, 4);
1650         } else {
1651           __ Drop(3);
1652         }
1653         break;
1654       case ObjectLiteral::Property::PROTOTYPE:
1655         __ push(Operand(esp, 0));  // Duplicate receiver.
1656         VisitForStackValue(value);
1657         if (property->emit_store()) {
1658           __ CallRuntime(Runtime::kSetPrototype, 2);
1659         } else {
1660           __ Drop(2);
1661         }
1662         break;
1663       case ObjectLiteral::Property::GETTER:
1664         accessor_table.lookup(key)->second->getter = value;
1665         break;
1666       case ObjectLiteral::Property::SETTER:
1667         accessor_table.lookup(key)->second->setter = value;
1668         break;
1669     }
1670   }
1671
1672   // Emit code to define accessors, using only a single call to the runtime for
1673   // each pair of corresponding getters and setters.
1674   for (AccessorTable::Iterator it = accessor_table.begin();
1675        it != accessor_table.end();
1676        ++it) {
1677     __ push(Operand(esp, 0));  // Duplicate receiver.
1678     VisitForStackValue(it->first);
1679     EmitAccessor(it->second->getter);
1680     EmitAccessor(it->second->setter);
1681     __ push(Immediate(Smi::FromInt(NONE)));
1682     __ CallRuntime(Runtime::kDefineAccessorPropertyUnchecked, 5);
1683   }
1684
1685   if (expr->has_function()) {
1686     DCHECK(result_saved);
1687     __ push(Operand(esp, 0));
1688     __ CallRuntime(Runtime::kToFastProperties, 1);
1689   }
1690
1691   if (result_saved) {
1692     context()->PlugTOS();
1693   } else {
1694     context()->Plug(eax);
1695   }
1696 }
1697
1698
1699 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1700   Comment cmnt(masm_, "[ ArrayLiteral");
1701
1702   expr->BuildConstantElements(isolate());
1703   int flags = expr->depth() == 1
1704       ? ArrayLiteral::kShallowElements
1705       : ArrayLiteral::kNoFlags;
1706
1707   ZoneList<Expression*>* subexprs = expr->values();
1708   int length = subexprs->length();
1709   Handle<FixedArray> constant_elements = expr->constant_elements();
1710   DCHECK_EQ(2, constant_elements->length());
1711   ElementsKind constant_elements_kind =
1712       static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
1713   bool has_constant_fast_elements =
1714       IsFastObjectElementsKind(constant_elements_kind);
1715   Handle<FixedArrayBase> constant_elements_values(
1716       FixedArrayBase::cast(constant_elements->get(1)));
1717
1718   AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1719   if (has_constant_fast_elements && !FLAG_allocation_site_pretenuring) {
1720     // If the only customer of allocation sites is transitioning, then
1721     // we can turn it off if we don't have anywhere else to transition to.
1722     allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1723   }
1724
1725   if (expr->depth() > 1 || length > JSObject::kInitialMaxFastElementArray) {
1726     __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1727     __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1728     __ push(Immediate(Smi::FromInt(expr->literal_index())));
1729     __ push(Immediate(constant_elements));
1730     __ push(Immediate(Smi::FromInt(flags)));
1731     __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
1732   } else {
1733     __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1734     __ mov(eax, FieldOperand(ebx, JSFunction::kLiteralsOffset));
1735     __ mov(ebx, Immediate(Smi::FromInt(expr->literal_index())));
1736     __ mov(ecx, Immediate(constant_elements));
1737     FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1738     __ CallStub(&stub);
1739   }
1740
1741   bool result_saved = false;  // Is the result saved to the stack?
1742
1743   // Emit code to evaluate all the non-constant subexpressions and to store
1744   // them into the newly cloned array.
1745   for (int i = 0; i < length; i++) {
1746     Expression* subexpr = subexprs->at(i);
1747     // If the subexpression is a literal or a simple materialized literal it
1748     // is already set in the cloned array.
1749     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1750
1751     if (!result_saved) {
1752       __ push(eax);  // array literal.
1753       __ push(Immediate(Smi::FromInt(expr->literal_index())));
1754       result_saved = true;
1755     }
1756     VisitForAccumulatorValue(subexpr);
1757
1758     if (IsFastObjectElementsKind(constant_elements_kind)) {
1759       // Fast-case array literal with ElementsKind of FAST_*_ELEMENTS, they
1760       // cannot transition and don't need to call the runtime stub.
1761       int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1762       __ mov(ebx, Operand(esp, kPointerSize));  // Copy of array literal.
1763       __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1764       // Store the subexpression value in the array's elements.
1765       __ mov(FieldOperand(ebx, offset), result_register());
1766       // Update the write barrier for the array store.
1767       __ RecordWriteField(ebx, offset, result_register(), ecx,
1768                           EMIT_REMEMBERED_SET,
1769                           INLINE_SMI_CHECK);
1770     } else {
1771       // Store the subexpression value in the array's elements.
1772       __ mov(ecx, Immediate(Smi::FromInt(i)));
1773       StoreArrayLiteralElementStub stub(isolate());
1774       __ CallStub(&stub);
1775     }
1776
1777     PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
1778   }
1779
1780   if (result_saved) {
1781     __ add(esp, Immediate(kPointerSize));  // literal index
1782     context()->PlugTOS();
1783   } else {
1784     context()->Plug(eax);
1785   }
1786 }
1787
1788
1789 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1790   DCHECK(expr->target()->IsValidReferenceExpression());
1791
1792   Comment cmnt(masm_, "[ Assignment");
1793
1794   // Left-hand side can only be a property, a global or a (parameter or local)
1795   // slot.
1796   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1797   LhsKind assign_type = VARIABLE;
1798   Property* property = expr->target()->AsProperty();
1799   if (property != NULL) {
1800     assign_type = (property->key()->IsPropertyName())
1801         ? NAMED_PROPERTY
1802         : KEYED_PROPERTY;
1803   }
1804
1805   // Evaluate LHS expression.
1806   switch (assign_type) {
1807     case VARIABLE:
1808       // Nothing to do here.
1809       break;
1810     case NAMED_PROPERTY:
1811       if (expr->is_compound()) {
1812         // We need the receiver both on the stack and in the register.
1813         VisitForStackValue(property->obj());
1814         __ mov(LoadIC::ReceiverRegister(), Operand(esp, 0));
1815       } else {
1816         VisitForStackValue(property->obj());
1817       }
1818       break;
1819     case KEYED_PROPERTY: {
1820       if (expr->is_compound()) {
1821         VisitForStackValue(property->obj());
1822         VisitForStackValue(property->key());
1823         __ mov(LoadIC::ReceiverRegister(), Operand(esp, kPointerSize));
1824         __ mov(LoadIC::NameRegister(), Operand(esp, 0));
1825       } else {
1826         VisitForStackValue(property->obj());
1827         VisitForStackValue(property->key());
1828       }
1829       break;
1830     }
1831   }
1832
1833   // For compound assignments we need another deoptimization point after the
1834   // variable/property load.
1835   if (expr->is_compound()) {
1836     AccumulatorValueContext result_context(this);
1837     { AccumulatorValueContext left_operand_context(this);
1838       switch (assign_type) {
1839         case VARIABLE:
1840           EmitVariableLoad(expr->target()->AsVariableProxy());
1841           PrepareForBailout(expr->target(), TOS_REG);
1842           break;
1843         case NAMED_PROPERTY:
1844           EmitNamedPropertyLoad(property);
1845           PrepareForBailoutForId(property->LoadId(), TOS_REG);
1846           break;
1847         case KEYED_PROPERTY:
1848           EmitKeyedPropertyLoad(property);
1849           PrepareForBailoutForId(property->LoadId(), TOS_REG);
1850           break;
1851       }
1852     }
1853
1854     Token::Value op = expr->binary_op();
1855     __ push(eax);  // Left operand goes on the stack.
1856     VisitForAccumulatorValue(expr->value());
1857
1858     OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1859         ? OVERWRITE_RIGHT
1860         : NO_OVERWRITE;
1861     SetSourcePosition(expr->position() + 1);
1862     if (ShouldInlineSmiCase(op)) {
1863       EmitInlineSmiBinaryOp(expr->binary_operation(),
1864                             op,
1865                             mode,
1866                             expr->target(),
1867                             expr->value());
1868     } else {
1869       EmitBinaryOp(expr->binary_operation(), op, mode);
1870     }
1871
1872     // Deoptimization point in case the binary operation may have side effects.
1873     PrepareForBailout(expr->binary_operation(), TOS_REG);
1874   } else {
1875     VisitForAccumulatorValue(expr->value());
1876   }
1877
1878   // Record source position before possible IC call.
1879   SetSourcePosition(expr->position());
1880
1881   // Store the value.
1882   switch (assign_type) {
1883     case VARIABLE:
1884       EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
1885                              expr->op());
1886       PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1887       context()->Plug(eax);
1888       break;
1889     case NAMED_PROPERTY:
1890       EmitNamedPropertyAssignment(expr);
1891       break;
1892     case KEYED_PROPERTY:
1893       EmitKeyedPropertyAssignment(expr);
1894       break;
1895   }
1896 }
1897
1898
1899 void FullCodeGenerator::VisitYield(Yield* expr) {
1900   Comment cmnt(masm_, "[ Yield");
1901   // Evaluate yielded value first; the initial iterator definition depends on
1902   // this.  It stays on the stack while we update the iterator.
1903   VisitForStackValue(expr->expression());
1904
1905   switch (expr->yield_kind()) {
1906     case Yield::SUSPEND:
1907       // Pop value from top-of-stack slot; box result into result register.
1908       EmitCreateIteratorResult(false);
1909       __ push(result_register());
1910       // Fall through.
1911     case Yield::INITIAL: {
1912       Label suspend, continuation, post_runtime, resume;
1913
1914       __ jmp(&suspend);
1915
1916       __ bind(&continuation);
1917       __ jmp(&resume);
1918
1919       __ bind(&suspend);
1920       VisitForAccumulatorValue(expr->generator_object());
1921       DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1922       __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1923              Immediate(Smi::FromInt(continuation.pos())));
1924       __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1925       __ mov(ecx, esi);
1926       __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx);
1927       __ lea(ebx, Operand(ebp, StandardFrameConstants::kExpressionsOffset));
1928       __ cmp(esp, ebx);
1929       __ j(equal, &post_runtime);
1930       __ push(eax);  // generator object
1931       __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1932       __ mov(context_register(),
1933              Operand(ebp, StandardFrameConstants::kContextOffset));
1934       __ bind(&post_runtime);
1935       __ pop(result_register());
1936       EmitReturnSequence();
1937
1938       __ bind(&resume);
1939       context()->Plug(result_register());
1940       break;
1941     }
1942
1943     case Yield::FINAL: {
1944       VisitForAccumulatorValue(expr->generator_object());
1945       __ mov(FieldOperand(result_register(),
1946                           JSGeneratorObject::kContinuationOffset),
1947              Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
1948       // Pop value from top-of-stack slot, box result into result register.
1949       EmitCreateIteratorResult(true);
1950       EmitUnwindBeforeReturn();
1951       EmitReturnSequence();
1952       break;
1953     }
1954
1955     case Yield::DELEGATING: {
1956       VisitForStackValue(expr->generator_object());
1957
1958       // Initial stack layout is as follows:
1959       // [sp + 1 * kPointerSize] iter
1960       // [sp + 0 * kPointerSize] g
1961
1962       Label l_catch, l_try, l_suspend, l_continuation, l_resume;
1963       Label l_next, l_call, l_loop;
1964       Register load_receiver = LoadIC::ReceiverRegister();
1965       Register load_name = LoadIC::NameRegister();
1966
1967       // Initial send value is undefined.
1968       __ mov(eax, isolate()->factory()->undefined_value());
1969       __ jmp(&l_next);
1970
1971       // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
1972       __ bind(&l_catch);
1973       handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
1974       __ mov(load_name, isolate()->factory()->throw_string());  // "throw"
1975       __ push(load_name);                                       // "throw"
1976       __ push(Operand(esp, 2 * kPointerSize));                  // iter
1977       __ push(eax);                                             // exception
1978       __ jmp(&l_call);
1979
1980       // try { received = %yield result }
1981       // Shuffle the received result above a try handler and yield it without
1982       // re-boxing.
1983       __ bind(&l_try);
1984       __ pop(eax);                                       // result
1985       __ PushTryHandler(StackHandler::CATCH, expr->index());
1986       const int handler_size = StackHandlerConstants::kSize;
1987       __ push(eax);                                      // result
1988       __ jmp(&l_suspend);
1989       __ bind(&l_continuation);
1990       __ jmp(&l_resume);
1991       __ bind(&l_suspend);
1992       const int generator_object_depth = kPointerSize + handler_size;
1993       __ mov(eax, Operand(esp, generator_object_depth));
1994       __ push(eax);                                      // g
1995       DCHECK(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
1996       __ mov(FieldOperand(eax, JSGeneratorObject::kContinuationOffset),
1997              Immediate(Smi::FromInt(l_continuation.pos())));
1998       __ mov(FieldOperand(eax, JSGeneratorObject::kContextOffset), esi);
1999       __ mov(ecx, esi);
2000       __ RecordWriteField(eax, JSGeneratorObject::kContextOffset, ecx, edx);
2001       __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2002       __ mov(context_register(),
2003              Operand(ebp, StandardFrameConstants::kContextOffset));
2004       __ pop(eax);                                       // result
2005       EmitReturnSequence();
2006       __ bind(&l_resume);                                // received in eax
2007       __ PopTryHandler();
2008
2009       // receiver = iter; f = iter.next; arg = received;
2010       __ bind(&l_next);
2011
2012       __ mov(load_name, isolate()->factory()->next_string());
2013       __ push(load_name);                           // "next"
2014       __ push(Operand(esp, 2 * kPointerSize));      // iter
2015       __ push(eax);                                 // received
2016
2017       // result = receiver[f](arg);
2018       __ bind(&l_call);
2019       __ mov(load_receiver, Operand(esp, kPointerSize));
2020       if (FLAG_vector_ics) {
2021         __ mov(LoadIC::SlotRegister(),
2022                Immediate(Smi::FromInt(expr->KeyedLoadFeedbackSlot())));
2023       }
2024       Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
2025       CallIC(ic, TypeFeedbackId::None());
2026       __ mov(edi, eax);
2027       __ mov(Operand(esp, 2 * kPointerSize), edi);
2028       CallFunctionStub stub(isolate(), 1, CALL_AS_METHOD);
2029       __ CallStub(&stub);
2030
2031       __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2032       __ Drop(1);  // The function is still on the stack; drop it.
2033
2034       // if (!result.done) goto l_try;
2035       __ bind(&l_loop);
2036       __ push(eax);                                      // save result
2037       __ Move(load_receiver, eax);                       // result
2038       __ mov(load_name,
2039              isolate()->factory()->done_string());       // "done"
2040       if (FLAG_vector_ics) {
2041         __ mov(LoadIC::SlotRegister(),
2042                Immediate(Smi::FromInt(expr->DoneFeedbackSlot())));
2043       }
2044       CallLoadIC(NOT_CONTEXTUAL);                        // result.done in eax
2045       Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2046       CallIC(bool_ic);
2047       __ test(eax, eax);
2048       __ j(zero, &l_try);
2049
2050       // result.value
2051       __ pop(load_receiver);                              // result
2052       __ mov(load_name,
2053              isolate()->factory()->value_string());       // "value"
2054       if (FLAG_vector_ics) {
2055         __ mov(LoadIC::SlotRegister(),
2056                Immediate(Smi::FromInt(expr->ValueFeedbackSlot())));
2057       }
2058       CallLoadIC(NOT_CONTEXTUAL);                         // result.value in eax
2059       context()->DropAndPlug(2, eax);                     // drop iter and g
2060       break;
2061     }
2062   }
2063 }
2064
2065
2066 void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2067     Expression *value,
2068     JSGeneratorObject::ResumeMode resume_mode) {
2069   // The value stays in eax, and is ultimately read by the resumed generator, as
2070   // if CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. Or it
2071   // is read to throw the value when the resumed generator is already closed.
2072   // ebx will hold the generator object until the activation has been resumed.
2073   VisitForStackValue(generator);
2074   VisitForAccumulatorValue(value);
2075   __ pop(ebx);
2076
2077   // Check generator state.
2078   Label wrong_state, closed_state, done;
2079   STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting < 0);
2080   STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed == 0);
2081   __ cmp(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2082          Immediate(Smi::FromInt(0)));
2083   __ j(equal, &closed_state);
2084   __ j(less, &wrong_state);
2085
2086   // Load suspended function and context.
2087   __ mov(esi, FieldOperand(ebx, JSGeneratorObject::kContextOffset));
2088   __ mov(edi, FieldOperand(ebx, JSGeneratorObject::kFunctionOffset));
2089
2090   // Push receiver.
2091   __ push(FieldOperand(ebx, JSGeneratorObject::kReceiverOffset));
2092
2093   // Push holes for arguments to generator function.
2094   __ mov(edx, FieldOperand(edi, JSFunction::kSharedFunctionInfoOffset));
2095   __ mov(edx,
2096          FieldOperand(edx, SharedFunctionInfo::kFormalParameterCountOffset));
2097   __ mov(ecx, isolate()->factory()->the_hole_value());
2098   Label push_argument_holes, push_frame;
2099   __ bind(&push_argument_holes);
2100   __ sub(edx, Immediate(Smi::FromInt(1)));
2101   __ j(carry, &push_frame);
2102   __ push(ecx);
2103   __ jmp(&push_argument_holes);
2104
2105   // Enter a new JavaScript frame, and initialize its slots as they were when
2106   // the generator was suspended.
2107   Label resume_frame;
2108   __ bind(&push_frame);
2109   __ call(&resume_frame);
2110   __ jmp(&done);
2111   __ bind(&resume_frame);
2112   __ push(ebp);  // Caller's frame pointer.
2113   __ mov(ebp, esp);
2114   __ push(esi);  // Callee's context.
2115   __ push(edi);  // Callee's JS Function.
2116
2117   // Load the operand stack size.
2118   __ mov(edx, FieldOperand(ebx, JSGeneratorObject::kOperandStackOffset));
2119   __ mov(edx, FieldOperand(edx, FixedArray::kLengthOffset));
2120   __ SmiUntag(edx);
2121
2122   // If we are sending a value and there is no operand stack, we can jump back
2123   // in directly.
2124   if (resume_mode == JSGeneratorObject::NEXT) {
2125     Label slow_resume;
2126     __ cmp(edx, Immediate(0));
2127     __ j(not_zero, &slow_resume);
2128     __ mov(edx, FieldOperand(edi, JSFunction::kCodeEntryOffset));
2129     __ mov(ecx, FieldOperand(ebx, JSGeneratorObject::kContinuationOffset));
2130     __ SmiUntag(ecx);
2131     __ add(edx, ecx);
2132     __ mov(FieldOperand(ebx, JSGeneratorObject::kContinuationOffset),
2133            Immediate(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2134     __ jmp(edx);
2135     __ bind(&slow_resume);
2136   }
2137
2138   // Otherwise, we push holes for the operand stack and call the runtime to fix
2139   // up the stack and the handlers.
2140   Label push_operand_holes, call_resume;
2141   __ bind(&push_operand_holes);
2142   __ sub(edx, Immediate(1));
2143   __ j(carry, &call_resume);
2144   __ push(ecx);
2145   __ jmp(&push_operand_holes);
2146   __ bind(&call_resume);
2147   __ push(ebx);
2148   __ push(result_register());
2149   __ Push(Smi::FromInt(resume_mode));
2150   __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2151   // Not reached: the runtime call returns elsewhere.
2152   __ Abort(kGeneratorFailedToResume);
2153
2154   // Reach here when generator is closed.
2155   __ bind(&closed_state);
2156   if (resume_mode == JSGeneratorObject::NEXT) {
2157     // Return completed iterator result when generator is closed.
2158     __ push(Immediate(isolate()->factory()->undefined_value()));
2159     // Pop value from top-of-stack slot; box result into result register.
2160     EmitCreateIteratorResult(true);
2161   } else {
2162     // Throw the provided value.
2163     __ push(eax);
2164     __ CallRuntime(Runtime::kThrow, 1);
2165   }
2166   __ jmp(&done);
2167
2168   // Throw error if we attempt to operate on a running generator.
2169   __ bind(&wrong_state);
2170   __ push(ebx);
2171   __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
2172
2173   __ bind(&done);
2174   context()->Plug(result_register());
2175 }
2176
2177
2178 void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
2179   Label gc_required;
2180   Label allocated;
2181
2182   Handle<Map> map(isolate()->native_context()->iterator_result_map());
2183
2184   __ Allocate(map->instance_size(), eax, ecx, edx, &gc_required, TAG_OBJECT);
2185   __ jmp(&allocated);
2186
2187   __ bind(&gc_required);
2188   __ Push(Smi::FromInt(map->instance_size()));
2189   __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2190   __ mov(context_register(),
2191          Operand(ebp, StandardFrameConstants::kContextOffset));
2192
2193   __ bind(&allocated);
2194   __ mov(ebx, map);
2195   __ pop(ecx);
2196   __ mov(edx, isolate()->factory()->ToBoolean(done));
2197   DCHECK_EQ(map->instance_size(), 5 * kPointerSize);
2198   __ mov(FieldOperand(eax, HeapObject::kMapOffset), ebx);
2199   __ mov(FieldOperand(eax, JSObject::kPropertiesOffset),
2200          isolate()->factory()->empty_fixed_array());
2201   __ mov(FieldOperand(eax, JSObject::kElementsOffset),
2202          isolate()->factory()->empty_fixed_array());
2203   __ mov(FieldOperand(eax, JSGeneratorObject::kResultValuePropertyOffset), ecx);
2204   __ mov(FieldOperand(eax, JSGeneratorObject::kResultDonePropertyOffset), edx);
2205
2206   // Only the value field needs a write barrier, as the other values are in the
2207   // root set.
2208   __ RecordWriteField(eax, JSGeneratorObject::kResultValuePropertyOffset,
2209                       ecx, edx);
2210 }
2211
2212
2213 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2214   SetSourcePosition(prop->position());
2215   Literal* key = prop->key()->AsLiteral();
2216   DCHECK(!key->value()->IsSmi());
2217   __ mov(LoadIC::NameRegister(), Immediate(key->value()));
2218   if (FLAG_vector_ics) {
2219     __ mov(LoadIC::SlotRegister(),
2220            Immediate(Smi::FromInt(prop->PropertyFeedbackSlot())));
2221     CallLoadIC(NOT_CONTEXTUAL);
2222   } else {
2223     CallLoadIC(NOT_CONTEXTUAL, prop->PropertyFeedbackId());
2224   }
2225 }
2226
2227
2228 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2229   SetSourcePosition(prop->position());
2230   Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
2231   if (FLAG_vector_ics) {
2232     __ mov(LoadIC::SlotRegister(),
2233            Immediate(Smi::FromInt(prop->PropertyFeedbackSlot())));
2234     CallIC(ic);
2235   } else {
2236     CallIC(ic, prop->PropertyFeedbackId());
2237   }
2238 }
2239
2240
2241 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
2242                                               Token::Value op,
2243                                               OverwriteMode mode,
2244                                               Expression* left,
2245                                               Expression* right) {
2246   // Do combined smi check of the operands. Left operand is on the
2247   // stack. Right operand is in eax.
2248   Label smi_case, done, stub_call;
2249   __ pop(edx);
2250   __ mov(ecx, eax);
2251   __ or_(eax, edx);
2252   JumpPatchSite patch_site(masm_);
2253   patch_site.EmitJumpIfSmi(eax, &smi_case, Label::kNear);
2254
2255   __ bind(&stub_call);
2256   __ mov(eax, ecx);
2257   BinaryOpICStub stub(isolate(), op, mode);
2258   CallIC(stub.GetCode(), expr->BinaryOperationFeedbackId());
2259   patch_site.EmitPatchInfo();
2260   __ jmp(&done, Label::kNear);
2261
2262   // Smi case.
2263   __ bind(&smi_case);
2264   __ mov(eax, edx);  // Copy left operand in case of a stub call.
2265
2266   switch (op) {
2267     case Token::SAR:
2268       __ SmiUntag(ecx);
2269       __ sar_cl(eax);  // No checks of result necessary
2270       __ and_(eax, Immediate(~kSmiTagMask));
2271       break;
2272     case Token::SHL: {
2273       Label result_ok;
2274       __ SmiUntag(eax);
2275       __ SmiUntag(ecx);
2276       __ shl_cl(eax);
2277       // Check that the *signed* result fits in a smi.
2278       __ cmp(eax, 0xc0000000);
2279       __ j(positive, &result_ok);
2280       __ SmiTag(ecx);
2281       __ jmp(&stub_call);
2282       __ bind(&result_ok);
2283       __ SmiTag(eax);
2284       break;
2285     }
2286     case Token::SHR: {
2287       Label result_ok;
2288       __ SmiUntag(eax);
2289       __ SmiUntag(ecx);
2290       __ shr_cl(eax);
2291       __ test(eax, Immediate(0xc0000000));
2292       __ j(zero, &result_ok);
2293       __ SmiTag(ecx);
2294       __ jmp(&stub_call);
2295       __ bind(&result_ok);
2296       __ SmiTag(eax);
2297       break;
2298     }
2299     case Token::ADD:
2300       __ add(eax, ecx);
2301       __ j(overflow, &stub_call);
2302       break;
2303     case Token::SUB:
2304       __ sub(eax, ecx);
2305       __ j(overflow, &stub_call);
2306       break;
2307     case Token::MUL: {
2308       __ SmiUntag(eax);
2309       __ imul(eax, ecx);
2310       __ j(overflow, &stub_call);
2311       __ test(eax, eax);
2312       __ j(not_zero, &done, Label::kNear);
2313       __ mov(ebx, edx);
2314       __ or_(ebx, ecx);
2315       __ j(negative, &stub_call);
2316       break;
2317     }
2318     case Token::BIT_OR:
2319       __ or_(eax, ecx);
2320       break;
2321     case Token::BIT_AND:
2322       __ and_(eax, ecx);
2323       break;
2324     case Token::BIT_XOR:
2325       __ xor_(eax, ecx);
2326       break;
2327     default:
2328       UNREACHABLE();
2329   }
2330
2331   __ bind(&done);
2332   context()->Plug(eax);
2333 }
2334
2335
2336 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2337                                      Token::Value op,
2338                                      OverwriteMode mode) {
2339   __ pop(edx);
2340   BinaryOpICStub stub(isolate(), op, mode);
2341   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
2342   CallIC(stub.GetCode(), expr->BinaryOperationFeedbackId());
2343   patch_site.EmitPatchInfo();
2344   context()->Plug(eax);
2345 }
2346
2347
2348 void FullCodeGenerator::EmitAssignment(Expression* expr) {
2349   DCHECK(expr->IsValidReferenceExpression());
2350
2351   // Left-hand side can only be a property, a global or a (parameter or local)
2352   // slot.
2353   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2354   LhsKind assign_type = VARIABLE;
2355   Property* prop = expr->AsProperty();
2356   if (prop != NULL) {
2357     assign_type = (prop->key()->IsPropertyName())
2358         ? NAMED_PROPERTY
2359         : KEYED_PROPERTY;
2360   }
2361
2362   switch (assign_type) {
2363     case VARIABLE: {
2364       Variable* var = expr->AsVariableProxy()->var();
2365       EffectContext context(this);
2366       EmitVariableAssignment(var, Token::ASSIGN);
2367       break;
2368     }
2369     case NAMED_PROPERTY: {
2370       __ push(eax);  // Preserve value.
2371       VisitForAccumulatorValue(prop->obj());
2372       __ Move(StoreIC::ReceiverRegister(), eax);
2373       __ pop(StoreIC::ValueRegister());  // Restore value.
2374       __ mov(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
2375       CallStoreIC();
2376       break;
2377     }
2378     case KEYED_PROPERTY: {
2379       __ push(eax);  // Preserve value.
2380       VisitForStackValue(prop->obj());
2381       VisitForAccumulatorValue(prop->key());
2382       __ Move(KeyedStoreIC::NameRegister(), eax);
2383       __ pop(KeyedStoreIC::ReceiverRegister());  // Receiver.
2384       __ pop(KeyedStoreIC::ValueRegister());  // Restore value.
2385       Handle<Code> ic = strict_mode() == SLOPPY
2386           ? isolate()->builtins()->KeyedStoreIC_Initialize()
2387           : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
2388       CallIC(ic);
2389       break;
2390     }
2391   }
2392   context()->Plug(eax);
2393 }
2394
2395
2396 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2397     Variable* var, MemOperand location) {
2398   __ mov(location, eax);
2399   if (var->IsContextSlot()) {
2400     __ mov(edx, eax);
2401     int offset = Context::SlotOffset(var->index());
2402     __ RecordWriteContextSlot(ecx, offset, edx, ebx);
2403   }
2404 }
2405
2406
2407 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
2408                                                Token::Value op) {
2409   if (var->IsUnallocated()) {
2410     // Global var, const, or let.
2411     __ mov(StoreIC::NameRegister(), var->name());
2412     __ mov(StoreIC::ReceiverRegister(), GlobalObjectOperand());
2413     CallStoreIC();
2414
2415   } else if (op == Token::INIT_CONST_LEGACY) {
2416     // Const initializers need a write barrier.
2417     DCHECK(!var->IsParameter());  // No const parameters.
2418     if (var->IsLookupSlot()) {
2419       __ push(eax);
2420       __ push(esi);
2421       __ push(Immediate(var->name()));
2422       __ CallRuntime(Runtime::kInitializeLegacyConstLookupSlot, 3);
2423     } else {
2424       DCHECK(var->IsStackLocal() || var->IsContextSlot());
2425       Label skip;
2426       MemOperand location = VarOperand(var, ecx);
2427       __ mov(edx, location);
2428       __ cmp(edx, isolate()->factory()->the_hole_value());
2429       __ j(not_equal, &skip, Label::kNear);
2430       EmitStoreToStackLocalOrContextSlot(var, location);
2431       __ bind(&skip);
2432     }
2433
2434   } else if (var->mode() == LET && op != Token::INIT_LET) {
2435     // Non-initializing assignment to let variable needs a write barrier.
2436     DCHECK(!var->IsLookupSlot());
2437     DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2438     Label assign;
2439     MemOperand location = VarOperand(var, ecx);
2440     __ mov(edx, location);
2441     __ cmp(edx, isolate()->factory()->the_hole_value());
2442     __ j(not_equal, &assign, Label::kNear);
2443     __ push(Immediate(var->name()));
2444     __ CallRuntime(Runtime::kThrowReferenceError, 1);
2445     __ bind(&assign);
2446     EmitStoreToStackLocalOrContextSlot(var, location);
2447
2448   } else if (!var->is_const_mode() || op == Token::INIT_CONST) {
2449     if (var->IsLookupSlot()) {
2450       // Assignment to var.
2451       __ push(eax);  // Value.
2452       __ push(esi);  // Context.
2453       __ push(Immediate(var->name()));
2454       __ push(Immediate(Smi::FromInt(strict_mode())));
2455       __ CallRuntime(Runtime::kStoreLookupSlot, 4);
2456     } else {
2457       // Assignment to var or initializing assignment to let/const in harmony
2458       // mode.
2459       DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2460       MemOperand location = VarOperand(var, ecx);
2461       if (generate_debug_code_ && op == Token::INIT_LET) {
2462         // Check for an uninitialized let binding.
2463         __ mov(edx, location);
2464         __ cmp(edx, isolate()->factory()->the_hole_value());
2465         __ Check(equal, kLetBindingReInitialization);
2466       }
2467       EmitStoreToStackLocalOrContextSlot(var, location);
2468     }
2469   }
2470   // Non-initializing assignments to consts are ignored.
2471 }
2472
2473
2474 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2475   // Assignment to a property, using a named store IC.
2476   // eax    : value
2477   // esp[0] : receiver
2478
2479   Property* prop = expr->target()->AsProperty();
2480   DCHECK(prop != NULL);
2481   DCHECK(prop->key()->IsLiteral());
2482
2483   // Record source code position before IC call.
2484   SetSourcePosition(expr->position());
2485   __ mov(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
2486   __ pop(StoreIC::ReceiverRegister());
2487   CallStoreIC(expr->AssignmentFeedbackId());
2488   PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2489   context()->Plug(eax);
2490 }
2491
2492
2493 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2494   // Assignment to a property, using a keyed store IC.
2495   // eax               : value
2496   // esp[0]            : key
2497   // esp[kPointerSize] : receiver
2498
2499   __ pop(KeyedStoreIC::NameRegister());  // Key.
2500   __ pop(KeyedStoreIC::ReceiverRegister());
2501   DCHECK(KeyedStoreIC::ValueRegister().is(eax));
2502   // Record source code position before IC call.
2503   SetSourcePosition(expr->position());
2504   Handle<Code> ic = strict_mode() == SLOPPY
2505       ? isolate()->builtins()->KeyedStoreIC_Initialize()
2506       : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
2507   CallIC(ic, expr->AssignmentFeedbackId());
2508
2509   PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2510   context()->Plug(eax);
2511 }
2512
2513
2514 void FullCodeGenerator::VisitProperty(Property* expr) {
2515   Comment cmnt(masm_, "[ Property");
2516   Expression* key = expr->key();
2517
2518   if (key->IsPropertyName()) {
2519     VisitForAccumulatorValue(expr->obj());
2520     __ Move(LoadIC::ReceiverRegister(), result_register());
2521     EmitNamedPropertyLoad(expr);
2522     PrepareForBailoutForId(expr->LoadId(), TOS_REG);
2523     context()->Plug(eax);
2524   } else {
2525     VisitForStackValue(expr->obj());
2526     VisitForAccumulatorValue(expr->key());
2527     __ pop(LoadIC::ReceiverRegister());                  // Object.
2528     __ Move(LoadIC::NameRegister(), result_register());  // Key.
2529     EmitKeyedPropertyLoad(expr);
2530     context()->Plug(eax);
2531   }
2532 }
2533
2534
2535 void FullCodeGenerator::CallIC(Handle<Code> code,
2536                                TypeFeedbackId ast_id) {
2537   ic_total_count_++;
2538   __ call(code, RelocInfo::CODE_TARGET, ast_id);
2539 }
2540
2541
2542 // Code common for calls using the IC.
2543 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2544   Expression* callee = expr->expression();
2545
2546   CallIC::CallType call_type = callee->IsVariableProxy()
2547       ? CallIC::FUNCTION
2548       : CallIC::METHOD;
2549   // Get the target function.
2550   if (call_type == CallIC::FUNCTION) {
2551     { StackValueContext context(this);
2552       EmitVariableLoad(callee->AsVariableProxy());
2553       PrepareForBailout(callee, NO_REGISTERS);
2554     }
2555     // Push undefined as receiver. This is patched in the method prologue if it
2556     // is a sloppy mode method.
2557     __ push(Immediate(isolate()->factory()->undefined_value()));
2558   } else {
2559     // Load the function from the receiver.
2560     DCHECK(callee->IsProperty());
2561     __ mov(LoadIC::ReceiverRegister(), Operand(esp, 0));
2562     EmitNamedPropertyLoad(callee->AsProperty());
2563     PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2564     // Push the target function under the receiver.
2565     __ push(Operand(esp, 0));
2566     __ mov(Operand(esp, kPointerSize), eax);
2567   }
2568
2569   EmitCall(expr, call_type);
2570 }
2571
2572
2573 // Code common for calls using the IC.
2574 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2575                                                 Expression* key) {
2576   // Load the key.
2577   VisitForAccumulatorValue(key);
2578
2579   Expression* callee = expr->expression();
2580
2581   // Load the function from the receiver.
2582   DCHECK(callee->IsProperty());
2583   __ mov(LoadIC::ReceiverRegister(), Operand(esp, 0));
2584   __ mov(LoadIC::NameRegister(), eax);
2585   EmitKeyedPropertyLoad(callee->AsProperty());
2586   PrepareForBailoutForId(callee->AsProperty()->LoadId(), TOS_REG);
2587
2588   // Push the target function under the receiver.
2589   __ push(Operand(esp, 0));
2590   __ mov(Operand(esp, kPointerSize), eax);
2591
2592   EmitCall(expr, CallIC::METHOD);
2593 }
2594
2595
2596 void FullCodeGenerator::EmitCall(Call* expr, CallIC::CallType call_type) {
2597   // Load the arguments.
2598   ZoneList<Expression*>* args = expr->arguments();
2599   int arg_count = args->length();
2600   { PreservePositionScope scope(masm()->positions_recorder());
2601     for (int i = 0; i < arg_count; i++) {
2602       VisitForStackValue(args->at(i));
2603     }
2604   }
2605
2606   // Record source position of the IC call.
2607   SetSourcePosition(expr->position());
2608   Handle<Code> ic = CallIC::initialize_stub(
2609       isolate(), arg_count, call_type);
2610   __ Move(edx, Immediate(Smi::FromInt(expr->CallFeedbackSlot())));
2611   __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2612   // Don't assign a type feedback id to the IC, since type feedback is provided
2613   // by the vector above.
2614   CallIC(ic);
2615
2616   RecordJSReturnSite(expr);
2617
2618   // Restore context register.
2619   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2620
2621   context()->DropAndPlug(1, eax);
2622 }
2623
2624
2625 void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
2626   // Push copy of the first argument or undefined if it doesn't exist.
2627   if (arg_count > 0) {
2628     __ push(Operand(esp, arg_count * kPointerSize));
2629   } else {
2630     __ push(Immediate(isolate()->factory()->undefined_value()));
2631   }
2632
2633   // Push the receiver of the enclosing function.
2634   __ push(Operand(ebp, (2 + info_->scope()->num_parameters()) * kPointerSize));
2635   // Push the language mode.
2636   __ push(Immediate(Smi::FromInt(strict_mode())));
2637
2638   // Push the start position of the scope the calls resides in.
2639   __ push(Immediate(Smi::FromInt(scope()->start_position())));
2640
2641   // Do the runtime call.
2642   __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
2643 }
2644
2645
2646 void FullCodeGenerator::VisitCall(Call* expr) {
2647 #ifdef DEBUG
2648   // We want to verify that RecordJSReturnSite gets called on all paths
2649   // through this function.  Avoid early returns.
2650   expr->return_is_recorded_ = false;
2651 #endif
2652
2653   Comment cmnt(masm_, "[ Call");
2654   Expression* callee = expr->expression();
2655   Call::CallType call_type = expr->GetCallType(isolate());
2656
2657   if (call_type == Call::POSSIBLY_EVAL_CALL) {
2658     // In a call to eval, we first call RuntimeHidden_ResolvePossiblyDirectEval
2659     // to resolve the function we need to call and the receiver of the call.
2660     // Then we call the resolved function using the given arguments.
2661     ZoneList<Expression*>* args = expr->arguments();
2662     int arg_count = args->length();
2663     { PreservePositionScope pos_scope(masm()->positions_recorder());
2664       VisitForStackValue(callee);
2665       // Reserved receiver slot.
2666       __ push(Immediate(isolate()->factory()->undefined_value()));
2667       // Push the arguments.
2668       for (int i = 0; i < arg_count; i++) {
2669         VisitForStackValue(args->at(i));
2670       }
2671
2672       // Push a copy of the function (found below the arguments) and
2673       // resolve eval.
2674       __ push(Operand(esp, (arg_count + 1) * kPointerSize));
2675       EmitResolvePossiblyDirectEval(arg_count);
2676
2677       // The runtime call returns a pair of values in eax (function) and
2678       // edx (receiver). Touch up the stack with the right values.
2679       __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
2680       __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
2681     }
2682     // Record source position for debugger.
2683     SetSourcePosition(expr->position());
2684     CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
2685     __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
2686     __ CallStub(&stub);
2687     RecordJSReturnSite(expr);
2688     // Restore context register.
2689     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2690     context()->DropAndPlug(1, eax);
2691
2692   } else if (call_type == Call::GLOBAL_CALL) {
2693     EmitCallWithLoadIC(expr);
2694
2695   } else if (call_type == Call::LOOKUP_SLOT_CALL) {
2696     // Call to a lookup slot (dynamically introduced variable).
2697     VariableProxy* proxy = callee->AsVariableProxy();
2698     Label slow, done;
2699     { PreservePositionScope scope(masm()->positions_recorder());
2700       // Generate code for loading from variables potentially shadowed by
2701       // eval-introduced variables.
2702       EmitDynamicLookupFastCase(proxy, NOT_INSIDE_TYPEOF, &slow, &done);
2703     }
2704     __ bind(&slow);
2705     // Call the runtime to find the function to call (returned in eax) and
2706     // the object holding it (returned in edx).
2707     __ push(context_register());
2708     __ push(Immediate(proxy->name()));
2709     __ CallRuntime(Runtime::kLoadLookupSlot, 2);
2710     __ push(eax);  // Function.
2711     __ push(edx);  // Receiver.
2712
2713     // If fast case code has been generated, emit code to push the function
2714     // and receiver and have the slow path jump around this code.
2715     if (done.is_linked()) {
2716       Label call;
2717       __ jmp(&call, Label::kNear);
2718       __ bind(&done);
2719       // Push function.
2720       __ push(eax);
2721       // The receiver is implicitly the global receiver. Indicate this by
2722       // passing the hole to the call function stub.
2723       __ push(Immediate(isolate()->factory()->undefined_value()));
2724       __ bind(&call);
2725     }
2726
2727     // The receiver is either the global receiver or an object found by
2728     // LoadContextSlot.
2729     EmitCall(expr);
2730
2731   } else if (call_type == Call::PROPERTY_CALL) {
2732     Property* property = callee->AsProperty();
2733     { PreservePositionScope scope(masm()->positions_recorder());
2734       VisitForStackValue(property->obj());
2735     }
2736     if (property->key()->IsPropertyName()) {
2737       EmitCallWithLoadIC(expr);
2738     } else {
2739       EmitKeyedCallWithLoadIC(expr, property->key());
2740     }
2741
2742   } else {
2743     DCHECK(call_type == Call::OTHER_CALL);
2744     // Call to an arbitrary expression not handled specially above.
2745     { PreservePositionScope scope(masm()->positions_recorder());
2746       VisitForStackValue(callee);
2747     }
2748     __ push(Immediate(isolate()->factory()->undefined_value()));
2749     // Emit function call.
2750     EmitCall(expr);
2751   }
2752
2753 #ifdef DEBUG
2754   // RecordJSReturnSite should have been called.
2755   DCHECK(expr->return_is_recorded_);
2756 #endif
2757 }
2758
2759
2760 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2761   Comment cmnt(masm_, "[ CallNew");
2762   // According to ECMA-262, section 11.2.2, page 44, the function
2763   // expression in new calls must be evaluated before the
2764   // arguments.
2765
2766   // Push constructor on the stack.  If it's not a function it's used as
2767   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2768   // ignored.
2769   VisitForStackValue(expr->expression());
2770
2771   // Push the arguments ("left-to-right") on the stack.
2772   ZoneList<Expression*>* args = expr->arguments();
2773   int arg_count = args->length();
2774   for (int i = 0; i < arg_count; i++) {
2775     VisitForStackValue(args->at(i));
2776   }
2777
2778   // Call the construct call builtin that handles allocation and
2779   // constructor invocation.
2780   SetSourcePosition(expr->position());
2781
2782   // Load function and argument count into edi and eax.
2783   __ Move(eax, Immediate(arg_count));
2784   __ mov(edi, Operand(esp, arg_count * kPointerSize));
2785
2786   // Record call targets in unoptimized code.
2787   if (FLAG_pretenuring_call_new) {
2788     EnsureSlotContainsAllocationSite(expr->AllocationSiteFeedbackSlot());
2789     DCHECK(expr->AllocationSiteFeedbackSlot() ==
2790            expr->CallNewFeedbackSlot() + 1);
2791   }
2792
2793   __ LoadHeapObject(ebx, FeedbackVector());
2794   __ mov(edx, Immediate(Smi::FromInt(expr->CallNewFeedbackSlot())));
2795
2796   CallConstructStub stub(isolate(), RECORD_CONSTRUCTOR_TARGET);
2797   __ call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
2798   PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
2799   context()->Plug(eax);
2800 }
2801
2802
2803 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2804   ZoneList<Expression*>* args = expr->arguments();
2805   DCHECK(args->length() == 1);
2806
2807   VisitForAccumulatorValue(args->at(0));
2808
2809   Label materialize_true, materialize_false;
2810   Label* if_true = NULL;
2811   Label* if_false = NULL;
2812   Label* fall_through = NULL;
2813   context()->PrepareTest(&materialize_true, &materialize_false,
2814                          &if_true, &if_false, &fall_through);
2815
2816   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2817   __ test(eax, Immediate(kSmiTagMask));
2818   Split(zero, if_true, if_false, fall_through);
2819
2820   context()->Plug(if_true, if_false);
2821 }
2822
2823
2824 void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2825   ZoneList<Expression*>* args = expr->arguments();
2826   DCHECK(args->length() == 1);
2827
2828   VisitForAccumulatorValue(args->at(0));
2829
2830   Label materialize_true, materialize_false;
2831   Label* if_true = NULL;
2832   Label* if_false = NULL;
2833   Label* fall_through = NULL;
2834   context()->PrepareTest(&materialize_true, &materialize_false,
2835                          &if_true, &if_false, &fall_through);
2836
2837   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2838   __ test(eax, Immediate(kSmiTagMask | 0x80000000));
2839   Split(zero, if_true, if_false, fall_through);
2840
2841   context()->Plug(if_true, if_false);
2842 }
2843
2844
2845 void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2846   ZoneList<Expression*>* args = expr->arguments();
2847   DCHECK(args->length() == 1);
2848
2849   VisitForAccumulatorValue(args->at(0));
2850
2851   Label materialize_true, materialize_false;
2852   Label* if_true = NULL;
2853   Label* if_false = NULL;
2854   Label* fall_through = NULL;
2855   context()->PrepareTest(&materialize_true, &materialize_false,
2856                          &if_true, &if_false, &fall_through);
2857
2858   __ JumpIfSmi(eax, if_false);
2859   __ cmp(eax, isolate()->factory()->null_value());
2860   __ j(equal, if_true);
2861   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2862   // Undetectable objects behave like undefined when tested with typeof.
2863   __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2864   __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2865   __ j(not_zero, if_false);
2866   __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2867   __ cmp(ecx, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
2868   __ j(below, if_false);
2869   __ cmp(ecx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
2870   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2871   Split(below_equal, if_true, if_false, fall_through);
2872
2873   context()->Plug(if_true, if_false);
2874 }
2875
2876
2877 void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2878   ZoneList<Expression*>* args = expr->arguments();
2879   DCHECK(args->length() == 1);
2880
2881   VisitForAccumulatorValue(args->at(0));
2882
2883   Label materialize_true, materialize_false;
2884   Label* if_true = NULL;
2885   Label* if_false = NULL;
2886   Label* fall_through = NULL;
2887   context()->PrepareTest(&materialize_true, &materialize_false,
2888                          &if_true, &if_false, &fall_through);
2889
2890   __ JumpIfSmi(eax, if_false);
2891   __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, ebx);
2892   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2893   Split(above_equal, if_true, if_false, fall_through);
2894
2895   context()->Plug(if_true, if_false);
2896 }
2897
2898
2899 void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2900   ZoneList<Expression*>* args = expr->arguments();
2901   DCHECK(args->length() == 1);
2902
2903   VisitForAccumulatorValue(args->at(0));
2904
2905   Label materialize_true, materialize_false;
2906   Label* if_true = NULL;
2907   Label* if_false = NULL;
2908   Label* fall_through = NULL;
2909   context()->PrepareTest(&materialize_true, &materialize_false,
2910                          &if_true, &if_false, &fall_through);
2911
2912   __ JumpIfSmi(eax, if_false);
2913   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2914   __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2915   __ test(ebx, Immediate(1 << Map::kIsUndetectable));
2916   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2917   Split(not_zero, if_true, if_false, fall_through);
2918
2919   context()->Plug(if_true, if_false);
2920 }
2921
2922
2923 void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2924     CallRuntime* expr) {
2925   ZoneList<Expression*>* args = expr->arguments();
2926   DCHECK(args->length() == 1);
2927
2928   VisitForAccumulatorValue(args->at(0));
2929
2930   Label materialize_true, materialize_false, skip_lookup;
2931   Label* if_true = NULL;
2932   Label* if_false = NULL;
2933   Label* fall_through = NULL;
2934   context()->PrepareTest(&materialize_true, &materialize_false,
2935                          &if_true, &if_false, &fall_through);
2936
2937   __ AssertNotSmi(eax);
2938
2939   // Check whether this map has already been checked to be safe for default
2940   // valueOf.
2941   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2942   __ test_b(FieldOperand(ebx, Map::kBitField2Offset),
2943             1 << Map::kStringWrapperSafeForDefaultValueOf);
2944   __ j(not_zero, &skip_lookup);
2945
2946   // Check for fast case object. Return false for slow case objects.
2947   __ mov(ecx, FieldOperand(eax, JSObject::kPropertiesOffset));
2948   __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
2949   __ cmp(ecx, isolate()->factory()->hash_table_map());
2950   __ j(equal, if_false);
2951
2952   // Look for valueOf string in the descriptor array, and indicate false if
2953   // found. Since we omit an enumeration index check, if it is added via a
2954   // transition that shares its descriptor array, this is a false positive.
2955   Label entry, loop, done;
2956
2957   // Skip loop if no descriptors are valid.
2958   __ NumberOfOwnDescriptors(ecx, ebx);
2959   __ cmp(ecx, 0);
2960   __ j(equal, &done);
2961
2962   __ LoadInstanceDescriptors(ebx, ebx);
2963   // ebx: descriptor array.
2964   // ecx: valid entries in the descriptor array.
2965   // Calculate the end of the descriptor array.
2966   STATIC_ASSERT(kSmiTag == 0);
2967   STATIC_ASSERT(kSmiTagSize == 1);
2968   STATIC_ASSERT(kPointerSize == 4);
2969   __ imul(ecx, ecx, DescriptorArray::kDescriptorSize);
2970   __ lea(ecx, Operand(ebx, ecx, times_4, DescriptorArray::kFirstOffset));
2971   // Calculate location of the first key name.
2972   __ add(ebx, Immediate(DescriptorArray::kFirstOffset));
2973   // Loop through all the keys in the descriptor array. If one of these is the
2974   // internalized string "valueOf" the result is false.
2975   __ jmp(&entry);
2976   __ bind(&loop);
2977   __ mov(edx, FieldOperand(ebx, 0));
2978   __ cmp(edx, isolate()->factory()->value_of_string());
2979   __ j(equal, if_false);
2980   __ add(ebx, Immediate(DescriptorArray::kDescriptorSize * kPointerSize));
2981   __ bind(&entry);
2982   __ cmp(ebx, ecx);
2983   __ j(not_equal, &loop);
2984
2985   __ bind(&done);
2986
2987   // Reload map as register ebx was used as temporary above.
2988   __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2989
2990   // Set the bit in the map to indicate that there is no local valueOf field.
2991   __ or_(FieldOperand(ebx, Map::kBitField2Offset),
2992          Immediate(1 << Map::kStringWrapperSafeForDefaultValueOf));
2993
2994   __ bind(&skip_lookup);
2995
2996   // If a valueOf property is not found on the object check that its
2997   // prototype is the un-modified String prototype. If not result is false.
2998   __ mov(ecx, FieldOperand(ebx, Map::kPrototypeOffset));
2999   __ JumpIfSmi(ecx, if_false);
3000   __ mov(ecx, FieldOperand(ecx, HeapObject::kMapOffset));
3001   __ mov(edx, Operand(esi, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
3002   __ mov(edx,
3003          FieldOperand(edx, GlobalObject::kNativeContextOffset));
3004   __ cmp(ecx,
3005          ContextOperand(edx,
3006                         Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
3007   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3008   Split(equal, if_true, if_false, fall_through);
3009
3010   context()->Plug(if_true, if_false);
3011 }
3012
3013
3014 void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3015   ZoneList<Expression*>* args = expr->arguments();
3016   DCHECK(args->length() == 1);
3017
3018   VisitForAccumulatorValue(args->at(0));
3019
3020   Label materialize_true, materialize_false;
3021   Label* if_true = NULL;
3022   Label* if_false = NULL;
3023   Label* fall_through = NULL;
3024   context()->PrepareTest(&materialize_true, &materialize_false,
3025                          &if_true, &if_false, &fall_through);
3026
3027   __ JumpIfSmi(eax, if_false);
3028   __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3029   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3030   Split(equal, if_true, if_false, fall_through);
3031
3032   context()->Plug(if_true, if_false);
3033 }
3034
3035
3036 void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3037   ZoneList<Expression*>* args = expr->arguments();
3038   DCHECK(args->length() == 1);
3039
3040   VisitForAccumulatorValue(args->at(0));
3041
3042   Label materialize_true, materialize_false;
3043   Label* if_true = NULL;
3044   Label* if_false = NULL;
3045   Label* fall_through = NULL;
3046   context()->PrepareTest(&materialize_true, &materialize_false,
3047                          &if_true, &if_false, &fall_through);
3048
3049   Handle<Map> map = masm()->isolate()->factory()->heap_number_map();
3050   __ CheckMap(eax, map, if_false, DO_SMI_CHECK);
3051   // Check if the exponent half is 0x80000000. Comparing against 1 and
3052   // checking for overflow is the shortest possible encoding.
3053   __ cmp(FieldOperand(eax, HeapNumber::kExponentOffset), Immediate(0x1));
3054   __ j(no_overflow, if_false);
3055   __ cmp(FieldOperand(eax, HeapNumber::kMantissaOffset), Immediate(0x0));
3056   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3057   Split(equal, if_true, if_false, fall_through);
3058
3059   context()->Plug(if_true, if_false);
3060 }
3061
3062
3063
3064 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3065   ZoneList<Expression*>* args = expr->arguments();
3066   DCHECK(args->length() == 1);
3067
3068   VisitForAccumulatorValue(args->at(0));
3069
3070   Label materialize_true, materialize_false;
3071   Label* if_true = NULL;
3072   Label* if_false = NULL;
3073   Label* fall_through = NULL;
3074   context()->PrepareTest(&materialize_true, &materialize_false,
3075                          &if_true, &if_false, &fall_through);
3076
3077   __ JumpIfSmi(eax, if_false);
3078   __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
3079   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3080   Split(equal, if_true, if_false, fall_through);
3081
3082   context()->Plug(if_true, if_false);
3083 }
3084
3085
3086 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3087   ZoneList<Expression*>* args = expr->arguments();
3088   DCHECK(args->length() == 1);
3089
3090   VisitForAccumulatorValue(args->at(0));
3091
3092   Label materialize_true, materialize_false;
3093   Label* if_true = NULL;
3094   Label* if_false = NULL;
3095   Label* fall_through = NULL;
3096   context()->PrepareTest(&materialize_true, &materialize_false,
3097                          &if_true, &if_false, &fall_through);
3098
3099   __ JumpIfSmi(eax, if_false);
3100   __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
3101   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3102   Split(equal, if_true, if_false, fall_through);
3103
3104   context()->Plug(if_true, if_false);
3105 }
3106
3107
3108
3109 void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
3110   DCHECK(expr->arguments()->length() == 0);
3111
3112   Label materialize_true, materialize_false;
3113   Label* if_true = NULL;
3114   Label* if_false = NULL;
3115   Label* fall_through = NULL;
3116   context()->PrepareTest(&materialize_true, &materialize_false,
3117                          &if_true, &if_false, &fall_through);
3118
3119   // Get the frame pointer for the calling frame.
3120   __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3121
3122   // Skip the arguments adaptor frame if it exists.
3123   Label check_frame_marker;
3124   __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
3125          Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3126   __ j(not_equal, &check_frame_marker);
3127   __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
3128
3129   // Check the marker in the calling frame.
3130   __ bind(&check_frame_marker);
3131   __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
3132          Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
3133   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3134   Split(equal, if_true, if_false, fall_through);
3135
3136   context()->Plug(if_true, if_false);
3137 }
3138
3139
3140 void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3141   ZoneList<Expression*>* args = expr->arguments();
3142   DCHECK(args->length() == 2);
3143
3144   // Load the two objects into registers and perform the comparison.
3145   VisitForStackValue(args->at(0));
3146   VisitForAccumulatorValue(args->at(1));
3147
3148   Label materialize_true, materialize_false;
3149   Label* if_true = NULL;
3150   Label* if_false = NULL;
3151   Label* fall_through = NULL;
3152   context()->PrepareTest(&materialize_true, &materialize_false,
3153                          &if_true, &if_false, &fall_through);
3154
3155   __ pop(ebx);
3156   __ cmp(eax, ebx);
3157   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3158   Split(equal, if_true, if_false, fall_through);
3159
3160   context()->Plug(if_true, if_false);
3161 }
3162
3163
3164 void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3165   ZoneList<Expression*>* args = expr->arguments();
3166   DCHECK(args->length() == 1);
3167
3168   // ArgumentsAccessStub expects the key in edx and the formal
3169   // parameter count in eax.
3170   VisitForAccumulatorValue(args->at(0));
3171   __ mov(edx, eax);
3172   __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3173   ArgumentsAccessStub stub(isolate(), ArgumentsAccessStub::READ_ELEMENT);
3174   __ CallStub(&stub);
3175   context()->Plug(eax);
3176 }
3177
3178
3179 void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3180   DCHECK(expr->arguments()->length() == 0);
3181
3182   Label exit;
3183   // Get the number of formal parameters.
3184   __ Move(eax, Immediate(Smi::FromInt(info_->scope()->num_parameters())));
3185
3186   // Check if the calling frame is an arguments adaptor frame.
3187   __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
3188   __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
3189          Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
3190   __ j(not_equal, &exit);
3191
3192   // Arguments adaptor case: Read the arguments length from the
3193   // adaptor frame.
3194   __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
3195
3196   __ bind(&exit);
3197   __ AssertSmi(eax);
3198   context()->Plug(eax);
3199 }
3200
3201
3202 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3203   ZoneList<Expression*>* args = expr->arguments();
3204   DCHECK(args->length() == 1);
3205   Label done, null, function, non_function_constructor;
3206
3207   VisitForAccumulatorValue(args->at(0));
3208
3209   // If the object is a smi, we return null.
3210   __ JumpIfSmi(eax, &null);
3211
3212   // Check that the object is a JS object but take special care of JS
3213   // functions to make sure they have 'Function' as their class.
3214   // Assume that there are only two callable types, and one of them is at
3215   // either end of the type range for JS object types. Saves extra comparisons.
3216   STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
3217   __ CmpObjectType(eax, FIRST_SPEC_OBJECT_TYPE, eax);
3218   // Map is now in eax.
3219   __ j(below, &null);
3220   STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3221                 FIRST_SPEC_OBJECT_TYPE + 1);
3222   __ j(equal, &function);
3223
3224   __ CmpInstanceType(eax, LAST_SPEC_OBJECT_TYPE);
3225   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3226                 LAST_SPEC_OBJECT_TYPE - 1);
3227   __ j(equal, &function);
3228   // Assume that there is no larger type.
3229   STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
3230
3231   // Check if the constructor in the map is a JS function.
3232   __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
3233   __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3234   __ j(not_equal, &non_function_constructor);
3235
3236   // eax now contains the constructor function. Grab the
3237   // instance class name from there.
3238   __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
3239   __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
3240   __ jmp(&done);
3241
3242   // Functions have class 'Function'.
3243   __ bind(&function);
3244   __ mov(eax, isolate()->factory()->function_class_string());
3245   __ jmp(&done);
3246
3247   // Objects with a non-function constructor have class 'Object'.
3248   __ bind(&non_function_constructor);
3249   __ mov(eax, isolate()->factory()->Object_string());
3250   __ jmp(&done);
3251
3252   // Non-JS objects have class null.
3253   __ bind(&null);
3254   __ mov(eax, isolate()->factory()->null_value());
3255
3256   // All done.
3257   __ bind(&done);
3258
3259   context()->Plug(eax);
3260 }
3261
3262
3263 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
3264   // Load the arguments on the stack and call the stub.
3265   SubStringStub stub(isolate());
3266   ZoneList<Expression*>* args = expr->arguments();
3267   DCHECK(args->length() == 3);
3268   VisitForStackValue(args->at(0));
3269   VisitForStackValue(args->at(1));
3270   VisitForStackValue(args->at(2));
3271   __ CallStub(&stub);
3272   context()->Plug(eax);
3273 }
3274
3275
3276 void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
3277   // Load the arguments on the stack and call the stub.
3278   RegExpExecStub stub(isolate());
3279   ZoneList<Expression*>* args = expr->arguments();
3280   DCHECK(args->length() == 4);
3281   VisitForStackValue(args->at(0));
3282   VisitForStackValue(args->at(1));
3283   VisitForStackValue(args->at(2));
3284   VisitForStackValue(args->at(3));
3285   __ CallStub(&stub);
3286   context()->Plug(eax);
3287 }
3288
3289
3290 void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3291   ZoneList<Expression*>* args = expr->arguments();
3292   DCHECK(args->length() == 1);
3293
3294   VisitForAccumulatorValue(args->at(0));  // Load the object.
3295
3296   Label done;
3297   // If the object is a smi return the object.
3298   __ JumpIfSmi(eax, &done, Label::kNear);
3299   // If the object is not a value type, return the object.
3300   __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
3301   __ j(not_equal, &done, Label::kNear);
3302   __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
3303
3304   __ bind(&done);
3305   context()->Plug(eax);
3306 }
3307
3308
3309 void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3310   ZoneList<Expression*>* args = expr->arguments();
3311   DCHECK(args->length() == 2);
3312   DCHECK_NE(NULL, args->at(1)->AsLiteral());
3313   Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
3314
3315   VisitForAccumulatorValue(args->at(0));  // Load the object.
3316
3317   Label runtime, done, not_date_object;
3318   Register object = eax;
3319   Register result = eax;
3320   Register scratch = ecx;
3321
3322   __ JumpIfSmi(object, &not_date_object);
3323   __ CmpObjectType(object, JS_DATE_TYPE, scratch);
3324   __ j(not_equal, &not_date_object);
3325
3326   if (index->value() == 0) {
3327     __ mov(result, FieldOperand(object, JSDate::kValueOffset));
3328     __ jmp(&done);
3329   } else {
3330     if (index->value() < JSDate::kFirstUncachedField) {
3331       ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3332       __ mov(scratch, Operand::StaticVariable(stamp));
3333       __ cmp(scratch, FieldOperand(object, JSDate::kCacheStampOffset));
3334       __ j(not_equal, &runtime, Label::kNear);
3335       __ mov(result, FieldOperand(object, JSDate::kValueOffset +
3336                                           kPointerSize * index->value()));
3337       __ jmp(&done);
3338     }
3339     __ bind(&runtime);
3340     __ PrepareCallCFunction(2, scratch);
3341     __ mov(Operand(esp, 0), object);
3342     __ mov(Operand(esp, 1 * kPointerSize), Immediate(index));
3343     __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3344     __ jmp(&done);
3345   }
3346
3347   __ bind(&not_date_object);
3348   __ CallRuntime(Runtime::kThrowNotDateError, 0);
3349   __ bind(&done);
3350   context()->Plug(result);
3351 }
3352
3353
3354 void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3355   ZoneList<Expression*>* args = expr->arguments();
3356   DCHECK_EQ(3, args->length());
3357
3358   Register string = eax;
3359   Register index = ebx;
3360   Register value = ecx;
3361
3362   VisitForStackValue(args->at(1));  // index
3363   VisitForStackValue(args->at(2));  // value
3364   VisitForAccumulatorValue(args->at(0));  // string
3365
3366   __ pop(value);
3367   __ pop(index);
3368
3369   if (FLAG_debug_code) {
3370     __ test(value, Immediate(kSmiTagMask));
3371     __ Check(zero, kNonSmiValue);
3372     __ test(index, Immediate(kSmiTagMask));
3373     __ Check(zero, kNonSmiValue);
3374   }
3375
3376   __ SmiUntag(value);
3377   __ SmiUntag(index);
3378
3379   if (FLAG_debug_code) {
3380     static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
3381     __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3382   }
3383
3384   __ mov_b(FieldOperand(string, index, times_1, SeqOneByteString::kHeaderSize),
3385            value);
3386   context()->Plug(string);
3387 }
3388
3389
3390 void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3391   ZoneList<Expression*>* args = expr->arguments();
3392   DCHECK_EQ(3, args->length());
3393
3394   Register string = eax;
3395   Register index = ebx;
3396   Register value = ecx;
3397
3398   VisitForStackValue(args->at(1));  // index
3399   VisitForStackValue(args->at(2));  // value
3400   VisitForAccumulatorValue(args->at(0));  // string
3401   __ pop(value);
3402   __ pop(index);
3403
3404   if (FLAG_debug_code) {
3405     __ test(value, Immediate(kSmiTagMask));
3406     __ Check(zero, kNonSmiValue);
3407     __ test(index, Immediate(kSmiTagMask));
3408     __ Check(zero, kNonSmiValue);
3409     __ SmiUntag(index);
3410     static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
3411     __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3412     __ SmiTag(index);
3413   }
3414
3415   __ SmiUntag(value);
3416   // No need to untag a smi for two-byte addressing.
3417   __ mov_w(FieldOperand(string, index, times_1, SeqTwoByteString::kHeaderSize),
3418            value);
3419   context()->Plug(string);
3420 }
3421
3422
3423 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
3424   // Load the arguments on the stack and call the runtime function.
3425   ZoneList<Expression*>* args = expr->arguments();
3426   DCHECK(args->length() == 2);
3427   VisitForStackValue(args->at(0));
3428   VisitForStackValue(args->at(1));
3429
3430   __ CallRuntime(Runtime::kMathPowSlow, 2);
3431   context()->Plug(eax);
3432 }
3433
3434
3435 void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3436   ZoneList<Expression*>* args = expr->arguments();
3437   DCHECK(args->length() == 2);
3438
3439   VisitForStackValue(args->at(0));  // Load the object.
3440   VisitForAccumulatorValue(args->at(1));  // Load the value.
3441   __ pop(ebx);  // eax = value. ebx = object.
3442
3443   Label done;
3444   // If the object is a smi, return the value.
3445   __ JumpIfSmi(ebx, &done, Label::kNear);
3446
3447   // If the object is not a value type, return the value.
3448   __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
3449   __ j(not_equal, &done, Label::kNear);
3450
3451   // Store the value.
3452   __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
3453
3454   // Update the write barrier.  Save the value as it will be
3455   // overwritten by the write barrier code and is needed afterward.
3456   __ mov(edx, eax);
3457   __ RecordWriteField(ebx, JSValue::kValueOffset, edx, ecx);
3458
3459   __ bind(&done);
3460   context()->Plug(eax);
3461 }
3462
3463
3464 void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3465   ZoneList<Expression*>* args = expr->arguments();
3466   DCHECK_EQ(args->length(), 1);
3467
3468   // Load the argument into eax and call the stub.
3469   VisitForAccumulatorValue(args->at(0));
3470
3471   NumberToStringStub stub(isolate());
3472   __ CallStub(&stub);
3473   context()->Plug(eax);
3474 }
3475
3476
3477 void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3478   ZoneList<Expression*>* args = expr->arguments();
3479   DCHECK(args->length() == 1);
3480
3481   VisitForAccumulatorValue(args->at(0));
3482
3483   Label done;
3484   StringCharFromCodeGenerator generator(eax, ebx);
3485   generator.GenerateFast(masm_);
3486   __ jmp(&done);
3487
3488   NopRuntimeCallHelper call_helper;
3489   generator.GenerateSlow(masm_, call_helper);
3490
3491   __ bind(&done);
3492   context()->Plug(ebx);
3493 }
3494
3495
3496 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3497   ZoneList<Expression*>* args = expr->arguments();
3498   DCHECK(args->length() == 2);
3499
3500   VisitForStackValue(args->at(0));
3501   VisitForAccumulatorValue(args->at(1));
3502
3503   Register object = ebx;
3504   Register index = eax;
3505   Register result = edx;
3506
3507   __ pop(object);
3508
3509   Label need_conversion;
3510   Label index_out_of_range;
3511   Label done;
3512   StringCharCodeAtGenerator generator(object,
3513                                       index,
3514                                       result,
3515                                       &need_conversion,
3516                                       &need_conversion,
3517                                       &index_out_of_range,
3518                                       STRING_INDEX_IS_NUMBER);
3519   generator.GenerateFast(masm_);
3520   __ jmp(&done);
3521
3522   __ bind(&index_out_of_range);
3523   // When the index is out of range, the spec requires us to return
3524   // NaN.
3525   __ Move(result, Immediate(isolate()->factory()->nan_value()));
3526   __ jmp(&done);
3527
3528   __ bind(&need_conversion);
3529   // Move the undefined value into the result register, which will
3530   // trigger conversion.
3531   __ Move(result, Immediate(isolate()->factory()->undefined_value()));
3532   __ jmp(&done);
3533
3534   NopRuntimeCallHelper call_helper;
3535   generator.GenerateSlow(masm_, call_helper);
3536
3537   __ bind(&done);
3538   context()->Plug(result);
3539 }
3540
3541
3542 void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3543   ZoneList<Expression*>* args = expr->arguments();
3544   DCHECK(args->length() == 2);
3545
3546   VisitForStackValue(args->at(0));
3547   VisitForAccumulatorValue(args->at(1));
3548
3549   Register object = ebx;
3550   Register index = eax;
3551   Register scratch = edx;
3552   Register result = eax;
3553
3554   __ pop(object);
3555
3556   Label need_conversion;
3557   Label index_out_of_range;
3558   Label done;
3559   StringCharAtGenerator generator(object,
3560                                   index,
3561                                   scratch,
3562                                   result,
3563                                   &need_conversion,
3564                                   &need_conversion,
3565                                   &index_out_of_range,
3566                                   STRING_INDEX_IS_NUMBER);
3567   generator.GenerateFast(masm_);
3568   __ jmp(&done);
3569
3570   __ bind(&index_out_of_range);
3571   // When the index is out of range, the spec requires us to return
3572   // the empty string.
3573   __ Move(result, Immediate(isolate()->factory()->empty_string()));
3574   __ jmp(&done);
3575
3576   __ bind(&need_conversion);
3577   // Move smi zero into the result register, which will trigger
3578   // conversion.
3579   __ Move(result, Immediate(Smi::FromInt(0)));
3580   __ jmp(&done);
3581
3582   NopRuntimeCallHelper call_helper;
3583   generator.GenerateSlow(masm_, call_helper);
3584
3585   __ bind(&done);
3586   context()->Plug(result);
3587 }
3588
3589
3590 void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3591   ZoneList<Expression*>* args = expr->arguments();
3592   DCHECK_EQ(2, args->length());
3593   VisitForStackValue(args->at(0));
3594   VisitForAccumulatorValue(args->at(1));
3595
3596   __ pop(edx);
3597   StringAddStub stub(isolate(), STRING_ADD_CHECK_BOTH, NOT_TENURED);
3598   __ CallStub(&stub);
3599   context()->Plug(eax);
3600 }
3601
3602
3603 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3604   ZoneList<Expression*>* args = expr->arguments();
3605   DCHECK_EQ(2, args->length());
3606
3607   VisitForStackValue(args->at(0));
3608   VisitForStackValue(args->at(1));
3609
3610   StringCompareStub stub(isolate());
3611   __ CallStub(&stub);
3612   context()->Plug(eax);
3613 }
3614
3615
3616 void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3617   ZoneList<Expression*>* args = expr->arguments();
3618   DCHECK(args->length() >= 2);
3619
3620   int arg_count = args->length() - 2;  // 2 ~ receiver and function.
3621   for (int i = 0; i < arg_count + 1; ++i) {
3622     VisitForStackValue(args->at(i));
3623   }
3624   VisitForAccumulatorValue(args->last());  // Function.
3625
3626   Label runtime, done;
3627   // Check for non-function argument (including proxy).
3628   __ JumpIfSmi(eax, &runtime);
3629   __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
3630   __ j(not_equal, &runtime);
3631
3632   // InvokeFunction requires the function in edi. Move it in there.
3633   __ mov(edi, result_register());
3634   ParameterCount count(arg_count);
3635   __ InvokeFunction(edi, count, CALL_FUNCTION, NullCallWrapper());
3636   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
3637   __ jmp(&done);
3638
3639   __ bind(&runtime);
3640   __ push(eax);
3641   __ CallRuntime(Runtime::kCall, args->length());
3642   __ bind(&done);
3643
3644   context()->Plug(eax);
3645 }
3646
3647
3648 void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
3649   // Load the arguments on the stack and call the stub.
3650   RegExpConstructResultStub stub(isolate());
3651   ZoneList<Expression*>* args = expr->arguments();
3652   DCHECK(args->length() == 3);
3653   VisitForStackValue(args->at(0));
3654   VisitForStackValue(args->at(1));
3655   VisitForAccumulatorValue(args->at(2));
3656   __ pop(ebx);
3657   __ pop(ecx);
3658   __ CallStub(&stub);
3659   context()->Plug(eax);
3660 }
3661
3662
3663 void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3664   ZoneList<Expression*>* args = expr->arguments();
3665   DCHECK_EQ(2, args->length());
3666
3667   DCHECK_NE(NULL, args->at(0)->AsLiteral());
3668   int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
3669
3670   Handle<FixedArray> jsfunction_result_caches(
3671       isolate()->native_context()->jsfunction_result_caches());
3672   if (jsfunction_result_caches->length() <= cache_id) {
3673     __ Abort(kAttemptToUseUndefinedCache);
3674     __ mov(eax, isolate()->factory()->undefined_value());
3675     context()->Plug(eax);
3676     return;
3677   }
3678
3679   VisitForAccumulatorValue(args->at(1));
3680
3681   Register key = eax;
3682   Register cache = ebx;
3683   Register tmp = ecx;
3684   __ mov(cache, ContextOperand(esi, Context::GLOBAL_OBJECT_INDEX));
3685   __ mov(cache,
3686          FieldOperand(cache, GlobalObject::kNativeContextOffset));
3687   __ mov(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
3688   __ mov(cache,
3689          FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3690
3691   Label done, not_found;
3692   STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3693   __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
3694   // tmp now holds finger offset as a smi.
3695   __ cmp(key, FixedArrayElementOperand(cache, tmp));
3696   __ j(not_equal, &not_found);
3697
3698   __ mov(eax, FixedArrayElementOperand(cache, tmp, 1));
3699   __ jmp(&done);
3700
3701   __ bind(&not_found);
3702   // Call runtime to perform the lookup.
3703   __ push(cache);
3704   __ push(key);
3705   __ CallRuntime(Runtime::kGetFromCache, 2);
3706
3707   __ bind(&done);
3708   context()->Plug(eax);
3709 }
3710
3711
3712 void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3713   ZoneList<Expression*>* args = expr->arguments();
3714   DCHECK(args->length() == 1);
3715
3716   VisitForAccumulatorValue(args->at(0));
3717
3718   __ AssertString(eax);
3719
3720   Label materialize_true, materialize_false;
3721   Label* if_true = NULL;
3722   Label* if_false = NULL;
3723   Label* fall_through = NULL;
3724   context()->PrepareTest(&materialize_true, &materialize_false,
3725                          &if_true, &if_false, &fall_through);
3726
3727   __ test(FieldOperand(eax, String::kHashFieldOffset),
3728           Immediate(String::kContainsCachedArrayIndexMask));
3729   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3730   Split(zero, if_true, if_false, fall_through);
3731
3732   context()->Plug(if_true, if_false);
3733 }
3734
3735
3736 void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3737   ZoneList<Expression*>* args = expr->arguments();
3738   DCHECK(args->length() == 1);
3739   VisitForAccumulatorValue(args->at(0));
3740
3741   __ AssertString(eax);
3742
3743   __ mov(eax, FieldOperand(eax, String::kHashFieldOffset));
3744   __ IndexFromHash(eax, eax);
3745
3746   context()->Plug(eax);
3747 }
3748
3749
3750 void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
3751   Label bailout, done, one_char_separator, long_separator,
3752       non_trivial_array, not_size_one_array, loop,
3753       loop_1, loop_1_condition, loop_2, loop_2_entry, loop_3, loop_3_entry;
3754
3755   ZoneList<Expression*>* args = expr->arguments();
3756   DCHECK(args->length() == 2);
3757   // We will leave the separator on the stack until the end of the function.
3758   VisitForStackValue(args->at(1));
3759   // Load this to eax (= array)
3760   VisitForAccumulatorValue(args->at(0));
3761   // All aliases of the same register have disjoint lifetimes.
3762   Register array = eax;
3763   Register elements = no_reg;  // Will be eax.
3764
3765   Register index = edx;
3766
3767   Register string_length = ecx;
3768
3769   Register string = esi;
3770
3771   Register scratch = ebx;
3772
3773   Register array_length = edi;
3774   Register result_pos = no_reg;  // Will be edi.
3775
3776   // Separator operand is already pushed.
3777   Operand separator_operand = Operand(esp, 2 * kPointerSize);
3778   Operand result_operand = Operand(esp, 1 * kPointerSize);
3779   Operand array_length_operand = Operand(esp, 0);
3780   __ sub(esp, Immediate(2 * kPointerSize));
3781   __ cld();
3782   // Check that the array is a JSArray
3783   __ JumpIfSmi(array, &bailout);
3784   __ CmpObjectType(array, JS_ARRAY_TYPE, scratch);
3785   __ j(not_equal, &bailout);
3786
3787   // Check that the array has fast elements.
3788   __ CheckFastElements(scratch, &bailout);
3789
3790   // If the array has length zero, return the empty string.
3791   __ mov(array_length, FieldOperand(array, JSArray::kLengthOffset));
3792   __ SmiUntag(array_length);
3793   __ j(not_zero, &non_trivial_array);
3794   __ mov(result_operand, isolate()->factory()->empty_string());
3795   __ jmp(&done);
3796
3797   // Save the array length.
3798   __ bind(&non_trivial_array);
3799   __ mov(array_length_operand, array_length);
3800
3801   // Save the FixedArray containing array's elements.
3802   // End of array's live range.
3803   elements = array;
3804   __ mov(elements, FieldOperand(array, JSArray::kElementsOffset));
3805   array = no_reg;
3806
3807
3808   // Check that all array elements are sequential ASCII strings, and
3809   // accumulate the sum of their lengths, as a smi-encoded value.
3810   __ Move(index, Immediate(0));
3811   __ Move(string_length, Immediate(0));
3812   // Loop condition: while (index < length).
3813   // Live loop registers: index, array_length, string,
3814   //                      scratch, string_length, elements.
3815   if (generate_debug_code_) {
3816     __ cmp(index, array_length);
3817     __ Assert(less, kNoEmptyArraysHereInEmitFastAsciiArrayJoin);
3818   }
3819   __ bind(&loop);
3820   __ mov(string, FieldOperand(elements,
3821                               index,
3822                               times_pointer_size,
3823                               FixedArray::kHeaderSize));
3824   __ JumpIfSmi(string, &bailout);
3825   __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3826   __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3827   __ and_(scratch, Immediate(
3828       kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3829   __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
3830   __ j(not_equal, &bailout);
3831   __ add(string_length,
3832          FieldOperand(string, SeqOneByteString::kLengthOffset));
3833   __ j(overflow, &bailout);
3834   __ add(index, Immediate(1));
3835   __ cmp(index, array_length);
3836   __ j(less, &loop);
3837
3838   // If array_length is 1, return elements[0], a string.
3839   __ cmp(array_length, 1);
3840   __ j(not_equal, &not_size_one_array);
3841   __ mov(scratch, FieldOperand(elements, FixedArray::kHeaderSize));
3842   __ mov(result_operand, scratch);
3843   __ jmp(&done);
3844
3845   __ bind(&not_size_one_array);
3846
3847   // End of array_length live range.
3848   result_pos = array_length;
3849   array_length = no_reg;
3850
3851   // Live registers:
3852   // string_length: Sum of string lengths, as a smi.
3853   // elements: FixedArray of strings.
3854
3855   // Check that the separator is a flat ASCII string.
3856   __ mov(string, separator_operand);
3857   __ JumpIfSmi(string, &bailout);
3858   __ mov(scratch, FieldOperand(string, HeapObject::kMapOffset));
3859   __ movzx_b(scratch, FieldOperand(scratch, Map::kInstanceTypeOffset));
3860   __ and_(scratch, Immediate(
3861       kIsNotStringMask | kStringEncodingMask | kStringRepresentationMask));
3862   __ cmp(scratch, kStringTag | kOneByteStringTag | kSeqStringTag);
3863   __ j(not_equal, &bailout);
3864
3865   // Add (separator length times array_length) - separator length
3866   // to string_length.
3867   __ mov(scratch, separator_operand);
3868   __ mov(scratch, FieldOperand(scratch, SeqOneByteString::kLengthOffset));
3869   __ sub(string_length, scratch);  // May be negative, temporarily.
3870   __ imul(scratch, array_length_operand);
3871   __ j(overflow, &bailout);
3872   __ add(string_length, scratch);
3873   __ j(overflow, &bailout);
3874
3875   __ shr(string_length, 1);
3876   // Live registers and stack values:
3877   //   string_length
3878   //   elements
3879   __ AllocateAsciiString(result_pos, string_length, scratch,
3880                          index, string, &bailout);
3881   __ mov(result_operand, result_pos);
3882   __ lea(result_pos, FieldOperand(result_pos, SeqOneByteString::kHeaderSize));
3883
3884
3885   __ mov(string, separator_operand);
3886   __ cmp(FieldOperand(string, SeqOneByteString::kLengthOffset),
3887          Immediate(Smi::FromInt(1)));
3888   __ j(equal, &one_char_separator);
3889   __ j(greater, &long_separator);
3890
3891
3892   // Empty separator case
3893   __ mov(index, Immediate(0));
3894   __ jmp(&loop_1_condition);
3895   // Loop condition: while (index < length).
3896   __ bind(&loop_1);
3897   // Each iteration of the loop concatenates one string to the result.
3898   // Live values in registers:
3899   //   index: which element of the elements array we are adding to the result.
3900   //   result_pos: the position to which we are currently copying characters.
3901   //   elements: the FixedArray of strings we are joining.
3902
3903   // Get string = array[index].
3904   __ mov(string, FieldOperand(elements, index,
3905                               times_pointer_size,
3906                               FixedArray::kHeaderSize));
3907   __ mov(string_length,
3908          FieldOperand(string, String::kLengthOffset));
3909   __ shr(string_length, 1);
3910   __ lea(string,
3911          FieldOperand(string, SeqOneByteString::kHeaderSize));
3912   __ CopyBytes(string, result_pos, string_length, scratch);
3913   __ add(index, Immediate(1));
3914   __ bind(&loop_1_condition);
3915   __ cmp(index, array_length_operand);
3916   __ j(less, &loop_1);  // End while (index < length).
3917   __ jmp(&done);
3918
3919
3920
3921   // One-character separator case
3922   __ bind(&one_char_separator);
3923   // Replace separator with its ASCII character value.
3924   __ mov_b(scratch, FieldOperand(string, SeqOneByteString::kHeaderSize));
3925   __ mov_b(separator_operand, scratch);
3926
3927   __ Move(index, Immediate(0));
3928   // Jump into the loop after the code that copies the separator, so the first
3929   // element is not preceded by a separator
3930   __ jmp(&loop_2_entry);
3931   // Loop condition: while (index < length).
3932   __ bind(&loop_2);
3933   // Each iteration of the loop concatenates one string to the result.
3934   // Live values in registers:
3935   //   index: which element of the elements array we are adding to the result.
3936   //   result_pos: the position to which we are currently copying characters.
3937
3938   // Copy the separator character to the result.
3939   __ mov_b(scratch, separator_operand);
3940   __ mov_b(Operand(result_pos, 0), scratch);
3941   __ inc(result_pos);
3942
3943   __ bind(&loop_2_entry);
3944   // Get string = array[index].
3945   __ mov(string, FieldOperand(elements, index,
3946                               times_pointer_size,
3947                               FixedArray::kHeaderSize));
3948   __ mov(string_length,
3949          FieldOperand(string, String::kLengthOffset));
3950   __ shr(string_length, 1);
3951   __ lea(string,
3952          FieldOperand(string, SeqOneByteString::kHeaderSize));
3953   __ CopyBytes(string, result_pos, string_length, scratch);
3954   __ add(index, Immediate(1));
3955
3956   __ cmp(index, array_length_operand);
3957   __ j(less, &loop_2);  // End while (index < length).
3958   __ jmp(&done);
3959
3960
3961   // Long separator case (separator is more than one character).
3962   __ bind(&long_separator);
3963
3964   __ Move(index, Immediate(0));
3965   // Jump into the loop after the code that copies the separator, so the first
3966   // element is not preceded by a separator
3967   __ jmp(&loop_3_entry);
3968   // Loop condition: while (index < length).
3969   __ bind(&loop_3);
3970   // Each iteration of the loop concatenates one string to the result.
3971   // Live values in registers:
3972   //   index: which element of the elements array we are adding to the result.
3973   //   result_pos: the position to which we are currently copying characters.
3974
3975   // Copy the separator to the result.
3976   __ mov(string, separator_operand);
3977   __ mov(string_length,
3978          FieldOperand(string, String::kLengthOffset));
3979   __ shr(string_length, 1);
3980   __ lea(string,
3981          FieldOperand(string, SeqOneByteString::kHeaderSize));
3982   __ CopyBytes(string, result_pos, string_length, scratch);
3983
3984   __ bind(&loop_3_entry);
3985   // Get string = array[index].
3986   __ mov(string, FieldOperand(elements, index,
3987                               times_pointer_size,
3988                               FixedArray::kHeaderSize));
3989   __ mov(string_length,
3990          FieldOperand(string, String::kLengthOffset));
3991   __ shr(string_length, 1);
3992   __ lea(string,
3993          FieldOperand(string, SeqOneByteString::kHeaderSize));
3994   __ CopyBytes(string, result_pos, string_length, scratch);
3995   __ add(index, Immediate(1));
3996
3997   __ cmp(index, array_length_operand);
3998   __ j(less, &loop_3);  // End while (index < length).
3999   __ jmp(&done);
4000
4001
4002   __ bind(&bailout);
4003   __ mov(result_operand, isolate()->factory()->undefined_value());
4004   __ bind(&done);
4005   __ mov(eax, result_operand);
4006   // Drop temp values from the stack, and restore context register.
4007   __ add(esp, Immediate(3 * kPointerSize));
4008
4009   __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4010   context()->Plug(eax);
4011 }
4012
4013
4014 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
4015   DCHECK(expr->arguments()->length() == 0);
4016   ExternalReference debug_is_active =
4017       ExternalReference::debug_is_active_address(isolate());
4018   __ movzx_b(eax, Operand::StaticVariable(debug_is_active));
4019   __ SmiTag(eax);
4020   context()->Plug(eax);
4021 }
4022
4023
4024 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
4025   if (expr->function() != NULL &&
4026       expr->function()->intrinsic_type == Runtime::INLINE) {
4027     Comment cmnt(masm_, "[ InlineRuntimeCall");
4028     EmitInlineRuntimeCall(expr);
4029     return;
4030   }
4031
4032   Comment cmnt(masm_, "[ CallRuntime");
4033   ZoneList<Expression*>* args = expr->arguments();
4034
4035   if (expr->is_jsruntime()) {
4036     // Push the builtins object as receiver.
4037     __ mov(eax, GlobalObjectOperand());
4038     __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
4039
4040     // Load the function from the receiver.
4041     __ mov(LoadIC::ReceiverRegister(), Operand(esp, 0));
4042     __ mov(LoadIC::NameRegister(), Immediate(expr->name()));
4043     if (FLAG_vector_ics) {
4044       __ mov(LoadIC::SlotRegister(),
4045              Immediate(Smi::FromInt(expr->CallRuntimeFeedbackSlot())));
4046       CallLoadIC(NOT_CONTEXTUAL);
4047     } else {
4048       CallLoadIC(NOT_CONTEXTUAL, expr->CallRuntimeFeedbackId());
4049     }
4050
4051     // Push the target function under the receiver.
4052     __ push(Operand(esp, 0));
4053     __ mov(Operand(esp, kPointerSize), eax);
4054
4055     // Code common for calls using the IC.
4056     ZoneList<Expression*>* args = expr->arguments();
4057     int arg_count = args->length();
4058     for (int i = 0; i < arg_count; i++) {
4059       VisitForStackValue(args->at(i));
4060     }
4061
4062     // Record source position of the IC call.
4063     SetSourcePosition(expr->position());
4064     CallFunctionStub stub(isolate(), arg_count, NO_CALL_FUNCTION_FLAGS);
4065     __ mov(edi, Operand(esp, (arg_count + 1) * kPointerSize));
4066     __ CallStub(&stub);
4067     // Restore context register.
4068     __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
4069     context()->DropAndPlug(1, eax);
4070
4071   } else {
4072     // Push the arguments ("left-to-right").
4073     int arg_count = args->length();
4074     for (int i = 0; i < arg_count; i++) {
4075       VisitForStackValue(args->at(i));
4076     }
4077
4078     // Call the C runtime function.
4079     __ CallRuntime(expr->function(), arg_count);
4080
4081     context()->Plug(eax);
4082   }
4083 }
4084
4085
4086 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4087   switch (expr->op()) {
4088     case Token::DELETE: {
4089       Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
4090       Property* property = expr->expression()->AsProperty();
4091       VariableProxy* proxy = expr->expression()->AsVariableProxy();
4092
4093       if (property != NULL) {
4094         VisitForStackValue(property->obj());
4095         VisitForStackValue(property->key());
4096         __ push(Immediate(Smi::FromInt(strict_mode())));
4097         __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4098         context()->Plug(eax);
4099       } else if (proxy != NULL) {
4100         Variable* var = proxy->var();
4101         // Delete of an unqualified identifier is disallowed in strict mode
4102         // but "delete this" is allowed.
4103         DCHECK(strict_mode() == SLOPPY || var->is_this());
4104         if (var->IsUnallocated()) {
4105           __ push(GlobalObjectOperand());
4106           __ push(Immediate(var->name()));
4107           __ push(Immediate(Smi::FromInt(SLOPPY)));
4108           __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4109           context()->Plug(eax);
4110         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
4111           // Result of deleting non-global variables is false.  'this' is
4112           // not really a variable, though we implement it as one.  The
4113           // subexpression does not have side effects.
4114           context()->Plug(var->is_this());
4115         } else {
4116           // Non-global variable.  Call the runtime to try to delete from the
4117           // context where the variable was introduced.
4118           __ push(context_register());
4119           __ push(Immediate(var->name()));
4120           __ CallRuntime(Runtime::kDeleteLookupSlot, 2);
4121           context()->Plug(eax);
4122         }
4123       } else {
4124         // Result of deleting non-property, non-variable reference is true.
4125         // The subexpression may have side effects.
4126         VisitForEffect(expr->expression());
4127         context()->Plug(true);
4128       }
4129       break;
4130     }
4131
4132     case Token::VOID: {
4133       Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4134       VisitForEffect(expr->expression());
4135       context()->Plug(isolate()->factory()->undefined_value());
4136       break;
4137     }
4138
4139     case Token::NOT: {
4140       Comment cmnt(masm_, "[ UnaryOperation (NOT)");
4141       if (context()->IsEffect()) {
4142         // Unary NOT has no side effects so it's only necessary to visit the
4143         // subexpression.  Match the optimizing compiler by not branching.
4144         VisitForEffect(expr->expression());
4145       } else if (context()->IsTest()) {
4146         const TestContext* test = TestContext::cast(context());
4147         // The labels are swapped for the recursive call.
4148         VisitForControl(expr->expression(),
4149                         test->false_label(),
4150                         test->true_label(),
4151                         test->fall_through());
4152         context()->Plug(test->true_label(), test->false_label());
4153       } else {
4154         // We handle value contexts explicitly rather than simply visiting
4155         // for control and plugging the control flow into the context,
4156         // because we need to prepare a pair of extra administrative AST ids
4157         // for the optimizing compiler.
4158         DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
4159         Label materialize_true, materialize_false, done;
4160         VisitForControl(expr->expression(),
4161                         &materialize_false,
4162                         &materialize_true,
4163                         &materialize_true);
4164         __ bind(&materialize_true);
4165         PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4166         if (context()->IsAccumulatorValue()) {
4167           __ mov(eax, isolate()->factory()->true_value());
4168         } else {
4169           __ Push(isolate()->factory()->true_value());
4170         }
4171         __ jmp(&done, Label::kNear);
4172         __ bind(&materialize_false);
4173         PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4174         if (context()->IsAccumulatorValue()) {
4175           __ mov(eax, isolate()->factory()->false_value());
4176         } else {
4177           __ Push(isolate()->factory()->false_value());
4178         }
4179         __ bind(&done);
4180       }
4181       break;
4182     }
4183
4184     case Token::TYPEOF: {
4185       Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
4186       { StackValueContext context(this);
4187         VisitForTypeofValue(expr->expression());
4188       }
4189       __ CallRuntime(Runtime::kTypeof, 1);
4190       context()->Plug(eax);
4191       break;
4192     }
4193
4194     default:
4195       UNREACHABLE();
4196   }
4197 }
4198
4199
4200 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4201   DCHECK(expr->expression()->IsValidReferenceExpression());
4202
4203   Comment cmnt(masm_, "[ CountOperation");
4204   SetSourcePosition(expr->position());
4205
4206   // Expression can only be a property, a global or a (parameter or local)
4207   // slot.
4208   enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4209   LhsKind assign_type = VARIABLE;
4210   Property* prop = expr->expression()->AsProperty();
4211   // In case of a property we use the uninitialized expression context
4212   // of the key to detect a named property.
4213   if (prop != NULL) {
4214     assign_type =
4215         (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4216   }
4217
4218   // Evaluate expression and get value.
4219   if (assign_type == VARIABLE) {
4220     DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
4221     AccumulatorValueContext context(this);
4222     EmitVariableLoad(expr->expression()->AsVariableProxy());
4223   } else {
4224     // Reserve space for result of postfix operation.
4225     if (expr->is_postfix() && !context()->IsEffect()) {
4226       __ push(Immediate(Smi::FromInt(0)));
4227     }
4228     if (assign_type == NAMED_PROPERTY) {
4229       // Put the object both on the stack and in the register.
4230       VisitForStackValue(prop->obj());
4231       __ mov(LoadIC::ReceiverRegister(), Operand(esp, 0));
4232       EmitNamedPropertyLoad(prop);
4233     } else {
4234       VisitForStackValue(prop->obj());
4235       VisitForStackValue(prop->key());
4236       __ mov(LoadIC::ReceiverRegister(),
4237              Operand(esp, kPointerSize));               // Object.
4238       __ mov(LoadIC::NameRegister(), Operand(esp, 0));  // Key.
4239       EmitKeyedPropertyLoad(prop);
4240     }
4241   }
4242
4243   // We need a second deoptimization point after loading the value
4244   // in case evaluating the property load my have a side effect.
4245   if (assign_type == VARIABLE) {
4246     PrepareForBailout(expr->expression(), TOS_REG);
4247   } else {
4248     PrepareForBailoutForId(prop->LoadId(), TOS_REG);
4249   }
4250
4251   // Inline smi case if we are in a loop.
4252   Label done, stub_call;
4253   JumpPatchSite patch_site(masm_);
4254   if (ShouldInlineSmiCase(expr->op())) {
4255     Label slow;
4256     patch_site.EmitJumpIfNotSmi(eax, &slow, Label::kNear);
4257
4258     // Save result for postfix expressions.
4259     if (expr->is_postfix()) {
4260       if (!context()->IsEffect()) {
4261         // Save the result on the stack. If we have a named or keyed property
4262         // we store the result under the receiver that is currently on top
4263         // of the stack.
4264         switch (assign_type) {
4265           case VARIABLE:
4266             __ push(eax);
4267             break;
4268           case NAMED_PROPERTY:
4269             __ mov(Operand(esp, kPointerSize), eax);
4270             break;
4271           case KEYED_PROPERTY:
4272             __ mov(Operand(esp, 2 * kPointerSize), eax);
4273             break;
4274         }
4275       }
4276     }
4277
4278     if (expr->op() == Token::INC) {
4279       __ add(eax, Immediate(Smi::FromInt(1)));
4280     } else {
4281       __ sub(eax, Immediate(Smi::FromInt(1)));
4282     }
4283     __ j(no_overflow, &done, Label::kNear);
4284     // Call stub. Undo operation first.
4285     if (expr->op() == Token::INC) {
4286       __ sub(eax, Immediate(Smi::FromInt(1)));
4287     } else {
4288       __ add(eax, Immediate(Smi::FromInt(1)));
4289     }
4290     __ jmp(&stub_call, Label::kNear);
4291     __ bind(&slow);
4292   }
4293   ToNumberStub convert_stub(isolate());
4294   __ CallStub(&convert_stub);
4295
4296   // Save result for postfix expressions.
4297   if (expr->is_postfix()) {
4298     if (!context()->IsEffect()) {
4299       // Save the result on the stack. If we have a named or keyed property
4300       // we store the result under the receiver that is currently on top
4301       // of the stack.
4302       switch (assign_type) {
4303         case VARIABLE:
4304           __ push(eax);
4305           break;
4306         case NAMED_PROPERTY:
4307           __ mov(Operand(esp, kPointerSize), eax);
4308           break;
4309         case KEYED_PROPERTY:
4310           __ mov(Operand(esp, 2 * kPointerSize), eax);
4311           break;
4312       }
4313     }
4314   }
4315
4316   // Record position before stub call.
4317   SetSourcePosition(expr->position());
4318
4319   // Call stub for +1/-1.
4320   __ bind(&stub_call);
4321   __ mov(edx, eax);
4322   __ mov(eax, Immediate(Smi::FromInt(1)));
4323   BinaryOpICStub stub(isolate(), expr->binary_op(), NO_OVERWRITE);
4324   CallIC(stub.GetCode(), expr->CountBinOpFeedbackId());
4325   patch_site.EmitPatchInfo();
4326   __ bind(&done);
4327
4328   // Store the value returned in eax.
4329   switch (assign_type) {
4330     case VARIABLE:
4331       if (expr->is_postfix()) {
4332         // Perform the assignment as if via '='.
4333         { EffectContext context(this);
4334           EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4335                                  Token::ASSIGN);
4336           PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4337           context.Plug(eax);
4338         }
4339         // For all contexts except EffectContext We have the result on
4340         // top of the stack.
4341         if (!context()->IsEffect()) {
4342           context()->PlugTOS();
4343         }
4344       } else {
4345         // Perform the assignment as if via '='.
4346         EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4347                                Token::ASSIGN);
4348         PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4349         context()->Plug(eax);
4350       }
4351       break;
4352     case NAMED_PROPERTY: {
4353       __ mov(StoreIC::NameRegister(), prop->key()->AsLiteral()->value());
4354       __ pop(StoreIC::ReceiverRegister());
4355       CallStoreIC(expr->CountStoreFeedbackId());
4356       PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4357       if (expr->is_postfix()) {
4358         if (!context()->IsEffect()) {
4359           context()->PlugTOS();
4360         }
4361       } else {
4362         context()->Plug(eax);
4363       }
4364       break;
4365     }
4366     case KEYED_PROPERTY: {
4367       __ pop(KeyedStoreIC::NameRegister());
4368       __ pop(KeyedStoreIC::ReceiverRegister());
4369       Handle<Code> ic = strict_mode() == SLOPPY
4370           ? isolate()->builtins()->KeyedStoreIC_Initialize()
4371           : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
4372       CallIC(ic, expr->CountStoreFeedbackId());
4373       PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4374       if (expr->is_postfix()) {
4375         // Result is on the stack
4376         if (!context()->IsEffect()) {
4377           context()->PlugTOS();
4378         }
4379       } else {
4380         context()->Plug(eax);
4381       }
4382       break;
4383     }
4384   }
4385 }
4386
4387
4388 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
4389   VariableProxy* proxy = expr->AsVariableProxy();
4390   DCHECK(!context()->IsEffect());
4391   DCHECK(!context()->IsTest());
4392
4393   if (proxy != NULL && proxy->var()->IsUnallocated()) {
4394     Comment cmnt(masm_, "[ Global variable");
4395     __ mov(LoadIC::ReceiverRegister(), GlobalObjectOperand());
4396     __ mov(LoadIC::NameRegister(), Immediate(proxy->name()));
4397     if (FLAG_vector_ics) {
4398       __ mov(LoadIC::SlotRegister(),
4399              Immediate(Smi::FromInt(proxy->VariableFeedbackSlot())));
4400     }
4401     // Use a regular load, not a contextual load, to avoid a reference
4402     // error.
4403     CallLoadIC(NOT_CONTEXTUAL);
4404     PrepareForBailout(expr, TOS_REG);
4405     context()->Plug(eax);
4406   } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
4407     Comment cmnt(masm_, "[ Lookup slot");
4408     Label done, slow;
4409
4410     // Generate code for loading from variables potentially shadowed
4411     // by eval-introduced variables.
4412     EmitDynamicLookupFastCase(proxy, INSIDE_TYPEOF, &slow, &done);
4413
4414     __ bind(&slow);
4415     __ push(esi);
4416     __ push(Immediate(proxy->name()));
4417     __ CallRuntime(Runtime::kLoadLookupSlotNoReferenceError, 2);
4418     PrepareForBailout(expr, TOS_REG);
4419     __ bind(&done);
4420
4421     context()->Plug(eax);
4422   } else {
4423     // This expression cannot throw a reference error at the top level.
4424     VisitInDuplicateContext(expr);
4425   }
4426 }
4427
4428
4429 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
4430                                                  Expression* sub_expr,
4431                                                  Handle<String> check) {
4432   Label materialize_true, materialize_false;
4433   Label* if_true = NULL;
4434   Label* if_false = NULL;
4435   Label* fall_through = NULL;
4436   context()->PrepareTest(&materialize_true, &materialize_false,
4437                          &if_true, &if_false, &fall_through);
4438
4439   { AccumulatorValueContext context(this);
4440     VisitForTypeofValue(sub_expr);
4441   }
4442   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4443
4444   Factory* factory = isolate()->factory();
4445   if (String::Equals(check, factory->number_string())) {
4446     __ JumpIfSmi(eax, if_true);
4447     __ cmp(FieldOperand(eax, HeapObject::kMapOffset),
4448            isolate()->factory()->heap_number_map());
4449     Split(equal, if_true, if_false, fall_through);
4450   } else if (String::Equals(check, factory->string_string())) {
4451     __ JumpIfSmi(eax, if_false);
4452     __ CmpObjectType(eax, FIRST_NONSTRING_TYPE, edx);
4453     __ j(above_equal, if_false);
4454     // Check for undetectable objects => false.
4455     __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4456               1 << Map::kIsUndetectable);
4457     Split(zero, if_true, if_false, fall_through);
4458   } else if (String::Equals(check, factory->symbol_string())) {
4459     __ JumpIfSmi(eax, if_false);
4460     __ CmpObjectType(eax, SYMBOL_TYPE, edx);
4461     Split(equal, if_true, if_false, fall_through);
4462   } else if (String::Equals(check, factory->boolean_string())) {
4463     __ cmp(eax, isolate()->factory()->true_value());
4464     __ j(equal, if_true);
4465     __ cmp(eax, isolate()->factory()->false_value());
4466     Split(equal, if_true, if_false, fall_through);
4467   } else if (String::Equals(check, factory->undefined_string())) {
4468     __ cmp(eax, isolate()->factory()->undefined_value());
4469     __ j(equal, if_true);
4470     __ JumpIfSmi(eax, if_false);
4471     // Check for undetectable objects => true.
4472     __ mov(edx, FieldOperand(eax, HeapObject::kMapOffset));
4473     __ movzx_b(ecx, FieldOperand(edx, Map::kBitFieldOffset));
4474     __ test(ecx, Immediate(1 << Map::kIsUndetectable));
4475     Split(not_zero, if_true, if_false, fall_through);
4476   } else if (String::Equals(check, factory->function_string())) {
4477     __ JumpIfSmi(eax, if_false);
4478     STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4479     __ CmpObjectType(eax, JS_FUNCTION_TYPE, edx);
4480     __ j(equal, if_true);
4481     __ CmpInstanceType(edx, JS_FUNCTION_PROXY_TYPE);
4482     Split(equal, if_true, if_false, fall_through);
4483   } else if (String::Equals(check, factory->object_string())) {
4484     __ JumpIfSmi(eax, if_false);
4485     __ cmp(eax, isolate()->factory()->null_value());
4486     __ j(equal, if_true);
4487     __ CmpObjectType(eax, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE, edx);
4488     __ j(below, if_false);
4489     __ CmpInstanceType(edx, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4490     __ j(above, if_false);
4491     // Check for undetectable objects => false.
4492     __ test_b(FieldOperand(edx, Map::kBitFieldOffset),
4493               1 << Map::kIsUndetectable);
4494     Split(zero, if_true, if_false, fall_through);
4495   } else {
4496     if (if_false != fall_through) __ jmp(if_false);
4497   }
4498   context()->Plug(if_true, if_false);
4499 }
4500
4501
4502 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4503   Comment cmnt(masm_, "[ CompareOperation");
4504   SetSourcePosition(expr->position());
4505
4506   // First we try a fast inlined version of the compare when one of
4507   // the operands is a literal.
4508   if (TryLiteralCompare(expr)) return;
4509
4510   // Always perform the comparison for its control flow.  Pack the result
4511   // into the expression's context after the comparison is performed.
4512   Label materialize_true, materialize_false;
4513   Label* if_true = NULL;
4514   Label* if_false = NULL;
4515   Label* fall_through = NULL;
4516   context()->PrepareTest(&materialize_true, &materialize_false,
4517                          &if_true, &if_false, &fall_through);
4518
4519   Token::Value op = expr->op();
4520   VisitForStackValue(expr->left());
4521   switch (op) {
4522     case Token::IN:
4523       VisitForStackValue(expr->right());
4524       __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
4525       PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
4526       __ cmp(eax, isolate()->factory()->true_value());
4527       Split(equal, if_true, if_false, fall_through);
4528       break;
4529
4530     case Token::INSTANCEOF: {
4531       VisitForStackValue(expr->right());
4532       InstanceofStub stub(isolate(), InstanceofStub::kNoFlags);
4533       __ CallStub(&stub);
4534       PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4535       __ test(eax, eax);
4536       // The stub returns 0 for true.
4537       Split(zero, if_true, if_false, fall_through);
4538       break;
4539     }
4540
4541     default: {
4542       VisitForAccumulatorValue(expr->right());
4543       Condition cc = CompareIC::ComputeCondition(op);
4544       __ pop(edx);
4545
4546       bool inline_smi_code = ShouldInlineSmiCase(op);
4547       JumpPatchSite patch_site(masm_);
4548       if (inline_smi_code) {
4549         Label slow_case;
4550         __ mov(ecx, edx);
4551         __ or_(ecx, eax);
4552         patch_site.EmitJumpIfNotSmi(ecx, &slow_case, Label::kNear);
4553         __ cmp(edx, eax);
4554         Split(cc, if_true, if_false, NULL);
4555         __ bind(&slow_case);
4556       }
4557
4558       // Record position and call the compare IC.
4559       SetSourcePosition(expr->position());
4560       Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
4561       CallIC(ic, expr->CompareOperationFeedbackId());
4562       patch_site.EmitPatchInfo();
4563
4564       PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4565       __ test(eax, eax);
4566       Split(cc, if_true, if_false, fall_through);
4567     }
4568   }
4569
4570   // Convert the result of the comparison into one expected for this
4571   // expression's context.
4572   context()->Plug(if_true, if_false);
4573 }
4574
4575
4576 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4577                                               Expression* sub_expr,
4578                                               NilValue nil) {
4579   Label materialize_true, materialize_false;
4580   Label* if_true = NULL;
4581   Label* if_false = NULL;
4582   Label* fall_through = NULL;
4583   context()->PrepareTest(&materialize_true, &materialize_false,
4584                          &if_true, &if_false, &fall_through);
4585
4586   VisitForAccumulatorValue(sub_expr);
4587   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
4588
4589   Handle<Object> nil_value = nil == kNullValue
4590       ? isolate()->factory()->null_value()
4591       : isolate()->factory()->undefined_value();
4592   if (expr->op() == Token::EQ_STRICT) {
4593     __ cmp(eax, nil_value);
4594     Split(equal, if_true, if_false, fall_through);
4595   } else {
4596     Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
4597     CallIC(ic, expr->CompareOperationFeedbackId());
4598     __ test(eax, eax);
4599     Split(not_zero, if_true, if_false, fall_through);
4600   }
4601   context()->Plug(if_true, if_false);
4602 }
4603
4604
4605 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4606   __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4607   context()->Plug(eax);
4608 }
4609
4610
4611 Register FullCodeGenerator::result_register() {
4612   return eax;
4613 }
4614
4615
4616 Register FullCodeGenerator::context_register() {
4617   return esi;
4618 }
4619
4620
4621 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4622   DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4623   __ mov(Operand(ebp, frame_offset), value);
4624 }
4625
4626
4627 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
4628   __ mov(dst, ContextOperand(esi, context_index));
4629 }
4630
4631
4632 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
4633   Scope* declaration_scope = scope()->DeclarationScope();
4634   if (declaration_scope->is_global_scope() ||
4635       declaration_scope->is_module_scope()) {
4636     // Contexts nested in the native context have a canonical empty function
4637     // as their closure, not the anonymous closure containing the global
4638     // code.  Pass a smi sentinel and let the runtime look up the empty
4639     // function.
4640     __ push(Immediate(Smi::FromInt(0)));
4641   } else if (declaration_scope->is_eval_scope()) {
4642     // Contexts nested inside eval code have the same closure as the context
4643     // calling eval, not the anonymous closure containing the eval code.
4644     // Fetch it from the context.
4645     __ push(ContextOperand(esi, Context::CLOSURE_INDEX));
4646   } else {
4647     DCHECK(declaration_scope->is_function_scope());
4648     __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
4649   }
4650 }
4651
4652
4653 // ----------------------------------------------------------------------------
4654 // Non-local control flow support.
4655
4656 void FullCodeGenerator::EnterFinallyBlock() {
4657   // Cook return address on top of stack (smi encoded Code* delta)
4658   DCHECK(!result_register().is(edx));
4659   __ pop(edx);
4660   __ sub(edx, Immediate(masm_->CodeObject()));
4661   STATIC_ASSERT(kSmiTagSize + kSmiShiftSize == 1);
4662   STATIC_ASSERT(kSmiTag == 0);
4663   __ SmiTag(edx);
4664   __ push(edx);
4665
4666   // Store result register while executing finally block.
4667   __ push(result_register());
4668
4669   // Store pending message while executing finally block.
4670   ExternalReference pending_message_obj =
4671       ExternalReference::address_of_pending_message_obj(isolate());
4672   __ mov(edx, Operand::StaticVariable(pending_message_obj));
4673   __ push(edx);
4674
4675   ExternalReference has_pending_message =
4676       ExternalReference::address_of_has_pending_message(isolate());
4677   __ mov(edx, Operand::StaticVariable(has_pending_message));
4678   __ SmiTag(edx);
4679   __ push(edx);
4680
4681   ExternalReference pending_message_script =
4682       ExternalReference::address_of_pending_message_script(isolate());
4683   __ mov(edx, Operand::StaticVariable(pending_message_script));
4684   __ push(edx);
4685 }
4686
4687
4688 void FullCodeGenerator::ExitFinallyBlock() {
4689   DCHECK(!result_register().is(edx));
4690   // Restore pending message from stack.
4691   __ pop(edx);
4692   ExternalReference pending_message_script =
4693       ExternalReference::address_of_pending_message_script(isolate());
4694   __ mov(Operand::StaticVariable(pending_message_script), edx);
4695
4696   __ pop(edx);
4697   __ SmiUntag(edx);
4698   ExternalReference has_pending_message =
4699       ExternalReference::address_of_has_pending_message(isolate());
4700   __ mov(Operand::StaticVariable(has_pending_message), edx);
4701
4702   __ pop(edx);
4703   ExternalReference pending_message_obj =
4704       ExternalReference::address_of_pending_message_obj(isolate());
4705   __ mov(Operand::StaticVariable(pending_message_obj), edx);
4706
4707   // Restore result register from stack.
4708   __ pop(result_register());
4709
4710   // Uncook return address.
4711   __ pop(edx);
4712   __ SmiUntag(edx);
4713   __ add(edx, Immediate(masm_->CodeObject()));
4714   __ jmp(edx);
4715 }
4716
4717
4718 #undef __
4719
4720 #define __ ACCESS_MASM(masm())
4721
4722 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4723     int* stack_depth,
4724     int* context_length) {
4725   // The macros used here must preserve the result register.
4726
4727   // Because the handler block contains the context of the finally
4728   // code, we can restore it directly from there for the finally code
4729   // rather than iteratively unwinding contexts via their previous
4730   // links.
4731   __ Drop(*stack_depth);  // Down to the handler block.
4732   if (*context_length > 0) {
4733     // Restore the context to its dedicated register and the stack.
4734     __ mov(esi, Operand(esp, StackHandlerConstants::kContextOffset));
4735     __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
4736   }
4737   __ PopTryHandler();
4738   __ call(finally_entry_);
4739
4740   *stack_depth = 0;
4741   *context_length = 0;
4742   return previous_;
4743 }
4744
4745 #undef __
4746
4747
4748 static const byte kJnsInstruction = 0x79;
4749 static const byte kJnsOffset = 0x11;
4750 static const byte kNopByteOne = 0x66;
4751 static const byte kNopByteTwo = 0x90;
4752 #ifdef DEBUG
4753 static const byte kCallInstruction = 0xe8;
4754 #endif
4755
4756
4757 void BackEdgeTable::PatchAt(Code* unoptimized_code,
4758                             Address pc,
4759                             BackEdgeState target_state,
4760                             Code* replacement_code) {
4761   Address call_target_address = pc - kIntSize;
4762   Address jns_instr_address = call_target_address - 3;
4763   Address jns_offset_address = call_target_address - 2;
4764
4765   switch (target_state) {
4766     case INTERRUPT:
4767       //     sub <profiling_counter>, <delta>  ;; Not changed
4768       //     jns ok
4769       //     call <interrupt stub>
4770       //   ok:
4771       *jns_instr_address = kJnsInstruction;
4772       *jns_offset_address = kJnsOffset;
4773       break;
4774     case ON_STACK_REPLACEMENT:
4775     case OSR_AFTER_STACK_CHECK:
4776       //     sub <profiling_counter>, <delta>  ;; Not changed
4777       //     nop
4778       //     nop
4779       //     call <on-stack replacment>
4780       //   ok:
4781       *jns_instr_address = kNopByteOne;
4782       *jns_offset_address = kNopByteTwo;
4783       break;
4784   }
4785
4786   Assembler::set_target_address_at(call_target_address,
4787                                    unoptimized_code,
4788                                    replacement_code->entry());
4789   unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
4790       unoptimized_code, call_target_address, replacement_code);
4791 }
4792
4793
4794 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
4795     Isolate* isolate,
4796     Code* unoptimized_code,
4797     Address pc) {
4798   Address call_target_address = pc - kIntSize;
4799   Address jns_instr_address = call_target_address - 3;
4800   DCHECK_EQ(kCallInstruction, *(call_target_address - 1));
4801
4802   if (*jns_instr_address == kJnsInstruction) {
4803     DCHECK_EQ(kJnsOffset, *(call_target_address - 2));
4804     DCHECK_EQ(isolate->builtins()->InterruptCheck()->entry(),
4805               Assembler::target_address_at(call_target_address,
4806                                            unoptimized_code));
4807     return INTERRUPT;
4808   }
4809
4810   DCHECK_EQ(kNopByteOne, *jns_instr_address);
4811   DCHECK_EQ(kNopByteTwo, *(call_target_address - 2));
4812
4813   if (Assembler::target_address_at(call_target_address, unoptimized_code) ==
4814       isolate->builtins()->OnStackReplacement()->entry()) {
4815     return ON_STACK_REPLACEMENT;
4816   }
4817
4818   DCHECK_EQ(isolate->builtins()->OsrAfterStackCheck()->entry(),
4819             Assembler::target_address_at(call_target_address,
4820                                          unoptimized_code));
4821   return OSR_AFTER_STACK_CHECK;
4822 }
4823
4824
4825 } }  // namespace v8::internal
4826
4827 #endif  // V8_TARGET_ARCH_X87