blob: e7555cba051eedc43d1d45078120e99e5769ef66 [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
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_ARM)
31
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_);
73 __ bind(&patch_site_);
74 __ cmp(reg, Operand(reg));
75 // Don't use b(al, ...) as that might emit the constant pool right after the
76 // branch. After patching when the branch is no longer unconditional
77 // execution can continue into the constant pool.
78 __ b(eq, target); // Always taken before patched.
79 }
80
81 // When initially emitting this ensure that a jump is never generated to skip
82 // the inlined smi code.
83 void EmitJumpIfSmi(Register reg, Label* target) {
84 ASSERT(!patch_site_.is_bound() && !info_emitted_);
85 __ bind(&patch_site_);
86 __ cmp(reg, Operand(reg));
87 __ b(ne, target); // Never taken before patched.
88 }
89
90 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000091 if (patch_site_.is_bound()) {
92 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
93 Register reg;
94 reg.set_code(delta_to_patch_site / kOff12Mask);
95 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000096#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +000097 info_emitted_ = true;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000098#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +000099 } else {
100 __ nop(); // Signals no inlined code.
101 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000102 }
103
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000104 private:
105 MacroAssembler* masm_;
106 Label patch_site_;
107#ifdef DEBUG
108 bool info_emitted_;
109#endif
110};
111
112
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000113// Generate code for a JS function. On entry to the function the receiver
114// and arguments have been pushed on the stack left to right. The actual
115// argument count matches the formal parameter count expected by the
116// function.
117//
118// The live registers are:
ulan@chromium.org2efb9002012-01-19 15:36:35 +0000119// o r1: the JS function object being called (i.e., ourselves)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000120// o cp: our context
121// o fp: our caller's frame pointer
122// o sp: stack pointer
123// o lr: return address
124//
125// The function builds a JS frame. Please see JavaScriptFrameConstants in
126// frames-arm.h for its layout.
yangguo@chromium.org56454712012-02-16 15:33:53 +0000127void FullCodeGenerator::Generate() {
128 CompilationInfo* info = info_;
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +0000129 handler_table_ =
130 isolate()->factory()->NewFixedArray(function()->handler_count(), TENURED);
danno@chromium.org88aa0582012-03-23 15:11:57 +0000131 profiling_counter_ = isolate()->factory()->NewJSGlobalPropertyCell(
132 Handle<Smi>(Smi::FromInt(FLAG_interrupt_budget)));
ager@chromium.org5c838252010-02-19 08:53:10 +0000133 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000134 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000135
yangguo@chromium.orga7d3df92012-02-27 11:46:55 +0000136#ifdef DEBUG
137 if (strlen(FLAG_stop_at) > 0 &&
138 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
139 __ stop("stop-at");
140 }
141#endif
142
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000143 // Strict mode functions and builtins need to replace the receiver
144 // with undefined when called as functions (without an explicit
145 // receiver object). r5 is zero for method calls and non-zero for
146 // function calls.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000147 if (!info->is_classic_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000148 Label ok;
149 __ cmp(r5, Operand(0));
150 __ b(eq, &ok);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000151 int receiver_offset = info->scope()->num_parameters() * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000152 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
153 __ str(r2, MemOperand(sp, receiver_offset));
154 __ bind(&ok);
155 }
156
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000157 // Open a frame scope to indicate that there is a frame on the stack. The
158 // MANUAL indicates that the scope shouldn't actually generate code to set up
159 // the frame (that is done below).
160 FrameScope frame_scope(masm_, StackFrame::MANUAL);
161
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000162 int locals_count = info->scope()->num_stack_slots();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000164 __ Push(lr, fp, cp, r1);
165 if (locals_count > 0) {
166 // Load undefined value here, so the value is ready for the loop
167 // below.
168 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
169 }
170 // Adjust fp to point to caller's fp.
171 __ add(fp, sp, Operand(2 * kPointerSize));
172
173 { Comment cmnt(masm_, "[ Allocate locals");
174 for (int i = 0; i < locals_count; i++) {
175 __ push(ip);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000176 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000177 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000178
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000179 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000180
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000181 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000182 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000183 if (heap_slots > 0) {
184 Comment cmnt(masm_, "[ Allocate local context");
185 // Argument to NewContext is the function, which is in r1.
186 __ push(r1);
187 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
188 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000189 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000190 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000191 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000192 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000193 function_in_register = false;
194 // Context is returned in both r0 and cp. It replaces the context
195 // passed to us. It's saved in the stack and kept live in cp.
196 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
197 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000198 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000199 for (int i = 0; i < num_parameters; i++) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000200 Variable* var = scope()->parameter(i);
201 if (var->IsContextSlot()) {
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000202 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
203 (num_parameters - 1 - i) * kPointerSize;
204 // Load parameter from stack.
205 __ ldr(r0, MemOperand(fp, parameter_offset));
206 // Store it in the context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000207 MemOperand target = ContextOperand(cp, var->index());
208 __ str(r0, target);
209
210 // Update the write barrier.
211 __ RecordWriteContextSlot(
212 cp, target.offset(), r0, r3, kLRHasBeenSaved, kDontSaveFPRegs);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000213 }
214 }
215 }
216
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000217 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000218 if (arguments != NULL) {
219 // Function uses arguments object.
220 Comment cmnt(masm_, "[ Allocate arguments object");
221 if (!function_in_register) {
222 // Load this again, if it's used by the local context below.
223 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
224 } else {
225 __ mov(r3, r1);
226 }
227 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000228 int num_parameters = info->scope()->num_parameters();
229 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000230 __ add(r2, fp,
231 Operand(StandardFrameConstants::kCallerSPOffset + offset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000232 __ mov(r1, Operand(Smi::FromInt(num_parameters)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000233 __ Push(r3, r2, r1);
234
235 // Arguments to ArgumentsAccessStub:
236 // function, receiver address, parameter count.
237 // The stub will rewrite receiever and parameter count if the previous
238 // stack frame was an arguments adapter frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000239 ArgumentsAccessStub::Type type;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000240 if (!is_classic_mode()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +0000241 type = ArgumentsAccessStub::NEW_STRICT;
242 } else if (function()->has_duplicate_parameters()) {
243 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
244 } else {
245 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
246 }
247 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000248 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000249
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000250 SetVar(arguments, r0, r1, r2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000251 }
252
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000253 if (FLAG_trace) {
254 __ CallRuntime(Runtime::kTraceEnter, 0);
255 }
256
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000257 // Visit the declarations and body unless there is an illegal
258 // redeclaration.
259 if (scope()->HasIllegalRedeclaration()) {
260 Comment cmnt(masm_, "[ Declarations");
261 scope()->VisitIllegalRedeclaration(this);
262
263 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000264 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000265 { Comment cmnt(masm_, "[ Declarations");
266 // For named function expressions, declare the function name as a
267 // constant.
268 if (scope()->is_function_scope() && scope()->function() != NULL) {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000269 VariableDeclaration* function = scope()->function();
270 ASSERT(function->proxy()->var()->mode() == CONST ||
271 function->proxy()->var()->mode() == CONST_HARMONY);
272 ASSERT(function->proxy()->var()->location() != Variable::UNALLOCATED);
273 VisitVariableDeclaration(function);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000274 }
275 VisitDeclarations(scope()->declarations());
276 }
277
278 { Comment cmnt(masm_, "[ Stack check");
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000279 PrepareForBailoutForId(AstNode::kDeclarationsId, NO_REGISTERS);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000280 Label ok;
281 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
282 __ cmp(sp, Operand(ip));
283 __ b(hs, &ok);
284 StackCheckStub stub;
285 __ CallStub(&stub);
286 __ bind(&ok);
287 }
288
289 { Comment cmnt(masm_, "[ Body");
290 ASSERT(loop_depth() == 0);
291 VisitStatements(function()->body());
292 ASSERT(loop_depth() == 0);
293 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000294 }
295
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000296 // Always emit a 'return undefined' in case control fell off the end of
297 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000298 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000299 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
300 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000301 EmitReturnSequence();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000302
303 // Force emit the constant pool, so it doesn't get emitted in the middle
304 // of the stack check table.
305 masm()->CheckConstPool(true, false);
306}
307
308
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000309void FullCodeGenerator::ClearAccumulator() {
310 __ mov(r0, Operand(Smi::FromInt(0)));
311}
312
313
danno@chromium.org88aa0582012-03-23 15:11:57 +0000314void FullCodeGenerator::EmitProfilingCounterDecrement(int delta) {
315 __ mov(r2, Operand(profiling_counter_));
316 __ ldr(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
317 __ sub(r3, r3, Operand(Smi::FromInt(delta)), SetCC);
318 __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
319}
320
321
322void FullCodeGenerator::EmitProfilingCounterReset() {
323 int reset_value = FLAG_interrupt_budget;
324 if (info_->ShouldSelfOptimize() && !FLAG_retry_self_opt) {
325 // Self-optimization is a one-off thing: if it fails, don't try again.
326 reset_value = Smi::kMaxValue;
327 }
328 if (isolate()->IsDebuggerActive()) {
329 // Detect debug break requests as soon as possible.
330 reset_value = 10;
331 }
332 __ mov(r2, Operand(profiling_counter_));
333 __ mov(r3, Operand(Smi::FromInt(reset_value)));
334 __ str(r3, FieldMemOperand(r2, JSGlobalPropertyCell::kValueOffset));
335}
336
337
338static const int kMaxBackEdgeWeight = 127;
339static const int kBackEdgeDistanceDivisor = 142;
340
341
yangguo@chromium.org56454712012-02-16 15:33:53 +0000342void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt,
343 Label* back_edge_target) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000344 Comment cmnt(masm_, "[ Stack check");
345 Label ok;
danno@chromium.org88aa0582012-03-23 15:11:57 +0000346
347 if (FLAG_count_based_interrupts) {
348 int weight = 1;
349 if (FLAG_weighted_back_edges) {
350 ASSERT(back_edge_target->is_bound());
351 int distance = masm_->SizeOfCodeGeneratedSince(back_edge_target);
352 weight = Min(kMaxBackEdgeWeight,
353 Max(1, distance / kBackEdgeDistanceDivisor));
354 }
355 EmitProfilingCounterDecrement(weight);
356 __ b(pl, &ok);
357 InterruptStub stub;
358 __ CallStub(&stub);
359 } else {
360 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
361 __ cmp(sp, Operand(ip));
362 __ b(hs, &ok);
363 StackCheckStub stub;
364 __ CallStub(&stub);
365 }
366
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000367 // Record a mapping of this PC offset to the OSR id. This is used to find
368 // the AST id from the unoptimized code in order to use it as a key into
369 // the deoptimization input data found in the optimized code.
370 RecordStackCheck(stmt->OsrEntryId());
371
danno@chromium.org88aa0582012-03-23 15:11:57 +0000372 if (FLAG_count_based_interrupts) {
373 EmitProfilingCounterReset();
374 }
375
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000376 __ bind(&ok);
377 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000378 // Record a mapping of the OSR id to this PC. This is used if the OSR
379 // entry becomes the target of a bailout. We don't expect it to be, but
380 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000381 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000382}
383
384
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000385void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000386 Comment cmnt(masm_, "[ Return sequence");
387 if (return_label_.is_bound()) {
388 __ b(&return_label_);
389 } else {
390 __ bind(&return_label_);
391 if (FLAG_trace) {
392 // Push the return value on the stack as the parameter.
393 // Runtime::TraceExit returns its parameter in r0.
394 __ push(r0);
395 __ CallRuntime(Runtime::kTraceExit, 1);
396 }
danno@chromium.org88aa0582012-03-23 15:11:57 +0000397 if (FLAG_interrupt_at_exit || FLAG_self_optimization) {
398 // Pretend that the exit is a backwards jump to the entry.
399 int weight = 1;
400 if (info_->ShouldSelfOptimize()) {
401 weight = FLAG_interrupt_budget / FLAG_self_opt_count;
402 } else if (FLAG_weighted_back_edges) {
403 int distance = masm_->pc_offset();
404 weight = Min(kMaxBackEdgeWeight,
405 Max(1, distance / kBackEdgeDistanceDivisor));
406 }
407 EmitProfilingCounterDecrement(weight);
408 Label ok;
409 __ b(pl, &ok);
410 __ push(r0);
411 if (info_->ShouldSelfOptimize() && FLAG_direct_self_opt) {
412 __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
413 __ push(r2);
414 __ CallRuntime(Runtime::kOptimizeFunctionOnNextCall, 1);
415 } else {
416 InterruptStub stub;
417 __ CallStub(&stub);
418 }
419 __ pop(r0);
420 EmitProfilingCounterReset();
421 __ bind(&ok);
422 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000423
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000424#ifdef DEBUG
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425 // Add a label for checking the size of the code used for returning.
426 Label check_exit_codesize;
427 masm_->bind(&check_exit_codesize);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000428#endif
429 // Make sure that the constant pool is not emitted inside of the return
430 // sequence.
431 { Assembler::BlockConstPoolScope block_const_pool(masm_);
432 // Here we use masm_-> instead of the __ macro to avoid the code coverage
433 // tool from instrumenting as we rely on the code size here.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000434 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000435 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000436 __ RecordJSReturn();
437 masm_->mov(sp, fp);
438 masm_->ldm(ia_w, sp, fp.bit() | lr.bit());
439 masm_->add(sp, sp, Operand(sp_delta));
440 masm_->Jump(lr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000441 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000442
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000443#ifdef DEBUG
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000444 // Check that the size of the code used for returning is large enough
445 // for the debugger's requirements.
446 ASSERT(Assembler::kJSReturnSequenceInstructions <=
447 masm_->InstructionsGeneratedSince(&check_exit_codesize));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000448#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000449 }
450}
451
452
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000453void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
454 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000455}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000456
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000457
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000458void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
459 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
460 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000461}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000462
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000463
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000464void FullCodeGenerator::StackValueContext::Plug(Variable* var) const {
465 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
466 codegen()->GetVar(result_register(), var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000467 __ push(result_register());
468}
469
470
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000471void FullCodeGenerator::TestContext::Plug(Variable* var) const {
472 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000473 // For simplicity we always test the accumulator register.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000474 codegen()->GetVar(result_register(), var);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000475 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000476 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000477}
478
479
480void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
481}
482
483
484void FullCodeGenerator::AccumulatorValueContext::Plug(
485 Heap::RootListIndex index) const {
486 __ LoadRoot(result_register(), index);
487}
488
489
490void FullCodeGenerator::StackValueContext::Plug(
491 Heap::RootListIndex index) const {
492 __ LoadRoot(result_register(), index);
493 __ push(result_register());
494}
495
496
497void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000498 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000499 true,
500 true_label_,
501 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000502 if (index == Heap::kUndefinedValueRootIndex ||
503 index == Heap::kNullValueRootIndex ||
504 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000505 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000506 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000507 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000508 } else {
509 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000510 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000511 }
512}
513
514
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000515void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
516}
517
518
519void FullCodeGenerator::AccumulatorValueContext::Plug(
520 Handle<Object> lit) const {
521 __ mov(result_register(), Operand(lit));
522}
523
524
525void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000526 // Immediates cannot be pushed directly.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000527 __ mov(result_register(), Operand(lit));
528 __ push(result_register());
529}
530
531
532void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000533 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000534 true,
535 true_label_,
536 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000537 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
538 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000539 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000540 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000541 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000542 } else if (lit->IsString()) {
543 if (String::cast(*lit)->length() == 0) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000544 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000545 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000546 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000547 }
548 } else if (lit->IsSmi()) {
549 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000550 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000551 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000552 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000553 }
554 } else {
555 // For simplicity we always test the accumulator register.
556 __ mov(result_register(), Operand(lit));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000557 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000558 }
559}
560
561
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000562void FullCodeGenerator::EffectContext::DropAndPlug(int count,
563 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000564 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000565 __ Drop(count);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000566}
567
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000568
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000569void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
570 int count,
571 Register reg) const {
572 ASSERT(count > 0);
573 __ Drop(count);
574 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000575}
576
577
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000578void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
579 Register reg) const {
580 ASSERT(count > 0);
581 if (count > 1) __ Drop(count - 1);
582 __ str(reg, MemOperand(sp, 0));
583}
584
585
586void FullCodeGenerator::TestContext::DropAndPlug(int count,
587 Register reg) const {
588 ASSERT(count > 0);
589 // For simplicity we always test the accumulator register.
590 __ Drop(count);
591 __ Move(result_register(), reg);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000592 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000593 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000594}
595
596
597void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
598 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000599 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000600 __ bind(materialize_true);
601}
602
603
604void FullCodeGenerator::AccumulatorValueContext::Plug(
605 Label* materialize_true,
606 Label* materialize_false) const {
607 Label done;
608 __ bind(materialize_true);
609 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
610 __ jmp(&done);
611 __ bind(materialize_false);
612 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
613 __ bind(&done);
614}
615
616
617void FullCodeGenerator::StackValueContext::Plug(
618 Label* materialize_true,
619 Label* materialize_false) const {
620 Label done;
621 __ bind(materialize_true);
622 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
623 __ push(ip);
624 __ jmp(&done);
625 __ bind(materialize_false);
626 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
627 __ push(ip);
628 __ bind(&done);
629}
630
631
632void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
633 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000634 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000635 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000636}
637
638
639void FullCodeGenerator::EffectContext::Plug(bool flag) const {
640}
641
642
643void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
644 Heap::RootListIndex value_root_index =
645 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
646 __ LoadRoot(result_register(), value_root_index);
647}
648
649
650void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
651 Heap::RootListIndex value_root_index =
652 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
653 __ LoadRoot(ip, value_root_index);
654 __ push(ip);
655}
656
657
658void FullCodeGenerator::TestContext::Plug(bool flag) const {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000659 codegen()->PrepareForBailoutBeforeSplit(condition(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000660 true,
661 true_label_,
662 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000663 if (flag) {
664 if (true_label_ != fall_through_) __ b(true_label_);
665 } else {
666 if (false_label_ != fall_through_) __ b(false_label_);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000667 }
668}
669
670
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000671void FullCodeGenerator::DoTest(Expression* condition,
672 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000673 Label* if_false,
674 Label* fall_through) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000675 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000676 ToBooleanStub stub(result_register());
677 __ CallStub(&stub);
678 __ tst(result_register(), result_register());
679 } else {
680 // Call the runtime to find the boolean value of the source and then
681 // translate it into control flow to the pair of labels.
682 __ push(result_register());
683 __ CallRuntime(Runtime::kToBool, 1);
684 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
685 __ cmp(r0, ip);
686 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000687 Split(ne, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000688}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000689
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000690
ager@chromium.org378b34e2011-01-28 08:04:38 +0000691void FullCodeGenerator::Split(Condition cond,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000692 Label* if_true,
693 Label* if_false,
694 Label* fall_through) {
695 if (if_false == fall_through) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000696 __ b(cond, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000697 } else if (if_true == fall_through) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000698 __ b(NegateCondition(cond), if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000699 } else {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000700 __ b(cond, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000701 __ b(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000702 }
703}
704
705
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000706MemOperand FullCodeGenerator::StackOperand(Variable* var) {
707 ASSERT(var->IsStackAllocated());
708 // Offset is negative because higher indexes are at lower addresses.
709 int offset = -var->index() * kPointerSize;
710 // Adjust by a (parameter or local) base offset.
711 if (var->IsParameter()) {
712 offset += (info_->scope()->num_parameters() + 1) * kPointerSize;
713 } else {
714 offset += JavaScriptFrameConstants::kLocal0Offset;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000715 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000716 return MemOperand(fp, offset);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000717}
718
719
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000720MemOperand FullCodeGenerator::VarOperand(Variable* var, Register scratch) {
721 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
722 if (var->IsContextSlot()) {
723 int context_chain_length = scope()->ContextChainLength(var->scope());
724 __ LoadContext(scratch, context_chain_length);
725 return ContextOperand(scratch, var->index());
726 } else {
727 return StackOperand(var);
728 }
729}
730
731
732void FullCodeGenerator::GetVar(Register dest, Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000733 // Use destination as scratch.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000734 MemOperand location = VarOperand(var, dest);
735 __ ldr(dest, location);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000736}
737
738
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000739void FullCodeGenerator::SetVar(Variable* var,
740 Register src,
741 Register scratch0,
742 Register scratch1) {
743 ASSERT(var->IsContextSlot() || var->IsStackAllocated());
744 ASSERT(!scratch0.is(src));
745 ASSERT(!scratch0.is(scratch1));
746 ASSERT(!scratch1.is(src));
747 MemOperand location = VarOperand(var, scratch0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000748 __ str(src, location);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000749
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000750 // Emit the write barrier code if the location is in the heap.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000751 if (var->IsContextSlot()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000752 __ RecordWriteContextSlot(scratch0,
753 location.offset(),
754 src,
755 scratch1,
756 kLRHasBeenSaved,
757 kDontSaveFPRegs);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000758 }
759}
760
761
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000762void FullCodeGenerator::PrepareForBailoutBeforeSplit(Expression* expr,
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000763 bool should_normalize,
764 Label* if_true,
765 Label* if_false) {
766 // Only prepare for bailouts before splits if we're in a test
767 // context. Otherwise, we let the Visit function deal with the
768 // preparation to avoid preparing with the same AST id twice.
769 if (!context()->IsTest() || !info_->IsOptimizable()) return;
770
771 Label skip;
772 if (should_normalize) __ b(&skip);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000773 PrepareForBailout(expr, TOS_REG);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000774 if (should_normalize) {
775 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
776 __ cmp(r0, ip);
777 Split(eq, if_true, if_false, NULL);
778 __ bind(&skip);
779 }
780}
781
782
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000783void FullCodeGenerator::EmitDebugCheckDeclarationContext(Variable* variable) {
784 // The variable in the declaration always resides in the current function
785 // context.
786 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
787 if (FLAG_debug_code) {
788 // Check that we're not inside a with or catch context.
789 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
790 __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
791 __ Check(ne, "Declaration in with context.");
792 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
793 __ Check(ne, "Declaration in catch context.");
794 }
795}
796
797
798void FullCodeGenerator::VisitVariableDeclaration(
799 VariableDeclaration* declaration) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000800 // If it was not possible to allocate the variable at compile time, we
801 // need to "declare" it at runtime to make sure it actually exists in the
802 // local context.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000803 VariableProxy* proxy = declaration->proxy();
804 VariableMode mode = declaration->mode();
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000805 Variable* variable = proxy->var();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000806 bool hole_init = mode == CONST || mode == CONST_HARMONY || mode == LET;
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000807 switch (variable->location()) {
808 case Variable::UNALLOCATED:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000809 globals_->Add(variable->name());
810 globals_->Add(variable->binding_needs_init()
811 ? isolate()->factory()->the_hole_value()
812 : isolate()->factory()->undefined_value());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000813 break;
814
815 case Variable::PARAMETER:
816 case Variable::LOCAL:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000817 if (hole_init) {
818 Comment cmnt(masm_, "[ VariableDeclaration");
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000819 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000820 __ str(ip, StackOperand(variable));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000821 }
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000822 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000823
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000824 case Variable::CONTEXT:
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000825 if (hole_init) {
826 Comment cmnt(masm_, "[ VariableDeclaration");
827 EmitDebugCheckDeclarationContext(variable);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000828 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000829 __ str(ip, ContextOperand(cp, variable->index()));
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000830 // No write barrier since the_hole_value is in old space.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000831 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000832 }
833 break;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000834
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000835 case Variable::LOOKUP: {
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000836 Comment cmnt(masm_, "[ VariableDeclaration");
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000837 __ mov(r2, Operand(variable->name()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000838 // Declaration nodes are always introduced in one of four modes.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000839 ASSERT(mode == VAR || mode == LET ||
840 mode == CONST || mode == CONST_HARMONY);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000841 PropertyAttributes attr = (mode == CONST || mode == CONST_HARMONY)
842 ? READ_ONLY : NONE;
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000843 __ mov(r1, Operand(Smi::FromInt(attr)));
844 // Push initial value, if any.
845 // Note: For variables we must not push an initial value (such as
846 // 'undefined') because we may have a (legal) redeclaration and we
847 // must not destroy the current value.
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000848 if (hole_init) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +0000849 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
850 __ Push(cp, r2, r1, r0);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000851 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +0000852 __ mov(r0, Operand(Smi::FromInt(0))); // Indicates no initial value.
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000853 __ Push(cp, r2, r1, r0);
854 }
855 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
856 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000857 }
858 }
859}
860
861
erik.corry@gmail.comed49e962012-04-17 11:57:53 +0000862void FullCodeGenerator::VisitFunctionDeclaration(
863 FunctionDeclaration* declaration) {
864 VariableProxy* proxy = declaration->proxy();
865 Variable* variable = proxy->var();
866 switch (variable->location()) {
867 case Variable::UNALLOCATED: {
868 globals_->Add(variable->name());
869 Handle<SharedFunctionInfo> function =
870 Compiler::BuildFunctionInfo(declaration->fun(), script());
871 // Check for stack-overflow exception.
872 if (function.is_null()) return SetStackOverflow();
873 globals_->Add(function);
874 break;
875 }
876
877 case Variable::PARAMETER:
878 case Variable::LOCAL: {
879 Comment cmnt(masm_, "[ FunctionDeclaration");
880 VisitForAccumulatorValue(declaration->fun());
881 __ str(result_register(), StackOperand(variable));
882 break;
883 }
884
885 case Variable::CONTEXT: {
886 Comment cmnt(masm_, "[ FunctionDeclaration");
887 EmitDebugCheckDeclarationContext(variable);
888 VisitForAccumulatorValue(declaration->fun());
889 __ str(result_register(), ContextOperand(cp, variable->index()));
890 int offset = Context::SlotOffset(variable->index());
891 // We know that we have written a function, which is not a smi.
892 __ RecordWriteContextSlot(cp,
893 offset,
894 result_register(),
895 r2,
896 kLRHasBeenSaved,
897 kDontSaveFPRegs,
898 EMIT_REMEMBERED_SET,
899 OMIT_SMI_CHECK);
900 PrepareForBailoutForId(proxy->id(), NO_REGISTERS);
901 break;
902 }
903
904 case Variable::LOOKUP: {
905 Comment cmnt(masm_, "[ FunctionDeclaration");
906 __ mov(r2, Operand(variable->name()));
907 __ mov(r1, Operand(Smi::FromInt(NONE)));
908 __ Push(cp, r2, r1);
909 // Push initial value for function declaration.
910 VisitForStackValue(declaration->fun());
911 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
912 break;
913 }
914 }
915}
916
917
918void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* declaration) {
919 VariableProxy* proxy = declaration->proxy();
920 Variable* variable = proxy->var();
921 Handle<JSModule> instance = declaration->module()->interface()->Instance();
922 ASSERT(!instance.is_null());
923
924 switch (variable->location()) {
925 case Variable::UNALLOCATED: {
926 Comment cmnt(masm_, "[ ModuleDeclaration");
927 globals_->Add(variable->name());
928 globals_->Add(instance);
929 Visit(declaration->module());
930 break;
931 }
932
933 case Variable::CONTEXT: {
934 Comment cmnt(masm_, "[ ModuleDeclaration");
935 EmitDebugCheckDeclarationContext(variable);
936 __ mov(r1, Operand(instance));
937 __ str(r1, ContextOperand(cp, variable->index()));
938 Visit(declaration->module());
939 break;
940 }
941
942 case Variable::PARAMETER:
943 case Variable::LOCAL:
944 case Variable::LOOKUP:
945 UNREACHABLE();
946 }
947}
948
949
950void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
951 VariableProxy* proxy = declaration->proxy();
952 Variable* variable = proxy->var();
953 switch (variable->location()) {
954 case Variable::UNALLOCATED:
955 // TODO(rossberg)
956 break;
957
958 case Variable::CONTEXT: {
959 Comment cmnt(masm_, "[ ImportDeclaration");
960 EmitDebugCheckDeclarationContext(variable);
961 // TODO(rossberg)
962 break;
963 }
964
965 case Variable::PARAMETER:
966 case Variable::LOCAL:
967 case Variable::LOOKUP:
968 UNREACHABLE();
969 }
970}
971
972
973void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
974 // TODO(rossberg)
975}
976
977
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000978void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
979 // Call the runtime to declare the globals.
980 // The context is the first argument.
fschneider@chromium.org1805e212011-09-05 10:49:12 +0000981 __ mov(r1, Operand(pairs));
982 __ mov(r0, Operand(Smi::FromInt(DeclareGlobalsFlags())));
983 __ Push(cp, r1, r0);
984 __ CallRuntime(Runtime::kDeclareGlobals, 3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000985 // Return value is ignored.
986}
987
988
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000989void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000990 Comment cmnt(masm_, "[ SwitchStatement");
991 Breakable nested_statement(this, stmt);
992 SetStatementPosition(stmt);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000993
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000994 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000995 VisitForStackValue(stmt->tag());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000996 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
997
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000998 ZoneList<CaseClause*>* clauses = stmt->cases();
999 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
1000
1001 Label next_test; // Recycled for each test.
1002 // Compile all the tests with branches to their bodies.
1003 for (int i = 0; i < clauses->length(); i++) {
1004 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001005 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +00001006
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001007 // The default is not a test, but remember it as final fall through.
1008 if (clause->is_default()) {
1009 default_clause = clause;
1010 continue;
1011 }
1012
1013 Comment cmnt(masm_, "[ Case comparison");
1014 __ bind(&next_test);
1015 next_test.Unuse();
1016
1017 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001018 VisitForAccumulatorValue(clause->label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001019
ricow@chromium.org65fae842010-08-25 15:26:24 +00001020 // Perform the comparison as if via '==='.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001021 __ ldr(r1, MemOperand(sp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001022 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001023 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00001024 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00001025 Label slow_case;
1026 __ orr(r2, r1, r0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001027 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
1028
ricow@chromium.org65fae842010-08-25 15:26:24 +00001029 __ cmp(r1, r0);
1030 __ b(ne, &next_test);
1031 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001032 __ b(clause->body_target());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001033 __ bind(&slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001034 }
1035
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001036 // Record position before stub call for type feedback.
1037 SetSourcePosition(clause->position());
1038 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
danno@chromium.org88aa0582012-03-23 15:11:57 +00001039 CallIC(ic, RelocInfo::CODE_TARGET, clause->CompareId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001040 patch_site.EmitPatchInfo();
danno@chromium.org40cb8782011-05-25 07:58:50 +00001041
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001042 __ cmp(r0, Operand(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001043 __ b(ne, &next_test);
1044 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001045 __ b(clause->body_target());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001046 }
1047
1048 // Discard the test value and jump to the default if present, otherwise to
1049 // the end of the statement.
1050 __ bind(&next_test);
1051 __ Drop(1); // Switch value is no longer needed.
1052 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001053 __ b(nested_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001054 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001055 __ b(default_clause->body_target());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001056 }
1057
1058 // Compile all the case bodies.
1059 for (int i = 0; i < clauses->length(); i++) {
1060 Comment cmnt(masm_, "[ Case body");
1061 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00001062 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00001063 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001064 VisitStatements(clause->statements());
1065 }
1066
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001067 __ bind(nested_statement.break_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001068 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001069}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001070
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001071
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001072void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001073 Comment cmnt(masm_, "[ ForInStatement");
1074 SetStatementPosition(stmt);
1075
1076 Label loop, exit;
1077 ForIn loop_statement(this, stmt);
1078 increment_loop_depth();
1079
1080 // Get the object to enumerate over. Both SpiderMonkey and JSC
1081 // ignore null and undefined in contrast to the specification; see
1082 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001083 VisitForAccumulatorValue(stmt->enumerable());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001084 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1085 __ cmp(r0, ip);
1086 __ b(eq, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001087 Register null_value = r5;
1088 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
1089 __ cmp(r0, null_value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001090 __ b(eq, &exit);
1091
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001092 PrepareForBailoutForId(stmt->PrepareId(), TOS_REG);
1093
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001094 // Convert the object to a JS object.
1095 Label convert, done_convert;
ager@chromium.org378b34e2011-01-28 08:04:38 +00001096 __ JumpIfSmi(r0, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00001097 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
1098 __ b(ge, &done_convert);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001099 __ bind(&convert);
1100 __ push(r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001101 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001102 __ bind(&done_convert);
1103 __ push(r0);
1104
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001105 // Check for proxies.
1106 Label call_runtime;
1107 STATIC_ASSERT(FIRST_JS_PROXY_TYPE == FIRST_SPEC_OBJECT_TYPE);
1108 __ CompareObjectType(r0, r1, r1, LAST_JS_PROXY_TYPE);
1109 __ b(le, &call_runtime);
1110
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001111 // Check cache validity in generated code. This is a fast case for
1112 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
1113 // guarantee cache validity, call the runtime system to check cache
1114 // validity or get the property names in a fixed array.
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00001115 __ CheckEnumCache(null_value, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001116
1117 // The enum cache is valid. Load the map of the object being
1118 // iterated over and use the cache for the iteration.
1119 Label use_cache;
1120 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
1121 __ b(&use_cache);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001122
1123 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001124 __ bind(&call_runtime);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001125 __ push(r0); // Duplicate the enumerable object on the stack.
1126 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
1127
1128 // If we got a map from the runtime call, we can do a fast
1129 // modification check. Otherwise, we got a fixed array, and we have
1130 // to do a slow check.
1131 Label fixed_array;
1132 __ mov(r2, r0);
1133 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
1134 __ LoadRoot(ip, Heap::kMetaMapRootIndex);
1135 __ cmp(r1, ip);
1136 __ b(ne, &fixed_array);
1137
1138 // We got a map in register r0. Get the enumeration cache from it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001139 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001140 __ LoadInstanceDescriptors(r0, r1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001141 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
1142 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
1143
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001144 // Set up the four remaining stack slots.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001145 __ push(r0); // Map.
1146 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001147 __ mov(r0, Operand(Smi::FromInt(0)));
1148 // Push enumeration cache, enumeration cache length (as smi) and zero.
1149 __ Push(r2, r1, r0);
1150 __ jmp(&loop);
1151
1152 // We got a fixed array in register r0. Iterate through that.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001153 Label non_proxy;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001154 __ bind(&fixed_array);
ulan@chromium.org9a21ec42012-03-06 08:42:24 +00001155
1156 Handle<JSGlobalPropertyCell> cell =
1157 isolate()->factory()->NewJSGlobalPropertyCell(
1158 Handle<Object>(
1159 Smi::FromInt(TypeFeedbackCells::kForInFastCaseMarker)));
1160 RecordTypeFeedbackCell(stmt->PrepareId(), cell);
1161 __ LoadHeapObject(r1, cell);
1162 __ mov(r2, Operand(Smi::FromInt(TypeFeedbackCells::kForInSlowCaseMarker)));
1163 __ str(r2, FieldMemOperand(r1, JSGlobalPropertyCell::kValueOffset));
1164
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));
1188 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1189
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
yangguo@chromium.org56454712012-02-16 15:33:53 +00001235 EmitStackCheck(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
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001249void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1250 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001251 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001252 // space for nested functions that don't need literals cloning. If
1253 // we're running with the --always-opt or the --prepare-always-opt
1254 // flag, we need to use the runtime function so that the new function
1255 // we are creating here gets a chance to have its code optimized and
1256 // doesn't just get a copy of the existing unoptimized code.
1257 if (!FLAG_always_opt &&
1258 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001259 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001260 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001261 info->num_literals() == 0) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001262 FastNewClosureStub stub(info->language_mode());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001263 __ mov(r0, Operand(info));
1264 __ push(r0);
1265 __ CallStub(&stub);
1266 } else {
1267 __ mov(r0, Operand(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001268 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
1269 : Heap::kFalseValueRootIndex);
1270 __ Push(cp, r0, r1);
1271 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001272 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001273 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001274}
1275
1276
1277void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1278 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001279 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001280}
1281
1282
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001283void FullCodeGenerator::EmitLoadGlobalCheckExtensions(Variable* var,
1284 TypeofState typeof_state,
1285 Label* slow) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001286 Register current = cp;
1287 Register next = r1;
1288 Register temp = r2;
1289
1290 Scope* s = scope();
1291 while (s != NULL) {
1292 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001293 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001294 // Check that extension is NULL.
1295 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
1296 __ tst(temp, temp);
1297 __ b(ne, slow);
1298 }
1299 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001300 __ ldr(next, ContextOperand(current, Context::PREVIOUS_INDEX));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001301 // Walk the rest of the chain without clobbering cp.
1302 current = next;
1303 }
1304 // If no outer scope calls eval, we do not need to check more
1305 // context extensions.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001306 if (!s->outer_scope_calls_non_strict_eval() || s->is_eval_scope()) break;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001307 s = s->outer_scope();
1308 }
1309
1310 if (s->is_eval_scope()) {
1311 Label loop, fast;
1312 if (!current.is(next)) {
1313 __ Move(next, current);
1314 }
1315 __ bind(&loop);
1316 // Terminate at global context.
1317 __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset));
1318 __ LoadRoot(ip, Heap::kGlobalContextMapRootIndex);
1319 __ cmp(temp, ip);
1320 __ b(eq, &fast);
1321 // Check that extension is NULL.
1322 __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX));
1323 __ tst(temp, temp);
1324 __ b(ne, slow);
1325 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001326 __ ldr(next, ContextOperand(next, Context::PREVIOUS_INDEX));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001327 __ b(&loop);
1328 __ bind(&fast);
1329 }
1330
1331 __ ldr(r0, GlobalObjectOperand());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001332 __ mov(r2, Operand(var->name()));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001333 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1334 ? RelocInfo::CODE_TARGET
1335 : RelocInfo::CODE_TARGET_CONTEXT;
1336 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001337 CallIC(ic, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001338}
1339
1340
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001341MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(Variable* var,
1342 Label* slow) {
1343 ASSERT(var->IsContextSlot());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001344 Register context = cp;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001345 Register next = r3;
1346 Register temp = r4;
1347
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001348 for (Scope* s = scope(); s != var->scope(); s = s->outer_scope()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001349 if (s->num_heap_slots() > 0) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001350 if (s->calls_non_strict_eval()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001351 // Check that extension is NULL.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001352 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001353 __ tst(temp, temp);
1354 __ b(ne, slow);
1355 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001356 __ ldr(next, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001357 // Walk the rest of the chain without clobbering cp.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001358 context = next;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001359 }
1360 }
1361 // Check that last extension is NULL.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001362 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001363 __ tst(temp, temp);
1364 __ b(ne, slow);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001365
1366 // This function is used only for loads, not stores, so it's safe to
1367 // return an cp-based operand (the write barrier cannot be allowed to
1368 // destroy the cp register).
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001369 return ContextOperand(context, var->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001370}
1371
1372
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001373void FullCodeGenerator::EmitDynamicLookupFastCase(Variable* var,
1374 TypeofState typeof_state,
1375 Label* slow,
1376 Label* done) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001377 // Generate fast-case code for variables that might be shadowed by
1378 // eval-introduced variables. Eval is used a lot without
1379 // introducing variables. In those cases, we do not want to
1380 // perform a runtime call for all variables in the scope
1381 // containing the eval.
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001382 if (var->mode() == DYNAMIC_GLOBAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001383 EmitLoadGlobalCheckExtensions(var, typeof_state, slow);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001384 __ jmp(done);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001385 } else if (var->mode() == DYNAMIC_LOCAL) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001386 Variable* local = var->local_if_not_shadowed();
1387 __ ldr(r0, ContextSlotOperandCheckExtensions(local, slow));
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001388 if (local->mode() == CONST ||
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001389 local->mode() == CONST_HARMONY ||
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001390 local->mode() == LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001391 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00001392 if (local->mode() == CONST) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001393 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001394 } else { // LET || CONST_HARMONY
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00001395 __ b(ne, done);
1396 __ mov(r0, Operand(var->name()));
1397 __ push(r0);
1398 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1399 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001400 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001401 __ jmp(done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001402 }
1403}
1404
1405
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001406void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1407 // Record position before possible IC call.
1408 SetSourcePosition(proxy->position());
1409 Variable* var = proxy->var();
1410
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001411 // Three cases: global variables, lookup variables, and all other types of
1412 // variables.
1413 switch (var->location()) {
1414 case Variable::UNALLOCATED: {
1415 Comment cmnt(masm_, "Global variable");
1416 // Use inline caching. Variable name is passed in r2 and the global
1417 // object (receiver) in r0.
1418 __ ldr(r0, GlobalObjectOperand());
1419 __ mov(r2, Operand(var->name()));
1420 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001421 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001422 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001423 break;
1424 }
1425
1426 case Variable::PARAMETER:
1427 case Variable::LOCAL:
1428 case Variable::CONTEXT: {
1429 Comment cmnt(masm_, var->IsContextSlot()
1430 ? "Context variable"
1431 : "Stack variable");
danno@chromium.orgc612e022011-11-10 11:38:15 +00001432 if (var->binding_needs_init()) {
1433 // var->scope() may be NULL when the proxy is located in eval code and
1434 // refers to a potential outside binding. Currently those bindings are
1435 // always looked up dynamically, i.e. in that case
1436 // var->location() == LOOKUP.
1437 // always holds.
1438 ASSERT(var->scope() != NULL);
1439
1440 // Check if the binding really needs an initialization check. The check
1441 // can be skipped in the following situation: we have a LET or CONST
1442 // binding in harmony mode, both the Variable and the VariableProxy have
1443 // the same declaration scope (i.e. they are both in global code, in the
1444 // same function or in the same eval code) and the VariableProxy is in
1445 // the source physically located after the initializer of the variable.
1446 //
1447 // We cannot skip any initialization checks for CONST in non-harmony
1448 // mode because const variables may be declared but never initialized:
1449 // if (false) { const x; }; var y = x;
1450 //
1451 // The condition on the declaration scopes is a conservative check for
1452 // nested functions that access a binding and are called before the
1453 // binding is initialized:
1454 // function() { f(); let x = 1; function f() { x = 2; } }
1455 //
1456 bool skip_init_check;
1457 if (var->scope()->DeclarationScope() != scope()->DeclarationScope()) {
1458 skip_init_check = false;
jkummerow@chromium.orgac45fed2011-11-07 13:11:02 +00001459 } else {
danno@chromium.orgc612e022011-11-10 11:38:15 +00001460 // Check that we always have valid source position.
1461 ASSERT(var->initializer_position() != RelocInfo::kNoPosition);
1462 ASSERT(proxy->position() != RelocInfo::kNoPosition);
1463 skip_init_check = var->mode() != CONST &&
1464 var->initializer_position() < proxy->position();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001465 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001466
1467 if (!skip_init_check) {
1468 // Let and const need a read barrier.
1469 GetVar(r0, var);
1470 __ CompareRoot(r0, Heap::kTheHoleValueRootIndex);
1471 if (var->mode() == LET || var->mode() == CONST_HARMONY) {
1472 // Throw a reference error when using an uninitialized let/const
1473 // binding in harmony mode.
1474 Label done;
1475 __ b(ne, &done);
1476 __ mov(r0, Operand(var->name()));
1477 __ push(r0);
1478 __ CallRuntime(Runtime::kThrowReferenceError, 1);
1479 __ bind(&done);
1480 } else {
1481 // Uninitalized const bindings outside of harmony mode are unholed.
1482 ASSERT(var->mode() == CONST);
1483 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1484 }
1485 context()->Plug(r0);
1486 break;
1487 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001488 }
danno@chromium.orgc612e022011-11-10 11:38:15 +00001489 context()->Plug(var);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00001490 break;
1491 }
1492
1493 case Variable::LOOKUP: {
1494 Label done, slow;
1495 // Generate code for loading from variables potentially shadowed
1496 // by eval-introduced variables.
1497 EmitDynamicLookupFastCase(var, NOT_INSIDE_TYPEOF, &slow, &done);
1498 __ bind(&slow);
1499 Comment cmnt(masm_, "Lookup variable");
1500 __ mov(r1, Operand(var->name()));
1501 __ Push(cp, r1); // Context and name.
1502 __ CallRuntime(Runtime::kLoadContextSlot, 2);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001503 __ bind(&done);
1504 context()->Plug(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001505 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001506 }
1507}
1508
1509
1510void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1511 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001512 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001513 // Registers will be used as follows:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001514 // r5 = materialized value (RegExp literal)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001515 // r4 = JS function, literals array
1516 // r3 = literal index
1517 // r2 = RegExp pattern
1518 // r1 = RegExp flags
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001519 // r0 = RegExp literal clone
ricow@chromium.org65fae842010-08-25 15:26:24 +00001520 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1521 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001522 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001523 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001524 __ ldr(r5, FieldMemOperand(r4, literal_offset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001525 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001526 __ cmp(r5, ip);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001527 __ b(ne, &materialized);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001528
1529 // Create regexp literal using runtime function.
1530 // Result will be in r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001531 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1532 __ mov(r2, Operand(expr->pattern()));
1533 __ mov(r1, Operand(expr->flags()));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001534 __ Push(r4, r3, r2, r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001535 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001536 __ mov(r5, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001537
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001538 __ bind(&materialized);
1539 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001540 Label allocated, runtime_allocate;
1541 __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
1542 __ jmp(&allocated);
1543
1544 __ bind(&runtime_allocate);
1545 __ push(r5);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001546 __ mov(r0, Operand(Smi::FromInt(size)));
1547 __ push(r0);
1548 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001549 __ pop(r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001550
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001551 __ bind(&allocated);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001552 // After this, registers are used as follows:
1553 // r0: Newly allocated regexp.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001554 // r5: Materialized regexp.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001555 // r2: temp.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001556 __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001557 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001558}
1559
1560
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001561void FullCodeGenerator::EmitAccessor(Expression* expression) {
1562 if (expression == NULL) {
1563 __ LoadRoot(r1, Heap::kNullValueRootIndex);
1564 __ push(r1);
1565 } else {
1566 VisitForStackValue(expression);
1567 }
1568}
1569
1570
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001571void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1572 Comment cmnt(masm_, "[ ObjectLiteral");
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001573 Handle<FixedArray> constant_properties = expr->constant_properties();
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001574 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1575 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1576 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001577 __ mov(r1, Operand(constant_properties));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001578 int flags = expr->fast_elements()
1579 ? ObjectLiteral::kFastElements
1580 : ObjectLiteral::kNoFlags;
1581 flags |= expr->has_function()
1582 ? ObjectLiteral::kHasFunction
1583 : ObjectLiteral::kNoFlags;
1584 __ mov(r0, Operand(Smi::FromInt(flags)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001585 __ Push(r3, r2, r1, r0);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001586 int properties_count = constant_properties->length() / 2;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001587 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001588 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001589 } else if (flags != ObjectLiteral::kFastElements ||
1590 properties_count > FastCloneShallowObjectStub::kMaximumClonedProperties) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001591 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001592 } else {
1593 FastCloneShallowObjectStub stub(properties_count);
1594 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001595 }
1596
1597 // If result_saved is true the result is on top of the stack. If
1598 // result_saved is false the result is in r0.
1599 bool result_saved = false;
1600
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001601 // Mark all computed expressions that are bound to a key that
1602 // is shadowed by a later occurrence of the same key. For the
1603 // marked expressions, no store code is emitted.
1604 expr->CalculateEmitStore();
1605
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001606 AccessorTable accessor_table(isolate()->zone());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001607 for (int i = 0; i < expr->properties()->length(); i++) {
1608 ObjectLiteral::Property* property = expr->properties()->at(i);
1609 if (property->IsCompileTimeValue()) continue;
1610
1611 Literal* key = property->key();
1612 Expression* value = property->value();
1613 if (!result_saved) {
1614 __ push(r0); // Save result on stack
1615 result_saved = true;
1616 }
1617 switch (property->kind()) {
1618 case ObjectLiteral::Property::CONSTANT:
1619 UNREACHABLE();
1620 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1621 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
1622 // Fall through.
1623 case ObjectLiteral::Property::COMPUTED:
1624 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001625 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001626 VisitForAccumulatorValue(value);
1627 __ mov(r2, Operand(key->handle()));
1628 __ ldr(r1, MemOperand(sp));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001629 Handle<Code> ic = is_classic_mode()
1630 ? isolate()->builtins()->StoreIC_Initialize()
1631 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001632 CallIC(ic, RelocInfo::CODE_TARGET, key->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001633 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1634 } else {
1635 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001636 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001637 break;
1638 }
1639 // Fall through.
1640 case ObjectLiteral::Property::PROTOTYPE:
1641 // Duplicate receiver on stack.
1642 __ ldr(r0, MemOperand(sp));
1643 __ push(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001644 VisitForStackValue(key);
1645 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001646 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001647 __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1648 __ push(r0);
1649 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001650 } else {
1651 __ Drop(3);
1652 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001653 break;
1654 case ObjectLiteral::Property::GETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001655 accessor_table.lookup(key)->second->getter = value;
1656 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001657 case ObjectLiteral::Property::SETTER:
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001658 accessor_table.lookup(key)->second->setter = value;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001659 break;
1660 }
1661 }
1662
rossberg@chromium.org2c067b12012-03-19 11:01:52 +00001663 // Emit code to define accessors, using only a single call to the runtime for
1664 // each pair of corresponding getters and setters.
1665 for (AccessorTable::Iterator it = accessor_table.begin();
1666 it != accessor_table.end();
1667 ++it) {
1668 __ ldr(r0, MemOperand(sp)); // Duplicate receiver.
1669 __ push(r0);
1670 VisitForStackValue(it->first);
1671 EmitAccessor(it->second->getter);
1672 EmitAccessor(it->second->setter);
1673 __ mov(r0, Operand(Smi::FromInt(NONE)));
1674 __ push(r0);
1675 __ CallRuntime(Runtime::kDefineOrRedefineAccessorProperty, 5);
1676 }
1677
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001678 if (expr->has_function()) {
1679 ASSERT(result_saved);
1680 __ ldr(r0, MemOperand(sp));
1681 __ push(r0);
1682 __ CallRuntime(Runtime::kToFastProperties, 1);
1683 }
1684
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001685 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001686 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001687 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001688 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001689 }
1690}
1691
1692
1693void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1694 Comment cmnt(masm_, "[ ArrayLiteral");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001695
1696 ZoneList<Expression*>* subexprs = expr->values();
1697 int length = subexprs->length();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001698 Handle<FixedArray> constant_elements = expr->constant_elements();
1699 ASSERT_EQ(2, constant_elements->length());
1700 ElementsKind constant_elements_kind =
1701 static_cast<ElementsKind>(Smi::cast(constant_elements->get(0))->value());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001702 bool has_fast_elements = constant_elements_kind == FAST_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001703 Handle<FixedArrayBase> constant_elements_values(
1704 FixedArrayBase::cast(constant_elements->get(1)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001705
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001706 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1707 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1708 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001709 __ mov(r1, Operand(constant_elements));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001710 __ Push(r3, r2, r1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001711 if (has_fast_elements && constant_elements_values->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001712 isolate()->heap()->fixed_cow_array_map()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001713 FastCloneShallowArrayStub stub(
1714 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1715 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001716 __ IncrementCounter(
1717 isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001718 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001719 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001720 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001721 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001722 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001723 ASSERT(constant_elements_kind == FAST_ELEMENTS ||
1724 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
1725 FLAG_smi_only_arrays);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001726 FastCloneShallowArrayStub::Mode mode = has_fast_elements
1727 ? FastCloneShallowArrayStub::CLONE_ELEMENTS
1728 : FastCloneShallowArrayStub::CLONE_ANY_ELEMENTS;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001729 FastCloneShallowArrayStub stub(mode, length);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001730 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001731 }
1732
1733 bool result_saved = false; // Is the result saved to the stack?
1734
1735 // Emit code to evaluate all the non-constant subexpressions and to store
1736 // them into the newly cloned array.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001737 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001738 Expression* subexpr = subexprs->at(i);
1739 // If the subexpression is a literal or a simple materialized literal it
1740 // is already set in the cloned array.
1741 if (subexpr->AsLiteral() != NULL ||
1742 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1743 continue;
1744 }
1745
1746 if (!result_saved) {
1747 __ push(r0);
1748 result_saved = true;
1749 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001750 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001751
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001752 if (constant_elements_kind == FAST_ELEMENTS) {
1753 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1754 __ ldr(r6, MemOperand(sp)); // Copy of array literal.
1755 __ ldr(r1, FieldMemOperand(r6, JSObject::kElementsOffset));
1756 __ str(result_register(), FieldMemOperand(r1, offset));
1757 // Update the write barrier for the array store.
1758 __ RecordWriteField(r1, offset, result_register(), r2,
1759 kLRHasBeenSaved, kDontSaveFPRegs,
1760 EMIT_REMEMBERED_SET, INLINE_SMI_CHECK);
1761 } else {
1762 __ ldr(r1, MemOperand(sp)); // Copy of array literal.
1763 __ ldr(r2, FieldMemOperand(r1, JSObject::kMapOffset));
1764 __ mov(r3, Operand(Smi::FromInt(i)));
1765 __ mov(r4, Operand(Smi::FromInt(expr->literal_index())));
1766 StoreArrayLiteralElementStub stub;
1767 __ CallStub(&stub);
1768 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001769
1770 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001771 }
1772
1773 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001774 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001775 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001776 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001777 }
1778}
1779
1780
ager@chromium.org5c838252010-02-19 08:53:10 +00001781void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1782 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001783 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1784 // on the left-hand side.
1785 if (!expr->target()->IsValidLeftHandSide()) {
1786 VisitForEffect(expr->target());
1787 return;
1788 }
1789
ager@chromium.org5c838252010-02-19 08:53:10 +00001790 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001791 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001792 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1793 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001794 Property* property = expr->target()->AsProperty();
1795 if (property != NULL) {
1796 assign_type = (property->key()->IsPropertyName())
1797 ? NAMED_PROPERTY
1798 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001799 }
1800
1801 // Evaluate LHS expression.
1802 switch (assign_type) {
1803 case VARIABLE:
1804 // Nothing to do here.
1805 break;
1806 case NAMED_PROPERTY:
1807 if (expr->is_compound()) {
1808 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001809 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001810 __ push(result_register());
1811 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001812 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001813 }
1814 break;
1815 case KEYED_PROPERTY:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001816 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001817 VisitForStackValue(property->obj());
1818 VisitForAccumulatorValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001819 __ ldr(r1, MemOperand(sp, 0));
1820 __ push(r0);
1821 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001822 VisitForStackValue(property->obj());
1823 VisitForStackValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001824 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001825 break;
1826 }
1827
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001828 // For compound assignments we need another deoptimization point after the
1829 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001830 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001831 { AccumulatorValueContext context(this);
1832 switch (assign_type) {
1833 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001834 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001835 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001836 break;
1837 case NAMED_PROPERTY:
1838 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001839 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001840 break;
1841 case KEYED_PROPERTY:
1842 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001843 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001844 break;
1845 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001846 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001847
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001848 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001849 __ push(r0); // Left operand goes on the stack.
1850 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001851
ricow@chromium.org65fae842010-08-25 15:26:24 +00001852 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1853 ? OVERWRITE_RIGHT
1854 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001855 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001856 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001857 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001858 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001859 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001860 mode,
1861 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001862 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001863 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001864 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001865 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001866
1867 // Deoptimization point in case the binary operation may have side effects.
1868 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001869 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001870 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001871 }
1872
1873 // Record source position before possible IC call.
1874 SetSourcePosition(expr->position());
1875
1876 // Store the value.
1877 switch (assign_type) {
1878 case VARIABLE:
1879 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001880 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001881 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1882 context()->Plug(r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001883 break;
1884 case NAMED_PROPERTY:
1885 EmitNamedPropertyAssignment(expr);
1886 break;
1887 case KEYED_PROPERTY:
1888 EmitKeyedPropertyAssignment(expr);
1889 break;
1890 }
1891}
1892
1893
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001894void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1895 SetSourcePosition(prop->position());
1896 Literal* key = prop->key()->AsLiteral();
1897 __ mov(r2, Operand(key->handle()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001898 // Call load IC. It has arguments receiver and property name r0 and r2.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001899 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001900 CallIC(ic, RelocInfo::CODE_TARGET, prop->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001901}
1902
1903
1904void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1905 SetSourcePosition(prop->position());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001906 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001907 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
danno@chromium.org88aa0582012-03-23 15:11:57 +00001908 CallIC(ic, RelocInfo::CODE_TARGET, prop->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001909}
1910
1911
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001912void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001913 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001914 OverwriteMode mode,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001915 Expression* left_expr,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001916 Expression* right_expr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001917 Label done, smi_case, stub_call;
1918
1919 Register scratch1 = r2;
1920 Register scratch2 = r3;
1921
1922 // Get the arguments.
1923 Register left = r1;
1924 Register right = r0;
1925 __ pop(left);
1926
1927 // Perform combined smi check on both operands.
1928 __ orr(scratch1, left, Operand(right));
1929 STATIC_ASSERT(kSmiTag == 0);
1930 JumpPatchSite patch_site(masm_);
1931 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1932
1933 __ bind(&stub_call);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001934 BinaryOpStub stub(op, mode);
danno@chromium.org88aa0582012-03-23 15:11:57 +00001935 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001936 patch_site.EmitPatchInfo();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001937 __ jmp(&done);
1938
1939 __ bind(&smi_case);
1940 // Smi case. This code works the same way as the smi-smi case in the type
1941 // recording binary operation stub, see
danno@chromium.org40cb8782011-05-25 07:58:50 +00001942 // BinaryOpStub::GenerateSmiSmiOperation for comments.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001943 switch (op) {
1944 case Token::SAR:
1945 __ b(&stub_call);
1946 __ GetLeastBitsFromSmi(scratch1, right, 5);
1947 __ mov(right, Operand(left, ASR, scratch1));
1948 __ bic(right, right, Operand(kSmiTagMask));
1949 break;
1950 case Token::SHL: {
1951 __ b(&stub_call);
1952 __ SmiUntag(scratch1, left);
1953 __ GetLeastBitsFromSmi(scratch2, right, 5);
1954 __ mov(scratch1, Operand(scratch1, LSL, scratch2));
1955 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
1956 __ b(mi, &stub_call);
1957 __ SmiTag(right, scratch1);
1958 break;
1959 }
1960 case Token::SHR: {
1961 __ b(&stub_call);
1962 __ SmiUntag(scratch1, left);
1963 __ GetLeastBitsFromSmi(scratch2, right, 5);
1964 __ mov(scratch1, Operand(scratch1, LSR, scratch2));
1965 __ tst(scratch1, Operand(0xc0000000));
1966 __ b(ne, &stub_call);
1967 __ SmiTag(right, scratch1);
1968 break;
1969 }
1970 case Token::ADD:
1971 __ add(scratch1, left, Operand(right), SetCC);
1972 __ b(vs, &stub_call);
1973 __ mov(right, scratch1);
1974 break;
1975 case Token::SUB:
1976 __ sub(scratch1, left, Operand(right), SetCC);
1977 __ b(vs, &stub_call);
1978 __ mov(right, scratch1);
1979 break;
1980 case Token::MUL: {
1981 __ SmiUntag(ip, right);
1982 __ smull(scratch1, scratch2, left, ip);
1983 __ mov(ip, Operand(scratch1, ASR, 31));
1984 __ cmp(ip, Operand(scratch2));
1985 __ b(ne, &stub_call);
danno@chromium.orgfa458e42012-02-01 10:48:36 +00001986 __ cmp(scratch1, Operand(0));
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001987 __ mov(right, Operand(scratch1), LeaveCC, ne);
1988 __ b(ne, &done);
1989 __ add(scratch2, right, Operand(left), SetCC);
1990 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
1991 __ b(mi, &stub_call);
1992 break;
1993 }
1994 case Token::BIT_OR:
1995 __ orr(right, left, Operand(right));
1996 break;
1997 case Token::BIT_AND:
1998 __ and_(right, left, Operand(right));
1999 break;
2000 case Token::BIT_XOR:
2001 __ eor(right, left, Operand(right));
2002 break;
2003 default:
2004 UNREACHABLE();
2005 }
2006
2007 __ bind(&done);
2008 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002009}
2010
2011
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002012void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
2013 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00002014 OverwriteMode mode) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002015 __ pop(r1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00002016 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002017 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002018 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002019 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002020 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002021}
2022
2023
kmillikin@chromium.orgbe6bd102012-02-23 08:45:21 +00002024void FullCodeGenerator::EmitAssignment(Expression* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002025 // Invalid left-hand sides are rewritten to have a 'throw
2026 // ReferenceError' on the left-hand side.
2027 if (!expr->IsValidLeftHandSide()) {
2028 VisitForEffect(expr);
2029 return;
2030 }
2031
2032 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00002033 // slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002034 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2035 LhsKind assign_type = VARIABLE;
2036 Property* prop = expr->AsProperty();
2037 if (prop != NULL) {
2038 assign_type = (prop->key()->IsPropertyName())
2039 ? NAMED_PROPERTY
2040 : KEYED_PROPERTY;
2041 }
2042
2043 switch (assign_type) {
2044 case VARIABLE: {
2045 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002046 EffectContext context(this);
2047 EmitVariableAssignment(var, Token::ASSIGN);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002048 break;
2049 }
2050 case NAMED_PROPERTY: {
2051 __ push(r0); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002052 VisitForAccumulatorValue(prop->obj());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002053 __ mov(r1, r0);
2054 __ pop(r0); // Restore value.
2055 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002056 Handle<Code> ic = is_classic_mode()
2057 ? isolate()->builtins()->StoreIC_Initialize()
2058 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002059 CallIC(ic);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002060 break;
2061 }
2062 case KEYED_PROPERTY: {
2063 __ push(r0); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00002064 VisitForStackValue(prop->obj());
2065 VisitForAccumulatorValue(prop->key());
2066 __ mov(r1, r0);
2067 __ pop(r2);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002068 __ pop(r0); // Restore value.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002069 Handle<Code> ic = is_classic_mode()
2070 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2071 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002072 CallIC(ic);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002073 break;
2074 }
2075 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002076 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002077}
2078
2079
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002080void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002081 Token::Value op) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002082 if (var->IsUnallocated()) {
2083 // Global var, const, or let.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002084 __ mov(r2, Operand(var->name()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002085 __ ldr(r1, GlobalObjectOperand());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002086 Handle<Code> ic = is_classic_mode()
2087 ? isolate()->builtins()->StoreIC_Initialize()
2088 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002089 CallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002090
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002091 } else if (op == Token::INIT_CONST) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002092 // Const initializers need a write barrier.
2093 ASSERT(!var->IsParameter()); // No const parameters.
2094 if (var->IsStackLocal()) {
2095 Label skip;
2096 __ ldr(r1, StackOperand(var));
2097 __ CompareRoot(r1, Heap::kTheHoleValueRootIndex);
2098 __ b(ne, &skip);
2099 __ str(result_register(), StackOperand(var));
2100 __ bind(&skip);
2101 } else {
2102 ASSERT(var->IsContextSlot() || var->IsLookupSlot());
2103 // Like var declarations, const declarations are hoisted to function
2104 // scope. However, unlike var initializers, const initializers are
2105 // able to drill a hole to that function context, even from inside a
2106 // 'with' context. We thus bypass the normal static scope lookup for
2107 // var->IsContextSlot().
2108 __ push(r0);
2109 __ mov(r0, Operand(var->name()));
2110 __ Push(cp, r0); // Context and name.
2111 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002112 }
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00002113
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00002114 } else if (var->mode() == LET && op != Token::INIT_LET) {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002115 // Non-initializing assignment to let variable needs a write barrier.
2116 if (var->IsLookupSlot()) {
2117 __ push(r0); // Value.
2118 __ mov(r1, Operand(var->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002119 __ mov(r0, Operand(Smi::FromInt(language_mode())));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002120 __ Push(cp, r1, r0); // Context, name, strict mode.
2121 __ CallRuntime(Runtime::kStoreContextSlot, 4);
2122 } else {
2123 ASSERT(var->IsStackAllocated() || var->IsContextSlot());
2124 Label assign;
2125 MemOperand location = VarOperand(var, r1);
2126 __ ldr(r3, location);
2127 __ CompareRoot(r3, Heap::kTheHoleValueRootIndex);
2128 __ b(ne, &assign);
2129 __ mov(r3, Operand(var->name()));
2130 __ push(r3);
2131 __ CallRuntime(Runtime::kThrowReferenceError, 1);
2132 // Perform the assignment.
2133 __ bind(&assign);
2134 __ str(result_register(), location);
2135 if (var->IsContextSlot()) {
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002136 // RecordWrite may destroy all its register arguments.
2137 __ mov(r3, result_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002138 int offset = Context::SlotOffset(var->index());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002139 __ RecordWriteContextSlot(
2140 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002141 }
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00002142 }
2143
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002144 } else if (!var->is_const_mode() || op == Token::INIT_CONST_HARMONY) {
2145 // Assignment to var or initializing assignment to let/const
2146 // in harmony mode.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002147 if (var->IsStackAllocated() || var->IsContextSlot()) {
2148 MemOperand location = VarOperand(var, r1);
2149 if (FLAG_debug_code && op == Token::INIT_LET) {
2150 // Check for an uninitialized let binding.
2151 __ ldr(r2, location);
2152 __ CompareRoot(r2, Heap::kTheHoleValueRootIndex);
2153 __ Check(eq, "Let binding re-initialization.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002154 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002155 // Perform the assignment.
2156 __ str(r0, location);
2157 if (var->IsContextSlot()) {
2158 __ mov(r3, r0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002159 int offset = Context::SlotOffset(var->index());
2160 __ RecordWriteContextSlot(
2161 r1, offset, r3, r2, kLRHasBeenSaved, kDontSaveFPRegs);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002162 }
2163 } else {
2164 ASSERT(var->IsLookupSlot());
2165 __ push(r0); // Value.
2166 __ mov(r1, Operand(var->name()));
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002167 __ mov(r0, Operand(Smi::FromInt(language_mode())));
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002168 __ Push(cp, r1, r0); // Context, name, strict mode.
2169 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002170 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002171 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002172 // Non-initializing assignments to consts are ignored.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002173}
2174
2175
2176void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
2177 // Assignment to a property, using a named store IC.
2178 Property* prop = expr->target()->AsProperty();
2179 ASSERT(prop != NULL);
2180 ASSERT(prop->key()->AsLiteral() != NULL);
2181
2182 // If the assignment starts a block of assignments to the same object,
2183 // change to slow case to avoid the quadratic behavior of repeatedly
2184 // adding fast properties.
2185 if (expr->starts_initialization_block()) {
2186 __ push(result_register());
2187 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value.
2188 __ push(ip);
2189 __ CallRuntime(Runtime::kToSlowProperties, 1);
2190 __ pop(result_register());
2191 }
2192
2193 // Record source code position before IC call.
2194 SetSourcePosition(expr->position());
2195 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002196 // Load receiver to r1. Leave a copy in the stack if needed for turning the
2197 // receiver into fast case.
ager@chromium.org5c838252010-02-19 08:53:10 +00002198 if (expr->ends_initialization_block()) {
2199 __ ldr(r1, MemOperand(sp));
2200 } else {
2201 __ pop(r1);
2202 }
2203
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002204 Handle<Code> ic = is_classic_mode()
2205 ? isolate()->builtins()->StoreIC_Initialize()
2206 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002207 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002208
2209 // If the assignment ends an initialization block, revert to fast case.
2210 if (expr->ends_initialization_block()) {
2211 __ push(r0); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002212 // Receiver is under the result value.
2213 __ ldr(ip, MemOperand(sp, kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002214 __ push(ip);
2215 __ CallRuntime(Runtime::kToFastProperties, 1);
2216 __ pop(r0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002217 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002218 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002219 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2220 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002221}
2222
2223
2224void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
2225 // Assignment to a property, using a keyed store IC.
2226
2227 // If the assignment starts a block of assignments to the same object,
2228 // change to slow case to avoid the quadratic behavior of repeatedly
2229 // adding fast properties.
2230 if (expr->starts_initialization_block()) {
2231 __ push(result_register());
2232 // Receiver is now under the key and value.
2233 __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
2234 __ push(ip);
2235 __ CallRuntime(Runtime::kToSlowProperties, 1);
2236 __ pop(result_register());
2237 }
2238
2239 // Record source code position before IC call.
2240 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002241 __ pop(r1); // Key.
2242 // Load receiver to r2. Leave a copy in the stack if needed for turning the
2243 // receiver into fast case.
2244 if (expr->ends_initialization_block()) {
2245 __ ldr(r2, MemOperand(sp));
2246 } else {
2247 __ pop(r2);
2248 }
2249
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002250 Handle<Code> ic = is_classic_mode()
2251 ? isolate()->builtins()->KeyedStoreIC_Initialize()
2252 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00002253 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002254
2255 // If the assignment ends an initialization block, revert to fast case.
2256 if (expr->ends_initialization_block()) {
2257 __ push(r0); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002258 // Receiver is under the result value.
2259 __ ldr(ip, MemOperand(sp, kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002260 __ push(ip);
2261 __ CallRuntime(Runtime::kToFastProperties, 1);
2262 __ pop(r0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002263 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002264 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002265 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2266 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002267}
2268
2269
2270void FullCodeGenerator::VisitProperty(Property* expr) {
2271 Comment cmnt(masm_, "[ Property");
2272 Expression* key = expr->key();
2273
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002274 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002275 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002276 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002277 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002278 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002279 VisitForStackValue(expr->obj());
2280 VisitForAccumulatorValue(expr->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002281 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002282 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002283 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002284 }
2285}
2286
danno@chromium.org88aa0582012-03-23 15:11:57 +00002287
2288void FullCodeGenerator::CallIC(Handle<Code> code,
2289 RelocInfo::Mode rmode,
2290 unsigned ast_id) {
2291 ic_total_count_++;
2292 __ Call(code, rmode, ast_id);
2293}
2294
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002295void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002296 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002297 RelocInfo::Mode mode) {
2298 // Code common for calls using the IC.
2299 ZoneList<Expression*>* args = expr->arguments();
2300 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002301 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002302 for (int i = 0; i < arg_count; i++) {
2303 VisitForStackValue(args->at(i));
2304 }
2305 __ mov(r2, Operand(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002306 }
2307 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002308 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002309 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002310 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002311 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
danno@chromium.org88aa0582012-03-23 15:11:57 +00002312 CallIC(ic, mode, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002313 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002314 // Restore context register.
2315 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002316 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002317}
2318
2319
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002320void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002321 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002322 // Load the key.
2323 VisitForAccumulatorValue(key);
2324
2325 // Swap the name of the function and the receiver on the stack to follow
2326 // the calling convention for call ICs.
2327 __ pop(r1);
2328 __ push(r0);
2329 __ push(r1);
2330
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002331 // Code common for calls using the IC.
2332 ZoneList<Expression*>* args = expr->arguments();
2333 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002334 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002335 for (int i = 0; i < arg_count; i++) {
2336 VisitForStackValue(args->at(i));
2337 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002338 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002339 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002340 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002341 // Call the IC initialization code.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002342 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00002343 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002344 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
danno@chromium.org88aa0582012-03-23 15:11:57 +00002345 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002346 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002347 // Restore context register.
2348 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002349 context()->DropAndPlug(1, r0); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002350}
2351
2352
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002353void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002354 // Code common for calls using the call stub.
2355 ZoneList<Expression*>* args = expr->arguments();
2356 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002357 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002358 for (int i = 0; i < arg_count; i++) {
2359 VisitForStackValue(args->at(i));
2360 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002361 }
2362 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002363 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002364 CallFunctionStub stub(arg_count, flags);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002365 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002366 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002367 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002368 // Restore context register.
2369 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002370 context()->DropAndPlug(1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002371}
2372
2373
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002374void FullCodeGenerator::EmitResolvePossiblyDirectEval(int arg_count) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002375 // Push copy of the first argument or undefined if it doesn't exist.
2376 if (arg_count > 0) {
2377 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
2378 } else {
2379 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
2380 }
2381 __ push(r1);
2382
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002383 // Push the receiver of the enclosing function.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002384 int receiver_offset = 2 + info_->scope()->num_parameters();
2385 __ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002386 __ push(r1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002387 // Push the language mode.
2388 __ mov(r1, Operand(Smi::FromInt(language_mode())));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002389 __ push(r1);
2390
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002391 // Push the start position of the scope the calls resides in.
2392 __ mov(r1, Operand(Smi::FromInt(scope()->start_position())));
2393 __ push(r1);
2394
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00002395 // Do the runtime call.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00002396 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 5);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002397}
2398
2399
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002400void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002401#ifdef DEBUG
2402 // We want to verify that RecordJSReturnSite gets called on all paths
2403 // through this function. Avoid early returns.
2404 expr->return_is_recorded_ = false;
2405#endif
2406
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002407 Comment cmnt(masm_, "[ Call");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002408 Expression* callee = expr->expression();
2409 VariableProxy* proxy = callee->AsVariableProxy();
2410 Property* property = callee->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002411
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002412 if (proxy != NULL && proxy->var()->is_possibly_eval()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002413 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2414 // resolve the function we need to call and the receiver of the
2415 // call. Then we call the resolved function using the given
2416 // arguments.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002417 ZoneList<Expression*>* args = expr->arguments();
2418 int arg_count = args->length();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002419
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002420 { PreservePositionScope pos_scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002421 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002422 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
2423 __ push(r2); // Reserved receiver slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002424
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002425 // Push the arguments.
2426 for (int i = 0; i < arg_count; i++) {
2427 VisitForStackValue(args->at(i));
2428 }
2429
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002430 // Push a copy of the function (found below the arguments) and
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002431 // resolve eval.
2432 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002433 __ push(r1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002434 EmitResolvePossiblyDirectEval(arg_count);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002435
2436 // The runtime call returns a pair of values in r0 (function) and
2437 // r1 (receiver). Touch up the stack with the right values.
2438 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2439 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002440 }
2441
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002442 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002443 SetSourcePosition(expr->position());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002444 CallFunctionStub stub(arg_count, RECEIVER_MIGHT_BE_IMPLICIT);
danno@chromium.orgc612e022011-11-10 11:38:15 +00002445 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002446 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002447 RecordJSReturnSite(expr);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002448 // Restore context register.
2449 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002450 context()->DropAndPlug(1, r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002451 } else if (proxy != NULL && proxy->var()->IsUnallocated()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002452 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002453 __ ldr(r0, GlobalObjectOperand());
ager@chromium.org5c838252010-02-19 08:53:10 +00002454 __ push(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002455 EmitCallWithIC(expr, proxy->name(), RelocInfo::CODE_TARGET_CONTEXT);
2456 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002457 // Call to a lookup slot (dynamically introduced variable).
2458 Label slow, done;
2459
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002460 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002461 // Generate code for loading from variables potentially shadowed
2462 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002463 EmitDynamicLookupFastCase(proxy->var(), NOT_INSIDE_TYPEOF, &slow, &done);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002464 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002465
2466 __ bind(&slow);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002467 // Call the runtime to find the function to call (returned in r0)
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002468 // and the object holding it (returned in edx).
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002469 __ push(context_register());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002470 __ mov(r2, Operand(proxy->name()));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002471 __ push(r2);
2472 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002473 __ Push(r0, r1); // Function, receiver.
2474
2475 // If fast case code has been generated, emit code to push the
2476 // function and receiver and have the slow path jump around this
2477 // code.
2478 if (done.is_linked()) {
2479 Label call;
2480 __ b(&call);
2481 __ bind(&done);
2482 // Push function.
2483 __ push(r0);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002484 // The receiver is implicitly the global receiver. Indicate this
2485 // by passing the hole to the call function stub.
2486 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002487 __ push(r1);
2488 __ bind(&call);
2489 }
2490
danno@chromium.org40cb8782011-05-25 07:58:50 +00002491 // The receiver is either the global receiver or an object found
2492 // by LoadContextSlot. That object could be the hole if the
2493 // receiver is implicitly the global object.
2494 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002495 } else if (property != NULL) {
2496 { PreservePositionScope scope(masm()->positions_recorder());
2497 VisitForStackValue(property->obj());
2498 }
2499 if (property->key()->IsPropertyName()) {
2500 EmitCallWithIC(expr,
2501 property->key()->AsLiteral()->handle(),
2502 RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002503 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002504 EmitKeyedCallWithIC(expr, property->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002505 }
2506 } else {
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002507 // Call to an arbitrary expression not handled specially above.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002508 { PreservePositionScope scope(masm()->positions_recorder());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00002509 VisitForStackValue(callee);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002510 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002511 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002512 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002513 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
2514 __ push(r1);
2515 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002516 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002517 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002518
2519#ifdef DEBUG
2520 // RecordJSReturnSite should have been called.
2521 ASSERT(expr->return_is_recorded_);
2522#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002523}
2524
2525
2526void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2527 Comment cmnt(masm_, "[ CallNew");
2528 // According to ECMA-262, section 11.2.2, page 44, the function
2529 // expression in new calls must be evaluated before the
2530 // arguments.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002531
2532 // Push constructor on the stack. If it's not a function it's used as
2533 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2534 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002535 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002536
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002537 // Push the arguments ("left-to-right") on the stack.
2538 ZoneList<Expression*>* args = expr->arguments();
2539 int arg_count = args->length();
2540 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002541 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002542 }
2543
2544 // Call the construct call builtin that handles allocation and
2545 // constructor invocation.
2546 SetSourcePosition(expr->position());
2547
ricow@chromium.org65fae842010-08-25 15:26:24 +00002548 // Load function and argument count into r1 and r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002549 __ mov(r0, Operand(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002550 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002551
danno@chromium.orgfa458e42012-02-01 10:48:36 +00002552 // Record call targets in unoptimized code, but not in the snapshot.
2553 CallFunctionFlags flags;
2554 if (!Serializer::enabled()) {
2555 flags = RECORD_CALL_TARGET;
2556 Handle<Object> uninitialized =
2557 TypeFeedbackCells::UninitializedSentinel(isolate());
2558 Handle<JSGlobalPropertyCell> cell =
2559 isolate()->factory()->NewJSGlobalPropertyCell(uninitialized);
2560 RecordTypeFeedbackCell(expr->id(), cell);
2561 __ mov(r2, Operand(cell));
2562 } else {
2563 flags = NO_CALL_FUNCTION_FLAGS;
2564 }
2565
2566 CallConstructStub stub(flags);
2567 __ Call(stub.GetCode(), RelocInfo::CONSTRUCT_CALL);
ulan@chromium.org967e2702012-02-28 09:49:15 +00002568 PrepareForBailoutForId(expr->ReturnId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002569 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002570}
2571
2572
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002573void FullCodeGenerator::EmitIsSmi(CallRuntime* expr) {
2574 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002575 ASSERT(args->length() == 1);
2576
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002577 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002578
2579 Label materialize_true, materialize_false;
2580 Label* if_true = NULL;
2581 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002582 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002583 context()->PrepareTest(&materialize_true, &materialize_false,
2584 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002585
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002586 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002587 __ tst(r0, Operand(kSmiTagMask));
2588 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002589
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002590 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002591}
2592
2593
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002594void FullCodeGenerator::EmitIsNonNegativeSmi(CallRuntime* expr) {
2595 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002596 ASSERT(args->length() == 1);
2597
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002598 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002599
2600 Label materialize_true, materialize_false;
2601 Label* if_true = NULL;
2602 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002603 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002604 context()->PrepareTest(&materialize_true, &materialize_false,
2605 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002606
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002607 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002608 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002609 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002610
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002611 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002612}
2613
2614
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002615void FullCodeGenerator::EmitIsObject(CallRuntime* expr) {
2616 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002617 ASSERT(args->length() == 1);
2618
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002619 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002620
2621 Label materialize_true, materialize_false;
2622 Label* if_true = NULL;
2623 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002624 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002625 context()->PrepareTest(&materialize_true, &materialize_false,
2626 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002627
ager@chromium.org378b34e2011-01-28 08:04:38 +00002628 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002629 __ LoadRoot(ip, Heap::kNullValueRootIndex);
2630 __ cmp(r0, ip);
2631 __ b(eq, if_true);
2632 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
2633 // Undetectable objects behave like undefined when tested with typeof.
2634 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
2635 __ tst(r1, Operand(1 << Map::kIsUndetectable));
2636 __ b(ne, if_false);
2637 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002638 __ cmp(r1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002639 __ b(lt, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002640 __ cmp(r1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002641 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002642 Split(le, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002643
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002644 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002645}
2646
2647
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002648void FullCodeGenerator::EmitIsSpecObject(CallRuntime* expr) {
2649 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002650 ASSERT(args->length() == 1);
2651
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002652 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002653
2654 Label materialize_true, materialize_false;
2655 Label* if_true = NULL;
2656 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002657 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002658 context()->PrepareTest(&materialize_true, &materialize_false,
2659 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002660
ager@chromium.org378b34e2011-01-28 08:04:38 +00002661 __ JumpIfSmi(r0, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002662 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002663 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002664 Split(ge, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002665
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002666 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002667}
2668
2669
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002670void FullCodeGenerator::EmitIsUndetectableObject(CallRuntime* expr) {
2671 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002672 ASSERT(args->length() == 1);
2673
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002674 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002675
2676 Label materialize_true, materialize_false;
2677 Label* if_true = NULL;
2678 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002679 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002680 context()->PrepareTest(&materialize_true, &materialize_false,
2681 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002682
ager@chromium.org378b34e2011-01-28 08:04:38 +00002683 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002684 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2685 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
2686 __ tst(r1, Operand(1 << Map::kIsUndetectable));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002687 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002688 Split(ne, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002689
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002690 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002691}
2692
2693
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002694void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002695 CallRuntime* expr) {
2696 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002697 ASSERT(args->length() == 1);
2698
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002699 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002700
2701 Label materialize_true, materialize_false;
2702 Label* if_true = NULL;
2703 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002704 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002705 context()->PrepareTest(&materialize_true, &materialize_false,
2706 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002707
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002708 if (FLAG_debug_code) __ AbortIfSmi(r0);
2709
2710 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2711 __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset));
2712 __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
2713 __ b(ne, if_true);
2714
2715 // Check for fast case object. Generate false result for slow case object.
2716 __ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset));
2717 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
2718 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
2719 __ cmp(r2, ip);
2720 __ b(eq, if_false);
2721
2722 // Look for valueOf symbol in the descriptor array, and indicate false if
2723 // found. The type is not checked, so if it is a transition it is a false
2724 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002725 __ LoadInstanceDescriptors(r1, r4);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002726 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset));
2727 // r4: descriptor array
2728 // r3: length of descriptor array
2729 // Calculate the end of the descriptor array.
2730 STATIC_ASSERT(kSmiTag == 0);
2731 STATIC_ASSERT(kSmiTagSize == 1);
2732 STATIC_ASSERT(kPointerSize == 4);
2733 __ add(r2, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2734 __ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
2735
2736 // Calculate location of the first key name.
2737 __ add(r4,
2738 r4,
2739 Operand(FixedArray::kHeaderSize - kHeapObjectTag +
2740 DescriptorArray::kFirstIndex * kPointerSize));
2741 // Loop through all the keys in the descriptor array. If one of these is the
2742 // symbol valueOf the result is false.
2743 Label entry, loop;
2744 // The use of ip to store the valueOf symbol asumes that it is not otherwise
2745 // used in the loop below.
2746 __ mov(ip, Operand(FACTORY->value_of_symbol()));
2747 __ jmp(&entry);
2748 __ bind(&loop);
2749 __ ldr(r3, MemOperand(r4, 0));
2750 __ cmp(r3, ip);
2751 __ b(eq, if_false);
2752 __ add(r4, r4, Operand(kPointerSize));
2753 __ bind(&entry);
2754 __ cmp(r4, Operand(r2));
2755 __ b(ne, &loop);
2756
2757 // If a valueOf property is not found on the object check that it's
2758 // prototype is the un-modified String prototype. If not result is false.
2759 __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002760 __ JumpIfSmi(r2, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002761 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
2762 __ ldr(r3, ContextOperand(cp, Context::GLOBAL_INDEX));
2763 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalContextOffset));
2764 __ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2765 __ cmp(r2, r3);
2766 __ b(ne, if_false);
2767
2768 // Set the bit in the map to indicate that it has been checked safe for
2769 // default valueOf and set true result.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002770 __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002771 __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002772 __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002773 __ jmp(if_true);
2774
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002775 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002777}
2778
2779
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002780void FullCodeGenerator::EmitIsFunction(CallRuntime* expr) {
2781 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002782 ASSERT(args->length() == 1);
2783
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002784 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002785
2786 Label materialize_true, materialize_false;
2787 Label* if_true = NULL;
2788 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002789 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002790 context()->PrepareTest(&materialize_true, &materialize_false,
2791 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002792
ager@chromium.org378b34e2011-01-28 08:04:38 +00002793 __ JumpIfSmi(r0, if_false);
lrn@chromium.org34e60782011-09-15 07:25:40 +00002794 __ CompareObjectType(r0, r1, r2, JS_FUNCTION_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002795 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002796 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002797
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002798 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002799}
2800
2801
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002802void FullCodeGenerator::EmitIsArray(CallRuntime* expr) {
2803 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002804 ASSERT(args->length() == 1);
2805
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002806 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002807
2808 Label materialize_true, materialize_false;
2809 Label* if_true = NULL;
2810 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002811 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002812 context()->PrepareTest(&materialize_true, &materialize_false,
2813 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002814
ager@chromium.org378b34e2011-01-28 08:04:38 +00002815 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002816 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002817 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002818 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002819
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002820 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002821}
2822
2823
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002824void FullCodeGenerator::EmitIsRegExp(CallRuntime* expr) {
2825 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002826 ASSERT(args->length() == 1);
2827
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002828 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002829
2830 Label materialize_true, materialize_false;
2831 Label* if_true = NULL;
2832 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002833 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002834 context()->PrepareTest(&materialize_true, &materialize_false,
2835 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002836
ager@chromium.org378b34e2011-01-28 08:04:38 +00002837 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002838 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002839 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002840 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002841
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002842 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002843}
2844
2845
2846
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002847void FullCodeGenerator::EmitIsConstructCall(CallRuntime* expr) {
2848 ASSERT(expr->arguments()->length() == 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002849
2850 Label materialize_true, materialize_false;
2851 Label* if_true = NULL;
2852 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002853 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002854 context()->PrepareTest(&materialize_true, &materialize_false,
2855 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002856
2857 // Get the frame pointer for the calling frame.
2858 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2859
2860 // Skip the arguments adaptor frame if it exists.
2861 Label check_frame_marker;
2862 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset));
2863 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2864 __ b(ne, &check_frame_marker);
2865 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset));
2866
2867 // Check the marker in the calling frame.
2868 __ bind(&check_frame_marker);
2869 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
2870 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002871 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002872 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002873
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002874 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002875}
2876
2877
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002878void FullCodeGenerator::EmitObjectEquals(CallRuntime* expr) {
2879 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002880 ASSERT(args->length() == 2);
2881
2882 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002883 VisitForStackValue(args->at(0));
2884 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002885
2886 Label materialize_true, materialize_false;
2887 Label* if_true = NULL;
2888 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002889 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002890 context()->PrepareTest(&materialize_true, &materialize_false,
2891 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002892
2893 __ pop(r1);
2894 __ cmp(r0, r1);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002895 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002896 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002897
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002898 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002899}
2900
2901
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002902void FullCodeGenerator::EmitArguments(CallRuntime* expr) {
2903 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002904 ASSERT(args->length() == 1);
2905
2906 // ArgumentsAccessStub expects the key in edx and the formal
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002907 // parameter count in r0.
2908 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002909 __ mov(r1, r0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002910 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002911 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2912 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002913 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002914}
2915
2916
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002917void FullCodeGenerator::EmitArgumentsLength(CallRuntime* expr) {
2918 ASSERT(expr->arguments()->length() == 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002919 Label exit;
2920 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002921 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002922
2923 // Check if the calling frame is an arguments adaptor frame.
2924 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2925 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2926 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2927 __ b(ne, &exit);
2928
2929 // Arguments adaptor case: Read the arguments length from the
2930 // adaptor frame.
2931 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2932
2933 __ bind(&exit);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002934 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002935}
2936
2937
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002938void FullCodeGenerator::EmitClassOf(CallRuntime* expr) {
2939 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002940 ASSERT(args->length() == 1);
2941 Label done, null, function, non_function_constructor;
2942
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002943 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002944
2945 // If the object is a smi, we return null.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002946 __ JumpIfSmi(r0, &null);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002947
2948 // Check that the object is a JS object but take special care of JS
2949 // functions to make sure they have 'Function' as their class.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002950 // Assume that there are only two callable types, and one of them is at
2951 // either end of the type range for JS object types. Saves extra comparisons.
2952 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002953 __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE);
2954 // Map is now in r0.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002955 __ b(lt, &null);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002956 STATIC_ASSERT(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2957 FIRST_SPEC_OBJECT_TYPE + 1);
2958 __ b(eq, &function);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002959
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002960 __ cmp(r1, Operand(LAST_SPEC_OBJECT_TYPE));
2961 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE ==
2962 LAST_SPEC_OBJECT_TYPE - 1);
2963 __ b(eq, &function);
2964 // Assume that there is no larger type.
2965 STATIC_ASSERT(LAST_NONCALLABLE_SPEC_OBJECT_TYPE == LAST_TYPE - 1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002966
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002967 // Check if the constructor in the map is a JS function.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002968 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset));
2969 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
2970 __ b(ne, &non_function_constructor);
2971
2972 // r0 now contains the constructor function. Grab the
2973 // instance class name from there.
2974 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
2975 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset));
2976 __ b(&done);
2977
2978 // Functions have class 'Function'.
2979 __ bind(&function);
2980 __ LoadRoot(r0, Heap::kfunction_class_symbolRootIndex);
2981 __ jmp(&done);
2982
2983 // Objects with a non-function constructor have class 'Object'.
2984 __ bind(&non_function_constructor);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002985 __ LoadRoot(r0, Heap::kObject_symbolRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002986 __ jmp(&done);
2987
2988 // Non-JS objects have class null.
2989 __ bind(&null);
2990 __ LoadRoot(r0, Heap::kNullValueRootIndex);
2991
2992 // All done.
2993 __ bind(&done);
2994
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002995 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002996}
2997
2998
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00002999void FullCodeGenerator::EmitLog(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003000 // Conditionally generate a log call.
3001 // Args:
3002 // 0 (literal string): The type of logging (corresponds to the flags).
3003 // This is used to determine whether or not to generate the log call.
3004 // 1 (string): Format string. Access the string at argument index 2
3005 // with '%2s' (see Logger::LogRuntime for all the formats).
3006 // 2 (array): Arguments to the format string.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003007 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003008 ASSERT_EQ(args->length(), 3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003009 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003010 VisitForStackValue(args->at(1));
3011 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003012 __ CallRuntime(Runtime::kLog, 2);
3013 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003014
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003015 // Finally, we're expected to leave a value on the top of the stack.
3016 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003017 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003018}
3019
3020
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003021void FullCodeGenerator::EmitRandomHeapNumber(CallRuntime* expr) {
3022 ASSERT(expr->arguments()->length() == 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003023 Label slow_allocate_heapnumber;
3024 Label heapnumber_allocated;
3025
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00003026 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
3027 __ AllocateHeapNumber(r4, r1, r2, r6, &slow_allocate_heapnumber);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003028 __ jmp(&heapnumber_allocated);
3029
3030 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00003031 // Allocate a heap number.
3032 __ CallRuntime(Runtime::kNumberAlloc, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003033 __ mov(r4, Operand(r0));
3034
3035 __ bind(&heapnumber_allocated);
3036
3037 // Convert 32 random bits in r0 to 0.(32 random bits) in a double
3038 // by computing:
3039 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003040 if (CpuFeatures::IsSupported(VFP3)) {
3041 __ PrepareCallCFunction(1, r0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003042 __ ldr(r0, ContextOperand(context_register(), Context::GLOBAL_INDEX));
3043 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kGlobalContextOffset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003044 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003045
3046 CpuFeatures::Scope scope(VFP3);
3047 // 0x41300000 is the top half of 1.0 x 2^20 as a double.
3048 // Create this constant using mov/orr to avoid PC relative load.
3049 __ mov(r1, Operand(0x41000000));
3050 __ orr(r1, r1, Operand(0x300000));
3051 // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
3052 __ vmov(d7, r0, r1);
3053 // Move 0x4130000000000000 to VFP.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003054 __ mov(r0, Operand(0, RelocInfo::NONE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003055 __ vmov(d8, r0, r1);
3056 // Subtract and store the result in the heap number.
3057 __ vsub(d7, d7, d8);
3058 __ sub(r0, r4, Operand(kHeapObjectTag));
3059 __ vstr(d7, r0, HeapNumber::kValueOffset);
3060 __ mov(r0, r4);
3061 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003062 __ PrepareCallCFunction(2, r0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003063 __ ldr(r1, ContextOperand(context_register(), Context::GLOBAL_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003064 __ mov(r0, Operand(r4));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00003065 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003066 __ CallCFunction(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003067 ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003068 }
3069
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003070 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003071}
3072
3073
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003074void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003075 // Load the arguments on the stack and call the stub.
3076 SubStringStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003077 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003078 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003079 VisitForStackValue(args->at(0));
3080 VisitForStackValue(args->at(1));
3081 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003082 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003083 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003084}
3085
3086
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003087void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003088 // Load the arguments on the stack and call the stub.
3089 RegExpExecStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003090 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003091 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003092 VisitForStackValue(args->at(0));
3093 VisitForStackValue(args->at(1));
3094 VisitForStackValue(args->at(2));
3095 VisitForStackValue(args->at(3));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003096 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003097 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003098}
3099
3100
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003101void FullCodeGenerator::EmitValueOf(CallRuntime* expr) {
3102 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003103 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003104 VisitForAccumulatorValue(args->at(0)); // Load the object.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003105
3106 Label done;
3107 // If the object is a smi return the object.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003108 __ JumpIfSmi(r0, &done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003109 // If the object is not a value type, return the object.
3110 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE);
3111 __ b(ne, &done);
3112 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
3113
3114 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003115 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003116}
3117
3118
svenpanne@chromium.org4efbdb12012-03-12 08:18:42 +00003119void FullCodeGenerator::EmitDateField(CallRuntime* expr) {
3120 ZoneList<Expression*>* args = expr->arguments();
3121 ASSERT(args->length() == 2);
3122 ASSERT_NE(NULL, args->at(1)->AsLiteral());
3123 Smi* index = Smi::cast(*(args->at(1)->AsLiteral()->handle()));
3124
3125 VisitForAccumulatorValue(args->at(0)); // Load the object.
3126
3127 Label runtime, done;
3128 Register object = r0;
3129 Register result = r0;
3130 Register scratch0 = r9;
3131 Register scratch1 = r1;
3132
3133#ifdef DEBUG
3134 __ AbortIfSmi(object);
3135 __ CompareObjectType(object, scratch1, scratch1, JS_DATE_TYPE);
3136 __ Assert(eq, "Trying to get date field from non-date.");
3137#endif
3138
3139 if (index->value() == 0) {
3140 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset));
3141 } else {
3142 if (index->value() < JSDate::kFirstUncachedField) {
3143 ExternalReference stamp = ExternalReference::date_cache_stamp(isolate());
3144 __ mov(scratch1, Operand(stamp));
3145 __ ldr(scratch1, MemOperand(scratch1));
3146 __ ldr(scratch0, FieldMemOperand(object, JSDate::kCacheStampOffset));
3147 __ cmp(scratch1, scratch0);
3148 __ b(ne, &runtime);
3149 __ ldr(result, FieldMemOperand(object, JSDate::kValueOffset +
3150 kPointerSize * index->value()));
3151 __ jmp(&done);
3152 }
3153 __ bind(&runtime);
3154 __ PrepareCallCFunction(2, scratch1);
3155 __ mov(r1, Operand(index));
3156 __ CallCFunction(ExternalReference::get_date_field_function(isolate()), 2);
3157 __ bind(&done);
3158 }
3159 context()->Plug(r0);
3160}
3161
3162
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003163void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003164 // Load the arguments on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003165 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003166 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003167 VisitForStackValue(args->at(0));
3168 VisitForStackValue(args->at(1));
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00003169 if (CpuFeatures::IsSupported(VFP3)) {
3170 MathPowStub stub(MathPowStub::ON_STACK);
3171 __ CallStub(&stub);
3172 } else {
3173 __ CallRuntime(Runtime::kMath_pow, 2);
3174 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003175 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003176}
3177
3178
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003179void FullCodeGenerator::EmitSetValueOf(CallRuntime* expr) {
3180 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003181 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003182 VisitForStackValue(args->at(0)); // Load the object.
3183 VisitForAccumulatorValue(args->at(1)); // Load the value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003184 __ pop(r1); // r0 = value. r1 = object.
3185
3186 Label done;
3187 // If the object is a smi, return the value.
ager@chromium.org378b34e2011-01-28 08:04:38 +00003188 __ JumpIfSmi(r1, &done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003189
3190 // If the object is not a value type, return the value.
3191 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE);
3192 __ b(ne, &done);
3193
3194 // Store the value.
3195 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
3196 // Update the write barrier. Save the value as it will be
3197 // overwritten by the write barrier code and is needed afterward.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003198 __ mov(r2, r0);
3199 __ RecordWriteField(
3200 r1, JSValue::kValueOffset, r2, r3, kLRHasBeenSaved, kDontSaveFPRegs);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003201
3202 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003203 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003204}
3205
3206
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003207void FullCodeGenerator::EmitNumberToString(CallRuntime* expr) {
3208 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003209 ASSERT_EQ(args->length(), 1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003210 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003211 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003212
3213 NumberToStringStub stub;
3214 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003215 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003216}
3217
3218
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003219void FullCodeGenerator::EmitStringCharFromCode(CallRuntime* expr) {
3220 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003221 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003222 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003223
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003224 Label done;
3225 StringCharFromCodeGenerator generator(r0, r1);
3226 generator.GenerateFast(masm_);
3227 __ jmp(&done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003228
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003229 NopRuntimeCallHelper call_helper;
3230 generator.GenerateSlow(masm_, call_helper);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003231
3232 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003233 context()->Plug(r1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003234}
3235
3236
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003237void FullCodeGenerator::EmitStringCharCodeAt(CallRuntime* expr) {
3238 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003239 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003240 VisitForStackValue(args->at(0));
3241 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003242
3243 Register object = r1;
3244 Register index = r0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003245 Register result = r3;
3246
3247 __ pop(object);
3248
3249 Label need_conversion;
3250 Label index_out_of_range;
3251 Label done;
3252 StringCharCodeAtGenerator generator(object,
3253 index,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003254 result,
3255 &need_conversion,
3256 &need_conversion,
3257 &index_out_of_range,
3258 STRING_INDEX_IS_NUMBER);
3259 generator.GenerateFast(masm_);
3260 __ jmp(&done);
3261
3262 __ bind(&index_out_of_range);
3263 // When the index is out of range, the spec requires us to return
3264 // NaN.
3265 __ LoadRoot(result, Heap::kNanValueRootIndex);
3266 __ jmp(&done);
3267
3268 __ bind(&need_conversion);
3269 // Load the undefined value into the result register, which will
3270 // trigger conversion.
3271 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
3272 __ jmp(&done);
3273
3274 NopRuntimeCallHelper call_helper;
3275 generator.GenerateSlow(masm_, call_helper);
3276
3277 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003278 context()->Plug(result);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003279}
3280
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003281
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003282void FullCodeGenerator::EmitStringCharAt(CallRuntime* expr) {
3283 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003284 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003285 VisitForStackValue(args->at(0));
3286 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003287
3288 Register object = r1;
3289 Register index = r0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00003290 Register scratch = r3;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003291 Register result = r0;
3292
3293 __ pop(object);
3294
3295 Label need_conversion;
3296 Label index_out_of_range;
3297 Label done;
3298 StringCharAtGenerator generator(object,
3299 index,
danno@chromium.orgc612e022011-11-10 11:38:15 +00003300 scratch,
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003301 result,
3302 &need_conversion,
3303 &need_conversion,
3304 &index_out_of_range,
3305 STRING_INDEX_IS_NUMBER);
3306 generator.GenerateFast(masm_);
3307 __ jmp(&done);
3308
3309 __ bind(&index_out_of_range);
3310 // When the index is out of range, the spec requires us to return
3311 // the empty string.
3312 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
3313 __ jmp(&done);
3314
3315 __ bind(&need_conversion);
3316 // Move smi zero into the result register, which will trigger
3317 // conversion.
3318 __ mov(result, Operand(Smi::FromInt(0)));
3319 __ jmp(&done);
3320
3321 NopRuntimeCallHelper call_helper;
3322 generator.GenerateSlow(masm_, call_helper);
3323
3324 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003325 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003326}
3327
3328
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003329void FullCodeGenerator::EmitStringAdd(CallRuntime* expr) {
3330 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003331 ASSERT_EQ(2, args->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003332 VisitForStackValue(args->at(0));
3333 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003334
3335 StringAddStub stub(NO_STRING_ADD_FLAGS);
3336 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003337 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003338}
3339
3340
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003341void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
3342 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003343 ASSERT_EQ(2, args->length());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003344 VisitForStackValue(args->at(0));
3345 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003346
3347 StringCompareStub stub;
3348 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003349 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003350}
3351
3352
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003353void FullCodeGenerator::EmitMathSin(CallRuntime* expr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003354 // Load the argument on the stack and call the stub.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003355 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3356 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003357 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003358 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003359 VisitForStackValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003360 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003361 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003362}
3363
3364
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003365void FullCodeGenerator::EmitMathCos(CallRuntime* expr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003366 // Load the argument on the stack and call the stub.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003367 TranscendentalCacheStub stub(TranscendentalCache::COS,
3368 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003369 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003370 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003371 VisitForStackValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003372 __ CallStub(&stub);
3373 context()->Plug(r0);
3374}
3375
3376
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003377void FullCodeGenerator::EmitMathTan(CallRuntime* expr) {
3378 // Load the argument on the stack and call the stub.
3379 TranscendentalCacheStub stub(TranscendentalCache::TAN,
3380 TranscendentalCacheStub::TAGGED);
3381 ZoneList<Expression*>* args = expr->arguments();
3382 ASSERT(args->length() == 1);
3383 VisitForStackValue(args->at(0));
3384 __ CallStub(&stub);
3385 context()->Plug(r0);
3386}
3387
3388
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003389void FullCodeGenerator::EmitMathLog(CallRuntime* expr) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003390 // Load the argument on the stack and call the stub.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003391 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3392 TranscendentalCacheStub::TAGGED);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003393 ZoneList<Expression*>* args = expr->arguments();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003394 ASSERT(args->length() == 1);
3395 VisitForStackValue(args->at(0));
3396 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003397 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003398}
3399
3400
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003401void FullCodeGenerator::EmitMathSqrt(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003402 // Load the argument on the stack and call the runtime function.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003403 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003404 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003405 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003406 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003407 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003408}
3409
3410
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003411void FullCodeGenerator::EmitCallFunction(CallRuntime* expr) {
3412 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003413 ASSERT(args->length() >= 2);
3414
danno@chromium.org160a7b02011-04-18 15:51:38 +00003415 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3416 for (int i = 0; i < arg_count + 1; i++) {
3417 VisitForStackValue(args->at(i));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003418 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003419 VisitForAccumulatorValue(args->last()); // Function.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003420
danno@chromium.orgc612e022011-11-10 11:38:15 +00003421 // Check for proxy.
3422 Label proxy, done;
3423 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_PROXY_TYPE);
3424 __ b(eq, &proxy);
3425
danno@chromium.org160a7b02011-04-18 15:51:38 +00003426 // InvokeFunction requires the function in r1. Move it in there.
3427 __ mov(r1, result_register());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003428 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003429 __ InvokeFunction(r1, count, CALL_FUNCTION,
3430 NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003431 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
danno@chromium.orgc612e022011-11-10 11:38:15 +00003432 __ jmp(&done);
3433
3434 __ bind(&proxy);
3435 __ push(r0);
3436 __ CallRuntime(Runtime::kCall, args->length());
3437 __ bind(&done);
3438
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003439 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003440}
3441
3442
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003443void FullCodeGenerator::EmitRegExpConstructResult(CallRuntime* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003444 RegExpConstructResultStub stub;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003445 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003446 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003447 VisitForStackValue(args->at(0));
3448 VisitForStackValue(args->at(1));
3449 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003450 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003451 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003452}
3453
3454
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003455void FullCodeGenerator::EmitSwapElements(CallRuntime* expr) {
3456 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003457 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003458 VisitForStackValue(args->at(0));
3459 VisitForStackValue(args->at(1));
3460 VisitForStackValue(args->at(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003461 Label done;
3462 Label slow_case;
3463 Register object = r0;
3464 Register index1 = r1;
3465 Register index2 = r2;
3466 Register elements = r3;
3467 Register scratch1 = r4;
3468 Register scratch2 = r5;
3469
3470 __ ldr(object, MemOperand(sp, 2 * kPointerSize));
3471 // Fetch the map and check if array is in fast case.
3472 // Check that object doesn't require security checks and
3473 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003474 __ CompareObjectType(object, scratch1, scratch2, JS_ARRAY_TYPE);
3475 __ b(ne, &slow_case);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003476 // Map is now in scratch1.
3477
3478 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
3479 __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
3480 __ b(ne, &slow_case);
3481
3482 // Check the object's elements are in fast case and writable.
3483 __ ldr(elements, FieldMemOperand(object, JSObject::kElementsOffset));
3484 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
3485 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
3486 __ cmp(scratch1, ip);
3487 __ b(ne, &slow_case);
3488
3489 // Check that both indices are smis.
3490 __ ldr(index1, MemOperand(sp, 1 * kPointerSize));
3491 __ ldr(index2, MemOperand(sp, 0));
3492 __ JumpIfNotBothSmi(index1, index2, &slow_case);
3493
3494 // Check that both indices are valid.
3495 __ ldr(scratch1, FieldMemOperand(object, JSArray::kLengthOffset));
3496 __ cmp(scratch1, index1);
3497 __ cmp(scratch1, index2, hi);
3498 __ b(ls, &slow_case);
3499
3500 // Bring the address of the elements into index1 and index2.
3501 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3502 __ add(index1,
3503 scratch1,
3504 Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize));
3505 __ add(index2,
3506 scratch1,
3507 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize));
3508
3509 // Swap elements.
3510 __ ldr(scratch1, MemOperand(index1, 0));
3511 __ ldr(scratch2, MemOperand(index2, 0));
3512 __ str(scratch1, MemOperand(index2, 0));
3513 __ str(scratch2, MemOperand(index1, 0));
3514
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003515 Label no_remembered_set;
3516 __ CheckPageFlag(elements,
3517 scratch1,
3518 1 << MemoryChunk::SCAN_ON_SCAVENGE,
3519 ne,
3520 &no_remembered_set);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003521 // Possible optimization: do a check that both values are Smis
3522 // (or them and test against Smi mask.)
3523
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003524 // We are swapping two objects in an array and the incremental marker never
3525 // pauses in the middle of scanning a single object. Therefore the
3526 // incremental marker is not disturbed, so we don't need to call the
3527 // RecordWrite stub that notifies the incremental marker.
3528 __ RememberedSetHelper(elements,
3529 index1,
3530 scratch2,
3531 kDontSaveFPRegs,
3532 MacroAssembler::kFallThroughAtEnd);
3533 __ RememberedSetHelper(elements,
3534 index2,
3535 scratch2,
3536 kDontSaveFPRegs,
3537 MacroAssembler::kFallThroughAtEnd);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003538
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003539 __ bind(&no_remembered_set);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003540 // We are done. Drop elements from the stack, and return undefined.
3541 __ Drop(3);
3542 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
3543 __ jmp(&done);
3544
3545 __ bind(&slow_case);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003546 __ CallRuntime(Runtime::kSwapElements, 3);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003547
3548 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003549 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003550}
3551
3552
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003553void FullCodeGenerator::EmitGetFromCache(CallRuntime* expr) {
3554 ZoneList<Expression*>* args = expr->arguments();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003555 ASSERT_EQ(2, args->length());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003556 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3557 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3558
3559 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 isolate()->global_context()->jsfunction_result_caches());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003561 if (jsfunction_result_caches->length() <= cache_id) {
3562 __ Abort("Attempt to use undefined cache.");
3563 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003564 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003565 return;
3566 }
3567
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003568 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003569
3570 Register key = r0;
3571 Register cache = r1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003572 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003573 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003574 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003575 __ ldr(cache,
3576 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3577
3578
3579 Label done, not_found;
3580 // tmp now holds finger offset as a smi.
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00003581 STATIC_ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003582 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
3583 // r2 now holds finger offset as a smi.
3584 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3585 // r3 now points to the start of fixed array elements.
3586 __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex));
3587 // Note side effect of PreIndex: r3 now points to the key of the pair.
3588 __ cmp(key, r2);
3589 __ b(ne, &not_found);
3590
3591 __ ldr(r0, MemOperand(r3, kPointerSize));
3592 __ b(&done);
3593
3594 __ bind(&not_found);
3595 // Call runtime to perform the lookup.
3596 __ Push(cache, key);
3597 __ CallRuntime(Runtime::kGetFromCache, 2);
3598
3599 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003600 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003601}
3602
3603
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003604void FullCodeGenerator::EmitIsRegExpEquivalent(CallRuntime* expr) {
3605 ZoneList<Expression*>* args = expr->arguments();
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003606 ASSERT_EQ(2, args->length());
3607
3608 Register right = r0;
3609 Register left = r1;
3610 Register tmp = r2;
3611 Register tmp2 = r3;
3612
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003613 VisitForStackValue(args->at(0));
3614 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003615 __ pop(left);
3616
3617 Label done, fail, ok;
3618 __ cmp(left, Operand(right));
3619 __ b(eq, &ok);
3620 // Fail if either is a non-HeapObject.
3621 __ and_(tmp, left, Operand(right));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003622 __ JumpIfSmi(tmp, &fail);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003623 __ ldr(tmp, FieldMemOperand(left, HeapObject::kMapOffset));
3624 __ ldrb(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset));
3625 __ cmp(tmp2, Operand(JS_REGEXP_TYPE));
3626 __ b(ne, &fail);
3627 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
3628 __ cmp(tmp, Operand(tmp2));
3629 __ b(ne, &fail);
3630 __ ldr(tmp, FieldMemOperand(left, JSRegExp::kDataOffset));
3631 __ ldr(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset));
3632 __ cmp(tmp, tmp2);
3633 __ b(eq, &ok);
3634 __ bind(&fail);
3635 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
3636 __ jmp(&done);
3637 __ bind(&ok);
3638 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
3639 __ bind(&done);
3640
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003641 context()->Plug(r0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003642}
3643
3644
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003645void FullCodeGenerator::EmitHasCachedArrayIndex(CallRuntime* expr) {
3646 ZoneList<Expression*>* args = expr->arguments();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003647 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003648
3649 Label materialize_true, materialize_false;
3650 Label* if_true = NULL;
3651 Label* if_false = NULL;
3652 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003653 context()->PrepareTest(&materialize_true, &materialize_false,
3654 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003655
3656 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3657 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003658 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003659 Split(eq, if_true, if_false, fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003660
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003661 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003662}
3663
3664
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003665void FullCodeGenerator::EmitGetCachedArrayIndex(CallRuntime* expr) {
3666 ZoneList<Expression*>* args = expr->arguments();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003667 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003668 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003669
3670 if (FLAG_debug_code) {
3671 __ AbortIfNotString(r0);
3672 }
3673
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003674 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3675 __ IndexFromHash(r0, r0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003676
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003677 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003678}
3679
3680
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003681void FullCodeGenerator::EmitFastAsciiArrayJoin(CallRuntime* expr) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003682 Label bailout, done, one_char_separator, long_separator,
3683 non_trivial_array, not_size_one_array, loop,
3684 empty_separator_loop, one_char_separator_loop,
3685 one_char_separator_loop_entry, long_separator_loop;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00003686 ZoneList<Expression*>* args = expr->arguments();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003687 ASSERT(args->length() == 2);
3688 VisitForStackValue(args->at(1));
3689 VisitForAccumulatorValue(args->at(0));
3690
3691 // All aliases of the same register have disjoint lifetimes.
3692 Register array = r0;
3693 Register elements = no_reg; // Will be r0.
3694 Register result = no_reg; // Will be r0.
3695 Register separator = r1;
3696 Register array_length = r2;
3697 Register result_pos = no_reg; // Will be r2
3698 Register string_length = r3;
3699 Register string = r4;
3700 Register element = r5;
3701 Register elements_end = r6;
3702 Register scratch1 = r7;
3703 Register scratch2 = r9;
3704
3705 // Separator operand is on the stack.
3706 __ pop(separator);
3707
3708 // Check that the array is a JSArray.
3709 __ JumpIfSmi(array, &bailout);
3710 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
3711 __ b(ne, &bailout);
3712
3713 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003714 __ CheckFastElements(scratch1, scratch2, &bailout);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003715
3716 // If the array has length zero, return the empty string.
3717 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3718 __ SmiUntag(array_length, SetCC);
3719 __ b(ne, &non_trivial_array);
3720 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
3721 __ b(&done);
3722
3723 __ bind(&non_trivial_array);
3724
3725 // Get the FixedArray containing array's elements.
3726 elements = array;
3727 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3728 array = no_reg; // End of array's live range.
3729
3730 // Check that all array elements are sequential ASCII strings, and
3731 // accumulate the sum of their lengths, as a smi-encoded value.
3732 __ mov(string_length, Operand(0));
3733 __ add(element,
3734 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3735 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3736 // Loop condition: while (element < elements_end).
3737 // Live values in registers:
3738 // elements: Fixed array of strings.
3739 // array_length: Length of the fixed array of strings (not smi)
3740 // separator: Separator string
3741 // string_length: Accumulated sum of string lengths (smi).
3742 // element: Current array element.
3743 // elements_end: Array end.
3744 if (FLAG_debug_code) {
3745 __ cmp(array_length, Operand(0));
3746 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin");
3747 }
3748 __ bind(&loop);
3749 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3750 __ JumpIfSmi(string, &bailout);
3751 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
3752 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3753 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3754 __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003755 __ add(string_length, string_length, Operand(scratch1), SetCC);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003756 __ b(vs, &bailout);
3757 __ cmp(element, elements_end);
3758 __ b(lt, &loop);
3759
3760 // If array_length is 1, return elements[0], a string.
3761 __ cmp(array_length, Operand(1));
3762 __ b(ne, &not_size_one_array);
3763 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
3764 __ b(&done);
3765
3766 __ bind(&not_size_one_array);
3767
3768 // Live values in registers:
3769 // separator: Separator string
3770 // array_length: Length of the array.
3771 // string_length: Sum of string lengths (smi).
3772 // elements: FixedArray of strings.
3773
3774 // Check that the separator is a flat ASCII string.
3775 __ JumpIfSmi(separator, &bailout);
3776 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
3777 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3778 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3779
3780 // Add (separator length times array_length) - separator length to the
3781 // string_length to get the length of the result string. array_length is not
3782 // smi but the other values are, so the result is a smi
3783 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3784 __ sub(string_length, string_length, Operand(scratch1));
3785 __ smull(scratch2, ip, array_length, scratch1);
3786 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3787 // zero.
3788 __ cmp(ip, Operand(0));
3789 __ b(ne, &bailout);
3790 __ tst(scratch2, Operand(0x80000000));
3791 __ b(ne, &bailout);
fschneider@chromium.org7d10be52012-04-10 12:30:14 +00003792 __ add(string_length, string_length, Operand(scratch2), SetCC);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003793 __ b(vs, &bailout);
3794 __ SmiUntag(string_length);
3795
3796 // Get first element in the array to free up the elements register to be used
3797 // for the result.
3798 __ add(element,
3799 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3800 result = elements; // End of live range for elements.
3801 elements = no_reg;
3802 // Live values in registers:
3803 // element: First array element
3804 // separator: Separator string
3805 // string_length: Length of result string (not smi)
3806 // array_length: Length of the array.
3807 __ AllocateAsciiString(result,
3808 string_length,
3809 scratch1,
3810 scratch2,
3811 elements_end,
3812 &bailout);
3813 // Prepare for looping. Set up elements_end to end of the array. Set
3814 // result_pos to the position of the result where to write the first
3815 // character.
3816 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3817 result_pos = array_length; // End of live range for array_length.
3818 array_length = no_reg;
3819 __ add(result_pos,
3820 result,
3821 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3822
3823 // Check the length of the separator.
3824 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3825 __ cmp(scratch1, Operand(Smi::FromInt(1)));
3826 __ b(eq, &one_char_separator);
3827 __ b(gt, &long_separator);
3828
3829 // Empty separator case
3830 __ bind(&empty_separator_loop);
3831 // Live values in registers:
3832 // result_pos: the position to which we are currently copying characters.
3833 // element: Current array element.
3834 // elements_end: Array end.
3835
3836 // Copy next array element to the result.
3837 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3838 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3839 __ SmiUntag(string_length);
3840 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3841 __ CopyBytes(string, result_pos, string_length, scratch1);
3842 __ cmp(element, elements_end);
3843 __ b(lt, &empty_separator_loop); // End while (element < elements_end).
3844 ASSERT(result.is(r0));
3845 __ b(&done);
3846
3847 // One-character separator case
3848 __ bind(&one_char_separator);
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003849 // Replace separator with its ASCII character value.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003850 __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
3851 // Jump into the loop after the code that copies the separator, so the first
3852 // element is not preceded by a separator
3853 __ jmp(&one_char_separator_loop_entry);
3854
3855 __ bind(&one_char_separator_loop);
3856 // Live values in registers:
3857 // result_pos: the position to which we are currently copying characters.
3858 // element: Current array element.
3859 // elements_end: Array end.
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003860 // separator: Single separator ASCII char (in lower byte).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003861
3862 // Copy the separator character to the result.
3863 __ strb(separator, MemOperand(result_pos, 1, PostIndex));
3864
3865 // Copy next array element to the result.
3866 __ bind(&one_char_separator_loop_entry);
3867 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3868 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3869 __ SmiUntag(string_length);
3870 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3871 __ CopyBytes(string, result_pos, string_length, scratch1);
3872 __ cmp(element, elements_end);
3873 __ b(lt, &one_char_separator_loop); // End while (element < elements_end).
3874 ASSERT(result.is(r0));
3875 __ b(&done);
3876
3877 // Long separator case (separator is more than one character). Entry is at the
3878 // label long_separator below.
3879 __ bind(&long_separator_loop);
3880 // Live values in registers:
3881 // result_pos: the position to which we are currently copying characters.
3882 // element: Current array element.
3883 // elements_end: Array end.
3884 // separator: Separator string.
3885
3886 // Copy the separator to the result.
3887 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset));
3888 __ SmiUntag(string_length);
3889 __ add(string,
3890 separator,
3891 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3892 __ CopyBytes(string, result_pos, string_length, scratch1);
3893
3894 __ bind(&long_separator);
3895 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3896 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3897 __ SmiUntag(string_length);
3898 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3899 __ CopyBytes(string, result_pos, string_length, scratch1);
3900 __ cmp(element, elements_end);
3901 __ b(lt, &long_separator_loop); // End while (element < elements_end).
3902 ASSERT(result.is(r0));
3903 __ b(&done);
3904
3905 __ bind(&bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003906 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003907 __ bind(&done);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003908 context()->Plug(r0);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003909}
3910
3911
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003912void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003913 Handle<String> name = expr->name();
3914 if (name->length() > 0 && name->Get(0) == '_') {
3915 Comment cmnt(masm_, "[ InlineRuntimeCall");
3916 EmitInlineRuntimeCall(expr);
3917 return;
3918 }
3919
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003920 Comment cmnt(masm_, "[ CallRuntime");
3921 ZoneList<Expression*>* args = expr->arguments();
3922
3923 if (expr->is_jsruntime()) {
3924 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003925 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003926 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +00003927 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003928 }
3929
3930 // Push the arguments ("left-to-right").
3931 int arg_count = args->length();
3932 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003933 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003934 }
3935
3936 if (expr->is_jsruntime()) {
3937 // Call the JS runtime function.
ager@chromium.org5c838252010-02-19 08:53:10 +00003938 __ mov(r2, Operand(expr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003939 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003940 Handle<Code> ic =
lrn@chromium.org34e60782011-09-15 07:25:40 +00003941 isolate()->stub_cache()->ComputeCallInitialize(arg_count, mode);
danno@chromium.org88aa0582012-03-23 15:11:57 +00003942 CallIC(ic, mode, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003943 // Restore context register.
3944 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003945 } else {
3946 // Call the C runtime function.
3947 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003948 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003949 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003950}
3951
3952
3953void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3954 switch (expr->op()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003955 case Token::DELETE: {
3956 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003957 Property* property = expr->expression()->AsProperty();
3958 VariableProxy* proxy = expr->expression()->AsVariableProxy();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003959
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003960 if (property != NULL) {
3961 VisitForStackValue(property->obj());
3962 VisitForStackValue(property->key());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003963 StrictModeFlag strict_mode_flag = (language_mode() == CLASSIC_MODE)
3964 ? kNonStrictMode : kStrictMode;
3965 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag)));
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003966 __ push(r1);
3967 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
3968 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003969 } else if (proxy != NULL) {
3970 Variable* var = proxy->var();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003971 // Delete of an unqualified identifier is disallowed in strict mode
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003972 // but "delete this" is allowed.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00003973 ASSERT(language_mode() == CLASSIC_MODE || var->is_this());
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003974 if (var->IsUnallocated()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003975 __ ldr(r2, GlobalObjectOperand());
3976 __ mov(r1, Operand(var->name()));
3977 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
3978 __ Push(r2, r1, r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003979 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003980 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003981 } else if (var->IsStackAllocated() || var->IsContextSlot()) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003982 // Result of deleting non-global, non-dynamic variables is false.
3983 // The subexpression does not have side effects.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00003984 context()->Plug(var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003985 } else {
3986 // Non-global variable. Call the runtime to try to delete from the
3987 // context where the variable was introduced.
3988 __ push(context_register());
3989 __ mov(r2, Operand(var->name()));
3990 __ push(r2);
3991 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3992 context()->Plug(r0);
3993 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003994 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003995 // Result of deleting non-property, non-variable reference is true.
3996 // The subexpression may have side effects.
3997 VisitForEffect(expr->expression());
3998 context()->Plug(true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003999 }
4000 break;
4001 }
4002
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004003 case Token::VOID: {
4004 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
4005 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004006 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004007 break;
4008 }
4009
4010 case Token::NOT: {
4011 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004012 if (context()->IsEffect()) {
4013 // Unary NOT has no side effects so it's only necessary to visit the
4014 // subexpression. Match the optimizing compiler by not branching.
4015 VisitForEffect(expr->expression());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004016 } else if (context()->IsTest()) {
4017 const TestContext* test = TestContext::cast(context());
4018 // The labels are swapped for the recursive call.
4019 VisitForControl(expr->expression(),
4020 test->false_label(),
4021 test->true_label(),
4022 test->fall_through());
4023 context()->Plug(test->true_label(), test->false_label());
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004024 } else {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004025 // We handle value contexts explicitly rather than simply visiting
4026 // for control and plugging the control flow into the context,
4027 // because we need to prepare a pair of extra administrative AST ids
4028 // for the optimizing compiler.
4029 ASSERT(context()->IsAccumulatorValue() || context()->IsStackValue());
4030 Label materialize_true, materialize_false, done;
4031 VisitForControl(expr->expression(),
4032 &materialize_false,
4033 &materialize_true,
4034 &materialize_true);
4035 __ bind(&materialize_true);
4036 PrepareForBailoutForId(expr->MaterializeTrueId(), NO_REGISTERS);
4037 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
4038 if (context()->IsStackValue()) __ push(r0);
4039 __ jmp(&done);
4040 __ bind(&materialize_false);
4041 PrepareForBailoutForId(expr->MaterializeFalseId(), NO_REGISTERS);
4042 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
4043 if (context()->IsStackValue()) __ push(r0);
4044 __ bind(&done);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004045 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004046 break;
4047 }
4048
4049 case Token::TYPEOF: {
4050 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004051 { StackValueContext context(this);
4052 VisitForTypeofValue(expr->expression());
4053 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004054 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004055 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004056 break;
4057 }
4058
4059 case Token::ADD: {
4060 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004061 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004062 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00004063 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00004064 ToNumberStub convert_stub;
4065 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004066 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004067 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004068 break;
4069 }
4070
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004071 case Token::SUB:
4072 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004073 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004074
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004075 case Token::BIT_NOT:
4076 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004077 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004078
4079 default:
4080 UNREACHABLE();
4081 }
4082}
4083
4084
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004085void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
4086 const char* comment) {
4087 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
4088 Comment cmt(masm_, comment);
4089 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
4090 UnaryOverwriteMode overwrite =
4091 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00004092 UnaryOpStub stub(expr->op(), overwrite);
4093 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004094 // accumulator register r0.
4095 VisitForAccumulatorValue(expr->expression());
4096 SetSourcePosition(expr->position());
danno@chromium.org88aa0582012-03-23 15:11:57 +00004097 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004098 context()->Plug(r0);
4099}
4100
4101
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004102void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
4103 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004104 SetSourcePosition(expr->position());
4105
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004106 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
4107 // as the left-hand side.
4108 if (!expr->expression()->IsValidLeftHandSide()) {
4109 VisitForEffect(expr->expression());
4110 return;
4111 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004112
4113 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00004114 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004115 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
4116 LhsKind assign_type = VARIABLE;
4117 Property* prop = expr->expression()->AsProperty();
4118 // In case of a property we use the uninitialized expression context
4119 // of the key to detect a named property.
4120 if (prop != NULL) {
4121 assign_type =
4122 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
4123 }
4124
4125 // Evaluate expression and get value.
4126 if (assign_type == VARIABLE) {
4127 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004128 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00004129 EmitVariableLoad(expr->expression()->AsVariableProxy());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004130 } else {
4131 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004132 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004133 __ mov(ip, Operand(Smi::FromInt(0)));
4134 __ push(ip);
4135 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004136 if (assign_type == NAMED_PROPERTY) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004137 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004138 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004139 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004140 EmitNamedPropertyLoad(prop);
4141 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004142 VisitForStackValue(prop->obj());
4143 VisitForAccumulatorValue(prop->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00004144 __ ldr(r1, MemOperand(sp, 0));
4145 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004146 EmitKeyedPropertyLoad(prop);
4147 }
4148 }
4149
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004150 // We need a second deoptimization point after loading the value
4151 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004152 if (assign_type == VARIABLE) {
4153 PrepareForBailout(expr->expression(), TOS_REG);
4154 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00004155 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004156 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004157
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004158 // Call ToNumber only if operand is not a smi.
4159 Label no_conversion;
ager@chromium.org378b34e2011-01-28 08:04:38 +00004160 __ JumpIfSmi(r0, &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00004161 ToNumberStub convert_stub;
4162 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004163 __ bind(&no_conversion);
4164
4165 // Save result for postfix expressions.
4166 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004167 if (!context()->IsEffect()) {
4168 // Save the result on the stack. If we have a named or keyed property
4169 // we store the result under the receiver that is currently on top
4170 // of the stack.
4171 switch (assign_type) {
4172 case VARIABLE:
4173 __ push(r0);
4174 break;
4175 case NAMED_PROPERTY:
4176 __ str(r0, MemOperand(sp, kPointerSize));
4177 break;
4178 case KEYED_PROPERTY:
4179 __ str(r0, MemOperand(sp, 2 * kPointerSize));
4180 break;
4181 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004182 }
4183 }
4184
4185
4186 // Inline smi case if we are in a loop.
4187 Label stub_call, done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004188 JumpPatchSite patch_site(masm_);
4189
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00004190 int count_value = expr->op() == Token::INC ? 1 : -1;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004191 if (ShouldInlineSmiCase(expr->op())) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00004192 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004193 __ b(vs, &stub_call);
4194 // We could eliminate this smi check if we split the code at
4195 // the first smi check before calling ToNumber.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004196 patch_site.EmitJumpIfSmi(r0, &done);
4197
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004198 __ bind(&stub_call);
4199 // Call stub. Undo operation first.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00004200 __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004201 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00004202 __ mov(r1, Operand(Smi::FromInt(count_value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004203
4204 // Record position before stub call.
4205 SetSourcePosition(expr->position());
4206
danno@chromium.org40cb8782011-05-25 07:58:50 +00004207 BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
danno@chromium.org88aa0582012-03-23 15:11:57 +00004208 CallIC(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004209 patch_site.EmitPatchInfo();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004210 __ bind(&done);
4211
4212 // Store the value returned in r0.
4213 switch (assign_type) {
4214 case VARIABLE:
4215 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004216 { EffectContext context(this);
4217 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
4218 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004219 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4220 context.Plug(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004221 }
4222 // For all contexts except EffectConstant We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004223 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004224 if (!context()->IsEffect()) {
4225 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004226 }
4227 } else {
4228 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004229 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004230 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
4231 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004232 }
4233 break;
4234 case NAMED_PROPERTY: {
4235 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
ager@chromium.org5c838252010-02-19 08:53:10 +00004236 __ pop(r1);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004237 Handle<Code> ic = is_classic_mode()
4238 ? isolate()->builtins()->StoreIC_Initialize()
4239 : isolate()->builtins()->StoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00004240 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004241 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004242 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004243 if (!context()->IsEffect()) {
4244 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004245 }
4246 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004247 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004248 }
4249 break;
4250 }
4251 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004252 __ pop(r1); // Key.
4253 __ pop(r2); // Receiver.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004254 Handle<Code> ic = is_classic_mode()
4255 ? isolate()->builtins()->KeyedStoreIC_Initialize()
4256 : isolate()->builtins()->KeyedStoreIC_Initialize_Strict();
danno@chromium.org88aa0582012-03-23 15:11:57 +00004257 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004258 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004259 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004260 if (!context()->IsEffect()) {
4261 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004262 }
4263 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004264 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004265 }
4266 break;
4267 }
4268 }
4269}
4270
4271
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004272void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
4273 ASSERT(!context()->IsEffect());
4274 ASSERT(!context()->IsTest());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004275 VariableProxy* proxy = expr->AsVariableProxy();
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004276 if (proxy != NULL && proxy->var()->IsUnallocated()) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004277 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00004278 __ ldr(r0, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004279 __ mov(r2, Operand(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00004280 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00004281 // Use a regular load, not a contextual load, to avoid a reference
4282 // error.
danno@chromium.org88aa0582012-03-23 15:11:57 +00004283 CallIC(ic);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004284 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004285 context()->Plug(r0);
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004286 } else if (proxy != NULL && proxy->var()->IsLookupSlot()) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004287 Label done, slow;
4288
4289 // Generate code for loading from variables potentially shadowed
4290 // by eval-introduced variables.
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004291 EmitDynamicLookupFastCase(proxy->var(), INSIDE_TYPEOF, &slow, &done);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004292
4293 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004294 __ mov(r0, Operand(proxy->name()));
4295 __ Push(cp, r0);
4296 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004297 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004298 __ bind(&done);
4299
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004300 context()->Plug(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004301 } else {
4302 // This expression cannot throw a reference error at the top level.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004303 VisitInDuplicateContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004304 }
4305}
4306
4307
ager@chromium.org04921a82011-06-27 13:21:41 +00004308void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004309 Expression* sub_expr,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004310 Handle<String> check) {
4311 Label materialize_true, materialize_false;
4312 Label* if_true = NULL;
4313 Label* if_false = NULL;
4314 Label* fall_through = NULL;
4315 context()->PrepareTest(&materialize_true, &materialize_false,
4316 &if_true, &if_false, &fall_through);
4317
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004318 { AccumulatorValueContext context(this);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004319 VisitForTypeofValue(sub_expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004320 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004321 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004322
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004323 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004324 __ JumpIfSmi(r0, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004325 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
4326 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
4327 __ cmp(r0, ip);
4328 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004329 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004330 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004331 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004332 __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
4333 __ b(ge, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004334 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004335 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4336 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004337 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004338 __ CompareRoot(r0, Heap::kTrueValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004339 __ b(eq, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004340 __ CompareRoot(r0, Heap::kFalseValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004341 Split(eq, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004342 } else if (FLAG_harmony_typeof &&
4343 check->Equals(isolate()->heap()->null_symbol())) {
4344 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4345 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004346 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004347 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004348 __ b(eq, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004349 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004350 // Check for undetectable objects => true.
4351 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
4352 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004353 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4354 Split(ne, if_true, if_false, fall_through);
4355
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004356 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004357 __ JumpIfSmi(r0, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004358 STATIC_ASSERT(NUM_OF_CALLABLE_SPEC_OBJECT_TYPES == 2);
4359 __ CompareObjectType(r0, r0, r1, JS_FUNCTION_TYPE);
4360 __ b(eq, if_true);
4361 __ cmp(r1, Operand(JS_FUNCTION_PROXY_TYPE));
4362 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004363 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004364 __ JumpIfSmi(r0, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004365 if (!FLAG_harmony_typeof) {
4366 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4367 __ b(eq, if_true);
4368 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004369 // Check for JS objects => true.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004370 __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
4371 __ b(lt, if_false);
4372 __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4373 __ b(gt, if_false);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004374 // Check for undetectable objects => false.
4375 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
4376 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4377 Split(eq, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004378 } else {
4379 if (if_false != fall_through) __ jmp(if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004380 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004381 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004382}
4383
4384
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004385void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4386 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004387 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004388
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004389 // First we try a fast inlined version of the compare when one of
4390 // the operands is a literal.
4391 if (TryLiteralCompare(expr)) return;
4392
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004393 // Always perform the comparison for its control flow. Pack the result
4394 // into the expression's context after the comparison is performed.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004395 Label materialize_true, materialize_false;
4396 Label* if_true = NULL;
4397 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004398 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004399 context()->PrepareTest(&materialize_true, &materialize_false,
4400 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004401
ager@chromium.org04921a82011-06-27 13:21:41 +00004402 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004403 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004404 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004405 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004406 VisitForStackValue(expr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004407 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004408 PrepareForBailoutBeforeSplit(expr, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004409 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
4410 __ cmp(r0, ip);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004411 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004412 break;
4413
4414 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004415 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004416 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004417 __ CallStub(&stub);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004418 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004419 // The stub returns 0 for true.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004420 __ tst(r0, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004421 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004422 break;
4423 }
4424
4425 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004426 VisitForAccumulatorValue(expr->right());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004427 Condition cond = eq;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004428 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004429 case Token::EQ_STRICT:
ricow@chromium.org65fae842010-08-25 15:26:24 +00004430 case Token::EQ:
ager@chromium.org378b34e2011-01-28 08:04:38 +00004431 cond = eq;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004432 break;
4433 case Token::LT:
ager@chromium.org378b34e2011-01-28 08:04:38 +00004434 cond = lt;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004435 break;
4436 case Token::GT:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004437 cond = gt;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004438 break;
4439 case Token::LTE:
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004440 cond = le;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004441 break;
4442 case Token::GTE:
ager@chromium.org378b34e2011-01-28 08:04:38 +00004443 cond = ge;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004444 break;
4445 case Token::IN:
4446 case Token::INSTANCEOF:
4447 default:
4448 UNREACHABLE();
4449 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004450 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004451
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004452 bool inline_smi_code = ShouldInlineSmiCase(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004453 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004454 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004455 Label slow_case;
4456 __ orr(r2, r0, Operand(r1));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004457 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004458 __ cmp(r1, r0);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004459 Split(cond, if_true, if_false, NULL);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004460 __ bind(&slow_case);
4461 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004462
4463 // Record position and call the compare IC.
4464 SetSourcePosition(expr->position());
4465 Handle<Code> ic = CompareIC::GetUninitialized(op);
danno@chromium.org88aa0582012-03-23 15:11:57 +00004466 CallIC(ic, RelocInfo::CODE_TARGET, expr->id());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004467 patch_site.EmitPatchInfo();
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004468 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004469 __ cmp(r0, Operand(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00004470 Split(cond, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004471 }
4472 }
4473
4474 // Convert the result of the comparison into one expected for this
4475 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004476 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004477}
4478
4479
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004480void FullCodeGenerator::EmitLiteralCompareNil(CompareOperation* expr,
4481 Expression* sub_expr,
4482 NilValue nil) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004483 Label materialize_true, materialize_false;
4484 Label* if_true = NULL;
4485 Label* if_false = NULL;
4486 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004487 context()->PrepareTest(&materialize_true, &materialize_false,
4488 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004489
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004490 VisitForAccumulatorValue(sub_expr);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004491 PrepareForBailoutBeforeSplit(expr, true, if_true, if_false);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004492 Heap::RootListIndex nil_value = nil == kNullValue ?
4493 Heap::kNullValueRootIndex :
4494 Heap::kUndefinedValueRootIndex;
4495 __ LoadRoot(r1, nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004496 __ cmp(r0, r1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004497 if (expr->op() == Token::EQ_STRICT) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004498 Split(eq, if_true, if_false, fall_through);
4499 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004500 Heap::RootListIndex other_nil_value = nil == kNullValue ?
4501 Heap::kUndefinedValueRootIndex :
4502 Heap::kNullValueRootIndex;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004503 __ b(eq, if_true);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004504 __ LoadRoot(r1, other_nil_value);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004505 __ cmp(r0, r1);
4506 __ b(eq, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004507 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004508 // It can be an undetectable object.
4509 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
4510 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
4511 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
4512 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
4513 Split(eq, if_true, if_false, fall_through);
4514 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004515 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004516}
4517
4518
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004519void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4520 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004521 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004522}
4523
4524
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004525Register FullCodeGenerator::result_register() {
4526 return r0;
4527}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004528
4529
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004530Register FullCodeGenerator::context_register() {
4531 return cp;
4532}
4533
4534
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004535void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4536 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4537 __ str(value, MemOperand(fp, frame_offset));
4538}
4539
4540
4541void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004542 __ ldr(dst, ContextOperand(cp, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004543}
4544
4545
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004546void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004547 Scope* declaration_scope = scope()->DeclarationScope();
erik.corry@gmail.comed49e962012-04-17 11:57:53 +00004548 if (declaration_scope->is_global_scope() ||
4549 declaration_scope->is_module_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004550 // Contexts nested in the global context have a canonical empty function
4551 // as their closure, not the anonymous closure containing the global
4552 // code. Pass a smi sentinel and let the runtime look up the empty
4553 // function.
4554 __ mov(ip, Operand(Smi::FromInt(0)));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004555 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004556 // Contexts created by a call to eval have the same closure as the
4557 // context calling eval, not the anonymous closure containing the eval
4558 // code. Fetch it from the context.
4559 __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX));
4560 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004561 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004562 __ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4563 }
4564 __ push(ip);
4565}
4566
4567
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004568// ----------------------------------------------------------------------------
4569// Non-local control flow support.
4570
4571void FullCodeGenerator::EnterFinallyBlock() {
4572 ASSERT(!result_register().is(r1));
4573 // Store result register while executing finally block.
4574 __ push(result_register());
4575 // Cook return address in link register to stack (smi encoded Code* delta)
4576 __ sub(r1, lr, Operand(masm_->CodeObject()));
4577 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00004578 STATIC_ASSERT(kSmiTag == 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004579 __ add(r1, r1, Operand(r1)); // Convert to smi.
4580 __ push(r1);
4581}
4582
4583
4584void FullCodeGenerator::ExitFinallyBlock() {
4585 ASSERT(!result_register().is(r1));
4586 // Restore result register from stack.
4587 __ pop(r1);
4588 // Uncook return address and return.
4589 __ pop(result_register());
4590 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4591 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
4592 __ add(pc, r1, Operand(masm_->CodeObject()));
4593}
4594
4595
4596#undef __
4597
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00004598#define __ ACCESS_MASM(masm())
4599
4600FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
4601 int* stack_depth,
4602 int* context_length) {
4603 // The macros used here must preserve the result register.
4604
4605 // Because the handler block contains the context of the finally
4606 // code, we can restore it directly from there for the finally code
4607 // rather than iteratively unwinding contexts via their previous
4608 // links.
4609 __ Drop(*stack_depth); // Down to the handler block.
4610 if (*context_length > 0) {
4611 // Restore the context to its dedicated register and the stack.
4612 __ ldr(cp, MemOperand(sp, StackHandlerConstants::kContextOffset));
4613 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
4614 }
4615 __ PopTryHandler();
4616 __ bl(finally_entry_);
4617
4618 *stack_depth = 0;
4619 *context_length = 0;
4620 return previous_;
4621}
4622
4623
4624#undef __
4625
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004626} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004627
4628#endif // V8_TARGET_ARCH_ARM