blob: f04015bd787b1473ab114accc318c2efa55064d0 [file] [log] [blame]
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_ARM)
31
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000032#include "code-stubs.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000033#include "codegen-inl.h"
34#include "compiler.h"
35#include "debug.h"
36#include "full-codegen.h"
37#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000038#include "scopes.h"
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +000039#include "stub-cache.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000040
41namespace v8 {
42namespace internal {
43
44#define __ ACCESS_MASM(masm_)
45
46// Generate code for a JS function. On entry to the function the receiver
47// and arguments have been pushed on the stack left to right. The actual
48// argument count matches the formal parameter count expected by the
49// function.
50//
51// The live registers are:
52// o r1: the JS function object being called (ie, ourselves)
53// o cp: our context
54// o fp: our caller's frame pointer
55// o sp: stack pointer
56// o lr: return address
57//
58// The function builds a JS frame. Please see JavaScriptFrameConstants in
59// frames-arm.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000060void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +000061 ASSERT(info_ == NULL);
62 info_ = info;
63 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000064 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000065
vegorov@chromium.org42841962010-10-18 11:18:59 +000066#ifdef DEBUG
67 if (strlen(FLAG_stop_at) > 0 &&
68 info->function()->name()->IsEqualTo(CStrVector(FLAG_stop_at))) {
69 __ stop("stop-at");
70 }
71#endif
72
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000073 int locals_count = scope()->num_stack_slots();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000074
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000075 __ Push(lr, fp, cp, r1);
76 if (locals_count > 0) {
77 // Load undefined value here, so the value is ready for the loop
78 // below.
79 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
80 }
81 // Adjust fp to point to caller's fp.
82 __ add(fp, sp, Operand(2 * kPointerSize));
83
84 { Comment cmnt(masm_, "[ Allocate locals");
85 for (int i = 0; i < locals_count; i++) {
86 __ push(ip);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000087 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000088 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000089
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000090 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000091
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000092 // Possibly allocate a local context.
93 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
94 if (heap_slots > 0) {
95 Comment cmnt(masm_, "[ Allocate local context");
96 // Argument to NewContext is the function, which is in r1.
97 __ push(r1);
98 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
99 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000100 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000101 } else {
102 __ CallRuntime(Runtime::kNewContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000103 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000104 function_in_register = false;
105 // Context is returned in both r0 and cp. It replaces the context
106 // passed to us. It's saved in the stack and kept live in cp.
107 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
108 // Copy any necessary parameters into the context.
109 int num_parameters = scope()->num_parameters();
110 for (int i = 0; i < num_parameters; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000111 Slot* slot = scope()->parameter(i)->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000112 if (slot != NULL && slot->type() == Slot::CONTEXT) {
113 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
114 (num_parameters - 1 - i) * kPointerSize;
115 // Load parameter from stack.
116 __ ldr(r0, MemOperand(fp, parameter_offset));
117 // Store it in the context.
118 __ mov(r1, Operand(Context::SlotOffset(slot->index())));
119 __ str(r0, MemOperand(cp, r1));
120 // Update the write barrier. This clobbers all involved
121 // registers, so we have to use two more registers to avoid
122 // clobbering cp.
123 __ mov(r2, Operand(cp));
124 __ RecordWrite(r2, Operand(r1), r3, r0);
125 }
126 }
127 }
128
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000129 Variable* arguments = scope()->arguments();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000130 if (arguments != NULL) {
131 // Function uses arguments object.
132 Comment cmnt(masm_, "[ Allocate arguments object");
133 if (!function_in_register) {
134 // Load this again, if it's used by the local context below.
135 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
136 } else {
137 __ mov(r3, r1);
138 }
139 // Receiver is just before the parameters on the caller's stack.
140 int offset = scope()->num_parameters() * kPointerSize;
141 __ add(r2, fp,
142 Operand(StandardFrameConstants::kCallerSPOffset + offset));
143 __ mov(r1, Operand(Smi::FromInt(scope()->num_parameters())));
144 __ Push(r3, r2, r1);
145
146 // Arguments to ArgumentsAccessStub:
147 // function, receiver address, parameter count.
148 // The stub will rewrite receiever and parameter count if the previous
149 // stack frame was an arguments adapter frame.
150 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
151 __ CallStub(&stub);
152 // Duplicate the value; move-to-slot operation might clobber registers.
153 __ mov(r3, r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000154 Move(arguments->AsSlot(), r0, r1, r2);
155 Slot* dot_arguments_slot = scope()->arguments_shadow()->AsSlot();
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000156 Move(dot_arguments_slot, r3, r1, r2);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000157 }
158
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000159 { Comment cmnt(masm_, "[ Declarations");
160 // For named function expressions, declare the function name as a
161 // constant.
162 if (scope()->is_function_scope() && scope()->function() != NULL) {
163 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
164 }
165 // Visit all the explicit declarations unless there is an illegal
166 // redeclaration.
167 if (scope()->HasIllegalRedeclaration()) {
168 scope()->VisitIllegalRedeclaration(this);
169 } else {
170 VisitDeclarations(scope()->declarations());
171 }
172 }
173
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000174 // Check the stack for overflow or break request.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 { Comment cmnt(masm_, "[ Stack check");
176 __ LoadRoot(r2, Heap::kStackLimitRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 __ cmp(sp, Operand(r2));
178 StackCheckStub stub;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000179 __ mov(ip,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000180 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
181 RelocInfo::CODE_TARGET),
182 LeaveCC,
183 lo);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +0000184 __ Call(ip, lo);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 }
186
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000187 if (FLAG_trace) {
188 __ CallRuntime(Runtime::kTraceEnter, 0);
189 }
190
191 { Comment cmnt(masm_, "[ Body");
192 ASSERT(loop_depth() == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000193 VisitStatements(function()->body());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000194 ASSERT(loop_depth() == 0);
195 }
196
197 { Comment cmnt(masm_, "[ return <undefined>;");
198 // Emit a 'return undefined' in case control fell off the end of the
199 // body.
200 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
201 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000202 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000203}
204
205
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000206void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000207 Comment cmnt(masm_, "[ Return sequence");
208 if (return_label_.is_bound()) {
209 __ b(&return_label_);
210 } else {
211 __ bind(&return_label_);
212 if (FLAG_trace) {
213 // Push the return value on the stack as the parameter.
214 // Runtime::TraceExit returns its parameter in r0.
215 __ push(r0);
216 __ CallRuntime(Runtime::kTraceExit, 1);
217 }
218
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000219#ifdef DEBUG
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000220 // Add a label for checking the size of the code used for returning.
221 Label check_exit_codesize;
222 masm_->bind(&check_exit_codesize);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000223#endif
224 // Make sure that the constant pool is not emitted inside of the return
225 // sequence.
226 { Assembler::BlockConstPoolScope block_const_pool(masm_);
227 // Here we use masm_-> instead of the __ macro to avoid the code coverage
228 // tool from instrumenting as we rely on the code size here.
229 int32_t sp_delta = (scope()->num_parameters() + 1) * kPointerSize;
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000230 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000231 __ RecordJSReturn();
232 masm_->mov(sp, fp);
233 masm_->ldm(ia_w, sp, fp.bit() | lr.bit());
234 masm_->add(sp, sp, Operand(sp_delta));
235 masm_->Jump(lr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000236 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000237
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000238#ifdef DEBUG
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000239 // Check that the size of the code used for returning matches what is
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000240 // expected by the debugger. If the sp_delts above cannot be encoded in the
241 // add instruction the add will generate two instructions.
242 int return_sequence_length =
243 masm_->InstructionsGeneratedSince(&check_exit_codesize);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000244 CHECK(return_sequence_length ==
245 Assembler::kJSReturnSequenceInstructions ||
246 return_sequence_length ==
247 Assembler::kJSReturnSequenceInstructions + 1);
fschneider@chromium.org013f3e12010-04-26 13:27:52 +0000248#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000249 }
250}
251
252
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000253FullCodeGenerator::ConstantOperand FullCodeGenerator::GetConstantOperand(
254 Token::Value op, Expression* left, Expression* right) {
255 ASSERT(ShouldInlineSmiCase(op));
256 return kNoConstants;
257}
258
259
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000260void FullCodeGenerator::EffectContext::Plug(Slot* slot) const {
261}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000262
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000263
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000264void FullCodeGenerator::AccumulatorValueContext::Plug(Slot* slot) const {
265 codegen()->Move(result_register(), slot);
266}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000267
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000268
269void FullCodeGenerator::StackValueContext::Plug(Slot* slot) const {
270 codegen()->Move(result_register(), slot);
271 __ push(result_register());
272}
273
274
275void FullCodeGenerator::TestContext::Plug(Slot* slot) const {
276 // For simplicity we always test the accumulator register.
277 codegen()->Move(result_register(), slot);
278 codegen()->DoTest(true_label_, false_label_, fall_through_);
279}
280
281
282void FullCodeGenerator::EffectContext::Plug(Heap::RootListIndex index) const {
283}
284
285
286void FullCodeGenerator::AccumulatorValueContext::Plug(
287 Heap::RootListIndex index) const {
288 __ LoadRoot(result_register(), index);
289}
290
291
292void FullCodeGenerator::StackValueContext::Plug(
293 Heap::RootListIndex index) const {
294 __ LoadRoot(result_register(), index);
295 __ push(result_register());
296}
297
298
299void FullCodeGenerator::TestContext::Plug(Heap::RootListIndex index) const {
300 if (index == Heap::kUndefinedValueRootIndex ||
301 index == Heap::kNullValueRootIndex ||
302 index == Heap::kFalseValueRootIndex) {
303 __ b(false_label_);
304 } else if (index == Heap::kTrueValueRootIndex) {
305 __ b(true_label_);
306 } else {
307 __ LoadRoot(result_register(), index);
308 codegen()->DoTest(true_label_, false_label_, fall_through_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000309 }
310}
311
312
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000313void FullCodeGenerator::EffectContext::Plug(Handle<Object> lit) const {
314}
315
316
317void FullCodeGenerator::AccumulatorValueContext::Plug(
318 Handle<Object> lit) const {
319 __ mov(result_register(), Operand(lit));
320}
321
322
323void FullCodeGenerator::StackValueContext::Plug(Handle<Object> lit) const {
324 // Immediates can be pushed directly.
325 __ mov(result_register(), Operand(lit));
326 __ push(result_register());
327}
328
329
330void FullCodeGenerator::TestContext::Plug(Handle<Object> lit) const {
331 ASSERT(!lit->IsUndetectableObject()); // There are no undetectable literals.
332 if (lit->IsUndefined() || lit->IsNull() || lit->IsFalse()) {
333 __ b(false_label_);
334 } else if (lit->IsTrue() || lit->IsJSObject()) {
335 __ b(true_label_);
336 } else if (lit->IsString()) {
337 if (String::cast(*lit)->length() == 0) {
338 __ b(false_label_);
339 } else {
340 __ b(true_label_);
341 }
342 } else if (lit->IsSmi()) {
343 if (Smi::cast(*lit)->value() == 0) {
344 __ b(false_label_);
345 } else {
346 __ b(true_label_);
347 }
348 } else {
349 // For simplicity we always test the accumulator register.
350 __ mov(result_register(), Operand(lit));
351 codegen()->DoTest(true_label_, false_label_, fall_through_);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000352 }
353}
354
355
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000356void FullCodeGenerator::EffectContext::DropAndPlug(int count,
357 Register reg) const {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000358 ASSERT(count > 0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000359 __ Drop(count);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000360}
361
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000362
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000363void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
364 int count,
365 Register reg) const {
366 ASSERT(count > 0);
367 __ Drop(count);
368 __ Move(result_register(), reg);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000369}
370
371
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000372void FullCodeGenerator::StackValueContext::DropAndPlug(int count,
373 Register reg) const {
374 ASSERT(count > 0);
375 if (count > 1) __ Drop(count - 1);
376 __ str(reg, MemOperand(sp, 0));
377}
378
379
380void FullCodeGenerator::TestContext::DropAndPlug(int count,
381 Register reg) const {
382 ASSERT(count > 0);
383 // For simplicity we always test the accumulator register.
384 __ Drop(count);
385 __ Move(result_register(), reg);
386 codegen()->DoTest(true_label_, false_label_, fall_through_);
387}
388
389
390void FullCodeGenerator::EffectContext::Plug(Label* materialize_true,
391 Label* materialize_false) const {
392 ASSERT_EQ(materialize_true, materialize_false);
393 __ bind(materialize_true);
394}
395
396
397void FullCodeGenerator::AccumulatorValueContext::Plug(
398 Label* materialize_true,
399 Label* materialize_false) const {
400 Label done;
401 __ bind(materialize_true);
402 __ LoadRoot(result_register(), Heap::kTrueValueRootIndex);
403 __ jmp(&done);
404 __ bind(materialize_false);
405 __ LoadRoot(result_register(), Heap::kFalseValueRootIndex);
406 __ bind(&done);
407}
408
409
410void FullCodeGenerator::StackValueContext::Plug(
411 Label* materialize_true,
412 Label* materialize_false) const {
413 Label done;
414 __ bind(materialize_true);
415 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
416 __ push(ip);
417 __ jmp(&done);
418 __ bind(materialize_false);
419 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
420 __ push(ip);
421 __ bind(&done);
422}
423
424
425void FullCodeGenerator::TestContext::Plug(Label* materialize_true,
426 Label* materialize_false) const {
427 ASSERT(materialize_false == false_label_);
428 ASSERT(materialize_true == true_label_);
429}
430
431
432void FullCodeGenerator::EffectContext::Plug(bool flag) const {
433}
434
435
436void FullCodeGenerator::AccumulatorValueContext::Plug(bool flag) const {
437 Heap::RootListIndex value_root_index =
438 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
439 __ LoadRoot(result_register(), value_root_index);
440}
441
442
443void FullCodeGenerator::StackValueContext::Plug(bool flag) const {
444 Heap::RootListIndex value_root_index =
445 flag ? Heap::kTrueValueRootIndex : Heap::kFalseValueRootIndex;
446 __ LoadRoot(ip, value_root_index);
447 __ push(ip);
448}
449
450
451void FullCodeGenerator::TestContext::Plug(bool flag) const {
452 if (flag) {
453 if (true_label_ != fall_through_) __ b(true_label_);
454 } else {
455 if (false_label_ != fall_through_) __ b(false_label_);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000456 }
457}
458
459
ricow@chromium.org65fae842010-08-25 15:26:24 +0000460void FullCodeGenerator::DoTest(Label* if_true,
461 Label* if_false,
462 Label* fall_through) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000463 // Call the runtime to find the boolean value of the source and then
464 // translate it into control flow to the pair of labels.
ricow@chromium.org65fae842010-08-25 15:26:24 +0000465 __ push(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000466 __ CallRuntime(Runtime::kToBool, 1);
467 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
468 __ cmp(r0, ip);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000469 Split(eq, if_true, if_false, fall_through);
470}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000471
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000472
ricow@chromium.org65fae842010-08-25 15:26:24 +0000473void FullCodeGenerator::Split(Condition cc,
474 Label* if_true,
475 Label* if_false,
476 Label* fall_through) {
477 if (if_false == fall_through) {
478 __ b(cc, if_true);
479 } else if (if_true == fall_through) {
480 __ b(NegateCondition(cc), if_false);
481 } else {
482 __ b(cc, if_true);
483 __ b(if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000484 }
485}
486
487
488MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
489 switch (slot->type()) {
490 case Slot::PARAMETER:
491 case Slot::LOCAL:
492 return MemOperand(fp, SlotOffset(slot));
493 case Slot::CONTEXT: {
494 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000495 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000496 __ LoadContext(scratch, context_chain_length);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000497 return ContextOperand(scratch, slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000498 }
499 case Slot::LOOKUP:
500 UNREACHABLE();
501 }
502 UNREACHABLE();
503 return MemOperand(r0, 0);
504}
505
506
507void FullCodeGenerator::Move(Register destination, Slot* source) {
508 // Use destination as scratch.
509 MemOperand slot_operand = EmitSlotSearch(source, destination);
510 __ ldr(destination, slot_operand);
511}
512
513
514void FullCodeGenerator::Move(Slot* dst,
515 Register src,
516 Register scratch1,
517 Register scratch2) {
518 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
519 ASSERT(!scratch1.is(src) && !scratch2.is(src));
520 MemOperand location = EmitSlotSearch(dst, scratch1);
521 __ str(src, location);
522 // Emit the write barrier code if the location is in the heap.
523 if (dst->type() == Slot::CONTEXT) {
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000524 __ RecordWrite(scratch1,
525 Operand(Context::SlotOffset(dst->index())),
526 scratch2,
527 src);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000528 }
529}
530
531
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000532void FullCodeGenerator::EmitDeclaration(Variable* variable,
533 Variable::Mode mode,
534 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000535 Comment cmnt(masm_, "[ Declaration");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000536 ASSERT(variable != NULL); // Must have been resolved.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000537 Slot* slot = variable->AsSlot();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000538 Property* prop = variable->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000539
540 if (slot != NULL) {
541 switch (slot->type()) {
542 case Slot::PARAMETER:
543 case Slot::LOCAL:
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000544 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000545 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
546 __ str(ip, MemOperand(fp, SlotOffset(slot)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000547 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000548 VisitForAccumulatorValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000549 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
550 }
551 break;
552
553 case Slot::CONTEXT:
554 // We bypass the general EmitSlotSearch because we know more about
555 // this specific context.
556
557 // The variable in the decl always resides in the current context.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000558 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000559 if (FLAG_debug_code) {
560 // Check if we have the correct context pointer.
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000561 __ ldr(r1, ContextOperand(cp, Context::FCONTEXT_INDEX));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000562 __ cmp(r1, cp);
563 __ Check(eq, "Unexpected declaration in current context.");
564 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000565 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000566 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000567 __ str(ip, ContextOperand(cp, slot->index()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000568 // No write barrier since the_hole_value is in old space.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000569 } else if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000570 VisitForAccumulatorValue(function);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000571 __ str(result_register(), ContextOperand(cp, slot->index()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000572 int offset = Context::SlotOffset(slot->index());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000573 // We know that we have written a function, which is not a smi.
574 __ mov(r1, Operand(cp));
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +0000575 __ RecordWrite(r1, Operand(offset), r2, result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000576 }
577 break;
578
579 case Slot::LOOKUP: {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000580 __ mov(r2, Operand(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000581 // Declaration nodes are always introduced in one of two modes.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000582 ASSERT(mode == Variable::VAR ||
583 mode == Variable::CONST);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000584 PropertyAttributes attr =
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000585 (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000586 __ mov(r1, Operand(Smi::FromInt(attr)));
587 // Push initial value, if any.
588 // Note: For variables we must not push an initial value (such as
589 // 'undefined') because we may have a (legal) redeclaration and we
590 // must not destroy the current value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000591 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000592 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000593 __ Push(cp, r2, r1, r0);
594 } else if (function != NULL) {
595 __ Push(cp, r2, r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000596 // Push initial value for function declaration.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000597 VisitForStackValue(function);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000598 } else {
599 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000600 __ Push(cp, r2, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000601 }
602 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
603 break;
604 }
605 }
606
607 } else if (prop != NULL) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000608 if (function != NULL || mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000609 // We are declaring a function or constant that rewrites to a
610 // property. Use (keyed) IC to set the initial value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000611 VisitForStackValue(prop->obj());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000612 if (function != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000613 VisitForStackValue(prop->key());
614 VisitForAccumulatorValue(function);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000615 __ pop(r1); // Key.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000616 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000617 VisitForAccumulatorValue(prop->key());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000618 __ mov(r1, result_register()); // Key.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000619 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
620 }
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000621 __ pop(r2); // Receiver.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000622
623 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000624 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000625 // Value in r0 is ignored (declarations are statements).
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000626 }
627 }
628}
629
630
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000631void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
632 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
633}
634
635
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000636void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
637 // Call the runtime to declare the globals.
638 // The context is the first argument.
639 __ mov(r1, Operand(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000640 __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000641 __ Push(cp, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000642 __ CallRuntime(Runtime::kDeclareGlobals, 3);
643 // Return value is ignored.
644}
645
646
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000647void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000648 Comment cmnt(masm_, "[ SwitchStatement");
649 Breakable nested_statement(this, stmt);
650 SetStatementPosition(stmt);
651 // Keep the switch value on the stack until a case matches.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000652 VisitForStackValue(stmt->tag());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000653
654 ZoneList<CaseClause*>* clauses = stmt->cases();
655 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
656
657 Label next_test; // Recycled for each test.
658 // Compile all the tests with branches to their bodies.
659 for (int i = 0; i < clauses->length(); i++) {
660 CaseClause* clause = clauses->at(i);
661 // The default is not a test, but remember it as final fall through.
662 if (clause->is_default()) {
663 default_clause = clause;
664 continue;
665 }
666
667 Comment cmnt(masm_, "[ Case comparison");
668 __ bind(&next_test);
669 next_test.Unuse();
670
671 // Compile the label expression.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000672 VisitForAccumulatorValue(clause->label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000673
ricow@chromium.org65fae842010-08-25 15:26:24 +0000674 // Perform the comparison as if via '==='.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000675 __ ldr(r1, MemOperand(sp, 0)); // Switch value.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000676 bool inline_smi_code = ShouldInlineSmiCase(Token::EQ_STRICT);
677 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000678 Label slow_case;
679 __ orr(r2, r1, r0);
680 __ tst(r2, Operand(kSmiTagMask));
681 __ b(ne, &slow_case);
682 __ cmp(r1, r0);
683 __ b(ne, &next_test);
684 __ Drop(1); // Switch value is no longer needed.
685 __ b(clause->body_target()->entry_label());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000686 __ bind(&slow_case);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000687 }
688
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000689 CompareFlags flags = inline_smi_code
690 ? NO_SMI_COMPARE_IN_STUB
691 : NO_COMPARE_FLAGS;
692 CompareStub stub(eq, true, flags, r1, r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000693 __ CallStub(&stub);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000694 __ cmp(r0, Operand(0, RelocInfo::NONE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000695 __ b(ne, &next_test);
696 __ Drop(1); // Switch value is no longer needed.
697 __ b(clause->body_target()->entry_label());
698 }
699
700 // Discard the test value and jump to the default if present, otherwise to
701 // the end of the statement.
702 __ bind(&next_test);
703 __ Drop(1); // Switch value is no longer needed.
704 if (default_clause == NULL) {
705 __ b(nested_statement.break_target());
706 } else {
707 __ b(default_clause->body_target()->entry_label());
708 }
709
710 // Compile all the case bodies.
711 for (int i = 0; i < clauses->length(); i++) {
712 Comment cmnt(masm_, "[ Case body");
713 CaseClause* clause = clauses->at(i);
714 __ bind(clause->body_target()->entry_label());
715 VisitStatements(clause->statements());
716 }
717
718 __ bind(nested_statement.break_target());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000719}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000720
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000721
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000722void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000723 Comment cmnt(masm_, "[ ForInStatement");
724 SetStatementPosition(stmt);
725
726 Label loop, exit;
727 ForIn loop_statement(this, stmt);
728 increment_loop_depth();
729
730 // Get the object to enumerate over. Both SpiderMonkey and JSC
731 // ignore null and undefined in contrast to the specification; see
732 // ECMA-262 section 12.6.4.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000733 VisitForAccumulatorValue(stmt->enumerable());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000734 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
735 __ cmp(r0, ip);
736 __ b(eq, &exit);
737 __ LoadRoot(ip, Heap::kNullValueRootIndex);
738 __ cmp(r0, ip);
739 __ b(eq, &exit);
740
741 // Convert the object to a JS object.
742 Label convert, done_convert;
743 __ BranchOnSmi(r0, &convert);
744 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
745 __ b(hs, &done_convert);
746 __ bind(&convert);
747 __ push(r0);
748 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
749 __ bind(&done_convert);
750 __ push(r0);
751
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000752 // BUG(867): Check cache validity in generated code. This is a fast
753 // case for the JSObject::IsSimpleEnum cache validity checks. If we
754 // cannot guarantee cache validity, call the runtime system to check
755 // cache validity or get the property names in a fixed array.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000756
757 // Get the set of properties to enumerate.
758 __ push(r0); // Duplicate the enumerable object on the stack.
759 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
760
761 // If we got a map from the runtime call, we can do a fast
762 // modification check. Otherwise, we got a fixed array, and we have
763 // to do a slow check.
764 Label fixed_array;
765 __ mov(r2, r0);
766 __ ldr(r1, FieldMemOperand(r2, HeapObject::kMapOffset));
767 __ LoadRoot(ip, Heap::kMetaMapRootIndex);
768 __ cmp(r1, ip);
769 __ b(ne, &fixed_array);
770
771 // We got a map in register r0. Get the enumeration cache from it.
772 __ ldr(r1, FieldMemOperand(r0, Map::kInstanceDescriptorsOffset));
773 __ ldr(r1, FieldMemOperand(r1, DescriptorArray::kEnumerationIndexOffset));
774 __ ldr(r2, FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
775
776 // Setup the four remaining stack slots.
777 __ push(r0); // Map.
778 __ ldr(r1, FieldMemOperand(r2, FixedArray::kLengthOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000779 __ mov(r0, Operand(Smi::FromInt(0)));
780 // Push enumeration cache, enumeration cache length (as smi) and zero.
781 __ Push(r2, r1, r0);
782 __ jmp(&loop);
783
784 // We got a fixed array in register r0. Iterate through that.
785 __ bind(&fixed_array);
786 __ mov(r1, Operand(Smi::FromInt(0))); // Map (0) - force slow check.
787 __ Push(r1, r0);
788 __ ldr(r1, FieldMemOperand(r0, FixedArray::kLengthOffset));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000789 __ mov(r0, Operand(Smi::FromInt(0)));
790 __ Push(r1, r0); // Fixed array length (as smi) and initial index.
791
792 // Generate code for doing the condition check.
793 __ bind(&loop);
794 // Load the current count to r0, load the length to r1.
795 __ Ldrd(r0, r1, MemOperand(sp, 0 * kPointerSize));
796 __ cmp(r0, r1); // Compare to the array length.
797 __ b(hs, loop_statement.break_target());
798
799 // Get the current entry of the array into register r3.
800 __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
801 __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
802 __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
803
804 // Get the expected map from the stack or a zero map in the
805 // permanent slow case into register r2.
806 __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
807
808 // Check if the expected map still matches that of the enumerable.
809 // If not, we have to filter the key.
810 Label update_each;
811 __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
812 __ ldr(r4, FieldMemOperand(r1, HeapObject::kMapOffset));
813 __ cmp(r4, Operand(r2));
814 __ b(eq, &update_each);
815
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000816 // Convert the entry to a string or (smi) 0 if it isn't a property
817 // any more. If the property has been removed while iterating, we
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000818 // just skip it.
819 __ push(r1); // Enumerable.
820 __ push(r3); // Current entry.
821 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000822 __ mov(r3, Operand(r0), SetCC);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +0000823 __ b(eq, loop_statement.continue_target());
824
825 // Update the 'each' property or variable from the possibly filtered
826 // entry in register r3.
827 __ bind(&update_each);
828 __ mov(result_register(), r3);
829 // Perform the assignment as if via '='.
830 EmitAssignment(stmt->each());
831
832 // Generate code for the body of the loop.
833 Label stack_limit_hit, stack_check_done;
834 Visit(stmt->body());
835
836 __ StackLimitCheck(&stack_limit_hit);
837 __ bind(&stack_check_done);
838
839 // Generate code for the going to the next element by incrementing
840 // the index (smi) stored on top of the stack.
841 __ bind(loop_statement.continue_target());
842 __ pop(r0);
843 __ add(r0, r0, Operand(Smi::FromInt(1)));
844 __ push(r0);
845 __ b(&loop);
846
847 // Slow case for the stack limit check.
848 StackCheckStub stack_check_stub;
849 __ bind(&stack_limit_hit);
850 __ CallStub(&stack_check_stub);
851 __ b(&stack_check_done);
852
853 // Remove the pointers stored on the stack.
854 __ bind(loop_statement.break_target());
855 __ Drop(5);
856
857 // Exit and decrement the loop depth.
858 __ bind(&exit);
859 decrement_loop_depth();
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000860}
861
862
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000863void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
864 bool pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000865 // Use the fast case closure allocation code that allocates in new
866 // space for nested functions that don't need literals cloning.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000867 if (scope()->is_function_scope() &&
868 info->num_literals() == 0 &&
869 !pretenure) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000870 FastNewClosureStub stub;
871 __ mov(r0, Operand(info));
872 __ push(r0);
873 __ CallStub(&stub);
874 } else {
875 __ mov(r0, Operand(info));
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000876 __ LoadRoot(r1, pretenure ? Heap::kTrueValueRootIndex
877 : Heap::kFalseValueRootIndex);
878 __ Push(cp, r0, r1);
879 __ CallRuntime(Runtime::kNewClosure, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000880 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000881 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000882}
883
884
885void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
886 Comment cmnt(masm_, "[ VariableProxy");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000887 EmitVariableLoad(expr->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000888}
889
890
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000891MemOperand FullCodeGenerator::ContextSlotOperandCheckExtensions(
892 Slot* slot,
893 Label* slow) {
894 ASSERT(slot->type() == Slot::CONTEXT);
895 Register current = cp;
896 Register next = r3;
897 Register temp = r4;
898
899 for (Scope* s = scope(); s != slot->var()->scope(); s = s->outer_scope()) {
900 if (s->num_heap_slots() > 0) {
901 if (s->calls_eval()) {
902 // Check that extension is NULL.
903 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
904 __ tst(temp, temp);
905 __ b(ne, slow);
906 }
907 __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX));
908 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
909 // Walk the rest of the chain without clobbering cp.
910 current = next;
911 }
912 }
913 // Check that last extension is NULL.
914 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
915 __ tst(temp, temp);
916 __ b(ne, slow);
917 __ ldr(temp, ContextOperand(current, Context::FCONTEXT_INDEX));
918 return ContextOperand(temp, slot->index());
919}
920
921
922void FullCodeGenerator::EmitDynamicLoadFromSlotFastCase(
923 Slot* slot,
924 TypeofState typeof_state,
925 Label* slow,
926 Label* done) {
927 // Generate fast-case code for variables that might be shadowed by
928 // eval-introduced variables. Eval is used a lot without
929 // introducing variables. In those cases, we do not want to
930 // perform a runtime call for all variables in the scope
931 // containing the eval.
932 if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
933 EmitLoadGlobalSlotCheckExtensions(slot, typeof_state, slow);
934 __ jmp(done);
935 } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000936 Slot* potential_slot = slot->var()->local_if_not_shadowed()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000937 Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
938 if (potential_slot != NULL) {
939 // Generate fast case for locals that rewrite to slots.
940 __ ldr(r0, ContextSlotOperandCheckExtensions(potential_slot, slow));
941 if (potential_slot->var()->mode() == Variable::CONST) {
942 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
943 __ cmp(r0, ip);
944 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
945 }
946 __ jmp(done);
947 } else if (rewrite != NULL) {
948 // Generate fast case for calls of an argument function.
949 Property* property = rewrite->AsProperty();
950 if (property != NULL) {
951 VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
952 Literal* key_literal = property->key()->AsLiteral();
953 if (obj_proxy != NULL &&
954 key_literal != NULL &&
955 obj_proxy->IsArguments() &&
956 key_literal->handle()->IsSmi()) {
957 // Load arguments object if there are no eval-introduced
958 // variables. Then load the argument from the arguments
959 // object using keyed load.
960 __ ldr(r1,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000961 ContextSlotOperandCheckExtensions(obj_proxy->var()->AsSlot(),
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000962 slow));
963 __ mov(r0, Operand(key_literal->handle()));
964 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +0000965 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000966 __ jmp(done);
967 }
968 }
969 }
970 }
971}
972
973
974void FullCodeGenerator::EmitLoadGlobalSlotCheckExtensions(
975 Slot* slot,
976 TypeofState typeof_state,
977 Label* slow) {
978 Register current = cp;
979 Register next = r1;
980 Register temp = r2;
981
982 Scope* s = scope();
983 while (s != NULL) {
984 if (s->num_heap_slots() > 0) {
985 if (s->calls_eval()) {
986 // Check that extension is NULL.
987 __ ldr(temp, ContextOperand(current, Context::EXTENSION_INDEX));
988 __ tst(temp, temp);
989 __ b(ne, slow);
990 }
991 // Load next context in chain.
992 __ ldr(next, ContextOperand(current, Context::CLOSURE_INDEX));
993 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
994 // Walk the rest of the chain without clobbering cp.
995 current = next;
996 }
997 // If no outer scope calls eval, we do not need to check more
998 // context extensions.
999 if (!s->outer_scope_calls_eval() || s->is_eval_scope()) break;
1000 s = s->outer_scope();
1001 }
1002
1003 if (s->is_eval_scope()) {
1004 Label loop, fast;
1005 if (!current.is(next)) {
1006 __ Move(next, current);
1007 }
1008 __ bind(&loop);
1009 // Terminate at global context.
1010 __ ldr(temp, FieldMemOperand(next, HeapObject::kMapOffset));
1011 __ LoadRoot(ip, Heap::kGlobalContextMapRootIndex);
1012 __ cmp(temp, ip);
1013 __ b(eq, &fast);
1014 // Check that extension is NULL.
1015 __ ldr(temp, ContextOperand(next, Context::EXTENSION_INDEX));
1016 __ tst(temp, temp);
1017 __ b(ne, slow);
1018 // Load next context in chain.
1019 __ ldr(next, ContextOperand(next, Context::CLOSURE_INDEX));
1020 __ ldr(next, FieldMemOperand(next, JSFunction::kContextOffset));
1021 __ b(&loop);
1022 __ bind(&fast);
1023 }
1024
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001025 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001026 __ mov(r2, Operand(slot->var()->name()));
1027 RelocInfo::Mode mode = (typeof_state == INSIDE_TYPEOF)
1028 ? RelocInfo::CODE_TARGET
1029 : RelocInfo::CODE_TARGET_CONTEXT;
1030 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001031 EmitCallIC(ic, mode);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001032}
1033
1034
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001035void FullCodeGenerator::EmitVariableLoad(Variable* var) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001036 // Four cases: non-this global variables, lookup slots, all other
1037 // types of slots, and parameters that rewrite to explicit property
1038 // accesses on the arguments object.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001039 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001040 Property* property = var->AsProperty();
1041
1042 if (var->is_global() && !var->is_this()) {
1043 Comment cmnt(masm_, "Global variable");
1044 // Use inline caching. Variable name is passed in r2 and the global
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001045 // object (receiver) in r0.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001046 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001047 __ mov(r2, Operand(var->name()));
1048 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001049 EmitCallIC(ic, RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001050 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001051
1052 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001053 Label done, slow;
1054
1055 // Generate code for loading from variables potentially shadowed
1056 // by eval-introduced variables.
1057 EmitDynamicLoadFromSlotFastCase(slot, NOT_INSIDE_TYPEOF, &slow, &done);
1058
1059 __ bind(&slow);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001060 Comment cmnt(masm_, "Lookup slot");
1061 __ mov(r1, Operand(var->name()));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001062 __ Push(cp, r1); // Context and name.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001063 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001064 __ bind(&done);
1065
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001066 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001067
1068 } else if (slot != NULL) {
1069 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1070 ? "Context slot"
1071 : "Stack slot");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001072 if (var->mode() == Variable::CONST) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001073 // Constants may be the hole value if they have not been initialized.
1074 // Unhole them.
1075 MemOperand slot_operand = EmitSlotSearch(slot, r0);
1076 __ ldr(r0, slot_operand);
1077 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1078 __ cmp(r0, ip);
1079 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
1080 context()->Plug(r0);
1081 } else {
1082 context()->Plug(slot);
1083 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001084 } else {
1085 Comment cmnt(masm_, "Rewritten parameter");
1086 ASSERT_NOT_NULL(property);
1087 // Rewritten parameter accesses are of the form "slot[literal]".
1088
1089 // Assert that the object is in a slot.
1090 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1091 ASSERT_NOT_NULL(object_var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 Slot* object_slot = object_var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001093 ASSERT_NOT_NULL(object_slot);
1094
1095 // Load the object.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001096 Move(r1, object_slot);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001097
1098 // Assert that the key is a smi.
1099 Literal* key_literal = property->key()->AsLiteral();
1100 ASSERT_NOT_NULL(key_literal);
1101 ASSERT(key_literal->handle()->IsSmi());
1102
1103 // Load the key.
ager@chromium.orgac091b72010-05-05 07:34:42 +00001104 __ mov(r0, Operand(key_literal->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001105
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001106 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001107 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001108 EmitCallIC(ic, RelocInfo::CODE_TARGET);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001109 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001110 }
1111}
1112
1113
1114void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1115 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001116 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001117 // Registers will be used as follows:
1118 // r4 = JS function, literals array
1119 // r3 = literal index
1120 // r2 = RegExp pattern
1121 // r1 = RegExp flags
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001122 // r0 = temp + materialized value (RegExp literal)
ricow@chromium.org65fae842010-08-25 15:26:24 +00001123 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1124 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001125 int literal_offset =
ricow@chromium.org65fae842010-08-25 15:26:24 +00001126 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001127 __ ldr(r0, FieldMemOperand(r4, literal_offset));
1128 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
1129 __ cmp(r0, ip);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001130 __ b(ne, &materialized);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001131
1132 // Create regexp literal using runtime function.
1133 // Result will be in r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001134 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
1135 __ mov(r2, Operand(expr->pattern()));
1136 __ mov(r1, Operand(expr->flags()));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001137 __ Push(r4, r3, r2, r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001138 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001139
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001140 __ bind(&materialized);
1141 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1142 __ push(r0);
1143 __ mov(r0, Operand(Smi::FromInt(size)));
1144 __ push(r0);
1145 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001146
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001147 // After this, registers are used as follows:
1148 // r0: Newly allocated regexp.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001149 // r1: Materialized regexp.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001150 // r2: temp.
1151 __ pop(r1);
1152 __ CopyFields(r0, r1, r2.bit(), size / kPointerSize);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001153 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001154}
1155
1156
1157void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1158 Comment cmnt(masm_, "[ ObjectLiteral");
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001159 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1160 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1161 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1162 __ mov(r1, Operand(expr->constant_properties()));
1163 __ mov(r0, Operand(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001164 __ Push(r3, r2, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001165 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001166 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001167 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001168 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001169 }
1170
1171 // If result_saved is true the result is on top of the stack. If
1172 // result_saved is false the result is in r0.
1173 bool result_saved = false;
1174
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001175 // Mark all computed expressions that are bound to a key that
1176 // is shadowed by a later occurrence of the same key. For the
1177 // marked expressions, no store code is emitted.
1178 expr->CalculateEmitStore();
1179
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001180 for (int i = 0; i < expr->properties()->length(); i++) {
1181 ObjectLiteral::Property* property = expr->properties()->at(i);
1182 if (property->IsCompileTimeValue()) continue;
1183
1184 Literal* key = property->key();
1185 Expression* value = property->value();
1186 if (!result_saved) {
1187 __ push(r0); // Save result on stack
1188 result_saved = true;
1189 }
1190 switch (property->kind()) {
1191 case ObjectLiteral::Property::CONSTANT:
1192 UNREACHABLE();
1193 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1194 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
1195 // Fall through.
1196 case ObjectLiteral::Property::COMPUTED:
1197 if (key->handle()->IsSymbol()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001198 VisitForAccumulatorValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001199 __ mov(r2, Operand(key->handle()));
ager@chromium.org5c838252010-02-19 08:53:10 +00001200 __ ldr(r1, MemOperand(sp));
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001201 if (property->emit_store()) {
1202 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1203 EmitCallIC(ic, RelocInfo::CODE_TARGET);
1204 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001205 break;
1206 }
1207 // Fall through.
1208 case ObjectLiteral::Property::PROTOTYPE:
1209 // Duplicate receiver on stack.
1210 __ ldr(r0, MemOperand(sp));
1211 __ push(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001212 VisitForStackValue(key);
1213 VisitForStackValue(value);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00001214 if (property->emit_store()) {
1215 __ CallRuntime(Runtime::kSetProperty, 3);
1216 } else {
1217 __ Drop(3);
1218 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001219 break;
1220 case ObjectLiteral::Property::GETTER:
1221 case ObjectLiteral::Property::SETTER:
1222 // Duplicate receiver on stack.
1223 __ ldr(r0, MemOperand(sp));
1224 __ push(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001225 VisitForStackValue(key);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001226 __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
1227 Smi::FromInt(1) :
1228 Smi::FromInt(0)));
1229 __ push(r1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001230 VisitForStackValue(value);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001231 __ CallRuntime(Runtime::kDefineAccessor, 4);
1232 break;
1233 }
1234 }
1235
1236 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001237 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001238 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001239 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001240 }
1241}
1242
1243
1244void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1245 Comment cmnt(masm_, "[ ArrayLiteral");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001246
1247 ZoneList<Expression*>* subexprs = expr->values();
1248 int length = subexprs->length();
1249
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001250 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1251 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
1252 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
1253 __ mov(r1, Operand(expr->constant_elements()));
lrn@chromium.orgc34f5802010-04-28 12:53:43 +00001254 __ Push(r3, r2, r1);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001255 if (expr->constant_elements()->map() == Heap::fixed_cow_array_map()) {
1256 FastCloneShallowArrayStub stub(
1257 FastCloneShallowArrayStub::COPY_ON_WRITE_ELEMENTS, length);
1258 __ CallStub(&stub);
1259 __ IncrementCounter(&Counters::cow_arrays_created_stub, 1, r1, r2);
1260 } else if (expr->depth() > 1) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001261 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001262 } else if (length > FastCloneShallowArrayStub::kMaximumClonedLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001263 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001264 } else {
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00001265 FastCloneShallowArrayStub stub(
1266 FastCloneShallowArrayStub::CLONE_ELEMENTS, length);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001267 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001268 }
1269
1270 bool result_saved = false; // Is the result saved to the stack?
1271
1272 // Emit code to evaluate all the non-constant subexpressions and to store
1273 // them into the newly cloned array.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001274 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001275 Expression* subexpr = subexprs->at(i);
1276 // If the subexpression is a literal or a simple materialized literal it
1277 // is already set in the cloned array.
1278 if (subexpr->AsLiteral() != NULL ||
1279 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1280 continue;
1281 }
1282
1283 if (!result_saved) {
1284 __ push(r0);
1285 result_saved = true;
1286 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001287 VisitForAccumulatorValue(subexpr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001288
1289 // Store the subexpression value in the array's elements.
1290 __ ldr(r1, MemOperand(sp)); // Copy of array literal.
1291 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
1292 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1293 __ str(result_register(), FieldMemOperand(r1, offset));
1294
1295 // Update the write barrier for the array store with r0 as the scratch
1296 // register.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001297 __ RecordWrite(r1, Operand(offset), r2, result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001298 }
1299
1300 if (result_saved) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001301 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001302 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001303 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001304 }
1305}
1306
1307
ager@chromium.org5c838252010-02-19 08:53:10 +00001308void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1309 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001310 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1311 // on the left-hand side.
1312 if (!expr->target()->IsValidLeftHandSide()) {
1313 VisitForEffect(expr->target());
1314 return;
1315 }
1316
ager@chromium.org5c838252010-02-19 08:53:10 +00001317 // Left-hand side can only be a property, a global or a (parameter or local)
1318 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1319 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1320 LhsKind assign_type = VARIABLE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001321 Property* property = expr->target()->AsProperty();
1322 if (property != NULL) {
1323 assign_type = (property->key()->IsPropertyName())
1324 ? NAMED_PROPERTY
1325 : KEYED_PROPERTY;
ager@chromium.org5c838252010-02-19 08:53:10 +00001326 }
1327
1328 // Evaluate LHS expression.
1329 switch (assign_type) {
1330 case VARIABLE:
1331 // Nothing to do here.
1332 break;
1333 case NAMED_PROPERTY:
1334 if (expr->is_compound()) {
1335 // We need the receiver both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001336 VisitForAccumulatorValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001337 __ push(result_register());
1338 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001339 VisitForStackValue(property->obj());
ager@chromium.org5c838252010-02-19 08:53:10 +00001340 }
1341 break;
1342 case KEYED_PROPERTY:
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001343 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001344 VisitForStackValue(property->obj());
1345 VisitForAccumulatorValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001346 __ ldr(r1, MemOperand(sp, 0));
1347 __ push(r0);
1348 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001349 VisitForStackValue(property->obj());
1350 VisitForStackValue(property->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001351 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001352 break;
1353 }
1354
ager@chromium.org5c838252010-02-19 08:53:10 +00001355 if (expr->is_compound()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001356 { AccumulatorValueContext context(this);
1357 switch (assign_type) {
1358 case VARIABLE:
1359 EmitVariableLoad(expr->target()->AsVariableProxy()->var());
1360 break;
1361 case NAMED_PROPERTY:
1362 EmitNamedPropertyLoad(property);
1363 break;
1364 case KEYED_PROPERTY:
1365 EmitKeyedPropertyLoad(property);
1366 break;
1367 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001368 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001369
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001370 Token::Value op = expr->binary_op();
1371 ConstantOperand constant = ShouldInlineSmiCase(op)
1372 ? GetConstantOperand(op, expr->target(), expr->value())
1373 : kNoConstants;
1374 ASSERT(constant == kRightConstant || constant == kNoConstants);
1375 if (constant == kNoConstants) {
1376 __ push(r0); // Left operand goes on the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001377 VisitForAccumulatorValue(expr->value());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001378 }
ager@chromium.org5c838252010-02-19 08:53:10 +00001379
ricow@chromium.org65fae842010-08-25 15:26:24 +00001380 OverwriteMode mode = expr->value()->ResultOverwriteAllowed()
1381 ? OVERWRITE_RIGHT
1382 : NO_OVERWRITE;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001383 SetSourcePosition(expr->position() + 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001384 AccumulatorValueContext context(this);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001385 if (ShouldInlineSmiCase(op)) {
1386 EmitInlineSmiBinaryOp(expr,
1387 op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001388 mode,
1389 expr->target(),
1390 expr->value(),
1391 constant);
1392 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001393 EmitBinaryOp(op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001394 }
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001395 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001396 VisitForAccumulatorValue(expr->value());
ager@chromium.org5c838252010-02-19 08:53:10 +00001397 }
1398
1399 // Record source position before possible IC call.
1400 SetSourcePosition(expr->position());
1401
1402 // Store the value.
1403 switch (assign_type) {
1404 case VARIABLE:
1405 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001406 expr->op());
ager@chromium.org5c838252010-02-19 08:53:10 +00001407 break;
1408 case NAMED_PROPERTY:
1409 EmitNamedPropertyAssignment(expr);
1410 break;
1411 case KEYED_PROPERTY:
1412 EmitKeyedPropertyAssignment(expr);
1413 break;
1414 }
1415}
1416
1417
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001418void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1419 SetSourcePosition(prop->position());
1420 Literal* key = prop->key()->AsLiteral();
1421 __ mov(r2, Operand(key->handle()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001422 // Call load IC. It has arguments receiver and property name r0 and r2.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001423 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001424 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001425}
1426
1427
1428void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1429 SetSourcePosition(prop->position());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001430 // Call keyed load IC. It has arguments key and receiver in r0 and r1.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001431 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001432 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001433}
1434
1435
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001436void FullCodeGenerator::EmitInlineSmiBinaryOp(Expression* expr,
1437 Token::Value op,
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001438 OverwriteMode mode,
1439 Expression* left,
1440 Expression* right,
1441 ConstantOperand constant) {
1442 ASSERT(constant == kNoConstants); // Only handled case.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001443 EmitBinaryOp(op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00001444}
1445
1446
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001447void FullCodeGenerator::EmitBinaryOp(Token::Value op,
ricow@chromium.org65fae842010-08-25 15:26:24 +00001448 OverwriteMode mode) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001449 __ pop(r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00001450 GenericBinaryOpStub stub(op, mode, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001451 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001452 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001453}
1454
1455
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001456void FullCodeGenerator::EmitAssignment(Expression* expr) {
1457 // Invalid left-hand sides are rewritten to have a 'throw
1458 // ReferenceError' on the left-hand side.
1459 if (!expr->IsValidLeftHandSide()) {
1460 VisitForEffect(expr);
1461 return;
1462 }
1463
1464 // Left-hand side can only be a property, a global or a (parameter or local)
1465 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1466 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1467 LhsKind assign_type = VARIABLE;
1468 Property* prop = expr->AsProperty();
1469 if (prop != NULL) {
1470 assign_type = (prop->key()->IsPropertyName())
1471 ? NAMED_PROPERTY
1472 : KEYED_PROPERTY;
1473 }
1474
1475 switch (assign_type) {
1476 case VARIABLE: {
1477 Variable* var = expr->AsVariableProxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001478 EffectContext context(this);
1479 EmitVariableAssignment(var, Token::ASSIGN);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001480 break;
1481 }
1482 case NAMED_PROPERTY: {
1483 __ push(r0); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001484 VisitForAccumulatorValue(prop->obj());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001485 __ mov(r1, r0);
1486 __ pop(r0); // Restore value.
1487 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1488 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001489 EmitCallIC(ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001490 break;
1491 }
1492 case KEYED_PROPERTY: {
1493 __ push(r0); // Preserve value.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001494 VisitForStackValue(prop->obj());
1495 VisitForAccumulatorValue(prop->key());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001496 __ mov(r1, r0);
1497 __ pop(r2);
1498 __ pop(r0); // Restore value.
1499 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001500 EmitCallIC(ic, RelocInfo::CODE_TARGET);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001501 break;
1502 }
1503 }
1504}
1505
1506
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001507void FullCodeGenerator::EmitVariableAssignment(Variable* var,
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001508 Token::Value op) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001509 // Left-hand sides that rewrite to explicit property accesses do not reach
1510 // here.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001511 ASSERT(var != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001512 ASSERT(var->is_global() || var->AsSlot() != NULL);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001513
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001514 if (var->is_global()) {
1515 ASSERT(!var->is_this());
1516 // Assignment to a global variable. Use inline caching for the
1517 // assignment. Right-hand-side value is passed in r0, variable name in
ager@chromium.org5c838252010-02-19 08:53:10 +00001518 // r2, and the global object in r1.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001519 __ mov(r2, Operand(var->name()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001520 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001521 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001522 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001523
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001524 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1525 // Perform the assignment for non-const variables and for initialization
1526 // of const variables. Const assignments are simply skipped.
1527 Label done;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001528 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001529 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001530 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001531 case Slot::LOCAL:
1532 if (op == Token::INIT_CONST) {
1533 // Detect const reinitialization by checking for the hole value.
1534 __ ldr(r1, MemOperand(fp, SlotOffset(slot)));
1535 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
1536 __ cmp(r1, ip);
1537 __ b(ne, &done);
1538 }
1539 // Perform the assignment.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001540 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
1541 break;
1542
1543 case Slot::CONTEXT: {
1544 MemOperand target = EmitSlotSearch(slot, r1);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001545 if (op == Token::INIT_CONST) {
1546 // Detect const reinitialization by checking for the hole value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001547 __ ldr(r2, target);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001548 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001549 __ cmp(r2, ip);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001550 __ b(ne, &done);
1551 }
1552 // Perform the assignment and issue the write barrier.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001553 __ str(result_register(), target);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001554 // RecordWrite may destroy all its register arguments.
1555 __ mov(r3, result_register());
1556 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00001557 __ RecordWrite(r1, Operand(offset), r2, r3);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001558 break;
1559 }
1560
1561 case Slot::LOOKUP:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001562 // Call the runtime for the assignment. The runtime will ignore
1563 // const reinitialization.
1564 __ push(r0); // Value.
1565 __ mov(r0, Operand(slot->var()->name()));
1566 __ Push(cp, r0); // Context and name.
1567 if (op == Token::INIT_CONST) {
1568 // The runtime will ignore const redeclaration.
1569 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1570 } else {
1571 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1572 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001573 break;
1574 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001575 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001576 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001577
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001578 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001579}
1580
1581
1582void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1583 // Assignment to a property, using a named store IC.
1584 Property* prop = expr->target()->AsProperty();
1585 ASSERT(prop != NULL);
1586 ASSERT(prop->key()->AsLiteral() != NULL);
1587
1588 // If the assignment starts a block of assignments to the same object,
1589 // change to slow case to avoid the quadratic behavior of repeatedly
1590 // adding fast properties.
1591 if (expr->starts_initialization_block()) {
1592 __ push(result_register());
1593 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value.
1594 __ push(ip);
1595 __ CallRuntime(Runtime::kToSlowProperties, 1);
1596 __ pop(result_register());
1597 }
1598
1599 // Record source code position before IC call.
1600 SetSourcePosition(expr->position());
1601 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001602 // Load receiver to r1. Leave a copy in the stack if needed for turning the
1603 // receiver into fast case.
ager@chromium.org5c838252010-02-19 08:53:10 +00001604 if (expr->ends_initialization_block()) {
1605 __ ldr(r1, MemOperand(sp));
1606 } else {
1607 __ pop(r1);
1608 }
1609
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001610 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001611 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001612
1613 // If the assignment ends an initialization block, revert to fast case.
1614 if (expr->ends_initialization_block()) {
1615 __ push(r0); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001616 // Receiver is under the result value.
1617 __ ldr(ip, MemOperand(sp, kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001618 __ push(ip);
1619 __ CallRuntime(Runtime::kToFastProperties, 1);
1620 __ pop(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001621 context()->DropAndPlug(1, r0);
ager@chromium.org5c838252010-02-19 08:53:10 +00001622 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001623 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001624 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001625}
1626
1627
1628void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1629 // Assignment to a property, using a keyed store IC.
1630
1631 // If the assignment starts a block of assignments to the same object,
1632 // change to slow case to avoid the quadratic behavior of repeatedly
1633 // adding fast properties.
1634 if (expr->starts_initialization_block()) {
1635 __ push(result_register());
1636 // Receiver is now under the key and value.
1637 __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
1638 __ push(ip);
1639 __ CallRuntime(Runtime::kToSlowProperties, 1);
1640 __ pop(result_register());
1641 }
1642
1643 // Record source code position before IC call.
1644 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001645 __ pop(r1); // Key.
1646 // Load receiver to r2. Leave a copy in the stack if needed for turning the
1647 // receiver into fast case.
1648 if (expr->ends_initialization_block()) {
1649 __ ldr(r2, MemOperand(sp));
1650 } else {
1651 __ pop(r2);
1652 }
1653
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001654 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001655 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001656
1657 // If the assignment ends an initialization block, revert to fast case.
1658 if (expr->ends_initialization_block()) {
1659 __ push(r0); // Result of assignment, saved even if not needed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001660 // Receiver is under the result value.
1661 __ ldr(ip, MemOperand(sp, kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001662 __ push(ip);
1663 __ CallRuntime(Runtime::kToFastProperties, 1);
1664 __ pop(r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001665 context()->DropAndPlug(1, r0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001666 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001667 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001668 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001669}
1670
1671
1672void FullCodeGenerator::VisitProperty(Property* expr) {
1673 Comment cmnt(masm_, "[ Property");
1674 Expression* key = expr->key();
1675
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001676 if (key->IsPropertyName()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001677 VisitForAccumulatorValue(expr->obj());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001678 EmitNamedPropertyLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001679 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001680 VisitForStackValue(expr->obj());
1681 VisitForAccumulatorValue(expr->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001682 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001683 EmitKeyedPropertyLoad(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001684 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001685 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001686}
1687
1688void FullCodeGenerator::EmitCallWithIC(Call* expr,
ager@chromium.org5c838252010-02-19 08:53:10 +00001689 Handle<Object> name,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001690 RelocInfo::Mode mode) {
1691 // Code common for calls using the IC.
1692 ZoneList<Expression*>* args = expr->arguments();
1693 int arg_count = args->length();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001694 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1695 for (int i = 0; i < arg_count; i++) {
1696 VisitForStackValue(args->at(i));
1697 }
1698 __ mov(r2, Operand(name));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001699 }
1700 // Record source position for debugger.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001701 SetSourcePosition(expr->position(), FORCED_POSITION);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001702 // Call the IC initialization code.
ager@chromium.org5c838252010-02-19 08:53:10 +00001703 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001704 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, in_loop);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001705 EmitCallIC(ic, mode);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001706 // Restore context register.
1707 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001708 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001709}
1710
1711
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001712void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
1713 Expression* key,
1714 RelocInfo::Mode mode) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001715 // Load the key.
1716 VisitForAccumulatorValue(key);
1717
1718 // Swap the name of the function and the receiver on the stack to follow
1719 // the calling convention for call ICs.
1720 __ pop(r1);
1721 __ push(r0);
1722 __ push(r1);
1723
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001724 // Code common for calls using the IC.
1725 ZoneList<Expression*>* args = expr->arguments();
1726 int arg_count = args->length();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001727 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1728 for (int i = 0; i < arg_count; i++) {
1729 VisitForStackValue(args->at(i));
1730 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001731 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001732 // Record source position for debugger.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001733 SetSourcePosition(expr->position(), FORCED_POSITION);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001734 // Call the IC initialization code.
1735 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001736 Handle<Code> ic = StubCache::ComputeKeyedCallInitialize(arg_count, in_loop);
1737 __ ldr(r2, MemOperand(sp, (arg_count + 1) * kPointerSize)); // Key.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001738 EmitCallIC(ic, mode);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001739 // Restore context register.
1740 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001741 context()->DropAndPlug(1, r0); // Drop the key still on the stack.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001742}
1743
1744
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001745void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1746 // Code common for calls using the call stub.
1747 ZoneList<Expression*>* args = expr->arguments();
1748 int arg_count = args->length();
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001749 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1750 for (int i = 0; i < arg_count; i++) {
1751 VisitForStackValue(args->at(i));
1752 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001753 }
1754 // Record source position for debugger.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001755 SetSourcePosition(expr->position(), FORCED_POSITION);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001756 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1757 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001758 __ CallStub(&stub);
1759 // Restore context register.
1760 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001761 context()->DropAndPlug(1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001762}
1763
1764
1765void FullCodeGenerator::VisitCall(Call* expr) {
1766 Comment cmnt(masm_, "[ Call");
1767 Expression* fun = expr->expression();
1768 Variable* var = fun->AsVariableProxy()->AsVariable();
1769
1770 if (var != NULL && var->is_possibly_eval()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001771 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1772 // resolve the function we need to call and the receiver of the
1773 // call. Then we call the resolved function using the given
1774 // arguments.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001775 ZoneList<Expression*>* args = expr->arguments();
1776 int arg_count = args->length();
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001777
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001778 { PreserveStatementPositionScope pos_scope(masm()->positions_recorder());
1779 VisitForStackValue(fun);
1780 __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
1781 __ push(r2); // Reserved receiver slot.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001782
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001783 // Push the arguments.
1784 for (int i = 0; i < arg_count; i++) {
1785 VisitForStackValue(args->at(i));
1786 }
1787
1788 // Push copy of the function - found below the arguments.
1789 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001790 __ push(r1);
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001791
1792 // Push copy of the first argument or undefined if it doesn't exist.
1793 if (arg_count > 0) {
1794 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
1795 __ push(r1);
1796 } else {
1797 __ push(r2);
1798 }
1799
1800 // Push the receiver of the enclosing function and do runtime call.
1801 __ ldr(r1,
1802 MemOperand(fp, (2 + scope()->num_parameters()) * kPointerSize));
1803 __ push(r1);
1804 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1805
1806 // The runtime call returns a pair of values in r0 (function) and
1807 // r1 (receiver). Touch up the stack with the right values.
1808 __ str(r0, MemOperand(sp, (arg_count + 1) * kPointerSize));
1809 __ str(r1, MemOperand(sp, arg_count * kPointerSize));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001810 }
1811
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001812 // Record source position for debugger.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001813 SetSourcePosition(expr->position(), FORCED_POSITION);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001814 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1815 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1816 __ CallStub(&stub);
1817 // Restore context register.
1818 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001819 context()->DropAndPlug(1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001820 } else if (var != NULL && !var->is_this() && var->is_global()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001821 // Push global object as receiver for the call IC.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001822 __ ldr(r0, GlobalObjectOperand());
ager@chromium.org5c838252010-02-19 08:53:10 +00001823 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001824 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001825 } else if (var != NULL && var->AsSlot() != NULL &&
1826 var->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001827 // Call to a lookup slot (dynamically introduced variable).
1828 Label slow, done;
1829
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001830 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1831 // Generate code for loading from variables potentially shadowed
1832 // by eval-introduced variables.
1833 EmitDynamicLoadFromSlotFastCase(var->AsSlot(),
1834 NOT_INSIDE_TYPEOF,
1835 &slow,
1836 &done);
1837 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001838
1839 __ bind(&slow);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001840 // Call the runtime to find the function to call (returned in r0)
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001841 // and the object holding it (returned in edx).
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001842 __ push(context_register());
1843 __ mov(r2, Operand(var->name()));
1844 __ push(r2);
1845 __ CallRuntime(Runtime::kLoadContextSlot, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001846 __ Push(r0, r1); // Function, receiver.
1847
1848 // If fast case code has been generated, emit code to push the
1849 // function and receiver and have the slow path jump around this
1850 // code.
1851 if (done.is_linked()) {
1852 Label call;
1853 __ b(&call);
1854 __ bind(&done);
1855 // Push function.
1856 __ push(r0);
1857 // Push global receiver.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001858 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001859 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1860 __ push(r1);
1861 __ bind(&call);
1862 }
1863
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001864 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001865 } else if (fun->AsProperty() != NULL) {
1866 // Call to an object property.
1867 Property* prop = fun->AsProperty();
1868 Literal* key = prop->key()->AsLiteral();
1869 if (key != NULL && key->handle()->IsSymbol()) {
1870 // Call to a named property, use call IC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001871 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1872 VisitForStackValue(prop->obj());
1873 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001874 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1875 } else {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001876 // Call to a keyed property.
1877 // For a synthetic property use keyed load IC followed by function call,
1878 // for a regular property use keyed CallIC.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001879 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1880 VisitForStackValue(prop->obj());
1881 }
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001882 if (prop->is_synthetic()) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001883 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1884 VisitForAccumulatorValue(prop->key());
1885 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001886 // Record source code position for IC call.
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001887 SetSourcePosition(prop->position(), FORCED_POSITION);
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001888 __ pop(r1); // We do not need to keep the receiver.
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001889
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001890 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001891 EmitCallIC(ic, RelocInfo::CODE_TARGET);
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001892 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001893 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00001894 __ Push(r0, r1); // Function, receiver.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001895 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001896 } else {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00001897 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001898 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001899 }
1900 } else {
1901 // Call to some other expression. If the expression is an anonymous
1902 // function literal not called in a loop, mark it as one that should
1903 // also use the fast code generator.
1904 FunctionLiteral* lit = fun->AsFunctionLiteral();
1905 if (lit != NULL &&
1906 lit->name()->Equals(Heap::empty_string()) &&
1907 loop_depth() == 0) {
1908 lit->set_try_full_codegen(true);
1909 }
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +00001910
1911 { PreserveStatementPositionScope scope(masm()->positions_recorder());
1912 VisitForStackValue(fun);
1913 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001914 // Load global receiver object.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00001915 __ ldr(r1, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001916 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1917 __ push(r1);
1918 // Emit function call.
1919 EmitCallWithStub(expr);
1920 }
1921}
1922
1923
1924void FullCodeGenerator::VisitCallNew(CallNew* expr) {
1925 Comment cmnt(masm_, "[ CallNew");
1926 // According to ECMA-262, section 11.2.2, page 44, the function
1927 // expression in new calls must be evaluated before the
1928 // arguments.
ricow@chromium.org65fae842010-08-25 15:26:24 +00001929
1930 // Push constructor on the stack. If it's not a function it's used as
1931 // receiver for CALL_NON_FUNCTION, otherwise the value on the stack is
1932 // ignored.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001933 VisitForStackValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001934
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001935 // Push the arguments ("left-to-right") on the stack.
1936 ZoneList<Expression*>* args = expr->arguments();
1937 int arg_count = args->length();
1938 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001939 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001940 }
1941
1942 // Call the construct call builtin that handles allocation and
1943 // constructor invocation.
1944 SetSourcePosition(expr->position());
1945
ricow@chromium.org65fae842010-08-25 15:26:24 +00001946 // Load function and argument count into r1 and r0.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001947 __ mov(r0, Operand(arg_count));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001948 __ ldr(r1, MemOperand(sp, arg_count * kPointerSize));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001949
1950 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1951 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001952 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001953}
1954
1955
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001956void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1957 ASSERT(args->length() == 1);
1958
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001959 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001960
1961 Label materialize_true, materialize_false;
1962 Label* if_true = NULL;
1963 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001964 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001965 context()->PrepareTest(&materialize_true, &materialize_false,
1966 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001967
1968 __ BranchOnSmi(r0, if_true);
1969 __ b(if_false);
1970
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001971 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001972}
1973
1974
1975void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1976 ASSERT(args->length() == 1);
1977
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001978 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001979
1980 Label materialize_true, materialize_false;
1981 Label* if_true = NULL;
1982 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001983 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001984 context()->PrepareTest(&materialize_true, &materialize_false,
1985 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001986
1987 __ tst(r0, Operand(kSmiTagMask | 0x80000000));
ricow@chromium.org65fae842010-08-25 15:26:24 +00001988 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001989
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001990 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001991}
1992
1993
1994void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
1995 ASSERT(args->length() == 1);
1996
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001997 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00001998
1999 Label materialize_true, materialize_false;
2000 Label* if_true = NULL;
2001 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002002 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002003 context()->PrepareTest(&materialize_true, &materialize_false,
2004 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002005
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002006 __ BranchOnSmi(r0, if_false);
2007 __ LoadRoot(ip, Heap::kNullValueRootIndex);
2008 __ cmp(r0, ip);
2009 __ b(eq, if_true);
2010 __ ldr(r2, FieldMemOperand(r0, HeapObject::kMapOffset));
2011 // Undetectable objects behave like undefined when tested with typeof.
2012 __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
2013 __ tst(r1, Operand(1 << Map::kIsUndetectable));
2014 __ b(ne, if_false);
2015 __ ldrb(r1, FieldMemOperand(r2, Map::kInstanceTypeOffset));
2016 __ cmp(r1, Operand(FIRST_JS_OBJECT_TYPE));
2017 __ b(lt, if_false);
2018 __ cmp(r1, Operand(LAST_JS_OBJECT_TYPE));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002019 Split(le, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002020
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002021 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002022}
2023
2024
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002025void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2026 ASSERT(args->length() == 1);
2027
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002028 VisitForAccumulatorValue(args->at(0));
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002029
2030 Label materialize_true, materialize_false;
2031 Label* if_true = NULL;
2032 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002033 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002034 context()->PrepareTest(&materialize_true, &materialize_false,
2035 &if_true, &if_false, &fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002036
2037 __ BranchOnSmi(r0, if_false);
2038 __ CompareObjectType(r0, r1, r1, FIRST_JS_OBJECT_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002039 Split(ge, if_true, if_false, fall_through);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002040
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002041 context()->Plug(if_true, if_false);
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002042}
2043
2044
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002045void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2046 ASSERT(args->length() == 1);
2047
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002048 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002049
2050 Label materialize_true, materialize_false;
2051 Label* if_true = NULL;
2052 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002053 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002054 context()->PrepareTest(&materialize_true, &materialize_false,
2055 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002056
2057 __ BranchOnSmi(r0, if_false);
2058 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
2059 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
2060 __ tst(r1, Operand(1 << Map::kIsUndetectable));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002061 Split(ne, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002062
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002063 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002064}
2065
2066
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002067void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2068 ZoneList<Expression*>* args) {
2069
2070 ASSERT(args->length() == 1);
2071
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002072 VisitForAccumulatorValue(args->at(0));
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002073
2074 Label materialize_true, materialize_false;
2075 Label* if_true = NULL;
2076 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002077 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002078 context()->PrepareTest(&materialize_true, &materialize_false,
2079 &if_true, &if_false, &fall_through);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002080
2081 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
2082 // used in a few functions in runtime.js which should not normally be hit by
2083 // this compiler.
2084 __ jmp(if_false);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002085 context()->Plug(if_true, if_false);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002086}
2087
2088
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002089void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2090 ASSERT(args->length() == 1);
2091
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002092 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002093
2094 Label materialize_true, materialize_false;
2095 Label* if_true = NULL;
2096 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002097 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002098 context()->PrepareTest(&materialize_true, &materialize_false,
2099 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002100
2101 __ BranchOnSmi(r0, if_false);
2102 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002103 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002104
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002105 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002106}
2107
2108
2109void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2110 ASSERT(args->length() == 1);
2111
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002112 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002113
2114 Label materialize_true, materialize_false;
2115 Label* if_true = NULL;
2116 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002117 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002118 context()->PrepareTest(&materialize_true, &materialize_false,
2119 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002120
2121 __ BranchOnSmi(r0, if_false);
2122 __ CompareObjectType(r0, r1, r1, JS_ARRAY_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002123 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002124
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002125 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002126}
2127
2128
2129void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2130 ASSERT(args->length() == 1);
2131
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002132 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002133
2134 Label materialize_true, materialize_false;
2135 Label* if_true = NULL;
2136 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002137 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002138 context()->PrepareTest(&materialize_true, &materialize_false,
2139 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002140
2141 __ BranchOnSmi(r0, if_false);
2142 __ CompareObjectType(r0, r1, r1, JS_REGEXP_TYPE);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002143 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002144
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002145 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002146}
2147
2148
2149
2150void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2151 ASSERT(args->length() == 0);
2152
2153 Label materialize_true, materialize_false;
2154 Label* if_true = NULL;
2155 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002156 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002157 context()->PrepareTest(&materialize_true, &materialize_false,
2158 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002159
2160 // Get the frame pointer for the calling frame.
2161 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2162
2163 // Skip the arguments adaptor frame if it exists.
2164 Label check_frame_marker;
2165 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kContextOffset));
2166 __ cmp(r1, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2167 __ b(ne, &check_frame_marker);
2168 __ ldr(r2, MemOperand(r2, StandardFrameConstants::kCallerFPOffset));
2169
2170 // Check the marker in the calling frame.
2171 __ bind(&check_frame_marker);
2172 __ ldr(r1, MemOperand(r2, StandardFrameConstants::kMarkerOffset));
2173 __ cmp(r1, Operand(Smi::FromInt(StackFrame::CONSTRUCT)));
ricow@chromium.org65fae842010-08-25 15:26:24 +00002174 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002175
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002176 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002177}
2178
2179
2180void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2181 ASSERT(args->length() == 2);
2182
2183 // Load the two objects into registers and perform the comparison.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002184 VisitForStackValue(args->at(0));
2185 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002186
2187 Label materialize_true, materialize_false;
2188 Label* if_true = NULL;
2189 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002190 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002191 context()->PrepareTest(&materialize_true, &materialize_false,
2192 &if_true, &if_false, &fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002193
2194 __ pop(r1);
2195 __ cmp(r0, r1);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002196 Split(eq, if_true, if_false, fall_through);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002197
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002198 context()->Plug(if_true, if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002199}
2200
2201
2202void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2203 ASSERT(args->length() == 1);
2204
2205 // ArgumentsAccessStub expects the key in edx and the formal
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002206 // parameter count in r0.
2207 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002208 __ mov(r1, r0);
2209 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters())));
2210 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2211 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002212 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002213}
2214
2215
2216void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2217 ASSERT(args->length() == 0);
2218
2219 Label exit;
2220 // Get the number of formal parameters.
2221 __ mov(r0, Operand(Smi::FromInt(scope()->num_parameters())));
2222
2223 // Check if the calling frame is an arguments adaptor frame.
2224 __ ldr(r2, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
2225 __ ldr(r3, MemOperand(r2, StandardFrameConstants::kContextOffset));
2226 __ cmp(r3, Operand(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2227 __ b(ne, &exit);
2228
2229 // Arguments adaptor case: Read the arguments length from the
2230 // adaptor frame.
2231 __ ldr(r0, MemOperand(r2, ArgumentsAdaptorFrameConstants::kLengthOffset));
2232
2233 __ bind(&exit);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002234 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002235}
2236
2237
2238void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2239 ASSERT(args->length() == 1);
2240 Label done, null, function, non_function_constructor;
2241
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002242 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002243
2244 // If the object is a smi, we return null.
2245 __ BranchOnSmi(r0, &null);
2246
2247 // Check that the object is a JS object but take special care of JS
2248 // functions to make sure they have 'Function' as their class.
2249 __ CompareObjectType(r0, r0, r1, FIRST_JS_OBJECT_TYPE); // Map is now in r0.
2250 __ b(lt, &null);
2251
2252 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2253 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2254 // LAST_JS_OBJECT_TYPE.
2255 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2256 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
2257 __ cmp(r1, Operand(JS_FUNCTION_TYPE));
2258 __ b(eq, &function);
2259
2260 // Check if the constructor in the map is a function.
2261 __ ldr(r0, FieldMemOperand(r0, Map::kConstructorOffset));
2262 __ CompareObjectType(r0, r1, r1, JS_FUNCTION_TYPE);
2263 __ b(ne, &non_function_constructor);
2264
2265 // r0 now contains the constructor function. Grab the
2266 // instance class name from there.
2267 __ ldr(r0, FieldMemOperand(r0, JSFunction::kSharedFunctionInfoOffset));
2268 __ ldr(r0, FieldMemOperand(r0, SharedFunctionInfo::kInstanceClassNameOffset));
2269 __ b(&done);
2270
2271 // Functions have class 'Function'.
2272 __ bind(&function);
2273 __ LoadRoot(r0, Heap::kfunction_class_symbolRootIndex);
2274 __ jmp(&done);
2275
2276 // Objects with a non-function constructor have class 'Object'.
2277 __ bind(&non_function_constructor);
2278 __ LoadRoot(r0, Heap::kfunction_class_symbolRootIndex);
2279 __ jmp(&done);
2280
2281 // Non-JS objects have class null.
2282 __ bind(&null);
2283 __ LoadRoot(r0, Heap::kNullValueRootIndex);
2284
2285 // All done.
2286 __ bind(&done);
2287
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002288 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002289}
2290
2291
2292void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2293 // Conditionally generate a log call.
2294 // Args:
2295 // 0 (literal string): The type of logging (corresponds to the flags).
2296 // This is used to determine whether or not to generate the log call.
2297 // 1 (string): Format string. Access the string at argument index 2
2298 // with '%2s' (see Logger::LogRuntime for all the formats).
2299 // 2 (array): Arguments to the format string.
2300 ASSERT_EQ(args->length(), 3);
2301#ifdef ENABLE_LOGGING_AND_PROFILING
2302 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002303 VisitForStackValue(args->at(1));
2304 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002305 __ CallRuntime(Runtime::kLog, 2);
2306 }
2307#endif
2308 // Finally, we're expected to leave a value on the top of the stack.
2309 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002310 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002311}
2312
2313
2314void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2315 ASSERT(args->length() == 0);
2316
2317 Label slow_allocate_heapnumber;
2318 Label heapnumber_allocated;
2319
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00002320 __ LoadRoot(r6, Heap::kHeapNumberMapRootIndex);
2321 __ AllocateHeapNumber(r4, r1, r2, r6, &slow_allocate_heapnumber);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002322 __ jmp(&heapnumber_allocated);
2323
2324 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002325 // Allocate a heap number.
2326 __ CallRuntime(Runtime::kNumberAlloc, 0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002327 __ mov(r4, Operand(r0));
2328
2329 __ bind(&heapnumber_allocated);
2330
2331 // Convert 32 random bits in r0 to 0.(32 random bits) in a double
2332 // by computing:
2333 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2334 if (CpuFeatures::IsSupported(VFP3)) {
2335 __ PrepareCallCFunction(0, r1);
2336 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2337
2338 CpuFeatures::Scope scope(VFP3);
2339 // 0x41300000 is the top half of 1.0 x 2^20 as a double.
2340 // Create this constant using mov/orr to avoid PC relative load.
2341 __ mov(r1, Operand(0x41000000));
2342 __ orr(r1, r1, Operand(0x300000));
2343 // Move 0x41300000xxxxxxxx (x = random bits) to VFP.
2344 __ vmov(d7, r0, r1);
2345 // Move 0x4130000000000000 to VFP.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00002346 __ mov(r0, Operand(0, RelocInfo::NONE));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002347 __ vmov(d8, r0, r1);
2348 // Subtract and store the result in the heap number.
2349 __ vsub(d7, d7, d8);
2350 __ sub(r0, r4, Operand(kHeapObjectTag));
2351 __ vstr(d7, r0, HeapNumber::kValueOffset);
2352 __ mov(r0, r4);
2353 } else {
2354 __ mov(r0, Operand(r4));
2355 __ PrepareCallCFunction(1, r1);
2356 __ CallCFunction(
2357 ExternalReference::fill_heap_number_with_random_function(), 1);
2358 }
2359
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002360 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002361}
2362
2363
2364void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2365 // Load the arguments on the stack and call the stub.
2366 SubStringStub stub;
2367 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002368 VisitForStackValue(args->at(0));
2369 VisitForStackValue(args->at(1));
2370 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002371 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002372 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002373}
2374
2375
2376void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2377 // Load the arguments on the stack and call the stub.
2378 RegExpExecStub stub;
2379 ASSERT(args->length() == 4);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002380 VisitForStackValue(args->at(0));
2381 VisitForStackValue(args->at(1));
2382 VisitForStackValue(args->at(2));
2383 VisitForStackValue(args->at(3));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002384 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002385 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002386}
2387
2388
2389void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2390 ASSERT(args->length() == 1);
2391
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002392 VisitForAccumulatorValue(args->at(0)); // Load the object.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002393
2394 Label done;
2395 // If the object is a smi return the object.
2396 __ BranchOnSmi(r0, &done);
2397 // If the object is not a value type, return the object.
2398 __ CompareObjectType(r0, r1, r1, JS_VALUE_TYPE);
2399 __ b(ne, &done);
2400 __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
2401
2402 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002403 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002404}
2405
2406
2407void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2408 // Load the arguments on the stack and call the runtime function.
2409 ASSERT(args->length() == 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002410 VisitForStackValue(args->at(0));
2411 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002412 __ CallRuntime(Runtime::kMath_pow, 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002413 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002414}
2415
2416
2417void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2418 ASSERT(args->length() == 2);
2419
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002420 VisitForStackValue(args->at(0)); // Load the object.
2421 VisitForAccumulatorValue(args->at(1)); // Load the value.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002422 __ pop(r1); // r0 = value. r1 = object.
2423
2424 Label done;
2425 // If the object is a smi, return the value.
2426 __ BranchOnSmi(r1, &done);
2427
2428 // If the object is not a value type, return the value.
2429 __ CompareObjectType(r1, r2, r2, JS_VALUE_TYPE);
2430 __ b(ne, &done);
2431
2432 // Store the value.
2433 __ str(r0, FieldMemOperand(r1, JSValue::kValueOffset));
2434 // Update the write barrier. Save the value as it will be
2435 // overwritten by the write barrier code and is needed afterward.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00002436 __ RecordWrite(r1, Operand(JSValue::kValueOffset - kHeapObjectTag), r2, r3);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002437
2438 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002439 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002440}
2441
2442
2443void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2444 ASSERT_EQ(args->length(), 1);
2445
2446 // Load the argument on the stack and call the stub.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002447 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002448
2449 NumberToStringStub stub;
2450 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002451 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002452}
2453
2454
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002455void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002456 ASSERT(args->length() == 1);
2457
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002458 VisitForAccumulatorValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002459
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002460 Label done;
2461 StringCharFromCodeGenerator generator(r0, r1);
2462 generator.GenerateFast(masm_);
2463 __ jmp(&done);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002464
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002465 NopRuntimeCallHelper call_helper;
2466 generator.GenerateSlow(masm_, call_helper);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002467
2468 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002469 context()->Plug(r1);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002470}
2471
2472
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002473void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2474 ASSERT(args->length() == 2);
2475
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002476 VisitForStackValue(args->at(0));
2477 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002478
2479 Register object = r1;
2480 Register index = r0;
2481 Register scratch = r2;
2482 Register result = r3;
2483
2484 __ pop(object);
2485
2486 Label need_conversion;
2487 Label index_out_of_range;
2488 Label done;
2489 StringCharCodeAtGenerator generator(object,
2490 index,
2491 scratch,
2492 result,
2493 &need_conversion,
2494 &need_conversion,
2495 &index_out_of_range,
2496 STRING_INDEX_IS_NUMBER);
2497 generator.GenerateFast(masm_);
2498 __ jmp(&done);
2499
2500 __ bind(&index_out_of_range);
2501 // When the index is out of range, the spec requires us to return
2502 // NaN.
2503 __ LoadRoot(result, Heap::kNanValueRootIndex);
2504 __ jmp(&done);
2505
2506 __ bind(&need_conversion);
2507 // Load the undefined value into the result register, which will
2508 // trigger conversion.
2509 __ LoadRoot(result, Heap::kUndefinedValueRootIndex);
2510 __ jmp(&done);
2511
2512 NopRuntimeCallHelper call_helper;
2513 generator.GenerateSlow(masm_, call_helper);
2514
2515 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002516 context()->Plug(result);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002517}
2518
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002519
2520void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2521 ASSERT(args->length() == 2);
2522
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002523 VisitForStackValue(args->at(0));
2524 VisitForAccumulatorValue(args->at(1));
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002525
2526 Register object = r1;
2527 Register index = r0;
2528 Register scratch1 = r2;
2529 Register scratch2 = r3;
2530 Register result = r0;
2531
2532 __ pop(object);
2533
2534 Label need_conversion;
2535 Label index_out_of_range;
2536 Label done;
2537 StringCharAtGenerator generator(object,
2538 index,
2539 scratch1,
2540 scratch2,
2541 result,
2542 &need_conversion,
2543 &need_conversion,
2544 &index_out_of_range,
2545 STRING_INDEX_IS_NUMBER);
2546 generator.GenerateFast(masm_);
2547 __ jmp(&done);
2548
2549 __ bind(&index_out_of_range);
2550 // When the index is out of range, the spec requires us to return
2551 // the empty string.
2552 __ LoadRoot(result, Heap::kEmptyStringRootIndex);
2553 __ jmp(&done);
2554
2555 __ bind(&need_conversion);
2556 // Move smi zero into the result register, which will trigger
2557 // conversion.
2558 __ mov(result, Operand(Smi::FromInt(0)));
2559 __ jmp(&done);
2560
2561 NopRuntimeCallHelper call_helper;
2562 generator.GenerateSlow(masm_, call_helper);
2563
2564 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002565 context()->Plug(result);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002566}
2567
2568
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002569void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2570 ASSERT_EQ(2, args->length());
2571
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002572 VisitForStackValue(args->at(0));
2573 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002574
2575 StringAddStub stub(NO_STRING_ADD_FLAGS);
2576 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002577 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002578}
2579
2580
2581void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2582 ASSERT_EQ(2, args->length());
2583
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002584 VisitForStackValue(args->at(0));
2585 VisitForStackValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002586
2587 StringCompareStub stub;
2588 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002589 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002590}
2591
2592
2593void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2594 // Load the argument on the stack and call the runtime.
2595 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002596 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002597 __ CallRuntime(Runtime::kMath_sin, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002598 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002599}
2600
2601
2602void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2603 // Load the argument on the stack and call the runtime.
2604 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002605 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002606 __ CallRuntime(Runtime::kMath_cos, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002607 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002608}
2609
2610
2611void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2612 // Load the argument on the stack and call the runtime function.
2613 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002614 VisitForStackValue(args->at(0));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002615 __ CallRuntime(Runtime::kMath_sqrt, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002616 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002617}
2618
2619
2620void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2621 ASSERT(args->length() >= 2);
2622
2623 int arg_count = args->length() - 2; // For receiver and function.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002624 VisitForStackValue(args->at(0)); // Receiver.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002625 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002626 VisitForStackValue(args->at(i + 1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002627 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002628 VisitForAccumulatorValue(args->at(arg_count + 1)); // Function.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002629
2630 // InvokeFunction requires function in r1. Move it in there.
2631 if (!result_register().is(r1)) __ mov(r1, result_register());
2632 ParameterCount count(arg_count);
2633 __ InvokeFunction(r1, count, CALL_FUNCTION);
2634 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002635 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002636}
2637
2638
2639void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2640 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002641 VisitForStackValue(args->at(0));
2642 VisitForStackValue(args->at(1));
2643 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002644 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002645 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002646}
2647
2648
2649void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2650 ASSERT(args->length() == 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002651 VisitForStackValue(args->at(0));
2652 VisitForStackValue(args->at(1));
2653 VisitForStackValue(args->at(2));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002654 __ CallRuntime(Runtime::kSwapElements, 3);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002655 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002656}
2657
2658
2659void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2660 ASSERT_EQ(2, args->length());
2661
2662 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2663 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2664
2665 Handle<FixedArray> jsfunction_result_caches(
2666 Top::global_context()->jsfunction_result_caches());
2667 if (jsfunction_result_caches->length() <= cache_id) {
2668 __ Abort("Attempt to use undefined cache.");
2669 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002670 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002671 return;
2672 }
2673
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002674 VisitForAccumulatorValue(args->at(1));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002675
2676 Register key = r0;
2677 Register cache = r1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002678 __ ldr(cache, ContextOperand(cp, Context::GLOBAL_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002679 __ ldr(cache, FieldMemOperand(cache, GlobalObject::kGlobalContextOffset));
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00002680 __ ldr(cache, ContextOperand(cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002681 __ ldr(cache,
2682 FieldMemOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2683
2684
2685 Label done, not_found;
2686 // tmp now holds finger offset as a smi.
2687 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2688 __ ldr(r2, FieldMemOperand(cache, JSFunctionResultCache::kFingerOffset));
2689 // r2 now holds finger offset as a smi.
2690 __ add(r3, cache, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
2691 // r3 now points to the start of fixed array elements.
2692 __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2 - kSmiTagSize, PreIndex));
2693 // Note side effect of PreIndex: r3 now points to the key of the pair.
2694 __ cmp(key, r2);
2695 __ b(ne, &not_found);
2696
2697 __ ldr(r0, MemOperand(r3, kPointerSize));
2698 __ b(&done);
2699
2700 __ bind(&not_found);
2701 // Call runtime to perform the lookup.
2702 __ Push(cache, key);
2703 __ CallRuntime(Runtime::kGetFromCache, 2);
2704
2705 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002706 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002707}
2708
2709
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00002710void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
2711 ASSERT_EQ(2, args->length());
2712
2713 Register right = r0;
2714 Register left = r1;
2715 Register tmp = r2;
2716 Register tmp2 = r3;
2717
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002718 VisitForStackValue(args->at(0));
2719 VisitForAccumulatorValue(args->at(1));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00002720 __ pop(left);
2721
2722 Label done, fail, ok;
2723 __ cmp(left, Operand(right));
2724 __ b(eq, &ok);
2725 // Fail if either is a non-HeapObject.
2726 __ and_(tmp, left, Operand(right));
2727 __ tst(tmp, Operand(kSmiTagMask));
2728 __ b(eq, &fail);
2729 __ ldr(tmp, FieldMemOperand(left, HeapObject::kMapOffset));
2730 __ ldrb(tmp2, FieldMemOperand(tmp, Map::kInstanceTypeOffset));
2731 __ cmp(tmp2, Operand(JS_REGEXP_TYPE));
2732 __ b(ne, &fail);
2733 __ ldr(tmp2, FieldMemOperand(right, HeapObject::kMapOffset));
2734 __ cmp(tmp, Operand(tmp2));
2735 __ b(ne, &fail);
2736 __ ldr(tmp, FieldMemOperand(left, JSRegExp::kDataOffset));
2737 __ ldr(tmp2, FieldMemOperand(right, JSRegExp::kDataOffset));
2738 __ cmp(tmp, tmp2);
2739 __ b(eq, &ok);
2740 __ bind(&fail);
2741 __ LoadRoot(r0, Heap::kFalseValueRootIndex);
2742 __ jmp(&done);
2743 __ bind(&ok);
2744 __ LoadRoot(r0, Heap::kTrueValueRootIndex);
2745 __ bind(&done);
2746
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002747 context()->Plug(r0);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00002748}
2749
2750
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002751void FullCodeGenerator::EmitHasCachedArrayIndex(ZoneList<Expression*>* args) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002752 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002753
2754 Label materialize_true, materialize_false;
2755 Label* if_true = NULL;
2756 Label* if_false = NULL;
2757 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002758 context()->PrepareTest(&materialize_true, &materialize_false,
2759 &if_true, &if_false, &fall_through);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002760
2761 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
2762 __ tst(r0, Operand(String::kContainsCachedArrayIndexMask));
2763
2764 __ b(eq, if_true);
2765 __ b(if_false);
2766
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002767 context()->Plug(if_true, if_false);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002768}
2769
2770
2771void FullCodeGenerator::EmitGetCachedArrayIndex(ZoneList<Expression*>* args) {
2772 ASSERT(args->length() == 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002773 VisitForAccumulatorValue(args->at(0));
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002774 __ ldr(r0, FieldMemOperand(r0, String::kHashFieldOffset));
2775 __ IndexFromHash(r0, r0);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002776 context()->Plug(r0);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002777}
2778
2779
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00002780void FullCodeGenerator::EmitFastAsciiArrayJoin(ZoneList<Expression*>* args) {
2781 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
2782 context()->Plug(r0);
2783 return;
2784}
2785
2786
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002787void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002788 Handle<String> name = expr->name();
2789 if (name->length() > 0 && name->Get(0) == '_') {
2790 Comment cmnt(masm_, "[ InlineRuntimeCall");
2791 EmitInlineRuntimeCall(expr);
2792 return;
2793 }
2794
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002795 Comment cmnt(masm_, "[ CallRuntime");
2796 ZoneList<Expression*>* args = expr->arguments();
2797
2798 if (expr->is_jsruntime()) {
2799 // Prepare for calling JS runtime function.
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002800 __ ldr(r0, GlobalObjectOperand());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002801 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
ager@chromium.org5c838252010-02-19 08:53:10 +00002802 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002803 }
2804
2805 // Push the arguments ("left-to-right").
2806 int arg_count = args->length();
2807 for (int i = 0; i < arg_count; i++) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002808 VisitForStackValue(args->at(i));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002809 }
2810
2811 if (expr->is_jsruntime()) {
2812 // Call the JS runtime function.
ager@chromium.org5c838252010-02-19 08:53:10 +00002813 __ mov(r2, Operand(expr->name()));
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002814 Handle<Code> ic = StubCache::ComputeCallInitialize(arg_count, NOT_IN_LOOP);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00002815 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002816 // Restore context register.
2817 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002818 } else {
2819 // Call the C runtime function.
2820 __ CallRuntime(expr->function(), arg_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002821 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002822 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002823}
2824
2825
2826void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2827 switch (expr->op()) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002828 case Token::DELETE: {
2829 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2830 Property* prop = expr->expression()->AsProperty();
2831 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2832 if (prop == NULL && var == NULL) {
2833 // Result of deleting non-property, non-variable reference is true.
2834 // The subexpression may have side effects.
2835 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002836 context()->Plug(true);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002837 } else if (var != NULL &&
2838 !var->is_global() &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002839 var->AsSlot() != NULL &&
2840 var->AsSlot()->type() != Slot::LOOKUP) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002841 // Result of deleting non-global, non-dynamic variables is false.
2842 // The subexpression does not have side effects.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002843 context()->Plug(false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002844 } else {
2845 // Property or variable reference. Call the delete builtin with
2846 // object and property name as arguments.
2847 if (prop != NULL) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002848 VisitForStackValue(prop->obj());
2849 VisitForStackValue(prop->key());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002850 } else if (var->is_global()) {
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00002851 __ ldr(r1, GlobalObjectOperand());
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002852 __ mov(r0, Operand(var->name()));
2853 __ Push(r1, r0);
2854 } else {
2855 // Non-global variable. Call the runtime to look up the context
2856 // where the variable was introduced.
2857 __ push(context_register());
2858 __ mov(r2, Operand(var->name()));
2859 __ push(r2);
2860 __ CallRuntime(Runtime::kLookupContext, 2);
2861 __ push(r0);
2862 __ mov(r2, Operand(var->name()));
2863 __ push(r2);
2864 }
2865 __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002866 context()->Plug(r0);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002867 }
2868 break;
2869 }
2870
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002871 case Token::VOID: {
2872 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
2873 VisitForEffect(expr->expression());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002874 context()->Plug(Heap::kUndefinedValueRootIndex);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002875 break;
2876 }
2877
2878 case Token::NOT: {
2879 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002880 Label materialize_true, materialize_false;
2881 Label* if_true = NULL;
2882 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002883 Label* fall_through = NULL;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002884
2885 // Notice that the labels are swapped.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002886 context()->PrepareTest(&materialize_true, &materialize_false,
2887 &if_false, &if_true, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00002888 VisitForControl(expr->expression(), if_true, if_false, fall_through);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002889 context()->Plug(if_false, if_true); // Labels swapped.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002890 break;
2891 }
2892
2893 case Token::TYPEOF: {
2894 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002895 { StackValueContext context(this);
2896 VisitForTypeofValue(expr->expression());
2897 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002898 __ CallRuntime(Runtime::kTypeof, 1);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002899 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002900 break;
2901 }
2902
2903 case Token::ADD: {
2904 Comment cmt(masm_, "[ UnaryOperation (ADD)");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002905 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002906 Label no_conversion;
2907 __ tst(result_register(), Operand(kSmiTagMask));
2908 __ b(eq, &no_conversion);
2909 __ push(r0);
2910 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
2911 __ bind(&no_conversion);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002912 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002913 break;
2914 }
2915
2916 case Token::SUB: {
2917 Comment cmt(masm_, "[ UnaryOperation (SUB)");
ricow@chromium.org65fae842010-08-25 15:26:24 +00002918 bool can_overwrite = expr->expression()->ResultOverwriteAllowed();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002919 UnaryOverwriteMode overwrite =
2920 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002921 GenericUnaryOpStub stub(Token::SUB,
2922 overwrite,
2923 NO_UNARY_FLAGS);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002924 // GenericUnaryOpStub expects the argument to be in the
2925 // accumulator register r0.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002926 VisitForAccumulatorValue(expr->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002927 __ CallStub(&stub);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002928 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002929 break;
2930 }
2931
2932 case Token::BIT_NOT: {
2933 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
ricow@chromium.org65fae842010-08-25 15:26:24 +00002934 // The generic unary operation stub expects the argument to be
2935 // in the accumulator register r0.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002936 VisitForAccumulatorValue(expr->expression());
ricow@chromium.org65fae842010-08-25 15:26:24 +00002937 Label done;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002938 bool inline_smi_code = ShouldInlineSmiCase(expr->op());
2939 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00002940 Label call_stub;
2941 __ BranchOnNotSmi(r0, &call_stub);
2942 __ mvn(r0, Operand(r0));
2943 // Bit-clear inverted smi-tag.
2944 __ bic(r0, r0, Operand(kSmiTagMask));
2945 __ b(&done);
2946 __ bind(&call_stub);
2947 }
2948 bool overwrite = expr->expression()->ResultOverwriteAllowed();
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002949 UnaryOpFlags flags = inline_smi_code
2950 ? NO_UNARY_SMI_CODE_IN_STUB
2951 : NO_UNARY_FLAGS;
ricow@chromium.org65fae842010-08-25 15:26:24 +00002952 UnaryOverwriteMode mode =
2953 overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00002954 GenericUnaryOpStub stub(Token::BIT_NOT, mode, flags);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002955 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002956 __ bind(&done);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002957 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002958 break;
2959 }
2960
2961 default:
2962 UNREACHABLE();
2963 }
2964}
2965
2966
2967void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
2968 Comment cmnt(masm_, "[ CountOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00002969 SetSourcePosition(expr->position());
2970
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002971 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
2972 // as the left-hand side.
2973 if (!expr->expression()->IsValidLeftHandSide()) {
2974 VisitForEffect(expr->expression());
2975 return;
2976 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002977
2978 // Expression can only be a property, a global or a (parameter or local)
2979 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
2980 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2981 LhsKind assign_type = VARIABLE;
2982 Property* prop = expr->expression()->AsProperty();
2983 // In case of a property we use the uninitialized expression context
2984 // of the key to detect a named property.
2985 if (prop != NULL) {
2986 assign_type =
2987 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
2988 }
2989
2990 // Evaluate expression and get value.
2991 if (assign_type == VARIABLE) {
2992 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002993 AccumulatorValueContext context(this);
2994 EmitVariableLoad(expr->expression()->AsVariableProxy()->var());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002995 } else {
2996 // Reserve space for result of postfix operation.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00002997 if (expr->is_postfix() && !context()->IsEffect()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002998 __ mov(ip, Operand(Smi::FromInt(0)));
2999 __ push(ip);
3000 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003001 if (assign_type == NAMED_PROPERTY) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003002 // Put the object both on the stack and in the accumulator.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003003 VisitForAccumulatorValue(prop->obj());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003004 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003005 EmitNamedPropertyLoad(prop);
3006 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003007 VisitForStackValue(prop->obj());
3008 VisitForAccumulatorValue(prop->key());
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00003009 __ ldr(r1, MemOperand(sp, 0));
3010 __ push(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003011 EmitKeyedPropertyLoad(prop);
3012 }
3013 }
3014
3015 // Call ToNumber only if operand is not a smi.
3016 Label no_conversion;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003017 __ BranchOnSmi(r0, &no_conversion);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003018 __ push(r0);
3019 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
3020 __ bind(&no_conversion);
3021
3022 // Save result for postfix expressions.
3023 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003024 if (!context()->IsEffect()) {
3025 // Save the result on the stack. If we have a named or keyed property
3026 // we store the result under the receiver that is currently on top
3027 // of the stack.
3028 switch (assign_type) {
3029 case VARIABLE:
3030 __ push(r0);
3031 break;
3032 case NAMED_PROPERTY:
3033 __ str(r0, MemOperand(sp, kPointerSize));
3034 break;
3035 case KEYED_PROPERTY:
3036 __ str(r0, MemOperand(sp, 2 * kPointerSize));
3037 break;
3038 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003039 }
3040 }
3041
3042
3043 // Inline smi case if we are in a loop.
3044 Label stub_call, done;
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003045 int count_value = expr->op() == Token::INC ? 1 : -1;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003046 if (ShouldInlineSmiCase(expr->op())) {
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003047 __ add(r0, r0, Operand(Smi::FromInt(count_value)), SetCC);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003048 __ b(vs, &stub_call);
3049 // We could eliminate this smi check if we split the code at
3050 // the first smi check before calling ToNumber.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003051 __ BranchOnSmi(r0, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003052 __ bind(&stub_call);
3053 // Call stub. Undo operation first.
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003054 __ sub(r0, r0, Operand(Smi::FromInt(count_value)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003055 }
fschneider@chromium.org013f3e12010-04-26 13:27:52 +00003056 __ mov(r1, Operand(Smi::FromInt(count_value)));
ager@chromium.org357bf652010-04-12 11:30:10 +00003057 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003058 __ CallStub(&stub);
3059 __ bind(&done);
3060
3061 // Store the value returned in r0.
3062 switch (assign_type) {
3063 case VARIABLE:
3064 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003065 { EffectContext context(this);
3066 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
3067 Token::ASSIGN);
3068 }
3069 // For all contexts except EffectConstant We have the result on
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003070 // top of the stack.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003071 if (!context()->IsEffect()) {
3072 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003073 }
3074 } else {
3075 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003076 Token::ASSIGN);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003077 }
3078 break;
3079 case NAMED_PROPERTY: {
3080 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
ager@chromium.org5c838252010-02-19 08:53:10 +00003081 __ pop(r1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003082 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003083 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003084 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003085 if (!context()->IsEffect()) {
3086 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003087 }
3088 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003089 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003090 }
3091 break;
3092 }
3093 case KEYED_PROPERTY: {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003094 __ pop(r1); // Key.
3095 __ pop(r2); // Receiver.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003096 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003097 EmitCallIC(ic, RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003098 if (expr->is_postfix()) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003099 if (!context()->IsEffect()) {
3100 context()->PlugTOS();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003101 }
3102 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003103 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003104 }
3105 break;
3106 }
3107 }
3108}
3109
3110
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003111void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
3112 ASSERT(!context()->IsEffect());
3113 ASSERT(!context()->IsTest());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003114 VariableProxy* proxy = expr->AsVariableProxy();
3115 if (proxy != NULL && !proxy->var()->is_this() && proxy->var()->is_global()) {
3116 Comment cmnt(masm_, "Global variable");
erik.corry@gmail.com4a6c3272010-11-18 12:04:40 +00003117 __ ldr(r0, GlobalObjectOperand());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003118 __ mov(r2, Operand(proxy->name()));
3119 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
3120 // Use a regular load, not a contextual load, to avoid a reference
3121 // error.
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003122 EmitCallIC(ic, RelocInfo::CODE_TARGET);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003123 context()->Plug(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003124 } else if (proxy != NULL &&
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003125 proxy->var()->AsSlot() != NULL &&
3126 proxy->var()->AsSlot()->type() == Slot::LOOKUP) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003127 Label done, slow;
3128
3129 // Generate code for loading from variables potentially shadowed
3130 // by eval-introduced variables.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003131 Slot* slot = proxy->var()->AsSlot();
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003132 EmitDynamicLoadFromSlotFastCase(slot, INSIDE_TYPEOF, &slow, &done);
3133
3134 __ bind(&slow);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003135 __ mov(r0, Operand(proxy->name()));
3136 __ Push(cp, r0);
3137 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003138 __ bind(&done);
3139
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003140 context()->Plug(r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003141 } else {
3142 // This expression cannot throw a reference error at the top level.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003143 Visit(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003144 }
3145}
3146
3147
ricow@chromium.org65fae842010-08-25 15:26:24 +00003148bool FullCodeGenerator::TryLiteralCompare(Token::Value op,
3149 Expression* left,
3150 Expression* right,
3151 Label* if_true,
3152 Label* if_false,
3153 Label* fall_through) {
3154 if (op != Token::EQ && op != Token::EQ_STRICT) return false;
3155
3156 // Check for the pattern: typeof <expression> == <string literal>.
3157 Literal* right_literal = right->AsLiteral();
3158 if (right_literal == NULL) return false;
3159 Handle<Object> right_literal_value = right_literal->handle();
3160 if (!right_literal_value->IsString()) return false;
3161 UnaryOperation* left_unary = left->AsUnaryOperation();
3162 if (left_unary == NULL || left_unary->op() != Token::TYPEOF) return false;
3163 Handle<String> check = Handle<String>::cast(right_literal_value);
3164
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003165 { AccumulatorValueContext context(this);
3166 VisitForTypeofValue(left_unary->expression());
3167 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003168 if (check->Equals(Heap::number_symbol())) {
3169 __ tst(r0, Operand(kSmiTagMask));
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003170 __ b(eq, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003171 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
3172 __ LoadRoot(ip, Heap::kHeapNumberMapRootIndex);
3173 __ cmp(r0, ip);
3174 Split(eq, if_true, if_false, fall_through);
3175 } else if (check->Equals(Heap::string_symbol())) {
3176 __ tst(r0, Operand(kSmiTagMask));
3177 __ b(eq, if_false);
3178 // Check for undetectable objects => false.
3179 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
3180 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
3181 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
3182 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
3183 __ b(eq, if_false);
3184 __ ldrb(r1, FieldMemOperand(r0, Map::kInstanceTypeOffset));
3185 __ cmp(r1, Operand(FIRST_NONSTRING_TYPE));
3186 Split(lt, if_true, if_false, fall_through);
3187 } else if (check->Equals(Heap::boolean_symbol())) {
3188 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
3189 __ cmp(r0, ip);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003190 __ b(eq, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003191 __ LoadRoot(ip, Heap::kFalseValueRootIndex);
3192 __ cmp(r0, ip);
3193 Split(eq, if_true, if_false, fall_through);
3194 } else if (check->Equals(Heap::undefined_symbol())) {
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003195 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003196 __ cmp(r0, ip);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003197 __ b(eq, if_true);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003198 __ tst(r0, Operand(kSmiTagMask));
3199 __ b(eq, if_false);
3200 // Check for undetectable objects => true.
3201 __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
3202 __ ldrb(r1, FieldMemOperand(r0, Map::kBitFieldOffset));
3203 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
3204 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
3205 Split(eq, if_true, if_false, fall_through);
3206 } else if (check->Equals(Heap::function_symbol())) {
3207 __ tst(r0, Operand(kSmiTagMask));
3208 __ b(eq, if_false);
3209 __ CompareObjectType(r0, r1, r0, JS_FUNCTION_TYPE);
3210 __ b(eq, if_true);
3211 // Regular expressions => 'function' (they are callable).
3212 __ CompareInstanceType(r1, r0, JS_REGEXP_TYPE);
3213 Split(eq, if_true, if_false, fall_through);
3214 } else if (check->Equals(Heap::object_symbol())) {
3215 __ tst(r0, Operand(kSmiTagMask));
3216 __ b(eq, if_false);
3217 __ LoadRoot(ip, Heap::kNullValueRootIndex);
3218 __ cmp(r0, ip);
3219 __ b(eq, if_true);
3220 // Regular expressions => 'function', not 'object'.
3221 __ CompareObjectType(r0, r1, r0, JS_REGEXP_TYPE);
3222 __ b(eq, if_false);
3223 // Check for undetectable objects => false.
3224 __ ldrb(r0, FieldMemOperand(r1, Map::kBitFieldOffset));
3225 __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
3226 __ cmp(r0, Operand(1 << Map::kIsUndetectable));
3227 __ b(eq, if_false);
3228 // Check for JS objects => true.
3229 __ ldrb(r0, FieldMemOperand(r1, Map::kInstanceTypeOffset));
3230 __ cmp(r0, Operand(FIRST_JS_OBJECT_TYPE));
3231 __ b(lt, if_false);
3232 __ cmp(r0, Operand(LAST_JS_OBJECT_TYPE));
3233 Split(le, if_true, if_false, fall_through);
3234 } else {
3235 if (if_false != fall_through) __ jmp(if_false);
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003236 }
ricow@chromium.org65fae842010-08-25 15:26:24 +00003237
3238 return true;
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003239}
3240
3241
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003242void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3243 Comment cmnt(masm_, "[ CompareOperation");
ricow@chromium.org65fae842010-08-25 15:26:24 +00003244 SetSourcePosition(expr->position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003245
3246 // Always perform the comparison for its control flow. Pack the result
3247 // into the expression's context after the comparison is performed.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00003248
3249 Label materialize_true, materialize_false;
3250 Label* if_true = NULL;
3251 Label* if_false = NULL;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003252 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003253 context()->PrepareTest(&materialize_true, &materialize_false,
3254 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003255
3256 // First we try a fast inlined version of the compare when one of
3257 // the operands is a literal.
3258 Token::Value op = expr->op();
3259 Expression* left = expr->left();
3260 Expression* right = expr->right();
3261 if (TryLiteralCompare(op, left, right, if_true, if_false, fall_through)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003262 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003263 return;
3264 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003265
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003266 VisitForStackValue(expr->left());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003267 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003268 case Token::IN:
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003269 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003270 __ InvokeBuiltin(Builtins::IN, CALL_JS);
3271 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
3272 __ cmp(r0, ip);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003273 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003274 break;
3275
3276 case Token::INSTANCEOF: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003277 VisitForStackValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003278 InstanceofStub stub;
3279 __ CallStub(&stub);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003280 // The stub returns 0 for true.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003281 __ tst(r0, r0);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003282 Split(eq, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003283 break;
3284 }
3285
3286 default: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003287 VisitForAccumulatorValue(expr->right());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003288 Condition cc = eq;
3289 bool strict = false;
ricow@chromium.org65fae842010-08-25 15:26:24 +00003290 switch (op) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003291 case Token::EQ_STRICT:
3292 strict = true;
3293 // Fall through
ricow@chromium.org65fae842010-08-25 15:26:24 +00003294 case Token::EQ:
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003295 cc = eq;
3296 __ pop(r1);
3297 break;
3298 case Token::LT:
3299 cc = lt;
3300 __ pop(r1);
3301 break;
3302 case Token::GT:
3303 // Reverse left and right sides to obtain ECMA-262 conversion order.
3304 cc = lt;
3305 __ mov(r1, result_register());
3306 __ pop(r0);
3307 break;
3308 case Token::LTE:
3309 // Reverse left and right sides to obtain ECMA-262 conversion order.
3310 cc = ge;
3311 __ mov(r1, result_register());
3312 __ pop(r0);
3313 break;
3314 case Token::GTE:
3315 cc = ge;
3316 __ pop(r1);
3317 break;
3318 case Token::IN:
3319 case Token::INSTANCEOF:
3320 default:
3321 UNREACHABLE();
3322 }
3323
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003324 bool inline_smi_code = ShouldInlineSmiCase(op);
3325 if (inline_smi_code) {
ricow@chromium.org65fae842010-08-25 15:26:24 +00003326 Label slow_case;
3327 __ orr(r2, r0, Operand(r1));
3328 __ BranchOnNotSmi(r2, &slow_case);
3329 __ cmp(r1, r0);
3330 Split(cc, if_true, if_false, NULL);
3331 __ bind(&slow_case);
3332 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +00003333 CompareFlags flags = inline_smi_code
3334 ? NO_SMI_COMPARE_IN_STUB
3335 : NO_COMPARE_FLAGS;
3336 CompareStub stub(cc, strict, flags, r1, r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003337 __ CallStub(&stub);
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00003338 __ cmp(r0, Operand(0, RelocInfo::NONE));
ricow@chromium.org65fae842010-08-25 15:26:24 +00003339 Split(cc, if_true, if_false, fall_through);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003340 }
3341 }
3342
3343 // Convert the result of the comparison into one expected for this
3344 // expression's context.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003345 context()->Plug(if_true, if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003346}
3347
3348
ricow@chromium.org65fae842010-08-25 15:26:24 +00003349void FullCodeGenerator::VisitCompareToNull(CompareToNull* expr) {
3350 Comment cmnt(masm_, "[ CompareToNull");
3351 Label materialize_true, materialize_false;
3352 Label* if_true = NULL;
3353 Label* if_false = NULL;
3354 Label* fall_through = NULL;
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003355 context()->PrepareTest(&materialize_true, &materialize_false,
3356 &if_true, &if_false, &fall_through);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003357
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003358 VisitForAccumulatorValue(expr->expression());
ricow@chromium.org65fae842010-08-25 15:26:24 +00003359 __ LoadRoot(r1, Heap::kNullValueRootIndex);
3360 __ cmp(r0, r1);
3361 if (expr->is_strict()) {
3362 Split(eq, if_true, if_false, fall_through);
3363 } else {
3364 __ b(eq, if_true);
3365 __ LoadRoot(r1, Heap::kUndefinedValueRootIndex);
3366 __ cmp(r0, r1);
3367 __ b(eq, if_true);
3368 __ tst(r0, Operand(kSmiTagMask));
3369 __ b(eq, if_false);
3370 // It can be an undetectable object.
3371 __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
3372 __ ldrb(r1, FieldMemOperand(r1, Map::kBitFieldOffset));
3373 __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
3374 __ cmp(r1, Operand(1 << Map::kIsUndetectable));
3375 Split(eq, if_true, if_false, fall_through);
3376 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003377 context()->Plug(if_true, if_false);
ricow@chromium.org65fae842010-08-25 15:26:24 +00003378}
3379
3380
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003381void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
3382 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003383 context()->Plug(r0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003384}
3385
3386
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003387Register FullCodeGenerator::result_register() {
3388 return r0;
3389}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003390
3391
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00003392Register FullCodeGenerator::context_register() {
3393 return cp;
3394}
3395
3396
3397void FullCodeGenerator::EmitCallIC(Handle<Code> ic, RelocInfo::Mode mode) {
3398 ASSERT(mode == RelocInfo::CODE_TARGET ||
3399 mode == RelocInfo::CODE_TARGET_CONTEXT);
3400 __ Call(ic, mode);
3401}
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003402
3403
3404void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3405 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3406 __ str(value, MemOperand(fp, frame_offset));
3407}
3408
3409
3410void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003411 __ ldr(dst, ContextOperand(cp, context_index));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003412}
3413
3414
3415// ----------------------------------------------------------------------------
3416// Non-local control flow support.
3417
3418void FullCodeGenerator::EnterFinallyBlock() {
3419 ASSERT(!result_register().is(r1));
3420 // Store result register while executing finally block.
3421 __ push(result_register());
3422 // Cook return address in link register to stack (smi encoded Code* delta)
3423 __ sub(r1, lr, Operand(masm_->CodeObject()));
3424 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
3425 ASSERT_EQ(0, kSmiTag);
3426 __ add(r1, r1, Operand(r1)); // Convert to smi.
3427 __ push(r1);
3428}
3429
3430
3431void FullCodeGenerator::ExitFinallyBlock() {
3432 ASSERT(!result_register().is(r1));
3433 // Restore result register from stack.
3434 __ pop(r1);
3435 // Uncook return address and return.
3436 __ pop(result_register());
3437 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
3438 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
3439 __ add(pc, r1, Operand(masm_->CodeObject()));
3440}
3441
3442
3443#undef __
3444
3445} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003446
3447#endif // V8_TARGET_ARCH_ARM