blob: 63714392cd8768af8e9956d8298e9757133143cf [file] [log] [blame]
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29
30#include "codegen-inl.h"
31#include "compiler.h"
32#include "full-codegen.h"
33#include "stub-cache.h"
34#include "debug.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000035#include "liveedit.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000036
37namespace v8 {
38namespace internal {
39
40#define BAILOUT(reason) \
41 do { \
42 if (FLAG_trace_bailout) { \
43 PrintF("%s\n", reason); \
44 } \
45 has_supported_syntax_ = false; \
46 return; \
47 } while (false)
48
49
50#define CHECK_BAILOUT \
51 do { \
52 if (!has_supported_syntax_) return; \
53 } while (false)
54
55
56void FullCodeGenSyntaxChecker::Check(FunctionLiteral* fun) {
57 Scope* scope = fun->scope();
58 VisitDeclarations(scope->declarations());
59 CHECK_BAILOUT;
60
61 VisitStatements(fun->body());
62}
63
64
65void FullCodeGenSyntaxChecker::VisitDeclarations(
66 ZoneList<Declaration*>* decls) {
67 for (int i = 0; i < decls->length(); i++) {
68 Visit(decls->at(i));
69 CHECK_BAILOUT;
70 }
71}
72
73
74void FullCodeGenSyntaxChecker::VisitStatements(ZoneList<Statement*>* stmts) {
75 for (int i = 0, len = stmts->length(); i < len; i++) {
76 Visit(stmts->at(i));
77 CHECK_BAILOUT;
78 }
79}
80
81
82void FullCodeGenSyntaxChecker::VisitDeclaration(Declaration* decl) {
83 Property* prop = decl->proxy()->AsProperty();
84 if (prop != NULL) {
85 Visit(prop->obj());
86 Visit(prop->key());
87 }
88
89 if (decl->fun() != NULL) {
90 Visit(decl->fun());
91 }
92}
93
94
95void FullCodeGenSyntaxChecker::VisitBlock(Block* stmt) {
96 VisitStatements(stmt->statements());
97}
98
99
100void FullCodeGenSyntaxChecker::VisitExpressionStatement(
101 ExpressionStatement* stmt) {
102 Visit(stmt->expression());
103}
104
105
106void FullCodeGenSyntaxChecker::VisitEmptyStatement(EmptyStatement* stmt) {
107 // Supported.
108}
109
110
111void FullCodeGenSyntaxChecker::VisitIfStatement(IfStatement* stmt) {
112 Visit(stmt->condition());
113 CHECK_BAILOUT;
114 Visit(stmt->then_statement());
115 CHECK_BAILOUT;
116 Visit(stmt->else_statement());
117}
118
119
120void FullCodeGenSyntaxChecker::VisitContinueStatement(ContinueStatement* stmt) {
121 // Supported.
122}
123
124
125void FullCodeGenSyntaxChecker::VisitBreakStatement(BreakStatement* stmt) {
126 // Supported.
127}
128
129
130void FullCodeGenSyntaxChecker::VisitReturnStatement(ReturnStatement* stmt) {
131 Visit(stmt->expression());
132}
133
134
135void FullCodeGenSyntaxChecker::VisitWithEnterStatement(
136 WithEnterStatement* stmt) {
137 Visit(stmt->expression());
138}
139
140
141void FullCodeGenSyntaxChecker::VisitWithExitStatement(WithExitStatement* stmt) {
142 // Supported.
143}
144
145
146void FullCodeGenSyntaxChecker::VisitSwitchStatement(SwitchStatement* stmt) {
147 BAILOUT("SwitchStatement");
148}
149
150
151void FullCodeGenSyntaxChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
152 Visit(stmt->cond());
153 CHECK_BAILOUT;
154 Visit(stmt->body());
155}
156
157
158void FullCodeGenSyntaxChecker::VisitWhileStatement(WhileStatement* stmt) {
159 Visit(stmt->cond());
160 CHECK_BAILOUT;
161 Visit(stmt->body());
162}
163
164
165void FullCodeGenSyntaxChecker::VisitForStatement(ForStatement* stmt) {
166 if (!FLAG_always_full_compiler) BAILOUT("ForStatement");
167 if (stmt->init() != NULL) {
168 Visit(stmt->init());
169 CHECK_BAILOUT;
170 }
171 if (stmt->cond() != NULL) {
172 Visit(stmt->cond());
173 CHECK_BAILOUT;
174 }
175 Visit(stmt->body());
176 if (stmt->next() != NULL) {
177 CHECK_BAILOUT;
178 Visit(stmt->next());
179 }
180}
181
182
183void FullCodeGenSyntaxChecker::VisitForInStatement(ForInStatement* stmt) {
184 BAILOUT("ForInStatement");
185}
186
187
188void FullCodeGenSyntaxChecker::VisitTryCatchStatement(TryCatchStatement* stmt) {
189 Visit(stmt->try_block());
190 CHECK_BAILOUT;
191 Visit(stmt->catch_block());
192}
193
194
195void FullCodeGenSyntaxChecker::VisitTryFinallyStatement(
196 TryFinallyStatement* stmt) {
197 Visit(stmt->try_block());
198 CHECK_BAILOUT;
199 Visit(stmt->finally_block());
200}
201
202
203void FullCodeGenSyntaxChecker::VisitDebuggerStatement(
204 DebuggerStatement* stmt) {
205 // Supported.
206}
207
208
209void FullCodeGenSyntaxChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
210 // Supported.
211}
212
213
214void FullCodeGenSyntaxChecker::VisitFunctionBoilerplateLiteral(
215 FunctionBoilerplateLiteral* expr) {
216 BAILOUT("FunctionBoilerplateLiteral");
217}
218
219
220void FullCodeGenSyntaxChecker::VisitConditional(Conditional* expr) {
221 Visit(expr->condition());
222 CHECK_BAILOUT;
223 Visit(expr->then_expression());
224 CHECK_BAILOUT;
225 Visit(expr->else_expression());
226}
227
228
229void FullCodeGenSyntaxChecker::VisitSlot(Slot* expr) {
230 UNREACHABLE();
231}
232
233
234void FullCodeGenSyntaxChecker::VisitVariableProxy(VariableProxy* expr) {
235 // Supported.
236}
237
238
239void FullCodeGenSyntaxChecker::VisitLiteral(Literal* expr) {
240 // Supported.
241}
242
243
244void FullCodeGenSyntaxChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
245 // Supported.
246}
247
248
249void FullCodeGenSyntaxChecker::VisitObjectLiteral(ObjectLiteral* expr) {
250 ZoneList<ObjectLiteral::Property*>* properties = expr->properties();
251
252 for (int i = 0, len = properties->length(); i < len; i++) {
253 ObjectLiteral::Property* property = properties->at(i);
254 if (property->IsCompileTimeValue()) continue;
255 Visit(property->key());
256 CHECK_BAILOUT;
257 Visit(property->value());
258 CHECK_BAILOUT;
259 }
260}
261
262
263void FullCodeGenSyntaxChecker::VisitArrayLiteral(ArrayLiteral* expr) {
264 ZoneList<Expression*>* subexprs = expr->values();
265 for (int i = 0, len = subexprs->length(); i < len; i++) {
266 Expression* subexpr = subexprs->at(i);
267 if (subexpr->AsLiteral() != NULL) continue;
268 if (CompileTimeValue::IsCompileTimeValue(subexpr)) continue;
269 Visit(subexpr);
270 CHECK_BAILOUT;
271 }
272}
273
274
275void FullCodeGenSyntaxChecker::VisitCatchExtensionObject(
276 CatchExtensionObject* expr) {
277 Visit(expr->key());
278 CHECK_BAILOUT;
279 Visit(expr->value());
280}
281
282
283void FullCodeGenSyntaxChecker::VisitAssignment(Assignment* expr) {
284 Token::Value op = expr->op();
285 if (op == Token::INIT_CONST) BAILOUT("initialize constant");
286
287 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
288 Property* prop = expr->target()->AsProperty();
289 ASSERT(var == NULL || prop == NULL);
290 if (var != NULL) {
291 if (var->mode() == Variable::CONST) BAILOUT("Assignment to const");
292 // All other variables are supported.
293 } else if (prop != NULL) {
294 Visit(prop->obj());
295 CHECK_BAILOUT;
296 Visit(prop->key());
297 CHECK_BAILOUT;
298 } else {
299 // This is a throw reference error.
300 BAILOUT("non-variable/non-property assignment");
301 }
302
303 Visit(expr->value());
304}
305
306
307void FullCodeGenSyntaxChecker::VisitThrow(Throw* expr) {
308 Visit(expr->exception());
309}
310
311
312void FullCodeGenSyntaxChecker::VisitProperty(Property* expr) {
313 Visit(expr->obj());
314 CHECK_BAILOUT;
315 Visit(expr->key());
316}
317
318
319void FullCodeGenSyntaxChecker::VisitCall(Call* expr) {
320 Expression* fun = expr->expression();
321 ZoneList<Expression*>* args = expr->arguments();
322 Variable* var = fun->AsVariableProxy()->AsVariable();
323
324 // Check for supported calls
325 if (var != NULL && var->is_possibly_eval()) {
326 BAILOUT("call to the identifier 'eval'");
327 } else if (var != NULL && !var->is_this() && var->is_global()) {
328 // Calls to global variables are supported.
329 } else if (var != NULL && var->slot() != NULL &&
330 var->slot()->type() == Slot::LOOKUP) {
331 BAILOUT("call to a lookup slot");
332 } else if (fun->AsProperty() != NULL) {
333 Property* prop = fun->AsProperty();
334 Visit(prop->obj());
335 CHECK_BAILOUT;
336 Visit(prop->key());
337 CHECK_BAILOUT;
338 } else {
339 // Otherwise the call is supported if the function expression is.
340 Visit(fun);
341 }
342 // Check all arguments to the call.
343 for (int i = 0; i < args->length(); i++) {
344 Visit(args->at(i));
345 CHECK_BAILOUT;
346 }
347}
348
349
350void FullCodeGenSyntaxChecker::VisitCallNew(CallNew* expr) {
351 Visit(expr->expression());
352 CHECK_BAILOUT;
353 ZoneList<Expression*>* args = expr->arguments();
354 // Check all arguments to the call
355 for (int i = 0; i < args->length(); i++) {
356 Visit(args->at(i));
357 CHECK_BAILOUT;
358 }
359}
360
361
362void FullCodeGenSyntaxChecker::VisitCallRuntime(CallRuntime* expr) {
363 // Check for inline runtime call
364 if (expr->name()->Get(0) == '_' &&
365 CodeGenerator::FindInlineRuntimeLUT(expr->name()) != NULL) {
366 BAILOUT("inlined runtime call");
367 }
368 // Check all arguments to the call. (Relies on TEMP meaning STACK.)
369 for (int i = 0; i < expr->arguments()->length(); i++) {
370 Visit(expr->arguments()->at(i));
371 CHECK_BAILOUT;
372 }
373}
374
375
376void FullCodeGenSyntaxChecker::VisitUnaryOperation(UnaryOperation* expr) {
377 switch (expr->op()) {
378 case Token::ADD:
379 case Token::BIT_NOT:
380 case Token::NOT:
381 case Token::SUB:
382 case Token::TYPEOF:
383 case Token::VOID:
384 Visit(expr->expression());
385 break;
386 case Token::DELETE:
387 BAILOUT("UnaryOperation: DELETE");
388 default:
389 UNREACHABLE();
390 }
391}
392
393
394void FullCodeGenSyntaxChecker::VisitCountOperation(CountOperation* expr) {
395 Variable* var = expr->expression()->AsVariableProxy()->AsVariable();
396 Property* prop = expr->expression()->AsProperty();
397 ASSERT(var == NULL || prop == NULL);
398 if (var != NULL) {
399 // All global variables are supported.
400 if (!var->is_global()) {
401 ASSERT(var->slot() != NULL);
402 Slot::Type type = var->slot()->type();
403 if (type == Slot::LOOKUP) {
404 BAILOUT("CountOperation with lookup slot");
405 }
406 }
407 } else if (prop != NULL) {
408 Visit(prop->obj());
409 CHECK_BAILOUT;
410 Visit(prop->key());
411 CHECK_BAILOUT;
412 } else {
413 // This is a throw reference error.
414 BAILOUT("CountOperation non-variable/non-property expression");
415 }
416}
417
418
419void FullCodeGenSyntaxChecker::VisitBinaryOperation(BinaryOperation* expr) {
420 Visit(expr->left());
421 CHECK_BAILOUT;
422 Visit(expr->right());
423}
424
425
426void FullCodeGenSyntaxChecker::VisitCompareOperation(CompareOperation* expr) {
427 Visit(expr->left());
428 CHECK_BAILOUT;
429 Visit(expr->right());
430}
431
432
433void FullCodeGenSyntaxChecker::VisitThisFunction(ThisFunction* expr) {
434 // Supported.
435}
436
437#undef BAILOUT
438#undef CHECK_BAILOUT
439
440
441#define __ ACCESS_MASM(masm())
442
ager@chromium.org5c838252010-02-19 08:53:10 +0000443Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
444 Handle<Script> script = info->script();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000445 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
446 int len = String::cast(script->source())->length();
447 Counters::total_full_codegen_source_size.Increment(len);
448 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000449 CodeGenerator::MakeCodePrologue(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000450 const int kInitialBufferSize = 4 * KB;
451 MacroAssembler masm(NULL, kInitialBufferSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000452 LiveEditFunctionTracker live_edit_tracker(info->function());
453
454 FullCodeGenerator cgen(&masm);
455 cgen.Generate(info, PRIMARY);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000456 if (cgen.HasStackOverflow()) {
457 ASSERT(!Top::has_pending_exception());
458 return Handle<Code>::null();
459 }
460 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
ager@chromium.org5c838252010-02-19 08:53:10 +0000461 Handle<Code> result = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
462 live_edit_tracker.RecordFunctionCode(result);
463 return result;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000464}
465
466
467int FullCodeGenerator::SlotOffset(Slot* slot) {
468 ASSERT(slot != NULL);
469 // Offset is negative because higher indexes are at lower addresses.
470 int offset = -slot->index() * kPointerSize;
471 // Adjust by a (parameter or local) base offset.
472 switch (slot->type()) {
473 case Slot::PARAMETER:
ager@chromium.org5c838252010-02-19 08:53:10 +0000474 offset += (scope()->num_parameters() + 1) * kPointerSize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000475 break;
476 case Slot::LOCAL:
477 offset += JavaScriptFrameConstants::kLocal0Offset;
478 break;
479 case Slot::CONTEXT:
480 case Slot::LOOKUP:
481 UNREACHABLE();
482 }
483 return offset;
484}
485
486
487void FullCodeGenerator::VisitDeclarations(
488 ZoneList<Declaration*>* declarations) {
489 int length = declarations->length();
490 int globals = 0;
491 for (int i = 0; i < length; i++) {
492 Declaration* decl = declarations->at(i);
493 Variable* var = decl->proxy()->var();
494 Slot* slot = var->slot();
495
496 // If it was not possible to allocate the variable at compile
497 // time, we need to "declare" it at runtime to make sure it
498 // actually exists in the local context.
499 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
500 VisitDeclaration(decl);
501 } else {
502 // Count global variables and functions for later processing
503 globals++;
504 }
505 }
506
507 // Compute array of global variable and function declarations.
508 // Do nothing in case of no declared global functions or variables.
509 if (globals > 0) {
510 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
511 for (int j = 0, i = 0; i < length; i++) {
512 Declaration* decl = declarations->at(i);
513 Variable* var = decl->proxy()->var();
514 Slot* slot = var->slot();
515
516 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
517 array->set(j++, *(var->name()));
518 if (decl->fun() == NULL) {
519 if (var->mode() == Variable::CONST) {
520 // In case this is const property use the hole.
521 array->set_the_hole(j++);
522 } else {
523 array->set_undefined(j++);
524 }
525 } else {
526 Handle<JSFunction> function =
ager@chromium.org5c838252010-02-19 08:53:10 +0000527 Compiler::BuildBoilerplate(decl->fun(), script(), this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000528 // Check for stack-overflow exception.
529 if (HasStackOverflow()) return;
530 array->set(j++, *function);
531 }
532 }
533 }
534 // Invoke the platform-dependent code generator to do the actual
535 // declaration the global variables and functions.
536 DeclareGlobals(array);
537 }
538}
539
540
541void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
542 if (FLAG_debug_info) {
543 CodeGenerator::RecordPositions(masm_, fun->start_position());
544 }
545}
546
547
548void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
549 if (FLAG_debug_info) {
550 CodeGenerator::RecordPositions(masm_, fun->end_position());
551 }
552}
553
554
555void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
556 if (FLAG_debug_info) {
557 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
558 }
559}
560
561
562void FullCodeGenerator::SetStatementPosition(int pos) {
563 if (FLAG_debug_info) {
564 CodeGenerator::RecordPositions(masm_, pos);
565 }
566}
567
568
569void FullCodeGenerator::SetSourcePosition(int pos) {
570 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
571 masm_->RecordPosition(pos);
572 }
573}
574
575
576void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
577 Label eval_right, done;
578
579 // Set up the appropriate context for the left subexpression based
580 // on the operation and our own context. Initially assume we can
581 // inherit both true and false labels from our context.
582 if (expr->op() == Token::OR) {
583 switch (context_) {
584 case Expression::kUninitialized:
585 UNREACHABLE();
586 case Expression::kEffect:
587 VisitForControl(expr->left(), &done, &eval_right);
588 break;
589 case Expression::kValue:
590 VisitForValueControl(expr->left(),
591 location_,
592 &done,
593 &eval_right);
594 break;
595 case Expression::kTest:
596 VisitForControl(expr->left(), true_label_, &eval_right);
597 break;
598 case Expression::kValueTest:
599 VisitForValueControl(expr->left(),
600 location_,
601 true_label_,
602 &eval_right);
603 break;
604 case Expression::kTestValue:
605 VisitForControl(expr->left(), true_label_, &eval_right);
606 break;
607 }
608 } else {
609 ASSERT_EQ(Token::AND, expr->op());
610 switch (context_) {
611 case Expression::kUninitialized:
612 UNREACHABLE();
613 case Expression::kEffect:
614 VisitForControl(expr->left(), &eval_right, &done);
615 break;
616 case Expression::kValue:
617 VisitForControlValue(expr->left(),
618 location_,
619 &eval_right,
620 &done);
621 break;
622 case Expression::kTest:
623 VisitForControl(expr->left(), &eval_right, false_label_);
624 break;
625 case Expression::kValueTest:
626 VisitForControl(expr->left(), &eval_right, false_label_);
627 break;
628 case Expression::kTestValue:
629 VisitForControlValue(expr->left(),
630 location_,
631 &eval_right,
632 false_label_);
633 break;
634 }
635 }
636
637 __ bind(&eval_right);
638 Visit(expr->right());
639
640 __ bind(&done);
641}
642
643
644void FullCodeGenerator::VisitBlock(Block* stmt) {
645 Comment cmnt(masm_, "[ Block");
646 Breakable nested_statement(this, stmt);
647 SetStatementPosition(stmt);
648 VisitStatements(stmt->statements());
649 __ bind(nested_statement.break_target());
650}
651
652
653void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
654 Comment cmnt(masm_, "[ ExpressionStatement");
655 SetStatementPosition(stmt);
656 VisitForEffect(stmt->expression());
657}
658
659
660void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
661 Comment cmnt(masm_, "[ EmptyStatement");
662 SetStatementPosition(stmt);
663}
664
665
666void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
667 Comment cmnt(masm_, "[ IfStatement");
668 SetStatementPosition(stmt);
669 Label then_part, else_part, done;
670
671 // Do not worry about optimizing for empty then or else bodies.
672 VisitForControl(stmt->condition(), &then_part, &else_part);
673
674 __ bind(&then_part);
675 Visit(stmt->then_statement());
676 __ jmp(&done);
677
678 __ bind(&else_part);
679 Visit(stmt->else_statement());
680
681 __ bind(&done);
682}
683
684
685void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
686 Comment cmnt(masm_, "[ ContinueStatement");
687 SetStatementPosition(stmt);
688 NestedStatement* current = nesting_stack_;
689 int stack_depth = 0;
690 while (!current->IsContinueTarget(stmt->target())) {
691 stack_depth = current->Exit(stack_depth);
692 current = current->outer();
693 }
694 __ Drop(stack_depth);
695
696 Iteration* loop = current->AsIteration();
697 __ jmp(loop->continue_target());
698}
699
700
701void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
702 Comment cmnt(masm_, "[ BreakStatement");
703 SetStatementPosition(stmt);
704 NestedStatement* current = nesting_stack_;
705 int stack_depth = 0;
706 while (!current->IsBreakTarget(stmt->target())) {
707 stack_depth = current->Exit(stack_depth);
708 current = current->outer();
709 }
710 __ Drop(stack_depth);
711
712 Breakable* target = current->AsBreakable();
713 __ jmp(target->break_target());
714}
715
716
717void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
718 Comment cmnt(masm_, "[ ReturnStatement");
719 SetStatementPosition(stmt);
720 Expression* expr = stmt->expression();
721 VisitForValue(expr, kAccumulator);
722
723 // Exit all nested statements.
724 NestedStatement* current = nesting_stack_;
725 int stack_depth = 0;
726 while (current != NULL) {
727 stack_depth = current->Exit(stack_depth);
728 current = current->outer();
729 }
730 __ Drop(stack_depth);
731
732 EmitReturnSequence(stmt->statement_pos());
733}
734
735
736void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
737 Comment cmnt(masm_, "[ WithEnterStatement");
738 SetStatementPosition(stmt);
739
740 VisitForValue(stmt->expression(), kStack);
741 if (stmt->is_catch_block()) {
742 __ CallRuntime(Runtime::kPushCatchContext, 1);
743 } else {
744 __ CallRuntime(Runtime::kPushContext, 1);
745 }
746 // Both runtime calls return the new context in both the context and the
747 // result registers.
748
749 // Update local stack frame context field.
750 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
751}
752
753
754void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
755 Comment cmnt(masm_, "[ WithExitStatement");
756 SetStatementPosition(stmt);
757
758 // Pop context.
759 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
760 // Update local stack frame context field.
761 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
762}
763
764
765void FullCodeGenerator::VisitSwitchStatement(SwitchStatement* stmt) {
766 UNREACHABLE();
767}
768
769
770void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
771 Comment cmnt(masm_, "[ DoWhileStatement");
772 SetStatementPosition(stmt);
773 Label body, stack_limit_hit, stack_check_success;
774
775 Iteration loop_statement(this, stmt);
776 increment_loop_depth();
777
778 __ bind(&body);
779 Visit(stmt->body());
780
781 // Check stack before looping.
782 __ StackLimitCheck(&stack_limit_hit);
783 __ bind(&stack_check_success);
784
785 __ bind(loop_statement.continue_target());
786 SetStatementPosition(stmt->condition_position());
787 VisitForControl(stmt->cond(), &body, loop_statement.break_target());
788
789 __ bind(&stack_limit_hit);
790 StackCheckStub stack_stub;
791 __ CallStub(&stack_stub);
792 __ jmp(&stack_check_success);
793
794 __ bind(loop_statement.break_target());
795
796 decrement_loop_depth();
797}
798
799
800void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
801 Comment cmnt(masm_, "[ WhileStatement");
802 SetStatementPosition(stmt);
803 Label body, stack_limit_hit, stack_check_success;
804
805 Iteration loop_statement(this, stmt);
806 increment_loop_depth();
807
808 // Emit the test at the bottom of the loop.
809 __ jmp(loop_statement.continue_target());
810
811 __ bind(&body);
812 Visit(stmt->body());
813
814 __ bind(loop_statement.continue_target());
815 // Check stack before looping.
816 __ StackLimitCheck(&stack_limit_hit);
817 __ bind(&stack_check_success);
818
819 VisitForControl(stmt->cond(), &body, loop_statement.break_target());
820
821 __ bind(&stack_limit_hit);
822 StackCheckStub stack_stub;
823 __ CallStub(&stack_stub);
824 __ jmp(&stack_check_success);
825
826 __ bind(loop_statement.break_target());
827 decrement_loop_depth();
828}
829
830
831void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
832 Comment cmnt(masm_, "[ ForStatement");
833 SetStatementPosition(stmt);
834 Label test, body, stack_limit_hit, stack_check_success;
835
836 Iteration loop_statement(this, stmt);
837 if (stmt->init() != NULL) {
838 Visit(stmt->init());
839 }
840
841 increment_loop_depth();
842 // Emit the test at the bottom of the loop (even if empty).
843 __ jmp(&test);
844
845 __ bind(&body);
846 Visit(stmt->body());
847
848 __ bind(loop_statement.continue_target());
849
850 SetStatementPosition(stmt);
851 if (stmt->next() != NULL) {
852 Visit(stmt->next());
853 }
854
855 __ bind(&test);
856
857 // Check stack before looping.
858 __ StackLimitCheck(&stack_limit_hit);
859 __ bind(&stack_check_success);
860
861 if (stmt->cond() != NULL) {
862 VisitForControl(stmt->cond(), &body, loop_statement.break_target());
863 } else {
864 __ jmp(&body);
865 }
866
867 __ bind(&stack_limit_hit);
868 StackCheckStub stack_stub;
869 __ CallStub(&stack_stub);
870 __ jmp(&stack_check_success);
871
872 __ bind(loop_statement.break_target());
873 decrement_loop_depth();
874}
875
876
877void FullCodeGenerator::VisitForInStatement(ForInStatement* stmt) {
878 UNREACHABLE();
879}
880
881
882void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
883 Comment cmnt(masm_, "[ TryCatchStatement");
884 SetStatementPosition(stmt);
885 // The try block adds a handler to the exception handler chain
886 // before entering, and removes it again when exiting normally.
887 // If an exception is thrown during execution of the try block,
888 // control is passed to the handler, which also consumes the handler.
889 // At this point, the exception is in a register, and store it in
890 // the temporary local variable (prints as ".catch-var") before
891 // executing the catch block. The catch block has been rewritten
892 // to introduce a new scope to bind the catch variable and to remove
893 // that scope again afterwards.
894
895 Label try_handler_setup, catch_entry, done;
896 __ Call(&try_handler_setup);
897 // Try handler code, exception in result register.
898
899 // Store exception in local .catch variable before executing catch block.
900 {
901 // The catch variable is *always* a variable proxy for a local variable.
902 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
903 ASSERT_NOT_NULL(catch_var);
904 Slot* variable_slot = catch_var->slot();
905 ASSERT_NOT_NULL(variable_slot);
906 ASSERT_EQ(Slot::LOCAL, variable_slot->type());
907 StoreToFrameField(SlotOffset(variable_slot), result_register());
908 }
909
910 Visit(stmt->catch_block());
911 __ jmp(&done);
912
913 // Try block code. Sets up the exception handler chain.
914 __ bind(&try_handler_setup);
915 {
916 TryCatch try_block(this, &catch_entry);
917 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
918 Visit(stmt->try_block());
919 __ PopTryHandler();
920 }
921 __ bind(&done);
922}
923
924
925void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
926 Comment cmnt(masm_, "[ TryFinallyStatement");
927 SetStatementPosition(stmt);
928 // Try finally is compiled by setting up a try-handler on the stack while
929 // executing the try body, and removing it again afterwards.
930 //
931 // The try-finally construct can enter the finally block in three ways:
932 // 1. By exiting the try-block normally. This removes the try-handler and
933 // calls the finally block code before continuing.
934 // 2. By exiting the try-block with a function-local control flow transfer
935 // (break/continue/return). The site of the, e.g., break removes the
936 // try handler and calls the finally block code before continuing
937 // its outward control transfer.
938 // 3. by exiting the try-block with a thrown exception.
939 // This can happen in nested function calls. It traverses the try-handler
940 // chain and consumes the try-handler entry before jumping to the
941 // handler code. The handler code then calls the finally-block before
942 // rethrowing the exception.
943 //
944 // The finally block must assume a return address on top of the stack
945 // (or in the link register on ARM chips) and a value (return value or
946 // exception) in the result register (rax/eax/r0), both of which must
947 // be preserved. The return address isn't GC-safe, so it should be
948 // cooked before GC.
949 Label finally_entry;
950 Label try_handler_setup;
951
952 // Setup the try-handler chain. Use a call to
953 // Jump to try-handler setup and try-block code. Use call to put try-handler
954 // address on stack.
955 __ Call(&try_handler_setup);
956 // Try handler code. Return address of call is pushed on handler stack.
957 {
958 // This code is only executed during stack-handler traversal when an
959 // exception is thrown. The execption is in the result register, which
960 // is retained by the finally block.
961 // Call the finally block and then rethrow the exception.
962 __ Call(&finally_entry);
963 __ push(result_register());
964 __ CallRuntime(Runtime::kReThrow, 1);
965 }
966
967 __ bind(&finally_entry);
968 {
969 // Finally block implementation.
970 Finally finally_block(this);
971 EnterFinallyBlock();
972 Visit(stmt->finally_block());
973 ExitFinallyBlock(); // Return to the calling code.
974 }
975
976 __ bind(&try_handler_setup);
977 {
978 // Setup try handler (stack pointer registers).
979 TryFinally try_block(this, &finally_entry);
980 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
981 Visit(stmt->try_block());
982 __ PopTryHandler();
983 }
984 // Execute the finally block on the way out.
985 __ Call(&finally_entry);
986}
987
988
989void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
990#ifdef ENABLE_DEBUGGER_SUPPORT
991 Comment cmnt(masm_, "[ DebuggerStatement");
992 SetStatementPosition(stmt);
993
ager@chromium.org5c838252010-02-19 08:53:10 +0000994 __ DebugBreak();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000995 // Ignore the return value.
996#endif
997}
998
999
1000void FullCodeGenerator::VisitFunctionBoilerplateLiteral(
1001 FunctionBoilerplateLiteral* expr) {
1002 UNREACHABLE();
1003}
1004
1005
1006void FullCodeGenerator::VisitConditional(Conditional* expr) {
1007 Comment cmnt(masm_, "[ Conditional");
1008 Label true_case, false_case, done;
1009 VisitForControl(expr->condition(), &true_case, &false_case);
1010
1011 __ bind(&true_case);
1012 Visit(expr->then_expression());
1013 // If control flow falls through Visit, jump to done.
1014 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1015 __ jmp(&done);
1016 }
1017
1018 __ bind(&false_case);
1019 Visit(expr->else_expression());
1020 // If control flow falls through Visit, merge it with true case here.
1021 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1022 __ bind(&done);
1023 }
1024}
1025
1026
1027void FullCodeGenerator::VisitSlot(Slot* expr) {
1028 // Slots do not appear directly in the AST.
1029 UNREACHABLE();
1030}
1031
1032
1033void FullCodeGenerator::VisitLiteral(Literal* expr) {
1034 Comment cmnt(masm_, "[ Literal");
1035 Apply(context_, expr);
1036}
1037
1038
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001039void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1040 // Call runtime routine to allocate the catch extension object and
1041 // assign the exception value to the catch variable.
1042 Comment cmnt(masm_, "[ CatchExtensionObject");
1043 VisitForValue(expr->key(), kStack);
1044 VisitForValue(expr->value(), kStack);
1045 // Create catch extension object.
1046 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
1047 Apply(context_, result_register());
1048}
1049
1050
1051void FullCodeGenerator::VisitThrow(Throw* expr) {
1052 Comment cmnt(masm_, "[ Throw");
1053 VisitForValue(expr->exception(), kStack);
1054 __ CallRuntime(Runtime::kThrow, 1);
1055 // Never returns here.
1056}
1057
1058
1059int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
1060 // The macros used here must preserve the result register.
1061 __ Drop(stack_depth);
1062 __ PopTryHandler();
1063 __ Call(finally_entry_);
1064 return 0;
1065}
1066
1067
1068int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
1069 // The macros used here must preserve the result register.
1070 __ Drop(stack_depth);
1071 __ PopTryHandler();
1072 return 0;
1073}
1074
1075#undef __
1076
1077
1078} } // namespace v8::internal