blob: cb36904ee380315a046cf8b179c25e58347636c6 [file] [log] [blame]
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001// Copyright 2010 the V8 project authors. All rights reserved.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +000030#if defined(V8_TARGET_ARCH_IA32)
31
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000032#include "codegen-inl.h"
33#include "compiler.h"
34#include "debug.h"
35#include "full-codegen.h"
36#include "parser.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000037#include "scopes.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038
39namespace v8 {
40namespace internal {
41
42#define __ ACCESS_MASM(masm_)
43
44// Generate code for a JS function. On entry to the function the receiver
45// and arguments have been pushed on the stack left to right, with the
46// return address on top of them. The actual argument count matches the
47// formal parameter count expected by the function.
48//
49// The live registers are:
50// o edi: the JS function object being called (ie, ourselves)
51// o esi: our context
52// o ebp: our caller's frame pointer
53// o esp: stack pointer (pointing to return address)
54//
55// The function builds a JS frame. Please see JavaScriptFrameConstants in
56// frames-ia32.h for its layout.
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000057void FullCodeGenerator::Generate(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +000058 ASSERT(info_ == NULL);
59 info_ = info;
60 SetFunctionPosition(function());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000061 Comment cmnt(masm_, "[ function compiled by full code generator");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000062
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000063 __ push(ebp); // Caller's frame pointer.
64 __ mov(ebp, esp);
65 __ push(esi); // Callee's context.
66 __ push(edi); // Callee's JS Function.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000067
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000068 { Comment cmnt(masm_, "[ Allocate locals");
69 int locals_count = scope()->num_stack_slots();
70 if (locals_count == 1) {
71 __ push(Immediate(Factory::undefined_value()));
72 } else if (locals_count > 1) {
73 __ mov(eax, Immediate(Factory::undefined_value()));
74 for (int i = 0; i < locals_count; i++) {
75 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000076 }
77 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000078 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000079
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000080 bool function_in_register = true;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000081
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000082 // Possibly allocate a local context.
83 int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
84 if (heap_slots > 0) {
85 Comment cmnt(masm_, "[ Allocate local context");
86 // Argument to NewContext is the function, which is still in edi.
87 __ push(edi);
88 if (heap_slots <= FastNewContextStub::kMaximumSlots) {
89 FastNewContextStub stub(heap_slots);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000090 __ CallStub(&stub);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000091 } else {
92 __ CallRuntime(Runtime::kNewContext, 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000093 }
ager@chromium.orgea4f62e2010-08-16 16:28:43 +000094 function_in_register = false;
95 // Context is returned in both eax and esi. It replaces the context
96 // passed to us. It's saved in the stack and kept live in esi.
97 __ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
98
99 // Copy parameters into context if necessary.
100 int num_parameters = scope()->num_parameters();
101 for (int i = 0; i < num_parameters; i++) {
102 Slot* slot = scope()->parameter(i)->slot();
103 if (slot != NULL && slot->type() == Slot::CONTEXT) {
104 int parameter_offset = StandardFrameConstants::kCallerSPOffset +
105 (num_parameters - 1 - i) * kPointerSize;
106 // Load parameter from stack.
107 __ mov(eax, Operand(ebp, parameter_offset));
108 // Store it in the context.
109 int context_offset = Context::SlotOffset(slot->index());
110 __ mov(Operand(esi, context_offset), eax);
111 // Update the write barrier. This clobbers all involved
112 // registers, so we have use a third register to avoid
113 // clobbering esi.
114 __ mov(ecx, esi);
115 __ RecordWrite(ecx, context_offset, eax, ebx);
116 }
117 }
118 }
119
120 Variable* arguments = scope()->arguments()->AsVariable();
121 if (arguments != NULL) {
122 // Function uses arguments object.
123 Comment cmnt(masm_, "[ Allocate arguments object");
124 if (function_in_register) {
125 __ push(edi);
126 } else {
127 __ push(Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
128 }
129 // Receiver is just before the parameters on the caller's stack.
130 int offset = scope()->num_parameters() * kPointerSize;
131 __ lea(edx,
132 Operand(ebp, StandardFrameConstants::kCallerSPOffset + offset));
133 __ push(edx);
134 __ push(Immediate(Smi::FromInt(scope()->num_parameters())));
135 // Arguments to ArgumentsAccessStub:
136 // function, receiver address, parameter count.
137 // The stub will rewrite receiver and parameter count if the previous
138 // stack frame was an arguments adapter frame.
139 ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
140 __ CallStub(&stub);
141 __ mov(ecx, eax); // Duplicate result.
142 Move(arguments->slot(), eax, ebx, edx);
143 Slot* dot_arguments_slot =
144 scope()->arguments_shadow()->AsVariable()->slot();
145 Move(dot_arguments_slot, ecx, ebx, edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000146 }
147
148 { Comment cmnt(masm_, "[ Declarations");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000149 // For named function expressions, declare the function name as a
150 // constant.
151 if (scope()->is_function_scope() && scope()->function() != NULL) {
152 EmitDeclaration(scope()->function(), Variable::CONST, NULL);
153 }
154 // Visit all the explicit declarations unless there is an illegal
155 // redeclaration.
156 if (scope()->HasIllegalRedeclaration()) {
157 scope()->VisitIllegalRedeclaration(this);
158 } else {
159 VisitDeclarations(scope()->declarations());
160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000161 }
162
163 { Comment cmnt(masm_, "[ Stack check");
164 Label ok;
165 ExternalReference stack_limit =
166 ExternalReference::address_of_stack_limit();
167 __ cmp(esp, Operand::StaticVariable(stack_limit));
168 __ j(above_equal, &ok, taken);
169 StackCheckStub stub;
170 __ CallStub(&stub);
171 __ bind(&ok);
172 }
173
174 if (FLAG_trace) {
175 __ CallRuntime(Runtime::kTraceEnter, 0);
176 }
177
178 { Comment cmnt(masm_, "[ Body");
179 ASSERT(loop_depth() == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +0000180 VisitStatements(function()->body());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000181 ASSERT(loop_depth() == 0);
182 }
183
184 { Comment cmnt(masm_, "[ return <undefined>;");
185 // Emit a 'return undefined' in case control fell off the end of the body.
186 __ mov(eax, Factory::undefined_value());
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000187 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000188 }
189}
190
191
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000192void FullCodeGenerator::EmitReturnSequence() {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000193 Comment cmnt(masm_, "[ Return sequence");
194 if (return_label_.is_bound()) {
195 __ jmp(&return_label_);
196 } else {
197 // Common return label
198 __ bind(&return_label_);
199 if (FLAG_trace) {
200 __ push(eax);
201 __ CallRuntime(Runtime::kTraceExit, 1);
202 }
203#ifdef DEBUG
204 // Add a label for checking the size of the code used for returning.
205 Label check_exit_codesize;
206 masm_->bind(&check_exit_codesize);
207#endif
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000208 CodeGenerator::RecordPositions(masm_, function()->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000209 __ RecordJSReturn();
210 // Do not use the leave instruction here because it is too short to
211 // patch with the code required by the debugger.
212 __ mov(esp, ebp);
213 __ pop(ebp);
ager@chromium.org5c838252010-02-19 08:53:10 +0000214 __ ret((scope()->num_parameters() + 1) * kPointerSize);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000215#ifdef ENABLE_DEBUGGER_SUPPORT
216 // Check that the size of the code used for returning matches what is
217 // expected by the debugger.
218 ASSERT_EQ(Assembler::kJSReturnSequenceLength,
219 masm_->SizeOfCodeGeneratedSince(&check_exit_codesize));
220#endif
221 }
222}
223
224
225void FullCodeGenerator::Apply(Expression::Context context, Register reg) {
226 switch (context) {
227 case Expression::kUninitialized:
228 UNREACHABLE();
229
230 case Expression::kEffect:
231 // Nothing to do.
232 break;
233
234 case Expression::kValue:
235 // Move value into place.
236 switch (location_) {
237 case kAccumulator:
238 if (!reg.is(result_register())) __ mov(result_register(), reg);
239 break;
240 case kStack:
241 __ push(reg);
242 break;
243 }
244 break;
245
246 case Expression::kTest:
247 // For simplicity we always test the accumulator register.
248 if (!reg.is(result_register())) __ mov(result_register(), reg);
249 DoTest(context);
250 break;
251
252 case Expression::kValueTest:
253 case Expression::kTestValue:
254 if (!reg.is(result_register())) __ mov(result_register(), reg);
255 switch (location_) {
256 case kAccumulator:
257 break;
258 case kStack:
259 __ push(result_register());
260 break;
261 }
262 DoTest(context);
263 break;
264 }
265}
266
267
268void FullCodeGenerator::Apply(Expression::Context context, Slot* slot) {
269 switch (context) {
270 case Expression::kUninitialized:
271 UNREACHABLE();
272 case Expression::kEffect:
273 // Nothing to do.
274 break;
275 case Expression::kValue: {
276 MemOperand slot_operand = EmitSlotSearch(slot, result_register());
277 switch (location_) {
278 case kAccumulator:
279 __ mov(result_register(), slot_operand);
280 break;
281 case kStack:
282 // Memory operands can be pushed directly.
283 __ push(slot_operand);
284 break;
285 }
286 break;
287 }
288
289 case Expression::kTest:
290 // For simplicity we always test the accumulator register.
291 Move(result_register(), slot);
292 DoTest(context);
293 break;
294
295 case Expression::kValueTest:
296 case Expression::kTestValue:
297 Move(result_register(), slot);
298 switch (location_) {
299 case kAccumulator:
300 break;
301 case kStack:
302 __ push(result_register());
303 break;
304 }
305 DoTest(context);
306 break;
307 }
308}
309
310
311void FullCodeGenerator::Apply(Expression::Context context, Literal* lit) {
312 switch (context) {
313 case Expression::kUninitialized:
314 UNREACHABLE();
315 case Expression::kEffect:
316 // Nothing to do.
317 break;
318 case Expression::kValue:
319 switch (location_) {
320 case kAccumulator:
321 __ mov(result_register(), lit->handle());
322 break;
323 case kStack:
324 // Immediates can be pushed directly.
325 __ push(Immediate(lit->handle()));
326 break;
327 }
328 break;
329
330 case Expression::kTest:
331 // For simplicity we always test the accumulator register.
332 __ mov(result_register(), lit->handle());
333 DoTest(context);
334 break;
335
336 case Expression::kValueTest:
337 case Expression::kTestValue:
338 __ mov(result_register(), lit->handle());
339 switch (location_) {
340 case kAccumulator:
341 break;
342 case kStack:
343 __ push(result_register());
344 break;
345 }
346 DoTest(context);
347 break;
348 }
349}
350
351
352void FullCodeGenerator::ApplyTOS(Expression::Context context) {
353 switch (context) {
354 case Expression::kUninitialized:
355 UNREACHABLE();
356
357 case Expression::kEffect:
358 __ Drop(1);
359 break;
360
361 case Expression::kValue:
362 switch (location_) {
363 case kAccumulator:
364 __ pop(result_register());
365 break;
366 case kStack:
367 break;
368 }
369 break;
370
371 case Expression::kTest:
372 // For simplicity we always test the accumulator register.
373 __ pop(result_register());
374 DoTest(context);
375 break;
376
377 case Expression::kValueTest:
378 case Expression::kTestValue:
379 switch (location_) {
380 case kAccumulator:
381 __ pop(result_register());
382 break;
383 case kStack:
384 __ mov(result_register(), Operand(esp, 0));
385 break;
386 }
387 DoTest(context);
388 break;
389 }
390}
391
392
393void FullCodeGenerator::DropAndApply(int count,
394 Expression::Context context,
395 Register reg) {
396 ASSERT(count > 0);
397 ASSERT(!reg.is(esp));
398 switch (context) {
399 case Expression::kUninitialized:
400 UNREACHABLE();
401
402 case Expression::kEffect:
403 __ Drop(count);
404 break;
405
406 case Expression::kValue:
407 switch (location_) {
408 case kAccumulator:
409 __ Drop(count);
410 if (!reg.is(result_register())) __ mov(result_register(), reg);
411 break;
412 case kStack:
413 if (count > 1) __ Drop(count - 1);
414 __ mov(Operand(esp, 0), reg);
415 break;
416 }
417 break;
418
419 case Expression::kTest:
420 // For simplicity we always test the accumulator register.
421 __ Drop(count);
422 if (!reg.is(result_register())) __ mov(result_register(), reg);
423 DoTest(context);
424 break;
425
426 case Expression::kValueTest:
427 case Expression::kTestValue:
428 switch (location_) {
429 case kAccumulator:
430 __ Drop(count);
431 if (!reg.is(result_register())) __ mov(result_register(), reg);
432 break;
433 case kStack:
434 if (count > 1) __ Drop(count - 1);
435 __ mov(result_register(), reg);
436 __ mov(Operand(esp, 0), result_register());
437 break;
438 }
439 DoTest(context);
440 break;
441 }
442}
443
444
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000445void FullCodeGenerator::PrepareTest(Label* materialize_true,
446 Label* materialize_false,
447 Label** if_true,
448 Label** if_false) {
449 switch (context_) {
450 case Expression::kUninitialized:
451 UNREACHABLE();
452 break;
453 case Expression::kEffect:
454 // In an effect context, the true and the false case branch to the
455 // same label.
456 *if_true = *if_false = materialize_true;
457 break;
458 case Expression::kValue:
459 *if_true = materialize_true;
460 *if_false = materialize_false;
461 break;
462 case Expression::kTest:
463 *if_true = true_label_;
464 *if_false = false_label_;
465 break;
466 case Expression::kValueTest:
467 *if_true = materialize_true;
468 *if_false = false_label_;
469 break;
470 case Expression::kTestValue:
471 *if_true = true_label_;
472 *if_false = materialize_false;
473 break;
474 }
475}
476
477
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000478void FullCodeGenerator::Apply(Expression::Context context,
479 Label* materialize_true,
480 Label* materialize_false) {
481 switch (context) {
482 case Expression::kUninitialized:
483
484 case Expression::kEffect:
485 ASSERT_EQ(materialize_true, materialize_false);
486 __ bind(materialize_true);
487 break;
488
489 case Expression::kValue: {
490 Label done;
491 switch (location_) {
492 case kAccumulator:
493 __ bind(materialize_true);
494 __ mov(result_register(), Factory::true_value());
495 __ jmp(&done);
496 __ bind(materialize_false);
497 __ mov(result_register(), Factory::false_value());
498 break;
499 case kStack:
500 __ bind(materialize_true);
501 __ push(Immediate(Factory::true_value()));
502 __ jmp(&done);
503 __ bind(materialize_false);
504 __ push(Immediate(Factory::false_value()));
505 break;
506 }
507 __ bind(&done);
508 break;
509 }
510
511 case Expression::kTest:
512 break;
513
514 case Expression::kValueTest:
515 __ bind(materialize_true);
516 switch (location_) {
517 case kAccumulator:
518 __ mov(result_register(), Factory::true_value());
519 break;
520 case kStack:
521 __ push(Immediate(Factory::true_value()));
522 break;
523 }
524 __ jmp(true_label_);
525 break;
526
527 case Expression::kTestValue:
528 __ bind(materialize_false);
529 switch (location_) {
530 case kAccumulator:
531 __ mov(result_register(), Factory::false_value());
532 break;
533 case kStack:
534 __ push(Immediate(Factory::false_value()));
535 break;
536 }
537 __ jmp(false_label_);
538 break;
539 }
540}
541
542
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000543// Convert constant control flow (true or false) to the result expected for
544// a given expression context.
545void FullCodeGenerator::Apply(Expression::Context context, bool flag) {
546 switch (context) {
547 case Expression::kUninitialized:
548 UNREACHABLE();
549 break;
550 case Expression::kEffect:
551 break;
552 case Expression::kValue: {
553 Handle<Object> value =
554 flag ? Factory::true_value() : Factory::false_value();
555 switch (location_) {
556 case kAccumulator:
557 __ mov(result_register(), value);
558 break;
559 case kStack:
560 __ push(Immediate(value));
561 break;
562 }
563 break;
564 }
565 case Expression::kTest:
566 __ jmp(flag ? true_label_ : false_label_);
567 break;
568 case Expression::kTestValue:
569 switch (location_) {
570 case kAccumulator:
571 // If value is false it's needed.
572 if (!flag) __ mov(result_register(), Factory::false_value());
573 break;
574 case kStack:
575 // If value is false it's needed.
576 if (!flag) __ push(Immediate(Factory::false_value()));
577 break;
578 }
579 __ jmp(flag ? true_label_ : false_label_);
580 break;
581 case Expression::kValueTest:
582 switch (location_) {
583 case kAccumulator:
584 // If value is true it's needed.
585 if (flag) __ mov(result_register(), Factory::true_value());
586 break;
587 case kStack:
588 // If value is true it's needed.
589 if (flag) __ push(Immediate(Factory::true_value()));
590 break;
591 }
592 __ jmp(flag ? true_label_ : false_label_);
593 break;
594 }
595}
596
597
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000598void FullCodeGenerator::DoTest(Expression::Context context) {
599 // The value to test is in the accumulator. If the value might be needed
600 // on the stack (value/test and test/value contexts with a stack location
601 // desired), then the value is already duplicated on the stack.
602 ASSERT_NE(NULL, true_label_);
603 ASSERT_NE(NULL, false_label_);
604
605 // In value/test and test/value expression contexts with stack as the
606 // desired location, there is already an extra value on the stack. Use a
607 // label to discard it if unneeded.
608 Label discard;
609 Label* if_true = true_label_;
610 Label* if_false = false_label_;
611 switch (context) {
612 case Expression::kUninitialized:
613 case Expression::kEffect:
614 case Expression::kValue:
615 UNREACHABLE();
616 case Expression::kTest:
617 break;
618 case Expression::kValueTest:
619 switch (location_) {
620 case kAccumulator:
621 break;
622 case kStack:
623 if_false = &discard;
624 break;
625 }
626 break;
627 case Expression::kTestValue:
628 switch (location_) {
629 case kAccumulator:
630 break;
631 case kStack:
632 if_true = &discard;
633 break;
634 }
635 break;
636 }
637
638 // Emit the inlined tests assumed by the stub.
639 __ cmp(result_register(), Factory::undefined_value());
640 __ j(equal, if_false);
641 __ cmp(result_register(), Factory::true_value());
642 __ j(equal, if_true);
643 __ cmp(result_register(), Factory::false_value());
644 __ j(equal, if_false);
645 ASSERT_EQ(0, kSmiTag);
646 __ test(result_register(), Operand(result_register()));
647 __ j(zero, if_false);
648 __ test(result_register(), Immediate(kSmiTagMask));
649 __ j(zero, if_true);
650
651 // Save a copy of the value if it may be needed and isn't already saved.
652 switch (context) {
653 case Expression::kUninitialized:
654 case Expression::kEffect:
655 case Expression::kValue:
656 UNREACHABLE();
657 case Expression::kTest:
658 break;
659 case Expression::kValueTest:
660 switch (location_) {
661 case kAccumulator:
662 __ push(result_register());
663 break;
664 case kStack:
665 break;
666 }
667 break;
668 case Expression::kTestValue:
669 switch (location_) {
670 case kAccumulator:
671 __ push(result_register());
672 break;
673 case kStack:
674 break;
675 }
676 break;
677 }
678
679 // Call the ToBoolean stub for all other cases.
680 ToBooleanStub stub;
681 __ push(result_register());
682 __ CallStub(&stub);
683 __ test(eax, Operand(eax));
684
685 // The stub returns nonzero for true. Complete based on the context.
686 switch (context) {
687 case Expression::kUninitialized:
688 case Expression::kEffect:
689 case Expression::kValue:
690 UNREACHABLE();
691
692 case Expression::kTest:
693 __ j(not_zero, true_label_);
694 __ jmp(false_label_);
695 break;
696
697 case Expression::kValueTest:
698 switch (location_) {
699 case kAccumulator:
700 __ j(zero, &discard);
701 __ pop(result_register());
702 __ jmp(true_label_);
703 break;
704 case kStack:
705 __ j(not_zero, true_label_);
706 break;
707 }
708 __ bind(&discard);
709 __ Drop(1);
710 __ jmp(false_label_);
711 break;
712
713 case Expression::kTestValue:
714 switch (location_) {
715 case kAccumulator:
716 __ j(not_zero, &discard);
717 __ pop(result_register());
718 __ jmp(false_label_);
719 break;
720 case kStack:
721 __ j(zero, false_label_);
722 break;
723 }
724 __ bind(&discard);
725 __ Drop(1);
726 __ jmp(true_label_);
727 break;
728 }
729}
730
731
732MemOperand FullCodeGenerator::EmitSlotSearch(Slot* slot, Register scratch) {
733 switch (slot->type()) {
734 case Slot::PARAMETER:
735 case Slot::LOCAL:
736 return Operand(ebp, SlotOffset(slot));
737 case Slot::CONTEXT: {
738 int context_chain_length =
ager@chromium.org5c838252010-02-19 08:53:10 +0000739 scope()->ContextChainLength(slot->var()->scope());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000740 __ LoadContext(scratch, context_chain_length);
741 return CodeGenerator::ContextOperand(scratch, slot->index());
742 }
743 case Slot::LOOKUP:
744 UNREACHABLE();
745 }
746 UNREACHABLE();
747 return Operand(eax, 0);
748}
749
750
751void FullCodeGenerator::Move(Register destination, Slot* source) {
752 MemOperand location = EmitSlotSearch(source, destination);
753 __ mov(destination, location);
754}
755
756
757void FullCodeGenerator::Move(Slot* dst,
758 Register src,
759 Register scratch1,
760 Register scratch2) {
761 ASSERT(dst->type() != Slot::LOOKUP); // Not yet implemented.
762 ASSERT(!scratch1.is(src) && !scratch2.is(src));
763 MemOperand location = EmitSlotSearch(dst, scratch1);
764 __ mov(location, src);
765 // Emit the write barrier code if the location is in the heap.
766 if (dst->type() == Slot::CONTEXT) {
767 int offset = FixedArray::kHeaderSize + dst->index() * kPointerSize;
768 __ RecordWrite(scratch1, offset, src, scratch2);
769 }
770}
771
772
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000773void FullCodeGenerator::EmitDeclaration(Variable* variable,
774 Variable::Mode mode,
775 FunctionLiteral* function) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000776 Comment cmnt(masm_, "[ Declaration");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000777 ASSERT(variable != NULL); // Must have been resolved.
778 Slot* slot = variable->slot();
779 Property* prop = variable->AsProperty();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000780 if (slot != NULL) {
781 switch (slot->type()) {
782 case Slot::PARAMETER:
783 case Slot::LOCAL:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000784 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000785 __ mov(Operand(ebp, SlotOffset(slot)),
786 Immediate(Factory::the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000787 } else if (function != NULL) {
788 VisitForValue(function, kAccumulator);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000789 __ mov(Operand(ebp, SlotOffset(slot)), result_register());
790 }
791 break;
792
793 case Slot::CONTEXT:
794 // We bypass the general EmitSlotSearch because we know more about
795 // this specific context.
796
797 // The variable in the decl always resides in the current context.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000798 ASSERT_EQ(0, scope()->ContextChainLength(variable->scope()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000799 if (FLAG_debug_code) {
800 // Check if we have the correct context pointer.
801 __ mov(ebx,
802 CodeGenerator::ContextOperand(esi, Context::FCONTEXT_INDEX));
803 __ cmp(ebx, Operand(esi));
804 __ Check(equal, "Unexpected declaration in current context.");
805 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000806 if (mode == Variable::CONST) {
807 __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
808 Immediate(Factory::the_hole_value()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000809 // No write barrier since the hole value is in old space.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000810 } else if (function != NULL) {
811 VisitForValue(function, kAccumulator);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000812 __ mov(CodeGenerator::ContextOperand(esi, slot->index()),
813 result_register());
814 int offset = Context::SlotOffset(slot->index());
815 __ mov(ebx, esi);
816 __ RecordWrite(ebx, offset, result_register(), ecx);
817 }
818 break;
819
820 case Slot::LOOKUP: {
821 __ push(esi);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000822 __ push(Immediate(variable->name()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000823 // Declaration nodes are always introduced in one of two modes.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000824 ASSERT(mode == Variable::VAR || mode == Variable::CONST);
825 PropertyAttributes attr = (mode == Variable::VAR) ? NONE : READ_ONLY;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 __ push(Immediate(Smi::FromInt(attr)));
827 // Push initial value, if any.
828 // Note: For variables we must not push an initial value (such as
829 // 'undefined') because we may have a (legal) redeclaration and we
830 // must not destroy the current value.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000831 if (mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000832 __ push(Immediate(Factory::the_hole_value()));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000833 } else if (function != NULL) {
834 VisitForValue(function, kStack);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000835 } else {
836 __ push(Immediate(Smi::FromInt(0))); // No initial value!
837 }
838 __ CallRuntime(Runtime::kDeclareContextSlot, 4);
839 break;
840 }
841 }
842
843 } else if (prop != NULL) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000844 if (function != NULL || mode == Variable::CONST) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000845 // We are declaring a function or constant that rewrites to a
846 // property. Use (keyed) IC to set the initial value.
847 VisitForValue(prop->obj(), kStack);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000848 if (function != NULL) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000849 VisitForValue(prop->key(), kStack);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000850 VisitForValue(function, kAccumulator);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000851 __ pop(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000852 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000853 VisitForValue(prop->key(), kAccumulator);
854 __ mov(ecx, result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000855 __ mov(result_register(), Factory::the_hole_value());
856 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +0000857 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000858
859 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
860 __ call(ic, RelocInfo::CODE_TARGET);
861 // Absence of a test eax instruction following the call
862 // indicates that none of the load was inlined.
863 __ nop();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000864 }
865 }
866}
867
868
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000869void FullCodeGenerator::VisitDeclaration(Declaration* decl) {
870 EmitDeclaration(decl->proxy()->var(), decl->mode(), decl->fun());
871}
872
873
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000874void FullCodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
875 // Call the runtime to declare the globals.
876 __ push(esi); // The context is the first argument.
877 __ push(Immediate(pairs));
ager@chromium.org5c838252010-02-19 08:53:10 +0000878 __ push(Immediate(Smi::FromInt(is_eval() ? 1 : 0)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000879 __ CallRuntime(Runtime::kDeclareGlobals, 3);
880 // Return value is ignored.
881}
882
883
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000884void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
885 Comment cmnt(masm_, "[ SwitchStatement");
886 Breakable nested_statement(this, stmt);
887 SetStatementPosition(stmt);
888 // Keep the switch value on the stack until a case matches.
889 VisitForValue(stmt->tag(), kStack);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000890
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000891 ZoneList<CaseClause*>* clauses = stmt->cases();
892 CaseClause* default_clause = NULL; // Can occur anywhere in the list.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000893
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000894 Label next_test; // Recycled for each test.
895 // Compile all the tests with branches to their bodies.
896 for (int i = 0; i < clauses->length(); i++) {
897 CaseClause* clause = clauses->at(i);
898 // The default is not a test, but remember it as final fall through.
899 if (clause->is_default()) {
900 default_clause = clause;
901 continue;
902 }
903
904 Comment cmnt(masm_, "[ Case comparison");
905 __ bind(&next_test);
906 next_test.Unuse();
907
908 // Compile the label expression.
909 VisitForValue(clause->label(), kAccumulator);
910
911 // Perform the comparison as if via '==='. The comparison stub expects
912 // the smi vs. smi case to be handled before it is called.
913 Label slow_case;
914 __ mov(edx, Operand(esp, 0)); // Switch value.
915 __ mov(ecx, edx);
916 __ or_(ecx, Operand(eax));
917 __ test(ecx, Immediate(kSmiTagMask));
918 __ j(not_zero, &slow_case, not_taken);
919 __ cmp(edx, Operand(eax));
920 __ j(not_equal, &next_test);
921 __ Drop(1); // Switch value is no longer needed.
922 __ jmp(clause->body_target()->entry_label());
923
924 __ bind(&slow_case);
925 CompareStub stub(equal, true);
926 __ CallStub(&stub);
927 __ test(eax, Operand(eax));
928 __ j(not_equal, &next_test);
929 __ Drop(1); // Switch value is no longer needed.
930 __ jmp(clause->body_target()->entry_label());
931 }
932
933 // Discard the test value and jump to the default if present, otherwise to
934 // the end of the statement.
935 __ bind(&next_test);
936 __ Drop(1); // Switch value is no longer needed.
937 if (default_clause == NULL) {
938 __ jmp(nested_statement.break_target());
939 } else {
940 __ jmp(default_clause->body_target()->entry_label());
941 }
942
943 // Compile all the case bodies.
944 for (int i = 0; i < clauses->length(); i++) {
945 Comment cmnt(masm_, "[ Case body");
946 CaseClause* clause = clauses->at(i);
947 __ bind(clause->body_target()->entry_label());
948 VisitStatements(clause->statements());
949 }
950
951 __ bind(nested_statement.break_target());
952}
953
954
955void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
956 Comment cmnt(masm_, "[ ForInStatement");
957 SetStatementPosition(stmt);
958
959 Label loop, exit;
960 ForIn loop_statement(this, stmt);
961 increment_loop_depth();
962
963 // Get the object to enumerate over. Both SpiderMonkey and JSC
964 // ignore null and undefined in contrast to the specification; see
965 // ECMA-262 section 12.6.4.
966 VisitForValue(stmt->enumerable(), kAccumulator);
967 __ cmp(eax, Factory::undefined_value());
968 __ j(equal, &exit);
969 __ cmp(eax, Factory::null_value());
970 __ j(equal, &exit);
971
972 // Convert the object to a JS object.
973 Label convert, done_convert;
974 __ test(eax, Immediate(kSmiTagMask));
975 __ j(zero, &convert);
976 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ecx);
977 __ j(above_equal, &done_convert);
978 __ bind(&convert);
979 __ push(eax);
980 __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_FUNCTION);
981 __ bind(&done_convert);
982 __ push(eax);
983
984 // TODO(kasperl): Check cache validity in generated code. This is a
985 // fast case for the JSObject::IsSimpleEnum cache validity
986 // checks. If we cannot guarantee cache validity, call the runtime
987 // system to check cache validity or get the property names in a
988 // fixed array.
989
990 // Get the set of properties to enumerate.
991 __ push(eax); // Duplicate the enumerable object on the stack.
992 __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
993
994 // If we got a map from the runtime call, we can do a fast
995 // modification check. Otherwise, we got a fixed array, and we have
996 // to do a slow check.
997 Label fixed_array;
998 __ cmp(FieldOperand(eax, HeapObject::kMapOffset), Factory::meta_map());
999 __ j(not_equal, &fixed_array);
1000
1001 // We got a map in register eax. Get the enumeration cache from it.
1002 __ mov(ecx, FieldOperand(eax, Map::kInstanceDescriptorsOffset));
1003 __ mov(ecx, FieldOperand(ecx, DescriptorArray::kEnumerationIndexOffset));
1004 __ mov(edx, FieldOperand(ecx, DescriptorArray::kEnumCacheBridgeCacheOffset));
1005
1006 // Setup the four remaining stack slots.
1007 __ push(eax); // Map.
1008 __ push(edx); // Enumeration cache.
1009 __ mov(eax, FieldOperand(edx, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001010 __ push(eax); // Enumeration cache length (as smi).
1011 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1012 __ jmp(&loop);
1013
1014 // We got a fixed array in register eax. Iterate through that.
1015 __ bind(&fixed_array);
1016 __ push(Immediate(Smi::FromInt(0))); // Map (0) - force slow check.
1017 __ push(eax);
1018 __ mov(eax, FieldOperand(eax, FixedArray::kLengthOffset));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001019 __ push(eax); // Fixed array length (as smi).
1020 __ push(Immediate(Smi::FromInt(0))); // Initial index.
1021
1022 // Generate code for doing the condition check.
1023 __ bind(&loop);
1024 __ mov(eax, Operand(esp, 0 * kPointerSize)); // Get the current index.
1025 __ cmp(eax, Operand(esp, 1 * kPointerSize)); // Compare to the array length.
1026 __ j(above_equal, loop_statement.break_target());
1027
1028 // Get the current entry of the array into register ebx.
1029 __ mov(ebx, Operand(esp, 2 * kPointerSize));
1030 __ mov(ebx, FieldOperand(ebx, eax, times_2, FixedArray::kHeaderSize));
1031
1032 // Get the expected map from the stack or a zero map in the
1033 // permanent slow case into register edx.
1034 __ mov(edx, Operand(esp, 3 * kPointerSize));
1035
1036 // Check if the expected map still matches that of the enumerable.
1037 // If not, we have to filter the key.
1038 Label update_each;
1039 __ mov(ecx, Operand(esp, 4 * kPointerSize));
1040 __ cmp(edx, FieldOperand(ecx, HeapObject::kMapOffset));
1041 __ j(equal, &update_each);
1042
1043 // Convert the entry to a string or null if it isn't a property
1044 // anymore. If the property has been removed while iterating, we
1045 // just skip it.
1046 __ push(ecx); // Enumerable.
1047 __ push(ebx); // Current entry.
1048 __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_FUNCTION);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00001049 __ test(eax, Operand(eax));
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001050 __ j(equal, loop_statement.continue_target());
1051 __ mov(ebx, Operand(eax));
1052
1053 // Update the 'each' property or variable from the possibly filtered
1054 // entry in register ebx.
1055 __ bind(&update_each);
1056 __ mov(result_register(), ebx);
1057 // Perform the assignment as if via '='.
1058 EmitAssignment(stmt->each());
1059
1060 // Generate code for the body of the loop.
1061 Label stack_limit_hit, stack_check_done;
1062 Visit(stmt->body());
1063
1064 __ StackLimitCheck(&stack_limit_hit);
1065 __ bind(&stack_check_done);
1066
1067 // Generate code for going to the next element by incrementing the
1068 // index (smi) stored on top of the stack.
1069 __ bind(loop_statement.continue_target());
1070 __ add(Operand(esp, 0 * kPointerSize), Immediate(Smi::FromInt(1)));
1071 __ jmp(&loop);
1072
1073 // Slow case for the stack limit check.
1074 StackCheckStub stack_check_stub;
1075 __ bind(&stack_limit_hit);
1076 __ CallStub(&stack_check_stub);
1077 __ jmp(&stack_check_done);
1078
1079 // Remove the pointers stored on the stack.
1080 __ bind(loop_statement.break_target());
1081 __ add(Operand(esp), Immediate(5 * kPointerSize));
1082
1083 // Exit and decrement the loop depth.
1084 __ bind(&exit);
1085 decrement_loop_depth();
1086}
1087
1088
1089void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info) {
1090 // Use the fast case closure allocation code that allocates in new
1091 // space for nested functions that don't need literals cloning.
1092 if (scope()->is_function_scope() && info->num_literals() == 0) {
1093 FastNewClosureStub stub;
1094 __ push(Immediate(info));
1095 __ CallStub(&stub);
1096 } else {
1097 __ push(esi);
1098 __ push(Immediate(info));
1099 __ CallRuntime(Runtime::kNewClosure, 2);
1100 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001101 Apply(context_, eax);
1102}
1103
1104
1105void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
1106 Comment cmnt(masm_, "[ VariableProxy");
1107 EmitVariableLoad(expr->var(), context_);
1108}
1109
1110
1111void FullCodeGenerator::EmitVariableLoad(Variable* var,
1112 Expression::Context context) {
1113 // Four cases: non-this global variables, lookup slots, all other
1114 // types of slots, and parameters that rewrite to explicit property
1115 // accesses on the arguments object.
1116 Slot* slot = var->slot();
1117 Property* property = var->AsProperty();
1118
1119 if (var->is_global() && !var->is_this()) {
1120 Comment cmnt(masm_, "Global variable");
1121 // Use inline caching. Variable name is passed in ecx and the global
1122 // object on the stack.
ager@chromium.org5c838252010-02-19 08:53:10 +00001123 __ mov(eax, CodeGenerator::GlobalObject());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001124 __ mov(ecx, var->name());
1125 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1126 __ call(ic, RelocInfo::CODE_TARGET_CONTEXT);
1127 // By emitting a nop we make sure that we do not have a test eax
1128 // instruction after the call it is treated specially by the LoadIC code
1129 // Remember that the assembler may choose to do peephole optimization
1130 // (eg, push/pop elimination).
1131 __ nop();
ager@chromium.org5c838252010-02-19 08:53:10 +00001132 Apply(context, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001133
1134 } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
1135 Comment cmnt(masm_, "Lookup slot");
1136 __ push(esi); // Context.
1137 __ push(Immediate(var->name()));
1138 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1139 Apply(context, eax);
1140
1141 } else if (slot != NULL) {
1142 Comment cmnt(masm_, (slot->type() == Slot::CONTEXT)
1143 ? "Context slot"
1144 : "Stack slot");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001145 if (var->mode() == Variable::CONST) {
1146 // Constants may be the hole value if they have not been initialized.
1147 // Unhole them.
1148 Label done;
1149 MemOperand slot_operand = EmitSlotSearch(slot, eax);
1150 __ mov(eax, slot_operand);
1151 __ cmp(eax, Factory::the_hole_value());
1152 __ j(not_equal, &done);
1153 __ mov(eax, Factory::undefined_value());
1154 __ bind(&done);
1155 Apply(context, eax);
1156 } else {
1157 Apply(context, slot);
1158 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001159
1160 } else {
1161 Comment cmnt(masm_, "Rewritten parameter");
1162 ASSERT_NOT_NULL(property);
1163 // Rewritten parameter accesses are of the form "slot[literal]".
1164
1165 // Assert that the object is in a slot.
1166 Variable* object_var = property->obj()->AsVariableProxy()->AsVariable();
1167 ASSERT_NOT_NULL(object_var);
1168 Slot* object_slot = object_var->slot();
1169 ASSERT_NOT_NULL(object_slot);
1170
1171 // Load the object.
1172 MemOperand object_loc = EmitSlotSearch(object_slot, eax);
ager@chromium.org5c838252010-02-19 08:53:10 +00001173 __ mov(edx, object_loc);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001174
1175 // Assert that the key is a smi.
1176 Literal* key_literal = property->key()->AsLiteral();
1177 ASSERT_NOT_NULL(key_literal);
1178 ASSERT(key_literal->handle()->IsSmi());
1179
1180 // Load the key.
ager@chromium.org5c838252010-02-19 08:53:10 +00001181 __ mov(eax, Immediate(key_literal->handle()));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001182
1183 // Do a keyed property load.
1184 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1185 __ call(ic, RelocInfo::CODE_TARGET);
1186 // Notice: We must not have a "test eax, ..." instruction after the
1187 // call. It is treated specially by the LoadIC code.
1188 __ nop();
1189 // Drop key and object left on the stack by IC.
ager@chromium.org5c838252010-02-19 08:53:10 +00001190 Apply(context, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001191 }
1192}
1193
1194
1195void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1196 Comment cmnt(masm_, "[ RegExpLiteral");
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001197 Label materialized;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001198 // Registers will be used as follows:
1199 // edi = JS function.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001200 // ecx = literals array.
1201 // ebx = regexp literal.
1202 // eax = regexp literal clone.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001203 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001204 __ mov(ecx, FieldOperand(edi, JSFunction::kLiteralsOffset));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001205 int literal_offset =
1206 FixedArray::kHeaderSize + expr->literal_index() * kPointerSize;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001207 __ mov(ebx, FieldOperand(ecx, literal_offset));
1208 __ cmp(ebx, Factory::undefined_value());
1209 __ j(not_equal, &materialized);
1210
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001211 // Create regexp literal using runtime function
1212 // Result will be in eax.
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001213 __ push(ecx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001214 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1215 __ push(Immediate(expr->pattern()));
1216 __ push(Immediate(expr->flags()));
1217 __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00001218 __ mov(ebx, eax);
1219
1220 __ bind(&materialized);
1221 int size = JSRegExp::kSize + JSRegExp::kInObjectFieldCount * kPointerSize;
1222 Label allocated, runtime_allocate;
1223 __ AllocateInNewSpace(size, eax, ecx, edx, &runtime_allocate, TAG_OBJECT);
1224 __ jmp(&allocated);
1225
1226 __ bind(&runtime_allocate);
1227 __ push(ebx);
1228 __ push(Immediate(Smi::FromInt(size)));
1229 __ CallRuntime(Runtime::kAllocateInNewSpace, 1);
1230 __ pop(ebx);
1231
1232 __ bind(&allocated);
1233 // Copy the content into the newly allocated memory.
1234 // (Unroll copy loop once for better throughput).
1235 for (int i = 0; i < size - kPointerSize; i += 2 * kPointerSize) {
1236 __ mov(edx, FieldOperand(ebx, i));
1237 __ mov(ecx, FieldOperand(ebx, i + kPointerSize));
1238 __ mov(FieldOperand(eax, i), edx);
1239 __ mov(FieldOperand(eax, i + kPointerSize), ecx);
1240 }
1241 if ((size % (2 * kPointerSize)) != 0) {
1242 __ mov(edx, FieldOperand(ebx, size - kPointerSize));
1243 __ mov(FieldOperand(eax, size - kPointerSize), edx);
1244 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001245 Apply(context_, eax);
1246}
1247
1248
1249void FullCodeGenerator::VisitObjectLiteral(ObjectLiteral* expr) {
1250 Comment cmnt(masm_, "[ ObjectLiteral");
1251 __ mov(edi, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1252 __ push(FieldOperand(edi, JSFunction::kLiteralsOffset));
1253 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1254 __ push(Immediate(expr->constant_properties()));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001255 __ push(Immediate(Smi::FromInt(expr->fast_elements() ? 1 : 0)));
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001256 if (expr->depth() > 1) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001257 __ CallRuntime(Runtime::kCreateObjectLiteral, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001258 } else {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001259 __ CallRuntime(Runtime::kCreateObjectLiteralShallow, 4);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001260 }
1261
1262 // If result_saved is true the result is on top of the stack. If
1263 // result_saved is false the result is in eax.
1264 bool result_saved = false;
1265
1266 for (int i = 0; i < expr->properties()->length(); i++) {
1267 ObjectLiteral::Property* property = expr->properties()->at(i);
1268 if (property->IsCompileTimeValue()) continue;
1269
1270 Literal* key = property->key();
1271 Expression* value = property->value();
1272 if (!result_saved) {
1273 __ push(eax); // Save result on the stack
1274 result_saved = true;
1275 }
1276 switch (property->kind()) {
1277 case ObjectLiteral::Property::MATERIALIZED_LITERAL:
1278 ASSERT(!CompileTimeValue::IsCompileTimeValue(value));
1279 // Fall through.
1280 case ObjectLiteral::Property::COMPUTED:
1281 if (key->handle()->IsSymbol()) {
1282 VisitForValue(value, kAccumulator);
1283 __ mov(ecx, Immediate(key->handle()));
1284 __ mov(edx, Operand(esp, 0));
1285 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1286 __ call(ic, RelocInfo::CODE_TARGET);
1287 __ nop();
1288 break;
1289 }
1290 // Fall through.
1291 case ObjectLiteral::Property::PROTOTYPE:
1292 __ push(Operand(esp, 0)); // Duplicate receiver.
1293 VisitForValue(key, kStack);
1294 VisitForValue(value, kStack);
1295 __ CallRuntime(Runtime::kSetProperty, 3);
1296 break;
1297 case ObjectLiteral::Property::SETTER:
1298 case ObjectLiteral::Property::GETTER:
1299 __ push(Operand(esp, 0)); // Duplicate receiver.
1300 VisitForValue(key, kStack);
1301 __ push(Immediate(property->kind() == ObjectLiteral::Property::SETTER ?
1302 Smi::FromInt(1) :
1303 Smi::FromInt(0)));
1304 VisitForValue(value, kStack);
1305 __ CallRuntime(Runtime::kDefineAccessor, 4);
1306 break;
1307 default: UNREACHABLE();
1308 }
1309 }
1310
1311 if (result_saved) {
1312 ApplyTOS(context_);
1313 } else {
1314 Apply(context_, eax);
1315 }
1316}
1317
1318
1319void FullCodeGenerator::VisitArrayLiteral(ArrayLiteral* expr) {
1320 Comment cmnt(masm_, "[ ArrayLiteral");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001321
1322 ZoneList<Expression*>* subexprs = expr->values();
1323 int length = subexprs->length();
1324
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001325 __ mov(ebx, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
1326 __ push(FieldOperand(ebx, JSFunction::kLiteralsOffset));
1327 __ push(Immediate(Smi::FromInt(expr->literal_index())));
1328 __ push(Immediate(expr->constant_elements()));
1329 if (expr->depth() > 1) {
1330 __ CallRuntime(Runtime::kCreateArrayLiteral, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001331 } else if (length > FastCloneShallowArrayStub::kMaximumLength) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001332 __ CallRuntime(Runtime::kCreateArrayLiteralShallow, 3);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001333 } else {
1334 FastCloneShallowArrayStub stub(length);
1335 __ CallStub(&stub);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001336 }
1337
1338 bool result_saved = false; // Is the result saved to the stack?
1339
1340 // Emit code to evaluate all the non-constant subexpressions and to store
1341 // them into the newly cloned array.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001342 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001343 Expression* subexpr = subexprs->at(i);
1344 // If the subexpression is a literal or a simple materialized literal it
1345 // is already set in the cloned array.
1346 if (subexpr->AsLiteral() != NULL ||
1347 CompileTimeValue::IsCompileTimeValue(subexpr)) {
1348 continue;
1349 }
1350
1351 if (!result_saved) {
1352 __ push(eax);
1353 result_saved = true;
1354 }
1355 VisitForValue(subexpr, kAccumulator);
1356
1357 // Store the subexpression value in the array's elements.
1358 __ mov(ebx, Operand(esp, 0)); // Copy of array literal.
1359 __ mov(ebx, FieldOperand(ebx, JSObject::kElementsOffset));
1360 int offset = FixedArray::kHeaderSize + (i * kPointerSize);
1361 __ mov(FieldOperand(ebx, offset), result_register());
1362
1363 // Update the write barrier for the array store.
1364 __ RecordWrite(ebx, offset, result_register(), ecx);
1365 }
1366
1367 if (result_saved) {
1368 ApplyTOS(context_);
1369 } else {
1370 Apply(context_, eax);
1371 }
1372}
1373
1374
ager@chromium.org5c838252010-02-19 08:53:10 +00001375void FullCodeGenerator::VisitAssignment(Assignment* expr) {
1376 Comment cmnt(masm_, "[ Assignment");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001377 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
1378 // on the left-hand side.
1379 if (!expr->target()->IsValidLeftHandSide()) {
1380 VisitForEffect(expr->target());
1381 return;
1382 }
1383
ager@chromium.org5c838252010-02-19 08:53:10 +00001384 // Left-hand side can only be a property, a global or a (parameter or local)
1385 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1386 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1387 LhsKind assign_type = VARIABLE;
1388 Property* prop = expr->target()->AsProperty();
1389 if (prop != NULL) {
1390 assign_type =
1391 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
1392 }
1393
1394 // Evaluate LHS expression.
1395 switch (assign_type) {
1396 case VARIABLE:
1397 // Nothing to do here.
1398 break;
1399 case NAMED_PROPERTY:
1400 if (expr->is_compound()) {
1401 // We need the receiver both on the stack and in the accumulator.
1402 VisitForValue(prop->obj(), kAccumulator);
1403 __ push(result_register());
1404 } else {
1405 VisitForValue(prop->obj(), kStack);
1406 }
1407 break;
1408 case KEYED_PROPERTY:
1409 if (expr->is_compound()) {
1410 VisitForValue(prop->obj(), kStack);
1411 VisitForValue(prop->key(), kAccumulator);
1412 __ mov(edx, Operand(esp, 0));
1413 __ push(eax);
1414 } else {
1415 VisitForValue(prop->obj(), kStack);
1416 VisitForValue(prop->key(), kStack);
1417 }
1418 break;
1419 }
1420
1421 // If we have a compound assignment: Get value of LHS expression and
1422 // store in on top of the stack.
1423 if (expr->is_compound()) {
1424 Location saved_location = location_;
1425 location_ = kStack;
1426 switch (assign_type) {
1427 case VARIABLE:
1428 EmitVariableLoad(expr->target()->AsVariableProxy()->var(),
1429 Expression::kValue);
1430 break;
1431 case NAMED_PROPERTY:
1432 EmitNamedPropertyLoad(prop);
1433 __ push(result_register());
1434 break;
1435 case KEYED_PROPERTY:
1436 EmitKeyedPropertyLoad(prop);
1437 __ push(result_register());
1438 break;
1439 }
1440 location_ = saved_location;
1441 }
1442
1443 // Evaluate RHS expression.
1444 Expression* rhs = expr->value();
1445 VisitForValue(rhs, kAccumulator);
1446
1447 // If we have a compound assignment: Apply operator.
1448 if (expr->is_compound()) {
1449 Location saved_location = location_;
1450 location_ = kAccumulator;
1451 EmitBinaryOp(expr->binary_op(), Expression::kValue);
1452 location_ = saved_location;
1453 }
1454
1455 // Record source position before possible IC call.
1456 SetSourcePosition(expr->position());
1457
1458 // Store the value.
1459 switch (assign_type) {
1460 case VARIABLE:
1461 EmitVariableAssignment(expr->target()->AsVariableProxy()->var(),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001462 expr->op(),
ager@chromium.org5c838252010-02-19 08:53:10 +00001463 context_);
1464 break;
1465 case NAMED_PROPERTY:
1466 EmitNamedPropertyAssignment(expr);
1467 break;
1468 case KEYED_PROPERTY:
1469 EmitKeyedPropertyAssignment(expr);
1470 break;
1471 }
1472}
1473
1474
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001475void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1476 SetSourcePosition(prop->position());
1477 Literal* key = prop->key()->AsLiteral();
1478 __ mov(ecx, Immediate(key->handle()));
1479 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
1480 __ call(ic, RelocInfo::CODE_TARGET);
1481 __ nop();
1482}
1483
1484
1485void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1486 SetSourcePosition(prop->position());
1487 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1488 __ call(ic, RelocInfo::CODE_TARGET);
1489 __ nop();
1490}
1491
1492
1493void FullCodeGenerator::EmitBinaryOp(Token::Value op,
1494 Expression::Context context) {
1495 __ push(result_register());
1496 GenericBinaryOpStub stub(op,
1497 NO_OVERWRITE,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001498 NO_GENERIC_BINARY_FLAGS,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00001499 TypeInfo::Unknown());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001500 __ CallStub(&stub);
1501 Apply(context, eax);
1502}
1503
1504
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001505void FullCodeGenerator::EmitAssignment(Expression* expr) {
1506 // Invalid left-hand sides are rewritten to have a 'throw
1507 // ReferenceError' on the left-hand side.
1508 if (!expr->IsValidLeftHandSide()) {
1509 VisitForEffect(expr);
1510 return;
1511 }
1512
1513 // Left-hand side can only be a property, a global or a (parameter or local)
1514 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
1515 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
1516 LhsKind assign_type = VARIABLE;
1517 Property* prop = expr->AsProperty();
1518 if (prop != NULL) {
1519 assign_type = (prop->key()->IsPropertyName())
1520 ? NAMED_PROPERTY
1521 : KEYED_PROPERTY;
1522 }
1523
1524 switch (assign_type) {
1525 case VARIABLE: {
1526 Variable* var = expr->AsVariableProxy()->var();
1527 EmitVariableAssignment(var, Token::ASSIGN, Expression::kEffect);
1528 break;
1529 }
1530 case NAMED_PROPERTY: {
1531 __ push(eax); // Preserve value.
1532 VisitForValue(prop->obj(), kAccumulator);
1533 __ mov(edx, eax);
1534 __ pop(eax); // Restore value.
1535 __ mov(ecx, prop->key()->AsLiteral()->handle());
1536 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1537 __ call(ic, RelocInfo::CODE_TARGET);
1538 __ nop(); // Signal no inlined code.
1539 break;
1540 }
1541 case KEYED_PROPERTY: {
1542 __ push(eax); // Preserve value.
1543 VisitForValue(prop->obj(), kStack);
1544 VisitForValue(prop->key(), kAccumulator);
1545 __ mov(ecx, eax);
1546 __ pop(edx);
1547 __ pop(eax); // Restore value.
1548 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1549 __ call(ic, RelocInfo::CODE_TARGET);
1550 __ nop(); // Signal no inlined code.
1551 break;
1552 }
1553 }
1554}
1555
1556
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001557void FullCodeGenerator::EmitVariableAssignment(Variable* var,
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001558 Token::Value op,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001559 Expression::Context context) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001560 // Left-hand sides that rewrite to explicit property accesses do not reach
1561 // here.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001562 ASSERT(var != NULL);
1563 ASSERT(var->is_global() || var->slot() != NULL);
1564
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001565 if (var->is_global()) {
1566 ASSERT(!var->is_this());
1567 // Assignment to a global variable. Use inline caching for the
1568 // assignment. Right-hand-side value is passed in eax, variable name in
1569 // ecx, and the global object on the stack.
1570 __ mov(ecx, var->name());
1571 __ mov(edx, CodeGenerator::GlobalObject());
1572 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1573 __ call(ic, RelocInfo::CODE_TARGET);
1574 __ nop();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001575
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001576 } else if (var->mode() != Variable::CONST || op == Token::INIT_CONST) {
1577 // Perform the assignment for non-const variables and for initialization
1578 // of const variables. Const assignments are simply skipped.
1579 Label done;
1580 Slot* slot = var->slot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001581 switch (slot->type()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001582 case Slot::PARAMETER:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001583 case Slot::LOCAL:
1584 if (op == Token::INIT_CONST) {
1585 // Detect const reinitialization by checking for the hole value.
1586 __ mov(edx, Operand(ebp, SlotOffset(slot)));
1587 __ cmp(edx, Factory::the_hole_value());
1588 __ j(not_equal, &done);
1589 }
1590 // Perform the assignment.
1591 __ mov(Operand(ebp, SlotOffset(slot)), eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001592 break;
1593
1594 case Slot::CONTEXT: {
1595 MemOperand target = EmitSlotSearch(slot, ecx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001596 if (op == Token::INIT_CONST) {
1597 // Detect const reinitialization by checking for the hole value.
1598 __ mov(edx, target);
1599 __ cmp(edx, Factory::the_hole_value());
1600 __ j(not_equal, &done);
1601 }
1602 // Perform the assignment and issue the write barrier.
1603 __ mov(target, eax);
1604 // The value of the assignment is in eax. RecordWrite clobbers its
1605 // register arguments.
1606 __ mov(edx, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001607 int offset = FixedArray::kHeaderSize + slot->index() * kPointerSize;
1608 __ RecordWrite(ecx, offset, edx, ebx);
1609 break;
1610 }
1611
1612 case Slot::LOOKUP:
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001613 // Call the runtime for the assignment. The runtime will ignore
1614 // const reinitialization.
1615 __ push(eax); // Value.
1616 __ push(esi); // Context.
1617 __ push(Immediate(var->name()));
1618 if (op == Token::INIT_CONST) {
1619 // The runtime will ignore const redeclaration.
1620 __ CallRuntime(Runtime::kInitializeConstContextSlot, 3);
1621 } else {
1622 __ CallRuntime(Runtime::kStoreContextSlot, 3);
1623 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001624 break;
1625 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001626 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001627 }
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001628
1629 Apply(context, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001630}
1631
1632
1633void FullCodeGenerator::EmitNamedPropertyAssignment(Assignment* expr) {
1634 // Assignment to a property, using a named store IC.
1635 Property* prop = expr->target()->AsProperty();
1636 ASSERT(prop != NULL);
1637 ASSERT(prop->key()->AsLiteral() != NULL);
1638
1639 // If the assignment starts a block of assignments to the same object,
1640 // change to slow case to avoid the quadratic behavior of repeatedly
1641 // adding fast properties.
1642 if (expr->starts_initialization_block()) {
1643 __ push(result_register());
1644 __ push(Operand(esp, kPointerSize)); // Receiver is now under value.
1645 __ CallRuntime(Runtime::kToSlowProperties, 1);
1646 __ pop(result_register());
1647 }
1648
1649 // Record source code position before IC call.
1650 SetSourcePosition(expr->position());
1651 __ mov(ecx, prop->key()->AsLiteral()->handle());
1652 if (expr->ends_initialization_block()) {
1653 __ mov(edx, Operand(esp, 0));
1654 } else {
1655 __ pop(edx);
1656 }
1657 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
1658 __ call(ic, RelocInfo::CODE_TARGET);
1659 __ nop();
1660
1661 // If the assignment ends an initialization block, revert to fast case.
1662 if (expr->ends_initialization_block()) {
1663 __ push(eax); // Result of assignment, saved even if not needed.
1664 __ push(Operand(esp, kPointerSize)); // Receiver is under value.
1665 __ CallRuntime(Runtime::kToFastProperties, 1);
1666 __ pop(eax);
1667 DropAndApply(1, context_, eax);
1668 } else {
1669 Apply(context_, eax);
1670 }
1671}
1672
1673
1674void FullCodeGenerator::EmitKeyedPropertyAssignment(Assignment* expr) {
1675 // Assignment to a property, using a keyed store IC.
1676
1677 // If the assignment starts a block of assignments to the same object,
1678 // change to slow case to avoid the quadratic behavior of repeatedly
1679 // adding fast properties.
1680 if (expr->starts_initialization_block()) {
1681 __ push(result_register());
1682 // Receiver is now under the key and value.
1683 __ push(Operand(esp, 2 * kPointerSize));
1684 __ CallRuntime(Runtime::kToSlowProperties, 1);
1685 __ pop(result_register());
1686 }
1687
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001688 __ pop(ecx);
1689 if (expr->ends_initialization_block()) {
1690 __ mov(edx, Operand(esp, 0)); // Leave receiver on the stack for later.
1691 } else {
1692 __ pop(edx);
1693 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001694 // Record source code position before IC call.
1695 SetSourcePosition(expr->position());
1696 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
1697 __ call(ic, RelocInfo::CODE_TARGET);
1698 // This nop signals to the IC that there is no inlined code at the call
1699 // site for it to patch.
1700 __ nop();
1701
1702 // If the assignment ends an initialization block, revert to fast case.
1703 if (expr->ends_initialization_block()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001704 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001705 __ push(eax); // Result of assignment, saved even if not needed.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001706 __ push(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001707 __ CallRuntime(Runtime::kToFastProperties, 1);
1708 __ pop(eax);
1709 }
1710
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001711 Apply(context_, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001712}
1713
1714
1715void FullCodeGenerator::VisitProperty(Property* expr) {
1716 Comment cmnt(masm_, "[ Property");
1717 Expression* key = expr->key();
1718
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001719 if (key->IsPropertyName()) {
ager@chromium.org5c838252010-02-19 08:53:10 +00001720 VisitForValue(expr->obj(), kAccumulator);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001721 EmitNamedPropertyLoad(expr);
ager@chromium.org5c838252010-02-19 08:53:10 +00001722 Apply(context_, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001723 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +00001724 VisitForValue(expr->obj(), kStack);
1725 VisitForValue(expr->key(), kAccumulator);
1726 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001727 EmitKeyedPropertyLoad(expr);
ager@chromium.org5c838252010-02-19 08:53:10 +00001728 Apply(context_, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001729 }
1730}
1731
1732
1733void FullCodeGenerator::EmitCallWithIC(Call* expr,
1734 Handle<Object> name,
1735 RelocInfo::Mode mode) {
1736 // Code common for calls using the IC.
1737 ZoneList<Expression*>* args = expr->arguments();
1738 int arg_count = args->length();
1739 for (int i = 0; i < arg_count; i++) {
1740 VisitForValue(args->at(i), kStack);
1741 }
1742 __ Set(ecx, Immediate(name));
1743 // Record source position of the IC call.
1744 SetSourcePosition(expr->position());
1745 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1746 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
1747 __ call(ic, mode);
1748 // Restore context register.
1749 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1750 Apply(context_, eax);
1751}
1752
1753
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001754void FullCodeGenerator::EmitKeyedCallWithIC(Call* expr,
1755 Expression* key,
1756 RelocInfo::Mode mode) {
1757 // Code common for calls using the IC.
1758 ZoneList<Expression*>* args = expr->arguments();
1759 int arg_count = args->length();
1760 for (int i = 0; i < arg_count; i++) {
1761 VisitForValue(args->at(i), kStack);
1762 }
1763 VisitForValue(key, kAccumulator);
1764 __ mov(ecx, eax);
1765 // Record source position of the IC call.
1766 SetSourcePosition(expr->position());
1767 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1768 Handle<Code> ic = CodeGenerator::ComputeKeyedCallInitialize(
1769 arg_count, in_loop);
1770 __ call(ic, mode);
1771 // Restore context register.
1772 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1773 Apply(context_, eax);
1774}
1775
1776
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001777void FullCodeGenerator::EmitCallWithStub(Call* expr) {
1778 // Code common for calls using the call stub.
1779 ZoneList<Expression*>* args = expr->arguments();
1780 int arg_count = args->length();
1781 for (int i = 0; i < arg_count; i++) {
1782 VisitForValue(args->at(i), kStack);
1783 }
1784 // Record source position for debugger.
1785 SetSourcePosition(expr->position());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001786 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1787 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001788 __ CallStub(&stub);
1789 // Restore context register.
1790 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1791 DropAndApply(1, context_, eax);
1792}
1793
1794
1795void FullCodeGenerator::VisitCall(Call* expr) {
1796 Comment cmnt(masm_, "[ Call");
1797 Expression* fun = expr->expression();
1798 Variable* var = fun->AsVariableProxy()->AsVariable();
1799
1800 if (var != NULL && var->is_possibly_eval()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001801 // In a call to eval, we first call %ResolvePossiblyDirectEval to
1802 // resolve the function we need to call and the receiver of the
1803 // call. Then we call the resolved function using the given
1804 // arguments.
1805 VisitForValue(fun, kStack);
1806 __ push(Immediate(Factory::undefined_value())); // Reserved receiver slot.
1807
1808 // Push the arguments.
1809 ZoneList<Expression*>* args = expr->arguments();
1810 int arg_count = args->length();
1811 for (int i = 0; i < arg_count; i++) {
1812 VisitForValue(args->at(i), kStack);
1813 }
1814
1815 // Push copy of the function - found below the arguments.
1816 __ push(Operand(esp, (arg_count + 1) * kPointerSize));
1817
1818 // Push copy of the first argument or undefined if it doesn't exist.
1819 if (arg_count > 0) {
1820 __ push(Operand(esp, arg_count * kPointerSize));
1821 } else {
1822 __ push(Immediate(Factory::undefined_value()));
1823 }
1824
1825 // Push the receiver of the enclosing function and do runtime call.
1826 __ push(Operand(ebp, (2 + scope()->num_parameters()) * kPointerSize));
1827 __ CallRuntime(Runtime::kResolvePossiblyDirectEval, 3);
1828
1829 // The runtime call returns a pair of values in eax (function) and
1830 // edx (receiver). Touch up the stack with the right values.
1831 __ mov(Operand(esp, (arg_count + 0) * kPointerSize), edx);
1832 __ mov(Operand(esp, (arg_count + 1) * kPointerSize), eax);
1833
1834 // Record source position for debugger.
1835 SetSourcePosition(expr->position());
1836 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
1837 CallFunctionStub stub(arg_count, in_loop, RECEIVER_MIGHT_BE_VALUE);
1838 __ CallStub(&stub);
1839 // Restore context register.
1840 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
1841 DropAndApply(1, context_, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001842 } else if (var != NULL && !var->is_this() && var->is_global()) {
1843 // Push global object as receiver for the call IC.
1844 __ push(CodeGenerator::GlobalObject());
1845 EmitCallWithIC(expr, var->name(), RelocInfo::CODE_TARGET_CONTEXT);
1846 } else if (var != NULL && var->slot() != NULL &&
1847 var->slot()->type() == Slot::LOOKUP) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001848 // Call to a lookup slot (dynamically introduced variable). Call the
1849 // runtime to find the function to call (returned in eax) and the object
1850 // holding it (returned in edx).
1851 __ push(context_register());
1852 __ push(Immediate(var->name()));
1853 __ CallRuntime(Runtime::kLoadContextSlot, 2);
1854 __ push(eax); // Function.
1855 __ push(edx); // Receiver.
1856 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001857 } else if (fun->AsProperty() != NULL) {
1858 // Call to an object property.
1859 Property* prop = fun->AsProperty();
1860 Literal* key = prop->key()->AsLiteral();
1861 if (key != NULL && key->handle()->IsSymbol()) {
1862 // Call to a named property, use call IC.
1863 VisitForValue(prop->obj(), kStack);
1864 EmitCallWithIC(expr, key->handle(), RelocInfo::CODE_TARGET);
1865 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001866 // Call to a keyed property.
1867 // For a synthetic property use keyed load IC followed by function call,
1868 // for a regular property use keyed CallIC.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001869 VisitForValue(prop->obj(), kStack);
ager@chromium.org5c838252010-02-19 08:53:10 +00001870 if (prop->is_synthetic()) {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001871 VisitForValue(prop->key(), kAccumulator);
1872 // Record source code position for IC call.
1873 SetSourcePosition(prop->position());
ager@chromium.org5c838252010-02-19 08:53:10 +00001874 __ pop(edx); // We do not need to keep the receiver.
ager@chromium.org5c838252010-02-19 08:53:10 +00001875
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001876 Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
1877 __ call(ic, RelocInfo::CODE_TARGET);
1878 // By emitting a nop we make sure that we do not have a "test eax,..."
1879 // instruction after the call as it is treated specially
1880 // by the LoadIC code.
1881 __ nop();
ager@chromium.org5c838252010-02-19 08:53:10 +00001882 // Push result (function).
1883 __ push(eax);
1884 // Push Global receiver.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001885 __ mov(ecx, CodeGenerator::GlobalObject());
1886 __ push(FieldOperand(ecx, GlobalObject::kGlobalReceiverOffset));
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001887 EmitCallWithStub(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001888 } else {
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00001889 EmitKeyedCallWithIC(expr, prop->key(), RelocInfo::CODE_TARGET);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001890 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001891 }
1892 } else {
1893 // Call to some other expression. If the expression is an anonymous
1894 // function literal not called in a loop, mark it as one that should
1895 // also use the full code generator.
1896 FunctionLiteral* lit = fun->AsFunctionLiteral();
1897 if (lit != NULL &&
1898 lit->name()->Equals(Heap::empty_string()) &&
1899 loop_depth() == 0) {
1900 lit->set_try_full_codegen(true);
1901 }
1902 VisitForValue(fun, kStack);
1903 // Load global receiver object.
1904 __ mov(ebx, CodeGenerator::GlobalObject());
1905 __ push(FieldOperand(ebx, GlobalObject::kGlobalReceiverOffset));
1906 // Emit function call.
1907 EmitCallWithStub(expr);
1908 }
1909}
1910
1911
1912void FullCodeGenerator::VisitCallNew(CallNew* expr) {
1913 Comment cmnt(masm_, "[ CallNew");
1914 // According to ECMA-262, section 11.2.2, page 44, the function
1915 // expression in new calls must be evaluated before the
1916 // arguments.
1917 // Push function on the stack.
1918 VisitForValue(expr->expression(), kStack);
1919
1920 // Push global object (receiver).
1921 __ push(CodeGenerator::GlobalObject());
1922
1923 // Push the arguments ("left-to-right") on the stack.
1924 ZoneList<Expression*>* args = expr->arguments();
1925 int arg_count = args->length();
1926 for (int i = 0; i < arg_count; i++) {
1927 VisitForValue(args->at(i), kStack);
1928 }
1929
1930 // Call the construct call builtin that handles allocation and
1931 // constructor invocation.
1932 SetSourcePosition(expr->position());
1933
1934 // Load function, arg_count into edi and eax.
1935 __ Set(eax, Immediate(arg_count));
1936 // Function is in esp[arg_count + 1].
1937 __ mov(edi, Operand(esp, eax, times_pointer_size, kPointerSize));
1938
1939 Handle<Code> construct_builtin(Builtins::builtin(Builtins::JSConstructCall));
1940 __ call(construct_builtin, RelocInfo::CONSTRUCT_CALL);
1941
1942 // Replace function on TOS with result in eax, or pop it.
1943 DropAndApply(1, context_, eax);
1944}
1945
1946
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001947void FullCodeGenerator::EmitIsSmi(ZoneList<Expression*>* args) {
1948 ASSERT(args->length() == 1);
1949
1950 VisitForValue(args->at(0), kAccumulator);
1951
1952 Label materialize_true, materialize_false;
1953 Label* if_true = NULL;
1954 Label* if_false = NULL;
1955 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1956
1957 __ test(eax, Immediate(kSmiTagMask));
1958 __ j(zero, if_true);
1959 __ jmp(if_false);
1960
1961 Apply(context_, if_true, if_false);
1962}
1963
1964
1965void FullCodeGenerator::EmitIsNonNegativeSmi(ZoneList<Expression*>* args) {
1966 ASSERT(args->length() == 1);
1967
1968 VisitForValue(args->at(0), kAccumulator);
1969
1970 Label materialize_true, materialize_false;
1971 Label* if_true = NULL;
1972 Label* if_false = NULL;
1973 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1974
1975 __ test(eax, Immediate(kSmiTagMask | 0x80000000));
1976 __ j(zero, if_true);
1977 __ jmp(if_false);
1978
1979 Apply(context_, if_true, if_false);
1980}
1981
1982
1983void FullCodeGenerator::EmitIsObject(ZoneList<Expression*>* args) {
1984 ASSERT(args->length() == 1);
1985
1986 VisitForValue(args->at(0), kAccumulator);
1987
1988 Label materialize_true, materialize_false;
1989 Label* if_true = NULL;
1990 Label* if_false = NULL;
1991 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
1992
1993 __ test(eax, Immediate(kSmiTagMask));
1994 __ j(zero, if_false);
1995 __ cmp(eax, Factory::null_value());
1996 __ j(equal, if_true);
1997 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
1998 // Undetectable objects behave like undefined when tested with typeof.
1999 __ movzx_b(ecx, FieldOperand(ebx, Map::kBitFieldOffset));
2000 __ test(ecx, Immediate(1 << Map::kIsUndetectable));
2001 __ j(not_zero, if_false);
2002 __ movzx_b(ecx, FieldOperand(ebx, Map::kInstanceTypeOffset));
2003 __ cmp(ecx, FIRST_JS_OBJECT_TYPE);
2004 __ j(below, if_false);
2005 __ cmp(ecx, LAST_JS_OBJECT_TYPE);
2006 __ j(below_equal, if_true);
2007 __ jmp(if_false);
2008
2009 Apply(context_, if_true, if_false);
2010}
2011
2012
ricow@chromium.org4980dff2010-07-19 08:33:45 +00002013void FullCodeGenerator::EmitIsSpecObject(ZoneList<Expression*>* args) {
2014 ASSERT(args->length() == 1);
2015
2016 VisitForValue(args->at(0), kAccumulator);
2017
2018 Label materialize_true, materialize_false;
2019 Label* if_true = NULL;
2020 Label* if_false = NULL;
2021 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2022
2023 __ test(eax, Immediate(kSmiTagMask));
2024 __ j(equal, if_false);
2025 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, ebx);
2026 __ j(above_equal, if_true);
2027 __ jmp(if_false);
2028
2029 Apply(context_, if_true, if_false);
2030}
2031
2032
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002033void FullCodeGenerator::EmitIsUndetectableObject(ZoneList<Expression*>* args) {
2034 ASSERT(args->length() == 1);
2035
2036 VisitForValue(args->at(0), kAccumulator);
2037
2038 Label materialize_true, materialize_false;
2039 Label* if_true = NULL;
2040 Label* if_false = NULL;
2041 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2042
2043 __ test(eax, Immediate(kSmiTagMask));
2044 __ j(zero, if_false);
2045 __ mov(ebx, FieldOperand(eax, HeapObject::kMapOffset));
2046 __ movzx_b(ebx, FieldOperand(ebx, Map::kBitFieldOffset));
2047 __ test(ebx, Immediate(1 << Map::kIsUndetectable));
2048 __ j(not_zero, if_true);
2049 __ jmp(if_false);
2050
2051 Apply(context_, if_true, if_false);
2052}
2053
2054
ager@chromium.orgea4f62e2010-08-16 16:28:43 +00002055void FullCodeGenerator::EmitIsStringWrapperSafeForDefaultValueOf(
2056 ZoneList<Expression*>* args) {
2057 ASSERT(args->length() == 1);
2058
2059 VisitForValue(args->at(0), kAccumulator);
2060
2061 Label materialize_true, materialize_false;
2062 Label* if_true = NULL;
2063 Label* if_false = NULL;
2064 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2065
2066 // Just indicate false, as %_IsStringWrapperSafeForDefaultValueOf() is only
2067 // used in a few functions in runtime.js which should not normally be hit by
2068 // this compiler.
2069 __ jmp(if_false);
2070 Apply(context_, if_true, if_false);
2071}
2072
2073
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002074void FullCodeGenerator::EmitIsFunction(ZoneList<Expression*>* args) {
2075 ASSERT(args->length() == 1);
2076
2077 VisitForValue(args->at(0), kAccumulator);
2078
2079 Label materialize_true, materialize_false;
2080 Label* if_true = NULL;
2081 Label* if_false = NULL;
2082 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2083
2084 __ test(eax, Immediate(kSmiTagMask));
2085 __ j(zero, if_false);
2086 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2087 __ j(equal, if_true);
2088 __ jmp(if_false);
2089
2090 Apply(context_, if_true, if_false);
2091}
2092
2093
2094void FullCodeGenerator::EmitIsArray(ZoneList<Expression*>* args) {
2095 ASSERT(args->length() == 1);
2096
2097 VisitForValue(args->at(0), kAccumulator);
2098
2099 Label materialize_true, materialize_false;
2100 Label* if_true = NULL;
2101 Label* if_false = NULL;
2102 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2103
2104 __ test(eax, Immediate(kSmiTagMask));
2105 __ j(equal, if_false);
2106 __ CmpObjectType(eax, JS_ARRAY_TYPE, ebx);
2107 __ j(equal, if_true);
2108 __ jmp(if_false);
2109
2110 Apply(context_, if_true, if_false);
2111}
2112
2113
2114void FullCodeGenerator::EmitIsRegExp(ZoneList<Expression*>* args) {
2115 ASSERT(args->length() == 1);
2116
2117 VisitForValue(args->at(0), kAccumulator);
2118
2119 Label materialize_true, materialize_false;
2120 Label* if_true = NULL;
2121 Label* if_false = NULL;
2122 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2123
2124 __ test(eax, Immediate(kSmiTagMask));
2125 __ j(equal, if_false);
2126 __ CmpObjectType(eax, JS_REGEXP_TYPE, ebx);
2127 __ j(equal, if_true);
2128 __ jmp(if_false);
2129
2130 Apply(context_, if_true, if_false);
2131}
2132
2133
2134
2135void FullCodeGenerator::EmitIsConstructCall(ZoneList<Expression*>* args) {
2136 ASSERT(args->length() == 0);
2137
2138 Label materialize_true, materialize_false;
2139 Label* if_true = NULL;
2140 Label* if_false = NULL;
2141 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2142
2143 // Get the frame pointer for the calling frame.
2144 __ mov(eax, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2145
2146 // Skip the arguments adaptor frame if it exists.
2147 Label check_frame_marker;
2148 __ cmp(Operand(eax, StandardFrameConstants::kContextOffset),
2149 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2150 __ j(not_equal, &check_frame_marker);
2151 __ mov(eax, Operand(eax, StandardFrameConstants::kCallerFPOffset));
2152
2153 // Check the marker in the calling frame.
2154 __ bind(&check_frame_marker);
2155 __ cmp(Operand(eax, StandardFrameConstants::kMarkerOffset),
2156 Immediate(Smi::FromInt(StackFrame::CONSTRUCT)));
2157 __ j(equal, if_true);
2158 __ jmp(if_false);
2159
2160 Apply(context_, if_true, if_false);
2161}
2162
2163
2164void FullCodeGenerator::EmitObjectEquals(ZoneList<Expression*>* args) {
2165 ASSERT(args->length() == 2);
2166
2167 // Load the two objects into registers and perform the comparison.
2168 VisitForValue(args->at(0), kStack);
2169 VisitForValue(args->at(1), kAccumulator);
2170
2171 Label materialize_true, materialize_false;
2172 Label* if_true = NULL;
2173 Label* if_false = NULL;
2174 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
2175
2176 __ pop(ebx);
2177 __ cmp(eax, Operand(ebx));
2178 __ j(equal, if_true);
2179 __ jmp(if_false);
2180
2181 Apply(context_, if_true, if_false);
2182}
2183
2184
2185void FullCodeGenerator::EmitArguments(ZoneList<Expression*>* args) {
2186 ASSERT(args->length() == 1);
2187
2188 // ArgumentsAccessStub expects the key in edx and the formal
2189 // parameter count in eax.
2190 VisitForValue(args->at(0), kAccumulator);
2191 __ mov(edx, eax);
2192 __ mov(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2193 ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
2194 __ CallStub(&stub);
2195 Apply(context_, eax);
2196}
2197
2198
2199void FullCodeGenerator::EmitArgumentsLength(ZoneList<Expression*>* args) {
2200 ASSERT(args->length() == 0);
2201
2202 Label exit;
2203 // Get the number of formal parameters.
2204 __ Set(eax, Immediate(Smi::FromInt(scope()->num_parameters())));
2205
2206 // Check if the calling frame is an arguments adaptor frame.
2207 __ mov(ebx, Operand(ebp, StandardFrameConstants::kCallerFPOffset));
2208 __ cmp(Operand(ebx, StandardFrameConstants::kContextOffset),
2209 Immediate(Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR)));
2210 __ j(not_equal, &exit);
2211
2212 // Arguments adaptor case: Read the arguments length from the
2213 // adaptor frame.
2214 __ mov(eax, Operand(ebx, ArgumentsAdaptorFrameConstants::kLengthOffset));
2215
2216 __ bind(&exit);
2217 if (FLAG_debug_code) __ AbortIfNotSmi(eax);
2218 Apply(context_, eax);
2219}
2220
2221
2222void FullCodeGenerator::EmitClassOf(ZoneList<Expression*>* args) {
2223 ASSERT(args->length() == 1);
2224 Label done, null, function, non_function_constructor;
2225
2226 VisitForValue(args->at(0), kAccumulator);
2227
2228 // If the object is a smi, we return null.
2229 __ test(eax, Immediate(kSmiTagMask));
2230 __ j(zero, &null);
2231
2232 // Check that the object is a JS object but take special care of JS
2233 // functions to make sure they have 'Function' as their class.
kmillikin@chromium.org9155e252010-05-26 13:27:57 +00002234 __ CmpObjectType(eax, FIRST_JS_OBJECT_TYPE, eax); // Map is now in eax.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002235 __ j(below, &null);
2236
2237 // As long as JS_FUNCTION_TYPE is the last instance type and it is
2238 // right after LAST_JS_OBJECT_TYPE, we can avoid checking for
2239 // LAST_JS_OBJECT_TYPE.
2240 ASSERT(LAST_TYPE == JS_FUNCTION_TYPE);
2241 ASSERT(JS_FUNCTION_TYPE == LAST_JS_OBJECT_TYPE + 1);
fschneider@chromium.org40b9da32010-06-28 11:29:21 +00002242 __ CmpInstanceType(eax, JS_FUNCTION_TYPE);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002243 __ j(equal, &function);
2244
2245 // Check if the constructor in the map is a function.
2246 __ mov(eax, FieldOperand(eax, Map::kConstructorOffset));
2247 __ CmpObjectType(eax, JS_FUNCTION_TYPE, ebx);
2248 __ j(not_equal, &non_function_constructor);
2249
2250 // eax now contains the constructor function. Grab the
2251 // instance class name from there.
2252 __ mov(eax, FieldOperand(eax, JSFunction::kSharedFunctionInfoOffset));
2253 __ mov(eax, FieldOperand(eax, SharedFunctionInfo::kInstanceClassNameOffset));
2254 __ jmp(&done);
2255
2256 // Functions have class 'Function'.
2257 __ bind(&function);
2258 __ mov(eax, Factory::function_class_symbol());
2259 __ jmp(&done);
2260
2261 // Objects with a non-function constructor have class 'Object'.
2262 __ bind(&non_function_constructor);
2263 __ mov(eax, Factory::Object_symbol());
2264 __ jmp(&done);
2265
2266 // Non-JS objects have class null.
2267 __ bind(&null);
2268 __ mov(eax, Factory::null_value());
2269
2270 // All done.
2271 __ bind(&done);
2272
2273 Apply(context_, eax);
2274}
2275
2276
2277void FullCodeGenerator::EmitLog(ZoneList<Expression*>* args) {
2278 // Conditionally generate a log call.
2279 // Args:
2280 // 0 (literal string): The type of logging (corresponds to the flags).
2281 // This is used to determine whether or not to generate the log call.
2282 // 1 (string): Format string. Access the string at argument index 2
2283 // with '%2s' (see Logger::LogRuntime for all the formats).
2284 // 2 (array): Arguments to the format string.
2285 ASSERT_EQ(args->length(), 3);
2286#ifdef ENABLE_LOGGING_AND_PROFILING
2287 if (CodeGenerator::ShouldGenerateLog(args->at(0))) {
2288 VisitForValue(args->at(1), kStack);
2289 VisitForValue(args->at(2), kStack);
2290 __ CallRuntime(Runtime::kLog, 2);
2291 }
2292#endif
2293 // Finally, we're expected to leave a value on the top of the stack.
2294 __ mov(eax, Factory::undefined_value());
2295 Apply(context_, eax);
2296}
2297
2298
2299void FullCodeGenerator::EmitRandomHeapNumber(ZoneList<Expression*>* args) {
2300 ASSERT(args->length() == 0);
2301
2302 Label slow_allocate_heapnumber;
2303 Label heapnumber_allocated;
2304
2305 __ AllocateHeapNumber(edi, ebx, ecx, &slow_allocate_heapnumber);
2306 __ jmp(&heapnumber_allocated);
2307
2308 __ bind(&slow_allocate_heapnumber);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002309 // Allocate a heap number.
2310 __ CallRuntime(Runtime::kNumberAlloc, 0);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002311 __ mov(edi, eax);
2312
2313 __ bind(&heapnumber_allocated);
2314
2315 __ PrepareCallCFunction(0, ebx);
2316 __ CallCFunction(ExternalReference::random_uint32_function(), 0);
2317
2318 // Convert 32 random bits in eax to 0.(32 random bits) in a double
2319 // by computing:
2320 // ( 1.(20 0s)(32 random bits) x 2^20 ) - (1.0 x 2^20)).
2321 // This is implemented on both SSE2 and FPU.
2322 if (CpuFeatures::IsSupported(SSE2)) {
2323 CpuFeatures::Scope fscope(SSE2);
2324 __ mov(ebx, Immediate(0x49800000)); // 1.0 x 2^20 as single.
2325 __ movd(xmm1, Operand(ebx));
2326 __ movd(xmm0, Operand(eax));
2327 __ cvtss2sd(xmm1, xmm1);
2328 __ pxor(xmm0, xmm1);
2329 __ subsd(xmm0, xmm1);
2330 __ movdbl(FieldOperand(edi, HeapNumber::kValueOffset), xmm0);
2331 } else {
2332 // 0x4130000000000000 is 1.0 x 2^20 as a double.
2333 __ mov(FieldOperand(edi, HeapNumber::kExponentOffset),
2334 Immediate(0x41300000));
2335 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), eax);
2336 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2337 __ mov(FieldOperand(edi, HeapNumber::kMantissaOffset), Immediate(0));
2338 __ fld_d(FieldOperand(edi, HeapNumber::kValueOffset));
2339 __ fsubp(1);
2340 __ fstp_d(FieldOperand(edi, HeapNumber::kValueOffset));
2341 }
2342 __ mov(eax, edi);
2343 Apply(context_, eax);
2344}
2345
2346
2347void FullCodeGenerator::EmitSubString(ZoneList<Expression*>* args) {
2348 // Load the arguments on the stack and call the stub.
2349 SubStringStub stub;
2350 ASSERT(args->length() == 3);
2351 VisitForValue(args->at(0), kStack);
2352 VisitForValue(args->at(1), kStack);
2353 VisitForValue(args->at(2), kStack);
2354 __ CallStub(&stub);
2355 Apply(context_, eax);
2356}
2357
2358
2359void FullCodeGenerator::EmitRegExpExec(ZoneList<Expression*>* args) {
2360 // Load the arguments on the stack and call the stub.
2361 RegExpExecStub stub;
2362 ASSERT(args->length() == 4);
2363 VisitForValue(args->at(0), kStack);
2364 VisitForValue(args->at(1), kStack);
2365 VisitForValue(args->at(2), kStack);
2366 VisitForValue(args->at(3), kStack);
2367 __ CallStub(&stub);
2368 Apply(context_, eax);
2369}
2370
2371
2372void FullCodeGenerator::EmitValueOf(ZoneList<Expression*>* args) {
2373 ASSERT(args->length() == 1);
2374
2375 VisitForValue(args->at(0), kAccumulator); // Load the object.
2376
2377 Label done;
2378 // If the object is a smi return the object.
2379 __ test(eax, Immediate(kSmiTagMask));
2380 __ j(zero, &done);
2381 // If the object is not a value type, return the object.
2382 __ CmpObjectType(eax, JS_VALUE_TYPE, ebx);
2383 __ j(not_equal, &done);
2384 __ mov(eax, FieldOperand(eax, JSValue::kValueOffset));
2385
2386 __ bind(&done);
2387 Apply(context_, eax);
2388}
2389
2390
2391void FullCodeGenerator::EmitMathPow(ZoneList<Expression*>* args) {
2392 // Load the arguments on the stack and call the runtime function.
2393 ASSERT(args->length() == 2);
2394 VisitForValue(args->at(0), kStack);
2395 VisitForValue(args->at(1), kStack);
2396 __ CallRuntime(Runtime::kMath_pow, 2);
2397 Apply(context_, eax);
2398}
2399
2400
2401void FullCodeGenerator::EmitSetValueOf(ZoneList<Expression*>* args) {
2402 ASSERT(args->length() == 2);
2403
2404 VisitForValue(args->at(0), kStack); // Load the object.
2405 VisitForValue(args->at(1), kAccumulator); // Load the value.
2406 __ pop(ebx); // eax = value. ebx = object.
2407
2408 Label done;
2409 // If the object is a smi, return the value.
2410 __ test(ebx, Immediate(kSmiTagMask));
2411 __ j(zero, &done);
2412
2413 // If the object is not a value type, return the value.
2414 __ CmpObjectType(ebx, JS_VALUE_TYPE, ecx);
2415 __ j(not_equal, &done);
2416
2417 // Store the value.
2418 __ mov(FieldOperand(ebx, JSValue::kValueOffset), eax);
2419 // Update the write barrier. Save the value as it will be
2420 // overwritten by the write barrier code and is needed afterward.
2421 __ mov(edx, eax);
2422 __ RecordWrite(ebx, JSValue::kValueOffset, edx, ecx);
2423
2424 __ bind(&done);
2425 Apply(context_, eax);
2426}
2427
2428
2429void FullCodeGenerator::EmitNumberToString(ZoneList<Expression*>* args) {
2430 ASSERT_EQ(args->length(), 1);
2431
2432 // Load the argument on the stack and call the stub.
2433 VisitForValue(args->at(0), kStack);
2434
2435 NumberToStringStub stub;
2436 __ CallStub(&stub);
2437 Apply(context_, eax);
2438}
2439
2440
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002441void FullCodeGenerator::EmitStringCharFromCode(ZoneList<Expression*>* args) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002442 ASSERT(args->length() == 1);
2443
2444 VisitForValue(args->at(0), kAccumulator);
2445
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002446 Label done;
2447 StringCharFromCodeGenerator generator(eax, ebx);
2448 generator.GenerateFast(masm_);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002449 __ jmp(&done);
2450
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002451 NopRuntimeCallHelper call_helper;
2452 generator.GenerateSlow(masm_, call_helper);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002453
2454 __ bind(&done);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002455 Apply(context_, ebx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002456}
2457
2458
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002459void FullCodeGenerator::EmitStringCharCodeAt(ZoneList<Expression*>* args) {
2460 ASSERT(args->length() == 2);
2461
2462 VisitForValue(args->at(0), kStack);
2463 VisitForValue(args->at(1), kAccumulator);
2464
2465 Register object = ebx;
2466 Register index = eax;
2467 Register scratch = ecx;
2468 Register result = edx;
2469
2470 __ pop(object);
2471
2472 Label need_conversion;
2473 Label index_out_of_range;
2474 Label done;
2475 StringCharCodeAtGenerator generator(object,
2476 index,
2477 scratch,
2478 result,
2479 &need_conversion,
2480 &need_conversion,
2481 &index_out_of_range,
2482 STRING_INDEX_IS_NUMBER);
2483 generator.GenerateFast(masm_);
2484 __ jmp(&done);
2485
2486 __ bind(&index_out_of_range);
2487 // When the index is out of range, the spec requires us to return
2488 // NaN.
2489 __ Set(result, Immediate(Factory::nan_value()));
2490 __ jmp(&done);
2491
2492 __ bind(&need_conversion);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002493 // Move the undefined value into the result register, which will
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002494 // trigger conversion.
2495 __ Set(result, Immediate(Factory::undefined_value()));
2496 __ jmp(&done);
2497
2498 NopRuntimeCallHelper call_helper;
2499 generator.GenerateSlow(masm_, call_helper);
2500
2501 __ bind(&done);
2502 Apply(context_, result);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002503}
2504
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002505
2506void FullCodeGenerator::EmitStringCharAt(ZoneList<Expression*>* args) {
2507 ASSERT(args->length() == 2);
2508
2509 VisitForValue(args->at(0), kStack);
2510 VisitForValue(args->at(1), kAccumulator);
2511
2512 Register object = ebx;
2513 Register index = eax;
2514 Register scratch1 = ecx;
2515 Register scratch2 = edx;
2516 Register result = eax;
2517
2518 __ pop(object);
2519
2520 Label need_conversion;
2521 Label index_out_of_range;
2522 Label done;
2523 StringCharAtGenerator generator(object,
2524 index,
2525 scratch1,
2526 scratch2,
2527 result,
2528 &need_conversion,
2529 &need_conversion,
2530 &index_out_of_range,
2531 STRING_INDEX_IS_NUMBER);
2532 generator.GenerateFast(masm_);
2533 __ jmp(&done);
2534
2535 __ bind(&index_out_of_range);
2536 // When the index is out of range, the spec requires us to return
2537 // the empty string.
2538 __ Set(result, Immediate(Factory::empty_string()));
2539 __ jmp(&done);
2540
2541 __ bind(&need_conversion);
2542 // Move smi zero into the result register, which will trigger
2543 // conversion.
2544 __ Set(result, Immediate(Smi::FromInt(0)));
2545 __ jmp(&done);
2546
2547 NopRuntimeCallHelper call_helper;
2548 generator.GenerateSlow(masm_, call_helper);
2549
2550 __ bind(&done);
2551 Apply(context_, result);
2552}
2553
2554
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002555void FullCodeGenerator::EmitStringAdd(ZoneList<Expression*>* args) {
2556 ASSERT_EQ(2, args->length());
2557
2558 VisitForValue(args->at(0), kStack);
2559 VisitForValue(args->at(1), kStack);
2560
2561 StringAddStub stub(NO_STRING_ADD_FLAGS);
2562 __ CallStub(&stub);
2563 Apply(context_, eax);
2564}
2565
2566
2567void FullCodeGenerator::EmitStringCompare(ZoneList<Expression*>* args) {
2568 ASSERT_EQ(2, args->length());
2569
2570 VisitForValue(args->at(0), kStack);
2571 VisitForValue(args->at(1), kStack);
2572
2573 StringCompareStub stub;
2574 __ CallStub(&stub);
2575 Apply(context_, eax);
2576}
2577
2578
2579void FullCodeGenerator::EmitMathSin(ZoneList<Expression*>* args) {
2580 // Load the argument on the stack and call the stub.
2581 TranscendentalCacheStub stub(TranscendentalCache::SIN);
2582 ASSERT(args->length() == 1);
2583 VisitForValue(args->at(0), kStack);
2584 __ CallStub(&stub);
2585 Apply(context_, eax);
2586}
2587
2588
2589void FullCodeGenerator::EmitMathCos(ZoneList<Expression*>* args) {
2590 // Load the argument on the stack and call the stub.
2591 TranscendentalCacheStub stub(TranscendentalCache::COS);
2592 ASSERT(args->length() == 1);
2593 VisitForValue(args->at(0), kStack);
2594 __ CallStub(&stub);
2595 Apply(context_, eax);
2596}
2597
2598
2599void FullCodeGenerator::EmitMathSqrt(ZoneList<Expression*>* args) {
2600 // Load the argument on the stack and call the runtime function.
2601 ASSERT(args->length() == 1);
2602 VisitForValue(args->at(0), kStack);
2603 __ CallRuntime(Runtime::kMath_sqrt, 1);
2604 Apply(context_, eax);
2605}
2606
2607
2608void FullCodeGenerator::EmitCallFunction(ZoneList<Expression*>* args) {
2609 ASSERT(args->length() >= 2);
2610
2611 int arg_count = args->length() - 2; // For receiver and function.
2612 VisitForValue(args->at(0), kStack); // Receiver.
2613 for (int i = 0; i < arg_count; i++) {
2614 VisitForValue(args->at(i + 1), kStack);
2615 }
2616 VisitForValue(args->at(arg_count + 1), kAccumulator); // Function.
2617
2618 // InvokeFunction requires function in edi. Move it in there.
2619 if (!result_register().is(edi)) __ mov(edi, result_register());
2620 ParameterCount count(arg_count);
2621 __ InvokeFunction(edi, count, CALL_FUNCTION);
2622 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2623 Apply(context_, eax);
2624}
2625
2626
2627void FullCodeGenerator::EmitRegExpConstructResult(ZoneList<Expression*>* args) {
2628 ASSERT(args->length() == 3);
2629 VisitForValue(args->at(0), kStack);
2630 VisitForValue(args->at(1), kStack);
2631 VisitForValue(args->at(2), kStack);
2632 __ CallRuntime(Runtime::kRegExpConstructResult, 3);
2633 Apply(context_, eax);
2634}
2635
2636
2637void FullCodeGenerator::EmitSwapElements(ZoneList<Expression*>* args) {
2638 ASSERT(args->length() == 3);
2639 VisitForValue(args->at(0), kStack);
2640 VisitForValue(args->at(1), kStack);
2641 VisitForValue(args->at(2), kStack);
2642 __ CallRuntime(Runtime::kSwapElements, 3);
2643 Apply(context_, eax);
2644}
2645
2646
2647void FullCodeGenerator::EmitGetFromCache(ZoneList<Expression*>* args) {
2648 ASSERT_EQ(2, args->length());
2649
2650 ASSERT_NE(NULL, args->at(0)->AsLiteral());
2651 int cache_id = Smi::cast(*(args->at(0)->AsLiteral()->handle()))->value();
2652
2653 Handle<FixedArray> jsfunction_result_caches(
2654 Top::global_context()->jsfunction_result_caches());
2655 if (jsfunction_result_caches->length() <= cache_id) {
2656 __ Abort("Attempt to use undefined cache.");
2657 __ mov(eax, Factory::undefined_value());
2658 Apply(context_, eax);
2659 return;
2660 }
2661
2662 VisitForValue(args->at(1), kAccumulator);
2663
2664 Register key = eax;
2665 Register cache = ebx;
2666 Register tmp = ecx;
2667 __ mov(cache, CodeGenerator::ContextOperand(esi, Context::GLOBAL_INDEX));
2668 __ mov(cache,
2669 FieldOperand(cache, GlobalObject::kGlobalContextOffset));
2670 __ mov(cache,
2671 CodeGenerator::ContextOperand(
2672 cache, Context::JSFUNCTION_RESULT_CACHES_INDEX));
2673 __ mov(cache,
2674 FieldOperand(cache, FixedArray::OffsetOfElementAt(cache_id)));
2675
2676 Label done, not_found;
2677 // tmp now holds finger offset as a smi.
2678 ASSERT(kSmiTag == 0 && kSmiTagSize == 1);
2679 __ mov(tmp, FieldOperand(cache, JSFunctionResultCache::kFingerOffset));
2680 __ cmp(key, CodeGenerator::FixedArrayElementOperand(cache, tmp));
2681 __ j(not_equal, &not_found);
2682
2683 __ mov(eax, CodeGenerator::FixedArrayElementOperand(cache, tmp, 1));
2684 __ jmp(&done);
2685
2686 __ bind(&not_found);
2687 // Call runtime to perform the lookup.
2688 __ push(cache);
2689 __ push(key);
2690 __ CallRuntime(Runtime::kGetFromCache, 2);
2691
2692 __ bind(&done);
2693 Apply(context_, eax);
2694}
2695
2696
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00002697void FullCodeGenerator::EmitIsRegExpEquivalent(ZoneList<Expression*>* args) {
2698 ASSERT_EQ(2, args->length());
2699
2700 Register right = eax;
2701 Register left = ebx;
2702 Register tmp = ecx;
2703
2704 VisitForValue(args->at(0), kStack);
2705 VisitForValue(args->at(1), kAccumulator);
2706 __ pop(left);
2707
2708 Label done, fail, ok;
2709 __ cmp(left, Operand(right));
2710 __ j(equal, &ok);
2711 // Fail if either is a non-HeapObject.
2712 __ mov(tmp, left);
2713 __ and_(Operand(tmp), right);
2714 __ test(Operand(tmp), Immediate(kSmiTagMask));
2715 __ j(zero, &fail);
lrn@chromium.org19375882010-08-09 12:49:57 +00002716 __ CmpObjectType(left, JS_REGEXP_TYPE, tmp);
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00002717 __ j(not_equal, &fail);
2718 __ cmp(tmp, FieldOperand(right, HeapObject::kMapOffset));
2719 __ j(not_equal, &fail);
2720 __ mov(tmp, FieldOperand(left, JSRegExp::kDataOffset));
2721 __ cmp(tmp, FieldOperand(right, JSRegExp::kDataOffset));
2722 __ j(equal, &ok);
2723 __ bind(&fail);
2724 __ mov(eax, Immediate(Factory::false_value()));
2725 __ jmp(&done);
2726 __ bind(&ok);
2727 __ mov(eax, Immediate(Factory::true_value()));
2728 __ bind(&done);
2729
2730 Apply(context_, eax);
2731}
2732
2733
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002734void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002735 Handle<String> name = expr->name();
2736 if (name->length() > 0 && name->Get(0) == '_') {
2737 Comment cmnt(masm_, "[ InlineRuntimeCall");
2738 EmitInlineRuntimeCall(expr);
2739 return;
2740 }
2741
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002742 Comment cmnt(masm_, "[ CallRuntime");
2743 ZoneList<Expression*>* args = expr->arguments();
2744
2745 if (expr->is_jsruntime()) {
2746 // Prepare for calling JS runtime function.
2747 __ mov(eax, CodeGenerator::GlobalObject());
2748 __ push(FieldOperand(eax, GlobalObject::kBuiltinsOffset));
2749 }
2750
2751 // Push the arguments ("left-to-right").
2752 int arg_count = args->length();
2753 for (int i = 0; i < arg_count; i++) {
2754 VisitForValue(args->at(i), kStack);
2755 }
2756
2757 if (expr->is_jsruntime()) {
2758 // Call the JS runtime function via a call IC.
2759 __ Set(ecx, Immediate(expr->name()));
2760 InLoopFlag in_loop = (loop_depth() > 0) ? IN_LOOP : NOT_IN_LOOP;
2761 Handle<Code> ic = CodeGenerator::ComputeCallInitialize(arg_count, in_loop);
2762 __ call(ic, RelocInfo::CODE_TARGET);
2763 // Restore context register.
2764 __ mov(esi, Operand(ebp, StandardFrameConstants::kContextOffset));
2765 } else {
2766 // Call the C runtime function.
2767 __ CallRuntime(expr->function(), arg_count);
2768 }
2769 Apply(context_, eax);
2770}
2771
2772
2773void FullCodeGenerator::VisitUnaryOperation(UnaryOperation* expr) {
2774 switch (expr->op()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002775 case Token::DELETE: {
2776 Comment cmnt(masm_, "[ UnaryOperation (DELETE)");
2777 Property* prop = expr->expression()->AsProperty();
2778 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
2779 if (prop == NULL && var == NULL) {
2780 // Result of deleting non-property, non-variable reference is true.
2781 // The subexpression may have side effects.
2782 VisitForEffect(expr->expression());
2783 Apply(context_, true);
2784 } else if (var != NULL &&
2785 !var->is_global() &&
2786 var->slot() != NULL &&
2787 var->slot()->type() != Slot::LOOKUP) {
2788 // Result of deleting non-global, non-dynamic variables is false.
2789 // The subexpression does not have side effects.
2790 Apply(context_, false);
2791 } else {
2792 // Property or variable reference. Call the delete builtin with
2793 // object and property name as arguments.
2794 if (prop != NULL) {
2795 VisitForValue(prop->obj(), kStack);
2796 VisitForValue(prop->key(), kStack);
2797 } else if (var->is_global()) {
2798 __ push(CodeGenerator::GlobalObject());
2799 __ push(Immediate(var->name()));
2800 } else {
2801 // Non-global variable. Call the runtime to look up the context
2802 // where the variable was introduced.
2803 __ push(context_register());
2804 __ push(Immediate(var->name()));
2805 __ CallRuntime(Runtime::kLookupContext, 2);
2806 __ push(eax);
2807 __ push(Immediate(var->name()));
2808 }
2809 __ InvokeBuiltin(Builtins::DELETE, CALL_FUNCTION);
2810 Apply(context_, eax);
2811 }
2812 break;
2813 }
2814
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002815 case Token::VOID: {
2816 Comment cmnt(masm_, "[ UnaryOperation (VOID)");
2817 VisitForEffect(expr->expression());
2818 switch (context_) {
2819 case Expression::kUninitialized:
2820 UNREACHABLE();
2821 break;
2822 case Expression::kEffect:
2823 break;
2824 case Expression::kValue:
2825 switch (location_) {
2826 case kAccumulator:
2827 __ mov(result_register(), Factory::undefined_value());
2828 break;
2829 case kStack:
2830 __ push(Immediate(Factory::undefined_value()));
2831 break;
2832 }
2833 break;
2834 case Expression::kTestValue:
2835 // Value is false so it's needed.
2836 switch (location_) {
2837 case kAccumulator:
2838 __ mov(result_register(), Factory::undefined_value());
2839 break;
2840 case kStack:
2841 __ push(Immediate(Factory::undefined_value()));
2842 break;
2843 }
2844 // Fall through.
2845 case Expression::kTest:
2846 case Expression::kValueTest:
2847 __ jmp(false_label_);
2848 break;
2849 }
2850 break;
2851 }
2852
2853 case Token::NOT: {
2854 Comment cmnt(masm_, "[ UnaryOperation (NOT)");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002855 Label materialize_true, materialize_false;
2856 Label* if_true = NULL;
2857 Label* if_false = NULL;
2858
2859 // Notice that the labels are swapped.
2860 PrepareTest(&materialize_true, &materialize_false, &if_false, &if_true);
2861
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002862 VisitForControl(expr->expression(), if_true, if_false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002863
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002864 Apply(context_, if_false, if_true); // Labels swapped.
2865 break;
2866 }
2867
2868 case Token::TYPEOF: {
2869 Comment cmnt(masm_, "[ UnaryOperation (TYPEOF)");
2870 VariableProxy* proxy = expr->expression()->AsVariableProxy();
2871 if (proxy != NULL &&
2872 !proxy->var()->is_this() &&
2873 proxy->var()->is_global()) {
2874 Comment cmnt(masm_, "Global variable");
ager@chromium.org5c838252010-02-19 08:53:10 +00002875 __ mov(eax, CodeGenerator::GlobalObject());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002876 __ mov(ecx, Immediate(proxy->name()));
2877 Handle<Code> ic(Builtins::builtin(Builtins::LoadIC_Initialize));
2878 // Use a regular load, not a contextual load, to avoid a reference
2879 // error.
2880 __ call(ic, RelocInfo::CODE_TARGET);
ager@chromium.org5c838252010-02-19 08:53:10 +00002881 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002882 } else if (proxy != NULL &&
2883 proxy->var()->slot() != NULL &&
2884 proxy->var()->slot()->type() == Slot::LOOKUP) {
2885 __ push(esi);
2886 __ push(Immediate(proxy->name()));
2887 __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
2888 __ push(eax);
2889 } else {
2890 // This expression cannot throw a reference error at the top level.
2891 VisitForValue(expr->expression(), kStack);
2892 }
2893
2894 __ CallRuntime(Runtime::kTypeof, 1);
2895 Apply(context_, eax);
2896 break;
2897 }
2898
2899 case Token::ADD: {
2900 Comment cmt(masm_, "[ UnaryOperation (ADD)");
2901 VisitForValue(expr->expression(), kAccumulator);
2902 Label no_conversion;
2903 __ test(result_register(), Immediate(kSmiTagMask));
2904 __ j(zero, &no_conversion);
2905 __ push(result_register());
2906 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
2907 __ bind(&no_conversion);
2908 Apply(context_, result_register());
2909 break;
2910 }
2911
2912 case Token::SUB: {
2913 Comment cmt(masm_, "[ UnaryOperation (SUB)");
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002914 bool can_overwrite =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002915 (expr->expression()->AsBinaryOperation() != NULL &&
2916 expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002917 UnaryOverwriteMode overwrite =
2918 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002919 GenericUnaryOpStub stub(Token::SUB, overwrite);
2920 // GenericUnaryOpStub expects the argument to be in the
2921 // accumulator register eax.
2922 VisitForValue(expr->expression(), kAccumulator);
2923 __ CallStub(&stub);
2924 Apply(context_, eax);
2925 break;
2926 }
2927
2928 case Token::BIT_NOT: {
2929 Comment cmt(masm_, "[ UnaryOperation (BIT_NOT)");
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002930 bool can_overwrite =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002931 (expr->expression()->AsBinaryOperation() != NULL &&
2932 expr->expression()->AsBinaryOperation()->ResultOverwriteAllowed());
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00002933 UnaryOverwriteMode overwrite =
2934 can_overwrite ? UNARY_OVERWRITE : UNARY_NO_OVERWRITE;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002935 GenericUnaryOpStub stub(Token::BIT_NOT, overwrite);
2936 // GenericUnaryOpStub expects the argument to be in the
2937 // accumulator register eax.
2938 VisitForValue(expr->expression(), kAccumulator);
2939 // Avoid calling the stub for Smis.
2940 Label smi, done;
2941 __ test(result_register(), Immediate(kSmiTagMask));
2942 __ j(zero, &smi);
2943 // Non-smi: call stub leaving result in accumulator register.
2944 __ CallStub(&stub);
2945 __ jmp(&done);
2946 // Perform operation directly on Smis.
2947 __ bind(&smi);
2948 __ not_(result_register());
2949 __ and_(result_register(), ~kSmiTagMask); // Remove inverted smi-tag.
2950 __ bind(&done);
2951 Apply(context_, result_register());
2952 break;
2953 }
2954
2955 default:
2956 UNREACHABLE();
2957 }
2958}
2959
2960
2961void FullCodeGenerator::VisitCountOperation(CountOperation* expr) {
2962 Comment cmnt(masm_, "[ CountOperation");
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002963 // Invalid left-hand sides are rewritten to have a 'throw ReferenceError'
2964 // as the left-hand side.
2965 if (!expr->expression()->IsValidLeftHandSide()) {
2966 VisitForEffect(expr->expression());
2967 return;
2968 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002969
2970 // Expression can only be a property, a global or a (parameter or local)
2971 // slot. Variables with rewrite to .arguments are treated as KEYED_PROPERTY.
2972 enum LhsKind { VARIABLE, NAMED_PROPERTY, KEYED_PROPERTY };
2973 LhsKind assign_type = VARIABLE;
2974 Property* prop = expr->expression()->AsProperty();
2975 // In case of a property we use the uninitialized expression context
2976 // of the key to detect a named property.
2977 if (prop != NULL) {
2978 assign_type =
2979 (prop->key()->IsPropertyName()) ? NAMED_PROPERTY : KEYED_PROPERTY;
2980 }
2981
2982 // Evaluate expression and get value.
2983 if (assign_type == VARIABLE) {
2984 ASSERT(expr->expression()->AsVariableProxy()->var() != NULL);
2985 Location saved_location = location_;
2986 location_ = kAccumulator;
2987 EmitVariableLoad(expr->expression()->AsVariableProxy()->var(),
2988 Expression::kValue);
2989 location_ = saved_location;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00002990 } else {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002991 // Reserve space for result of postfix operation.
2992 if (expr->is_postfix() && context_ != Expression::kEffect) {
2993 __ push(Immediate(Smi::FromInt(0)));
2994 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002995 if (assign_type == NAMED_PROPERTY) {
ager@chromium.org5c838252010-02-19 08:53:10 +00002996 // Put the object both on the stack and in the accumulator.
2997 VisitForValue(prop->obj(), kAccumulator);
2998 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002999 EmitNamedPropertyLoad(prop);
3000 } else {
ager@chromium.org5c838252010-02-19 08:53:10 +00003001 VisitForValue(prop->obj(), kStack);
3002 VisitForValue(prop->key(), kAccumulator);
3003 __ mov(edx, Operand(esp, 0));
3004 __ push(eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003005 EmitKeyedPropertyLoad(prop);
3006 }
3007 }
3008
3009 // Call ToNumber only if operand is not a smi.
3010 Label no_conversion;
3011 __ test(eax, Immediate(kSmiTagMask));
3012 __ j(zero, &no_conversion);
3013 __ push(eax);
3014 __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_FUNCTION);
3015 __ bind(&no_conversion);
3016
3017 // Save result for postfix expressions.
3018 if (expr->is_postfix()) {
3019 switch (context_) {
3020 case Expression::kUninitialized:
3021 UNREACHABLE();
3022 case Expression::kEffect:
3023 // Do not save result.
3024 break;
3025 case Expression::kValue:
3026 case Expression::kTest:
3027 case Expression::kValueTest:
3028 case Expression::kTestValue:
3029 // Save the result on the stack. If we have a named or keyed property
3030 // we store the result under the receiver that is currently on top
3031 // of the stack.
3032 switch (assign_type) {
3033 case VARIABLE:
3034 __ push(eax);
3035 break;
3036 case NAMED_PROPERTY:
3037 __ mov(Operand(esp, kPointerSize), eax);
3038 break;
3039 case KEYED_PROPERTY:
3040 __ mov(Operand(esp, 2 * kPointerSize), eax);
3041 break;
3042 }
3043 break;
3044 }
3045 }
3046
3047 // Inline smi case if we are in a loop.
3048 Label stub_call, done;
3049 if (loop_depth() > 0) {
3050 if (expr->op() == Token::INC) {
3051 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3052 } else {
3053 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3054 }
3055 __ j(overflow, &stub_call);
3056 // We could eliminate this smi check if we split the code at
3057 // the first smi check before calling ToNumber.
3058 __ test(eax, Immediate(kSmiTagMask));
3059 __ j(zero, &done);
3060 __ bind(&stub_call);
3061 // Call stub. Undo operation first.
3062 if (expr->op() == Token::INC) {
3063 __ sub(Operand(eax), Immediate(Smi::FromInt(1)));
3064 } else {
3065 __ add(Operand(eax), Immediate(Smi::FromInt(1)));
3066 }
3067 }
3068 // Call stub for +1/-1.
3069 GenericBinaryOpStub stub(expr->binary_op(),
3070 NO_OVERWRITE,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003071 NO_GENERIC_BINARY_FLAGS,
sgjesse@chromium.orgdf7a2842010-03-25 14:34:15 +00003072 TypeInfo::Unknown());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003073 stub.GenerateCall(masm(), eax, Smi::FromInt(1));
3074 __ bind(&done);
3075
3076 // Store the value returned in eax.
3077 switch (assign_type) {
3078 case VARIABLE:
3079 if (expr->is_postfix()) {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003080 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003081 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003082 Token::ASSIGN,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003083 Expression::kEffect);
3084 // For all contexts except kEffect: We have the result on
3085 // top of the stack.
3086 if (context_ != Expression::kEffect) {
3087 ApplyTOS(context_);
3088 }
3089 } else {
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003090 // Perform the assignment as if via '='.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003091 EmitVariableAssignment(expr->expression()->AsVariableProxy()->var(),
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003092 Token::ASSIGN,
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003093 context_);
3094 }
3095 break;
3096 case NAMED_PROPERTY: {
3097 __ mov(ecx, prop->key()->AsLiteral()->handle());
3098 __ pop(edx);
3099 Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
3100 __ call(ic, RelocInfo::CODE_TARGET);
3101 // This nop signals to the IC that there is no inlined code at the call
3102 // site for it to patch.
3103 __ nop();
3104 if (expr->is_postfix()) {
3105 if (context_ != Expression::kEffect) {
3106 ApplyTOS(context_);
3107 }
3108 } else {
3109 Apply(context_, eax);
3110 }
3111 break;
3112 }
3113 case KEYED_PROPERTY: {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003114 __ pop(ecx);
3115 __ pop(edx);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003116 Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
3117 __ call(ic, RelocInfo::CODE_TARGET);
3118 // This nop signals to the IC that there is no inlined code at the call
3119 // site for it to patch.
3120 __ nop();
3121 if (expr->is_postfix()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003122 // Result is on the stack
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003123 if (context_ != Expression::kEffect) {
3124 ApplyTOS(context_);
3125 }
3126 } else {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003127 Apply(context_, eax);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003128 }
3129 break;
3130 }
3131 }
3132}
3133
3134
3135void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
3136 Comment cmnt(masm_, "[ BinaryOperation");
3137 switch (expr->op()) {
3138 case Token::COMMA:
3139 VisitForEffect(expr->left());
3140 Visit(expr->right());
3141 break;
3142
3143 case Token::OR:
3144 case Token::AND:
3145 EmitLogicalOperation(expr);
3146 break;
3147
3148 case Token::ADD:
3149 case Token::SUB:
3150 case Token::DIV:
3151 case Token::MOD:
3152 case Token::MUL:
3153 case Token::BIT_OR:
3154 case Token::BIT_AND:
3155 case Token::BIT_XOR:
3156 case Token::SHL:
3157 case Token::SHR:
3158 case Token::SAR:
3159 VisitForValue(expr->left(), kStack);
3160 VisitForValue(expr->right(), kAccumulator);
3161 EmitBinaryOp(expr->op(), context_);
3162 break;
3163
3164 default:
3165 UNREACHABLE();
3166 }
3167}
3168
3169
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003170void FullCodeGenerator::EmitNullCompare(bool strict,
3171 Register obj,
3172 Register null_const,
3173 Label* if_true,
3174 Label* if_false,
3175 Register scratch) {
3176 __ cmp(obj, Operand(null_const));
3177 if (strict) {
3178 __ j(equal, if_true);
3179 } else {
3180 __ j(equal, if_true);
3181 __ cmp(obj, Factory::undefined_value());
3182 __ j(equal, if_true);
3183 __ test(obj, Immediate(kSmiTagMask));
3184 __ j(zero, if_false);
3185 // It can be an undetectable object.
3186 __ mov(scratch, FieldOperand(obj, HeapObject::kMapOffset));
3187 __ movzx_b(scratch, FieldOperand(scratch, Map::kBitFieldOffset));
3188 __ test(scratch, Immediate(1 << Map::kIsUndetectable));
3189 __ j(not_zero, if_true);
3190 }
3191 __ jmp(if_false);
3192}
3193
3194
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003195void FullCodeGenerator::VisitCompareOperation(CompareOperation* expr) {
3196 Comment cmnt(masm_, "[ CompareOperation");
3197
3198 // Always perform the comparison for its control flow. Pack the result
3199 // into the expression's context after the comparison is performed.
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003200
3201 Label materialize_true, materialize_false;
3202 Label* if_true = NULL;
3203 Label* if_false = NULL;
3204 PrepareTest(&materialize_true, &materialize_false, &if_true, &if_false);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003205
3206 VisitForValue(expr->left(), kStack);
3207 switch (expr->op()) {
3208 case Token::IN:
3209 VisitForValue(expr->right(), kStack);
3210 __ InvokeBuiltin(Builtins::IN, CALL_FUNCTION);
3211 __ cmp(eax, Factory::true_value());
3212 __ j(equal, if_true);
3213 __ jmp(if_false);
3214 break;
3215
3216 case Token::INSTANCEOF: {
3217 VisitForValue(expr->right(), kStack);
3218 InstanceofStub stub;
3219 __ CallStub(&stub);
3220 __ test(eax, Operand(eax));
3221 __ j(zero, if_true); // The stub returns 0 for true.
3222 __ jmp(if_false);
3223 break;
3224 }
3225
3226 default: {
3227 VisitForValue(expr->right(), kAccumulator);
3228 Condition cc = no_condition;
3229 bool strict = false;
3230 switch (expr->op()) {
3231 case Token::EQ_STRICT:
3232 strict = true;
3233 // Fall through
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003234 case Token::EQ: {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003235 cc = equal;
3236 __ pop(edx);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003237 // If either operand is constant null we do a fast compare
3238 // against null.
3239 Literal* right_literal = expr->right()->AsLiteral();
3240 Literal* left_literal = expr->left()->AsLiteral();
3241 if (right_literal != NULL && right_literal->handle()->IsNull()) {
3242 EmitNullCompare(strict, edx, eax, if_true, if_false, ecx);
3243 Apply(context_, if_true, if_false);
3244 return;
3245 } else if (left_literal != NULL && left_literal->handle()->IsNull()) {
3246 EmitNullCompare(strict, eax, edx, if_true, if_false, ecx);
3247 Apply(context_, if_true, if_false);
3248 return;
3249 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003250 break;
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003251 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00003252 case Token::LT:
3253 cc = less;
3254 __ pop(edx);
3255 break;
3256 case Token::GT:
3257 // Reverse left and right sizes to obtain ECMA-262 conversion order.
3258 cc = less;
3259 __ mov(edx, result_register());
3260 __ pop(eax);
3261 break;
3262 case Token::LTE:
3263 // Reverse left and right sizes to obtain ECMA-262 conversion order.
3264 cc = greater_equal;
3265 __ mov(edx, result_register());
3266 __ pop(eax);
3267 break;
3268 case Token::GTE:
3269 cc = greater_equal;
3270 __ pop(edx);
3271 break;
3272 case Token::IN:
3273 case Token::INSTANCEOF:
3274 default:
3275 UNREACHABLE();
3276 }
3277
3278 // The comparison stub expects the smi vs. smi case to be handled
3279 // before it is called.
3280 Label slow_case;
3281 __ mov(ecx, Operand(edx));
3282 __ or_(ecx, Operand(eax));
3283 __ test(ecx, Immediate(kSmiTagMask));
3284 __ j(not_zero, &slow_case, not_taken);
3285 __ cmp(edx, Operand(eax));
3286 __ j(cc, if_true);
3287 __ jmp(if_false);
3288
3289 __ bind(&slow_case);
3290 CompareStub stub(cc, strict);
3291 __ CallStub(&stub);
3292 __ test(eax, Operand(eax));
3293 __ j(cc, if_true);
3294 __ jmp(if_false);
3295 }
3296 }
3297
3298 // Convert the result of the comparison into one expected for this
3299 // expression's context.
3300 Apply(context_, if_true, if_false);
3301}
3302
3303
3304void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
3305 __ mov(eax, Operand(ebp, JavaScriptFrameConstants::kFunctionOffset));
3306 Apply(context_, eax);
3307}
3308
3309
3310Register FullCodeGenerator::result_register() { return eax; }
3311
3312
3313Register FullCodeGenerator::context_register() { return esi; }
3314
3315
3316void FullCodeGenerator::StoreToFrameField(int frame_offset, Register value) {
3317 ASSERT_EQ(POINTER_SIZE_ALIGN(frame_offset), frame_offset);
3318 __ mov(Operand(ebp, frame_offset), value);
3319}
3320
3321
3322void FullCodeGenerator::LoadContextField(Register dst, int context_index) {
3323 __ mov(dst, CodeGenerator::ContextOperand(esi, context_index));
3324}
3325
3326
3327// ----------------------------------------------------------------------------
3328// Non-local control flow support.
3329
3330void FullCodeGenerator::EnterFinallyBlock() {
3331 // Cook return address on top of stack (smi encoded Code* delta)
3332 ASSERT(!result_register().is(edx));
3333 __ mov(edx, Operand(esp, 0));
3334 __ sub(Operand(edx), Immediate(masm_->CodeObject()));
3335 ASSERT_EQ(1, kSmiTagSize + kSmiShiftSize);
3336 ASSERT_EQ(0, kSmiTag);
3337 __ add(edx, Operand(edx)); // Convert to smi.
3338 __ mov(Operand(esp, 0), edx);
3339 // Store result register while executing finally block.
3340 __ push(result_register());
3341}
3342
3343
3344void FullCodeGenerator::ExitFinallyBlock() {
3345 ASSERT(!result_register().is(edx));
3346 // Restore result register from stack.
3347 __ pop(result_register());
3348 // Uncook return address.
3349 __ mov(edx, Operand(esp, 0));
3350 __ sar(edx, 1); // Convert smi to int.
3351 __ add(Operand(edx), Immediate(masm_->CodeObject()));
3352 __ mov(Operand(esp, 0), edx);
3353 // And return.
3354 __ ret(0);
3355}
3356
3357
3358#undef __
3359
3360} } // namespace v8::internal
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00003361
3362#endif // V8_TARGET_ARCH_IA32