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