Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(78)

Side by Side Diff: src/arm/fast-codegen-arm.cc

Issue 549109: Rename the fast-codegen* files to full-codegen*. (Closed) Base URL: http://v8.googlecode.com/svn/branches/bleeding_edge/
Patch Set: Created 10 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/SConscript ('k') | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // 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
30 #include "codegen-inl.h"
31 #include "compiler.h"
32 #include "debug.h"
33 #include "fast-codegen.h"
34 #include "parser.h"
35
36 namespace v8 {
37 namespace internal {
38
39 #define __ ACCESS_MASM(masm_)
40
41 // Generate code for a JS function. On entry to the function the receiver
42 // and arguments have been pushed on the stack left to right. The actual
43 // argument count matches the formal parameter count expected by the
44 // function.
45 //
46 // The live registers are:
47 // o r1: the JS function object being called (ie, ourselves)
48 // o cp: our context
49 // o fp: our caller's frame pointer
50 // o sp: stack pointer
51 // o lr: return address
52 //
53 // The function builds a JS frame. Please see JavaScriptFrameConstants in
54 // frames-arm.h for its layout.
55 void FullCodeGenerator::Generate(FunctionLiteral* fun) {
56 function_ = fun;
57 SetFunctionPosition(fun);
58 int locals_count = fun->scope()->num_stack_slots();
59
60 __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
61 if (locals_count > 0) {
62 // Load undefined value here, so the value is ready for the loop below.
63 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
64 }
65 // Adjust fp to point to caller's fp.
66 __ add(fp, sp, Operand(2 * kPointerSize));
67
68 { Comment cmnt(masm_, "[ Allocate locals");
69 for (int i = 0; i < locals_count; i++) {
70 __ push(ip);
71 }
72 }
73
74 bool function_in_register = true;
75
76 // Possibly allocate a local context.
77 if (fun->scope()->num_heap_slots() > 0) {
78 Comment cmnt(masm_, "[ Allocate local context");
79 // Argument to NewContext is the function, which is in r1.
80 __ push(r1);
81 __ CallRuntime(Runtime::kNewContext, 1);
82 function_in_register = false;
83 // Context is returned in both r0 and cp. It replaces the context
84 // passed to us. It's saved in the stack and kept live in cp.
85 __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
86 // Copy any necessary parameters into the context.
87 int num_parameters = fun->scope()->num_parameters();
88 for (int i = 0; i < num_parameters; i++) {
89 Slot* slot = fun->scope()->parameter(i)->slot();
90 if (slot != NULL && slot->type() == Slot::CONTEXT) {
91 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
92 (num_parameters - 1 - i) * kPointerSize;
93 // Load parameter from stack.
94 __ ldr(r0, MemOperand(fp, parameter_offset));
95 // Store it in the context
96 __ str(r0, MemOperand(cp, Context::SlotOffset(slot->index())));
97 }
98 }
99 }
100
101 Variable* arguments = fun->scope()->arguments()->AsVariable();
102 if (arguments != NULL) {
103 // Function uses arguments object.
104 Comment cmnt(masm_, "[ Allocate arguments object");
105 if (!function_in_register) {
106 // Load this again, if it's used by the local context below.
107 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
108 } else {
109 __ mov(r3, r1);
110 }
111 // Receiver is just before the parameters on the caller's stack.
112 __ add(r2, fp, Operand(StandardFrameConstants::kCallerSPOffset +
113 fun->num_parameters() * kPointerSize));
114 __ mov(r1, Operand(Smi::FromInt(fun->num_parameters())));
115 __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
116
117 // Arguments to ArgumentsAccessStub:
118 // function, receiver address, parameter count.
119 // The stub will rewrite receiever and parameter count if the previous
120 // stack frame was an arguments adapter frame.
121 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
122 __ CallStub(&stub);
123 // Duplicate the value; move-to-slot operation might clobber registers.
124 __ mov(r3, r0);
125 Move(arguments->slot(), r0, r1, r2);
126 Slot* dot_arguments_slot =
127 fun->scope()->arguments_shadow()->AsVariable()->slot();
128 Move(dot_arguments_slot, r3, r1, r2);
129 }
130
131 // Check the stack for overflow or break request.
132 // Put the lr setup instruction in the delay slot. The kInstrSize is
133 // added to the implicit 8 byte offset that always applies to operations
134 // with pc and gives a return address 12 bytes down.
135 { Comment cmnt(masm_, "[ Stack check");
136 __ LoadRoot(r2, Heap::kStackLimitRootIndex);
137 __ add(lr, pc, Operand(Assembler::kInstrSize));
138 __ cmp(sp, Operand(r2));
139 StackCheckStub stub;
140 __ mov(pc,
141 Operand(reinterpret_cast<intptr_t>(stub.GetCode().location()),
142 RelocInfo::CODE_TARGET),
143 LeaveCC,
144 lo);
145 }
146
147 { Comment cmnt(masm_, "[ Declarations");
148 VisitDeclarations(fun->scope()->declarations());
149 }
150
151 if (FLAG_trace) {
152 __ CallRuntime(Runtime::kTraceEnter, 0);
153 }
154
155 { Comment cmnt(masm_, "[ Body");
156 ASSERT(loop_depth() == 0);
157 VisitStatements(fun->body());
158 ASSERT(loop_depth() == 0);
159 }
160
161 { Comment cmnt(masm_, "[ return <undefined>;");
162 // Emit a 'return undefined' in case control fell off the end of the
163 // body.
164 __ LoadRoot(r0, Heap::kUndefinedValueRootIndex);
165 }
166 EmitReturnSequence(function_->end_position());
167 }
168
169
170 void FullCodeGenerator::EmitReturnSequence(int position) {
171 Comment cmnt(masm_, "[ Return sequence");
172 if (return_label_.is_bound()) {
173 __ b(&return_label_);
174 } else {
175 __ bind(&return_label_);
176 if (FLAG_trace) {
177 // Push the return value on the stack as the parameter.
178 // Runtime::TraceExit returns its parameter in r0.
179 __ push(r0);
180 __ CallRuntime(Runtime::kTraceExit, 1);
181 }
182
183 // Add a label for checking the size of the code used for returning.
184 Label check_exit_codesize;
185 masm_->bind(&check_exit_codesize);
186
187 // Calculate the exact length of the return sequence and make sure that
188 // the constant pool is not emitted inside of the return sequence.
189 int num_parameters = function_->scope()->num_parameters();
190 int32_t sp_delta = (num_parameters + 1) * kPointerSize;
191 int return_sequence_length = Assembler::kJSReturnSequenceLength;
192 if (!masm_->ImmediateFitsAddrMode1Instruction(sp_delta)) {
193 // Additional mov instruction generated.
194 return_sequence_length++;
195 }
196 masm_->BlockConstPoolFor(return_sequence_length);
197
198 CodeGenerator::RecordPositions(masm_, position);
199 __ RecordJSReturn();
200 __ mov(sp, fp);
201 __ ldm(ia_w, sp, fp.bit() | lr.bit());
202 __ add(sp, sp, Operand(sp_delta));
203 __ Jump(lr);
204
205 // Check that the size of the code used for returning matches what is
206 // expected by the debugger. The add instruction above is an addressing
207 // mode 1 instruction where there are restrictions on which immediate values
208 // can be encoded in the instruction and which immediate values requires
209 // use of an additional instruction for moving the immediate to a temporary
210 // register.
211 ASSERT_EQ(return_sequence_length,
212 masm_->InstructionsGeneratedSince(&check_exit_codesize));
213 }
214 }
215
216
217 void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
218 switch (context) {
219 case Expression::kUninitialized:
220 UNREACHABLE();
221
222 case Expression::kEffect:
223 // Nothing to do.
224 break;
225
226 case Expression::kValue:
227 // Move value into place.
228 switch (location_) {
229 case kAccumulator:
230 if (!reg.is(result_register())) __ mov(result_register(), reg);
231 break;
232 case kStack:
233 __ push(reg);
234 break;
235 }
236 break;
237
238 case Expression::kValueTest:
239 case Expression::kTestValue:
240 // Push an extra copy of the value in case it's needed.
241 __ push(reg);
242 // Fall through.
243
244 case Expression::kTest:
245 // We always call the runtime on ARM, so push the value as argument.
246 __ push(reg);
247 DoTest(context);
248 break;
249 }
250 }
251
252
253 void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
254 switch (context) {
255 case Expression::kUninitialized:
256 UNREACHABLE();
257 case Expression::kEffect:
258 // Nothing to do.
259 break;
260 case Expression::kValue:
261 case Expression::kTest:
262 case Expression::kValueTest:
263 case Expression::kTestValue:
264 // On ARM we have to move the value into a register to do anything
265 // with it.
266 Move(result_register(), slot);
267 Apply(context, result_register());
268 break;
269 }
270 }
271
272
273 void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
274 switch (context) {
275 case Expression::kUninitialized:
276 UNREACHABLE();
277 case Expression::kEffect:
278 break;
279 // Nothing to do.
280 case Expression::kValue:
281 case Expression::kTest:
282 case Expression::kValueTest:
283 case Expression::kTestValue:
284 // On ARM we have to move the value into a register to do anything
285 // with it.
286 __ mov(result_register(), Operand(lit->handle()));
287 Apply(context, result_register());
288 break;
289 }
290 }
291
292
293 void FullCodeGenerator::ApplyTOS(Expression::Context context) {
294 switch (context) {
295 case Expression::kUninitialized:
296 UNREACHABLE();
297
298 case Expression::kEffect:
299 __ Drop(1);
300 break;
301
302 case Expression::kValue:
303 switch (location_) {
304 case kAccumulator:
305 __ pop(result_register());
306 break;
307 case kStack:
308 break;
309 }
310 break;
311
312 case Expression::kValueTest:
313 case Expression::kTestValue:
314 // Duplicate the value on the stack in case it's needed.
315 __ ldr(ip, MemOperand(sp));
316 __ push(ip);
317 // Fall through.
318
319 case Expression::kTest:
320 DoTest(context);
321 break;
322 }
323 }
324
325
326 void FullCodeGenerator::DropAndApply(int count,
327 Expression::Context context,
328 Register reg) {
329 ASSERT(count > 0);
330 ASSERT(!reg.is(sp));
331 switch (context) {
332 case Expression::kUninitialized:
333 UNREACHABLE();
334
335 case Expression::kEffect:
336 __ Drop(count);
337 break;
338
339 case Expression::kValue:
340 switch (location_) {
341 case kAccumulator:
342 __ Drop(count);
343 if (!reg.is(result_register())) __ mov(result_register(), reg);
344 break;
345 case kStack:
346 if (count > 1) __ Drop(count - 1);
347 __ str(reg, MemOperand(sp));
348 break;
349 }
350 break;
351
352 case Expression::kTest:
353 if (count > 1) __ Drop(count - 1);
354 __ str(reg, MemOperand(sp));
355 DoTest(context);
356 break;
357
358 case Expression::kValueTest:
359 case Expression::kTestValue:
360 if (count == 1) {
361 __ str(reg, MemOperand(sp));
362 __ push(reg);
363 } else { // count > 1
364 __ Drop(count - 2);
365 __ str(reg, MemOperand(sp, kPointerSize));
366 __ str(reg, MemOperand(sp));
367 }
368 DoTest(context);
369 break;
370 }
371 }
372
373
374 void FullCodeGenerator::Apply(Expression::Context context,
375 Label* materialize_true,
376 Label* materialize_false) {
377 switch (context) {
378 case Expression::kUninitialized:
379
380 case Expression::kEffect:
381 ASSERT_EQ(materialize_true, materialize_false);
382 __ bind(materialize_true);
383 break;
384
385 case Expression::kValue: {
386 Label done;
387 __ bind(materialize_true);
388 __ mov(result_register(), Operand(Factory::true_value()));
389 __ jmp(&done);
390 __ bind(materialize_false);
391 __ mov(result_register(), Operand(Factory::false_value()));
392 __ bind(&done);
393 switch (location_) {
394 case kAccumulator:
395 break;
396 case kStack:
397 __ push(result_register());
398 break;
399 }
400 break;
401 }
402
403 case Expression::kTest:
404 break;
405
406 case Expression::kValueTest:
407 __ bind(materialize_true);
408 __ mov(result_register(), Operand(Factory::true_value()));
409 switch (location_) {
410 case kAccumulator:
411 break;
412 case kStack:
413 __ push(result_register());
414 break;
415 }
416 __ jmp(true_label_);
417 break;
418
419 case Expression::kTestValue:
420 __ bind(materialize_false);
421 __ mov(result_register(), Operand(Factory::false_value()));
422 switch (location_) {
423 case kAccumulator:
424 break;
425 case kStack:
426 __ push(result_register());
427 break;
428 }
429 __ jmp(false_label_);
430 break;
431 }
432 }
433
434
435 void FullCodeGenerator::DoTest(Expression::Context context) {
436 // The value to test is pushed on the stack, and duplicated on the stack
437 // if necessary (for value/test and test/value contexts).
438 ASSERT_NE(NULL, true_label_);
439 ASSERT_NE(NULL, false_label_);
440
441 // Call the runtime to find the boolean value of the source and then
442 // translate it into control flow to the pair of labels.
443 __ CallRuntime(Runtime::kToBool, 1);
444 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
445 __ cmp(r0, ip);
446
447 // Complete based on the context.
448 switch (context) {
449 case Expression::kUninitialized:
450 case Expression::kEffect:
451 case Expression::kValue:
452 UNREACHABLE();
453
454 case Expression::kTest:
455 __ b(eq, true_label_);
456 __ jmp(false_label_);
457 break;
458
459 case Expression::kValueTest: {
460 Label discard;
461 switch (location_) {
462 case kAccumulator:
463 __ b(ne, &discard);
464 __ pop(result_register());
465 __ jmp(true_label_);
466 break;
467 case kStack:
468 __ b(eq, true_label_);
469 break;
470 }
471 __ bind(&discard);
472 __ Drop(1);
473 __ jmp(false_label_);
474 break;
475 }
476
477 case Expression::kTestValue: {
478 Label discard;
479 switch (location_) {
480 case kAccumulator:
481 __ b(eq, &discard);
482 __ pop(result_register());
483 __ jmp(false_label_);
484 break;
485 case kStack:
486 __ b(ne, false_label_);
487 break;
488 }
489 __ bind(&discard);
490 __ Drop(1);
491 __ jmp(true_label_);
492 break;
493 }
494 }
495 }
496
497
498 MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
499 switch (slot->type()) {
500 case Slot::PARAMETER:
501 case Slot::LOCAL:
502 return MemOperand(fp, SlotOffset(slot));
503 case Slot::CONTEXT: {
504 int context_chain_length =
505 function_->scope()->ContextChainLength(slot->var()->scope());
506 __ LoadContext(scratch, context_chain_length);
507 return CodeGenerator::ContextOperand(scratch, slot->index());
508 }
509 case Slot::LOOKUP:
510 UNREACHABLE();
511 }
512 UNREACHABLE();
513 return MemOperand(r0, 0);
514 }
515
516
517 void FullCodeGenerator::Move(Register destination, Slot* source) {
518 // Use destination as scratch.
519 MemOperand slot_operand = EmitSlotSearch(source, destination);
520 __ ldr(destination, slot_operand);
521 }
522
523
524 void FullCodeGenerator::Move(Slot* dst,
525 Register src,
526 Register scratch1,
527 Register scratch2) {
528 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
529 ASSERT(!scratch1.is(src) && !scratch2.is(src));
530 MemOperand location = EmitSlotSearch(dst, scratch1);
531 __ str(src, location);
532 // Emit the write barrier code if the location is in the heap.
533 if (dst->type() == Slot::CONTEXT) {
534 __ mov(scratch2, Operand(Context::SlotOffset(dst->index())));
535 __ RecordWrite(scratch1, scratch2, src);
536 }
537 }
538
539
540 void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
541 Comment cmnt(masm_, "[ Declaration");
542 Variable* var = decl->proxy()->var();
543 ASSERT(var != NULL); // Must have been resolved.
544 Slot* slot = var->slot();
545 Property* prop = var->AsProperty();
546
547 if (slot != NULL) {
548 switch (slot->type()) {
549 case Slot::PARAMETER:
550 case Slot::LOCAL:
551 if (decl->mode() == Variable::CONST) {
552 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
553 __ str(ip, MemOperand(fp, SlotOffset(slot)));
554 } else if (decl->fun() != NULL) {
555 VisitForValue(decl->fun(), kAccumulator);
556 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
557 }
558 break;
559
560 case Slot::CONTEXT:
561 // We bypass the general EmitSlotSearch because we know more about
562 // this specific context.
563
564 // The variable in the decl always resides in the current context.
565 ASSERT_EQ(0, function_->scope()->ContextChainLength(var->scope()));
566 if (FLAG_debug_code) {
567 // Check if we have the correct context pointer.
568 __ ldr(r1,
569 CodeGenerator::ContextOperand(cp, Context::FCONTEXT_INDEX));
570 __ cmp(r1, cp);
571 __ Check(eq, "Unexpected declaration in current context.");
572 }
573 if (decl->mode() == Variable::CONST) {
574 __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
575 __ str(ip, CodeGenerator::ContextOperand(cp, slot->index()));
576 // No write barrier since the_hole_value is in old space.
577 } else if (decl->fun() != NULL) {
578 VisitForValue(decl->fun(), kAccumulator);
579 __ str(result_register(),
580 CodeGenerator::ContextOperand(cp, slot->index()));
581 int offset = Context::SlotOffset(slot->index());
582 __ mov(r2, Operand(offset));
583 // We know that we have written a function, which is not a smi.
584 __ RecordWrite(cp, r2, result_register());
585 }
586 break;
587
588 case Slot::LOOKUP: {
589 __ mov(r2, Operand(var->name()));
590 // Declaration nodes are always introduced in one of two modes.
591 ASSERT(decl->mode() == Variable::VAR ||
592 decl->mode() == Variable::CONST);
593 PropertyAttributes attr =
594 (decl->mode() == Variable::VAR) ? NONE : READ_ONLY;
595 __ mov(r1, Operand(Smi::FromInt(attr)));
596 // Push initial value, if any.
597 // Note: For variables we must not push an initial value (such as
598 // 'undefined') because we may have a (legal) redeclaration and we
599 // must not destroy the current value.
600 if (decl->mode() == Variable::CONST) {
601 __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
602 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
603 } else if (decl->fun() != NULL) {
604 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit());
605 // Push initial value for function declaration.
606 VisitForValue(decl->fun(), kStack);
607 } else {
608 __ mov(r0, Operand(Smi::FromInt(0))); // No initial value!
609 __ stm(db_w, sp, cp.bit() | r2.bit() | r1.bit() | r0.bit());
610 }
611 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
612 break;
613 }
614 }
615
616 } else if (prop != NULL) {
617 if (decl->fun() != NULL || decl->mode() == Variable::CONST) {
618 // We are declaring a function or constant that rewrites to a
619 // property. Use (keyed) IC to set the initial value.
620 VisitForValue(prop->obj(), kStack);
621 VisitForValue(prop->key(), kStack);
622
623 if (decl->fun() != NULL) {
624 VisitForValue(decl->fun(), kAccumulator);
625 } else {
626 __ LoadRoot(result_register(), Heap::kTheHoleValueRootIndex);
627 }
628
629 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
630 __ Call(ic, RelocInfo::CODE_TARGET);
631
632 // Value in r0 is ignored (declarations are statements). Receiver
633 // and key on stack are discarded.
634 __ Drop(2);
635 }
636 }
637 }
638
639
640 void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
641 // Call the runtime to declare the globals.
642 // The context is the first argument.
643 __ mov(r1, Operand(pairs));
644 __ mov(r0, Operand(Smi::FromInt(is_eval_ ? 1 : 0)));
645 __ stm(db_w, sp, cp.bit() | r1.bit() | r0.bit());
646 __ CallRuntime(Runtime::kDeclareGlobals, 3);
647 // Return value is ignored.
648 }
649
650
651 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
652 Comment cmnt(masm_, "[ FunctionLiteral");
653
654 // Build the function boilerplate and instantiate it.
655 Handle<JSFunction> boilerplate =
656 Compiler::BuildBoilerplate(expr, script_, this);
657 if (HasStackOverflow()) return;
658
659 ASSERT(boilerplate->IsBoilerplate());
660
661 // Create a new closure.
662 __ mov(r0, Operand(boilerplate));
663 __ stm(db_w, sp, cp.bit() | r0.bit());
664 __ CallRuntime(Runtime::kNewClosure, 2);
665 Apply(context_, r0);
666 }
667
668
669 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
670 Comment cmnt(masm_, "[ VariableProxy");
671 EmitVariableLoad(expr->var(), context_);
672 }
673
674
675 void FullCodeGenerator::EmitVariableLoad(Variable* var,
676 Expression::Context context) {
677 Expression* rewrite = var->rewrite();
678 if (rewrite == NULL) {
679 ASSERT(var->is_global());
680 Comment cmnt(masm_, "Global variable");
681 // Use inline caching. Variable name is passed in r2 and the global
682 // object on the stack.
683 __ ldr(ip, CodeGenerator::GlobalObject());
684 __ push(ip);
685 __ mov(r2, Operand(var->name()));
686 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
687 __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
688 DropAndApply(1, context, r0);
689 } else if (rewrite->AsSlot() != NULL) {
690 Slot* slot = rewrite->AsSlot();
691 if (FLAG_debug_code) {
692 switch (slot->type()) {
693 case Slot::PARAMETER:
694 case Slot::LOCAL: {
695 Comment cmnt(masm_, "Stack slot");
696 break;
697 }
698 case Slot::CONTEXT: {
699 Comment cmnt(masm_, "Context slot");
700 break;
701 }
702 case Slot::LOOKUP:
703 UNIMPLEMENTED();
704 break;
705 }
706 }
707 Apply(context, slot);
708 } else {
709 Comment cmnt(masm_, "Variable rewritten to property");
710 // A variable has been rewritten into an explicit access to an object
711 // property.
712 Property* property = rewrite->AsProperty();
713 ASSERT_NOT_NULL(property);
714
715 // The only property expressions that can occur are of the form
716 // "slot[literal]".
717
718 // Assert that the object is in a slot.
719 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
720 ASSERT_NOT_NULL(object_var);
721 Slot* object_slot = object_var->slot();
722 ASSERT_NOT_NULL(object_slot);
723
724 // Load the object.
725 Move(r2, object_slot);
726
727 // Assert that the key is a smi.
728 Literal* key_literal = property->key()->AsLiteral();
729 ASSERT_NOT_NULL(key_literal);
730 ASSERT(key_literal->handle()->IsSmi());
731
732 // Load the key.
733 __ mov(r1, Operand(key_literal->handle()));
734
735 // Push both as arguments to ic.
736 __ stm(db_w, sp, r2.bit() | r1.bit());
737
738 // Do a keyed property load.
739 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
740 __ Call(ic, RelocInfo::CODE_TARGET);
741
742 // Drop key and object left on the stack by IC, and push the result.
743 DropAndApply(2, context, r0);
744 }
745 }
746
747
748 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
749 Comment cmnt(masm_, "[ RegExpLiteral");
750 Label done;
751 // Registers will be used as follows:
752 // r4 = JS function, literals array
753 // r3 = literal index
754 // r2 = RegExp pattern
755 // r1 = RegExp flags
756 // r0 = temp + return value (RegExp literal)
757 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
758 __ ldr(r4, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
759 int literal_offset =
760 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
761 __ ldr(r0, FieldMemOperand(r4, literal_offset));
762 __ LoadRoot(ip, Heap::kUndefinedValueRootIndex);
763 __ cmp(r0, ip);
764 __ b(ne, &done);
765 __ mov(r3, Operand(Smi::FromInt(expr->literal_index())));
766 __ mov(r2, Operand(expr->pattern()));
767 __ mov(r1, Operand(expr->flags()));
768 __ stm(db_w, sp, r4.bit() | r3.bit() | r2.bit() | r1.bit());
769 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
770 __ bind(&done);
771 Apply(context_, r0);
772 }
773
774
775 void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
776 Comment cmnt(masm_, "[ ObjectLiteral");
777 __ ldr(r2, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
778 __ ldr(r2, FieldMemOperand(r2, JSFunction::kLiteralsOffset));
779 __ mov(r1, Operand(Smi::FromInt(expr->literal_index())));
780 __ mov(r0, Operand(expr->constant_properties()));
781 __ stm(db_w, sp, r2.bit() | r1.bit() | r0.bit());
782 if (expr->depth() > 1) {
783 __ CallRuntime(Runtime::kCreateObjectLiteral, 3);
784 } else {
785 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 3);
786 }
787
788 // If result_saved is true the result is on top of the stack. If
789 // result_saved is false the result is in r0.
790 bool result_saved = false;
791
792 for (int i = 0; i < expr->properties()->length(); i++) {
793 ObjectLiteral::Property* property = expr->properties()->at(i);
794 if (property->IsCompileTimeValue()) continue;
795
796 Literal* key = property->key();
797 Expression* value = property->value();
798 if (!result_saved) {
799 __ push(r0); // Save result on stack
800 result_saved = true;
801 }
802 switch (property->kind()) {
803 case ObjectLiteral::Property::CONSTANT:
804 UNREACHABLE();
805 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
806 ASSERT(!CompileTimeValue::IsCompileTimeValue(property->value()));
807 // Fall through.
808 case ObjectLiteral::Property::COMPUTED:
809 if (key->handle()->IsSymbol()) {
810 VisitForValue(value, kAccumulator);
811 __ mov(r2, Operand(key->handle()));
812 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
813 __ Call(ic, RelocInfo::CODE_TARGET);
814 // StoreIC leaves the receiver on the stack.
815 break;
816 }
817 // Fall through.
818 case ObjectLiteral::Property::PROTOTYPE:
819 // Duplicate receiver on stack.
820 __ ldr(r0, MemOperand(sp));
821 __ push(r0);
822 VisitForValue(key, kStack);
823 VisitForValue(value, kStack);
824 __ CallRuntime(Runtime::kSetProperty, 3);
825 break;
826 case ObjectLiteral::Property::GETTER:
827 case ObjectLiteral::Property::SETTER:
828 // Duplicate receiver on stack.
829 __ ldr(r0, MemOperand(sp));
830 __ push(r0);
831 VisitForValue(key, kStack);
832 __ mov(r1, Operand(property->kind() == ObjectLiteral::Property::SETTER ?
833 Smi::FromInt(1) :
834 Smi::FromInt(0)));
835 __ push(r1);
836 VisitForValue(value, kStack);
837 __ CallRuntime(Runtime::kDefineAccessor, 4);
838 break;
839 }
840 }
841
842 if (result_saved) {
843 ApplyTOS(context_);
844 } else {
845 Apply(context_, r0);
846 }
847 }
848
849
850 void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
851 Comment cmnt(masm_, "[ ArrayLiteral");
852 __ ldr(r3, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
853 __ ldr(r3, FieldMemOperand(r3, JSFunction::kLiteralsOffset));
854 __ mov(r2, Operand(Smi::FromInt(expr->literal_index())));
855 __ mov(r1, Operand(expr->constant_elements()));
856 __ stm(db_w, sp, r3.bit() | r2.bit() | r1.bit());
857 if (expr->depth() > 1) {
858 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
859 } else {
860 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
861 }
862
863 bool result_saved = false; // Is the result saved to the stack?
864
865 // Emit code to evaluate all the non-constant subexpressions and to store
866 // them into the newly cloned array.
867 ZoneList<Expression*>* subexprs = expr->values();
868 for (int i = 0, len = subexprs->length(); i < len; i++) {
869 Expression* subexpr = subexprs->at(i);
870 // If the subexpression is a literal or a simple materialized literal it
871 // is already set in the cloned array.
872 if (subexpr->AsLiteral() != NULL ||
873 CompileTimeValue::IsCompileTimeValue(subexpr)) {
874 continue;
875 }
876
877 if (!result_saved) {
878 __ push(r0);
879 result_saved = true;
880 }
881 VisitForValue(subexpr, kAccumulator);
882
883 // Store the subexpression value in the array's elements.
884 __ ldr(r1, MemOperand(sp)); // Copy of array literal.
885 __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
886 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
887 __ str(result_register(), FieldMemOperand(r1, offset));
888
889 // Update the write barrier for the array store with r0 as the scratch
890 // register.
891 __ mov(r2, Operand(offset));
892 __ RecordWrite(r1, r2, result_register());
893 }
894
895 if (result_saved) {
896 ApplyTOS(context_);
897 } else {
898 Apply(context_, r0);
899 }
900 }
901
902
903 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
904 SetSourcePosition(prop->position());
905 Literal* key = prop->key()->AsLiteral();
906 __ mov(r2, Operand(key->handle()));
907 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
908 __ Call(ic, RelocInfo::CODE_TARGET);
909 }
910
911
912 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
913 SetSourcePosition(prop->position());
914 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
915 __ Call(ic, RelocInfo::CODE_TARGET);
916 }
917
918
919 void FullCodeGenerator::EmitBinaryOp(Token::Value op,
920 Expression::Context context) {
921 __ pop(r1);
922 GenericBinaryOpStub stub(op, NO_OVERWRITE);
923 __ CallStub(&stub);
924 Apply(context, r0);
925 }
926
927
928 void FullCodeGenerator::EmitVariableAssignment(Variable* var,
929 Expression::Context context) {
930 ASSERT(var != NULL);
931 ASSERT(var->is_global() || var->slot() != NULL);
932 if (var->is_global()) {
933 // Assignment to a global variable. Use inline caching for the
934 // assignment. Right-hand-side value is passed in r0, variable name in
935 // r2, and the global object on the stack.
936 __ mov(r2, Operand(var->name()));
937 __ ldr(ip, CodeGenerator::GlobalObject());
938 __ push(ip);
939 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
940 __ Call(ic, RelocInfo::CODE_TARGET);
941 // Overwrite the global object on the stack with the result if needed.
942 DropAndApply(1, context, r0);
943
944 } else if (var->slot() != NULL) {
945 Slot* slot = var->slot();
946 switch (slot->type()) {
947 case Slot::LOCAL:
948 case Slot::PARAMETER:
949 __ str(result_register(), MemOperand(fp, SlotOffset(slot)));
950 break;
951
952 case Slot::CONTEXT: {
953 MemOperand target = EmitSlotSearch(slot, r1);
954 __ str(result_register(), target);
955
956 // RecordWrite may destroy all its register arguments.
957 __ mov(r3, result_register());
958 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
959
960 __ mov(r2, Operand(offset));
961 __ RecordWrite(r1, r2, r3);
962 break;
963 }
964
965 case Slot::LOOKUP:
966 UNREACHABLE();
967 break;
968 }
969 Apply(context, result_register());
970 } else {
971 // Variables rewritten as properties are not treated as variables in
972 // assignments.
973 UNREACHABLE();
974 }
975 }
976
977
978 void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
979 // Assignment to a property, using a named store IC.
980 Property* prop = expr->target()->AsProperty();
981 ASSERT(prop != NULL);
982 ASSERT(prop->key()->AsLiteral() != NULL);
983
984 // If the assignment starts a block of assignments to the same object,
985 // change to slow case to avoid the quadratic behavior of repeatedly
986 // adding fast properties.
987 if (expr->starts_initialization_block()) {
988 __ push(result_register());
989 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is now under value.
990 __ push(ip);
991 __ CallRuntime(Runtime::kToSlowProperties, 1);
992 __ pop(result_register());
993 }
994
995 // Record source code position before IC call.
996 SetSourcePosition(expr->position());
997 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
998 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
999 __ Call(ic, RelocInfo::CODE_TARGET);
1000
1001 // If the assignment ends an initialization block, revert to fast case.
1002 if (expr->ends_initialization_block()) {
1003 __ push(r0); // Result of assignment, saved even if not needed.
1004 __ ldr(ip, MemOperand(sp, kPointerSize)); // Receiver is under value.
1005 __ push(ip);
1006 __ CallRuntime(Runtime::kToFastProperties, 1);
1007 __ pop(r0);
1008 }
1009
1010 DropAndApply(1, context_, r0);
1011 }
1012
1013
1014 void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1015 // Assignment to a property, using a keyed store IC.
1016
1017 // If the assignment starts a block of assignments to the same object,
1018 // change to slow case to avoid the quadratic behavior of repeatedly
1019 // adding fast properties.
1020 if (expr->starts_initialization_block()) {
1021 __ push(result_register());
1022 // Receiver is now under the key and value.
1023 __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
1024 __ push(ip);
1025 __ CallRuntime(Runtime::kToSlowProperties, 1);
1026 __ pop(result_register());
1027 }
1028
1029 // Record source code position before IC call.
1030 SetSourcePosition(expr->position());
1031 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1032 __ Call(ic, RelocInfo::CODE_TARGET);
1033
1034 // If the assignment ends an initialization block, revert to fast case.
1035 if (expr->ends_initialization_block()) {
1036 __ push(r0); // Result of assignment, saved even if not needed.
1037 // Receiver is under the key and value.
1038 __ ldr(ip, MemOperand(sp, 2 * kPointerSize));
1039 __ push(ip);
1040 __ CallRuntime(Runtime::kToFastProperties, 1);
1041 __ pop(r0);
1042 }
1043
1044 // Receiver and key are still on stack.
1045 DropAndApply(2, context_, r0);
1046 }
1047
1048
1049 void FullCodeGenerator::VisitProperty(Property* expr) {
1050 Comment cmnt(masm_, "[ Property");
1051 Expression* key = expr->key();
1052
1053 // Evaluate receiver.
1054 VisitForValue(expr->obj(), kStack);
1055
1056 if (key->IsPropertyName()) {
1057 EmitNamedPropertyLoad(expr);
1058 // Drop receiver left on the stack by IC.
1059 DropAndApply(1, context_, r0);
1060 } else {
1061 VisitForValue(expr->key(), kStack);
1062 EmitKeyedPropertyLoad(expr);
1063 // Drop key and receiver left on the stack by IC.
1064 DropAndApply(2, context_, r0);
1065 }
1066 }
1067
1068 void FullCodeGenerator::EmitCallWithIC(Call* expr,
1069 Handle<Object> ignored,
1070 RelocInfo::Mode mode) {
1071 // Code common for calls using the IC.
1072 ZoneList<Expression*>* args = expr->arguments();
1073 int arg_count = args->length();
1074 for (int i = 0; i < arg_count; i++) {
1075 VisitForValue(args->at(i), kStack);
1076 }
1077 // Record source position for debugger.
1078 SetSourcePosition(expr->position());
1079 // Call the IC initialization code.
1080 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
1081 NOT_IN_LOOP);
1082 __ Call(ic, mode);
1083 // Restore context register.
1084 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1085 // Discard the function left on TOS.
1086 DropAndApply(1, context_, r0);
1087 }
1088
1089
1090 void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1091 // Code common for calls using the call stub.
1092 ZoneList<Expression*>* args = expr->arguments();
1093 int arg_count = args->length();
1094 for (int i = 0; i < arg_count; i++) {
1095 VisitForValue(args->at(i), kStack);
1096 }
1097 // Record source position for debugger.
1098 SetSourcePosition(expr->position());
1099 CallFunctionStub stub(arg_count, NOT_IN_LOOP, RECEIVER_MIGHT_BE_VALUE);
1100 __ CallStub(&stub);
1101 // Restore context register.
1102 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1103 // Discard the function left on TOS.
1104 DropAndApply(1, context_, r0);
1105 }
1106
1107
1108 void FullCodeGenerator::VisitCall(Call* expr) {
1109 Comment cmnt(masm_, "[ Call");
1110 Expression* fun = expr->expression();
1111 Variable* var = fun->AsVariableProxy()->AsVariable();
1112
1113 if (var != NULL && var->is_possibly_eval()) {
1114 // Call to the identifier 'eval'.
1115 UNREACHABLE();
1116 } else if (var != NULL && !var->is_this() && var->is_global()) {
1117 // Call to a global variable.
1118 __ mov(r1, Operand(var->name()));
1119 // Push global object as receiver for the call IC lookup.
1120 __ ldr(r0, CodeGenerator::GlobalObject());
1121 __ stm(db_w, sp, r1.bit() | r0.bit());
1122 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1123 } else if (var != NULL && var->slot() != NULL &&
1124 var->slot()->type() == Slot::LOOKUP) {
1125 // Call to a lookup slot.
1126 UNREACHABLE();
1127 } else if (fun->AsProperty() != NULL) {
1128 // Call to an object property.
1129 Property* prop = fun->AsProperty();
1130 Literal* key = prop->key()->AsLiteral();
1131 if (key != NULL && key->handle()->IsSymbol()) {
1132 // Call to a named property, use call IC.
1133 __ mov(r0, Operand(key->handle()));
1134 __ push(r0);
1135 VisitForValue(prop->obj(), kStack);
1136 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1137 } else {
1138 // Call to a keyed property, use keyed load IC followed by function
1139 // call.
1140 VisitForValue(prop->obj(), kStack);
1141 VisitForValue(prop->key(), kStack);
1142 // Record source code position for IC call.
1143 SetSourcePosition(prop->position());
1144 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1145 __ Call(ic, RelocInfo::CODE_TARGET);
1146 // Load receiver object into r1.
1147 if (prop->is_synthetic()) {
1148 __ ldr(r1, CodeGenerator::GlobalObject());
1149 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1150 } else {
1151 __ ldr(r1, MemOperand(sp, kPointerSize));
1152 }
1153 // Overwrite (object, key) with (function, receiver).
1154 __ str(r0, MemOperand(sp, kPointerSize));
1155 __ str(r1, MemOperand(sp));
1156 EmitCallWithStub(expr);
1157 }
1158 } else {
1159 // Call to some other expression. If the expression is an anonymous
1160 // function literal not called in a loop, mark it as one that should
1161 // also use the fast code generator.
1162 FunctionLiteral* lit = fun->AsFunctionLiteral();
1163 if (lit != NULL &&
1164 lit->name()->Equals(Heap::empty_string()) &&
1165 loop_depth() == 0) {
1166 lit->set_try_fast_codegen(true);
1167 }
1168 VisitForValue(fun, kStack);
1169 // Load global receiver object.
1170 __ ldr(r1, CodeGenerator::GlobalObject());
1171 __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
1172 __ push(r1);
1173 // Emit function call.
1174 EmitCallWithStub(expr);
1175 }
1176 }
1177
1178
1179 void FullCodeGenerator::VisitCallNew(CallNew* expr) {
1180 Comment cmnt(masm_, "[ CallNew");
1181 // According to ECMA-262, section 11.2.2, page 44, the function
1182 // expression in new calls must be evaluated before the
1183 // arguments.
1184 // Push function on the stack.
1185 VisitForValue(expr->expression(), kStack);
1186
1187 // Push global object (receiver).
1188 __ ldr(r0, CodeGenerator::GlobalObject());
1189 __ push(r0);
1190 // Push the arguments ("left-to-right") on the stack.
1191 ZoneList<Expression*>* args = expr->arguments();
1192 int arg_count = args->length();
1193 for (int i = 0; i < arg_count; i++) {
1194 VisitForValue(args->at(i), kStack);
1195 }
1196
1197 // Call the construct call builtin that handles allocation and
1198 // constructor invocation.
1199 SetSourcePosition(expr->position());
1200
1201 // Load function, arg_count into r1 and r0.
1202 __ mov(r0, Operand(arg_count));
1203 // Function is in sp[arg_count + 1].
1204 __ ldr(r1, MemOperand(sp, (arg_count + 1) * kPointerSize));
1205
1206 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1207 __ Call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1208
1209 // Replace function on TOS with result in r0, or pop it.
1210 DropAndApply(1, context_, r0);
1211 }
1212
1213
1214 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
1215 Comment cmnt(masm_, "[ CallRuntime");
1216 ZoneList<Expression*>* args = expr->arguments();
1217
1218 if (expr->is_jsruntime()) {
1219 // Prepare for calling JS runtime function.
1220 __ mov(r1, Operand(expr->name()));
1221 __ ldr(r0, CodeGenerator::GlobalObject());
1222 __ ldr(r0, FieldMemOperand(r0, GlobalObject::kBuiltinsOffset));
1223 __ stm(db_w, sp, r1.bit() | r0.bit());
1224 }
1225
1226 // Push the arguments ("left-to-right").
1227 int arg_count = args->length();
1228 for (int i = 0; i < arg_count; i++) {
1229 VisitForValue(args->at(i), kStack);
1230 }
1231
1232 if (expr->is_jsruntime()) {
1233 // Call the JS runtime function.
1234 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count,
1235 NOT_IN_LOOP);
1236 __ Call(ic, RelocInfo::CODE_TARGET);
1237 // Restore context register.
1238 __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
1239 // Discard the function left on TOS.
1240 DropAndApply(1, context_, r0);
1241 } else {
1242 // Call the C runtime function.
1243 __ CallRuntime(expr->function(), arg_count);
1244 Apply(context_, r0);
1245 }
1246 }
1247
1248
1249 void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
1250 switch (expr->op()) {
1251 case Token::VOID: {
1252 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
1253 VisitForEffect(expr->expression());
1254 switch (context_) {
1255 case Expression::kUninitialized:
1256 UNREACHABLE();
1257 break;
1258 case Expression::kEffect:
1259 break;
1260 case Expression::kValue:
1261 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
1262 switch (location_) {
1263 case kAccumulator:
1264 break;
1265 case kStack:
1266 __ push(result_register());
1267 break;
1268 }
1269 break;
1270 case Expression::kTestValue:
1271 // Value is false so it's needed.
1272 __ LoadRoot(result_register(), Heap::kUndefinedValueRootIndex);
1273 switch (location_) {
1274 case kAccumulator:
1275 break;
1276 case kStack:
1277 __ push(result_register());
1278 break;
1279 }
1280 // Fall through.
1281 case Expression::kTest:
1282 case Expression::kValueTest:
1283 __ jmp(false_label_);
1284 break;
1285 }
1286 break;
1287 }
1288
1289 case Token::NOT: {
1290 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
1291 Label materialize_true, materialize_false, done;
1292 // Initially assume a pure test context. Notice that the labels are
1293 // swapped.
1294 Label* if_true = false_label_;
1295 Label* if_false = true_label_;
1296 switch (context_) {
1297 case Expression::kUninitialized:
1298 UNREACHABLE();
1299 break;
1300 case Expression::kEffect:
1301 if_true = &done;
1302 if_false = &done;
1303 break;
1304 case Expression::kValue:
1305 if_true = &materialize_false;
1306 if_false = &materialize_true;
1307 break;
1308 case Expression::kTest:
1309 break;
1310 case Expression::kValueTest:
1311 if_false = &materialize_true;
1312 break;
1313 case Expression::kTestValue:
1314 if_true = &materialize_false;
1315 break;
1316 }
1317 VisitForControl(expr->expression(), if_true, if_false);
1318 Apply(context_, if_false, if_true); // Labels swapped.
1319 break;
1320 }
1321
1322 case Token::TYPEOF: {
1323 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
1324 VariableProxy* proxy = expr->expression()->AsVariableProxy();
1325 if (proxy != NULL &&
1326 !proxy->var()->is_this() &&
1327 proxy->var()->is_global()) {
1328 Comment cmnt(masm_, "Global variable");
1329 __ ldr(r0, CodeGenerator::GlobalObject());
1330 __ push(r0);
1331 __ mov(r2, Operand(proxy->name()));
1332 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1333 // Use a regular load, not a contextual load, to avoid a reference
1334 // error.
1335 __ Call(ic, RelocInfo::CODE_TARGET);
1336 __ str(r0, MemOperand(sp));
1337 } else if (proxy != NULL &&
1338 proxy->var()->slot() != NULL &&
1339 proxy->var()->slot()->type() == Slot::LOOKUP) {
1340 __ mov(r0, Operand(proxy->name()));
1341 __ stm(db_w, sp, cp.bit() | r0.bit());
1342 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
1343 __ push(r0);
1344 } else {
1345 // This expression cannot throw a reference error at the top level.
1346 VisitForValue(expr->expression(), kStack);
1347 }
1348
1349 __ CallRuntime(Runtime::kTypeof, 1);
1350 Apply(context_, r0);
1351 break;
1352 }
1353
1354 default:
1355 UNREACHABLE();
1356 }
1357 }
1358
1359
1360 void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
1361 Comment cmnt(masm_, "[ CountOperation");
1362
1363 // Expression can only be a property, a global or a (parameter or local)
1364 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1365 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1366 LhsKind assign_type = VARIABLE;
1367 Property* prop = expr->expression()->AsProperty();
1368 // In case of a property we use the uninitialized expression context
1369 // of the key to detect a named property.
1370 if (prop != NULL) {
1371 assign_type =
1372 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1373 }
1374
1375 // Evaluate expression and get value.
1376 if (assign_type == VARIABLE) {
1377 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
1378 Location saved_location = location_;
1379 location_ = kStack;
1380 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
1381 Expression::kValue);
1382 location_ = saved_location;
1383 } else {
1384 // Reserve space for result of postfix operation.
1385 if (expr->is_postfix() && context_ != Expression::kEffect) {
1386 __ mov(ip, Operand(Smi::FromInt(0)));
1387 __ push(ip);
1388 }
1389 VisitForValue(prop->obj(), kStack);
1390 if (assign_type == NAMED_PROPERTY) {
1391 EmitNamedPropertyLoad(prop);
1392 } else {
1393 VisitForValue(prop->key(), kStack);
1394 EmitKeyedPropertyLoad(prop);
1395 }
1396 __ push(r0);
1397 }
1398
1399 // Convert to number.
1400 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
1401
1402 // Save result for postfix expressions.
1403 if (expr->is_postfix()) {
1404 switch (context_) {
1405 case Expression::kUninitialized:
1406 UNREACHABLE();
1407 case Expression::kEffect:
1408 // Do not save result.
1409 break;
1410 case Expression::kValue:
1411 case Expression::kTest:
1412 case Expression::kValueTest:
1413 case Expression::kTestValue:
1414 // Save the result on the stack. If we have a named or keyed property
1415 // we store the result under the receiver that is currently on top
1416 // of the stack.
1417 switch (assign_type) {
1418 case VARIABLE:
1419 __ push(r0);
1420 break;
1421 case NAMED_PROPERTY:
1422 __ str(r0, MemOperand(sp, kPointerSize));
1423 break;
1424 case KEYED_PROPERTY:
1425 __ str(r0, MemOperand(sp, 2 * kPointerSize));
1426 break;
1427 }
1428 break;
1429 }
1430 }
1431
1432 // Call stub for +1/-1.
1433 __ mov(r1, Operand(expr->op() == Token::INC
1434 ? Smi::FromInt(1)
1435 : Smi::FromInt(-1)));
1436 GenericBinaryOpStub stub(Token::ADD, NO_OVERWRITE);
1437 __ CallStub(&stub);
1438
1439 // Store the value returned in r0.
1440 switch (assign_type) {
1441 case VARIABLE:
1442 if (expr->is_postfix()) {
1443 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1444 Expression::kEffect);
1445 // For all contexts except kEffect: We have the result on
1446 // top of the stack.
1447 if (context_ != Expression::kEffect) {
1448 ApplyTOS(context_);
1449 }
1450 } else {
1451 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
1452 context_);
1453 }
1454 break;
1455 case NAMED_PROPERTY: {
1456 __ mov(r2, Operand(prop->key()->AsLiteral()->handle()));
1457 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1458 __ Call(ic, RelocInfo::CODE_TARGET);
1459 if (expr->is_postfix()) {
1460 __ Drop(1); // Result is on the stack under the receiver.
1461 if (context_ != Expression::kEffect) {
1462 ApplyTOS(context_);
1463 }
1464 } else {
1465 DropAndApply(1, context_, r0);
1466 }
1467 break;
1468 }
1469 case KEYED_PROPERTY: {
1470 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1471 __ Call(ic, RelocInfo::CODE_TARGET);
1472 if (expr->is_postfix()) {
1473 __ Drop(2); // Result is on the stack under the key and the receiver.
1474 if (context_ != Expression::kEffect) {
1475 ApplyTOS(context_);
1476 }
1477 } else {
1478 DropAndApply(2, context_, r0);
1479 }
1480 break;
1481 }
1482 }
1483 }
1484
1485
1486 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
1487 Comment cmnt(masm_, "[ BinaryOperation");
1488 switch (expr->op()) {
1489 case Token::COMMA:
1490 VisitForEffect(expr->left());
1491 Visit(expr->right());
1492 break;
1493
1494 case Token::OR:
1495 case Token::AND:
1496 EmitLogicalOperation(expr);
1497 break;
1498
1499 case Token::ADD:
1500 case Token::SUB:
1501 case Token::DIV:
1502 case Token::MOD:
1503 case Token::MUL:
1504 case Token::BIT_OR:
1505 case Token::BIT_AND:
1506 case Token::BIT_XOR:
1507 case Token::SHL:
1508 case Token::SHR:
1509 case Token::SAR:
1510 VisitForValue(expr->left(), kStack);
1511 VisitForValue(expr->right(), kAccumulator);
1512 EmitBinaryOp(expr->op(), context_);
1513 break;
1514
1515 default:
1516 UNREACHABLE();
1517 }
1518 }
1519
1520
1521 void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
1522 Comment cmnt(masm_, "[ CompareOperation");
1523
1524 // Always perform the comparison for its control flow. Pack the result
1525 // into the expression's context after the comparison is performed.
1526 Label materialize_true, materialize_false, done;
1527 // Initially assume we are in a test context.
1528 Label* if_true = true_label_;
1529 Label* if_false = false_label_;
1530 switch (context_) {
1531 case Expression::kUninitialized:
1532 UNREACHABLE();
1533 break;
1534 case Expression::kEffect:
1535 if_true = &done;
1536 if_false = &done;
1537 break;
1538 case Expression::kValue:
1539 if_true = &materialize_true;
1540 if_false = &materialize_false;
1541 break;
1542 case Expression::kTest:
1543 break;
1544 case Expression::kValueTest:
1545 if_true = &materialize_true;
1546 break;
1547 case Expression::kTestValue:
1548 if_false = &materialize_false;
1549 break;
1550 }
1551
1552 VisitForValue(expr->left(), kStack);
1553 switch (expr->op()) {
1554 case Token::IN:
1555 VisitForValue(expr->right(), kStack);
1556 __ InvokeBuiltin(Builtins::IN, CALL_JS);
1557 __ LoadRoot(ip, Heap::kTrueValueRootIndex);
1558 __ cmp(r0, ip);
1559 __ b(eq, if_true);
1560 __ jmp(if_false);
1561 break;
1562
1563 case Token::INSTANCEOF: {
1564 VisitForValue(expr->right(), kStack);
1565 InstanceofStub stub;
1566 __ CallStub(&stub);
1567 __ tst(r0, r0);
1568 __ b(eq, if_true); // The stub returns 0 for true.
1569 __ jmp(if_false);
1570 break;
1571 }
1572
1573 default: {
1574 VisitForValue(expr->right(), kAccumulator);
1575 Condition cc = eq;
1576 bool strict = false;
1577 switch (expr->op()) {
1578 case Token::EQ_STRICT:
1579 strict = true;
1580 // Fall through
1581 case Token::EQ:
1582 cc = eq;
1583 __ pop(r1);
1584 break;
1585 case Token::LT:
1586 cc = lt;
1587 __ pop(r1);
1588 break;
1589 case Token::GT:
1590 // Reverse left and right sides to obtain ECMA-262 conversion order.
1591 cc = lt;
1592 __ mov(r1, result_register());
1593 __ pop(r0);
1594 break;
1595 case Token::LTE:
1596 // Reverse left and right sides to obtain ECMA-262 conversion order.
1597 cc = ge;
1598 __ mov(r1, result_register());
1599 __ pop(r0);
1600 break;
1601 case Token::GTE:
1602 cc = ge;
1603 __ pop(r1);
1604 break;
1605 case Token::IN:
1606 case Token::INSTANCEOF:
1607 default:
1608 UNREACHABLE();
1609 }
1610
1611 // The comparison stub expects the smi vs. smi case to be handled
1612 // before it is called.
1613 Label slow_case;
1614 __ orr(r2, r0, Operand(r1));
1615 __ tst(r2, Operand(kSmiTagMask));
1616 __ b(ne, &slow_case);
1617 __ cmp(r1, r0);
1618 __ b(cc, if_true);
1619 __ jmp(if_false);
1620
1621 __ bind(&slow_case);
1622 CompareStub stub(cc, strict);
1623 __ CallStub(&stub);
1624 __ cmp(r0, Operand(0));
1625 __ b(cc, if_true);
1626 __ jmp(if_false);
1627 }
1628 }
1629
1630 // Convert the result of the comparison into one expected for this
1631 // expression's context.
1632 Apply(context_, if_true, if_false);
1633 }
1634
1635
1636 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
1637 __ ldr(r0, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
1638 Apply(context_, r0);
1639 }
1640
1641
1642 Register FullCodeGenerator::result_register() { return r0; }
1643
1644
1645 Register FullCodeGenerator::context_register() { return cp; }
1646
1647
1648 void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
1649 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
1650 __ str(value, MemOperand(fp, frame_offset));
1651 }
1652
1653
1654 void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
1655 __ ldr(dst, CodeGenerator::ContextOperand(cp, context_index));
1656 }
1657
1658
1659 // ----------------------------------------------------------------------------
1660 // Non-local control flow support.
1661
1662 void FullCodeGenerator::EnterFinallyBlock() {
1663 ASSERT(!result_register().is(r1));
1664 // Store result register while executing finally block.
1665 __ push(result_register());
1666 // Cook return address in link register to stack (smi encoded Code* delta)
1667 __ sub(r1, lr, Operand(masm_->CodeObject()));
1668 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
1669 ASSERT_EQ(0, kSmiTag);
1670 __ add(r1, r1, Operand(r1)); // Convert to smi.
1671 __ push(r1);
1672 }
1673
1674
1675 void FullCodeGenerator::ExitFinallyBlock() {
1676 ASSERT(!result_register().is(r1));
1677 // Restore result register from stack.
1678 __ pop(r1);
1679 // Uncook return address and return.
1680 __ pop(result_register());
1681 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
1682 __ mov(r1, Operand(r1, ASR, 1)); // Un-smi-tag value.
1683 __ add(pc, r1, Operand(masm_->CodeObject()));
1684 }
1685
1686
1687 #undef __
1688
1689 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/SConscript ('k') | src/arm/full-codegen-arm.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698