blob: b362f12948f9624a474a2eaa3a8154e093f72c4b [file] [log] [blame]
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00001// Copyright 2012 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
jkummerow@chromium.org93a47f42013-07-02 14:43:41 +000030#if V8_TARGET_ARCH_ARM
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000031
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000032#include "code-stubs.h"
karlklose@chromium.org44bc7082011-04-11 12:33:05 +000033#include "codegen.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000034#include "compiler.h"
35#include "debug.h"
36#include "full-codegen.h"
danno@chromium.org88aa0582012-03-23 15:11:57 +000037#include "isolate-inl.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000039#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000040#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000041
lrn@chromium.org5d00b602011-01-05 09:51:43 +000042#include "arm/code-stubs-arm.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000043#include "arm/macro-assembler-arm.h"
lrn@chromium.org5d00b602011-01-05 09:51:43 +000044
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000045namespace v8 {
46namespace internal {
47
48#define __ ACCESS_MASM(masm_)
49
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000050
51// A patch site is a location in the code which it is possible to patch. This
52// class has a number of methods to emit the code which is patchable and the
53// method EmitPatchInfo to record a marker back to the patchable code. This
54// marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit
55// immediate value is used) is the delta from the pc to the first instruction of
56// the patchable code.
57class JumpPatchSite BASE_EMBEDDED {
58 public:
59 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
60#ifdef DEBUG
61 info_emitted_ = false;
62#endif
63 }
64
65 ~JumpPatchSite() {
66 ASSERT(patch_site_.is_bound() == info_emitted_);
67 }
68
69 // When initially emitting this ensure that a jump is always generated to skip
70 // the inlined smi code.
71 void EmitJumpIfNotSmi(Register reg, Label* target) {
72 ASSERT(!patch_site_.is_bound() && !info_emitted_);
danno@chromium.org1044a4d2012-04-30 12:34:39 +000073 Assembler::BlockConstPoolScope block_const_pool(masm_);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000074 __ bind(&patch_site_);
75 __ cmp(reg, Operand(reg));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000076 __ b(eq, target); // Always taken before patched.
77 }
78
79 // When initially emitting this ensure that a jump is never generated to skip
80 // the inlined smi code.
81 void EmitJumpIfSmi(Register reg, Label* target) {
82 ASSERT(!patch_site_.is_bound() && !info_emitted_);
danno@chromium.org1044a4d2012-04-30 12:34:39 +000083 Assembler::BlockConstPoolScope block_const_pool(masm_);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000084 __ bind(&patch_site_);
85 __ cmp(reg, Operand(reg));
86 __ b(ne, target); // Never taken before patched.
87 }
88
89 void EmitPatchInfo() {
mmassi@chromium.org7028c052012-06-13 11:51:58 +000090 // Block literal pool emission whilst recording patch site information.
91 Assembler::BlockConstPoolScope block_const_pool(masm_);
ricow@chromium.org4f693d62011-07-04 14:01:31 +000092 if (patch_site_.is_bound()) {
93 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
94 Register reg;
95 reg.set_code(delta_to_patch_site / kOff12Mask);
96 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000097#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000098 info_emitted_ = true;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000099#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000100 } else {
101 __ nop(); // Signals no inlined code.
102 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000103 }
104
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000105 private:
106 MacroAssembler* masm_;
107 Label patch_site_;
108#ifdef DEBUG
109 bool info_emitted_;
110#endif
111};
112
113
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000114// Generate code for a JS function. On entry to the function the receiver
115// and arguments have been pushed on the stack left to right. The actual
116// argument count matches the formal parameter count expected by the
117// function.
118//
119// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000120// o r1: the JS function object being called (i.e., ourselves)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000121// o cp: our context
ulan@chromium.org9ca30172014-01-02 12:10:54 +0000122// o pp: our caller's constant pool pointer (if FLAG_enable_ool_constant_pool)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000123// o fp: our caller's frame pointer
124// o sp: stack pointer
125// o lr: return address
126//
127// The function builds a JS frame. Please see JavaScriptFrameConstants in
128// frames-arm.h for its layout.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000129void FullCodeGenerator::Generate() {
130 CompilationInfo* info = info_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000131 handler_table_ =
132 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
danno@chromium.org41728482013-06-12 22:31:22 +0000133 profiling_counter_ = isolate()->factory()->NewCell(
yangguo@chromium.orgfb377212012-11-16 14:43:43 +0000134 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget), isolate()));
ager@chromium.org5c838252010-02-19 08:53:10 +0000135 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000136 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137
verwaest@chromium.org753aee42012-07-17 16:15:42 +0000138 ProfileEntryHookStub::MaybeCallEntryHook(masm_);
139
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000140#ifdef DEBUG
141 if (strlen(FLAG_stop_at) > 0 &&
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000142 info->function()->name()->IsUtf8EqualTo(CStrVector(FLAG_stop_at))) {
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000143 __ stop("stop-at");
144 }
145#endif
146
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000147 // Strict mode functions and builtins need to replace the receiver
148 // with undefined when called as functions (without an explicit
149 // receiver object). r5 is zero for method calls and non-zero for
150 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000151 if (!info->is_classic_mode() || info->is_native()) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +0000152 __ cmp(r5, Operand::Zero());
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000153 int receiver_offset = info->scope()->num_parameters() * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000154 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
jkummerow@chromium.orgef33a542013-10-28 18:03:37 +0000155 __ str(r2, MemOperand(sp, receiver_offset), ne);
danno@chromium.org40cb8782011-05-25 07:58:50 +0000156 }
157
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000158 // Open a frame scope to indicate that there is a frame on the stack. The
159 // MANUAL indicates that the scope shouldn't actually generate code to set up
160 // the frame (that is done below).
161 FrameScope frame_scope(masm_, StackFrame::MANUAL);
162
svenpanne@chromium.org83130cf2012-11-30 10:13:25 +0000163 info->set_prologue_offset(masm_->pc_offset());
bmeurer@chromium.orgc9913f02013-10-24 06:31:36 +0000164 __ Prologue(BUILD_FUNCTION_FRAME);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000165 info->AddNoFrameRange(0, masm_->pc_offset());
ulan@chromium.org9ca30172014-01-02 12:10:54 +0000166 __ LoadConstantPoolPointerRegister();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000167
168 { Comment cmnt(masm_, "[ Allocate locals");
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000169 int locals_count = info->scope()->num_stack_slots();
170 // Generators allocate locals, if any, in context slots.
171 ASSERT(!info->function()->is_generator() || locals_count == 0);
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000172 if (locals_count > 0) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000173 // Emit a loop to initialize stack cells for locals when optimizing for
174 // size. Otherwise, unroll the loop for maximum performance.
175 __ LoadRoot(r9, Heap::kUndefinedValueRootIndex);
176 if (FLAG_optimize_for_size && locals_count > 4) {
177 Label loop;
178 __ mov(r2, Operand(locals_count));
179 __ bind(&loop);
180 __ sub(r2, r2, Operand(1), SetCC);
181 __ push(r9);
182 __ b(&loop, ne);
183 } else {
184 for (int i = 0; i < locals_count; i++) {
185 __ push(r9);
186 }
jkummerow@chromium.org10480472013-07-17 08:22:15 +0000187 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000188 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000189 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000190
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000191 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000193 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000194 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000195 if (heap_slots > 0) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000196 // Argument to NewContext is the function, which is still in r1.
197 Comment cmnt(masm_, "[ Allocate context");
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000198 __ push(r1);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +0000199 if (FLAG_harmony_scoping && info->scope()->is_global_scope()) {
200 __ Push(info->scope()->GetScopeInfo());
201 __ CallRuntime(Runtime::kNewGlobalContext, 2);
202 } else if (heap_slots <= FastNewContextStub::kMaximumSlots) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000203 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000204 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000205 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000206 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000207 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000208 function_in_register = false;
209 // Context is returned in both r0 and cp. It replaces the context
210 // passed to us. It's saved in the stack and kept live in cp.
211 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
212 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000213 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000214 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000215 Variable* var = scope()->parameter(i);
216 if (var->IsContextSlot()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000217 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
218 (num_parameters - 1 - i) * kPointerSize;
219 // Load parameter from stack.
220 __ ldr(r0, MemOperand(fp, parameter_offset));
221 // Store it in the context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000222 MemOperand target = ContextOperand(cp, var->index());
223 __ str(r0, target);
224
225 // Update the write barrier.
226 __ RecordWriteContextSlot(
227 cp, target.offset(), r0, r3, kLRHasBeenSaved, kDontSaveFPRegs);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000228 }
229 }
230 }
231
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000232 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000233 if (arguments != NULL) {
234 // Function uses arguments object.
235 Comment cmnt(masm_, "[ Allocate arguments object");
236 if (!function_in_register) {
237 // Load this again, if it's used by the local context below.
238 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
239 } else {
240 __ mov(r3, r1);
241 }
242 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000243 int num_parameters = info->scope()->num_parameters();
244 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000245 __ add(r2, fp,
246 Operand(StandardFrameConstants::kCallerSPOffset + offset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000247 __ mov(r1, Operand(Smi::FromInt(num_parameters)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000248 __ Push(r3, r2, r1);
249
250 // Arguments to ArgumentsAccessStub:
251 // function, receiver address, parameter count.
252 // The stub will rewrite receiever and parameter count if the previous
253 // stack frame was an arguments adapter frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000254 ArgumentsAccessStub::Type type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000255 if (!is_classic_mode()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000256 type = ArgumentsAccessStub::NEW_STRICT;
257 } else if (function()->has_duplicate_parameters()) {
258 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
259 } else {
260 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
261 }
262 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000263 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000264
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000265 SetVar(arguments, r0, r1, r2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000266 }
267
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000268 if (FLAG_trace) {
269 __ CallRuntime(Runtime::kTraceEnter, 0);
270 }
271
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000272 // Visit the declarations and body unless there is an illegal
273 // redeclaration.
274 if (scope()->HasIllegalRedeclaration()) {
275 Comment cmnt(masm_, "[ Declarations");
276 scope()->VisitIllegalRedeclaration(this);
277
278 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000279 PrepareForBailoutForId(BailoutId::FunctionEntry(), NO_REGISTERS);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000280 { Comment cmnt(masm_, "[ Declarations");
281 // For named function expressions, declare the function name as a
282 // constant.
283 if (scope()->is_function_scope() && scope()->function() != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000284 VariableDeclaration* function = scope()->function();
285 ASSERT(function->proxy()->var()->mode() == CONST ||
286 function->proxy()->var()->mode() == CONST_HARMONY);
287 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
288 VisitVariableDeclaration(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000289 }
290 VisitDeclarations(scope()->declarations());
291 }
292
293 { Comment cmnt(masm_, "[ Stack check");
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000294 PrepareForBailoutForId(BailoutId::Declarations(), NO_REGISTERS);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000295 Label ok;
296 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
297 __ cmp(sp, Operand(ip));
298 __ b(hs, &ok);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000299 PredictableCodeSizeScope predictable(masm_, 2 * Assembler::kInstrSize);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000300 __ Call(isolate()->builtins()->StackCheck(), RelocInfo::CODE_TARGET);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000301 __ bind(&ok);
302 }
303
304 { Comment cmnt(masm_, "[ Body");
305 ASSERT(loop_depth() == 0);
306 VisitStatements(function()->body());
307 ASSERT(loop_depth() == 0);
308 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000309 }
310
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000311 // Always emit a 'return undefined' in case control fell off the end of
312 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000313 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000314 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
315 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000316 EmitReturnSequence();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000317
318 // Force emit the constant pool, so it doesn't get emitted in the middle
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000319 // of the back edge table.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000320 masm()->CheckConstPool(true, false);
321}
322
323
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000324void FullCodeGenerator::ClearAccumulator() {
325 __ mov(r0, Operand(Smi::FromInt(0)));
326}
327
328
danno@chromium.org88aa0582012-03-23 15:11:57 +0000329void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
330 __ mov(r2, Operand(profiling_counter_));
danno@chromium.org41728482013-06-12 22:31:22 +0000331 __ ldr(r3, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000332 __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC);
danno@chromium.org41728482013-06-12 22:31:22 +0000333 __ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000334}
335
336
337void FullCodeGenerator::EmitProfilingCounterReset() {
338 int reset_value = FLAG_interrupt_budget;
danno@chromium.org88aa0582012-03-23 15:11:57 +0000339 if (isolate()->IsDebuggerActive()) {
340 // Detect debug break requests as soon as possible.
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +0000341 reset_value = FLAG_interrupt_budget >> 4;
danno@chromium.org88aa0582012-03-23 15:11:57 +0000342 }
343 __ mov(r2, Operand(profiling_counter_));
344 __ mov(r3, Operand(Smi::FromInt(reset_value)));
danno@chromium.org41728482013-06-12 22:31:22 +0000345 __ str(r3, FieldMemOperand(r2, Cell::kValueOffset));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000346}
347
348
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000349void FullCodeGenerator::EmitBackEdgeBookkeeping(IterationStatement* stmt,
350 Label* back_edge_target) {
351 Comment cmnt(masm_, "[ Back edge bookkeeping");
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +0000352 // Block literal pools whilst emitting back edge code.
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000353 Assembler::BlockConstPoolScope block_const_pool(masm_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000354 Label ok;
danno@chromium.org88aa0582012-03-23 15:11:57 +0000355
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000356 ASSERT(back_edge_target->is_bound());
357 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
358 int weight = Min(kMaxBackEdgeWeight,
359 Max(1, distance / kCodeSizeMultiplier));
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000360 EmitProfilingCounterDecrement(weight);
361 __ b(pl, &ok);
jkummerow@chromium.orgdc94e192013-08-30 11:35:42 +0000362 __ Call(isolate()->builtins()->InterruptCheck(), RelocInfo::CODE_TARGET);
danno@chromium.org88aa0582012-03-23 15:11:57 +0000363
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000364 // Record a mapping of this PC offset to the OSR id. This is used to find
365 // the AST id from the unoptimized code in order to use it as a key into
366 // the deoptimization input data found in the optimized code.
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000367 RecordBackEdge(stmt->OsrEntryId());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000368
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +0000369 EmitProfilingCounterReset();
danno@chromium.org88aa0582012-03-23 15:11:57 +0000370
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000371 __ bind(&ok);
372 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000373 // Record a mapping of the OSR id to this PC. This is used if the OSR
374 // entry becomes the target of a bailout. We don't expect it to be, but
375 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000376 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000377}
378
379
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000380void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000381 Comment cmnt(masm_, "[ Return sequence");
382 if (return_label_.is_bound()) {
383 __ b(&return_label_);
384 } else {
385 __ bind(&return_label_);
386 if (FLAG_trace) {
387 // Push the return value on the stack as the parameter.
388 // Runtime::TraceExit returns its parameter in r0.
389 __ push(r0);
390 __ CallRuntime(Runtime::kTraceExit, 1);
391 }
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000392 // Pretend that the exit is a backwards jump to the entry.
393 int weight = 1;
394 if (info_->ShouldSelfOptimize()) {
395 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
396 } else {
397 int distance = masm_->pc_offset();
398 weight = Min(kMaxBackEdgeWeight,
399 Max(1, distance / kCodeSizeMultiplier));
danno@chromium.org88aa0582012-03-23 15:11:57 +0000400 }
machenbach@chromium.orgafbdadc2013-12-09 16:12:18 +0000401 EmitProfilingCounterDecrement(weight);
402 Label ok;
403 __ b(pl, &ok);
404 __ push(r0);
405 __ Call(isolate()->builtins()->InterruptCheck(),
406 RelocInfo::CODE_TARGET);
407 __ pop(r0);
408 EmitProfilingCounterReset();
409 __ bind(&ok);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000410
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000411#ifdef DEBUG
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000412 // Add a label for checking the size of the code used for returning.
413 Label check_exit_codesize;
ulan@chromium.org9ca30172014-01-02 12:10:54 +0000414 __ bind(&check_exit_codesize);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000415#endif
416 // Make sure that the constant pool is not emitted inside of the return
417 // sequence.
418 { Assembler::BlockConstPoolScope block_const_pool(masm_);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000419 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000420 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000421 // TODO(svenpanne) The code below is sometimes 4 words, sometimes 5!
422 PredictableCodeSizeScope predictable(masm_, -1);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000423 __ RecordJSReturn();
ulan@chromium.org9ca30172014-01-02 12:10:54 +0000424 int no_frame_start = __ LeaveFrame(StackFrame::JAVA_SCRIPT);
425 __ add(sp, sp, Operand(sp_delta));
426 __ Jump(lr);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +0000427 info_->AddNoFrameRange(no_frame_start, masm_->pc_offset());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000428 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000429
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000430#ifdef DEBUG
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000431 // Check that the size of the code used for returning is large enough
432 // for the debugger's requirements.
433 ASSERT(Assembler::kJSReturnSequenceInstructions <=
434 masm_->InstructionsGeneratedSince(&check_exit_codesize));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000435#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000436 }
437}
438
439
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000440void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
441 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000442}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000443
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000444
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000445void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
446 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
447 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000448}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000449
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000450
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000451void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
452 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
453 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000454 __ push(result_register());
455}
456
457
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000458void FullCodeGenerator::TestContext::Plug(Variable* var) const {
459 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000460 // For simplicity we always test the accumulator register.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000461 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000462 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000463 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000464}
465
466
467void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
468}
469
470
471void FullCodeGenerator::AccumulatorValueContext::Plug(
472 Heap::RootListIndex index) const {
473 __ LoadRoot(result_register(), index);
474}
475
476
477void FullCodeGenerator::StackValueContext::Plug(
478 Heap::RootListIndex index) const {
479 __ LoadRoot(result_register(), index);
480 __ push(result_register());
481}
482
483
484void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000485 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000486 true,
487 true_label_,
488 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000489 if (index == Heap::kUndefinedValueRootIndex ||
490 index == Heap::kNullValueRootIndex ||
491 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000492 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000493 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000494 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000495 } else {
496 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000497 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000498 }
499}
500
501
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000502void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
503}
504
505
506void FullCodeGenerator::AccumulatorValueContext::Plug(
507 Handle<Object> lit) const {
508 __ mov(result_register(), Operand(lit));
509}
510
511
512void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000513 // Immediates cannot be pushed directly.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000514 __ mov(result_register(), Operand(lit));
515 __ push(result_register());
516}
517
518
519void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000520 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000521 true,
522 true_label_,
523 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000524 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
525 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000526 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000527 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000528 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000529 } else if (lit->IsString()) {
530 if (String::cast(*lit)->length() == 0) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000531 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000532 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000533 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000534 }
535 } else if (lit->IsSmi()) {
536 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000537 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000538 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000540 }
541 } else {
542 // For simplicity we always test the accumulator register.
543 __ mov(result_register(), Operand(lit));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000544 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000545 }
546}
547
548
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000549void FullCodeGenerator::EffectContext::DropAndPlug(int count,
550 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000551 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000552 __ Drop(count);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000553}
554
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000555
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000556void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
557 int count,
558 Register reg) const {
559 ASSERT(count > 0);
560 __ Drop(count);
561 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000562}
563
564
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000565void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
566 Register reg) const {
567 ASSERT(count > 0);
568 if (count > 1) __ Drop(count - 1);
569 __ str(reg, MemOperand(sp, 0));
570}
571
572
573void FullCodeGenerator::TestContext::DropAndPlug(int count,
574 Register reg) const {
575 ASSERT(count > 0);
576 // For simplicity we always test the accumulator register.
577 __ Drop(count);
578 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000579 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000580 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000581}
582
583
584void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
585 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000586 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000587 __ bind(materialize_true);
588}
589
590
591void FullCodeGenerator::AccumulatorValueContext::Plug(
592 Label* materialize_true,
593 Label* materialize_false) const {
594 Label done;
595 __ bind(materialize_true);
596 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
597 __ jmp(&done);
598 __ bind(materialize_false);
599 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
600 __ bind(&done);
601}
602
603
604void FullCodeGenerator::StackValueContext::Plug(
605 Label* materialize_true,
606 Label* materialize_false) const {
607 Label done;
608 __ bind(materialize_true);
609 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000610 __ jmp(&done);
611 __ bind(materialize_false);
612 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000613 __ bind(&done);
verwaest@chromium.org057bd502013-11-06 12:03:29 +0000614 __ push(ip);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000615}
616
617
618void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
619 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000620 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000621 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000622}
623
624
625void FullCodeGenerator::EffectContext::Plug(bool flag) const {
626}
627
628
629void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
630 Heap::RootListIndex value_root_index =
631 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
632 __ LoadRoot(result_register(), value_root_index);
633}
634
635
636void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
637 Heap::RootListIndex value_root_index =
638 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
639 __ LoadRoot(ip, value_root_index);
640 __ push(ip);
641}
642
643
644void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000645 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000646 true,
647 true_label_,
648 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000649 if (flag) {
650 if (true_label_ != fall_through_) __ b(true_label_);
651 } else {
652 if (false_label_ != fall_through_) __ b(false_label_);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000653 }
654}
655
656
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000657void FullCodeGenerator::DoTest(Expression* condition,
658 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000659 Label* if_false,
660 Label* fall_through) {
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +0000661 Handle<Code> ic = ToBooleanStub::GetUninitialized(isolate());
662 CallIC(ic, RelocInfo::CODE_TARGET, condition->test_id());
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +0000663 __ tst(result_register(), result_register());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000664 Split(ne, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000665}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000666
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000667
ager@chromium.org378b34e2011-01-28 08:04:38 +0000668void FullCodeGenerator::Split(Condition cond,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000669 Label* if_true,
670 Label* if_false,
671 Label* fall_through) {
672 if (if_false == fall_through) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000673 __ b(cond, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000674 } else if (if_true == fall_through) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000675 __ b(NegateCondition(cond), if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000676 } else {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000677 __ b(cond, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000678 __ b(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000679 }
680}
681
682
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000683MemOperand FullCodeGenerator::StackOperand(Variable* var) {
684 ASSERT(var->IsStackAllocated());
685 // Offset is negative because higher indexes are at lower addresses.
686 int offset = -var->index() * kPointerSize;
687 // Adjust by a (parameter or local) base offset.
688 if (var->IsParameter()) {
689 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
690 } else {
691 offset += JavaScriptFrameConstants::kLocal0Offset;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000692 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000693 return MemOperand(fp, offset);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000694}
695
696
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000697MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
698 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
699 if (var->IsContextSlot()) {
700 int context_chain_length = scope()->ContextChainLength(var->scope());
701 __ LoadContext(scratch, context_chain_length);
702 return ContextOperand(scratch, var->index());
703 } else {
704 return StackOperand(var);
705 }
706}
707
708
709void FullCodeGenerator::GetVar(Register dest, Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000710 // Use destination as scratch.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000711 MemOperand location = VarOperand(var, dest);
712 __ ldr(dest, location);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000713}
714
715
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000716void FullCodeGenerator::SetVar(Variable* var,
717 Register src,
718 Register scratch0,
719 Register scratch1) {
720 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
721 ASSERT(!scratch0.is(src));
722 ASSERT(!scratch0.is(scratch1));
723 ASSERT(!scratch1.is(src));
724 MemOperand location = VarOperand(var, scratch0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000725 __ str(src, location);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000726
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000727 // Emit the write barrier code if the location is in the heap.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000728 if (var->IsContextSlot()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000729 __ RecordWriteContextSlot(scratch0,
730 location.offset(),
731 src,
732 scratch1,
733 kLRHasBeenSaved,
734 kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000735 }
736}
737
738
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000739void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000740 bool should_normalize,
741 Label* if_true,
742 Label* if_false) {
743 // Only prepare for bailouts before splits if we're in a test
744 // context. Otherwise, we let the Visit function deal with the
745 // preparation to avoid preparing with the same AST id twice.
746 if (!context()->IsTest() || !info_->IsOptimizable()) return;
747
748 Label skip;
749 if (should_normalize) __ b(&skip);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000750 PrepareForBailout(expr, TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000751 if (should_normalize) {
752 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
753 __ cmp(r0, ip);
754 Split(eq, if_true, if_false, NULL);
755 __ bind(&skip);
756 }
757}
758
759
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000760void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
761 // The variable in the declaration always resides in the current function
762 // context.
763 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +0000764 if (generate_debug_code_) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000765 // Check that we're not inside a with or catch context.
766 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
767 __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +0000768 __ Check(ne, kDeclarationInWithContext);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000769 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +0000770 __ Check(ne, kDeclarationInCatchContext);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000771 }
772}
773
774
775void FullCodeGenerator::VisitVariableDeclaration(
776 VariableDeclaration* declaration) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000777 // If it was not possible to allocate the variable at compile time, we
778 // need to "declare" it at runtime to make sure it actually exists in the
779 // local context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000780 VariableProxy* proxy = declaration->proxy();
781 VariableMode mode = declaration->mode();
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000782 Variable* variable = proxy->var();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000783 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000784 switch (variable->location()) {
785 case Variable::UNALLOCATED:
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000786 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000787 globals_->Add(variable->binding_needs_init()
788 ? isolate()->factory()->the_hole_value()
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000789 : isolate()->factory()->undefined_value(),
790 zone());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000791 break;
792
793 case Variable::PARAMETER:
794 case Variable::LOCAL:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000795 if (hole_init) {
796 Comment cmnt(masm_, "[ VariableDeclaration");
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000797 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000798 __ str(ip, StackOperand(variable));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000799 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000800 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000801
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000802 case Variable::CONTEXT:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000803 if (hole_init) {
804 Comment cmnt(masm_, "[ VariableDeclaration");
805 EmitDebugCheckDeclarationContext(variable);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000806 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000807 __ str(ip, ContextOperand(cp, variable->index()));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000808 // No write barrier since the_hole_value is in old space.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000809 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000810 }
811 break;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000812
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000813 case Variable::LOOKUP: {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000814 Comment cmnt(masm_, "[ VariableDeclaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000815 __ mov(r2, Operand(variable->name()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000816 // Declaration nodes are always introduced in one of four modes.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +0000817 ASSERT(IsDeclaredVariableMode(mode));
818 PropertyAttributes attr =
819 IsImmutableVariableMode(mode) ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000820 __ mov(r1, Operand(Smi::FromInt(attr)));
821 // Push initial value, if any.
822 // Note: For variables we must not push an initial value (such as
823 // 'undefined') because we may have a (legal) redeclaration and we
824 // must not destroy the current value.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000825 if (hole_init) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000826 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
827 __ Push(cp, r2, r1, r0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000828 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000829 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000830 __ Push(cp, r2, r1, r0);
831 }
832 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
833 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000834 }
835 }
836}
837
838
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000839void FullCodeGenerator::VisitFunctionDeclaration(
840 FunctionDeclaration* declaration) {
841 VariableProxy* proxy = declaration->proxy();
842 Variable* variable = proxy->var();
843 switch (variable->location()) {
844 case Variable::UNALLOCATED: {
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000845 globals_->Add(variable->name(), zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000846 Handle<SharedFunctionInfo> function =
847 Compiler::BuildFunctionInfo(declaration->fun(), script());
848 // Check for stack-overflow exception.
849 if (function.is_null()) return SetStackOverflow();
mmassi@chromium.org7028c052012-06-13 11:51:58 +0000850 globals_->Add(function, zone());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000851 break;
852 }
853
854 case Variable::PARAMETER:
855 case Variable::LOCAL: {
856 Comment cmnt(masm_, "[ FunctionDeclaration");
857 VisitForAccumulatorValue(declaration->fun());
858 __ str(result_register(), StackOperand(variable));
859 break;
860 }
861
862 case Variable::CONTEXT: {
863 Comment cmnt(masm_, "[ FunctionDeclaration");
864 EmitDebugCheckDeclarationContext(variable);
865 VisitForAccumulatorValue(declaration->fun());
866 __ str(result_register(), ContextOperand(cp, variable->index()));
867 int offset = Context::SlotOffset(variable->index());
868 // We know that we have written a function, which is not a smi.
869 __ RecordWriteContextSlot(cp,
870 offset,
871 result_register(),
872 r2,
873 kLRHasBeenSaved,
874 kDontSaveFPRegs,
875 EMIT_REMEMBERED_SET,
876 OMIT_SMI_CHECK);
877 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
878 break;
879 }
880
881 case Variable::LOOKUP: {
882 Comment cmnt(masm_, "[ FunctionDeclaration");
883 __ mov(r2, Operand(variable->name()));
884 __ mov(r1, Operand(Smi::FromInt(NONE)));
885 __ Push(cp, r2, r1);
886 // Push initial value for function declaration.
887 VisitForStackValue(declaration->fun());
888 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
889 break;
890 }
891 }
892}
893
894
895void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000896 Variable* variable = declaration->proxy()->var();
897 ASSERT(variable->location() == Variable::CONTEXT);
898 ASSERT(variable->interface()->IsFrozen());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000899
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000900 Comment cmnt(masm_, "[ ModuleDeclaration");
901 EmitDebugCheckDeclarationContext(variable);
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000902
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000903 // Load instance object.
904 __ LoadContext(r1, scope_->ContextChainLength(scope_->GlobalScope()));
905 __ ldr(r1, ContextOperand(r1, variable->interface()->Index()));
906 __ ldr(r1, ContextOperand(r1, Context::EXTENSION_INDEX));
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000907
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000908 // Assign it.
909 __ str(r1, ContextOperand(cp, variable->index()));
910 // We know that we have written a module, which is not a smi.
911 __ RecordWriteContextSlot(cp,
912 Context::SlotOffset(variable->index()),
913 r1,
914 r3,
915 kLRHasBeenSaved,
916 kDontSaveFPRegs,
917 EMIT_REMEMBERED_SET,
918 OMIT_SMI_CHECK);
919 PrepareForBailoutForId(declaration->proxy()->id(), NO_REGISTERS);
920
921 // Traverse into body.
922 Visit(declaration->module());
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000923}
924
925
926void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
927 VariableProxy* proxy = declaration->proxy();
928 Variable* variable = proxy->var();
929 switch (variable->location()) {
930 case Variable::UNALLOCATED:
931 // TODO(rossberg)
932 break;
933
934 case Variable::CONTEXT: {
935 Comment cmnt(masm_, "[ ImportDeclaration");
936 EmitDebugCheckDeclarationContext(variable);
937 // TODO(rossberg)
938 break;
939 }
940
941 case Variable::PARAMETER:
942 case Variable::LOCAL:
943 case Variable::LOOKUP:
944 UNREACHABLE();
945 }
946}
947
948
949void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
950 // TODO(rossberg)
951}
952
953
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000954void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
955 // Call the runtime to declare the globals.
956 // The context is the first argument.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000957 __ mov(r1, Operand(pairs));
958 __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
959 __ Push(cp, r1, r0);
960 __ CallRuntime(Runtime::kDeclareGlobals, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000961 // Return value is ignored.
962}
963
964
ulan@chromium.org8e8d8822012-11-23 14:36:46 +0000965void FullCodeGenerator::DeclareModules(Handle<FixedArray> descriptions) {
966 // Call the runtime to declare the modules.
967 __ Push(descriptions);
968 __ CallRuntime(Runtime::kDeclareModules, 1);
969 // Return value is ignored.
970}
971
972
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000973void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000974 Comment cmnt(masm_, "[ SwitchStatement");
975 Breakable nested_statement(this, stmt);
976 SetStatementPosition(stmt);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000977
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000978 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000979 VisitForStackValue(stmt->tag());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000980 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
981
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000982 ZoneList<CaseClause*>* clauses = stmt->cases();
983 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
984
985 Label next_test; // Recycled for each test.
986 // Compile all the tests with branches to their bodies.
987 for (int i = 0; i < clauses->length(); i++) {
988 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000989 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000990
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000991 // The default is not a test, but remember it as final fall through.
992 if (clause->is_default()) {
993 default_clause = clause;
994 continue;
995 }
996
997 Comment cmnt(masm_, "[ Case comparison");
998 __ bind(&next_test);
999 next_test.Unuse();
1000
1001 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001002 VisitForAccumulatorValue(clause->label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001003
ricow@chromium.org65fae842010-08-25 15:26:24 +00001004 // Perform the comparison as if via '==='.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001005 __ ldr(r1, MemOperand(sp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001006 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001007 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001008 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001009 Label slow_case;
1010 __ orr(r2, r1, r0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001011 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
1012
ricow@chromium.org65fae842010-08-25 15:26:24 +00001013 __ cmp(r1, r0);
1014 __ b(ne, &next_test);
1015 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001016 __ b(clause->body_target());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001017 __ bind(&slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001018 }
1019
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001020 // Record position before stub call for type feedback.
1021 SetSourcePosition(clause->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00001022 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), Token::EQ_STRICT);
danno@chromium.org88aa0582012-03-23 15:11:57 +00001023 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001024 patch_site.EmitPatchInfo();
danno@chromium.org40cb8782011-05-25 07:58:50 +00001025
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00001026 Label skip;
1027 __ b(&skip);
1028 PrepareForBailout(clause, TOS_REG);
1029 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1030 __ cmp(r0, ip);
1031 __ b(ne, &next_test);
1032 __ Drop(1);
1033 __ jmp(clause->body_target());
1034 __ bind(&skip);
1035
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001036 __ cmp(r0, Operand::Zero());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001037 __ b(ne, &next_test);
1038 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001039 __ b(clause->body_target());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001040 }
1041
1042 // Discard the test value and jump to the default if present, otherwise to
1043 // the end of the statement.
1044 __ bind(&next_test);
1045 __ Drop(1); // Switch value is no longer needed.
1046 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001047 __ b(nested_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001048 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001049 __ b(default_clause->body_target());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001050 }
1051
1052 // Compile all the case bodies.
1053 for (int i = 0; i < clauses->length(); i++) {
1054 Comment cmnt(masm_, "[ Case body");
1055 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001056 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001057 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001058 VisitStatements(clause->statements());
1059 }
1060
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001061 __ bind(nested_statement.break_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001062 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001063}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001064
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001065
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001066void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001067 Comment cmnt(masm_, "[ ForInStatement");
1068 SetStatementPosition(stmt);
1069
1070 Label loop, exit;
1071 ForIn loop_statement(this, stmt);
1072 increment_loop_depth();
1073
danno@chromium.org1fd77d52013-06-07 16:01:45 +00001074 // Get the object to enumerate over. If the object is null or undefined, skip
1075 // over the loop. See ECMA-262 version 5, section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001076 VisitForAccumulatorValue(stmt->enumerable());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001077 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1078 __ cmp(r0, ip);
1079 __ b(eq, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001080 Register null_value = r5;
1081 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
1082 __ cmp(r0, null_value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001083 __ b(eq, &exit);
1084
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001085 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1086
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001087 // Convert the object to a JS object.
1088 Label convert, done_convert;
ager@chromium.org378b34e2011-01-28 08:04:38 +00001089 __ JumpIfSmi(r0, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001090 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
1091 __ b(ge, &done_convert);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001092 __ bind(&convert);
1093 __ push(r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001094 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001095 __ bind(&done_convert);
1096 __ push(r0);
1097
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001098 // Check for proxies.
1099 Label call_runtime;
1100 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1101 __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE);
1102 __ b(le, &call_runtime);
1103
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001104 // Check cache validity in generated code. This is a fast case for
1105 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1106 // guarantee cache validity, call the runtime system to check cache
1107 // validity or get the property names in a fixed array.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001108 __ CheckEnumCache(null_value, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001109
1110 // The enum cache is valid. Load the map of the object being
1111 // iterated over and use the cache for the iteration.
1112 Label use_cache;
1113 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
1114 __ b(&use_cache);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001115
1116 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001117 __ bind(&call_runtime);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001118 __ push(r0); // Duplicate the enumerable object on the stack.
1119 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1120
1121 // If we got a map from the runtime call, we can do a fast
1122 // modification check. Otherwise, we got a fixed array, and we have
1123 // to do a slow check.
1124 Label fixed_array;
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001125 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001126 __ LoadRoot(ip, Heap::kMetaMapRootIndex);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001127 __ cmp(r2, ip);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001128 __ b(ne, &fixed_array);
1129
1130 // We got a map in register r0. Get the enumeration cache from it.
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001131 Label no_descriptors;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001132 __ bind(&use_cache);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001133
1134 __ EnumLength(r1, r0);
1135 __ cmp(r1, Operand(Smi::FromInt(0)));
1136 __ b(eq, &no_descriptors);
1137
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00001138 __ LoadInstanceDescriptors(r0, r2);
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001139 __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheOffset));
1140 __ ldr(r2, FieldMemOperand(r2, DescriptorArray::kEnumCacheBridgeCacheOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001141
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001142 // Set up the four remaining stack slots.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001143 __ push(r0); // Map.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001144 __ mov(r0, Operand(Smi::FromInt(0)));
1145 // Push enumeration cache, enumeration cache length (as smi) and zero.
1146 __ Push(r2, r1, r0);
1147 __ jmp(&loop);
1148
yangguo@chromium.org355cfd12012-08-29 15:32:24 +00001149 __ bind(&no_descriptors);
1150 __ Drop(1);
1151 __ jmp(&exit);
1152
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001153 // We got a fixed array in register r0. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001154 Label non_proxy;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001155 __ bind(&fixed_array);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001156
danno@chromium.org41728482013-06-12 22:31:22 +00001157 Handle<Cell> cell = isolate()->factory()->NewCell(
1158 Handle<Object>(Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker),
1159 isolate()));
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001160 RecordTypeFeedbackCell(stmt->ForInFeedbackId(), cell);
bmeurer@chromium.orge94b5ff2013-10-25 09:22:31 +00001161 __ Move(r1, cell);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001162 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
danno@chromium.org41728482013-06-12 22:31:22 +00001163 __ str(r2, FieldMemOperand(r1, Cell::kValueOffset));
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001164
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001165 __ mov(r1, Operand(Smi::FromInt(1))); // Smi indicates slow check
1166 __ ldr(r2, MemOperand(sp, 0 * kPointerSize)); // Get enumerated object
1167 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1168 __ CompareObjectType(r2, r3, r3, LAST_JS_PROXY_TYPE);
1169 __ b(gt, &non_proxy);
1170 __ mov(r1, Operand(Smi::FromInt(0))); // Zero indicates proxy
1171 __ bind(&non_proxy);
1172 __ Push(r1, r0); // Smi and array
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001173 __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001174 __ mov(r0, Operand(Smi::FromInt(0)));
1175 __ Push(r1, r0); // Fixed array length (as smi) and initial index.
1176
1177 // Generate code for doing the condition check.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001178 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001179 __ bind(&loop);
1180 // Load the current count to r0, load the length to r1.
1181 __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
1182 __ cmp(r0, r1); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001183 __ b(hs, loop_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001184
1185 // Get the current entry of the array into register r3.
1186 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
1187 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00001188 __ ldr(r3, MemOperand::PointerAddressFromSmiKey(r2, r0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001189
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001190 // Get the expected map from the stack or a smi in the
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001191 // permanent slow case into register r2.
1192 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
1193
1194 // Check if the expected map still matches that of the enumerable.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001195 // If not, we may have to filter the key.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001196 Label update_each;
1197 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
1198 __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
1199 __ cmp(r4, Operand(r2));
1200 __ b(eq, &update_each);
1201
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001202 // For proxies, no filtering is done.
1203 // TODO(rossberg): What if only a prototype is a proxy? Not specified yet.
1204 __ cmp(r2, Operand(Smi::FromInt(0)));
1205 __ b(eq, &update_each);
1206
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001207 // Convert the entry to a string or (smi) 0 if it isn't a property
1208 // any more. If the property has been removed while iterating, we
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001209 // just skip it.
1210 __ push(r1); // Enumerable.
1211 __ push(r3); // Current entry.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001212 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001213 __ mov(r3, Operand(r0), SetCC);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001214 __ b(eq, loop_statement.continue_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001215
1216 // Update the 'each' property or variable from the possibly filtered
1217 // entry in register r3.
1218 __ bind(&update_each);
1219 __ mov(result_register(), r3);
1220 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001221 { EffectContext context(this);
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001222 EmitAssignment(stmt->each());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001223 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001224
1225 // Generate code for the body of the loop.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001226 Visit(stmt->body());
1227
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001228 // Generate code for the going to the next element by incrementing
1229 // the index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001230 __ bind(loop_statement.continue_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001231 __ pop(r0);
1232 __ add(r0, r0, Operand(Smi::FromInt(1)));
1233 __ push(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001234
rossberg@chromium.orgcddc71f2012-12-07 12:40:13 +00001235 EmitBackEdgeBookkeeping(stmt, &loop);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001236 __ b(&loop);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001237
1238 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001239 __ bind(loop_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001240 __ Drop(5);
1241
1242 // Exit and decrement the loop depth.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001243 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001244 __ bind(&exit);
1245 decrement_loop_depth();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001246}
1247
1248
danno@chromium.org1fd77d52013-06-07 16:01:45 +00001249void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1250 Comment cmnt(masm_, "[ ForOfStatement");
1251 SetStatementPosition(stmt);
1252
1253 Iteration loop_statement(this, stmt);
1254 increment_loop_depth();
1255
1256 // var iterator = iterable[@@iterator]()
1257 VisitForAccumulatorValue(stmt->assign_iterator());
1258
1259 // As with for-in, skip the loop if the iterator is null or undefined.
1260 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
1261 __ b(eq, loop_statement.break_label());
1262 __ CompareRoot(r0, Heap::kNullValueRootIndex);
1263 __ b(eq, loop_statement.break_label());
1264
1265 // Convert the iterator to a JS object.
1266 Label convert, done_convert;
1267 __ JumpIfSmi(r0, &convert);
1268 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
1269 __ b(ge, &done_convert);
1270 __ bind(&convert);
1271 __ push(r0);
1272 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
1273 __ bind(&done_convert);
1274 __ push(r0);
1275
1276 // Loop entry.
1277 __ bind(loop_statement.continue_label());
1278
1279 // result = iterator.next()
1280 VisitForEffect(stmt->next_result());
1281
1282 // if (result.done) break;
1283 Label result_not_done;
1284 VisitForControl(stmt->result_done(),
1285 loop_statement.break_label(),
1286 &result_not_done,
1287 &result_not_done);
1288 __ bind(&result_not_done);
1289
1290 // each = result.value
1291 VisitForEffect(stmt->assign_each());
1292
1293 // Generate code for the body of the loop.
1294 Visit(stmt->body());
1295
1296 // Check stack before looping.
1297 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
1298 EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
1299 __ jmp(loop_statement.continue_label());
1300
1301 // Exit and decrement the loop depth.
1302 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1303 __ bind(loop_statement.break_label());
1304 decrement_loop_depth();
1305}
1306
1307
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001308void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1309 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001310 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001311 // space for nested functions that don't need literals cloning. If
1312 // we're running with the --always-opt or the --prepare-always-opt
1313 // flag, we need to use the runtime function so that the new function
1314 // we are creating here gets a chance to have its code optimized and
1315 // doesn't just get a copy of the existing unoptimized code.
1316 if (!FLAG_always_opt &&
1317 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001318 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001319 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001320 info->num_literals() == 0) {
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00001321 FastNewClosureStub stub(info->language_mode(), info->is_generator());
verwaest@chromium.org662436e2013-08-28 08:41:27 +00001322 __ mov(r2, Operand(info));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001323 __ CallStub(&stub);
1324 } else {
1325 __ mov(r0, Operand(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001326 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
1327 : Heap::kFalseValueRootIndex);
1328 __ Push(cp, r0, r1);
1329 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001330 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001331 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001332}
1333
1334
1335void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1336 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001337 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001338}
1339
1340
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001341void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1342 TypeofState typeof_state,
1343 Label* slow) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001344 Register current = cp;
1345 Register next = r1;
1346 Register temp = r2;
1347
1348 Scope* s = scope();
1349 while (s != NULL) {
1350 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001351 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001352 // Check that extension is NULL.
1353 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
1354 __ tst(temp, temp);
1355 __ b(ne, slow);
1356 }
1357 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001358 __ ldr(next, ContextOperand(current, Context::PREVIOUS_INDEX));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001359 // Walk the rest of the chain without clobbering cp.
1360 current = next;
1361 }
1362 // If no outer scope calls eval, we do not need to check more
1363 // context extensions.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001364 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001365 s = s->outer_scope();
1366 }
1367
1368 if (s->is_eval_scope()) {
1369 Label loop, fast;
1370 if (!current.is(next)) {
1371 __ Move(next, current);
1372 }
1373 __ bind(&loop);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001374 // Terminate at native context.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001375 __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00001376 __ LoadRoot(ip, Heap::kNativeContextMapRootIndex);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001377 __ cmp(temp, ip);
1378 __ b(eq, &fast);
1379 // Check that extension is NULL.
1380 __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX));
1381 __ tst(temp, temp);
1382 __ b(ne, slow);
1383 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001384 __ ldr(next, ContextOperand(next, Context::PREVIOUS_INDEX));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001385 __ b(&loop);
1386 __ bind(&fast);
1387 }
1388
1389 __ ldr(r0, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001390 __ mov(r2, Operand(var->name()));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001391 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1392 ? RelocInfo::CODE_TARGET
1393 : RelocInfo::CODE_TARGET_CONTEXT;
1394 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001395 CallIC(ic, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001396}
1397
1398
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001399MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1400 Label* slow) {
1401 ASSERT(var->IsContextSlot());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001402 Register context = cp;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001403 Register next = r3;
1404 Register temp = r4;
1405
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001406 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001407 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001408 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001409 // Check that extension is NULL.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001410 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001411 __ tst(temp, temp);
1412 __ b(ne, slow);
1413 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001414 __ ldr(next, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001415 // Walk the rest of the chain without clobbering cp.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001416 context = next;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001417 }
1418 }
1419 // Check that last extension is NULL.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001420 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001421 __ tst(temp, temp);
1422 __ b(ne, slow);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001423
1424 // This function is used only for loads, not stores, so it's safe to
1425 // return an cp-based operand (the write barrier cannot be allowed to
1426 // destroy the cp register).
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001427 return ContextOperand(context, var->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001428}
1429
1430
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001431void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1432 TypeofState typeof_state,
1433 Label* slow,
1434 Label* done) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001435 // Generate fast-case code for variables that might be shadowed by
1436 // eval-introduced variables. Eval is used a lot without
1437 // introducing variables. In those cases, we do not want to
1438 // perform a runtime call for all variables in the scope
1439 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001440 if (var->mode() == DYNAMIC_GLOBAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001441 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001442 __ jmp(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001443 } else if (var->mode() == DYNAMIC_LOCAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001444 Variable* local = var->local_if_not_shadowed();
1445 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
ulan@chromium.org8e8d8822012-11-23 14:36:46 +00001446 if (local->mode() == LET ||
1447 local->mode() == CONST ||
1448 local->mode() == CONST_HARMONY) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001449 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001450 if (local->mode() == CONST) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001451 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001452 } else { // LET || CONST_HARMONY
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001453 __ b(ne, done);
1454 __ mov(r0, Operand(var->name()));
1455 __ push(r0);
1456 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1457 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001458 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001459 __ jmp(done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001460 }
1461}
1462
1463
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001464void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1465 // Record position before possible IC call.
1466 SetSourcePosition(proxy->position());
1467 Variable* var = proxy->var();
1468
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001469 // Three cases: global variables, lookup variables, and all other types of
1470 // variables.
1471 switch (var->location()) {
1472 case Variable::UNALLOCATED: {
1473 Comment cmnt(masm_, "Global variable");
1474 // Use inline caching. Variable name is passed in r2 and the global
1475 // object (receiver) in r0.
1476 __ ldr(r0, GlobalObjectOperand());
1477 __ mov(r2, Operand(var->name()));
1478 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001479 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001480 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001481 break;
1482 }
1483
1484 case Variable::PARAMETER:
1485 case Variable::LOCAL:
1486 case Variable::CONTEXT: {
1487 Comment cmnt(masm_, var->IsContextSlot()
1488 ? "Context variable"
1489 : "Stack variable");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001490 if (var->binding_needs_init()) {
1491 // var->scope() may be NULL when the proxy is located in eval code and
1492 // refers to a potential outside binding. Currently those bindings are
1493 // always looked up dynamically, i.e. in that case
1494 // var->location() == LOOKUP.
1495 // always holds.
1496 ASSERT(var->scope() != NULL);
1497
1498 // Check if the binding really needs an initialization check. The check
1499 // can be skipped in the following situation: we have a LET or CONST
1500 // binding in harmony mode, both the Variable and the VariableProxy have
1501 // the same declaration scope (i.e. they are both in global code, in the
1502 // same function or in the same eval code) and the VariableProxy is in
1503 // the source physically located after the initializer of the variable.
1504 //
1505 // We cannot skip any initialization checks for CONST in non-harmony
1506 // mode because const variables may be declared but never initialized:
1507 // if (false) { const x; }; var y = x;
1508 //
1509 // The condition on the declaration scopes is a conservative check for
1510 // nested functions that access a binding and are called before the
1511 // binding is initialized:
1512 // function() { f(); let x = 1; function f() { x = 2; } }
1513 //
1514 bool skip_init_check;
1515 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1516 skip_init_check = false;
jkummerow@chromium.orgac45fed2011-11-07 13:11:02 +00001517 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001518 // Check that we always have valid source position.
1519 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1520 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1521 skip_init_check = var->mode() != CONST &&
1522 var->initializer_position() < proxy->position();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001523 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001524
1525 if (!skip_init_check) {
1526 // Let and const need a read barrier.
1527 GetVar(r0, var);
1528 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
1529 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1530 // Throw a reference error when using an uninitialized let/const
1531 // binding in harmony mode.
1532 Label done;
1533 __ b(ne, &done);
1534 __ mov(r0, Operand(var->name()));
1535 __ push(r0);
1536 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1537 __ bind(&done);
1538 } else {
1539 // Uninitalized const bindings outside of harmony mode are unholed.
1540 ASSERT(var->mode() == CONST);
1541 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1542 }
1543 context()->Plug(r0);
1544 break;
1545 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001546 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001547 context()->Plug(var);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001548 break;
1549 }
1550
1551 case Variable::LOOKUP: {
1552 Label done, slow;
1553 // Generate code for loading from variables potentially shadowed
1554 // by eval-introduced variables.
1555 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1556 __ bind(&slow);
1557 Comment cmnt(masm_, "Lookup variable");
1558 __ mov(r1, Operand(var->name()));
1559 __ Push(cp, r1); // Context and name.
1560 __ CallRuntime(Runtime::kLoadContextSlot, 2);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001561 __ bind(&done);
1562 context()->Plug(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001563 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001564 }
1565}
1566
1567
1568void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1569 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001570 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001571 // Registers will be used as follows:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001572 // r5 = materialized value (RegExp literal)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001573 // r4 = JS function, literals array
1574 // r3 = literal index
1575 // r2 = RegExp pattern
1576 // r1 = RegExp flags
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001577 // r0 = RegExp literal clone
ricow@chromium.org65fae842010-08-25 15:26:24 +00001578 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1579 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001580 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001581 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001582 __ ldr(r5, FieldMemOperand(r4, literal_offset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001583 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001584 __ cmp(r5, ip);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001585 __ b(ne, &materialized);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001586
1587 // Create regexp literal using runtime function.
1588 // Result will be in r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001589 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1590 __ mov(r2, Operand(expr->pattern()));
1591 __ mov(r1, Operand(expr->flags()));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001592 __ Push(r4, r3, r2, r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001593 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001594 __ mov(r5, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001595
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001596 __ bind(&materialized);
1597 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001598 Label allocated, runtime_allocate;
svenpanne@chromium.org2bda5432013-03-15 12:39:50 +00001599 __ Allocate(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001600 __ jmp(&allocated);
1601
1602 __ bind(&runtime_allocate);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001603 __ mov(r0, Operand(Smi::FromInt(size)));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001604 __ Push(r5, r0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001605 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001606 __ pop(r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001607
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001608 __ bind(&allocated);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001609 // After this, registers are used as follows:
1610 // r0: Newly allocated regexp.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001611 // r5: Materialized regexp.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001612 // r2: temp.
jkummerow@chromium.orgfb732b12013-07-26 10:27:09 +00001613 __ CopyFields(r0, r5, d0, size / kPointerSize);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001614 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001615}
1616
1617
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001618void FullCodeGenerator::EmitAccessor(Expression* expression) {
1619 if (expression == NULL) {
1620 __ LoadRoot(r1, Heap::kNullValueRootIndex);
1621 __ push(r1);
1622 } else {
1623 VisitForStackValue(expression);
1624 }
1625}
1626
1627
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001628void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1629 Comment cmnt(masm_, "[ ObjectLiteral");
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00001630
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001631 expr->BuildConstantProperties(isolate());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001632 Handle<FixedArray> constant_properties = expr->constant_properties();
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001633 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001634 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1635 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001636 __ mov(r1, Operand(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001637 int flags = expr->fast_elements()
1638 ? ObjectLiteral::kFastElements
1639 : ObjectLiteral::kNoFlags;
1640 flags |= expr->has_function()
1641 ? ObjectLiteral::kHasFunction
1642 : ObjectLiteral::kNoFlags;
1643 __ mov(r0, Operand(Smi::FromInt(flags)));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001644 int properties_count = constant_properties->length() / 2;
ulan@chromium.org57ff8812013-05-10 08:16:55 +00001645 if ((FLAG_track_double_fields && expr->may_store_doubles()) ||
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001646 expr->depth() > 1 || Serializer::enabled() ||
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001647 flags != ObjectLiteral::kFastElements ||
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001648 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
mstarzinger@chromium.org71fc3462013-02-27 09:34:27 +00001649 __ Push(r3, r2, r1, r0);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00001650 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001651 } else {
1652 FastCloneShallowObjectStub stub(properties_count);
1653 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001654 }
1655
1656 // If result_saved is true the result is on top of the stack. If
1657 // result_saved is false the result is in r0.
1658 bool result_saved = false;
1659
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001660 // Mark all computed expressions that are bound to a key that
1661 // is shadowed by a later occurrence of the same key. For the
1662 // marked expressions, no store code is emitted.
mmassi@chromium.org7028c052012-06-13 11:51:58 +00001663 expr->CalculateEmitStore(zone());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001664
yangguo@chromium.org5a11aaf2012-06-20 11:29:00 +00001665 AccessorTable accessor_table(zone());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001666 for (int i = 0; i < expr->properties()->length(); i++) {
1667 ObjectLiteral::Property* property = expr->properties()->at(i);
1668 if (property->IsCompileTimeValue()) continue;
1669
1670 Literal* key = property->key();
1671 Expression* value = property->value();
1672 if (!result_saved) {
1673 __ push(r0); // Save result on stack
1674 result_saved = true;
1675 }
1676 switch (property->kind()) {
1677 case ObjectLiteral::Property::CONSTANT:
1678 UNREACHABLE();
1679 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1680 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
1681 // Fall through.
1682 case ObjectLiteral::Property::COMPUTED:
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001683 if (key->value()->IsInternalizedString()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001684 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001685 VisitForAccumulatorValue(value);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001686 __ mov(r2, Operand(key->value()));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001687 __ ldr(r1, MemOperand(sp));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001688 Handle<Code> ic = is_classic_mode()
1689 ? isolate()->builtins()->StoreIC_Initialize()
1690 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001691 CallIC(ic, RelocInfo::CODE_TARGET, key->LiteralFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001692 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1693 } else {
1694 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001695 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001696 break;
1697 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001698 // Duplicate receiver on stack.
1699 __ ldr(r0, MemOperand(sp));
1700 __ push(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001701 VisitForStackValue(key);
1702 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001703 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001704 __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1705 __ push(r0);
1706 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001707 } else {
1708 __ Drop(3);
1709 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001710 break;
ulan@chromium.org750145a2013-03-07 15:14:13 +00001711 case ObjectLiteral::Property::PROTOTYPE:
1712 // Duplicate receiver on stack.
1713 __ ldr(r0, MemOperand(sp));
1714 __ push(r0);
1715 VisitForStackValue(value);
1716 if (property->emit_store()) {
1717 __ CallRuntime(Runtime::kSetPrototype, 2);
1718 } else {
1719 __ Drop(2);
1720 }
1721 break;
1722
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001723 case ObjectLiteral::Property::GETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001724 accessor_table.lookup(key)->second->getter = value;
1725 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001726 case ObjectLiteral::Property::SETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001727 accessor_table.lookup(key)->second->setter = value;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001728 break;
1729 }
1730 }
1731
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001732 // Emit code to define accessors, using only a single call to the runtime for
1733 // each pair of corresponding getters and setters.
1734 for (AccessorTable::Iterator it = accessor_table.begin();
1735 it != accessor_table.end();
1736 ++it) {
1737 __ ldr(r0, MemOperand(sp)); // Duplicate receiver.
1738 __ push(r0);
1739 VisitForStackValue(it->first);
1740 EmitAccessor(it->second->getter);
1741 EmitAccessor(it->second->setter);
1742 __ mov(r0, Operand(Smi::FromInt(NONE)));
1743 __ push(r0);
1744 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1745 }
1746
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001747 if (expr->has_function()) {
1748 ASSERT(result_saved);
1749 __ ldr(r0, MemOperand(sp));
1750 __ push(r0);
1751 __ CallRuntime(Runtime::kToFastProperties, 1);
1752 }
1753
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001754 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001755 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001756 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001757 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001758 }
1759}
1760
1761
1762void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1763 Comment cmnt(masm_, "[ ArrayLiteral");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001764
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001765 expr->BuildConstantElements(isolate());
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001766 int flags = expr->depth() == 1
1767 ? ArrayLiteral::kShallowElements
1768 : ArrayLiteral::kNoFlags;
1769
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001770 ZoneList<Expression*>* subexprs = expr->values();
1771 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001772 Handle<FixedArray> constant_elements = expr->constant_elements();
1773 ASSERT_EQ(2, constant_elements->length());
1774 ElementsKind constant_elements_kind =
1775 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001776 bool has_fast_elements = IsFastObjectElementsKind(constant_elements_kind);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001777 Handle<FixedArrayBase> constant_elements_values(
1778 FixedArrayBase::cast(constant_elements->get(1)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001779
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00001780 AllocationSiteMode allocation_site_mode = FLAG_track_allocation_sites
1781 ? TRACK_ALLOCATION_SITE : DONT_TRACK_ALLOCATION_SITE;
1782 if (has_fast_elements && !FLAG_allocation_site_pretenuring) {
1783 // If the only customer of allocation sites is transitioning, then
1784 // we can turn it off if we don't have anywhere else to transition to.
1785 allocation_site_mode = DONT_TRACK_ALLOCATION_SITE;
1786 }
1787
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001788 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1789 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1790 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001791 __ mov(r1, Operand(constant_elements));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001792 if (has_fast_elements && constant_elements_values->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001793 isolate()->heap()->fixed_cow_array_map()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001794 FastCloneShallowArrayStub stub(
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001795 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS,
machenbach@chromium.orgc86e8c22013-11-27 15:11:04 +00001796 allocation_site_mode,
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001797 length);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001798 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001799 __ IncrementCounter(
1800 isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
machenbach@chromium.org7ff76072013-11-21 09:47:43 +00001801 } else if (expr->depth() > 1 || Serializer::enabled() ||
verwaest@chromium.org057bd502013-11-06 12:03:29 +00001802 length > FastCloneShallowArrayStub::kMaximumClonedLength) {
machenbach@chromium.org37be4082013-11-26 13:50:38 +00001803 __ mov(r0, Operand(Smi::FromInt(flags)));
1804 __ Push(r3, r2, r1, r0);
1805 __ CallRuntime(Runtime::kCreateArrayLiteral, 4);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001806 } else {
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001807 ASSERT(IsFastSmiOrObjectElementsKind(constant_elements_kind) ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001808 FLAG_smi_only_arrays);
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001809 FastCloneShallowArrayStub::Mode mode =
1810 FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001811
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001812 if (has_fast_elements) {
1813 mode = FastCloneShallowArrayStub::CLONE_ELEMENTS;
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00001814 }
1815
yangguo@chromium.org46a2a512013-01-18 16:29:40 +00001816 FastCloneShallowArrayStub stub(mode, allocation_site_mode, length);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001817 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001818 }
1819
1820 bool result_saved = false; // Is the result saved to the stack?
1821
1822 // Emit code to evaluate all the non-constant subexpressions and to store
1823 // them into the newly cloned array.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001824 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001825 Expression* subexpr = subexprs->at(i);
1826 // If the subexpression is a literal or a simple materialized literal it
1827 // is already set in the cloned array.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001828 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001829
1830 if (!result_saved) {
1831 __ push(r0);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001832 __ Push(Smi::FromInt(expr->literal_index()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001833 result_saved = true;
1834 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001835 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001836
svenpanne@chromium.org830d30c2012-05-29 13:20:14 +00001837 if (IsFastObjectElementsKind(constant_elements_kind)) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001838 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001839 __ ldr(r6, MemOperand(sp, kPointerSize)); // Copy of array literal.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001840 __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
1841 __ str(result_register(), FieldMemOperand(r1, offset));
1842 // Update the write barrier for the array store.
1843 __ RecordWriteField(r1, offset, result_register(), r2,
1844 kLRHasBeenSaved, kDontSaveFPRegs,
1845 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
1846 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001847 __ mov(r3, Operand(Smi::FromInt(i)));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001848 StoreArrayLiteralElementStub stub;
1849 __ CallStub(&stub);
1850 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001851
1852 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001853 }
1854
1855 if (result_saved) {
dslomov@chromium.orgb752d402013-06-18 11:54:54 +00001856 __ pop(); // literal index
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001857 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001858 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001859 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001860 }
1861}
1862
1863
ager@chromium.org5c838252010-02-19 08:53:10 +00001864void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1865 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001866 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1867 // on the left-hand side.
1868 if (!expr->target()->IsValidLeftHandSide()) {
1869 VisitForEffect(expr->target());
1870 return;
1871 }
1872
ager@chromium.org5c838252010-02-19 08:53:10 +00001873 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001874 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001875 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1876 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001877 Property* property = expr->target()->AsProperty();
1878 if (property != NULL) {
1879 assign_type = (property->key()->IsPropertyName())
1880 ? NAMED_PROPERTY
1881 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001882 }
1883
1884 // Evaluate LHS expression.
1885 switch (assign_type) {
1886 case VARIABLE:
1887 // Nothing to do here.
1888 break;
1889 case NAMED_PROPERTY:
1890 if (expr->is_compound()) {
1891 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001892 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001893 __ push(result_register());
1894 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001895 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001896 }
1897 break;
1898 case KEYED_PROPERTY:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001899 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001900 VisitForStackValue(property->obj());
1901 VisitForAccumulatorValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001902 __ ldr(r1, MemOperand(sp, 0));
1903 __ push(r0);
1904 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001905 VisitForStackValue(property->obj());
1906 VisitForStackValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001907 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001908 break;
1909 }
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911 // For compound assignments we need another deoptimization point after the
1912 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001913 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001914 { AccumulatorValueContext context(this);
1915 switch (assign_type) {
1916 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001917 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001919 break;
1920 case NAMED_PROPERTY:
1921 EmitNamedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001922 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001923 break;
1924 case KEYED_PROPERTY:
1925 EmitKeyedPropertyLoad(property);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00001926 PrepareForBailoutForId(property->LoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001927 break;
1928 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001929 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001930
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001931 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001932 __ push(r0); // Left operand goes on the stack.
1933 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001934
ricow@chromium.org65fae842010-08-25 15:26:24 +00001935 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1936 ? OVERWRITE_RIGHT
1937 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001938 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001939 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001940 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001941 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001942 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001943 mode,
1944 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001945 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001946 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001947 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001948 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001949
1950 // Deoptimization point in case the binary operation may have side effects.
1951 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001952 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001953 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001954 }
1955
1956 // Record source position before possible IC call.
1957 SetSourcePosition(expr->position());
1958
1959 // Store the value.
1960 switch (assign_type) {
1961 case VARIABLE:
1962 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001963 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001964 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1965 context()->Plug(r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001966 break;
1967 case NAMED_PROPERTY:
1968 EmitNamedPropertyAssignment(expr);
1969 break;
1970 case KEYED_PROPERTY:
1971 EmitKeyedPropertyAssignment(expr);
1972 break;
1973 }
1974}
1975
1976
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001977void FullCodeGenerator::VisitYield(Yield* expr) {
1978 Comment cmnt(masm_, "[ Yield");
1979 // Evaluate yielded value first; the initial iterator definition depends on
1980 // this. It stays on the stack while we update the iterator.
1981 VisitForStackValue(expr->expression());
1982
1983 switch (expr->yield_kind()) {
danno@chromium.org41728482013-06-12 22:31:22 +00001984 case Yield::SUSPEND:
1985 // Pop value from top-of-stack slot; box result into result register.
1986 EmitCreateIteratorResult(false);
1987 __ push(result_register());
1988 // Fall through.
1989 case Yield::INITIAL: {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001990 Label suspend, continuation, post_runtime, resume;
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00001991
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00001992 __ jmp(&suspend);
1993
1994 __ bind(&continuation);
1995 __ jmp(&resume);
1996
1997 __ bind(&suspend);
1998 VisitForAccumulatorValue(expr->generator_object());
1999 ASSERT(continuation.pos() > 0 && Smi::IsValid(continuation.pos()));
2000 __ mov(r1, Operand(Smi::FromInt(continuation.pos())));
2001 __ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset));
2002 __ str(cp, FieldMemOperand(r0, JSGeneratorObject::kContextOffset));
2003 __ mov(r1, cp);
2004 __ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2,
2005 kLRHasBeenSaved, kDontSaveFPRegs);
2006 __ add(r1, fp, Operand(StandardFrameConstants::kExpressionsOffset));
2007 __ cmp(sp, r1);
2008 __ b(eq, &post_runtime);
2009 __ push(r0); // generator object
2010 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
2011 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
2012 __ bind(&post_runtime);
danno@chromium.org41728482013-06-12 22:31:22 +00002013 __ pop(result_register());
2014 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002015
2016 __ bind(&resume);
2017 context()->Plug(result_register());
2018 break;
2019 }
2020
2021 case Yield::FINAL: {
2022 VisitForAccumulatorValue(expr->generator_object());
2023 __ mov(r1, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorClosed)));
2024 __ str(r1, FieldMemOperand(result_register(),
2025 JSGeneratorObject::kContinuationOffset));
danno@chromium.org41728482013-06-12 22:31:22 +00002026 // Pop value from top-of-stack slot, box result into result register.
2027 EmitCreateIteratorResult(true);
2028 EmitUnwindBeforeReturn();
2029 EmitReturnSequence();
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002030 break;
2031 }
2032
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002033 case Yield::DELEGATING: {
2034 VisitForStackValue(expr->generator_object());
2035
2036 // Initial stack layout is as follows:
2037 // [sp + 1 * kPointerSize] iter
2038 // [sp + 0 * kPointerSize] g
2039
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002040 Label l_catch, l_try, l_suspend, l_continuation, l_resume;
2041 Label l_next, l_call, l_loop;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002042 // Initial send value is undefined.
2043 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002044 __ b(&l_next);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002045
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002046 // catch (e) { receiver = iter; f = 'throw'; arg = e; goto l_call; }
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002047 __ bind(&l_catch);
2048 handler_table()->set(expr->index(), Smi::FromInt(l_catch.pos()));
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002049 __ LoadRoot(r2, Heap::kthrow_stringRootIndex); // "throw"
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002050 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002051 __ Push(r3, r0); // iter, exception
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002052 __ jmp(&l_call);
2053
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002054 // try { received = %yield result }
2055 // Shuffle the received result above a try handler and yield it without
2056 // re-boxing.
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002057 __ bind(&l_try);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002058 __ pop(r0); // result
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002059 __ PushTryHandler(StackHandler::CATCH, expr->index());
2060 const int handler_size = StackHandlerConstants::kSize;
danno@chromium.org41728482013-06-12 22:31:22 +00002061 __ push(r0); // result
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002062 __ jmp(&l_suspend);
2063 __ bind(&l_continuation);
2064 __ jmp(&l_resume);
2065 __ bind(&l_suspend);
2066 const int generator_object_depth = kPointerSize + handler_size;
2067 __ ldr(r0, MemOperand(sp, generator_object_depth));
2068 __ push(r0); // g
2069 ASSERT(l_continuation.pos() > 0 && Smi::IsValid(l_continuation.pos()));
2070 __ mov(r1, Operand(Smi::FromInt(l_continuation.pos())));
2071 __ str(r1, FieldMemOperand(r0, JSGeneratorObject::kContinuationOffset));
2072 __ str(cp, FieldMemOperand(r0, JSGeneratorObject::kContextOffset));
2073 __ mov(r1, cp);
2074 __ RecordWriteField(r0, JSGeneratorObject::kContextOffset, r1, r2,
2075 kLRHasBeenSaved, kDontSaveFPRegs);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002076 __ CallRuntime(Runtime::kSuspendJSGeneratorObject, 1);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002077 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
danno@chromium.org41728482013-06-12 22:31:22 +00002078 __ pop(r0); // result
2079 EmitReturnSequence();
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002080 __ bind(&l_resume); // received in r0
2081 __ PopTryHandler();
2082
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002083 // receiver = iter; f = 'next'; arg = received;
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002084 __ bind(&l_next);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002085 __ LoadRoot(r2, Heap::knext_stringRootIndex); // "next"
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002086 __ ldr(r3, MemOperand(sp, 1 * kPointerSize)); // iter
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002087 __ Push(r3, r0); // iter, received
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002088
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002089 // result = receiver[f](arg);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002090 __ bind(&l_call);
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002091 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(1);
2092 CallIC(ic);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002093 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002094
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002095 // if (!result.done) goto l_try;
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002096 __ bind(&l_loop);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002097 __ push(r0); // save result
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002098 __ LoadRoot(r2, Heap::kdone_stringRootIndex); // "done"
2099 Handle<Code> done_ic = isolate()->builtins()->LoadIC_Initialize();
2100 CallIC(done_ic); // result.done in r0
rossberg@chromium.orgb99c7542013-05-31 11:40:45 +00002101 Handle<Code> bool_ic = ToBooleanStub::GetUninitialized(isolate());
2102 CallIC(bool_ic);
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002103 __ cmp(r0, Operand(0));
2104 __ b(eq, &l_try);
2105
2106 // result.value
danno@chromium.orgf95d4b92013-06-13 14:40:17 +00002107 __ pop(r0); // result
2108 __ LoadRoot(r2, Heap::kvalue_stringRootIndex); // "value"
2109 Handle<Code> value_ic = isolate()->builtins()->LoadIC_Initialize();
2110 CallIC(value_ic); // result.value in r0
jkummerow@chromium.org4e308cf2013-05-17 13:39:16 +00002111 context()->DropAndPlug(2, r0); // drop iter and g
2112 break;
2113 }
ulan@chromium.org77ca49a2013-04-22 09:43:56 +00002114 }
2115}
2116
2117
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002118void FullCodeGenerator::EmitGeneratorResume(Expression *generator,
2119 Expression *value,
2120 JSGeneratorObject::ResumeMode resume_mode) {
2121 // The value stays in r0, and is ultimately read by the resumed generator, as
2122 // if the CallRuntime(Runtime::kSuspendJSGeneratorObject) returned it. r1
2123 // will hold the generator object until the activation has been resumed.
2124 VisitForStackValue(generator);
2125 VisitForAccumulatorValue(value);
2126 __ pop(r1);
2127
2128 // Check generator state.
2129 Label wrong_state, done;
2130 __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset));
2131 STATIC_ASSERT(JSGeneratorObject::kGeneratorExecuting <= 0);
2132 STATIC_ASSERT(JSGeneratorObject::kGeneratorClosed <= 0);
2133 __ cmp(r3, Operand(Smi::FromInt(0)));
2134 __ b(le, &wrong_state);
2135
2136 // Load suspended function and context.
2137 __ ldr(cp, FieldMemOperand(r1, JSGeneratorObject::kContextOffset));
2138 __ ldr(r4, FieldMemOperand(r1, JSGeneratorObject::kFunctionOffset));
2139
2140 // Load receiver and store as the first argument.
2141 __ ldr(r2, FieldMemOperand(r1, JSGeneratorObject::kReceiverOffset));
2142 __ push(r2);
2143
2144 // Push holes for the rest of the arguments to the generator function.
2145 __ ldr(r3, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
2146 __ ldr(r3,
2147 FieldMemOperand(r3, SharedFunctionInfo::kFormalParameterCountOffset));
2148 __ LoadRoot(r2, Heap::kTheHoleValueRootIndex);
2149 Label push_argument_holes, push_frame;
2150 __ bind(&push_argument_holes);
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002151 __ sub(r3, r3, Operand(Smi::FromInt(1)), SetCC);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002152 __ b(mi, &push_frame);
2153 __ push(r2);
2154 __ jmp(&push_argument_holes);
2155
2156 // Enter a new JavaScript frame, and initialize its slots as they were when
2157 // the generator was suspended.
2158 Label resume_frame;
2159 __ bind(&push_frame);
2160 __ bl(&resume_frame);
2161 __ jmp(&done);
2162 __ bind(&resume_frame);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002163 // lr = return address.
2164 // fp = caller's frame pointer.
ulan@chromium.org9ca30172014-01-02 12:10:54 +00002165 // pp = caller's constant pool (if FLAG_enable_ool_constant_pool),
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002166 // cp = callee's context,
2167 // r4 = callee's JS function.
ulan@chromium.org9ca30172014-01-02 12:10:54 +00002168 __ PushFixedFrame(r4);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002169 // Adjust FP to point to saved FP.
ulan@chromium.org9ca30172014-01-02 12:10:54 +00002170 __ add(fp, sp, Operand(StandardFrameConstants::kFixedFrameSizeFromFp));
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002171
2172 // Load the operand stack size.
2173 __ ldr(r3, FieldMemOperand(r1, JSGeneratorObject::kOperandStackOffset));
2174 __ ldr(r3, FieldMemOperand(r3, FixedArray::kLengthOffset));
2175 __ SmiUntag(r3);
2176
2177 // If we are sending a value and there is no operand stack, we can jump back
2178 // in directly.
verwaest@chromium.org8a00e822013-06-10 15:11:22 +00002179 if (resume_mode == JSGeneratorObject::NEXT) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002180 Label slow_resume;
2181 __ cmp(r3, Operand(0));
2182 __ b(ne, &slow_resume);
2183 __ ldr(r3, FieldMemOperand(r4, JSFunction::kCodeEntryOffset));
2184 __ ldr(r2, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset));
2185 __ SmiUntag(r2);
2186 __ add(r3, r3, r2);
2187 __ mov(r2, Operand(Smi::FromInt(JSGeneratorObject::kGeneratorExecuting)));
2188 __ str(r2, FieldMemOperand(r1, JSGeneratorObject::kContinuationOffset));
2189 __ Jump(r3);
2190 __ bind(&slow_resume);
2191 }
2192
2193 // Otherwise, we push holes for the operand stack and call the runtime to fix
2194 // up the stack and the handlers.
2195 Label push_operand_holes, call_resume;
2196 __ bind(&push_operand_holes);
2197 __ sub(r3, r3, Operand(1), SetCC);
2198 __ b(mi, &call_resume);
2199 __ push(r2);
2200 __ b(&push_operand_holes);
2201 __ bind(&call_resume);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002202 ASSERT(!result_register().is(r1));
2203 __ Push(r1, result_register());
danno@chromium.orgca29dd82013-04-26 11:59:48 +00002204 __ Push(Smi::FromInt(resume_mode));
2205 __ CallRuntime(Runtime::kResumeJSGeneratorObject, 3);
2206 // Not reached: the runtime call returns elsewhere.
2207 __ stop("not-reached");
2208
2209 // Throw error if we attempt to operate on a running generator.
2210 __ bind(&wrong_state);
2211 __ push(r1);
2212 __ CallRuntime(Runtime::kThrowGeneratorStateError, 1);
2213
2214 __ bind(&done);
2215 context()->Plug(result_register());
2216}
2217
2218
danno@chromium.org41728482013-06-12 22:31:22 +00002219void FullCodeGenerator::EmitCreateIteratorResult(bool done) {
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002220 Label gc_required;
2221 Label allocated;
2222
2223 Handle<Map> map(isolate()->native_context()->generator_result_map());
2224
2225 __ Allocate(map->instance_size(), r0, r2, r3, &gc_required, TAG_OBJECT);
danno@chromium.org41728482013-06-12 22:31:22 +00002226 __ jmp(&allocated);
2227
2228 __ bind(&gc_required);
2229 __ Push(Smi::FromInt(map->instance_size()));
2230 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
2231 __ ldr(context_register(),
2232 MemOperand(fp, StandardFrameConstants::kContextOffset));
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002233
2234 __ bind(&allocated);
2235 __ mov(r1, Operand(map));
2236 __ pop(r2);
2237 __ mov(r3, Operand(isolate()->factory()->ToBoolean(done)));
2238 __ mov(r4, Operand(isolate()->factory()->empty_fixed_array()));
2239 ASSERT_EQ(map->instance_size(), 5 * kPointerSize);
2240 __ str(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2241 __ str(r4, FieldMemOperand(r0, JSObject::kPropertiesOffset));
2242 __ str(r4, FieldMemOperand(r0, JSObject::kElementsOffset));
2243 __ str(r2,
2244 FieldMemOperand(r0, JSGeneratorObject::kResultValuePropertyOffset));
2245 __ str(r3,
2246 FieldMemOperand(r0, JSGeneratorObject::kResultDonePropertyOffset));
2247
2248 // Only the value field needs a write barrier, as the other values are in the
2249 // root set.
2250 __ RecordWriteField(r0, JSGeneratorObject::kResultValuePropertyOffset,
2251 r2, r3, kLRHasBeenSaved, kDontSaveFPRegs);
ulan@chromium.org57ff8812013-05-10 08:16:55 +00002252}
2253
2254
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002255void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
2256 SetSourcePosition(prop->position());
2257 Literal* key = prop->key()->AsLiteral();
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002258 __ mov(r2, Operand(key->value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002259 // Call load IC. It has arguments receiver and property name r0 and r2.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002260 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002261 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002262}
2263
2264
2265void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
2266 SetSourcePosition(prop->position());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002267 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002268 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002269 CallIC(ic, RelocInfo::CODE_TARGET, prop->PropertyFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002270}
2271
2272
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002273void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002274 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002275 OverwriteMode mode,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002276 Expression* left_expr,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002277 Expression* right_expr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002278 Label done, smi_case, stub_call;
2279
2280 Register scratch1 = r2;
2281 Register scratch2 = r3;
2282
2283 // Get the arguments.
2284 Register left = r1;
2285 Register right = r0;
2286 __ pop(left);
2287
2288 // Perform combined smi check on both operands.
2289 __ orr(scratch1, left, Operand(right));
2290 STATIC_ASSERT(kSmiTag == 0);
2291 JumpPatchSite patch_site(masm_);
2292 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
2293
2294 __ bind(&stub_call);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002295 BinaryOpICStub stub(op, mode);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002296 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002297 expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002298 patch_site.EmitPatchInfo();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002299 __ jmp(&done);
2300
2301 __ bind(&smi_case);
2302 // Smi case. This code works the same way as the smi-smi case in the type
2303 // recording binary operation stub, see
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002304 switch (op) {
2305 case Token::SAR:
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002306 __ GetLeastBitsFromSmi(scratch1, right, 5);
2307 __ mov(right, Operand(left, ASR, scratch1));
2308 __ bic(right, right, Operand(kSmiTagMask));
2309 break;
2310 case Token::SHL: {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002311 __ SmiUntag(scratch1, left);
2312 __ GetLeastBitsFromSmi(scratch2, right, 5);
2313 __ mov(scratch1, Operand(scratch1, LSL, scratch2));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002314 __ TrySmiTag(right, scratch1, &stub_call);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002315 break;
2316 }
2317 case Token::SHR: {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002318 __ SmiUntag(scratch1, left);
2319 __ GetLeastBitsFromSmi(scratch2, right, 5);
2320 __ mov(scratch1, Operand(scratch1, LSR, scratch2));
2321 __ tst(scratch1, Operand(0xc0000000));
2322 __ b(ne, &stub_call);
2323 __ SmiTag(right, scratch1);
2324 break;
2325 }
2326 case Token::ADD:
2327 __ add(scratch1, left, Operand(right), SetCC);
2328 __ b(vs, &stub_call);
2329 __ mov(right, scratch1);
2330 break;
2331 case Token::SUB:
2332 __ sub(scratch1, left, Operand(right), SetCC);
2333 __ b(vs, &stub_call);
2334 __ mov(right, scratch1);
2335 break;
2336 case Token::MUL: {
2337 __ SmiUntag(ip, right);
2338 __ smull(scratch1, scratch2, left, ip);
2339 __ mov(ip, Operand(scratch1, ASR, 31));
2340 __ cmp(ip, Operand(scratch2));
2341 __ b(ne, &stub_call);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00002342 __ cmp(scratch1, Operand::Zero());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00002343 __ mov(right, Operand(scratch1), LeaveCC, ne);
2344 __ b(ne, &done);
2345 __ add(scratch2, right, Operand(left), SetCC);
2346 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
2347 __ b(mi, &stub_call);
2348 break;
2349 }
2350 case Token::BIT_OR:
2351 __ orr(right, left, Operand(right));
2352 break;
2353 case Token::BIT_AND:
2354 __ and_(right, left, Operand(right));
2355 break;
2356 case Token::BIT_XOR:
2357 __ eor(right, left, Operand(right));
2358 break;
2359 default:
2360 UNREACHABLE();
2361 }
2362
2363 __ bind(&done);
2364 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002365}
2366
2367
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002368void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2369 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00002370 OverwriteMode mode) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002371 __ pop(r1);
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00002372 BinaryOpICStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002373 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002374 CallIC(stub.GetCode(isolate()), RelocInfo::CODE_TARGET,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002375 expr->BinaryOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002376 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002377 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002378}
2379
2380
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002381void FullCodeGenerator::EmitAssignment(Expression* expr) {
yangguo@chromium.orga6bbcc82012-12-21 12:35:02 +00002382 // Invalid left-hand sides are rewritten by the parser to have a 'throw
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002383 // ReferenceError' on the left-hand side.
2384 if (!expr->IsValidLeftHandSide()) {
2385 VisitForEffect(expr);
2386 return;
2387 }
2388
2389 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002390 // slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002391 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2392 LhsKind assign_type = VARIABLE;
2393 Property* prop = expr->AsProperty();
2394 if (prop != NULL) {
2395 assign_type = (prop->key()->IsPropertyName())
2396 ? NAMED_PROPERTY
2397 : KEYED_PROPERTY;
2398 }
2399
2400 switch (assign_type) {
2401 case VARIABLE: {
2402 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002403 EffectContext context(this);
2404 EmitVariableAssignment(var, Token::ASSIGN);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002405 break;
2406 }
2407 case NAMED_PROPERTY: {
2408 __ push(r0); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002409 VisitForAccumulatorValue(prop->obj());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002410 __ mov(r1, r0);
2411 __ pop(r0); // Restore value.
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002412 __ mov(r2, Operand(prop->key()->AsLiteral()->value()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002413 Handle<Code> ic = is_classic_mode()
2414 ? isolate()->builtins()->StoreIC_Initialize()
2415 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002416 CallIC(ic);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002417 break;
2418 }
2419 case KEYED_PROPERTY: {
2420 __ push(r0); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002421 VisitForStackValue(prop->obj());
2422 VisitForAccumulatorValue(prop->key());
2423 __ mov(r1, r0);
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002424 __ Pop(r0, r2); // r0 = restored value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002425 Handle<Code> ic = is_classic_mode()
2426 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2427 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002428 CallIC(ic);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002429 break;
2430 }
2431 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002432 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002433}
2434
2435
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002436void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002437 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002438 if (var->IsUnallocated()) {
2439 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002440 __ mov(r2, Operand(var->name()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002441 __ ldr(r1, GlobalObjectOperand());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002442 Handle<Code> ic = is_classic_mode()
2443 ? isolate()->builtins()->StoreIC_Initialize()
2444 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002445 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002446
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002447 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002448 // Const initializers need a write barrier.
2449 ASSERT(!var->IsParameter()); // No const parameters.
2450 if (var->IsStackLocal()) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002451 __ ldr(r1, StackOperand(var));
2452 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
ulan@chromium.org9ca30172014-01-02 12:10:54 +00002453 __ str(result_register(), StackOperand(var), eq);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002454 } else {
2455 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
2456 // Like var declarations, const declarations are hoisted to function
2457 // scope. However, unlike var initializers, const initializers are
2458 // able to drill a hole to that function context, even from inside a
2459 // 'with' context. We thus bypass the normal static scope lookup for
2460 // var->IsContextSlot().
2461 __ push(r0);
2462 __ mov(r0, Operand(var->name()));
2463 __ Push(cp, r0); // Context and name.
2464 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002465 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002466
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002467 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002468 // Non-initializing assignment to let variable needs a write barrier.
2469 if (var->IsLookupSlot()) {
2470 __ push(r0); // Value.
2471 __ mov(r1, Operand(var->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002472 __ mov(r0, Operand(Smi::FromInt(language_mode())));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002473 __ Push(cp, r1, r0); // Context, name, strict mode.
2474 __ CallRuntime(Runtime::kStoreContextSlot, 4);
2475 } else {
2476 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2477 Label assign;
2478 MemOperand location = VarOperand(var, r1);
2479 __ ldr(r3, location);
2480 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
2481 __ b(ne, &assign);
2482 __ mov(r3, Operand(var->name()));
2483 __ push(r3);
2484 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2485 // Perform the assignment.
2486 __ bind(&assign);
2487 __ str(result_register(), location);
2488 if (var->IsContextSlot()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002489 // RecordWrite may destroy all its register arguments.
2490 __ mov(r3, result_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002491 int offset = Context::SlotOffset(var->index());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002492 __ RecordWriteContextSlot(
2493 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002494 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002495 }
2496
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002497 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2498 // Assignment to var or initializing assignment to let/const
2499 // in harmony mode.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002500 if (var->IsStackAllocated() || var->IsContextSlot()) {
2501 MemOperand location = VarOperand(var, r1);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002502 if (generate_debug_code_ && op == Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002503 // Check for an uninitialized let binding.
2504 __ ldr(r2, location);
2505 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
danno@chromium.org59400602013-08-13 17:09:37 +00002506 __ Check(eq, kLetBindingReInitialization);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002507 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002508 // Perform the assignment.
2509 __ str(r0, location);
2510 if (var->IsContextSlot()) {
2511 __ mov(r3, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002512 int offset = Context::SlotOffset(var->index());
2513 __ RecordWriteContextSlot(
2514 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002515 }
2516 } else {
2517 ASSERT(var->IsLookupSlot());
2518 __ push(r0); // Value.
2519 __ mov(r1, Operand(var->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002520 __ mov(r0, Operand(Smi::FromInt(language_mode())));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002521 __ Push(cp, r1, r0); // Context, name, strict mode.
2522 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002523 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002524 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002525 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002526}
2527
2528
2529void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2530 // Assignment to a property, using a named store IC.
2531 Property* prop = expr->target()->AsProperty();
2532 ASSERT(prop != NULL);
2533 ASSERT(prop->key()->AsLiteral() != NULL);
2534
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002535 // Record source code position before IC call.
2536 SetSourcePosition(expr->position());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002537 __ mov(r2, Operand(prop->key()->AsLiteral()->value()));
verwaest@chromium.org33e09c82012-10-10 17:07:22 +00002538 __ pop(r1);
ager@chromium.org5c838252010-02-19 08:53:10 +00002539
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002540 Handle<Code> ic = is_classic_mode()
2541 ? isolate()->builtins()->StoreIC_Initialize()
2542 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002543 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002544
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002545 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2546 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002547}
2548
2549
2550void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2551 // Assignment to a property, using a keyed store IC.
2552
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002553 // Record source code position before IC call.
2554 SetSourcePosition(expr->position());
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002555 __ Pop(r2, r1); // r1 = key.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002556
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002557 Handle<Code> ic = is_classic_mode()
2558 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2559 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002560 CallIC(ic, RelocInfo::CODE_TARGET, expr->AssignmentFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002561
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002562 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2563 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002564}
2565
2566
2567void FullCodeGenerator::VisitProperty(Property* expr) {
2568 Comment cmnt(masm_, "[ Property");
2569 Expression* key = expr->key();
2570
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002571 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002572 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002573 EmitNamedPropertyLoad(expr);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002574 PrepareForBailoutForId(expr->LoadId(), TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002575 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002576 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002577 VisitForStackValue(expr->obj());
2578 VisitForAccumulatorValue(expr->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002579 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002580 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002581 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002582 }
2583}
2584
danno@chromium.org88aa0582012-03-23 15:11:57 +00002585
2586void FullCodeGenerator::CallIC(Handle<Code> code,
2587 RelocInfo::Mode rmode,
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002588 TypeFeedbackId ast_id) {
danno@chromium.org88aa0582012-03-23 15:11:57 +00002589 ic_total_count_++;
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00002590 // All calls must have a predictable size in full-codegen code to ensure that
2591 // the debugger can patch them correctly.
2592 __ Call(code, rmode, ast_id, al, NEVER_INLINE_TARGET_ADDRESS);
danno@chromium.org88aa0582012-03-23 15:11:57 +00002593}
2594
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002595void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002596 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002597 RelocInfo::Mode mode) {
2598 // Code common for calls using the IC.
2599 ZoneList<Expression*>* args = expr->arguments();
2600 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002601 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002602 for (int i = 0; i < arg_count; i++) {
2603 VisitForStackValue(args->at(i));
2604 }
2605 __ mov(r2, Operand(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002606 }
2607 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002608 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002609 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002610 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002611 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002612 CallIC(ic, mode, expr->CallFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002613 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002614 // Restore context register.
2615 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002616 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002617}
2618
2619
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002620void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002621 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002622 // Load the key.
2623 VisitForAccumulatorValue(key);
2624
2625 // Swap the name of the function and the receiver on the stack to follow
2626 // the calling convention for call ICs.
2627 __ pop(r1);
2628 __ push(r0);
2629 __ push(r1);
2630
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002631 // Code common for calls using the IC.
2632 ZoneList<Expression*>* args = expr->arguments();
2633 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002634 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002635 for (int i = 0; i < arg_count; i++) {
2636 VisitForStackValue(args->at(i));
2637 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002638 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002639 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002640 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002641 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002642 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002643 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002644 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002645 CallIC(ic, RelocInfo::CODE_TARGET, expr->CallFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002646 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002647 // Restore context register.
2648 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002649 context()->DropAndPlug(1, r0); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002650}
2651
2652
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002653void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002654 // Code common for calls using the call stub.
2655 ZoneList<Expression*>* args = expr->arguments();
2656 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002657 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002658 for (int i = 0; i < arg_count; i++) {
2659 VisitForStackValue(args->at(i));
2660 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002661 }
2662 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002663 SetSourcePosition(expr->position());
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002664
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002665 // Record call targets in unoptimized code.
2666 flags = static_cast<CallFunctionFlags>(flags | RECORD_CALL_TARGET);
2667 Handle<Object> uninitialized =
2668 TypeFeedbackCells::UninitializedSentinel(isolate());
danno@chromium.org41728482013-06-12 22:31:22 +00002669 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002670 RecordTypeFeedbackCell(expr->CallFeedbackId(), cell);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002671 __ mov(r2, Operand(cell));
mstarzinger@chromium.org88d326b2012-04-23 12:57:22 +00002672
lrn@chromium.org34e60782011-09-15 07:25:40 +00002673 CallFunctionStub stub(arg_count, flags);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002674 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
yangguo@chromium.org4cd70b42013-01-04 08:57:54 +00002675 __ CallStub(&stub, expr->CallFeedbackId());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002676 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002677 // Restore context register.
2678 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002679 context()->DropAndPlug(1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002680}
2681
2682
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002683void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002684 // r4: copy of the first argument or undefined if it doesn't exist.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002685 if (arg_count > 0) {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002686 __ ldr(r4, MemOperand(sp, arg_count * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002687 } else {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002688 __ LoadRoot(r4, Heap::kUndefinedValueRootIndex);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002689 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002690
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002691 // r3: the receiver of the enclosing function.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002692 int receiver_offset = 2 + info_->scope()->num_parameters();
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002693 __ ldr(r3, MemOperand(fp, receiver_offset * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002694
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002695 // r2: the language mode.
2696 __ mov(r2, Operand(Smi::FromInt(language_mode())));
2697
2698 // r1: the start position of the scope the calls resides in.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002699 __ mov(r1, Operand(Smi::FromInt(scope()->start_position())));
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002700
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002701 // Do the runtime call.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002702 __ Push(r4, r3, r2, r1);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002703 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002704}
2705
2706
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002707void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002708#ifdef DEBUG
2709 // We want to verify that RecordJSReturnSite gets called on all paths
2710 // through this function. Avoid early returns.
2711 expr->return_is_recorded_ = false;
2712#endif
2713
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002714 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002715 Expression* callee = expr->expression();
2716 VariableProxy* proxy = callee->AsVariableProxy();
2717 Property* property = callee->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002718
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00002719 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002720 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2721 // resolve the function we need to call and the receiver of the
2722 // call. Then we call the resolved function using the given
2723 // arguments.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002724 ZoneList<Expression*>* args = expr->arguments();
2725 int arg_count = args->length();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002726
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002727 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002728 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002729 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
2730 __ push(r2); // Reserved receiver slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002731
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002732 // Push the arguments.
2733 for (int i = 0; i < arg_count; i++) {
2734 VisitForStackValue(args->at(i));
2735 }
2736
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002737 // Push a copy of the function (found below the arguments) and
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002738 // resolve eval.
2739 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002740 __ push(r1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002741 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002742
2743 // The runtime call returns a pair of values in r0 (function) and
2744 // r1 (receiver). Touch up the stack with the right values.
2745 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2746 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002747 }
2748
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002749 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002750 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002751 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002752 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002753 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002754 RecordJSReturnSite(expr);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002755 // Restore context register.
2756 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002757 context()->DropAndPlug(1, r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002758 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002759 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002760 __ ldr(r0, GlobalObjectOperand());
ager@chromium.org5c838252010-02-19 08:53:10 +00002761 __ push(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002762 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2763 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002764 // Call to a lookup slot (dynamically introduced variable).
2765 Label slow, done;
2766
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002767 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002768 // Generate code for loading from variables potentially shadowed
2769 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002770 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002771 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002772
2773 __ bind(&slow);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002774 // Call the runtime to find the function to call (returned in r0)
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002775 // and the object holding it (returned in edx).
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002776 ASSERT(!context_register().is(r2));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002777 __ mov(r2, Operand(proxy->name()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00002778 __ Push(context_register(), r2);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002779 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002780 __ Push(r0, r1); // Function, receiver.
2781
2782 // If fast case code has been generated, emit code to push the
2783 // function and receiver and have the slow path jump around this
2784 // code.
2785 if (done.is_linked()) {
2786 Label call;
2787 __ b(&call);
2788 __ bind(&done);
2789 // Push function.
2790 __ push(r0);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002791 // The receiver is implicitly the global receiver. Indicate this
2792 // by passing the hole to the call function stub.
2793 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002794 __ push(r1);
2795 __ bind(&call);
2796 }
2797
danno@chromium.org40cb8782011-05-25 07:58:50 +00002798 // The receiver is either the global receiver or an object found
2799 // by LoadContextSlot. That object could be the hole if the
2800 // receiver is implicitly the global object.
2801 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002802 } else if (property != NULL) {
2803 { PreservePositionScope scope(masm()->positions_recorder());
2804 VisitForStackValue(property->obj());
2805 }
2806 if (property->key()->IsPropertyName()) {
2807 EmitCallWithIC(expr,
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00002808 property->key()->AsLiteral()->value(),
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002809 RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002810 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002811 EmitKeyedCallWithIC(expr, property->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002812 }
2813 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002814 // Call to an arbitrary expression not handled specially above.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002815 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002816 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002817 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002818 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002819 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002820 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
2821 __ push(r1);
2822 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002823 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002824 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002825
2826#ifdef DEBUG
2827 // RecordJSReturnSite should have been called.
2828 ASSERT(expr->return_is_recorded_);
2829#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002830}
2831
2832
2833void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2834 Comment cmnt(masm_, "[ CallNew");
2835 // According to ECMA-262, section 11.2.2, page 44, the function
2836 // expression in new calls must be evaluated before the
2837 // arguments.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002838
2839 // Push constructor on the stack. If it's not a function it's used as
2840 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2841 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002842 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002843
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002844 // Push the arguments ("left-to-right") on the stack.
2845 ZoneList<Expression*>* args = expr->arguments();
2846 int arg_count = args->length();
2847 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002848 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002849 }
2850
2851 // Call the construct call builtin that handles allocation and
2852 // constructor invocation.
2853 SetSourcePosition(expr->position());
2854
ricow@chromium.org65fae842010-08-25 15:26:24 +00002855 // Load function and argument count into r1 and r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002856 __ mov(r0, Operand(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002857 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002858
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002859 // Record call targets in unoptimized code.
2860 Handle<Object> uninitialized =
2861 TypeFeedbackCells::UninitializedSentinel(isolate());
danno@chromium.org41728482013-06-12 22:31:22 +00002862 Handle<Cell> cell = isolate()->factory()->NewCell(uninitialized);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00002863 RecordTypeFeedbackCell(expr->CallNewFeedbackId(), cell);
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002864 __ mov(r2, Operand(cell));
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002865
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00002866 CallConstructStub stub(RECORD_CALL_TARGET);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00002867 __ Call(stub.GetCode(isolate()), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002868 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002869 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002870}
2871
2872
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002873void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2874 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002875 ASSERT(args->length() == 1);
2876
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002877 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002878
2879 Label materialize_true, materialize_false;
2880 Label* if_true = NULL;
2881 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002882 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002883 context()->PrepareTest(&materialize_true, &materialize_false,
2884 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002885
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002886 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002887 __ SmiTst(r0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002888 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002889
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002890 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002891}
2892
2893
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002894void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2895 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002896 ASSERT(args->length() == 1);
2897
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002898 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002899
2900 Label materialize_true, materialize_false;
2901 Label* if_true = NULL;
2902 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002903 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002904 context()->PrepareTest(&materialize_true, &materialize_false,
2905 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002906
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002907 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00002908 __ NonNegativeSmiTst(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002909 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002910
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002911 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002912}
2913
2914
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002915void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2916 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002917 ASSERT(args->length() == 1);
2918
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002919 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002920
2921 Label materialize_true, materialize_false;
2922 Label* if_true = NULL;
2923 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002924 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002925 context()->PrepareTest(&materialize_true, &materialize_false,
2926 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002927
ager@chromium.org378b34e2011-01-28 08:04:38 +00002928 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002929 __ LoadRoot(ip, Heap::kNullValueRootIndex);
2930 __ cmp(r0, ip);
2931 __ b(eq, if_true);
2932 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
2933 // Undetectable objects behave like undefined when tested with typeof.
2934 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
2935 __ tst(r1, Operand(1 << Map::kIsUndetectable));
2936 __ b(ne, if_false);
2937 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002938 __ cmp(r1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002939 __ b(lt, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002940 __ cmp(r1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002941 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002942 Split(le, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002943
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002944 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002945}
2946
2947
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002948void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2949 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002950 ASSERT(args->length() == 1);
2951
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002952 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002953
2954 Label materialize_true, materialize_false;
2955 Label* if_true = NULL;
2956 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002957 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002958 context()->PrepareTest(&materialize_true, &materialize_false,
2959 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002960
ager@chromium.org378b34e2011-01-28 08:04:38 +00002961 __ JumpIfSmi(r0, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002962 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002963 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002964 Split(ge, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002965
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002966 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002967}
2968
2969
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002970void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2971 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002972 ASSERT(args->length() == 1);
2973
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002974 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002975
2976 Label materialize_true, materialize_false;
2977 Label* if_true = NULL;
2978 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002979 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002980 context()->PrepareTest(&materialize_true, &materialize_false,
2981 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002982
ager@chromium.org378b34e2011-01-28 08:04:38 +00002983 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002984 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2985 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
2986 __ tst(r1, Operand(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002987 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002988 Split(ne, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002989
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002990 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002991}
2992
2993
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002994void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002995 CallRuntime* expr) {
2996 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002997 ASSERT(args->length() == 1);
2998
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002999 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003000
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003001 Label materialize_true, materialize_false, skip_lookup;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003002 Label* if_true = NULL;
3003 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003004 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003005 context()->PrepareTest(&materialize_true, &materialize_false,
3006 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003007
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003008 __ AssertNotSmi(r0);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003009
3010 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
3011 __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset));
3012 __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003013 __ b(ne, &skip_lookup);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003014
3015 // Check for fast case object. Generate false result for slow case object.
3016 __ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset));
3017 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
3018 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
3019 __ cmp(r2, ip);
3020 __ b(eq, if_false);
3021
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003022 // Look for valueOf name in the descriptor array, and indicate false if
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003023 // found. Since we omit an enumeration index check, if it is added via a
3024 // transition that shares its descriptor array, this is a false positive.
3025 Label entry, loop, done;
3026
3027 // Skip loop if no descriptors are valid.
3028 __ NumberOfOwnDescriptors(r3, r1);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003029 __ cmp(r3, Operand::Zero());
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003030 __ b(eq, &done);
3031
rossberg@chromium.org89e18f52012-10-22 13:09:53 +00003032 __ LoadInstanceDescriptors(r1, r4);
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003033 // r4: descriptor array.
3034 // r3: valid entries in the descriptor array.
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003035 __ mov(ip, Operand(DescriptorArray::kDescriptorSize));
3036 __ mul(r3, r3, ip);
3037 // Calculate location of the first key name.
3038 __ add(r4, r4, Operand(DescriptorArray::kFirstOffset - kHeapObjectTag));
3039 // Calculate the end of the descriptor array.
3040 __ mov(r2, r4);
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003041 __ add(r2, r2, Operand::PointerOffsetFromSmiKey(r3));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003043 // Loop through all the keys in the descriptor array. If one of these is the
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003044 // string "valueOf" the result is false.
3045 // The use of ip to store the valueOf string assumes that it is not otherwise
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003046 // used in the loop below.
verwaest@chromium.orgd4be0f02013-06-05 13:39:03 +00003047 __ mov(ip, Operand(isolate()->factory()->value_of_string()));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003048 __ jmp(&entry);
3049 __ bind(&loop);
3050 __ ldr(r3, MemOperand(r4, 0));
3051 __ cmp(r3, ip);
3052 __ b(eq, if_false);
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003053 __ add(r4, r4, Operand(DescriptorArray::kDescriptorSize * kPointerSize));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003054 __ bind(&entry);
3055 __ cmp(r4, Operand(r2));
3056 __ b(ne, &loop);
3057
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003058 __ bind(&done);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003059
3060 // Set the bit in the map to indicate that there is no local valueOf field.
3061 __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
3062 __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
3063 __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
3064
3065 __ bind(&skip_lookup);
3066
verwaest@chromium.org06ab2ec2012-10-09 17:00:13 +00003067 // If a valueOf property is not found on the object check that its
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003068 // prototype is the un-modified String prototype. If not result is false.
3069 __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003070 __ JumpIfSmi(r2, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003071 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003072 __ ldr(r3, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
3073 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kNativeContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003074 __ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
3075 __ cmp(r2, r3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003076 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
dslomov@chromium.org4a35c5a2013-09-13 07:28:52 +00003077 Split(eq, if_true, if_false, fall_through);
3078
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003079 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00003080}
3081
3082
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003083void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
3084 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003085 ASSERT(args->length() == 1);
3086
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003087 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003088
3089 Label materialize_true, materialize_false;
3090 Label* if_true = NULL;
3091 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003092 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003093 context()->PrepareTest(&materialize_true, &materialize_false,
3094 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003095
ager@chromium.org378b34e2011-01-28 08:04:38 +00003096 __ JumpIfSmi(r0, if_false);
lrn@chromium.org34e60782011-09-15 07:25:40 +00003097 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003098 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003099 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003100
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003101 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003102}
3103
3104
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00003105void FullCodeGenerator::EmitIsMinusZero(CallRuntime* expr) {
3106 ZoneList<Expression*>* args = expr->arguments();
3107 ASSERT(args->length() == 1);
3108
3109 VisitForAccumulatorValue(args->at(0));
3110
3111 Label materialize_true, materialize_false;
3112 Label* if_true = NULL;
3113 Label* if_false = NULL;
3114 Label* fall_through = NULL;
3115 context()->PrepareTest(&materialize_true, &materialize_false,
3116 &if_true, &if_false, &fall_through);
3117
3118 __ CheckMap(r0, r1, Heap::kHeapNumberMapRootIndex, if_false, DO_SMI_CHECK);
3119 __ ldr(r2, FieldMemOperand(r0, HeapNumber::kExponentOffset));
3120 __ ldr(r1, FieldMemOperand(r0, HeapNumber::kMantissaOffset));
3121 __ cmp(r2, Operand(0x80000000));
3122 __ cmp(r1, Operand(0x00000000), eq);
3123
3124 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
3125 Split(eq, if_true, if_false, fall_through);
3126
3127 context()->Plug(if_true, if_false);
3128}
3129
3130
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003131void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
3132 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003133 ASSERT(args->length() == 1);
3134
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003135 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003136
3137 Label materialize_true, materialize_false;
3138 Label* if_true = NULL;
3139 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003140 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003141 context()->PrepareTest(&materialize_true, &materialize_false,
3142 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003143
ager@chromium.org378b34e2011-01-28 08:04:38 +00003144 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003145 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003146 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003147 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003148
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003149 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003150}
3151
3152
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003153void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
3154 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003155 ASSERT(args->length() == 1);
3156
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003157 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003158
3159 Label materialize_true, materialize_false;
3160 Label* if_true = NULL;
3161 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003162 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003163 context()->PrepareTest(&materialize_true, &materialize_false,
3164 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003165
ager@chromium.org378b34e2011-01-28 08:04:38 +00003166 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003167 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003168 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003169 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003170
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003171 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003172}
3173
3174
3175
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003176void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
3177 ASSERT(expr->arguments()->length() == 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003178
3179 Label materialize_true, materialize_false;
3180 Label* if_true = NULL;
3181 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003182 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003183 context()->PrepareTest(&materialize_true, &materialize_false,
3184 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003185
3186 // Get the frame pointer for the calling frame.
3187 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3188
3189 // Skip the arguments adaptor frame if it exists.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003190 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset));
3191 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
ulan@chromium.org9ca30172014-01-02 12:10:54 +00003192 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset), eq);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003193
3194 // Check the marker in the calling frame.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003195 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
3196 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003197 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003198 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003199
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003200 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003201}
3202
3203
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003204void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
3205 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003206 ASSERT(args->length() == 2);
3207
3208 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003209 VisitForStackValue(args->at(0));
3210 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003211
3212 Label materialize_true, materialize_false;
3213 Label* if_true = NULL;
3214 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003215 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003216 context()->PrepareTest(&materialize_true, &materialize_false,
3217 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003218
3219 __ pop(r1);
3220 __ cmp(r0, r1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003221 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003222 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003223
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003224 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003225}
3226
3227
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003228void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
3229 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003230 ASSERT(args->length() == 1);
3231
3232 // ArgumentsAccessStub expects the key in edx and the formal
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003233 // parameter count in r0.
3234 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003235 __ mov(r1, r0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003236 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003237 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
3238 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003239 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003240}
3241
3242
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003243void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
3244 ASSERT(expr->arguments()->length() == 0);
ulan@chromium.org9ca30172014-01-02 12:10:54 +00003245
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003246 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003247 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003248
3249 // Check if the calling frame is an arguments adaptor frame.
3250 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
3251 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
3252 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003253
3254 // Arguments adaptor case: Read the arguments length from the
3255 // adaptor frame.
ulan@chromium.org9ca30172014-01-02 12:10:54 +00003256 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset), eq);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003257
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003258 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003259}
3260
3261
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003262void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
3263 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003264 ASSERT(args->length() == 1);
3265 Label done, null, function, non_function_constructor;
3266
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003267 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003268
3269 // If the object is a smi, we return null.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003270 __ JumpIfSmi(r0, &null);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003271
3272 // Check that the object is a JS object but take special care of JS
3273 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003274 // Assume that there are only two callable types, and one of them is at
3275 // either end of the type range for JS object types. Saves extra comparisons.
3276 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003277 __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE);
3278 // Map is now in r0.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003279 __ b(lt, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003280 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3281 FIRST_SPEC_OBJECT_TYPE + 1);
3282 __ b(eq, &function);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003283
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003284 __ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE));
3285 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
3286 LAST_SPEC_OBJECT_TYPE - 1);
3287 __ b(eq, &function);
3288 // Assume that there is no larger type.
3289 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003290
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003291 // Check if the constructor in the map is a JS function.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003292 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset));
3293 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
3294 __ b(ne, &non_function_constructor);
3295
3296 // r0 now contains the constructor function. Grab the
3297 // instance class name from there.
3298 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
3299 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset));
3300 __ b(&done);
3301
3302 // Functions have class 'Function'.
3303 __ bind(&function);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003304 __ LoadRoot(r0, Heap::kfunction_class_stringRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003305 __ jmp(&done);
3306
3307 // Objects with a non-function constructor have class 'Object'.
3308 __ bind(&non_function_constructor);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003309 __ LoadRoot(r0, Heap::kObject_stringRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003310 __ jmp(&done);
3311
3312 // Non-JS objects have class null.
3313 __ bind(&null);
3314 __ LoadRoot(r0, Heap::kNullValueRootIndex);
3315
3316 // All done.
3317 __ bind(&done);
3318
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003319 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003320}
3321
3322
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003323void FullCodeGenerator::EmitLog(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003324 // Conditionally generate a log call.
3325 // Args:
3326 // 0 (literal string): The type of logging (corresponds to the flags).
3327 // This is used to determine whether or not to generate the log call.
3328 // 1 (string): Format string. Access the string at argument index 2
3329 // with '%2s' (see Logger::LogRuntime for all the formats).
3330 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003331 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003332 ASSERT_EQ(args->length(), 3);
mstarzinger@chromium.orge9000182013-09-03 11:25:39 +00003333 if (CodeGenerator::ShouldGenerateLog(isolate(), args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003334 VisitForStackValue(args->at(1));
3335 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003336 __ CallRuntime(Runtime::kLog, 2);
3337 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003338
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003339 // Finally, we're expected to leave a value on the top of the stack.
3340 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003341 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003342}
3343
3344
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003345void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003346 // Load the arguments on the stack and call the stub.
3347 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003348 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003349 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003350 VisitForStackValue(args->at(0));
3351 VisitForStackValue(args->at(1));
3352 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003353 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003354 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003355}
3356
3357
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003358void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003359 // Load the arguments on the stack and call the stub.
3360 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003361 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003362 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003363 VisitForStackValue(args->at(0));
3364 VisitForStackValue(args->at(1));
3365 VisitForStackValue(args->at(2));
3366 VisitForStackValue(args->at(3));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003367 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003368 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003369}
3370
3371
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003372void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3373 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003374 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003375 VisitForAccumulatorValue(args->at(0)); // Load the object.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003376
3377 Label done;
3378 // If the object is a smi return the object.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003379 __ JumpIfSmi(r0, &done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003380 // If the object is not a value type, return the object.
3381 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE);
ulan@chromium.org9ca30172014-01-02 12:10:54 +00003382 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset), eq);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003383
3384 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003385 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003386}
3387
3388
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003389void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3390 ZoneList<Expression*>* args = expr->arguments();
3391 ASSERT(args->length() == 2);
3392 ASSERT_NE(NULL, args->at(1)->AsLiteral());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003393 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->value()));
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003394
3395 VisitForAccumulatorValue(args->at(0)); // Load the object.
3396
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003397 Label runtime, done, not_date_object;
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003398 Register object = r0;
3399 Register result = r0;
3400 Register scratch0 = r9;
3401 Register scratch1 = r1;
3402
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003403 __ JumpIfSmi(object, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003404 __ CompareObjectType(object, scratch1, scratch1, JS_DATE_TYPE);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003405 __ b(ne, &not_date_object);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003406
3407 if (index->value() == 0) {
3408 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003409 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003410 } else {
3411 if (index->value() < JSDate::kFirstUncachedField) {
3412 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3413 __ mov(scratch1, Operand(stamp));
3414 __ ldr(scratch1, MemOperand(scratch1));
3415 __ ldr(scratch0, FieldMemOperand(object, JSDate::kCacheStampOffset));
3416 __ cmp(scratch1, scratch0);
3417 __ b(ne, &runtime);
3418 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset +
3419 kPointerSize * index->value()));
3420 __ jmp(&done);
3421 }
3422 __ bind(&runtime);
3423 __ PrepareCallCFunction(2, scratch1);
3424 __ mov(r1, Operand(index));
3425 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003426 __ jmp(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003427 }
mstarzinger@chromium.orgde886792012-09-11 13:22:37 +00003428
3429 __ bind(&not_date_object);
3430 __ CallRuntime(Runtime::kThrowNotDateError, 0);
3431 __ bind(&done);
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003432 context()->Plug(r0);
3433}
3434
3435
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003436void FullCodeGenerator::EmitOneByteSeqStringSetChar(CallRuntime* expr) {
3437 ZoneList<Expression*>* args = expr->arguments();
3438 ASSERT_EQ(3, args->length());
3439
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003440 Register string = r0;
3441 Register index = r1;
3442 Register value = r2;
3443
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003444 VisitForStackValue(args->at(1)); // index
3445 VisitForStackValue(args->at(2)); // value
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003446 VisitForAccumulatorValue(args->at(0)); // string
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003447 __ Pop(index, value);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003448
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003449 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003450 __ SmiTst(value);
3451 __ ThrowIf(ne, kNonSmiValue);
3452 __ SmiTst(index);
3453 __ ThrowIf(ne, kNonSmiIndex);
3454 __ SmiUntag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003455 static const uint32_t one_byte_seq_type = kSeqStringTag | kOneByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003456 __ EmitSeqStringSetCharCheck(string, index, value, one_byte_seq_type);
3457 __ SmiTag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003458 }
3459
3460 __ SmiUntag(value, value);
3461 __ add(ip,
3462 string,
3463 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
3464 __ strb(value, MemOperand(ip, index, LSR, kSmiTagSize));
3465 context()->Plug(string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003466}
3467
3468
3469void FullCodeGenerator::EmitTwoByteSeqStringSetChar(CallRuntime* expr) {
3470 ZoneList<Expression*>* args = expr->arguments();
3471 ASSERT_EQ(3, args->length());
3472
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003473 Register string = r0;
3474 Register index = r1;
3475 Register value = r2;
3476
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003477 VisitForStackValue(args->at(1)); // index
3478 VisitForStackValue(args->at(2)); // value
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003479 VisitForAccumulatorValue(args->at(0)); // string
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003480 __ Pop(index, value);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003481
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003482 if (FLAG_debug_code) {
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003483 __ SmiTst(value);
3484 __ ThrowIf(ne, kNonSmiValue);
3485 __ SmiTst(index);
3486 __ ThrowIf(ne, kNonSmiIndex);
3487 __ SmiUntag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003488 static const uint32_t two_byte_seq_type = kSeqStringTag | kTwoByteStringTag;
machenbach@chromium.org9af454f2013-11-20 09:25:57 +00003489 __ EmitSeqStringSetCharCheck(string, index, value, two_byte_seq_type);
3490 __ SmiTag(index, index);
svenpanne@chromium.orga53e8e02013-05-24 12:35:50 +00003491 }
3492
3493 __ SmiUntag(value, value);
3494 __ add(ip,
3495 string,
3496 Operand(SeqTwoByteString::kHeaderSize - kHeapObjectTag));
3497 STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
3498 __ strh(value, MemOperand(ip, index));
3499 context()->Plug(string);
mstarzinger@chromium.org32280cf2012-12-06 17:32:37 +00003500}
3501
3502
3503
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003504void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003505 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003506 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003507 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003508 VisitForStackValue(args->at(0));
3509 VisitForStackValue(args->at(1));
mstarzinger@chromium.orge27d6172013-04-17 11:51:44 +00003510 MathPowStub stub(MathPowStub::ON_STACK);
3511 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003512 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003513}
3514
3515
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003516void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3517 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003518 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003519 VisitForStackValue(args->at(0)); // Load the object.
3520 VisitForAccumulatorValue(args->at(1)); // Load the value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003521 __ pop(r1); // r0 = value. r1 = object.
3522
3523 Label done;
3524 // If the object is a smi, return the value.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003525 __ JumpIfSmi(r1, &done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003526
3527 // If the object is not a value type, return the value.
3528 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE);
3529 __ b(ne, &done);
3530
3531 // Store the value.
3532 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
3533 // Update the write barrier. Save the value as it will be
3534 // overwritten by the write barrier code and is needed afterward.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003535 __ mov(r2, r0);
3536 __ RecordWriteField(
3537 r1, JSValue::kValueOffset, r2, r3, kLRHasBeenSaved, kDontSaveFPRegs);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003538
3539 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003540 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003541}
3542
3543
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003544void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3545 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003546 ASSERT_EQ(args->length(), 1);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003547 // Load the argument into r0 and call the stub.
3548 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003549
3550 NumberToStringStub stub;
3551 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003552 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003553}
3554
3555
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003556void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3557 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003558 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003559 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003560
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003561 Label done;
3562 StringCharFromCodeGenerator generator(r0, r1);
3563 generator.GenerateFast(masm_);
3564 __ jmp(&done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003565
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003566 NopRuntimeCallHelper call_helper;
3567 generator.GenerateSlow(masm_, call_helper);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003568
3569 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003570 context()->Plug(r1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003571}
3572
3573
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003574void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3575 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003576 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003577 VisitForStackValue(args->at(0));
3578 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003579
3580 Register object = r1;
3581 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003582 Register result = r3;
3583
3584 __ pop(object);
3585
3586 Label need_conversion;
3587 Label index_out_of_range;
3588 Label done;
3589 StringCharCodeAtGenerator generator(object,
3590 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003591 result,
3592 &need_conversion,
3593 &need_conversion,
3594 &index_out_of_range,
3595 STRING_INDEX_IS_NUMBER);
3596 generator.GenerateFast(masm_);
3597 __ jmp(&done);
3598
3599 __ bind(&index_out_of_range);
3600 // When the index is out of range, the spec requires us to return
3601 // NaN.
3602 __ LoadRoot(result, Heap::kNanValueRootIndex);
3603 __ jmp(&done);
3604
3605 __ bind(&need_conversion);
3606 // Load the undefined value into the result register, which will
3607 // trigger conversion.
3608 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3609 __ jmp(&done);
3610
3611 NopRuntimeCallHelper call_helper;
3612 generator.GenerateSlow(masm_, call_helper);
3613
3614 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003615 context()->Plug(result);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003616}
3617
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003618
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003619void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3620 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003621 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003622 VisitForStackValue(args->at(0));
3623 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003624
3625 Register object = r1;
3626 Register index = r0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003627 Register scratch = r3;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003628 Register result = r0;
3629
3630 __ pop(object);
3631
3632 Label need_conversion;
3633 Label index_out_of_range;
3634 Label done;
3635 StringCharAtGenerator generator(object,
3636 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003637 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003638 result,
3639 &need_conversion,
3640 &need_conversion,
3641 &index_out_of_range,
3642 STRING_INDEX_IS_NUMBER);
3643 generator.GenerateFast(masm_);
3644 __ jmp(&done);
3645
3646 __ bind(&index_out_of_range);
3647 // When the index is out of range, the spec requires us to return
3648 // the empty string.
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003649 __ LoadRoot(result, Heap::kempty_stringRootIndex);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003650 __ jmp(&done);
3651
3652 __ bind(&need_conversion);
3653 // Move smi zero into the result register, which will trigger
3654 // conversion.
3655 __ mov(result, Operand(Smi::FromInt(0)));
3656 __ jmp(&done);
3657
3658 NopRuntimeCallHelper call_helper;
3659 generator.GenerateSlow(masm_, call_helper);
3660
3661 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003662 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003663}
3664
3665
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003666void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3667 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003668 ASSERT_EQ(2, args->length());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003669
machenbach@chromium.org0cc09502013-11-13 12:20:55 +00003670 if (FLAG_new_string_add) {
3671 VisitForStackValue(args->at(0));
3672 VisitForAccumulatorValue(args->at(1));
3673
3674 __ pop(r1);
3675 NewStringAddStub stub(STRING_ADD_CHECK_BOTH, NOT_TENURED);
3676 __ CallStub(&stub);
3677 } else {
3678 VisitForStackValue(args->at(0));
3679 VisitForStackValue(args->at(1));
3680
3681 StringAddStub stub(STRING_ADD_CHECK_BOTH);
3682 __ CallStub(&stub);
3683 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003684 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003685}
3686
3687
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003688void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3689 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003690 ASSERT_EQ(2, args->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003691 VisitForStackValue(args->at(0));
3692 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003693
3694 StringCompareStub stub;
3695 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003696 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003697}
3698
3699
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003700void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003701 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003702 ZoneList<Expression*>* args = expr->arguments();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003703 ASSERT(args->length() == 1);
3704 VisitForStackValue(args->at(0));
hpayer@chromium.org4f99be92013-12-18 16:23:55 +00003705 __ CallRuntime(Runtime::kMath_log, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003706 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003707}
3708
3709
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003710void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003711 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003712 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003713 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003714 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003715 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003716 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003717}
3718
3719
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003720void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3721 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003722 ASSERT(args->length() >= 2);
3723
danno@chromium.org160a7b02011-04-18 15:51:38 +00003724 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3725 for (int i = 0; i < arg_count + 1; i++) {
3726 VisitForStackValue(args->at(i));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003727 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003728 VisitForAccumulatorValue(args->last()); // Function.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003729
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003730 Label runtime, done;
3731 // Check for non-function argument (including proxy).
3732 __ JumpIfSmi(r0, &runtime);
3733 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
3734 __ b(ne, &runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003735
danno@chromium.org160a7b02011-04-18 15:51:38 +00003736 // InvokeFunction requires the function in r1. Move it in there.
3737 __ mov(r1, result_register());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003738 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003739 __ InvokeFunction(r1, count, CALL_FUNCTION,
3740 NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003741 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003742 __ jmp(&done);
3743
verwaest@chromium.orgde64f722012-08-16 15:44:54 +00003744 __ bind(&runtime);
danno@chromium.orgc612e022011-11-10 11:38:15 +00003745 __ push(r0);
3746 __ CallRuntime(Runtime::kCall, args->length());
3747 __ bind(&done);
3748
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003749 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003750}
3751
3752
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003753void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003754 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003755 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003756 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003757 VisitForStackValue(args->at(0));
3758 VisitForStackValue(args->at(1));
3759 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003760 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003761 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003762}
3763
3764
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003765void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3766 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003767 ASSERT_EQ(2, args->length());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003768 ASSERT_NE(NULL, args->at(0)->AsLiteral());
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00003769 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->value()))->value();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003770
3771 Handle<FixedArray> jsfunction_result_caches(
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003772 isolate()->native_context()->jsfunction_result_caches());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003773 if (jsfunction_result_caches->length() <= cache_id) {
danno@chromium.org59400602013-08-13 17:09:37 +00003774 __ Abort(kAttemptToUseUndefinedCache);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003775 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003776 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003777 return;
3778 }
3779
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003780 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003781
3782 Register key = r0;
3783 Register cache = r1;
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00003784 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_OBJECT_INDEX));
3785 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kNativeContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003786 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003787 __ ldr(cache,
3788 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3789
3790
3791 Label done, not_found;
3792 // tmp now holds finger offset as a smi.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003793 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
3794 // r2 now holds finger offset as a smi.
3795 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3796 // r3 now points to the start of fixed array elements.
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00003797 __ ldr(r2, MemOperand::PointerAddressFromSmiKey(r3, r2, PreIndex));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003798 // Note side effect of PreIndex: r3 now points to the key of the pair.
3799 __ cmp(key, r2);
3800 __ b(ne, &not_found);
3801
3802 __ ldr(r0, MemOperand(r3, kPointerSize));
3803 __ b(&done);
3804
3805 __ bind(&not_found);
3806 // Call runtime to perform the lookup.
3807 __ Push(cache, key);
3808 __ CallRuntime(Runtime::kGetFromCache, 2);
3809
3810 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003811 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003812}
3813
3814
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003815void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3816 ZoneList<Expression*>* args = expr->arguments();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003817 ASSERT_EQ(2, args->length());
3818
3819 Register right = r0;
3820 Register left = r1;
3821 Register tmp = r2;
3822 Register tmp2 = r3;
3823
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003824 VisitForStackValue(args->at(0));
3825 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003826 __ pop(left);
3827
3828 Label done, fail, ok;
3829 __ cmp(left, Operand(right));
3830 __ b(eq, &ok);
3831 // Fail if either is a non-HeapObject.
3832 __ and_(tmp, left, Operand(right));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003833 __ JumpIfSmi(tmp, &fail);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003834 __ ldr(tmp, FieldMemOperand(left, HeapObject::kMapOffset));
3835 __ ldrb(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset));
3836 __ cmp(tmp2, Operand(JS_REGEXP_TYPE));
3837 __ b(ne, &fail);
3838 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
3839 __ cmp(tmp, Operand(tmp2));
3840 __ b(ne, &fail);
3841 __ ldr(tmp, FieldMemOperand(left, JSRegExp::kDataOffset));
3842 __ ldr(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset));
3843 __ cmp(tmp, tmp2);
3844 __ b(eq, &ok);
3845 __ bind(&fail);
3846 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
3847 __ jmp(&done);
3848 __ bind(&ok);
3849 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
3850 __ bind(&done);
3851
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003852 context()->Plug(r0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003853}
3854
3855
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003856void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3857 ZoneList<Expression*>* args = expr->arguments();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003858 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003859
3860 Label materialize_true, materialize_false;
3861 Label* if_true = NULL;
3862 Label* if_false = NULL;
3863 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003864 context()->PrepareTest(&materialize_true, &materialize_false,
3865 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003866
3867 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3868 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003869 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003870 Split(eq, if_true, if_false, fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003871
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003872 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003873}
3874
3875
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003876void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3877 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003878 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003879 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003880
svenpanne@chromium.orgc859c4f2012-10-15 11:51:39 +00003881 __ AssertString(r0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003882
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003883 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3884 __ IndexFromHash(r0, r0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003885
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003886 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003887}
3888
3889
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003890void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003891 Label bailout, done, one_char_separator, long_separator, non_trivial_array,
3892 not_size_one_array, loop, empty_separator_loop, one_char_separator_loop,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003893 one_char_separator_loop_entry, long_separator_loop;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003894 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003895 ASSERT(args->length() == 2);
3896 VisitForStackValue(args->at(1));
3897 VisitForAccumulatorValue(args->at(0));
3898
3899 // All aliases of the same register have disjoint lifetimes.
3900 Register array = r0;
3901 Register elements = no_reg; // Will be r0.
3902 Register result = no_reg; // Will be r0.
3903 Register separator = r1;
3904 Register array_length = r2;
3905 Register result_pos = no_reg; // Will be r2
3906 Register string_length = r3;
3907 Register string = r4;
3908 Register element = r5;
3909 Register elements_end = r6;
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003910 Register scratch = r9;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003911
3912 // Separator operand is on the stack.
3913 __ pop(separator);
3914
3915 // Check that the array is a JSArray.
3916 __ JumpIfSmi(array, &bailout);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003917 __ CompareObjectType(array, scratch, array_length, JS_ARRAY_TYPE);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003918 __ b(ne, &bailout);
3919
3920 // Check that the array has fast elements.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003921 __ CheckFastElements(scratch, array_length, &bailout);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003922
3923 // If the array has length zero, return the empty string.
3924 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3925 __ SmiUntag(array_length, SetCC);
3926 __ b(ne, &non_trivial_array);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00003927 __ LoadRoot(r0, Heap::kempty_stringRootIndex);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003928 __ b(&done);
3929
3930 __ bind(&non_trivial_array);
3931
3932 // Get the FixedArray containing array's elements.
3933 elements = array;
3934 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3935 array = no_reg; // End of array's live range.
3936
3937 // Check that all array elements are sequential ASCII strings, and
3938 // accumulate the sum of their lengths, as a smi-encoded value.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003939 __ mov(string_length, Operand::Zero());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003940 __ add(element,
3941 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3942 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3943 // Loop condition: while (element < elements_end).
3944 // Live values in registers:
3945 // elements: Fixed array of strings.
3946 // array_length: Length of the fixed array of strings (not smi)
3947 // separator: Separator string
3948 // string_length: Accumulated sum of string lengths (smi).
3949 // element: Current array element.
3950 // elements_end: Array end.
jkummerow@chromium.org000f7fb2012-08-01 11:14:42 +00003951 if (generate_debug_code_) {
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003952 __ cmp(array_length, Operand::Zero());
danno@chromium.org59400602013-08-13 17:09:37 +00003953 __ Assert(gt, kNoEmptyArraysHereInEmitFastAsciiArrayJoin);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003954 }
3955 __ bind(&loop);
3956 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3957 __ JumpIfSmi(string, &bailout);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003958 __ ldr(scratch, FieldMemOperand(string, HeapObject::kMapOffset));
3959 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
3960 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout);
3961 __ ldr(scratch, FieldMemOperand(string, SeqOneByteString::kLengthOffset));
3962 __ add(string_length, string_length, Operand(scratch), SetCC);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003963 __ b(vs, &bailout);
3964 __ cmp(element, elements_end);
3965 __ b(lt, &loop);
3966
3967 // If array_length is 1, return elements[0], a string.
3968 __ cmp(array_length, Operand(1));
3969 __ b(ne, &not_size_one_array);
3970 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
3971 __ b(&done);
3972
3973 __ bind(&not_size_one_array);
3974
3975 // Live values in registers:
3976 // separator: Separator string
3977 // array_length: Length of the array.
3978 // string_length: Sum of string lengths (smi).
3979 // elements: FixedArray of strings.
3980
3981 // Check that the separator is a flat ASCII string.
3982 __ JumpIfSmi(separator, &bailout);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003983 __ ldr(scratch, FieldMemOperand(separator, HeapObject::kMapOffset));
3984 __ ldrb(scratch, FieldMemOperand(scratch, Map::kInstanceTypeOffset));
3985 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch, scratch, &bailout);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003986
3987 // Add (separator length times array_length) - separator length to the
3988 // string_length to get the length of the result string. array_length is not
3989 // smi but the other values are, so the result is a smi
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003990 __ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
3991 __ sub(string_length, string_length, Operand(scratch));
3992 __ smull(scratch, ip, array_length, scratch);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003993 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3994 // zero.
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00003995 __ cmp(ip, Operand::Zero());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003996 __ b(ne, &bailout);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003997 __ tst(scratch, Operand(0x80000000));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003998 __ b(ne, &bailout);
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00003999 __ add(string_length, string_length, Operand(scratch), SetCC);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004000 __ b(vs, &bailout);
4001 __ SmiUntag(string_length);
4002
4003 // Get first element in the array to free up the elements register to be used
4004 // for the result.
4005 __ add(element,
4006 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
4007 result = elements; // End of live range for elements.
4008 elements = no_reg;
4009 // Live values in registers:
4010 // element: First array element
4011 // separator: Separator string
4012 // string_length: Length of result string (not smi)
4013 // array_length: Length of the array.
4014 __ AllocateAsciiString(result,
4015 string_length,
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004016 scratch,
4017 string, // used as scratch
4018 elements_end, // used as scratch
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004019 &bailout);
4020 // Prepare for looping. Set up elements_end to end of the array. Set
4021 // result_pos to the position of the result where to write the first
4022 // character.
4023 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
4024 result_pos = array_length; // End of live range for array_length.
4025 array_length = no_reg;
4026 __ add(result_pos,
4027 result,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004028 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004029
4030 // Check the length of the separator.
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004031 __ ldr(scratch, FieldMemOperand(separator, SeqOneByteString::kLengthOffset));
4032 __ cmp(scratch, Operand(Smi::FromInt(1)));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004033 __ b(eq, &one_char_separator);
4034 __ b(gt, &long_separator);
4035
4036 // Empty separator case
4037 __ bind(&empty_separator_loop);
4038 // Live values in registers:
4039 // result_pos: the position to which we are currently copying characters.
4040 // element: Current array element.
4041 // elements_end: Array end.
4042
4043 // Copy next array element to the result.
4044 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
4045 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
4046 __ SmiUntag(string_length);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004047 __ add(string,
4048 string,
4049 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004050 __ CopyBytes(string, result_pos, string_length, scratch);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004051 __ cmp(element, elements_end);
4052 __ b(lt, &empty_separator_loop); // End while (element < elements_end).
4053 ASSERT(result.is(r0));
4054 __ b(&done);
4055
4056 // One-character separator case
4057 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004058 // Replace separator with its ASCII character value.
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004059 __ ldrb(separator, FieldMemOperand(separator, SeqOneByteString::kHeaderSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004060 // Jump into the loop after the code that copies the separator, so the first
4061 // element is not preceded by a separator
4062 __ jmp(&one_char_separator_loop_entry);
4063
4064 __ bind(&one_char_separator_loop);
4065 // Live values in registers:
4066 // result_pos: the position to which we are currently copying characters.
4067 // element: Current array element.
4068 // elements_end: Array end.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00004069 // separator: Single separator ASCII char (in lower byte).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004070
4071 // Copy the separator character to the result.
4072 __ strb(separator, MemOperand(result_pos, 1, PostIndex));
4073
4074 // Copy next array element to the result.
4075 __ bind(&one_char_separator_loop_entry);
4076 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
4077 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
4078 __ SmiUntag(string_length);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004079 __ add(string,
4080 string,
4081 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004082 __ CopyBytes(string, result_pos, string_length, scratch);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004083 __ cmp(element, elements_end);
4084 __ b(lt, &one_char_separator_loop); // End while (element < elements_end).
4085 ASSERT(result.is(r0));
4086 __ b(&done);
4087
4088 // Long separator case (separator is more than one character). Entry is at the
4089 // label long_separator below.
4090 __ bind(&long_separator_loop);
4091 // Live values in registers:
4092 // result_pos: the position to which we are currently copying characters.
4093 // element: Current array element.
4094 // elements_end: Array end.
4095 // separator: Separator string.
4096
4097 // Copy the separator to the result.
4098 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset));
4099 __ SmiUntag(string_length);
4100 __ add(string,
4101 separator,
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004102 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004103 __ CopyBytes(string, result_pos, string_length, scratch);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004104
4105 __ bind(&long_separator);
4106 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
4107 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
4108 __ SmiUntag(string_length);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004109 __ add(string,
4110 string,
4111 Operand(SeqOneByteString::kHeaderSize - kHeapObjectTag));
machenbach@chromium.org3d079fe2013-09-25 08:19:55 +00004112 __ CopyBytes(string, result_pos, string_length, scratch);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004113 __ cmp(element, elements_end);
4114 __ b(lt, &long_separator_loop); // End while (element < elements_end).
4115 ASSERT(result.is(r0));
4116 __ b(&done);
4117
4118 __ bind(&bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004119 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004120 __ bind(&done);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004121 context()->Plug(r0);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00004122}
4123
4124
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004125void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004126 Handle<String> name = expr->name();
4127 if (name->length() > 0 && name->Get(0) == '_') {
4128 Comment cmnt(masm_, "[ InlineRuntimeCall");
4129 EmitInlineRuntimeCall(expr);
4130 return;
4131 }
4132
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004133 Comment cmnt(masm_, "[ CallRuntime");
4134 ZoneList<Expression*>* args = expr->arguments();
4135
4136 if (expr->is_jsruntime()) {
4137 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004138 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004139 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +00004140 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004141 }
4142
4143 // Push the arguments ("left-to-right").
4144 int arg_count = args->length();
4145 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004146 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004147 }
4148
4149 if (expr->is_jsruntime()) {
4150 // Call the JS runtime function.
ager@chromium.org5c838252010-02-19 08:53:10 +00004151 __ mov(r2, Operand(expr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00004152 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004153 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00004154 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004155 CallIC(ic, mode, expr->CallRuntimeFeedbackId());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004156 // Restore context register.
4157 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004158 } else {
4159 // Call the C runtime function.
4160 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004161 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004162 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004163}
4164
4165
4166void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
4167 switch (expr->op()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004168 case Token::DELETE: {
4169 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004170 Property* property = expr->expression()->AsProperty();
4171 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004172
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004173 if (property != NULL) {
4174 VisitForStackValue(property->obj());
4175 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004176 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
4177 ? kNonStrictMode : kStrictMode;
4178 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag)));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00004179 __ push(r1);
4180 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
4181 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004182 } else if (proxy != NULL) {
4183 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004184 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004185 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004186 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004187 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004188 __ ldr(r2, GlobalObjectOperand());
4189 __ mov(r1, Operand(var->name()));
4190 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
4191 __ Push(r2, r1, r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004192 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004193 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004194 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004195 // Result of deleting non-global, non-dynamic variables is false.
4196 // The subexpression does not have side effects.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004197 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004198 } else {
4199 // Non-global variable. Call the runtime to try to delete from the
4200 // context where the variable was introduced.
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004201 ASSERT(!context_register().is(r2));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004202 __ mov(r2, Operand(var->name()));
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004203 __ Push(context_register(), r2);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004204 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
4205 context()->Plug(r0);
4206 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004207 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004208 // Result of deleting non-property, non-variable reference is true.
4209 // The subexpression may have side effects.
4210 VisitForEffect(expr->expression());
4211 context()->Plug(true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004212 }
4213 break;
4214 }
4215
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004216 case Token::VOID: {
4217 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4218 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004219 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004220 break;
4221 }
4222
4223 case Token::NOT: {
4224 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004225 if (context()->IsEffect()) {
4226 // Unary NOT has no side effects so it's only necessary to visit the
4227 // subexpression. Match the optimizing compiler by not branching.
4228 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004229 } else if (context()->IsTest()) {
4230 const TestContext* test = TestContext::cast(context());
4231 // The labels are swapped for the recursive call.
4232 VisitForControl(expr->expression(),
4233 test->false_label(),
4234 test->true_label(),
4235 test->fall_through());
4236 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004237 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004238 // We handle value contexts explicitly rather than simply visiting
4239 // for control and plugging the control flow into the context,
4240 // because we need to prepare a pair of extra administrative AST ids
4241 // for the optimizing compiler.
4242 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
4243 Label materialize_true, materialize_false, done;
4244 VisitForControl(expr->expression(),
4245 &materialize_false,
4246 &materialize_true,
4247 &materialize_true);
4248 __ bind(&materialize_true);
4249 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4250 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
4251 if (context()->IsStackValue()) __ push(r0);
4252 __ jmp(&done);
4253 __ bind(&materialize_false);
4254 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4255 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
4256 if (context()->IsStackValue()) __ push(r0);
4257 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004258 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004259 break;
4260 }
4261
4262 case Token::TYPEOF: {
4263 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004264 { StackValueContext context(this);
4265 VisitForTypeofValue(expr->expression());
4266 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004267 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004268 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004269 break;
4270 }
4271
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004272 default:
4273 UNREACHABLE();
4274 }
4275}
4276
4277
4278void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4279 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004280 SetSourcePosition(expr->position());
4281
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004282 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
4283 // as the left-hand side.
4284 if (!expr->expression()->IsValidLeftHandSide()) {
4285 VisitForEffect(expr->expression());
4286 return;
4287 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004288
4289 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00004290 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004291 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4292 LhsKind assign_type = VARIABLE;
4293 Property* prop = expr->expression()->AsProperty();
4294 // In case of a property we use the uninitialized expression context
4295 // of the key to detect a named property.
4296 if (prop != NULL) {
4297 assign_type =
4298 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4299 }
4300
4301 // Evaluate expression and get value.
4302 if (assign_type == VARIABLE) {
4303 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004304 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00004305 EmitVariableLoad(expr->expression()->AsVariableProxy());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004306 } else {
4307 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004308 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004309 __ mov(ip, Operand(Smi::FromInt(0)));
4310 __ push(ip);
4311 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004312 if (assign_type == NAMED_PROPERTY) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004313 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004314 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004315 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004316 EmitNamedPropertyLoad(prop);
4317 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004318 VisitForStackValue(prop->obj());
4319 VisitForAccumulatorValue(prop->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00004320 __ ldr(r1, MemOperand(sp, 0));
4321 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004322 EmitKeyedPropertyLoad(prop);
4323 }
4324 }
4325
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004326 // We need a second deoptimization point after loading the value
4327 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004328 if (assign_type == VARIABLE) {
4329 PrepareForBailout(expr->expression(), TOS_REG);
4330 } else {
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004331 PrepareForBailoutForId(prop->LoadId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004332 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004333
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004334 // Inline smi case if we are in a loop.
4335 Label stub_call, done;
4336 JumpPatchSite patch_site(masm_);
4337
4338 int count_value = expr->op() == Token::INC ? 1 : -1;
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004339 if (ShouldInlineSmiCase(expr->op())) {
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004340 Label slow;
4341 patch_site.EmitJumpIfNotSmi(r0, &slow);
4342
4343 // Save result for postfix expressions.
4344 if (expr->is_postfix()) {
4345 if (!context()->IsEffect()) {
4346 // Save the result on the stack. If we have a named or keyed property
4347 // we store the result under the receiver that is currently on top
4348 // of the stack.
4349 switch (assign_type) {
4350 case VARIABLE:
4351 __ push(r0);
4352 break;
4353 case NAMED_PROPERTY:
4354 __ str(r0, MemOperand(sp, kPointerSize));
4355 break;
4356 case KEYED_PROPERTY:
4357 __ str(r0, MemOperand(sp, 2 * kPointerSize));
4358 break;
4359 }
4360 }
4361 }
4362
4363 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
4364 __ b(vc, &done);
4365 // Call stub. Undo operation first.
4366 __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
4367 __ jmp(&stub_call);
4368 __ bind(&slow);
jkummerow@chromium.orgba72ec82013-07-22 09:21:20 +00004369 }
whesse@chromium.org7a392b32011-01-31 11:30:36 +00004370 ToNumberStub convert_stub;
4371 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004372
4373 // Save result for postfix expressions.
4374 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004375 if (!context()->IsEffect()) {
4376 // Save the result on the stack. If we have a named or keyed property
4377 // we store the result under the receiver that is currently on top
4378 // of the stack.
4379 switch (assign_type) {
4380 case VARIABLE:
4381 __ push(r0);
4382 break;
4383 case NAMED_PROPERTY:
4384 __ str(r0, MemOperand(sp, kPointerSize));
4385 break;
4386 case KEYED_PROPERTY:
4387 __ str(r0, MemOperand(sp, 2 * kPointerSize));
4388 break;
4389 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004390 }
4391 }
4392
4393
machenbach@chromium.orge8412be2013-11-08 10:23:52 +00004394 __ bind(&stub_call);
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004395 __ mov(r1, r0);
4396 __ mov(r0, Operand(Smi::FromInt(count_value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004397
4398 // Record position before stub call.
4399 SetSourcePosition(expr->position());
4400
machenbach@chromium.orgce9c5142013-12-03 08:00:39 +00004401 BinaryOpICStub stub(Token::ADD, NO_OVERWRITE);
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004402 CallIC(stub.GetCode(isolate()),
4403 RelocInfo::CODE_TARGET,
4404 expr->CountBinOpFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004405 patch_site.EmitPatchInfo();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004406 __ bind(&done);
4407
4408 // Store the value returned in r0.
4409 switch (assign_type) {
4410 case VARIABLE:
4411 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004412 { EffectContext context(this);
4413 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4414 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004415 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4416 context.Plug(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004417 }
4418 // For all contexts except EffectConstant We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004419 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004420 if (!context()->IsEffect()) {
4421 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004422 }
4423 } else {
4424 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004425 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004426 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4427 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004428 }
4429 break;
4430 case NAMED_PROPERTY: {
mstarzinger@chromium.org1510d582013-06-28 14:00:48 +00004431 __ mov(r2, Operand(prop->key()->AsLiteral()->value()));
ager@chromium.org5c838252010-02-19 08:53:10 +00004432 __ pop(r1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004433 Handle<Code> ic = is_classic_mode()
4434 ? isolate()->builtins()->StoreIC_Initialize()
4435 : isolate()->builtins()->StoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004436 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004437 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004438 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004439 if (!context()->IsEffect()) {
4440 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004441 }
4442 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004443 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004444 }
4445 break;
4446 }
4447 case KEYED_PROPERTY: {
verwaest@chromium.org057bd502013-11-06 12:03:29 +00004448 __ Pop(r2, r1); // r1 = key. r2 = receiver.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004449 Handle<Code> ic = is_classic_mode()
4450 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4451 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004452 CallIC(ic, RelocInfo::CODE_TARGET, expr->CountStoreFeedbackId());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004453 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004454 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004455 if (!context()->IsEffect()) {
4456 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004457 }
4458 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004459 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004460 }
4461 break;
4462 }
4463 }
4464}
4465
4466
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004467void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
4468 ASSERT(!context()->IsEffect());
4469 ASSERT(!context()->IsTest());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004470 VariableProxy* proxy = expr->AsVariableProxy();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004471 if (proxy != NULL && proxy->var()->IsUnallocated()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004472 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004473 __ ldr(r0, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004474 __ mov(r2, Operand(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004475 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004476 // Use a regular load, not a contextual load, to avoid a reference
4477 // error.
danno@chromium.org88aa0582012-03-23 15:11:57 +00004478 CallIC(ic);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004479 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004480 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004481 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004482 Label done, slow;
4483
4484 // Generate code for loading from variables potentially shadowed
4485 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004486 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004487
4488 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004489 __ mov(r0, Operand(proxy->name()));
4490 __ Push(cp, r0);
4491 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004492 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004493 __ bind(&done);
4494
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004495 context()->Plug(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004496 } else {
4497 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004498 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004499 }
4500}
4501
4502
ager@chromium.org04921a82011-06-27 13:21:41 +00004503void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004504 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004505 Handle<String> check) {
4506 Label materialize_true, materialize_false;
4507 Label* if_true = NULL;
4508 Label* if_false = NULL;
4509 Label* fall_through = NULL;
4510 context()->PrepareTest(&materialize_true, &materialize_false,
4511 &if_true, &if_false, &fall_through);
4512
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004513 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004514 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004515 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004516 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004517
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004518 if (check->Equals(isolate()->heap()->number_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004519 __ JumpIfSmi(r0, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004520 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
4521 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
4522 __ cmp(r0, ip);
4523 Split(eq, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004524 } else if (check->Equals(isolate()->heap()->string_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004525 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004526 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004527 __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
4528 __ b(ge, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004529 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004530 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4531 Split(eq, if_true, if_false, fall_through);
mstarzinger@chromium.orgf705b502013-04-04 11:38:09 +00004532 } else if (check->Equals(isolate()->heap()->symbol_string())) {
4533 __ JumpIfSmi(r0, if_false);
4534 __ CompareObjectType(r0, r0, r1, SYMBOL_TYPE);
4535 Split(eq, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004536 } else if (check->Equals(isolate()->heap()->boolean_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004537 __ CompareRoot(r0, Heap::kTrueValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004538 __ b(eq, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004539 __ CompareRoot(r0, Heap::kFalseValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004540 Split(eq, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004541 } else if (FLAG_harmony_typeof &&
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004542 check->Equals(isolate()->heap()->null_string())) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004543 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4544 Split(eq, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004545 } else if (check->Equals(isolate()->heap()->undefined_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004546 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004547 __ b(eq, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004548 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004549 // Check for undetectable objects => true.
4550 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
4551 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004552 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4553 Split(ne, if_true, if_false, fall_through);
4554
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004555 } else if (check->Equals(isolate()->heap()->function_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004556 __ JumpIfSmi(r0, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004557 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4558 __ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE);
4559 __ b(eq, if_true);
4560 __ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE));
4561 Split(eq, if_true, if_false, fall_through);
yangguo@chromium.org4a9f6552013-03-04 14:46:33 +00004562 } else if (check->Equals(isolate()->heap()->object_string())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004563 __ JumpIfSmi(r0, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004564 if (!FLAG_harmony_typeof) {
4565 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4566 __ b(eq, if_true);
4567 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004568 // Check for JS objects => true.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004569 __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
4570 __ b(lt, if_false);
4571 __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4572 __ b(gt, if_false);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004573 // Check for undetectable objects => false.
4574 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
4575 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4576 Split(eq, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004577 } else {
4578 if (if_false != fall_through) __ jmp(if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004579 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004580 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004581}
4582
4583
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004584void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4585 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004586 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004587
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004588 // First we try a fast inlined version of the compare when one of
4589 // the operands is a literal.
4590 if (TryLiteralCompare(expr)) return;
4591
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004592 // Always perform the comparison for its control flow. Pack the result
4593 // into the expression's context after the comparison is performed.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004594 Label materialize_true, materialize_false;
4595 Label* if_true = NULL;
4596 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004597 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004598 context()->PrepareTest(&materialize_true, &materialize_false,
4599 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004600
ager@chromium.org04921a82011-06-27 13:21:41 +00004601 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004602 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004603 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004604 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004605 VisitForStackValue(expr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004606 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004607 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004608 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
4609 __ cmp(r0, ip);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004610 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004611 break;
4612
4613 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004614 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004615 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004616 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004617 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004618 // The stub returns 0 for true.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004619 __ tst(r0, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004620 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004621 break;
4622 }
4623
4624 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004625 VisitForAccumulatorValue(expr->right());
yangguo@chromium.orgfb377212012-11-16 14:43:43 +00004626 Condition cond = CompareIC::ComputeCondition(op);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004627 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004628
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004629 bool inline_smi_code = ShouldInlineSmiCase(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004630 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004631 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004632 Label slow_case;
4633 __ orr(r2, r0, Operand(r1));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004634 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004635 __ cmp(r1, r0);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004636 Split(cond, if_true, if_false, NULL);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004637 __ bind(&slow_case);
4638 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004639
4640 // Record position and call the compare IC.
4641 SetSourcePosition(expr->position());
hpayer@chromium.org8432c912013-02-28 15:55:26 +00004642 Handle<Code> ic = CompareIC::GetUninitialized(isolate(), op);
mstarzinger@chromium.org471f2f12012-08-10 14:46:33 +00004643 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004644 patch_site.EmitPatchInfo();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004645 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
jkummerow@chromium.org59297c72013-01-09 16:32:23 +00004646 __ cmp(r0, Operand::Zero());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004647 Split(cond, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004648 }
4649 }
4650
4651 // Convert the result of the comparison into one expected for this
4652 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004653 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004654}
4655
4656
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004657void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4658 Expression* sub_expr,
4659 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004660 Label materialize_true, materialize_false;
4661 Label* if_true = NULL;
4662 Label* if_false = NULL;
4663 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004664 context()->PrepareTest(&materialize_true, &materialize_false,
4665 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004666
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004667 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004668 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ulan@chromium.org837a67e2013-06-11 15:39:48 +00004669 if (expr->op() == Token::EQ_STRICT) {
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004670 Heap::RootListIndex nil_value = nil == kNullValue ?
4671 Heap::kNullValueRootIndex :
4672 Heap::kUndefinedValueRootIndex;
4673 __ LoadRoot(r1, nil_value);
4674 __ cmp(r0, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004675 Split(eq, if_true, if_false, fall_through);
4676 } else {
ulan@chromium.org837a67e2013-06-11 15:39:48 +00004677 Handle<Code> ic = CompareNilICStub::GetUninitialized(isolate(), nil);
danno@chromium.orgca29dd82013-04-26 11:59:48 +00004678 CallIC(ic, RelocInfo::CODE_TARGET, expr->CompareOperationFeedbackId());
4679 __ cmp(r0, Operand(0));
4680 Split(ne, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004681 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004682 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004683}
4684
4685
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004686void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4687 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004688 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004689}
4690
4691
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004692Register FullCodeGenerator::result_register() {
4693 return r0;
4694}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004695
4696
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004697Register FullCodeGenerator::context_register() {
4698 return cp;
4699}
4700
4701
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004702void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4703 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4704 __ str(value, MemOperand(fp, frame_offset));
4705}
4706
4707
4708void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004709 __ ldr(dst, ContextOperand(cp, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004710}
4711
4712
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004713void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004714 Scope* declaration_scope = scope()->DeclarationScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004715 if (declaration_scope->is_global_scope() ||
4716 declaration_scope->is_module_scope()) {
yangguo@chromium.org46839fb2012-08-28 09:06:19 +00004717 // Contexts nested in the native context have a canonical empty function
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004718 // as their closure, not the anonymous closure containing the global
4719 // code. Pass a smi sentinel and let the runtime look up the empty
4720 // function.
4721 __ mov(ip, Operand(Smi::FromInt(0)));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004722 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004723 // Contexts created by a call to eval have the same closure as the
4724 // context calling eval, not the anonymous closure containing the eval
4725 // code. Fetch it from the context.
4726 __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX));
4727 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004728 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004729 __ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4730 }
4731 __ push(ip);
4732}
4733
4734
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004735// ----------------------------------------------------------------------------
4736// Non-local control flow support.
4737
4738void FullCodeGenerator::EnterFinallyBlock() {
4739 ASSERT(!result_register().is(r1));
4740 // Store result register while executing finally block.
4741 __ push(result_register());
4742 // Cook return address in link register to stack (smi encoded Code* delta)
4743 __ sub(r1, lr, Operand(masm_->CodeObject()));
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004744 __ SmiTag(r1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004745
4746 // Store result register while executing finally block.
4747 __ push(r1);
4748
4749 // Store pending message while executing finally block.
4750 ExternalReference pending_message_obj =
4751 ExternalReference::address_of_pending_message_obj(isolate());
4752 __ mov(ip, Operand(pending_message_obj));
4753 __ ldr(r1, MemOperand(ip));
4754 __ push(r1);
4755
4756 ExternalReference has_pending_message =
4757 ExternalReference::address_of_has_pending_message(isolate());
4758 __ mov(ip, Operand(has_pending_message));
4759 __ ldr(r1, MemOperand(ip));
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004760 __ SmiTag(r1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004761 __ push(r1);
4762
4763 ExternalReference pending_message_script =
4764 ExternalReference::address_of_pending_message_script(isolate());
4765 __ mov(ip, Operand(pending_message_script));
4766 __ ldr(r1, MemOperand(ip));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004767 __ push(r1);
4768}
4769
4770
4771void FullCodeGenerator::ExitFinallyBlock() {
4772 ASSERT(!result_register().is(r1));
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004773 // Restore pending message from stack.
4774 __ pop(r1);
4775 ExternalReference pending_message_script =
4776 ExternalReference::address_of_pending_message_script(isolate());
4777 __ mov(ip, Operand(pending_message_script));
4778 __ str(r1, MemOperand(ip));
4779
4780 __ pop(r1);
verwaest@chromium.org753aee42012-07-17 16:15:42 +00004781 __ SmiUntag(r1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004782 ExternalReference has_pending_message =
4783 ExternalReference::address_of_has_pending_message(isolate());
4784 __ mov(ip, Operand(has_pending_message));
4785 __ str(r1, MemOperand(ip));
4786
4787 __ pop(r1);
4788 ExternalReference pending_message_obj =
4789 ExternalReference::address_of_pending_message_obj(isolate());
4790 __ mov(ip, Operand(pending_message_obj));
4791 __ str(r1, MemOperand(ip));
4792
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004793 // Restore result register from stack.
4794 __ pop(r1);
mmassi@chromium.org7028c052012-06-13 11:51:58 +00004795
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004796 // Uncook return address and return.
4797 __ pop(result_register());
ulan@chromium.orgbf9432e2013-05-22 14:05:23 +00004798 __ SmiUntag(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004799 __ add(pc, r1, Operand(masm_->CodeObject()));
4800}
4801
4802
4803#undef __
4804
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004805#define __ ACCESS_MASM(masm())
4806
4807FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4808 int* stack_depth,
4809 int* context_length) {
4810 // The macros used here must preserve the result register.
4811
4812 // Because the handler block contains the context of the finally
4813 // code, we can restore it directly from there for the finally code
4814 // rather than iteratively unwinding contexts via their previous
4815 // links.
4816 __ Drop(*stack_depth); // Down to the handler block.
4817 if (*context_length > 0) {
4818 // Restore the context to its dedicated register and the stack.
4819 __ ldr(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
4820 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4821 }
4822 __ PopTryHandler();
4823 __ bl(finally_entry_);
4824
4825 *stack_depth = 0;
4826 *context_length = 0;
4827 return previous_;
4828}
4829
4830
4831#undef __
4832
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004833
4834static const int32_t kBranchBeforeInterrupt = 0x5a000004;
4835
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004836
4837void BackEdgeTable::PatchAt(Code* unoptimized_code,
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004838 Address pc,
4839 BackEdgeState target_state,
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004840 Code* replacement_code) {
4841 static const int kInstrSize = Assembler::kInstrSize;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004842 Address branch_address = pc - 3 * kInstrSize;
4843 CodePatcher patcher(branch_address, 1);
4844
4845 switch (target_state) {
4846 case INTERRUPT:
4847 // <decrement profiling counter>
4848 // 2a 00 00 01 bpl ok
4849 // e5 9f c? ?? ldr ip, [pc, <interrupt stub address>]
4850 // e1 2f ff 3c blx ip
4851 // ok-label
4852 patcher.masm()->b(4 * kInstrSize, pl); // Jump offset is 4 instructions.
4853 ASSERT_EQ(kBranchBeforeInterrupt, Memory::int32_at(branch_address));
4854 break;
4855 case ON_STACK_REPLACEMENT:
4856 case OSR_AFTER_STACK_CHECK:
4857 // <decrement profiling counter>
4858 // e1 a0 00 00 mov r0, r0 (NOP)
4859 // e5 9f c? ?? ldr ip, [pc, <on-stack replacement address>]
4860 // e1 2f ff 3c blx ip
4861 // ok-label
4862 patcher.masm()->nop();
4863 break;
4864 }
4865
4866 Address pc_immediate_load_address = pc - 2 * kInstrSize;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004867 // Replace the call address.
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004868 uint32_t interrupt_address_offset =
4869 Memory::uint16_at(pc_immediate_load_address) & 0xfff;
4870 Address interrupt_address_pointer = pc + interrupt_address_offset;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004871 Memory::uint32_at(interrupt_address_pointer) =
4872 reinterpret_cast<uint32_t>(replacement_code->entry());
4873
4874 unoptimized_code->GetHeap()->incremental_marking()->RecordCodeTargetPatch(
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004875 unoptimized_code, pc_immediate_load_address, replacement_code);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004876}
4877
4878
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004879BackEdgeTable::BackEdgeState BackEdgeTable::GetBackEdgeState(
4880 Isolate* isolate,
4881 Code* unoptimized_code,
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004882 Address pc) {
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004883 static const int kInstrSize = Assembler::kInstrSize;
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004884 ASSERT(Memory::int32_at(pc - kInstrSize) == kBlxIp);
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004885
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004886 Address branch_address = pc - 3 * kInstrSize;
4887 Address pc_immediate_load_address = pc - 2 * kInstrSize;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004888 uint32_t interrupt_address_offset =
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004889 Memory::uint16_at(pc_immediate_load_address) & 0xfff;
4890 Address interrupt_address_pointer = pc + interrupt_address_offset;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004891
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004892 if (Memory::int32_at(branch_address) == kBranchBeforeInterrupt) {
4893 ASSERT(Memory::uint32_at(interrupt_address_pointer) ==
4894 reinterpret_cast<uint32_t>(
4895 isolate->builtins()->InterruptCheck()->entry()));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004896 ASSERT(Assembler::IsLdrPcImmediateOffset(
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004897 Assembler::instr_at(pc_immediate_load_address)));
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004898 return INTERRUPT;
4899 }
machenbach@chromium.org8e36b5b2013-09-26 07:36:30 +00004900
4901 ASSERT(Assembler::IsNop(Assembler::instr_at(branch_address)));
4902 ASSERT(Assembler::IsLdrPcImmediateOffset(
4903 Assembler::instr_at(pc_immediate_load_address)));
4904
4905 if (Memory::uint32_at(interrupt_address_pointer) ==
4906 reinterpret_cast<uint32_t>(
4907 isolate->builtins()->OnStackReplacement()->entry())) {
4908 return ON_STACK_REPLACEMENT;
4909 }
4910
4911 ASSERT(Memory::uint32_at(interrupt_address_pointer) ==
4912 reinterpret_cast<uint32_t>(
4913 isolate->builtins()->OsrAfterStackCheck()->entry()));
4914 return OSR_AFTER_STACK_CHECK;
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004915}
machenbach@chromium.org528ce022013-09-23 14:09:36 +00004916
4917
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004918} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004919
4920#endif // V8_TARGET_ARCH_ARM