blob: a890f15974a23c46b9e58440f55f83d14c268802 [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.orgb61a0d12010-10-13 08:35:23 +0000280bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
ager@chromium.org5c838252010-02-19 08:53:10 +0000281 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());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000294 return false;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000295 }
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000296
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000297 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION, NOT_IN_LOOP);
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000298 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
299 info->SetCode(code); // may be an empty handle.
300 return !code.is_null();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000301}
302
303
304int FullCodeGenerator::SlotOffset(Slot* slot) {
305 ASSERT(slot != NULL);
306 // Offset is negative because higher indexes are at lower addresses.
307 int offset = -slot->index() * kPointerSize;
308 // Adjust by a (parameter or local) base offset.
309 switch (slot->type()) {
310 case Slot::PARAMETER:
ager@chromium.org5c838252010-02-19 08:53:10 +0000311 offset += (scope()->num_parameters() + 1) * kPointerSize;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000312 break;
313 case Slot::LOCAL:
314 offset += JavaScriptFrameConstants::kLocal0Offset;
315 break;
316 case Slot::CONTEXT:
317 case Slot::LOOKUP:
318 UNREACHABLE();
319 }
320 return offset;
321}
322
323
ricow@chromium.org65fae842010-08-25 15:26:24 +0000324bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000325 // Inline smi case inside loops, but not division and modulo which
326 // are too complicated and take up too much space.
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000327 if (op == Token::DIV ||op == Token::MOD) return false;
328 if (FLAG_always_inline_smi_code) return true;
329 return loop_depth_ > 0;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000330}
331
332
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000333void FullCodeGenerator::EffectContext::Plug(Register reg) const {
334}
335
336
337void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
338 // Move value into place.
339 __ Move(result_register(), reg);
340}
341
342
343void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
344 // Move value into place.
345 __ push(reg);
346}
347
348
349void FullCodeGenerator::TestContext::Plug(Register reg) const {
350 // For simplicity we always test the accumulator register.
351 __ Move(result_register(), reg);
352 codegen()->DoTest(true_label_, false_label_, fall_through_);
353}
354
355
356void FullCodeGenerator::EffectContext::PlugTOS() const {
357 __ Drop(1);
358}
359
360
361void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
362 __ pop(result_register());
363}
364
365
366void FullCodeGenerator::StackValueContext::PlugTOS() const {
367}
368
369
370void FullCodeGenerator::TestContext::PlugTOS() const {
371 // For simplicity we always test the accumulator register.
372 __ pop(result_register());
373 codegen()->DoTest(true_label_, false_label_, fall_through_);
374}
375
376
377void FullCodeGenerator::EffectContext::PrepareTest(
378 Label* materialize_true,
379 Label* materialize_false,
380 Label** if_true,
381 Label** if_false,
382 Label** fall_through) const {
383 // In an effect context, the true and the false case branch to the
384 // same label.
385 *if_true = *if_false = *fall_through = materialize_true;
386}
387
388
389void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
390 Label* materialize_true,
391 Label* materialize_false,
392 Label** if_true,
393 Label** if_false,
394 Label** fall_through) const {
395 *if_true = *fall_through = materialize_true;
396 *if_false = materialize_false;
397}
398
399
400void FullCodeGenerator::StackValueContext::PrepareTest(
401 Label* materialize_true,
402 Label* materialize_false,
403 Label** if_true,
404 Label** if_false,
405 Label** fall_through) const {
406 *if_true = *fall_through = materialize_true;
407 *if_false = materialize_false;
408}
409
410
411void FullCodeGenerator::TestContext::PrepareTest(
412 Label* materialize_true,
413 Label* materialize_false,
414 Label** if_true,
415 Label** if_false,
416 Label** fall_through) const {
417 *if_true = true_label_;
418 *if_false = false_label_;
419 *fall_through = fall_through_;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000420}
421
422
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000423void FullCodeGenerator::VisitDeclarations(
424 ZoneList<Declaration*>* declarations) {
425 int length = declarations->length();
426 int globals = 0;
427 for (int i = 0; i < length; i++) {
428 Declaration* decl = declarations->at(i);
429 Variable* var = decl->proxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000430 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000431
432 // If it was not possible to allocate the variable at compile
433 // time, we need to "declare" it at runtime to make sure it
434 // actually exists in the local context.
435 if ((slot != NULL && slot->type() == Slot::LOOKUP) || !var->is_global()) {
436 VisitDeclaration(decl);
437 } else {
438 // Count global variables and functions for later processing
439 globals++;
440 }
441 }
442
443 // Compute array of global variable and function declarations.
444 // Do nothing in case of no declared global functions or variables.
445 if (globals > 0) {
446 Handle<FixedArray> array = Factory::NewFixedArray(2 * globals, TENURED);
447 for (int j = 0, i = 0; i < length; i++) {
448 Declaration* decl = declarations->at(i);
449 Variable* var = decl->proxy()->var();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000450 Slot* slot = var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000451
452 if ((slot == NULL || slot->type() != Slot::LOOKUP) && var->is_global()) {
453 array->set(j++, *(var->name()));
454 if (decl->fun() == NULL) {
455 if (var->mode() == Variable::CONST) {
456 // In case this is const property use the hole.
457 array->set_the_hole(j++);
458 } else {
459 array->set_undefined(j++);
460 }
461 } else {
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +0000462 Handle<SharedFunctionInfo> function =
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000463 Compiler::BuildFunctionInfo(decl->fun(), script());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000464 // Check for stack-overflow exception.
ager@chromium.orgb61a0d12010-10-13 08:35:23 +0000465 if (function.is_null()) {
466 SetStackOverflow();
467 return;
468 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000469 array->set(j++, *function);
470 }
471 }
472 }
473 // Invoke the platform-dependent code generator to do the actual
474 // declaration the global variables and functions.
475 DeclareGlobals(array);
476 }
477}
478
479
480void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
481 if (FLAG_debug_info) {
482 CodeGenerator::RecordPositions(masm_, fun->start_position());
483 }
484}
485
486
487void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
488 if (FLAG_debug_info) {
whesse@chromium.orge90029b2010-08-02 11:52:17 +0000489 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000490 }
491}
492
493
494void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
495 if (FLAG_debug_info) {
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000496#ifdef ENABLE_DEBUGGER_SUPPORT
497 if (!Debugger::IsDebuggerActive()) {
498 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
499 } else {
500 // Check if the statement will be breakable without adding a debug break
501 // slot.
502 BreakableStatementChecker checker;
503 checker.Check(stmt);
504 // Record the statement position right here if the statement is not
505 // breakable. For breakable statements the actual recording of the
506 // position will be postponed to the breakable code (typically an IC).
507 bool position_recorded = CodeGenerator::RecordPositions(
508 masm_, stmt->statement_pos(), !checker.is_breakable());
509 // If the position recording did record a new position generate a debug
510 // break slot to make the statement breakable.
511 if (position_recorded) {
512 Debug::GenerateSlot(masm_);
513 }
514 }
515#else
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000516 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000517#endif
518 }
519}
520
521
522void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
523 if (FLAG_debug_info) {
524#ifdef ENABLE_DEBUGGER_SUPPORT
525 if (!Debugger::IsDebuggerActive()) {
526 CodeGenerator::RecordPositions(masm_, pos);
527 } else {
528 // Check if the expression will be breakable without adding a debug break
529 // slot.
530 BreakableStatementChecker checker;
531 checker.Check(expr);
532 // Record a statement position right here if the expression is not
533 // breakable. For breakable expressions the actual recording of the
534 // position will be postponed to the breakable code (typically an IC).
535 // NOTE this will record a statement position for something which might
536 // not be a statement. As stepping in the debugger will only stop at
537 // statement positions this is used for e.g. the condition expression of
538 // a do while loop.
539 bool position_recorded = CodeGenerator::RecordPositions(
540 masm_, pos, !checker.is_breakable());
541 // If the position recording did record a new position generate a debug
542 // break slot to make the statement breakable.
543 if (position_recorded) {
544 Debug::GenerateSlot(masm_);
545 }
546 }
547#else
548 CodeGenerator::RecordPositions(masm_, pos);
549#endif
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000550 }
551}
552
553
554void FullCodeGenerator::SetStatementPosition(int pos) {
555 if (FLAG_debug_info) {
556 CodeGenerator::RecordPositions(masm_, pos);
557 }
558}
559
560
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000561void FullCodeGenerator::SetSourcePosition(
562 int pos, PositionRecordingType recording_type) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000563 if (FLAG_debug_info && pos != RelocInfo::kNoPosition) {
whesse@chromium.orgf0ac72d2010-11-08 12:47:26 +0000564 masm_->positions_recorder()->RecordPosition(pos, recording_type);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000565 }
566}
567
568
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000569// Lookup table for code generators for special runtime calls which are
570// generated inline.
571#define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
572 &FullCodeGenerator::Emit##Name,
erik.corry@gmail.com145eff52010-08-23 11:36:18 +0000573
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +0000574const FullCodeGenerator::InlineFunctionGenerator
575 FullCodeGenerator::kInlineFunctionGenerators[] = {
576 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
577 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
578 };
579#undef INLINE_FUNCTION_GENERATOR_ADDRESS
580
581
582FullCodeGenerator::InlineFunctionGenerator
583 FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
584 return kInlineFunctionGenerators[
585 static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction)];
586}
587
588
589void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* node) {
590 ZoneList<Expression*>* args = node->arguments();
591 Handle<String> name = node->name();
592 Runtime::Function* function = node->function();
593 ASSERT(function != NULL);
594 ASSERT(function->intrinsic_type == Runtime::INLINE);
595 InlineFunctionGenerator generator =
596 FindInlineFunctionGenerator(function->function_id);
597 ASSERT(generator != NULL);
598 ((*this).*(generator))(args);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000599}
600
601
602void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
603 Comment cmnt(masm_, "[ BinaryOperation");
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000604 Token::Value op = expr->op();
605 Expression* left = expr->left();
606 Expression* right = expr->right();
ricow@chromium.org65fae842010-08-25 15:26:24 +0000607
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000608 OverwriteMode mode = NO_OVERWRITE;
609 if (left->ResultOverwriteAllowed()) {
610 mode = OVERWRITE_LEFT;
611 } else if (right->ResultOverwriteAllowed()) {
612 mode = OVERWRITE_RIGHT;
ricow@chromium.org65fae842010-08-25 15:26:24 +0000613 }
614
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000615 switch (op) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000616 case Token::COMMA:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000617 VisitForEffect(left);
618 Visit(right);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000619 break;
620
621 case Token::OR:
622 case Token::AND:
623 EmitLogicalOperation(expr);
624 break;
625
626 case Token::ADD:
627 case Token::SUB:
628 case Token::DIV:
629 case Token::MOD:
630 case Token::MUL:
631 case Token::BIT_OR:
632 case Token::BIT_AND:
633 case Token::BIT_XOR:
634 case Token::SHL:
635 case Token::SHR:
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000636 case Token::SAR: {
637 // Figure out if either of the operands is a constant.
638 ConstantOperand constant = ShouldInlineSmiCase(op)
639 ? GetConstantOperand(op, left, right)
640 : kNoConstants;
641
642 // Load only the operands that we need to materialize.
643 if (constant == kNoConstants) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000644 VisitForStackValue(left);
645 VisitForAccumulatorValue(right);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000646 } else if (constant == kRightConstant) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000647 VisitForAccumulatorValue(left);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000648 } else {
649 ASSERT(constant == kLeftConstant);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000650 VisitForAccumulatorValue(right);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000651 }
652
ricow@chromium.org65fae842010-08-25 15:26:24 +0000653 SetSourcePosition(expr->position());
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000654 if (ShouldInlineSmiCase(op)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000655 EmitInlineSmiBinaryOp(expr, op, mode, left, right, constant);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000656 } else {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000657 EmitBinaryOp(op, mode);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000658 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000659 break;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +0000660 }
ricow@chromium.org65fae842010-08-25 15:26:24 +0000661
662 default:
663 UNREACHABLE();
664 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000665}
666
667
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000668void FullCodeGenerator::EmitLogicalOperation(BinaryOperation* expr) {
669 Label eval_right, done;
670
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000671 context()->EmitLogicalLeft(expr, &eval_right, &done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000672
673 __ bind(&eval_right);
674 Visit(expr->right());
675
676 __ bind(&done);
677}
678
679
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000680void FullCodeGenerator::EffectContext::EmitLogicalLeft(BinaryOperation* expr,
681 Label* eval_right,
682 Label* done) const {
683 if (expr->op() == Token::OR) {
684 codegen()->VisitForControl(expr->left(), done, eval_right, eval_right);
685 } else {
686 ASSERT(expr->op() == Token::AND);
687 codegen()->VisitForControl(expr->left(), eval_right, done, eval_right);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000688 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000689}
ricow@chromium.org65fae842010-08-25 15:26:24 +0000690
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000691
692void FullCodeGenerator::AccumulatorValueContext::EmitLogicalLeft(
693 BinaryOperation* expr,
694 Label* eval_right,
695 Label* done) const {
696 codegen()->Visit(expr->left());
697 // We want the value in the accumulator for the test, and on the stack in case
698 // we need it.
699 __ push(result_register());
700 Label discard, restore;
701 if (expr->op() == Token::OR) {
702 codegen()->DoTest(&restore, &discard, &restore);
703 } else {
704 ASSERT(expr->op() == Token::AND);
705 codegen()->DoTest(&discard, &restore, &restore);
706 }
707 __ bind(&restore);
708 __ pop(result_register());
709 __ jmp(done);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000710 __ bind(&discard);
711 __ Drop(1);
712}
713
714
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000715void FullCodeGenerator::StackValueContext::EmitLogicalLeft(
716 BinaryOperation* expr,
717 Label* eval_right,
718 Label* done) const {
719 codegen()->VisitForAccumulatorValue(expr->left());
720 // We want the value in the accumulator for the test, and on the stack in case
721 // we need it.
722 __ push(result_register());
723 Label discard;
724 if (expr->op() == Token::OR) {
725 codegen()->DoTest(done, &discard, &discard);
726 } else {
727 ASSERT(expr->op() == Token::AND);
728 codegen()->DoTest(&discard, done, &discard);
729 }
730 __ bind(&discard);
731 __ Drop(1);
732}
733
734
735void FullCodeGenerator::TestContext::EmitLogicalLeft(BinaryOperation* expr,
736 Label* eval_right,
737 Label* done) const {
738 if (expr->op() == Token::OR) {
739 codegen()->VisitForControl(expr->left(),
740 true_label_, eval_right, eval_right);
741 } else {
742 ASSERT(expr->op() == Token::AND);
743 codegen()->VisitForControl(expr->left(),
744 eval_right, false_label_, eval_right);
745 }
746}
747
748
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000749void FullCodeGenerator::VisitBlock(Block* stmt) {
750 Comment cmnt(masm_, "[ Block");
751 Breakable nested_statement(this, stmt);
752 SetStatementPosition(stmt);
753 VisitStatements(stmt->statements());
754 __ bind(nested_statement.break_target());
755}
756
757
758void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
759 Comment cmnt(masm_, "[ ExpressionStatement");
760 SetStatementPosition(stmt);
761 VisitForEffect(stmt->expression());
762}
763
764
765void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
766 Comment cmnt(masm_, "[ EmptyStatement");
767 SetStatementPosition(stmt);
768}
769
770
771void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
772 Comment cmnt(masm_, "[ IfStatement");
773 SetStatementPosition(stmt);
774 Label then_part, else_part, done;
775
ricow@chromium.org65fae842010-08-25 15:26:24 +0000776 if (stmt->HasElseStatement()) {
777 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
778 __ bind(&then_part);
779 Visit(stmt->then_statement());
780 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000781
ricow@chromium.org65fae842010-08-25 15:26:24 +0000782 __ bind(&else_part);
783 Visit(stmt->else_statement());
784 } else {
785 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
786 __ bind(&then_part);
787 Visit(stmt->then_statement());
788 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000789 __ bind(&done);
790}
791
792
793void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
794 Comment cmnt(masm_, "[ ContinueStatement");
795 SetStatementPosition(stmt);
796 NestedStatement* current = nesting_stack_;
797 int stack_depth = 0;
798 while (!current->IsContinueTarget(stmt->target())) {
799 stack_depth = current->Exit(stack_depth);
800 current = current->outer();
801 }
802 __ Drop(stack_depth);
803
804 Iteration* loop = current->AsIteration();
805 __ jmp(loop->continue_target());
806}
807
808
809void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
810 Comment cmnt(masm_, "[ BreakStatement");
811 SetStatementPosition(stmt);
812 NestedStatement* current = nesting_stack_;
813 int stack_depth = 0;
814 while (!current->IsBreakTarget(stmt->target())) {
815 stack_depth = current->Exit(stack_depth);
816 current = current->outer();
817 }
818 __ Drop(stack_depth);
819
820 Breakable* target = current->AsBreakable();
821 __ jmp(target->break_target());
822}
823
824
825void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
826 Comment cmnt(masm_, "[ ReturnStatement");
827 SetStatementPosition(stmt);
828 Expression* expr = stmt->expression();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000829 VisitForAccumulatorValue(expr);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000830
831 // Exit all nested statements.
832 NestedStatement* current = nesting_stack_;
833 int stack_depth = 0;
834 while (current != NULL) {
835 stack_depth = current->Exit(stack_depth);
836 current = current->outer();
837 }
838 __ Drop(stack_depth);
839
ager@chromium.org2cc82ae2010-06-14 07:35:38 +0000840 EmitReturnSequence();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000841}
842
843
844void FullCodeGenerator::VisitWithEnterStatement(WithEnterStatement* stmt) {
845 Comment cmnt(masm_, "[ WithEnterStatement");
846 SetStatementPosition(stmt);
847
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000848 VisitForStackValue(stmt->expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000849 if (stmt->is_catch_block()) {
850 __ CallRuntime(Runtime::kPushCatchContext, 1);
851 } else {
852 __ CallRuntime(Runtime::kPushContext, 1);
853 }
854 // Both runtime calls return the new context in both the context and the
855 // result registers.
856
857 // Update local stack frame context field.
858 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
859}
860
861
862void FullCodeGenerator::VisitWithExitStatement(WithExitStatement* stmt) {
863 Comment cmnt(masm_, "[ WithExitStatement");
864 SetStatementPosition(stmt);
865
866 // Pop context.
867 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
868 // Update local stack frame context field.
869 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
870}
871
872
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000873void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
874 Comment cmnt(masm_, "[ DoWhileStatement");
875 SetStatementPosition(stmt);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000876 Label body, stack_limit_hit, stack_check_success, done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000877
878 Iteration loop_statement(this, stmt);
879 increment_loop_depth();
880
881 __ bind(&body);
882 Visit(stmt->body());
883
884 // Check stack before looping.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +0000885 __ bind(loop_statement.continue_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000886 __ StackLimitCheck(&stack_limit_hit);
887 __ bind(&stack_check_success);
888
ricow@chromium.org65fae842010-08-25 15:26:24 +0000889 // Record the position of the do while condition and make sure it is
890 // possible to break on the condition.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000891 SetExpressionPosition(stmt->cond(), stmt->condition_position());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000892 VisitForControl(stmt->cond(),
893 &body,
894 loop_statement.break_target(),
895 loop_statement.break_target());
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000896
ricow@chromium.org65fae842010-08-25 15:26:24 +0000897 __ bind(loop_statement.break_target());
898 __ jmp(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000899
900 __ bind(&stack_limit_hit);
901 StackCheckStub stack_stub;
902 __ CallStub(&stack_stub);
903 __ jmp(&stack_check_success);
904
ricow@chromium.org65fae842010-08-25 15:26:24 +0000905 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000906 decrement_loop_depth();
907}
908
909
910void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
911 Comment cmnt(masm_, "[ WhileStatement");
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000912 Label body, stack_limit_hit, stack_check_success, done;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000913
914 Iteration loop_statement(this, stmt);
915 increment_loop_depth();
916
917 // Emit the test at the bottom of the loop.
918 __ jmp(loop_statement.continue_target());
919
920 __ bind(&body);
921 Visit(stmt->body());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000922 __ bind(loop_statement.continue_target());
ricow@chromium.org65fae842010-08-25 15:26:24 +0000923
924 // Emit the statement position here as this is where the while
925 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000926 SetStatementPosition(stmt);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +0000927
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000928 // Check stack before looping.
929 __ StackLimitCheck(&stack_limit_hit);
930 __ bind(&stack_check_success);
931
ricow@chromium.org65fae842010-08-25 15:26:24 +0000932 VisitForControl(stmt->cond(),
933 &body,
934 loop_statement.break_target(),
935 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000936
937 __ bind(loop_statement.break_target());
ager@chromium.org5b2fbee2010-09-08 06:38:15 +0000938 __ jmp(&done);
939
940 __ bind(&stack_limit_hit);
941 StackCheckStub stack_stub;
942 __ CallStub(&stack_stub);
943 __ jmp(&stack_check_success);
944
945 __ bind(&done);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000946 decrement_loop_depth();
947}
948
949
950void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
951 Comment cmnt(masm_, "[ ForStatement");
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000952 Label test, body, stack_limit_hit, stack_check_success;
953
954 Iteration loop_statement(this, stmt);
955 if (stmt->init() != NULL) {
956 Visit(stmt->init());
957 }
958
959 increment_loop_depth();
960 // Emit the test at the bottom of the loop (even if empty).
961 __ jmp(&test);
962
ricow@chromium.org65fae842010-08-25 15:26:24 +0000963 __ bind(&stack_limit_hit);
964 StackCheckStub stack_stub;
965 __ CallStub(&stack_stub);
966 __ jmp(&stack_check_success);
967
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000968 __ bind(&body);
969 Visit(stmt->body());
970
971 __ bind(loop_statement.continue_target());
972
973 SetStatementPosition(stmt);
974 if (stmt->next() != NULL) {
975 Visit(stmt->next());
976 }
977
978 __ bind(&test);
ricow@chromium.org65fae842010-08-25 15:26:24 +0000979 // Emit the statement position here as this is where the for
980 // statement code starts.
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +0000981 SetStatementPosition(stmt);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000982
983 // Check stack before looping.
984 __ StackLimitCheck(&stack_limit_hit);
985 __ bind(&stack_check_success);
986
987 if (stmt->cond() != NULL) {
ricow@chromium.org65fae842010-08-25 15:26:24 +0000988 VisitForControl(stmt->cond(),
989 &body,
990 loop_statement.break_target(),
991 loop_statement.break_target());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000992 } else {
993 __ jmp(&body);
994 }
995
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000996 __ bind(loop_statement.break_target());
997 decrement_loop_depth();
998}
999
1000
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001001void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1002 Comment cmnt(masm_, "[ TryCatchStatement");
1003 SetStatementPosition(stmt);
1004 // The try block adds a handler to the exception handler chain
1005 // before entering, and removes it again when exiting normally.
1006 // If an exception is thrown during execution of the try block,
1007 // control is passed to the handler, which also consumes the handler.
1008 // At this point, the exception is in a register, and store it in
1009 // the temporary local variable (prints as ".catch-var") before
1010 // executing the catch block. The catch block has been rewritten
1011 // to introduce a new scope to bind the catch variable and to remove
1012 // that scope again afterwards.
1013
1014 Label try_handler_setup, catch_entry, done;
1015 __ Call(&try_handler_setup);
1016 // Try handler code, exception in result register.
1017
1018 // Store exception in local .catch variable before executing catch block.
1019 {
1020 // The catch variable is *always* a variable proxy for a local variable.
1021 Variable* catch_var = stmt->catch_var()->AsVariableProxy()->AsVariable();
1022 ASSERT_NOT_NULL(catch_var);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 Slot* variable_slot = catch_var->AsSlot();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001024 ASSERT_NOT_NULL(variable_slot);
1025 ASSERT_EQ(Slot::LOCAL, variable_slot->type());
1026 StoreToFrameField(SlotOffset(variable_slot), result_register());
1027 }
1028
1029 Visit(stmt->catch_block());
1030 __ jmp(&done);
1031
1032 // Try block code. Sets up the exception handler chain.
1033 __ bind(&try_handler_setup);
1034 {
1035 TryCatch try_block(this, &catch_entry);
1036 __ PushTryHandler(IN_JAVASCRIPT, TRY_CATCH_HANDLER);
1037 Visit(stmt->try_block());
1038 __ PopTryHandler();
1039 }
1040 __ bind(&done);
1041}
1042
1043
1044void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1045 Comment cmnt(masm_, "[ TryFinallyStatement");
1046 SetStatementPosition(stmt);
1047 // Try finally is compiled by setting up a try-handler on the stack while
1048 // executing the try body, and removing it again afterwards.
1049 //
1050 // The try-finally construct can enter the finally block in three ways:
1051 // 1. By exiting the try-block normally. This removes the try-handler and
1052 // calls the finally block code before continuing.
1053 // 2. By exiting the try-block with a function-local control flow transfer
1054 // (break/continue/return). The site of the, e.g., break removes the
1055 // try handler and calls the finally block code before continuing
1056 // its outward control transfer.
1057 // 3. by exiting the try-block with a thrown exception.
1058 // This can happen in nested function calls. It traverses the try-handler
1059 // chain and consumes the try-handler entry before jumping to the
1060 // handler code. The handler code then calls the finally-block before
1061 // rethrowing the exception.
1062 //
1063 // The finally block must assume a return address on top of the stack
1064 // (or in the link register on ARM chips) and a value (return value or
1065 // exception) in the result register (rax/eax/r0), both of which must
1066 // be preserved. The return address isn't GC-safe, so it should be
1067 // cooked before GC.
1068 Label finally_entry;
1069 Label try_handler_setup;
1070
1071 // Setup the try-handler chain. Use a call to
1072 // Jump to try-handler setup and try-block code. Use call to put try-handler
1073 // address on stack.
1074 __ Call(&try_handler_setup);
1075 // Try handler code. Return address of call is pushed on handler stack.
1076 {
1077 // This code is only executed during stack-handler traversal when an
1078 // exception is thrown. The execption is in the result register, which
1079 // is retained by the finally block.
1080 // Call the finally block and then rethrow the exception.
1081 __ Call(&finally_entry);
1082 __ push(result_register());
1083 __ CallRuntime(Runtime::kReThrow, 1);
1084 }
1085
1086 __ bind(&finally_entry);
1087 {
1088 // Finally block implementation.
1089 Finally finally_block(this);
1090 EnterFinallyBlock();
1091 Visit(stmt->finally_block());
1092 ExitFinallyBlock(); // Return to the calling code.
1093 }
1094
1095 __ bind(&try_handler_setup);
1096 {
1097 // Setup try handler (stack pointer registers).
1098 TryFinally try_block(this, &finally_entry);
1099 __ PushTryHandler(IN_JAVASCRIPT, TRY_FINALLY_HANDLER);
1100 Visit(stmt->try_block());
1101 __ PopTryHandler();
1102 }
1103 // Execute the finally block on the way out.
1104 __ Call(&finally_entry);
1105}
1106
1107
1108void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1109#ifdef ENABLE_DEBUGGER_SUPPORT
1110 Comment cmnt(masm_, "[ DebuggerStatement");
1111 SetStatementPosition(stmt);
1112
ager@chromium.org5c838252010-02-19 08:53:10 +00001113 __ DebugBreak();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001114 // Ignore the return value.
1115#endif
1116}
1117
1118
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001119void FullCodeGenerator::VisitConditional(Conditional* expr) {
1120 Comment cmnt(masm_, "[ Conditional");
1121 Label true_case, false_case, done;
ricow@chromium.org65fae842010-08-25 15:26:24 +00001122 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001123
1124 __ bind(&true_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001125 SetExpressionPosition(expr->then_expression(),
1126 expr->then_expression_position());
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001127 if (context()->IsTest()) {
1128 const TestContext* for_test = TestContext::cast(context());
1129 VisitForControl(expr->then_expression(),
1130 for_test->true_label(),
1131 for_test->false_label(),
1132 NULL);
1133 } else {
1134 Visit(expr->then_expression());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001135 __ jmp(&done);
1136 }
1137
1138 __ bind(&false_case);
vegorov@chromium.org2356e6f2010-06-09 09:38:56 +00001139 SetExpressionPosition(expr->else_expression(),
1140 expr->else_expression_position());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001141 Visit(expr->else_expression());
1142 // If control flow falls through Visit, merge it with true case here.
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001143 if (!context()->IsTest()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001144 __ bind(&done);
1145 }
1146}
1147
1148
1149void FullCodeGenerator::VisitSlot(Slot* expr) {
1150 // Slots do not appear directly in the AST.
1151 UNREACHABLE();
1152}
1153
1154
1155void FullCodeGenerator::VisitLiteral(Literal* expr) {
1156 Comment cmnt(masm_, "[ Literal");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001157 context()->Plug(expr->handle());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001158}
1159
1160
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001161void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1162 Comment cmnt(masm_, "[ FunctionLiteral");
1163
1164 // Build the function boilerplate and instantiate it.
1165 Handle<SharedFunctionInfo> function_info =
ager@chromium.orgb61a0d12010-10-13 08:35:23 +00001166 Compiler::BuildFunctionInfo(expr, script());
1167 if (function_info.is_null()) {
1168 SetStackOverflow();
1169 return;
1170 }
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001171 EmitNewClosure(function_info, expr->pretenure());
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001172}
1173
1174
1175void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
1176 SharedFunctionInfoLiteral* expr) {
1177 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00001178 EmitNewClosure(expr->shared_function_info(), false);
erik.corry@gmail.com9dfbea42010-05-21 12:58:28 +00001179}
1180
1181
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001182void FullCodeGenerator::VisitCatchExtensionObject(CatchExtensionObject* expr) {
1183 // Call runtime routine to allocate the catch extension object and
1184 // assign the exception value to the catch variable.
1185 Comment cmnt(masm_, "[ CatchExtensionObject");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001186 VisitForStackValue(expr->key());
1187 VisitForStackValue(expr->value());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001188 // Create catch extension object.
1189 __ CallRuntime(Runtime::kCreateCatchExtensionObject, 2);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001190 context()->Plug(result_register());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001191}
1192
1193
1194void FullCodeGenerator::VisitThrow(Throw* expr) {
1195 Comment cmnt(masm_, "[ Throw");
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001196 VisitForStackValue(expr->exception());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001197 __ CallRuntime(Runtime::kThrow, 1);
1198 // Never returns here.
1199}
1200
1201
ricow@chromium.org65fae842010-08-25 15:26:24 +00001202void FullCodeGenerator::VisitIncrementOperation(IncrementOperation* expr) {
1203 UNREACHABLE();
1204}
1205
1206
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001207int FullCodeGenerator::TryFinally::Exit(int stack_depth) {
1208 // The macros used here must preserve the result register.
1209 __ Drop(stack_depth);
1210 __ PopTryHandler();
1211 __ Call(finally_entry_);
1212 return 0;
1213}
1214
1215
1216int FullCodeGenerator::TryCatch::Exit(int stack_depth) {
1217 // The macros used here must preserve the result register.
1218 __ Drop(stack_depth);
1219 __ PopTryHandler();
1220 return 0;
1221}
1222
ricow@chromium.org65fae842010-08-25 15:26:24 +00001223
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001224#undef __
1225
1226
1227} } // namespace v8::internal