blob: 65c1e2adead6353fa55bf7d288b0d245703eb41a [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"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000033#include "scopes.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000034#include "stub-cache.h"
35#include "debug.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000036#include "liveedit.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000037
38namespace v8 {
39namespace internal {
40
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000041void BreakableStatementChecker::Check(Statement* stmt) {
42 Visit(stmt);
43}
44
45
46void BreakableStatementChecker::Check(Expression* expr) {
47 Visit(expr);
48}
49
50
51void BreakableStatementChecker::VisitDeclaration(Declaration* decl) {
52}
53
54
55void BreakableStatementChecker::VisitBlock(Block* stmt) {
56}
57
58
59void BreakableStatementChecker::VisitExpressionStatement(
60 ExpressionStatement* stmt) {
61 // Check if expression is breakable.
62 Visit(stmt->expression());
63}
64
65
66void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
67}
68
69
70void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
71 // If the condition is breakable the if statement is breakable.
72 Visit(stmt->condition());
73}
74
75
76void BreakableStatementChecker::VisitContinueStatement(
77 ContinueStatement* stmt) {
78}
79
80
81void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
82}
83
84
85void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
86 // Return is breakable if the expression is.
87 Visit(stmt->expression());
88}
89
90
91void BreakableStatementChecker::VisitWithEnterStatement(
92 WithEnterStatement* stmt) {
93 Visit(stmt->expression());
94}
95
96
97void BreakableStatementChecker::VisitWithExitStatement(
98 WithExitStatement* stmt) {
99}
100
101
102void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
103 // Switch statements breakable if the tag expression is.
104 Visit(stmt->tag());
105}
106
107
108void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
109 // Mark do while as breakable to avoid adding a break slot in front of it.
110 is_breakable_ = true;
111}
112
113
114void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
115 // Mark while statements breakable if the condition expression is.
116 Visit(stmt->cond());
117}
118
119
120void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
121 // Mark for statements breakable if the condition expression is.
122 if (stmt->cond() != NULL) {
123 Visit(stmt->cond());
124 }
125}
126
127
128void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
129 // Mark for in statements breakable if the enumerable expression is.
130 Visit(stmt->enumerable());
131}
132
133
134void BreakableStatementChecker::VisitTryCatchStatement(
135 TryCatchStatement* stmt) {
136 // Mark try catch as breakable to avoid adding a break slot in front of it.
137 is_breakable_ = true;
138}
139
140
141void BreakableStatementChecker::VisitTryFinallyStatement(
142 TryFinallyStatement* stmt) {
143 // Mark try finally as breakable to avoid adding a break slot in front of it.
144 is_breakable_ = true;
145}
146
147
148void BreakableStatementChecker::VisitDebuggerStatement(
149 DebuggerStatement* stmt) {
150 // The debugger statement is breakable.
151 is_breakable_ = true;
152}
153
154
155void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
156}
157
158
159void BreakableStatementChecker::VisitSharedFunctionInfoLiteral(
160 SharedFunctionInfoLiteral* expr) {
161}
162
163
164void BreakableStatementChecker::VisitConditional(Conditional* expr) {
165}
166
167
168void BreakableStatementChecker::VisitSlot(Slot* expr) {
169}
170
171
172void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
173}
174
175
176void BreakableStatementChecker::VisitLiteral(Literal* expr) {
177}
178
179
180void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
181}
182
183
184void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
185}
186
187
188void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
189}
190
191
192void BreakableStatementChecker::VisitCatchExtensionObject(
193 CatchExtensionObject* expr) {
194}
195
196
197void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
198 // If assigning to a property (including a global property) the assignment is
199 // breakable.
200 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
201 Property* prop = expr->target()->AsProperty();
202 if (prop != NULL || (var != NULL && var->is_global())) {
203 is_breakable_ = true;
204 return;
205 }
206
207 // Otherwise the assignment is breakable if the assigned value is.
208 Visit(expr->value());
209}
210
211
212void BreakableStatementChecker::VisitThrow(Throw* expr) {
213 // Throw is breakable if the expression is.
214 Visit(expr->exception());
215}
216
217
ricow@chromium.org65fae842010-08-25 15:26:24 +0000218void BreakableStatementChecker::VisitIncrementOperation(
219 IncrementOperation* expr) {
220 UNREACHABLE();
221}
222
223
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000224void BreakableStatementChecker::VisitProperty(Property* expr) {
225 // Property load is breakable.
226 is_breakable_ = true;
227}
228
229
230void BreakableStatementChecker::VisitCall(Call* expr) {
231 // Function calls both through IC and call stub are breakable.
232 is_breakable_ = true;
233}
234
235
236void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
237 // Function calls through new are breakable.
238 is_breakable_ = true;
239}
240
241
242void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
243}
244
245
246void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
247 Visit(expr->expression());
248}
249
250
251void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
252 Visit(expr->expression());
253}
254
255
256void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
257 Visit(expr->left());
258 Visit(expr->right());
259}
260
261
ricow@chromium.org65fae842010-08-25 15:26:24 +0000262void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) {
263 Visit(expr->expression());
264}
265
266
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000267void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
268 Visit(expr->left());
269 Visit(expr->right());
270}
271
272
273void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
274}
275
276
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000277#define __ ACCESS_MASM(masm())
278
ager@chromium.org5c838252010-02-19 08:53:10 +0000279Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
280 Handle<Script> script = info->script();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000281 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
282 int len = String::cast(script->source())->length();
283 Counters::total_full_codegen_source_size.Increment(len);
284 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000285 CodeGenerator::MakeCodePrologue(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000286 const int kInitialBufferSize = 4 * KB;
287 MacroAssembler masm(NULL, kInitialBufferSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000288
289 FullCodeGenerator cgen(&masm);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000290 cgen.Generate(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000291 if (cgen.HasStackOverflow()) {
292 ASSERT(!Top::has_pending_exception());
293 return Handle<Code>::null();
294 }
295 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000296 return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000297}
298
299
300int FullCodeGenerator::SlotOffset(Slot* slot) {
301 ASSERT(slot != NULL);
302 // Offset is negative because higher indexes are at lower addresses.
303 int offset = -slot->index() * kPointerSize;
304 // Adjust by a (parameter or local) base offset.
305 switch (slot->type()) {
306 case Slot::PARAMETER:
ager@chromium.org5c838252010-02-19 08:53:10 +0000307 offset += (scope()->num_parameters() + 1) * kPointerSize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000308 break;
309 case Slot::LOCAL:
310 offset += JavaScriptFrameConstants::kLocal0Offset;
311 break;
312 case Slot::CONTEXT:
313 case Slot::LOOKUP:
314 UNREACHABLE();
315 }
316 return offset;
317}
318
319
ricow@chromium.org65fae842010-08-25 15:26:24 +0000320bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
321 // TODO(kasperl): Once the compare stub allows leaving out the
322 // inlined smi case, we should get rid of this check.
323 if (Token::IsCompareOp(op)) return true;
324 // TODO(kasperl): Once the unary bit not stub allows leaving out
325 // the inlined smi case, we should get rid of this check.
326 if (op == Token::BIT_NOT) return true;
327 // Inline smi case inside loops, but not division and modulo which
328 // are too complicated and take up too much space.
329 return (op != Token::DIV) && (op != Token::MOD) && (loop_depth_ > 0);
330}
331
332
333void FullCodeGenerator::PrepareTest(Label* materialize_true,
334 Label* materialize_false,
335 Label** if_true,
336 Label** if_false,
337 Label** fall_through) {
338 switch (context_) {
339 case Expression::kUninitialized:
340 UNREACHABLE();
341 break;
342 case Expression::kEffect:
343 // In an effect context, the true and the false case branch to the
344 // same label.
345 *if_true = *if_false = *fall_through = materialize_true;
346 break;
347 case Expression::kValue:
348 *if_true = *fall_through = materialize_true;
349 *if_false = materialize_false;
350 break;
351 case Expression::kTest:
352 *if_true = true_label_;
353 *if_false = false_label_;
354 *fall_through = fall_through_;
355 break;
356 }
357}
358
359
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000360void FullCodeGenerator::VisitDeclarations(
361 ZoneList<Declaration*>* declarations) {
362 int length = declarations->length();
363 int globals = 0;
364 for (int i = 0; i < length; i++) {
365 Declaration* decl = declarations->at(i);
366 Variable* var = decl->proxy()->var();
367 Slot* slot = var->slot();
368
369 // If it was not possible to allocate the variable at compile
370 // time, we need to "declare" it at runtime to make sure it
371 // actually exists in the local context.
372 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
373 VisitDeclaration(decl);
374 } else {
375 // Count global variables and functions for later processing
376 globals++;
377 }
378 }
379
380 // Compute array of global variable and function declarations.
381 // Do nothing in case of no declared global functions or variables.
382 if (globals > 0) {
383 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
384 for (int j = 0, i = 0; i < length; i++) {
385 Declaration* decl = declarations->at(i);
386 Variable* var = decl->proxy()->var();
387 Slot* slot = var->slot();
388
389 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
390 array->set(j++, *(var->name()));
391 if (decl->fun() == NULL) {
392 if (var->mode() == Variable::CONST) {
393 // In case this is const property use the hole.
394 array->set_the_hole(j++);
395 } else {
396 array->set_undefined(j++);
397 }
398 } else {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000399 Handle<SharedFunctionInfo> function =
400 Compiler::BuildFunctionInfo(decl->fun(), script(), this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000401 // Check for stack-overflow exception.
402 if (HasStackOverflow()) return;
403 array->set(j++, *function);
404 }
405 }
406 }
407 // Invoke the platform-dependent code generator to do the actual
408 // declaration the global variables and functions.
409 DeclareGlobals(array);
410 }
411}
412
413
414void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
415 if (FLAG_debug_info) {
416 CodeGenerator::RecordPositions(masm_, fun->start_position());
417 }
418}
419
420
421void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
422 if (FLAG_debug_info) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000423 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000424 }
425}
426
427
428void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
429 if (FLAG_debug_info) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000430#ifdef ENABLE_DEBUGGER_SUPPORT
431 if (!Debugger::IsDebuggerActive()) {
432 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
433 } else {
434 // Check if the statement will be breakable without adding a debug break
435 // slot.
436 BreakableStatementChecker checker;
437 checker.Check(stmt);
438 // Record the statement position right here if the statement is not
439 // breakable. For breakable statements the actual recording of the
440 // position will be postponed to the breakable code (typically an IC).
441 bool position_recorded = CodeGenerator::RecordPositions(
442 masm_, stmt->statement_pos(), !checker.is_breakable());
443 // If the position recording did record a new position generate a debug
444 // break slot to make the statement breakable.
445 if (position_recorded) {
446 Debug::GenerateSlot(masm_);
447 }
448 }
449#else
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000450 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000451#endif
452 }
453}
454
455
456void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
457 if (FLAG_debug_info) {
458#ifdef ENABLE_DEBUGGER_SUPPORT
459 if (!Debugger::IsDebuggerActive()) {
460 CodeGenerator::RecordPositions(masm_, pos);
461 } else {
462 // Check if the expression will be breakable without adding a debug break
463 // slot.
464 BreakableStatementChecker checker;
465 checker.Check(expr);
466 // Record a statement position right here if the expression is not
467 // breakable. For breakable expressions the actual recording of the
468 // position will be postponed to the breakable code (typically an IC).
469 // NOTE this will record a statement position for something which might
470 // not be a statement. As stepping in the debugger will only stop at
471 // statement positions this is used for e.g. the condition expression of
472 // a do while loop.
473 bool position_recorded = CodeGenerator::RecordPositions(
474 masm_, pos, !checker.is_breakable());
475 // If the position recording did record a new position generate a debug
476 // break slot to make the statement breakable.
477 if (position_recorded) {
478 Debug::GenerateSlot(masm_);
479 }
480 }
481#else
482 CodeGenerator::RecordPositions(masm_, pos);
483#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000484 }
485}
486
487
488void FullCodeGenerator::SetStatementPosition(int pos) {
489 if (FLAG_debug_info) {
490 CodeGenerator::RecordPositions(masm_, pos);
491 }
492}
493
494
495void FullCodeGenerator::SetSourcePosition(int pos) {
496 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
497 masm_->RecordPosition(pos);
498 }
499}
500
501
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000502void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
503 Handle<String> name = expr->name();
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000504 SmartPointer<char> cstring = name->ToCString();
505
506#define CHECK_EMIT_INLINE_CALL(name, x, y) \
507 if (strcmp("_"#name, *cstring) == 0) { \
508 Emit##name(expr->arguments()); \
509 return; \
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000510 }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000511 INLINE_RUNTIME_FUNCTION_LIST(CHECK_EMIT_INLINE_CALL)
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000512#undef CHECK_EMIT_INLINE_CALL
ricow@chromium.org65fae842010-08-25 15:26:24 +0000513 UNREACHABLE();
514}
515
516
517void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
518 Comment cmnt(masm_, "[ BinaryOperation");
519
520 OverwriteMode overwrite_mode = NO_OVERWRITE;
521 if (expr->left()->ResultOverwriteAllowed()) {
522 overwrite_mode = OVERWRITE_LEFT;
523 } else if (expr->right()->ResultOverwriteAllowed()) {
524 overwrite_mode = OVERWRITE_RIGHT;
525 }
526
527 switch (expr->op()) {
528 case Token::COMMA:
529 VisitForEffect(expr->left());
530 Visit(expr->right());
531 break;
532
533 case Token::OR:
534 case Token::AND:
535 EmitLogicalOperation(expr);
536 break;
537
538 case Token::ADD:
539 case Token::SUB:
540 case Token::DIV:
541 case Token::MOD:
542 case Token::MUL:
543 case Token::BIT_OR:
544 case Token::BIT_AND:
545 case Token::BIT_XOR:
546 case Token::SHL:
547 case Token::SHR:
548 case Token::SAR:
549 VisitForValue(expr->left(), kStack);
550 VisitForValue(expr->right(), kAccumulator);
551 SetSourcePosition(expr->position());
552 EmitBinaryOp(expr->op(), context_, overwrite_mode);
553 break;
554
555 default:
556 UNREACHABLE();
557 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000558}
559
560
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000561void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
562 Label eval_right, done;
563
564 // Set up the appropriate context for the left subexpression based
565 // on the operation and our own context. Initially assume we can
566 // inherit both true and false labels from our context.
567 if (expr->op() == Token::OR) {
568 switch (context_) {
569 case Expression::kUninitialized:
570 UNREACHABLE();
571 case Expression::kEffect:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000572 VisitForControl(expr->left(), &done, &eval_right, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000573 break;
574 case Expression::kValue:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000575 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000576 break;
577 case Expression::kTest:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000578 VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000579 break;
580 }
581 } else {
582 ASSERT_EQ(Token::AND, expr->op());
583 switch (context_) {
584 case Expression::kUninitialized:
585 UNREACHABLE();
586 case Expression::kEffect:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000587 VisitForControl(expr->left(), &eval_right, &done, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000588 break;
589 case Expression::kValue:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000590 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000591 break;
592 case Expression::kTest:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000593 VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000594 break;
595 }
596 }
597
598 __ bind(&eval_right);
599 Visit(expr->right());
600
601 __ bind(&done);
602}
603
604
ricow@chromium.org65fae842010-08-25 15:26:24 +0000605void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
606 Token::Value op,
607 Location where,
608 Label* done) {
609 ASSERT(op == Token::AND || op == Token::OR);
610 VisitForValue(expr, kAccumulator);
611 __ push(result_register());
612
613 Label discard;
614 switch (where) {
615 case kAccumulator: {
616 Label restore;
617 if (op == Token::OR) {
618 DoTest(&restore, &discard, &restore);
619 } else {
620 DoTest(&discard, &restore, &restore);
621 }
622 __ bind(&restore);
623 __ pop(result_register());
624 __ jmp(done);
625 break;
626 }
627 case kStack: {
628 if (op == Token::OR) {
629 DoTest(done, &discard, &discard);
630 } else {
631 DoTest(&discard, done, &discard);
632 }
633 break;
634 }
635 }
636
637 __ bind(&discard);
638 __ Drop(1);
639}
640
641
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000642void FullCodeGenerator::VisitBlock(Block* stmt) {
643 Comment cmnt(masm_, "[ Block");
644 Breakable nested_statement(this, stmt);
645 SetStatementPosition(stmt);
646 VisitStatements(stmt->statements());
647 __ bind(nested_statement.break_target());
648}
649
650
651void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
652 Comment cmnt(masm_, "[ ExpressionStatement");
653 SetStatementPosition(stmt);
654 VisitForEffect(stmt->expression());
655}
656
657
658void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
659 Comment cmnt(masm_, "[ EmptyStatement");
660 SetStatementPosition(stmt);
661}
662
663
664void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
665 Comment cmnt(masm_, "[ IfStatement");
666 SetStatementPosition(stmt);
667 Label then_part, else_part, done;
668
ricow@chromium.org65fae842010-08-25 15:26:24 +0000669 if (stmt->HasElseStatement()) {
670 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
671 __ bind(&then_part);
672 Visit(stmt->then_statement());
673 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000674
ricow@chromium.org65fae842010-08-25 15:26:24 +0000675 __ bind(&else_part);
676 Visit(stmt->else_statement());
677 } else {
678 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
679 __ bind(&then_part);
680 Visit(stmt->then_statement());
681 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000682 __ bind(&done);
683}
684
685
686void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
687 Comment cmnt(masm_, "[ ContinueStatement");
688 SetStatementPosition(stmt);
689 NestedStatement* current = nesting_stack_;
690 int stack_depth = 0;
691 while (!current->IsContinueTarget(stmt->target())) {
692 stack_depth = current->Exit(stack_depth);
693 current = current->outer();
694 }
695 __ Drop(stack_depth);
696
697 Iteration* loop = current->AsIteration();
698 __ jmp(loop->continue_target());
699}
700
701
702void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
703 Comment cmnt(masm_, "[ BreakStatement");
704 SetStatementPosition(stmt);
705 NestedStatement* current = nesting_stack_;
706 int stack_depth = 0;
707 while (!current->IsBreakTarget(stmt->target())) {
708 stack_depth = current->Exit(stack_depth);
709 current = current->outer();
710 }
711 __ Drop(stack_depth);
712
713 Breakable* target = current->AsBreakable();
714 __ jmp(target->break_target());
715}
716
717
718void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
719 Comment cmnt(masm_, "[ ReturnStatement");
720 SetStatementPosition(stmt);
721 Expression* expr = stmt->expression();
722 VisitForValue(expr, kAccumulator);
723
724 // Exit all nested statements.
725 NestedStatement* current = nesting_stack_;
726 int stack_depth = 0;
727 while (current != NULL) {
728 stack_depth = current->Exit(stack_depth);
729 current = current->outer();
730 }
731 __ Drop(stack_depth);
732
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000733 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000734}
735
736
737void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
738 Comment cmnt(masm_, "[ WithEnterStatement");
739 SetStatementPosition(stmt);
740
741 VisitForValue(stmt->expression(), kStack);
742 if (stmt->is_catch_block()) {
743 __ CallRuntime(Runtime::kPushCatchContext, 1);
744 } else {
745 __ CallRuntime(Runtime::kPushContext, 1);
746 }
747 // Both runtime calls return the new context in both the context and the
748 // result registers.
749
750 // Update local stack frame context field.
751 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
752}
753
754
755void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
756 Comment cmnt(masm_, "[ WithExitStatement");
757 SetStatementPosition(stmt);
758
759 // Pop context.
760 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
761 // Update local stack frame context field.
762 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
763}
764
765
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000766void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
767 Comment cmnt(masm_, "[ DoWhileStatement");
768 SetStatementPosition(stmt);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000769 Label body, stack_limit_hit, stack_check_success, done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000770
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
ricow@chromium.org65fae842010-08-25 15:26:24 +0000781 // Record the position of the do while condition and make sure it is
782 // possible to break on the condition.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000783 __ bind(loop_statement.continue_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000784 SetExpressionPosition(stmt->cond(), stmt->condition_position());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000785 VisitForControl(stmt->cond(),
786 &body,
787 loop_statement.break_target(),
788 loop_statement.break_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000789
ricow@chromium.org65fae842010-08-25 15:26:24 +0000790 __ bind(loop_statement.break_target());
791 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000792
793 __ bind(&stack_limit_hit);
794 StackCheckStub stack_stub;
795 __ CallStub(&stack_stub);
796 __ jmp(&stack_check_success);
797
ricow@chromium.org65fae842010-08-25 15:26:24 +0000798 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000799 decrement_loop_depth();
800}
801
802
803void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
804 Comment cmnt(masm_, "[ WhileStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000805 Label body, stack_limit_hit, stack_check_success;
806
807 Iteration loop_statement(this, stmt);
808 increment_loop_depth();
809
810 // Emit the test at the bottom of the loop.
811 __ jmp(loop_statement.continue_target());
812
ricow@chromium.org65fae842010-08-25 15:26:24 +0000813 __ bind(&stack_limit_hit);
814 StackCheckStub stack_stub;
815 __ CallStub(&stack_stub);
816 __ jmp(&stack_check_success);
817
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000818 __ bind(&body);
819 Visit(stmt->body());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000820 __ bind(loop_statement.continue_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000821
822 // Emit the statement position here as this is where the while
823 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000824 SetStatementPosition(stmt);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000825
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000826 // Check stack before looping.
827 __ StackLimitCheck(&stack_limit_hit);
828 __ bind(&stack_check_success);
829
ricow@chromium.org65fae842010-08-25 15:26:24 +0000830 VisitForControl(stmt->cond(),
831 &body,
832 loop_statement.break_target(),
833 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000834
835 __ bind(loop_statement.break_target());
836 decrement_loop_depth();
837}
838
839
840void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
841 Comment cmnt(masm_, "[ ForStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000842 Label test, body, stack_limit_hit, stack_check_success;
843
844 Iteration loop_statement(this, stmt);
845 if (stmt->init() != NULL) {
846 Visit(stmt->init());
847 }
848
849 increment_loop_depth();
850 // Emit the test at the bottom of the loop (even if empty).
851 __ jmp(&test);
852
ricow@chromium.org65fae842010-08-25 15:26:24 +0000853 __ bind(&stack_limit_hit);
854 StackCheckStub stack_stub;
855 __ CallStub(&stack_stub);
856 __ jmp(&stack_check_success);
857
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000858 __ bind(&body);
859 Visit(stmt->body());
860
861 __ bind(loop_statement.continue_target());
862
863 SetStatementPosition(stmt);
864 if (stmt->next() != NULL) {
865 Visit(stmt->next());
866 }
867
868 __ bind(&test);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000869 // Emit the statement position here as this is where the for
870 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000871 SetStatementPosition(stmt);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000872
873 // Check stack before looping.
874 __ StackLimitCheck(&stack_limit_hit);
875 __ bind(&stack_check_success);
876
877 if (stmt->cond() != NULL) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000878 VisitForControl(stmt->cond(),
879 &body,
880 loop_statement.break_target(),
881 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000882 } else {
883 __ jmp(&body);
884 }
885
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000886 __ bind(loop_statement.break_target());
887 decrement_loop_depth();
888}
889
890
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000891void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
892 Comment cmnt(masm_, "[ TryCatchStatement");
893 SetStatementPosition(stmt);
894 // The try block adds a handler to the exception handler chain
895 // before entering, and removes it again when exiting normally.
896 // If an exception is thrown during execution of the try block,
897 // control is passed to the handler, which also consumes the handler.
898 // At this point, the exception is in a register, and store it in
899 // the temporary local variable (prints as ".catch-var") before
900 // executing the catch block. The catch block has been rewritten
901 // to introduce a new scope to bind the catch variable and to remove
902 // that scope again afterwards.
903
904 Label try_handler_setup, catch_entry, done;
905 __ Call(&try_handler_setup);
906 // Try handler code, exception in result register.
907
908 // Store exception in local .catch variable before executing catch block.
909 {
910 // The catch variable is *always* a variable proxy for a local variable.
911 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
912 ASSERT_NOT_NULL(catch_var);
913 Slot* variable_slot = catch_var->slot();
914 ASSERT_NOT_NULL(variable_slot);
915 ASSERT_EQ(Slot::LOCAL, variable_slot->type());
916 StoreToFrameField(SlotOffset(variable_slot), result_register());
917 }
918
919 Visit(stmt->catch_block());
920 __ jmp(&done);
921
922 // Try block code. Sets up the exception handler chain.
923 __ bind(&try_handler_setup);
924 {
925 TryCatch try_block(this, &catch_entry);
926 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
927 Visit(stmt->try_block());
928 __ PopTryHandler();
929 }
930 __ bind(&done);
931}
932
933
934void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
935 Comment cmnt(masm_, "[ TryFinallyStatement");
936 SetStatementPosition(stmt);
937 // Try finally is compiled by setting up a try-handler on the stack while
938 // executing the try body, and removing it again afterwards.
939 //
940 // The try-finally construct can enter the finally block in three ways:
941 // 1. By exiting the try-block normally. This removes the try-handler and
942 // calls the finally block code before continuing.
943 // 2. By exiting the try-block with a function-local control flow transfer
944 // (break/continue/return). The site of the, e.g., break removes the
945 // try handler and calls the finally block code before continuing
946 // its outward control transfer.
947 // 3. by exiting the try-block with a thrown exception.
948 // This can happen in nested function calls. It traverses the try-handler
949 // chain and consumes the try-handler entry before jumping to the
950 // handler code. The handler code then calls the finally-block before
951 // rethrowing the exception.
952 //
953 // The finally block must assume a return address on top of the stack
954 // (or in the link register on ARM chips) and a value (return value or
955 // exception) in the result register (rax/eax/r0), both of which must
956 // be preserved. The return address isn't GC-safe, so it should be
957 // cooked before GC.
958 Label finally_entry;
959 Label try_handler_setup;
960
961 // Setup the try-handler chain. Use a call to
962 // Jump to try-handler setup and try-block code. Use call to put try-handler
963 // address on stack.
964 __ Call(&try_handler_setup);
965 // Try handler code. Return address of call is pushed on handler stack.
966 {
967 // This code is only executed during stack-handler traversal when an
968 // exception is thrown. The execption is in the result register, which
969 // is retained by the finally block.
970 // Call the finally block and then rethrow the exception.
971 __ Call(&finally_entry);
972 __ push(result_register());
973 __ CallRuntime(Runtime::kReThrow, 1);
974 }
975
976 __ bind(&finally_entry);
977 {
978 // Finally block implementation.
979 Finally finally_block(this);
980 EnterFinallyBlock();
981 Visit(stmt->finally_block());
982 ExitFinallyBlock(); // Return to the calling code.
983 }
984
985 __ bind(&try_handler_setup);
986 {
987 // Setup try handler (stack pointer registers).
988 TryFinally try_block(this, &finally_entry);
989 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
990 Visit(stmt->try_block());
991 __ PopTryHandler();
992 }
993 // Execute the finally block on the way out.
994 __ Call(&finally_entry);
995}
996
997
998void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
999#ifdef ENABLE_DEBUGGER_SUPPORT
1000 Comment cmnt(masm_, "[ DebuggerStatement");
1001 SetStatementPosition(stmt);
1002
ager@chromium.org5c838252010-02-19 08:53:10 +00001003 __ DebugBreak();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001004 // Ignore the return value.
1005#endif
1006}
1007
1008
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001009void FullCodeGenerator::VisitConditional(Conditional* expr) {
1010 Comment cmnt(masm_, "[ Conditional");
1011 Label true_case, false_case, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001012 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001013
1014 __ bind(&true_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001015 SetExpressionPosition(expr->then_expression(),
1016 expr->then_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001017 Visit(expr->then_expression());
1018 // If control flow falls through Visit, jump to done.
1019 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1020 __ jmp(&done);
1021 }
1022
1023 __ bind(&false_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001024 SetExpressionPosition(expr->else_expression(),
1025 expr->else_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001026 Visit(expr->else_expression());
1027 // If control flow falls through Visit, merge it with true case here.
1028 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1029 __ bind(&done);
1030 }
1031}
1032
1033
1034void FullCodeGenerator::VisitSlot(Slot* expr) {
1035 // Slots do not appear directly in the AST.
1036 UNREACHABLE();
1037}
1038
1039
1040void FullCodeGenerator::VisitLiteral(Literal* expr) {
1041 Comment cmnt(masm_, "[ Literal");
1042 Apply(context_, expr);
1043}
1044
1045
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001046void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1047 Comment cmnt(masm_, "[ FunctionLiteral");
1048
1049 // Build the function boilerplate and instantiate it.
1050 Handle<SharedFunctionInfo> function_info =
1051 Compiler::BuildFunctionInfo(expr, script(), this);
1052 if (HasStackOverflow()) return;
1053 EmitNewClosure(function_info);
1054}
1055
1056
1057void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
1058 SharedFunctionInfoLiteral* expr) {
1059 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
1060 EmitNewClosure(expr->shared_function_info());
1061}
1062
1063
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001064void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1065 // Call runtime routine to allocate the catch extension object and
1066 // assign the exception value to the catch variable.
1067 Comment cmnt(masm_, "[ CatchExtensionObject");
1068 VisitForValue(expr->key(), kStack);
1069 VisitForValue(expr->value(), kStack);
1070 // Create catch extension object.
1071 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
1072 Apply(context_, result_register());
1073}
1074
1075
1076void FullCodeGenerator::VisitThrow(Throw* expr) {
1077 Comment cmnt(masm_, "[ Throw");
1078 VisitForValue(expr->exception(), kStack);
1079 __ CallRuntime(Runtime::kThrow, 1);
1080 // Never returns here.
1081}
1082
1083
ricow@chromium.org65fae842010-08-25 15:26:24 +00001084void FullCodeGenerator::VisitIncrementOperation(IncrementOperation* expr) {
1085 UNREACHABLE();
1086}
1087
1088
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001089int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
1090 // The macros used here must preserve the result register.
1091 __ Drop(stack_depth);
1092 __ PopTryHandler();
1093 __ Call(finally_entry_);
1094 return 0;
1095}
1096
1097
1098int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
1099 // The macros used here must preserve the result register.
1100 __ Drop(stack_depth);
1101 __ PopTryHandler();
1102 return 0;
1103}
1104
ricow@chromium.org65fae842010-08-25 15:26:24 +00001105
1106void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
1107 ASSERT(args->length() == 1);
1108 VisitForValue(args->at(0), kStack);
1109 __ CallRuntime(Runtime::kRegExpCloneResult, 1);
1110 Apply(context_, result_register());
1111}
1112
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001113#undef __
1114
1115
1116} } // namespace v8::internal