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 #if V8_TARGET_ARCH_MIPS64
6 
7 // Note on Mips implementation:
8 //
9 // The result_register() for mips is the 'v0' register, which is defined
10 // by the ABI to contain function return values. However, the first
11 // parameter to a function is defined to be 'a0'. So there are many
12 // places where we have to move a previous result in v0 to a0 for the
13 // next call: mov(a0, v0). This is not needed on the other architectures.
14 
15 #include "src/full-codegen/full-codegen.h"
16 #include "src/ast/compile-time-value.h"
17 #include "src/ast/scopes.h"
18 #include "src/code-factory.h"
19 #include "src/code-stubs.h"
20 #include "src/codegen.h"
21 #include "src/compilation-info.h"
22 #include "src/compiler.h"
23 #include "src/debug/debug.h"
24 #include "src/ic/ic.h"
25 
26 #include "src/mips64/code-stubs-mips64.h"
27 #include "src/mips64/macro-assembler-mips64.h"
28 
29 namespace v8 {
30 namespace internal {
31 
32 #define __ ACCESS_MASM(masm())
33 
34 // A patch site is a location in the code which it is possible to patch. This
35 // class has a number of methods to emit the code which is patchable and the
36 // method EmitPatchInfo to record a marker back to the patchable code. This
37 // marker is a andi zero_reg, rx, #yyyy instruction, and rx * 0x0000ffff + yyyy
38 // (raw 16 bit immediate value is used) is the delta from the pc to the first
39 // instruction of the patchable code.
40 // The marker instruction is effectively a NOP (dest is zero_reg) and will
41 // never be emitted by normal code.
42 class JumpPatchSite BASE_EMBEDDED {
43  public:
JumpPatchSite(MacroAssembler * masm)44   explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
45 #ifdef DEBUG
46     info_emitted_ = false;
47 #endif
48   }
49 
~JumpPatchSite()50   ~JumpPatchSite() {
51     DCHECK(patch_site_.is_bound() == info_emitted_);
52   }
53 
54   // When initially emitting this ensure that a jump is always generated to skip
55   // the inlined smi code.
EmitJumpIfNotSmi(Register reg,Label * target)56   void EmitJumpIfNotSmi(Register reg, Label* target) {
57     DCHECK(!patch_site_.is_bound() && !info_emitted_);
58     Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
59     __ bind(&patch_site_);
60     __ andi(at, reg, 0);
61     // Always taken before patched.
62     __ BranchShort(target, eq, at, Operand(zero_reg));
63   }
64 
65   // When initially emitting this ensure that a jump is never generated to skip
66   // the inlined smi code.
EmitJumpIfSmi(Register reg,Label * target)67   void EmitJumpIfSmi(Register reg, Label* target) {
68     Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
69     DCHECK(!patch_site_.is_bound() && !info_emitted_);
70     __ bind(&patch_site_);
71     __ andi(at, reg, 0);
72     // Never taken before patched.
73     __ BranchShort(target, ne, at, Operand(zero_reg));
74   }
75 
EmitPatchInfo()76   void EmitPatchInfo() {
77     if (patch_site_.is_bound()) {
78       int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
79       Register reg = Register::from_code(delta_to_patch_site / kImm16Mask);
80       __ andi(zero_reg, reg, delta_to_patch_site % kImm16Mask);
81 #ifdef DEBUG
82       info_emitted_ = true;
83 #endif
84     } else {
85       __ nop();  // Signals no inlined code.
86     }
87   }
88 
89  private:
masm()90   MacroAssembler* masm() { return masm_; }
91   MacroAssembler* masm_;
92   Label patch_site_;
93 #ifdef DEBUG
94   bool info_emitted_;
95 #endif
96 };
97 
98 
99 // Generate code for a JS function.  On entry to the function the receiver
100 // and arguments have been pushed on the stack left to right.  The actual
101 // argument count matches the formal parameter count expected by the
102 // function.
103 //
104 // The live registers are:
105 //   o a1: the JS function object being called (i.e. ourselves)
106 //   o a3: the new target value
107 //   o cp: our context
108 //   o fp: our caller's frame pointer
109 //   o sp: stack pointer
110 //   o ra: return address
111 //
112 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
113 // frames-mips.h for its layout.
Generate()114 void FullCodeGenerator::Generate() {
115   CompilationInfo* info = info_;
116   profiling_counter_ = isolate()->factory()->NewCell(
117       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
118   SetFunctionPosition(literal());
119   Comment cmnt(masm_, "[ function compiled by full code generator");
120 
121   ProfileEntryHookStub::MaybeCallEntryHook(masm_);
122 
123   if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
124     int receiver_offset = info->scope()->num_parameters() * kPointerSize;
125     __ ld(a2, MemOperand(sp, receiver_offset));
126     __ AssertNotSmi(a2);
127     __ GetObjectType(a2, a2, a2);
128     __ Check(ge, kSloppyFunctionExpectsJSReceiverReceiver, a2,
129              Operand(FIRST_JS_RECEIVER_TYPE));
130   }
131 
132   // Open a frame scope to indicate that there is a frame on the stack.  The
133   // MANUAL indicates that the scope shouldn't actually generate code to set up
134   // the frame (that is done below).
135   FrameScope frame_scope(masm_, StackFrame::MANUAL);
136   info->set_prologue_offset(masm_->pc_offset());
137   __ Prologue(info->GeneratePreagedPrologue());
138 
139   // Increment invocation count for the function.
140   {
141     Comment cmnt(masm_, "[ Increment invocation count");
142     __ ld(a0, FieldMemOperand(a1, JSFunction::kLiteralsOffset));
143     __ ld(a0, FieldMemOperand(a0, LiteralsArray::kFeedbackVectorOffset));
144     __ ld(a4, FieldMemOperand(
145                   a0, TypeFeedbackVector::kInvocationCountIndex * kPointerSize +
146                           TypeFeedbackVector::kHeaderSize));
147     __ Daddu(a4, a4, Operand(Smi::FromInt(1)));
148     __ sd(a4, FieldMemOperand(
149                   a0, TypeFeedbackVector::kInvocationCountIndex * kPointerSize +
150                           TypeFeedbackVector::kHeaderSize));
151   }
152 
153   { Comment cmnt(masm_, "[ Allocate locals");
154     int locals_count = info->scope()->num_stack_slots();
155     // Generators allocate locals, if any, in context slots.
156     DCHECK(!IsGeneratorFunction(info->literal()->kind()) || locals_count == 0);
157     OperandStackDepthIncrement(locals_count);
158     if (locals_count > 0) {
159       if (locals_count >= 128) {
160         Label ok;
161         __ Dsubu(t1, sp, Operand(locals_count * kPointerSize));
162         __ LoadRoot(a2, Heap::kRealStackLimitRootIndex);
163         __ Branch(&ok, hs, t1, Operand(a2));
164         __ CallRuntime(Runtime::kThrowStackOverflow);
165         __ bind(&ok);
166       }
167       __ LoadRoot(t1, Heap::kUndefinedValueRootIndex);
168       int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
169       if (locals_count >= kMaxPushes) {
170         int loop_iterations = locals_count / kMaxPushes;
171         __ li(a2, Operand(loop_iterations));
172         Label loop_header;
173         __ bind(&loop_header);
174         // Do pushes.
175         __ Dsubu(sp, sp, Operand(kMaxPushes * kPointerSize));
176         for (int i = 0; i < kMaxPushes; i++) {
177           __ sd(t1, MemOperand(sp, i * kPointerSize));
178         }
179         // Continue loop if not done.
180         __ Dsubu(a2, a2, Operand(1));
181         __ Branch(&loop_header, ne, a2, Operand(zero_reg));
182       }
183       int remaining = locals_count % kMaxPushes;
184       // Emit the remaining pushes.
185       __ Dsubu(sp, sp, Operand(remaining * kPointerSize));
186       for (int i  = 0; i < remaining; i++) {
187         __ sd(t1, MemOperand(sp, i * kPointerSize));
188       }
189     }
190   }
191 
192   bool function_in_register_a1 = true;
193 
194   // Possibly allocate a local context.
195   if (info->scope()->NeedsContext()) {
196     Comment cmnt(masm_, "[ Allocate context");
197     // Argument to NewContext is the function, which is still in a1.
198     bool need_write_barrier = true;
199     int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
200     if (info->scope()->is_script_scope()) {
201       __ push(a1);
202       __ Push(info->scope()->scope_info());
203       __ CallRuntime(Runtime::kNewScriptContext);
204       PrepareForBailoutForId(BailoutId::ScriptContext(),
205                              BailoutState::TOS_REGISTER);
206       // The new target value is not used, clobbering is safe.
207       DCHECK_NULL(info->scope()->new_target_var());
208     } else {
209       if (info->scope()->new_target_var() != nullptr) {
210         __ push(a3);  // Preserve new target.
211       }
212       if (slots <= FastNewFunctionContextStub::kMaximumSlots) {
213         FastNewFunctionContextStub stub(isolate());
214         __ li(FastNewFunctionContextDescriptor::SlotsRegister(),
215               Operand(slots));
216         __ CallStub(&stub);
217         // Result of FastNewFunctionContextStub is always in new space.
218         need_write_barrier = false;
219       } else {
220         __ push(a1);
221         __ CallRuntime(Runtime::kNewFunctionContext);
222       }
223       if (info->scope()->new_target_var() != nullptr) {
224         __ pop(a3);  // Restore new target.
225       }
226     }
227     function_in_register_a1 = false;
228     // Context is returned in v0. It replaces the context passed to us.
229     // It's saved in the stack and kept live in cp.
230     __ mov(cp, v0);
231     __ sd(v0, MemOperand(fp, StandardFrameConstants::kContextOffset));
232     // Copy any necessary parameters into the context.
233     int num_parameters = info->scope()->num_parameters();
234     int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
235     for (int i = first_parameter; i < num_parameters; i++) {
236       Variable* var =
237           (i == -1) ? info->scope()->receiver() : info->scope()->parameter(i);
238       if (var->IsContextSlot()) {
239         int parameter_offset = StandardFrameConstants::kCallerSPOffset +
240                                  (num_parameters - 1 - i) * kPointerSize;
241         // Load parameter from stack.
242         __ ld(a0, MemOperand(fp, parameter_offset));
243         // Store it in the context.
244         MemOperand target = ContextMemOperand(cp, var->index());
245         __ sd(a0, target);
246 
247         // Update the write barrier.
248         if (need_write_barrier) {
249           __ RecordWriteContextSlot(cp, target.offset(), a0, a2,
250                                     kRAHasBeenSaved, kDontSaveFPRegs);
251         } else if (FLAG_debug_code) {
252           Label done;
253           __ JumpIfInNewSpace(cp, a0, &done);
254           __ Abort(kExpectedNewSpaceObject);
255           __ bind(&done);
256         }
257       }
258     }
259   }
260 
261   // Register holding this function and new target are both trashed in case we
262   // bailout here. But since that can happen only when new target is not used
263   // and we allocate a context, the value of |function_in_register| is correct.
264   PrepareForBailoutForId(BailoutId::FunctionContext(),
265                          BailoutState::NO_REGISTERS);
266 
267   // Possibly set up a local binding to the this function which is used in
268   // derived constructors with super calls.
269   Variable* this_function_var = info->scope()->this_function_var();
270   if (this_function_var != nullptr) {
271     Comment cmnt(masm_, "[ This function");
272     if (!function_in_register_a1) {
273       __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
274       // The write barrier clobbers register again, keep it marked as such.
275     }
276     SetVar(this_function_var, a1, a0, a2);
277   }
278 
279   Variable* new_target_var = info->scope()->new_target_var();
280   if (new_target_var != nullptr) {
281     Comment cmnt(masm_, "[ new.target");
282     SetVar(new_target_var, a3, a0, a2);
283   }
284 
285   // Possibly allocate RestParameters
286   Variable* rest_param = info->scope()->rest_parameter();
287   if (rest_param != nullptr) {
288     Comment cmnt(masm_, "[ Allocate rest parameter array");
289     if (!function_in_register_a1) {
290       __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
291     }
292     FastNewRestParameterStub stub(isolate());
293     __ CallStub(&stub);
294     function_in_register_a1 = false;
295     SetVar(rest_param, v0, a1, a2);
296   }
297 
298   Variable* arguments = info->scope()->arguments();
299   if (arguments != NULL) {
300     // Function uses arguments object.
301     Comment cmnt(masm_, "[ Allocate arguments object");
302     if (!function_in_register_a1) {
303       // Load this again, if it's used by the local context below.
304       __ ld(a1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
305     }
306     if (is_strict(language_mode()) || !has_simple_parameters()) {
307       FastNewStrictArgumentsStub stub(isolate());
308       __ CallStub(&stub);
309     } else if (literal()->has_duplicate_parameters()) {
310       __ Push(a1);
311       __ CallRuntime(Runtime::kNewSloppyArguments_Generic);
312     } else {
313       FastNewSloppyArgumentsStub stub(isolate());
314       __ CallStub(&stub);
315     }
316 
317     SetVar(arguments, v0, a1, a2);
318   }
319 
320   if (FLAG_trace) {
321     __ CallRuntime(Runtime::kTraceEnter);
322   }
323 
324   // Visit the declarations and body.
325   PrepareForBailoutForId(BailoutId::FunctionEntry(),
326                          BailoutState::NO_REGISTERS);
327   {
328     Comment cmnt(masm_, "[ Declarations");
329     VisitDeclarations(scope()->declarations());
330   }
331 
332   // Assert that the declarations do not use ICs. Otherwise the debugger
333   // won't be able to redirect a PC at an IC to the correct IC in newly
334   // recompiled code.
335   DCHECK_EQ(0, ic_total_count_);
336 
337   {
338     Comment cmnt(masm_, "[ Stack check");
339     PrepareForBailoutForId(BailoutId::Declarations(),
340                            BailoutState::NO_REGISTERS);
341     Label ok;
342     __ LoadRoot(at, Heap::kStackLimitRootIndex);
343     __ Branch(&ok, hs, sp, Operand(at));
344     Handle<Code> stack_check = isolate()->builtins()->StackCheck();
345     PredictableCodeSizeScope predictable(
346         masm_, masm_->CallSize(stack_check, RelocInfo::CODE_TARGET));
347     __ Call(stack_check, RelocInfo::CODE_TARGET);
348     __ bind(&ok);
349   }
350 
351   {
352     Comment cmnt(masm_, "[ Body");
353     DCHECK(loop_depth() == 0);
354 
355     VisitStatements(literal()->body());
356 
357     DCHECK(loop_depth() == 0);
358   }
359 
360   // Always emit a 'return undefined' in case control fell off the end of
361   // the body.
362   { Comment cmnt(masm_, "[ return <undefined>;");
363     __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
364   }
365   EmitReturnSequence();
366 }
367 
368 
ClearAccumulator()369 void FullCodeGenerator::ClearAccumulator() {
370   DCHECK(Smi::kZero == 0);
371   __ mov(v0, zero_reg);
372 }
373 
374 
EmitProfilingCounterDecrement(int delta)375 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
376   __ li(a2, Operand(profiling_counter_));
377   __ ld(a3, FieldMemOperand(a2, Cell::kValueOffset));
378   __ Dsubu(a3, a3, Operand(Smi::FromInt(delta)));
379   __ sd(a3, FieldMemOperand(a2, Cell::kValueOffset));
380 }
381 
382 
EmitProfilingCounterReset()383 void FullCodeGenerator::EmitProfilingCounterReset() {
384   int reset_value = FLAG_interrupt_budget;
385   if (info_->is_debug()) {
386     // Detect debug break requests as soon as possible.
387     reset_value = FLAG_interrupt_budget >> 4;
388   }
389   __ li(a2, Operand(profiling_counter_));
390   __ li(a3, Operand(Smi::FromInt(reset_value)));
391   __ sd(a3, FieldMemOperand(a2, Cell::kValueOffset));
392 }
393 
394 
EmitBackEdgeBookkeeping(IterationStatement * stmt,Label * back_edge_target)395 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
396                                                 Label* back_edge_target) {
397   // The generated code is used in Deoptimizer::PatchStackCheckCodeAt so we need
398   // to make sure it is constant. Branch may emit a skip-or-jump sequence
399   // instead of the normal Branch. It seems that the "skip" part of that
400   // sequence is about as long as this Branch would be so it is safe to ignore
401   // that.
402   Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
403   Comment cmnt(masm_, "[ Back edge bookkeeping");
404   Label ok;
405   DCHECK(back_edge_target->is_bound());
406   int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
407   int weight = Min(kMaxBackEdgeWeight,
408                    Max(1, distance / kCodeSizeMultiplier));
409   EmitProfilingCounterDecrement(weight);
410   __ slt(at, a3, zero_reg);
411   __ beq(at, zero_reg, &ok);
412   // Call will emit a li t9 first, so it is safe to use the delay slot.
413   __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
414   // Record a mapping of this PC offset to the OSR id.  This is used to find
415   // the AST id from the unoptimized code in order to use it as a key into
416   // the deoptimization input data found in the optimized code.
417   RecordBackEdge(stmt->OsrEntryId());
418   EmitProfilingCounterReset();
419 
420   __ bind(&ok);
421   PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
422   // Record a mapping of the OSR id to this PC.  This is used if the OSR
423   // entry becomes the target of a bailout.  We don't expect it to be, but
424   // we want it to work if it is.
425   PrepareForBailoutForId(stmt->OsrEntryId(), BailoutState::NO_REGISTERS);
426 }
427 
EmitProfilingCounterHandlingForReturnSequence(bool is_tail_call)428 void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence(
429     bool is_tail_call) {
430   // Pretend that the exit is a backwards jump to the entry.
431   int weight = 1;
432   if (info_->ShouldSelfOptimize()) {
433     weight = FLAG_interrupt_budget / FLAG_self_opt_count;
434   } else {
435     int distance = masm_->pc_offset();
436     weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
437   }
438   EmitProfilingCounterDecrement(weight);
439   Label ok;
440   __ Branch(&ok, ge, a3, Operand(zero_reg));
441   // Don't need to save result register if we are going to do a tail call.
442   if (!is_tail_call) {
443     __ push(v0);
444   }
445   __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
446   if (!is_tail_call) {
447     __ pop(v0);
448   }
449   EmitProfilingCounterReset();
450   __ bind(&ok);
451 }
452 
EmitReturnSequence()453 void FullCodeGenerator::EmitReturnSequence() {
454   Comment cmnt(masm_, "[ Return sequence");
455   if (return_label_.is_bound()) {
456     __ Branch(&return_label_);
457   } else {
458     __ bind(&return_label_);
459     if (FLAG_trace) {
460       // Push the return value on the stack as the parameter.
461       // Runtime::TraceExit returns its parameter in v0.
462       __ push(v0);
463       __ CallRuntime(Runtime::kTraceExit);
464     }
465     EmitProfilingCounterHandlingForReturnSequence(false);
466 
467     // Make sure that the constant pool is not emitted inside of the return
468     // sequence.
469     { Assembler::BlockTrampolinePoolScope block_trampoline_pool(masm_);
470       int32_t arg_count = info_->scope()->num_parameters() + 1;
471       int32_t sp_delta = arg_count * kPointerSize;
472       SetReturnPosition(literal());
473       __ mov(sp, fp);
474       __ MultiPop(static_cast<RegList>(fp.bit() | ra.bit()));
475       __ Daddu(sp, sp, Operand(sp_delta));
476       __ Jump(ra);
477     }
478   }
479 }
480 
RestoreContext()481 void FullCodeGenerator::RestoreContext() {
482   __ ld(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
483 }
484 
Plug(Variable * var) const485 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
486   DCHECK(var->IsStackAllocated() || var->IsContextSlot());
487   codegen()->GetVar(result_register(), var);
488   codegen()->PushOperand(result_register());
489 }
490 
491 
Plug(Heap::RootListIndex index) const492 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
493 }
494 
495 
Plug(Heap::RootListIndex index) const496 void FullCodeGenerator::AccumulatorValueContext::Plug(
497     Heap::RootListIndex index) const {
498   __ LoadRoot(result_register(), index);
499 }
500 
501 
Plug(Heap::RootListIndex index) const502 void FullCodeGenerator::StackValueContext::Plug(
503     Heap::RootListIndex index) const {
504   __ LoadRoot(result_register(), index);
505   codegen()->PushOperand(result_register());
506 }
507 
508 
Plug(Heap::RootListIndex index) const509 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
510   codegen()->PrepareForBailoutBeforeSplit(condition(),
511                                           true,
512                                           true_label_,
513                                           false_label_);
514   if (index == Heap::kUndefinedValueRootIndex ||
515       index == Heap::kNullValueRootIndex ||
516       index == Heap::kFalseValueRootIndex) {
517     if (false_label_ != fall_through_) __ Branch(false_label_);
518   } else if (index == Heap::kTrueValueRootIndex) {
519     if (true_label_ != fall_through_) __ Branch(true_label_);
520   } else {
521     __ LoadRoot(result_register(), index);
522     codegen()->DoTest(this);
523   }
524 }
525 
526 
Plug(Handle<Object> lit) const527 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
528 }
529 
530 
Plug(Handle<Object> lit) const531 void FullCodeGenerator::AccumulatorValueContext::Plug(
532     Handle<Object> lit) const {
533   __ li(result_register(), Operand(lit));
534 }
535 
536 
Plug(Handle<Object> lit) const537 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
538   // Immediates cannot be pushed directly.
539   __ li(result_register(), Operand(lit));
540   codegen()->PushOperand(result_register());
541 }
542 
543 
Plug(Handle<Object> lit) const544 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
545   codegen()->PrepareForBailoutBeforeSplit(condition(),
546                                           true,
547                                           true_label_,
548                                           false_label_);
549   DCHECK(lit->IsNull(isolate()) || lit->IsUndefined(isolate()) ||
550          !lit->IsUndetectable());
551   if (lit->IsUndefined(isolate()) || lit->IsNull(isolate()) ||
552       lit->IsFalse(isolate())) {
553     if (false_label_ != fall_through_) __ Branch(false_label_);
554   } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) {
555     if (true_label_ != fall_through_) __ Branch(true_label_);
556   } else if (lit->IsString()) {
557     if (String::cast(*lit)->length() == 0) {
558       if (false_label_ != fall_through_) __ Branch(false_label_);
559     } else {
560       if (true_label_ != fall_through_) __ Branch(true_label_);
561     }
562   } else if (lit->IsSmi()) {
563     if (Smi::cast(*lit)->value() == 0) {
564       if (false_label_ != fall_through_) __ Branch(false_label_);
565     } else {
566       if (true_label_ != fall_through_) __ Branch(true_label_);
567     }
568   } else {
569     // For simplicity we always test the accumulator register.
570     __ li(result_register(), Operand(lit));
571     codegen()->DoTest(this);
572   }
573 }
574 
575 
DropAndPlug(int count,Register reg) const576 void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
577                                                        Register reg) const {
578   DCHECK(count > 0);
579   if (count > 1) codegen()->DropOperands(count - 1);
580   __ sd(reg, MemOperand(sp, 0));
581 }
582 
583 
Plug(Label * materialize_true,Label * materialize_false) const584 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
585                                             Label* materialize_false) const {
586   DCHECK(materialize_true == materialize_false);
587   __ bind(materialize_true);
588 }
589 
590 
Plug(Label * materialize_true,Label * materialize_false) const591 void FullCodeGenerator::AccumulatorValueContext::Plug(
592     Label* materialize_true,
593     Label* materialize_false) const {
594   Label done;
595   __ bind(materialize_true);
596   __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
597   __ Branch(&done);
598   __ bind(materialize_false);
599   __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
600   __ bind(&done);
601 }
602 
603 
Plug(Label * materialize_true,Label * materialize_false) const604 void FullCodeGenerator::StackValueContext::Plug(
605     Label* materialize_true,
606     Label* materialize_false) const {
607   codegen()->OperandStackDepthIncrement(1);
608   Label done;
609   __ bind(materialize_true);
610   __ LoadRoot(at, Heap::kTrueValueRootIndex);
611   // Push the value as the following branch can clobber at in long branch mode.
612   __ push(at);
613   __ Branch(&done);
614   __ bind(materialize_false);
615   __ LoadRoot(at, Heap::kFalseValueRootIndex);
616   __ push(at);
617   __ bind(&done);
618 }
619 
620 
Plug(Label * materialize_true,Label * materialize_false) const621 void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
622                                           Label* materialize_false) const {
623   DCHECK(materialize_true == true_label_);
624   DCHECK(materialize_false == false_label_);
625 }
626 
627 
Plug(bool flag) const628 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
629   Heap::RootListIndex value_root_index =
630       flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
631   __ LoadRoot(result_register(), value_root_index);
632 }
633 
634 
Plug(bool flag) const635 void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
636   Heap::RootListIndex value_root_index =
637       flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
638   __ LoadRoot(at, value_root_index);
639   codegen()->PushOperand(at);
640 }
641 
642 
Plug(bool flag) const643 void FullCodeGenerator::TestContext::Plug(bool flag) const {
644   codegen()->PrepareForBailoutBeforeSplit(condition(),
645                                           true,
646                                           true_label_,
647                                           false_label_);
648   if (flag) {
649     if (true_label_ != fall_through_) __ Branch(true_label_);
650   } else {
651     if (false_label_ != fall_through_) __ Branch(false_label_);
652   }
653 }
654 
655 
DoTest(Expression * condition,Label * if_true,Label * if_false,Label * fall_through)656 void FullCodeGenerator::DoTest(Expression* condition,
657                                Label* if_true,
658                                Label* if_false,
659                                Label* fall_through) {
660   __ mov(a0, result_register());
661   Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
662   CallIC(ic, condition->test_id());
663   __ LoadRoot(at, Heap::kTrueValueRootIndex);
664   Split(eq, result_register(), Operand(at), if_true, if_false, fall_through);
665 }
666 
667 
Split(Condition cc,Register lhs,const Operand & rhs,Label * if_true,Label * if_false,Label * fall_through)668 void FullCodeGenerator::Split(Condition cc,
669                               Register lhs,
670                               const Operand&  rhs,
671                               Label* if_true,
672                               Label* if_false,
673                               Label* fall_through) {
674   if (if_false == fall_through) {
675     __ Branch(if_true, cc, lhs, rhs);
676   } else if (if_true == fall_through) {
677     __ Branch(if_false, NegateCondition(cc), lhs, rhs);
678   } else {
679     __ Branch(if_true, cc, lhs, rhs);
680     __ Branch(if_false);
681   }
682 }
683 
684 
StackOperand(Variable * var)685 MemOperand FullCodeGenerator::StackOperand(Variable* var) {
686   DCHECK(var->IsStackAllocated());
687   // Offset is negative because higher indexes are at lower addresses.
688   int offset = -var->index() * kPointerSize;
689   // Adjust by a (parameter or local) base offset.
690   if (var->IsParameter()) {
691     offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
692   } else {
693     offset += JavaScriptFrameConstants::kLocal0Offset;
694   }
695   return MemOperand(fp, offset);
696 }
697 
698 
VarOperand(Variable * var,Register scratch)699 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
700   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
701   if (var->IsContextSlot()) {
702     int context_chain_length = scope()->ContextChainLength(var->scope());
703     __ LoadContext(scratch, context_chain_length);
704     return ContextMemOperand(scratch, var->index());
705   } else {
706     return StackOperand(var);
707   }
708 }
709 
710 
GetVar(Register dest,Variable * var)711 void FullCodeGenerator::GetVar(Register dest, Variable* var) {
712   // Use destination as scratch.
713   MemOperand location = VarOperand(var, dest);
714   __ ld(dest, location);
715 }
716 
717 
SetVar(Variable * var,Register src,Register scratch0,Register scratch1)718 void FullCodeGenerator::SetVar(Variable* var,
719                                Register src,
720                                Register scratch0,
721                                Register scratch1) {
722   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
723   DCHECK(!scratch0.is(src));
724   DCHECK(!scratch0.is(scratch1));
725   DCHECK(!scratch1.is(src));
726   MemOperand location = VarOperand(var, scratch0);
727   __ sd(src, location);
728   // Emit the write barrier code if the location is in the heap.
729   if (var->IsContextSlot()) {
730     __ RecordWriteContextSlot(scratch0,
731                               location.offset(),
732                               src,
733                               scratch1,
734                               kRAHasBeenSaved,
735                               kDontSaveFPRegs);
736   }
737 }
738 
739 
PrepareForBailoutBeforeSplit(Expression * expr,bool should_normalize,Label * if_true,Label * if_false)740 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
741                                                      bool should_normalize,
742                                                      Label* if_true,
743                                                      Label* if_false) {
744   // Only prepare for bailouts before splits if we're in a test
745   // context. Otherwise, we let the Visit function deal with the
746   // preparation to avoid preparing with the same AST id twice.
747   if (!context()->IsTest()) return;
748 
749   Label skip;
750   if (should_normalize) __ Branch(&skip);
751   PrepareForBailout(expr, BailoutState::TOS_REGISTER);
752   if (should_normalize) {
753     __ LoadRoot(a4, Heap::kTrueValueRootIndex);
754     Split(eq, v0, Operand(a4), if_true, if_false, NULL);
755     __ bind(&skip);
756   }
757 }
758 
759 
EmitDebugCheckDeclarationContext(Variable * variable)760 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
761   // The variable in the declaration always resides in the current function
762   // context.
763   DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
764   if (FLAG_debug_code) {
765     // Check that we're not inside a with or catch context.
766     __ ld(a1, FieldMemOperand(cp, HeapObject::kMapOffset));
767     __ LoadRoot(a4, Heap::kWithContextMapRootIndex);
768     __ Check(ne, kDeclarationInWithContext,
769         a1, Operand(a4));
770     __ LoadRoot(a4, Heap::kCatchContextMapRootIndex);
771     __ Check(ne, kDeclarationInCatchContext,
772         a1, Operand(a4));
773   }
774 }
775 
776 
VisitVariableDeclaration(VariableDeclaration * declaration)777 void FullCodeGenerator::VisitVariableDeclaration(
778     VariableDeclaration* declaration) {
779   VariableProxy* proxy = declaration->proxy();
780   Variable* variable = proxy->var();
781   switch (variable->location()) {
782     case VariableLocation::UNALLOCATED: {
783       DCHECK(!variable->binding_needs_init());
784       FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
785       DCHECK(!slot.IsInvalid());
786       globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
787       globals_->Add(isolate()->factory()->undefined_value(), zone());
788       break;
789     }
790     case VariableLocation::PARAMETER:
791     case VariableLocation::LOCAL:
792       if (variable->binding_needs_init()) {
793         Comment cmnt(masm_, "[ VariableDeclaration");
794         __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
795         __ sd(a4, StackOperand(variable));
796       }
797       break;
798 
799     case VariableLocation::CONTEXT:
800       if (variable->binding_needs_init()) {
801         Comment cmnt(masm_, "[ VariableDeclaration");
802         EmitDebugCheckDeclarationContext(variable);
803           __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
804           __ sd(at, ContextMemOperand(cp, variable->index()));
805           // No write barrier since the_hole_value is in old space.
806           PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
807       }
808       break;
809 
810     case VariableLocation::LOOKUP: {
811       Comment cmnt(masm_, "[ VariableDeclaration");
812       DCHECK_EQ(VAR, variable->mode());
813       DCHECK(!variable->binding_needs_init());
814       __ li(a2, Operand(variable->name()));
815       __ Push(a2);
816       __ CallRuntime(Runtime::kDeclareEvalVar);
817       PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
818       break;
819     }
820 
821     case VariableLocation::MODULE:
822       UNREACHABLE();
823   }
824 }
825 
826 
VisitFunctionDeclaration(FunctionDeclaration * declaration)827 void FullCodeGenerator::VisitFunctionDeclaration(
828     FunctionDeclaration* declaration) {
829   VariableProxy* proxy = declaration->proxy();
830   Variable* variable = proxy->var();
831   switch (variable->location()) {
832     case VariableLocation::UNALLOCATED: {
833       FeedbackVectorSlot slot = proxy->VariableFeedbackSlot();
834       DCHECK(!slot.IsInvalid());
835       globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
836       Handle<SharedFunctionInfo> function =
837           Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
838       // Check for stack-overflow exception.
839       if (function.is_null()) return SetStackOverflow();
840       globals_->Add(function, zone());
841       break;
842     }
843 
844     case VariableLocation::PARAMETER:
845     case VariableLocation::LOCAL: {
846       Comment cmnt(masm_, "[ FunctionDeclaration");
847       VisitForAccumulatorValue(declaration->fun());
848       __ sd(result_register(), StackOperand(variable));
849       break;
850     }
851 
852     case VariableLocation::CONTEXT: {
853       Comment cmnt(masm_, "[ FunctionDeclaration");
854       EmitDebugCheckDeclarationContext(variable);
855       VisitForAccumulatorValue(declaration->fun());
856       __ sd(result_register(), ContextMemOperand(cp, variable->index()));
857       int offset = Context::SlotOffset(variable->index());
858       // We know that we have written a function, which is not a smi.
859       __ RecordWriteContextSlot(cp,
860                                 offset,
861                                 result_register(),
862                                 a2,
863                                 kRAHasBeenSaved,
864                                 kDontSaveFPRegs,
865                                 EMIT_REMEMBERED_SET,
866                                 OMIT_SMI_CHECK);
867       PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
868       break;
869     }
870 
871     case VariableLocation::LOOKUP: {
872       Comment cmnt(masm_, "[ FunctionDeclaration");
873       __ li(a2, Operand(variable->name()));
874       PushOperand(a2);
875       // Push initial value for function declaration.
876       VisitForStackValue(declaration->fun());
877       CallRuntimeWithOperands(Runtime::kDeclareEvalFunction);
878       PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
879       break;
880     }
881 
882     case VariableLocation::MODULE:
883       UNREACHABLE();
884   }
885 }
886 
887 
DeclareGlobals(Handle<FixedArray> pairs)888 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
889   // Call the runtime to declare the globals.
890   __ li(a1, Operand(pairs));
891   __ li(a0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
892   __ EmitLoadTypeFeedbackVector(a2);
893   __ Push(a1, a0, a2);
894   __ CallRuntime(Runtime::kDeclareGlobals);
895   // Return value is ignored.
896 }
897 
898 
VisitSwitchStatement(SwitchStatement * stmt)899 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
900   Comment cmnt(masm_, "[ SwitchStatement");
901   Breakable nested_statement(this, stmt);
902   SetStatementPosition(stmt);
903 
904   // Keep the switch value on the stack until a case matches.
905   VisitForStackValue(stmt->tag());
906   PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
907 
908   ZoneList<CaseClause*>* clauses = stmt->cases();
909   CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
910 
911   Label next_test;  // Recycled for each test.
912   // Compile all the tests with branches to their bodies.
913   for (int i = 0; i < clauses->length(); i++) {
914     CaseClause* clause = clauses->at(i);
915     clause->body_target()->Unuse();
916 
917     // The default is not a test, but remember it as final fall through.
918     if (clause->is_default()) {
919       default_clause = clause;
920       continue;
921     }
922 
923     Comment cmnt(masm_, "[ Case comparison");
924     __ bind(&next_test);
925     next_test.Unuse();
926 
927     // Compile the label expression.
928     VisitForAccumulatorValue(clause->label());
929     __ mov(a0, result_register());  // CompareStub requires args in a0, a1.
930 
931     // Perform the comparison as if via '==='.
932     __ ld(a1, MemOperand(sp, 0));  // Switch value.
933     bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
934     JumpPatchSite patch_site(masm_);
935     if (inline_smi_code) {
936       Label slow_case;
937       __ or_(a2, a1, a0);
938       patch_site.EmitJumpIfNotSmi(a2, &slow_case);
939 
940       __ Branch(&next_test, ne, a1, Operand(a0));
941       __ Drop(1);  // Switch value is no longer needed.
942       __ Branch(clause->body_target());
943 
944       __ bind(&slow_case);
945     }
946 
947     // Record position before stub call for type feedback.
948     SetExpressionPosition(clause);
949     Handle<Code> ic =
950         CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
951     CallIC(ic, clause->CompareId());
952     patch_site.EmitPatchInfo();
953 
954     Label skip;
955     __ Branch(&skip);
956     PrepareForBailout(clause, BailoutState::TOS_REGISTER);
957     __ LoadRoot(at, Heap::kTrueValueRootIndex);
958     __ Branch(&next_test, ne, v0, Operand(at));
959     __ Drop(1);
960     __ Branch(clause->body_target());
961     __ bind(&skip);
962 
963     __ Branch(&next_test, ne, v0, Operand(zero_reg));
964     __ Drop(1);  // Switch value is no longer needed.
965     __ Branch(clause->body_target());
966   }
967 
968   // Discard the test value and jump to the default if present, otherwise to
969   // the end of the statement.
970   __ bind(&next_test);
971   DropOperands(1);  // Switch value is no longer needed.
972   if (default_clause == NULL) {
973     __ Branch(nested_statement.break_label());
974   } else {
975     __ Branch(default_clause->body_target());
976   }
977 
978   // Compile all the case bodies.
979   for (int i = 0; i < clauses->length(); i++) {
980     Comment cmnt(masm_, "[ Case body");
981     CaseClause* clause = clauses->at(i);
982     __ bind(clause->body_target());
983     PrepareForBailoutForId(clause->EntryId(), BailoutState::NO_REGISTERS);
984     VisitStatements(clause->statements());
985   }
986 
987   __ bind(nested_statement.break_label());
988   PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
989 }
990 
991 
VisitForInStatement(ForInStatement * stmt)992 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
993   Comment cmnt(masm_, "[ ForInStatement");
994   SetStatementPosition(stmt, SKIP_BREAK);
995 
996   FeedbackVectorSlot slot = stmt->ForInFeedbackSlot();
997 
998   // Get the object to enumerate over. If the object is null or undefined, skip
999   // over the loop.  See ECMA-262 version 5, section 12.6.4.
1000   SetExpressionAsStatementPosition(stmt->enumerable());
1001   VisitForAccumulatorValue(stmt->enumerable());
1002   __ mov(a0, result_register());
1003   OperandStackDepthIncrement(5);
1004 
1005   Label loop, exit;
1006   Iteration loop_statement(this, stmt);
1007   increment_loop_depth();
1008 
1009   // If the object is null or undefined, skip over the loop, otherwise convert
1010   // it to a JS receiver.  See ECMA-262 version 5, section 12.6.4.
1011   Label convert, done_convert;
1012   __ JumpIfSmi(a0, &convert);
1013   __ GetObjectType(a0, a1, a1);
1014   __ Branch(USE_DELAY_SLOT, &done_convert, ge, a1,
1015             Operand(FIRST_JS_RECEIVER_TYPE));
1016   __ LoadRoot(at, Heap::kNullValueRootIndex);  // In delay slot.
1017   __ Branch(USE_DELAY_SLOT, &exit, eq, a0, Operand(at));
1018   __ LoadRoot(at, Heap::kUndefinedValueRootIndex);  // In delay slot.
1019   __ Branch(&exit, eq, a0, Operand(at));
1020   __ bind(&convert);
1021   __ Call(isolate()->builtins()->ToObject(), RelocInfo::CODE_TARGET);
1022   RestoreContext();
1023   __ mov(a0, v0);
1024   __ bind(&done_convert);
1025   PrepareForBailoutForId(stmt->ToObjectId(), BailoutState::TOS_REGISTER);
1026   __ push(a0);
1027 
1028   // Check cache validity in generated code. If we cannot guarantee cache
1029   // validity, call the runtime system to check cache validity or get the
1030   // property names in a fixed array. Note: Proxies never have an enum cache,
1031   // so will always take the slow path.
1032   Label call_runtime;
1033   __ CheckEnumCache(&call_runtime);
1034 
1035   // The enum cache is valid.  Load the map of the object being
1036   // iterated over and use the cache for the iteration.
1037   Label use_cache;
1038   __ ld(v0, FieldMemOperand(a0, HeapObject::kMapOffset));
1039   __ Branch(&use_cache);
1040 
1041   // Get the set of properties to enumerate.
1042   __ bind(&call_runtime);
1043   __ push(a0);  // Duplicate the enumerable object on the stack.
1044   __ CallRuntime(Runtime::kForInEnumerate);
1045   PrepareForBailoutForId(stmt->EnumId(), BailoutState::TOS_REGISTER);
1046 
1047   // If we got a map from the runtime call, we can do a fast
1048   // modification check. Otherwise, we got a fixed array, and we have
1049   // to do a slow check.
1050   Label fixed_array;
1051   __ ld(a2, FieldMemOperand(v0, HeapObject::kMapOffset));
1052   __ LoadRoot(at, Heap::kMetaMapRootIndex);
1053   __ Branch(&fixed_array, ne, a2, Operand(at));
1054 
1055   // We got a map in register v0. Get the enumeration cache from it.
1056   Label no_descriptors;
1057   __ bind(&use_cache);
1058 
1059   __ EnumLength(a1, v0);
1060   __ Branch(&no_descriptors, eq, a1, Operand(Smi::kZero));
1061 
1062   __ LoadInstanceDescriptors(v0, a2);
1063   __ ld(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheOffset));
1064   __ ld(a2, FieldMemOperand(a2, DescriptorArray::kEnumCacheBridgeCacheOffset));
1065 
1066   // Set up the four remaining stack slots.
1067   __ li(a0, Operand(Smi::kZero));
1068   // Push map, enumeration cache, enumeration cache length (as smi) and zero.
1069   __ Push(v0, a2, a1, a0);
1070   __ jmp(&loop);
1071 
1072   __ bind(&no_descriptors);
1073   __ Drop(1);
1074   __ jmp(&exit);
1075 
1076   // We got a fixed array in register v0. Iterate through that.
1077   __ bind(&fixed_array);
1078 
1079   __ li(a1, Operand(Smi::FromInt(1)));  // Smi(1) indicates slow check
1080   __ Push(a1, v0);  // Smi and array
1081   __ ld(a1, FieldMemOperand(v0, FixedArray::kLengthOffset));
1082   __ Push(a1);  // Fixed array length (as smi).
1083   PrepareForBailoutForId(stmt->PrepareId(), BailoutState::NO_REGISTERS);
1084   __ li(a0, Operand(Smi::kZero));
1085   __ Push(a0);  // Initial index.
1086 
1087   // Generate code for doing the condition check.
1088   __ bind(&loop);
1089   SetExpressionAsStatementPosition(stmt->each());
1090 
1091   // Load the current count to a0, load the length to a1.
1092   __ ld(a0, MemOperand(sp, 0 * kPointerSize));
1093   __ ld(a1, MemOperand(sp, 1 * kPointerSize));
1094   __ Branch(loop_statement.break_label(), hs, a0, Operand(a1));
1095 
1096   // Get the current entry of the array into register a3.
1097   __ ld(a2, MemOperand(sp, 2 * kPointerSize));
1098   __ Daddu(a2, a2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1099   __ SmiScale(a4, a0, kPointerSizeLog2);
1100   __ daddu(a4, a2, a4);  // Array base + scaled (smi) index.
1101   __ ld(result_register(), MemOperand(a4));  // Current entry.
1102 
1103   // Get the expected map from the stack or a smi in the
1104   // permanent slow case into register a2.
1105   __ ld(a2, MemOperand(sp, 3 * kPointerSize));
1106 
1107   // Check if the expected map still matches that of the enumerable.
1108   // If not, we may have to filter the key.
1109   Label update_each;
1110   __ ld(a1, MemOperand(sp, 4 * kPointerSize));
1111   __ ld(a4, FieldMemOperand(a1, HeapObject::kMapOffset));
1112   __ Branch(&update_each, eq, a4, Operand(a2));
1113 
1114   // We need to filter the key, record slow-path here.
1115   int const vector_index = SmiFromSlot(slot)->value();
1116   __ EmitLoadTypeFeedbackVector(a3);
1117   __ li(a2, Operand(TypeFeedbackVector::MegamorphicSentinel(isolate())));
1118   __ sd(a2, FieldMemOperand(a3, FixedArray::OffsetOfElementAt(vector_index)));
1119 
1120   __ mov(a0, result_register());
1121   // a0 contains the key. The receiver in a1 is the second argument to the
1122   // ForInFilter. ForInFilter returns undefined if the receiver doesn't
1123   // have the key or returns the name-converted key.
1124   __ Call(isolate()->builtins()->ForInFilter(), RelocInfo::CODE_TARGET);
1125   RestoreContext();
1126   PrepareForBailoutForId(stmt->FilterId(), BailoutState::TOS_REGISTER);
1127   __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
1128   __ Branch(loop_statement.continue_label(), eq, result_register(),
1129             Operand(at));
1130 
1131   // Update the 'each' property or variable from the possibly filtered
1132   // entry in the result_register.
1133   __ bind(&update_each);
1134   // Perform the assignment as if via '='.
1135   { EffectContext context(this);
1136     EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
1137     PrepareForBailoutForId(stmt->AssignmentId(), BailoutState::NO_REGISTERS);
1138   }
1139 
1140   // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
1141   PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
1142   // Generate code for the body of the loop.
1143   Visit(stmt->body());
1144 
1145   // Generate code for the going to the next element by incrementing
1146   // the index (smi) stored on top of the stack.
1147   __ bind(loop_statement.continue_label());
1148   PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
1149   __ pop(a0);
1150   __ Daddu(a0, a0, Operand(Smi::FromInt(1)));
1151   __ push(a0);
1152 
1153   EmitBackEdgeBookkeeping(stmt, &loop);
1154   __ Branch(&loop);
1155 
1156   // Remove the pointers stored on the stack.
1157   __ bind(loop_statement.break_label());
1158   DropOperands(5);
1159 
1160   // Exit and decrement the loop depth.
1161   PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
1162   __ bind(&exit);
1163   decrement_loop_depth();
1164 }
1165 
1166 
EmitSetHomeObject(Expression * initializer,int offset,FeedbackVectorSlot slot)1167 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
1168                                           FeedbackVectorSlot slot) {
1169   DCHECK(NeedsHomeObject(initializer));
1170   __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
1171   __ ld(StoreDescriptor::ValueRegister(),
1172         MemOperand(sp, offset * kPointerSize));
1173   CallStoreIC(slot, isolate()->factory()->home_object_symbol());
1174 }
1175 
1176 
EmitSetHomeObjectAccumulator(Expression * initializer,int offset,FeedbackVectorSlot slot)1177 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
1178                                                      int offset,
1179                                                      FeedbackVectorSlot slot) {
1180   DCHECK(NeedsHomeObject(initializer));
1181   __ Move(StoreDescriptor::ReceiverRegister(), v0);
1182   __ ld(StoreDescriptor::ValueRegister(),
1183         MemOperand(sp, offset * kPointerSize));
1184   CallStoreIC(slot, isolate()->factory()->home_object_symbol());
1185 }
1186 
1187 
EmitLoadGlobalCheckExtensions(VariableProxy * proxy,TypeofMode typeof_mode,Label * slow)1188 void FullCodeGenerator::EmitLoadGlobalCheckExtensions(VariableProxy* proxy,
1189                                                       TypeofMode typeof_mode,
1190                                                       Label* slow) {
1191   Register current = cp;
1192   Register next = a1;
1193   Register temp = a2;
1194 
1195   int to_check = scope()->ContextChainLengthUntilOutermostSloppyEval();
1196   for (Scope* s = scope(); to_check > 0; s = s->outer_scope()) {
1197     if (!s->NeedsContext()) continue;
1198     if (s->calls_sloppy_eval()) {
1199       // Check that extension is "the hole".
1200       __ ld(temp, ContextMemOperand(current, Context::EXTENSION_INDEX));
1201       __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1202     }
1203     // Load next context in chain.
1204     __ ld(next, ContextMemOperand(current, Context::PREVIOUS_INDEX));
1205     // Walk the rest of the chain without clobbering cp.
1206     current = next;
1207     to_check--;
1208   }
1209 
1210   // All extension objects were empty and it is safe to use a normal global
1211   // load machinery.
1212   EmitGlobalVariableLoad(proxy, typeof_mode);
1213 }
1214 
1215 
ContextSlotOperandCheckExtensions(Variable * var,Label * slow)1216 MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1217                                                                 Label* slow) {
1218   DCHECK(var->IsContextSlot());
1219   Register context = cp;
1220   Register next = a3;
1221   Register temp = a4;
1222 
1223   for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
1224     if (s->NeedsContext()) {
1225       if (s->calls_sloppy_eval()) {
1226         // Check that extension is "the hole".
1227         __ ld(temp, ContextMemOperand(context, Context::EXTENSION_INDEX));
1228         __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1229       }
1230       __ ld(next, ContextMemOperand(context, Context::PREVIOUS_INDEX));
1231       // Walk the rest of the chain without clobbering cp.
1232       context = next;
1233     }
1234   }
1235   // Check that last extension is "the hole".
1236   __ ld(temp, ContextMemOperand(context, Context::EXTENSION_INDEX));
1237   __ JumpIfNotRoot(temp, Heap::kTheHoleValueRootIndex, slow);
1238 
1239   // This function is used only for loads, not stores, so it's safe to
1240   // return an cp-based operand (the write barrier cannot be allowed to
1241   // destroy the cp register).
1242   return ContextMemOperand(context, var->index());
1243 }
1244 
1245 
EmitDynamicLookupFastCase(VariableProxy * proxy,TypeofMode typeof_mode,Label * slow,Label * done)1246 void FullCodeGenerator::EmitDynamicLookupFastCase(VariableProxy* proxy,
1247                                                   TypeofMode typeof_mode,
1248                                                   Label* slow, Label* done) {
1249   // Generate fast-case code for variables that might be shadowed by
1250   // eval-introduced variables.  Eval is used a lot without
1251   // introducing variables.  In those cases, we do not want to
1252   // perform a runtime call for all variables in the scope
1253   // containing the eval.
1254   Variable* var = proxy->var();
1255   if (var->mode() == DYNAMIC_GLOBAL) {
1256     EmitLoadGlobalCheckExtensions(proxy, typeof_mode, slow);
1257     __ Branch(done);
1258   } else if (var->mode() == DYNAMIC_LOCAL) {
1259     Variable* local = var->local_if_not_shadowed();
1260     __ ld(v0, ContextSlotOperandCheckExtensions(local, slow));
1261     if (local->binding_needs_init()) {
1262       __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1263       __ dsubu(at, v0, at);  // Sub as compare: at == 0 on eq.
1264       __ Branch(done, ne, at, Operand(zero_reg));
1265       __ li(a0, Operand(var->name()));
1266       __ push(a0);
1267       __ CallRuntime(Runtime::kThrowReferenceError);
1268     } else {
1269       __ Branch(done);
1270     }
1271   }
1272 }
1273 
EmitVariableLoad(VariableProxy * proxy,TypeofMode typeof_mode)1274 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
1275                                          TypeofMode typeof_mode) {
1276   // Record position before possible IC call.
1277   SetExpressionPosition(proxy);
1278   PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS);
1279   Variable* var = proxy->var();
1280 
1281   // Three cases: global variables, lookup variables, and all other types of
1282   // variables.
1283   switch (var->location()) {
1284     case VariableLocation::UNALLOCATED: {
1285       Comment cmnt(masm_, "[ Global variable");
1286       EmitGlobalVariableLoad(proxy, typeof_mode);
1287       context()->Plug(v0);
1288       break;
1289     }
1290 
1291     case VariableLocation::PARAMETER:
1292     case VariableLocation::LOCAL:
1293     case VariableLocation::CONTEXT: {
1294       DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
1295       Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
1296                                                : "[ Stack variable");
1297       if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
1298         // Throw a reference error when using an uninitialized let/const
1299         // binding in harmony mode.
1300         Label done;
1301         GetVar(v0, var);
1302         __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
1303         __ dsubu(at, v0, at);  // Sub as compare: at == 0 on eq.
1304         __ Branch(&done, ne, at, Operand(zero_reg));
1305         __ li(a0, Operand(var->name()));
1306         __ push(a0);
1307         __ CallRuntime(Runtime::kThrowReferenceError);
1308         __ bind(&done);
1309         context()->Plug(v0);
1310         break;
1311       }
1312       context()->Plug(var);
1313       break;
1314     }
1315 
1316     case VariableLocation::LOOKUP: {
1317       Comment cmnt(masm_, "[ Lookup variable");
1318       Label done, slow;
1319       // Generate code for loading from variables potentially shadowed
1320       // by eval-introduced variables.
1321       EmitDynamicLookupFastCase(proxy, typeof_mode, &slow, &done);
1322       __ bind(&slow);
1323       __ Push(var->name());
1324       Runtime::FunctionId function_id =
1325           typeof_mode == NOT_INSIDE_TYPEOF
1326               ? Runtime::kLoadLookupSlot
1327               : Runtime::kLoadLookupSlotInsideTypeof;
1328       __ CallRuntime(function_id);
1329       __ bind(&done);
1330       context()->Plug(v0);
1331       break;
1332     }
1333 
1334     case VariableLocation::MODULE:
1335       UNREACHABLE();
1336   }
1337 }
1338 
1339 
EmitAccessor(ObjectLiteralProperty * property)1340 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
1341   Expression* expression = (property == NULL) ? NULL : property->value();
1342   if (expression == NULL) {
1343     __ LoadRoot(a1, Heap::kNullValueRootIndex);
1344     PushOperand(a1);
1345   } else {
1346     VisitForStackValue(expression);
1347     if (NeedsHomeObject(expression)) {
1348       DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
1349              property->kind() == ObjectLiteral::Property::SETTER);
1350       int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
1351       EmitSetHomeObject(expression, offset, property->GetSlot());
1352     }
1353   }
1354 }
1355 
1356 
VisitObjectLiteral(ObjectLiteral * expr)1357 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1358   Comment cmnt(masm_, "[ ObjectLiteral");
1359 
1360   Handle<FixedArray> constant_properties = expr->constant_properties();
1361   __ ld(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1362   __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
1363   __ li(a1, Operand(constant_properties));
1364   __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags())));
1365   if (MustCreateObjectLiteralWithRuntime(expr)) {
1366     __ Push(a3, a2, a1, a0);
1367     __ CallRuntime(Runtime::kCreateObjectLiteral);
1368   } else {
1369     FastCloneShallowObjectStub stub(isolate(), expr->properties_count());
1370     __ CallStub(&stub);
1371     RestoreContext();
1372   }
1373   PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
1374 
1375   // If result_saved is true the result is on top of the stack.  If
1376   // result_saved is false the result is in v0.
1377   bool result_saved = false;
1378 
1379   AccessorTable accessor_table(zone());
1380   int property_index = 0;
1381   for (; property_index < expr->properties()->length(); property_index++) {
1382     ObjectLiteral::Property* property = expr->properties()->at(property_index);
1383     if (property->is_computed_name()) break;
1384     if (property->IsCompileTimeValue()) continue;
1385 
1386     Literal* key = property->key()->AsLiteral();
1387     Expression* value = property->value();
1388     if (!result_saved) {
1389       PushOperand(v0);  // Save result on stack.
1390       result_saved = true;
1391     }
1392     switch (property->kind()) {
1393       case ObjectLiteral::Property::CONSTANT:
1394         UNREACHABLE();
1395       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1396         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
1397         // Fall through.
1398       case ObjectLiteral::Property::COMPUTED:
1399         // It is safe to use [[Put]] here because the boilerplate already
1400         // contains computed properties with an uninitialized value.
1401         if (key->IsStringLiteral()) {
1402           DCHECK(key->IsPropertyName());
1403           if (property->emit_store()) {
1404             VisitForAccumulatorValue(value);
1405             __ mov(StoreDescriptor::ValueRegister(), result_register());
1406             DCHECK(StoreDescriptor::ValueRegister().is(a0));
1407             __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
1408             CallStoreIC(property->GetSlot(0), key->value());
1409             PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS);
1410 
1411             if (NeedsHomeObject(value)) {
1412               EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
1413             }
1414           } else {
1415             VisitForEffect(value);
1416           }
1417           break;
1418         }
1419         // Duplicate receiver on stack.
1420         __ ld(a0, MemOperand(sp));
1421         PushOperand(a0);
1422         VisitForStackValue(key);
1423         VisitForStackValue(value);
1424         if (property->emit_store()) {
1425           if (NeedsHomeObject(value)) {
1426             EmitSetHomeObject(value, 2, property->GetSlot());
1427           }
1428           __ li(a0, Operand(Smi::FromInt(SLOPPY)));  // PropertyAttributes.
1429           PushOperand(a0);
1430           CallRuntimeWithOperands(Runtime::kSetProperty);
1431         } else {
1432           DropOperands(3);
1433         }
1434         break;
1435       case ObjectLiteral::Property::PROTOTYPE:
1436         // Duplicate receiver on stack.
1437         __ ld(a0, MemOperand(sp));
1438         PushOperand(a0);
1439         VisitForStackValue(value);
1440         DCHECK(property->emit_store());
1441         CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
1442         PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1443                                BailoutState::NO_REGISTERS);
1444         break;
1445       case ObjectLiteral::Property::GETTER:
1446         if (property->emit_store()) {
1447           AccessorTable::Iterator it = accessor_table.lookup(key);
1448           it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1449           it->second->getter = property;
1450         }
1451         break;
1452       case ObjectLiteral::Property::SETTER:
1453         if (property->emit_store()) {
1454           AccessorTable::Iterator it = accessor_table.lookup(key);
1455           it->second->bailout_id = expr->GetIdForPropertySet(property_index);
1456           it->second->setter = property;
1457         }
1458         break;
1459     }
1460   }
1461 
1462   // Emit code to define accessors, using only a single call to the runtime for
1463   // each pair of corresponding getters and setters.
1464   for (AccessorTable::Iterator it = accessor_table.begin();
1465        it != accessor_table.end();
1466        ++it) {
1467     __ ld(a0, MemOperand(sp));  // Duplicate receiver.
1468     PushOperand(a0);
1469     VisitForStackValue(it->first);
1470     EmitAccessor(it->second->getter);
1471     EmitAccessor(it->second->setter);
1472     __ li(a0, Operand(Smi::FromInt(NONE)));
1473     PushOperand(a0);
1474     CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked);
1475     PrepareForBailoutForId(it->second->bailout_id, BailoutState::NO_REGISTERS);
1476   }
1477 
1478   // Object literals have two parts. The "static" part on the left contains no
1479   // computed property names, and so we can compute its map ahead of time; see
1480   // runtime.cc::CreateObjectLiteralBoilerplate. The second "dynamic" part
1481   // starts with the first computed property name, and continues with all
1482   // properties to its right.  All the code from above initializes the static
1483   // component of the object literal, and arranges for the map of the result to
1484   // reflect the static order in which the keys appear. For the dynamic
1485   // properties, we compile them into a series of "SetOwnProperty" runtime
1486   // calls. This will preserve insertion order.
1487   for (; property_index < expr->properties()->length(); property_index++) {
1488     ObjectLiteral::Property* property = expr->properties()->at(property_index);
1489 
1490     Expression* value = property->value();
1491     if (!result_saved) {
1492       PushOperand(v0);  // Save result on the stack
1493       result_saved = true;
1494     }
1495 
1496     __ ld(a0, MemOperand(sp));  // Duplicate receiver.
1497     PushOperand(a0);
1498 
1499     if (property->kind() == ObjectLiteral::Property::PROTOTYPE) {
1500       DCHECK(!property->is_computed_name());
1501       VisitForStackValue(value);
1502       DCHECK(property->emit_store());
1503       CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
1504       PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1505                              BailoutState::NO_REGISTERS);
1506     } else {
1507       EmitPropertyKey(property, expr->GetIdForPropertyName(property_index));
1508       VisitForStackValue(value);
1509       if (NeedsHomeObject(value)) {
1510         EmitSetHomeObject(value, 2, property->GetSlot());
1511       }
1512 
1513       switch (property->kind()) {
1514         case ObjectLiteral::Property::CONSTANT:
1515         case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1516         case ObjectLiteral::Property::COMPUTED:
1517           if (property->emit_store()) {
1518             PushOperand(Smi::FromInt(NONE));
1519             PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1520             CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
1521             PrepareForBailoutForId(expr->GetIdForPropertySet(property_index),
1522                                    BailoutState::NO_REGISTERS);
1523           } else {
1524             DropOperands(3);
1525           }
1526           break;
1527 
1528         case ObjectLiteral::Property::PROTOTYPE:
1529           UNREACHABLE();
1530           break;
1531 
1532         case ObjectLiteral::Property::GETTER:
1533           PushOperand(Smi::FromInt(NONE));
1534           CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
1535           break;
1536 
1537         case ObjectLiteral::Property::SETTER:
1538           PushOperand(Smi::FromInt(NONE));
1539           CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
1540           break;
1541       }
1542     }
1543   }
1544 
1545   if (result_saved) {
1546     context()->PlugTOS();
1547   } else {
1548     context()->Plug(v0);
1549   }
1550 }
1551 
1552 
VisitArrayLiteral(ArrayLiteral * expr)1553 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1554   Comment cmnt(masm_, "[ ArrayLiteral");
1555 
1556   Handle<FixedArray> constant_elements = expr->constant_elements();
1557   bool has_fast_elements =
1558       IsFastObjectElementsKind(expr->constant_elements_kind());
1559 
1560   AllocationSiteMode allocation_site_mode = TRACK_ALLOCATION_SITE;
1561   if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
1562     // If the only customer of allocation sites is transitioning, then
1563     // we can turn it off if we don't have anywhere else to transition to.
1564     allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1565   }
1566 
1567   __ mov(a0, result_register());
1568   __ ld(a3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1569   __ li(a2, Operand(Smi::FromInt(expr->literal_index())));
1570   __ li(a1, Operand(constant_elements));
1571   if (MustCreateArrayLiteralWithRuntime(expr)) {
1572     __ li(a0, Operand(Smi::FromInt(expr->ComputeFlags())));
1573     __ Push(a3, a2, a1, a0);
1574     __ CallRuntime(Runtime::kCreateArrayLiteral);
1575   } else {
1576     FastCloneShallowArrayStub stub(isolate(), allocation_site_mode);
1577     __ CallStub(&stub);
1578     RestoreContext();
1579   }
1580   PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
1581 
1582   bool result_saved = false;  // Is the result saved to the stack?
1583   ZoneList<Expression*>* subexprs = expr->values();
1584   int length = subexprs->length();
1585 
1586   // Emit code to evaluate all the non-constant subexpressions and to store
1587   // them into the newly cloned array.
1588   for (int array_index = 0; array_index < length; array_index++) {
1589     Expression* subexpr = subexprs->at(array_index);
1590     DCHECK(!subexpr->IsSpread());
1591 
1592     // If the subexpression is a literal or a simple materialized literal it
1593     // is already set in the cloned array.
1594     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
1595 
1596     if (!result_saved) {
1597       PushOperand(v0);  // array literal
1598       result_saved = true;
1599     }
1600 
1601     VisitForAccumulatorValue(subexpr);
1602 
1603     __ li(StoreDescriptor::NameRegister(), Operand(Smi::FromInt(array_index)));
1604     __ ld(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0));
1605     __ mov(StoreDescriptor::ValueRegister(), result_register());
1606     CallKeyedStoreIC(expr->LiteralFeedbackSlot());
1607 
1608     PrepareForBailoutForId(expr->GetIdForElement(array_index),
1609                            BailoutState::NO_REGISTERS);
1610   }
1611 
1612   if (result_saved) {
1613     context()->PlugTOS();
1614   } else {
1615     context()->Plug(v0);
1616   }
1617 }
1618 
1619 
VisitAssignment(Assignment * expr)1620 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1621   DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
1622 
1623   Comment cmnt(masm_, "[ Assignment");
1624 
1625   Property* property = expr->target()->AsProperty();
1626   LhsKind assign_type = Property::GetAssignType(property);
1627 
1628   // Evaluate LHS expression.
1629   switch (assign_type) {
1630     case VARIABLE:
1631       // Nothing to do here.
1632       break;
1633     case NAMED_PROPERTY:
1634       if (expr->is_compound()) {
1635         // We need the receiver both on the stack and in the register.
1636         VisitForStackValue(property->obj());
1637         __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
1638       } else {
1639         VisitForStackValue(property->obj());
1640       }
1641       break;
1642     case NAMED_SUPER_PROPERTY:
1643       VisitForStackValue(
1644           property->obj()->AsSuperPropertyReference()->this_var());
1645       VisitForAccumulatorValue(
1646           property->obj()->AsSuperPropertyReference()->home_object());
1647       PushOperand(result_register());
1648       if (expr->is_compound()) {
1649         const Register scratch = a1;
1650         __ ld(scratch, MemOperand(sp, kPointerSize));
1651         PushOperands(scratch, result_register());
1652       }
1653       break;
1654     case KEYED_SUPER_PROPERTY: {
1655       VisitForStackValue(
1656           property->obj()->AsSuperPropertyReference()->this_var());
1657       VisitForStackValue(
1658           property->obj()->AsSuperPropertyReference()->home_object());
1659       VisitForAccumulatorValue(property->key());
1660       PushOperand(result_register());
1661       if (expr->is_compound()) {
1662         const Register scratch1 = a4;
1663         const Register scratch2 = a1;
1664         __ ld(scratch1, MemOperand(sp, 2 * kPointerSize));
1665         __ ld(scratch2, MemOperand(sp, 1 * kPointerSize));
1666         PushOperands(scratch1, scratch2, result_register());
1667       }
1668       break;
1669     }
1670     case KEYED_PROPERTY:
1671       // We need the key and receiver on both the stack and in v0 and a1.
1672       if (expr->is_compound()) {
1673         VisitForStackValue(property->obj());
1674         VisitForStackValue(property->key());
1675         __ ld(LoadDescriptor::ReceiverRegister(),
1676               MemOperand(sp, 1 * kPointerSize));
1677         __ ld(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
1678       } else {
1679         VisitForStackValue(property->obj());
1680         VisitForStackValue(property->key());
1681       }
1682       break;
1683   }
1684 
1685   // For compound assignments we need another deoptimization point after the
1686   // variable/property load.
1687   if (expr->is_compound()) {
1688     { AccumulatorValueContext context(this);
1689       switch (assign_type) {
1690         case VARIABLE:
1691           EmitVariableLoad(expr->target()->AsVariableProxy());
1692           PrepareForBailout(expr->target(), BailoutState::TOS_REGISTER);
1693           break;
1694         case NAMED_PROPERTY:
1695           EmitNamedPropertyLoad(property);
1696           PrepareForBailoutForId(property->LoadId(),
1697                                  BailoutState::TOS_REGISTER);
1698           break;
1699         case NAMED_SUPER_PROPERTY:
1700           EmitNamedSuperPropertyLoad(property);
1701           PrepareForBailoutForId(property->LoadId(),
1702                                  BailoutState::TOS_REGISTER);
1703           break;
1704         case KEYED_SUPER_PROPERTY:
1705           EmitKeyedSuperPropertyLoad(property);
1706           PrepareForBailoutForId(property->LoadId(),
1707                                  BailoutState::TOS_REGISTER);
1708           break;
1709         case KEYED_PROPERTY:
1710           EmitKeyedPropertyLoad(property);
1711           PrepareForBailoutForId(property->LoadId(),
1712                                  BailoutState::TOS_REGISTER);
1713           break;
1714       }
1715     }
1716 
1717     Token::Value op = expr->binary_op();
1718     PushOperand(v0);  // Left operand goes on the stack.
1719     VisitForAccumulatorValue(expr->value());
1720 
1721     AccumulatorValueContext context(this);
1722     if (ShouldInlineSmiCase(op)) {
1723       EmitInlineSmiBinaryOp(expr->binary_operation(),
1724                             op,
1725                             expr->target(),
1726                             expr->value());
1727     } else {
1728       EmitBinaryOp(expr->binary_operation(), op);
1729     }
1730 
1731     // Deoptimization point in case the binary operation may have side effects.
1732     PrepareForBailout(expr->binary_operation(), BailoutState::TOS_REGISTER);
1733   } else {
1734     VisitForAccumulatorValue(expr->value());
1735   }
1736 
1737   SetExpressionPosition(expr);
1738 
1739   // Store the value.
1740   switch (assign_type) {
1741     case VARIABLE: {
1742       VariableProxy* proxy = expr->target()->AsVariableProxy();
1743       EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
1744                              proxy->hole_check_mode());
1745       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
1746       context()->Plug(v0);
1747       break;
1748     }
1749     case NAMED_PROPERTY:
1750       EmitNamedPropertyAssignment(expr);
1751       break;
1752     case NAMED_SUPER_PROPERTY:
1753       EmitNamedSuperPropertyStore(property);
1754       context()->Plug(v0);
1755       break;
1756     case KEYED_SUPER_PROPERTY:
1757       EmitKeyedSuperPropertyStore(property);
1758       context()->Plug(v0);
1759       break;
1760     case KEYED_PROPERTY:
1761       EmitKeyedPropertyAssignment(expr);
1762       break;
1763   }
1764 }
1765 
1766 
VisitYield(Yield * expr)1767 void FullCodeGenerator::VisitYield(Yield* expr) {
1768   Comment cmnt(masm_, "[ Yield");
1769   SetExpressionPosition(expr);
1770 
1771   // Evaluate yielded value first; the initial iterator definition depends on
1772   // this.  It stays on the stack while we update the iterator.
1773   VisitForStackValue(expr->expression());
1774 
1775   Label suspend, continuation, post_runtime, resume, exception;
1776 
1777   __ jmp(&suspend);
1778   __ bind(&continuation);
1779   // When we arrive here, v0 holds the generator object.
1780   __ RecordGeneratorContinuation();
1781   __ ld(a1, FieldMemOperand(v0, JSGeneratorObject::kResumeModeOffset));
1782   __ ld(v0, FieldMemOperand(v0, JSGeneratorObject::kInputOrDebugPosOffset));
1783   __ Branch(&resume, eq, a1, Operand(Smi::FromInt(JSGeneratorObject::kNext)));
1784   __ Push(result_register());
1785   __ Branch(&exception, eq, a1,
1786             Operand(Smi::FromInt(JSGeneratorObject::kThrow)));
1787   EmitCreateIteratorResult(true);
1788   EmitUnwindAndReturn();
1789 
1790   __ bind(&exception);
1791   __ CallRuntime(expr->rethrow_on_exception() ? Runtime::kReThrow
1792                                               : Runtime::kThrow);
1793 
1794   __ bind(&suspend);
1795   OperandStackDepthIncrement(1);  // Not popped on this path.
1796   VisitForAccumulatorValue(expr->generator_object());
1797   DCHECK(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
1798   __ li(a1, Operand(Smi::FromInt(continuation.pos())));
1799   __ sd(a1, FieldMemOperand(v0, JSGeneratorObject::kContinuationOffset));
1800   __ sd(cp, FieldMemOperand(v0, JSGeneratorObject::kContextOffset));
1801   __ mov(a1, cp);
1802   __ RecordWriteField(v0, JSGeneratorObject::kContextOffset, a1, a2,
1803                       kRAHasBeenSaved, kDontSaveFPRegs);
1804   __ Daddu(a1, fp, Operand(StandardFrameConstants::kExpressionsOffset));
1805   __ Branch(&post_runtime, eq, sp, Operand(a1));
1806   __ push(v0);  // generator object
1807   __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
1808   RestoreContext();
1809   __ bind(&post_runtime);
1810   PopOperand(result_register());
1811   EmitReturnSequence();
1812 
1813   __ bind(&resume);
1814   context()->Plug(result_register());
1815 }
1816 
PushOperands(Register reg1,Register reg2)1817 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) {
1818   OperandStackDepthIncrement(2);
1819   __ Push(reg1, reg2);
1820 }
1821 
PushOperands(Register reg1,Register reg2,Register reg3)1822 void FullCodeGenerator::PushOperands(Register reg1, Register reg2,
1823                                      Register reg3) {
1824   OperandStackDepthIncrement(3);
1825   __ Push(reg1, reg2, reg3);
1826 }
1827 
PushOperands(Register reg1,Register reg2,Register reg3,Register reg4)1828 void FullCodeGenerator::PushOperands(Register reg1, Register reg2,
1829                                      Register reg3, Register reg4) {
1830   OperandStackDepthIncrement(4);
1831   __ Push(reg1, reg2, reg3, reg4);
1832 }
1833 
PopOperands(Register reg1,Register reg2)1834 void FullCodeGenerator::PopOperands(Register reg1, Register reg2) {
1835   OperandStackDepthDecrement(2);
1836   __ Pop(reg1, reg2);
1837 }
1838 
EmitOperandStackDepthCheck()1839 void FullCodeGenerator::EmitOperandStackDepthCheck() {
1840   if (FLAG_debug_code) {
1841     int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp +
1842                         operand_stack_depth_ * kPointerSize;
1843     __ Dsubu(v0, fp, sp);
1844     __ Assert(eq, kUnexpectedStackDepth, v0, Operand(expected_diff));
1845   }
1846 }
1847 
EmitCreateIteratorResult(bool done)1848 void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
1849   Label allocate, done_allocate;
1850 
1851   __ Allocate(JSIteratorResult::kSize, v0, a2, a3, &allocate,
1852               NO_ALLOCATION_FLAGS);
1853   __ jmp(&done_allocate);
1854 
1855   __ bind(&allocate);
1856   __ Push(Smi::FromInt(JSIteratorResult::kSize));
1857   __ CallRuntime(Runtime::kAllocateInNewSpace);
1858 
1859   __ bind(&done_allocate);
1860   __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, a1);
1861   PopOperand(a2);
1862   __ LoadRoot(a3,
1863               done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
1864   __ LoadRoot(a4, Heap::kEmptyFixedArrayRootIndex);
1865   __ sd(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
1866   __ sd(a4, FieldMemOperand(v0, JSObject::kPropertiesOffset));
1867   __ sd(a4, FieldMemOperand(v0, JSObject::kElementsOffset));
1868   __ sd(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
1869   __ sd(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
1870   STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
1871 }
1872 
1873 
EmitInlineSmiBinaryOp(BinaryOperation * expr,Token::Value op,Expression * left_expr,Expression * right_expr)1874 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
1875                                               Token::Value op,
1876                                               Expression* left_expr,
1877                                               Expression* right_expr) {
1878   Label done, smi_case, stub_call;
1879 
1880   Register scratch1 = a2;
1881   Register scratch2 = a3;
1882 
1883   // Get the arguments.
1884   Register left = a1;
1885   Register right = a0;
1886   PopOperand(left);
1887   __ mov(a0, result_register());
1888 
1889   // Perform combined smi check on both operands.
1890   __ Or(scratch1, left, Operand(right));
1891   STATIC_ASSERT(kSmiTag == 0);
1892   JumpPatchSite patch_site(masm_);
1893   patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1894 
1895   __ bind(&stub_call);
1896   Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
1897   CallIC(code, expr->BinaryOperationFeedbackId());
1898   patch_site.EmitPatchInfo();
1899   __ jmp(&done);
1900 
1901   __ bind(&smi_case);
1902   // Smi case. This code works the same way as the smi-smi case in the type
1903   // recording binary operation stub, see
1904   switch (op) {
1905     case Token::SAR:
1906       __ GetLeastBitsFromSmi(scratch1, right, 5);
1907       __ dsrav(right, left, scratch1);
1908       __ And(v0, right, Operand(0xffffffff00000000L));
1909       break;
1910     case Token::SHL: {
1911       __ SmiUntag(scratch1, left);
1912       __ GetLeastBitsFromSmi(scratch2, right, 5);
1913       __ dsllv(scratch1, scratch1, scratch2);
1914       __ SmiTag(v0, scratch1);
1915       break;
1916     }
1917     case Token::SHR: {
1918       __ SmiUntag(scratch1, left);
1919       __ GetLeastBitsFromSmi(scratch2, right, 5);
1920       __ dsrlv(scratch1, scratch1, scratch2);
1921       __ And(scratch2, scratch1, 0x80000000);
1922       __ Branch(&stub_call, ne, scratch2, Operand(zero_reg));
1923       __ SmiTag(v0, scratch1);
1924       break;
1925     }
1926     case Token::ADD:
1927       __ DaddBranchOvf(v0, left, Operand(right), &stub_call);
1928       break;
1929     case Token::SUB:
1930       __ DsubBranchOvf(v0, left, Operand(right), &stub_call);
1931       break;
1932     case Token::MUL: {
1933       __ Dmulh(v0, left, right);
1934       __ dsra32(scratch2, v0, 0);
1935       __ sra(scratch1, v0, 31);
1936       __ Branch(USE_DELAY_SLOT, &stub_call, ne, scratch2, Operand(scratch1));
1937       __ SmiTag(v0);
1938       __ Branch(USE_DELAY_SLOT, &done, ne, v0, Operand(zero_reg));
1939       __ Daddu(scratch2, right, left);
1940       __ Branch(&stub_call, lt, scratch2, Operand(zero_reg));
1941       DCHECK(Smi::kZero == 0);
1942       __ mov(v0, zero_reg);
1943       break;
1944     }
1945     case Token::BIT_OR:
1946       __ Or(v0, left, Operand(right));
1947       break;
1948     case Token::BIT_AND:
1949       __ And(v0, left, Operand(right));
1950       break;
1951     case Token::BIT_XOR:
1952       __ Xor(v0, left, Operand(right));
1953       break;
1954     default:
1955       UNREACHABLE();
1956   }
1957 
1958   __ bind(&done);
1959   context()->Plug(v0);
1960 }
1961 
1962 
EmitClassDefineProperties(ClassLiteral * lit)1963 void FullCodeGenerator::EmitClassDefineProperties(ClassLiteral* lit) {
1964   for (int i = 0; i < lit->properties()->length(); i++) {
1965     ClassLiteral::Property* property = lit->properties()->at(i);
1966     Expression* value = property->value();
1967 
1968     Register scratch = a1;
1969     if (property->is_static()) {
1970       __ ld(scratch, MemOperand(sp, kPointerSize));  // constructor
1971     } else {
1972       __ ld(scratch, MemOperand(sp, 0));  // prototype
1973     }
1974     PushOperand(scratch);
1975     EmitPropertyKey(property, lit->GetIdForProperty(i));
1976 
1977     // The static prototype property is read only. We handle the non computed
1978     // property name case in the parser. Since this is the only case where we
1979     // need to check for an own read only property we special case this so we do
1980     // not need to do this for every property.
1981     if (property->is_static() && property->is_computed_name()) {
1982       __ CallRuntime(Runtime::kThrowIfStaticPrototype);
1983       __ push(v0);
1984     }
1985 
1986     VisitForStackValue(value);
1987     if (NeedsHomeObject(value)) {
1988       EmitSetHomeObject(value, 2, property->GetSlot());
1989     }
1990 
1991     switch (property->kind()) {
1992       case ClassLiteral::Property::METHOD:
1993         PushOperand(Smi::FromInt(DONT_ENUM));
1994         PushOperand(Smi::FromInt(property->NeedsSetFunctionName()));
1995         CallRuntimeWithOperands(Runtime::kDefineDataPropertyInLiteral);
1996         break;
1997 
1998       case ClassLiteral::Property::GETTER:
1999         PushOperand(Smi::FromInt(DONT_ENUM));
2000         CallRuntimeWithOperands(Runtime::kDefineGetterPropertyUnchecked);
2001         break;
2002 
2003       case ClassLiteral::Property::SETTER:
2004         PushOperand(Smi::FromInt(DONT_ENUM));
2005         CallRuntimeWithOperands(Runtime::kDefineSetterPropertyUnchecked);
2006         break;
2007 
2008       case ClassLiteral::Property::FIELD:
2009       default:
2010         UNREACHABLE();
2011     }
2012   }
2013 }
2014 
2015 
EmitBinaryOp(BinaryOperation * expr,Token::Value op)2016 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
2017   __ mov(a0, result_register());
2018   PopOperand(a1);
2019   Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
2020   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
2021   CallIC(code, expr->BinaryOperationFeedbackId());
2022   patch_site.EmitPatchInfo();
2023   context()->Plug(v0);
2024 }
2025 
2026 
EmitAssignment(Expression * expr,FeedbackVectorSlot slot)2027 void FullCodeGenerator::EmitAssignment(Expression* expr,
2028                                        FeedbackVectorSlot slot) {
2029   DCHECK(expr->IsValidReferenceExpressionOrThis());
2030 
2031   Property* prop = expr->AsProperty();
2032   LhsKind assign_type = Property::GetAssignType(prop);
2033 
2034   switch (assign_type) {
2035     case VARIABLE: {
2036       VariableProxy* proxy = expr->AsVariableProxy();
2037       EffectContext context(this);
2038       EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
2039                              proxy->hole_check_mode());
2040       break;
2041     }
2042     case NAMED_PROPERTY: {
2043       PushOperand(result_register());  // Preserve value.
2044       VisitForAccumulatorValue(prop->obj());
2045       __ mov(StoreDescriptor::ReceiverRegister(), result_register());
2046       PopOperand(StoreDescriptor::ValueRegister());  // Restore value.
2047       CallStoreIC(slot, prop->key()->AsLiteral()->value());
2048       break;
2049     }
2050     case NAMED_SUPER_PROPERTY: {
2051       PushOperand(v0);
2052       VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2053       VisitForAccumulatorValue(
2054           prop->obj()->AsSuperPropertyReference()->home_object());
2055       // stack: value, this; v0: home_object
2056       Register scratch = a2;
2057       Register scratch2 = a3;
2058       __ mov(scratch, result_register());             // home_object
2059       __ ld(v0, MemOperand(sp, kPointerSize));        // value
2060       __ ld(scratch2, MemOperand(sp, 0));             // this
2061       __ sd(scratch2, MemOperand(sp, kPointerSize));  // this
2062       __ sd(scratch, MemOperand(sp, 0));              // home_object
2063       // stack: this, home_object; v0: value
2064       EmitNamedSuperPropertyStore(prop);
2065       break;
2066     }
2067     case KEYED_SUPER_PROPERTY: {
2068       PushOperand(v0);
2069       VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
2070       VisitForStackValue(
2071           prop->obj()->AsSuperPropertyReference()->home_object());
2072       VisitForAccumulatorValue(prop->key());
2073       Register scratch = a2;
2074       Register scratch2 = a3;
2075       __ ld(scratch2, MemOperand(sp, 2 * kPointerSize));  // value
2076       // stack: value, this, home_object; v0: key, a3: value
2077       __ ld(scratch, MemOperand(sp, kPointerSize));  // this
2078       __ sd(scratch, MemOperand(sp, 2 * kPointerSize));
2079       __ ld(scratch, MemOperand(sp, 0));  // home_object
2080       __ sd(scratch, MemOperand(sp, kPointerSize));
2081       __ sd(v0, MemOperand(sp, 0));
2082       __ Move(v0, scratch2);
2083       // stack: this, home_object, key; v0: value.
2084       EmitKeyedSuperPropertyStore(prop);
2085       break;
2086     }
2087     case KEYED_PROPERTY: {
2088       PushOperand(result_register());  // Preserve value.
2089       VisitForStackValue(prop->obj());
2090       VisitForAccumulatorValue(prop->key());
2091       __ Move(StoreDescriptor::NameRegister(), result_register());
2092       PopOperands(StoreDescriptor::ValueRegister(),
2093                   StoreDescriptor::ReceiverRegister());
2094       CallKeyedStoreIC(slot);
2095       break;
2096     }
2097   }
2098   context()->Plug(v0);
2099 }
2100 
2101 
EmitStoreToStackLocalOrContextSlot(Variable * var,MemOperand location)2102 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
2103     Variable* var, MemOperand location) {
2104   __ sd(result_register(), location);
2105   if (var->IsContextSlot()) {
2106     // RecordWrite may destroy all its register arguments.
2107     __ Move(a3, result_register());
2108     int offset = Context::SlotOffset(var->index());
2109     __ RecordWriteContextSlot(
2110         a1, offset, a3, a2, kRAHasBeenSaved, kDontSaveFPRegs);
2111   }
2112 }
2113 
EmitVariableAssignment(Variable * var,Token::Value op,FeedbackVectorSlot slot,HoleCheckMode hole_check_mode)2114 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
2115                                                FeedbackVectorSlot slot,
2116                                                HoleCheckMode hole_check_mode) {
2117   if (var->IsUnallocated()) {
2118     // Global var, const, or let.
2119     __ mov(StoreDescriptor::ValueRegister(), result_register());
2120     __ LoadGlobalObject(StoreDescriptor::ReceiverRegister());
2121     CallStoreIC(slot, var->name());
2122 
2123   } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) {
2124     DCHECK(!var->IsLookupSlot());
2125     DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2126     MemOperand location = VarOperand(var, a1);
2127     // Perform an initialization check for lexically declared variables.
2128     if (hole_check_mode == HoleCheckMode::kRequired) {
2129       Label assign;
2130       __ ld(a3, location);
2131       __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
2132       __ Branch(&assign, ne, a3, Operand(a4));
2133       __ li(a3, Operand(var->name()));
2134       __ push(a3);
2135       __ CallRuntime(Runtime::kThrowReferenceError);
2136       __ bind(&assign);
2137     }
2138     if (var->mode() != CONST) {
2139       EmitStoreToStackLocalOrContextSlot(var, location);
2140     } else if (var->throw_on_const_assignment(language_mode())) {
2141       __ CallRuntime(Runtime::kThrowConstAssignError);
2142     }
2143   } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
2144     // Initializing assignment to const {this} needs a write barrier.
2145     DCHECK(var->IsStackAllocated() || var->IsContextSlot());
2146     Label uninitialized_this;
2147     MemOperand location = VarOperand(var, a1);
2148     __ ld(a3, location);
2149     __ LoadRoot(at, Heap::kTheHoleValueRootIndex);
2150     __ Branch(&uninitialized_this, eq, a3, Operand(at));
2151     __ li(a0, Operand(var->name()));
2152     __ Push(a0);
2153     __ CallRuntime(Runtime::kThrowReferenceError);
2154     __ bind(&uninitialized_this);
2155     EmitStoreToStackLocalOrContextSlot(var, location);
2156 
2157   } else {
2158     DCHECK(var->mode() != CONST || op == Token::INIT);
2159     if (var->IsLookupSlot()) {
2160       __ Push(var->name());
2161       __ Push(v0);
2162       __ CallRuntime(is_strict(language_mode())
2163                          ? Runtime::kStoreLookupSlot_Strict
2164                          : Runtime::kStoreLookupSlot_Sloppy);
2165     } else {
2166       // Assignment to var or initializing assignment to let/const in harmony
2167       // mode.
2168       DCHECK((var->IsStackAllocated() || var->IsContextSlot()));
2169       MemOperand location = VarOperand(var, a1);
2170       if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) {
2171         // Check for an uninitialized let binding.
2172         __ ld(a2, location);
2173         __ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
2174         __ Check(eq, kLetBindingReInitialization, a2, Operand(a4));
2175       }
2176       EmitStoreToStackLocalOrContextSlot(var, location);
2177     }
2178   }
2179 }
2180 
2181 
EmitNamedPropertyAssignment(Assignment * expr)2182 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2183   // Assignment to a property, using a named store IC.
2184   Property* prop = expr->target()->AsProperty();
2185   DCHECK(prop != NULL);
2186   DCHECK(prop->key()->IsLiteral());
2187 
2188   __ mov(StoreDescriptor::ValueRegister(), result_register());
2189   PopOperand(StoreDescriptor::ReceiverRegister());
2190   CallStoreIC(expr->AssignmentSlot(), prop->key()->AsLiteral()->value());
2191 
2192   PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
2193   context()->Plug(v0);
2194 }
2195 
2196 
EmitNamedSuperPropertyStore(Property * prop)2197 void FullCodeGenerator::EmitNamedSuperPropertyStore(Property* prop) {
2198   // Assignment to named property of super.
2199   // v0 : value
2200   // stack : receiver ('this'), home_object
2201   DCHECK(prop != NULL);
2202   Literal* key = prop->key()->AsLiteral();
2203   DCHECK(key != NULL);
2204 
2205   PushOperand(key->value());
2206   PushOperand(v0);
2207   CallRuntimeWithOperands(is_strict(language_mode())
2208                               ? Runtime::kStoreToSuper_Strict
2209                               : Runtime::kStoreToSuper_Sloppy);
2210 }
2211 
2212 
EmitKeyedSuperPropertyStore(Property * prop)2213 void FullCodeGenerator::EmitKeyedSuperPropertyStore(Property* prop) {
2214   // Assignment to named property of super.
2215   // v0 : value
2216   // stack : receiver ('this'), home_object, key
2217   DCHECK(prop != NULL);
2218 
2219   PushOperand(v0);
2220   CallRuntimeWithOperands(is_strict(language_mode())
2221                               ? Runtime::kStoreKeyedToSuper_Strict
2222                               : Runtime::kStoreKeyedToSuper_Sloppy);
2223 }
2224 
2225 
EmitKeyedPropertyAssignment(Assignment * expr)2226 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2227   // Assignment to a property, using a keyed store IC.
2228   // Call keyed store IC.
2229   // The arguments are:
2230   // - a0 is the value,
2231   // - a1 is the key,
2232   // - a2 is the receiver.
2233   __ mov(StoreDescriptor::ValueRegister(), result_register());
2234   PopOperands(StoreDescriptor::ReceiverRegister(),
2235               StoreDescriptor::NameRegister());
2236   DCHECK(StoreDescriptor::ValueRegister().is(a0));
2237 
2238   CallKeyedStoreIC(expr->AssignmentSlot());
2239 
2240   PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
2241   context()->Plug(v0);
2242 }
2243 
2244 // Code common for calls using the IC.
EmitCallWithLoadIC(Call * expr)2245 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
2246   Expression* callee = expr->expression();
2247 
2248   // Get the target function.
2249   ConvertReceiverMode convert_mode;
2250   if (callee->IsVariableProxy()) {
2251     { StackValueContext context(this);
2252       EmitVariableLoad(callee->AsVariableProxy());
2253       PrepareForBailout(callee, BailoutState::NO_REGISTERS);
2254     }
2255     // Push undefined as receiver. This is patched in the method prologue if it
2256     // is a sloppy mode method.
2257     __ LoadRoot(at, Heap::kUndefinedValueRootIndex);
2258     PushOperand(at);
2259     convert_mode = ConvertReceiverMode::kNullOrUndefined;
2260   } else {
2261     // Load the function from the receiver.
2262     DCHECK(callee->IsProperty());
2263     DCHECK(!callee->AsProperty()->IsSuperAccess());
2264     __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
2265     EmitNamedPropertyLoad(callee->AsProperty());
2266     PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2267                            BailoutState::TOS_REGISTER);
2268     // Push the target function under the receiver.
2269     __ ld(at, MemOperand(sp, 0));
2270     PushOperand(at);
2271     __ sd(v0, MemOperand(sp, kPointerSize));
2272     convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
2273   }
2274 
2275   EmitCall(expr, convert_mode);
2276 }
2277 
2278 
EmitSuperCallWithLoadIC(Call * expr)2279 void FullCodeGenerator::EmitSuperCallWithLoadIC(Call* expr) {
2280   SetExpressionPosition(expr);
2281   Expression* callee = expr->expression();
2282   DCHECK(callee->IsProperty());
2283   Property* prop = callee->AsProperty();
2284   DCHECK(prop->IsSuperAccess());
2285 
2286   Literal* key = prop->key()->AsLiteral();
2287   DCHECK(!key->value()->IsSmi());
2288   // Load the function from the receiver.
2289   const Register scratch = a1;
2290   SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2291   VisitForAccumulatorValue(super_ref->home_object());
2292   __ mov(scratch, v0);
2293   VisitForAccumulatorValue(super_ref->this_var());
2294   PushOperands(scratch, v0, v0, scratch);
2295   PushOperand(key->value());
2296 
2297   // Stack here:
2298   //  - home_object
2299   //  - this (receiver)
2300   //  - this (receiver) <-- LoadFromSuper will pop here and below.
2301   //  - home_object
2302   //  - key
2303   CallRuntimeWithOperands(Runtime::kLoadFromSuper);
2304   PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
2305 
2306   // Replace home_object with target function.
2307   __ sd(v0, MemOperand(sp, kPointerSize));
2308 
2309   // Stack here:
2310   // - target function
2311   // - this (receiver)
2312   EmitCall(expr);
2313 }
2314 
2315 
2316 // Code common for calls using the IC.
EmitKeyedCallWithLoadIC(Call * expr,Expression * key)2317 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
2318                                                 Expression* key) {
2319   // Load the key.
2320   VisitForAccumulatorValue(key);
2321 
2322   Expression* callee = expr->expression();
2323 
2324   // Load the function from the receiver.
2325   DCHECK(callee->IsProperty());
2326   __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
2327   __ Move(LoadDescriptor::NameRegister(), v0);
2328   EmitKeyedPropertyLoad(callee->AsProperty());
2329   PrepareForBailoutForId(callee->AsProperty()->LoadId(),
2330                          BailoutState::TOS_REGISTER);
2331 
2332   // Push the target function under the receiver.
2333   __ ld(at, MemOperand(sp, 0));
2334   PushOperand(at);
2335   __ sd(v0, MemOperand(sp, kPointerSize));
2336 
2337   EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
2338 }
2339 
2340 
EmitKeyedSuperCallWithLoadIC(Call * expr)2341 void FullCodeGenerator::EmitKeyedSuperCallWithLoadIC(Call* expr) {
2342   Expression* callee = expr->expression();
2343   DCHECK(callee->IsProperty());
2344   Property* prop = callee->AsProperty();
2345   DCHECK(prop->IsSuperAccess());
2346 
2347   SetExpressionPosition(prop);
2348   // Load the function from the receiver.
2349   const Register scratch = a1;
2350   SuperPropertyReference* super_ref = prop->obj()->AsSuperPropertyReference();
2351   VisitForAccumulatorValue(super_ref->home_object());
2352   __ Move(scratch, v0);
2353   VisitForAccumulatorValue(super_ref->this_var());
2354   PushOperands(scratch, v0, v0, scratch);
2355   VisitForStackValue(prop->key());
2356 
2357   // Stack here:
2358   //  - home_object
2359   //  - this (receiver)
2360   //  - this (receiver) <-- LoadKeyedFromSuper will pop here and below.
2361   //  - home_object
2362   //  - key
2363   CallRuntimeWithOperands(Runtime::kLoadKeyedFromSuper);
2364   PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
2365 
2366   // Replace home_object with target function.
2367   __ sd(v0, MemOperand(sp, kPointerSize));
2368 
2369   // Stack here:
2370   // - target function
2371   // - this (receiver)
2372   EmitCall(expr);
2373 }
2374 
2375 
EmitCall(Call * expr,ConvertReceiverMode mode)2376 void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
2377   // Load the arguments.
2378   ZoneList<Expression*>* args = expr->arguments();
2379   int arg_count = args->length();
2380   for (int i = 0; i < arg_count; i++) {
2381     VisitForStackValue(args->at(i));
2382   }
2383 
2384   PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
2385   // Record source position of the IC call.
2386   SetCallPosition(expr, expr->tail_call_mode());
2387   if (expr->tail_call_mode() == TailCallMode::kAllow) {
2388     if (FLAG_trace) {
2389       __ CallRuntime(Runtime::kTraceTailCall);
2390     }
2391     // Update profiling counters before the tail call since we will
2392     // not return to this function.
2393     EmitProfilingCounterHandlingForReturnSequence(true);
2394   }
2395   Handle<Code> code =
2396       CodeFactory::CallIC(isolate(), mode, expr->tail_call_mode()).code();
2397   __ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
2398   __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2399   __ li(a0, Operand(arg_count));
2400   CallIC(code);
2401   OperandStackDepthDecrement(arg_count + 1);
2402 
2403   RecordJSReturnSite(expr);
2404   RestoreContext();
2405   context()->DropAndPlug(1, v0);
2406 }
2407 
EmitResolvePossiblyDirectEval(Call * expr)2408 void FullCodeGenerator::EmitResolvePossiblyDirectEval(Call* expr) {
2409   int arg_count = expr->arguments()->length();
2410   // a6: copy of the first argument or undefined if it doesn't exist.
2411   if (arg_count > 0) {
2412     __ ld(a6, MemOperand(sp, arg_count * kPointerSize));
2413   } else {
2414     __ LoadRoot(a6, Heap::kUndefinedValueRootIndex);
2415   }
2416 
2417   // a5: the receiver of the enclosing function.
2418   __ ld(a5, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
2419 
2420   // a4: the language mode.
2421   __ li(a4, Operand(Smi::FromInt(language_mode())));
2422 
2423   // a1: the start position of the scope the calls resides in.
2424   __ li(a1, Operand(Smi::FromInt(scope()->start_position())));
2425 
2426   // a0: the source position of the eval call.
2427   __ li(a0, Operand(Smi::FromInt(expr->position())));
2428 
2429   // Do the runtime call.
2430   __ Push(a6, a5, a4, a1, a0);
2431   __ CallRuntime(Runtime::kResolvePossiblyDirectEval);
2432 }
2433 
2434 
2435 // See http://www.ecma-international.org/ecma-262/6.0/#sec-function-calls.
PushCalleeAndWithBaseObject(Call * expr)2436 void FullCodeGenerator::PushCalleeAndWithBaseObject(Call* expr) {
2437   VariableProxy* callee = expr->expression()->AsVariableProxy();
2438   if (callee->var()->IsLookupSlot()) {
2439     Label slow, done;
2440 
2441     SetExpressionPosition(callee);
2442     // Generate code for loading from variables potentially shadowed by
2443     // eval-introduced variables.
2444     EmitDynamicLookupFastCase(callee, NOT_INSIDE_TYPEOF, &slow, &done);
2445 
2446     __ bind(&slow);
2447     // Call the runtime to find the function to call (returned in v0)
2448     // and the object holding it (returned in v1).
2449     __ Push(callee->name());
2450     __ CallRuntime(Runtime::kLoadLookupSlotForCall);
2451     PushOperands(v0, v1);  // Function, receiver.
2452     PrepareForBailoutForId(expr->LookupId(), BailoutState::NO_REGISTERS);
2453 
2454     // If fast case code has been generated, emit code to push the
2455     // function and receiver and have the slow path jump around this
2456     // code.
2457     if (done.is_linked()) {
2458       Label call;
2459       __ Branch(&call);
2460       __ bind(&done);
2461       // Push function.
2462       __ push(v0);
2463       // The receiver is implicitly the global receiver. Indicate this
2464       // by passing the hole to the call function stub.
2465       __ LoadRoot(a1, Heap::kUndefinedValueRootIndex);
2466       __ push(a1);
2467       __ bind(&call);
2468     }
2469   } else {
2470     VisitForStackValue(callee);
2471     // refEnv.WithBaseObject()
2472     __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
2473     PushOperand(a2);  // Reserved receiver slot.
2474   }
2475 }
2476 
2477 
EmitPossiblyEvalCall(Call * expr)2478 void FullCodeGenerator::EmitPossiblyEvalCall(Call* expr) {
2479   // In a call to eval, we first call Runtime_ResolvePossiblyDirectEval
2480   // to resolve the function we need to call.  Then we call the resolved
2481   // function using the given arguments.
2482   ZoneList<Expression*>* args = expr->arguments();
2483   int arg_count = args->length();
2484   PushCalleeAndWithBaseObject(expr);
2485 
2486   // Push the arguments.
2487   for (int i = 0; i < arg_count; i++) {
2488     VisitForStackValue(args->at(i));
2489   }
2490 
2491   // Push a copy of the function (found below the arguments) and
2492   // resolve eval.
2493   __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2494   __ push(a1);
2495   EmitResolvePossiblyDirectEval(expr);
2496 
2497   // Touch up the stack with the resolved function.
2498   __ sd(v0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2499 
2500   PrepareForBailoutForId(expr->EvalId(), BailoutState::NO_REGISTERS);
2501   // Record source position for debugger.
2502   SetCallPosition(expr);
2503   Handle<Code> code = CodeFactory::CallIC(isolate(), ConvertReceiverMode::kAny,
2504                                           expr->tail_call_mode())
2505                           .code();
2506   __ li(a3, Operand(SmiFromSlot(expr->CallFeedbackICSlot())));
2507   __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2508   __ li(a0, Operand(arg_count));
2509   __ Call(code, RelocInfo::CODE_TARGET);
2510   OperandStackDepthDecrement(arg_count + 1);
2511   RecordJSReturnSite(expr);
2512   RestoreContext();
2513   context()->DropAndPlug(1, v0);
2514 }
2515 
2516 
VisitCallNew(CallNew * expr)2517 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2518   Comment cmnt(masm_, "[ CallNew");
2519   // According to ECMA-262, section 11.2.2, page 44, the function
2520   // expression in new calls must be evaluated before the
2521   // arguments.
2522 
2523   // Push constructor on the stack.  If it's not a function it's used as
2524   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2525   // ignored.
2526   DCHECK(!expr->expression()->IsSuperPropertyReference());
2527   VisitForStackValue(expr->expression());
2528 
2529   // Push the arguments ("left-to-right") on the stack.
2530   ZoneList<Expression*>* args = expr->arguments();
2531   int arg_count = args->length();
2532   for (int i = 0; i < arg_count; i++) {
2533     VisitForStackValue(args->at(i));
2534   }
2535 
2536   // Call the construct call builtin that handles allocation and
2537   // constructor invocation.
2538   SetConstructCallPosition(expr);
2539 
2540   // Load function and argument count into a1 and a0.
2541   __ li(a0, Operand(arg_count));
2542   __ ld(a1, MemOperand(sp, arg_count * kPointerSize));
2543 
2544   // Record call targets in unoptimized code.
2545   __ EmitLoadTypeFeedbackVector(a2);
2546   __ li(a3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
2547 
2548   CallConstructStub stub(isolate());
2549   CallIC(stub.GetCode());
2550   OperandStackDepthDecrement(arg_count + 1);
2551   PrepareForBailoutForId(expr->ReturnId(), BailoutState::TOS_REGISTER);
2552   RestoreContext();
2553   context()->Plug(v0);
2554 }
2555 
2556 
EmitSuperConstructorCall(Call * expr)2557 void FullCodeGenerator::EmitSuperConstructorCall(Call* expr) {
2558   SuperCallReference* super_call_ref =
2559       expr->expression()->AsSuperCallReference();
2560   DCHECK_NOT_NULL(super_call_ref);
2561 
2562   // Push the super constructor target on the stack (may be null,
2563   // but the Construct builtin can deal with that properly).
2564   VisitForAccumulatorValue(super_call_ref->this_function_var());
2565   __ AssertFunction(result_register());
2566   __ ld(result_register(),
2567         FieldMemOperand(result_register(), HeapObject::kMapOffset));
2568   __ ld(result_register(),
2569         FieldMemOperand(result_register(), Map::kPrototypeOffset));
2570   PushOperand(result_register());
2571 
2572   // Push the arguments ("left-to-right") on the stack.
2573   ZoneList<Expression*>* args = expr->arguments();
2574   int arg_count = args->length();
2575   for (int i = 0; i < arg_count; i++) {
2576     VisitForStackValue(args->at(i));
2577   }
2578 
2579   // Call the construct call builtin that handles allocation and
2580   // constructor invocation.
2581   SetConstructCallPosition(expr);
2582 
2583   // Load new target into a3.
2584   VisitForAccumulatorValue(super_call_ref->new_target_var());
2585   __ mov(a3, result_register());
2586 
2587   // Load function and argument count into a1 and a0.
2588   __ li(a0, Operand(arg_count));
2589   __ ld(a1, MemOperand(sp, arg_count * kPointerSize));
2590 
2591   __ Call(isolate()->builtins()->Construct(), RelocInfo::CODE_TARGET);
2592   OperandStackDepthDecrement(arg_count + 1);
2593 
2594   RecordJSReturnSite(expr);
2595   RestoreContext();
2596   context()->Plug(v0);
2597 }
2598 
2599 
EmitIsSmi(CallRuntime * expr)2600 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2601   ZoneList<Expression*>* args = expr->arguments();
2602   DCHECK(args->length() == 1);
2603 
2604   VisitForAccumulatorValue(args->at(0));
2605 
2606   Label materialize_true, materialize_false;
2607   Label* if_true = NULL;
2608   Label* if_false = NULL;
2609   Label* fall_through = NULL;
2610   context()->PrepareTest(&materialize_true, &materialize_false,
2611                          &if_true, &if_false, &fall_through);
2612 
2613   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2614   __ SmiTst(v0, a4);
2615   Split(eq, a4, Operand(zero_reg), if_true, if_false, fall_through);
2616 
2617   context()->Plug(if_true, if_false);
2618 }
2619 
2620 
EmitIsJSReceiver(CallRuntime * expr)2621 void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
2622   ZoneList<Expression*>* args = expr->arguments();
2623   DCHECK(args->length() == 1);
2624 
2625   VisitForAccumulatorValue(args->at(0));
2626 
2627   Label materialize_true, materialize_false;
2628   Label* if_true = NULL;
2629   Label* if_false = NULL;
2630   Label* fall_through = NULL;
2631   context()->PrepareTest(&materialize_true, &materialize_false,
2632                          &if_true, &if_false, &fall_through);
2633 
2634   __ JumpIfSmi(v0, if_false);
2635   __ GetObjectType(v0, a1, a1);
2636   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2637   Split(ge, a1, Operand(FIRST_JS_RECEIVER_TYPE),
2638         if_true, if_false, fall_through);
2639 
2640   context()->Plug(if_true, if_false);
2641 }
2642 
2643 
EmitIsArray(CallRuntime * expr)2644 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2645   ZoneList<Expression*>* args = expr->arguments();
2646   DCHECK(args->length() == 1);
2647 
2648   VisitForAccumulatorValue(args->at(0));
2649 
2650   Label materialize_true, materialize_false;
2651   Label* if_true = NULL;
2652   Label* if_false = NULL;
2653   Label* fall_through = NULL;
2654   context()->PrepareTest(&materialize_true, &materialize_false,
2655                          &if_true, &if_false, &fall_through);
2656 
2657   __ JumpIfSmi(v0, if_false);
2658   __ GetObjectType(v0, a1, a1);
2659   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2660   Split(eq, a1, Operand(JS_ARRAY_TYPE),
2661         if_true, if_false, fall_through);
2662 
2663   context()->Plug(if_true, if_false);
2664 }
2665 
2666 
EmitIsTypedArray(CallRuntime * expr)2667 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
2668   ZoneList<Expression*>* args = expr->arguments();
2669   DCHECK(args->length() == 1);
2670 
2671   VisitForAccumulatorValue(args->at(0));
2672 
2673   Label materialize_true, materialize_false;
2674   Label* if_true = NULL;
2675   Label* if_false = NULL;
2676   Label* fall_through = NULL;
2677   context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2678                          &if_false, &fall_through);
2679 
2680   __ JumpIfSmi(v0, if_false);
2681   __ GetObjectType(v0, a1, a1);
2682   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2683   Split(eq, a1, Operand(JS_TYPED_ARRAY_TYPE), if_true, if_false, fall_through);
2684 
2685   context()->Plug(if_true, if_false);
2686 }
2687 
2688 
EmitIsRegExp(CallRuntime * expr)2689 void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2690   ZoneList<Expression*>* args = expr->arguments();
2691   DCHECK(args->length() == 1);
2692 
2693   VisitForAccumulatorValue(args->at(0));
2694 
2695   Label materialize_true, materialize_false;
2696   Label* if_true = NULL;
2697   Label* if_false = NULL;
2698   Label* fall_through = NULL;
2699   context()->PrepareTest(&materialize_true, &materialize_false,
2700                          &if_true, &if_false, &fall_through);
2701 
2702   __ JumpIfSmi(v0, if_false);
2703   __ GetObjectType(v0, a1, a1);
2704   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2705   Split(eq, a1, Operand(JS_REGEXP_TYPE), if_true, if_false, fall_through);
2706 
2707   context()->Plug(if_true, if_false);
2708 }
2709 
2710 
EmitIsJSProxy(CallRuntime * expr)2711 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
2712   ZoneList<Expression*>* args = expr->arguments();
2713   DCHECK(args->length() == 1);
2714 
2715   VisitForAccumulatorValue(args->at(0));
2716 
2717   Label materialize_true, materialize_false;
2718   Label* if_true = NULL;
2719   Label* if_false = NULL;
2720   Label* fall_through = NULL;
2721   context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
2722                          &if_false, &fall_through);
2723 
2724   __ JumpIfSmi(v0, if_false);
2725   __ GetObjectType(v0, a1, a1);
2726   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
2727   Split(eq, a1, Operand(JS_PROXY_TYPE), if_true, if_false, fall_through);
2728 
2729   context()->Plug(if_true, if_false);
2730 }
2731 
2732 
EmitClassOf(CallRuntime * expr)2733 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2734   ZoneList<Expression*>* args = expr->arguments();
2735   DCHECK(args->length() == 1);
2736   Label done, null, function, non_function_constructor;
2737 
2738   VisitForAccumulatorValue(args->at(0));
2739 
2740   // If the object is not a JSReceiver, we return null.
2741   __ JumpIfSmi(v0, &null);
2742   STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
2743   __ GetObjectType(v0, v0, a1);  // Map is now in v0.
2744   __ Branch(&null, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
2745 
2746   // Return 'Function' for JSFunction and JSBoundFunction objects.
2747   STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
2748   __ Branch(&function, hs, a1, Operand(FIRST_FUNCTION_TYPE));
2749 
2750   // Check if the constructor in the map is a JS function.
2751   Register instance_type = a2;
2752   __ GetMapConstructor(v0, v0, a1, instance_type);
2753   __ Branch(&non_function_constructor, ne, instance_type,
2754             Operand(JS_FUNCTION_TYPE));
2755 
2756   // v0 now contains the constructor function. Grab the
2757   // instance class name from there.
2758   __ ld(v0, FieldMemOperand(v0, JSFunction::kSharedFunctionInfoOffset));
2759   __ ld(v0, FieldMemOperand(v0, SharedFunctionInfo::kInstanceClassNameOffset));
2760   __ Branch(&done);
2761 
2762   // Functions have class 'Function'.
2763   __ bind(&function);
2764   __ LoadRoot(v0, Heap::kFunction_stringRootIndex);
2765   __ jmp(&done);
2766 
2767   // Objects with a non-function constructor have class 'Object'.
2768   __ bind(&non_function_constructor);
2769   __ LoadRoot(v0, Heap::kObject_stringRootIndex);
2770   __ jmp(&done);
2771 
2772   // Non-JS objects have class null.
2773   __ bind(&null);
2774   __ LoadRoot(v0, Heap::kNullValueRootIndex);
2775 
2776   // All done.
2777   __ bind(&done);
2778 
2779   context()->Plug(v0);
2780 }
2781 
2782 
EmitStringCharCodeAt(CallRuntime * expr)2783 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
2784   ZoneList<Expression*>* args = expr->arguments();
2785   DCHECK(args->length() == 2);
2786 
2787   VisitForStackValue(args->at(0));
2788   VisitForAccumulatorValue(args->at(1));
2789   __ mov(a0, result_register());
2790 
2791   Register object = a1;
2792   Register index = a0;
2793   Register result = v0;
2794 
2795   PopOperand(object);
2796 
2797   Label need_conversion;
2798   Label index_out_of_range;
2799   Label done;
2800   StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
2801                                       &need_conversion, &index_out_of_range);
2802   generator.GenerateFast(masm_);
2803   __ jmp(&done);
2804 
2805   __ bind(&index_out_of_range);
2806   // When the index is out of range, the spec requires us to return
2807   // NaN.
2808   __ LoadRoot(result, Heap::kNanValueRootIndex);
2809   __ jmp(&done);
2810 
2811   __ bind(&need_conversion);
2812   // Load the undefined value into the result register, which will
2813   // trigger conversion.
2814   __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2815   __ jmp(&done);
2816 
2817   NopRuntimeCallHelper call_helper;
2818   generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
2819 
2820   __ bind(&done);
2821   context()->Plug(result);
2822 }
2823 
2824 
EmitCall(CallRuntime * expr)2825 void FullCodeGenerator::EmitCall(CallRuntime* expr) {
2826   ZoneList<Expression*>* args = expr->arguments();
2827   DCHECK_LE(2, args->length());
2828   // Push target, receiver and arguments onto the stack.
2829   for (Expression* const arg : *args) {
2830     VisitForStackValue(arg);
2831   }
2832   PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
2833   // Move target to a1.
2834   int const argc = args->length() - 2;
2835   __ ld(a1, MemOperand(sp, (argc + 1) * kPointerSize));
2836   // Call the target.
2837   __ li(a0, Operand(argc));
2838   __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
2839   OperandStackDepthDecrement(argc + 1);
2840   RestoreContext();
2841   // Discard the function left on TOS.
2842   context()->DropAndPlug(1, v0);
2843 }
2844 
EmitGetSuperConstructor(CallRuntime * expr)2845 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
2846   ZoneList<Expression*>* args = expr->arguments();
2847   DCHECK_EQ(1, args->length());
2848   VisitForAccumulatorValue(args->at(0));
2849   __ AssertFunction(v0);
2850   __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
2851   __ ld(v0, FieldMemOperand(v0, Map::kPrototypeOffset));
2852   context()->Plug(v0);
2853 }
2854 
EmitDebugIsActive(CallRuntime * expr)2855 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
2856   DCHECK(expr->arguments()->length() == 0);
2857   ExternalReference debug_is_active =
2858       ExternalReference::debug_is_active_address(isolate());
2859   __ li(at, Operand(debug_is_active));
2860   __ lbu(v0, MemOperand(at));
2861   __ SmiTag(v0);
2862   context()->Plug(v0);
2863 }
2864 
2865 
EmitCreateIterResultObject(CallRuntime * expr)2866 void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
2867   ZoneList<Expression*>* args = expr->arguments();
2868   DCHECK_EQ(2, args->length());
2869   VisitForStackValue(args->at(0));
2870   VisitForStackValue(args->at(1));
2871 
2872   Label runtime, done;
2873 
2874   __ Allocate(JSIteratorResult::kSize, v0, a2, a3, &runtime,
2875               NO_ALLOCATION_FLAGS);
2876   __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, a1);
2877   __ Pop(a2, a3);
2878   __ LoadRoot(a4, Heap::kEmptyFixedArrayRootIndex);
2879   __ sd(a1, FieldMemOperand(v0, HeapObject::kMapOffset));
2880   __ sd(a4, FieldMemOperand(v0, JSObject::kPropertiesOffset));
2881   __ sd(a4, FieldMemOperand(v0, JSObject::kElementsOffset));
2882   __ sd(a2, FieldMemOperand(v0, JSIteratorResult::kValueOffset));
2883   __ sd(a3, FieldMemOperand(v0, JSIteratorResult::kDoneOffset));
2884   STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
2885   __ jmp(&done);
2886 
2887   __ bind(&runtime);
2888   CallRuntimeWithOperands(Runtime::kCreateIterResultObject);
2889 
2890   __ bind(&done);
2891   context()->Plug(v0);
2892 }
2893 
2894 
EmitLoadJSRuntimeFunction(CallRuntime * expr)2895 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
2896   // Push function.
2897   __ LoadNativeContextSlot(expr->context_index(), v0);
2898   PushOperand(v0);
2899 
2900   // Push undefined as the receiver.
2901   __ LoadRoot(v0, Heap::kUndefinedValueRootIndex);
2902   PushOperand(v0);
2903 }
2904 
2905 
EmitCallJSRuntimeFunction(CallRuntime * expr)2906 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
2907   ZoneList<Expression*>* args = expr->arguments();
2908   int arg_count = args->length();
2909 
2910   SetCallPosition(expr);
2911   __ ld(a1, MemOperand(sp, (arg_count + 1) * kPointerSize));
2912   __ li(a0, Operand(arg_count));
2913   __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
2914           RelocInfo::CODE_TARGET);
2915   OperandStackDepthDecrement(arg_count + 1);
2916   RestoreContext();
2917 }
2918 
2919 
VisitUnaryOperation(UnaryOperation * expr)2920 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2921   switch (expr->op()) {
2922     case Token::DELETE: {
2923       Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2924       Property* property = expr->expression()->AsProperty();
2925       VariableProxy* proxy = expr->expression()->AsVariableProxy();
2926 
2927       if (property != NULL) {
2928         VisitForStackValue(property->obj());
2929         VisitForStackValue(property->key());
2930         CallRuntimeWithOperands(is_strict(language_mode())
2931                                     ? Runtime::kDeleteProperty_Strict
2932                                     : Runtime::kDeleteProperty_Sloppy);
2933         context()->Plug(v0);
2934       } else if (proxy != NULL) {
2935         Variable* var = proxy->var();
2936         // Delete of an unqualified identifier is disallowed in strict mode but
2937         // "delete this" is allowed.
2938         bool is_this = var->is_this();
2939         DCHECK(is_sloppy(language_mode()) || is_this);
2940         if (var->IsUnallocated()) {
2941           __ LoadGlobalObject(a2);
2942           __ li(a1, Operand(var->name()));
2943           __ Push(a2, a1);
2944           __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
2945           context()->Plug(v0);
2946         } else if (var->IsStackAllocated() || var->IsContextSlot()) {
2947           // Result of deleting non-global, non-dynamic variables is false.
2948           // The subexpression does not have side effects.
2949           context()->Plug(is_this);
2950         } else {
2951           // Non-global variable.  Call the runtime to try to delete from the
2952           // context where the variable was introduced.
2953           DCHECK(!context_register().is(a2));
2954           __ Push(var->name());
2955           __ CallRuntime(Runtime::kDeleteLookupSlot);
2956           context()->Plug(v0);
2957         }
2958       } else {
2959         // Result of deleting non-property, non-variable reference is true.
2960         // The subexpression may have side effects.
2961         VisitForEffect(expr->expression());
2962         context()->Plug(true);
2963       }
2964       break;
2965     }
2966 
2967     case Token::VOID: {
2968       Comment cmnt(masm_, "[ UnaryOperation (VOID)");
2969       VisitForEffect(expr->expression());
2970       context()->Plug(Heap::kUndefinedValueRootIndex);
2971       break;
2972     }
2973 
2974     case Token::NOT: {
2975       Comment cmnt(masm_, "[ UnaryOperation (NOT)");
2976       if (context()->IsEffect()) {
2977         // Unary NOT has no side effects so it's only necessary to visit the
2978         // subexpression.  Match the optimizing compiler by not branching.
2979         VisitForEffect(expr->expression());
2980       } else if (context()->IsTest()) {
2981         const TestContext* test = TestContext::cast(context());
2982         // The labels are swapped for the recursive call.
2983         VisitForControl(expr->expression(),
2984                         test->false_label(),
2985                         test->true_label(),
2986                         test->fall_through());
2987         context()->Plug(test->true_label(), test->false_label());
2988       } else {
2989         // We handle value contexts explicitly rather than simply visiting
2990         // for control and plugging the control flow into the context,
2991         // because we need to prepare a pair of extra administrative AST ids
2992         // for the optimizing compiler.
2993         DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
2994         Label materialize_true, materialize_false, done;
2995         VisitForControl(expr->expression(),
2996                         &materialize_false,
2997                         &materialize_true,
2998                         &materialize_true);
2999         if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1);
3000         __ bind(&materialize_true);
3001         PrepareForBailoutForId(expr->MaterializeTrueId(),
3002                                BailoutState::NO_REGISTERS);
3003         __ LoadRoot(v0, Heap::kTrueValueRootIndex);
3004         if (context()->IsStackValue()) __ push(v0);
3005         __ jmp(&done);
3006         __ bind(&materialize_false);
3007         PrepareForBailoutForId(expr->MaterializeFalseId(),
3008                                BailoutState::NO_REGISTERS);
3009         __ LoadRoot(v0, Heap::kFalseValueRootIndex);
3010         if (context()->IsStackValue()) __ push(v0);
3011         __ bind(&done);
3012       }
3013       break;
3014     }
3015 
3016     case Token::TYPEOF: {
3017       Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
3018       {
3019         AccumulatorValueContext context(this);
3020         VisitForTypeofValue(expr->expression());
3021       }
3022       __ mov(a3, v0);
3023       __ Call(isolate()->builtins()->Typeof(), RelocInfo::CODE_TARGET);
3024       context()->Plug(v0);
3025       break;
3026     }
3027 
3028     default:
3029       UNREACHABLE();
3030   }
3031 }
3032 
3033 
VisitCountOperation(CountOperation * expr)3034 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3035   DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
3036 
3037   Comment cmnt(masm_, "[ CountOperation");
3038 
3039   Property* prop = expr->expression()->AsProperty();
3040   LhsKind assign_type = Property::GetAssignType(prop);
3041 
3042   // Evaluate expression and get value.
3043   if (assign_type == VARIABLE) {
3044     DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
3045     AccumulatorValueContext context(this);
3046     EmitVariableLoad(expr->expression()->AsVariableProxy());
3047   } else {
3048     // Reserve space for result of postfix operation.
3049     if (expr->is_postfix() && !context()->IsEffect()) {
3050       __ li(at, Operand(Smi::kZero));
3051       PushOperand(at);
3052     }
3053     switch (assign_type) {
3054       case NAMED_PROPERTY: {
3055         // Put the object both on the stack and in the register.
3056         VisitForStackValue(prop->obj());
3057         __ ld(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
3058         EmitNamedPropertyLoad(prop);
3059         break;
3060       }
3061 
3062       case NAMED_SUPER_PROPERTY: {
3063         VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3064         VisitForAccumulatorValue(
3065             prop->obj()->AsSuperPropertyReference()->home_object());
3066         const Register scratch = a1;
3067         __ ld(scratch, MemOperand(sp, 0));  // this
3068         PushOperands(result_register(), scratch, result_register());
3069         EmitNamedSuperPropertyLoad(prop);
3070         break;
3071       }
3072 
3073       case KEYED_SUPER_PROPERTY: {
3074         VisitForStackValue(prop->obj()->AsSuperPropertyReference()->this_var());
3075         VisitForStackValue(
3076             prop->obj()->AsSuperPropertyReference()->home_object());
3077         VisitForAccumulatorValue(prop->key());
3078         const Register scratch1 = a1;
3079         const Register scratch2 = a4;
3080         __ ld(scratch1, MemOperand(sp, 1 * kPointerSize));  // this
3081         __ ld(scratch2, MemOperand(sp, 0 * kPointerSize));  // home object
3082         PushOperands(result_register(), scratch1, scratch2, result_register());
3083         EmitKeyedSuperPropertyLoad(prop);
3084         break;
3085       }
3086 
3087       case KEYED_PROPERTY: {
3088         VisitForStackValue(prop->obj());
3089         VisitForStackValue(prop->key());
3090         __ ld(LoadDescriptor::ReceiverRegister(),
3091               MemOperand(sp, 1 * kPointerSize));
3092         __ ld(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
3093         EmitKeyedPropertyLoad(prop);
3094         break;
3095       }
3096 
3097       case VARIABLE:
3098         UNREACHABLE();
3099     }
3100   }
3101 
3102   // We need a second deoptimization point after loading the value
3103   // in case evaluating the property load my have a side effect.
3104   if (assign_type == VARIABLE) {
3105     PrepareForBailout(expr->expression(), BailoutState::TOS_REGISTER);
3106   } else {
3107     PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
3108   }
3109 
3110   // Inline smi case if we are in a loop.
3111   Label stub_call, done;
3112   JumpPatchSite patch_site(masm_);
3113 
3114   int count_value = expr->op() == Token::INC ? 1 : -1;
3115   __ mov(a0, v0);
3116   if (ShouldInlineSmiCase(expr->op())) {
3117     Label slow;
3118     patch_site.EmitJumpIfNotSmi(v0, &slow);
3119 
3120     // Save result for postfix expressions.
3121     if (expr->is_postfix()) {
3122       if (!context()->IsEffect()) {
3123         // Save the result on the stack. If we have a named or keyed property
3124         // we store the result under the receiver that is currently on top
3125         // of the stack.
3126         switch (assign_type) {
3127           case VARIABLE:
3128             __ push(v0);
3129             break;
3130           case NAMED_PROPERTY:
3131             __ sd(v0, MemOperand(sp, kPointerSize));
3132             break;
3133           case NAMED_SUPER_PROPERTY:
3134             __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3135             break;
3136           case KEYED_PROPERTY:
3137             __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3138             break;
3139           case KEYED_SUPER_PROPERTY:
3140             __ sd(v0, MemOperand(sp, 3 * kPointerSize));
3141             break;
3142         }
3143       }
3144     }
3145 
3146     Register scratch1 = a1;
3147     __ li(scratch1, Operand(Smi::FromInt(count_value)));
3148     __ DaddBranchNoOvf(v0, v0, Operand(scratch1), &done);
3149     // Call stub. Undo operation first.
3150     __ Move(v0, a0);
3151     __ jmp(&stub_call);
3152     __ bind(&slow);
3153   }
3154 
3155   // Convert old value into a number.
3156   __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
3157   RestoreContext();
3158   PrepareForBailoutForId(expr->ToNumberId(), BailoutState::TOS_REGISTER);
3159 
3160   // Save result for postfix expressions.
3161   if (expr->is_postfix()) {
3162     if (!context()->IsEffect()) {
3163       // Save the result on the stack. If we have a named or keyed property
3164       // we store the result under the receiver that is currently on top
3165       // of the stack.
3166       switch (assign_type) {
3167         case VARIABLE:
3168           PushOperand(v0);
3169           break;
3170         case NAMED_PROPERTY:
3171           __ sd(v0, MemOperand(sp, kPointerSize));
3172           break;
3173         case NAMED_SUPER_PROPERTY:
3174           __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3175           break;
3176         case KEYED_PROPERTY:
3177           __ sd(v0, MemOperand(sp, 2 * kPointerSize));
3178           break;
3179         case KEYED_SUPER_PROPERTY:
3180           __ sd(v0, MemOperand(sp, 3 * kPointerSize));
3181           break;
3182       }
3183     }
3184   }
3185 
3186   __ bind(&stub_call);
3187   __ mov(a1, v0);
3188   __ li(a0, Operand(Smi::FromInt(count_value)));
3189 
3190   SetExpressionPosition(expr);
3191 
3192   Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
3193   CallIC(code, expr->CountBinOpFeedbackId());
3194   patch_site.EmitPatchInfo();
3195   __ bind(&done);
3196 
3197   // Store the value returned in v0.
3198   switch (assign_type) {
3199     case VARIABLE: {
3200       VariableProxy* proxy = expr->expression()->AsVariableProxy();
3201       if (expr->is_postfix()) {
3202         { EffectContext context(this);
3203           EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
3204                                  proxy->hole_check_mode());
3205           PrepareForBailoutForId(expr->AssignmentId(),
3206                                  BailoutState::TOS_REGISTER);
3207           context.Plug(v0);
3208         }
3209         // For all contexts except EffectConstant we have the result on
3210         // top of the stack.
3211         if (!context()->IsEffect()) {
3212           context()->PlugTOS();
3213         }
3214       } else {
3215         EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
3216                                proxy->hole_check_mode());
3217         PrepareForBailoutForId(expr->AssignmentId(),
3218                                BailoutState::TOS_REGISTER);
3219         context()->Plug(v0);
3220       }
3221       break;
3222     }
3223     case NAMED_PROPERTY: {
3224       __ mov(StoreDescriptor::ValueRegister(), result_register());
3225       PopOperand(StoreDescriptor::ReceiverRegister());
3226       CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
3227       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3228       if (expr->is_postfix()) {
3229         if (!context()->IsEffect()) {
3230           context()->PlugTOS();
3231         }
3232       } else {
3233         context()->Plug(v0);
3234       }
3235       break;
3236     }
3237     case NAMED_SUPER_PROPERTY: {
3238       EmitNamedSuperPropertyStore(prop);
3239       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3240       if (expr->is_postfix()) {
3241         if (!context()->IsEffect()) {
3242           context()->PlugTOS();
3243         }
3244       } else {
3245         context()->Plug(v0);
3246       }
3247       break;
3248     }
3249     case KEYED_SUPER_PROPERTY: {
3250       EmitKeyedSuperPropertyStore(prop);
3251       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3252       if (expr->is_postfix()) {
3253         if (!context()->IsEffect()) {
3254           context()->PlugTOS();
3255         }
3256       } else {
3257         context()->Plug(v0);
3258       }
3259       break;
3260     }
3261     case KEYED_PROPERTY: {
3262       __ mov(StoreDescriptor::ValueRegister(), result_register());
3263       PopOperands(StoreDescriptor::ReceiverRegister(),
3264                   StoreDescriptor::NameRegister());
3265       CallKeyedStoreIC(expr->CountSlot());
3266       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
3267       if (expr->is_postfix()) {
3268         if (!context()->IsEffect()) {
3269           context()->PlugTOS();
3270         }
3271       } else {
3272         context()->Plug(v0);
3273       }
3274       break;
3275     }
3276   }
3277 }
3278 
3279 
EmitLiteralCompareTypeof(Expression * expr,Expression * sub_expr,Handle<String> check)3280 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
3281                                                  Expression* sub_expr,
3282                                                  Handle<String> check) {
3283   Label materialize_true, materialize_false;
3284   Label* if_true = NULL;
3285   Label* if_false = NULL;
3286   Label* fall_through = NULL;
3287   context()->PrepareTest(&materialize_true, &materialize_false,
3288                          &if_true, &if_false, &fall_through);
3289 
3290   { AccumulatorValueContext context(this);
3291     VisitForTypeofValue(sub_expr);
3292   }
3293   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3294 
3295   Factory* factory = isolate()->factory();
3296   if (String::Equals(check, factory->number_string())) {
3297     __ JumpIfSmi(v0, if_true);
3298     __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3299     __ LoadRoot(at, Heap::kHeapNumberMapRootIndex);
3300     Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3301   } else if (String::Equals(check, factory->string_string())) {
3302     __ JumpIfSmi(v0, if_false);
3303     __ GetObjectType(v0, v0, a1);
3304     Split(lt, a1, Operand(FIRST_NONSTRING_TYPE), if_true, if_false,
3305           fall_through);
3306   } else if (String::Equals(check, factory->symbol_string())) {
3307     __ JumpIfSmi(v0, if_false);
3308     __ GetObjectType(v0, v0, a1);
3309     Split(eq, a1, Operand(SYMBOL_TYPE), if_true, if_false, fall_through);
3310   } else if (String::Equals(check, factory->boolean_string())) {
3311     __ LoadRoot(at, Heap::kTrueValueRootIndex);
3312     __ Branch(if_true, eq, v0, Operand(at));
3313     __ LoadRoot(at, Heap::kFalseValueRootIndex);
3314     Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3315   } else if (String::Equals(check, factory->undefined_string())) {
3316     __ LoadRoot(at, Heap::kNullValueRootIndex);
3317     __ Branch(if_false, eq, v0, Operand(at));
3318     __ JumpIfSmi(v0, if_false);
3319     // Check for undetectable objects => true.
3320     __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3321     __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3322     __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3323     Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
3324   } else if (String::Equals(check, factory->function_string())) {
3325     __ JumpIfSmi(v0, if_false);
3326     __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3327     __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3328     __ And(a1, a1,
3329            Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3330     Split(eq, a1, Operand(1 << Map::kIsCallable), if_true, if_false,
3331           fall_through);
3332   } else if (String::Equals(check, factory->object_string())) {
3333     __ JumpIfSmi(v0, if_false);
3334     __ LoadRoot(at, Heap::kNullValueRootIndex);
3335     __ Branch(if_true, eq, v0, Operand(at));
3336     STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
3337     __ GetObjectType(v0, v0, a1);
3338     __ Branch(if_false, lt, a1, Operand(FIRST_JS_RECEIVER_TYPE));
3339     // Check for callable or undetectable objects => false.
3340     __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3341     __ And(a1, a1,
3342            Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
3343     Split(eq, a1, Operand(zero_reg), if_true, if_false, fall_through);
3344 // clang-format off
3345 #define SIMD128_TYPE(TYPE, Type, type, lane_count, lane_type)    \
3346   } else if (String::Equals(check, factory->type##_string())) {  \
3347     __ JumpIfSmi(v0, if_false);                                  \
3348     __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));      \
3349     __ LoadRoot(at, Heap::k##Type##MapRootIndex);                \
3350     Split(eq, v0, Operand(at), if_true, if_false, fall_through);
3351   SIMD128_TYPES(SIMD128_TYPE)
3352 #undef SIMD128_TYPE
3353     // clang-format on
3354   } else {
3355     if (if_false != fall_through) __ jmp(if_false);
3356   }
3357   context()->Plug(if_true, if_false);
3358 }
3359 
3360 
VisitCompareOperation(CompareOperation * expr)3361 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3362   Comment cmnt(masm_, "[ CompareOperation");
3363 
3364   // First we try a fast inlined version of the compare when one of
3365   // the operands is a literal.
3366   if (TryLiteralCompare(expr)) return;
3367 
3368   // Always perform the comparison for its control flow.  Pack the result
3369   // into the expression's context after the comparison is performed.
3370   Label materialize_true, materialize_false;
3371   Label* if_true = NULL;
3372   Label* if_false = NULL;
3373   Label* fall_through = NULL;
3374   context()->PrepareTest(&materialize_true, &materialize_false,
3375                          &if_true, &if_false, &fall_through);
3376 
3377   Token::Value op = expr->op();
3378   VisitForStackValue(expr->left());
3379   switch (op) {
3380     case Token::IN:
3381       VisitForStackValue(expr->right());
3382       SetExpressionPosition(expr);
3383       EmitHasProperty();
3384       PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3385       __ LoadRoot(a4, Heap::kTrueValueRootIndex);
3386       Split(eq, v0, Operand(a4), if_true, if_false, fall_through);
3387       break;
3388 
3389     case Token::INSTANCEOF: {
3390       VisitForAccumulatorValue(expr->right());
3391       SetExpressionPosition(expr);
3392       __ mov(a0, result_register());
3393       PopOperand(a1);
3394       __ Call(isolate()->builtins()->InstanceOf(), RelocInfo::CODE_TARGET);
3395       PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
3396       __ LoadRoot(a4, Heap::kTrueValueRootIndex);
3397       Split(eq, v0, Operand(a4), if_true, if_false, fall_through);
3398       break;
3399     }
3400 
3401     default: {
3402       VisitForAccumulatorValue(expr->right());
3403       SetExpressionPosition(expr);
3404       Condition cc = CompareIC::ComputeCondition(op);
3405       __ mov(a0, result_register());
3406       PopOperand(a1);
3407 
3408       bool inline_smi_code = ShouldInlineSmiCase(op);
3409       JumpPatchSite patch_site(masm_);
3410       if (inline_smi_code) {
3411         Label slow_case;
3412         __ Or(a2, a0, Operand(a1));
3413         patch_site.EmitJumpIfNotSmi(a2, &slow_case);
3414         Split(cc, a1, Operand(a0), if_true, if_false, NULL);
3415         __ bind(&slow_case);
3416       }
3417 
3418       Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
3419       CallIC(ic, expr->CompareOperationFeedbackId());
3420       patch_site.EmitPatchInfo();
3421       PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3422       Split(cc, v0, Operand(zero_reg), if_true, if_false, fall_through);
3423     }
3424   }
3425 
3426   // Convert the result of the comparison into one expected for this
3427   // expression's context.
3428   context()->Plug(if_true, if_false);
3429 }
3430 
3431 
EmitLiteralCompareNil(CompareOperation * expr,Expression * sub_expr,NilValue nil)3432 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
3433                                               Expression* sub_expr,
3434                                               NilValue nil) {
3435   Label materialize_true, materialize_false;
3436   Label* if_true = NULL;
3437   Label* if_false = NULL;
3438   Label* fall_through = NULL;
3439   context()->PrepareTest(&materialize_true, &materialize_false,
3440                          &if_true, &if_false, &fall_through);
3441 
3442   VisitForAccumulatorValue(sub_expr);
3443   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3444   if (expr->op() == Token::EQ_STRICT) {
3445     Heap::RootListIndex nil_value = nil == kNullValue ?
3446         Heap::kNullValueRootIndex :
3447         Heap::kUndefinedValueRootIndex;
3448     __ LoadRoot(a1, nil_value);
3449     Split(eq, v0, Operand(a1), if_true, if_false, fall_through);
3450   } else {
3451     __ JumpIfSmi(v0, if_false);
3452     __ ld(v0, FieldMemOperand(v0, HeapObject::kMapOffset));
3453     __ lbu(a1, FieldMemOperand(v0, Map::kBitFieldOffset));
3454     __ And(a1, a1, Operand(1 << Map::kIsUndetectable));
3455     Split(ne, a1, Operand(zero_reg), if_true, if_false, fall_through);
3456   }
3457   context()->Plug(if_true, if_false);
3458 }
3459 
3460 
result_register()3461 Register FullCodeGenerator::result_register() {
3462   return v0;
3463 }
3464 
3465 
context_register()3466 Register FullCodeGenerator::context_register() {
3467   return cp;
3468 }
3469 
LoadFromFrameField(int frame_offset,Register value)3470 void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) {
3471   // DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3472   DCHECK(IsAligned(frame_offset, kPointerSize));
3473   //  __ sw(value, MemOperand(fp, frame_offset));
3474   __ ld(value, MemOperand(fp, frame_offset));
3475 }
3476 
StoreToFrameField(int frame_offset,Register value)3477 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3478   // DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3479   DCHECK(IsAligned(frame_offset, kPointerSize));
3480   //  __ sw(value, MemOperand(fp, frame_offset));
3481   __ sd(value, MemOperand(fp, frame_offset));
3482 }
3483 
3484 
LoadContextField(Register dst,int context_index)3485 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3486   __ ld(dst, ContextMemOperand(cp, context_index));
3487 }
3488 
3489 
PushFunctionArgumentForContextAllocation()3490 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
3491   DeclarationScope* closure_scope = scope()->GetClosureScope();
3492   if (closure_scope->is_script_scope() ||
3493       closure_scope->is_module_scope()) {
3494     // Contexts nested in the native context have a canonical empty function
3495     // as their closure, not the anonymous closure containing the global
3496     // code.
3497     __ LoadNativeContextSlot(Context::CLOSURE_INDEX, at);
3498   } else if (closure_scope->is_eval_scope()) {
3499     // Contexts created by a call to eval have the same closure as the
3500     // context calling eval, not the anonymous closure containing the eval
3501     // code.  Fetch it from the context.
3502     __ ld(at, ContextMemOperand(cp, Context::CLOSURE_INDEX));
3503   } else {
3504     DCHECK(closure_scope->is_function_scope());
3505     __ ld(at, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
3506   }
3507   PushOperand(at);
3508 }
3509 
3510 
3511 // ----------------------------------------------------------------------------
3512 // Non-local control flow support.
3513 
EnterFinallyBlock()3514 void FullCodeGenerator::EnterFinallyBlock() {
3515   DCHECK(!result_register().is(a1));
3516   // Store pending message while executing finally block.
3517   ExternalReference pending_message_obj =
3518       ExternalReference::address_of_pending_message_obj(isolate());
3519   __ li(at, Operand(pending_message_obj));
3520   __ ld(a1, MemOperand(at));
3521   PushOperand(a1);
3522 
3523   ClearPendingMessage();
3524 }
3525 
3526 
ExitFinallyBlock()3527 void FullCodeGenerator::ExitFinallyBlock() {
3528   DCHECK(!result_register().is(a1));
3529   // Restore pending message from stack.
3530   PopOperand(a1);
3531   ExternalReference pending_message_obj =
3532       ExternalReference::address_of_pending_message_obj(isolate());
3533   __ li(at, Operand(pending_message_obj));
3534   __ sd(a1, MemOperand(at));
3535 }
3536 
3537 
ClearPendingMessage()3538 void FullCodeGenerator::ClearPendingMessage() {
3539   DCHECK(!result_register().is(a1));
3540   ExternalReference pending_message_obj =
3541       ExternalReference::address_of_pending_message_obj(isolate());
3542   __ LoadRoot(a1, Heap::kTheHoleValueRootIndex);
3543   __ li(at, Operand(pending_message_obj));
3544   __ sd(a1, MemOperand(at));
3545 }
3546 
3547 
EmitCommands()3548 void FullCodeGenerator::DeferredCommands::EmitCommands() {
3549   __ Pop(result_register());  // Restore the accumulator.
3550   __ Pop(a1);                 // Get the token.
3551   for (DeferredCommand cmd : commands_) {
3552     Label skip;
3553     __ li(at, Operand(Smi::FromInt(cmd.token)));
3554     __ Branch(&skip, ne, a1, Operand(at));
3555     switch (cmd.command) {
3556       case kReturn:
3557         codegen_->EmitUnwindAndReturn();
3558         break;
3559       case kThrow:
3560         __ Push(result_register());
3561         __ CallRuntime(Runtime::kReThrow);
3562         break;
3563       case kContinue:
3564         codegen_->EmitContinue(cmd.target);
3565         break;
3566       case kBreak:
3567         codegen_->EmitBreak(cmd.target);
3568         break;
3569     }
3570     __ bind(&skip);
3571   }
3572 }
3573 
3574 #undef __
3575 
3576 
PatchAt(Code * unoptimized_code,Address pc,BackEdgeState target_state,Code * replacement_code)3577 void BackEdgeTable::PatchAt(Code* unoptimized_code,
3578                             Address pc,
3579                             BackEdgeState target_state,
3580                             Code* replacement_code) {
3581   static const int kInstrSize = Assembler::kInstrSize;
3582   Address pc_immediate_load_address =
3583       Assembler::target_address_from_return_address(pc);
3584   Address branch_address = pc_immediate_load_address - 2 * kInstrSize;
3585   Isolate* isolate = unoptimized_code->GetIsolate();
3586   CodePatcher patcher(isolate, branch_address, 1);
3587 
3588   switch (target_state) {
3589     case INTERRUPT:
3590       // slt  at, a3, zero_reg (in case of count based interrupts)
3591       // beq  at, zero_reg, ok
3592       // lui  t9, <interrupt stub address> upper
3593       // ori  t9, <interrupt stub address> u-middle
3594       // dsll t9, t9, 16
3595       // ori  t9, <interrupt stub address> lower
3596       // jalr t9
3597       // nop
3598       // ok-label ----- pc_after points here
3599       patcher.masm()->slt(at, a3, zero_reg);
3600       break;
3601     case ON_STACK_REPLACEMENT:
3602       // addiu at, zero_reg, 1
3603       // beq  at, zero_reg, ok  ;; Not changed
3604       // lui  t9, <on-stack replacement address> upper
3605       // ori  t9, <on-stack replacement address> middle
3606       // dsll t9, t9, 16
3607       // ori  t9, <on-stack replacement address> lower
3608       // jalr t9  ;; Not changed
3609       // nop  ;; Not changed
3610       // ok-label ----- pc_after points here
3611       patcher.masm()->daddiu(at, zero_reg, 1);
3612       break;
3613   }
3614   // Replace the stack check address in the load-immediate (6-instr sequence)
3615   // with the entry address of the replacement code.
3616   Assembler::set_target_address_at(isolate, pc_immediate_load_address,
3617                                    replacement_code->entry());
3618 
3619   unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
3620       unoptimized_code, pc_immediate_load_address, replacement_code);
3621 }
3622 
3623 
GetBackEdgeState(Isolate * isolate,Code * unoptimized_code,Address pc)3624 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
3625     Isolate* isolate,
3626     Code* unoptimized_code,
3627     Address pc) {
3628   static const int kInstrSize = Assembler::kInstrSize;
3629   Address pc_immediate_load_address =
3630       Assembler::target_address_from_return_address(pc);
3631   Address branch_address = pc_immediate_load_address - 2 * kInstrSize;
3632 
3633   DCHECK(Assembler::IsBeq(Assembler::instr_at(branch_address + kInstrSize)));
3634   if (!Assembler::IsAddImmediate(Assembler::instr_at(branch_address))) {
3635     DCHECK(reinterpret_cast<uint64_t>(
3636         Assembler::target_address_at(pc_immediate_load_address)) ==
3637            reinterpret_cast<uint64_t>(
3638                isolate->builtins()->InterruptCheck()->entry()));
3639     return INTERRUPT;
3640   }
3641 
3642   DCHECK(Assembler::IsAddImmediate(Assembler::instr_at(branch_address)));
3643 
3644   DCHECK(reinterpret_cast<uint64_t>(
3645              Assembler::target_address_at(pc_immediate_load_address)) ==
3646          reinterpret_cast<uint64_t>(
3647              isolate->builtins()->OnStackReplacement()->entry()));
3648   return ON_STACK_REPLACEMENT;
3649 }
3650 
3651 
3652 }  // namespace internal
3653 }  // namespace v8
3654 
3655 #endif  // V8_TARGET_ARCH_MIPS64
3656