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