blob: 0823f77865c382a22e61099109f36246bce561f4 [file] [log] [blame]
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +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
30#include "bootstrapper.h"
31#include "codegen-inl.h"
32#include "debug.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000033#include "parser.h"
34#include "register-allocator-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000035#include "runtime.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000036#include "scopes.h"
37
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038
39namespace v8 { namespace internal {
40
ager@chromium.org3bf7b912008-11-17 09:09:45 +000041#define __ masm_->
42
43// -------------------------------------------------------------------------
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000044// CodeGenState implementation.
45
ager@chromium.org7c537e22008-10-16 08:43:32 +000046CodeGenState::CodeGenState(CodeGenerator* owner)
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000047 : owner_(owner),
ager@chromium.org7c537e22008-10-16 08:43:32 +000048 typeof_state_(NOT_INSIDE_TYPEOF),
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000049 true_target_(NULL),
50 false_target_(NULL),
51 previous_(NULL) {
52 owner_->set_state(this);
53}
54
55
ager@chromium.org7c537e22008-10-16 08:43:32 +000056CodeGenState::CodeGenState(CodeGenerator* owner,
57 TypeofState typeof_state,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000058 JumpTarget* true_target,
59 JumpTarget* false_target)
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000060 : owner_(owner),
ager@chromium.org7c537e22008-10-16 08:43:32 +000061 typeof_state_(typeof_state),
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000062 true_target_(true_target),
63 false_target_(false_target),
64 previous_(owner->state()) {
65 owner_->set_state(this);
66}
67
68
kasperl@chromium.orgb9123622008-09-17 14:05:56 +000069CodeGenState::~CodeGenState() {
70 ASSERT(owner_->state() == this);
71 owner_->set_state(previous_);
72}
73
74
ager@chromium.org3bf7b912008-11-17 09:09:45 +000075// -------------------------------------------------------------------------
ager@chromium.org7c537e22008-10-16 08:43:32 +000076// CodeGenerator implementation
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000077
ager@chromium.org7c537e22008-10-16 08:43:32 +000078CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
79 bool is_eval)
80 : is_eval_(is_eval),
81 script_(script),
82 deferred_(8),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000083 masm_(new MacroAssembler(NULL, buffer_size)),
84 scope_(NULL),
ager@chromium.org3bf7b912008-11-17 09:09:45 +000085 frame_(NULL),
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000086 allocator_(NULL),
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000087 cc_reg_(al),
88 state_(NULL),
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000089 function_return_is_shadowed_(false),
90 in_spilled_code_(false) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000091}
92
93
94// Calling conventions:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000095// fp: caller's frame pointer
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// sp: stack pointer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +000097// r1: called JS function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000098// cp: callee's context
99
ager@chromium.org7c537e22008-10-16 08:43:32 +0000100void CodeGenerator::GenCode(FunctionLiteral* fun) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000101 ZoneList<Statement*>* body = fun->body();
102
103 // Initialize state.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000104 ASSERT(scope_ == NULL);
105 scope_ = fun->scope();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000106 ASSERT(allocator_ == NULL);
107 RegisterAllocator register_allocator(this);
108 allocator_ = &register_allocator;
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000109 ASSERT(frame_ == NULL);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000110 frame_ = new VirtualFrame(this);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000111 cc_reg_ = al;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000112 set_in_spilled_code(false);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000113 {
114 CodeGenState state(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000115
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000116 // Entry:
117 // Stack: receiver, arguments
118 // lr: return address
119 // fp: caller's frame pointer
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000120 // sp: stack pointer
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000121 // r1: called JS function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000122 // cp: callee's context
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000123 allocator_->Initialize();
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000124 frame_->Enter();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000125 // tos: code slot
126#ifdef DEBUG
127 if (strlen(FLAG_stop_at) > 0 &&
128 fun->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000129 frame_->SpillAll();
kasper.lund7276f142008-07-30 08:49:36 +0000130 __ stop("stop-at");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000131 }
132#endif
133
134 // Allocate space for locals and initialize them.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000135 frame_->AllocateStackSlots(scope_->num_stack_slots());
136 // Initialize the function return target after the locals are set
137 // up, because it needs the expected frame height from the frame.
138 function_return_.Initialize(this, JumpTarget::BIDIRECTIONAL);
139 function_return_is_shadowed_ = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000140
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000141 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000142 if (scope_->num_heap_slots() > 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000143 // Allocate local context.
144 // Get outer context and create a new context based on it.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000145 __ ldr(r0, frame_->Function());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000146 frame_->EmitPush(r0);
147 frame_->CallRuntime(Runtime::kNewContext, 1); // r0 holds the result
kasper.lund7276f142008-07-30 08:49:36 +0000148
149 if (kDebug) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000150 JumpTarget verified_true(this);
kasper.lund7276f142008-07-30 08:49:36 +0000151 __ cmp(r0, Operand(cp));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000152 verified_true.Branch(eq);
kasper.lund7276f142008-07-30 08:49:36 +0000153 __ stop("NewContext: r0 is expected to be the same as cp");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000154 verified_true.Bind();
kasper.lund7276f142008-07-30 08:49:36 +0000155 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000156 // Update context local.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000157 __ str(cp, frame_->Context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000158 }
159
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000160 // TODO(1241774): Improve this code:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000161 // 1) only needed if we have a context
162 // 2) no need to recompute context ptr every single time
163 // 3) don't copy parameter operand code from SlotOperand!
164 {
165 Comment cmnt2(masm_, "[ copy context parameters into .context");
166
167 // Note that iteration order is relevant here! If we have the same
168 // parameter twice (e.g., function (x, y, x)), and that parameter
169 // needs to be copied into the context, it must be the last argument
170 // passed to the parameter that needs to be copied. This is a rare
171 // case so we don't check for it, instead we rely on the copying
172 // order: such a parameter is copied repeatedly into the same
173 // context location and thus the last value is what is seen inside
174 // the function.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000175 for (int i = 0; i < scope_->num_parameters(); i++) {
176 Variable* par = scope_->parameter(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000177 Slot* slot = par->slot();
178 if (slot != NULL && slot->type() == Slot::CONTEXT) {
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000179 ASSERT(!scope_->is_global_scope()); // no parameters in global scope
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000180 __ ldr(r1, frame_->ParameterAt(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000181 // Loads r2 with context; used below in RecordWrite.
182 __ str(r1, SlotOperand(slot, r2));
183 // Load the offset into r3.
184 int slot_offset =
185 FixedArray::kHeaderSize + slot->index() * kPointerSize;
186 __ mov(r3, Operand(slot_offset));
187 __ RecordWrite(r2, r3, r1);
188 }
189 }
190 }
191
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000192 // Store the arguments object. This must happen after context
193 // initialization because the arguments object may be stored in the
194 // context.
195 if (scope_->arguments() != NULL) {
196 ASSERT(scope_->arguments_shadow() != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000197 Comment cmnt(masm_, "[ allocate arguments object");
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000198 { Reference shadow_ref(this, scope_->arguments_shadow());
199 { Reference arguments_ref(this, scope_->arguments());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000200 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000201 __ ldr(r2, frame_->Function());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000202 // The receiver is below the arguments, the return address,
203 // and the frame pointer on the stack.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000204 const int kReceiverDisplacement = 2 + scope_->num_parameters();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000205 __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000206 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000207 frame_->Adjust(3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000208 __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000209 frame_->CallStub(&stub, 3);
210 frame_->EmitPush(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000211 arguments_ref.SetValue(NOT_CONST_INIT);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000212 }
ager@chromium.org7c537e22008-10-16 08:43:32 +0000213 shadow_ref.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000214 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000215 frame_->Drop(); // Value is no longer needed.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000216 }
217
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000218 // Generate code to 'execute' declarations and initialize functions
219 // (source elements). In case of an illegal redeclaration we need to
220 // handle that instead of processing the declarations.
221 if (scope_->HasIllegalRedeclaration()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000222 Comment cmnt(masm_, "[ illegal redeclarations");
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000223 scope_->VisitIllegalRedeclaration(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000224 } else {
225 Comment cmnt(masm_, "[ declarations");
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000226 ProcessDeclarations(scope_->declarations());
227 // Bail out if a stack-overflow exception occurred when processing
228 // declarations.
kasper.lund212ac232008-07-16 07:07:30 +0000229 if (HasStackOverflow()) return;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000230 }
231
mads.s.ager31e71382008-08-13 09:32:07 +0000232 if (FLAG_trace) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000233 frame_->CallRuntime(Runtime::kTraceEnter, 0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000234 // Ignore the return value.
mads.s.ager31e71382008-08-13 09:32:07 +0000235 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000236 CheckStack();
237
238 // Compile the body of the function in a vanilla state. Don't
239 // bother compiling all the code if the scope has an illegal
240 // redeclaration.
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000241 if (!scope_->HasIllegalRedeclaration()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000242 Comment cmnt(masm_, "[ function body");
243#ifdef DEBUG
244 bool is_builtin = Bootstrapper::IsActive();
245 bool should_trace =
246 is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
mads.s.ager31e71382008-08-13 09:32:07 +0000247 if (should_trace) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000248 frame_->CallRuntime(Runtime::kDebugTrace, 0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000249 // Ignore the return value.
mads.s.ager31e71382008-08-13 09:32:07 +0000250 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000251#endif
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000252 VisitStatementsAndSpill(body);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000253 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000254 }
255
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000256 // Generate the return sequence if necessary.
257 if (frame_ != NULL || function_return_.is_linked()) {
258 // exit
259 // r0: result
260 // sp: stack pointer
261 // fp: frame pointer
262 // pp: parameter pointer
263 // cp: callee's context
264 __ mov(r0, Operand(Factory::undefined_value()));
mads.s.ager31e71382008-08-13 09:32:07 +0000265
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000266 function_return_.Bind();
267 if (FLAG_trace) {
268 // Push the return value on the stack as the parameter.
269 // Runtime::TraceExit returns the parameter as it is.
270 frame_->EmitPush(r0);
271 frame_->CallRuntime(Runtime::kTraceExit, 1);
272 }
273
274 // Tear down the frame which will restore the caller's frame pointer and
275 // the link register.
276 frame_->Exit();
277
278 __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
279 __ mov(pc, lr);
mads.s.ager31e71382008-08-13 09:32:07 +0000280 }
281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000282 // Code generation state must be reset.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000283 ASSERT(!has_cc());
284 ASSERT(state_ == NULL);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000285 ASSERT(!function_return_is_shadowed_);
286 function_return_.Unuse();
287 DeleteFrame();
288
289 // Process any deferred code using the register allocator.
290 if (HasStackOverflow()) {
291 ClearDeferred();
292 } else {
293 ProcessDeferred();
294 }
295
296 allocator_ = NULL;
297 scope_ = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000298}
299
300
ager@chromium.org7c537e22008-10-16 08:43:32 +0000301MemOperand CodeGenerator::SlotOperand(Slot* slot, Register tmp) {
302 // Currently, this assertion will fail if we try to assign to
303 // a constant variable that is constant because it is read-only
304 // (such as the variable referring to a named function expression).
305 // We need to implement assignments to read-only variables.
306 // Ideally, we should do this during AST generation (by converting
307 // such assignments into expression statements); however, in general
308 // we may not be able to make the decision until past AST generation,
309 // that is when the entire program is known.
310 ASSERT(slot != NULL);
311 int index = slot->index();
312 switch (slot->type()) {
313 case Slot::PARAMETER:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000314 return frame_->ParameterAt(index);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000315
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000316 case Slot::LOCAL:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000317 return frame_->LocalAt(index);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000318
319 case Slot::CONTEXT: {
320 // Follow the context chain if necessary.
321 ASSERT(!tmp.is(cp)); // do not overwrite context register
322 Register context = cp;
323 int chain_length = scope()->ContextChainLength(slot->var()->scope());
ager@chromium.org381abbb2009-02-25 13:23:22 +0000324 for (int i = 0; i < chain_length; i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000325 // Load the closure.
326 // (All contexts, even 'with' contexts, have a closure,
327 // and it is the same for all contexts inside a function.
328 // There is no need to go to the function context first.)
329 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
330 // Load the function context (which is the incoming, outer context).
331 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
332 context = tmp;
333 }
334 // We may have a 'with' context now. Get the function context.
335 // (In fact this mov may never be the needed, since the scope analysis
336 // may not permit a direct context access in this case and thus we are
337 // always at a function context. However it is safe to dereference be-
338 // cause the function context of a function context is itself. Before
339 // deleting this mov we should try to create a counter-example first,
340 // though...)
341 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
342 return ContextOperand(tmp, index);
343 }
344
345 default:
346 UNREACHABLE();
347 return MemOperand(r0, 0);
348 }
349}
350
351
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000352MemOperand CodeGenerator::ContextSlotOperandCheckExtensions(
353 Slot* slot,
354 Register tmp,
355 Register tmp2,
356 JumpTarget* slow) {
ager@chromium.org381abbb2009-02-25 13:23:22 +0000357 ASSERT(slot->type() == Slot::CONTEXT);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000358 Register context = cp;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000359
ager@chromium.org381abbb2009-02-25 13:23:22 +0000360 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
361 if (s->num_heap_slots() > 0) {
362 if (s->calls_eval()) {
363 // Check that extension is NULL.
364 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
365 __ tst(tmp2, tmp2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000366 slow->Branch(ne);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000367 }
368 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
369 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
370 context = tmp;
371 }
372 }
373 // Check that last extension is NULL.
374 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
375 __ tst(tmp2, tmp2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000376 slow->Branch(ne);
ager@chromium.org381abbb2009-02-25 13:23:22 +0000377 __ ldr(tmp, ContextOperand(context, Context::FCONTEXT_INDEX));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000378 return ContextOperand(tmp, slot->index());
ager@chromium.org381abbb2009-02-25 13:23:22 +0000379}
380
381
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000382void CodeGenerator::LoadConditionAndSpill(Expression* expression,
383 TypeofState typeof_state,
384 JumpTarget* true_target,
385 JumpTarget* false_target,
386 bool force_control) {
387 ASSERT(in_spilled_code());
388 set_in_spilled_code(false);
389 LoadCondition(expression, typeof_state, true_target, false_target,
390 force_control);
391 if (frame_ != NULL) {
392 frame_->SpillAll();
393 }
394 set_in_spilled_code(true);
395}
396
397
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000398// Loads a value on TOS. If it is a boolean value, the result may have been
399// (partially) translated into branches, or it may have set the condition
400// code register. If force_cc is set, the value is forced to set the
401// condition code register and no value is pushed. If the condition code
402// register was set, has_cc() is true and cc_reg_ contains the condition to
403// test for 'true'.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000404void CodeGenerator::LoadCondition(Expression* x,
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000405 TypeofState typeof_state,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000406 JumpTarget* true_target,
407 JumpTarget* false_target,
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000408 bool force_cc) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000409 ASSERT(!in_spilled_code());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000410 ASSERT(!has_cc());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000411 int original_height = frame_->height();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000412
ager@chromium.org7c537e22008-10-16 08:43:32 +0000413 { CodeGenState new_state(this, typeof_state, true_target, false_target);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000414 Visit(x);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000415
416 // If we hit a stack overflow, we may not have actually visited
417 // the expression. In that case, we ensure that we have a
418 // valid-looking frame state because we will continue to generate
419 // code as we unwind the C++ stack.
420 //
421 // It's possible to have both a stack overflow and a valid frame
422 // state (eg, a subexpression overflowed, visiting it returned
423 // with a dummied frame state, and visiting this expression
424 // returned with a normal-looking state).
425 if (HasStackOverflow() &&
426 has_valid_frame() &&
427 !has_cc() &&
428 frame_->height() == original_height) {
429 true_target->Jump();
430 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +0000431 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000432 if (force_cc && frame_ != NULL && !has_cc()) {
mads.s.ager31e71382008-08-13 09:32:07 +0000433 // Convert the TOS value to a boolean in the condition code register.
434 ToBoolean(true_target, false_target);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000435 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000436 ASSERT(!force_cc || !has_valid_frame() || has_cc());
437 ASSERT(!has_valid_frame() ||
438 (has_cc() && frame_->height() == original_height) ||
439 (!has_cc() && frame_->height() == original_height + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000440}
441
442
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000443void CodeGenerator::LoadAndSpill(Expression* expression,
444 TypeofState typeof_state) {
445 ASSERT(in_spilled_code());
446 set_in_spilled_code(false);
447 Load(expression, typeof_state);
448 frame_->SpillAll();
449 set_in_spilled_code(true);
450}
451
452
ager@chromium.org7c537e22008-10-16 08:43:32 +0000453void CodeGenerator::Load(Expression* x, TypeofState typeof_state) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000454#ifdef DEBUG
455 int original_height = frame_->height();
456#endif
457 ASSERT(!in_spilled_code());
458 JumpTarget true_target(this);
459 JumpTarget false_target(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000460 LoadCondition(x, typeof_state, &true_target, &false_target, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000461
462 if (has_cc()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000463 // Convert cc_reg_ into a boolean value.
464 JumpTarget loaded(this);
465 JumpTarget materialize_true(this);
466 materialize_true.Branch(cc_reg_);
mads.s.ager31e71382008-08-13 09:32:07 +0000467 __ mov(r0, Operand(Factory::false_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000468 frame_->EmitPush(r0);
469 loaded.Jump();
470 materialize_true.Bind();
mads.s.ager31e71382008-08-13 09:32:07 +0000471 __ mov(r0, Operand(Factory::true_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000472 frame_->EmitPush(r0);
473 loaded.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000474 cc_reg_ = al;
475 }
476
477 if (true_target.is_linked() || false_target.is_linked()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000478 // We have at least one condition value that has been "translated"
479 // into a branch, thus it needs to be loaded explicitly.
480 JumpTarget loaded(this);
481 if (frame_ != NULL) {
482 loaded.Jump(); // Don't lose the current TOS.
483 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000484 bool both = true_target.is_linked() && false_target.is_linked();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000485 // Load "true" if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000486 if (true_target.is_linked()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000487 true_target.Bind();
mads.s.ager31e71382008-08-13 09:32:07 +0000488 __ mov(r0, Operand(Factory::true_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000489 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000490 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000491 // If both "true" and "false" need to be loaded jump across the code for
492 // "false".
493 if (both) {
494 loaded.Jump();
495 }
496 // Load "false" if necessary.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000497 if (false_target.is_linked()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000498 false_target.Bind();
mads.s.ager31e71382008-08-13 09:32:07 +0000499 __ mov(r0, Operand(Factory::false_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000500 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000501 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000502 // A value is loaded on all paths reaching this point.
503 loaded.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000504 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000505 ASSERT(has_valid_frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000506 ASSERT(!has_cc());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000507 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000508}
509
510
ager@chromium.org7c537e22008-10-16 08:43:32 +0000511void CodeGenerator::LoadGlobal() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000512 VirtualFrame::SpilledScope spilled_scope(this);
mads.s.ager31e71382008-08-13 09:32:07 +0000513 __ ldr(r0, GlobalObject());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000514 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000515}
516
517
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000518void CodeGenerator::LoadGlobalReceiver(Register scratch) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000519 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000520 __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX));
521 __ ldr(scratch,
522 FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000523 frame_->EmitPush(scratch);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000524}
525
526
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000527// TODO(1241834): Get rid of this function in favor of just using Load, now
ager@chromium.org7c537e22008-10-16 08:43:32 +0000528// that we have the INSIDE_TYPEOF typeof state. => Need to handle global
529// variables w/o reference errors elsewhere.
530void CodeGenerator::LoadTypeofExpression(Expression* x) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000531 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000532 Variable* variable = x->AsVariableProxy()->AsVariable();
533 if (variable != NULL && !variable->is_this() && variable->is_global()) {
534 // NOTE: This is somewhat nasty. We force the compiler to load
535 // the variable as if through '<global>.<variable>' to make sure we
536 // do not get reference errors.
537 Slot global(variable, Slot::CONTEXT, Context::GLOBAL_INDEX);
538 Literal key(variable->name());
539 // TODO(1241834): Fetch the position from the variable instead of using
540 // no position.
ager@chromium.org236ad962008-09-25 09:45:57 +0000541 Property property(&global, &key, RelocInfo::kNoPosition);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000542 LoadAndSpill(&property);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000543 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000544 LoadAndSpill(x, INSIDE_TYPEOF);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000545 }
546}
547
548
ager@chromium.org7c537e22008-10-16 08:43:32 +0000549Reference::Reference(CodeGenerator* cgen, Expression* expression)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000550 : cgen_(cgen), expression_(expression), type_(ILLEGAL) {
551 cgen->LoadReference(this);
552}
553
554
555Reference::~Reference() {
556 cgen_->UnloadReference(this);
557}
558
559
ager@chromium.org7c537e22008-10-16 08:43:32 +0000560void CodeGenerator::LoadReference(Reference* ref) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000561 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +0000562 Comment cmnt(masm_, "[ LoadReference");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000563 Expression* e = ref->expression();
564 Property* property = e->AsProperty();
565 Variable* var = e->AsVariableProxy()->AsVariable();
566
567 if (property != NULL) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000568 // The expression is either a property or a variable proxy that rewrites
569 // to a property.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000570 LoadAndSpill(property->obj());
ager@chromium.org7c537e22008-10-16 08:43:32 +0000571 // We use a named reference if the key is a literal symbol, unless it is
572 // a string that can be legally parsed as an integer. This is because
573 // otherwise we will not get into the slow case code that handles [] on
574 // String objects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000575 Literal* literal = property->key()->AsLiteral();
576 uint32_t dummy;
ager@chromium.org7c537e22008-10-16 08:43:32 +0000577 if (literal != NULL &&
578 literal->handle()->IsSymbol() &&
579 !String::cast(*(literal->handle()))->AsArrayIndex(&dummy)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000580 ref->set_type(Reference::NAMED);
581 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000582 LoadAndSpill(property->key());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000583 ref->set_type(Reference::KEYED);
584 }
585 } else if (var != NULL) {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000586 // The expression is a variable proxy that does not rewrite to a
587 // property. Global variables are treated as named property references.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000588 if (var->is_global()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000589 LoadGlobal();
590 ref->set_type(Reference::NAMED);
591 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000592 ASSERT(var->slot() != NULL);
593 ref->set_type(Reference::SLOT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000594 }
595 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +0000596 // Anything else is a runtime error.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000597 LoadAndSpill(e);
598 frame_->CallRuntime(Runtime::kThrowReferenceError, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000599 }
600}
601
602
ager@chromium.org7c537e22008-10-16 08:43:32 +0000603void CodeGenerator::UnloadReference(Reference* ref) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000604 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000605 // Pop a reference from the stack while preserving TOS.
ager@chromium.org7c537e22008-10-16 08:43:32 +0000606 Comment cmnt(masm_, "[ UnloadReference");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000607 int size = ref->size();
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000608 if (size > 0) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000609 frame_->EmitPop(r0);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000610 frame_->Drop(size);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000611 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000612 }
613}
614
615
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000616// ECMA-262, section 9.2, page 30: ToBoolean(). Convert the given
617// register to a boolean in the condition code register. The code
618// may jump to 'false_target' in case the register converts to 'false'.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000619void CodeGenerator::ToBoolean(JumpTarget* true_target,
620 JumpTarget* false_target) {
621 VirtualFrame::SpilledScope spilled_scope(this);
mads.s.ager31e71382008-08-13 09:32:07 +0000622 // Note: The generated code snippet does not change stack variables.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000623 // Only the condition code should be set.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000624 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000625
626 // Fast case checks
627
mads.s.ager31e71382008-08-13 09:32:07 +0000628 // Check if the value is 'false'.
629 __ cmp(r0, Operand(Factory::false_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000630 false_target->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000631
mads.s.ager31e71382008-08-13 09:32:07 +0000632 // Check if the value is 'true'.
633 __ cmp(r0, Operand(Factory::true_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000634 true_target->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000635
mads.s.ager31e71382008-08-13 09:32:07 +0000636 // Check if the value is 'undefined'.
637 __ cmp(r0, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000638 false_target->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000639
mads.s.ager31e71382008-08-13 09:32:07 +0000640 // Check if the value is a smi.
641 __ cmp(r0, Operand(Smi::FromInt(0)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000642 false_target->Branch(eq);
mads.s.ager31e71382008-08-13 09:32:07 +0000643 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000644 true_target->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000645
646 // Slow case: call the runtime.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000647 frame_->EmitPush(r0);
648 frame_->CallRuntime(Runtime::kToBool, 1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000649 // Convert the result (r0) to a condition code.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000650 __ cmp(r0, Operand(Factory::false_value()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000651
652 cc_reg_ = ne;
653}
654
655
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000656class GetPropertyStub : public CodeStub {
657 public:
658 GetPropertyStub() { }
659
660 private:
661 Major MajorKey() { return GetProperty; }
662 int MinorKey() { return 0; }
663 void Generate(MacroAssembler* masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000664};
665
666
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000667class SetPropertyStub : public CodeStub {
668 public:
669 SetPropertyStub() { }
670
671 private:
672 Major MajorKey() { return SetProperty; }
673 int MinorKey() { return 0; }
674 void Generate(MacroAssembler* masm);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000675};
676
677
kasper.lund7276f142008-07-30 08:49:36 +0000678class GenericBinaryOpStub : public CodeStub {
679 public:
680 explicit GenericBinaryOpStub(Token::Value op) : op_(op) { }
681
682 private:
683 Token::Value op_;
684
685 Major MajorKey() { return GenericBinaryOp; }
686 int MinorKey() { return static_cast<int>(op_); }
687 void Generate(MacroAssembler* masm);
688
689 const char* GetName() {
690 switch (op_) {
691 case Token::ADD: return "GenericBinaryOpStub_ADD";
692 case Token::SUB: return "GenericBinaryOpStub_SUB";
693 case Token::MUL: return "GenericBinaryOpStub_MUL";
694 case Token::DIV: return "GenericBinaryOpStub_DIV";
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000695 case Token::BIT_OR: return "GenericBinaryOpStub_BIT_OR";
696 case Token::BIT_AND: return "GenericBinaryOpStub_BIT_AND";
697 case Token::BIT_XOR: return "GenericBinaryOpStub_BIT_XOR";
698 case Token::SAR: return "GenericBinaryOpStub_SAR";
699 case Token::SHL: return "GenericBinaryOpStub_SHL";
700 case Token::SHR: return "GenericBinaryOpStub_SHR";
kasper.lund7276f142008-07-30 08:49:36 +0000701 default: return "GenericBinaryOpStub";
702 }
703 }
704
705#ifdef DEBUG
706 void Print() { PrintF("GenericBinaryOpStub (%s)\n", Token::String(op_)); }
707#endif
708};
709
710
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000711class InvokeBuiltinStub : public CodeStub {
712 public:
713 enum Kind { Inc, Dec, ToNumber };
714 InvokeBuiltinStub(Kind kind, int argc) : kind_(kind), argc_(argc) { }
715
716 private:
717 Kind kind_;
718 int argc_;
719
720 Major MajorKey() { return InvokeBuiltin; }
721 int MinorKey() { return (argc_ << 3) | static_cast<int>(kind_); }
722 void Generate(MacroAssembler* masm);
723
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000724#ifdef DEBUG
725 void Print() {
726 PrintF("InvokeBuiltinStub (kind %d, argc, %d)\n",
727 static_cast<int>(kind_),
728 argc_);
729 }
730#endif
731};
732
733
ager@chromium.org7c537e22008-10-16 08:43:32 +0000734void CodeGenerator::GenericBinaryOperation(Token::Value op) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000735 VirtualFrame::SpilledScope spilled_scope(this);
mads.s.ager31e71382008-08-13 09:32:07 +0000736 // sp[0] : y
737 // sp[1] : x
738 // result : r0
739
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000740 // Stub is entered with a call: 'return address' is in lr.
741 switch (op) {
742 case Token::ADD: // fall through.
743 case Token::SUB: // fall through.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000744 case Token::MUL:
745 case Token::BIT_OR:
746 case Token::BIT_AND:
747 case Token::BIT_XOR:
748 case Token::SHL:
749 case Token::SHR:
750 case Token::SAR: {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000751 frame_->EmitPop(r0); // r0 : y
752 frame_->EmitPop(r1); // r1 : x
kasper.lund7276f142008-07-30 08:49:36 +0000753 GenericBinaryOpStub stub(op);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000754 frame_->CallStub(&stub, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000755 break;
756 }
757
758 case Token::DIV: {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000759 Result arg_count = allocator_->Allocate(r0);
760 ASSERT(arg_count.is_valid());
761 __ mov(arg_count.reg(), Operand(1));
762 frame_->InvokeBuiltin(Builtins::DIV, CALL_JS, &arg_count, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000763 break;
764 }
765
766 case Token::MOD: {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000767 Result arg_count = allocator_->Allocate(r0);
768 ASSERT(arg_count.is_valid());
769 __ mov(arg_count.reg(), Operand(1));
770 frame_->InvokeBuiltin(Builtins::MOD, CALL_JS, &arg_count, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000771 break;
772 }
773
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000774 case Token::COMMA:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000775 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000776 // simply discard left value
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000777 frame_->Drop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000778 break;
779
780 default:
781 // Other cases should have been handled before this point.
782 UNREACHABLE();
783 break;
784 }
785}
786
787
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000788class DeferredInlineSmiOperation: public DeferredCode {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000789 public:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000790 DeferredInlineSmiOperation(CodeGenerator* generator,
791 Token::Value op,
792 int value,
793 bool reversed)
794 : DeferredCode(generator),
795 op_(op),
796 value_(value),
797 reversed_(reversed) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000798 set_comment("[ DeferredInlinedSmiOperation");
799 }
800
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000801 virtual void Generate();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000802
803 private:
804 Token::Value op_;
805 int value_;
806 bool reversed_;
807};
808
809
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000810void DeferredInlineSmiOperation::Generate() {
811 enter()->Bind();
812 VirtualFrame::SpilledScope spilled_scope(generator());
813
814 switch (op_) {
815 case Token::ADD: {
816 if (reversed_) {
817 // revert optimistic add
818 __ sub(r0, r0, Operand(Smi::FromInt(value_)));
819 __ mov(r1, Operand(Smi::FromInt(value_)));
820 } else {
821 // revert optimistic add
822 __ sub(r1, r0, Operand(Smi::FromInt(value_)));
823 __ mov(r0, Operand(Smi::FromInt(value_)));
824 }
825 break;
826 }
827
828 case Token::SUB: {
829 if (reversed_) {
830 // revert optimistic sub
831 __ rsb(r0, r0, Operand(Smi::FromInt(value_)));
832 __ mov(r1, Operand(Smi::FromInt(value_)));
833 } else {
834 __ add(r1, r0, Operand(Smi::FromInt(value_)));
835 __ mov(r0, Operand(Smi::FromInt(value_)));
836 }
837 break;
838 }
839
840 case Token::BIT_OR:
841 case Token::BIT_XOR:
842 case Token::BIT_AND: {
843 if (reversed_) {
844 __ mov(r1, Operand(Smi::FromInt(value_)));
845 } else {
846 __ mov(r1, Operand(r0));
847 __ mov(r0, Operand(Smi::FromInt(value_)));
848 }
849 break;
850 }
851
852 case Token::SHL:
853 case Token::SHR:
854 case Token::SAR: {
855 if (!reversed_) {
856 __ mov(r1, Operand(r0));
857 __ mov(r0, Operand(Smi::FromInt(value_)));
858 } else {
859 UNREACHABLE(); // should have been handled in SmiOperation
860 }
861 break;
862 }
863
864 default:
865 // other cases should have been handled before this point.
866 UNREACHABLE();
867 break;
868 }
869
870 GenericBinaryOpStub igostub(op_);
ager@chromium.org41826e72009-03-30 13:30:57 +0000871 Result arg0 = generator()->allocator()->Allocate(r1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000872 ASSERT(arg0.is_valid());
ager@chromium.org41826e72009-03-30 13:30:57 +0000873 Result arg1 = generator()->allocator()->Allocate(r0);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000874 ASSERT(arg1.is_valid());
ager@chromium.org41826e72009-03-30 13:30:57 +0000875 generator()->frame()->CallStub(&igostub, &arg0, &arg1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000876 exit_.Jump();
877}
878
879
ager@chromium.org7c537e22008-10-16 08:43:32 +0000880void CodeGenerator::SmiOperation(Token::Value op,
ager@chromium.org3bf7b912008-11-17 09:09:45 +0000881 Handle<Object> value,
882 bool reversed) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000883 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000884 // NOTE: This is an attempt to inline (a bit) more of the code for
885 // some possible smi operations (like + and -) when (at least) one
886 // of the operands is a literal smi. With this optimization, the
887 // performance of the system is increased by ~15%, and the generated
888 // code size is increased by ~1% (measured on a combination of
889 // different benchmarks).
890
mads.s.ager31e71382008-08-13 09:32:07 +0000891 // sp[0] : operand
892
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000893 int int_value = Smi::cast(*value)->value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000894
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000895 JumpTarget exit(this);
896 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000897
898 switch (op) {
899 case Token::ADD: {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000900 DeferredCode* deferred =
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000901 new DeferredInlineSmiOperation(this, op, int_value, reversed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000902
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000903 __ add(r0, r0, Operand(value), SetCC);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000904 deferred->enter()->Branch(vs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000905 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000906 deferred->enter()->Branch(ne);
907 deferred->BindExit();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000908 break;
909 }
910
911 case Token::SUB: {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000912 DeferredCode* deferred =
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000913 new DeferredInlineSmiOperation(this, op, int_value, reversed);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000915 if (!reversed) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000916 __ sub(r0, r0, Operand(value), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000917 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000918 __ rsb(r0, r0, Operand(value), SetCC);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000919 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000920 deferred->enter()->Branch(vs);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000921 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000922 deferred->enter()->Branch(ne);
923 deferred->BindExit();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000924 break;
925 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000926
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000927 case Token::BIT_OR:
928 case Token::BIT_XOR:
929 case Token::BIT_AND: {
930 DeferredCode* deferred =
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000931 new DeferredInlineSmiOperation(this, op, int_value, reversed);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000932 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000933 deferred->enter()->Branch(ne);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000934 switch (op) {
935 case Token::BIT_OR: __ orr(r0, r0, Operand(value)); break;
936 case Token::BIT_XOR: __ eor(r0, r0, Operand(value)); break;
937 case Token::BIT_AND: __ and_(r0, r0, Operand(value)); break;
938 default: UNREACHABLE();
939 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000940 deferred->BindExit();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000941 break;
942 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000943
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000944 case Token::SHL:
945 case Token::SHR:
946 case Token::SAR: {
947 if (reversed) {
948 __ mov(ip, Operand(value));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000949 frame_->EmitPush(ip);
950 frame_->EmitPush(r0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000951 GenericBinaryOperation(op);
952
953 } else {
954 int shift_value = int_value & 0x1f; // least significant 5 bits
955 DeferredCode* deferred =
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000956 new DeferredInlineSmiOperation(this, op, shift_value, false);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000957 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000958 deferred->enter()->Branch(ne);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000959 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // remove tags
960 switch (op) {
961 case Token::SHL: {
962 __ mov(r2, Operand(r2, LSL, shift_value));
963 // check that the *unsigned* result fits in a smi
964 __ add(r3, r2, Operand(0x40000000), SetCC);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000965 deferred->enter()->Branch(mi);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000966 break;
967 }
968 case Token::SHR: {
969 // LSR by immediate 0 means shifting 32 bits.
970 if (shift_value != 0) {
971 __ mov(r2, Operand(r2, LSR, shift_value));
972 }
973 // check that the *unsigned* result fits in a smi
974 // neither of the two high-order bits can be set:
975 // - 0x80000000: high bit would be lost when smi tagging
976 // - 0x40000000: this number would convert to negative when
977 // smi tagging these two cases can only happen with shifts
978 // by 0 or 1 when handed a valid smi
979 __ and_(r3, r2, Operand(0xc0000000), SetCC);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000980 deferred->enter()->Branch(ne);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000981 break;
982 }
983 case Token::SAR: {
984 if (shift_value != 0) {
985 // ASR by immediate 0 means shifting 32 bits.
986 __ mov(r2, Operand(r2, ASR, shift_value));
987 }
988 break;
989 }
990 default: UNREACHABLE();
991 }
992 __ mov(r0, Operand(r2, LSL, kSmiTagSize));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000993 deferred->BindExit();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +0000994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000995 break;
996 }
997
998 default:
999 if (!reversed) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001000 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001001 __ mov(r0, Operand(value));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001002 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001003 } else {
1004 __ mov(ip, Operand(value));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001005 frame_->EmitPush(ip);
1006 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001007 }
kasper.lund7276f142008-07-30 08:49:36 +00001008 GenericBinaryOperation(op);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001009 break;
1010 }
1011
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001012 exit.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001013}
1014
1015
ager@chromium.org7c537e22008-10-16 08:43:32 +00001016void CodeGenerator::Comparison(Condition cc, bool strict) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001017 VirtualFrame::SpilledScope spilled_scope(this);
mads.s.ager31e71382008-08-13 09:32:07 +00001018 // sp[0] : y
1019 // sp[1] : x
1020 // result : cc register
1021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001022 // Strict only makes sense for equality comparisons.
1023 ASSERT(!strict || cc == eq);
1024
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001025 JumpTarget exit(this);
1026 JumpTarget smi(this);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001027 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
1028 if (cc == gt || cc == le) {
1029 cc = ReverseCondition(cc);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001030 frame_->EmitPop(r1);
1031 frame_->EmitPop(r0);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001032 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001033 frame_->EmitPop(r0);
1034 frame_->EmitPop(r1);
mads.s.ager@gmail.com769cc962008-08-06 10:02:49 +00001035 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001036 __ orr(r2, r0, Operand(r1));
1037 __ tst(r2, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001038 smi.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001039
1040 // Perform non-smi comparison by runtime call.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001041 frame_->EmitPush(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001042
1043 // Figure out which native to call and setup the arguments.
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001044 Builtins::JavaScript native;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001045 int arg_count = 1;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001046 if (cc == eq) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001047 native = strict ? Builtins::STRICT_EQUALS : Builtins::EQUALS;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001048 } else {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001049 native = Builtins::COMPARE;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001050 int ncr; // NaN compare result
1051 if (cc == lt || cc == le) {
1052 ncr = GREATER;
1053 } else {
1054 ASSERT(cc == gt || cc == ge); // remaining cases
1055 ncr = LESS;
1056 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001057 frame_->EmitPush(r0);
1058 arg_count++;
mads.s.ager31e71382008-08-13 09:32:07 +00001059 __ mov(r0, Operand(Smi::FromInt(ncr)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001060 }
1061
1062 // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
1063 // tagged as a small integer.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001064 frame_->EmitPush(r0);
1065 Result arg_count_register = allocator_->Allocate(r0);
1066 ASSERT(arg_count_register.is_valid());
1067 __ mov(arg_count_register.reg(), Operand(arg_count));
1068 Result result = frame_->InvokeBuiltin(native,
1069 CALL_JS,
1070 &arg_count_register,
1071 arg_count + 1);
1072 __ cmp(result.reg(), Operand(0));
1073 result.Unuse();
1074 exit.Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001075
1076 // test smi equality by pointer comparison.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001077 smi.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001078 __ cmp(r1, Operand(r0));
1079
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001080 exit.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001081 cc_reg_ = cc;
1082}
1083
1084
kasper.lund7276f142008-07-30 08:49:36 +00001085class CallFunctionStub: public CodeStub {
1086 public:
1087 explicit CallFunctionStub(int argc) : argc_(argc) {}
1088
1089 void Generate(MacroAssembler* masm);
1090
1091 private:
1092 int argc_;
1093
kasper.lund7276f142008-07-30 08:49:36 +00001094#if defined(DEBUG)
1095 void Print() { PrintF("CallFunctionStub (argc %d)\n", argc_); }
1096#endif // defined(DEBUG)
1097
1098 Major MajorKey() { return CallFunction; }
1099 int MinorKey() { return argc_; }
1100};
1101
1102
mads.s.ager31e71382008-08-13 09:32:07 +00001103// Call the function on the stack with the given arguments.
ager@chromium.org7c537e22008-10-16 08:43:32 +00001104void CodeGenerator::CallWithArguments(ZoneList<Expression*>* args,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001105 int position) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001106 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001107 // Push the arguments ("left-to-right") on the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001108 int arg_count = args->length();
1109 for (int i = 0; i < arg_count; i++) {
1110 LoadAndSpill(args->at(i));
mads.s.ager31e71382008-08-13 09:32:07 +00001111 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001112
kasper.lund7276f142008-07-30 08:49:36 +00001113 // Record the position for debugging purposes.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001114 CodeForSourcePosition(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001115
kasper.lund7276f142008-07-30 08:49:36 +00001116 // Use the shared code stub to call the function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001117 CallFunctionStub call_function(arg_count);
1118 frame_->CallStub(&call_function, arg_count + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001119
1120 // Restore context and pop function from the stack.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001121 __ ldr(cp, frame_->Context());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001122 frame_->Drop(); // discard the TOS
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001123}
1124
1125
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001126void CodeGenerator::Branch(bool if_true, JumpTarget* target) {
1127 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001128 ASSERT(has_cc());
1129 Condition cc = if_true ? cc_reg_ : NegateCondition(cc_reg_);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001130 target->Branch(cc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001131 cc_reg_ = al;
1132}
1133
1134
ager@chromium.org7c537e22008-10-16 08:43:32 +00001135void CodeGenerator::CheckStack() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001136 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001137 if (FLAG_check_stack) {
1138 Comment cmnt(masm_, "[ check stack");
1139 StackCheckStub stub;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001140 frame_->CallStub(&stub, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001141 }
1142}
1143
1144
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00001145void CodeGenerator::VisitAndSpill(Statement* statement) {
1146 ASSERT(in_spilled_code());
1147 set_in_spilled_code(false);
1148 Visit(statement);
1149 if (frame_ != NULL) {
1150 frame_->SpillAll();
1151 }
1152 set_in_spilled_code(true);
1153}
1154
1155
1156void CodeGenerator::VisitStatementsAndSpill(ZoneList<Statement*>* statements) {
1157 ASSERT(in_spilled_code());
1158 set_in_spilled_code(false);
1159 VisitStatements(statements);
1160 if (frame_ != NULL) {
1161 frame_->SpillAll();
1162 }
1163 set_in_spilled_code(true);
1164}
1165
1166
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001167void CodeGenerator::VisitStatements(ZoneList<Statement*>* statements) {
1168#ifdef DEBUG
1169 int original_height = frame_->height();
1170#endif
1171 VirtualFrame::SpilledScope spilled_scope(this);
1172 for (int i = 0; frame_ != NULL && i < statements->length(); i++) {
1173 VisitAndSpill(statements->at(i));
1174 }
1175 ASSERT(!has_valid_frame() || frame_->height() == original_height);
1176}
1177
1178
ager@chromium.org7c537e22008-10-16 08:43:32 +00001179void CodeGenerator::VisitBlock(Block* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001180#ifdef DEBUG
1181 int original_height = frame_->height();
1182#endif
1183 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 Comment cmnt(masm_, "[ Block");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001185 CodeForStatementPosition(node);
1186 node->break_target()->Initialize(this);
1187 VisitStatementsAndSpill(node->statements());
1188 if (node->break_target()->is_linked()) {
1189 node->break_target()->Bind();
1190 }
1191 node->break_target()->Unuse();
1192 ASSERT(!has_valid_frame() || frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
ager@chromium.org7c537e22008-10-16 08:43:32 +00001196void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001197 VirtualFrame::SpilledScope spilled_scope(this);
mads.s.ager31e71382008-08-13 09:32:07 +00001198 __ mov(r0, Operand(pairs));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001199 frame_->EmitPush(r0);
1200 frame_->EmitPush(cp);
mads.s.ager31e71382008-08-13 09:32:07 +00001201 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001202 frame_->EmitPush(r0);
1203 frame_->CallRuntime(Runtime::kDeclareGlobals, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00001204 // The result is discarded.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001205}
1206
1207
ager@chromium.org7c537e22008-10-16 08:43:32 +00001208void CodeGenerator::VisitDeclaration(Declaration* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001209#ifdef DEBUG
1210 int original_height = frame_->height();
1211#endif
1212 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001213 Comment cmnt(masm_, "[ Declaration");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001214 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001215 Variable* var = node->proxy()->var();
1216 ASSERT(var != NULL); // must have been resolved
1217 Slot* slot = var->slot();
1218
1219 // If it was not possible to allocate the variable at compile time,
1220 // we need to "declare" it at runtime to make sure it actually
1221 // exists in the local context.
1222 if (slot != NULL && slot->type() == Slot::LOOKUP) {
1223 // Variables with a "LOOKUP" slot were introduced as non-locals
1224 // during variable resolution and must have mode DYNAMIC.
ager@chromium.org381abbb2009-02-25 13:23:22 +00001225 ASSERT(var->is_dynamic());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001226 // For now, just do a runtime call.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001227 frame_->EmitPush(cp);
mads.s.ager31e71382008-08-13 09:32:07 +00001228 __ mov(r0, Operand(var->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001229 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001230 // Declaration nodes are always declared in only two modes.
1231 ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
1232 PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
mads.s.ager31e71382008-08-13 09:32:07 +00001233 __ mov(r0, Operand(Smi::FromInt(attr)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001234 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001235 // Push initial value, if any.
1236 // Note: For variables we must not push an initial value (such as
1237 // 'undefined') because we may have a (legal) redeclaration and we
1238 // must not destroy the current value.
1239 if (node->mode() == Variable::CONST) {
mads.s.ager31e71382008-08-13 09:32:07 +00001240 __ mov(r0, Operand(Factory::the_hole_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001241 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001242 } else if (node->fun() != NULL) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001243 LoadAndSpill(node->fun());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001244 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001245 __ mov(r0, Operand(0)); // no initial value!
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001246 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001247 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001248 frame_->CallRuntime(Runtime::kDeclareContextSlot, 4);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001249 // Ignore the return value (declarations are statements).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001250 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001251 return;
1252 }
1253
1254 ASSERT(!var->is_global());
1255
1256 // If we have a function or a constant, we need to initialize the variable.
1257 Expression* val = NULL;
1258 if (node->mode() == Variable::CONST) {
1259 val = new Literal(Factory::the_hole_value());
1260 } else {
1261 val = node->fun(); // NULL if we don't have a function
1262 }
1263
1264 if (val != NULL) {
iposva@chromium.org245aa852009-02-10 00:49:54 +00001265 {
1266 // Set initial value.
1267 Reference target(this, node->proxy());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001268 LoadAndSpill(val);
iposva@chromium.org245aa852009-02-10 00:49:54 +00001269 target.SetValue(NOT_CONST_INIT);
1270 // The reference is removed from the stack (preserving TOS) when
1271 // it goes out of scope.
1272 }
1273 // Get rid of the assigned value (declarations are statements).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001274 frame_->Drop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001276 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001277}
1278
1279
ager@chromium.org7c537e22008-10-16 08:43:32 +00001280void CodeGenerator::VisitExpressionStatement(ExpressionStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001281#ifdef DEBUG
1282 int original_height = frame_->height();
1283#endif
1284 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001285 Comment cmnt(masm_, "[ ExpressionStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001286 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 Expression* expression = node->expression();
1288 expression->MarkAsStatement();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001289 LoadAndSpill(expression);
1290 frame_->Drop();
1291 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001292}
1293
1294
ager@chromium.org7c537e22008-10-16 08:43:32 +00001295void CodeGenerator::VisitEmptyStatement(EmptyStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001296#ifdef DEBUG
1297 int original_height = frame_->height();
1298#endif
1299 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001300 Comment cmnt(masm_, "// EmptyStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001301 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001302 // nothing to do
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001303 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304}
1305
1306
ager@chromium.org7c537e22008-10-16 08:43:32 +00001307void CodeGenerator::VisitIfStatement(IfStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001308#ifdef DEBUG
1309 int original_height = frame_->height();
1310#endif
1311 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001312 Comment cmnt(masm_, "[ IfStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001313 // Generate different code depending on which parts of the if statement
1314 // are present or not.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001315 bool has_then_stm = node->HasThenStatement();
1316 bool has_else_stm = node->HasElseStatement();
1317
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001318 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001319
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001320 JumpTarget exit(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001321 if (has_then_stm && has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001322 Comment cmnt(masm_, "[ IfThenElse");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001323 JumpTarget then(this);
1324 JumpTarget else_(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001325 // if (cond)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001326 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF,
1327 &then, &else_, true);
1328 if (frame_ != NULL) {
1329 Branch(false, &else_);
1330 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001331 // then
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001332 if (frame_ != NULL || then.is_linked()) {
1333 then.Bind();
1334 VisitAndSpill(node->then_statement());
1335 }
1336 if (frame_ != NULL) {
1337 exit.Jump();
1338 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001339 // else
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001340 if (else_.is_linked()) {
1341 else_.Bind();
1342 VisitAndSpill(node->else_statement());
1343 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001344
1345 } else if (has_then_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001346 Comment cmnt(masm_, "[ IfThen");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 ASSERT(!has_else_stm);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001348 JumpTarget then(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001349 // if (cond)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001350 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF,
1351 &then, &exit, true);
1352 if (frame_ != NULL) {
1353 Branch(false, &exit);
1354 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001355 // then
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001356 if (frame_ != NULL || then.is_linked()) {
1357 then.Bind();
1358 VisitAndSpill(node->then_statement());
1359 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360
1361 } else if (has_else_stm) {
mads.s.ager31e71382008-08-13 09:32:07 +00001362 Comment cmnt(masm_, "[ IfElse");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001363 ASSERT(!has_then_stm);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001364 JumpTarget else_(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365 // if (!cond)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001366 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF,
1367 &exit, &else_, true);
1368 if (frame_ != NULL) {
1369 Branch(true, &exit);
1370 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371 // else
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001372 if (frame_ != NULL || else_.is_linked()) {
1373 else_.Bind();
1374 VisitAndSpill(node->else_statement());
1375 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
1377 } else {
mads.s.ager31e71382008-08-13 09:32:07 +00001378 Comment cmnt(masm_, "[ If");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 ASSERT(!has_then_stm && !has_else_stm);
1380 // if (cond)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001381 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF,
1382 &exit, &exit, false);
1383 if (frame_ != NULL) {
1384 if (has_cc()) {
1385 cc_reg_ = al;
1386 } else {
1387 frame_->Drop();
1388 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389 }
1390 }
1391
1392 // end
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001393 if (exit.is_linked()) {
1394 exit.Bind();
1395 }
1396 ASSERT(!has_valid_frame() || frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397}
1398
1399
ager@chromium.org7c537e22008-10-16 08:43:32 +00001400void CodeGenerator::VisitContinueStatement(ContinueStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001401 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 Comment cmnt(masm_, "[ ContinueStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001403 CodeForStatementPosition(node);
1404 node->target()->continue_target()->Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405}
1406
1407
ager@chromium.org7c537e22008-10-16 08:43:32 +00001408void CodeGenerator::VisitBreakStatement(BreakStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001409 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001410 Comment cmnt(masm_, "[ BreakStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001411 CodeForStatementPosition(node);
1412 node->target()->break_target()->Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001413}
1414
1415
ager@chromium.org7c537e22008-10-16 08:43:32 +00001416void CodeGenerator::VisitReturnStatement(ReturnStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001417 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 Comment cmnt(masm_, "[ ReturnStatement");
mads.s.ager31e71382008-08-13 09:32:07 +00001419
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001420 if (function_return_is_shadowed_) {
1421 CodeForStatementPosition(node);
1422 LoadAndSpill(node->expression());
1423 frame_->EmitPop(r0);
1424 function_return_.Jump();
1425 } else {
1426 // Load the returned value.
1427 CodeForStatementPosition(node);
1428 LoadAndSpill(node->expression());
1429
1430 // Pop the result from the frame and prepare the frame for
1431 // returning thus making it easier to merge.
1432 frame_->EmitPop(r0);
1433 frame_->PrepareForReturn();
1434
1435 function_return_.Jump();
1436 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001437}
1438
1439
ager@chromium.org7c537e22008-10-16 08:43:32 +00001440void CodeGenerator::VisitWithEnterStatement(WithEnterStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001441#ifdef DEBUG
1442 int original_height = frame_->height();
1443#endif
1444 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001445 Comment cmnt(masm_, "[ WithEnterStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001446 CodeForStatementPosition(node);
1447 LoadAndSpill(node->expression());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001448 if (node->is_catch_block()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001449 frame_->CallRuntime(Runtime::kPushCatchContext, 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001450 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001451 frame_->CallRuntime(Runtime::kPushContext, 1);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00001452 }
kasper.lund7276f142008-07-30 08:49:36 +00001453 if (kDebug) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001454 JumpTarget verified_true(this);
kasper.lund7276f142008-07-30 08:49:36 +00001455 __ cmp(r0, Operand(cp));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001456 verified_true.Branch(eq);
kasper.lund7276f142008-07-30 08:49:36 +00001457 __ stop("PushContext: r0 is expected to be the same as cp");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001458 verified_true.Bind();
kasper.lund7276f142008-07-30 08:49:36 +00001459 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460 // Update context local.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001461 __ str(cp, frame_->Context());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001462 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001463}
1464
1465
ager@chromium.org7c537e22008-10-16 08:43:32 +00001466void CodeGenerator::VisitWithExitStatement(WithExitStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001467#ifdef DEBUG
1468 int original_height = frame_->height();
1469#endif
1470 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001471 Comment cmnt(masm_, "[ WithExitStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001472 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473 // Pop context.
1474 __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
1475 // Update context local.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001476 __ str(cp, frame_->Context());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001477 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001478}
1479
1480
ager@chromium.org7c537e22008-10-16 08:43:32 +00001481int CodeGenerator::FastCaseSwitchMaxOverheadFactor() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001482 return kFastSwitchMaxOverheadFactor;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001483}
1484
ager@chromium.org7c537e22008-10-16 08:43:32 +00001485int CodeGenerator::FastCaseSwitchMinCaseCount() {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001486 return kFastSwitchMinCaseCount;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001487}
1488
1489
ager@chromium.org7c537e22008-10-16 08:43:32 +00001490void CodeGenerator::GenerateFastCaseSwitchJumpTable(
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001491 SwitchStatement* node,
1492 int min_index,
1493 int range,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001494 Label* default_label,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001495 Vector<Label*> case_targets,
1496 Vector<Label> case_labels) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001497 VirtualFrame::SpilledScope spilled_scope(this);
1498 JumpTarget setup_default(this);
1499 JumpTarget is_smi(this);
1500
1501 // A non-null default label pointer indicates a default case among
1502 // the case labels. Otherwise we use the break target as a
1503 // "default" for failure to hit the jump table.
1504 JumpTarget* default_target =
1505 (default_label == NULL) ? node->break_target() : &setup_default;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001506
1507 ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001508 frame_->EmitPop(r0);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001509
1510 // Test for a Smi value in a HeapNumber.
ager@chromium.org870a0b62008-11-04 11:43:05 +00001511 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001512 is_smi.Branch(eq);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001513 __ ldr(r1, MemOperand(r0, HeapObject::kMapOffset - kHeapObjectTag));
1514 __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
1515 __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001516 default_target->Branch(ne);
1517 frame_->EmitPush(r0);
1518 frame_->CallRuntime(Runtime::kNumberToSmi, 1);
1519 is_smi.Bind();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001520
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001521 if (min_index != 0) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001522 // Small positive numbers can be immediate operands.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001523 if (min_index < 0) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001524 // If min_index is Smi::kMinValue, -min_index is not a Smi.
1525 if (Smi::IsValid(-min_index)) {
1526 __ add(r0, r0, Operand(Smi::FromInt(-min_index)));
1527 } else {
1528 __ add(r0, r0, Operand(Smi::FromInt(-min_index - 1)));
1529 __ add(r0, r0, Operand(Smi::FromInt(1)));
1530 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001531 } else {
1532 __ sub(r0, r0, Operand(Smi::FromInt(min_index)));
1533 }
1534 }
1535 __ tst(r0, Operand(0x80000000 | kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001536 default_target->Branch(ne);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001537 __ cmp(r0, Operand(Smi::FromInt(range)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001538 default_target->Branch(ge);
1539 VirtualFrame* start_frame = new VirtualFrame(frame_);
ager@chromium.org8bb60582008-12-11 12:02:20 +00001540 __ SmiJumpTable(r0, case_targets);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001541
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001542 GenerateFastCaseSwitchCases(node, case_labels, start_frame);
1543
1544 // If there was a default case among the case labels, we need to
1545 // emit code to jump to it from the default target used for failure
1546 // to hit the jump table.
1547 if (default_label != NULL) {
1548 if (has_valid_frame()) {
1549 node->break_target()->Jump();
1550 }
1551 setup_default.Bind();
1552 frame_->MergeTo(start_frame);
1553 __ b(default_label);
1554 DeleteFrame();
1555 }
1556 if (node->break_target()->is_linked()) {
1557 node->break_target()->Bind();
1558 }
1559
1560 delete start_frame;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001561}
1562
1563
ager@chromium.org7c537e22008-10-16 08:43:32 +00001564void CodeGenerator::VisitSwitchStatement(SwitchStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001565#ifdef DEBUG
1566 int original_height = frame_->height();
1567#endif
1568 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 Comment cmnt(masm_, "[ SwitchStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001570 CodeForStatementPosition(node);
1571 node->break_target()->Initialize(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001572
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001573 LoadAndSpill(node->tag());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001574 if (TryGenerateFastCaseSwitchStatement(node)) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001575 ASSERT(!has_valid_frame() || frame_->height() == original_height);
1576 return;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001577 }
1578
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001579 JumpTarget next_test(this);
1580 JumpTarget fall_through(this);
1581 JumpTarget default_entry(this);
1582 JumpTarget default_exit(this, JumpTarget::BIDIRECTIONAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001583 ZoneList<CaseClause*>* cases = node->cases();
1584 int length = cases->length();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001585 CaseClause* default_clause = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001586
1587 for (int i = 0; i < length; i++) {
1588 CaseClause* clause = cases->at(i);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001589 if (clause->is_default()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001590 // Remember the default clause and compile it at the end.
1591 default_clause = clause;
1592 continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001593 }
1594
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001595 Comment cmnt(masm_, "[ Case clause");
1596 // Compile the test.
1597 next_test.Bind();
1598 next_test.Unuse();
1599 // Duplicate TOS.
1600 __ ldr(r0, frame_->Top());
1601 frame_->EmitPush(r0);
1602 LoadAndSpill(clause->label());
1603 Comparison(eq, true);
1604 Branch(false, &next_test);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001605
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001606 // Before entering the body from the test, remove the switch value from
1607 // the stack.
1608 frame_->Drop();
1609
1610 // Label the body so that fall through is enabled.
1611 if (i > 0 && cases->at(i - 1)->is_default()) {
1612 default_exit.Bind();
1613 } else {
1614 fall_through.Bind();
1615 fall_through.Unuse();
1616 }
1617 VisitStatementsAndSpill(clause->statements());
1618
1619 // If control flow can fall through from the body, jump to the next body
1620 // or the end of the statement.
1621 if (frame_ != NULL) {
1622 if (i < length - 1 && cases->at(i + 1)->is_default()) {
1623 default_entry.Jump();
1624 } else {
1625 fall_through.Jump();
1626 }
1627 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628 }
1629
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001630 // The final "test" removes the switch value.
1631 next_test.Bind();
1632 frame_->Drop();
1633
1634 // If there is a default clause, compile it.
1635 if (default_clause != NULL) {
1636 Comment cmnt(masm_, "[ Default clause");
1637 default_entry.Bind();
1638 VisitStatementsAndSpill(default_clause->statements());
1639 // If control flow can fall out of the default and there is a case after
1640 // it, jup to that case's body.
1641 if (frame_ != NULL && default_exit.is_bound()) {
1642 default_exit.Jump();
1643 }
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00001644 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001645
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001646 if (fall_through.is_linked()) {
1647 fall_through.Bind();
1648 }
1649
1650 if (node->break_target()->is_linked()) {
1651 node->break_target()->Bind();
1652 }
1653 node->break_target()->Unuse();
1654 ASSERT(!has_valid_frame() || frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001655}
1656
1657
ager@chromium.org7c537e22008-10-16 08:43:32 +00001658void CodeGenerator::VisitLoopStatement(LoopStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001659#ifdef DEBUG
1660 int original_height = frame_->height();
1661#endif
1662 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001663 Comment cmnt(masm_, "[ LoopStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001664 CodeForStatementPosition(node);
1665 node->break_target()->Initialize(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001666
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001667 // Simple condition analysis. ALWAYS_TRUE and ALWAYS_FALSE represent a
1668 // known result for the test expression, with no side effects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 enum { ALWAYS_TRUE, ALWAYS_FALSE, DONT_KNOW } info = DONT_KNOW;
1670 if (node->cond() == NULL) {
1671 ASSERT(node->type() == LoopStatement::FOR_LOOP);
1672 info = ALWAYS_TRUE;
1673 } else {
1674 Literal* lit = node->cond()->AsLiteral();
1675 if (lit != NULL) {
1676 if (lit->IsTrue()) {
1677 info = ALWAYS_TRUE;
1678 } else if (lit->IsFalse()) {
1679 info = ALWAYS_FALSE;
1680 }
1681 }
1682 }
1683
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001684 switch (node->type()) {
1685 case LoopStatement::DO_LOOP: {
1686 JumpTarget body(this, JumpTarget::BIDIRECTIONAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001687
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001688 // Label the top of the loop for the backward CFG edge. If the test
1689 // is always true we can use the continue target, and if the test is
1690 // always false there is no need.
1691 if (info == ALWAYS_TRUE) {
1692 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
1693 node->continue_target()->Bind();
1694 } else if (info == ALWAYS_FALSE) {
1695 node->continue_target()->Initialize(this);
1696 } else {
1697 ASSERT(info == DONT_KNOW);
1698 node->continue_target()->Initialize(this);
1699 body.Bind();
1700 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001701
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001702 CheckStack(); // TODO(1222600): ignore if body contains calls.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001703 VisitAndSpill(node->body());
1704
1705 // Compile the test.
1706 if (info == ALWAYS_TRUE) {
1707 if (has_valid_frame()) {
1708 // If control can fall off the end of the body, jump back to the
1709 // top.
1710 node->continue_target()->Jump();
1711 }
1712 } else if (info == ALWAYS_FALSE) {
1713 // If we have a continue in the body, we only have to bind its jump
1714 // target.
1715 if (node->continue_target()->is_linked()) {
1716 node->continue_target()->Bind();
1717 }
1718 } else {
1719 ASSERT(info == DONT_KNOW);
1720 // We have to compile the test expression if it can be reached by
1721 // control flow falling out of the body or via continue.
1722 if (node->continue_target()->is_linked()) {
1723 node->continue_target()->Bind();
1724 }
1725 if (has_valid_frame()) {
1726 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
1727 &body, node->break_target(), true);
1728 if (has_valid_frame()) {
1729 // A invalid frame here indicates that control did not
1730 // fall out of the test expression.
1731 Branch(true, &body);
1732 }
1733 }
1734 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001735 break;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001736 }
1737
1738 case LoopStatement::WHILE_LOOP: {
1739 // If the test is never true and has no side effects there is no need
1740 // to compile the test or body.
1741 if (info == ALWAYS_FALSE) break;
1742
1743 // Label the top of the loop with the continue target for the backward
1744 // CFG edge.
1745 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
1746 node->continue_target()->Bind();
1747
1748 if (info == DONT_KNOW) {
1749 JumpTarget body(this);
1750 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
1751 &body, node->break_target(), true);
1752 if (has_valid_frame()) {
1753 // A NULL frame indicates that control did not fall out of the
1754 // test expression.
1755 Branch(false, node->break_target());
1756 }
1757 if (has_valid_frame() || body.is_linked()) {
1758 body.Bind();
1759 }
1760 }
1761
1762 if (has_valid_frame()) {
1763 CheckStack(); // TODO(1222600): ignore if body contains calls.
1764 VisitAndSpill(node->body());
1765
1766 // If control flow can fall out of the body, jump back to the top.
1767 if (has_valid_frame()) {
1768 node->continue_target()->Jump();
1769 }
1770 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001771 break;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001772 }
1773
1774 case LoopStatement::FOR_LOOP: {
1775 JumpTarget loop(this, JumpTarget::BIDIRECTIONAL);
1776
1777 if (node->init() != NULL) {
1778 VisitAndSpill(node->init());
1779 }
1780
1781 // There is no need to compile the test or body.
1782 if (info == ALWAYS_FALSE) break;
1783
1784 // If there is no update statement, label the top of the loop with the
1785 // continue target, otherwise with the loop target.
1786 if (node->next() == NULL) {
1787 node->continue_target()->Initialize(this, JumpTarget::BIDIRECTIONAL);
1788 node->continue_target()->Bind();
1789 } else {
1790 node->continue_target()->Initialize(this);
1791 loop.Bind();
1792 }
1793
1794 // If the test is always true, there is no need to compile it.
1795 if (info == DONT_KNOW) {
1796 JumpTarget body(this);
1797 LoadConditionAndSpill(node->cond(), NOT_INSIDE_TYPEOF,
1798 &body, node->break_target(), true);
1799 if (has_valid_frame()) {
1800 Branch(false, node->break_target());
1801 }
1802 if (has_valid_frame() || body.is_linked()) {
1803 body.Bind();
1804 }
1805 }
1806
1807 if (has_valid_frame()) {
1808 CheckStack(); // TODO(1222600): ignore if body contains calls.
1809 VisitAndSpill(node->body());
1810
1811 if (node->next() == NULL) {
1812 // If there is no update statement and control flow can fall out
1813 // of the loop, jump directly to the continue label.
1814 if (has_valid_frame()) {
1815 node->continue_target()->Jump();
1816 }
1817 } else {
1818 // If there is an update statement and control flow can reach it
1819 // via falling out of the body of the loop or continuing, we
1820 // compile the update statement.
1821 if (node->continue_target()->is_linked()) {
1822 node->continue_target()->Bind();
1823 }
1824 if (has_valid_frame()) {
1825 // Record source position of the statement as this code which is
1826 // after the code for the body actually belongs to the loop
1827 // statement and not the body.
1828 CodeForStatementPosition(node);
1829 VisitAndSpill(node->next());
1830 loop.Jump();
1831 }
1832 }
1833 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001834 break;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001835 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001836 }
1837
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001838 if (node->break_target()->is_linked()) {
1839 node->break_target()->Bind();
1840 }
1841 node->continue_target()->Unuse();
1842 node->break_target()->Unuse();
1843 ASSERT(!has_valid_frame() || frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001844}
1845
1846
ager@chromium.org7c537e22008-10-16 08:43:32 +00001847void CodeGenerator::VisitForInStatement(ForInStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001848#ifdef DEBUG
1849 int original_height = frame_->height();
1850#endif
1851 ASSERT(!in_spilled_code());
1852 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001853 Comment cmnt(masm_, "[ ForInStatement");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001854 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001855
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001856 JumpTarget primitive(this);
1857 JumpTarget jsobject(this);
1858 JumpTarget fixed_array(this);
1859 JumpTarget entry(this, JumpTarget::BIDIRECTIONAL);
1860 JumpTarget end_del_check(this);
1861 JumpTarget exit(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001862
1863 // Get the object to enumerate over (converted to JSObject).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001864 LoadAndSpill(node->enumerable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001865
1866 // Both SpiderMonkey and kjs ignore null and undefined in contrast
1867 // to the specification. 12.6.4 mandates a call to ToObject.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001868 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001869 __ cmp(r0, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001870 exit.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001871 __ cmp(r0, Operand(Factory::null_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001872 exit.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001873
1874 // Stack layout in body:
1875 // [iteration counter (Smi)]
1876 // [length of array]
1877 // [FixedArray]
1878 // [Map or 0]
1879 // [Object]
1880
1881 // Check if enumerable is already a JSObject
1882 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001883 primitive.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001884 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
1885 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00001886 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001887 jsobject.Branch(hs);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001888
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001889 primitive.Bind();
1890 frame_->EmitPush(r0);
1891 Result arg_count = allocator_->Allocate(r0);
1892 ASSERT(arg_count.is_valid());
1893 __ mov(arg_count.reg(), Operand(0));
1894 frame_->InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS, &arg_count, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001895
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001896 jsobject.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001897 // Get the set of properties (as a FixedArray or Map).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001898 frame_->EmitPush(r0); // duplicate the object being enumerated
1899 frame_->EmitPush(r0);
1900 frame_->CallRuntime(Runtime::kGetPropertyNamesFast, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001901
1902 // If we got a Map, we can do a fast modification check.
1903 // Otherwise, we got a FixedArray, and we have to do a slow check.
1904 __ mov(r2, Operand(r0));
1905 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
1906 __ cmp(r1, Operand(Factory::meta_map()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001907 fixed_array.Branch(ne);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001908
1909 // Get enum cache
1910 __ mov(r1, Operand(r0));
1911 __ ldr(r1, FieldMemOperand(r1, Map::kInstanceDescriptorsOffset));
1912 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
1913 __ ldr(r2,
1914 FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
1915
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001916 frame_->EmitPush(r0); // map
1917 frame_->EmitPush(r2); // enum cache bridge cache
mads.s.ager31e71382008-08-13 09:32:07 +00001918 __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001920 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001921 __ mov(r0, Operand(Smi::FromInt(0)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001922 frame_->EmitPush(r0);
1923 entry.Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001924
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001925 fixed_array.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001926 __ mov(r1, Operand(Smi::FromInt(0)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001927 frame_->EmitPush(r1); // insert 0 in place of Map
1928 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001929
1930 // Push the length of the array and the initial index onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00001931 __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 __ mov(r0, Operand(r0, LSL, kSmiTagSize));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001933 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001934 __ mov(r0, Operand(Smi::FromInt(0))); // init index
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001935 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001936
1937 // Condition.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001938 entry.Bind();
mads.s.ager31e71382008-08-13 09:32:07 +00001939 // sp[0] : index
1940 // sp[1] : array/enum cache length
1941 // sp[2] : array or enum cache
1942 // sp[3] : 0 or map
1943 // sp[4] : enumerable
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001944 // Grab the current frame's height for the break and continue
1945 // targets only after all the state is pushed on the frame.
1946 node->break_target()->Initialize(this);
1947 node->continue_target()->Initialize(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001948
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001949 __ ldr(r0, frame_->ElementAt(0)); // load the current count
1950 __ ldr(r1, frame_->ElementAt(1)); // load the length
1951 __ cmp(r0, Operand(r1)); // compare to the array length
1952 node->break_target()->Branch(hs);
1953
1954 __ ldr(r0, frame_->ElementAt(0));
mads.s.ager31e71382008-08-13 09:32:07 +00001955
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001956 // Get the i'th entry of the array.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001957 __ ldr(r2, frame_->ElementAt(2));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001958 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
1959 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
1960
1961 // Get Map or 0.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001962 __ ldr(r2, frame_->ElementAt(3));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001963 // Check if this (still) matches the map of the enumerable.
1964 // If not, we have to filter the key.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001965 __ ldr(r1, frame_->ElementAt(4));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001966 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
1967 __ cmp(r1, Operand(r2));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001968 end_del_check.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001969
1970 // Convert the entry to a string (or null if it isn't a property anymore).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001971 __ ldr(r0, frame_->ElementAt(4)); // push enumerable
1972 frame_->EmitPush(r0);
1973 frame_->EmitPush(r3); // push entry
1974 Result arg_count_register = allocator_->Allocate(r0);
1975 ASSERT(arg_count_register.is_valid());
1976 __ mov(arg_count_register.reg(), Operand(1));
1977 Result result = frame_->InvokeBuiltin(Builtins::FILTER_KEY,
1978 CALL_JS,
1979 &arg_count_register,
1980 2);
1981 __ mov(r3, Operand(result.reg()));
1982 result.Unuse();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001983
1984 // If the property has been removed while iterating, we just skip it.
1985 __ cmp(r3, Operand(Factory::null_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001986 node->continue_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001987
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001988 end_del_check.Bind();
1989 // Store the entry in the 'each' expression and take another spin in the
1990 // loop. r3: i'th entry of the enum cache (or string there of)
1991 frame_->EmitPush(r3); // push entry
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001992 { Reference each(this, node->each());
1993 if (!each.is_illegal()) {
mads.s.ager31e71382008-08-13 09:32:07 +00001994 if (each.size() > 0) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001995 __ ldr(r0, frame_->ElementAt(each.size()));
1996 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00001997 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001998 // If the reference was to a slot we rely on the convenient property
1999 // that it doesn't matter whether a value (eg, r3 pushed above) is
2000 // right on top of or right underneath a zero-sized reference.
2001 each.SetValue(NOT_CONST_INIT);
mads.s.ager31e71382008-08-13 09:32:07 +00002002 if (each.size() > 0) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002003 // It's safe to pop the value lying on top of the reference before
2004 // unloading the reference itself (which preserves the top of stack,
2005 // ie, now the topmost value of the non-zero sized reference), since
2006 // we will discard the top of stack after unloading the reference
2007 // anyway.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002008 frame_->EmitPop(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00002009 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010 }
2011 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00002012 // Discard the i'th entry pushed above or else the remainder of the
2013 // reference, whichever is currently on top of the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002014 frame_->Drop();
2015
2016 // Body.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002017 CheckStack(); // TODO(1222600): ignore if body contains calls.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002018 VisitAndSpill(node->body());
2019
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002020 // Next. Reestablish a spilled frame in case we are coming here via
2021 // a continue in the body.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002022 node->continue_target()->Bind();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002023 frame_->SpillAll();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002024 frame_->EmitPop(r0);
2025 __ add(r0, r0, Operand(Smi::FromInt(1)));
2026 frame_->EmitPush(r0);
2027 entry.Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002028
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002029 // Cleanup. No need to spill because VirtualFrame::Drop is safe for
2030 // any frame.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002031 node->break_target()->Bind();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002032 frame_->Drop(5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002033
2034 // Exit.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002035 exit.Bind();
2036 node->continue_target()->Unuse();
2037 node->break_target()->Unuse();
2038 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002039}
2040
2041
ager@chromium.org7c537e22008-10-16 08:43:32 +00002042void CodeGenerator::VisitTryCatch(TryCatch* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002043#ifdef DEBUG
2044 int original_height = frame_->height();
2045#endif
2046 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002047 Comment cmnt(masm_, "[ TryCatch");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002048 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002049
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002050 JumpTarget try_block(this);
2051 JumpTarget exit(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002052
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002053 try_block.Call();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002054 // --- Catch block ---
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002055 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002056
2057 // Store the caught exception in the catch variable.
2058 { Reference ref(this, node->catch_var());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002059 ASSERT(ref.is_slot());
2060 // Here we make use of the convenient property that it doesn't matter
2061 // whether a value is immediately on top of or underneath a zero-sized
2062 // reference.
2063 ref.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002064 }
2065
2066 // Remove the exception from the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002067 frame_->Drop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002068
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002069 VisitStatementsAndSpill(node->catch_block()->statements());
2070 if (frame_ != NULL) {
2071 exit.Jump();
2072 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002073
2074
2075 // --- Try block ---
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002076 try_block.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002077
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002078 frame_->PushTryHandler(TRY_CATCH_HANDLER);
2079 int handler_height = frame_->height();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002080
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002081 // Shadow the labels for all escapes from the try block, including
2082 // returns. During shadowing, the original label is hidden as the
2083 // LabelShadow and operations on the original actually affect the
2084 // shadowing label.
2085 //
2086 // We should probably try to unify the escaping labels and the return
2087 // label.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002088 int nof_escapes = node->escaping_targets()->length();
2089 List<ShadowTarget*> shadows(1 + nof_escapes);
2090
2091 // Add the shadow target for the function return.
2092 static const int kReturnShadowIndex = 0;
2093 shadows.Add(new ShadowTarget(&function_return_));
2094 bool function_return_was_shadowed = function_return_is_shadowed_;
2095 function_return_is_shadowed_ = true;
2096 ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);
2097
2098 // Add the remaining shadow targets.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002099 for (int i = 0; i < nof_escapes; i++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002100 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002101 }
2102
2103 // Generate code for the statements in the try block.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002104 VisitStatementsAndSpill(node->try_block()->statements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002105
2106 // Stop the introduced shadowing and count the number of required unlinks.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002107 // After shadowing stops, the original labels are unshadowed and the
2108 // LabelShadows represent the formerly shadowing labels.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002109 bool has_unlinks = false;
2110 for (int i = 0; i < shadows.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002111 shadows[i]->StopShadowing();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002112 has_unlinks = has_unlinks || shadows[i]->is_linked();
2113 }
2114 function_return_is_shadowed_ = function_return_was_shadowed;
2115
2116 // Get an external reference to the handler address.
2117 ExternalReference handler_address(Top::k_handler_address);
2118
2119 // The next handler address is at kNextIndex in the stack.
2120 const int kNextIndex = StackHandlerConstants::kNextOffset / kPointerSize;
2121 // If we can fall off the end of the try block, unlink from try chain.
2122 if (has_valid_frame()) {
2123 __ ldr(r1, frame_->ElementAt(kNextIndex));
2124 __ mov(r3, Operand(handler_address));
2125 __ str(r1, MemOperand(r3));
2126 frame_->Drop(StackHandlerConstants::kSize / kPointerSize);
2127 if (has_unlinks) {
2128 exit.Jump();
2129 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002130 }
2131
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002132 // Generate unlink code for the (formerly) shadowing labels that have been
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002133 // jumped to. Deallocate each shadow target.
2134 for (int i = 0; i < shadows.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002135 if (shadows[i]->is_linked()) {
mads.s.ager31e71382008-08-13 09:32:07 +00002136 // Unlink from try chain;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002137 shadows[i]->Bind();
2138 // Because we can be jumping here (to spilled code) from unspilled
2139 // code, we need to reestablish a spilled frame at this block.
2140 frame_->SpillAll();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002141
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002142 // Reload sp from the top handler, because some statements that we
2143 // break from (eg, for...in) may have left stuff on the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002144 __ mov(r3, Operand(handler_address));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002145 __ ldr(sp, MemOperand(r3));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002146 // The stack pointer was restored to just below the code slot
2147 // (the topmost slot) in the handler.
2148 frame_->Forget(frame_->height() - handler_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002149
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002150 // kNextIndex is off by one because the code slot has already
2151 // been dropped.
2152 __ ldr(r1, frame_->ElementAt(kNextIndex - 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002153 __ str(r1, MemOperand(r3));
ager@chromium.org381abbb2009-02-25 13:23:22 +00002154 // The code slot has already been dropped from the handler.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002155 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002156
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002157 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) {
2158 frame_->PrepareForReturn();
2159 }
2160 shadows[i]->other_target()->Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002161 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002162 delete shadows[i];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002163 }
2164
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002165 exit.Bind();
2166 ASSERT(!has_valid_frame() || frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002167}
2168
2169
ager@chromium.org7c537e22008-10-16 08:43:32 +00002170void CodeGenerator::VisitTryFinally(TryFinally* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002171#ifdef DEBUG
2172 int original_height = frame_->height();
2173#endif
2174 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002175 Comment cmnt(masm_, "[ TryFinally");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002176 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002177
2178 // State: Used to keep track of reason for entering the finally
2179 // block. Should probably be extended to hold information for
2180 // break/continue from within the try block.
2181 enum { FALLING, THROWING, JUMPING };
2182
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002183 JumpTarget try_block(this);
2184 JumpTarget finally_block(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002185
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002186 try_block.Call();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002187
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002188 frame_->EmitPush(r0); // save exception object on the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002189 // In case of thrown exceptions, this is where we continue.
2190 __ mov(r2, Operand(Smi::FromInt(THROWING)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002191 finally_block.Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002192
2193 // --- Try block ---
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002194 try_block.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002195
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002196 frame_->PushTryHandler(TRY_FINALLY_HANDLER);
2197 int handler_height = frame_->height();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002198
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002199 // Shadow the labels for all escapes from the try block, including
2200 // returns. Shadowing hides the original label as the LabelShadow and
2201 // operations on the original actually affect the shadowing label.
2202 //
2203 // We should probably try to unify the escaping labels and the return
2204 // label.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002205 int nof_escapes = node->escaping_targets()->length();
2206 List<ShadowTarget*> shadows(1 + nof_escapes);
2207
2208 // Add the shadow target for the function return.
2209 static const int kReturnShadowIndex = 0;
2210 shadows.Add(new ShadowTarget(&function_return_));
2211 bool function_return_was_shadowed = function_return_is_shadowed_;
2212 function_return_is_shadowed_ = true;
2213 ASSERT(shadows[kReturnShadowIndex]->other_target() == &function_return_);
2214
2215 // Add the remaining shadow targets.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002216 for (int i = 0; i < nof_escapes; i++) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002217 shadows.Add(new ShadowTarget(node->escaping_targets()->at(i)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002218 }
2219
2220 // Generate code for the statements in the try block.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002221 VisitStatementsAndSpill(node->try_block()->statements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002222
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002223 // Stop the introduced shadowing and count the number of required unlinks.
2224 // After shadowing stops, the original labels are unshadowed and the
2225 // LabelShadows represent the formerly shadowing labels.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002226 int nof_unlinks = 0;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002227 for (int i = 0; i < shadows.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002228 shadows[i]->StopShadowing();
2229 if (shadows[i]->is_linked()) nof_unlinks++;
2230 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002231 function_return_is_shadowed_ = function_return_was_shadowed;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002232
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002233 // Get an external reference to the handler address.
2234 ExternalReference handler_address(Top::k_handler_address);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002235
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002236 // The next handler address is at kNextIndex in the stack.
2237 const int kNextIndex = StackHandlerConstants::kNextOffset / kPointerSize;
2238 // If we can fall off the end of the try block, unlink from the try
2239 // chain and set the state on the frame to FALLING.
2240 if (has_valid_frame()) {
2241 __ ldr(r1, frame_->ElementAt(kNextIndex));
2242 __ mov(r3, Operand(handler_address));
2243 __ str(r1, MemOperand(r3));
2244 frame_->Drop(StackHandlerConstants::kSize / kPointerSize);
2245
2246 // Fake a top of stack value (unneeded when FALLING) and set the
2247 // state in r2, then jump around the unlink blocks if any.
2248 __ mov(r0, Operand(Factory::undefined_value()));
2249 frame_->EmitPush(r0);
2250 __ mov(r2, Operand(Smi::FromInt(FALLING)));
2251 if (nof_unlinks > 0) {
2252 finally_block.Jump();
2253 }
2254 }
2255
2256 // Generate code to unlink and set the state for the (formerly)
2257 // shadowing targets that have been jumped to.
2258 for (int i = 0; i < shadows.length(); i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002259 if (shadows[i]->is_linked()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002260 // If we have come from the shadowed return, the return value is
2261 // in (a non-refcounted reference to) r0. We must preserve it
2262 // until it is pushed.
2263 //
2264 // Because we can be jumping here (to spilled code) from
2265 // unspilled code, we need to reestablish a spilled frame at
2266 // this block.
2267 shadows[i]->Bind();
2268 frame_->SpillAll();
2269
2270 // Reload sp from the top handler, because some statements that
2271 // we break from (eg, for...in) may have left stuff on the
2272 // stack.
2273 __ mov(r3, Operand(handler_address));
2274 __ ldr(sp, MemOperand(r3));
2275 // The stack pointer was restored to the address slot in the handler.
2276 ASSERT(StackHandlerConstants::kNextOffset == 1 * kPointerSize);
2277 frame_->Forget(frame_->height() - handler_height + 1);
2278
2279 // Unlink this handler and drop it from the frame. The next
2280 // handler address is now on top of the frame.
2281 frame_->EmitPop(r1);
2282 __ str(r1, MemOperand(r3));
2283 // The top (code) and the second (handler) slot have both been
2284 // dropped already.
2285 frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 2);
2286
2287 if (i == kReturnShadowIndex) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00002288 // If this label shadowed the function return, materialize the
2289 // return value on the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002290 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00002291 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002292 // Fake TOS for targets that shadowed breaks and continues.
mads.s.ager31e71382008-08-13 09:32:07 +00002293 __ mov(r0, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002294 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002295 }
2296 __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002297 if (--nof_unlinks > 0) {
2298 // If this is not the last unlink block, jump around the next.
2299 finally_block.Jump();
2300 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002301 }
2302 }
2303
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002304 // --- Finally block ---
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002305 finally_block.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002306
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002307 // Push the state on the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002308 frame_->EmitPush(r2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00002309
2310 // We keep two elements on the stack - the (possibly faked) result
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002311 // and the state - while evaluating the finally block.
2312 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002313 // Generate code for the statements in the finally block.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002314 VisitStatementsAndSpill(node->finally_block()->statements());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002315
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002316 if (has_valid_frame()) {
2317 // Restore state and return value or faked TOS.
2318 frame_->EmitPop(r2);
2319 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002320 }
2321
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002322 // Generate code to jump to the right destination for all used
2323 // formerly shadowing targets. Deallocate each shadow target.
2324 for (int i = 0; i < shadows.length(); i++) {
2325 if (has_valid_frame() && shadows[i]->is_bound()) {
2326 JumpTarget* original = shadows[i]->other_target();
2327 __ cmp(r2, Operand(Smi::FromInt(JUMPING + i)));
2328 if (!function_return_is_shadowed_ && i == kReturnShadowIndex) {
2329 JumpTarget skip(this);
2330 skip.Branch(ne);
2331 frame_->PrepareForReturn();
2332 original->Jump();
2333 skip.Bind();
2334 } else {
2335 original->Branch(eq);
2336 }
2337 }
2338 delete shadows[i];
2339 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002340
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002341 if (has_valid_frame()) {
2342 // Check if we need to rethrow the exception.
2343 JumpTarget exit(this);
2344 __ cmp(r2, Operand(Smi::FromInt(THROWING)));
2345 exit.Branch(ne);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002346
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002347 // Rethrow exception.
2348 frame_->EmitPush(r0);
2349 frame_->CallRuntime(Runtime::kReThrow, 1);
2350
2351 // Done.
2352 exit.Bind();
2353 }
2354 ASSERT(!has_valid_frame() || frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002355}
2356
2357
ager@chromium.org7c537e22008-10-16 08:43:32 +00002358void CodeGenerator::VisitDebuggerStatement(DebuggerStatement* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002359#ifdef DEBUG
2360 int original_height = frame_->height();
2361#endif
2362 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002363 Comment cmnt(masm_, "[ DebuggerStatament");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002364 CodeForStatementPosition(node);
2365 frame_->CallRuntime(Runtime::kDebugBreak, 0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00002366 // Ignore the return value.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002367 ASSERT(frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002368}
2369
2370
ager@chromium.org7c537e22008-10-16 08:43:32 +00002371void CodeGenerator::InstantiateBoilerplate(Handle<JSFunction> boilerplate) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002372 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002373 ASSERT(boilerplate->IsBoilerplate());
2374
2375 // Push the boilerplate on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002376 __ mov(r0, Operand(boilerplate));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002377 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002378
2379 // Create a new closure.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002380 frame_->EmitPush(cp);
2381 frame_->CallRuntime(Runtime::kNewClosure, 2);
2382 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002383}
2384
2385
ager@chromium.org7c537e22008-10-16 08:43:32 +00002386void CodeGenerator::VisitFunctionLiteral(FunctionLiteral* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002387#ifdef DEBUG
2388 int original_height = frame_->height();
2389#endif
2390 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002391 Comment cmnt(masm_, "[ FunctionLiteral");
2392
2393 // Build the function boilerplate and instantiate it.
2394 Handle<JSFunction> boilerplate = BuildBoilerplate(node);
kasper.lund212ac232008-07-16 07:07:30 +00002395 // Check for stack-overflow exception.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002396 if (HasStackOverflow()) {
2397 ASSERT(frame_->height() == original_height);
2398 return;
2399 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002400 InstantiateBoilerplate(boilerplate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002401 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002402}
2403
2404
ager@chromium.org7c537e22008-10-16 08:43:32 +00002405void CodeGenerator::VisitFunctionBoilerplateLiteral(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002406 FunctionBoilerplateLiteral* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002407#ifdef DEBUG
2408 int original_height = frame_->height();
2409#endif
2410 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002411 Comment cmnt(masm_, "[ FunctionBoilerplateLiteral");
2412 InstantiateBoilerplate(node->boilerplate());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002413 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002414}
2415
2416
ager@chromium.org7c537e22008-10-16 08:43:32 +00002417void CodeGenerator::VisitConditional(Conditional* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002418#ifdef DEBUG
2419 int original_height = frame_->height();
2420#endif
2421 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002422 Comment cmnt(masm_, "[ Conditional");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002423 JumpTarget then(this);
2424 JumpTarget else_(this);
2425 JumpTarget exit(this);
2426 LoadConditionAndSpill(node->condition(), NOT_INSIDE_TYPEOF,
2427 &then, &else_, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002428 Branch(false, &else_);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002429 then.Bind();
2430 LoadAndSpill(node->then_expression(), typeof_state());
2431 exit.Jump();
2432 else_.Bind();
2433 LoadAndSpill(node->else_expression(), typeof_state());
2434 exit.Bind();
2435 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002436}
2437
2438
ager@chromium.org7c537e22008-10-16 08:43:32 +00002439void CodeGenerator::LoadFromSlot(Slot* slot, TypeofState typeof_state) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002440 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002441 if (slot->type() == Slot::LOOKUP) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002442 ASSERT(slot->var()->is_dynamic());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002443
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002444 JumpTarget slow(this);
2445 JumpTarget done(this);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002446
2447 // Generate fast-case code for variables that might be shadowed by
2448 // eval-introduced variables. Eval is used a lot without
2449 // introducing variables. In those cases, we do not want to
2450 // perform a runtime call for all variables in the scope
2451 // containing the eval.
2452 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
2453 LoadFromGlobalSlotCheckExtensions(slot, typeof_state, r1, r2, &slow);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002454 // If there was no control flow to slow, we can exit early.
2455 if (!slow.is_linked()) {
2456 frame_->EmitPush(r0);
2457 return;
2458 }
2459
2460 done.Jump();
ager@chromium.org381abbb2009-02-25 13:23:22 +00002461
2462 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
2463 Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
2464 // Only generate the fast case for locals that rewrite to slots.
2465 // This rules out argument loads.
2466 if (potential_slot != NULL) {
2467 __ ldr(r0,
2468 ContextSlotOperandCheckExtensions(potential_slot,
2469 r1,
2470 r2,
2471 &slow));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002472 // There is always control flow to slow from
2473 // ContextSlotOperandCheckExtensions.
2474 done.Jump();
ager@chromium.org381abbb2009-02-25 13:23:22 +00002475 }
2476 }
2477
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002478 slow.Bind();
2479 frame_->EmitPush(cp);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002480 __ mov(r0, Operand(slot->var()->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002481 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002482
ager@chromium.org7c537e22008-10-16 08:43:32 +00002483 if (typeof_state == INSIDE_TYPEOF) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002484 frame_->CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002485 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002486 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002487 }
ager@chromium.org381abbb2009-02-25 13:23:22 +00002488
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002489 done.Bind();
2490 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002491
2492 } else {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002493 // Note: We would like to keep the assert below, but it fires because of
2494 // some nasty code in LoadTypeofExpression() which should be removed...
ager@chromium.org381abbb2009-02-25 13:23:22 +00002495 // ASSERT(!slot->var()->is_dynamic());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002496
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002497 // Special handling for locals allocated in registers.
ager@chromium.org7c537e22008-10-16 08:43:32 +00002498 __ ldr(r0, SlotOperand(slot, r2));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002499 frame_->EmitPush(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002500 if (slot->var()->mode() == Variable::CONST) {
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002501 // Const slots may contain 'the hole' value (the constant hasn't been
2502 // initialized yet) which needs to be converted into the 'undefined'
2503 // value.
2504 Comment cmnt(masm_, "[ Unhole const");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002505 frame_->EmitPop(r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002506 __ cmp(r0, Operand(Factory::the_hole_value()));
2507 __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002508 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002509 }
2510 }
2511}
2512
2513
ager@chromium.org381abbb2009-02-25 13:23:22 +00002514void CodeGenerator::LoadFromGlobalSlotCheckExtensions(Slot* slot,
2515 TypeofState typeof_state,
2516 Register tmp,
2517 Register tmp2,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002518 JumpTarget* slow) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00002519 // Check that no extension objects have been created by calls to
2520 // eval from the current scope to the global scope.
2521 Register context = cp;
2522 Scope* s = scope();
2523 while (s != NULL) {
2524 if (s->num_heap_slots() > 0) {
2525 if (s->calls_eval()) {
2526 // Check that extension is NULL.
2527 __ ldr(tmp2, ContextOperand(context, Context::EXTENSION_INDEX));
2528 __ tst(tmp2, tmp2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002529 slow->Branch(ne);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002530 }
2531 // Load next context in chain.
2532 __ ldr(tmp, ContextOperand(context, Context::CLOSURE_INDEX));
2533 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
2534 context = tmp;
2535 }
2536 // If no outer scope calls eval, we do not need to check more
2537 // context extensions.
2538 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
2539 s = s->outer_scope();
2540 }
2541
2542 if (s->is_eval_scope()) {
2543 Label next, fast;
2544 if (!context.is(tmp)) __ mov(tmp, Operand(context));
2545 __ bind(&next);
2546 // Terminate at global context.
2547 __ ldr(tmp2, FieldMemOperand(tmp, HeapObject::kMapOffset));
2548 __ cmp(tmp2, Operand(Factory::global_context_map()));
2549 __ b(eq, &fast);
2550 // Check that extension is NULL.
2551 __ ldr(tmp2, ContextOperand(tmp, Context::EXTENSION_INDEX));
2552 __ tst(tmp2, tmp2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002553 slow->Branch(ne);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002554 // Load next context in chain.
2555 __ ldr(tmp, ContextOperand(tmp, Context::CLOSURE_INDEX));
2556 __ ldr(tmp, FieldMemOperand(tmp, JSFunction::kContextOffset));
2557 __ b(&next);
2558 __ bind(&fast);
2559 }
2560
2561 // All extension objects were empty and it is safe to use a global
2562 // load IC call.
2563 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
2564 // Load the global object.
2565 LoadGlobal();
2566 // Setup the name register.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002567 Result name = allocator_->Allocate(r2);
2568 ASSERT(name.is_valid()); // We are in spilled code.
2569 __ mov(name.reg(), Operand(slot->var()->name()));
ager@chromium.org381abbb2009-02-25 13:23:22 +00002570 // Call IC stub.
2571 if (typeof_state == INSIDE_TYPEOF) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002572 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET, &name, 0);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002573 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002574 frame_->CallCodeObject(ic, RelocInfo::CODE_TARGET_CONTEXT, &name, 0);
ager@chromium.org381abbb2009-02-25 13:23:22 +00002575 }
2576
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002577 // Drop the global object. The result is in r0.
2578 frame_->Drop();
ager@chromium.org381abbb2009-02-25 13:23:22 +00002579}
2580
2581
ager@chromium.org7c537e22008-10-16 08:43:32 +00002582void CodeGenerator::VisitSlot(Slot* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002583#ifdef DEBUG
2584 int original_height = frame_->height();
2585#endif
2586 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002587 Comment cmnt(masm_, "[ Slot");
2588 LoadFromSlot(node, typeof_state());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002589 ASSERT(frame_->height() == original_height + 1);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002590}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002591
ager@chromium.org7c537e22008-10-16 08:43:32 +00002592
2593void CodeGenerator::VisitVariableProxy(VariableProxy* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002594#ifdef DEBUG
2595 int original_height = frame_->height();
2596#endif
2597 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org7c537e22008-10-16 08:43:32 +00002598 Comment cmnt(masm_, "[ VariableProxy");
2599
2600 Variable* var = node->var();
2601 Expression* expr = var->rewrite();
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00002602 if (expr != NULL) {
2603 Visit(expr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002604 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00002605 ASSERT(var->is_global());
2606 Reference ref(this, node);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002607 ref.GetValueAndSpill(typeof_state());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002608 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002609 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002610}
2611
2612
ager@chromium.org7c537e22008-10-16 08:43:32 +00002613void CodeGenerator::VisitLiteral(Literal* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002614#ifdef DEBUG
2615 int original_height = frame_->height();
2616#endif
2617 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002618 Comment cmnt(masm_, "[ Literal");
mads.s.ager31e71382008-08-13 09:32:07 +00002619 __ mov(r0, Operand(node->handle()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002620 frame_->EmitPush(r0);
2621 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002622}
2623
2624
ager@chromium.org7c537e22008-10-16 08:43:32 +00002625void CodeGenerator::VisitRegExpLiteral(RegExpLiteral* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002626#ifdef DEBUG
2627 int original_height = frame_->height();
2628#endif
2629 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002630 Comment cmnt(masm_, "[ RexExp Literal");
2631
2632 // Retrieve the literal array and check the allocated entry.
2633
2634 // Load the function of this activation.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002635 __ ldr(r1, frame_->Function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002636
2637 // Load the literals array of the function.
2638 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
2639
2640 // Load the literal at the ast saved index.
2641 int literal_offset =
2642 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
2643 __ ldr(r2, FieldMemOperand(r1, literal_offset));
2644
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002645 JumpTarget done(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002646 __ cmp(r2, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002647 done.Branch(ne);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002648
2649 // If the entry is undefined we call the runtime system to computed
2650 // the literal.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002651 frame_->EmitPush(r1); // literal array (0)
mads.s.ager31e71382008-08-13 09:32:07 +00002652 __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002653 frame_->EmitPush(r0); // literal index (1)
mads.s.ager31e71382008-08-13 09:32:07 +00002654 __ mov(r0, Operand(node->pattern())); // RegExp pattern (2)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002655 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00002656 __ mov(r0, Operand(node->flags())); // RegExp flags (3)
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002657 frame_->EmitPush(r0);
2658 frame_->CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
mads.s.ager31e71382008-08-13 09:32:07 +00002659 __ mov(r2, Operand(r0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002660
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002661 done.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002662 // Push the literal.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002663 frame_->EmitPush(r2);
2664 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002665}
2666
2667
2668// This deferred code stub will be used for creating the boilerplate
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669// by calling Runtime_CreateObjectLiteralBoilerplate.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002670// Each created boilerplate is stored in the JSFunction and they are
2671// therefore context dependent.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002672class DeferredObjectLiteral: public DeferredCode {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002673 public:
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002674 DeferredObjectLiteral(CodeGenerator* generator, ObjectLiteral* node)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002675 : DeferredCode(generator), node_(node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002676 set_comment("[ DeferredObjectLiteral");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002677 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002678
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002679 virtual void Generate();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002680
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002681 private:
2682 ObjectLiteral* node_;
2683};
2684
2685
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002686void DeferredObjectLiteral::Generate() {
2687 // Argument is passed in r1.
2688 enter()->Bind();
2689 VirtualFrame::SpilledScope spilled_scope(generator());
2690
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 // If the entry is undefined we call the runtime system to compute
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002692 // the literal.
2693
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002694 VirtualFrame* frame = generator()->frame();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002695 // Literal array (0).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002696 frame->EmitPush(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002697 // Literal index (1).
mads.s.ager31e71382008-08-13 09:32:07 +00002698 __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002699 frame->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002700 // Constant properties (2).
mads.s.ager31e71382008-08-13 09:32:07 +00002701 __ mov(r0, Operand(node_->constant_properties()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002702 frame->EmitPush(r0);
2703 Result boilerplate =
2704 frame->CallRuntime(Runtime::kCreateObjectLiteralBoilerplate, 3);
2705 __ mov(r2, Operand(boilerplate.reg()));
2706 // Result is returned in r2.
2707 exit_.Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002708}
2709
2710
ager@chromium.org7c537e22008-10-16 08:43:32 +00002711void CodeGenerator::VisitObjectLiteral(ObjectLiteral* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002712#ifdef DEBUG
2713 int original_height = frame_->height();
2714#endif
2715 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002716 Comment cmnt(masm_, "[ ObjectLiteral");
2717
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002718 DeferredObjectLiteral* deferred = new DeferredObjectLiteral(this, node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002719
2720 // Retrieve the literal array and check the allocated entry.
2721
2722 // Load the function of this activation.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002723 __ ldr(r1, frame_->Function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002724
2725 // Load the literals array of the function.
2726 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
2727
2728 // Load the literal at the ast saved index.
2729 int literal_offset =
2730 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
2731 __ ldr(r2, FieldMemOperand(r1, literal_offset));
2732
2733 // Check whether we need to materialize the object literal boilerplate.
2734 // If so, jump to the deferred code.
2735 __ cmp(r2, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002736 deferred->enter()->Branch(eq);
2737 deferred->BindExit();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002738
2739 // Push the object literal boilerplate.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002740 frame_->EmitPush(r2);
mads.s.ager31e71382008-08-13 09:32:07 +00002741
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002742 // Clone the boilerplate object.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002743 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
2744 if (node->depth() == 1) {
2745 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
2746 }
2747 frame_->CallRuntime(clone_function_id, 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002748 frame_->EmitPush(r0); // save the result
mads.s.ager31e71382008-08-13 09:32:07 +00002749 // r0: cloned object literal
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002750
2751 for (int i = 0; i < node->properties()->length(); i++) {
2752 ObjectLiteral::Property* property = node->properties()->at(i);
2753 Literal* key = property->key();
2754 Expression* value = property->value();
2755 switch (property->kind()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002756 case ObjectLiteral::Property::CONSTANT:
2757 break;
2758 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
2759 if (CompileTimeValue::IsCompileTimeValue(property->value())) break;
2760 // else fall through
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002761 case ObjectLiteral::Property::COMPUTED: // fall through
2762 case ObjectLiteral::Property::PROTOTYPE: {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002763 frame_->EmitPush(r0); // dup the result
2764 LoadAndSpill(key);
2765 LoadAndSpill(value);
2766 frame_->CallRuntime(Runtime::kSetProperty, 3);
mads.s.ager31e71382008-08-13 09:32:07 +00002767 // restore r0
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002768 __ ldr(r0, frame_->Top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002769 break;
2770 }
2771 case ObjectLiteral::Property::SETTER: {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002772 frame_->EmitPush(r0);
2773 LoadAndSpill(key);
mads.s.ager31e71382008-08-13 09:32:07 +00002774 __ mov(r0, Operand(Smi::FromInt(1)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002775 frame_->EmitPush(r0);
2776 LoadAndSpill(value);
2777 frame_->CallRuntime(Runtime::kDefineAccessor, 4);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002778 __ ldr(r0, frame_->Top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002779 break;
2780 }
2781 case ObjectLiteral::Property::GETTER: {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002782 frame_->EmitPush(r0);
2783 LoadAndSpill(key);
mads.s.ager31e71382008-08-13 09:32:07 +00002784 __ mov(r0, Operand(Smi::FromInt(0)));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002785 frame_->EmitPush(r0);
2786 LoadAndSpill(value);
2787 frame_->CallRuntime(Runtime::kDefineAccessor, 4);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00002788 __ ldr(r0, frame_->Top());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002789 break;
2790 }
2791 }
2792 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002793 ASSERT(frame_->height() == original_height + 1);
2794}
2795
2796
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002797// This deferred code stub will be used for creating the boilerplate
2798// by calling Runtime_CreateArrayLiteralBoilerplate.
2799// Each created boilerplate is stored in the JSFunction and they are
2800// therefore context dependent.
2801class DeferredArrayLiteral: public DeferredCode {
2802 public:
2803 DeferredArrayLiteral(CodeGenerator* generator, ArrayLiteral* node)
2804 : DeferredCode(generator), node_(node) {
2805 set_comment("[ DeferredArrayLiteral");
2806 }
2807
2808 virtual void Generate();
2809
2810 private:
2811 ArrayLiteral* node_;
2812};
2813
2814
2815void DeferredArrayLiteral::Generate() {
2816 // Argument is passed in r1.
2817 enter()->Bind();
2818 VirtualFrame::SpilledScope spilled_scope(generator());
2819
2820 // If the entry is undefined we call the runtime system to computed
2821 // the literal.
2822
2823 VirtualFrame* frame = generator()->frame();
2824 // Literal array (0).
2825 frame->EmitPush(r1);
2826 // Literal index (1).
2827 __ mov(r0, Operand(Smi::FromInt(node_->literal_index())));
2828 frame->EmitPush(r0);
2829 // Constant properties (2).
2830 __ mov(r0, Operand(node_->literals()));
2831 frame->EmitPush(r0);
2832 Result boilerplate =
2833 frame->CallRuntime(Runtime::kCreateArrayLiteralBoilerplate, 3);
2834 __ mov(r2, Operand(boilerplate.reg()));
2835 // Result is returned in r2.
2836 exit_.Jump();
2837}
2838
2839
ager@chromium.org7c537e22008-10-16 08:43:32 +00002840void CodeGenerator::VisitArrayLiteral(ArrayLiteral* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002841#ifdef DEBUG
2842 int original_height = frame_->height();
2843#endif
2844 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002845 Comment cmnt(masm_, "[ ArrayLiteral");
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002846
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002847 DeferredArrayLiteral* deferred = new DeferredArrayLiteral(this, node);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002848
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002849 // Retrieve the literal array and check the allocated entry.
2850
2851 // Load the function of this activation.
2852 __ ldr(r1, frame_->Function());
2853
2854 // Load the literals array of the function.
2855 __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
2856
2857 // Load the literal at the ast saved index.
2858 int literal_offset =
2859 FixedArray::kHeaderSize + node->literal_index() * kPointerSize;
2860 __ ldr(r2, FieldMemOperand(r1, literal_offset));
2861
2862 // Check whether we need to materialize the object literal boilerplate.
2863 // If so, jump to the deferred code.
2864 __ cmp(r2, Operand(Factory::undefined_value()));
2865 deferred->enter()->Branch(eq);
2866 deferred->BindExit();
2867
2868 // Push the object literal boilerplate.
2869 frame_->EmitPush(r2);
2870
2871 // Clone the boilerplate object.
2872 Runtime::FunctionId clone_function_id = Runtime::kCloneLiteralBoilerplate;
2873 if (node->depth() == 1) {
2874 clone_function_id = Runtime::kCloneShallowLiteralBoilerplate;
2875 }
2876 frame_->CallRuntime(clone_function_id, 1);
2877 frame_->EmitPush(r0); // save the result
2878 // r0: cloned object literal
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002879
2880 // Generate code to set the elements in the array that are not
2881 // literals.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002882 for (int i = 0; i < node->values()->length(); i++) {
2883 Expression* value = node->values()->at(i);
2884
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002885 // If value is a literal the property value is already set in the
2886 // boilerplate object.
2887 if (value->AsLiteral() != NULL) continue;
2888 // If value is a materialized literal the property value is already set
2889 // in the boilerplate object if it is simple.
2890 if (CompileTimeValue::IsCompileTimeValue(value)) continue;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002891
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002892 // The property must be set by generated code.
2893 LoadAndSpill(value);
2894 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002895
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002896 // Fetch the object literal.
2897 __ ldr(r1, frame_->Top());
2898 // Get the elements array.
2899 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002900
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002901 // Write to the indexed properties array.
2902 int offset = i * kPointerSize + Array::kHeaderSize;
2903 __ str(r0, FieldMemOperand(r1, offset));
2904
2905 // Update the write barrier for the array address.
2906 __ mov(r3, Operand(offset));
2907 __ RecordWrite(r1, r3, r2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002908 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002909 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002910}
2911
2912
ager@chromium.org32912102009-01-16 10:38:43 +00002913void CodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002914#ifdef DEBUG
2915 int original_height = frame_->height();
2916#endif
2917 ASSERT(!in_spilled_code());
2918 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org32912102009-01-16 10:38:43 +00002919 // Call runtime routine to allocate the catch extension object and
2920 // assign the exception value to the catch variable.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002921 Comment cmnt(masm_, "[ CatchExtensionObject");
2922 LoadAndSpill(node->key());
2923 LoadAndSpill(node->value());
2924 Result result =
2925 frame_->CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
2926 frame_->EmitPush(result.reg());
2927 ASSERT(frame_->height() == original_height + 1);
ager@chromium.org32912102009-01-16 10:38:43 +00002928}
2929
2930
ager@chromium.org7c537e22008-10-16 08:43:32 +00002931void CodeGenerator::VisitAssignment(Assignment* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002932#ifdef DEBUG
2933 int original_height = frame_->height();
2934#endif
2935 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002936 Comment cmnt(masm_, "[ Assignment");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002937 CodeForStatementPosition(node);
mads.s.ager31e71382008-08-13 09:32:07 +00002938
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002939 { Reference target(this, node->target());
2940 if (target.is_illegal()) {
2941 // Fool the virtual frame into thinking that we left the assignment's
2942 // value on the frame.
2943 __ mov(r0, Operand(Smi::FromInt(0)));
2944 frame_->EmitPush(r0);
2945 ASSERT(frame_->height() == original_height + 1);
2946 return;
2947 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002948
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002949 if (node->op() == Token::ASSIGN ||
2950 node->op() == Token::INIT_VAR ||
2951 node->op() == Token::INIT_CONST) {
2952 LoadAndSpill(node->value());
mads.s.ager31e71382008-08-13 09:32:07 +00002953
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002954 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002955 target.GetValueAndSpill(NOT_INSIDE_TYPEOF);
2956 Literal* literal = node->value()->AsLiteral();
2957 if (literal != NULL && literal->handle()->IsSmi()) {
2958 SmiOperation(node->binary_op(), literal->handle(), false);
2959 frame_->EmitPush(r0);
2960
2961 } else {
2962 LoadAndSpill(node->value());
2963 GenericBinaryOperation(node->binary_op());
2964 frame_->EmitPush(r0);
2965 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002966 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002967
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002968 Variable* var = node->target()->AsVariableProxy()->AsVariable();
2969 if (var != NULL &&
2970 (var->mode() == Variable::CONST) &&
2971 node->op() != Token::INIT_VAR && node->op() != Token::INIT_CONST) {
2972 // Assignment ignored - leave the value on the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00002973
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002974 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002975 CodeForSourcePosition(node->position());
2976 if (node->op() == Token::INIT_CONST) {
2977 // Dynamic constant initializations must use the function context
2978 // and initialize the actual constant declared. Dynamic variable
2979 // initializations are simply assignments and use SetValue.
2980 target.SetValue(CONST_INIT);
2981 } else {
2982 target.SetValue(NOT_CONST_INIT);
2983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002984 }
2985 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002986 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002987}
2988
2989
ager@chromium.org7c537e22008-10-16 08:43:32 +00002990void CodeGenerator::VisitThrow(Throw* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002991#ifdef DEBUG
2992 int original_height = frame_->height();
2993#endif
2994 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002995 Comment cmnt(masm_, "[ Throw");
2996
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002997 LoadAndSpill(node->exception());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002998 CodeForSourcePosition(node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00002999 frame_->CallRuntime(Runtime::kThrow, 1);
3000 frame_->EmitPush(r0);
3001 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003002}
3003
3004
ager@chromium.org7c537e22008-10-16 08:43:32 +00003005void CodeGenerator::VisitProperty(Property* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003006#ifdef DEBUG
3007 int original_height = frame_->height();
3008#endif
3009 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003010 Comment cmnt(masm_, "[ Property");
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003011
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003012 { Reference property(this, node);
3013 property.GetValueAndSpill(typeof_state());
3014 }
3015 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003016}
3017
3018
ager@chromium.org7c537e22008-10-16 08:43:32 +00003019void CodeGenerator::VisitCall(Call* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003020#ifdef DEBUG
3021 int original_height = frame_->height();
3022#endif
3023 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003024 Comment cmnt(masm_, "[ Call");
3025
3026 ZoneList<Expression*>* args = node->arguments();
3027
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003028 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003029 // Standard function call.
3030
3031 // Check if the function is a variable or a property.
3032 Expression* function = node->expression();
3033 Variable* var = function->AsVariableProxy()->AsVariable();
3034 Property* property = function->AsProperty();
3035
3036 // ------------------------------------------------------------------------
3037 // Fast-case: Use inline caching.
3038 // ---
3039 // According to ECMA-262, section 11.2.3, page 44, the function to call
3040 // must be resolved after the arguments have been evaluated. The IC code
3041 // automatically handles this by loading the arguments before the function
3042 // is resolved in cache misses (this also holds for megamorphic calls).
3043 // ------------------------------------------------------------------------
3044
3045 if (var != NULL && !var->is_this() && var->is_global()) {
3046 // ----------------------------------
3047 // JavaScript example: 'foo(1, 2, 3)' // foo is global
3048 // ----------------------------------
3049
3050 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003051 __ mov(r0, Operand(var->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003052 frame_->EmitPush(r0);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003053
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003054 // Pass the global object as the receiver and let the IC stub
3055 // patch the stack to use the global proxy as 'this' in the
3056 // invoked function.
3057 LoadGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003058
3059 // Load the arguments.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003060 int arg_count = args->length();
3061 for (int i = 0; i < arg_count; i++) {
3062 LoadAndSpill(args->at(i));
3063 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003064
3065 // Setup the receiver register and call the IC initialization code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003066 Handle<Code> stub = ComputeCallInitialize(arg_count);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003067 CodeForSourcePosition(node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003068 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET_CONTEXT,
3069 arg_count + 1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003070 __ ldr(cp, frame_->Context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003071 // Remove the function from the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003072 frame_->Drop();
3073 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003074
3075 } else if (var != NULL && var->slot() != NULL &&
3076 var->slot()->type() == Slot::LOOKUP) {
3077 // ----------------------------------
3078 // JavaScript example: 'with (obj) foo(1, 2, 3)' // foo is in obj
3079 // ----------------------------------
3080
3081 // Load the function
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003082 frame_->EmitPush(cp);
mads.s.ager31e71382008-08-13 09:32:07 +00003083 __ mov(r0, Operand(var->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003084 frame_->EmitPush(r0);
3085 frame_->CallRuntime(Runtime::kLoadContextSlot, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003086 // r0: slot value; r1: receiver
3087
3088 // Load the receiver.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003089 frame_->EmitPush(r0); // function
3090 frame_->EmitPush(r1); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003091
3092 // Call the function.
3093 CallWithArguments(args, node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003094 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003095
3096 } else if (property != NULL) {
3097 // Check if the key is a literal string.
3098 Literal* literal = property->key()->AsLiteral();
3099
3100 if (literal != NULL && literal->handle()->IsSymbol()) {
3101 // ------------------------------------------------------------------
3102 // JavaScript example: 'object.foo(1, 2, 3)' or 'map["key"](1, 2, 3)'
3103 // ------------------------------------------------------------------
3104
3105 // Push the name of the function and the receiver onto the stack.
mads.s.ager31e71382008-08-13 09:32:07 +00003106 __ mov(r0, Operand(literal->handle()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003107 frame_->EmitPush(r0);
3108 LoadAndSpill(property->obj());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003109
3110 // Load the arguments.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003111 int arg_count = args->length();
3112 for (int i = 0; i < arg_count; i++) {
3113 LoadAndSpill(args->at(i));
3114 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003115
3116 // Set the receiver register and call the IC initialization code.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003117 Handle<Code> stub = ComputeCallInitialize(arg_count);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003118 CodeForSourcePosition(node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003119 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003120 __ ldr(cp, frame_->Context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003121
3122 // Remove the function from the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003123 frame_->Drop();
mads.s.ager31e71382008-08-13 09:32:07 +00003124
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003125 frame_->EmitPush(r0); // push after get rid of function from the stack
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003126
3127 } else {
3128 // -------------------------------------------
3129 // JavaScript example: 'array[index](1, 2, 3)'
3130 // -------------------------------------------
3131
3132 // Load the function to call from the property through a reference.
3133 Reference ref(this, property);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003134 ref.GetValueAndSpill(NOT_INSIDE_TYPEOF); // receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003135
3136 // Pass receiver to called function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003137 if (property->is_synthetic()) {
3138 LoadGlobalReceiver(r0);
3139 } else {
3140 __ ldr(r0, frame_->ElementAt(ref.size()));
3141 frame_->EmitPush(r0);
3142 }
3143
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003144 // Call the function.
3145 CallWithArguments(args, node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003146 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003147 }
3148
3149 } else {
3150 // ----------------------------------
3151 // JavaScript example: 'foo(1, 2, 3)' // foo is not global
3152 // ----------------------------------
3153
3154 // Load the function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003155 LoadAndSpill(function);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003156
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003157 // Pass the global proxy as the receiver.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003158 LoadGlobalReceiver(r0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003159
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003160 // Call the function.
3161 CallWithArguments(args, node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003162 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003163 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003164 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003165}
3166
3167
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003168void CodeGenerator::VisitCallEval(CallEval* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003169#ifdef DEBUG
3170 int original_height = frame_->height();
3171#endif
3172 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003173 Comment cmnt(masm_, "[ CallEval");
3174
3175 // In a call to eval, we first call %ResolvePossiblyDirectEval to resolve
3176 // the function we need to call and the receiver of the call.
3177 // Then we call the resolved function using the given arguments.
3178
3179 ZoneList<Expression*>* args = node->arguments();
3180 Expression* function = node->expression();
3181
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003182 CodeForStatementPosition(node);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003183
3184 // Prepare stack for call to resolved function.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003185 LoadAndSpill(function);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003186 __ mov(r2, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003187 frame_->EmitPush(r2); // Slot for receiver
3188 int arg_count = args->length();
3189 for (int i = 0; i < arg_count; i++) {
3190 LoadAndSpill(args->at(i));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003191 }
3192
3193 // Prepare stack for call to ResolvePossiblyDirectEval.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003194 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize + kPointerSize));
3195 frame_->EmitPush(r1);
3196 if (arg_count > 0) {
3197 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
3198 frame_->EmitPush(r1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003199 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003200 frame_->EmitPush(r2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003201 }
3202
3203 // Resolve the call.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003204 frame_->CallRuntime(Runtime::kResolvePossiblyDirectEval, 2);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003205
3206 // Touch up stack with the right values for the function and the receiver.
3207 __ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003208 __ str(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003209 __ ldr(r1, FieldMemOperand(r0, FixedArray::kHeaderSize + kPointerSize));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003210 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003211
3212 // Call the function.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003213 CodeForSourcePosition(node->position());
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003214
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003215 CallFunctionStub call_function(arg_count);
3216 frame_->CallStub(&call_function, arg_count + 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003217
3218 __ ldr(cp, frame_->Context());
3219 // Remove the function from the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003220 frame_->Drop();
3221 frame_->EmitPush(r0);
3222 ASSERT(frame_->height() == original_height + 1);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00003223}
3224
3225
ager@chromium.org7c537e22008-10-16 08:43:32 +00003226void CodeGenerator::VisitCallNew(CallNew* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003227#ifdef DEBUG
3228 int original_height = frame_->height();
3229#endif
3230 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003231 Comment cmnt(masm_, "[ CallNew");
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003232 CodeForStatementPosition(node);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003233
3234 // According to ECMA-262, section 11.2.2, page 44, the function
3235 // expression in new calls must be evaluated before the
3236 // arguments. This is different from ordinary calls, where the
3237 // actual function to call is resolved after the arguments have been
3238 // evaluated.
3239
3240 // Compute function to call and use the global object as the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003241 // receiver. There is no need to use the global proxy here because
3242 // it will always be replaced with a newly allocated object.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003243 LoadAndSpill(node->expression());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00003244 LoadGlobal();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003245
3246 // Push the arguments ("left-to-right") on the stack.
3247 ZoneList<Expression*>* args = node->arguments();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003248 int arg_count = args->length();
3249 for (int i = 0; i < arg_count; i++) {
3250 LoadAndSpill(args->at(i));
3251 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003252
mads.s.ager31e71382008-08-13 09:32:07 +00003253 // r0: the number of arguments.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003254 Result num_args = allocator_->Allocate(r0);
3255 ASSERT(num_args.is_valid());
3256 __ mov(num_args.reg(), Operand(arg_count));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003257
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003258 // Load the function into r1 as per calling convention.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003259 Result function = allocator_->Allocate(r1);
3260 ASSERT(function.is_valid());
3261 __ ldr(function.reg(), frame_->ElementAt(arg_count + 1));
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003262
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003263 // Call the construct call builtin that handles allocation and
3264 // constructor invocation.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003265 CodeForSourcePosition(node->position());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003266 Handle<Code> ic(Builtins::builtin(Builtins::JSConstructCall));
3267 Result result = frame_->CallCodeObject(ic,
3268 RelocInfo::CONSTRUCT_CALL,
3269 &num_args,
3270 &function,
3271 arg_count + 1);
mads.s.ager31e71382008-08-13 09:32:07 +00003272
3273 // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003274 __ str(r0, frame_->Top());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003275 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003276}
3277
3278
ager@chromium.org7c537e22008-10-16 08:43:32 +00003279void CodeGenerator::GenerateValueOf(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003280 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003281 ASSERT(args->length() == 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003282 JumpTarget leave(this);
3283 LoadAndSpill(args->at(0));
3284 frame_->EmitPop(r0); // r0 contains object.
mads.s.ager31e71382008-08-13 09:32:07 +00003285 // if (object->IsSmi()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003286 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003287 leave.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003288 // It is a heap object - get map.
3289 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
3290 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
mads.s.ager31e71382008-08-13 09:32:07 +00003291 // if (!object->IsJSValue()) return the object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003292 __ cmp(r1, Operand(JS_VALUE_TYPE));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003293 leave.Branch(ne);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003294 // Load the value.
3295 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003296 leave.Bind();
3297 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003298}
3299
3300
ager@chromium.org7c537e22008-10-16 08:43:32 +00003301void CodeGenerator::GenerateSetValueOf(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003302 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003303 ASSERT(args->length() == 2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003304 JumpTarget leave(this);
3305 LoadAndSpill(args->at(0)); // Load the object.
3306 LoadAndSpill(args->at(1)); // Load the value.
3307 frame_->EmitPop(r0); // r0 contains value
3308 frame_->EmitPop(r1); // r1 contains object
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003309 // if (object->IsSmi()) return object.
3310 __ tst(r1, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003311 leave.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003312 // It is a heap object - get map.
3313 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3314 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
3315 // if (!object->IsJSValue()) return object.
3316 __ cmp(r2, Operand(JS_VALUE_TYPE));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003317 leave.Branch(ne);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003318 // Store the value.
3319 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
3320 // Update the write barrier.
3321 __ mov(r2, Operand(JSValue::kValueOffset - kHeapObjectTag));
3322 __ RecordWrite(r1, r2, r3);
3323 // Leave.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003324 leave.Bind();
3325 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003326}
3327
3328
ager@chromium.org7c537e22008-10-16 08:43:32 +00003329void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003330 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003331 ASSERT(args->length() == 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003332 LoadAndSpill(args->at(0));
3333 frame_->EmitPop(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00003334 __ tst(r0, Operand(kSmiTagMask));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003335 cc_reg_ = eq;
3336}
3337
3338
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003339void CodeGenerator::GenerateLog(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003340 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003341 // See comment in CodeGenerator::GenerateLog in codegen-ia32.cc.
3342 ASSERT_EQ(args->length(), 3);
christian.plesner.hansen@gmail.comaca49682009-01-07 14:29:04 +00003343#ifdef ENABLE_LOGGING_AND_PROFILING
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003344 if (ShouldGenerateLog(args->at(0))) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003345 LoadAndSpill(args->at(1));
3346 LoadAndSpill(args->at(2));
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003347 __ CallRuntime(Runtime::kLog, 2);
3348 }
christian.plesner.hansen@gmail.comaca49682009-01-07 14:29:04 +00003349#endif
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003350 __ mov(r0, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003351 frame_->EmitPush(r0);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00003352}
3353
3354
ager@chromium.org7c537e22008-10-16 08:43:32 +00003355void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003356 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00003357 ASSERT(args->length() == 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003358 LoadAndSpill(args->at(0));
3359 frame_->EmitPop(r0);
ager@chromium.orgc27e4e72008-09-04 13:52:27 +00003360 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
3361 cc_reg_ = eq;
3362}
3363
3364
kasper.lund7276f142008-07-30 08:49:36 +00003365// This should generate code that performs a charCodeAt() call or returns
3366// undefined in order to trigger the slow case, Runtime_StringCharCodeAt.
3367// It is not yet implemented on ARM, so it always goes to the slow case.
ager@chromium.org7c537e22008-10-16 08:43:32 +00003368void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003369 VirtualFrame::SpilledScope spilled_scope(this);
kasper.lund7276f142008-07-30 08:49:36 +00003370 ASSERT(args->length() == 2);
kasper.lund7276f142008-07-30 08:49:36 +00003371 __ mov(r0, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003372 frame_->EmitPush(r0);
kasper.lund7276f142008-07-30 08:49:36 +00003373}
3374
3375
ager@chromium.org7c537e22008-10-16 08:43:32 +00003376void CodeGenerator::GenerateIsArray(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003377 VirtualFrame::SpilledScope spilled_scope(this);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003378 ASSERT(args->length() == 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003379 LoadAndSpill(args->at(0));
3380 JumpTarget answer(this);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003381 // We need the CC bits to come out as not_equal in the case where the
3382 // object is a smi. This can't be done with the usual test opcode so
3383 // we use XOR to get the right CC bits.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003384 frame_->EmitPop(r0);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003385 __ and_(r1, r0, Operand(kSmiTagMask));
3386 __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003387 answer.Branch(ne);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003388 // It is a heap object - get the map.
3389 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
3390 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3391 // Check if the object is a JS array or not.
3392 __ cmp(r1, Operand(JS_ARRAY_TYPE));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003393 answer.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003394 cc_reg_ = eq;
3395}
3396
3397
ager@chromium.org7c537e22008-10-16 08:43:32 +00003398void CodeGenerator::GenerateArgumentsLength(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003399 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400 ASSERT(args->length() == 0);
3401
mads.s.ager31e71382008-08-13 09:32:07 +00003402 // Seed the result with the formal parameters count, which will be used
3403 // in case no arguments adaptor frame is found below the current frame.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003404 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
3405
3406 // Call the shared stub to get to the arguments.length.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003407 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003408 frame_->CallStub(&stub, 0);
3409 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003410}
3411
3412
ager@chromium.org7c537e22008-10-16 08:43:32 +00003413void CodeGenerator::GenerateArgumentsAccess(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003414 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003415 ASSERT(args->length() == 1);
3416
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003417 // Satisfy contract with ArgumentsAccessStub:
3418 // Load the key into r1 and the formal parameters count into r0.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003419 LoadAndSpill(args->at(0));
3420 frame_->EmitPop(r1);
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00003421 __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003422
3423 // Call the shared stub to get to arguments[key].
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003424 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003425 frame_->CallStub(&stub, 0);
3426 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003427}
3428
3429
ager@chromium.org7c537e22008-10-16 08:43:32 +00003430void CodeGenerator::GenerateObjectEquals(ZoneList<Expression*>* args) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003431 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003432 ASSERT(args->length() == 2);
3433
3434 // Load the two objects into registers and perform the comparison.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003435 LoadAndSpill(args->at(0));
3436 LoadAndSpill(args->at(1));
3437 frame_->EmitPop(r0);
3438 frame_->EmitPop(r1);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00003439 __ cmp(r0, Operand(r1));
3440 cc_reg_ = eq;
3441}
3442
3443
ager@chromium.org7c537e22008-10-16 08:43:32 +00003444void CodeGenerator::VisitCallRuntime(CallRuntime* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003445#ifdef DEBUG
3446 int original_height = frame_->height();
3447#endif
3448 VirtualFrame::SpilledScope spilled_scope(this);
3449 if (CheckForInlineRuntimeCall(node)) {
3450 ASSERT((has_cc() && frame_->height() == original_height) ||
3451 (!has_cc() && frame_->height() == original_height + 1));
3452 return;
3453 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
3455 ZoneList<Expression*>* args = node->arguments();
3456 Comment cmnt(masm_, "[ CallRuntime");
3457 Runtime::Function* function = node->function();
3458
ager@chromium.org41826e72009-03-30 13:30:57 +00003459 if (function == NULL) {
mads.s.ager31e71382008-08-13 09:32:07 +00003460 // Prepare stack for calling JS runtime function.
3461 __ mov(r0, Operand(node->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003462 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00003463 // Push the builtins object found in the current global object.
3464 __ ldr(r1, GlobalObject());
3465 __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003466 frame_->EmitPush(r0);
ager@chromium.org41826e72009-03-30 13:30:57 +00003467 }
mads.s.ager31e71382008-08-13 09:32:07 +00003468
ager@chromium.org41826e72009-03-30 13:30:57 +00003469 // Push the arguments ("left-to-right").
3470 int arg_count = args->length();
3471 for (int i = 0; i < arg_count; i++) {
3472 LoadAndSpill(args->at(i));
3473 }
mads.s.ager31e71382008-08-13 09:32:07 +00003474
ager@chromium.org41826e72009-03-30 13:30:57 +00003475 if (function == NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003476 // Call the JS runtime function.
ager@chromium.org41826e72009-03-30 13:30:57 +00003477 Handle<Code> stub = ComputeCallInitialize(arg_count);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003478 frame_->CallCodeObject(stub, RelocInfo::CODE_TARGET, arg_count + 1);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003479 __ ldr(cp, frame_->Context());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003480 frame_->Drop();
3481 frame_->EmitPush(r0);
ager@chromium.org41826e72009-03-30 13:30:57 +00003482 } else {
3483 // Call the C runtime function.
3484 frame_->CallRuntime(function, arg_count);
3485 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003486 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003487 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003488}
3489
3490
ager@chromium.org7c537e22008-10-16 08:43:32 +00003491void CodeGenerator::VisitUnaryOperation(UnaryOperation* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003492#ifdef DEBUG
3493 int original_height = frame_->height();
3494#endif
3495 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003496 Comment cmnt(masm_, "[ UnaryOperation");
3497
3498 Token::Value op = node->op();
3499
3500 if (op == Token::NOT) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003501 LoadConditionAndSpill(node->expression(),
3502 NOT_INSIDE_TYPEOF,
3503 false_target(),
3504 true_target(),
3505 true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003506 cc_reg_ = NegateCondition(cc_reg_);
3507
3508 } else if (op == Token::DELETE) {
3509 Property* property = node->expression()->AsProperty();
mads.s.ager31e71382008-08-13 09:32:07 +00003510 Variable* variable = node->expression()->AsVariableProxy()->AsVariable();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003511 if (property != NULL) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003512 LoadAndSpill(property->obj());
3513 LoadAndSpill(property->key());
3514 Result arg_count = allocator_->Allocate(r0);
3515 ASSERT(arg_count.is_valid());
3516 __ mov(arg_count.reg(), Operand(1)); // not counting receiver
3517 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, &arg_count, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003518
mads.s.ager31e71382008-08-13 09:32:07 +00003519 } else if (variable != NULL) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003520 Slot* slot = variable->slot();
3521 if (variable->is_global()) {
3522 LoadGlobal();
mads.s.ager31e71382008-08-13 09:32:07 +00003523 __ mov(r0, Operand(variable->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003524 frame_->EmitPush(r0);
3525 Result arg_count = allocator_->Allocate(r0);
3526 ASSERT(arg_count.is_valid());
3527 __ mov(arg_count.reg(), Operand(1)); // not counting receiver
3528 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, &arg_count, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003529
3530 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
3531 // lookup the context holding the named variable
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003532 frame_->EmitPush(cp);
mads.s.ager31e71382008-08-13 09:32:07 +00003533 __ mov(r0, Operand(variable->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003534 frame_->EmitPush(r0);
3535 frame_->CallRuntime(Runtime::kLookupContext, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003536 // r0: context
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003537 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00003538 __ mov(r0, Operand(variable->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003539 frame_->EmitPush(r0);
3540 Result arg_count = allocator_->Allocate(r0);
3541 ASSERT(arg_count.is_valid());
3542 __ mov(arg_count.reg(), Operand(1)); // not counting receiver
3543 frame_->InvokeBuiltin(Builtins::DELETE, CALL_JS, &arg_count, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003544
mads.s.ager31e71382008-08-13 09:32:07 +00003545 } else {
3546 // Default: Result of deleting non-global, not dynamically
3547 // introduced variables is false.
3548 __ mov(r0, Operand(Factory::false_value()));
3549 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003550
3551 } else {
3552 // Default: Result of deleting expressions is true.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003553 LoadAndSpill(node->expression()); // may have side-effects
3554 frame_->Drop();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003555 __ mov(r0, Operand(Factory::true_value()));
3556 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003557 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003558
3559 } else if (op == Token::TYPEOF) {
3560 // Special case for loading the typeof expression; see comment on
3561 // LoadTypeofExpression().
3562 LoadTypeofExpression(node->expression());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003563 frame_->CallRuntime(Runtime::kTypeof, 1);
3564 frame_->EmitPush(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003565
3566 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003567 LoadAndSpill(node->expression());
3568 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003569 switch (op) {
3570 case Token::NOT:
3571 case Token::DELETE:
3572 case Token::TYPEOF:
3573 UNREACHABLE(); // handled above
3574 break;
3575
3576 case Token::SUB: {
3577 UnarySubStub stub;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003578 frame_->CallStub(&stub, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003579 break;
3580 }
3581
3582 case Token::BIT_NOT: {
3583 // smi check
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003584 JumpTarget smi_label(this);
3585 JumpTarget continue_label(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003586 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003587 smi_label.Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003588
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003589 frame_->EmitPush(r0);
3590 Result arg_count = allocator_->Allocate(r0);
3591 ASSERT(arg_count.is_valid());
3592 __ mov(arg_count.reg(), Operand(0)); // not counting receiver
3593 frame_->InvokeBuiltin(Builtins::BIT_NOT, CALL_JS, &arg_count, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003594
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003595 continue_label.Jump();
3596 smi_label.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003597 __ mvn(r0, Operand(r0));
3598 __ bic(r0, r0, Operand(kSmiTagMask)); // bit-clear inverted smi-tag
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003599 continue_label.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003600 break;
3601 }
3602
3603 case Token::VOID:
3604 // since the stack top is cached in r0, popping and then
3605 // pushing a value can be done by just writing to r0.
3606 __ mov(r0, Operand(Factory::undefined_value()));
3607 break;
3608
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003609 case Token::ADD: {
3610 // Smi check.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003611 JumpTarget continue_label(this);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003612 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003613 continue_label.Branch(eq);
3614 frame_->EmitPush(r0);
3615 Result arg_count = allocator_->Allocate(r0);
3616 ASSERT(arg_count.is_valid());
3617 __ mov(arg_count.reg(), Operand(0)); // not counting receiver
3618 frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, &arg_count, 1);
3619 continue_label.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003620 break;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00003621 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003622 default:
3623 UNREACHABLE();
3624 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003625 frame_->EmitPush(r0); // r0 has result
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003626 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003627 ASSERT((has_cc() && frame_->height() == original_height) ||
3628 (!has_cc() && frame_->height() == original_height + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003629}
3630
3631
ager@chromium.org7c537e22008-10-16 08:43:32 +00003632void CodeGenerator::VisitCountOperation(CountOperation* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003633#ifdef DEBUG
3634 int original_height = frame_->height();
3635#endif
3636 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003637 Comment cmnt(masm_, "[ CountOperation");
3638
3639 bool is_postfix = node->is_postfix();
3640 bool is_increment = node->op() == Token::INC;
3641
3642 Variable* var = node->expression()->AsVariableProxy()->AsVariable();
3643 bool is_const = (var != NULL && var->mode() == Variable::CONST);
3644
3645 // Postfix: Make room for the result.
mads.s.ager31e71382008-08-13 09:32:07 +00003646 if (is_postfix) {
3647 __ mov(r0, Operand(0));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003648 frame_->EmitPush(r0);
mads.s.ager31e71382008-08-13 09:32:07 +00003649 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003650
3651 { Reference target(this, node->expression());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003652 if (target.is_illegal()) {
3653 // Spoof the virtual frame to have the expected height (one higher
3654 // than on entry).
3655 if (!is_postfix) {
3656 __ mov(r0, Operand(Smi::FromInt(0)));
3657 frame_->EmitPush(r0);
3658 }
3659 ASSERT(frame_->height() == original_height + 1);
3660 return;
3661 }
3662 target.GetValueAndSpill(NOT_INSIDE_TYPEOF);
3663 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003664
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003665 JumpTarget slow(this);
3666 JumpTarget exit(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003667
3668 // Load the value (1) into register r1.
3669 __ mov(r1, Operand(Smi::FromInt(1)));
3670
3671 // Check for smi operand.
3672 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003673 slow.Branch(ne);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003674
3675 // Postfix: Store the old value as the result.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003676 if (is_postfix) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003677 __ str(r0, frame_->ElementAt(target.size()));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003678 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003679
3680 // Perform optimistic increment/decrement.
3681 if (is_increment) {
3682 __ add(r0, r0, Operand(r1), SetCC);
3683 } else {
3684 __ sub(r0, r0, Operand(r1), SetCC);
3685 }
3686
3687 // If the increment/decrement didn't overflow, we're done.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003688 exit.Branch(vc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003689
3690 // Revert optimistic increment/decrement.
3691 if (is_increment) {
3692 __ sub(r0, r0, Operand(r1));
3693 } else {
3694 __ add(r0, r0, Operand(r1));
3695 }
3696
3697 // Slow case: Convert to number.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003698 slow.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003699
3700 // Postfix: Convert the operand to a number and store it as the result.
3701 if (is_postfix) {
3702 InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003703 frame_->CallStub(&stub, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003704 // Store to result (on the stack).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003705 __ str(r0, frame_->ElementAt(target.size()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003706 }
3707
3708 // Compute the new value by calling the right JavaScript native.
3709 if (is_increment) {
3710 InvokeBuiltinStub stub(InvokeBuiltinStub::Inc, 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003711 frame_->CallStub(&stub, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003712 } else {
3713 InvokeBuiltinStub stub(InvokeBuiltinStub::Dec, 1);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003714 frame_->CallStub(&stub, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003715 }
3716
3717 // Store the new value in the target if not const.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003718 exit.Bind();
3719 frame_->EmitPush(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003720 if (!is_const) target.SetValue(NOT_CONST_INIT);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003721 }
3722
3723 // Postfix: Discard the new value and use the old.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003724 if (is_postfix) frame_->EmitPop(r0);
3725 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003726}
3727
3728
ager@chromium.org7c537e22008-10-16 08:43:32 +00003729void CodeGenerator::VisitBinaryOperation(BinaryOperation* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003730#ifdef DEBUG
3731 int original_height = frame_->height();
3732#endif
3733 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003734 Comment cmnt(masm_, "[ BinaryOperation");
3735 Token::Value op = node->op();
3736
3737 // According to ECMA-262 section 11.11, page 58, the binary logical
3738 // operators must yield the result of one of the two expressions
3739 // before any ToBoolean() conversions. This means that the value
3740 // produced by a && or || operator is not necessarily a boolean.
3741
3742 // NOTE: If the left hand side produces a materialized value (not in
3743 // the CC register), we force the right hand side to do the
3744 // same. This is necessary because we may have to branch to the exit
3745 // after evaluating the left hand side (due to the shortcut
3746 // semantics), but the compiler must (statically) know if the result
3747 // of compiling the binary operation is materialized or not.
3748
3749 if (op == Token::AND) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003750 JumpTarget is_true(this);
3751 LoadConditionAndSpill(node->left(),
3752 NOT_INSIDE_TYPEOF,
3753 &is_true,
3754 false_target(),
3755 false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003756 if (has_cc()) {
3757 Branch(false, false_target());
3758
3759 // Evaluate right side expression.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003760 is_true.Bind();
3761 LoadConditionAndSpill(node->right(),
3762 NOT_INSIDE_TYPEOF,
3763 true_target(),
3764 false_target(),
3765 false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003766
3767 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003768 JumpTarget pop_and_continue(this);
3769 JumpTarget exit(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003770
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003771 __ ldr(r0, frame_->Top()); // dup the stack top
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003772 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003773 // Avoid popping the result if it converts to 'false' using the
3774 // standard ToBoolean() conversion as described in ECMA-262,
3775 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00003776 ToBoolean(&pop_and_continue, &exit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003777 Branch(false, &exit);
3778
3779 // Pop the result of evaluating the first part.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003780 pop_and_continue.Bind();
3781 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003782
3783 // Evaluate right side expression.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003784 is_true.Bind();
3785 LoadAndSpill(node->right());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003786
3787 // Exit (always with a materialized value).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003788 exit.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003789 }
3790
3791 } else if (op == Token::OR) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003792 JumpTarget is_false(this);
3793 LoadConditionAndSpill(node->left(),
3794 NOT_INSIDE_TYPEOF,
3795 true_target(),
3796 &is_false,
3797 false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003798 if (has_cc()) {
3799 Branch(true, true_target());
3800
3801 // Evaluate right side expression.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003802 is_false.Bind();
3803 LoadConditionAndSpill(node->right(),
3804 NOT_INSIDE_TYPEOF,
3805 true_target(),
3806 false_target(),
3807 false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003808
3809 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003810 JumpTarget pop_and_continue(this);
3811 JumpTarget exit(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003812
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003813 __ ldr(r0, frame_->Top());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003814 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003815 // Avoid popping the result if it converts to 'true' using the
3816 // standard ToBoolean() conversion as described in ECMA-262,
3817 // section 9.2, page 30.
mads.s.ager31e71382008-08-13 09:32:07 +00003818 ToBoolean(&exit, &pop_and_continue);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003819 Branch(true, &exit);
3820
3821 // Pop the result of evaluating the first part.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003822 pop_and_continue.Bind();
3823 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003824
3825 // Evaluate right side expression.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003826 is_false.Bind();
3827 LoadAndSpill(node->right());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003828
3829 // Exit (always with a materialized value).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003830 exit.Bind();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003831 }
3832
3833 } else {
3834 // Optimize for the case where (at least) one of the expressions
3835 // is a literal small integer.
3836 Literal* lliteral = node->left()->AsLiteral();
3837 Literal* rliteral = node->right()->AsLiteral();
3838
3839 if (rliteral != NULL && rliteral->handle()->IsSmi()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003840 LoadAndSpill(node->left());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003841 SmiOperation(node->op(), rliteral->handle(), false);
3842
3843 } else if (lliteral != NULL && lliteral->handle()->IsSmi()) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003844 LoadAndSpill(node->right());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003845 SmiOperation(node->op(), lliteral->handle(), true);
3846
3847 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003848 LoadAndSpill(node->left());
3849 LoadAndSpill(node->right());
kasper.lund7276f142008-07-30 08:49:36 +00003850 GenericBinaryOperation(node->op());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003851 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003852 frame_->EmitPush(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003853 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003854 ASSERT((has_cc() && frame_->height() == original_height) ||
3855 (!has_cc() && frame_->height() == original_height + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003856}
3857
3858
ager@chromium.org7c537e22008-10-16 08:43:32 +00003859void CodeGenerator::VisitThisFunction(ThisFunction* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003860#ifdef DEBUG
3861 int original_height = frame_->height();
3862#endif
3863 VirtualFrame::SpilledScope spilled_scope(this);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003864 __ ldr(r0, frame_->Function());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003865 frame_->EmitPush(r0);
3866 ASSERT(frame_->height() == original_height + 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003867}
3868
3869
ager@chromium.org7c537e22008-10-16 08:43:32 +00003870void CodeGenerator::VisitCompareOperation(CompareOperation* node) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003871#ifdef DEBUG
3872 int original_height = frame_->height();
3873#endif
3874 VirtualFrame::SpilledScope spilled_scope(this);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003875 Comment cmnt(masm_, "[ CompareOperation");
3876
3877 // Get the expressions from the node.
3878 Expression* left = node->left();
3879 Expression* right = node->right();
3880 Token::Value op = node->op();
3881
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003882 // To make null checks efficient, we check if either left or right is the
3883 // literal 'null'. If so, we optimize the code by inlining a null check
3884 // instead of calling the (very) general runtime routine for checking
3885 // equality.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003886 if (op == Token::EQ || op == Token::EQ_STRICT) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003887 bool left_is_null =
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003888 left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00003889 bool right_is_null =
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003890 right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
3891 // The 'null' value can only be equal to 'null' or 'undefined'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003892 if (left_is_null || right_is_null) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003893 LoadAndSpill(left_is_null ? right : left);
3894 frame_->EmitPop(r0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003895 __ cmp(r0, Operand(Factory::null_value()));
3896
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003897 // The 'null' value is only equal to 'undefined' if using non-strict
3898 // comparisons.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003899 if (op != Token::EQ_STRICT) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003900 true_target()->Branch(eq);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003901
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003902 __ cmp(r0, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003903 true_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003904
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003905 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003906 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003907
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003908 // It can be an undetectable object.
3909 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
3910 __ ldrb(r0, FieldMemOperand(r0, Map::kBitFieldOffset));
3911 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
3912 __ cmp(r0, Operand(1 << Map::kIsUndetectable));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003913 }
3914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003915 cc_reg_ = eq;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003916 ASSERT(has_cc() && frame_->height() == original_height);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003917 return;
3918 }
3919 }
3920
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003921 // To make typeof testing for natives implemented in JavaScript really
3922 // efficient, we generate special code for expressions of the form:
3923 // 'typeof <expression> == <string>'.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003924 UnaryOperation* operation = left->AsUnaryOperation();
3925 if ((op == Token::EQ || op == Token::EQ_STRICT) &&
3926 (operation != NULL && operation->op() == Token::TYPEOF) &&
3927 (right->AsLiteral() != NULL &&
3928 right->AsLiteral()->handle()->IsString())) {
3929 Handle<String> check(String::cast(*right->AsLiteral()->handle()));
3930
mads.s.ager31e71382008-08-13 09:32:07 +00003931 // Load the operand, move it to register r1.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003932 LoadTypeofExpression(operation->expression());
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003933 frame_->EmitPop(r1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003934
3935 if (check->Equals(Heap::number_symbol())) {
3936 __ tst(r1, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003937 true_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003938 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
3939 __ cmp(r1, Operand(Factory::heap_number_map()));
3940 cc_reg_ = eq;
3941
3942 } else if (check->Equals(Heap::string_symbol())) {
3943 __ tst(r1, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003944 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003945
3946 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
3947
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003948 // It can be an undetectable string object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
3950 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
3951 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003952 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953
3954 __ ldrb(r2, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3955 __ cmp(r2, Operand(FIRST_NONSTRING_TYPE));
3956 cc_reg_ = lt;
3957
3958 } else if (check->Equals(Heap::boolean_symbol())) {
3959 __ cmp(r1, Operand(Factory::true_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003960 true_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003961 __ cmp(r1, Operand(Factory::false_value()));
3962 cc_reg_ = eq;
3963
3964 } else if (check->Equals(Heap::undefined_symbol())) {
3965 __ cmp(r1, Operand(Factory::undefined_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003966 true_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003967
3968 __ tst(r1, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003969 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003970
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003971 // It can be an undetectable object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003972 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
3973 __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
3974 __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
3975 __ cmp(r2, Operand(1 << Map::kIsUndetectable));
3976
3977 cc_reg_ = eq;
3978
3979 } else if (check->Equals(Heap::function_symbol())) {
3980 __ tst(r1, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003981 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003982 __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
3983 __ ldrb(r1, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3984 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
3985 cc_reg_ = eq;
3986
3987 } else if (check->Equals(Heap::object_symbol())) {
3988 __ tst(r1, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003989 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990
3991 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
3992 __ cmp(r1, Operand(Factory::null_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003993 true_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994
ager@chromium.org3bf7b912008-11-17 09:09:45 +00003995 // It can be an undetectable object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
3997 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
3998 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00003999 false_target()->Branch(eq);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004000
4001 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4002 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004003 false_target()->Branch(lt);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004004 __ cmp(r2, Operand(LAST_JS_OBJECT_TYPE));
4005 cc_reg_ = le;
4006
4007 } else {
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004008 // Uncommon case: typeof testing against a string literal that is
4009 // never returned from the typeof operator.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004010 false_target()->Jump();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004011 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004012 ASSERT(!has_valid_frame() ||
4013 (has_cc() && frame_->height() == original_height));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004014 return;
4015 }
4016
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004017 LoadAndSpill(left);
4018 LoadAndSpill(right);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 switch (op) {
4020 case Token::EQ:
4021 Comparison(eq, false);
4022 break;
4023
4024 case Token::LT:
4025 Comparison(lt);
4026 break;
4027
4028 case Token::GT:
4029 Comparison(gt);
4030 break;
4031
4032 case Token::LTE:
4033 Comparison(le);
4034 break;
4035
4036 case Token::GTE:
4037 Comparison(ge);
4038 break;
4039
4040 case Token::EQ_STRICT:
4041 Comparison(eq, true);
4042 break;
4043
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004044 case Token::IN: {
4045 Result arg_count = allocator_->Allocate(r0);
4046 ASSERT(arg_count.is_valid());
4047 __ mov(arg_count.reg(), Operand(1)); // not counting receiver
4048 Result result = frame_->InvokeBuiltin(Builtins::IN,
4049 CALL_JS,
4050 &arg_count,
4051 2);
4052 frame_->EmitPush(result.reg());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004053 break;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004054 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004055
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004056 case Token::INSTANCEOF: {
4057 Result arg_count = allocator_->Allocate(r0);
4058 ASSERT(arg_count.is_valid());
4059 __ mov(arg_count.reg(), Operand(1)); // not counting receiver
4060 Result result = frame_->InvokeBuiltin(Builtins::INSTANCE_OF,
4061 CALL_JS,
4062 &arg_count,
4063 2);
4064 __ tst(result.reg(), Operand(result.reg()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00004065 cc_reg_ = eq;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 break;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004067 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068
4069 default:
4070 UNREACHABLE();
4071 }
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004072 ASSERT((has_cc() && frame_->height() == original_height) ||
4073 (!has_cc() && frame_->height() == original_height + 1));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004074}
4075
4076
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004077#ifdef DEBUG
4078bool CodeGenerator::HasValidEntryRegisters() { return true; }
4079#endif
4080
4081
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004082#undef __
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004083#define __ masm->
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004084
ager@chromium.org7c537e22008-10-16 08:43:32 +00004085Handle<String> Reference::GetName() {
4086 ASSERT(type_ == NAMED);
4087 Property* property = expression_->AsProperty();
4088 if (property == NULL) {
4089 // Global variable reference treated as a named property reference.
4090 VariableProxy* proxy = expression_->AsVariableProxy();
4091 ASSERT(proxy->AsVariable() != NULL);
4092 ASSERT(proxy->AsVariable()->is_global());
4093 return proxy->name();
4094 } else {
4095 Literal* raw_name = property->key()->AsLiteral();
4096 ASSERT(raw_name != NULL);
4097 return Handle<String>(String::cast(*raw_name->handle()));
4098 }
4099}
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004100
ager@chromium.org7c537e22008-10-16 08:43:32 +00004101
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004102void Reference::GetValueAndSpill(TypeofState typeof_state) {
4103 ASSERT(cgen_->in_spilled_code());
4104 cgen_->set_in_spilled_code(false);
4105 GetValue(typeof_state);
4106 cgen_->frame()->SpillAll();
4107 cgen_->set_in_spilled_code(true);
4108}
4109
4110
ager@chromium.org7c537e22008-10-16 08:43:32 +00004111void Reference::GetValue(TypeofState typeof_state) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004112 ASSERT(!cgen_->in_spilled_code());
4113 ASSERT(cgen_->HasValidEntryRegisters());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004114 ASSERT(!is_illegal());
4115 ASSERT(!cgen_->has_cc());
4116 MacroAssembler* masm = cgen_->masm();
4117 Property* property = expression_->AsProperty();
4118 if (property != NULL) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004119 cgen_->CodeForSourcePosition(property->position());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004120 }
4121
4122 switch (type_) {
4123 case SLOT: {
4124 Comment cmnt(masm, "[ Load from Slot");
4125 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
4126 ASSERT(slot != NULL);
4127 cgen_->LoadFromSlot(slot, typeof_state);
4128 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004129 }
4130
ager@chromium.org7c537e22008-10-16 08:43:32 +00004131 case NAMED: {
4132 // TODO(1241834): Make sure that this it is safe to ignore the
4133 // distinction between expressions in a typeof and not in a typeof. If
4134 // there is a chance that reference errors can be thrown below, we
4135 // must distinguish between the two kinds of loads (typeof expression
4136 // loads must not throw a reference error).
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004137 VirtualFrame* frame = cgen_->frame();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004138 Comment cmnt(masm, "[ Load from named Property");
ager@chromium.org7c537e22008-10-16 08:43:32 +00004139 Handle<String> name(GetName());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004140 Variable* var = expression_->AsVariableProxy()->AsVariable();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004141 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
4142 // Setup the name register.
4143 Result name_reg = cgen_->allocator()->Allocate(r2);
4144 ASSERT(name_reg.is_valid());
4145 __ mov(name_reg.reg(), Operand(name));
4146 ASSERT(var == NULL || var->is_global());
4147 RelocInfo::Mode rmode = (var == NULL)
4148 ? RelocInfo::CODE_TARGET
4149 : RelocInfo::CODE_TARGET_CONTEXT;
4150 Result answer = frame->CallCodeObject(ic, rmode, &name_reg, 0);
4151 frame->EmitPush(answer.reg());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004152 break;
4153 }
4154
4155 case KEYED: {
4156 // TODO(1241834): Make sure that this it is safe to ignore the
4157 // distinction between expressions in a typeof and not in a typeof.
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004158
4159 // TODO(181): Implement inlined version of array indexing once
4160 // loop nesting is properly tracked on ARM.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004161 VirtualFrame* frame = cgen_->frame();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004162 Comment cmnt(masm, "[ Load from keyed Property");
4163 ASSERT(property != NULL);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004164 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004165 Variable* var = expression_->AsVariableProxy()->AsVariable();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004166 ASSERT(var == NULL || var->is_global());
4167 RelocInfo::Mode rmode = (var == NULL)
4168 ? RelocInfo::CODE_TARGET
4169 : RelocInfo::CODE_TARGET_CONTEXT;
4170 Result answer = frame->CallCodeObject(ic, rmode, 0);
4171 frame->EmitPush(answer.reg());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004172 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004173 }
4174
4175 default:
4176 UNREACHABLE();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004177 }
4178}
4179
4180
ager@chromium.org7c537e22008-10-16 08:43:32 +00004181void Reference::SetValue(InitState init_state) {
4182 ASSERT(!is_illegal());
4183 ASSERT(!cgen_->has_cc());
4184 MacroAssembler* masm = cgen_->masm();
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004185 VirtualFrame* frame = cgen_->frame();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004186 Property* property = expression_->AsProperty();
4187 if (property != NULL) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004188 cgen_->CodeForSourcePosition(property->position());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004189 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004190
ager@chromium.org7c537e22008-10-16 08:43:32 +00004191 switch (type_) {
4192 case SLOT: {
4193 Comment cmnt(masm, "[ Store to Slot");
4194 Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
4195 ASSERT(slot != NULL);
4196 if (slot->type() == Slot::LOOKUP) {
ager@chromium.org381abbb2009-02-25 13:23:22 +00004197 ASSERT(slot->var()->is_dynamic());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004198
ager@chromium.org7c537e22008-10-16 08:43:32 +00004199 // For now, just do a runtime call.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004200 frame->EmitPush(cp);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004201 __ mov(r0, Operand(slot->var()->name()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004202 frame->EmitPush(r0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004203
ager@chromium.org7c537e22008-10-16 08:43:32 +00004204 if (init_state == CONST_INIT) {
4205 // Same as the case for a normal store, but ignores attribute
4206 // (e.g. READ_ONLY) of context slot so that we can initialize
4207 // const properties (introduced via eval("const foo = (some
4208 // expr);")). Also, uses the current function context instead of
4209 // the top context.
4210 //
4211 // Note that we must declare the foo upon entry of eval(), via a
4212 // context slot declaration, but we cannot initialize it at the
4213 // same time, because the const declaration may be at the end of
4214 // the eval code (sigh...) and the const variable may have been
4215 // used before (where its value is 'undefined'). Thus, we can only
4216 // do the initialization when we actually encounter the expression
4217 // and when the expression operands are defined and valid, and
4218 // thus we need the split into 2 operations: declaration of the
4219 // context slot followed by initialization.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004220 frame->CallRuntime(Runtime::kInitializeConstContextSlot, 3);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004221 } else {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004222 frame->CallRuntime(Runtime::kStoreContextSlot, 3);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004223 }
4224 // Storing a variable must keep the (new) value on the expression
4225 // stack. This is necessary for compiling assignment expressions.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004226 frame->EmitPush(r0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004227
ager@chromium.org7c537e22008-10-16 08:43:32 +00004228 } else {
ager@chromium.org381abbb2009-02-25 13:23:22 +00004229 ASSERT(!slot->var()->is_dynamic());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004230
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004231 JumpTarget exit(cgen_);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004232 if (init_state == CONST_INIT) {
4233 ASSERT(slot->var()->mode() == Variable::CONST);
4234 // Only the first const initialization must be executed (the slot
4235 // still contains 'the hole' value). When the assignment is
4236 // executed, the code is identical to a normal store (see below).
4237 Comment cmnt(masm, "[ Init const");
4238 __ ldr(r2, cgen_->SlotOperand(slot, r2));
4239 __ cmp(r2, Operand(Factory::the_hole_value()));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004240 exit.Branch(ne);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004241 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004242
ager@chromium.org7c537e22008-10-16 08:43:32 +00004243 // We must execute the store. Storing a variable must keep the
4244 // (new) value on the stack. This is necessary for compiling
4245 // assignment expressions.
4246 //
4247 // Note: We will reach here even with slot->var()->mode() ==
4248 // Variable::CONST because of const declarations which will
4249 // initialize consts to 'the hole' value and by doing so, end up
4250 // calling this code. r2 may be loaded with context; used below in
4251 // RecordWrite.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004252 frame->EmitPop(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004253 __ str(r0, cgen_->SlotOperand(slot, r2));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004254 frame->EmitPush(r0);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004255 if (slot->type() == Slot::CONTEXT) {
4256 // Skip write barrier if the written value is a smi.
4257 __ tst(r0, Operand(kSmiTagMask));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004258 exit.Branch(eq);
ager@chromium.org7c537e22008-10-16 08:43:32 +00004259 // r2 is loaded with context when calling SlotOperand above.
4260 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
4261 __ mov(r3, Operand(offset));
4262 __ RecordWrite(r2, r3, r1);
4263 }
4264 // If we definitely did not jump over the assignment, we do not need
4265 // to bind the exit label. Doing so can defeat peephole
4266 // optimization.
4267 if (init_state == CONST_INIT || slot->type() == Slot::CONTEXT) {
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004268 exit.Bind();
ager@chromium.org7c537e22008-10-16 08:43:32 +00004269 }
4270 }
4271 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004272 }
4273
ager@chromium.org7c537e22008-10-16 08:43:32 +00004274 case NAMED: {
4275 Comment cmnt(masm, "[ Store to named Property");
4276 // Call the appropriate IC code.
ager@chromium.org7c537e22008-10-16 08:43:32 +00004277 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004278 Handle<String> name(GetName());
4279
4280 Result value = cgen_->allocator()->Allocate(r0);
4281 ASSERT(value.is_valid());
4282 frame->EmitPop(value.reg());
4283
4284 // Setup the name register.
4285 Result property_name = cgen_->allocator()->Allocate(r2);
4286 ASSERT(property_name.is_valid());
4287 __ mov(property_name.reg(), Operand(name));
4288 Result answer = frame->CallCodeObject(ic,
4289 RelocInfo::CODE_TARGET,
4290 &value,
4291 &property_name,
4292 0);
4293 frame->EmitPush(answer.reg());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004294 break;
4295 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004296
ager@chromium.org7c537e22008-10-16 08:43:32 +00004297 case KEYED: {
4298 Comment cmnt(masm, "[ Store to keyed Property");
4299 Property* property = expression_->AsProperty();
4300 ASSERT(property != NULL);
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00004301 cgen_->CodeForSourcePosition(property->position());
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004302
4303 // Call IC code.
4304 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
4305 // TODO(1222589): Make the IC grab the values from the stack.
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00004306 Result value = cgen_->allocator()->Allocate(r0);
4307 ASSERT(value.is_valid());
4308 frame->EmitPop(value.reg()); // value
4309 Result result =
4310 frame->CallCodeObject(ic, RelocInfo::CODE_TARGET, &value, 0);
4311 frame->EmitPush(result.reg());
ager@chromium.org7c537e22008-10-16 08:43:32 +00004312 break;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004313 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004314
4315 default:
4316 UNREACHABLE();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004317 }
4318}
4319
4320
4321void GetPropertyStub::Generate(MacroAssembler* masm) {
4322 // sp[0]: key
4323 // sp[1]: receiver
4324 Label slow, fast;
4325 // Get the key and receiver object from the stack.
4326 __ ldm(ia, sp, r0.bit() | r1.bit());
4327 // Check that the key is a smi.
4328 __ tst(r0, Operand(kSmiTagMask));
4329 __ b(ne, &slow);
4330 __ mov(r0, Operand(r0, ASR, kSmiTagSize));
4331 // Check that the object isn't a smi.
4332 __ tst(r1, Operand(kSmiTagMask));
4333 __ b(eq, &slow);
4334
4335 // Check that the object is some kind of JS object EXCEPT JS Value type.
4336 // In the case that the object is a value-wrapper object,
4337 // we enter the runtime system to make sure that indexing into string
4338 // objects work as intended.
4339 ASSERT(JS_OBJECT_TYPE > JS_VALUE_TYPE);
4340 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
4341 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4342 __ cmp(r2, Operand(JS_OBJECT_TYPE));
4343 __ b(lt, &slow);
4344
4345 // Get the elements array of the object.
4346 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
4347 // Check that the object is in fast mode (not dictionary).
4348 __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
4349 __ cmp(r3, Operand(Factory::hash_table_map()));
4350 __ b(eq, &slow);
4351 // Check that the key (index) is within bounds.
4352 __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
4353 __ cmp(r0, Operand(r3));
4354 __ b(lo, &fast);
4355
4356 // Slow case: Push extra copies of the arguments (2).
4357 __ bind(&slow);
4358 __ ldm(ia, sp, r0.bit() | r1.bit());
4359 __ stm(db_w, sp, r0.bit() | r1.bit());
4360 // Do tail-call to runtime routine.
4361 __ TailCallRuntime(ExternalReference(Runtime::kGetProperty), 2);
4362
4363 // Fast case: Do the load.
4364 __ bind(&fast);
4365 __ add(r3, r1, Operand(Array::kHeaderSize - kHeapObjectTag));
4366 __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
4367 __ cmp(r0, Operand(Factory::the_hole_value()));
4368 // In case the loaded value is the_hole we have to consult GetProperty
4369 // to ensure the prototype chain is searched.
4370 __ b(eq, &slow);
4371
4372 __ StubReturn(1);
4373}
4374
4375
4376void SetPropertyStub::Generate(MacroAssembler* masm) {
4377 // r0 : value
4378 // sp[0] : key
4379 // sp[1] : receiver
4380
4381 Label slow, fast, array, extra, exit;
4382 // Get the key and the object from the stack.
4383 __ ldm(ia, sp, r1.bit() | r3.bit()); // r1 = key, r3 = receiver
4384 // Check that the key is a smi.
4385 __ tst(r1, Operand(kSmiTagMask));
4386 __ b(ne, &slow);
4387 // Check that the object isn't a smi.
4388 __ tst(r3, Operand(kSmiTagMask));
4389 __ b(eq, &slow);
4390 // Get the type of the object from its map.
4391 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
4392 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
4393 // Check if the object is a JS array or not.
4394 __ cmp(r2, Operand(JS_ARRAY_TYPE));
4395 __ b(eq, &array);
4396 // Check that the object is some kind of JS object.
4397 __ cmp(r2, Operand(FIRST_JS_OBJECT_TYPE));
4398 __ b(lt, &slow);
4399
4400
4401 // Object case: Check key against length in the elements array.
4402 __ ldr(r3, FieldMemOperand(r3, JSObject::kElementsOffset));
4403 // Check that the object is in fast mode (not dictionary).
4404 __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
4405 __ cmp(r2, Operand(Factory::hash_table_map()));
4406 __ b(eq, &slow);
4407 // Untag the key (for checking against untagged length in the fixed array).
4408 __ mov(r1, Operand(r1, ASR, kSmiTagSize));
4409 // Compute address to store into and check array bounds.
4410 __ add(r2, r3, Operand(Array::kHeaderSize - kHeapObjectTag));
4411 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2));
4412 __ ldr(ip, FieldMemOperand(r3, Array::kLengthOffset));
4413 __ cmp(r1, Operand(ip));
4414 __ b(lo, &fast);
4415
4416
4417 // Slow case: Push extra copies of the arguments (3).
4418 __ bind(&slow);
4419 __ ldm(ia, sp, r1.bit() | r3.bit()); // r0 == value, r1 == key, r3 == object
4420 __ stm(db_w, sp, r0.bit() | r1.bit() | r3.bit());
4421 // Do tail-call to runtime routine.
4422 __ TailCallRuntime(ExternalReference(Runtime::kSetProperty), 3);
4423
4424
4425 // Extra capacity case: Check if there is extra capacity to
4426 // perform the store and update the length. Used for adding one
4427 // element to the array by writing to array[array.length].
4428 // r0 == value, r1 == key, r2 == elements, r3 == object
4429 __ bind(&extra);
4430 __ b(ne, &slow); // do not leave holes in the array
4431 __ mov(r1, Operand(r1, ASR, kSmiTagSize)); // untag
4432 __ ldr(ip, FieldMemOperand(r2, Array::kLengthOffset));
4433 __ cmp(r1, Operand(ip));
4434 __ b(hs, &slow);
4435 __ mov(r1, Operand(r1, LSL, kSmiTagSize)); // restore tag
4436 __ add(r1, r1, Operand(1 << kSmiTagSize)); // and increment
4437 __ str(r1, FieldMemOperand(r3, JSArray::kLengthOffset));
4438 __ mov(r3, Operand(r2));
4439 // NOTE: Computing the address to store into must take the fact
4440 // that the key has been incremented into account.
4441 int displacement = Array::kHeaderSize - kHeapObjectTag -
4442 ((1 << kSmiTagSize) * 2);
4443 __ add(r2, r2, Operand(displacement));
4444 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
4445 __ b(&fast);
4446
4447
4448 // Array case: Get the length and the elements array from the JS
4449 // array. Check that the array is in fast mode; if it is the
4450 // length is always a smi.
4451 // r0 == value, r3 == object
4452 __ bind(&array);
4453 __ ldr(r2, FieldMemOperand(r3, JSObject::kElementsOffset));
4454 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
4455 __ cmp(r1, Operand(Factory::hash_table_map()));
4456 __ b(eq, &slow);
4457
4458 // Check the key against the length in the array, compute the
4459 // address to store into and fall through to fast case.
4460 __ ldr(r1, MemOperand(sp));
4461 // r0 == value, r1 == key, r2 == elements, r3 == object.
4462 __ ldr(ip, FieldMemOperand(r3, JSArray::kLengthOffset));
4463 __ cmp(r1, Operand(ip));
4464 __ b(hs, &extra);
4465 __ mov(r3, Operand(r2));
4466 __ add(r2, r2, Operand(Array::kHeaderSize - kHeapObjectTag));
4467 __ add(r2, r2, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
4468
4469
4470 // Fast case: Do the store.
4471 // r0 == value, r2 == address to store into, r3 == elements
4472 __ bind(&fast);
4473 __ str(r0, MemOperand(r2));
4474 // Skip write barrier if the written value is a smi.
4475 __ tst(r0, Operand(kSmiTagMask));
4476 __ b(eq, &exit);
4477 // Update write barrier for the elements array address.
4478 __ sub(r1, r2, Operand(r3));
4479 __ RecordWrite(r3, r1, r2);
4480 __ bind(&exit);
4481 __ StubReturn(1);
4482}
4483
4484
4485void GenericBinaryOpStub::Generate(MacroAssembler* masm) {
4486 // r1 : x
4487 // r0 : y
4488 // result : r0
4489
4490 switch (op_) {
4491 case Token::ADD: {
4492 Label slow, exit;
4493 // fast path
4494 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
4495 __ add(r0, r1, Operand(r0), SetCC); // add y optimistically
4496 // go slow-path in case of overflow
4497 __ b(vs, &slow);
4498 // go slow-path in case of non-smi operands
4499 ASSERT(kSmiTag == 0); // adjust code below
4500 __ tst(r2, Operand(kSmiTagMask));
4501 __ b(eq, &exit);
4502 // slow path
4503 __ bind(&slow);
4504 __ sub(r0, r0, Operand(r1)); // revert optimistic add
4505 __ push(r1);
4506 __ push(r0);
4507 __ mov(r0, Operand(1)); // set number of arguments
4508 __ InvokeBuiltin(Builtins::ADD, JUMP_JS);
4509 // done
4510 __ bind(&exit);
4511 break;
4512 }
4513
4514 case Token::SUB: {
4515 Label slow, exit;
4516 // fast path
4517 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
4518 __ sub(r3, r1, Operand(r0), SetCC); // subtract y optimistically
4519 // go slow-path in case of overflow
4520 __ b(vs, &slow);
4521 // go slow-path in case of non-smi operands
4522 ASSERT(kSmiTag == 0); // adjust code below
4523 __ tst(r2, Operand(kSmiTagMask));
4524 __ mov(r0, Operand(r3), LeaveCC, eq); // conditionally set r0 to result
4525 __ b(eq, &exit);
4526 // slow path
4527 __ bind(&slow);
4528 __ push(r1);
4529 __ push(r0);
4530 __ mov(r0, Operand(1)); // set number of arguments
4531 __ InvokeBuiltin(Builtins::SUB, JUMP_JS);
4532 // done
4533 __ bind(&exit);
4534 break;
4535 }
4536
4537 case Token::MUL: {
4538 Label slow, exit;
4539 // tag check
4540 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
4541 ASSERT(kSmiTag == 0); // adjust code below
4542 __ tst(r2, Operand(kSmiTagMask));
4543 __ b(ne, &slow);
4544 // remove tag from one operand (but keep sign), so that result is smi
4545 __ mov(ip, Operand(r0, ASR, kSmiTagSize));
4546 // do multiplication
4547 __ smull(r3, r2, r1, ip); // r3 = lower 32 bits of ip*r1
4548 // go slow on overflows (overflow bit is not set)
4549 __ mov(ip, Operand(r3, ASR, 31));
4550 __ cmp(ip, Operand(r2)); // no overflow if higher 33 bits are identical
4551 __ b(ne, &slow);
4552 // go slow on zero result to handle -0
4553 __ tst(r3, Operand(r3));
4554 __ mov(r0, Operand(r3), LeaveCC, ne);
4555 __ b(ne, &exit);
4556 // slow case
4557 __ bind(&slow);
4558 __ push(r1);
4559 __ push(r0);
4560 __ mov(r0, Operand(1)); // set number of arguments
4561 __ InvokeBuiltin(Builtins::MUL, JUMP_JS);
4562 // done
4563 __ bind(&exit);
4564 break;
4565 }
4566
4567 case Token::BIT_OR:
4568 case Token::BIT_AND:
4569 case Token::BIT_XOR: {
4570 Label slow, exit;
4571 // tag check
4572 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
4573 ASSERT(kSmiTag == 0); // adjust code below
4574 __ tst(r2, Operand(kSmiTagMask));
4575 __ b(ne, &slow);
4576 switch (op_) {
4577 case Token::BIT_OR: __ orr(r0, r0, Operand(r1)); break;
4578 case Token::BIT_AND: __ and_(r0, r0, Operand(r1)); break;
4579 case Token::BIT_XOR: __ eor(r0, r0, Operand(r1)); break;
4580 default: UNREACHABLE();
4581 }
4582 __ b(&exit);
4583 __ bind(&slow);
4584 __ push(r1); // restore stack
4585 __ push(r0);
4586 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
4587 switch (op_) {
4588 case Token::BIT_OR:
4589 __ InvokeBuiltin(Builtins::BIT_OR, JUMP_JS);
4590 break;
4591 case Token::BIT_AND:
4592 __ InvokeBuiltin(Builtins::BIT_AND, JUMP_JS);
4593 break;
4594 case Token::BIT_XOR:
4595 __ InvokeBuiltin(Builtins::BIT_XOR, JUMP_JS);
4596 break;
4597 default:
4598 UNREACHABLE();
4599 }
4600 __ bind(&exit);
4601 break;
4602 }
4603
4604 case Token::SHL:
4605 case Token::SHR:
4606 case Token::SAR: {
4607 Label slow, exit;
4608 // tag check
4609 __ orr(r2, r1, Operand(r0)); // r2 = x | y;
4610 ASSERT(kSmiTag == 0); // adjust code below
4611 __ tst(r2, Operand(kSmiTagMask));
4612 __ b(ne, &slow);
4613 // remove tags from operands (but keep sign)
4614 __ mov(r3, Operand(r1, ASR, kSmiTagSize)); // x
4615 __ mov(r2, Operand(r0, ASR, kSmiTagSize)); // y
4616 // use only the 5 least significant bits of the shift count
4617 __ and_(r2, r2, Operand(0x1f));
4618 // perform operation
4619 switch (op_) {
4620 case Token::SAR:
4621 __ mov(r3, Operand(r3, ASR, r2));
4622 // no checks of result necessary
4623 break;
4624
4625 case Token::SHR:
4626 __ mov(r3, Operand(r3, LSR, r2));
4627 // check that the *unsigned* result fits in a smi
4628 // neither of the two high-order bits can be set:
4629 // - 0x80000000: high bit would be lost when smi tagging
4630 // - 0x40000000: this number would convert to negative when
4631 // smi tagging these two cases can only happen with shifts
4632 // by 0 or 1 when handed a valid smi
4633 __ and_(r2, r3, Operand(0xc0000000), SetCC);
4634 __ b(ne, &slow);
4635 break;
4636
4637 case Token::SHL:
4638 __ mov(r3, Operand(r3, LSL, r2));
4639 // check that the *signed* result fits in a smi
4640 __ add(r2, r3, Operand(0x40000000), SetCC);
4641 __ b(mi, &slow);
4642 break;
4643
4644 default: UNREACHABLE();
4645 }
4646 // tag result and store it in r0
4647 ASSERT(kSmiTag == 0); // adjust code below
4648 __ mov(r0, Operand(r3, LSL, kSmiTagSize));
4649 __ b(&exit);
4650 // slow case
4651 __ bind(&slow);
4652 __ push(r1); // restore stack
4653 __ push(r0);
4654 __ mov(r0, Operand(1)); // 1 argument (not counting receiver).
4655 switch (op_) {
4656 case Token::SAR: __ InvokeBuiltin(Builtins::SAR, JUMP_JS); break;
4657 case Token::SHR: __ InvokeBuiltin(Builtins::SHR, JUMP_JS); break;
4658 case Token::SHL: __ InvokeBuiltin(Builtins::SHL, JUMP_JS); break;
4659 default: UNREACHABLE();
4660 }
4661 __ bind(&exit);
4662 break;
4663 }
4664
4665 default: UNREACHABLE();
4666 }
4667 __ Ret();
4668}
4669
4670
4671void StackCheckStub::Generate(MacroAssembler* masm) {
4672 Label within_limit;
4673 __ mov(ip, Operand(ExternalReference::address_of_stack_guard_limit()));
4674 __ ldr(ip, MemOperand(ip));
4675 __ cmp(sp, Operand(ip));
4676 __ b(hs, &within_limit);
4677 // Do tail-call to runtime routine.
4678 __ push(r0);
4679 __ TailCallRuntime(ExternalReference(Runtime::kStackGuard), 1);
4680 __ bind(&within_limit);
4681
4682 __ StubReturn(1);
4683}
4684
4685
4686void UnarySubStub::Generate(MacroAssembler* masm) {
4687 Label undo;
4688 Label slow;
4689 Label done;
4690
4691 // Enter runtime system if the value is not a smi.
4692 __ tst(r0, Operand(kSmiTagMask));
4693 __ b(ne, &slow);
4694
4695 // Enter runtime system if the value of the expression is zero
4696 // to make sure that we switch between 0 and -0.
4697 __ cmp(r0, Operand(0));
4698 __ b(eq, &slow);
4699
4700 // The value of the expression is a smi that is not zero. Try
4701 // optimistic subtraction '0 - value'.
4702 __ rsb(r1, r0, Operand(0), SetCC);
4703 __ b(vs, &slow);
4704
4705 // If result is a smi we are done.
4706 __ tst(r1, Operand(kSmiTagMask));
4707 __ mov(r0, Operand(r1), LeaveCC, eq); // conditionally set r0 to result
4708 __ b(eq, &done);
4709
4710 // Enter runtime system.
4711 __ bind(&slow);
4712 __ push(r0);
4713 __ mov(r0, Operand(0)); // set number of arguments
4714 __ InvokeBuiltin(Builtins::UNARY_MINUS, JUMP_JS);
4715
4716 __ bind(&done);
4717 __ StubReturn(1);
4718}
4719
4720
4721void InvokeBuiltinStub::Generate(MacroAssembler* masm) {
4722 __ push(r0);
4723 __ mov(r0, Operand(0)); // set number of arguments
4724 switch (kind_) {
4725 case ToNumber: __ InvokeBuiltin(Builtins::TO_NUMBER, JUMP_JS); break;
4726 case Inc: __ InvokeBuiltin(Builtins::INC, JUMP_JS); break;
4727 case Dec: __ InvokeBuiltin(Builtins::DEC, JUMP_JS); break;
4728 default: UNREACHABLE();
4729 }
4730 __ StubReturn(argc_);
4731}
4732
4733
4734void CEntryStub::GenerateThrowTOS(MacroAssembler* masm) {
4735 // r0 holds exception
4736 ASSERT(StackHandlerConstants::kSize == 6 * kPointerSize); // adjust this code
4737 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
4738 __ ldr(sp, MemOperand(r3));
4739 __ pop(r2); // pop next in chain
4740 __ str(r2, MemOperand(r3));
4741 // restore parameter- and frame-pointer and pop state.
4742 __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
4743 // Before returning we restore the context from the frame pointer if not NULL.
4744 // The frame pointer is NULL in the exception handler of a JS entry frame.
4745 __ cmp(fp, Operand(0));
4746 // Set cp to NULL if fp is NULL.
4747 __ mov(cp, Operand(0), LeaveCC, eq);
4748 // Restore cp otherwise.
4749 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
4750 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
4751 __ pop(pc);
4752}
4753
4754
4755void CEntryStub::GenerateThrowOutOfMemory(MacroAssembler* masm) {
4756 // Fetch top stack handler.
4757 __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
4758 __ ldr(r3, MemOperand(r3));
4759
4760 // Unwind the handlers until the ENTRY handler is found.
4761 Label loop, done;
4762 __ bind(&loop);
4763 // Load the type of the current stack handler.
4764 const int kStateOffset = StackHandlerConstants::kAddressDisplacement +
4765 StackHandlerConstants::kStateOffset;
4766 __ ldr(r2, MemOperand(r3, kStateOffset));
4767 __ cmp(r2, Operand(StackHandler::ENTRY));
4768 __ b(eq, &done);
4769 // Fetch the next handler in the list.
4770 const int kNextOffset = StackHandlerConstants::kAddressDisplacement +
4771 StackHandlerConstants::kNextOffset;
4772 __ ldr(r3, MemOperand(r3, kNextOffset));
4773 __ jmp(&loop);
4774 __ bind(&done);
4775
4776 // Set the top handler address to next handler past the current ENTRY handler.
4777 __ ldr(r0, MemOperand(r3, kNextOffset));
4778 __ mov(r2, Operand(ExternalReference(Top::k_handler_address)));
4779 __ str(r0, MemOperand(r2));
4780
4781 // Set external caught exception to false.
4782 __ mov(r0, Operand(false));
4783 ExternalReference external_caught(Top::k_external_caught_exception_address);
4784 __ mov(r2, Operand(external_caught));
4785 __ str(r0, MemOperand(r2));
4786
4787 // Set pending exception and r0 to out of memory exception.
4788 Failure* out_of_memory = Failure::OutOfMemoryException();
4789 __ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
4790 __ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address)));
4791 __ str(r0, MemOperand(r2));
4792
4793 // Restore the stack to the address of the ENTRY handler
4794 __ mov(sp, Operand(r3));
4795
ager@chromium.org3bf7b912008-11-17 09:09:45 +00004796 // Stack layout at this point. See also PushTryHandler
4797 // r3, sp -> next handler
4798 // state (ENTRY)
4799 // pp
4800 // fp
4801 // lr
4802
4803 // Discard ENTRY state (r2 is not used), and restore parameter-
4804 // and frame-pointer and pop state.
4805 __ ldm(ia_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit());
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004806 // Before returning we restore the context from the frame pointer if not NULL.
4807 // The frame pointer is NULL in the exception handler of a JS entry frame.
4808 __ cmp(fp, Operand(0));
4809 // Set cp to NULL if fp is NULL.
4810 __ mov(cp, Operand(0), LeaveCC, eq);
4811 // Restore cp otherwise.
4812 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne);
4813 if (kDebug && FLAG_debug_code) __ mov(lr, Operand(pc));
4814 __ pop(pc);
4815}
4816
4817
4818void CEntryStub::GenerateCore(MacroAssembler* masm,
4819 Label* throw_normal_exception,
4820 Label* throw_out_of_memory_exception,
4821 StackFrame::Type frame_type,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004822 bool do_gc,
4823 bool always_allocate) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004824 // r0: result parameter for PerformGC, if any
4825 // r4: number of arguments including receiver (C callee-saved)
4826 // r5: pointer to builtin function (C callee-saved)
4827 // r6: pointer to the first argument (C callee-saved)
4828
4829 if (do_gc) {
4830 // Passing r0.
4831 __ Call(FUNCTION_ADDR(Runtime::PerformGC), RelocInfo::RUNTIME_ENTRY);
4832 }
4833
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004834 ExternalReference scope_depth =
4835 ExternalReference::heap_always_allocate_scope_depth();
4836 if (always_allocate) {
4837 __ mov(r0, Operand(scope_depth));
4838 __ ldr(r1, MemOperand(r0));
4839 __ add(r1, r1, Operand(1));
4840 __ str(r1, MemOperand(r0));
4841 }
4842
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004843 // Call C built-in.
4844 // r0 = argc, r1 = argv
4845 __ mov(r0, Operand(r4));
4846 __ mov(r1, Operand(r6));
4847
4848 // TODO(1242173): To let the GC traverse the return address of the exit
4849 // frames, we need to know where the return address is. Right now,
4850 // we push it on the stack to be able to find it again, but we never
4851 // restore from it in case of changes, which makes it impossible to
4852 // support moving the C entry code stub. This should be fixed, but currently
4853 // this is OK because the CEntryStub gets generated so early in the V8 boot
4854 // sequence that it is not moving ever.
4855 __ add(lr, pc, Operand(4)); // compute return address: (pc + 8) + 4
4856 __ push(lr);
4857#if !defined(__arm__)
4858 // Notify the simulator of the transition to C code.
4859 __ swi(assembler::arm::call_rt_r5);
4860#else /* !defined(__arm__) */
ager@chromium.org41826e72009-03-30 13:30:57 +00004861 __ Jump(r5);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004862#endif /* !defined(__arm__) */
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004863
4864 if (always_allocate) {
4865 // It's okay to clobber r2 and r3 here. Don't mess with r0 and r1
4866 // though (contain the result).
4867 __ mov(r2, Operand(scope_depth));
4868 __ ldr(r3, MemOperand(r2));
4869 __ sub(r3, r3, Operand(1));
4870 __ str(r3, MemOperand(r2));
4871 }
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004872
4873 // check for failure result
4874 Label failure_returned;
4875 ASSERT(((kFailureTag + 1) & kFailureTagMask) == 0);
4876 // Lower 2 bits of r2 are 0 iff r0 has failure tag.
4877 __ add(r2, r0, Operand(1));
4878 __ tst(r2, Operand(kFailureTagMask));
4879 __ b(eq, &failure_returned);
4880
4881 // Exit C frame and return.
4882 // r0:r1: result
4883 // sp: stack pointer
4884 // fp: frame pointer
4885 // pp: caller's parameter pointer pp (restored as C callee-saved)
4886 __ LeaveExitFrame(frame_type);
4887
4888 // check if we should retry or throw exception
4889 Label retry;
4890 __ bind(&failure_returned);
4891 ASSERT(Failure::RETRY_AFTER_GC == 0);
4892 __ tst(r0, Operand(((1 << kFailureTypeTagSize) - 1) << kFailureTagSize));
4893 __ b(eq, &retry);
4894
4895 Label continue_exception;
4896 // If the returned failure is EXCEPTION then promote Top::pending_exception().
4897 __ cmp(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
4898 __ b(ne, &continue_exception);
4899
4900 // Retrieve the pending exception and clear the variable.
ager@chromium.org32912102009-01-16 10:38:43 +00004901 __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004902 __ ldr(r3, MemOperand(ip));
ager@chromium.org32912102009-01-16 10:38:43 +00004903 __ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004904 __ ldr(r0, MemOperand(ip));
4905 __ str(r3, MemOperand(ip));
4906
4907 __ bind(&continue_exception);
4908 // Special handling of out of memory exception.
4909 Failure* out_of_memory = Failure::OutOfMemoryException();
4910 __ cmp(r0, Operand(reinterpret_cast<int32_t>(out_of_memory)));
4911 __ b(eq, throw_out_of_memory_exception);
4912
4913 // Handle normal exception.
4914 __ jmp(throw_normal_exception);
4915
4916 __ bind(&retry); // pass last failure (r0) as parameter (r0) when retrying
4917}
4918
4919
4920void CEntryStub::GenerateBody(MacroAssembler* masm, bool is_debug_break) {
4921 // Called from JavaScript; parameters are on stack as if calling JS function
4922 // r0: number of arguments including receiver
4923 // r1: pointer to builtin function
4924 // fp: frame pointer (restored after C call)
4925 // sp: stack pointer (restored as callee's pp after C call)
4926 // cp: current context (C callee-saved)
4927 // pp: caller's parameter pointer pp (C callee-saved)
4928
4929 // NOTE: Invocations of builtins may return failure objects
4930 // instead of a proper result. The builtin entry handles
4931 // this by performing a garbage collection and retrying the
4932 // builtin once.
4933
4934 StackFrame::Type frame_type = is_debug_break
4935 ? StackFrame::EXIT_DEBUG
4936 : StackFrame::EXIT;
4937
4938 // Enter the exit frame that transitions from JavaScript to C++.
4939 __ EnterExitFrame(frame_type);
4940
4941 // r4: number of arguments (C callee-saved)
4942 // r5: pointer to builtin function (C callee-saved)
4943 // r6: pointer to first argument (C callee-saved)
4944
4945 Label throw_out_of_memory_exception;
4946 Label throw_normal_exception;
4947
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004948 // Call into the runtime system. Collect garbage before the call if
4949 // running with --gc-greedy set.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004950 if (FLAG_gc_greedy) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004951 Failure* failure = Failure::RetryAfterGC(0);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004952 __ mov(r0, Operand(reinterpret_cast<intptr_t>(failure)));
4953 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004954 GenerateCore(masm, &throw_normal_exception,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004955 &throw_out_of_memory_exception,
4956 frame_type,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004957 FLAG_gc_greedy,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004958 false);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004959
4960 // Do space-specific GC and retry runtime call.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004961 GenerateCore(masm,
4962 &throw_normal_exception,
4963 &throw_out_of_memory_exception,
4964 frame_type,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00004965 true,
4966 false);
4967
4968 // Do full GC and retry runtime call one final time.
4969 Failure* failure = Failure::InternalError();
4970 __ mov(r0, Operand(reinterpret_cast<int32_t>(failure)));
4971 GenerateCore(masm,
4972 &throw_normal_exception,
4973 &throw_out_of_memory_exception,
4974 frame_type,
4975 true,
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004976 true);
4977
4978 __ bind(&throw_out_of_memory_exception);
4979 GenerateThrowOutOfMemory(masm);
4980 // control flow for generated will not return.
4981
4982 __ bind(&throw_normal_exception);
4983 GenerateThrowTOS(masm);
4984}
4985
4986
4987void JSEntryStub::GenerateBody(MacroAssembler* masm, bool is_construct) {
4988 // r0: code entry
4989 // r1: function
4990 // r2: receiver
4991 // r3: argc
4992 // [sp+0]: argv
4993
4994 Label invoke, exit;
4995
4996 // Called from C, so do not pop argc and args on exit (preserve sp)
4997 // No need to save register-passed args
4998 // Save callee-saved registers (incl. cp, pp, and fp), sp, and lr
4999 __ stm(db_w, sp, kCalleeSaved | lr.bit());
5000
5001 // Get address of argv, see stm above.
5002 // r0: code entry
5003 // r1: function
5004 // r2: receiver
5005 // r3: argc
5006 __ add(r4, sp, Operand((kNumCalleeSaved + 1)*kPointerSize));
5007 __ ldr(r4, MemOperand(r4)); // argv
5008
5009 // Push a frame with special values setup to mark it as an entry frame.
5010 // r0: code entry
5011 // r1: function
5012 // r2: receiver
5013 // r3: argc
5014 // r4: argv
5015 int marker = is_construct ? StackFrame::ENTRY_CONSTRUCT : StackFrame::ENTRY;
5016 __ mov(r8, Operand(-1)); // Push a bad frame pointer to fail if it is used.
5017 __ mov(r7, Operand(~ArgumentsAdaptorFrame::SENTINEL));
5018 __ mov(r6, Operand(Smi::FromInt(marker)));
5019 __ mov(r5, Operand(ExternalReference(Top::k_c_entry_fp_address)));
5020 __ ldr(r5, MemOperand(r5));
5021 __ stm(db_w, sp, r5.bit() | r6.bit() | r7.bit() | r8.bit());
5022
5023 // Setup frame pointer for the frame to be pushed.
5024 __ add(fp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
5025
5026 // Call a faked try-block that does the invoke.
5027 __ bl(&invoke);
5028
5029 // Caught exception: Store result (exception) in the pending
5030 // exception field in the JSEnv and return a failure sentinel.
5031 // Coming in here the fp will be invalid because the PushTryHandler below
5032 // sets it to 0 to signal the existence of the JSEntry frame.
ager@chromium.org32912102009-01-16 10:38:43 +00005033 __ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005034 __ str(r0, MemOperand(ip));
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005035 __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005036 __ b(&exit);
5037
5038 // Invoke: Link this frame into the handler chain.
5039 __ bind(&invoke);
5040 // Must preserve r0-r4, r5-r7 are available.
5041 __ PushTryHandler(IN_JS_ENTRY, JS_ENTRY_HANDLER);
5042 // If an exception not caught by another handler occurs, this handler returns
5043 // control to the code after the bl(&invoke) above, which restores all
5044 // kCalleeSaved registers (including cp, pp and fp) to their saved values
5045 // before returning a failure to C.
5046
5047 // Clear any pending exceptions.
5048 __ mov(ip, Operand(ExternalReference::the_hole_value_location()));
5049 __ ldr(r5, MemOperand(ip));
ager@chromium.org32912102009-01-16 10:38:43 +00005050 __ mov(ip, Operand(ExternalReference(Top::k_pending_exception_address)));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005051 __ str(r5, MemOperand(ip));
5052
5053 // Invoke the function by calling through JS entry trampoline builtin.
5054 // Notice that we cannot store a reference to the trampoline code directly in
5055 // this stub, because runtime stubs are not traversed when doing GC.
5056
5057 // Expected registers by Builtins::JSEntryTrampoline
5058 // r0: code entry
5059 // r1: function
5060 // r2: receiver
5061 // r3: argc
5062 // r4: argv
5063 if (is_construct) {
5064 ExternalReference construct_entry(Builtins::JSConstructEntryTrampoline);
5065 __ mov(ip, Operand(construct_entry));
5066 } else {
5067 ExternalReference entry(Builtins::JSEntryTrampoline);
5068 __ mov(ip, Operand(entry));
5069 }
5070 __ ldr(ip, MemOperand(ip)); // deref address
5071
5072 // Branch and link to JSEntryTrampoline
5073 __ mov(lr, Operand(pc));
5074 __ add(pc, ip, Operand(Code::kHeaderSize - kHeapObjectTag));
5075
5076 // Unlink this frame from the handler chain. When reading the
5077 // address of the next handler, there is no need to use the address
5078 // displacement since the current stack pointer (sp) points directly
5079 // to the stack handler.
5080 __ ldr(r3, MemOperand(sp, StackHandlerConstants::kNextOffset));
5081 __ mov(ip, Operand(ExternalReference(Top::k_handler_address)));
5082 __ str(r3, MemOperand(ip));
5083 // No need to restore registers
5084 __ add(sp, sp, Operand(StackHandlerConstants::kSize));
5085
5086 __ bind(&exit); // r0 holds result
5087 // Restore the top frame descriptors from the stack.
5088 __ pop(r3);
5089 __ mov(ip, Operand(ExternalReference(Top::k_c_entry_fp_address)));
5090 __ str(r3, MemOperand(ip));
5091
5092 // Reset the stack to the callee saved registers.
5093 __ add(sp, sp, Operand(-EntryFrameConstants::kCallerFPOffset));
5094
5095 // Restore callee-saved registers and return.
5096#ifdef DEBUG
5097 if (FLAG_debug_code) __ mov(lr, Operand(pc));
5098#endif
5099 __ ldm(ia_w, sp, kCalleeSaved | pc.bit());
5100}
5101
5102
ager@chromium.org7c537e22008-10-16 08:43:32 +00005103void ArgumentsAccessStub::GenerateReadLength(MacroAssembler* masm) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005104 // Check if the calling frame is an arguments adaptor frame.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005105 Label adaptor;
5106 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5107 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
5108 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
ager@chromium.org7c537e22008-10-16 08:43:32 +00005109 __ b(eq, &adaptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005110
ager@chromium.org7c537e22008-10-16 08:43:32 +00005111 // Nothing to do: The formal number of parameters has already been
5112 // passed in register r0 by calling function. Just return it.
5113 __ mov(pc, lr);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005114
ager@chromium.org7c537e22008-10-16 08:43:32 +00005115 // Arguments adaptor case: Read the arguments length from the
5116 // adaptor frame and return it.
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005117 __ bind(&adaptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005118 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
ager@chromium.org7c537e22008-10-16 08:43:32 +00005119 __ mov(pc, lr);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005120}
5121
5122
ager@chromium.org7c537e22008-10-16 08:43:32 +00005123void ArgumentsAccessStub::GenerateReadElement(MacroAssembler* masm) {
5124 // The displacement is the offset of the last parameter (if any)
5125 // relative to the frame pointer.
5126 static const int kDisplacement =
5127 StandardFrameConstants::kCallerSPOffset - kPointerSize;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005128
ager@chromium.org7c537e22008-10-16 08:43:32 +00005129 // Check that the key is a smi.
5130 Label slow;
5131 __ tst(r1, Operand(kSmiTagMask));
5132 __ b(ne, &slow);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005133
ager@chromium.org7c537e22008-10-16 08:43:32 +00005134 // Check if the calling frame is an arguments adaptor frame.
5135 Label adaptor;
5136 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5137 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
5138 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
5139 __ b(eq, &adaptor);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005140
ager@chromium.org7c537e22008-10-16 08:43:32 +00005141 // Check index against formal parameters count limit passed in
5142 // through register eax. Use unsigned comparison to get negative
5143 // check for free.
5144 __ cmp(r1, r0);
5145 __ b(cs, &slow);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005146
ager@chromium.org7c537e22008-10-16 08:43:32 +00005147 // Read the argument from the stack and return it.
5148 __ sub(r3, r0, r1);
5149 __ add(r3, fp, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
5150 __ ldr(r0, MemOperand(r3, kDisplacement));
5151 __ mov(pc, lr);
5152
5153 // Arguments adaptor case: Check index against actual arguments
5154 // limit found in the arguments adaptor frame. Use unsigned
5155 // comparison to get negative check for free.
5156 __ bind(&adaptor);
5157 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
5158 __ cmp(r1, r0);
5159 __ b(cs, &slow);
5160
5161 // Read the argument from the adaptor frame and return it.
5162 __ sub(r3, r0, r1);
5163 __ add(r3, r2, Operand(r3, LSL, kPointerSizeLog2 - kSmiTagSize));
5164 __ ldr(r0, MemOperand(r3, kDisplacement));
5165 __ mov(pc, lr);
5166
5167 // Slow-case: Handle non-smi or out-of-bounds access to arguments
5168 // by calling the runtime system.
5169 __ bind(&slow);
5170 __ push(r1);
5171 __ TailCallRuntime(ExternalReference(Runtime::kGetArgumentsProperty), 1);
5172}
5173
5174
5175void ArgumentsAccessStub::GenerateNewObject(MacroAssembler* masm) {
5176 // Check if the calling frame is an arguments adaptor frame.
5177 Label runtime;
5178 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
5179 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
5180 __ cmp(r3, Operand(ArgumentsAdaptorFrame::SENTINEL));
5181 __ b(ne, &runtime);
5182
5183 // Patch the arguments.length and the parameters pointer.
5184 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
5185 __ str(r0, MemOperand(sp, 0 * kPointerSize));
5186 __ add(r3, r2, Operand(r0, LSL, kPointerSizeLog2 - kSmiTagSize));
5187 __ add(r3, r3, Operand(StandardFrameConstants::kCallerSPOffset));
5188 __ str(r3, MemOperand(sp, 1 * kPointerSize));
5189
5190 // Do the runtime call to allocate the arguments object.
5191 __ bind(&runtime);
5192 __ TailCallRuntime(ExternalReference(Runtime::kNewArgumentsFast), 3);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005193}
5194
5195
5196void CallFunctionStub::Generate(MacroAssembler* masm) {
5197 Label slow;
5198 // Get the function to call from the stack.
5199 // function, receiver [, arguments]
5200 __ ldr(r1, MemOperand(sp, (argc_ + 1) * kPointerSize));
5201
5202 // Check that the function is really a JavaScript function.
5203 // r1: pushed function (to be verified)
5204 __ tst(r1, Operand(kSmiTagMask));
5205 __ b(eq, &slow);
5206 // Get the map of the function object.
5207 __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
5208 __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
5209 __ cmp(r2, Operand(JS_FUNCTION_TYPE));
5210 __ b(ne, &slow);
5211
5212 // Fast-case: Invoke the function now.
5213 // r1: pushed function
5214 ParameterCount actual(argc_);
5215 __ InvokeFunction(r1, actual, JUMP_FUNCTION);
5216
5217 // Slow-case: Non-function called.
5218 __ bind(&slow);
5219 __ mov(r0, Operand(argc_)); // Setup the number of arguments.
ager@chromium.org3bf7b912008-11-17 09:09:45 +00005220 __ mov(r2, Operand(0));
5221 __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
5222 __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
5223 RelocInfo::CODE_TARGET);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00005224}
5225
5226
5227#undef __
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005228
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005229} } // namespace v8::internal