blob: 7de4a0069c0e7fd2265f591d683326826d888188 [file] [log] [blame]
Leon Clarked91b9f72010-01-27 17:25:45 +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"
Kristian Monsen80d68ea2010-09-08 11:05:35 +010033#include "macro-assembler.h"
Steve Block6ded16b2010-05-10 14:33:55 +010034#include "scopes.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000035#include "stub-cache.h"
36#include "debug.h"
Andrei Popescu402d9372010-02-26 13:31:12 +000037#include "liveedit.h"
Leon Clarked91b9f72010-01-27 17:25:45 +000038
39namespace v8 {
40namespace internal {
41
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +010042void BreakableStatementChecker::Check(Statement* stmt) {
43 Visit(stmt);
44}
45
46
47void BreakableStatementChecker::Check(Expression* expr) {
48 Visit(expr);
49}
50
51
52void BreakableStatementChecker::VisitDeclaration(Declaration* decl) {
53}
54
55
56void BreakableStatementChecker::VisitBlock(Block* stmt) {
57}
58
59
60void BreakableStatementChecker::VisitExpressionStatement(
61 ExpressionStatement* stmt) {
62 // Check if expression is breakable.
63 Visit(stmt->expression());
64}
65
66
67void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
68}
69
70
71void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
72 // If the condition is breakable the if statement is breakable.
73 Visit(stmt->condition());
74}
75
76
77void BreakableStatementChecker::VisitContinueStatement(
78 ContinueStatement* stmt) {
79}
80
81
82void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
83}
84
85
86void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
87 // Return is breakable if the expression is.
88 Visit(stmt->expression());
89}
90
91
92void BreakableStatementChecker::VisitWithEnterStatement(
93 WithEnterStatement* stmt) {
94 Visit(stmt->expression());
95}
96
97
98void BreakableStatementChecker::VisitWithExitStatement(
99 WithExitStatement* stmt) {
100}
101
102
103void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
104 // Switch statements breakable if the tag expression is.
105 Visit(stmt->tag());
106}
107
108
109void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
110 // Mark do while as breakable to avoid adding a break slot in front of it.
111 is_breakable_ = true;
112}
113
114
115void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
116 // Mark while statements breakable if the condition expression is.
117 Visit(stmt->cond());
118}
119
120
121void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
122 // Mark for statements breakable if the condition expression is.
123 if (stmt->cond() != NULL) {
124 Visit(stmt->cond());
125 }
126}
127
128
129void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
130 // Mark for in statements breakable if the enumerable expression is.
131 Visit(stmt->enumerable());
132}
133
134
135void BreakableStatementChecker::VisitTryCatchStatement(
136 TryCatchStatement* stmt) {
137 // Mark try catch as breakable to avoid adding a break slot in front of it.
138 is_breakable_ = true;
139}
140
141
142void BreakableStatementChecker::VisitTryFinallyStatement(
143 TryFinallyStatement* stmt) {
144 // Mark try finally as breakable to avoid adding a break slot in front of it.
145 is_breakable_ = true;
146}
147
148
149void BreakableStatementChecker::VisitDebuggerStatement(
150 DebuggerStatement* stmt) {
151 // The debugger statement is breakable.
152 is_breakable_ = true;
153}
154
155
156void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
157}
158
159
160void BreakableStatementChecker::VisitSharedFunctionInfoLiteral(
161 SharedFunctionInfoLiteral* expr) {
162}
163
164
165void BreakableStatementChecker::VisitConditional(Conditional* expr) {
166}
167
168
169void BreakableStatementChecker::VisitSlot(Slot* expr) {
170}
171
172
173void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
174}
175
176
177void BreakableStatementChecker::VisitLiteral(Literal* expr) {
178}
179
180
181void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
182}
183
184
185void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
186}
187
188
189void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
190}
191
192
193void BreakableStatementChecker::VisitCatchExtensionObject(
194 CatchExtensionObject* expr) {
195}
196
197
198void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
199 // If assigning to a property (including a global property) the assignment is
200 // breakable.
201 Variable* var = expr->target()->AsVariableProxy()->AsVariable();
202 Property* prop = expr->target()->AsProperty();
203 if (prop != NULL || (var != NULL && var->is_global())) {
204 is_breakable_ = true;
205 return;
206 }
207
208 // Otherwise the assignment is breakable if the assigned value is.
209 Visit(expr->value());
210}
211
212
213void BreakableStatementChecker::VisitThrow(Throw* expr) {
214 // Throw is breakable if the expression is.
215 Visit(expr->exception());
216}
217
218
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100219void BreakableStatementChecker::VisitIncrementOperation(
220 IncrementOperation* expr) {
221 UNREACHABLE();
222}
223
224
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100225void BreakableStatementChecker::VisitProperty(Property* expr) {
226 // Property load is breakable.
227 is_breakable_ = true;
228}
229
230
231void BreakableStatementChecker::VisitCall(Call* expr) {
232 // Function calls both through IC and call stub are breakable.
233 is_breakable_ = true;
234}
235
236
237void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
238 // Function calls through new are breakable.
239 is_breakable_ = true;
240}
241
242
243void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
244}
245
246
247void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
248 Visit(expr->expression());
249}
250
251
252void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
253 Visit(expr->expression());
254}
255
256
257void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
258 Visit(expr->left());
259 Visit(expr->right());
260}
261
262
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100263void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) {
264 Visit(expr->expression());
265}
266
267
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100268void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
269 Visit(expr->left());
270 Visit(expr->right());
271}
272
273
274void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
275}
276
277
Leon Clarked91b9f72010-01-27 17:25:45 +0000278#define __ ACCESS_MASM(masm())
279
Andrei Popescu31002712010-02-23 13:46:05 +0000280Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
281 Handle<Script> script = info->script();
Leon Clarked91b9f72010-01-27 17:25:45 +0000282 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
283 int len = String::cast(script->source())->length();
284 Counters::total_full_codegen_source_size.Increment(len);
285 }
Andrei Popescu31002712010-02-23 13:46:05 +0000286 CodeGenerator::MakeCodePrologue(info);
Leon Clarked91b9f72010-01-27 17:25:45 +0000287 const int kInitialBufferSize = 4 * KB;
288 MacroAssembler masm(NULL, kInitialBufferSize);
Andrei Popescu402d9372010-02-26 13:31:12 +0000289
Andrei Popescu31002712010-02-23 13:46:05 +0000290 FullCodeGenerator cgen(&masm);
Iain Merrick75681382010-08-19 15:07:18 +0100291 cgen.Generate(info);
Leon Clarked91b9f72010-01-27 17:25:45 +0000292 if (cgen.HasStackOverflow()) {
293 ASSERT(!Top::has_pending_exception());
294 return Handle<Code>::null();
295 }
296 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
Steve Block6ded16b2010-05-10 14:33:55 +0100297 return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
Leon Clarked91b9f72010-01-27 17:25:45 +0000298}
299
300
Steve Block59151502010-09-22 15:07:15 +0100301MemOperand FullCodeGenerator::ContextOperand(Register context, int index) {
302 return CodeGenerator::ContextOperand(context, index);
303}
304
305
Leon Clarked91b9f72010-01-27 17:25:45 +0000306int FullCodeGenerator::SlotOffset(Slot* slot) {
307 ASSERT(slot != NULL);
308 // Offset is negative because higher indexes are at lower addresses.
309 int offset = -slot->index() * kPointerSize;
310 // Adjust by a (parameter or local) base offset.
311 switch (slot->type()) {
312 case Slot::PARAMETER:
Andrei Popescu31002712010-02-23 13:46:05 +0000313 offset += (scope()->num_parameters() + 1) * kPointerSize;
Leon Clarked91b9f72010-01-27 17:25:45 +0000314 break;
315 case Slot::LOCAL:
316 offset += JavaScriptFrameConstants::kLocal0Offset;
317 break;
318 case Slot::CONTEXT:
319 case Slot::LOOKUP:
320 UNREACHABLE();
321 }
322 return offset;
323}
324
325
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100326bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
327 // TODO(kasperl): Once the compare stub allows leaving out the
328 // inlined smi case, we should get rid of this check.
329 if (Token::IsCompareOp(op)) return true;
330 // TODO(kasperl): Once the unary bit not stub allows leaving out
331 // the inlined smi case, we should get rid of this check.
332 if (op == Token::BIT_NOT) return true;
333 // Inline smi case inside loops, but not division and modulo which
334 // are too complicated and take up too much space.
335 return (op != Token::DIV) && (op != Token::MOD) && (loop_depth_ > 0);
336}
337
338
339void FullCodeGenerator::PrepareTest(Label* materialize_true,
340 Label* materialize_false,
341 Label** if_true,
342 Label** if_false,
343 Label** fall_through) {
344 switch (context_) {
345 case Expression::kUninitialized:
346 UNREACHABLE();
347 break;
348 case Expression::kEffect:
349 // In an effect context, the true and the false case branch to the
350 // same label.
351 *if_true = *if_false = *fall_through = materialize_true;
352 break;
353 case Expression::kValue:
354 *if_true = *fall_through = materialize_true;
355 *if_false = materialize_false;
356 break;
357 case Expression::kTest:
358 *if_true = true_label_;
359 *if_false = false_label_;
360 *fall_through = fall_through_;
361 break;
362 }
363}
364
365
Leon Clarked91b9f72010-01-27 17:25:45 +0000366void FullCodeGenerator::VisitDeclarations(
367 ZoneList<Declaration*>* declarations) {
368 int length = declarations->length();
369 int globals = 0;
370 for (int i = 0; i < length; i++) {
371 Declaration* decl = declarations->at(i);
372 Variable* var = decl->proxy()->var();
373 Slot* slot = var->slot();
374
375 // If it was not possible to allocate the variable at compile
376 // time, we need to "declare" it at runtime to make sure it
377 // actually exists in the local context.
378 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
379 VisitDeclaration(decl);
380 } else {
381 // Count global variables and functions for later processing
382 globals++;
383 }
384 }
385
386 // Compute array of global variable and function declarations.
387 // Do nothing in case of no declared global functions or variables.
388 if (globals > 0) {
389 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
390 for (int j = 0, i = 0; i < length; i++) {
391 Declaration* decl = declarations->at(i);
392 Variable* var = decl->proxy()->var();
393 Slot* slot = var->slot();
394
395 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
396 array->set(j++, *(var->name()));
397 if (decl->fun() == NULL) {
398 if (var->mode() == Variable::CONST) {
399 // In case this is const property use the hole.
400 array->set_the_hole(j++);
401 } else {
402 array->set_undefined(j++);
403 }
404 } else {
Steve Block6ded16b2010-05-10 14:33:55 +0100405 Handle<SharedFunctionInfo> function =
406 Compiler::BuildFunctionInfo(decl->fun(), script(), this);
Leon Clarked91b9f72010-01-27 17:25:45 +0000407 // Check for stack-overflow exception.
408 if (HasStackOverflow()) return;
409 array->set(j++, *function);
410 }
411 }
412 }
413 // Invoke the platform-dependent code generator to do the actual
414 // declaration the global variables and functions.
415 DeclareGlobals(array);
416 }
417}
418
419
420void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
421 if (FLAG_debug_info) {
422 CodeGenerator::RecordPositions(masm_, fun->start_position());
423 }
424}
425
426
427void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
428 if (FLAG_debug_info) {
Ben Murdochbb769b22010-08-11 14:56:33 +0100429 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
Leon Clarked91b9f72010-01-27 17:25:45 +0000430 }
431}
432
433
434void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
435 if (FLAG_debug_info) {
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100436#ifdef ENABLE_DEBUGGER_SUPPORT
437 if (!Debugger::IsDebuggerActive()) {
438 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
439 } else {
440 // Check if the statement will be breakable without adding a debug break
441 // slot.
442 BreakableStatementChecker checker;
443 checker.Check(stmt);
444 // Record the statement position right here if the statement is not
445 // breakable. For breakable statements the actual recording of the
446 // position will be postponed to the breakable code (typically an IC).
447 bool position_recorded = CodeGenerator::RecordPositions(
448 masm_, stmt->statement_pos(), !checker.is_breakable());
449 // If the position recording did record a new position generate a debug
450 // break slot to make the statement breakable.
451 if (position_recorded) {
452 Debug::GenerateSlot(masm_);
453 }
454 }
455#else
Leon Clarked91b9f72010-01-27 17:25:45 +0000456 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100457#endif
458 }
459}
460
461
462void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
463 if (FLAG_debug_info) {
464#ifdef ENABLE_DEBUGGER_SUPPORT
465 if (!Debugger::IsDebuggerActive()) {
466 CodeGenerator::RecordPositions(masm_, pos);
467 } else {
468 // Check if the expression will be breakable without adding a debug break
469 // slot.
470 BreakableStatementChecker checker;
471 checker.Check(expr);
472 // Record a statement position right here if the expression is not
473 // breakable. For breakable expressions the actual recording of the
474 // position will be postponed to the breakable code (typically an IC).
475 // NOTE this will record a statement position for something which might
476 // not be a statement. As stepping in the debugger will only stop at
477 // statement positions this is used for e.g. the condition expression of
478 // a do while loop.
479 bool position_recorded = CodeGenerator::RecordPositions(
480 masm_, pos, !checker.is_breakable());
481 // If the position recording did record a new position generate a debug
482 // break slot to make the statement breakable.
483 if (position_recorded) {
484 Debug::GenerateSlot(masm_);
485 }
486 }
487#else
488 CodeGenerator::RecordPositions(masm_, pos);
489#endif
Leon Clarked91b9f72010-01-27 17:25:45 +0000490 }
491}
492
493
494void FullCodeGenerator::SetStatementPosition(int pos) {
495 if (FLAG_debug_info) {
496 CodeGenerator::RecordPositions(masm_, pos);
497 }
498}
499
500
501void FullCodeGenerator::SetSourcePosition(int pos) {
502 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
503 masm_->RecordPosition(pos);
504 }
505}
506
507
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100508void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
509 Handle<String> name = expr->name();
Steve Block791712a2010-08-27 10:21:07 +0100510 SmartPointer<char> cstring = name->ToCString();
511
512#define CHECK_EMIT_INLINE_CALL(name, x, y) \
513 if (strcmp("_"#name, *cstring) == 0) { \
514 Emit##name(expr->arguments()); \
515 return; \
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100516 }
Steve Block791712a2010-08-27 10:21:07 +0100517 INLINE_RUNTIME_FUNCTION_LIST(CHECK_EMIT_INLINE_CALL)
Steve Block791712a2010-08-27 10:21:07 +0100518#undef CHECK_EMIT_INLINE_CALL
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100519 UNREACHABLE();
520}
521
522
523void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
524 Comment cmnt(masm_, "[ BinaryOperation");
525 Token::Value op = expr->op();
526 Expression* left = expr->left();
527 Expression* right = expr->right();
528
529 OverwriteMode mode = NO_OVERWRITE;
530 if (left->ResultOverwriteAllowed()) {
531 mode = OVERWRITE_LEFT;
532 } else if (right->ResultOverwriteAllowed()) {
533 mode = OVERWRITE_RIGHT;
534 }
535
536 switch (op) {
537 case Token::COMMA:
538 VisitForEffect(left);
539 Visit(right);
540 break;
541
542 case Token::OR:
543 case Token::AND:
544 EmitLogicalOperation(expr);
545 break;
546
547 case Token::ADD:
548 case Token::SUB:
549 case Token::DIV:
550 case Token::MOD:
551 case Token::MUL:
552 case Token::BIT_OR:
553 case Token::BIT_AND:
554 case Token::BIT_XOR:
555 case Token::SHL:
556 case Token::SHR:
557 case Token::SAR: {
558 // Figure out if either of the operands is a constant.
559 ConstantOperand constant = ShouldInlineSmiCase(op)
560 ? GetConstantOperand(op, left, right)
561 : kNoConstants;
562
563 // Load only the operands that we need to materialize.
564 if (constant == kNoConstants) {
565 VisitForValue(left, kStack);
566 VisitForValue(right, kAccumulator);
567 } else if (constant == kRightConstant) {
568 VisitForValue(left, kAccumulator);
569 } else {
570 ASSERT(constant == kLeftConstant);
571 VisitForValue(right, kAccumulator);
572 }
573
574 SetSourcePosition(expr->position());
575 if (ShouldInlineSmiCase(op)) {
576 EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
577 } else {
578 EmitBinaryOp(op, context_, mode);
579 }
580 break;
581 }
582
583 default:
584 UNREACHABLE();
585 }
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100586}
587
588
Leon Clarked91b9f72010-01-27 17:25:45 +0000589void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
590 Label eval_right, done;
591
592 // Set up the appropriate context for the left subexpression based
593 // on the operation and our own context. Initially assume we can
594 // inherit both true and false labels from our context.
595 if (expr->op() == Token::OR) {
596 switch (context_) {
597 case Expression::kUninitialized:
598 UNREACHABLE();
599 case Expression::kEffect:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100600 VisitForControl(expr->left(), &done, &eval_right, &eval_right);
Leon Clarked91b9f72010-01-27 17:25:45 +0000601 break;
602 case Expression::kValue:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100603 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
Leon Clarked91b9f72010-01-27 17:25:45 +0000604 break;
605 case Expression::kTest:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100606 VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
Leon Clarked91b9f72010-01-27 17:25:45 +0000607 break;
608 }
609 } else {
610 ASSERT_EQ(Token::AND, expr->op());
611 switch (context_) {
612 case Expression::kUninitialized:
613 UNREACHABLE();
614 case Expression::kEffect:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100615 VisitForControl(expr->left(), &eval_right, &done, &eval_right);
Leon Clarked91b9f72010-01-27 17:25:45 +0000616 break;
617 case Expression::kValue:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100618 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
Leon Clarked91b9f72010-01-27 17:25:45 +0000619 break;
620 case Expression::kTest:
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100621 VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
Leon Clarked91b9f72010-01-27 17:25:45 +0000622 break;
623 }
624 }
625
626 __ bind(&eval_right);
627 Visit(expr->right());
628
629 __ bind(&done);
630}
631
632
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100633void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
634 Token::Value op,
635 Location where,
636 Label* done) {
637 ASSERT(op == Token::AND || op == Token::OR);
638 VisitForValue(expr, kAccumulator);
639 __ push(result_register());
640
641 Label discard;
642 switch (where) {
643 case kAccumulator: {
644 Label restore;
645 if (op == Token::OR) {
646 DoTest(&restore, &discard, &restore);
647 } else {
648 DoTest(&discard, &restore, &restore);
649 }
650 __ bind(&restore);
651 __ pop(result_register());
652 __ jmp(done);
653 break;
654 }
655 case kStack: {
656 if (op == Token::OR) {
657 DoTest(done, &discard, &discard);
658 } else {
659 DoTest(&discard, done, &discard);
660 }
661 break;
662 }
663 }
664
665 __ bind(&discard);
666 __ Drop(1);
667}
668
669
Leon Clarked91b9f72010-01-27 17:25:45 +0000670void 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
679void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
680 Comment cmnt(masm_, "[ ExpressionStatement");
681 SetStatementPosition(stmt);
682 VisitForEffect(stmt->expression());
683}
684
685
686void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
687 Comment cmnt(masm_, "[ EmptyStatement");
688 SetStatementPosition(stmt);
689}
690
691
692void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
693 Comment cmnt(masm_, "[ IfStatement");
694 SetStatementPosition(stmt);
695 Label then_part, else_part, done;
696
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100697 if (stmt->HasElseStatement()) {
698 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
699 __ bind(&then_part);
700 Visit(stmt->then_statement());
701 __ jmp(&done);
Leon Clarked91b9f72010-01-27 17:25:45 +0000702
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100703 __ bind(&else_part);
704 Visit(stmt->else_statement());
705 } else {
706 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
707 __ bind(&then_part);
708 Visit(stmt->then_statement());
709 }
Leon Clarked91b9f72010-01-27 17:25:45 +0000710 __ bind(&done);
711}
712
713
714void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
715 Comment cmnt(masm_, "[ ContinueStatement");
716 SetStatementPosition(stmt);
717 NestedStatement* current = nesting_stack_;
718 int stack_depth = 0;
719 while (!current->IsContinueTarget(stmt->target())) {
720 stack_depth = current->Exit(stack_depth);
721 current = current->outer();
722 }
723 __ Drop(stack_depth);
724
725 Iteration* loop = current->AsIteration();
726 __ jmp(loop->continue_target());
727}
728
729
730void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
731 Comment cmnt(masm_, "[ BreakStatement");
732 SetStatementPosition(stmt);
733 NestedStatement* current = nesting_stack_;
734 int stack_depth = 0;
735 while (!current->IsBreakTarget(stmt->target())) {
736 stack_depth = current->Exit(stack_depth);
737 current = current->outer();
738 }
739 __ Drop(stack_depth);
740
741 Breakable* target = current->AsBreakable();
742 __ jmp(target->break_target());
743}
744
745
746void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
747 Comment cmnt(masm_, "[ ReturnStatement");
748 SetStatementPosition(stmt);
749 Expression* expr = stmt->expression();
750 VisitForValue(expr, kAccumulator);
751
752 // Exit all nested statements.
753 NestedStatement* current = nesting_stack_;
754 int stack_depth = 0;
755 while (current != NULL) {
756 stack_depth = current->Exit(stack_depth);
757 current = current->outer();
758 }
759 __ Drop(stack_depth);
760
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100761 EmitReturnSequence();
Leon Clarked91b9f72010-01-27 17:25:45 +0000762}
763
764
765void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
766 Comment cmnt(masm_, "[ WithEnterStatement");
767 SetStatementPosition(stmt);
768
769 VisitForValue(stmt->expression(), kStack);
770 if (stmt->is_catch_block()) {
771 __ CallRuntime(Runtime::kPushCatchContext, 1);
772 } else {
773 __ CallRuntime(Runtime::kPushContext, 1);
774 }
775 // Both runtime calls return the new context in both the context and the
776 // result registers.
777
778 // Update local stack frame context field.
779 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
780}
781
782
783void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
784 Comment cmnt(masm_, "[ WithExitStatement");
785 SetStatementPosition(stmt);
786
787 // Pop context.
788 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
789 // Update local stack frame context field.
790 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
791}
792
793
Leon Clarked91b9f72010-01-27 17:25:45 +0000794void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
795 Comment cmnt(masm_, "[ DoWhileStatement");
796 SetStatementPosition(stmt);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100797 Label body, stack_limit_hit, stack_check_success, done;
Leon Clarked91b9f72010-01-27 17:25:45 +0000798
799 Iteration loop_statement(this, stmt);
800 increment_loop_depth();
801
802 __ bind(&body);
803 Visit(stmt->body());
804
805 // Check stack before looping.
806 __ StackLimitCheck(&stack_limit_hit);
807 __ bind(&stack_check_success);
808
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100809 // Record the position of the do while condition and make sure it is
810 // possible to break on the condition.
Leon Clarked91b9f72010-01-27 17:25:45 +0000811 __ bind(loop_statement.continue_target());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100812 SetExpressionPosition(stmt->cond(), stmt->condition_position());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100813 VisitForControl(stmt->cond(),
814 &body,
815 loop_statement.break_target(),
816 loop_statement.break_target());
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100817
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100818 __ bind(loop_statement.break_target());
819 __ jmp(&done);
Leon Clarked91b9f72010-01-27 17:25:45 +0000820
821 __ bind(&stack_limit_hit);
822 StackCheckStub stack_stub;
823 __ CallStub(&stack_stub);
824 __ jmp(&stack_check_success);
825
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100826 __ bind(&done);
Leon Clarked91b9f72010-01-27 17:25:45 +0000827 decrement_loop_depth();
828}
829
830
831void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
832 Comment cmnt(masm_, "[ WhileStatement");
Iain Merrick9ac36c92010-09-13 15:29:50 +0100833 Label body, stack_limit_hit, stack_check_success, done;
Leon Clarked91b9f72010-01-27 17:25:45 +0000834
835 Iteration loop_statement(this, stmt);
836 increment_loop_depth();
837
838 // Emit the test at the bottom of the loop.
839 __ jmp(loop_statement.continue_target());
840
841 __ bind(&body);
842 Visit(stmt->body());
Leon Clarked91b9f72010-01-27 17:25:45 +0000843 __ bind(loop_statement.continue_target());
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100844
845 // Emit the statement position here as this is where the while
846 // statement code starts.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100847 SetStatementPosition(stmt);
Leon Clarkef7060e22010-06-03 12:02:55 +0100848
Leon Clarked91b9f72010-01-27 17:25:45 +0000849 // Check stack before looping.
850 __ StackLimitCheck(&stack_limit_hit);
851 __ bind(&stack_check_success);
852
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100853 VisitForControl(stmt->cond(),
854 &body,
855 loop_statement.break_target(),
856 loop_statement.break_target());
Leon Clarked91b9f72010-01-27 17:25:45 +0000857
858 __ bind(loop_statement.break_target());
Iain Merrick9ac36c92010-09-13 15:29:50 +0100859 __ jmp(&done);
860
861 __ bind(&stack_limit_hit);
862 StackCheckStub stack_stub;
863 __ CallStub(&stack_stub);
864 __ jmp(&stack_check_success);
865
866 __ bind(&done);
Leon Clarked91b9f72010-01-27 17:25:45 +0000867 decrement_loop_depth();
868}
869
870
871void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
872 Comment cmnt(masm_, "[ ForStatement");
Leon Clarked91b9f72010-01-27 17:25:45 +0000873 Label test, body, stack_limit_hit, stack_check_success;
874
875 Iteration loop_statement(this, stmt);
876 if (stmt->init() != NULL) {
877 Visit(stmt->init());
878 }
879
880 increment_loop_depth();
881 // Emit the test at the bottom of the loop (even if empty).
882 __ jmp(&test);
883
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100884 __ bind(&stack_limit_hit);
885 StackCheckStub stack_stub;
886 __ CallStub(&stack_stub);
887 __ jmp(&stack_check_success);
888
Leon Clarked91b9f72010-01-27 17:25:45 +0000889 __ bind(&body);
890 Visit(stmt->body());
891
892 __ bind(loop_statement.continue_target());
893
894 SetStatementPosition(stmt);
895 if (stmt->next() != NULL) {
896 Visit(stmt->next());
897 }
898
899 __ bind(&test);
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100900 // Emit the statement position here as this is where the for
901 // statement code starts.
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +0100902 SetStatementPosition(stmt);
Leon Clarked91b9f72010-01-27 17:25:45 +0000903
904 // Check stack before looping.
905 __ StackLimitCheck(&stack_limit_hit);
906 __ bind(&stack_check_success);
907
908 if (stmt->cond() != NULL) {
Kristian Monsen80d68ea2010-09-08 11:05:35 +0100909 VisitForControl(stmt->cond(),
910 &body,
911 loop_statement.break_target(),
912 loop_statement.break_target());
Leon Clarked91b9f72010-01-27 17:25:45 +0000913 } else {
914 __ jmp(&body);
915 }
916
Leon Clarked91b9f72010-01-27 17:25:45 +0000917 __ bind(loop_statement.break_target());
918 decrement_loop_depth();
919}
920
921
Leon Clarked91b9f72010-01-27 17:25:45 +0000922void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
923 Comment cmnt(masm_, "[ TryCatchStatement");
924 SetStatementPosition(stmt);
925 // The try block adds a handler to the exception handler chain
926 // before entering, and removes it again when exiting normally.
927 // If an exception is thrown during execution of the try block,
928 // control is passed to the handler, which also consumes the handler.
929 // At this point, the exception is in a register, and store it in
930 // the temporary local variable (prints as ".catch-var") before
931 // executing the catch block. The catch block has been rewritten
932 // to introduce a new scope to bind the catch variable and to remove
933 // that scope again afterwards.
934
935 Label try_handler_setup, catch_entry, done;
936 __ Call(&try_handler_setup);
937 // Try handler code, exception in result register.
938
939 // Store exception in local .catch variable before executing catch block.
940 {
941 // The catch variable is *always* a variable proxy for a local variable.
942 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
943 ASSERT_NOT_NULL(catch_var);
944 Slot* variable_slot = catch_var->slot();
945 ASSERT_NOT_NULL(variable_slot);
946 ASSERT_EQ(Slot::LOCAL, variable_slot->type());
947 StoreToFrameField(SlotOffset(variable_slot), result_register());
948 }
949
950 Visit(stmt->catch_block());
951 __ jmp(&done);
952
953 // Try block code. Sets up the exception handler chain.
954 __ bind(&try_handler_setup);
955 {
956 TryCatch try_block(this, &catch_entry);
957 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
958 Visit(stmt->try_block());
959 __ PopTryHandler();
960 }
961 __ bind(&done);
962}
963
964
965void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
966 Comment cmnt(masm_, "[ TryFinallyStatement");
967 SetStatementPosition(stmt);
968 // Try finally is compiled by setting up a try-handler on the stack while
969 // executing the try body, and removing it again afterwards.
970 //
971 // The try-finally construct can enter the finally block in three ways:
972 // 1. By exiting the try-block normally. This removes the try-handler and
973 // calls the finally block code before continuing.
974 // 2. By exiting the try-block with a function-local control flow transfer
975 // (break/continue/return). The site of the, e.g., break removes the
976 // try handler and calls the finally block code before continuing
977 // its outward control transfer.
978 // 3. by exiting the try-block with a thrown exception.
979 // This can happen in nested function calls. It traverses the try-handler
980 // chain and consumes the try-handler entry before jumping to the
981 // handler code. The handler code then calls the finally-block before
982 // rethrowing the exception.
983 //
984 // The finally block must assume a return address on top of the stack
985 // (or in the link register on ARM chips) and a value (return value or
986 // exception) in the result register (rax/eax/r0), both of which must
987 // be preserved. The return address isn't GC-safe, so it should be
988 // cooked before GC.
989 Label finally_entry;
990 Label try_handler_setup;
991
992 // Setup the try-handler chain. Use a call to
993 // Jump to try-handler setup and try-block code. Use call to put try-handler
994 // address on stack.
995 __ Call(&try_handler_setup);
996 // Try handler code. Return address of call is pushed on handler stack.
997 {
998 // This code is only executed during stack-handler traversal when an
999 // exception is thrown. The execption is in the result register, which
1000 // is retained by the finally block.
1001 // Call the finally block and then rethrow the exception.
1002 __ Call(&finally_entry);
1003 __ push(result_register());
1004 __ CallRuntime(Runtime::kReThrow, 1);
1005 }
1006
1007 __ bind(&finally_entry);
1008 {
1009 // Finally block implementation.
1010 Finally finally_block(this);
1011 EnterFinallyBlock();
1012 Visit(stmt->finally_block());
1013 ExitFinallyBlock(); // Return to the calling code.
1014 }
1015
1016 __ bind(&try_handler_setup);
1017 {
1018 // Setup try handler (stack pointer registers).
1019 TryFinally try_block(this, &finally_entry);
1020 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
1021 Visit(stmt->try_block());
1022 __ PopTryHandler();
1023 }
1024 // Execute the finally block on the way out.
1025 __ Call(&finally_entry);
1026}
1027
1028
1029void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1030#ifdef ENABLE_DEBUGGER_SUPPORT
1031 Comment cmnt(masm_, "[ DebuggerStatement");
1032 SetStatementPosition(stmt);
Leon Clarke4515c472010-02-03 11:58:03 +00001033
Andrei Popescu402d9372010-02-26 13:31:12 +00001034 __ DebugBreak();
Leon Clarked91b9f72010-01-27 17:25:45 +00001035 // Ignore the return value.
1036#endif
1037}
1038
1039
Leon Clarked91b9f72010-01-27 17:25:45 +00001040void FullCodeGenerator::VisitConditional(Conditional* expr) {
1041 Comment cmnt(masm_, "[ Conditional");
1042 Label true_case, false_case, done;
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001043 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
Leon Clarked91b9f72010-01-27 17:25:45 +00001044
1045 __ bind(&true_case);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001046 SetExpressionPosition(expr->then_expression(),
1047 expr->then_expression_position());
Leon Clarked91b9f72010-01-27 17:25:45 +00001048 Visit(expr->then_expression());
1049 // If control flow falls through Visit, jump to done.
1050 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1051 __ jmp(&done);
1052 }
1053
1054 __ bind(&false_case);
Ben Murdoch7f4d5bd2010-06-15 11:15:29 +01001055 SetExpressionPosition(expr->else_expression(),
1056 expr->else_expression_position());
Leon Clarked91b9f72010-01-27 17:25:45 +00001057 Visit(expr->else_expression());
1058 // If control flow falls through Visit, merge it with true case here.
1059 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1060 __ bind(&done);
1061 }
1062}
1063
1064
1065void FullCodeGenerator::VisitSlot(Slot* expr) {
1066 // Slots do not appear directly in the AST.
1067 UNREACHABLE();
1068}
1069
1070
1071void FullCodeGenerator::VisitLiteral(Literal* expr) {
1072 Comment cmnt(masm_, "[ Literal");
1073 Apply(context_, expr);
1074}
1075
1076
Leon Clarkef7060e22010-06-03 12:02:55 +01001077void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1078 Comment cmnt(masm_, "[ FunctionLiteral");
1079
1080 // Build the function boilerplate and instantiate it.
1081 Handle<SharedFunctionInfo> function_info =
1082 Compiler::BuildFunctionInfo(expr, script(), this);
1083 if (HasStackOverflow()) return;
1084 EmitNewClosure(function_info);
1085}
1086
1087
1088void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
1089 SharedFunctionInfoLiteral* expr) {
1090 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
1091 EmitNewClosure(expr->shared_function_info());
1092}
1093
1094
Leon Clarked91b9f72010-01-27 17:25:45 +00001095void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1096 // Call runtime routine to allocate the catch extension object and
1097 // assign the exception value to the catch variable.
1098 Comment cmnt(masm_, "[ CatchExtensionObject");
1099 VisitForValue(expr->key(), kStack);
1100 VisitForValue(expr->value(), kStack);
1101 // Create catch extension object.
1102 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
1103 Apply(context_, result_register());
1104}
1105
1106
1107void FullCodeGenerator::VisitThrow(Throw* expr) {
1108 Comment cmnt(masm_, "[ Throw");
1109 VisitForValue(expr->exception(), kStack);
1110 __ CallRuntime(Runtime::kThrow, 1);
1111 // Never returns here.
1112}
1113
1114
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001115void FullCodeGenerator::VisitIncrementOperation(IncrementOperation* expr) {
1116 UNREACHABLE();
1117}
1118
1119
Leon Clarked91b9f72010-01-27 17:25:45 +00001120int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
1121 // The macros used here must preserve the result register.
1122 __ Drop(stack_depth);
1123 __ PopTryHandler();
1124 __ Call(finally_entry_);
1125 return 0;
1126}
1127
1128
1129int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
1130 // The macros used here must preserve the result register.
1131 __ Drop(stack_depth);
1132 __ PopTryHandler();
1133 return 0;
1134}
1135
Kristian Monsen80d68ea2010-09-08 11:05:35 +01001136
1137void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
1138 ASSERT(args->length() == 1);
1139 VisitForValue(args->at(0), kStack);
1140 __ CallRuntime(Runtime::kRegExpCloneResult, 1);
1141 Apply(context_, result_register());
1142}
1143
Leon Clarked91b9f72010-01-27 17:25:45 +00001144#undef __
1145
1146
1147} } // namespace v8::internal