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

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

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

Powered by Google App Engine
This is Rietveld 408576698