blob: 59cbad95b57d11a6b893ee8965fddb066384557a [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"
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +000033#include "macro-assembler.h"
sgjesse@chromium.org833cdd72010-02-26 10:06:16 +000034#include "scopes.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000035#include "stub-cache.h"
36#include "debug.h"
ager@chromium.org5c838252010-02-19 08:53:10 +000037#include "liveedit.h"
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000038
39namespace v8 {
40namespace internal {
41
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +000042void 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
ricow@chromium.org65fae842010-08-25 15:26:24 +0000219void BreakableStatementChecker::VisitIncrementOperation(
220 IncrementOperation* expr) {
221 UNREACHABLE();
222}
223
224
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000225void 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
ricow@chromium.org65fae842010-08-25 15:26:24 +0000263void BreakableStatementChecker::VisitCompareToNull(CompareToNull* expr) {
264 Visit(expr->expression());
265}
266
267
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000268void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
269 Visit(expr->left());
270 Visit(expr->right());
271}
272
273
274void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
275}
276
277
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000278#define __ ACCESS_MASM(masm())
279
ager@chromium.org5c838252010-02-19 08:53:10 +0000280Handle<Code> FullCodeGenerator::MakeCode(CompilationInfo* info) {
281 Handle<Script> script = info->script();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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 }
ager@chromium.org5c838252010-02-19 08:53:10 +0000286 CodeGenerator::MakeCodePrologue(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000287 const int kInitialBufferSize = 4 * KB;
288 MacroAssembler masm(NULL, kInitialBufferSize);
ager@chromium.org5c838252010-02-19 08:53:10 +0000289
290 FullCodeGenerator cgen(&masm);
ager@chromium.orgea4f62e2010-08-16 16:28:43 +0000291 cgen.Generate(info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +0000297 return CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000298}
299
300
301int FullCodeGenerator::SlotOffset(Slot* slot) {
302 ASSERT(slot != NULL);
303 // Offset is negative because higher indexes are at lower addresses.
304 int offset = -slot->index() * kPointerSize;
305 // Adjust by a (parameter or local) base offset.
306 switch (slot->type()) {
307 case Slot::PARAMETER:
ager@chromium.org5c838252010-02-19 08:53:10 +0000308 offset += (scope()->num_parameters() + 1) * kPointerSize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000309 break;
310 case Slot::LOCAL:
311 offset += JavaScriptFrameConstants::kLocal0Offset;
312 break;
313 case Slot::CONTEXT:
314 case Slot::LOOKUP:
315 UNREACHABLE();
316 }
317 return offset;
318}
319
320
ricow@chromium.org65fae842010-08-25 15:26:24 +0000321bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
322 // TODO(kasperl): Once the compare stub allows leaving out the
323 // inlined smi case, we should get rid of this check.
324 if (Token::IsCompareOp(op)) return true;
325 // TODO(kasperl): Once the unary bit not stub allows leaving out
326 // the inlined smi case, we should get rid of this check.
327 if (op == Token::BIT_NOT) return true;
328 // Inline smi case inside loops, but not division and modulo which
329 // are too complicated and take up too much space.
330 return (op != Token::DIV) && (op != Token::MOD) && (loop_depth_ > 0);
331}
332
333
334void FullCodeGenerator::PrepareTest(Label* materialize_true,
335 Label* materialize_false,
336 Label** if_true,
337 Label** if_false,
338 Label** fall_through) {
339 switch (context_) {
340 case Expression::kUninitialized:
341 UNREACHABLE();
342 break;
343 case Expression::kEffect:
344 // In an effect context, the true and the false case branch to the
345 // same label.
346 *if_true = *if_false = *fall_through = materialize_true;
347 break;
348 case Expression::kValue:
349 *if_true = *fall_through = materialize_true;
350 *if_false = materialize_false;
351 break;
352 case Expression::kTest:
353 *if_true = true_label_;
354 *if_false = false_label_;
355 *fall_through = fall_through_;
356 break;
357 }
358}
359
360
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000361void FullCodeGenerator::VisitDeclarations(
362 ZoneList<Declaration*>* declarations) {
363 int length = declarations->length();
364 int globals = 0;
365 for (int i = 0; i < length; i++) {
366 Declaration* decl = declarations->at(i);
367 Variable* var = decl->proxy()->var();
368 Slot* slot = var->slot();
369
370 // If it was not possible to allocate the variable at compile
371 // time, we need to "declare" it at runtime to make sure it
372 // actually exists in the local context.
373 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
374 VisitDeclaration(decl);
375 } else {
376 // Count global variables and functions for later processing
377 globals++;
378 }
379 }
380
381 // Compute array of global variable and function declarations.
382 // Do nothing in case of no declared global functions or variables.
383 if (globals > 0) {
384 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
385 for (int j = 0, i = 0; i < length; i++) {
386 Declaration* decl = declarations->at(i);
387 Variable* var = decl->proxy()->var();
388 Slot* slot = var->slot();
389
390 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
391 array->set(j++, *(var->name()));
392 if (decl->fun() == NULL) {
393 if (var->mode() == Variable::CONST) {
394 // In case this is const property use the hole.
395 array->set_the_hole(j++);
396 } else {
397 array->set_undefined(j++);
398 }
399 } else {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000400 Handle<SharedFunctionInfo> function =
401 Compiler::BuildFunctionInfo(decl->fun(), script(), this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000402 // Check for stack-overflow exception.
403 if (HasStackOverflow()) return;
404 array->set(j++, *function);
405 }
406 }
407 }
408 // Invoke the platform-dependent code generator to do the actual
409 // declaration the global variables and functions.
410 DeclareGlobals(array);
411 }
412}
413
414
415void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
416 if (FLAG_debug_info) {
417 CodeGenerator::RecordPositions(masm_, fun->start_position());
418 }
419}
420
421
422void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
423 if (FLAG_debug_info) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000424 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000425 }
426}
427
428
429void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
430 if (FLAG_debug_info) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000431#ifdef ENABLE_DEBUGGER_SUPPORT
432 if (!Debugger::IsDebuggerActive()) {
433 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
434 } else {
435 // Check if the statement will be breakable without adding a debug break
436 // slot.
437 BreakableStatementChecker checker;
438 checker.Check(stmt);
439 // Record the statement position right here if the statement is not
440 // breakable. For breakable statements the actual recording of the
441 // position will be postponed to the breakable code (typically an IC).
442 bool position_recorded = CodeGenerator::RecordPositions(
443 masm_, stmt->statement_pos(), !checker.is_breakable());
444 // If the position recording did record a new position generate a debug
445 // break slot to make the statement breakable.
446 if (position_recorded) {
447 Debug::GenerateSlot(masm_);
448 }
449 }
450#else
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000451 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000452#endif
453 }
454}
455
456
457void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
458 if (FLAG_debug_info) {
459#ifdef ENABLE_DEBUGGER_SUPPORT
460 if (!Debugger::IsDebuggerActive()) {
461 CodeGenerator::RecordPositions(masm_, pos);
462 } else {
463 // Check if the expression will be breakable without adding a debug break
464 // slot.
465 BreakableStatementChecker checker;
466 checker.Check(expr);
467 // Record a statement position right here if the expression is not
468 // breakable. For breakable expressions the actual recording of the
469 // position will be postponed to the breakable code (typically an IC).
470 // NOTE this will record a statement position for something which might
471 // not be a statement. As stepping in the debugger will only stop at
472 // statement positions this is used for e.g. the condition expression of
473 // a do while loop.
474 bool position_recorded = CodeGenerator::RecordPositions(
475 masm_, pos, !checker.is_breakable());
476 // If the position recording did record a new position generate a debug
477 // break slot to make the statement breakable.
478 if (position_recorded) {
479 Debug::GenerateSlot(masm_);
480 }
481 }
482#else
483 CodeGenerator::RecordPositions(masm_, pos);
484#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000485 }
486}
487
488
489void FullCodeGenerator::SetStatementPosition(int pos) {
490 if (FLAG_debug_info) {
491 CodeGenerator::RecordPositions(masm_, pos);
492 }
493}
494
495
496void FullCodeGenerator::SetSourcePosition(int pos) {
497 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
498 masm_->RecordPosition(pos);
499 }
500}
501
502
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000503void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
504 Handle<String> name = expr->name();
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000505 SmartPointer<char> cstring = name->ToCString();
506
507#define CHECK_EMIT_INLINE_CALL(name, x, y) \
508 if (strcmp("_"#name, *cstring) == 0) { \
509 Emit##name(expr->arguments()); \
510 return; \
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000511 }
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000512 INLINE_RUNTIME_FUNCTION_LIST(CHECK_EMIT_INLINE_CALL)
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000513#undef CHECK_EMIT_INLINE_CALL
ricow@chromium.org65fae842010-08-25 15:26:24 +0000514 UNREACHABLE();
515}
516
517
518void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
519 Comment cmnt(masm_, "[ BinaryOperation");
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000520 Token::Value op = expr->op();
521 Expression* left = expr->left();
522 Expression* right = expr->right();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000523
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000524 OverwriteMode mode = NO_OVERWRITE;
525 if (left->ResultOverwriteAllowed()) {
526 mode = OVERWRITE_LEFT;
527 } else if (right->ResultOverwriteAllowed()) {
528 mode = OVERWRITE_RIGHT;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000529 }
530
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000531 switch (op) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000532 case Token::COMMA:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000533 VisitForEffect(left);
534 Visit(right);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000535 break;
536
537 case Token::OR:
538 case Token::AND:
539 EmitLogicalOperation(expr);
540 break;
541
542 case Token::ADD:
543 case Token::SUB:
544 case Token::DIV:
545 case Token::MOD:
546 case Token::MUL:
547 case Token::BIT_OR:
548 case Token::BIT_AND:
549 case Token::BIT_XOR:
550 case Token::SHL:
551 case Token::SHR:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000552 case Token::SAR: {
553 // Figure out if either of the operands is a constant.
554 ConstantOperand constant = ShouldInlineSmiCase(op)
555 ? GetConstantOperand(op, left, right)
556 : kNoConstants;
557
558 // Load only the operands that we need to materialize.
559 if (constant == kNoConstants) {
560 VisitForValue(left, kStack);
561 VisitForValue(right, kAccumulator);
562 } else if (constant == kRightConstant) {
563 VisitForValue(left, kAccumulator);
564 } else {
565 ASSERT(constant == kLeftConstant);
566 VisitForValue(right, kAccumulator);
567 }
568
ricow@chromium.org65fae842010-08-25 15:26:24 +0000569 SetSourcePosition(expr->position());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000570 if (ShouldInlineSmiCase(op)) {
571 EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
572 } else {
573 EmitBinaryOp(op, context_, mode);
574 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000575 break;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000576 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000577
578 default:
579 UNREACHABLE();
580 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000581}
582
583
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000584void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
585 Label eval_right, done;
586
587 // Set up the appropriate context for the left subexpression based
588 // on the operation and our own context. Initially assume we can
589 // inherit both true and false labels from our context.
590 if (expr->op() == Token::OR) {
591 switch (context_) {
592 case Expression::kUninitialized:
593 UNREACHABLE();
594 case Expression::kEffect:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000595 VisitForControl(expr->left(), &done, &eval_right, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000596 break;
597 case Expression::kValue:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000598 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000599 break;
600 case Expression::kTest:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000601 VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000602 break;
603 }
604 } else {
605 ASSERT_EQ(Token::AND, expr->op());
606 switch (context_) {
607 case Expression::kUninitialized:
608 UNREACHABLE();
609 case Expression::kEffect:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000610 VisitForControl(expr->left(), &eval_right, &done, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000611 break;
612 case Expression::kValue:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000613 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000614 break;
615 case Expression::kTest:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000616 VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000617 break;
618 }
619 }
620
621 __ bind(&eval_right);
622 Visit(expr->right());
623
624 __ bind(&done);
625}
626
627
ricow@chromium.org65fae842010-08-25 15:26:24 +0000628void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
629 Token::Value op,
630 Location where,
631 Label* done) {
632 ASSERT(op == Token::AND || op == Token::OR);
633 VisitForValue(expr, kAccumulator);
634 __ push(result_register());
635
636 Label discard;
637 switch (where) {
638 case kAccumulator: {
639 Label restore;
640 if (op == Token::OR) {
641 DoTest(&restore, &discard, &restore);
642 } else {
643 DoTest(&discard, &restore, &restore);
644 }
645 __ bind(&restore);
646 __ pop(result_register());
647 __ jmp(done);
648 break;
649 }
650 case kStack: {
651 if (op == Token::OR) {
652 DoTest(done, &discard, &discard);
653 } else {
654 DoTest(&discard, done, &discard);
655 }
656 break;
657 }
658 }
659
660 __ bind(&discard);
661 __ Drop(1);
662}
663
664
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000665void FullCodeGenerator::VisitBlock(Block* stmt) {
666 Comment cmnt(masm_, "[ Block");
667 Breakable nested_statement(this, stmt);
668 SetStatementPosition(stmt);
669 VisitStatements(stmt->statements());
670 __ bind(nested_statement.break_target());
671}
672
673
674void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
675 Comment cmnt(masm_, "[ ExpressionStatement");
676 SetStatementPosition(stmt);
677 VisitForEffect(stmt->expression());
678}
679
680
681void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
682 Comment cmnt(masm_, "[ EmptyStatement");
683 SetStatementPosition(stmt);
684}
685
686
687void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
688 Comment cmnt(masm_, "[ IfStatement");
689 SetStatementPosition(stmt);
690 Label then_part, else_part, done;
691
ricow@chromium.org65fae842010-08-25 15:26:24 +0000692 if (stmt->HasElseStatement()) {
693 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
694 __ bind(&then_part);
695 Visit(stmt->then_statement());
696 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000697
ricow@chromium.org65fae842010-08-25 15:26:24 +0000698 __ bind(&else_part);
699 Visit(stmt->else_statement());
700 } else {
701 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
702 __ bind(&then_part);
703 Visit(stmt->then_statement());
704 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000705 __ bind(&done);
706}
707
708
709void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
710 Comment cmnt(masm_, "[ ContinueStatement");
711 SetStatementPosition(stmt);
712 NestedStatement* current = nesting_stack_;
713 int stack_depth = 0;
714 while (!current->IsContinueTarget(stmt->target())) {
715 stack_depth = current->Exit(stack_depth);
716 current = current->outer();
717 }
718 __ Drop(stack_depth);
719
720 Iteration* loop = current->AsIteration();
721 __ jmp(loop->continue_target());
722}
723
724
725void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
726 Comment cmnt(masm_, "[ BreakStatement");
727 SetStatementPosition(stmt);
728 NestedStatement* current = nesting_stack_;
729 int stack_depth = 0;
730 while (!current->IsBreakTarget(stmt->target())) {
731 stack_depth = current->Exit(stack_depth);
732 current = current->outer();
733 }
734 __ Drop(stack_depth);
735
736 Breakable* target = current->AsBreakable();
737 __ jmp(target->break_target());
738}
739
740
741void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
742 Comment cmnt(masm_, "[ ReturnStatement");
743 SetStatementPosition(stmt);
744 Expression* expr = stmt->expression();
745 VisitForValue(expr, kAccumulator);
746
747 // Exit all nested statements.
748 NestedStatement* current = nesting_stack_;
749 int stack_depth = 0;
750 while (current != NULL) {
751 stack_depth = current->Exit(stack_depth);
752 current = current->outer();
753 }
754 __ Drop(stack_depth);
755
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000756 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000757}
758
759
760void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
761 Comment cmnt(masm_, "[ WithEnterStatement");
762 SetStatementPosition(stmt);
763
764 VisitForValue(stmt->expression(), kStack);
765 if (stmt->is_catch_block()) {
766 __ CallRuntime(Runtime::kPushCatchContext, 1);
767 } else {
768 __ CallRuntime(Runtime::kPushContext, 1);
769 }
770 // Both runtime calls return the new context in both the context and the
771 // result registers.
772
773 // Update local stack frame context field.
774 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
775}
776
777
778void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
779 Comment cmnt(masm_, "[ WithExitStatement");
780 SetStatementPosition(stmt);
781
782 // Pop context.
783 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
784 // Update local stack frame context field.
785 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
786}
787
788
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000789void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
790 Comment cmnt(masm_, "[ DoWhileStatement");
791 SetStatementPosition(stmt);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000792 Label body, stack_limit_hit, stack_check_success, done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000793
794 Iteration loop_statement(this, stmt);
795 increment_loop_depth();
796
797 __ bind(&body);
798 Visit(stmt->body());
799
800 // Check stack before looping.
801 __ StackLimitCheck(&stack_limit_hit);
802 __ bind(&stack_check_success);
803
ricow@chromium.org65fae842010-08-25 15:26:24 +0000804 // Record the position of the do while condition and make sure it is
805 // possible to break on the condition.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000806 __ bind(loop_statement.continue_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000807 SetExpressionPosition(stmt->cond(), stmt->condition_position());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000808 VisitForControl(stmt->cond(),
809 &body,
810 loop_statement.break_target(),
811 loop_statement.break_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000812
ricow@chromium.org65fae842010-08-25 15:26:24 +0000813 __ bind(loop_statement.break_target());
814 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000815
816 __ bind(&stack_limit_hit);
817 StackCheckStub stack_stub;
818 __ CallStub(&stack_stub);
819 __ jmp(&stack_check_success);
820
ricow@chromium.org65fae842010-08-25 15:26:24 +0000821 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000822 decrement_loop_depth();
823}
824
825
826void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
827 Comment cmnt(masm_, "[ WhileStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000828 Label body, stack_limit_hit, stack_check_success;
829
830 Iteration loop_statement(this, stmt);
831 increment_loop_depth();
832
833 // Emit the test at the bottom of the loop.
834 __ jmp(loop_statement.continue_target());
835
ricow@chromium.org65fae842010-08-25 15:26:24 +0000836 __ bind(&stack_limit_hit);
837 StackCheckStub stack_stub;
838 __ CallStub(&stack_stub);
839 __ jmp(&stack_check_success);
840
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000841 __ bind(&body);
842 Visit(stmt->body());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000843 __ bind(loop_statement.continue_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000844
845 // Emit the statement position here as this is where the while
846 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000847 SetStatementPosition(stmt);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000848
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000849 // Check stack before looping.
850 __ StackLimitCheck(&stack_limit_hit);
851 __ bind(&stack_check_success);
852
ricow@chromium.org65fae842010-08-25 15:26:24 +0000853 VisitForControl(stmt->cond(),
854 &body,
855 loop_statement.break_target(),
856 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000857
858 __ bind(loop_statement.break_target());
859 decrement_loop_depth();
860}
861
862
863void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
864 Comment cmnt(masm_, "[ ForStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000865 Label test, body, stack_limit_hit, stack_check_success;
866
867 Iteration loop_statement(this, stmt);
868 if (stmt->init() != NULL) {
869 Visit(stmt->init());
870 }
871
872 increment_loop_depth();
873 // Emit the test at the bottom of the loop (even if empty).
874 __ jmp(&test);
875
ricow@chromium.org65fae842010-08-25 15:26:24 +0000876 __ bind(&stack_limit_hit);
877 StackCheckStub stack_stub;
878 __ CallStub(&stack_stub);
879 __ jmp(&stack_check_success);
880
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000881 __ bind(&body);
882 Visit(stmt->body());
883
884 __ bind(loop_statement.continue_target());
885
886 SetStatementPosition(stmt);
887 if (stmt->next() != NULL) {
888 Visit(stmt->next());
889 }
890
891 __ bind(&test);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000892 // Emit the statement position here as this is where the for
893 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000894 SetStatementPosition(stmt);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000895
896 // Check stack before looping.
897 __ StackLimitCheck(&stack_limit_hit);
898 __ bind(&stack_check_success);
899
900 if (stmt->cond() != NULL) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000901 VisitForControl(stmt->cond(),
902 &body,
903 loop_statement.break_target(),
904 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000905 } else {
906 __ jmp(&body);
907 }
908
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000909 __ bind(loop_statement.break_target());
910 decrement_loop_depth();
911}
912
913
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000914void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
915 Comment cmnt(masm_, "[ TryCatchStatement");
916 SetStatementPosition(stmt);
917 // The try block adds a handler to the exception handler chain
918 // before entering, and removes it again when exiting normally.
919 // If an exception is thrown during execution of the try block,
920 // control is passed to the handler, which also consumes the handler.
921 // At this point, the exception is in a register, and store it in
922 // the temporary local variable (prints as ".catch-var") before
923 // executing the catch block. The catch block has been rewritten
924 // to introduce a new scope to bind the catch variable and to remove
925 // that scope again afterwards.
926
927 Label try_handler_setup, catch_entry, done;
928 __ Call(&try_handler_setup);
929 // Try handler code, exception in result register.
930
931 // Store exception in local .catch variable before executing catch block.
932 {
933 // The catch variable is *always* a variable proxy for a local variable.
934 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
935 ASSERT_NOT_NULL(catch_var);
936 Slot* variable_slot = catch_var->slot();
937 ASSERT_NOT_NULL(variable_slot);
938 ASSERT_EQ(Slot::LOCAL, variable_slot->type());
939 StoreToFrameField(SlotOffset(variable_slot), result_register());
940 }
941
942 Visit(stmt->catch_block());
943 __ jmp(&done);
944
945 // Try block code. Sets up the exception handler chain.
946 __ bind(&try_handler_setup);
947 {
948 TryCatch try_block(this, &catch_entry);
949 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
950 Visit(stmt->try_block());
951 __ PopTryHandler();
952 }
953 __ bind(&done);
954}
955
956
957void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
958 Comment cmnt(masm_, "[ TryFinallyStatement");
959 SetStatementPosition(stmt);
960 // Try finally is compiled by setting up a try-handler on the stack while
961 // executing the try body, and removing it again afterwards.
962 //
963 // The try-finally construct can enter the finally block in three ways:
964 // 1. By exiting the try-block normally. This removes the try-handler and
965 // calls the finally block code before continuing.
966 // 2. By exiting the try-block with a function-local control flow transfer
967 // (break/continue/return). The site of the, e.g., break removes the
968 // try handler and calls the finally block code before continuing
969 // its outward control transfer.
970 // 3. by exiting the try-block with a thrown exception.
971 // This can happen in nested function calls. It traverses the try-handler
972 // chain and consumes the try-handler entry before jumping to the
973 // handler code. The handler code then calls the finally-block before
974 // rethrowing the exception.
975 //
976 // The finally block must assume a return address on top of the stack
977 // (or in the link register on ARM chips) and a value (return value or
978 // exception) in the result register (rax/eax/r0), both of which must
979 // be preserved. The return address isn't GC-safe, so it should be
980 // cooked before GC.
981 Label finally_entry;
982 Label try_handler_setup;
983
984 // Setup the try-handler chain. Use a call to
985 // Jump to try-handler setup and try-block code. Use call to put try-handler
986 // address on stack.
987 __ Call(&try_handler_setup);
988 // Try handler code. Return address of call is pushed on handler stack.
989 {
990 // This code is only executed during stack-handler traversal when an
991 // exception is thrown. The execption is in the result register, which
992 // is retained by the finally block.
993 // Call the finally block and then rethrow the exception.
994 __ Call(&finally_entry);
995 __ push(result_register());
996 __ CallRuntime(Runtime::kReThrow, 1);
997 }
998
999 __ bind(&finally_entry);
1000 {
1001 // Finally block implementation.
1002 Finally finally_block(this);
1003 EnterFinallyBlock();
1004 Visit(stmt->finally_block());
1005 ExitFinallyBlock(); // Return to the calling code.
1006 }
1007
1008 __ bind(&try_handler_setup);
1009 {
1010 // Setup try handler (stack pointer registers).
1011 TryFinally try_block(this, &finally_entry);
1012 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
1013 Visit(stmt->try_block());
1014 __ PopTryHandler();
1015 }
1016 // Execute the finally block on the way out.
1017 __ Call(&finally_entry);
1018}
1019
1020
1021void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1022#ifdef ENABLE_DEBUGGER_SUPPORT
1023 Comment cmnt(masm_, "[ DebuggerStatement");
1024 SetStatementPosition(stmt);
1025
ager@chromium.org5c838252010-02-19 08:53:10 +00001026 __ DebugBreak();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001027 // Ignore the return value.
1028#endif
1029}
1030
1031
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001032void FullCodeGenerator::VisitConditional(Conditional* expr) {
1033 Comment cmnt(masm_, "[ Conditional");
1034 Label true_case, false_case, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001035 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001036
1037 __ bind(&true_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001038 SetExpressionPosition(expr->then_expression(),
1039 expr->then_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001040 Visit(expr->then_expression());
1041 // If control flow falls through Visit, jump to done.
1042 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1043 __ jmp(&done);
1044 }
1045
1046 __ bind(&false_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001047 SetExpressionPosition(expr->else_expression(),
1048 expr->else_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001049 Visit(expr->else_expression());
1050 // If control flow falls through Visit, merge it with true case here.
1051 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1052 __ bind(&done);
1053 }
1054}
1055
1056
1057void FullCodeGenerator::VisitSlot(Slot* expr) {
1058 // Slots do not appear directly in the AST.
1059 UNREACHABLE();
1060}
1061
1062
1063void FullCodeGenerator::VisitLiteral(Literal* expr) {
1064 Comment cmnt(masm_, "[ Literal");
1065 Apply(context_, expr);
1066}
1067
1068
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001069void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1070 Comment cmnt(masm_, "[ FunctionLiteral");
1071
1072 // Build the function boilerplate and instantiate it.
1073 Handle<SharedFunctionInfo> function_info =
1074 Compiler::BuildFunctionInfo(expr, script(), this);
1075 if (HasStackOverflow()) return;
1076 EmitNewClosure(function_info);
1077}
1078
1079
1080void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
1081 SharedFunctionInfoLiteral* expr) {
1082 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
1083 EmitNewClosure(expr->shared_function_info());
1084}
1085
1086
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001087void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1088 // Call runtime routine to allocate the catch extension object and
1089 // assign the exception value to the catch variable.
1090 Comment cmnt(masm_, "[ CatchExtensionObject");
1091 VisitForValue(expr->key(), kStack);
1092 VisitForValue(expr->value(), kStack);
1093 // Create catch extension object.
1094 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
1095 Apply(context_, result_register());
1096}
1097
1098
1099void FullCodeGenerator::VisitThrow(Throw* expr) {
1100 Comment cmnt(masm_, "[ Throw");
1101 VisitForValue(expr->exception(), kStack);
1102 __ CallRuntime(Runtime::kThrow, 1);
1103 // Never returns here.
1104}
1105
1106
ricow@chromium.org65fae842010-08-25 15:26:24 +00001107void FullCodeGenerator::VisitIncrementOperation(IncrementOperation* expr) {
1108 UNREACHABLE();
1109}
1110
1111
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001112int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
1113 // The macros used here must preserve the result register.
1114 __ Drop(stack_depth);
1115 __ PopTryHandler();
1116 __ Call(finally_entry_);
1117 return 0;
1118}
1119
1120
1121int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
1122 // The macros used here must preserve the result register.
1123 __ Drop(stack_depth);
1124 __ PopTryHandler();
1125 return 0;
1126}
1127
ricow@chromium.org65fae842010-08-25 15:26:24 +00001128
1129void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
1130 ASSERT(args->length() == 1);
1131 VisitForValue(args->at(0), kStack);
1132 __ CallRuntime(Runtime::kRegExpCloneResult, 1);
1133 Apply(context_, result_register());
1134}
1135
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001136#undef __
1137
1138
1139} } // namespace v8::internal