Home | History | Annotate | Download | only in arm
      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_ARM
      6 
      7 #include "src/ast/compile-time-value.h"
      8 #include "src/ast/scopes.h"
      9 #include "src/builtins/builtins-constructor.h"
     10 #include "src/code-factory.h"
     11 #include "src/code-stubs.h"
     12 #include "src/codegen.h"
     13 #include "src/compilation-info.h"
     14 #include "src/compiler.h"
     15 #include "src/debug/debug.h"
     16 #include "src/full-codegen/full-codegen.h"
     17 #include "src/ic/ic.h"
     18 
     19 #include "src/arm/code-stubs-arm.h"
     20 #include "src/arm/macro-assembler-arm.h"
     21 
     22 namespace v8 {
     23 namespace internal {
     24 
     25 #define __ ACCESS_MASM(masm())
     26 
     27 // A patch site is a location in the code which it is possible to patch. This
     28 // class has a number of methods to emit the code which is patchable and the
     29 // method EmitPatchInfo to record a marker back to the patchable code. This
     30 // marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit
     31 // immediate value is used) is the delta from the pc to the first instruction of
     32 // the patchable code.
     33 class JumpPatchSite BASE_EMBEDDED {
     34  public:
     35   explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
     36 #ifdef DEBUG
     37     info_emitted_ = false;
     38 #endif
     39   }
     40 
     41   ~JumpPatchSite() {
     42     DCHECK(patch_site_.is_bound() == info_emitted_);
     43   }
     44 
     45   // When initially emitting this ensure that a jump is always generated to skip
     46   // the inlined smi code.
     47   void EmitJumpIfNotSmi(Register reg, Label* target) {
     48     DCHECK(!patch_site_.is_bound() && !info_emitted_);
     49     Assembler::BlockConstPoolScope block_const_pool(masm_);
     50     __ bind(&patch_site_);
     51     __ cmp(reg, Operand(reg));
     52     __ b(eq, target);  // Always taken before patched.
     53   }
     54 
     55   // When initially emitting this ensure that a jump is never generated to skip
     56   // the inlined smi code.
     57   void EmitJumpIfSmi(Register reg, Label* target) {
     58     DCHECK(!patch_site_.is_bound() && !info_emitted_);
     59     Assembler::BlockConstPoolScope block_const_pool(masm_);
     60     __ bind(&patch_site_);
     61     __ cmp(reg, Operand(reg));
     62     __ b(ne, target);  // Never taken before patched.
     63   }
     64 
     65   void EmitPatchInfo() {
     66     // Block literal pool emission whilst recording patch site information.
     67     Assembler::BlockConstPoolScope block_const_pool(masm_);
     68     if (patch_site_.is_bound()) {
     69       int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
     70       Register reg;
     71       reg.set_code(delta_to_patch_site / kOff12Mask);
     72       __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
     73 #ifdef DEBUG
     74       info_emitted_ = true;
     75 #endif
     76     } else {
     77       __ nop();  // Signals no inlined code.
     78     }
     79   }
     80 
     81  private:
     82   MacroAssembler* masm() { return masm_; }
     83   MacroAssembler* masm_;
     84   Label patch_site_;
     85 #ifdef DEBUG
     86   bool info_emitted_;
     87 #endif
     88 };
     89 
     90 
     91 // Generate code for a JS function.  On entry to the function the receiver
     92 // and arguments have been pushed on the stack left to right.  The actual
     93 // argument count matches the formal parameter count expected by the
     94 // function.
     95 //
     96 // The live registers are:
     97 //   o r1: the JS function object being called (i.e., ourselves)
     98 //   o r3: the new target value
     99 //   o cp: our context
    100 //   o pp: our caller's constant pool pointer (if enabled)
    101 //   o fp: our caller's frame pointer
    102 //   o sp: stack pointer
    103 //   o lr: return address
    104 //
    105 // The function builds a JS frame.  Please see JavaScriptFrameConstants in
    106 // frames-arm.h for its layout.
    107 void FullCodeGenerator::Generate() {
    108   CompilationInfo* info = info_;
    109   profiling_counter_ = isolate()->factory()->NewCell(
    110       Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
    111   SetFunctionPosition(literal());
    112   Comment cmnt(masm_, "[ function compiled by full code generator");
    113 
    114   ProfileEntryHookStub::MaybeCallEntryHook(masm_);
    115 
    116   if (FLAG_debug_code && info->ExpectsJSReceiverAsReceiver()) {
    117     int receiver_offset = info->scope()->num_parameters() * kPointerSize;
    118     __ ldr(r2, MemOperand(sp, receiver_offset));
    119     __ AssertNotSmi(r2);
    120     __ CompareObjectType(r2, r2, no_reg, FIRST_JS_RECEIVER_TYPE);
    121     __ Assert(ge, kSloppyFunctionExpectsJSReceiverReceiver);
    122   }
    123 
    124   // Open a frame scope to indicate that there is a frame on the stack.  The
    125   // MANUAL indicates that the scope shouldn't actually generate code to set up
    126   // the frame (that is done below).
    127   FrameScope frame_scope(masm_, StackFrame::MANUAL);
    128 
    129   info->set_prologue_offset(masm_->pc_offset());
    130   __ Prologue(info->GeneratePreagedPrologue());
    131 
    132   // Increment invocation count for the function.
    133   {
    134     Comment cmnt(masm_, "[ Increment invocation count");
    135     __ ldr(r2, FieldMemOperand(r1, JSFunction::kFeedbackVectorOffset));
    136     __ ldr(r2, FieldMemOperand(r2, Cell::kValueOffset));
    137     __ ldr(r9, FieldMemOperand(
    138                    r2, FeedbackVector::kInvocationCountIndex * kPointerSize +
    139                            FeedbackVector::kHeaderSize));
    140     __ add(r9, r9, Operand(Smi::FromInt(1)));
    141     __ str(r9, FieldMemOperand(
    142                    r2, FeedbackVector::kInvocationCountIndex * kPointerSize +
    143                            FeedbackVector::kHeaderSize));
    144   }
    145 
    146   { Comment cmnt(masm_, "[ Allocate locals");
    147     int locals_count = info->scope()->num_stack_slots();
    148     OperandStackDepthIncrement(locals_count);
    149     if (locals_count > 0) {
    150       if (locals_count >= 128) {
    151         Label ok;
    152         __ sub(r9, sp, Operand(locals_count * kPointerSize));
    153         __ LoadRoot(r2, Heap::kRealStackLimitRootIndex);
    154         __ cmp(r9, Operand(r2));
    155         __ b(hs, &ok);
    156         __ CallRuntime(Runtime::kThrowStackOverflow);
    157         __ bind(&ok);
    158       }
    159       __ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
    160       int kMaxPushes = FLAG_optimize_for_size ? 4 : 32;
    161       if (locals_count >= kMaxPushes) {
    162         int loop_iterations = locals_count / kMaxPushes;
    163         __ mov(r2, Operand(loop_iterations));
    164         Label loop_header;
    165         __ bind(&loop_header);
    166         // Do pushes.
    167         for (int i = 0; i < kMaxPushes; i++) {
    168           __ push(r9);
    169         }
    170         // Continue loop if not done.
    171         __ sub(r2, r2, Operand(1), SetCC);
    172         __ b(&loop_header, ne);
    173       }
    174       int remaining = locals_count % kMaxPushes;
    175       // Emit the remaining pushes.
    176       for (int i  = 0; i < remaining; i++) {
    177         __ push(r9);
    178       }
    179     }
    180   }
    181 
    182   bool function_in_register_r1 = true;
    183 
    184   // Possibly allocate a local context.
    185   if (info->scope()->NeedsContext()) {
    186     // Argument to NewContext is the function, which is still in r1.
    187     Comment cmnt(masm_, "[ Allocate context");
    188     bool need_write_barrier = true;
    189     int slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
    190     if (info->scope()->is_script_scope()) {
    191       __ push(r1);
    192       __ Push(info->scope()->scope_info());
    193       __ CallRuntime(Runtime::kNewScriptContext);
    194       PrepareForBailoutForId(BailoutId::ScriptContext(),
    195                              BailoutState::TOS_REGISTER);
    196       // The new target value is not used, clobbering is safe.
    197       DCHECK_NULL(info->scope()->new_target_var());
    198     } else {
    199       if (info->scope()->new_target_var() != nullptr) {
    200         __ push(r3);  // Preserve new target.
    201       }
    202       if (slots <=
    203           ConstructorBuiltinsAssembler::MaximumFunctionContextSlots()) {
    204         Callable callable = CodeFactory::FastNewFunctionContext(
    205             isolate(), info->scope()->scope_type());
    206         __ mov(FastNewFunctionContextDescriptor::SlotsRegister(),
    207                Operand(slots));
    208         __ Call(callable.code(), RelocInfo::CODE_TARGET);
    209         // Result of the FastNewFunctionContext builtin is always in new space.
    210         need_write_barrier = false;
    211       } else {
    212         __ push(r1);
    213         __ Push(Smi::FromInt(info->scope()->scope_type()));
    214         __ CallRuntime(Runtime::kNewFunctionContext);
    215       }
    216       if (info->scope()->new_target_var() != nullptr) {
    217         __ pop(r3);  // Preserve new target.
    218       }
    219     }
    220     function_in_register_r1 = false;
    221     // Context is returned in r0.  It replaces the context passed to us.
    222     // It's saved in the stack and kept live in cp.
    223     __ mov(cp, r0);
    224     __ str(r0, MemOperand(fp, StandardFrameConstants::kContextOffset));
    225     // Copy any necessary parameters into the context.
    226     int num_parameters = info->scope()->num_parameters();
    227     int first_parameter = info->scope()->has_this_declaration() ? -1 : 0;
    228     for (int i = first_parameter; i < num_parameters; i++) {
    229       Variable* var =
    230           (i == -1) ? info->scope()->receiver() : info->scope()->parameter(i);
    231       if (var->IsContextSlot()) {
    232         int parameter_offset = StandardFrameConstants::kCallerSPOffset +
    233             (num_parameters - 1 - i) * kPointerSize;
    234         // Load parameter from stack.
    235         __ ldr(r0, MemOperand(fp, parameter_offset));
    236         // Store it in the context.
    237         MemOperand target = ContextMemOperand(cp, var->index());
    238         __ str(r0, target);
    239 
    240         // Update the write barrier.
    241         if (need_write_barrier) {
    242           __ RecordWriteContextSlot(cp, target.offset(), r0, r2,
    243                                     kLRHasBeenSaved, kDontSaveFPRegs);
    244         } else if (FLAG_debug_code) {
    245           Label done;
    246           __ JumpIfInNewSpace(cp, r0, &done);
    247           __ Abort(kExpectedNewSpaceObject);
    248           __ bind(&done);
    249         }
    250       }
    251     }
    252   }
    253 
    254   // Register holding this function and new target are both trashed in case we
    255   // bailout here. But since that can happen only when new target is not used
    256   // and we allocate a context, the value of |function_in_register| is correct.
    257   PrepareForBailoutForId(BailoutId::FunctionContext(),
    258                          BailoutState::NO_REGISTERS);
    259 
    260   // We don't support new.target and rest parameters here.
    261   DCHECK_NULL(info->scope()->new_target_var());
    262   DCHECK_NULL(info->scope()->rest_parameter());
    263   DCHECK_NULL(info->scope()->this_function_var());
    264 
    265   Variable* arguments = info->scope()->arguments();
    266   if (arguments != NULL) {
    267     // Function uses arguments object.
    268     Comment cmnt(masm_, "[ Allocate arguments object");
    269     if (!function_in_register_r1) {
    270       // Load this again, if it's used by the local context below.
    271       __ ldr(r1, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
    272     }
    273     if (is_strict(language_mode()) || !has_simple_parameters()) {
    274       Callable callable = CodeFactory::FastNewStrictArguments(isolate());
    275       __ Call(callable.code(), RelocInfo::CODE_TARGET);
    276       RestoreContext();
    277     } else if (literal()->has_duplicate_parameters()) {
    278       __ Push(r1);
    279       __ CallRuntime(Runtime::kNewSloppyArguments_Generic);
    280     } else {
    281       Callable callable = CodeFactory::FastNewSloppyArguments(isolate());
    282       __ Call(callable.code(), RelocInfo::CODE_TARGET);
    283       RestoreContext();
    284     }
    285 
    286     SetVar(arguments, r0, r1, r2);
    287   }
    288 
    289   if (FLAG_trace) {
    290     __ CallRuntime(Runtime::kTraceEnter);
    291   }
    292 
    293   // Visit the declarations and body.
    294   PrepareForBailoutForId(BailoutId::FunctionEntry(),
    295                          BailoutState::NO_REGISTERS);
    296   {
    297     Comment cmnt(masm_, "[ Declarations");
    298     VisitDeclarations(scope()->declarations());
    299   }
    300 
    301   // Assert that the declarations do not use ICs. Otherwise the debugger
    302   // won't be able to redirect a PC at an IC to the correct IC in newly
    303   // recompiled code.
    304   DCHECK_EQ(0, ic_total_count_);
    305 
    306   {
    307     Comment cmnt(masm_, "[ Stack check");
    308     PrepareForBailoutForId(BailoutId::Declarations(),
    309                            BailoutState::NO_REGISTERS);
    310     Label ok;
    311     __ LoadRoot(ip, Heap::kStackLimitRootIndex);
    312     __ cmp(sp, Operand(ip));
    313     __ b(hs, &ok);
    314     Handle<Code> stack_check = isolate()->builtins()->StackCheck();
    315     PredictableCodeSizeScope predictable(masm_);
    316     predictable.ExpectSize(
    317         masm_->CallSize(stack_check, RelocInfo::CODE_TARGET));
    318     __ Call(stack_check, RelocInfo::CODE_TARGET);
    319     __ bind(&ok);
    320   }
    321 
    322   {
    323     Comment cmnt(masm_, "[ Body");
    324     DCHECK(loop_depth() == 0);
    325     VisitStatements(literal()->body());
    326     DCHECK(loop_depth() == 0);
    327   }
    328 
    329   // Always emit a 'return undefined' in case control fell off the end of
    330   // the body.
    331   { Comment cmnt(masm_, "[ return <undefined>;");
    332     __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
    333   }
    334   EmitReturnSequence();
    335 
    336   // Force emit the constant pool, so it doesn't get emitted in the middle
    337   // of the back edge table.
    338   masm()->CheckConstPool(true, false);
    339 }
    340 
    341 void FullCodeGenerator::ClearAccumulator() { __ mov(r0, Operand(Smi::kZero)); }
    342 
    343 void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
    344   __ mov(r2, Operand(profiling_counter_));
    345   __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
    346   __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC);
    347   __ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
    348 }
    349 
    350 
    351 #ifdef CAN_USE_ARMV7_INSTRUCTIONS
    352 static const int kProfileCounterResetSequenceLength = 5 * Assembler::kInstrSize;
    353 #else
    354 static const int kProfileCounterResetSequenceLength = 7 * Assembler::kInstrSize;
    355 #endif
    356 
    357 
    358 void FullCodeGenerator::EmitProfilingCounterReset() {
    359   Assembler::BlockConstPoolScope block_const_pool(masm_);
    360   PredictableCodeSizeScope predictable_code_size_scope(
    361       masm_, kProfileCounterResetSequenceLength);
    362   Label start;
    363   __ bind(&start);
    364   int reset_value = FLAG_interrupt_budget;
    365   __ mov(r2, Operand(profiling_counter_));
    366   // The mov instruction above can be either 1 to 3 (for ARMv7) or 1 to 5
    367   // instructions (for ARMv6) depending upon whether it is an extended constant
    368   // pool - insert nop to compensate.
    369   int expected_instr_count =
    370       (kProfileCounterResetSequenceLength / Assembler::kInstrSize) - 2;
    371   DCHECK(masm_->InstructionsGeneratedSince(&start) <= expected_instr_count);
    372   while (masm_->InstructionsGeneratedSince(&start) != expected_instr_count) {
    373     __ nop();
    374   }
    375   __ mov(r3, Operand(Smi::FromInt(reset_value)));
    376   __ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
    377 }
    378 
    379 
    380 void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
    381                                                 Label* back_edge_target) {
    382   Comment cmnt(masm_, "[ Back edge bookkeeping");
    383   // Block literal pools whilst emitting back edge code.
    384   Assembler::BlockConstPoolScope block_const_pool(masm_);
    385   Label ok;
    386 
    387   DCHECK(back_edge_target->is_bound());
    388   int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
    389   int weight = Min(kMaxBackEdgeWeight,
    390                    Max(1, distance / kCodeSizeMultiplier));
    391   EmitProfilingCounterDecrement(weight);
    392   __ b(pl, &ok);
    393   __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
    394 
    395   // Record a mapping of this PC offset to the OSR id.  This is used to find
    396   // the AST id from the unoptimized code in order to use it as a key into
    397   // the deoptimization input data found in the optimized code.
    398   RecordBackEdge(stmt->OsrEntryId());
    399 
    400   EmitProfilingCounterReset();
    401 
    402   __ bind(&ok);
    403   PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
    404   // Record a mapping of the OSR id to this PC.  This is used if the OSR
    405   // entry becomes the target of a bailout.  We don't expect it to be, but
    406   // we want it to work if it is.
    407   PrepareForBailoutForId(stmt->OsrEntryId(), BailoutState::NO_REGISTERS);
    408 }
    409 
    410 void FullCodeGenerator::EmitProfilingCounterHandlingForReturnSequence(
    411     bool is_tail_call) {
    412   // Pretend that the exit is a backwards jump to the entry.
    413   int weight = 1;
    414   if (info_->ShouldSelfOptimize()) {
    415     weight = FLAG_interrupt_budget / FLAG_self_opt_count;
    416   } else {
    417     int distance = masm_->pc_offset();
    418     weight = Min(kMaxBackEdgeWeight, Max(1, distance / kCodeSizeMultiplier));
    419   }
    420   EmitProfilingCounterDecrement(weight);
    421   Label ok;
    422   __ b(pl, &ok);
    423   // Don't need to save result register if we are going to do a tail call.
    424   if (!is_tail_call) {
    425     __ push(r0);
    426   }
    427   __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
    428   if (!is_tail_call) {
    429     __ pop(r0);
    430   }
    431   EmitProfilingCounterReset();
    432   __ bind(&ok);
    433 }
    434 
    435 void FullCodeGenerator::EmitReturnSequence() {
    436   Comment cmnt(masm_, "[ Return sequence");
    437   if (return_label_.is_bound()) {
    438     __ b(&return_label_);
    439   } else {
    440     __ bind(&return_label_);
    441     if (FLAG_trace) {
    442       // Push the return value on the stack as the parameter.
    443       // Runtime::TraceExit returns its parameter in r0.
    444       __ push(r0);
    445       __ CallRuntime(Runtime::kTraceExit);
    446     }
    447     EmitProfilingCounterHandlingForReturnSequence(false);
    448 
    449     // Make sure that the constant pool is not emitted inside of the return
    450     // sequence.
    451     { Assembler::BlockConstPoolScope block_const_pool(masm_);
    452       int32_t arg_count = info_->scope()->num_parameters() + 1;
    453       int32_t sp_delta = arg_count * kPointerSize;
    454       SetReturnPosition(literal());
    455       // TODO(svenpanne) The code below is sometimes 4 words, sometimes 5!
    456       PredictableCodeSizeScope predictable(masm_, -1);
    457       __ LeaveFrame(StackFrame::JAVA_SCRIPT);
    458       { ConstantPoolUnavailableScope constant_pool_unavailable(masm_);
    459         __ add(sp, sp, Operand(sp_delta));
    460         __ Jump(lr);
    461       }
    462     }
    463   }
    464 }
    465 
    466 void FullCodeGenerator::RestoreContext() {
    467   __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
    468 }
    469 
    470 void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
    471   DCHECK(var->IsStackAllocated() || var->IsContextSlot());
    472   codegen()->GetVar(result_register(), var);
    473   codegen()->PushOperand(result_register());
    474 }
    475 
    476 
    477 void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
    478 }
    479 
    480 
    481 void FullCodeGenerator::AccumulatorValueContext::Plug(
    482     Heap::RootListIndex index) const {
    483   __ LoadRoot(result_register(), index);
    484 }
    485 
    486 
    487 void FullCodeGenerator::StackValueContext::Plug(
    488     Heap::RootListIndex index) const {
    489   __ LoadRoot(result_register(), index);
    490   codegen()->PushOperand(result_register());
    491 }
    492 
    493 
    494 void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
    495   codegen()->PrepareForBailoutBeforeSplit(condition(),
    496                                           true,
    497                                           true_label_,
    498                                           false_label_);
    499   if (index == Heap::kUndefinedValueRootIndex ||
    500       index == Heap::kNullValueRootIndex ||
    501       index == Heap::kFalseValueRootIndex) {
    502     if (false_label_ != fall_through_) __ b(false_label_);
    503   } else if (index == Heap::kTrueValueRootIndex) {
    504     if (true_label_ != fall_through_) __ b(true_label_);
    505   } else {
    506     __ LoadRoot(result_register(), index);
    507     codegen()->DoTest(this);
    508   }
    509 }
    510 
    511 
    512 void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
    513 }
    514 
    515 
    516 void FullCodeGenerator::AccumulatorValueContext::Plug(
    517     Handle<Object> lit) const {
    518   __ mov(result_register(), Operand(lit));
    519 }
    520 
    521 
    522 void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
    523   // Immediates cannot be pushed directly.
    524   __ mov(result_register(), Operand(lit));
    525   codegen()->PushOperand(result_register());
    526 }
    527 
    528 
    529 void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
    530   codegen()->PrepareForBailoutBeforeSplit(condition(),
    531                                           true,
    532                                           true_label_,
    533                                           false_label_);
    534   DCHECK(lit->IsNullOrUndefined(isolate()) || !lit->IsUndetectable());
    535   if (lit->IsNullOrUndefined(isolate()) || lit->IsFalse(isolate())) {
    536     if (false_label_ != fall_through_) __ b(false_label_);
    537   } else if (lit->IsTrue(isolate()) || lit->IsJSObject()) {
    538     if (true_label_ != fall_through_) __ b(true_label_);
    539   } else if (lit->IsString()) {
    540     if (String::cast(*lit)->length() == 0) {
    541       if (false_label_ != fall_through_) __ b(false_label_);
    542     } else {
    543       if (true_label_ != fall_through_) __ b(true_label_);
    544     }
    545   } else if (lit->IsSmi()) {
    546     if (Smi::cast(*lit)->value() == 0) {
    547       if (false_label_ != fall_through_) __ b(false_label_);
    548     } else {
    549       if (true_label_ != fall_through_) __ b(true_label_);
    550     }
    551   } else {
    552     // For simplicity we always test the accumulator register.
    553     __ mov(result_register(), Operand(lit));
    554     codegen()->DoTest(this);
    555   }
    556 }
    557 
    558 
    559 void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
    560                                                        Register reg) const {
    561   DCHECK(count > 0);
    562   if (count > 1) codegen()->DropOperands(count - 1);
    563   __ str(reg, MemOperand(sp, 0));
    564 }
    565 
    566 
    567 void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
    568                                             Label* materialize_false) const {
    569   DCHECK(materialize_true == materialize_false);
    570   __ bind(materialize_true);
    571 }
    572 
    573 
    574 void FullCodeGenerator::AccumulatorValueContext::Plug(
    575     Label* materialize_true,
    576     Label* materialize_false) const {
    577   Label done;
    578   __ bind(materialize_true);
    579   __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
    580   __ jmp(&done);
    581   __ bind(materialize_false);
    582   __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
    583   __ bind(&done);
    584 }
    585 
    586 
    587 void FullCodeGenerator::StackValueContext::Plug(
    588     Label* materialize_true,
    589     Label* materialize_false) const {
    590   Label done;
    591   __ bind(materialize_true);
    592   __ LoadRoot(ip, Heap::kTrueValueRootIndex);
    593   __ jmp(&done);
    594   __ bind(materialize_false);
    595   __ LoadRoot(ip, Heap::kFalseValueRootIndex);
    596   __ bind(&done);
    597   codegen()->PushOperand(ip);
    598 }
    599 
    600 
    601 void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
    602                                           Label* materialize_false) const {
    603   DCHECK(materialize_true == true_label_);
    604   DCHECK(materialize_false == false_label_);
    605 }
    606 
    607 
    608 void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
    609   Heap::RootListIndex value_root_index =
    610       flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
    611   __ LoadRoot(result_register(), value_root_index);
    612 }
    613 
    614 
    615 void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
    616   Heap::RootListIndex value_root_index =
    617       flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
    618   __ LoadRoot(ip, value_root_index);
    619   codegen()->PushOperand(ip);
    620 }
    621 
    622 
    623 void FullCodeGenerator::TestContext::Plug(bool flag) const {
    624   codegen()->PrepareForBailoutBeforeSplit(condition(),
    625                                           true,
    626                                           true_label_,
    627                                           false_label_);
    628   if (flag) {
    629     if (true_label_ != fall_through_) __ b(true_label_);
    630   } else {
    631     if (false_label_ != fall_through_) __ b(false_label_);
    632   }
    633 }
    634 
    635 
    636 void FullCodeGenerator::DoTest(Expression* condition,
    637                                Label* if_true,
    638                                Label* if_false,
    639                                Label* fall_through) {
    640   Handle<Code> ic = ToBooleanICStub::GetUninitialized(isolate());
    641   CallIC(ic, condition->test_id());
    642   __ CompareRoot(result_register(), Heap::kTrueValueRootIndex);
    643   Split(eq, if_true, if_false, fall_through);
    644 }
    645 
    646 
    647 void FullCodeGenerator::Split(Condition cond,
    648                               Label* if_true,
    649                               Label* if_false,
    650                               Label* fall_through) {
    651   if (if_false == fall_through) {
    652     __ b(cond, if_true);
    653   } else if (if_true == fall_through) {
    654     __ b(NegateCondition(cond), if_false);
    655   } else {
    656     __ b(cond, if_true);
    657     __ b(if_false);
    658   }
    659 }
    660 
    661 
    662 MemOperand FullCodeGenerator::StackOperand(Variable* var) {
    663   DCHECK(var->IsStackAllocated());
    664   // Offset is negative because higher indexes are at lower addresses.
    665   int offset = -var->index() * kPointerSize;
    666   // Adjust by a (parameter or local) base offset.
    667   if (var->IsParameter()) {
    668     offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
    669   } else {
    670     offset += JavaScriptFrameConstants::kLocal0Offset;
    671   }
    672   return MemOperand(fp, offset);
    673 }
    674 
    675 
    676 MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
    677   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
    678   if (var->IsContextSlot()) {
    679     int context_chain_length = scope()->ContextChainLength(var->scope());
    680     __ LoadContext(scratch, context_chain_length);
    681     return ContextMemOperand(scratch, var->index());
    682   } else {
    683     return StackOperand(var);
    684   }
    685 }
    686 
    687 
    688 void FullCodeGenerator::GetVar(Register dest, Variable* var) {
    689   // Use destination as scratch.
    690   MemOperand location = VarOperand(var, dest);
    691   __ ldr(dest, location);
    692 }
    693 
    694 
    695 void FullCodeGenerator::SetVar(Variable* var,
    696                                Register src,
    697                                Register scratch0,
    698                                Register scratch1) {
    699   DCHECK(var->IsContextSlot() || var->IsStackAllocated());
    700   DCHECK(!scratch0.is(src));
    701   DCHECK(!scratch0.is(scratch1));
    702   DCHECK(!scratch1.is(src));
    703   MemOperand location = VarOperand(var, scratch0);
    704   __ str(src, location);
    705 
    706   // Emit the write barrier code if the location is in the heap.
    707   if (var->IsContextSlot()) {
    708     __ RecordWriteContextSlot(scratch0,
    709                               location.offset(),
    710                               src,
    711                               scratch1,
    712                               kLRHasBeenSaved,
    713                               kDontSaveFPRegs);
    714   }
    715 }
    716 
    717 
    718 void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
    719                                                      bool should_normalize,
    720                                                      Label* if_true,
    721                                                      Label* if_false) {
    722   // Only prepare for bailouts before splits if we're in a test
    723   // context. Otherwise, we let the Visit function deal with the
    724   // preparation to avoid preparing with the same AST id twice.
    725   if (!context()->IsTest()) return;
    726 
    727   Label skip;
    728   if (should_normalize) __ b(&skip);
    729   PrepareForBailout(expr, BailoutState::TOS_REGISTER);
    730   if (should_normalize) {
    731     __ LoadRoot(ip, Heap::kTrueValueRootIndex);
    732     __ cmp(r0, ip);
    733     Split(eq, if_true, if_false, NULL);
    734     __ bind(&skip);
    735   }
    736 }
    737 
    738 
    739 void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
    740   // The variable in the declaration always resides in the current function
    741   // context.
    742   DCHECK_EQ(0, scope()->ContextChainLength(variable->scope()));
    743   if (FLAG_debug_code) {
    744     // Check that we're not inside a with or catch context.
    745     __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
    746     __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
    747     __ Check(ne, kDeclarationInWithContext);
    748     __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
    749     __ Check(ne, kDeclarationInCatchContext);
    750   }
    751 }
    752 
    753 
    754 void FullCodeGenerator::VisitVariableDeclaration(
    755     VariableDeclaration* declaration) {
    756   VariableProxy* proxy = declaration->proxy();
    757   Variable* variable = proxy->var();
    758   switch (variable->location()) {
    759     case VariableLocation::UNALLOCATED: {
    760       DCHECK(!variable->binding_needs_init());
    761       globals_->Add(variable->name(), zone());
    762       FeedbackSlot slot = proxy->VariableFeedbackSlot();
    763       DCHECK(!slot.IsInvalid());
    764       globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
    765       globals_->Add(isolate()->factory()->undefined_value(), zone());
    766       globals_->Add(isolate()->factory()->undefined_value(), zone());
    767       break;
    768     }
    769     case VariableLocation::PARAMETER:
    770     case VariableLocation::LOCAL:
    771       if (variable->binding_needs_init()) {
    772         Comment cmnt(masm_, "[ VariableDeclaration");
    773         __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
    774         __ str(r0, StackOperand(variable));
    775       }
    776       break;
    777 
    778     case VariableLocation::CONTEXT:
    779       if (variable->binding_needs_init()) {
    780         Comment cmnt(masm_, "[ VariableDeclaration");
    781         EmitDebugCheckDeclarationContext(variable);
    782         __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
    783         __ str(r0, ContextMemOperand(cp, variable->index()));
    784         // No write barrier since the_hole_value is in old space.
    785         PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
    786       }
    787       break;
    788 
    789     case VariableLocation::LOOKUP:
    790     case VariableLocation::MODULE:
    791       UNREACHABLE();
    792   }
    793 }
    794 
    795 
    796 void FullCodeGenerator::VisitFunctionDeclaration(
    797     FunctionDeclaration* declaration) {
    798   VariableProxy* proxy = declaration->proxy();
    799   Variable* variable = proxy->var();
    800   switch (variable->location()) {
    801     case VariableLocation::UNALLOCATED: {
    802       globals_->Add(variable->name(), zone());
    803       FeedbackSlot slot = proxy->VariableFeedbackSlot();
    804       DCHECK(!slot.IsInvalid());
    805       globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
    806 
    807       // We need the slot where the literals array lives, too.
    808       slot = declaration->fun()->LiteralFeedbackSlot();
    809       DCHECK(!slot.IsInvalid());
    810       globals_->Add(handle(Smi::FromInt(slot.ToInt()), isolate()), zone());
    811 
    812       Handle<SharedFunctionInfo> function =
    813           Compiler::GetSharedFunctionInfo(declaration->fun(), script(), info_);
    814       // Check for stack-overflow exception.
    815       if (function.is_null()) return SetStackOverflow();
    816       globals_->Add(function, zone());
    817       break;
    818     }
    819 
    820     case VariableLocation::PARAMETER:
    821     case VariableLocation::LOCAL: {
    822       Comment cmnt(masm_, "[ FunctionDeclaration");
    823       VisitForAccumulatorValue(declaration->fun());
    824       __ str(result_register(), StackOperand(variable));
    825       break;
    826     }
    827 
    828     case VariableLocation::CONTEXT: {
    829       Comment cmnt(masm_, "[ FunctionDeclaration");
    830       EmitDebugCheckDeclarationContext(variable);
    831       VisitForAccumulatorValue(declaration->fun());
    832       __ str(result_register(), ContextMemOperand(cp, variable->index()));
    833       int offset = Context::SlotOffset(variable->index());
    834       // We know that we have written a function, which is not a smi.
    835       __ RecordWriteContextSlot(cp,
    836                                 offset,
    837                                 result_register(),
    838                                 r2,
    839                                 kLRHasBeenSaved,
    840                                 kDontSaveFPRegs,
    841                                 EMIT_REMEMBERED_SET,
    842                                 OMIT_SMI_CHECK);
    843       PrepareForBailoutForId(proxy->id(), BailoutState::NO_REGISTERS);
    844       break;
    845     }
    846 
    847     case VariableLocation::LOOKUP:
    848     case VariableLocation::MODULE:
    849       UNREACHABLE();
    850   }
    851 }
    852 
    853 
    854 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
    855   // Call the runtime to declare the globals.
    856   __ mov(r1, Operand(pairs));
    857   __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
    858   __ EmitLoadFeedbackVector(r2);
    859   __ Push(r1, r0, r2);
    860   __ CallRuntime(Runtime::kDeclareGlobals);
    861   // Return value is ignored.
    862 }
    863 
    864 
    865 void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
    866   Comment cmnt(masm_, "[ SwitchStatement");
    867   Breakable nested_statement(this, stmt);
    868   SetStatementPosition(stmt);
    869 
    870   // Keep the switch value on the stack until a case matches.
    871   VisitForStackValue(stmt->tag());
    872   PrepareForBailoutForId(stmt->EntryId(), BailoutState::NO_REGISTERS);
    873 
    874   ZoneList<CaseClause*>* clauses = stmt->cases();
    875   CaseClause* default_clause = NULL;  // Can occur anywhere in the list.
    876 
    877   Label next_test;  // Recycled for each test.
    878   // Compile all the tests with branches to their bodies.
    879   for (int i = 0; i < clauses->length(); i++) {
    880     CaseClause* clause = clauses->at(i);
    881     clause->body_target()->Unuse();
    882 
    883     // The default is not a test, but remember it as final fall through.
    884     if (clause->is_default()) {
    885       default_clause = clause;
    886       continue;
    887     }
    888 
    889     Comment cmnt(masm_, "[ Case comparison");
    890     __ bind(&next_test);
    891     next_test.Unuse();
    892 
    893     // Compile the label expression.
    894     VisitForAccumulatorValue(clause->label());
    895 
    896     // Perform the comparison as if via '==='.
    897     __ ldr(r1, MemOperand(sp, 0));  // Switch value.
    898     bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
    899     JumpPatchSite patch_site(masm_);
    900     if (inline_smi_code) {
    901       Label slow_case;
    902       __ orr(r2, r1, r0);
    903       patch_site.EmitJumpIfNotSmi(r2, &slow_case);
    904 
    905       __ cmp(r1, r0);
    906       __ b(ne, &next_test);
    907       __ Drop(1);  // Switch value is no longer needed.
    908       __ b(clause->body_target());
    909       __ bind(&slow_case);
    910     }
    911 
    912     // Record position before stub call for type feedback.
    913     SetExpressionPosition(clause);
    914     Handle<Code> ic =
    915         CodeFactory::CompareIC(isolate(), Token::EQ_STRICT).code();
    916     CallIC(ic, clause->CompareId());
    917     patch_site.EmitPatchInfo();
    918 
    919     Label skip;
    920     __ b(&skip);
    921     PrepareForBailout(clause, BailoutState::TOS_REGISTER);
    922     __ LoadRoot(ip, Heap::kTrueValueRootIndex);
    923     __ cmp(r0, ip);
    924     __ b(ne, &next_test);
    925     __ Drop(1);
    926     __ jmp(clause->body_target());
    927     __ bind(&skip);
    928 
    929     __ cmp(r0, Operand::Zero());
    930     __ b(ne, &next_test);
    931     __ Drop(1);  // Switch value is no longer needed.
    932     __ b(clause->body_target());
    933   }
    934 
    935   // Discard the test value and jump to the default if present, otherwise to
    936   // the end of the statement.
    937   __ bind(&next_test);
    938   DropOperands(1);  // Switch value is no longer needed.
    939   if (default_clause == NULL) {
    940     __ b(nested_statement.break_label());
    941   } else {
    942     __ b(default_clause->body_target());
    943   }
    944 
    945   // Compile all the case bodies.
    946   for (int i = 0; i < clauses->length(); i++) {
    947     Comment cmnt(masm_, "[ Case body");
    948     CaseClause* clause = clauses->at(i);
    949     __ bind(clause->body_target());
    950     PrepareForBailoutForId(clause->EntryId(), BailoutState::NO_REGISTERS);
    951     VisitStatements(clause->statements());
    952   }
    953 
    954   __ bind(nested_statement.break_label());
    955   PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
    956 }
    957 
    958 
    959 void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
    960   Comment cmnt(masm_, "[ ForInStatement");
    961   SetStatementPosition(stmt, SKIP_BREAK);
    962 
    963   FeedbackSlot slot = stmt->ForInFeedbackSlot();
    964 
    965   // Get the object to enumerate over.
    966   SetExpressionAsStatementPosition(stmt->enumerable());
    967   VisitForAccumulatorValue(stmt->enumerable());
    968   OperandStackDepthIncrement(5);
    969 
    970   Label loop, exit;
    971   Iteration loop_statement(this, stmt);
    972   increment_loop_depth();
    973 
    974   // If the object is null or undefined, skip over the loop, otherwise convert
    975   // it to a JS receiver.  See ECMA-262 version 5, section 12.6.4.
    976   Label convert, done_convert;
    977   __ JumpIfSmi(r0, &convert);
    978   __ CompareObjectType(r0, r1, r1, FIRST_JS_RECEIVER_TYPE);
    979   __ b(ge, &done_convert);
    980   __ CompareRoot(r0, Heap::kNullValueRootIndex);
    981   __ b(eq, &exit);
    982   __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
    983   __ b(eq, &exit);
    984   __ bind(&convert);
    985   __ Call(isolate()->builtins()->ToObject(), RelocInfo::CODE_TARGET);
    986   RestoreContext();
    987   __ bind(&done_convert);
    988   PrepareForBailoutForId(stmt->ToObjectId(), BailoutState::TOS_REGISTER);
    989   __ push(r0);
    990 
    991   // Check cache validity in generated code. If we cannot guarantee cache
    992   // validity, call the runtime system to check cache validity or get the
    993   // property names in a fixed array. Note: Proxies never have an enum cache,
    994   // so will always take the slow path.
    995   Label call_runtime;
    996   __ CheckEnumCache(&call_runtime);
    997 
    998   // The enum cache is valid.  Load the map of the object being
    999   // iterated over and use the cache for the iteration.
   1000   Label use_cache;
   1001   __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
   1002   __ b(&use_cache);
   1003 
   1004   // Get the set of properties to enumerate.
   1005   __ bind(&call_runtime);
   1006   __ push(r0);  // Duplicate the enumerable object on the stack.
   1007   __ CallRuntime(Runtime::kForInEnumerate);
   1008   PrepareForBailoutForId(stmt->EnumId(), BailoutState::TOS_REGISTER);
   1009 
   1010   // If we got a map from the runtime call, we can do a fast
   1011   // modification check. Otherwise, we got a fixed array, and we have
   1012   // to do a slow check.
   1013   Label fixed_array;
   1014   __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
   1015   __ LoadRoot(ip, Heap::kMetaMapRootIndex);
   1016   __ cmp(r2, ip);
   1017   __ b(ne, &fixed_array);
   1018 
   1019   // We got a map in register r0. Get the enumeration cache from it.
   1020   Label no_descriptors;
   1021   __ bind(&use_cache);
   1022 
   1023   __ EnumLength(r1, r0);
   1024   __ cmp(r1, Operand(Smi::kZero));
   1025   __ b(eq, &no_descriptors);
   1026 
   1027   __ LoadInstanceDescriptors(r0, r2);
   1028   __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheOffset));
   1029   __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheBridgeCacheOffset));
   1030 
   1031   // Set up the four remaining stack slots.
   1032   __ push(r0);  // Map.
   1033   __ mov(r0, Operand(Smi::kZero));
   1034   // Push enumeration cache, enumeration cache length (as smi) and zero.
   1035   __ Push(r2, r1, r0);
   1036   __ jmp(&loop);
   1037 
   1038   __ bind(&no_descriptors);
   1039   __ Drop(1);
   1040   __ jmp(&exit);
   1041 
   1042   // We got a fixed array in register r0. Iterate through that.
   1043   __ bind(&fixed_array);
   1044 
   1045   __ mov(r1, Operand(Smi::FromInt(1)));  // Smi(1) indicates slow check
   1046   __ Push(r1, r0);  // Smi and array
   1047   __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset));
   1048   __ Push(r1);  // Fixed array length (as smi).
   1049   PrepareForBailoutForId(stmt->PrepareId(), BailoutState::NO_REGISTERS);
   1050   __ mov(r0, Operand(Smi::kZero));
   1051   __ Push(r0);  // Initial index.
   1052 
   1053   // Generate code for doing the condition check.
   1054   __ bind(&loop);
   1055   SetExpressionAsStatementPosition(stmt->each());
   1056 
   1057   // Load the current count to r0, load the length to r1.
   1058   __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
   1059   __ cmp(r0, r1);  // Compare to the array length.
   1060   __ b(hs, loop_statement.break_label());
   1061 
   1062   // Get the current entry of the array into register r0.
   1063   __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
   1064   __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   1065   __ ldr(r0, MemOperand::PointerAddressFromSmiKey(r2, r0));
   1066 
   1067   // Get the expected map from the stack or a smi in the
   1068   // permanent slow case into register r2.
   1069   __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
   1070 
   1071   // Check if the expected map still matches that of the enumerable.
   1072   // If not, we may have to filter the key.
   1073   Label update_each;
   1074   __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
   1075   __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
   1076   __ cmp(r4, Operand(r2));
   1077   __ b(eq, &update_each);
   1078 
   1079   // We need to filter the key, record slow-path here.
   1080   int const vector_index = SmiFromSlot(slot)->value();
   1081   __ EmitLoadFeedbackVector(r3);
   1082   __ mov(r2, Operand(FeedbackVector::MegamorphicSentinel(isolate())));
   1083   __ str(r2, FieldMemOperand(r3, FixedArray::OffsetOfElementAt(vector_index)));
   1084 
   1085   // r0 contains the key. The receiver in r1 is the second argument to the
   1086   // ForInFilter. ForInFilter returns undefined if the receiver doesn't
   1087   // have the key or returns the name-converted key.
   1088   __ Call(isolate()->builtins()->ForInFilter(), RelocInfo::CODE_TARGET);
   1089   RestoreContext();
   1090   PrepareForBailoutForId(stmt->FilterId(), BailoutState::TOS_REGISTER);
   1091   __ CompareRoot(result_register(), Heap::kUndefinedValueRootIndex);
   1092   __ b(eq, loop_statement.continue_label());
   1093 
   1094   // Update the 'each' property or variable from the possibly filtered
   1095   // entry in register r0.
   1096   __ bind(&update_each);
   1097 
   1098   // Perform the assignment as if via '='.
   1099   { EffectContext context(this);
   1100     EmitAssignment(stmt->each(), stmt->EachFeedbackSlot());
   1101     PrepareForBailoutForId(stmt->AssignmentId(), BailoutState::NO_REGISTERS);
   1102   }
   1103 
   1104   // Both Crankshaft and Turbofan expect BodyId to be right before stmt->body().
   1105   PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
   1106   // Generate code for the body of the loop.
   1107   Visit(stmt->body());
   1108 
   1109   // Generate code for the going to the next element by incrementing
   1110   // the index (smi) stored on top of the stack.
   1111   __ bind(loop_statement.continue_label());
   1112   PrepareForBailoutForId(stmt->IncrementId(), BailoutState::NO_REGISTERS);
   1113   __ pop(r0);
   1114   __ add(r0, r0, Operand(Smi::FromInt(1)));
   1115   __ push(r0);
   1116 
   1117   EmitBackEdgeBookkeeping(stmt, &loop);
   1118   __ b(&loop);
   1119 
   1120   // Remove the pointers stored on the stack.
   1121   __ bind(loop_statement.break_label());
   1122   DropOperands(5);
   1123 
   1124   // Exit and decrement the loop depth.
   1125   PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
   1126   __ bind(&exit);
   1127   decrement_loop_depth();
   1128 }
   1129 
   1130 void FullCodeGenerator::EmitSetHomeObject(Expression* initializer, int offset,
   1131                                           FeedbackSlot slot) {
   1132   DCHECK(NeedsHomeObject(initializer));
   1133   __ ldr(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
   1134   __ ldr(StoreDescriptor::ValueRegister(),
   1135          MemOperand(sp, offset * kPointerSize));
   1136   CallStoreIC(slot, isolate()->factory()->home_object_symbol());
   1137 }
   1138 
   1139 void FullCodeGenerator::EmitSetHomeObjectAccumulator(Expression* initializer,
   1140                                                      int offset,
   1141                                                      FeedbackSlot slot) {
   1142   DCHECK(NeedsHomeObject(initializer));
   1143   __ Move(StoreDescriptor::ReceiverRegister(), r0);
   1144   __ ldr(StoreDescriptor::ValueRegister(),
   1145          MemOperand(sp, offset * kPointerSize));
   1146   CallStoreIC(slot, isolate()->factory()->home_object_symbol());
   1147 }
   1148 
   1149 void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy,
   1150                                          TypeofMode typeof_mode) {
   1151   // Record position before possible IC call.
   1152   SetExpressionPosition(proxy);
   1153   PrepareForBailoutForId(proxy->BeforeId(), BailoutState::NO_REGISTERS);
   1154   Variable* var = proxy->var();
   1155 
   1156   // Two cases: global variables and all other types of variables.
   1157   switch (var->location()) {
   1158     case VariableLocation::UNALLOCATED: {
   1159       Comment cmnt(masm_, "[ Global variable");
   1160       EmitGlobalVariableLoad(proxy, typeof_mode);
   1161       context()->Plug(r0);
   1162       break;
   1163     }
   1164 
   1165     case VariableLocation::PARAMETER:
   1166     case VariableLocation::LOCAL:
   1167     case VariableLocation::CONTEXT: {
   1168       DCHECK_EQ(NOT_INSIDE_TYPEOF, typeof_mode);
   1169       Comment cmnt(masm_, var->IsContextSlot() ? "[ Context variable"
   1170                                                : "[ Stack variable");
   1171       if (proxy->hole_check_mode() == HoleCheckMode::kRequired) {
   1172         // Throw a reference error when using an uninitialized let/const
   1173         // binding in harmony mode.
   1174         Label done;
   1175         GetVar(r0, var);
   1176         __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
   1177         __ b(ne, &done);
   1178         __ mov(r0, Operand(var->name()));
   1179         __ push(r0);
   1180         __ CallRuntime(Runtime::kThrowReferenceError);
   1181         __ bind(&done);
   1182         context()->Plug(r0);
   1183         break;
   1184       }
   1185       context()->Plug(var);
   1186       break;
   1187     }
   1188 
   1189     case VariableLocation::LOOKUP:
   1190     case VariableLocation::MODULE:
   1191       UNREACHABLE();
   1192   }
   1193 }
   1194 
   1195 
   1196 void FullCodeGenerator::EmitAccessor(ObjectLiteralProperty* property) {
   1197   Expression* expression = (property == NULL) ? NULL : property->value();
   1198   if (expression == NULL) {
   1199     __ LoadRoot(r1, Heap::kNullValueRootIndex);
   1200     PushOperand(r1);
   1201   } else {
   1202     VisitForStackValue(expression);
   1203     if (NeedsHomeObject(expression)) {
   1204       DCHECK(property->kind() == ObjectLiteral::Property::GETTER ||
   1205              property->kind() == ObjectLiteral::Property::SETTER);
   1206       int offset = property->kind() == ObjectLiteral::Property::GETTER ? 2 : 3;
   1207       EmitSetHomeObject(expression, offset, property->GetSlot());
   1208     }
   1209   }
   1210 }
   1211 
   1212 
   1213 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
   1214   Comment cmnt(masm_, "[ ObjectLiteral");
   1215 
   1216   Handle<BoilerplateDescription> constant_properties =
   1217       expr->GetOrBuildConstantProperties(isolate());
   1218   __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   1219   __ mov(r2, Operand(SmiFromSlot(expr->literal_slot())));
   1220   __ mov(r1, Operand(constant_properties));
   1221   int flags = expr->ComputeFlags();
   1222   __ mov(r0, Operand(Smi::FromInt(flags)));
   1223   if (MustCreateObjectLiteralWithRuntime(expr)) {
   1224     __ Push(r3, r2, r1, r0);
   1225     __ CallRuntime(Runtime::kCreateObjectLiteral);
   1226   } else {
   1227     Callable callable = CodeFactory::FastCloneShallowObject(
   1228         isolate(), expr->properties_count());
   1229     __ Call(callable.code(), RelocInfo::CODE_TARGET);
   1230     RestoreContext();
   1231   }
   1232   PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
   1233 
   1234   // If result_saved is true the result is on top of the stack.  If
   1235   // result_saved is false the result is in r0.
   1236   bool result_saved = false;
   1237 
   1238   AccessorTable accessor_table(zone());
   1239   for (int i = 0; i < expr->properties()->length(); i++) {
   1240     ObjectLiteral::Property* property = expr->properties()->at(i);
   1241     DCHECK(!property->is_computed_name());
   1242     if (property->IsCompileTimeValue()) continue;
   1243 
   1244     Literal* key = property->key()->AsLiteral();
   1245     Expression* value = property->value();
   1246     if (!result_saved) {
   1247       PushOperand(r0);  // Save result on stack
   1248       result_saved = true;
   1249     }
   1250     switch (property->kind()) {
   1251       case ObjectLiteral::Property::SPREAD:
   1252       case ObjectLiteral::Property::CONSTANT:
   1253         UNREACHABLE();
   1254       case ObjectLiteral::Property::MATERIALIZED_LITERAL:
   1255         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
   1256         // Fall through.
   1257       case ObjectLiteral::Property::COMPUTED:
   1258         // It is safe to use [[Put]] here because the boilerplate already
   1259         // contains computed properties with an uninitialized value.
   1260         if (key->IsStringLiteral()) {
   1261           DCHECK(key->IsPropertyName());
   1262           if (property->emit_store()) {
   1263             VisitForAccumulatorValue(value);
   1264             DCHECK(StoreDescriptor::ValueRegister().is(r0));
   1265             __ ldr(StoreDescriptor::ReceiverRegister(), MemOperand(sp));
   1266             CallStoreIC(property->GetSlot(0), key->value(), true);
   1267             PrepareForBailoutForId(key->id(), BailoutState::NO_REGISTERS);
   1268 
   1269             if (NeedsHomeObject(value)) {
   1270               EmitSetHomeObjectAccumulator(value, 0, property->GetSlot(1));
   1271             }
   1272           } else {
   1273             VisitForEffect(value);
   1274           }
   1275           break;
   1276         }
   1277         // Duplicate receiver on stack.
   1278         __ ldr(r0, MemOperand(sp));
   1279         PushOperand(r0);
   1280         VisitForStackValue(key);
   1281         VisitForStackValue(value);
   1282         if (property->emit_store()) {
   1283           if (NeedsHomeObject(value)) {
   1284             EmitSetHomeObject(value, 2, property->GetSlot());
   1285           }
   1286           __ mov(r0, Operand(Smi::FromInt(SLOPPY)));  // PropertyAttributes
   1287           PushOperand(r0);
   1288           CallRuntimeWithOperands(Runtime::kSetProperty);
   1289         } else {
   1290           DropOperands(3);
   1291         }
   1292         break;
   1293       case ObjectLiteral::Property::PROTOTYPE:
   1294         // Duplicate receiver on stack.
   1295         __ ldr(r0, MemOperand(sp));
   1296         PushOperand(r0);
   1297         VisitForStackValue(value);
   1298         DCHECK(property->emit_store());
   1299         CallRuntimeWithOperands(Runtime::kInternalSetPrototype);
   1300         PrepareForBailoutForId(expr->GetIdForPropertySet(i),
   1301                                BailoutState::NO_REGISTERS);
   1302         break;
   1303 
   1304       case ObjectLiteral::Property::GETTER:
   1305         if (property->emit_store()) {
   1306           AccessorTable::Iterator it = accessor_table.lookup(key);
   1307           it->second->bailout_id = expr->GetIdForPropertySet(i);
   1308           it->second->getter = property;
   1309         }
   1310         break;
   1311       case ObjectLiteral::Property::SETTER:
   1312         if (property->emit_store()) {
   1313           AccessorTable::Iterator it = accessor_table.lookup(key);
   1314           it->second->bailout_id = expr->GetIdForPropertySet(i);
   1315           it->second->setter = property;
   1316         }
   1317         break;
   1318     }
   1319   }
   1320 
   1321   // Emit code to define accessors, using only a single call to the runtime for
   1322   // each pair of corresponding getters and setters.
   1323   for (AccessorTable::Iterator it = accessor_table.begin();
   1324        it != accessor_table.end();
   1325        ++it) {
   1326     __ ldr(r0, MemOperand(sp));  // Duplicate receiver.
   1327     PushOperand(r0);
   1328     VisitForStackValue(it->first);
   1329     EmitAccessor(it->second->getter);
   1330     EmitAccessor(it->second->setter);
   1331     __ mov(r0, Operand(Smi::FromInt(NONE)));
   1332     PushOperand(r0);
   1333     CallRuntimeWithOperands(Runtime::kDefineAccessorPropertyUnchecked);
   1334     PrepareForBailoutForId(it->second->bailout_id, BailoutState::NO_REGISTERS);
   1335   }
   1336 
   1337   if (result_saved) {
   1338     context()->PlugTOS();
   1339   } else {
   1340     context()->Plug(r0);
   1341   }
   1342 }
   1343 
   1344 
   1345 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
   1346   Comment cmnt(masm_, "[ ArrayLiteral");
   1347 
   1348   Handle<ConstantElementsPair> constant_elements =
   1349       expr->GetOrBuildConstantElements(isolate());
   1350 
   1351   __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   1352   __ mov(r2, Operand(SmiFromSlot(expr->literal_slot())));
   1353   __ mov(r1, Operand(constant_elements));
   1354   if (MustCreateArrayLiteralWithRuntime(expr)) {
   1355     __ mov(r0, Operand(Smi::FromInt(expr->ComputeFlags())));
   1356     __ Push(r3, r2, r1, r0);
   1357     __ CallRuntime(Runtime::kCreateArrayLiteral);
   1358   } else {
   1359     Callable callable =
   1360         CodeFactory::FastCloneShallowArray(isolate(), TRACK_ALLOCATION_SITE);
   1361     __ Call(callable.code(), RelocInfo::CODE_TARGET);
   1362     RestoreContext();
   1363   }
   1364   PrepareForBailoutForId(expr->CreateLiteralId(), BailoutState::TOS_REGISTER);
   1365 
   1366   bool result_saved = false;  // Is the result saved to the stack?
   1367   ZoneList<Expression*>* subexprs = expr->values();
   1368   int length = subexprs->length();
   1369 
   1370   // Emit code to evaluate all the non-constant subexpressions and to store
   1371   // them into the newly cloned array.
   1372   for (int array_index = 0; array_index < length; array_index++) {
   1373     Expression* subexpr = subexprs->at(array_index);
   1374     DCHECK(!subexpr->IsSpread());
   1375 
   1376     // If the subexpression is a literal or a simple materialized literal it
   1377     // is already set in the cloned array.
   1378     if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
   1379 
   1380     if (!result_saved) {
   1381       PushOperand(r0);
   1382       result_saved = true;
   1383     }
   1384     VisitForAccumulatorValue(subexpr);
   1385 
   1386     __ mov(StoreDescriptor::NameRegister(), Operand(Smi::FromInt(array_index)));
   1387     __ ldr(StoreDescriptor::ReceiverRegister(), MemOperand(sp, 0));
   1388     CallKeyedStoreIC(expr->LiteralFeedbackSlot());
   1389 
   1390     PrepareForBailoutForId(expr->GetIdForElement(array_index),
   1391                            BailoutState::NO_REGISTERS);
   1392   }
   1393 
   1394   if (result_saved) {
   1395     context()->PlugTOS();
   1396   } else {
   1397     context()->Plug(r0);
   1398   }
   1399 }
   1400 
   1401 
   1402 void FullCodeGenerator::VisitAssignment(Assignment* expr) {
   1403   DCHECK(expr->target()->IsValidReferenceExpressionOrThis());
   1404 
   1405   Comment cmnt(masm_, "[ Assignment");
   1406 
   1407   Property* property = expr->target()->AsProperty();
   1408   LhsKind assign_type = Property::GetAssignType(property);
   1409 
   1410   // Evaluate LHS expression.
   1411   switch (assign_type) {
   1412     case VARIABLE:
   1413       // Nothing to do here.
   1414       break;
   1415     case NAMED_PROPERTY:
   1416       if (expr->is_compound()) {
   1417         // We need the receiver both on the stack and in the register.
   1418         VisitForStackValue(property->obj());
   1419         __ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
   1420       } else {
   1421         VisitForStackValue(property->obj());
   1422       }
   1423       break;
   1424     case KEYED_PROPERTY:
   1425       if (expr->is_compound()) {
   1426         VisitForStackValue(property->obj());
   1427         VisitForStackValue(property->key());
   1428         __ ldr(LoadDescriptor::ReceiverRegister(),
   1429                MemOperand(sp, 1 * kPointerSize));
   1430         __ ldr(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
   1431       } else {
   1432         VisitForStackValue(property->obj());
   1433         VisitForStackValue(property->key());
   1434       }
   1435       break;
   1436     case NAMED_SUPER_PROPERTY:
   1437     case KEYED_SUPER_PROPERTY:
   1438       UNREACHABLE();
   1439       break;
   1440   }
   1441 
   1442   // For compound assignments we need another deoptimization point after the
   1443   // variable/property load.
   1444   if (expr->is_compound()) {
   1445     { AccumulatorValueContext context(this);
   1446       switch (assign_type) {
   1447         case VARIABLE:
   1448           EmitVariableLoad(expr->target()->AsVariableProxy());
   1449           PrepareForBailout(expr->target(), BailoutState::TOS_REGISTER);
   1450           break;
   1451         case NAMED_PROPERTY:
   1452           EmitNamedPropertyLoad(property);
   1453           PrepareForBailoutForId(property->LoadId(),
   1454                                  BailoutState::TOS_REGISTER);
   1455           break;
   1456         case KEYED_PROPERTY:
   1457           EmitKeyedPropertyLoad(property);
   1458           PrepareForBailoutForId(property->LoadId(),
   1459                                  BailoutState::TOS_REGISTER);
   1460           break;
   1461         case NAMED_SUPER_PROPERTY:
   1462         case KEYED_SUPER_PROPERTY:
   1463           UNREACHABLE();
   1464           break;
   1465       }
   1466     }
   1467 
   1468     Token::Value op = expr->binary_op();
   1469     PushOperand(r0);  // Left operand goes on the stack.
   1470     VisitForAccumulatorValue(expr->value());
   1471 
   1472     AccumulatorValueContext context(this);
   1473     if (ShouldInlineSmiCase(op)) {
   1474       EmitInlineSmiBinaryOp(expr->binary_operation(),
   1475                             op,
   1476                             expr->target(),
   1477                             expr->value());
   1478     } else {
   1479       EmitBinaryOp(expr->binary_operation(), op);
   1480     }
   1481 
   1482     // Deoptimization point in case the binary operation may have side effects.
   1483     PrepareForBailout(expr->binary_operation(), BailoutState::TOS_REGISTER);
   1484   } else {
   1485     VisitForAccumulatorValue(expr->value());
   1486   }
   1487 
   1488   SetExpressionPosition(expr);
   1489 
   1490   // Store the value.
   1491   switch (assign_type) {
   1492     case VARIABLE: {
   1493       VariableProxy* proxy = expr->target()->AsVariableProxy();
   1494       EmitVariableAssignment(proxy->var(), expr->op(), expr->AssignmentSlot(),
   1495                              proxy->hole_check_mode());
   1496       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
   1497       context()->Plug(r0);
   1498       break;
   1499     }
   1500     case NAMED_PROPERTY:
   1501       EmitNamedPropertyAssignment(expr);
   1502       break;
   1503     case KEYED_PROPERTY:
   1504       EmitKeyedPropertyAssignment(expr);
   1505       break;
   1506     case NAMED_SUPER_PROPERTY:
   1507     case KEYED_SUPER_PROPERTY:
   1508       UNREACHABLE();
   1509       break;
   1510   }
   1511 }
   1512 
   1513 
   1514 void FullCodeGenerator::VisitYield(Yield* expr) {
   1515   // Resumable functions are not supported.
   1516   UNREACHABLE();
   1517 }
   1518 
   1519 void FullCodeGenerator::PushOperands(Register reg1, Register reg2) {
   1520   OperandStackDepthIncrement(2);
   1521   __ Push(reg1, reg2);
   1522 }
   1523 
   1524 void FullCodeGenerator::PopOperands(Register reg1, Register reg2) {
   1525   OperandStackDepthDecrement(2);
   1526   __ Pop(reg1, reg2);
   1527 }
   1528 
   1529 void FullCodeGenerator::EmitOperandStackDepthCheck() {
   1530   if (FLAG_debug_code) {
   1531     int expected_diff = StandardFrameConstants::kFixedFrameSizeFromFp +
   1532                         operand_stack_depth_ * kPointerSize;
   1533     __ sub(r0, fp, sp);
   1534     __ cmp(r0, Operand(expected_diff));
   1535     __ Assert(eq, kUnexpectedStackDepth);
   1536   }
   1537 }
   1538 
   1539 void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
   1540   Label allocate, done_allocate;
   1541 
   1542   __ Allocate(JSIteratorResult::kSize, r0, r2, r3, &allocate,
   1543               NO_ALLOCATION_FLAGS);
   1544   __ b(&done_allocate);
   1545 
   1546   __ bind(&allocate);
   1547   __ Push(Smi::FromInt(JSIteratorResult::kSize));
   1548   __ CallRuntime(Runtime::kAllocateInNewSpace);
   1549 
   1550   __ bind(&done_allocate);
   1551   __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r1);
   1552   PopOperand(r2);
   1553   __ LoadRoot(r3,
   1554               done ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex);
   1555   __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
   1556   __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
   1557   __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
   1558   __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
   1559   __ str(r2, FieldMemOperand(r0, JSIteratorResult::kValueOffset));
   1560   __ str(r3, FieldMemOperand(r0, JSIteratorResult::kDoneOffset));
   1561 }
   1562 
   1563 
   1564 void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
   1565                                               Token::Value op,
   1566                                               Expression* left_expr,
   1567                                               Expression* right_expr) {
   1568   Label done, smi_case, stub_call;
   1569 
   1570   Register scratch1 = r2;
   1571   Register scratch2 = r3;
   1572 
   1573   // Get the arguments.
   1574   Register left = r1;
   1575   Register right = r0;
   1576   PopOperand(left);
   1577 
   1578   // Perform combined smi check on both operands.
   1579   __ orr(scratch1, left, Operand(right));
   1580   STATIC_ASSERT(kSmiTag == 0);
   1581   JumpPatchSite patch_site(masm_);
   1582   patch_site.EmitJumpIfSmi(scratch1, &smi_case);
   1583 
   1584   __ bind(&stub_call);
   1585   Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
   1586   CallIC(code, expr->BinaryOperationFeedbackId());
   1587   patch_site.EmitPatchInfo();
   1588   __ jmp(&done);
   1589 
   1590   __ bind(&smi_case);
   1591   // Smi case. This code works the same way as the smi-smi case in the type
   1592   // recording binary operation stub, see
   1593   switch (op) {
   1594     case Token::SAR:
   1595       __ GetLeastBitsFromSmi(scratch1, right, 5);
   1596       __ mov(right, Operand(left, ASR, scratch1));
   1597       __ bic(right, right, Operand(kSmiTagMask));
   1598       break;
   1599     case Token::SHL: {
   1600       __ SmiUntag(scratch1, left);
   1601       __ GetLeastBitsFromSmi(scratch2, right, 5);
   1602       __ mov(scratch1, Operand(scratch1, LSL, scratch2));
   1603       __ TrySmiTag(right, scratch1, &stub_call);
   1604       break;
   1605     }
   1606     case Token::SHR: {
   1607       __ SmiUntag(scratch1, left);
   1608       __ GetLeastBitsFromSmi(scratch2, right, 5);
   1609       __ mov(scratch1, Operand(scratch1, LSR, scratch2));
   1610       __ tst(scratch1, Operand(0xc0000000));
   1611       __ b(ne, &stub_call);
   1612       __ SmiTag(right, scratch1);
   1613       break;
   1614     }
   1615     case Token::ADD:
   1616       __ add(scratch1, left, Operand(right), SetCC);
   1617       __ b(vs, &stub_call);
   1618       __ mov(right, scratch1);
   1619       break;
   1620     case Token::SUB:
   1621       __ sub(scratch1, left, Operand(right), SetCC);
   1622       __ b(vs, &stub_call);
   1623       __ mov(right, scratch1);
   1624       break;
   1625     case Token::MUL: {
   1626       __ SmiUntag(ip, right);
   1627       __ smull(scratch1, scratch2, left, ip);
   1628       __ mov(ip, Operand(scratch1, ASR, 31));
   1629       __ cmp(ip, Operand(scratch2));
   1630       __ b(ne, &stub_call);
   1631       __ cmp(scratch1, Operand::Zero());
   1632       __ mov(right, Operand(scratch1), LeaveCC, ne);
   1633       __ b(ne, &done);
   1634       __ add(scratch2, right, Operand(left), SetCC);
   1635       __ mov(right, Operand(Smi::kZero), LeaveCC, pl);
   1636       __ b(mi, &stub_call);
   1637       break;
   1638     }
   1639     case Token::BIT_OR:
   1640       __ orr(right, left, Operand(right));
   1641       break;
   1642     case Token::BIT_AND:
   1643       __ and_(right, left, Operand(right));
   1644       break;
   1645     case Token::BIT_XOR:
   1646       __ eor(right, left, Operand(right));
   1647       break;
   1648     default:
   1649       UNREACHABLE();
   1650   }
   1651 
   1652   __ bind(&done);
   1653   context()->Plug(r0);
   1654 }
   1655 
   1656 void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr, Token::Value op) {
   1657   PopOperand(r1);
   1658   Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), op).code();
   1659   JumpPatchSite patch_site(masm_);    // unbound, signals no inlined smi code.
   1660   CallIC(code, expr->BinaryOperationFeedbackId());
   1661   patch_site.EmitPatchInfo();
   1662   context()->Plug(r0);
   1663 }
   1664 
   1665 void FullCodeGenerator::EmitAssignment(Expression* expr, FeedbackSlot slot) {
   1666   DCHECK(expr->IsValidReferenceExpressionOrThis());
   1667 
   1668   Property* prop = expr->AsProperty();
   1669   LhsKind assign_type = Property::GetAssignType(prop);
   1670 
   1671   switch (assign_type) {
   1672     case VARIABLE: {
   1673       VariableProxy* proxy = expr->AsVariableProxy();
   1674       EffectContext context(this);
   1675       EmitVariableAssignment(proxy->var(), Token::ASSIGN, slot,
   1676                              proxy->hole_check_mode());
   1677       break;
   1678     }
   1679     case NAMED_PROPERTY: {
   1680       PushOperand(r0);  // Preserve value.
   1681       VisitForAccumulatorValue(prop->obj());
   1682       __ Move(StoreDescriptor::ReceiverRegister(), r0);
   1683       PopOperand(StoreDescriptor::ValueRegister());  // Restore value.
   1684       CallStoreIC(slot, prop->key()->AsLiteral()->value());
   1685       break;
   1686     }
   1687     case KEYED_PROPERTY: {
   1688       PushOperand(r0);  // Preserve value.
   1689       VisitForStackValue(prop->obj());
   1690       VisitForAccumulatorValue(prop->key());
   1691       __ Move(StoreDescriptor::NameRegister(), r0);
   1692       PopOperands(StoreDescriptor::ValueRegister(),
   1693                   StoreDescriptor::ReceiverRegister());
   1694       CallKeyedStoreIC(slot);
   1695       break;
   1696     }
   1697     case NAMED_SUPER_PROPERTY:
   1698     case KEYED_SUPER_PROPERTY:
   1699       UNREACHABLE();
   1700       break;
   1701   }
   1702   context()->Plug(r0);
   1703 }
   1704 
   1705 
   1706 void FullCodeGenerator::EmitStoreToStackLocalOrContextSlot(
   1707     Variable* var, MemOperand location) {
   1708   __ str(result_register(), location);
   1709   if (var->IsContextSlot()) {
   1710     // RecordWrite may destroy all its register arguments.
   1711     __ mov(r3, result_register());
   1712     int offset = Context::SlotOffset(var->index());
   1713     __ RecordWriteContextSlot(
   1714         r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs);
   1715   }
   1716 }
   1717 
   1718 void FullCodeGenerator::EmitVariableAssignment(Variable* var, Token::Value op,
   1719                                                FeedbackSlot slot,
   1720                                                HoleCheckMode hole_check_mode) {
   1721   if (var->IsUnallocated()) {
   1722     // Global var, const, or let.
   1723     __ LoadGlobalObject(StoreDescriptor::ReceiverRegister());
   1724     CallStoreIC(slot, var->name());
   1725 
   1726   } else if (IsLexicalVariableMode(var->mode()) && op != Token::INIT) {
   1727     DCHECK(!var->IsLookupSlot());
   1728     DCHECK(var->IsStackAllocated() || var->IsContextSlot());
   1729     MemOperand location = VarOperand(var, r1);
   1730     // Perform an initialization check for lexically declared variables.
   1731     if (hole_check_mode == HoleCheckMode::kRequired) {
   1732       Label assign;
   1733       __ ldr(r3, location);
   1734       __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
   1735       __ b(ne, &assign);
   1736       __ mov(r3, Operand(var->name()));
   1737       __ push(r3);
   1738       __ CallRuntime(Runtime::kThrowReferenceError);
   1739       __ bind(&assign);
   1740     }
   1741     if (var->mode() != CONST) {
   1742       EmitStoreToStackLocalOrContextSlot(var, location);
   1743     } else if (var->throw_on_const_assignment(language_mode())) {
   1744       __ CallRuntime(Runtime::kThrowConstAssignError);
   1745     }
   1746   } else if (var->is_this() && var->mode() == CONST && op == Token::INIT) {
   1747     // Initializing assignment to const {this} needs a write barrier.
   1748     DCHECK(var->IsStackAllocated() || var->IsContextSlot());
   1749     Label uninitialized_this;
   1750     MemOperand location = VarOperand(var, r1);
   1751     __ ldr(r3, location);
   1752     __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
   1753     __ b(eq, &uninitialized_this);
   1754     __ mov(r0, Operand(var->name()));
   1755     __ Push(r0);
   1756     __ CallRuntime(Runtime::kThrowReferenceError);
   1757     __ bind(&uninitialized_this);
   1758     EmitStoreToStackLocalOrContextSlot(var, location);
   1759 
   1760   } else {
   1761     DCHECK(var->mode() != CONST || op == Token::INIT);
   1762     DCHECK(var->IsStackAllocated() || var->IsContextSlot());
   1763     DCHECK(!var->IsLookupSlot());
   1764     // Assignment to var or initializing assignment to let/const in harmony
   1765     // mode.
   1766     MemOperand location = VarOperand(var, r1);
   1767     if (FLAG_debug_code && var->mode() == LET && op == Token::INIT) {
   1768       // Check for an uninitialized let binding.
   1769       __ ldr(r2, location);
   1770       __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
   1771       __ Check(eq, kLetBindingReInitialization);
   1772     }
   1773     EmitStoreToStackLocalOrContextSlot(var, location);
   1774   }
   1775 }
   1776 
   1777 
   1778 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
   1779   // Assignment to a property, using a named store IC.
   1780   Property* prop = expr->target()->AsProperty();
   1781   DCHECK(prop != NULL);
   1782   DCHECK(prop->key()->IsLiteral());
   1783 
   1784   PopOperand(StoreDescriptor::ReceiverRegister());
   1785   CallStoreIC(expr->AssignmentSlot(), prop->key()->AsLiteral()->value());
   1786 
   1787   PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
   1788   context()->Plug(r0);
   1789 }
   1790 
   1791 
   1792 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
   1793   // Assignment to a property, using a keyed store IC.
   1794   PopOperands(StoreDescriptor::ReceiverRegister(),
   1795               StoreDescriptor::NameRegister());
   1796   DCHECK(StoreDescriptor::ValueRegister().is(r0));
   1797 
   1798   CallKeyedStoreIC(expr->AssignmentSlot());
   1799 
   1800   PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
   1801   context()->Plug(r0);
   1802 }
   1803 
   1804 // Code common for calls using the IC.
   1805 void FullCodeGenerator::EmitCallWithLoadIC(Call* expr) {
   1806   Expression* callee = expr->expression();
   1807 
   1808   // Get the target function.
   1809   ConvertReceiverMode convert_mode;
   1810   if (callee->IsVariableProxy()) {
   1811     { StackValueContext context(this);
   1812       EmitVariableLoad(callee->AsVariableProxy());
   1813       PrepareForBailout(callee, BailoutState::NO_REGISTERS);
   1814     }
   1815     // Push undefined as receiver. This is patched in the method prologue if it
   1816     // is a sloppy mode method.
   1817     __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
   1818     PushOperand(ip);
   1819     convert_mode = ConvertReceiverMode::kNullOrUndefined;
   1820   } else {
   1821     // Load the function from the receiver.
   1822     DCHECK(callee->IsProperty());
   1823     DCHECK(!callee->AsProperty()->IsSuperAccess());
   1824     __ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
   1825     EmitNamedPropertyLoad(callee->AsProperty());
   1826     PrepareForBailoutForId(callee->AsProperty()->LoadId(),
   1827                            BailoutState::TOS_REGISTER);
   1828     // Push the target function under the receiver.
   1829     __ ldr(ip, MemOperand(sp, 0));
   1830     PushOperand(ip);
   1831     __ str(r0, MemOperand(sp, kPointerSize));
   1832     convert_mode = ConvertReceiverMode::kNotNullOrUndefined;
   1833   }
   1834 
   1835   EmitCall(expr, convert_mode);
   1836 }
   1837 
   1838 
   1839 // Code common for calls using the IC.
   1840 void FullCodeGenerator::EmitKeyedCallWithLoadIC(Call* expr,
   1841                                                 Expression* key) {
   1842   // Load the key.
   1843   VisitForAccumulatorValue(key);
   1844 
   1845   Expression* callee = expr->expression();
   1846 
   1847   // Load the function from the receiver.
   1848   DCHECK(callee->IsProperty());
   1849   __ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
   1850   __ Move(LoadDescriptor::NameRegister(), r0);
   1851   EmitKeyedPropertyLoad(callee->AsProperty());
   1852   PrepareForBailoutForId(callee->AsProperty()->LoadId(),
   1853                          BailoutState::TOS_REGISTER);
   1854 
   1855   // Push the target function under the receiver.
   1856   __ ldr(ip, MemOperand(sp, 0));
   1857   PushOperand(ip);
   1858   __ str(r0, MemOperand(sp, kPointerSize));
   1859 
   1860   EmitCall(expr, ConvertReceiverMode::kNotNullOrUndefined);
   1861 }
   1862 
   1863 
   1864 void FullCodeGenerator::EmitCall(Call* expr, ConvertReceiverMode mode) {
   1865   // Load the arguments.
   1866   ZoneList<Expression*>* args = expr->arguments();
   1867   int arg_count = args->length();
   1868   for (int i = 0; i < arg_count; i++) {
   1869     VisitForStackValue(args->at(i));
   1870   }
   1871 
   1872   PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
   1873   SetCallPosition(expr, expr->tail_call_mode());
   1874   if (expr->tail_call_mode() == TailCallMode::kAllow) {
   1875     if (FLAG_trace) {
   1876       __ CallRuntime(Runtime::kTraceTailCall);
   1877     }
   1878     // Update profiling counters before the tail call since we will
   1879     // not return to this function.
   1880     EmitProfilingCounterHandlingForReturnSequence(true);
   1881   }
   1882   Handle<Code> code =
   1883       CodeFactory::CallICTrampoline(isolate(), mode, expr->tail_call_mode())
   1884           .code();
   1885   __ mov(r3, Operand(IntFromSlot(expr->CallFeedbackICSlot())));
   1886   __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
   1887   __ mov(r0, Operand(arg_count));
   1888   CallIC(code);
   1889   OperandStackDepthDecrement(arg_count + 1);
   1890 
   1891   RecordJSReturnSite(expr);
   1892   RestoreContext();
   1893   context()->DropAndPlug(1, r0);
   1894 }
   1895 
   1896 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
   1897   Comment cmnt(masm_, "[ CallNew");
   1898   // According to ECMA-262, section 11.2.2, page 44, the function
   1899   // expression in new calls must be evaluated before the
   1900   // arguments.
   1901 
   1902   // Push constructor on the stack.  If it's not a function it's used as
   1903   // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
   1904   // ignored.
   1905   DCHECK(!expr->expression()->IsSuperPropertyReference());
   1906   VisitForStackValue(expr->expression());
   1907 
   1908   // Push the arguments ("left-to-right") on the stack.
   1909   ZoneList<Expression*>* args = expr->arguments();
   1910   int arg_count = args->length();
   1911   for (int i = 0; i < arg_count; i++) {
   1912     VisitForStackValue(args->at(i));
   1913   }
   1914 
   1915   // Call the construct call builtin that handles allocation and
   1916   // constructor invocation.
   1917   SetConstructCallPosition(expr);
   1918 
   1919   // Load function and argument count into r1 and r0.
   1920   __ mov(r0, Operand(arg_count));
   1921   __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
   1922 
   1923   // Record call targets in unoptimized code.
   1924   __ EmitLoadFeedbackVector(r2);
   1925   __ mov(r3, Operand(SmiFromSlot(expr->CallNewFeedbackSlot())));
   1926 
   1927   CallConstructStub stub(isolate());
   1928   CallIC(stub.GetCode());
   1929   OperandStackDepthDecrement(arg_count + 1);
   1930   PrepareForBailoutForId(expr->ReturnId(), BailoutState::TOS_REGISTER);
   1931   RestoreContext();
   1932   context()->Plug(r0);
   1933 }
   1934 
   1935 
   1936 void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
   1937   ZoneList<Expression*>* args = expr->arguments();
   1938   DCHECK(args->length() == 1);
   1939 
   1940   VisitForAccumulatorValue(args->at(0));
   1941 
   1942   Label materialize_true, materialize_false;
   1943   Label* if_true = NULL;
   1944   Label* if_false = NULL;
   1945   Label* fall_through = NULL;
   1946   context()->PrepareTest(&materialize_true, &materialize_false,
   1947                          &if_true, &if_false, &fall_through);
   1948 
   1949   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   1950   __ SmiTst(r0);
   1951   Split(eq, if_true, if_false, fall_through);
   1952 
   1953   context()->Plug(if_true, if_false);
   1954 }
   1955 
   1956 
   1957 void FullCodeGenerator::EmitIsJSReceiver(CallRuntime* expr) {
   1958   ZoneList<Expression*>* args = expr->arguments();
   1959   DCHECK(args->length() == 1);
   1960 
   1961   VisitForAccumulatorValue(args->at(0));
   1962 
   1963   Label materialize_true, materialize_false;
   1964   Label* if_true = NULL;
   1965   Label* if_false = NULL;
   1966   Label* fall_through = NULL;
   1967   context()->PrepareTest(&materialize_true, &materialize_false,
   1968                          &if_true, &if_false, &fall_through);
   1969 
   1970   __ JumpIfSmi(r0, if_false);
   1971   __ CompareObjectType(r0, r1, r1, FIRST_JS_RECEIVER_TYPE);
   1972   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   1973   Split(ge, if_true, if_false, fall_through);
   1974 
   1975   context()->Plug(if_true, if_false);
   1976 }
   1977 
   1978 
   1979 void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
   1980   ZoneList<Expression*>* args = expr->arguments();
   1981   DCHECK(args->length() == 1);
   1982 
   1983   VisitForAccumulatorValue(args->at(0));
   1984 
   1985   Label materialize_true, materialize_false;
   1986   Label* if_true = NULL;
   1987   Label* if_false = NULL;
   1988   Label* fall_through = NULL;
   1989   context()->PrepareTest(&materialize_true, &materialize_false,
   1990                          &if_true, &if_false, &fall_through);
   1991 
   1992   __ JumpIfSmi(r0, if_false);
   1993   __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
   1994   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   1995   Split(eq, if_true, if_false, fall_through);
   1996 
   1997   context()->Plug(if_true, if_false);
   1998 }
   1999 
   2000 
   2001 void FullCodeGenerator::EmitIsTypedArray(CallRuntime* expr) {
   2002   ZoneList<Expression*>* args = expr->arguments();
   2003   DCHECK(args->length() == 1);
   2004 
   2005   VisitForAccumulatorValue(args->at(0));
   2006 
   2007   Label materialize_true, materialize_false;
   2008   Label* if_true = NULL;
   2009   Label* if_false = NULL;
   2010   Label* fall_through = NULL;
   2011   context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
   2012                          &if_false, &fall_through);
   2013 
   2014   __ JumpIfSmi(r0, if_false);
   2015   __ CompareObjectType(r0, r1, r1, JS_TYPED_ARRAY_TYPE);
   2016   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   2017   Split(eq, if_true, if_false, fall_through);
   2018 
   2019   context()->Plug(if_true, if_false);
   2020 }
   2021 
   2022 
   2023 void FullCodeGenerator::EmitIsJSProxy(CallRuntime* expr) {
   2024   ZoneList<Expression*>* args = expr->arguments();
   2025   DCHECK(args->length() == 1);
   2026 
   2027   VisitForAccumulatorValue(args->at(0));
   2028 
   2029   Label materialize_true, materialize_false;
   2030   Label* if_true = NULL;
   2031   Label* if_false = NULL;
   2032   Label* fall_through = NULL;
   2033   context()->PrepareTest(&materialize_true, &materialize_false, &if_true,
   2034                          &if_false, &fall_through);
   2035 
   2036   __ JumpIfSmi(r0, if_false);
   2037   __ CompareObjectType(r0, r1, r1, JS_PROXY_TYPE);
   2038   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   2039   Split(eq, if_true, if_false, fall_through);
   2040 
   2041   context()->Plug(if_true, if_false);
   2042 }
   2043 
   2044 
   2045 void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
   2046   ZoneList<Expression*>* args = expr->arguments();
   2047   DCHECK(args->length() == 1);
   2048   Label done, null, function, non_function_constructor;
   2049 
   2050   VisitForAccumulatorValue(args->at(0));
   2051 
   2052   // If the object is not a JSReceiver, we return null.
   2053   __ JumpIfSmi(r0, &null);
   2054   STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
   2055   __ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE);
   2056   // Map is now in r0.
   2057   __ b(lt, &null);
   2058 
   2059   // Return 'Function' for JSFunction and JSBoundFunction objects.
   2060   __ cmp(r1, Operand(FIRST_FUNCTION_TYPE));
   2061   STATIC_ASSERT(LAST_FUNCTION_TYPE == LAST_TYPE);
   2062   __ b(hs, &function);
   2063 
   2064   // Check if the constructor in the map is a JS function.
   2065   Register instance_type = r2;
   2066   __ GetMapConstructor(r0, r0, r1, instance_type);
   2067   __ cmp(instance_type, Operand(JS_FUNCTION_TYPE));
   2068   __ b(ne, &non_function_constructor);
   2069 
   2070   // r0 now contains the constructor function. Grab the
   2071   // instance class name from there.
   2072   __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
   2073   __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset));
   2074   __ b(&done);
   2075 
   2076   // Functions have class 'Function'.
   2077   __ bind(&function);
   2078   __ LoadRoot(r0, Heap::kFunction_stringRootIndex);
   2079   __ jmp(&done);
   2080 
   2081   // Objects with a non-function constructor have class 'Object'.
   2082   __ bind(&non_function_constructor);
   2083   __ LoadRoot(r0, Heap::kObject_stringRootIndex);
   2084   __ jmp(&done);
   2085 
   2086   // Non-JS objects have class null.
   2087   __ bind(&null);
   2088   __ LoadRoot(r0, Heap::kNullValueRootIndex);
   2089 
   2090   // All done.
   2091   __ bind(&done);
   2092 
   2093   context()->Plug(r0);
   2094 }
   2095 
   2096 
   2097 void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
   2098   ZoneList<Expression*>* args = expr->arguments();
   2099   DCHECK(args->length() == 2);
   2100   VisitForStackValue(args->at(0));
   2101   VisitForAccumulatorValue(args->at(1));
   2102 
   2103   Register object = r1;
   2104   Register index = r0;
   2105   Register result = r3;
   2106 
   2107   PopOperand(object);
   2108 
   2109   Label need_conversion;
   2110   Label index_out_of_range;
   2111   Label done;
   2112   StringCharCodeAtGenerator generator(object, index, result, &need_conversion,
   2113                                       &need_conversion, &index_out_of_range);
   2114   generator.GenerateFast(masm_);
   2115   __ jmp(&done);
   2116 
   2117   __ bind(&index_out_of_range);
   2118   // When the index is out of range, the spec requires us to return
   2119   // NaN.
   2120   __ LoadRoot(result, Heap::kNanValueRootIndex);
   2121   __ jmp(&done);
   2122 
   2123   __ bind(&need_conversion);
   2124   // Load the undefined value into the result register, which will
   2125   // trigger conversion.
   2126   __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
   2127   __ jmp(&done);
   2128 
   2129   NopRuntimeCallHelper call_helper;
   2130   generator.GenerateSlow(masm_, NOT_PART_OF_IC_HANDLER, call_helper);
   2131 
   2132   __ bind(&done);
   2133   context()->Plug(result);
   2134 }
   2135 
   2136 
   2137 void FullCodeGenerator::EmitCall(CallRuntime* expr) {
   2138   ZoneList<Expression*>* args = expr->arguments();
   2139   DCHECK_LE(2, args->length());
   2140   // Push target, receiver and arguments onto the stack.
   2141   for (Expression* const arg : *args) {
   2142     VisitForStackValue(arg);
   2143   }
   2144   PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
   2145   // Move target to r1.
   2146   int const argc = args->length() - 2;
   2147   __ ldr(r1, MemOperand(sp, (argc + 1) * kPointerSize));
   2148   // Call the target.
   2149   __ mov(r0, Operand(argc));
   2150   __ Call(isolate()->builtins()->Call(), RelocInfo::CODE_TARGET);
   2151   OperandStackDepthDecrement(argc + 1);
   2152   RestoreContext();
   2153   // Discard the function left on TOS.
   2154   context()->DropAndPlug(1, r0);
   2155 }
   2156 
   2157 void FullCodeGenerator::EmitGetSuperConstructor(CallRuntime* expr) {
   2158   ZoneList<Expression*>* args = expr->arguments();
   2159   DCHECK_EQ(1, args->length());
   2160   VisitForAccumulatorValue(args->at(0));
   2161   __ AssertFunction(r0);
   2162   __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
   2163   __ ldr(r0, FieldMemOperand(r0, Map::kPrototypeOffset));
   2164   context()->Plug(r0);
   2165 }
   2166 
   2167 void FullCodeGenerator::EmitDebugIsActive(CallRuntime* expr) {
   2168   DCHECK(expr->arguments()->length() == 0);
   2169   ExternalReference debug_is_active =
   2170       ExternalReference::debug_is_active_address(isolate());
   2171   __ mov(ip, Operand(debug_is_active));
   2172   __ ldrb(r0, MemOperand(ip));
   2173   __ SmiTag(r0);
   2174   context()->Plug(r0);
   2175 }
   2176 
   2177 
   2178 void FullCodeGenerator::EmitCreateIterResultObject(CallRuntime* expr) {
   2179   ZoneList<Expression*>* args = expr->arguments();
   2180   DCHECK_EQ(2, args->length());
   2181   VisitForStackValue(args->at(0));
   2182   VisitForStackValue(args->at(1));
   2183 
   2184   Label runtime, done;
   2185 
   2186   __ Allocate(JSIteratorResult::kSize, r0, r2, r3, &runtime,
   2187               NO_ALLOCATION_FLAGS);
   2188   __ LoadNativeContextSlot(Context::ITERATOR_RESULT_MAP_INDEX, r1);
   2189   __ pop(r3);
   2190   __ pop(r2);
   2191   __ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
   2192   __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
   2193   __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
   2194   __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
   2195   __ str(r2, FieldMemOperand(r0, JSIteratorResult::kValueOffset));
   2196   __ str(r3, FieldMemOperand(r0, JSIteratorResult::kDoneOffset));
   2197   STATIC_ASSERT(JSIteratorResult::kSize == 5 * kPointerSize);
   2198   __ b(&done);
   2199 
   2200   __ bind(&runtime);
   2201   CallRuntimeWithOperands(Runtime::kCreateIterResultObject);
   2202 
   2203   __ bind(&done);
   2204   context()->Plug(r0);
   2205 }
   2206 
   2207 
   2208 void FullCodeGenerator::EmitLoadJSRuntimeFunction(CallRuntime* expr) {
   2209   // Push function.
   2210   __ LoadNativeContextSlot(expr->context_index(), r0);
   2211   PushOperand(r0);
   2212 
   2213   // Push undefined as the receiver.
   2214   __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
   2215   PushOperand(r0);
   2216 }
   2217 
   2218 
   2219 void FullCodeGenerator::EmitCallJSRuntimeFunction(CallRuntime* expr) {
   2220   ZoneList<Expression*>* args = expr->arguments();
   2221   int arg_count = args->length();
   2222 
   2223   SetCallPosition(expr);
   2224   __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
   2225   __ mov(r0, Operand(arg_count));
   2226   __ Call(isolate()->builtins()->Call(ConvertReceiverMode::kNullOrUndefined),
   2227           RelocInfo::CODE_TARGET);
   2228   OperandStackDepthDecrement(arg_count + 1);
   2229   RestoreContext();
   2230 }
   2231 
   2232 
   2233 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
   2234   switch (expr->op()) {
   2235     case Token::DELETE: {
   2236       Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
   2237       Property* property = expr->expression()->AsProperty();
   2238       VariableProxy* proxy = expr->expression()->AsVariableProxy();
   2239 
   2240       if (property != NULL) {
   2241         VisitForStackValue(property->obj());
   2242         VisitForStackValue(property->key());
   2243         CallRuntimeWithOperands(is_strict(language_mode())
   2244                                     ? Runtime::kDeleteProperty_Strict
   2245                                     : Runtime::kDeleteProperty_Sloppy);
   2246         context()->Plug(r0);
   2247       } else if (proxy != NULL) {
   2248         Variable* var = proxy->var();
   2249         // Delete of an unqualified identifier is disallowed in strict mode but
   2250         // "delete this" is allowed.
   2251         bool is_this = var->is_this();
   2252         DCHECK(is_sloppy(language_mode()) || is_this);
   2253         if (var->IsUnallocated()) {
   2254           __ LoadGlobalObject(r2);
   2255           __ mov(r1, Operand(var->name()));
   2256           __ Push(r2, r1);
   2257           __ CallRuntime(Runtime::kDeleteProperty_Sloppy);
   2258           context()->Plug(r0);
   2259         } else {
   2260           DCHECK(!var->IsLookupSlot());
   2261           DCHECK(var->IsStackAllocated() || var->IsContextSlot());
   2262           // Result of deleting non-global, non-dynamic variables is false.
   2263           // The subexpression does not have side effects.
   2264           context()->Plug(is_this);
   2265         }
   2266       } else {
   2267         // Result of deleting non-property, non-variable reference is true.
   2268         // The subexpression may have side effects.
   2269         VisitForEffect(expr->expression());
   2270         context()->Plug(true);
   2271       }
   2272       break;
   2273     }
   2274 
   2275     case Token::VOID: {
   2276       Comment cmnt(masm_, "[ UnaryOperation (VOID)");
   2277       VisitForEffect(expr->expression());
   2278       context()->Plug(Heap::kUndefinedValueRootIndex);
   2279       break;
   2280     }
   2281 
   2282     case Token::NOT: {
   2283       Comment cmnt(masm_, "[ UnaryOperation (NOT)");
   2284       if (context()->IsEffect()) {
   2285         // Unary NOT has no side effects so it's only necessary to visit the
   2286         // subexpression.  Match the optimizing compiler by not branching.
   2287         VisitForEffect(expr->expression());
   2288       } else if (context()->IsTest()) {
   2289         const TestContext* test = TestContext::cast(context());
   2290         // The labels are swapped for the recursive call.
   2291         VisitForControl(expr->expression(),
   2292                         test->false_label(),
   2293                         test->true_label(),
   2294                         test->fall_through());
   2295         context()->Plug(test->true_label(), test->false_label());
   2296       } else {
   2297         // We handle value contexts explicitly rather than simply visiting
   2298         // for control and plugging the control flow into the context,
   2299         // because we need to prepare a pair of extra administrative AST ids
   2300         // for the optimizing compiler.
   2301         DCHECK(context()->IsAccumulatorValue() || context()->IsStackValue());
   2302         Label materialize_true, materialize_false, done;
   2303         VisitForControl(expr->expression(),
   2304                         &materialize_false,
   2305                         &materialize_true,
   2306                         &materialize_true);
   2307         if (!context()->IsAccumulatorValue()) OperandStackDepthIncrement(1);
   2308         __ bind(&materialize_true);
   2309         PrepareForBailoutForId(expr->MaterializeTrueId(),
   2310                                BailoutState::NO_REGISTERS);
   2311         __ LoadRoot(r0, Heap::kTrueValueRootIndex);
   2312         if (context()->IsStackValue()) __ push(r0);
   2313         __ jmp(&done);
   2314         __ bind(&materialize_false);
   2315         PrepareForBailoutForId(expr->MaterializeFalseId(),
   2316                                BailoutState::NO_REGISTERS);
   2317         __ LoadRoot(r0, Heap::kFalseValueRootIndex);
   2318         if (context()->IsStackValue()) __ push(r0);
   2319         __ bind(&done);
   2320       }
   2321       break;
   2322     }
   2323 
   2324     case Token::TYPEOF: {
   2325       Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
   2326       {
   2327         AccumulatorValueContext context(this);
   2328         VisitForTypeofValue(expr->expression());
   2329       }
   2330       __ mov(r3, r0);
   2331       __ Call(isolate()->builtins()->Typeof(), RelocInfo::CODE_TARGET);
   2332       context()->Plug(r0);
   2333       break;
   2334     }
   2335 
   2336     default:
   2337       UNREACHABLE();
   2338   }
   2339 }
   2340 
   2341 
   2342 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
   2343   DCHECK(expr->expression()->IsValidReferenceExpressionOrThis());
   2344 
   2345   Comment cmnt(masm_, "[ CountOperation");
   2346 
   2347   Property* prop = expr->expression()->AsProperty();
   2348   LhsKind assign_type = Property::GetAssignType(prop);
   2349 
   2350   // Evaluate expression and get value.
   2351   if (assign_type == VARIABLE) {
   2352     DCHECK(expr->expression()->AsVariableProxy()->var() != NULL);
   2353     AccumulatorValueContext context(this);
   2354     EmitVariableLoad(expr->expression()->AsVariableProxy());
   2355   } else {
   2356     // Reserve space for result of postfix operation.
   2357     if (expr->is_postfix() && !context()->IsEffect()) {
   2358       __ mov(ip, Operand(Smi::kZero));
   2359       PushOperand(ip);
   2360     }
   2361     switch (assign_type) {
   2362       case NAMED_PROPERTY: {
   2363         // Put the object both on the stack and in the register.
   2364         VisitForStackValue(prop->obj());
   2365         __ ldr(LoadDescriptor::ReceiverRegister(), MemOperand(sp, 0));
   2366         EmitNamedPropertyLoad(prop);
   2367         break;
   2368       }
   2369 
   2370       case KEYED_PROPERTY: {
   2371         VisitForStackValue(prop->obj());
   2372         VisitForStackValue(prop->key());
   2373         __ ldr(LoadDescriptor::ReceiverRegister(),
   2374                MemOperand(sp, 1 * kPointerSize));
   2375         __ ldr(LoadDescriptor::NameRegister(), MemOperand(sp, 0));
   2376         EmitKeyedPropertyLoad(prop);
   2377         break;
   2378       }
   2379 
   2380       case NAMED_SUPER_PROPERTY:
   2381       case KEYED_SUPER_PROPERTY:
   2382       case VARIABLE:
   2383         UNREACHABLE();
   2384     }
   2385   }
   2386 
   2387   // We need a second deoptimization point after loading the value
   2388   // in case evaluating the property load my have a side effect.
   2389   if (assign_type == VARIABLE) {
   2390     PrepareForBailout(expr->expression(), BailoutState::TOS_REGISTER);
   2391   } else {
   2392     PrepareForBailoutForId(prop->LoadId(), BailoutState::TOS_REGISTER);
   2393   }
   2394 
   2395   // Inline smi case if we are in a loop.
   2396   Label stub_call, done;
   2397   JumpPatchSite patch_site(masm_);
   2398 
   2399   int count_value = expr->op() == Token::INC ? 1 : -1;
   2400   if (ShouldInlineSmiCase(expr->op())) {
   2401     Label slow;
   2402     patch_site.EmitJumpIfNotSmi(r0, &slow);
   2403 
   2404     // Save result for postfix expressions.
   2405     if (expr->is_postfix()) {
   2406       if (!context()->IsEffect()) {
   2407         // Save the result on the stack. If we have a named or keyed property
   2408         // we store the result under the receiver that is currently on top
   2409         // of the stack.
   2410         switch (assign_type) {
   2411           case VARIABLE:
   2412             __ push(r0);
   2413             break;
   2414           case NAMED_PROPERTY:
   2415             __ str(r0, MemOperand(sp, kPointerSize));
   2416             break;
   2417           case KEYED_PROPERTY:
   2418             __ str(r0, MemOperand(sp, 2 * kPointerSize));
   2419             break;
   2420           case NAMED_SUPER_PROPERTY:
   2421           case KEYED_SUPER_PROPERTY:
   2422             UNREACHABLE();
   2423             break;
   2424         }
   2425       }
   2426     }
   2427 
   2428     __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
   2429     __ b(vc, &done);
   2430     // Call stub. Undo operation first.
   2431     __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
   2432     __ jmp(&stub_call);
   2433     __ bind(&slow);
   2434   }
   2435 
   2436   // Convert old value into a number.
   2437   __ Call(isolate()->builtins()->ToNumber(), RelocInfo::CODE_TARGET);
   2438   RestoreContext();
   2439   PrepareForBailoutForId(expr->ToNumberId(), BailoutState::TOS_REGISTER);
   2440 
   2441   // Save result for postfix expressions.
   2442   if (expr->is_postfix()) {
   2443     if (!context()->IsEffect()) {
   2444       // Save the result on the stack. If we have a named or keyed property
   2445       // we store the result under the receiver that is currently on top
   2446       // of the stack.
   2447       switch (assign_type) {
   2448         case VARIABLE:
   2449           PushOperand(r0);
   2450           break;
   2451         case NAMED_PROPERTY:
   2452           __ str(r0, MemOperand(sp, kPointerSize));
   2453           break;
   2454         case KEYED_PROPERTY:
   2455           __ str(r0, MemOperand(sp, 2 * kPointerSize));
   2456           break;
   2457         case NAMED_SUPER_PROPERTY:
   2458         case KEYED_SUPER_PROPERTY:
   2459           UNREACHABLE();
   2460           break;
   2461       }
   2462     }
   2463   }
   2464 
   2465 
   2466   __ bind(&stub_call);
   2467   __ mov(r1, r0);
   2468   __ mov(r0, Operand(Smi::FromInt(count_value)));
   2469 
   2470   SetExpressionPosition(expr);
   2471 
   2472   Handle<Code> code = CodeFactory::BinaryOpIC(isolate(), Token::ADD).code();
   2473   CallIC(code, expr->CountBinOpFeedbackId());
   2474   patch_site.EmitPatchInfo();
   2475   __ bind(&done);
   2476 
   2477   // Store the value returned in r0.
   2478   switch (assign_type) {
   2479     case VARIABLE: {
   2480       VariableProxy* proxy = expr->expression()->AsVariableProxy();
   2481       if (expr->is_postfix()) {
   2482         { EffectContext context(this);
   2483           EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
   2484                                  proxy->hole_check_mode());
   2485           PrepareForBailoutForId(expr->AssignmentId(),
   2486                                  BailoutState::TOS_REGISTER);
   2487           context.Plug(r0);
   2488         }
   2489         // For all contexts except EffectConstant We have the result on
   2490         // top of the stack.
   2491         if (!context()->IsEffect()) {
   2492           context()->PlugTOS();
   2493         }
   2494       } else {
   2495         EmitVariableAssignment(proxy->var(), Token::ASSIGN, expr->CountSlot(),
   2496                                proxy->hole_check_mode());
   2497         PrepareForBailoutForId(expr->AssignmentId(),
   2498                                BailoutState::TOS_REGISTER);
   2499         context()->Plug(r0);
   2500       }
   2501       break;
   2502     }
   2503     case NAMED_PROPERTY: {
   2504       PopOperand(StoreDescriptor::ReceiverRegister());
   2505       CallStoreIC(expr->CountSlot(), prop->key()->AsLiteral()->value());
   2506       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
   2507       if (expr->is_postfix()) {
   2508         if (!context()->IsEffect()) {
   2509           context()->PlugTOS();
   2510         }
   2511       } else {
   2512         context()->Plug(r0);
   2513       }
   2514       break;
   2515     }
   2516     case KEYED_PROPERTY: {
   2517       PopOperands(StoreDescriptor::ReceiverRegister(),
   2518                   StoreDescriptor::NameRegister());
   2519       CallKeyedStoreIC(expr->CountSlot());
   2520       PrepareForBailoutForId(expr->AssignmentId(), BailoutState::TOS_REGISTER);
   2521       if (expr->is_postfix()) {
   2522         if (!context()->IsEffect()) {
   2523           context()->PlugTOS();
   2524         }
   2525       } else {
   2526         context()->Plug(r0);
   2527       }
   2528       break;
   2529     }
   2530     case NAMED_SUPER_PROPERTY:
   2531     case KEYED_SUPER_PROPERTY:
   2532       UNREACHABLE();
   2533       break;
   2534   }
   2535 }
   2536 
   2537 
   2538 void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
   2539                                                  Expression* sub_expr,
   2540                                                  Handle<String> check) {
   2541   Label materialize_true, materialize_false;
   2542   Label* if_true = NULL;
   2543   Label* if_false = NULL;
   2544   Label* fall_through = NULL;
   2545   context()->PrepareTest(&materialize_true, &materialize_false,
   2546                          &if_true, &if_false, &fall_through);
   2547 
   2548   { AccumulatorValueContext context(this);
   2549     VisitForTypeofValue(sub_expr);
   2550   }
   2551   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   2552 
   2553   Factory* factory = isolate()->factory();
   2554   if (String::Equals(check, factory->number_string())) {
   2555     __ JumpIfSmi(r0, if_true);
   2556     __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
   2557     __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
   2558     __ cmp(r0, ip);
   2559     Split(eq, if_true, if_false, fall_through);
   2560   } else if (String::Equals(check, factory->string_string())) {
   2561     __ JumpIfSmi(r0, if_false);
   2562     __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
   2563     Split(lt, if_true, if_false, fall_through);
   2564   } else if (String::Equals(check, factory->symbol_string())) {
   2565     __ JumpIfSmi(r0, if_false);
   2566     __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
   2567     Split(eq, if_true, if_false, fall_through);
   2568   } else if (String::Equals(check, factory->boolean_string())) {
   2569     __ CompareRoot(r0, Heap::kTrueValueRootIndex);
   2570     __ b(eq, if_true);
   2571     __ CompareRoot(r0, Heap::kFalseValueRootIndex);
   2572     Split(eq, if_true, if_false, fall_through);
   2573   } else if (String::Equals(check, factory->undefined_string())) {
   2574     __ CompareRoot(r0, Heap::kNullValueRootIndex);
   2575     __ b(eq, if_false);
   2576     __ JumpIfSmi(r0, if_false);
   2577     // Check for undetectable objects => true.
   2578     __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
   2579     __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
   2580     __ tst(r1, Operand(1 << Map::kIsUndetectable));
   2581     Split(ne, if_true, if_false, fall_through);
   2582 
   2583   } else if (String::Equals(check, factory->function_string())) {
   2584     __ JumpIfSmi(r0, if_false);
   2585     __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
   2586     __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
   2587     __ and_(r1, r1,
   2588             Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
   2589     __ cmp(r1, Operand(1 << Map::kIsCallable));
   2590     Split(eq, if_true, if_false, fall_through);
   2591   } else if (String::Equals(check, factory->object_string())) {
   2592     __ JumpIfSmi(r0, if_false);
   2593     __ CompareRoot(r0, Heap::kNullValueRootIndex);
   2594     __ b(eq, if_true);
   2595     STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
   2596     __ CompareObjectType(r0, r0, r1, FIRST_JS_RECEIVER_TYPE);
   2597     __ b(lt, if_false);
   2598     // Check for callable or undetectable objects => false.
   2599     __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
   2600     __ tst(r1, Operand((1 << Map::kIsCallable) | (1 << Map::kIsUndetectable)));
   2601     Split(eq, if_true, if_false, fall_through);
   2602   } else {
   2603     if (if_false != fall_through) __ jmp(if_false);
   2604   }
   2605   context()->Plug(if_true, if_false);
   2606 }
   2607 
   2608 
   2609 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
   2610   Comment cmnt(masm_, "[ CompareOperation");
   2611 
   2612   // First we try a fast inlined version of the compare when one of
   2613   // the operands is a literal.
   2614   if (TryLiteralCompare(expr)) return;
   2615 
   2616   // Always perform the comparison for its control flow.  Pack the result
   2617   // into the expression's context after the comparison is performed.
   2618   Label materialize_true, materialize_false;
   2619   Label* if_true = NULL;
   2620   Label* if_false = NULL;
   2621   Label* fall_through = NULL;
   2622   context()->PrepareTest(&materialize_true, &materialize_false,
   2623                          &if_true, &if_false, &fall_through);
   2624 
   2625   Token::Value op = expr->op();
   2626   VisitForStackValue(expr->left());
   2627   switch (op) {
   2628     case Token::IN:
   2629       VisitForStackValue(expr->right());
   2630       SetExpressionPosition(expr);
   2631       EmitHasProperty();
   2632       PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
   2633       __ CompareRoot(r0, Heap::kTrueValueRootIndex);
   2634       Split(eq, if_true, if_false, fall_through);
   2635       break;
   2636 
   2637     case Token::INSTANCEOF: {
   2638       VisitForAccumulatorValue(expr->right());
   2639       SetExpressionPosition(expr);
   2640       PopOperand(r1);
   2641       __ Call(isolate()->builtins()->InstanceOf(), RelocInfo::CODE_TARGET);
   2642       RestoreContext();
   2643       PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
   2644       __ CompareRoot(r0, Heap::kTrueValueRootIndex);
   2645       Split(eq, if_true, if_false, fall_through);
   2646       break;
   2647     }
   2648 
   2649     default: {
   2650       VisitForAccumulatorValue(expr->right());
   2651       SetExpressionPosition(expr);
   2652       Condition cond = CompareIC::ComputeCondition(op);
   2653       PopOperand(r1);
   2654 
   2655       bool inline_smi_code = ShouldInlineSmiCase(op);
   2656       JumpPatchSite patch_site(masm_);
   2657       if (inline_smi_code) {
   2658         Label slow_case;
   2659         __ orr(r2, r0, Operand(r1));
   2660         patch_site.EmitJumpIfNotSmi(r2, &slow_case);
   2661         __ cmp(r1, r0);
   2662         Split(cond, if_true, if_false, NULL);
   2663         __ bind(&slow_case);
   2664       }
   2665 
   2666       Handle<Code> ic = CodeFactory::CompareIC(isolate(), op).code();
   2667       CallIC(ic, expr->CompareOperationFeedbackId());
   2668       patch_site.EmitPatchInfo();
   2669       PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   2670       __ cmp(r0, Operand::Zero());
   2671       Split(cond, if_true, if_false, fall_through);
   2672     }
   2673   }
   2674 
   2675   // Convert the result of the comparison into one expected for this
   2676   // expression's context.
   2677   context()->Plug(if_true, if_false);
   2678 }
   2679 
   2680 
   2681 void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
   2682                                               Expression* sub_expr,
   2683                                               NilValue nil) {
   2684   Label materialize_true, materialize_false;
   2685   Label* if_true = NULL;
   2686   Label* if_false = NULL;
   2687   Label* fall_through = NULL;
   2688   context()->PrepareTest(&materialize_true, &materialize_false,
   2689                          &if_true, &if_false, &fall_through);
   2690 
   2691   VisitForAccumulatorValue(sub_expr);
   2692   PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
   2693   if (expr->op() == Token::EQ_STRICT) {
   2694     Heap::RootListIndex nil_value = nil == kNullValue ?
   2695         Heap::kNullValueRootIndex :
   2696         Heap::kUndefinedValueRootIndex;
   2697     __ LoadRoot(r1, nil_value);
   2698     __ cmp(r0, r1);
   2699     Split(eq, if_true, if_false, fall_through);
   2700   } else {
   2701     __ JumpIfSmi(r0, if_false);
   2702     __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
   2703     __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
   2704     __ tst(r1, Operand(1 << Map::kIsUndetectable));
   2705     Split(ne, if_true, if_false, fall_through);
   2706   }
   2707   context()->Plug(if_true, if_false);
   2708 }
   2709 
   2710 
   2711 Register FullCodeGenerator::result_register() {
   2712   return r0;
   2713 }
   2714 
   2715 
   2716 Register FullCodeGenerator::context_register() {
   2717   return cp;
   2718 }
   2719 
   2720 void FullCodeGenerator::LoadFromFrameField(int frame_offset, Register value) {
   2721   DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
   2722   __ ldr(value, MemOperand(fp, frame_offset));
   2723 }
   2724 
   2725 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
   2726   DCHECK_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
   2727   __ str(value, MemOperand(fp, frame_offset));
   2728 }
   2729 
   2730 
   2731 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
   2732   __ ldr(dst, ContextMemOperand(cp, context_index));
   2733 }
   2734 
   2735 
   2736 void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
   2737   DeclarationScope* closure_scope = scope()->GetClosureScope();
   2738   if (closure_scope->is_script_scope() ||
   2739       closure_scope->is_module_scope()) {
   2740     // Contexts nested in the native context have a canonical empty function
   2741     // as their closure, not the anonymous closure containing the global
   2742     // code.
   2743     __ LoadNativeContextSlot(Context::CLOSURE_INDEX, ip);
   2744   } else if (closure_scope->is_eval_scope()) {
   2745     // Contexts created by a call to eval have the same closure as the
   2746     // context calling eval, not the anonymous closure containing the eval
   2747     // code.  Fetch it from the context.
   2748     __ ldr(ip, ContextMemOperand(cp, Context::CLOSURE_INDEX));
   2749   } else {
   2750     DCHECK(closure_scope->is_function_scope());
   2751     __ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
   2752   }
   2753   PushOperand(ip);
   2754 }
   2755 
   2756 
   2757 #undef __
   2758 
   2759 
   2760 static Address GetInterruptImmediateLoadAddress(Address pc) {
   2761   Address load_address = pc - 2 * Assembler::kInstrSize;
   2762   if (!FLAG_enable_embedded_constant_pool) {
   2763     DCHECK(Assembler::IsLdrPcImmediateOffset(Memory::int32_at(load_address)));
   2764   } else if (Assembler::IsLdrPpRegOffset(Memory::int32_at(load_address))) {
   2765     // This is an extended constant pool lookup.
   2766     if (CpuFeatures::IsSupported(ARMv7)) {
   2767       load_address -= 2 * Assembler::kInstrSize;
   2768       DCHECK(Assembler::IsMovW(Memory::int32_at(load_address)));
   2769       DCHECK(Assembler::IsMovT(
   2770           Memory::int32_at(load_address + Assembler::kInstrSize)));
   2771     } else {
   2772       load_address -= 4 * Assembler::kInstrSize;
   2773       DCHECK(Assembler::IsMovImmed(Memory::int32_at(load_address)));
   2774       DCHECK(Assembler::IsOrrImmed(
   2775           Memory::int32_at(load_address + Assembler::kInstrSize)));
   2776       DCHECK(Assembler::IsOrrImmed(
   2777           Memory::int32_at(load_address + 2 * Assembler::kInstrSize)));
   2778       DCHECK(Assembler::IsOrrImmed(
   2779           Memory::int32_at(load_address + 3 * Assembler::kInstrSize)));
   2780     }
   2781   } else if (CpuFeatures::IsSupported(ARMv7) &&
   2782              Assembler::IsMovT(Memory::int32_at(load_address))) {
   2783     // This is a movw / movt immediate load.
   2784     load_address -= Assembler::kInstrSize;
   2785     DCHECK(Assembler::IsMovW(Memory::int32_at(load_address)));
   2786   } else if (!CpuFeatures::IsSupported(ARMv7) &&
   2787              Assembler::IsOrrImmed(Memory::int32_at(load_address))) {
   2788     // This is a mov / orr immediate load.
   2789     load_address -= 3 * Assembler::kInstrSize;
   2790     DCHECK(Assembler::IsMovImmed(Memory::int32_at(load_address)));
   2791     DCHECK(Assembler::IsOrrImmed(
   2792         Memory::int32_at(load_address + Assembler::kInstrSize)));
   2793     DCHECK(Assembler::IsOrrImmed(
   2794         Memory::int32_at(load_address + 2 * Assembler::kInstrSize)));
   2795   } else {
   2796     // This is a small constant pool lookup.
   2797     DCHECK(Assembler::IsLdrPpImmediateOffset(Memory::int32_at(load_address)));
   2798   }
   2799   return load_address;
   2800 }
   2801 
   2802 
   2803 void BackEdgeTable::PatchAt(Code* unoptimized_code,
   2804                             Address pc,
   2805                             BackEdgeState target_state,
   2806                             Code* replacement_code) {
   2807   Address pc_immediate_load_address = GetInterruptImmediateLoadAddress(pc);
   2808   Address branch_address = pc_immediate_load_address - Assembler::kInstrSize;
   2809   Isolate* isolate = unoptimized_code->GetIsolate();
   2810   CodePatcher patcher(isolate, branch_address, 1);
   2811   switch (target_state) {
   2812     case INTERRUPT:
   2813     {
   2814       //  <decrement profiling counter>
   2815       //   bpl ok
   2816       //   ; load interrupt stub address into ip - either of (for ARMv7):
   2817       //   ; <small cp load>      |  <extended cp load> |  <immediate load>
   2818       //   ldr ip, [pc/pp, #imm]  |   movw ip, #imm     |   movw ip, #imm
   2819       //                          |   movt ip, #imm     |   movw ip, #imm
   2820       //                          |   ldr  ip, [pp, ip]
   2821       //   ; or (for ARMv6):
   2822       //   ; <small cp load>      |  <extended cp load> |  <immediate load>
   2823       //   ldr ip, [pc/pp, #imm]  |   mov ip, #imm      |   mov ip, #imm
   2824       //                          |   orr ip, ip, #imm> |   orr ip, ip, #imm
   2825       //                          |   orr ip, ip, #imm> |   orr ip, ip, #imm
   2826       //                          |   orr ip, ip, #imm> |   orr ip, ip, #imm
   2827       //   blx ip
   2828       //  <reset profiling counter>
   2829       //  ok-label
   2830 
   2831       // Calculate branch offset to the ok-label - this is the difference
   2832       // between the branch address and |pc| (which points at <blx ip>) plus
   2833       // kProfileCounterResetSequence instructions
   2834       int branch_offset = pc - Instruction::kPCReadOffset - branch_address +
   2835                           kProfileCounterResetSequenceLength;
   2836       patcher.masm()->b(branch_offset, pl);
   2837       break;
   2838     }
   2839     case ON_STACK_REPLACEMENT:
   2840       //  <decrement profiling counter>
   2841       //   mov r0, r0 (NOP)
   2842       //   ; load on-stack replacement address into ip - either of (for ARMv7):
   2843       //   ; <small cp load>      |  <extended cp load> |  <immediate load>
   2844       //   ldr ip, [pc/pp, #imm]  |   movw ip, #imm     |   movw ip, #imm
   2845       //                          |   movt ip, #imm>    |   movw ip, #imm
   2846       //                          |   ldr  ip, [pp, ip]
   2847       //   ; or (for ARMv6):
   2848       //   ; <small cp load>      |  <extended cp load> |  <immediate load>
   2849       //   ldr ip, [pc/pp, #imm]  |   mov ip, #imm      |   mov ip, #imm
   2850       //                          |   orr ip, ip, #imm> |   orr ip, ip, #imm
   2851       //                          |   orr ip, ip, #imm> |   orr ip, ip, #imm
   2852       //                          |   orr ip, ip, #imm> |   orr ip, ip, #imm
   2853       //   blx ip
   2854       //  <reset profiling counter>
   2855       //  ok-label
   2856       patcher.masm()->nop();
   2857       break;
   2858   }
   2859 
   2860   // Replace the call address.
   2861   Assembler::set_target_address_at(isolate, pc_immediate_load_address,
   2862                                    unoptimized_code, replacement_code->entry());
   2863 
   2864   unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
   2865       unoptimized_code, pc_immediate_load_address, replacement_code);
   2866 }
   2867 
   2868 
   2869 BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
   2870     Isolate* isolate,
   2871     Code* unoptimized_code,
   2872     Address pc) {
   2873   DCHECK(Assembler::IsBlxIp(Memory::int32_at(pc - Assembler::kInstrSize)));
   2874 
   2875   Address pc_immediate_load_address = GetInterruptImmediateLoadAddress(pc);
   2876   Address branch_address = pc_immediate_load_address - Assembler::kInstrSize;
   2877 #ifdef DEBUG
   2878   Address interrupt_address = Assembler::target_address_at(
   2879       pc_immediate_load_address, unoptimized_code);
   2880 #endif
   2881 
   2882   if (Assembler::IsBranch(Assembler::instr_at(branch_address))) {
   2883     DCHECK(interrupt_address ==
   2884            isolate->builtins()->InterruptCheck()->entry());
   2885     return INTERRUPT;
   2886   }
   2887 
   2888   DCHECK(Assembler::IsNop(Assembler::instr_at(branch_address)));
   2889 
   2890   DCHECK(interrupt_address ==
   2891          isolate->builtins()->OnStackReplacement()->entry());
   2892   return ON_STACK_REPLACEMENT;
   2893 }
   2894 
   2895 
   2896 }  // namespace internal
   2897 }  // namespace v8
   2898 
   2899 #endif  // V8_TARGET_ARCH_ARM
   2900