blob: a1c5ec36af86b3b40dd6782b9f5ebcb726c677b1 [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
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +0000301MemOperand FullCodeGenerator::ContextOperand(Register context, int index) {
302 return CodeGenerator::ContextOperand(context, index);
303}
304
305
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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:
ager@chromium.org5c838252010-02-19 08:53:10 +0000313 offset += (scope()->num_parameters() + 1) * kPointerSize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +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
ricow@chromium.org65fae842010-08-25 15:26:24 +0000326bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000327 // Inline smi case inside loops, but not division and modulo which
328 // are too complicated and take up too much space.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000329 if (op == Token::DIV ||op == Token::MOD) return false;
330 if (FLAG_always_inline_smi_code) return true;
331 return loop_depth_ > 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000332}
333
334
335void FullCodeGenerator::PrepareTest(Label* materialize_true,
336 Label* materialize_false,
337 Label** if_true,
338 Label** if_false,
339 Label** fall_through) {
340 switch (context_) {
341 case Expression::kUninitialized:
342 UNREACHABLE();
343 break;
344 case Expression::kEffect:
345 // In an effect context, the true and the false case branch to the
346 // same label.
347 *if_true = *if_false = *fall_through = materialize_true;
348 break;
349 case Expression::kValue:
350 *if_true = *fall_through = materialize_true;
351 *if_false = materialize_false;
352 break;
353 case Expression::kTest:
354 *if_true = true_label_;
355 *if_false = false_label_;
356 *fall_through = fall_through_;
357 break;
358 }
359}
360
361
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000362void FullCodeGenerator::VisitDeclarations(
363 ZoneList<Declaration*>* declarations) {
364 int length = declarations->length();
365 int globals = 0;
366 for (int i = 0; i < length; i++) {
367 Declaration* decl = declarations->at(i);
368 Variable* var = decl->proxy()->var();
369 Slot* slot = var->slot();
370
371 // If it was not possible to allocate the variable at compile
372 // time, we need to "declare" it at runtime to make sure it
373 // actually exists in the local context.
374 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
375 VisitDeclaration(decl);
376 } else {
377 // Count global variables and functions for later processing
378 globals++;
379 }
380 }
381
382 // Compute array of global variable and function declarations.
383 // Do nothing in case of no declared global functions or variables.
384 if (globals > 0) {
385 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
386 for (int j = 0, i = 0; i < length; i++) {
387 Declaration* decl = declarations->at(i);
388 Variable* var = decl->proxy()->var();
389 Slot* slot = var->slot();
390
391 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
392 array->set(j++, *(var->name()));
393 if (decl->fun() == NULL) {
394 if (var->mode() == Variable::CONST) {
395 // In case this is const property use the hole.
396 array->set_the_hole(j++);
397 } else {
398 array->set_undefined(j++);
399 }
400 } else {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000401 Handle<SharedFunctionInfo> function =
402 Compiler::BuildFunctionInfo(decl->fun(), script(), this);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000403 // Check for stack-overflow exception.
404 if (HasStackOverflow()) return;
405 array->set(j++, *function);
406 }
407 }
408 }
409 // Invoke the platform-dependent code generator to do the actual
410 // declaration the global variables and functions.
411 DeclareGlobals(array);
412 }
413}
414
415
416void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
417 if (FLAG_debug_info) {
418 CodeGenerator::RecordPositions(masm_, fun->start_position());
419 }
420}
421
422
423void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
424 if (FLAG_debug_info) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000425 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000426 }
427}
428
429
430void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
431 if (FLAG_debug_info) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000432#ifdef ENABLE_DEBUGGER_SUPPORT
433 if (!Debugger::IsDebuggerActive()) {
434 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
435 } else {
436 // Check if the statement will be breakable without adding a debug break
437 // slot.
438 BreakableStatementChecker checker;
439 checker.Check(stmt);
440 // Record the statement position right here if the statement is not
441 // breakable. For breakable statements the actual recording of the
442 // position will be postponed to the breakable code (typically an IC).
443 bool position_recorded = CodeGenerator::RecordPositions(
444 masm_, stmt->statement_pos(), !checker.is_breakable());
445 // If the position recording did record a new position generate a debug
446 // break slot to make the statement breakable.
447 if (position_recorded) {
448 Debug::GenerateSlot(masm_);
449 }
450 }
451#else
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000452 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000453#endif
454 }
455}
456
457
458void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
459 if (FLAG_debug_info) {
460#ifdef ENABLE_DEBUGGER_SUPPORT
461 if (!Debugger::IsDebuggerActive()) {
462 CodeGenerator::RecordPositions(masm_, pos);
463 } else {
464 // Check if the expression will be breakable without adding a debug break
465 // slot.
466 BreakableStatementChecker checker;
467 checker.Check(expr);
468 // Record a statement position right here if the expression is not
469 // breakable. For breakable expressions the actual recording of the
470 // position will be postponed to the breakable code (typically an IC).
471 // NOTE this will record a statement position for something which might
472 // not be a statement. As stepping in the debugger will only stop at
473 // statement positions this is used for e.g. the condition expression of
474 // a do while loop.
475 bool position_recorded = CodeGenerator::RecordPositions(
476 masm_, pos, !checker.is_breakable());
477 // If the position recording did record a new position generate a debug
478 // break slot to make the statement breakable.
479 if (position_recorded) {
480 Debug::GenerateSlot(masm_);
481 }
482 }
483#else
484 CodeGenerator::RecordPositions(masm_, pos);
485#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000486 }
487}
488
489
490void FullCodeGenerator::SetStatementPosition(int pos) {
491 if (FLAG_debug_info) {
492 CodeGenerator::RecordPositions(masm_, pos);
493 }
494}
495
496
497void FullCodeGenerator::SetSourcePosition(int pos) {
498 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
499 masm_->RecordPosition(pos);
500 }
501}
502
503
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000504// Lookup table for code generators for special runtime calls which are
505// generated inline.
506#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
507 &FullCodeGenerator::Emit##Name,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000508
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000509const FullCodeGenerator::InlineFunctionGenerator
510 FullCodeGenerator::kInlineFunctionGenerators[] = {
511 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
512 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
513 };
514#undef INLINE_FUNCTION_GENERATOR_ADDRESS
515
516
517FullCodeGenerator::InlineFunctionGenerator
518 FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
519 return kInlineFunctionGenerators[
520 static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction)];
521}
522
523
524void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
525 ZoneList<Expression*>* args = node->arguments();
526 Handle<String> name = node->name();
527 Runtime::Function* function = node->function();
528 ASSERT(function != NULL);
529 ASSERT(function->intrinsic_type == Runtime::INLINE);
530 InlineFunctionGenerator generator =
531 FindInlineFunctionGenerator(function->function_id);
532 ASSERT(generator != NULL);
533 ((*this).*(generator))(args);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000534}
535
536
537void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
538 Comment cmnt(masm_, "[ BinaryOperation");
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000539 Token::Value op = expr->op();
540 Expression* left = expr->left();
541 Expression* right = expr->right();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000542
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000543 OverwriteMode mode = NO_OVERWRITE;
544 if (left->ResultOverwriteAllowed()) {
545 mode = OVERWRITE_LEFT;
546 } else if (right->ResultOverwriteAllowed()) {
547 mode = OVERWRITE_RIGHT;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000548 }
549
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000550 switch (op) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000551 case Token::COMMA:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000552 VisitForEffect(left);
553 Visit(right);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000554 break;
555
556 case Token::OR:
557 case Token::AND:
558 EmitLogicalOperation(expr);
559 break;
560
561 case Token::ADD:
562 case Token::SUB:
563 case Token::DIV:
564 case Token::MOD:
565 case Token::MUL:
566 case Token::BIT_OR:
567 case Token::BIT_AND:
568 case Token::BIT_XOR:
569 case Token::SHL:
570 case Token::SHR:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000571 case Token::SAR: {
572 // Figure out if either of the operands is a constant.
573 ConstantOperand constant = ShouldInlineSmiCase(op)
574 ? GetConstantOperand(op, left, right)
575 : kNoConstants;
576
577 // Load only the operands that we need to materialize.
578 if (constant == kNoConstants) {
579 VisitForValue(left, kStack);
580 VisitForValue(right, kAccumulator);
581 } else if (constant == kRightConstant) {
582 VisitForValue(left, kAccumulator);
583 } else {
584 ASSERT(constant == kLeftConstant);
585 VisitForValue(right, kAccumulator);
586 }
587
ricow@chromium.org65fae842010-08-25 15:26:24 +0000588 SetSourcePosition(expr->position());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000589 if (ShouldInlineSmiCase(op)) {
590 EmitInlineSmiBinaryOp(expr, op, context_, mode, left, right, constant);
591 } else {
592 EmitBinaryOp(op, context_, mode);
593 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000594 break;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000595 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000596
597 default:
598 UNREACHABLE();
599 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000600}
601
602
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000603void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
604 Label eval_right, done;
605
606 // Set up the appropriate context for the left subexpression based
607 // on the operation and our own context. Initially assume we can
608 // inherit both true and false labels from our context.
609 if (expr->op() == Token::OR) {
610 switch (context_) {
611 case Expression::kUninitialized:
612 UNREACHABLE();
613 case Expression::kEffect:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000614 VisitForControl(expr->left(), &done, &eval_right, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000615 break;
616 case Expression::kValue:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000617 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000618 break;
619 case Expression::kTest:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000620 VisitForControl(expr->left(), true_label_, &eval_right, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000621 break;
622 }
623 } else {
624 ASSERT_EQ(Token::AND, expr->op());
625 switch (context_) {
626 case Expression::kUninitialized:
627 UNREACHABLE();
628 case Expression::kEffect:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000629 VisitForControl(expr->left(), &eval_right, &done, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000630 break;
631 case Expression::kValue:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000632 VisitLogicalForValue(expr->left(), expr->op(), location_, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000633 break;
634 case Expression::kTest:
ricow@chromium.org65fae842010-08-25 15:26:24 +0000635 VisitForControl(expr->left(), &eval_right, false_label_, &eval_right);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000636 break;
637 }
638 }
639
640 __ bind(&eval_right);
641 Visit(expr->right());
642
643 __ bind(&done);
644}
645
646
ricow@chromium.org65fae842010-08-25 15:26:24 +0000647void FullCodeGenerator::VisitLogicalForValue(Expression* expr,
648 Token::Value op,
649 Location where,
650 Label* done) {
651 ASSERT(op == Token::AND || op == Token::OR);
652 VisitForValue(expr, kAccumulator);
653 __ push(result_register());
654
655 Label discard;
656 switch (where) {
657 case kAccumulator: {
658 Label restore;
659 if (op == Token::OR) {
660 DoTest(&restore, &discard, &restore);
661 } else {
662 DoTest(&discard, &restore, &restore);
663 }
664 __ bind(&restore);
665 __ pop(result_register());
666 __ jmp(done);
667 break;
668 }
669 case kStack: {
670 if (op == Token::OR) {
671 DoTest(done, &discard, &discard);
672 } else {
673 DoTest(&discard, done, &discard);
674 }
675 break;
676 }
677 }
678
679 __ bind(&discard);
680 __ Drop(1);
681}
682
683
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000684void FullCodeGenerator::VisitBlock(Block* stmt) {
685 Comment cmnt(masm_, "[ Block");
686 Breakable nested_statement(this, stmt);
687 SetStatementPosition(stmt);
688 VisitStatements(stmt->statements());
689 __ bind(nested_statement.break_target());
690}
691
692
693void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
694 Comment cmnt(masm_, "[ ExpressionStatement");
695 SetStatementPosition(stmt);
696 VisitForEffect(stmt->expression());
697}
698
699
700void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
701 Comment cmnt(masm_, "[ EmptyStatement");
702 SetStatementPosition(stmt);
703}
704
705
706void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
707 Comment cmnt(masm_, "[ IfStatement");
708 SetStatementPosition(stmt);
709 Label then_part, else_part, done;
710
ricow@chromium.org65fae842010-08-25 15:26:24 +0000711 if (stmt->HasElseStatement()) {
712 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
713 __ bind(&then_part);
714 Visit(stmt->then_statement());
715 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000716
ricow@chromium.org65fae842010-08-25 15:26:24 +0000717 __ bind(&else_part);
718 Visit(stmt->else_statement());
719 } else {
720 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
721 __ bind(&then_part);
722 Visit(stmt->then_statement());
723 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000724 __ bind(&done);
725}
726
727
728void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
729 Comment cmnt(masm_, "[ ContinueStatement");
730 SetStatementPosition(stmt);
731 NestedStatement* current = nesting_stack_;
732 int stack_depth = 0;
733 while (!current->IsContinueTarget(stmt->target())) {
734 stack_depth = current->Exit(stack_depth);
735 current = current->outer();
736 }
737 __ Drop(stack_depth);
738
739 Iteration* loop = current->AsIteration();
740 __ jmp(loop->continue_target());
741}
742
743
744void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
745 Comment cmnt(masm_, "[ BreakStatement");
746 SetStatementPosition(stmt);
747 NestedStatement* current = nesting_stack_;
748 int stack_depth = 0;
749 while (!current->IsBreakTarget(stmt->target())) {
750 stack_depth = current->Exit(stack_depth);
751 current = current->outer();
752 }
753 __ Drop(stack_depth);
754
755 Breakable* target = current->AsBreakable();
756 __ jmp(target->break_target());
757}
758
759
760void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
761 Comment cmnt(masm_, "[ ReturnStatement");
762 SetStatementPosition(stmt);
763 Expression* expr = stmt->expression();
764 VisitForValue(expr, kAccumulator);
765
766 // Exit all nested statements.
767 NestedStatement* current = nesting_stack_;
768 int stack_depth = 0;
769 while (current != NULL) {
770 stack_depth = current->Exit(stack_depth);
771 current = current->outer();
772 }
773 __ Drop(stack_depth);
774
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000775 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000776}
777
778
779void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
780 Comment cmnt(masm_, "[ WithEnterStatement");
781 SetStatementPosition(stmt);
782
783 VisitForValue(stmt->expression(), kStack);
784 if (stmt->is_catch_block()) {
785 __ CallRuntime(Runtime::kPushCatchContext, 1);
786 } else {
787 __ CallRuntime(Runtime::kPushContext, 1);
788 }
789 // Both runtime calls return the new context in both the context and the
790 // result registers.
791
792 // Update local stack frame context field.
793 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
794}
795
796
797void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
798 Comment cmnt(masm_, "[ WithExitStatement");
799 SetStatementPosition(stmt);
800
801 // Pop context.
802 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
803 // Update local stack frame context field.
804 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
805}
806
807
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000808void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
809 Comment cmnt(masm_, "[ DoWhileStatement");
810 SetStatementPosition(stmt);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000811 Label body, stack_limit_hit, stack_check_success, done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000812
813 Iteration loop_statement(this, stmt);
814 increment_loop_depth();
815
816 __ bind(&body);
817 Visit(stmt->body());
818
819 // Check stack before looping.
820 __ StackLimitCheck(&stack_limit_hit);
821 __ bind(&stack_check_success);
822
ricow@chromium.org65fae842010-08-25 15:26:24 +0000823 // Record the position of the do while condition and make sure it is
824 // possible to break on the condition.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000825 __ bind(loop_statement.continue_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000826 SetExpressionPosition(stmt->cond(), stmt->condition_position());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000827 VisitForControl(stmt->cond(),
828 &body,
829 loop_statement.break_target(),
830 loop_statement.break_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000831
ricow@chromium.org65fae842010-08-25 15:26:24 +0000832 __ bind(loop_statement.break_target());
833 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000834
835 __ bind(&stack_limit_hit);
836 StackCheckStub stack_stub;
837 __ CallStub(&stack_stub);
838 __ jmp(&stack_check_success);
839
ricow@chromium.org65fae842010-08-25 15:26:24 +0000840 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000841 decrement_loop_depth();
842}
843
844
845void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
846 Comment cmnt(masm_, "[ WhileStatement");
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000847 Label body, stack_limit_hit, stack_check_success, done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000848
849 Iteration loop_statement(this, stmt);
850 increment_loop_depth();
851
852 // Emit the test at the bottom of the loop.
853 __ jmp(loop_statement.continue_target());
854
855 __ bind(&body);
856 Visit(stmt->body());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000857 __ bind(loop_statement.continue_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000858
859 // Emit the statement position here as this is where the while
860 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000861 SetStatementPosition(stmt);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000862
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000863 // Check stack before looping.
864 __ StackLimitCheck(&stack_limit_hit);
865 __ bind(&stack_check_success);
866
ricow@chromium.org65fae842010-08-25 15:26:24 +0000867 VisitForControl(stmt->cond(),
868 &body,
869 loop_statement.break_target(),
870 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000871
872 __ bind(loop_statement.break_target());
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000873 __ jmp(&done);
874
875 __ bind(&stack_limit_hit);
876 StackCheckStub stack_stub;
877 __ CallStub(&stack_stub);
878 __ jmp(&stack_check_success);
879
880 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000881 decrement_loop_depth();
882}
883
884
885void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
886 Comment cmnt(masm_, "[ ForStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000887 Label test, body, stack_limit_hit, stack_check_success;
888
889 Iteration loop_statement(this, stmt);
890 if (stmt->init() != NULL) {
891 Visit(stmt->init());
892 }
893
894 increment_loop_depth();
895 // Emit the test at the bottom of the loop (even if empty).
896 __ jmp(&test);
897
ricow@chromium.org65fae842010-08-25 15:26:24 +0000898 __ bind(&stack_limit_hit);
899 StackCheckStub stack_stub;
900 __ CallStub(&stack_stub);
901 __ jmp(&stack_check_success);
902
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000903 __ bind(&body);
904 Visit(stmt->body());
905
906 __ bind(loop_statement.continue_target());
907
908 SetStatementPosition(stmt);
909 if (stmt->next() != NULL) {
910 Visit(stmt->next());
911 }
912
913 __ bind(&test);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000914 // Emit the statement position here as this is where the for
915 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000916 SetStatementPosition(stmt);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000917
918 // Check stack before looping.
919 __ StackLimitCheck(&stack_limit_hit);
920 __ bind(&stack_check_success);
921
922 if (stmt->cond() != NULL) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000923 VisitForControl(stmt->cond(),
924 &body,
925 loop_statement.break_target(),
926 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000927 } else {
928 __ jmp(&body);
929 }
930
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000931 __ bind(loop_statement.break_target());
932 decrement_loop_depth();
933}
934
935
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000936void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
937 Comment cmnt(masm_, "[ TryCatchStatement");
938 SetStatementPosition(stmt);
939 // The try block adds a handler to the exception handler chain
940 // before entering, and removes it again when exiting normally.
941 // If an exception is thrown during execution of the try block,
942 // control is passed to the handler, which also consumes the handler.
943 // At this point, the exception is in a register, and store it in
944 // the temporary local variable (prints as ".catch-var") before
945 // executing the catch block. The catch block has been rewritten
946 // to introduce a new scope to bind the catch variable and to remove
947 // that scope again afterwards.
948
949 Label try_handler_setup, catch_entry, done;
950 __ Call(&try_handler_setup);
951 // Try handler code, exception in result register.
952
953 // Store exception in local .catch variable before executing catch block.
954 {
955 // The catch variable is *always* a variable proxy for a local variable.
956 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
957 ASSERT_NOT_NULL(catch_var);
958 Slot* variable_slot = catch_var->slot();
959 ASSERT_NOT_NULL(variable_slot);
960 ASSERT_EQ(Slot::LOCAL, variable_slot->type());
961 StoreToFrameField(SlotOffset(variable_slot), result_register());
962 }
963
964 Visit(stmt->catch_block());
965 __ jmp(&done);
966
967 // Try block code. Sets up the exception handler chain.
968 __ bind(&try_handler_setup);
969 {
970 TryCatch try_block(this, &catch_entry);
971 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
972 Visit(stmt->try_block());
973 __ PopTryHandler();
974 }
975 __ bind(&done);
976}
977
978
979void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
980 Comment cmnt(masm_, "[ TryFinallyStatement");
981 SetStatementPosition(stmt);
982 // Try finally is compiled by setting up a try-handler on the stack while
983 // executing the try body, and removing it again afterwards.
984 //
985 // The try-finally construct can enter the finally block in three ways:
986 // 1. By exiting the try-block normally. This removes the try-handler and
987 // calls the finally block code before continuing.
988 // 2. By exiting the try-block with a function-local control flow transfer
989 // (break/continue/return). The site of the, e.g., break removes the
990 // try handler and calls the finally block code before continuing
991 // its outward control transfer.
992 // 3. by exiting the try-block with a thrown exception.
993 // This can happen in nested function calls. It traverses the try-handler
994 // chain and consumes the try-handler entry before jumping to the
995 // handler code. The handler code then calls the finally-block before
996 // rethrowing the exception.
997 //
998 // The finally block must assume a return address on top of the stack
999 // (or in the link register on ARM chips) and a value (return value or
1000 // exception) in the result register (rax/eax/r0), both of which must
1001 // be preserved. The return address isn't GC-safe, so it should be
1002 // cooked before GC.
1003 Label finally_entry;
1004 Label try_handler_setup;
1005
1006 // Setup the try-handler chain. Use a call to
1007 // Jump to try-handler setup and try-block code. Use call to put try-handler
1008 // address on stack.
1009 __ Call(&try_handler_setup);
1010 // Try handler code. Return address of call is pushed on handler stack.
1011 {
1012 // This code is only executed during stack-handler traversal when an
1013 // exception is thrown. The execption is in the result register, which
1014 // is retained by the finally block.
1015 // Call the finally block and then rethrow the exception.
1016 __ Call(&finally_entry);
1017 __ push(result_register());
1018 __ CallRuntime(Runtime::kReThrow, 1);
1019 }
1020
1021 __ bind(&finally_entry);
1022 {
1023 // Finally block implementation.
1024 Finally finally_block(this);
1025 EnterFinallyBlock();
1026 Visit(stmt->finally_block());
1027 ExitFinallyBlock(); // Return to the calling code.
1028 }
1029
1030 __ bind(&try_handler_setup);
1031 {
1032 // Setup try handler (stack pointer registers).
1033 TryFinally try_block(this, &finally_entry);
1034 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
1035 Visit(stmt->try_block());
1036 __ PopTryHandler();
1037 }
1038 // Execute the finally block on the way out.
1039 __ Call(&finally_entry);
1040}
1041
1042
1043void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1044#ifdef ENABLE_DEBUGGER_SUPPORT
1045 Comment cmnt(masm_, "[ DebuggerStatement");
1046 SetStatementPosition(stmt);
1047
ager@chromium.org5c838252010-02-19 08:53:10 +00001048 __ DebugBreak();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001049 // Ignore the return value.
1050#endif
1051}
1052
1053
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001054void FullCodeGenerator::VisitConditional(Conditional* expr) {
1055 Comment cmnt(masm_, "[ Conditional");
1056 Label true_case, false_case, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001057 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001058
1059 __ bind(&true_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001060 SetExpressionPosition(expr->then_expression(),
1061 expr->then_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001062 Visit(expr->then_expression());
1063 // If control flow falls through Visit, jump to done.
1064 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1065 __ jmp(&done);
1066 }
1067
1068 __ bind(&false_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001069 SetExpressionPosition(expr->else_expression(),
1070 expr->else_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001071 Visit(expr->else_expression());
1072 // If control flow falls through Visit, merge it with true case here.
1073 if (context_ == Expression::kEffect || context_ == Expression::kValue) {
1074 __ bind(&done);
1075 }
1076}
1077
1078
1079void FullCodeGenerator::VisitSlot(Slot* expr) {
1080 // Slots do not appear directly in the AST.
1081 UNREACHABLE();
1082}
1083
1084
1085void FullCodeGenerator::VisitLiteral(Literal* expr) {
1086 Comment cmnt(masm_, "[ Literal");
1087 Apply(context_, expr);
1088}
1089
1090
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001091void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1092 Comment cmnt(masm_, "[ FunctionLiteral");
1093
1094 // Build the function boilerplate and instantiate it.
1095 Handle<SharedFunctionInfo> function_info =
1096 Compiler::BuildFunctionInfo(expr, script(), this);
1097 if (HasStackOverflow()) return;
1098 EmitNewClosure(function_info);
1099}
1100
1101
1102void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
1103 SharedFunctionInfoLiteral* expr) {
1104 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
1105 EmitNewClosure(expr->shared_function_info());
1106}
1107
1108
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001109void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1110 // Call runtime routine to allocate the catch extension object and
1111 // assign the exception value to the catch variable.
1112 Comment cmnt(masm_, "[ CatchExtensionObject");
1113 VisitForValue(expr->key(), kStack);
1114 VisitForValue(expr->value(), kStack);
1115 // Create catch extension object.
1116 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
1117 Apply(context_, result_register());
1118}
1119
1120
1121void FullCodeGenerator::VisitThrow(Throw* expr) {
1122 Comment cmnt(masm_, "[ Throw");
1123 VisitForValue(expr->exception(), kStack);
1124 __ CallRuntime(Runtime::kThrow, 1);
1125 // Never returns here.
1126}
1127
1128
ricow@chromium.org65fae842010-08-25 15:26:24 +00001129void FullCodeGenerator::VisitIncrementOperation(IncrementOperation* expr) {
1130 UNREACHABLE();
1131}
1132
1133
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001134int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
1135 // The macros used here must preserve the result register.
1136 __ Drop(stack_depth);
1137 __ PopTryHandler();
1138 __ Call(finally_entry_);
1139 return 0;
1140}
1141
1142
1143int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
1144 // The macros used here must preserve the result register.
1145 __ Drop(stack_depth);
1146 __ PopTryHandler();
1147 return 0;
1148}
1149
ricow@chromium.org65fae842010-08-25 15:26:24 +00001150
1151void FullCodeGenerator::EmitRegExpCloneResult(ZoneList<Expression*>* args) {
1152 ASSERT(args->length() == 1);
1153 VisitForValue(args->at(0), kStack);
1154 __ CallRuntime(Runtime::kRegExpCloneResult, 1);
1155 Apply(context_, result_register());
1156}
1157
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001158#undef __
1159
1160
1161} } // namespace v8::internal