blob: d8ce956ec99cb9e78600607c504197db319e1ca8 [file] [log] [blame]
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001// Copyright 2011 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"
37#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000038#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000039#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040
lrn@chromium.org5d00b602011-01-05 09:51:43 +000041#include "arm/code-stubs-arm.h"
42
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000043namespace v8 {
44namespace internal {
45
46#define __ ACCESS_MASM(masm_)
47
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000048
danno@chromium.org40cb8782011-05-25 07:58:50 +000049static unsigned GetPropertyId(Property* property) {
50 if (property->is_synthetic()) return AstNode::kNoNumber;
51 return property->id();
52}
53
54
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000055// A patch site is a location in the code which it is possible to patch. This
56// class has a number of methods to emit the code which is patchable and the
57// method EmitPatchInfo to record a marker back to the patchable code. This
58// marker is a cmp rx, #yyy instruction, and x * 0x00000fff + yyy (raw 12 bit
59// immediate value is used) is the delta from the pc to the first instruction of
60// the patchable code.
61class JumpPatchSite BASE_EMBEDDED {
62 public:
63 explicit JumpPatchSite(MacroAssembler* masm) : masm_(masm) {
64#ifdef DEBUG
65 info_emitted_ = false;
66#endif
67 }
68
69 ~JumpPatchSite() {
70 ASSERT(patch_site_.is_bound() == info_emitted_);
71 }
72
73 // When initially emitting this ensure that a jump is always generated to skip
74 // the inlined smi code.
75 void EmitJumpIfNotSmi(Register reg, Label* target) {
76 ASSERT(!patch_site_.is_bound() && !info_emitted_);
77 __ bind(&patch_site_);
78 __ cmp(reg, Operand(reg));
79 // Don't use b(al, ...) as that might emit the constant pool right after the
80 // branch. After patching when the branch is no longer unconditional
81 // execution can continue into the constant pool.
82 __ b(eq, target); // Always taken before patched.
83 }
84
85 // When initially emitting this ensure that a jump is never generated to skip
86 // the inlined smi code.
87 void EmitJumpIfSmi(Register reg, Label* target) {
88 ASSERT(!patch_site_.is_bound() && !info_emitted_);
89 __ bind(&patch_site_);
90 __ cmp(reg, Operand(reg));
91 __ b(ne, target); // Never taken before patched.
92 }
93
94 void EmitPatchInfo() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000095 if (patch_site_.is_bound()) {
96 int delta_to_patch_site = masm_->InstructionsGeneratedSince(&patch_site_);
97 Register reg;
98 reg.set_code(delta_to_patch_site / kOff12Mask);
99 __ cmp_raw_immediate(reg, delta_to_patch_site % kOff12Mask);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000100#ifdef DEBUG
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000101 info_emitted_ = true;
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000102#endif
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000103 } else {
104 __ nop(); // Signals no inlined code.
105 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000106 }
107
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000108 private:
109 MacroAssembler* masm_;
110 Label patch_site_;
111#ifdef DEBUG
112 bool info_emitted_;
113#endif
114};
115
116
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000117// Generate code for a JS function. On entry to the function the receiver
118// and arguments have been pushed on the stack left to right. The actual
119// argument count matches the formal parameter count expected by the
120// function.
121//
122// The live registers are:
123// o r1: the JS function object being called (ie, ourselves)
124// o cp: our context
125// o fp: our caller's frame pointer
126// o sp: stack pointer
127// o lr: return address
128//
129// The function builds a JS frame. Please see JavaScriptFrameConstants in
130// frames-arm.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000131void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000132 ASSERT(info_ == NULL);
133 info_ = info;
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000134 scope_ = info->scope();
ager@chromium.org5c838252010-02-19 08:53:10 +0000135 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000136 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000137
vegorov@chromium.org42841962010-10-18 11:18:59 +0000138#ifdef DEBUG
139 if (strlen(FLAG_stop_at) > 0 &&
140 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
141 __ stop("stop-at");
142 }
143#endif
144
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000145 // Strict mode functions and builtins need to replace the receiver
146 // with undefined when called as functions (without an explicit
147 // receiver object). r5 is zero for method calls and non-zero for
148 // function calls.
149 if (info->is_strict_mode() || info->is_native()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000150 Label ok;
151 __ cmp(r5, Operand(0));
152 __ b(eq, &ok);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000153 int receiver_offset = info->scope()->num_parameters() * kPointerSize;
danno@chromium.org40cb8782011-05-25 07:58:50 +0000154 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
155 __ str(r2, MemOperand(sp, receiver_offset));
156 __ bind(&ok);
157 }
158
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000159 int locals_count = info->scope()->num_stack_slots();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000160
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000161 __ Push(lr, fp, cp, r1);
162 if (locals_count > 0) {
163 // Load undefined value here, so the value is ready for the loop
164 // below.
165 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
166 }
167 // Adjust fp to point to caller's fp.
168 __ add(fp, sp, Operand(2 * kPointerSize));
169
170 { Comment cmnt(masm_, "[ Allocate locals");
171 for (int i = 0; i < locals_count; i++) {
172 __ push(ip);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000173 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000174 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000176 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000178 // Possibly allocate a local context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000179 int heap_slots = info->scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000180 if (heap_slots > 0) {
181 Comment cmnt(masm_, "[ Allocate local context");
182 // Argument to NewContext is the function, which is in r1.
183 __ push(r1);
184 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
185 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000186 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000187 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000188 __ CallRuntime(Runtime::kNewFunctionContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000189 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000190 function_in_register = false;
191 // Context is returned in both r0 and cp. It replaces the context
192 // passed to us. It's saved in the stack and kept live in cp.
193 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
194 // Copy any necessary parameters into the context.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000195 int num_parameters = info->scope()->num_parameters();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000196 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000197 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000198 if (slot != NULL && slot->type() == Slot::CONTEXT) {
199 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
200 (num_parameters - 1 - i) * kPointerSize;
201 // Load parameter from stack.
202 __ ldr(r0, MemOperand(fp, parameter_offset));
203 // Store it in the context.
204 __ mov(r1, Operand(Context::SlotOffset(slot->index())));
205 __ str(r0, MemOperand(cp, r1));
206 // Update the write barrier. This clobbers all involved
207 // registers, so we have to use two more registers to avoid
208 // clobbering cp.
209 __ mov(r2, Operand(cp));
210 __ RecordWrite(r2, Operand(r1), r3, r0);
211 }
212 }
213 }
214
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000215 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000216 if (arguments != NULL) {
217 // Function uses arguments object.
218 Comment cmnt(masm_, "[ Allocate arguments object");
219 if (!function_in_register) {
220 // Load this again, if it's used by the local context below.
221 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
222 } else {
223 __ mov(r3, r1);
224 }
225 // Receiver is just before the parameters on the caller's stack.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000226 int num_parameters = info->scope()->num_parameters();
227 int offset = num_parameters * kPointerSize;
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000228 __ add(r2, fp,
229 Operand(StandardFrameConstants::kCallerSPOffset + offset));
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000230 __ mov(r1, Operand(Smi::FromInt(num_parameters)));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000231 __ Push(r3, r2, r1);
232
233 // Arguments to ArgumentsAccessStub:
234 // function, receiver address, parameter count.
235 // The stub will rewrite receiever and parameter count if the previous
236 // stack frame was an arguments adapter frame.
whesse@chromium.org7b260152011-06-20 15:33:18 +0000237 ArgumentsAccessStub::Type type;
238 if (is_strict_mode()) {
239 type = ArgumentsAccessStub::NEW_STRICT;
240 } else if (function()->has_duplicate_parameters()) {
241 type = ArgumentsAccessStub::NEW_NON_STRICT_SLOW;
242 } else {
243 type = ArgumentsAccessStub::NEW_NON_STRICT_FAST;
244 }
245 ArgumentsAccessStub stub(type);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000246 __ CallStub(&stub);
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000247
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000248 Move(arguments->AsSlot(), r0, r1, r2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000249 }
250
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000251 if (FLAG_trace) {
252 __ CallRuntime(Runtime::kTraceEnter, 0);
253 }
254
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000255 // Visit the declarations and body unless there is an illegal
256 // redeclaration.
257 if (scope()->HasIllegalRedeclaration()) {
258 Comment cmnt(masm_, "[ Declarations");
259 scope()->VisitIllegalRedeclaration(this);
260
261 } else {
262 { Comment cmnt(masm_, "[ Declarations");
263 // For named function expressions, declare the function name as a
264 // constant.
265 if (scope()->is_function_scope() && scope()->function() != NULL) {
266 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
267 }
268 VisitDeclarations(scope()->declarations());
269 }
270
271 { Comment cmnt(masm_, "[ Stack check");
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000272 PrepareForBailoutForId(AstNode::kFunctionEntryId, NO_REGISTERS);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000273 Label ok;
274 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
275 __ cmp(sp, Operand(ip));
276 __ b(hs, &ok);
277 StackCheckStub stub;
278 __ CallStub(&stub);
279 __ bind(&ok);
280 }
281
282 { Comment cmnt(masm_, "[ Body");
283 ASSERT(loop_depth() == 0);
284 VisitStatements(function()->body());
285 ASSERT(loop_depth() == 0);
286 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000287 }
288
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000289 // Always emit a 'return undefined' in case control fell off the end of
290 // the body.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000291 { Comment cmnt(masm_, "[ return <undefined>;");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000292 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
293 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000294 EmitReturnSequence();
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000295
296 // Force emit the constant pool, so it doesn't get emitted in the middle
297 // of the stack check table.
298 masm()->CheckConstPool(true, false);
299}
300
301
ager@chromium.org5f0c45f2010-12-17 08:51:21 +0000302void FullCodeGenerator::ClearAccumulator() {
303 __ mov(r0, Operand(Smi::FromInt(0)));
304}
305
306
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000307void FullCodeGenerator::EmitStackCheck(IterationStatement* stmt) {
308 Comment cmnt(masm_, "[ Stack check");
309 Label ok;
310 __ LoadRoot(ip, Heap::kStackLimitRootIndex);
311 __ cmp(sp, Operand(ip));
312 __ b(hs, &ok);
313 StackCheckStub stub;
314 __ CallStub(&stub);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000315 // Record a mapping of this PC offset to the OSR id. This is used to find
316 // the AST id from the unoptimized code in order to use it as a key into
317 // the deoptimization input data found in the optimized code.
318 RecordStackCheck(stmt->OsrEntryId());
319
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000320 __ bind(&ok);
321 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +0000322 // Record a mapping of the OSR id to this PC. This is used if the OSR
323 // entry becomes the target of a bailout. We don't expect it to be, but
324 // we want it to work if it is.
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000325 PrepareForBailoutForId(stmt->OsrEntryId(), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000326}
327
328
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000329void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000330 Comment cmnt(masm_, "[ Return sequence");
331 if (return_label_.is_bound()) {
332 __ b(&return_label_);
333 } else {
334 __ bind(&return_label_);
335 if (FLAG_trace) {
336 // Push the return value on the stack as the parameter.
337 // Runtime::TraceExit returns its parameter in r0.
338 __ push(r0);
339 __ CallRuntime(Runtime::kTraceExit, 1);
340 }
341
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000342#ifdef DEBUG
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000343 // Add a label for checking the size of the code used for returning.
344 Label check_exit_codesize;
345 masm_->bind(&check_exit_codesize);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000346#endif
347 // Make sure that the constant pool is not emitted inside of the return
348 // sequence.
349 { Assembler::BlockConstPoolScope block_const_pool(masm_);
350 // Here we use masm_-> instead of the __ macro to avoid the code coverage
351 // tool from instrumenting as we rely on the code size here.
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000352 int32_t sp_delta = (info_->scope()->num_parameters() + 1) * kPointerSize;
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000353 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000354 __ RecordJSReturn();
355 masm_->mov(sp, fp);
356 masm_->ldm(ia_w, sp, fp.bit() | lr.bit());
357 masm_->add(sp, sp, Operand(sp_delta));
358 masm_->Jump(lr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000359 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000360
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000361#ifdef DEBUG
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000362 // Check that the size of the code used for returning is large enough
363 // for the debugger's requirements.
364 ASSERT(Assembler::kJSReturnSequenceInstructions <=
365 masm_->InstructionsGeneratedSince(&check_exit_codesize));
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000366#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000367 }
368}
369
370
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000371void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
372}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000373
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000374
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000375void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
376 codegen()->Move(result_register(), slot);
377}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000378
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000379
380void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
381 codegen()->Move(result_register(), slot);
382 __ push(result_register());
383}
384
385
386void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
387 // For simplicity we always test the accumulator register.
388 codegen()->Move(result_register(), slot);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000389 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000390 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000391}
392
393
394void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
395}
396
397
398void FullCodeGenerator::AccumulatorValueContext::Plug(
399 Heap::RootListIndex index) const {
400 __ LoadRoot(result_register(), index);
401}
402
403
404void FullCodeGenerator::StackValueContext::Plug(
405 Heap::RootListIndex index) const {
406 __ LoadRoot(result_register(), index);
407 __ push(result_register());
408}
409
410
411void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000412 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
413 true,
414 true_label_,
415 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000416 if (index == Heap::kUndefinedValueRootIndex ||
417 index == Heap::kNullValueRootIndex ||
418 index == Heap::kFalseValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000419 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000420 } else if (index == Heap::kTrueValueRootIndex) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000421 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000422 } else {
423 __ LoadRoot(result_register(), index);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000424 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425 }
426}
427
428
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000429void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
430}
431
432
433void FullCodeGenerator::AccumulatorValueContext::Plug(
434 Handle<Object> lit) const {
435 __ mov(result_register(), Operand(lit));
436}
437
438
439void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000440 // Immediates cannot be pushed directly.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000441 __ mov(result_register(), Operand(lit));
442 __ push(result_register());
443}
444
445
446void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000447 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
448 true,
449 true_label_,
450 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000451 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
452 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000453 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000454 } else if (lit->IsTrue() || lit->IsJSObject()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000455 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000456 } else if (lit->IsString()) {
457 if (String::cast(*lit)->length() == 0) {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000458 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000459 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000460 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000461 }
462 } else if (lit->IsSmi()) {
463 if (Smi::cast(*lit)->value() == 0) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000464 if (false_label_ != fall_through_) __ b(false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000465 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000466 if (true_label_ != fall_through_) __ b(true_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000467 }
468 } else {
469 // For simplicity we always test the accumulator register.
470 __ mov(result_register(), Operand(lit));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000471 codegen()->DoTest(this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000472 }
473}
474
475
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000476void FullCodeGenerator::EffectContext::DropAndPlug(int count,
477 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000478 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000479 __ Drop(count);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000480}
481
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000482
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000483void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
484 int count,
485 Register reg) const {
486 ASSERT(count > 0);
487 __ Drop(count);
488 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000489}
490
491
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000492void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
493 Register reg) const {
494 ASSERT(count > 0);
495 if (count > 1) __ Drop(count - 1);
496 __ str(reg, MemOperand(sp, 0));
497}
498
499
500void FullCodeGenerator::TestContext::DropAndPlug(int count,
501 Register reg) const {
502 ASSERT(count > 0);
503 // For simplicity we always test the accumulator register.
504 __ Drop(count);
505 __ Move(result_register(), reg);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000506 codegen()->PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000507 codegen()->DoTest(this);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000508}
509
510
511void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
512 Label* materialize_false) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000513 ASSERT(materialize_true == materialize_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000514 __ bind(materialize_true);
515}
516
517
518void FullCodeGenerator::AccumulatorValueContext::Plug(
519 Label* materialize_true,
520 Label* materialize_false) const {
521 Label done;
522 __ bind(materialize_true);
523 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
524 __ jmp(&done);
525 __ bind(materialize_false);
526 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
527 __ bind(&done);
528}
529
530
531void FullCodeGenerator::StackValueContext::Plug(
532 Label* materialize_true,
533 Label* materialize_false) const {
534 Label done;
535 __ bind(materialize_true);
536 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
537 __ push(ip);
538 __ jmp(&done);
539 __ bind(materialize_false);
540 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
541 __ push(ip);
542 __ bind(&done);
543}
544
545
546void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
547 Label* materialize_false) const {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000548 ASSERT(materialize_true == true_label_);
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000549 ASSERT(materialize_false == false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000550}
551
552
553void FullCodeGenerator::EffectContext::Plug(bool flag) const {
554}
555
556
557void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
558 Heap::RootListIndex value_root_index =
559 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
560 __ LoadRoot(result_register(), value_root_index);
561}
562
563
564void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
565 Heap::RootListIndex value_root_index =
566 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
567 __ LoadRoot(ip, value_root_index);
568 __ push(ip);
569}
570
571
572void FullCodeGenerator::TestContext::Plug(bool flag) const {
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000573 codegen()->PrepareForBailoutBeforeSplit(TOS_REG,
574 true,
575 true_label_,
576 false_label_);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000577 if (flag) {
578 if (true_label_ != fall_through_) __ b(true_label_);
579 } else {
580 if (false_label_ != fall_through_) __ b(false_label_);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000581 }
582}
583
584
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000585void FullCodeGenerator::DoTest(Expression* condition,
586 Label* if_true,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000587 Label* if_false,
588 Label* fall_through) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000589 if (CpuFeatures::IsSupported(VFP3)) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000590 ToBooleanStub stub(result_register());
591 __ CallStub(&stub);
592 __ tst(result_register(), result_register());
593 } else {
594 // Call the runtime to find the boolean value of the source and then
595 // translate it into control flow to the pair of labels.
596 __ push(result_register());
597 __ CallRuntime(Runtime::kToBool, 1);
598 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
599 __ cmp(r0, ip);
600 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000601 Split(ne, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000602}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000603
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000604
ager@chromium.org378b34e2011-01-28 08:04:38 +0000605void FullCodeGenerator::Split(Condition cond,
ricow@chromium.org65fae842010-08-25 15:26:24 +0000606 Label* if_true,
607 Label* if_false,
608 Label* fall_through) {
609 if (if_false == fall_through) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000610 __ b(cond, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000611 } else if (if_true == fall_through) {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000612 __ b(NegateCondition(cond), if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000613 } else {
ager@chromium.org378b34e2011-01-28 08:04:38 +0000614 __ b(cond, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000615 __ b(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000616 }
617}
618
619
620MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
621 switch (slot->type()) {
622 case Slot::PARAMETER:
623 case Slot::LOCAL:
624 return MemOperand(fp, SlotOffset(slot));
625 case Slot::CONTEXT: {
626 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000627 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000628 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000629 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000630 }
631 case Slot::LOOKUP:
632 UNREACHABLE();
633 }
634 UNREACHABLE();
635 return MemOperand(r0, 0);
636}
637
638
639void FullCodeGenerator::Move(Register destination, Slot* source) {
640 // Use destination as scratch.
641 MemOperand slot_operand = EmitSlotSearch(source, destination);
642 __ ldr(destination, slot_operand);
643}
644
645
646void FullCodeGenerator::Move(Slot* dst,
647 Register src,
648 Register scratch1,
649 Register scratch2) {
650 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
651 ASSERT(!scratch1.is(src) && !scratch2.is(src));
652 MemOperand location = EmitSlotSearch(dst, scratch1);
653 __ str(src, location);
654 // Emit the write barrier code if the location is in the heap.
655 if (dst->type() == Slot::CONTEXT) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000656 __ RecordWrite(scratch1,
657 Operand(Context::SlotOffset(dst->index())),
658 scratch2,
659 src);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000660 }
661}
662
663
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000664void FullCodeGenerator::PrepareForBailoutBeforeSplit(State state,
665 bool should_normalize,
666 Label* if_true,
667 Label* if_false) {
668 // Only prepare for bailouts before splits if we're in a test
669 // context. Otherwise, we let the Visit function deal with the
670 // preparation to avoid preparing with the same AST id twice.
671 if (!context()->IsTest() || !info_->IsOptimizable()) return;
672
673 Label skip;
674 if (should_normalize) __ b(&skip);
675
676 ForwardBailoutStack* current = forward_bailout_stack_;
677 while (current != NULL) {
678 PrepareForBailout(current->expr(), state);
679 current = current->parent();
680 }
681
682 if (should_normalize) {
683 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
684 __ cmp(r0, ip);
685 Split(eq, if_true, if_false, NULL);
686 __ bind(&skip);
687 }
688}
689
690
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000691void FullCodeGenerator::EmitDeclaration(Variable* variable,
692 Variable::Mode mode,
693 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000694 Comment cmnt(masm_, "[ Declaration");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000695 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000696 Slot* slot = variable->AsSlot();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000697 Property* prop = variable->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000698
699 if (slot != NULL) {
700 switch (slot->type()) {
701 case Slot::PARAMETER:
702 case Slot::LOCAL:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000703 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000704 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
705 __ str(ip, MemOperand(fp, SlotOffset(slot)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000706 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000707 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000708 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
709 }
710 break;
711
712 case Slot::CONTEXT:
713 // We bypass the general EmitSlotSearch because we know more about
714 // this specific context.
715
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +0000716 // The variable in the decl always resides in the current function
717 // context.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000718 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000719 if (FLAG_debug_code) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +0000720 // Check that we're not inside a with or catch context.
721 __ ldr(r1, FieldMemOperand(cp, HeapObject::kMapOffset));
722 __ CompareRoot(r1, Heap::kWithContextMapRootIndex);
723 __ Check(ne, "Declaration in with context.");
724 __ CompareRoot(r1, Heap::kCatchContextMapRootIndex);
725 __ Check(ne, "Declaration in catch context.");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000726 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000727 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000728 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000729 __ str(ip, ContextOperand(cp, slot->index()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000730 // No write barrier since the_hole_value is in old space.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000731 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000732 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000733 __ str(result_register(), ContextOperand(cp, slot->index()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000734 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000735 // We know that we have written a function, which is not a smi.
736 __ mov(r1, Operand(cp));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000737 __ RecordWrite(r1, Operand(offset), r2, result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000738 }
739 break;
740
741 case Slot::LOOKUP: {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000742 __ mov(r2, Operand(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000743 // Declaration nodes are always introduced in one of two modes.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000744 ASSERT(mode == Variable::VAR ||
danno@chromium.orgb6451162011-08-17 14:33:23 +0000745 mode == Variable::CONST ||
746 mode == Variable::LET);
747 PropertyAttributes attr = (mode == Variable::CONST) ? READ_ONLY : NONE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000748 __ mov(r1, Operand(Smi::FromInt(attr)));
749 // Push initial value, if any.
750 // Note: For variables we must not push an initial value (such as
751 // 'undefined') because we may have a (legal) redeclaration and we
752 // must not destroy the current value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000753 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000754 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000755 __ Push(cp, r2, r1, r0);
756 } else if (function != NULL) {
757 __ Push(cp, r2, r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000758 // Push initial value for function declaration.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000759 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000760 } else {
761 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000762 __ Push(cp, r2, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000763 }
764 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
765 break;
766 }
767 }
768
769 } else if (prop != NULL) {
danno@chromium.org40cb8782011-05-25 07:58:50 +0000770 // A const declaration aliasing a parameter is an illegal redeclaration.
771 ASSERT(mode != Variable::CONST);
772 if (function != NULL) {
773 // We are declaring a function that rewrites to a property.
774 // Use (keyed) IC to set the initial value. We cannot visit the
775 // rewrite because it's shared and we risk recording duplicate AST
776 // IDs for bailouts from optimized code.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000777 ASSERT(prop->obj()->AsVariableProxy() != NULL);
778 { AccumulatorValueContext for_object(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +0000779 EmitVariableLoad(prop->obj()->AsVariableProxy());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000780 }
danno@chromium.org40cb8782011-05-25 07:58:50 +0000781
782 __ push(r0);
783 VisitForAccumulatorValue(function);
784 __ pop(r2);
785
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +0000786 ASSERT(prop->key()->AsLiteral() != NULL &&
787 prop->key()->AsLiteral()->handle()->IsSmi());
788 __ mov(r1, Operand(prop->key()->AsLiteral()->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000789
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000790 Handle<Code> ic = is_strict_mode()
791 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
792 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000793 __ Call(ic);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000794 // Value in r0 is ignored (declarations are statements).
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000795 }
796 }
797}
798
799
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000800void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
801 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
802}
803
804
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000805void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
806 // Call the runtime to declare the globals.
807 // The context is the first argument.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000808 __ mov(r2, Operand(pairs));
809 __ mov(r1, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
810 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
811 __ Push(cp, r2, r1, r0);
812 __ CallRuntime(Runtime::kDeclareGlobals, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000813 // Return value is ignored.
814}
815
816
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000817void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000818 Comment cmnt(masm_, "[ SwitchStatement");
819 Breakable nested_statement(this, stmt);
820 SetStatementPosition(stmt);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000821
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000822 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000823 VisitForStackValue(stmt->tag());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000824 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
825
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000826 ZoneList<CaseClause*>* clauses = stmt->cases();
827 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
828
829 Label next_test; // Recycled for each test.
830 // Compile all the tests with branches to their bodies.
831 for (int i = 0; i < clauses->length(); i++) {
832 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000833 clause->body_target()->Unuse();
fschneider@chromium.orgd2187832011-01-26 15:44:20 +0000834
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000835 // The default is not a test, but remember it as final fall through.
836 if (clause->is_default()) {
837 default_clause = clause;
838 continue;
839 }
840
841 Comment cmnt(masm_, "[ Case comparison");
842 __ bind(&next_test);
843 next_test.Unuse();
844
845 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000846 VisitForAccumulatorValue(clause->label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000847
ricow@chromium.org65fae842010-08-25 15:26:24 +0000848 // Perform the comparison as if via '==='.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000849 __ ldr(r1, MemOperand(sp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000850 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000851 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000852 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000853 Label slow_case;
854 __ orr(r2, r1, r0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000855 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
856
ricow@chromium.org65fae842010-08-25 15:26:24 +0000857 __ cmp(r1, r0);
858 __ b(ne, &next_test);
859 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000860 __ b(clause->body_target());
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000861 __ bind(&slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000862 }
863
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000864 // Record position before stub call for type feedback.
865 SetSourcePosition(clause->position());
866 Handle<Code> ic = CompareIC::GetUninitialized(Token::EQ_STRICT);
ricow@chromium.org4f693d62011-07-04 14:01:31 +0000867 __ Call(ic, RelocInfo::CODE_TARGET, clause->CompareId());
868 patch_site.EmitPatchInfo();
danno@chromium.org40cb8782011-05-25 07:58:50 +0000869
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +0000870 __ cmp(r0, Operand(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000871 __ b(ne, &next_test);
872 __ Drop(1); // Switch value is no longer needed.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000873 __ b(clause->body_target());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000874 }
875
876 // Discard the test value and jump to the default if present, otherwise to
877 // the end of the statement.
878 __ bind(&next_test);
879 __ Drop(1); // Switch value is no longer needed.
880 if (default_clause == NULL) {
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000881 __ b(nested_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000882 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000883 __ b(default_clause->body_target());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000884 }
885
886 // Compile all the case bodies.
887 for (int i = 0; i < clauses->length(); i++) {
888 Comment cmnt(masm_, "[ Case body");
889 CaseClause* clause = clauses->at(i);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +0000890 __ bind(clause->body_target());
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000891 PrepareForBailoutForId(clause->EntryId(), NO_REGISTERS);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000892 VisitStatements(clause->statements());
893 }
894
rossberg@chromium.org28a37082011-08-22 11:03:23 +0000895 __ bind(nested_statement.break_label());
kasperl@chromium.orga5551262010-12-07 12:49:48 +0000896 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000897}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000898
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000899
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000900void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000901 Comment cmnt(masm_, "[ ForInStatement");
902 SetStatementPosition(stmt);
903
904 Label loop, exit;
905 ForIn loop_statement(this, stmt);
906 increment_loop_depth();
907
908 // Get the object to enumerate over. Both SpiderMonkey and JSC
909 // ignore null and undefined in contrast to the specification; see
910 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000911 VisitForAccumulatorValue(stmt->enumerable());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000912 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
913 __ cmp(r0, ip);
914 __ b(eq, &exit);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000915 Register null_value = r5;
916 __ LoadRoot(null_value, Heap::kNullValueRootIndex);
917 __ cmp(r0, null_value);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000918 __ b(eq, &exit);
919
920 // Convert the object to a JS object.
921 Label convert, done_convert;
ager@chromium.org378b34e2011-01-28 08:04:38 +0000922 __ JumpIfSmi(r0, &convert);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +0000923 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
924 __ b(ge, &done_convert);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000925 __ bind(&convert);
926 __ push(r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +0000927 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000928 __ bind(&done_convert);
929 __ push(r0);
930
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000931 // Check cache validity in generated code. This is a fast case for
932 // the JSObject::IsSimpleEnum cache validity checks. If we cannot
933 // guarantee cache validity, call the runtime system to check cache
934 // validity or get the property names in a fixed array.
935 Label next, call_runtime;
936 // Preload a couple of values used in the loop.
937 Register empty_fixed_array_value = r6;
938 __ LoadRoot(empty_fixed_array_value, Heap::kEmptyFixedArrayRootIndex);
939 Register empty_descriptor_array_value = r7;
940 __ LoadRoot(empty_descriptor_array_value,
941 Heap::kEmptyDescriptorArrayRootIndex);
942 __ mov(r1, r0);
943 __ bind(&next);
944
945 // Check that there are no elements. Register r1 contains the
946 // current JS object we've reached through the prototype chain.
947 __ ldr(r2, FieldMemOperand(r1, JSObject::kElementsOffset));
948 __ cmp(r2, empty_fixed_array_value);
949 __ b(ne, &call_runtime);
950
951 // Check that instance descriptors are not empty so that we can
952 // check for an enum cache. Leave the map in r2 for the subsequent
953 // prototype load.
954 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
danno@chromium.org40cb8782011-05-25 07:58:50 +0000955 __ ldr(r3, FieldMemOperand(r2, Map::kInstanceDescriptorsOrBitField3Offset));
956 __ JumpIfSmi(r3, &call_runtime);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000957
958 // Check that there is an enum cache in the non-empty instance
959 // descriptors (r3). This is the case if the next enumeration
960 // index field does not contain a smi.
961 __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumerationIndexOffset));
962 __ JumpIfSmi(r3, &call_runtime);
963
964 // For all objects but the receiver, check that the cache is empty.
965 Label check_prototype;
966 __ cmp(r1, r0);
967 __ b(eq, &check_prototype);
968 __ ldr(r3, FieldMemOperand(r3, DescriptorArray::kEnumCacheBridgeCacheOffset));
969 __ cmp(r3, empty_fixed_array_value);
970 __ b(ne, &call_runtime);
971
972 // Load the prototype from the map and loop if non-null.
973 __ bind(&check_prototype);
974 __ ldr(r1, FieldMemOperand(r2, Map::kPrototypeOffset));
975 __ cmp(r1, null_value);
976 __ b(ne, &next);
977
978 // The enum cache is valid. Load the map of the object being
979 // iterated over and use the cache for the iteration.
980 Label use_cache;
981 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
982 __ b(&use_cache);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000983
984 // Get the set of properties to enumerate.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +0000985 __ bind(&call_runtime);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000986 __ push(r0); // Duplicate the enumerable object on the stack.
987 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
988
989 // If we got a map from the runtime call, we can do a fast
990 // modification check. Otherwise, we got a fixed array, and we have
991 // to do a slow check.
992 Label fixed_array;
993 __ mov(r2, r0);
994 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
995 __ LoadRoot(ip, Heap::kMetaMapRootIndex);
996 __ cmp(r1, ip);
997 __ b(ne, &fixed_array);
998
999 // We got a map in register r0. Get the enumeration cache from it.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001000 __ bind(&use_cache);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001001 __ LoadInstanceDescriptors(r0, r1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001002 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
1003 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
1004
1005 // Setup the four remaining stack slots.
1006 __ push(r0); // Map.
1007 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001008 __ mov(r0, Operand(Smi::FromInt(0)));
1009 // Push enumeration cache, enumeration cache length (as smi) and zero.
1010 __ Push(r2, r1, r0);
1011 __ jmp(&loop);
1012
1013 // We got a fixed array in register r0. Iterate through that.
1014 __ bind(&fixed_array);
1015 __ mov(r1, Operand(Smi::FromInt(0))); // Map (0) - force slow check.
1016 __ Push(r1, r0);
1017 __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001018 __ mov(r0, Operand(Smi::FromInt(0)));
1019 __ Push(r1, r0); // Fixed array length (as smi) and initial index.
1020
1021 // Generate code for doing the condition check.
1022 __ bind(&loop);
1023 // Load the current count to r0, load the length to r1.
1024 __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
1025 __ cmp(r0, r1); // Compare to the array length.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001026 __ b(hs, loop_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001027
1028 // Get the current entry of the array into register r3.
1029 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
1030 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1031 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1032
1033 // Get the expected map from the stack or a zero map in the
1034 // permanent slow case into register r2.
1035 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
1036
1037 // Check if the expected map still matches that of the enumerable.
1038 // If not, we have to filter the key.
1039 Label update_each;
1040 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
1041 __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
1042 __ cmp(r4, Operand(r2));
1043 __ b(eq, &update_each);
1044
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001045 // Convert the entry to a string or (smi) 0 if it isn't a property
1046 // any more. If the property has been removed while iterating, we
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001047 // just skip it.
1048 __ push(r1); // Enumerable.
1049 __ push(r3); // Current entry.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001050 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001051 __ mov(r3, Operand(r0), SetCC);
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001052 __ b(eq, loop_statement.continue_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001053
1054 // Update the 'each' property or variable from the possibly filtered
1055 // entry in register r3.
1056 __ bind(&update_each);
1057 __ mov(result_register(), r3);
1058 // Perform the assignment as if via '='.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001059 { EffectContext context(this);
1060 EmitAssignment(stmt->each(), stmt->AssignmentId());
1061 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001062
1063 // Generate code for the body of the loop.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001064 Visit(stmt->body());
1065
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001066 // Generate code for the going to the next element by incrementing
1067 // the index (smi) stored on top of the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001068 __ bind(loop_statement.continue_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001069 __ pop(r0);
1070 __ add(r0, r0, Operand(Smi::FromInt(1)));
1071 __ push(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001072
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001073 EmitStackCheck(stmt);
1074 __ b(&loop);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001075
1076 // Remove the pointers stored on the stack.
rossberg@chromium.org28a37082011-08-22 11:03:23 +00001077 __ bind(loop_statement.break_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001078 __ Drop(5);
1079
1080 // Exit and decrement the loop depth.
1081 __ bind(&exit);
1082 decrement_loop_depth();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001083}
1084
1085
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001086void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1087 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001088 // Use the fast case closure allocation code that allocates in new
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001089 // space for nested functions that don't need literals cloning. If
1090 // we're running with the --always-opt or the --prepare-always-opt
1091 // flag, we need to use the runtime function so that the new function
1092 // we are creating here gets a chance to have its code optimized and
1093 // doesn't just get a copy of the existing unoptimized code.
1094 if (!FLAG_always_opt &&
1095 !FLAG_prepare_always_opt &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001096 !pretenure &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001097 scope()->is_function_scope() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 info->num_literals() == 0) {
1099 FastNewClosureStub stub(info->strict_mode() ? kStrictMode : kNonStrictMode);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001100 __ mov(r0, Operand(info));
1101 __ push(r0);
1102 __ CallStub(&stub);
1103 } else {
1104 __ mov(r0, Operand(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001105 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
1106 : Heap::kFalseValueRootIndex);
1107 __ Push(cp, r0, r1);
1108 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001109 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001110 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001111}
1112
1113
1114void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1115 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001116 EmitVariableLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001117}
1118
1119
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001120void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
1121 Slot* slot,
1122 TypeofState typeof_state,
1123 Label* slow) {
1124 Register current = cp;
1125 Register next = r1;
1126 Register temp = r2;
1127
1128 Scope* s = scope();
1129 while (s != NULL) {
1130 if (s->num_heap_slots() > 0) {
1131 if (s->calls_eval()) {
1132 // Check that extension is NULL.
1133 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
1134 __ tst(temp, temp);
1135 __ b(ne, slow);
1136 }
1137 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001138 __ ldr(next, ContextOperand(current, Context::PREVIOUS_INDEX));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001139 // Walk the rest of the chain without clobbering cp.
1140 current = next;
1141 }
1142 // If no outer scope calls eval, we do not need to check more
1143 // context extensions.
1144 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1145 s = s->outer_scope();
1146 }
1147
1148 if (s->is_eval_scope()) {
1149 Label loop, fast;
1150 if (!current.is(next)) {
1151 __ Move(next, current);
1152 }
1153 __ bind(&loop);
1154 // Terminate at global context.
1155 __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset));
1156 __ LoadRoot(ip, Heap::kGlobalContextMapRootIndex);
1157 __ cmp(temp, ip);
1158 __ b(eq, &fast);
1159 // Check that extension is NULL.
1160 __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX));
1161 __ tst(temp, temp);
1162 __ b(ne, slow);
1163 // Load next context in chain.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001164 __ ldr(next, ContextOperand(next, Context::PREVIOUS_INDEX));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001165 __ b(&loop);
1166 __ bind(&fast);
1167 }
1168
1169 __ ldr(r0, GlobalObjectOperand());
1170 __ mov(r2, Operand(slot->var()->name()));
1171 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1172 ? RelocInfo::CODE_TARGET
1173 : RelocInfo::CODE_TARGET_CONTEXT;
1174 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001175 __ Call(ic, mode);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001176}
1177
1178
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001179MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
1180 Slot* slot,
1181 Label* slow) {
1182 ASSERT(slot->type() == Slot::CONTEXT);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001183 Register context = cp;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001184 Register next = r3;
1185 Register temp = r4;
1186
1187 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
1188 if (s->num_heap_slots() > 0) {
1189 if (s->calls_eval()) {
1190 // Check that extension is NULL.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001191 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001192 __ tst(temp, temp);
1193 __ b(ne, slow);
1194 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001195 __ ldr(next, ContextOperand(context, Context::PREVIOUS_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001196 // Walk the rest of the chain without clobbering cp.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001197 context = next;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001198 }
1199 }
1200 // Check that last extension is NULL.
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001201 __ ldr(temp, ContextOperand(context, Context::EXTENSION_INDEX));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001202 __ tst(temp, temp);
1203 __ b(ne, slow);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001204
1205 // This function is used only for loads, not stores, so it's safe to
1206 // return an cp-based operand (the write barrier cannot be allowed to
1207 // destroy the cp register).
1208 return ContextOperand(context, slot->index());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001209}
1210
1211
1212void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
1213 Slot* slot,
1214 TypeofState typeof_state,
1215 Label* slow,
1216 Label* done) {
1217 // Generate fast-case code for variables that might be shadowed by
1218 // eval-introduced variables. Eval is used a lot without
1219 // introducing variables. In those cases, we do not want to
1220 // perform a runtime call for all variables in the scope
1221 // containing the eval.
1222 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
1223 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
1224 __ jmp(done);
1225 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001226 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001227 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
1228 if (potential_slot != NULL) {
1229 // Generate fast case for locals that rewrite to slots.
1230 __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow));
1231 if (potential_slot->var()->mode() == Variable::CONST) {
1232 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1233 __ cmp(r0, ip);
1234 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1235 }
1236 __ jmp(done);
1237 } else if (rewrite != NULL) {
1238 // Generate fast case for calls of an argument function.
1239 Property* property = rewrite->AsProperty();
1240 if (property != NULL) {
1241 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
1242 Literal* key_literal = property->key()->AsLiteral();
1243 if (obj_proxy != NULL &&
1244 key_literal != NULL &&
1245 obj_proxy->IsArguments() &&
1246 key_literal->handle()->IsSmi()) {
1247 // Load arguments object if there are no eval-introduced
1248 // variables. Then load the argument from the arguments
1249 // object using keyed load.
1250 __ ldr(r1,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001251 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001252 slow));
1253 __ mov(r0, Operand(key_literal->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001254 Handle<Code> ic =
1255 isolate()->builtins()->KeyedLoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001256 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(property));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001257 __ jmp(done);
1258 }
1259 }
1260 }
1261 }
1262}
1263
1264
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001265void FullCodeGenerator::EmitVariableLoad(VariableProxy* proxy) {
1266 // Record position before possible IC call.
1267 SetSourcePosition(proxy->position());
1268 Variable* var = proxy->var();
1269
whesse@chromium.org7b260152011-06-20 15:33:18 +00001270 // Three cases: non-this global variables, lookup slots, and all other
1271 // types of slots.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001272 Slot* slot = var->AsSlot();
whesse@chromium.org7b260152011-06-20 15:33:18 +00001273 ASSERT((var->is_global() && !var->is_this()) == (slot == NULL));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001274
whesse@chromium.org7b260152011-06-20 15:33:18 +00001275 if (slot == NULL) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001276 Comment cmnt(masm_, "Global variable");
1277 // Use inline caching. Variable name is passed in r2 and the global
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001278 // object (receiver) in r0.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001279 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001280 __ mov(r2, Operand(var->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001281 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001282 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001283 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001284
whesse@chromium.org7b260152011-06-20 15:33:18 +00001285 } else if (slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001286 Label done, slow;
1287
1288 // Generate code for loading from variables potentially shadowed
1289 // by eval-introduced variables.
1290 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1291
1292 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001293 Comment cmnt(masm_, "Lookup slot");
1294 __ mov(r1, Operand(var->name()));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001295 __ Push(cp, r1); // Context and name.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001296 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001297 __ bind(&done);
1298
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001299 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001300
whesse@chromium.org7b260152011-06-20 15:33:18 +00001301 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001302 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1303 ? "Context slot"
1304 : "Stack slot");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001305 if (var->mode() == Variable::CONST) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001306 // Constants may be the hole value if they have not been initialized.
1307 // Unhole them.
1308 MemOperand slot_operand = EmitSlotSearch(slot, r0);
1309 __ ldr(r0, slot_operand);
1310 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1311 __ cmp(r0, ip);
1312 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1313 context()->Plug(r0);
1314 } else {
1315 context()->Plug(slot);
1316 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001317 }
1318}
1319
1320
1321void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1322 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001323 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001324 // Registers will be used as follows:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001325 // r5 = materialized value (RegExp literal)
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001326 // r4 = JS function, literals array
1327 // r3 = literal index
1328 // r2 = RegExp pattern
1329 // r1 = RegExp flags
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001330 // r0 = RegExp literal clone
ricow@chromium.org65fae842010-08-25 15:26:24 +00001331 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1332 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001333 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001334 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001335 __ ldr(r5, FieldMemOperand(r4, literal_offset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001336 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001337 __ cmp(r5, ip);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001338 __ b(ne, &materialized);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001339
1340 // Create regexp literal using runtime function.
1341 // Result will be in r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001342 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1343 __ mov(r2, Operand(expr->pattern()));
1344 __ mov(r1, Operand(expr->flags()));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001345 __ Push(r4, r3, r2, r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001346 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001347 __ mov(r5, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001348
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001349 __ bind(&materialized);
1350 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001351 Label allocated, runtime_allocate;
1352 __ AllocateInNewSpace(size, r0, r2, r3, &runtime_allocate, TAG_OBJECT);
1353 __ jmp(&allocated);
1354
1355 __ bind(&runtime_allocate);
1356 __ push(r5);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001357 __ mov(r0, Operand(Smi::FromInt(size)));
1358 __ push(r0);
1359 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001360 __ pop(r5);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001361
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001362 __ bind(&allocated);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001363 // After this, registers are used as follows:
1364 // r0: Newly allocated regexp.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001365 // r5: Materialized regexp.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001366 // r2: temp.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00001367 __ CopyFields(r0, r5, r2.bit(), size / kPointerSize);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001368 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001369}
1370
1371
1372void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1373 Comment cmnt(masm_, "[ ObjectLiteral");
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001374 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1375 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1376 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1377 __ mov(r1, Operand(expr->constant_properties()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001378 int flags = expr->fast_elements()
1379 ? ObjectLiteral::kFastElements
1380 : ObjectLiteral::kNoFlags;
1381 flags |= expr->has_function()
1382 ? ObjectLiteral::kHasFunction
1383 : ObjectLiteral::kNoFlags;
1384 __ mov(r0, Operand(Smi::FromInt(flags)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001385 __ Push(r3, r2, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001386 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001387 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001388 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001389 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001390 }
1391
1392 // If result_saved is true the result is on top of the stack. If
1393 // result_saved is false the result is in r0.
1394 bool result_saved = false;
1395
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001396 // Mark all computed expressions that are bound to a key that
1397 // is shadowed by a later occurrence of the same key. For the
1398 // marked expressions, no store code is emitted.
1399 expr->CalculateEmitStore();
1400
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001401 for (int i = 0; i < expr->properties()->length(); i++) {
1402 ObjectLiteral::Property* property = expr->properties()->at(i);
1403 if (property->IsCompileTimeValue()) continue;
1404
1405 Literal* key = property->key();
1406 Expression* value = property->value();
1407 if (!result_saved) {
1408 __ push(r0); // Save result on stack
1409 result_saved = true;
1410 }
1411 switch (property->kind()) {
1412 case ObjectLiteral::Property::CONSTANT:
1413 UNREACHABLE();
1414 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1415 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
1416 // Fall through.
1417 case ObjectLiteral::Property::COMPUTED:
1418 if (key->handle()->IsSymbol()) {
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001419 if (property->emit_store()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001420 VisitForAccumulatorValue(value);
1421 __ mov(r2, Operand(key->handle()));
1422 __ ldr(r1, MemOperand(sp));
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001423 Handle<Code> ic = is_strict_mode()
1424 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1425 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001426 __ Call(ic, RelocInfo::CODE_TARGET, key->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001427 PrepareForBailoutForId(key->id(), NO_REGISTERS);
1428 } else {
1429 VisitForEffect(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001430 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001431 break;
1432 }
1433 // Fall through.
1434 case ObjectLiteral::Property::PROTOTYPE:
1435 // Duplicate receiver on stack.
1436 __ ldr(r0, MemOperand(sp));
1437 __ push(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001438 VisitForStackValue(key);
1439 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001440 if (property->emit_store()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001441 __ mov(r0, Operand(Smi::FromInt(NONE))); // PropertyAttributes
1442 __ push(r0);
1443 __ CallRuntime(Runtime::kSetProperty, 4);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001444 } else {
1445 __ Drop(3);
1446 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001447 break;
1448 case ObjectLiteral::Property::GETTER:
1449 case ObjectLiteral::Property::SETTER:
1450 // Duplicate receiver on stack.
1451 __ ldr(r0, MemOperand(sp));
1452 __ push(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001453 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001454 __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
1455 Smi::FromInt(1) :
1456 Smi::FromInt(0)));
1457 __ push(r1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001458 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001459 __ CallRuntime(Runtime::kDefineAccessor, 4);
1460 break;
1461 }
1462 }
1463
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001464 if (expr->has_function()) {
1465 ASSERT(result_saved);
1466 __ ldr(r0, MemOperand(sp));
1467 __ push(r0);
1468 __ CallRuntime(Runtime::kToFastProperties, 1);
1469 }
1470
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001471 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001472 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001473 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001474 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001475 }
1476}
1477
1478
1479void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1480 Comment cmnt(masm_, "[ ArrayLiteral");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001481
1482 ZoneList<Expression*>* subexprs = expr->values();
1483 int length = subexprs->length();
1484
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001485 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1486 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1487 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1488 __ mov(r1, Operand(expr->constant_elements()));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001489 __ Push(r3, r2, r1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001490 if (expr->constant_elements()->map() ==
1491 isolate()->heap()->fixed_cow_array_map()) {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001492 FastCloneShallowArrayStub stub(
1493 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1494 __ CallStub(&stub);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001495 __ IncrementCounter(
1496 isolate()->counters()->cow_arrays_created_stub(), 1, r1, r2);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001497 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001498 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001499 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001500 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001501 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001502 FastCloneShallowArrayStub stub(
1503 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001504 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001505 }
1506
1507 bool result_saved = false; // Is the result saved to the stack?
1508
1509 // Emit code to evaluate all the non-constant subexpressions and to store
1510 // them into the newly cloned array.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001511 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001512 Expression* subexpr = subexprs->at(i);
1513 // If the subexpression is a literal or a simple materialized literal it
1514 // is already set in the cloned array.
1515 if (subexpr->AsLiteral() != NULL ||
1516 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1517 continue;
1518 }
1519
1520 if (!result_saved) {
1521 __ push(r0);
1522 result_saved = true;
1523 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001524 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001525
1526 // Store the subexpression value in the array's elements.
1527 __ ldr(r1, MemOperand(sp)); // Copy of array literal.
1528 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
1529 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1530 __ str(result_register(), FieldMemOperand(r1, offset));
1531
1532 // Update the write barrier for the array store with r0 as the scratch
1533 // register.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001534 __ RecordWrite(r1, Operand(offset), r2, result_register());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001535
1536 PrepareForBailoutForId(expr->GetIdForElement(i), NO_REGISTERS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001537 }
1538
1539 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001540 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001541 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001542 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001543 }
1544}
1545
1546
ager@chromium.org5c838252010-02-19 08:53:10 +00001547void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1548 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001549 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1550 // on the left-hand side.
1551 if (!expr->target()->IsValidLeftHandSide()) {
1552 VisitForEffect(expr->target());
1553 return;
1554 }
1555
ager@chromium.org5c838252010-02-19 08:53:10 +00001556 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001557 // slot.
ager@chromium.org5c838252010-02-19 08:53:10 +00001558 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1559 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001560 Property* property = expr->target()->AsProperty();
1561 if (property != NULL) {
1562 assign_type = (property->key()->IsPropertyName())
1563 ? NAMED_PROPERTY
1564 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001565 }
1566
1567 // Evaluate LHS expression.
1568 switch (assign_type) {
1569 case VARIABLE:
1570 // Nothing to do here.
1571 break;
1572 case NAMED_PROPERTY:
1573 if (expr->is_compound()) {
1574 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001575 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001576 __ push(result_register());
1577 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001578 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001579 }
1580 break;
1581 case KEYED_PROPERTY:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001582 if (expr->is_compound()) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001583 VisitForStackValue(property->obj());
1584 VisitForAccumulatorValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001585 __ ldr(r1, MemOperand(sp, 0));
1586 __ push(r0);
1587 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00001588 VisitForStackValue(property->obj());
1589 VisitForStackValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001590 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001591 break;
1592 }
1593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001594 // For compound assignments we need another deoptimization point after the
1595 // variable/property load.
ager@chromium.org5c838252010-02-19 08:53:10 +00001596 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001597 { AccumulatorValueContext context(this);
1598 switch (assign_type) {
1599 case VARIABLE:
whesse@chromium.org030d38e2011-07-13 13:23:34 +00001600 EmitVariableLoad(expr->target()->AsVariableProxy());
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001601 PrepareForBailout(expr->target(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001602 break;
1603 case NAMED_PROPERTY:
1604 EmitNamedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001605 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001606 break;
1607 case KEYED_PROPERTY:
1608 EmitKeyedPropertyLoad(property);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001609 PrepareForBailoutForId(expr->CompoundLoadId(), TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001610 break;
1611 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001612 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001613
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001614 Token::Value op = expr->binary_op();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001615 __ push(r0); // Left operand goes on the stack.
1616 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001617
ricow@chromium.org65fae842010-08-25 15:26:24 +00001618 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1619 ? OVERWRITE_RIGHT
1620 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001621 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001622 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001623 if (ShouldInlineSmiCase(op)) {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001624 EmitInlineSmiBinaryOp(expr->binary_operation(),
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001625 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001626 mode,
1627 expr->target(),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001628 expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001629 } else {
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001630 EmitBinaryOp(expr->binary_operation(), op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001631 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00001632
1633 // Deoptimization point in case the binary operation may have side effects.
1634 PrepareForBailout(expr->binary_operation(), TOS_REG);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001635 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001636 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001637 }
1638
1639 // Record source position before possible IC call.
1640 SetSourcePosition(expr->position());
1641
1642 // Store the value.
1643 switch (assign_type) {
1644 case VARIABLE:
1645 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001646 expr->op());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001647 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1648 context()->Plug(r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001649 break;
1650 case NAMED_PROPERTY:
1651 EmitNamedPropertyAssignment(expr);
1652 break;
1653 case KEYED_PROPERTY:
1654 EmitKeyedPropertyAssignment(expr);
1655 break;
1656 }
1657}
1658
1659
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001660void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1661 SetSourcePosition(prop->position());
1662 Literal* key = prop->key()->AsLiteral();
1663 __ mov(r2, Operand(key->handle()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001664 // Call load IC. It has arguments receiver and property name r0 and r2.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001665 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001666 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001667}
1668
1669
1670void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1671 SetSourcePosition(prop->position());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001672 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001673 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001674 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001675}
1676
1677
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001678void FullCodeGenerator::EmitInlineSmiBinaryOp(BinaryOperation* expr,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001679 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001680 OverwriteMode mode,
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001681 Expression* left_expr,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001682 Expression* right_expr) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001683 Label done, smi_case, stub_call;
1684
1685 Register scratch1 = r2;
1686 Register scratch2 = r3;
1687
1688 // Get the arguments.
1689 Register left = r1;
1690 Register right = r0;
1691 __ pop(left);
1692
1693 // Perform combined smi check on both operands.
1694 __ orr(scratch1, left, Operand(right));
1695 STATIC_ASSERT(kSmiTag == 0);
1696 JumpPatchSite patch_site(masm_);
1697 patch_site.EmitJumpIfSmi(scratch1, &smi_case);
1698
1699 __ bind(&stub_call);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001700 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001701 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1702 patch_site.EmitPatchInfo();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001703 __ jmp(&done);
1704
1705 __ bind(&smi_case);
1706 // Smi case. This code works the same way as the smi-smi case in the type
1707 // recording binary operation stub, see
danno@chromium.org40cb8782011-05-25 07:58:50 +00001708 // BinaryOpStub::GenerateSmiSmiOperation for comments.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00001709 switch (op) {
1710 case Token::SAR:
1711 __ b(&stub_call);
1712 __ GetLeastBitsFromSmi(scratch1, right, 5);
1713 __ mov(right, Operand(left, ASR, scratch1));
1714 __ bic(right, right, Operand(kSmiTagMask));
1715 break;
1716 case Token::SHL: {
1717 __ b(&stub_call);
1718 __ SmiUntag(scratch1, left);
1719 __ GetLeastBitsFromSmi(scratch2, right, 5);
1720 __ mov(scratch1, Operand(scratch1, LSL, scratch2));
1721 __ add(scratch2, scratch1, Operand(0x40000000), SetCC);
1722 __ b(mi, &stub_call);
1723 __ SmiTag(right, scratch1);
1724 break;
1725 }
1726 case Token::SHR: {
1727 __ b(&stub_call);
1728 __ SmiUntag(scratch1, left);
1729 __ GetLeastBitsFromSmi(scratch2, right, 5);
1730 __ mov(scratch1, Operand(scratch1, LSR, scratch2));
1731 __ tst(scratch1, Operand(0xc0000000));
1732 __ b(ne, &stub_call);
1733 __ SmiTag(right, scratch1);
1734 break;
1735 }
1736 case Token::ADD:
1737 __ add(scratch1, left, Operand(right), SetCC);
1738 __ b(vs, &stub_call);
1739 __ mov(right, scratch1);
1740 break;
1741 case Token::SUB:
1742 __ sub(scratch1, left, Operand(right), SetCC);
1743 __ b(vs, &stub_call);
1744 __ mov(right, scratch1);
1745 break;
1746 case Token::MUL: {
1747 __ SmiUntag(ip, right);
1748 __ smull(scratch1, scratch2, left, ip);
1749 __ mov(ip, Operand(scratch1, ASR, 31));
1750 __ cmp(ip, Operand(scratch2));
1751 __ b(ne, &stub_call);
1752 __ tst(scratch1, Operand(scratch1));
1753 __ mov(right, Operand(scratch1), LeaveCC, ne);
1754 __ b(ne, &done);
1755 __ add(scratch2, right, Operand(left), SetCC);
1756 __ mov(right, Operand(Smi::FromInt(0)), LeaveCC, pl);
1757 __ b(mi, &stub_call);
1758 break;
1759 }
1760 case Token::BIT_OR:
1761 __ orr(right, left, Operand(right));
1762 break;
1763 case Token::BIT_AND:
1764 __ and_(right, left, Operand(right));
1765 break;
1766 case Token::BIT_XOR:
1767 __ eor(right, left, Operand(right));
1768 break;
1769 default:
1770 UNREACHABLE();
1771 }
1772
1773 __ bind(&done);
1774 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001775}
1776
1777
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00001778void FullCodeGenerator::EmitBinaryOp(BinaryOperation* expr,
1779 Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001780 OverwriteMode mode) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001781 __ pop(r1);
danno@chromium.org40cb8782011-05-25 07:58:50 +00001782 BinaryOpStub stub(op, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001783 JumpPatchSite patch_site(masm_); // unbound, signals no inlined smi code.
1784 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
1785 patch_site.EmitPatchInfo();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001786 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001787}
1788
1789
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001790void FullCodeGenerator::EmitAssignment(Expression* expr, int bailout_ast_id) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001791 // Invalid left-hand sides are rewritten to have a 'throw
1792 // ReferenceError' on the left-hand side.
1793 if (!expr->IsValidLeftHandSide()) {
1794 VisitForEffect(expr);
1795 return;
1796 }
1797
1798 // Left-hand side can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00001799 // slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001800 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1801 LhsKind assign_type = VARIABLE;
1802 Property* prop = expr->AsProperty();
1803 if (prop != NULL) {
1804 assign_type = (prop->key()->IsPropertyName())
1805 ? NAMED_PROPERTY
1806 : KEYED_PROPERTY;
1807 }
1808
1809 switch (assign_type) {
1810 case VARIABLE: {
1811 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001812 EffectContext context(this);
1813 EmitVariableAssignment(var, Token::ASSIGN);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001814 break;
1815 }
1816 case NAMED_PROPERTY: {
1817 __ push(r0); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001818 VisitForAccumulatorValue(prop->obj());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001819 __ mov(r1, r0);
1820 __ pop(r0); // Restore value.
1821 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001822 Handle<Code> ic = is_strict_mode()
1823 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1824 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001825 __ Call(ic);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001826 break;
1827 }
1828 case KEYED_PROPERTY: {
1829 __ push(r0); // Preserve value.
whesse@chromium.org7b260152011-06-20 15:33:18 +00001830 VisitForStackValue(prop->obj());
1831 VisitForAccumulatorValue(prop->key());
1832 __ mov(r1, r0);
1833 __ pop(r2);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001834 __ pop(r0); // Restore value.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001835 Handle<Code> ic = is_strict_mode()
1836 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
1837 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001838 __ Call(ic);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001839 break;
1840 }
1841 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001842 PrepareForBailoutForId(bailout_ast_id, TOS_REG);
1843 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001844}
1845
1846
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001847void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001848 Token::Value op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001849 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001850 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001851
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001852 if (var->is_global()) {
1853 ASSERT(!var->is_this());
1854 // Assignment to a global variable. Use inline caching for the
1855 // assignment. Right-hand-side value is passed in r0, variable name in
ager@chromium.org5c838252010-02-19 08:53:10 +00001856 // r2, and the global object in r1.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001857 __ mov(r2, Operand(var->name()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001858 __ ldr(r1, GlobalObjectOperand());
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001859 Handle<Code> ic = is_strict_mode()
1860 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1861 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001862 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001863
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001864 } else if (op == Token::INIT_CONST) {
1865 // Like var declarations, const declarations are hoisted to function
1866 // scope. However, unlike var initializers, const initializers are able
1867 // to drill a hole to that function context, even from inside a 'with'
1868 // context. We thus bypass the normal static scope lookup.
1869 Slot* slot = var->AsSlot();
1870 Label skip;
1871 switch (slot->type()) {
1872 case Slot::PARAMETER:
1873 // No const parameters.
1874 UNREACHABLE();
1875 break;
1876 case Slot::LOCAL:
1877 // Detect const reinitialization by checking for the hole value.
1878 __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1879 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1880 __ cmp(r1, ip);
1881 __ b(ne, &skip);
1882 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1883 break;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001884 case Slot::CONTEXT:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001885 case Slot::LOOKUP:
1886 __ push(r0);
1887 __ mov(r0, Operand(slot->var()->name()));
1888 __ Push(cp, r0); // Context and name.
1889 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1890 break;
1891 }
1892 __ bind(&skip);
1893
1894 } else if (var->mode() != Variable::CONST) {
1895 // Perform the assignment for non-const variables. Const assignments
1896 // are simply skipped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001897 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001898 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001899 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001900 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001901 // Perform the assignment.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001902 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1903 break;
1904
1905 case Slot::CONTEXT: {
1906 MemOperand target = EmitSlotSearch(slot, r1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001907 // Perform the assignment and issue the write barrier.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001908 __ str(result_register(), target);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001909 // RecordWrite may destroy all its register arguments.
1910 __ mov(r3, result_register());
1911 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001912 __ RecordWrite(r1, Operand(offset), r2, r3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001913 break;
1914 }
1915
1916 case Slot::LOOKUP:
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001917 // Call the runtime for the assignment.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001918 __ push(r0); // Value.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001919 __ mov(r1, Operand(slot->var()->name()));
1920 __ mov(r0, Operand(Smi::FromInt(strict_mode_flag())));
1921 __ Push(cp, r1, r0); // Context, name, strict mode.
1922 __ CallRuntime(Runtime::kStoreContextSlot, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001923 break;
1924 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001925 }
1926}
1927
1928
1929void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1930 // Assignment to a property, using a named store IC.
1931 Property* prop = expr->target()->AsProperty();
1932 ASSERT(prop != NULL);
1933 ASSERT(prop->key()->AsLiteral() != NULL);
1934
1935 // If the assignment starts a block of assignments to the same object,
1936 // change to slow case to avoid the quadratic behavior of repeatedly
1937 // adding fast properties.
1938 if (expr->starts_initialization_block()) {
1939 __ push(result_register());
1940 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value.
1941 __ push(ip);
1942 __ CallRuntime(Runtime::kToSlowProperties, 1);
1943 __ pop(result_register());
1944 }
1945
1946 // Record source code position before IC call.
1947 SetSourcePosition(expr->position());
1948 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001949 // Load receiver to r1. Leave a copy in the stack if needed for turning the
1950 // receiver into fast case.
ager@chromium.org5c838252010-02-19 08:53:10 +00001951 if (expr->ends_initialization_block()) {
1952 __ ldr(r1, MemOperand(sp));
1953 } else {
1954 __ pop(r1);
1955 }
1956
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001957 Handle<Code> ic = is_strict_mode()
1958 ? isolate()->builtins()->StoreIC_Initialize_Strict()
1959 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00001960 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001961
1962 // If the assignment ends an initialization block, revert to fast case.
1963 if (expr->ends_initialization_block()) {
1964 __ push(r0); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001965 // Receiver is under the result value.
1966 __ ldr(ip, MemOperand(sp, kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001967 __ push(ip);
1968 __ CallRuntime(Runtime::kToFastProperties, 1);
1969 __ pop(r0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001970 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001971 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00001972 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
1973 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001974}
1975
1976
1977void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1978 // Assignment to a property, using a keyed store IC.
1979
1980 // If the assignment starts a block of assignments to the same object,
1981 // change to slow case to avoid the quadratic behavior of repeatedly
1982 // adding fast properties.
1983 if (expr->starts_initialization_block()) {
1984 __ push(result_register());
1985 // Receiver is now under the key and value.
1986 __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
1987 __ push(ip);
1988 __ CallRuntime(Runtime::kToSlowProperties, 1);
1989 __ pop(result_register());
1990 }
1991
1992 // Record source code position before IC call.
1993 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001994 __ pop(r1); // Key.
1995 // Load receiver to r2. Leave a copy in the stack if needed for turning the
1996 // receiver into fast case.
1997 if (expr->ends_initialization_block()) {
1998 __ ldr(r2, MemOperand(sp));
1999 } else {
2000 __ pop(r2);
2001 }
2002
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002003 Handle<Code> ic = is_strict_mode()
2004 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
2005 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002006 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002007
2008 // If the assignment ends an initialization block, revert to fast case.
2009 if (expr->ends_initialization_block()) {
2010 __ push(r0); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002011 // Receiver is under the result value.
2012 __ ldr(ip, MemOperand(sp, kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002013 __ push(ip);
2014 __ CallRuntime(Runtime::kToFastProperties, 1);
2015 __ pop(r0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002016 __ Drop(1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002017 }
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00002018 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
2019 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002020}
2021
2022
2023void FullCodeGenerator::VisitProperty(Property* expr) {
2024 Comment cmnt(masm_, "[ Property");
2025 Expression* key = expr->key();
2026
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002027 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002028 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002029 EmitNamedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002030 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002031 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002032 VisitForStackValue(expr->obj());
2033 VisitForAccumulatorValue(expr->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002034 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002035 EmitKeyedPropertyLoad(expr);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002036 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002037 }
2038}
2039
2040void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00002041 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002042 RelocInfo::Mode mode) {
2043 // Code common for calls using the IC.
2044 ZoneList<Expression*>* args = expr->arguments();
2045 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002046 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002047 for (int i = 0; i < arg_count; i++) {
2048 VisitForStackValue(args->at(i));
2049 }
2050 __ mov(r2, Operand(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002051 }
2052 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002053 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002054 // Call the IC initialization code.
ager@chromium.org5c838252010-02-19 08:53:10 +00002055 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002056 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00002057 isolate()->stub_cache()->ComputeCallInitialize(arg_count, in_loop, mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002058 __ Call(ic, mode, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002059 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002060 // Restore context register.
2061 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002062 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002063}
2064
2065
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002066void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
danno@chromium.org40cb8782011-05-25 07:58:50 +00002067 Expression* key) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002068 // Load the key.
2069 VisitForAccumulatorValue(key);
2070
2071 // Swap the name of the function and the receiver on the stack to follow
2072 // the calling convention for call ICs.
2073 __ pop(r1);
2074 __ push(r0);
2075 __ push(r1);
2076
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002077 // Code common for calls using the IC.
2078 ZoneList<Expression*>* args = expr->arguments();
2079 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002080 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002081 for (int i = 0; i < arg_count; i++) {
2082 VisitForStackValue(args->at(i));
2083 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002084 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002085 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002086 SetSourcePosition(expr->position());
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002087 // Call the IC initialization code.
2088 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002089 Handle<Code> ic =
2090 isolate()->stub_cache()->ComputeKeyedCallInitialize(arg_count, in_loop);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002091 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002092 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002093 RecordJSReturnSite(expr);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002094 // Restore context register.
2095 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002096 context()->DropAndPlug(1, r0); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002097}
2098
2099
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002100void FullCodeGenerator::EmitCallWithStub(Call* expr, CallFunctionFlags flags) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002101 // Code common for calls using the call stub.
2102 ZoneList<Expression*>* args = expr->arguments();
2103 int arg_count = args->length();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002104 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002105 for (int i = 0; i < arg_count; i++) {
2106 VisitForStackValue(args->at(i));
2107 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002108 }
2109 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002110 SetSourcePosition(expr->position());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002111 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002112 CallFunctionStub stub(arg_count, in_loop, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002113 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002114 RecordJSReturnSite(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002115 // Restore context register.
2116 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002117 context()->DropAndPlug(1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002118}
2119
2120
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002121void FullCodeGenerator::EmitResolvePossiblyDirectEval(ResolveEvalFlag flag,
2122 int arg_count) {
2123 // Push copy of the first argument or undefined if it doesn't exist.
2124 if (arg_count > 0) {
2125 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
2126 } else {
2127 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
2128 }
2129 __ push(r1);
2130
2131 // Push the receiver of the enclosing function and do runtime call.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002132 int receiver_offset = 2 + info_->scope()->num_parameters();
2133 __ ldr(r1, MemOperand(fp, receiver_offset * kPointerSize));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002134 __ push(r1);
2135 // Push the strict mode flag.
2136 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
2137 __ push(r1);
2138
2139 __ CallRuntime(flag == SKIP_CONTEXT_LOOKUP
2140 ? Runtime::kResolvePossiblyDirectEvalNoLookup
2141 : Runtime::kResolvePossiblyDirectEval, 4);
2142}
2143
2144
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002145void FullCodeGenerator::VisitCall(Call* expr) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002146#ifdef DEBUG
2147 // We want to verify that RecordJSReturnSite gets called on all paths
2148 // through this function. Avoid early returns.
2149 expr->return_is_recorded_ = false;
2150#endif
2151
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002152 Comment cmnt(masm_, "[ Call");
2153 Expression* fun = expr->expression();
2154 Variable* var = fun->AsVariableProxy()->AsVariable();
2155
2156 if (var != NULL && var->is_possibly_eval()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002157 // In a call to eval, we first call %ResolvePossiblyDirectEval to
2158 // resolve the function we need to call and the receiver of the
2159 // call. Then we call the resolved function using the given
2160 // arguments.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002161 ZoneList<Expression*>* args = expr->arguments();
2162 int arg_count = args->length();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002163
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002164 { PreservePositionScope pos_scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002165 VisitForStackValue(fun);
2166 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
2167 __ push(r2); // Reserved receiver slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002168
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002169 // Push the arguments.
2170 for (int i = 0; i < arg_count; i++) {
2171 VisitForStackValue(args->at(i));
2172 }
2173
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002174 // If we know that eval can only be shadowed by eval-introduced
2175 // variables we attempt to load the global eval function directly
2176 // in generated code. If we succeed, there is no need to perform a
2177 // context lookup in the runtime system.
2178 Label done;
2179 if (var->AsSlot() != NULL && var->mode() == Variable::DYNAMIC_GLOBAL) {
2180 Label slow;
2181 EmitLoadGlobalSlotCheckExtensions(var->AsSlot(),
2182 NOT_INSIDE_TYPEOF,
2183 &slow);
2184 // Push the function and resolve eval.
2185 __ push(r0);
2186 EmitResolvePossiblyDirectEval(SKIP_CONTEXT_LOOKUP, arg_count);
2187 __ jmp(&done);
2188 __ bind(&slow);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002189 }
2190
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002191 // Push copy of the function (found below the arguments) and
2192 // resolve eval.
2193 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002194 __ push(r1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00002195 EmitResolvePossiblyDirectEval(PERFORM_CONTEXT_LOOKUP, arg_count);
2196 if (done.is_linked()) {
2197 __ bind(&done);
2198 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002199
2200 // The runtime call returns a pair of values in r0 (function) and
2201 // r1 (receiver). Touch up the stack with the right values.
2202 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
2203 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002204 }
2205
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002206 // Record source position for debugger.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002207 SetSourcePosition(expr->position());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002208 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
danno@chromium.org40cb8782011-05-25 07:58:50 +00002209 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_IMPLICIT);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002210 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002211 RecordJSReturnSite(expr);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002212 // Restore context register.
2213 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002214 context()->DropAndPlug(1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002215 } else if (var != NULL && !var->is_this() && var->is_global()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002216 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002217 __ ldr(r0, GlobalObjectOperand());
ager@chromium.org5c838252010-02-19 08:53:10 +00002218 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002219 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002220 } else if (var != NULL && var->AsSlot() != NULL &&
2221 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002222 // Call to a lookup slot (dynamically introduced variable).
2223 Label slow, done;
2224
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002225 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002226 // Generate code for loading from variables potentially shadowed
2227 // by eval-introduced variables.
2228 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
2229 NOT_INSIDE_TYPEOF,
2230 &slow,
2231 &done);
2232 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002233
2234 __ bind(&slow);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002235 // Call the runtime to find the function to call (returned in r0)
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002236 // and the object holding it (returned in edx).
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002237 __ push(context_register());
2238 __ mov(r2, Operand(var->name()));
2239 __ push(r2);
2240 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002241 __ Push(r0, r1); // Function, receiver.
2242
2243 // If fast case code has been generated, emit code to push the
2244 // function and receiver and have the slow path jump around this
2245 // code.
2246 if (done.is_linked()) {
2247 Label call;
2248 __ b(&call);
2249 __ bind(&done);
2250 // Push function.
2251 __ push(r0);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002252 // The receiver is implicitly the global receiver. Indicate this
2253 // by passing the hole to the call function stub.
2254 __ LoadRoot(r1, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002255 __ push(r1);
2256 __ bind(&call);
2257 }
2258
danno@chromium.org40cb8782011-05-25 07:58:50 +00002259 // The receiver is either the global receiver or an object found
2260 // by LoadContextSlot. That object could be the hole if the
2261 // receiver is implicitly the global object.
2262 EmitCallWithStub(expr, RECEIVER_MIGHT_BE_IMPLICIT);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002263 } else if (fun->AsProperty() != NULL) {
2264 // Call to an object property.
2265 Property* prop = fun->AsProperty();
2266 Literal* key = prop->key()->AsLiteral();
2267 if (key != NULL && key->handle()->IsSymbol()) {
2268 // Call to a named property, use call IC.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002269 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002270 VisitForStackValue(prop->obj());
2271 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002272 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002273 } else {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002274 // Call to a keyed property.
2275 // For a synthetic property use keyed load IC followed by function call,
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002276 // for a regular property use EmitKeyedCallWithIC.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002277 if (prop->is_synthetic()) {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002278 // Do not visit the object and key subexpressions (they are shared
2279 // by all occurrences of the same rewritten parameter).
2280 ASSERT(prop->obj()->AsVariableProxy() != NULL);
2281 ASSERT(prop->obj()->AsVariableProxy()->var()->AsSlot() != NULL);
2282 Slot* slot = prop->obj()->AsVariableProxy()->var()->AsSlot();
2283 MemOperand operand = EmitSlotSearch(slot, r1);
2284 __ ldr(r1, operand);
2285
2286 ASSERT(prop->key()->AsLiteral() != NULL);
2287 ASSERT(prop->key()->AsLiteral()->handle()->IsSmi());
2288 __ mov(r0, Operand(prop->key()->AsLiteral()->handle()));
2289
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00002290 // Record source code position for IC call.
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002291 SetSourcePosition(prop->position());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00002292
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002293 Handle<Code> ic = isolate()->builtins()->KeyedLoadIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002294 __ Call(ic, RelocInfo::CODE_TARGET, GetPropertyId(prop));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002295 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002296 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002297 __ Push(r0, r1); // Function, receiver.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002298 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002299 } else {
vegorov@chromium.org0a4e9012011-01-24 12:33:13 +00002300 { PreservePositionScope scope(masm()->positions_recorder());
2301 VisitForStackValue(prop->obj());
2302 }
danno@chromium.org40cb8782011-05-25 07:58:50 +00002303 EmitKeyedCallWithIC(expr, prop->key());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002304 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002305 }
2306 } else {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002307 { PreservePositionScope scope(masm()->positions_recorder());
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00002308 VisitForStackValue(fun);
2309 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002310 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002311 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002312 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
2313 __ push(r1);
2314 // Emit function call.
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00002315 EmitCallWithStub(expr, NO_CALL_FUNCTION_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002316 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002317
2318#ifdef DEBUG
2319 // RecordJSReturnSite should have been called.
2320 ASSERT(expr->return_is_recorded_);
2321#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002322}
2323
2324
2325void FullCodeGenerator::VisitCallNew(CallNew* expr) {
2326 Comment cmnt(masm_, "[ CallNew");
2327 // According to ECMA-262, section 11.2.2, page 44, the function
2328 // expression in new calls must be evaluated before the
2329 // arguments.
ricow@chromium.org65fae842010-08-25 15:26:24 +00002330
2331 // Push constructor on the stack. If it's not a function it's used as
2332 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
2333 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002334 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002335
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002336 // Push the arguments ("left-to-right") on the stack.
2337 ZoneList<Expression*>* args = expr->arguments();
2338 int arg_count = args->length();
2339 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002340 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002341 }
2342
2343 // Call the construct call builtin that handles allocation and
2344 // constructor invocation.
2345 SetSourcePosition(expr->position());
2346
ricow@chromium.org65fae842010-08-25 15:26:24 +00002347 // Load function and argument count into r1 and r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002348 __ mov(r0, Operand(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002349 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002350
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00002351 Handle<Code> construct_builtin =
2352 isolate()->builtins()->JSConstructCall();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002353 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002354 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002355}
2356
2357
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002358void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
2359 ASSERT(args->length() == 1);
2360
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002361 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002362
2363 Label materialize_true, materialize_false;
2364 Label* if_true = NULL;
2365 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002366 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002367 context()->PrepareTest(&materialize_true, &materialize_false,
2368 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002369
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002370 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
2371 __ tst(r0, Operand(kSmiTagMask));
2372 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002373
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002374 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002375}
2376
2377
2378void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
2379 ASSERT(args->length() == 1);
2380
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002381 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002382
2383 Label materialize_true, materialize_false;
2384 Label* if_true = NULL;
2385 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002386 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002387 context()->PrepareTest(&materialize_true, &materialize_false,
2388 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002389
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002390 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002391 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002392 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002393
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002394 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002395}
2396
2397
2398void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
2399 ASSERT(args->length() == 1);
2400
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002401 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002402
2403 Label materialize_true, materialize_false;
2404 Label* if_true = NULL;
2405 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002406 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002407 context()->PrepareTest(&materialize_true, &materialize_false,
2408 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002409
ager@chromium.org378b34e2011-01-28 08:04:38 +00002410 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002411 __ LoadRoot(ip, Heap::kNullValueRootIndex);
2412 __ cmp(r0, ip);
2413 __ b(eq, if_true);
2414 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
2415 // Undetectable objects behave like undefined when tested with typeof.
2416 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
2417 __ tst(r1, Operand(1 << Map::kIsUndetectable));
2418 __ b(ne, if_false);
2419 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset));
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002420 __ cmp(r1, Operand(FIRST_NONCALLABLE_SPEC_OBJECT_TYPE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002421 __ b(lt, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002422 __ cmp(r1, Operand(LAST_NONCALLABLE_SPEC_OBJECT_TYPE));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002423 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002424 Split(le, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002425
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002426 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002427}
2428
2429
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002430void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2431 ASSERT(args->length() == 1);
2432
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002433 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002434
2435 Label materialize_true, materialize_false;
2436 Label* if_true = NULL;
2437 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002438 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002439 context()->PrepareTest(&materialize_true, &materialize_false,
2440 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002441
ager@chromium.org378b34e2011-01-28 08:04:38 +00002442 __ JumpIfSmi(r0, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002443 __ CompareObjectType(r0, r1, r1, FIRST_SPEC_OBJECT_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002444 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002445 Split(ge, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002446
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002447 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002448}
2449
2450
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002451void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2452 ASSERT(args->length() == 1);
2453
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002454 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002455
2456 Label materialize_true, materialize_false;
2457 Label* if_true = NULL;
2458 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002459 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002460 context()->PrepareTest(&materialize_true, &materialize_false,
2461 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002462
ager@chromium.org378b34e2011-01-28 08:04:38 +00002463 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002464 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2465 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
2466 __ tst(r1, Operand(1 << Map::kIsUndetectable));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002467 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002468 Split(ne, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002469
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002470 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002471}
2472
2473
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002474void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2475 ZoneList<Expression*>* args) {
2476
2477 ASSERT(args->length() == 1);
2478
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002479 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002480
2481 Label materialize_true, materialize_false;
2482 Label* if_true = NULL;
2483 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002484 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002485 context()->PrepareTest(&materialize_true, &materialize_false,
2486 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002488 if (FLAG_debug_code) __ AbortIfSmi(r0);
2489
2490 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2491 __ ldrb(ip, FieldMemOperand(r1, Map::kBitField2Offset));
2492 __ tst(ip, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
2493 __ b(ne, if_true);
2494
2495 // Check for fast case object. Generate false result for slow case object.
2496 __ ldr(r2, FieldMemOperand(r0, JSObject::kPropertiesOffset));
2497 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
2498 __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
2499 __ cmp(r2, ip);
2500 __ b(eq, if_false);
2501
2502 // Look for valueOf symbol in the descriptor array, and indicate false if
2503 // found. The type is not checked, so if it is a transition it is a false
2504 // negative.
danno@chromium.org40cb8782011-05-25 07:58:50 +00002505 __ LoadInstanceDescriptors(r1, r4);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002506 __ ldr(r3, FieldMemOperand(r4, FixedArray::kLengthOffset));
2507 // r4: descriptor array
2508 // r3: length of descriptor array
2509 // Calculate the end of the descriptor array.
2510 STATIC_ASSERT(kSmiTag == 0);
2511 STATIC_ASSERT(kSmiTagSize == 1);
2512 STATIC_ASSERT(kPointerSize == 4);
2513 __ add(r2, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2514 __ add(r2, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
2515
2516 // Calculate location of the first key name.
2517 __ add(r4,
2518 r4,
2519 Operand(FixedArray::kHeaderSize - kHeapObjectTag +
2520 DescriptorArray::kFirstIndex * kPointerSize));
2521 // Loop through all the keys in the descriptor array. If one of these is the
2522 // symbol valueOf the result is false.
2523 Label entry, loop;
2524 // The use of ip to store the valueOf symbol asumes that it is not otherwise
2525 // used in the loop below.
2526 __ mov(ip, Operand(FACTORY->value_of_symbol()));
2527 __ jmp(&entry);
2528 __ bind(&loop);
2529 __ ldr(r3, MemOperand(r4, 0));
2530 __ cmp(r3, ip);
2531 __ b(eq, if_false);
2532 __ add(r4, r4, Operand(kPointerSize));
2533 __ bind(&entry);
2534 __ cmp(r4, Operand(r2));
2535 __ b(ne, &loop);
2536
2537 // If a valueOf property is not found on the object check that it's
2538 // prototype is the un-modified String prototype. If not result is false.
2539 __ ldr(r2, FieldMemOperand(r1, Map::kPrototypeOffset));
whesse@chromium.org7b260152011-06-20 15:33:18 +00002540 __ JumpIfSmi(r2, if_false);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002541 __ ldr(r2, FieldMemOperand(r2, HeapObject::kMapOffset));
2542 __ ldr(r3, ContextOperand(cp, Context::GLOBAL_INDEX));
2543 __ ldr(r3, FieldMemOperand(r3, GlobalObject::kGlobalContextOffset));
2544 __ ldr(r3, ContextOperand(r3, Context::STRING_FUNCTION_PROTOTYPE_MAP_INDEX));
2545 __ cmp(r2, r3);
2546 __ b(ne, if_false);
2547
2548 // Set the bit in the map to indicate that it has been checked safe for
2549 // default valueOf and set true result.
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002550 __ ldrb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002551 __ orr(r2, r2, Operand(1 << Map::kStringWrapperSafeForDefaultValueOf));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00002552 __ strb(r2, FieldMemOperand(r1, Map::kBitField2Offset));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002553 __ jmp(if_true);
2554
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002555 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002556 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002557}
2558
2559
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002560void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2561 ASSERT(args->length() == 1);
2562
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002563 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002564
2565 Label materialize_true, materialize_false;
2566 Label* if_true = NULL;
2567 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002568 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002569 context()->PrepareTest(&materialize_true, &materialize_false,
2570 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002571
ager@chromium.org378b34e2011-01-28 08:04:38 +00002572 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002573 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002574 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002575 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002576
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002577 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002578}
2579
2580
2581void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2582 ASSERT(args->length() == 1);
2583
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002584 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002585
2586 Label materialize_true, materialize_false;
2587 Label* if_true = NULL;
2588 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002589 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002590 context()->PrepareTest(&materialize_true, &materialize_false,
2591 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002592
ager@chromium.org378b34e2011-01-28 08:04:38 +00002593 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002594 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002595 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002596 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002597
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002598 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002599}
2600
2601
2602void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2603 ASSERT(args->length() == 1);
2604
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002605 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002606
2607 Label materialize_true, materialize_false;
2608 Label* if_true = NULL;
2609 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002610 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002611 context()->PrepareTest(&materialize_true, &materialize_false,
2612 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002613
ager@chromium.org378b34e2011-01-28 08:04:38 +00002614 __ JumpIfSmi(r0, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002615 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002616 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002617 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002618
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002619 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002620}
2621
2622
2623
2624void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2625 ASSERT(args->length() == 0);
2626
2627 Label materialize_true, materialize_false;
2628 Label* if_true = NULL;
2629 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002630 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002631 context()->PrepareTest(&materialize_true, &materialize_false,
2632 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002633
2634 // Get the frame pointer for the calling frame.
2635 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2636
2637 // Skip the arguments adaptor frame if it exists.
2638 Label check_frame_marker;
2639 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset));
2640 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2641 __ b(ne, &check_frame_marker);
2642 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset));
2643
2644 // Check the marker in the calling frame.
2645 __ bind(&check_frame_marker);
2646 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
2647 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002648 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002649 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002650
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002651 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002652}
2653
2654
2655void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2656 ASSERT(args->length() == 2);
2657
2658 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002659 VisitForStackValue(args->at(0));
2660 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002661
2662 Label materialize_true, materialize_false;
2663 Label* if_true = NULL;
2664 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002665 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002666 context()->PrepareTest(&materialize_true, &materialize_false,
2667 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002668
2669 __ pop(r1);
2670 __ cmp(r0, r1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002671 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002672 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002673
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002674 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002675}
2676
2677
2678void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2679 ASSERT(args->length() == 1);
2680
2681 // ArgumentsAccessStub expects the key in edx and the formal
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002682 // parameter count in r0.
2683 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002684 __ mov(r1, r0);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002685 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002686 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2687 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002688 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002689}
2690
2691
2692void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2693 ASSERT(args->length() == 0);
2694
2695 Label exit;
2696 // Get the number of formal parameters.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00002697 __ mov(r0, Operand(Smi::FromInt(info_->scope()->num_parameters())));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002698
2699 // Check if the calling frame is an arguments adaptor frame.
2700 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2701 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2702 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2703 __ b(ne, &exit);
2704
2705 // Arguments adaptor case: Read the arguments length from the
2706 // adaptor frame.
2707 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2708
2709 __ bind(&exit);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002710 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002711}
2712
2713
2714void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2715 ASSERT(args->length() == 1);
2716 Label done, null, function, non_function_constructor;
2717
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002718 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002719
2720 // If the object is a smi, we return null.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002721 __ JumpIfSmi(r0, &null);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002722
2723 // Check that the object is a JS object but take special care of JS
2724 // functions to make sure they have 'Function' as their class.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002725 __ CompareObjectType(r0, r0, r1, FIRST_SPEC_OBJECT_TYPE);
2726 // Map is now in r0.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002727 __ b(lt, &null);
2728
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00002729 // As long as LAST_CALLABLE_SPEC_OBJECT_TYPE is the last instance type, and
2730 // FIRST_CALLABLE_SPEC_OBJECT_TYPE comes right after
2731 // LAST_NONCALLABLE_SPEC_OBJECT_TYPE, we can avoid checking for the latter.
2732 STATIC_ASSERT(LAST_TYPE == LAST_CALLABLE_SPEC_OBJECT_TYPE);
2733 STATIC_ASSERT(FIRST_CALLABLE_SPEC_OBJECT_TYPE ==
2734 LAST_NONCALLABLE_SPEC_OBJECT_TYPE + 1);
2735 __ cmp(r1, Operand(FIRST_CALLABLE_SPEC_OBJECT_TYPE));
2736 __ b(ge, &function);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002737
2738 // Check if the constructor in the map is a function.
2739 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset));
2740 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
2741 __ b(ne, &non_function_constructor);
2742
2743 // r0 now contains the constructor function. Grab the
2744 // instance class name from there.
2745 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
2746 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset));
2747 __ b(&done);
2748
2749 // Functions have class 'Function'.
2750 __ bind(&function);
2751 __ LoadRoot(r0, Heap::kfunction_class_symbolRootIndex);
2752 __ jmp(&done);
2753
2754 // Objects with a non-function constructor have class 'Object'.
2755 __ bind(&non_function_constructor);
ricow@chromium.org9fa09672011-07-25 11:05:35 +00002756 __ LoadRoot(r0, Heap::kObject_symbolRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002757 __ jmp(&done);
2758
2759 // Non-JS objects have class null.
2760 __ bind(&null);
2761 __ LoadRoot(r0, Heap::kNullValueRootIndex);
2762
2763 // All done.
2764 __ bind(&done);
2765
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002766 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002767}
2768
2769
2770void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2771 // Conditionally generate a log call.
2772 // Args:
2773 // 0 (literal string): The type of logging (corresponds to the flags).
2774 // This is used to determine whether or not to generate the log call.
2775 // 1 (string): Format string. Access the string at argument index 2
2776 // with '%2s' (see Logger::LogRuntime for all the formats).
2777 // 2 (array): Arguments to the format string.
2778 ASSERT_EQ(args->length(), 3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002779 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002780 VisitForStackValue(args->at(1));
2781 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002782 __ CallRuntime(Runtime::kLog, 2);
2783 }
whesse@chromium.org030d38e2011-07-13 13:23:34 +00002784
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002785 // Finally, we're expected to leave a value on the top of the stack.
2786 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002787 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002788}
2789
2790
2791void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2792 ASSERT(args->length() == 0);
2793
2794 Label slow_allocate_heapnumber;
2795 Label heapnumber_allocated;
2796
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00002797 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
2798 __ AllocateHeapNumber(r4, r1, r2, r6, &slow_allocate_heapnumber);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002799 __ jmp(&heapnumber_allocated);
2800
2801 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002802 // Allocate a heap number.
2803 __ CallRuntime(Runtime::kNumberAlloc, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002804 __ mov(r4, Operand(r0));
2805
2806 __ bind(&heapnumber_allocated);
2807
2808 // Convert 32 random bits in r0 to 0.(32 random bits) in a double
2809 // by computing:
2810 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002811 if (CpuFeatures::IsSupported(VFP3)) {
2812 __ PrepareCallCFunction(1, r0);
2813 __ mov(r0, Operand(ExternalReference::isolate_address()));
2814 __ CallCFunction(ExternalReference::random_uint32_function(isolate()), 1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002815
2816 CpuFeatures::Scope scope(VFP3);
2817 // 0x41300000 is the top half of 1.0 x 2^20 as a double.
2818 // Create this constant using mov/orr to avoid PC relative load.
2819 __ mov(r1, Operand(0x41000000));
2820 __ orr(r1, r1, Operand(0x300000));
2821 // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
2822 __ vmov(d7, r0, r1);
2823 // Move 0x4130000000000000 to VFP.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00002824 __ mov(r0, Operand(0, RelocInfo::NONE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002825 __ vmov(d8, r0, r1);
2826 // Subtract and store the result in the heap number.
2827 __ vsub(d7, d7, d8);
2828 __ sub(r0, r4, Operand(kHeapObjectTag));
2829 __ vstr(d7, r0, HeapNumber::kValueOffset);
2830 __ mov(r0, r4);
2831 } else {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002832 __ PrepareCallCFunction(2, r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002833 __ mov(r0, Operand(r4));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002834 __ mov(r1, Operand(ExternalReference::isolate_address()));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002835 __ CallCFunction(
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002836 ExternalReference::fill_heap_number_with_random_function(isolate()), 2);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002837 }
2838
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002839 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002840}
2841
2842
2843void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2844 // Load the arguments on the stack and call the stub.
2845 SubStringStub stub;
2846 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002847 VisitForStackValue(args->at(0));
2848 VisitForStackValue(args->at(1));
2849 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002850 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002851 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002852}
2853
2854
2855void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2856 // Load the arguments on the stack and call the stub.
2857 RegExpExecStub stub;
2858 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002859 VisitForStackValue(args->at(0));
2860 VisitForStackValue(args->at(1));
2861 VisitForStackValue(args->at(2));
2862 VisitForStackValue(args->at(3));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002863 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002864 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002865}
2866
2867
2868void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2869 ASSERT(args->length() == 1);
2870
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002871 VisitForAccumulatorValue(args->at(0)); // Load the object.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002872
2873 Label done;
2874 // If the object is a smi return the object.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002875 __ JumpIfSmi(r0, &done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002876 // If the object is not a value type, return the object.
2877 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE);
2878 __ b(ne, &done);
2879 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
2880
2881 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002882 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002883}
2884
2885
2886void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2887 // Load the arguments on the stack and call the runtime function.
2888 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002889 VisitForStackValue(args->at(0));
2890 VisitForStackValue(args->at(1));
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00002891 MathPowStub stub;
2892 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002893 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002894}
2895
2896
2897void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2898 ASSERT(args->length() == 2);
2899
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002900 VisitForStackValue(args->at(0)); // Load the object.
2901 VisitForAccumulatorValue(args->at(1)); // Load the value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002902 __ pop(r1); // r0 = value. r1 = object.
2903
2904 Label done;
2905 // If the object is a smi, return the value.
ager@chromium.org378b34e2011-01-28 08:04:38 +00002906 __ JumpIfSmi(r1, &done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002907
2908 // If the object is not a value type, return the value.
2909 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE);
2910 __ b(ne, &done);
2911
2912 // Store the value.
2913 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
2914 // Update the write barrier. Save the value as it will be
2915 // overwritten by the write barrier code and is needed afterward.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00002916 __ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002917
2918 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002919 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002920}
2921
2922
2923void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2924 ASSERT_EQ(args->length(), 1);
2925
2926 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002927 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002928
2929 NumberToStringStub stub;
2930 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002931 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002932}
2933
2934
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002935void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002936 ASSERT(args->length() == 1);
2937
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002938 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002939
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002940 Label done;
2941 StringCharFromCodeGenerator generator(r0, r1);
2942 generator.GenerateFast(masm_);
2943 __ jmp(&done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002944
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002945 NopRuntimeCallHelper call_helper;
2946 generator.GenerateSlow(masm_, call_helper);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002947
2948 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002949 context()->Plug(r1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002950}
2951
2952
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002953void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2954 ASSERT(args->length() == 2);
2955
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002956 VisitForStackValue(args->at(0));
2957 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002958
2959 Register object = r1;
2960 Register index = r0;
2961 Register scratch = r2;
2962 Register result = r3;
2963
2964 __ pop(object);
2965
2966 Label need_conversion;
2967 Label index_out_of_range;
2968 Label done;
2969 StringCharCodeAtGenerator generator(object,
2970 index,
2971 scratch,
2972 result,
2973 &need_conversion,
2974 &need_conversion,
2975 &index_out_of_range,
2976 STRING_INDEX_IS_NUMBER);
2977 generator.GenerateFast(masm_);
2978 __ jmp(&done);
2979
2980 __ bind(&index_out_of_range);
2981 // When the index is out of range, the spec requires us to return
2982 // NaN.
2983 __ LoadRoot(result, Heap::kNanValueRootIndex);
2984 __ jmp(&done);
2985
2986 __ bind(&need_conversion);
2987 // Load the undefined value into the result register, which will
2988 // trigger conversion.
2989 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2990 __ jmp(&done);
2991
2992 NopRuntimeCallHelper call_helper;
2993 generator.GenerateSlow(masm_, call_helper);
2994
2995 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002996 context()->Plug(result);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002997}
2998
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002999
3000void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
3001 ASSERT(args->length() == 2);
3002
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003003 VisitForStackValue(args->at(0));
3004 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003005
3006 Register object = r1;
3007 Register index = r0;
3008 Register scratch1 = r2;
3009 Register scratch2 = r3;
3010 Register result = r0;
3011
3012 __ pop(object);
3013
3014 Label need_conversion;
3015 Label index_out_of_range;
3016 Label done;
3017 StringCharAtGenerator generator(object,
3018 index,
3019 scratch1,
3020 scratch2,
3021 result,
3022 &need_conversion,
3023 &need_conversion,
3024 &index_out_of_range,
3025 STRING_INDEX_IS_NUMBER);
3026 generator.GenerateFast(masm_);
3027 __ jmp(&done);
3028
3029 __ bind(&index_out_of_range);
3030 // When the index is out of range, the spec requires us to return
3031 // the empty string.
3032 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
3033 __ jmp(&done);
3034
3035 __ bind(&need_conversion);
3036 // Move smi zero into the result register, which will trigger
3037 // conversion.
3038 __ mov(result, Operand(Smi::FromInt(0)));
3039 __ jmp(&done);
3040
3041 NopRuntimeCallHelper call_helper;
3042 generator.GenerateSlow(masm_, call_helper);
3043
3044 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003045 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003046}
3047
3048
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003049void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
3050 ASSERT_EQ(2, args->length());
3051
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003052 VisitForStackValue(args->at(0));
3053 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003054
3055 StringAddStub stub(NO_STRING_ADD_FLAGS);
3056 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003057 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003058}
3059
3060
3061void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
3062 ASSERT_EQ(2, args->length());
3063
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003064 VisitForStackValue(args->at(0));
3065 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003066
3067 StringCompareStub stub;
3068 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003069 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003070}
3071
3072
3073void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003074 // Load the argument on the stack and call the stub.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003075 TranscendentalCacheStub stub(TranscendentalCache::SIN,
3076 TranscendentalCacheStub::TAGGED);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003077 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003078 VisitForStackValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003079 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003080 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003081}
3082
3083
3084void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003085 // Load the argument on the stack and call the stub.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003086 TranscendentalCacheStub stub(TranscendentalCache::COS,
3087 TranscendentalCacheStub::TAGGED);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003088 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003089 VisitForStackValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003090 __ CallStub(&stub);
3091 context()->Plug(r0);
3092}
3093
3094
3095void FullCodeGenerator::EmitMathLog(ZoneList<Expression*>* args) {
3096 // Load the argument on the stack and call the stub.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003097 TranscendentalCacheStub stub(TranscendentalCache::LOG,
3098 TranscendentalCacheStub::TAGGED);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003099 ASSERT(args->length() == 1);
3100 VisitForStackValue(args->at(0));
3101 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003102 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003103}
3104
3105
3106void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
3107 // Load the argument on the stack and call the runtime function.
3108 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003109 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003110 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003111 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003112}
3113
3114
3115void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
3116 ASSERT(args->length() >= 2);
3117
danno@chromium.org160a7b02011-04-18 15:51:38 +00003118 int arg_count = args->length() - 2; // 2 ~ receiver and function.
3119 for (int i = 0; i < arg_count + 1; i++) {
3120 VisitForStackValue(args->at(i));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003121 }
danno@chromium.org160a7b02011-04-18 15:51:38 +00003122 VisitForAccumulatorValue(args->last()); // Function.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003123
danno@chromium.org160a7b02011-04-18 15:51:38 +00003124 // InvokeFunction requires the function in r1. Move it in there.
3125 __ mov(r1, result_register());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003126 ParameterCount count(arg_count);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003127 __ InvokeFunction(r1, count, CALL_FUNCTION,
3128 NullCallWrapper(), CALL_AS_METHOD);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003129 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003130 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003131}
3132
3133
3134void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003135 RegExpConstructResultStub stub;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003136 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003137 VisitForStackValue(args->at(0));
3138 VisitForStackValue(args->at(1));
3139 VisitForStackValue(args->at(2));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003140 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003141 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003142}
3143
3144
3145void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
3146 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003147 VisitForStackValue(args->at(0));
3148 VisitForStackValue(args->at(1));
3149 VisitForStackValue(args->at(2));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003150 Label done;
3151 Label slow_case;
3152 Register object = r0;
3153 Register index1 = r1;
3154 Register index2 = r2;
3155 Register elements = r3;
3156 Register scratch1 = r4;
3157 Register scratch2 = r5;
3158
3159 __ ldr(object, MemOperand(sp, 2 * kPointerSize));
3160 // Fetch the map and check if array is in fast case.
3161 // Check that object doesn't require security checks and
3162 // has no indexed interceptor.
ricow@chromium.orgbadaffc2011-03-17 12:15:27 +00003163 __ CompareObjectType(object, scratch1, scratch2, JS_ARRAY_TYPE);
3164 __ b(ne, &slow_case);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003165 // Map is now in scratch1.
3166
3167 __ ldrb(scratch2, FieldMemOperand(scratch1, Map::kBitFieldOffset));
3168 __ tst(scratch2, Operand(KeyedLoadIC::kSlowCaseBitFieldMask));
3169 __ b(ne, &slow_case);
3170
3171 // Check the object's elements are in fast case and writable.
3172 __ ldr(elements, FieldMemOperand(object, JSObject::kElementsOffset));
3173 __ ldr(scratch1, FieldMemOperand(elements, HeapObject::kMapOffset));
3174 __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
3175 __ cmp(scratch1, ip);
3176 __ b(ne, &slow_case);
3177
3178 // Check that both indices are smis.
3179 __ ldr(index1, MemOperand(sp, 1 * kPointerSize));
3180 __ ldr(index2, MemOperand(sp, 0));
3181 __ JumpIfNotBothSmi(index1, index2, &slow_case);
3182
3183 // Check that both indices are valid.
3184 __ ldr(scratch1, FieldMemOperand(object, JSArray::kLengthOffset));
3185 __ cmp(scratch1, index1);
3186 __ cmp(scratch1, index2, hi);
3187 __ b(ls, &slow_case);
3188
3189 // Bring the address of the elements into index1 and index2.
3190 __ add(scratch1, elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3191 __ add(index1,
3192 scratch1,
3193 Operand(index1, LSL, kPointerSizeLog2 - kSmiTagSize));
3194 __ add(index2,
3195 scratch1,
3196 Operand(index2, LSL, kPointerSizeLog2 - kSmiTagSize));
3197
3198 // Swap elements.
3199 __ ldr(scratch1, MemOperand(index1, 0));
3200 __ ldr(scratch2, MemOperand(index2, 0));
3201 __ str(scratch1, MemOperand(index2, 0));
3202 __ str(scratch2, MemOperand(index1, 0));
3203
3204 Label new_space;
3205 __ InNewSpace(elements, scratch1, eq, &new_space);
3206 // Possible optimization: do a check that both values are Smis
3207 // (or them and test against Smi mask.)
3208
3209 __ mov(scratch1, elements);
3210 __ RecordWriteHelper(elements, index1, scratch2);
3211 __ RecordWriteHelper(scratch1, index2, scratch2); // scratch1 holds elements.
3212
3213 __ bind(&new_space);
3214 // We are done. Drop elements from the stack, and return undefined.
3215 __ Drop(3);
3216 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
3217 __ jmp(&done);
3218
3219 __ bind(&slow_case);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003220 __ CallRuntime(Runtime::kSwapElements, 3);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00003221
3222 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003223 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003224}
3225
3226
3227void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
3228 ASSERT_EQ(2, args->length());
3229
3230 ASSERT_NE(NULL, args->at(0)->AsLiteral());
3231 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
3232
3233 Handle<FixedArray> jsfunction_result_caches(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003234 isolate()->global_context()->jsfunction_result_caches());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003235 if (jsfunction_result_caches->length() <= cache_id) {
3236 __ Abort("Attempt to use undefined cache.");
3237 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003238 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003239 return;
3240 }
3241
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003242 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003243
3244 Register key = r0;
3245 Register cache = r1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003246 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003247 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003248 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003249 __ ldr(cache,
3250 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
3251
3252
3253 Label done, not_found;
3254 // tmp now holds finger offset as a smi.
3255 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
3256 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
3257 // r2 now holds finger offset as a smi.
3258 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3259 // r3 now points to the start of fixed array elements.
3260 __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex));
3261 // Note side effect of PreIndex: r3 now points to the key of the pair.
3262 __ cmp(key, r2);
3263 __ b(ne, &not_found);
3264
3265 __ ldr(r0, MemOperand(r3, kPointerSize));
3266 __ b(&done);
3267
3268 __ bind(&not_found);
3269 // Call runtime to perform the lookup.
3270 __ Push(cache, key);
3271 __ CallRuntime(Runtime::kGetFromCache, 2);
3272
3273 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003274 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003275}
3276
3277
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003278void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
3279 ASSERT_EQ(2, args->length());
3280
3281 Register right = r0;
3282 Register left = r1;
3283 Register tmp = r2;
3284 Register tmp2 = r3;
3285
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003286 VisitForStackValue(args->at(0));
3287 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003288 __ pop(left);
3289
3290 Label done, fail, ok;
3291 __ cmp(left, Operand(right));
3292 __ b(eq, &ok);
3293 // Fail if either is a non-HeapObject.
3294 __ and_(tmp, left, Operand(right));
whesse@chromium.org7b260152011-06-20 15:33:18 +00003295 __ JumpIfSmi(tmp, &fail);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003296 __ ldr(tmp, FieldMemOperand(left, HeapObject::kMapOffset));
3297 __ ldrb(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset));
3298 __ cmp(tmp2, Operand(JS_REGEXP_TYPE));
3299 __ b(ne, &fail);
3300 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
3301 __ cmp(tmp, Operand(tmp2));
3302 __ b(ne, &fail);
3303 __ ldr(tmp, FieldMemOperand(left, JSRegExp::kDataOffset));
3304 __ ldr(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset));
3305 __ cmp(tmp, tmp2);
3306 __ b(eq, &ok);
3307 __ bind(&fail);
3308 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
3309 __ jmp(&done);
3310 __ bind(&ok);
3311 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
3312 __ bind(&done);
3313
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003314 context()->Plug(r0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00003315}
3316
3317
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003318void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003319 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003320
3321 Label materialize_true, materialize_false;
3322 Label* if_true = NULL;
3323 Label* if_false = NULL;
3324 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003325 context()->PrepareTest(&materialize_true, &materialize_false,
3326 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003327
3328 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3329 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003330 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3331 Split(eq, if_true, if_false, fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003332
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003333 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003334}
3335
3336
3337void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
3338 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003339 VisitForAccumulatorValue(args->at(0));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003340
3341 if (FLAG_debug_code) {
3342 __ AbortIfNotString(r0);
3343 }
3344
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003345 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
3346 __ IndexFromHash(r0, r0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00003347
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003348 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003349}
3350
3351
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003352void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003353 Label bailout, done, one_char_separator, long_separator,
3354 non_trivial_array, not_size_one_array, loop,
3355 empty_separator_loop, one_char_separator_loop,
3356 one_char_separator_loop_entry, long_separator_loop;
3357
3358 ASSERT(args->length() == 2);
3359 VisitForStackValue(args->at(1));
3360 VisitForAccumulatorValue(args->at(0));
3361
3362 // All aliases of the same register have disjoint lifetimes.
3363 Register array = r0;
3364 Register elements = no_reg; // Will be r0.
3365 Register result = no_reg; // Will be r0.
3366 Register separator = r1;
3367 Register array_length = r2;
3368 Register result_pos = no_reg; // Will be r2
3369 Register string_length = r3;
3370 Register string = r4;
3371 Register element = r5;
3372 Register elements_end = r6;
3373 Register scratch1 = r7;
3374 Register scratch2 = r9;
3375
3376 // Separator operand is on the stack.
3377 __ pop(separator);
3378
3379 // Check that the array is a JSArray.
3380 __ JumpIfSmi(array, &bailout);
3381 __ CompareObjectType(array, scratch1, scratch2, JS_ARRAY_TYPE);
3382 __ b(ne, &bailout);
3383
3384 // Check that the array has fast elements.
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +00003385 __ CheckFastElements(scratch1, scratch2, &bailout);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003386
3387 // If the array has length zero, return the empty string.
3388 __ ldr(array_length, FieldMemOperand(array, JSArray::kLengthOffset));
3389 __ SmiUntag(array_length, SetCC);
3390 __ b(ne, &non_trivial_array);
3391 __ LoadRoot(r0, Heap::kEmptyStringRootIndex);
3392 __ b(&done);
3393
3394 __ bind(&non_trivial_array);
3395
3396 // Get the FixedArray containing array's elements.
3397 elements = array;
3398 __ ldr(elements, FieldMemOperand(array, JSArray::kElementsOffset));
3399 array = no_reg; // End of array's live range.
3400
3401 // Check that all array elements are sequential ASCII strings, and
3402 // accumulate the sum of their lengths, as a smi-encoded value.
3403 __ mov(string_length, Operand(0));
3404 __ add(element,
3405 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3406 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3407 // Loop condition: while (element < elements_end).
3408 // Live values in registers:
3409 // elements: Fixed array of strings.
3410 // array_length: Length of the fixed array of strings (not smi)
3411 // separator: Separator string
3412 // string_length: Accumulated sum of string lengths (smi).
3413 // element: Current array element.
3414 // elements_end: Array end.
3415 if (FLAG_debug_code) {
3416 __ cmp(array_length, Operand(0));
3417 __ Assert(gt, "No empty arrays here in EmitFastAsciiArrayJoin");
3418 }
3419 __ bind(&loop);
3420 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3421 __ JumpIfSmi(string, &bailout);
3422 __ ldr(scratch1, FieldMemOperand(string, HeapObject::kMapOffset));
3423 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3424 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3425 __ ldr(scratch1, FieldMemOperand(string, SeqAsciiString::kLengthOffset));
3426 __ add(string_length, string_length, Operand(scratch1));
3427 __ b(vs, &bailout);
3428 __ cmp(element, elements_end);
3429 __ b(lt, &loop);
3430
3431 // If array_length is 1, return elements[0], a string.
3432 __ cmp(array_length, Operand(1));
3433 __ b(ne, &not_size_one_array);
3434 __ ldr(r0, FieldMemOperand(elements, FixedArray::kHeaderSize));
3435 __ b(&done);
3436
3437 __ bind(&not_size_one_array);
3438
3439 // Live values in registers:
3440 // separator: Separator string
3441 // array_length: Length of the array.
3442 // string_length: Sum of string lengths (smi).
3443 // elements: FixedArray of strings.
3444
3445 // Check that the separator is a flat ASCII string.
3446 __ JumpIfSmi(separator, &bailout);
3447 __ ldr(scratch1, FieldMemOperand(separator, HeapObject::kMapOffset));
3448 __ ldrb(scratch1, FieldMemOperand(scratch1, Map::kInstanceTypeOffset));
3449 __ JumpIfInstanceTypeIsNotSequentialAscii(scratch1, scratch2, &bailout);
3450
3451 // Add (separator length times array_length) - separator length to the
3452 // string_length to get the length of the result string. array_length is not
3453 // smi but the other values are, so the result is a smi
3454 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3455 __ sub(string_length, string_length, Operand(scratch1));
3456 __ smull(scratch2, ip, array_length, scratch1);
3457 // Check for smi overflow. No overflow if higher 33 bits of 64-bit result are
3458 // zero.
3459 __ cmp(ip, Operand(0));
3460 __ b(ne, &bailout);
3461 __ tst(scratch2, Operand(0x80000000));
3462 __ b(ne, &bailout);
3463 __ add(string_length, string_length, Operand(scratch2));
3464 __ b(vs, &bailout);
3465 __ SmiUntag(string_length);
3466
3467 // Get first element in the array to free up the elements register to be used
3468 // for the result.
3469 __ add(element,
3470 elements, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
3471 result = elements; // End of live range for elements.
3472 elements = no_reg;
3473 // Live values in registers:
3474 // element: First array element
3475 // separator: Separator string
3476 // string_length: Length of result string (not smi)
3477 // array_length: Length of the array.
3478 __ AllocateAsciiString(result,
3479 string_length,
3480 scratch1,
3481 scratch2,
3482 elements_end,
3483 &bailout);
3484 // Prepare for looping. Set up elements_end to end of the array. Set
3485 // result_pos to the position of the result where to write the first
3486 // character.
3487 __ add(elements_end, element, Operand(array_length, LSL, kPointerSizeLog2));
3488 result_pos = array_length; // End of live range for array_length.
3489 array_length = no_reg;
3490 __ add(result_pos,
3491 result,
3492 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3493
3494 // Check the length of the separator.
3495 __ ldr(scratch1, FieldMemOperand(separator, SeqAsciiString::kLengthOffset));
3496 __ cmp(scratch1, Operand(Smi::FromInt(1)));
3497 __ b(eq, &one_char_separator);
3498 __ b(gt, &long_separator);
3499
3500 // Empty separator case
3501 __ bind(&empty_separator_loop);
3502 // Live values in registers:
3503 // result_pos: the position to which we are currently copying characters.
3504 // element: Current array element.
3505 // elements_end: Array end.
3506
3507 // Copy next array element to the result.
3508 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3509 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3510 __ SmiUntag(string_length);
3511 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3512 __ CopyBytes(string, result_pos, string_length, scratch1);
3513 __ cmp(element, elements_end);
3514 __ b(lt, &empty_separator_loop); // End while (element < elements_end).
3515 ASSERT(result.is(r0));
3516 __ b(&done);
3517
3518 // One-character separator case
3519 __ bind(&one_char_separator);
3520 // Replace separator with its ascii character value.
3521 __ ldrb(separator, FieldMemOperand(separator, SeqAsciiString::kHeaderSize));
3522 // Jump into the loop after the code that copies the separator, so the first
3523 // element is not preceded by a separator
3524 __ jmp(&one_char_separator_loop_entry);
3525
3526 __ bind(&one_char_separator_loop);
3527 // Live values in registers:
3528 // result_pos: the position to which we are currently copying characters.
3529 // element: Current array element.
3530 // elements_end: Array end.
3531 // separator: Single separator ascii char (in lower byte).
3532
3533 // Copy the separator character to the result.
3534 __ strb(separator, MemOperand(result_pos, 1, PostIndex));
3535
3536 // Copy next array element to the result.
3537 __ bind(&one_char_separator_loop_entry);
3538 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3539 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3540 __ SmiUntag(string_length);
3541 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3542 __ CopyBytes(string, result_pos, string_length, scratch1);
3543 __ cmp(element, elements_end);
3544 __ b(lt, &one_char_separator_loop); // End while (element < elements_end).
3545 ASSERT(result.is(r0));
3546 __ b(&done);
3547
3548 // Long separator case (separator is more than one character). Entry is at the
3549 // label long_separator below.
3550 __ bind(&long_separator_loop);
3551 // Live values in registers:
3552 // result_pos: the position to which we are currently copying characters.
3553 // element: Current array element.
3554 // elements_end: Array end.
3555 // separator: Separator string.
3556
3557 // Copy the separator to the result.
3558 __ ldr(string_length, FieldMemOperand(separator, String::kLengthOffset));
3559 __ SmiUntag(string_length);
3560 __ add(string,
3561 separator,
3562 Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3563 __ CopyBytes(string, result_pos, string_length, scratch1);
3564
3565 __ bind(&long_separator);
3566 __ ldr(string, MemOperand(element, kPointerSize, PostIndex));
3567 __ ldr(string_length, FieldMemOperand(string, String::kLengthOffset));
3568 __ SmiUntag(string_length);
3569 __ add(string, string, Operand(SeqAsciiString::kHeaderSize - kHeapObjectTag));
3570 __ CopyBytes(string, result_pos, string_length, scratch1);
3571 __ cmp(element, elements_end);
3572 __ b(lt, &long_separator_loop); // End while (element < elements_end).
3573 ASSERT(result.is(r0));
3574 __ b(&done);
3575
3576 __ bind(&bailout);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003577 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00003578 __ bind(&done);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003579 context()->Plug(r0);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00003580}
3581
3582
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003583void FullCodeGenerator::EmitIsNativeOrStrictMode(ZoneList<Expression*>* args) {
3584 ASSERT(args->length() == 1);
3585
3586 // Load the function into r0.
3587 VisitForAccumulatorValue(args->at(0));
3588
3589 // Prepare for the test.
3590 Label materialize_true, materialize_false;
3591 Label* if_true = NULL;
3592 Label* if_false = NULL;
3593 Label* fall_through = NULL;
3594 context()->PrepareTest(&materialize_true, &materialize_false,
3595 &if_true, &if_false, &fall_through);
3596
3597 // Test for strict mode function.
3598 __ ldr(r1, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
3599 __ ldr(r1, FieldMemOperand(r1, SharedFunctionInfo::kCompilerHintsOffset));
3600 __ tst(r1, Operand(1 << (SharedFunctionInfo::kStrictModeFunction +
3601 kSmiTagSize)));
3602 __ b(ne, if_true);
3603
3604 // Test for native function.
3605 __ tst(r1, Operand(1 << (SharedFunctionInfo::kNative + kSmiTagSize)));
3606 __ b(ne, if_true);
3607
3608 // Not native or strict-mode function.
3609 __ b(if_false);
3610
3611 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
3612 context()->Plug(if_true, if_false);
3613}
3614
3615
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003616void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003617 Handle<String> name = expr->name();
3618 if (name->length() > 0 && name->Get(0) == '_') {
3619 Comment cmnt(masm_, "[ InlineRuntimeCall");
3620 EmitInlineRuntimeCall(expr);
3621 return;
3622 }
3623
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003624 Comment cmnt(masm_, "[ CallRuntime");
3625 ZoneList<Expression*>* args = expr->arguments();
3626
3627 if (expr->is_jsruntime()) {
3628 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003629 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003630 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +00003631 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003632 }
3633
3634 // Push the arguments ("left-to-right").
3635 int arg_count = args->length();
3636 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003637 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003638 }
3639
3640 if (expr->is_jsruntime()) {
3641 // Call the JS runtime function.
ager@chromium.org5c838252010-02-19 08:53:10 +00003642 __ mov(r2, Operand(expr->name()));
danno@chromium.org40cb8782011-05-25 07:58:50 +00003643 RelocInfo::Mode mode = RelocInfo::CODE_TARGET;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003644 Handle<Code> ic =
danno@chromium.org40cb8782011-05-25 07:58:50 +00003645 isolate()->stub_cache()->ComputeCallInitialize(arg_count,
3646 NOT_IN_LOOP,
3647 mode);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003648 __ Call(ic, mode, expr->id());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003649 // Restore context register.
3650 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003651 } else {
3652 // Call the C runtime function.
3653 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003654 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003655 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003656}
3657
3658
3659void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
3660 switch (expr->op()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003661 case Token::DELETE: {
3662 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
3663 Property* prop = expr->expression()->AsProperty();
3664 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003665
3666 if (prop != NULL) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003667 if (prop->is_synthetic()) {
3668 // Result of deleting parameters is false, even when they rewrite
3669 // to accesses on the arguments object.
3670 context()->Plug(false);
3671 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003672 VisitForStackValue(prop->obj());
3673 VisitForStackValue(prop->key());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003674 __ mov(r1, Operand(Smi::FromInt(strict_mode_flag())));
3675 __ push(r1);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003676 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003677 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003678 }
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003679 } else if (var != NULL) {
3680 // Delete of an unqualified identifier is disallowed in strict mode
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003681 // but "delete this" is.
3682 ASSERT(strict_mode_flag() == kNonStrictMode || var->is_this());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003683 if (var->is_global()) {
3684 __ ldr(r2, GlobalObjectOperand());
3685 __ mov(r1, Operand(var->name()));
3686 __ mov(r0, Operand(Smi::FromInt(kNonStrictMode)));
3687 __ Push(r2, r1, r0);
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003688 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003689 context()->Plug(r0);
3690 } else if (var->AsSlot() != NULL &&
3691 var->AsSlot()->type() != Slot::LOOKUP) {
3692 // Result of deleting non-global, non-dynamic variables is false.
3693 // The subexpression does not have side effects.
3694 context()->Plug(false);
3695 } else {
3696 // Non-global variable. Call the runtime to try to delete from the
3697 // context where the variable was introduced.
3698 __ push(context_register());
3699 __ mov(r2, Operand(var->name()));
3700 __ push(r2);
3701 __ CallRuntime(Runtime::kDeleteContextSlot, 2);
3702 context()->Plug(r0);
3703 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00003704 } else {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003705 // Result of deleting non-property, non-variable reference is true.
3706 // The subexpression may have side effects.
3707 VisitForEffect(expr->expression());
3708 context()->Plug(true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003709 }
3710 break;
3711 }
3712
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003713 case Token::VOID: {
3714 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
3715 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003716 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003717 break;
3718 }
3719
3720 case Token::NOT: {
3721 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003722 if (context()->IsEffect()) {
3723 // Unary NOT has no side effects so it's only necessary to visit the
3724 // subexpression. Match the optimizing compiler by not branching.
3725 VisitForEffect(expr->expression());
3726 } else {
3727 Label materialize_true, materialize_false;
3728 Label* if_true = NULL;
3729 Label* if_false = NULL;
3730 Label* fall_through = NULL;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003731
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00003732 // Notice that the labels are swapped.
3733 context()->PrepareTest(&materialize_true, &materialize_false,
3734 &if_false, &if_true, &fall_through);
3735 if (context()->IsTest()) ForwardBailoutToChild(expr);
3736 VisitForControl(expr->expression(), if_true, if_false, fall_through);
3737 context()->Plug(if_false, if_true); // Labels swapped.
3738 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003739 break;
3740 }
3741
3742 case Token::TYPEOF: {
3743 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003744 { StackValueContext context(this);
3745 VisitForTypeofValue(expr->expression());
3746 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003747 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003748 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003749 break;
3750 }
3751
3752 case Token::ADD: {
3753 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003754 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003755 Label no_conversion;
whesse@chromium.org7b260152011-06-20 15:33:18 +00003756 __ JumpIfSmi(result_register(), &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003757 ToNumberStub convert_stub;
3758 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003759 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003760 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003761 break;
3762 }
3763
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003764 case Token::SUB:
3765 EmitUnaryOperation(expr, "[ UnaryOperation (SUB)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003766 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003767
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003768 case Token::BIT_NOT:
3769 EmitUnaryOperation(expr, "[ UnaryOperation (BIT_NOT)");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003770 break;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003771
3772 default:
3773 UNREACHABLE();
3774 }
3775}
3776
3777
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003778void FullCodeGenerator::EmitUnaryOperation(UnaryOperation* expr,
3779 const char* comment) {
3780 // TODO(svenpanne): Allowing format strings in Comment would be nice here...
3781 Comment cmt(masm_, comment);
3782 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
3783 UnaryOverwriteMode overwrite =
3784 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
danno@chromium.org40cb8782011-05-25 07:58:50 +00003785 UnaryOpStub stub(expr->op(), overwrite);
3786 // UnaryOpStub expects the argument to be in the
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003787 // accumulator register r0.
3788 VisitForAccumulatorValue(expr->expression());
3789 SetSourcePosition(expr->position());
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003790 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->id());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00003791 context()->Plug(r0);
3792}
3793
3794
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003795void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
3796 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003797 SetSourcePosition(expr->position());
3798
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003799 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
3800 // as the left-hand side.
3801 if (!expr->expression()->IsValidLeftHandSide()) {
3802 VisitForEffect(expr->expression());
3803 return;
3804 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003805
3806 // Expression can only be a property, a global or a (parameter or local)
whesse@chromium.org7b260152011-06-20 15:33:18 +00003807 // slot.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003808 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
3809 LhsKind assign_type = VARIABLE;
3810 Property* prop = expr->expression()->AsProperty();
3811 // In case of a property we use the uninitialized expression context
3812 // of the key to detect a named property.
3813 if (prop != NULL) {
3814 assign_type =
3815 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
3816 }
3817
3818 // Evaluate expression and get value.
3819 if (assign_type == VARIABLE) {
3820 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003821 AccumulatorValueContext context(this);
whesse@chromium.org030d38e2011-07-13 13:23:34 +00003822 EmitVariableLoad(expr->expression()->AsVariableProxy());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003823 } else {
3824 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003825 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003826 __ mov(ip, Operand(Smi::FromInt(0)));
3827 __ push(ip);
3828 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003829 if (assign_type == NAMED_PROPERTY) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003830 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003831 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003832 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003833 EmitNamedPropertyLoad(prop);
3834 } else {
whesse@chromium.org7b260152011-06-20 15:33:18 +00003835 VisitForStackValue(prop->obj());
3836 VisitForAccumulatorValue(prop->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003837 __ ldr(r1, MemOperand(sp, 0));
3838 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003839 EmitKeyedPropertyLoad(prop);
3840 }
3841 }
3842
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003843 // We need a second deoptimization point after loading the value
3844 // in case evaluating the property load my have a side effect.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003845 if (assign_type == VARIABLE) {
3846 PrepareForBailout(expr->expression(), TOS_REG);
3847 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00003848 PrepareForBailoutForId(expr->CountId(), TOS_REG);
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003849 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003850
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003851 // Call ToNumber only if operand is not a smi.
3852 Label no_conversion;
ager@chromium.org378b34e2011-01-28 08:04:38 +00003853 __ JumpIfSmi(r0, &no_conversion);
whesse@chromium.org7a392b32011-01-31 11:30:36 +00003854 ToNumberStub convert_stub;
3855 __ CallStub(&convert_stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003856 __ bind(&no_conversion);
3857
3858 // Save result for postfix expressions.
3859 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003860 if (!context()->IsEffect()) {
3861 // Save the result on the stack. If we have a named or keyed property
3862 // we store the result under the receiver that is currently on top
3863 // of the stack.
3864 switch (assign_type) {
3865 case VARIABLE:
3866 __ push(r0);
3867 break;
3868 case NAMED_PROPERTY:
3869 __ str(r0, MemOperand(sp, kPointerSize));
3870 break;
3871 case KEYED_PROPERTY:
3872 __ str(r0, MemOperand(sp, 2 * kPointerSize));
3873 break;
3874 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003875 }
3876 }
3877
3878
3879 // Inline smi case if we are in a loop.
3880 Label stub_call, done;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003881 JumpPatchSite patch_site(masm_);
3882
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003883 int count_value = expr->op() == Token::INC ? 1 : -1;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003884 if (ShouldInlineSmiCase(expr->op())) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003885 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003886 __ b(vs, &stub_call);
3887 // We could eliminate this smi check if we split the code at
3888 // the first smi check before calling ToNumber.
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00003889 patch_site.EmitJumpIfSmi(r0, &done);
3890
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003891 __ bind(&stub_call);
3892 // Call stub. Undo operation first.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003893 __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003894 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003895 __ mov(r1, Operand(Smi::FromInt(count_value)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003896
3897 // Record position before stub call.
3898 SetSourcePosition(expr->position());
3899
danno@chromium.org40cb8782011-05-25 07:58:50 +00003900 BinaryOpStub stub(Token::ADD, NO_OVERWRITE);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003901 __ Call(stub.GetCode(), RelocInfo::CODE_TARGET, expr->CountId());
3902 patch_site.EmitPatchInfo();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003903 __ bind(&done);
3904
3905 // Store the value returned in r0.
3906 switch (assign_type) {
3907 case VARIABLE:
3908 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003909 { EffectContext context(this);
3910 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3911 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003912 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3913 context.Plug(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003914 }
3915 // For all contexts except EffectConstant We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003916 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003917 if (!context()->IsEffect()) {
3918 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003919 }
3920 } else {
3921 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003922 Token::ASSIGN);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003923 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
3924 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003925 }
3926 break;
3927 case NAMED_PROPERTY: {
3928 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
ager@chromium.org5c838252010-02-19 08:53:10 +00003929 __ pop(r1);
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003930 Handle<Code> ic = is_strict_mode()
3931 ? isolate()->builtins()->StoreIC_Initialize_Strict()
3932 : isolate()->builtins()->StoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003933 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003934 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003935 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003936 if (!context()->IsEffect()) {
3937 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003938 }
3939 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003940 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003941 }
3942 break;
3943 }
3944 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003945 __ pop(r1); // Key.
3946 __ pop(r2); // Receiver.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003947 Handle<Code> ic = is_strict_mode()
3948 ? isolate()->builtins()->KeyedStoreIC_Initialize_Strict()
3949 : isolate()->builtins()->KeyedStoreIC_Initialize();
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003950 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00003951 PrepareForBailoutForId(expr->AssignmentId(), TOS_REG);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003952 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003953 if (!context()->IsEffect()) {
3954 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003955 }
3956 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003957 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003958 }
3959 break;
3960 }
3961 }
3962}
3963
3964
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003965void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
3966 ASSERT(!context()->IsEffect());
3967 ASSERT(!context()->IsTest());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003968 VariableProxy* proxy = expr->AsVariableProxy();
3969 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3970 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003971 __ ldr(r0, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003972 __ mov(r2, Operand(proxy->name()));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00003973 Handle<Code> ic = isolate()->builtins()->LoadIC_Initialize();
ricow@chromium.org65fae842010-08-25 15:26:24 +00003974 // Use a regular load, not a contextual load, to avoid a reference
3975 // error.
ricow@chromium.org4f693d62011-07-04 14:01:31 +00003976 __ Call(ic);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003977 PrepareForBailout(expr, TOS_REG);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003978 context()->Plug(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003979 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003980 proxy->var()->AsSlot() != NULL &&
3981 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003982 Label done, slow;
3983
3984 // Generate code for loading from variables potentially shadowed
3985 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003986 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003987 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3988
3989 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003990 __ mov(r0, Operand(proxy->name()));
3991 __ Push(cp, r0);
3992 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003993 PrepareForBailout(expr, TOS_REG);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003994 __ bind(&done);
3995
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003996 context()->Plug(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003997 } else {
3998 // This expression cannot throw a reference error at the top level.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00003999 VisitInCurrentContext(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004000 }
4001}
4002
4003
ager@chromium.org04921a82011-06-27 13:21:41 +00004004void FullCodeGenerator::EmitLiteralCompareTypeof(Expression* expr,
4005 Handle<String> check,
4006 Label* if_true,
4007 Label* if_false,
4008 Label* fall_through) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004009 { AccumulatorValueContext context(this);
ager@chromium.org04921a82011-06-27 13:21:41 +00004010 VisitForTypeofValue(expr);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004011 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004012 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4013
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004014 if (check->Equals(isolate()->heap()->number_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004015 __ JumpIfSmi(r0, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004016 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
4017 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
4018 __ cmp(r0, ip);
4019 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004020 } else if (check->Equals(isolate()->heap()->string_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004021 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004022 // Check for undetectable objects => false.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004023 __ CompareObjectType(r0, r0, r1, FIRST_NONSTRING_TYPE);
4024 __ b(ge, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004025 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004026 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4027 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004028 } else if (check->Equals(isolate()->heap()->boolean_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004029 __ CompareRoot(r0, Heap::kTrueValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004030 __ b(eq, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004031 __ CompareRoot(r0, Heap::kFalseValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004032 Split(eq, if_true, if_false, fall_through);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004033 } else if (FLAG_harmony_typeof &&
4034 check->Equals(isolate()->heap()->null_symbol())) {
4035 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4036 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004037 } else if (check->Equals(isolate()->heap()->undefined_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004038 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004039 __ b(eq, if_true);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004040 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004041 // Check for undetectable objects => true.
4042 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
4043 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004044 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4045 Split(ne, if_true, if_false, fall_through);
4046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004047 } else if (check->Equals(isolate()->heap()->function_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004048 __ JumpIfSmi(r0, if_false);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004049 __ CompareObjectType(r0, r1, r0, FIRST_CALLABLE_SPEC_OBJECT_TYPE);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004050 Split(ge, if_true, if_false, fall_through);
4051
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004052 } else if (check->Equals(isolate()->heap()->object_symbol())) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004053 __ JumpIfSmi(r0, if_false);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00004054 if (!FLAG_harmony_typeof) {
4055 __ CompareRoot(r0, Heap::kNullValueRootIndex);
4056 __ b(eq, if_true);
4057 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00004058 // Check for JS objects => true.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004059 __ CompareObjectType(r0, r0, r1, FIRST_NONCALLABLE_SPEC_OBJECT_TYPE);
4060 __ b(lt, if_false);
4061 __ CompareInstanceType(r0, r1, LAST_NONCALLABLE_SPEC_OBJECT_TYPE);
4062 __ b(gt, if_false);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004063 // Check for undetectable objects => false.
4064 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
4065 __ tst(r1, Operand(1 << Map::kIsUndetectable));
4066 Split(eq, if_true, if_false, fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004067 } else {
4068 if (if_false != fall_through) __ jmp(if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004069 }
ager@chromium.org04921a82011-06-27 13:21:41 +00004070}
ricow@chromium.org65fae842010-08-25 15:26:24 +00004071
ager@chromium.org04921a82011-06-27 13:21:41 +00004072
4073void FullCodeGenerator::EmitLiteralCompareUndefined(Expression* expr,
4074 Label* if_true,
4075 Label* if_false,
4076 Label* fall_through) {
4077 VisitForAccumulatorValue(expr);
4078 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
4079
4080 __ CompareRoot(r0, Heap::kUndefinedValueRootIndex);
4081 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004082}
4083
4084
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004085void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
4086 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00004087 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004088
4089 // Always perform the comparison for its control flow. Pack the result
4090 // into the expression's context after the comparison is performed.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00004091
4092 Label materialize_true, materialize_false;
4093 Label* if_true = NULL;
4094 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004095 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004096 context()->PrepareTest(&materialize_true, &materialize_false,
4097 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004098
4099 // First we try a fast inlined version of the compare when one of
4100 // the operands is a literal.
ager@chromium.org04921a82011-06-27 13:21:41 +00004101 if (TryLiteralCompare(expr, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004102 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004103 return;
4104 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004105
ager@chromium.org04921a82011-06-27 13:21:41 +00004106 Token::Value op = expr->op();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004107 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00004108 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004109 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004110 VisitForStackValue(expr->right());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00004111 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004112 PrepareForBailoutBeforeSplit(TOS_REG, false, NULL, NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004113 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
4114 __ cmp(r0, ip);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004115 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004116 break;
4117
4118 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004119 VisitForStackValue(expr->right());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004120 InstanceofStub stub(InstanceofStub::kNoFlags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004121 __ CallStub(&stub);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004122 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004123 // The stub returns 0 for true.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004124 __ tst(r0, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004125 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004126 break;
4127 }
4128
4129 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004130 VisitForAccumulatorValue(expr->right());
ager@chromium.org378b34e2011-01-28 08:04:38 +00004131 Condition cond = eq;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004132 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00004133 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004134 case Token::EQ_STRICT:
4135 strict = true;
4136 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00004137 case Token::EQ:
ager@chromium.org378b34e2011-01-28 08:04:38 +00004138 cond = eq;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004139 __ pop(r1);
4140 break;
4141 case Token::LT:
ager@chromium.org378b34e2011-01-28 08:04:38 +00004142 cond = lt;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004143 __ pop(r1);
4144 break;
4145 case Token::GT:
4146 // Reverse left and right sides to obtain ECMA-262 conversion order.
ager@chromium.org378b34e2011-01-28 08:04:38 +00004147 cond = lt;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004148 __ mov(r1, result_register());
4149 __ pop(r0);
4150 break;
4151 case Token::LTE:
4152 // Reverse left and right sides to obtain ECMA-262 conversion order.
ager@chromium.org378b34e2011-01-28 08:04:38 +00004153 cond = ge;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004154 __ mov(r1, result_register());
4155 __ pop(r0);
4156 break;
4157 case Token::GTE:
ager@chromium.org378b34e2011-01-28 08:04:38 +00004158 cond = ge;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004159 __ pop(r1);
4160 break;
4161 case Token::IN:
4162 case Token::INSTANCEOF:
4163 default:
4164 UNREACHABLE();
4165 }
4166
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004167 bool inline_smi_code = ShouldInlineSmiCase(op);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004168 JumpPatchSite patch_site(masm_);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00004169 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00004170 Label slow_case;
4171 __ orr(r2, r0, Operand(r1));
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004172 patch_site.EmitJumpIfNotSmi(r2, &slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004173 __ cmp(r1, r0);
ager@chromium.org378b34e2011-01-28 08:04:38 +00004174 Split(cond, if_true, if_false, NULL);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004175 __ bind(&slow_case);
4176 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004177
4178 // Record position and call the compare IC.
4179 SetSourcePosition(expr->position());
4180 Handle<Code> ic = CompareIC::GetUninitialized(op);
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004181 __ Call(ic, RelocInfo::CODE_TARGET, expr->id());
4182 patch_site.EmitPatchInfo();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004183 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00004184 __ cmp(r0, Operand(0));
ager@chromium.org378b34e2011-01-28 08:04:38 +00004185 Split(cond, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004186 }
4187 }
4188
4189 // Convert the result of the comparison into one expected for this
4190 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004191 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004192}
4193
4194
ricow@chromium.org65fae842010-08-25 15:26:24 +00004195void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
4196 Comment cmnt(masm_, "[ CompareToNull");
4197 Label materialize_true, materialize_false;
4198 Label* if_true = NULL;
4199 Label* if_false = NULL;
4200 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004201 context()->PrepareTest(&materialize_true, &materialize_false,
4202 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004203
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004204 VisitForAccumulatorValue(expr->expression());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00004205 PrepareForBailoutBeforeSplit(TOS_REG, true, if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004206 __ LoadRoot(r1, Heap::kNullValueRootIndex);
4207 __ cmp(r0, r1);
4208 if (expr->is_strict()) {
4209 Split(eq, if_true, if_false, fall_through);
4210 } else {
4211 __ b(eq, if_true);
4212 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
4213 __ cmp(r0, r1);
4214 __ b(eq, if_true);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004215 __ JumpIfSmi(r0, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004216 // It can be an undetectable object.
4217 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
4218 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
4219 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
4220 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
4221 Split(eq, if_true, if_false, fall_through);
4222 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004223 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00004224}
4225
4226
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004227void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
4228 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00004229 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004230}
4231
4232
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004233Register FullCodeGenerator::result_register() {
4234 return r0;
4235}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004236
4237
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00004238Register FullCodeGenerator::context_register() {
4239 return cp;
4240}
4241
4242
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004243void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
4244 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
4245 __ str(value, MemOperand(fp, frame_offset));
4246}
4247
4248
4249void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00004250 __ ldr(dst, ContextOperand(cp, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004251}
4252
4253
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004254void FullCodeGenerator::PushFunctionArgumentForContextAllocation() {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004255 Scope* declaration_scope = scope()->DeclarationScope();
4256 if (declaration_scope->is_global_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004257 // Contexts nested in the global context have a canonical empty function
4258 // as their closure, not the anonymous closure containing the global
4259 // code. Pass a smi sentinel and let the runtime look up the empty
4260 // function.
4261 __ mov(ip, Operand(Smi::FromInt(0)));
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004262 } else if (declaration_scope->is_eval_scope()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004263 // Contexts created by a call to eval have the same closure as the
4264 // context calling eval, not the anonymous closure containing the eval
4265 // code. Fetch it from the context.
4266 __ ldr(ip, ContextOperand(cp, Context::CLOSURE_INDEX));
4267 } else {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004268 ASSERT(declaration_scope->is_function_scope());
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00004269 __ ldr(ip, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
4270 }
4271 __ push(ip);
4272}
4273
4274
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004275// ----------------------------------------------------------------------------
4276// Non-local control flow support.
4277
4278void FullCodeGenerator::EnterFinallyBlock() {
4279 ASSERT(!result_register().is(r1));
4280 // Store result register while executing finally block.
4281 __ push(result_register());
4282 // Cook return address in link register to stack (smi encoded Code* delta)
4283 __ sub(r1, lr, Operand(masm_->CodeObject()));
4284 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4285 ASSERT_EQ(0, kSmiTag);
4286 __ add(r1, r1, Operand(r1)); // Convert to smi.
4287 __ push(r1);
4288}
4289
4290
4291void FullCodeGenerator::ExitFinallyBlock() {
4292 ASSERT(!result_register().is(r1));
4293 // Restore result register from stack.
4294 __ pop(r1);
4295 // Uncook return address and return.
4296 __ pop(result_register());
4297 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
4298 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
4299 __ add(pc, r1, Operand(masm_->CodeObject()));
4300}
4301
4302
4303#undef __
4304
4305} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00004306
4307#endif // V8_TARGET_ARCH_ARM