1 // Copyright 2012 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.h"
31 #include "compiler.h"
32 #include "debug.h"
33 #include "full-codegen.h"
34 #include "liveedit.h"
35 #include "macro-assembler.h"
36 #include "prettyprinter.h"
37 #include "scopes.h"
38 #include "scopeinfo.h"
39 #include "stub-cache.h"
40
41 namespace v8 {
42 namespace internal {
43
Check(Statement * stmt)44 void BreakableStatementChecker::Check(Statement* stmt) {
45 Visit(stmt);
46 }
47
48
Check(Expression * expr)49 void BreakableStatementChecker::Check(Expression* expr) {
50 Visit(expr);
51 }
52
53
VisitVariableDeclaration(VariableDeclaration * decl)54 void BreakableStatementChecker::VisitVariableDeclaration(
55 VariableDeclaration* decl) {
56 }
57
VisitFunctionDeclaration(FunctionDeclaration * decl)58 void BreakableStatementChecker::VisitFunctionDeclaration(
59 FunctionDeclaration* decl) {
60 }
61
VisitModuleDeclaration(ModuleDeclaration * decl)62 void BreakableStatementChecker::VisitModuleDeclaration(
63 ModuleDeclaration* decl) {
64 }
65
VisitImportDeclaration(ImportDeclaration * decl)66 void BreakableStatementChecker::VisitImportDeclaration(
67 ImportDeclaration* decl) {
68 }
69
VisitExportDeclaration(ExportDeclaration * decl)70 void BreakableStatementChecker::VisitExportDeclaration(
71 ExportDeclaration* decl) {
72 }
73
74
VisitModuleLiteral(ModuleLiteral * module)75 void BreakableStatementChecker::VisitModuleLiteral(ModuleLiteral* module) {
76 }
77
VisitModuleVariable(ModuleVariable * module)78 void BreakableStatementChecker::VisitModuleVariable(ModuleVariable* module) {
79 }
80
VisitModulePath(ModulePath * module)81 void BreakableStatementChecker::VisitModulePath(ModulePath* module) {
82 }
83
VisitModuleUrl(ModuleUrl * module)84 void BreakableStatementChecker::VisitModuleUrl(ModuleUrl* module) {
85 }
86
87
VisitBlock(Block * stmt)88 void BreakableStatementChecker::VisitBlock(Block* stmt) {
89 }
90
91
VisitExpressionStatement(ExpressionStatement * stmt)92 void BreakableStatementChecker::VisitExpressionStatement(
93 ExpressionStatement* stmt) {
94 // Check if expression is breakable.
95 Visit(stmt->expression());
96 }
97
98
VisitEmptyStatement(EmptyStatement * stmt)99 void BreakableStatementChecker::VisitEmptyStatement(EmptyStatement* stmt) {
100 }
101
102
VisitIfStatement(IfStatement * stmt)103 void BreakableStatementChecker::VisitIfStatement(IfStatement* stmt) {
104 // If the condition is breakable the if statement is breakable.
105 Visit(stmt->condition());
106 }
107
108
VisitContinueStatement(ContinueStatement * stmt)109 void BreakableStatementChecker::VisitContinueStatement(
110 ContinueStatement* stmt) {
111 }
112
113
VisitBreakStatement(BreakStatement * stmt)114 void BreakableStatementChecker::VisitBreakStatement(BreakStatement* stmt) {
115 }
116
117
VisitReturnStatement(ReturnStatement * stmt)118 void BreakableStatementChecker::VisitReturnStatement(ReturnStatement* stmt) {
119 // Return is breakable if the expression is.
120 Visit(stmt->expression());
121 }
122
123
VisitWithStatement(WithStatement * stmt)124 void BreakableStatementChecker::VisitWithStatement(WithStatement* stmt) {
125 Visit(stmt->expression());
126 }
127
128
VisitSwitchStatement(SwitchStatement * stmt)129 void BreakableStatementChecker::VisitSwitchStatement(SwitchStatement* stmt) {
130 // Switch statements breakable if the tag expression is.
131 Visit(stmt->tag());
132 }
133
134
VisitDoWhileStatement(DoWhileStatement * stmt)135 void BreakableStatementChecker::VisitDoWhileStatement(DoWhileStatement* stmt) {
136 // Mark do while as breakable to avoid adding a break slot in front of it.
137 is_breakable_ = true;
138 }
139
140
VisitWhileStatement(WhileStatement * stmt)141 void BreakableStatementChecker::VisitWhileStatement(WhileStatement* stmt) {
142 // Mark while statements breakable if the condition expression is.
143 Visit(stmt->cond());
144 }
145
146
VisitForStatement(ForStatement * stmt)147 void BreakableStatementChecker::VisitForStatement(ForStatement* stmt) {
148 // Mark for statements breakable if the condition expression is.
149 if (stmt->cond() != NULL) {
150 Visit(stmt->cond());
151 }
152 }
153
154
VisitForInStatement(ForInStatement * stmt)155 void BreakableStatementChecker::VisitForInStatement(ForInStatement* stmt) {
156 // Mark for in statements breakable if the enumerable expression is.
157 Visit(stmt->enumerable());
158 }
159
160
VisitTryCatchStatement(TryCatchStatement * stmt)161 void BreakableStatementChecker::VisitTryCatchStatement(
162 TryCatchStatement* stmt) {
163 // Mark try catch as breakable to avoid adding a break slot in front of it.
164 is_breakable_ = true;
165 }
166
167
VisitTryFinallyStatement(TryFinallyStatement * stmt)168 void BreakableStatementChecker::VisitTryFinallyStatement(
169 TryFinallyStatement* stmt) {
170 // Mark try finally as breakable to avoid adding a break slot in front of it.
171 is_breakable_ = true;
172 }
173
174
VisitDebuggerStatement(DebuggerStatement * stmt)175 void BreakableStatementChecker::VisitDebuggerStatement(
176 DebuggerStatement* stmt) {
177 // The debugger statement is breakable.
178 is_breakable_ = true;
179 }
180
181
VisitFunctionLiteral(FunctionLiteral * expr)182 void BreakableStatementChecker::VisitFunctionLiteral(FunctionLiteral* expr) {
183 }
184
185
VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral * expr)186 void BreakableStatementChecker::VisitSharedFunctionInfoLiteral(
187 SharedFunctionInfoLiteral* expr) {
188 }
189
190
VisitConditional(Conditional * expr)191 void BreakableStatementChecker::VisitConditional(Conditional* expr) {
192 }
193
194
VisitVariableProxy(VariableProxy * expr)195 void BreakableStatementChecker::VisitVariableProxy(VariableProxy* expr) {
196 }
197
198
VisitLiteral(Literal * expr)199 void BreakableStatementChecker::VisitLiteral(Literal* expr) {
200 }
201
202
VisitRegExpLiteral(RegExpLiteral * expr)203 void BreakableStatementChecker::VisitRegExpLiteral(RegExpLiteral* expr) {
204 }
205
206
VisitObjectLiteral(ObjectLiteral * expr)207 void BreakableStatementChecker::VisitObjectLiteral(ObjectLiteral* expr) {
208 }
209
210
VisitArrayLiteral(ArrayLiteral * expr)211 void BreakableStatementChecker::VisitArrayLiteral(ArrayLiteral* expr) {
212 }
213
214
VisitAssignment(Assignment * expr)215 void BreakableStatementChecker::VisitAssignment(Assignment* expr) {
216 // If assigning to a property (including a global property) the assignment is
217 // breakable.
218 VariableProxy* proxy = expr->target()->AsVariableProxy();
219 Property* prop = expr->target()->AsProperty();
220 if (prop != NULL || (proxy != NULL && proxy->var()->IsUnallocated())) {
221 is_breakable_ = true;
222 return;
223 }
224
225 // Otherwise the assignment is breakable if the assigned value is.
226 Visit(expr->value());
227 }
228
229
VisitThrow(Throw * expr)230 void BreakableStatementChecker::VisitThrow(Throw* expr) {
231 // Throw is breakable if the expression is.
232 Visit(expr->exception());
233 }
234
235
VisitProperty(Property * expr)236 void BreakableStatementChecker::VisitProperty(Property* expr) {
237 // Property load is breakable.
238 is_breakable_ = true;
239 }
240
241
VisitCall(Call * expr)242 void BreakableStatementChecker::VisitCall(Call* expr) {
243 // Function calls both through IC and call stub are breakable.
244 is_breakable_ = true;
245 }
246
247
VisitCallNew(CallNew * expr)248 void BreakableStatementChecker::VisitCallNew(CallNew* expr) {
249 // Function calls through new are breakable.
250 is_breakable_ = true;
251 }
252
253
VisitCallRuntime(CallRuntime * expr)254 void BreakableStatementChecker::VisitCallRuntime(CallRuntime* expr) {
255 }
256
257
VisitUnaryOperation(UnaryOperation * expr)258 void BreakableStatementChecker::VisitUnaryOperation(UnaryOperation* expr) {
259 Visit(expr->expression());
260 }
261
262
VisitCountOperation(CountOperation * expr)263 void BreakableStatementChecker::VisitCountOperation(CountOperation* expr) {
264 Visit(expr->expression());
265 }
266
267
VisitBinaryOperation(BinaryOperation * expr)268 void BreakableStatementChecker::VisitBinaryOperation(BinaryOperation* expr) {
269 Visit(expr->left());
270 if (expr->op() != Token::AND &&
271 expr->op() != Token::OR) {
272 Visit(expr->right());
273 }
274 }
275
276
VisitCompareOperation(CompareOperation * expr)277 void BreakableStatementChecker::VisitCompareOperation(CompareOperation* expr) {
278 Visit(expr->left());
279 Visit(expr->right());
280 }
281
282
VisitThisFunction(ThisFunction * expr)283 void BreakableStatementChecker::VisitThisFunction(ThisFunction* expr) {
284 }
285
286
287 #define __ ACCESS_MASM(masm())
288
MakeCode(CompilationInfo * info)289 bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
290 Isolate* isolate = info->isolate();
291 Handle<Script> script = info->script();
292 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
293 int len = String::cast(script->source())->length();
294 isolate->counters()->total_full_codegen_source_size()->Increment(len);
295 }
296 if (FLAG_trace_codegen) {
297 PrintF("Full Compiler - ");
298 }
299 CodeGenerator::MakeCodePrologue(info);
300 const int kInitialBufferSize = 4 * KB;
301 MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize);
302 #ifdef ENABLE_GDB_JIT_INTERFACE
303 masm.positions_recorder()->StartGDBJITLineInfoRecording();
304 #endif
305
306 FullCodeGenerator cgen(&masm, info);
307 cgen.Generate();
308 if (cgen.HasStackOverflow()) {
309 ASSERT(!isolate->has_pending_exception());
310 return false;
311 }
312 unsigned table_offset = cgen.EmitStackCheckTable();
313
314 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
315 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
316 code->set_optimizable(info->IsOptimizable() &&
317 !info->function()->flags()->Contains(kDontOptimize) &&
318 info->function()->scope()->AllowsLazyRecompilation());
319 code->set_self_optimization_header(cgen.has_self_optimization_header_);
320 cgen.PopulateDeoptimizationData(code);
321 cgen.PopulateTypeFeedbackInfo(code);
322 cgen.PopulateTypeFeedbackCells(code);
323 code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
324 code->set_handler_table(*cgen.handler_table());
325 #ifdef ENABLE_DEBUGGER_SUPPORT
326 code->set_has_debug_break_slots(
327 info->isolate()->debugger()->IsDebuggerActive());
328 code->set_compiled_optimizable(info->IsOptimizable());
329 #endif // ENABLE_DEBUGGER_SUPPORT
330 code->set_allow_osr_at_loop_nesting_level(0);
331 code->set_profiler_ticks(0);
332 code->set_stack_check_table_offset(table_offset);
333 CodeGenerator::PrintCode(code, info);
334 info->SetCode(code); // May be an empty handle.
335 if (!code.is_null()) {
336 isolate->runtime_profiler()->NotifyCodeGenerated(code->instruction_size());
337 }
338 #ifdef ENABLE_GDB_JIT_INTERFACE
339 if (FLAG_gdbjit && !code.is_null()) {
340 GDBJITLineInfo* lineinfo =
341 masm.positions_recorder()->DetachGDBJITLineInfo();
342
343 GDBJIT(RegisterDetailedLineInfo(*code, lineinfo));
344 }
345 #endif
346 return !code.is_null();
347 }
348
349
EmitStackCheckTable()350 unsigned FullCodeGenerator::EmitStackCheckTable() {
351 // The stack check table consists of a length (in number of entries)
352 // field, and then a sequence of entries. Each entry is a pair of AST id
353 // and code-relative pc offset.
354 masm()->Align(kIntSize);
355 unsigned offset = masm()->pc_offset();
356 unsigned length = stack_checks_.length();
357 __ dd(length);
358 for (unsigned i = 0; i < length; ++i) {
359 __ dd(stack_checks_[i].id);
360 __ dd(stack_checks_[i].pc_and_state);
361 }
362 return offset;
363 }
364
365
PopulateDeoptimizationData(Handle<Code> code)366 void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
367 // Fill in the deoptimization information.
368 ASSERT(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty());
369 if (!info_->HasDeoptimizationSupport()) return;
370 int length = bailout_entries_.length();
371 Handle<DeoptimizationOutputData> data = isolate()->factory()->
372 NewDeoptimizationOutputData(length, TENURED);
373 for (int i = 0; i < length; i++) {
374 data->SetAstId(i, Smi::FromInt(bailout_entries_[i].id));
375 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state));
376 }
377 code->set_deoptimization_data(*data);
378 }
379
380
PopulateTypeFeedbackInfo(Handle<Code> code)381 void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) {
382 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo();
383 info->set_ic_total_count(ic_total_count_);
384 ASSERT(!isolate()->heap()->InNewSpace(*info));
385 code->set_type_feedback_info(*info);
386 }
387
388
PopulateTypeFeedbackCells(Handle<Code> code)389 void FullCodeGenerator::PopulateTypeFeedbackCells(Handle<Code> code) {
390 if (type_feedback_cells_.is_empty()) return;
391 int length = type_feedback_cells_.length();
392 int array_size = TypeFeedbackCells::LengthOfFixedArray(length);
393 Handle<TypeFeedbackCells> cache = Handle<TypeFeedbackCells>::cast(
394 isolate()->factory()->NewFixedArray(array_size, TENURED));
395 for (int i = 0; i < length; i++) {
396 cache->SetAstId(i, Smi::FromInt(type_feedback_cells_[i].ast_id));
397 cache->SetCell(i, *type_feedback_cells_[i].cell);
398 }
399 TypeFeedbackInfo::cast(code->type_feedback_info())->set_type_feedback_cells(
400 *cache);
401 }
402
403
404
PrepareForBailout(Expression * node,State state)405 void FullCodeGenerator::PrepareForBailout(Expression* node, State state) {
406 PrepareForBailoutForId(node->id(), state);
407 }
408
409
RecordJSReturnSite(Call * call)410 void FullCodeGenerator::RecordJSReturnSite(Call* call) {
411 // We record the offset of the function return so we can rebuild the frame
412 // if the function was inlined, i.e., this is the return address in the
413 // inlined function's frame.
414 //
415 // The state is ignored. We defensively set it to TOS_REG, which is the
416 // real state of the unoptimized code at the return site.
417 PrepareForBailoutForId(call->ReturnId(), TOS_REG);
418 #ifdef DEBUG
419 // In debug builds, mark the return so we can verify that this function
420 // was called.
421 ASSERT(!call->return_is_recorded_);
422 call->return_is_recorded_ = true;
423 #endif
424 }
425
426
PrepareForBailoutForId(unsigned id,State state)427 void FullCodeGenerator::PrepareForBailoutForId(unsigned id, State state) {
428 // There's no need to prepare this code for bailouts from already optimized
429 // code or code that can't be optimized.
430 if (!info_->HasDeoptimizationSupport()) return;
431 unsigned pc_and_state =
432 StateField::encode(state) | PcField::encode(masm_->pc_offset());
433 ASSERT(Smi::IsValid(pc_and_state));
434 BailoutEntry entry = { id, pc_and_state };
435 #ifdef DEBUG
436 if (FLAG_enable_slow_asserts) {
437 // Assert that we don't have multiple bailout entries for the same node.
438 for (int i = 0; i < bailout_entries_.length(); i++) {
439 if (bailout_entries_.at(i).id == entry.id) {
440 AstPrinter printer;
441 PrintF("%s", printer.PrintProgram(info_->function()));
442 UNREACHABLE();
443 }
444 }
445 }
446 #endif // DEBUG
447 bailout_entries_.Add(entry);
448 }
449
450
RecordTypeFeedbackCell(unsigned id,Handle<JSGlobalPropertyCell> cell)451 void FullCodeGenerator::RecordTypeFeedbackCell(
452 unsigned id, Handle<JSGlobalPropertyCell> cell) {
453 TypeFeedbackCellEntry entry = { id, cell };
454 type_feedback_cells_.Add(entry);
455 }
456
457
RecordStackCheck(unsigned ast_id)458 void FullCodeGenerator::RecordStackCheck(unsigned ast_id) {
459 // The pc offset does not need to be encoded and packed together with a
460 // state.
461 ASSERT(masm_->pc_offset() > 0);
462 BailoutEntry entry = { ast_id, static_cast<unsigned>(masm_->pc_offset()) };
463 stack_checks_.Add(entry);
464 }
465
466
ShouldInlineSmiCase(Token::Value op)467 bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
468 // Inline smi case inside loops, but not division and modulo which
469 // are too complicated and take up too much space.
470 if (op == Token::DIV ||op == Token::MOD) return false;
471 if (FLAG_always_inline_smi_code) return true;
472 return loop_depth_ > 0;
473 }
474
475
Plug(Register reg) const476 void FullCodeGenerator::EffectContext::Plug(Register reg) const {
477 }
478
479
Plug(Register reg) const480 void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
481 __ Move(result_register(), reg);
482 }
483
484
Plug(Register reg) const485 void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
486 __ push(reg);
487 }
488
489
Plug(Register reg) const490 void FullCodeGenerator::TestContext::Plug(Register reg) const {
491 // For simplicity we always test the accumulator register.
492 __ Move(result_register(), reg);
493 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
494 codegen()->DoTest(this);
495 }
496
497
PlugTOS() const498 void FullCodeGenerator::EffectContext::PlugTOS() const {
499 __ Drop(1);
500 }
501
502
PlugTOS() const503 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
504 __ pop(result_register());
505 }
506
507
PlugTOS() const508 void FullCodeGenerator::StackValueContext::PlugTOS() const {
509 }
510
511
PlugTOS() const512 void FullCodeGenerator::TestContext::PlugTOS() const {
513 // For simplicity we always test the accumulator register.
514 __ pop(result_register());
515 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
516 codegen()->DoTest(this);
517 }
518
519
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const520 void FullCodeGenerator::EffectContext::PrepareTest(
521 Label* materialize_true,
522 Label* materialize_false,
523 Label** if_true,
524 Label** if_false,
525 Label** fall_through) const {
526 // In an effect context, the true and the false case branch to the
527 // same label.
528 *if_true = *if_false = *fall_through = materialize_true;
529 }
530
531
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const532 void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
533 Label* materialize_true,
534 Label* materialize_false,
535 Label** if_true,
536 Label** if_false,
537 Label** fall_through) const {
538 *if_true = *fall_through = materialize_true;
539 *if_false = materialize_false;
540 }
541
542
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const543 void FullCodeGenerator::StackValueContext::PrepareTest(
544 Label* materialize_true,
545 Label* materialize_false,
546 Label** if_true,
547 Label** if_false,
548 Label** fall_through) const {
549 *if_true = *fall_through = materialize_true;
550 *if_false = materialize_false;
551 }
552
553
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const554 void FullCodeGenerator::TestContext::PrepareTest(
555 Label* materialize_true,
556 Label* materialize_false,
557 Label** if_true,
558 Label** if_false,
559 Label** fall_through) const {
560 *if_true = true_label_;
561 *if_false = false_label_;
562 *fall_through = fall_through_;
563 }
564
565
DoTest(const TestContext * context)566 void FullCodeGenerator::DoTest(const TestContext* context) {
567 DoTest(context->condition(),
568 context->true_label(),
569 context->false_label(),
570 context->fall_through());
571 }
572
573
VisitDeclarations(ZoneList<Declaration * > * declarations)574 void FullCodeGenerator::VisitDeclarations(
575 ZoneList<Declaration*>* declarations) {
576 int save_global_count = global_count_;
577 global_count_ = 0;
578
579 AstVisitor::VisitDeclarations(declarations);
580
581 // Batch declare global functions and variables.
582 if (global_count_ > 0) {
583 Handle<FixedArray> array =
584 isolate()->factory()->NewFixedArray(2 * global_count_, TENURED);
585 int length = declarations->length();
586 for (int j = 0, i = 0; i < length; i++) {
587 Declaration* decl = declarations->at(i);
588 Variable* var = decl->proxy()->var();
589
590 if (var->IsUnallocated()) {
591 array->set(j++, *(var->name()));
592 FunctionDeclaration* fun_decl = decl->AsFunctionDeclaration();
593 if (fun_decl == NULL) {
594 if (var->binding_needs_init()) {
595 // In case this binding needs initialization use the hole.
596 array->set_the_hole(j++);
597 } else {
598 array->set_undefined(j++);
599 }
600 } else {
601 Handle<SharedFunctionInfo> function =
602 Compiler::BuildFunctionInfo(fun_decl->fun(), script());
603 // Check for stack-overflow exception.
604 if (function.is_null()) {
605 SetStackOverflow();
606 return;
607 }
608 array->set(j++, *function);
609 }
610 }
611 }
612 // Invoke the platform-dependent code generator to do the actual
613 // declaration the global functions and variables.
614 DeclareGlobals(array);
615 }
616
617 global_count_ = save_global_count;
618 }
619
620
VisitVariableDeclaration(VariableDeclaration * decl)621 void FullCodeGenerator::VisitVariableDeclaration(VariableDeclaration* decl) {
622 EmitDeclaration(decl->proxy(), decl->mode(), NULL);
623 }
624
625
VisitFunctionDeclaration(FunctionDeclaration * decl)626 void FullCodeGenerator::VisitFunctionDeclaration(FunctionDeclaration* decl) {
627 EmitDeclaration(decl->proxy(), decl->mode(), decl->fun());
628 }
629
630
VisitModuleDeclaration(ModuleDeclaration * decl)631 void FullCodeGenerator::VisitModuleDeclaration(ModuleDeclaration* decl) {
632 EmitDeclaration(decl->proxy(), decl->mode(), NULL);
633 }
634
635
VisitImportDeclaration(ImportDeclaration * decl)636 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* decl) {
637 EmitDeclaration(decl->proxy(), decl->mode(), NULL);
638 }
639
640
VisitExportDeclaration(ExportDeclaration * decl)641 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* decl) {
642 // TODO(rossberg)
643 }
644
645
VisitModuleLiteral(ModuleLiteral * module)646 void FullCodeGenerator::VisitModuleLiteral(ModuleLiteral* module) {
647 // TODO(rossberg)
648 }
649
650
VisitModuleVariable(ModuleVariable * module)651 void FullCodeGenerator::VisitModuleVariable(ModuleVariable* module) {
652 // TODO(rossberg)
653 }
654
655
VisitModulePath(ModulePath * module)656 void FullCodeGenerator::VisitModulePath(ModulePath* module) {
657 // TODO(rossberg)
658 }
659
660
VisitModuleUrl(ModuleUrl * decl)661 void FullCodeGenerator::VisitModuleUrl(ModuleUrl* decl) {
662 // TODO(rossberg)
663 }
664
665
DeclareGlobalsFlags()666 int FullCodeGenerator::DeclareGlobalsFlags() {
667 ASSERT(DeclareGlobalsLanguageMode::is_valid(language_mode()));
668 return DeclareGlobalsEvalFlag::encode(is_eval()) |
669 DeclareGlobalsNativeFlag::encode(is_native()) |
670 DeclareGlobalsLanguageMode::encode(language_mode());
671 }
672
673
SetFunctionPosition(FunctionLiteral * fun)674 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
675 CodeGenerator::RecordPositions(masm_, fun->start_position());
676 }
677
678
SetReturnPosition(FunctionLiteral * fun)679 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
680 CodeGenerator::RecordPositions(masm_, fun->end_position() - 1);
681 }
682
683
SetStatementPosition(Statement * stmt)684 void FullCodeGenerator::SetStatementPosition(Statement* stmt) {
685 #ifdef ENABLE_DEBUGGER_SUPPORT
686 if (!isolate()->debugger()->IsDebuggerActive()) {
687 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
688 } else {
689 // Check if the statement will be breakable without adding a debug break
690 // slot.
691 BreakableStatementChecker checker;
692 checker.Check(stmt);
693 // Record the statement position right here if the statement is not
694 // breakable. For breakable statements the actual recording of the
695 // position will be postponed to the breakable code (typically an IC).
696 bool position_recorded = CodeGenerator::RecordPositions(
697 masm_, stmt->statement_pos(), !checker.is_breakable());
698 // If the position recording did record a new position generate a debug
699 // break slot to make the statement breakable.
700 if (position_recorded) {
701 Debug::GenerateSlot(masm_);
702 }
703 }
704 #else
705 CodeGenerator::RecordPositions(masm_, stmt->statement_pos());
706 #endif
707 }
708
709
SetExpressionPosition(Expression * expr,int pos)710 void FullCodeGenerator::SetExpressionPosition(Expression* expr, int pos) {
711 #ifdef ENABLE_DEBUGGER_SUPPORT
712 if (!isolate()->debugger()->IsDebuggerActive()) {
713 CodeGenerator::RecordPositions(masm_, pos);
714 } else {
715 // Check if the expression will be breakable without adding a debug break
716 // slot.
717 BreakableStatementChecker checker;
718 checker.Check(expr);
719 // Record a statement position right here if the expression is not
720 // breakable. For breakable expressions the actual recording of the
721 // position will be postponed to the breakable code (typically an IC).
722 // NOTE this will record a statement position for something which might
723 // not be a statement. As stepping in the debugger will only stop at
724 // statement positions this is used for e.g. the condition expression of
725 // a do while loop.
726 bool position_recorded = CodeGenerator::RecordPositions(
727 masm_, pos, !checker.is_breakable());
728 // If the position recording did record a new position generate a debug
729 // break slot to make the statement breakable.
730 if (position_recorded) {
731 Debug::GenerateSlot(masm_);
732 }
733 }
734 #else
735 CodeGenerator::RecordPositions(masm_, pos);
736 #endif
737 }
738
739
SetStatementPosition(int pos)740 void FullCodeGenerator::SetStatementPosition(int pos) {
741 CodeGenerator::RecordPositions(masm_, pos);
742 }
743
744
SetSourcePosition(int pos)745 void FullCodeGenerator::SetSourcePosition(int pos) {
746 if (pos != RelocInfo::kNoPosition) {
747 masm_->positions_recorder()->RecordPosition(pos);
748 }
749 }
750
751
752 // Lookup table for code generators for special runtime calls which are
753 // generated inline.
754 #define INLINE_FUNCTION_GENERATOR_ADDRESS(Name, argc, ressize) \
755 &FullCodeGenerator::Emit##Name,
756
757 const FullCodeGenerator::InlineFunctionGenerator
758 FullCodeGenerator::kInlineFunctionGenerators[] = {
759 INLINE_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
760 INLINE_RUNTIME_FUNCTION_LIST(INLINE_FUNCTION_GENERATOR_ADDRESS)
761 };
762 #undef INLINE_FUNCTION_GENERATOR_ADDRESS
763
764
765 FullCodeGenerator::InlineFunctionGenerator
FindInlineFunctionGenerator(Runtime::FunctionId id)766 FullCodeGenerator::FindInlineFunctionGenerator(Runtime::FunctionId id) {
767 int lookup_index =
768 static_cast<int>(id) - static_cast<int>(Runtime::kFirstInlineFunction);
769 ASSERT(lookup_index >= 0);
770 ASSERT(static_cast<size_t>(lookup_index) <
771 ARRAY_SIZE(kInlineFunctionGenerators));
772 return kInlineFunctionGenerators[lookup_index];
773 }
774
775
EmitInlineRuntimeCall(CallRuntime * expr)776 void FullCodeGenerator::EmitInlineRuntimeCall(CallRuntime* expr) {
777 const Runtime::Function* function = expr->function();
778 ASSERT(function != NULL);
779 ASSERT(function->intrinsic_type == Runtime::INLINE);
780 InlineFunctionGenerator generator =
781 FindInlineFunctionGenerator(function->function_id);
782 ((*this).*(generator))(expr);
783 }
784
785
VisitBinaryOperation(BinaryOperation * expr)786 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
787 switch (expr->op()) {
788 case Token::COMMA:
789 return VisitComma(expr);
790 case Token::OR:
791 case Token::AND:
792 return VisitLogicalExpression(expr);
793 default:
794 return VisitArithmeticExpression(expr);
795 }
796 }
797
798
VisitInDuplicateContext(Expression * expr)799 void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
800 if (context()->IsEffect()) {
801 VisitForEffect(expr);
802 } else if (context()->IsAccumulatorValue()) {
803 VisitForAccumulatorValue(expr);
804 } else if (context()->IsStackValue()) {
805 VisitForStackValue(expr);
806 } else if (context()->IsTest()) {
807 const TestContext* test = TestContext::cast(context());
808 VisitForControl(expr, test->true_label(), test->false_label(),
809 test->fall_through());
810 }
811 }
812
813
VisitComma(BinaryOperation * expr)814 void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
815 Comment cmnt(masm_, "[ Comma");
816 VisitForEffect(expr->left());
817 VisitInDuplicateContext(expr->right());
818 }
819
820
VisitLogicalExpression(BinaryOperation * expr)821 void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
822 bool is_logical_and = expr->op() == Token::AND;
823 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR");
824 Expression* left = expr->left();
825 Expression* right = expr->right();
826 int right_id = expr->RightId();
827 Label done;
828
829 if (context()->IsTest()) {
830 Label eval_right;
831 const TestContext* test = TestContext::cast(context());
832 if (is_logical_and) {
833 VisitForControl(left, &eval_right, test->false_label(), &eval_right);
834 } else {
835 VisitForControl(left, test->true_label(), &eval_right, &eval_right);
836 }
837 PrepareForBailoutForId(right_id, NO_REGISTERS);
838 __ bind(&eval_right);
839
840 } else if (context()->IsAccumulatorValue()) {
841 VisitForAccumulatorValue(left);
842 // We want the value in the accumulator for the test, and on the stack in
843 // case we need it.
844 __ push(result_register());
845 Label discard, restore;
846 if (is_logical_and) {
847 DoTest(left, &discard, &restore, &restore);
848 } else {
849 DoTest(left, &restore, &discard, &restore);
850 }
851 __ bind(&restore);
852 __ pop(result_register());
853 __ jmp(&done);
854 __ bind(&discard);
855 __ Drop(1);
856 PrepareForBailoutForId(right_id, NO_REGISTERS);
857
858 } else if (context()->IsStackValue()) {
859 VisitForAccumulatorValue(left);
860 // We want the value in the accumulator for the test, and on the stack in
861 // case we need it.
862 __ push(result_register());
863 Label discard;
864 if (is_logical_and) {
865 DoTest(left, &discard, &done, &discard);
866 } else {
867 DoTest(left, &done, &discard, &discard);
868 }
869 __ bind(&discard);
870 __ Drop(1);
871 PrepareForBailoutForId(right_id, NO_REGISTERS);
872
873 } else {
874 ASSERT(context()->IsEffect());
875 Label eval_right;
876 if (is_logical_and) {
877 VisitForControl(left, &eval_right, &done, &eval_right);
878 } else {
879 VisitForControl(left, &done, &eval_right, &eval_right);
880 }
881 PrepareForBailoutForId(right_id, NO_REGISTERS);
882 __ bind(&eval_right);
883 }
884
885 VisitInDuplicateContext(right);
886 __ bind(&done);
887 }
888
889
VisitArithmeticExpression(BinaryOperation * expr)890 void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
891 Token::Value op = expr->op();
892 Comment cmnt(masm_, "[ ArithmeticExpression");
893 Expression* left = expr->left();
894 Expression* right = expr->right();
895 OverwriteMode mode =
896 left->ResultOverwriteAllowed()
897 ? OVERWRITE_LEFT
898 : (right->ResultOverwriteAllowed() ? OVERWRITE_RIGHT : NO_OVERWRITE);
899
900 VisitForStackValue(left);
901 VisitForAccumulatorValue(right);
902
903 SetSourcePosition(expr->position());
904 if (ShouldInlineSmiCase(op)) {
905 EmitInlineSmiBinaryOp(expr, op, mode, left, right);
906 } else {
907 EmitBinaryOp(expr, op, mode);
908 }
909 }
910
911
VisitBlock(Block * stmt)912 void FullCodeGenerator::VisitBlock(Block* stmt) {
913 Comment cmnt(masm_, "[ Block");
914 NestedBlock nested_block(this, stmt);
915 SetStatementPosition(stmt);
916
917 Scope* saved_scope = scope();
918 // Push a block context when entering a block with block scoped variables.
919 if (stmt->block_scope() != NULL) {
920 { Comment cmnt(masm_, "[ Extend block context");
921 scope_ = stmt->block_scope();
922 Handle<ScopeInfo> scope_info = scope_->GetScopeInfo();
923 int heap_slots = scope_info->ContextLength() - Context::MIN_CONTEXT_SLOTS;
924 __ Push(scope_info);
925 PushFunctionArgumentForContextAllocation();
926 if (heap_slots <= FastNewBlockContextStub::kMaximumSlots) {
927 FastNewBlockContextStub stub(heap_slots);
928 __ CallStub(&stub);
929 } else {
930 __ CallRuntime(Runtime::kPushBlockContext, 2);
931 }
932
933 // Replace the context stored in the frame.
934 StoreToFrameField(StandardFrameConstants::kContextOffset,
935 context_register());
936 }
937 { Comment cmnt(masm_, "[ Declarations");
938 VisitDeclarations(scope_->declarations());
939 }
940 }
941 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
942 VisitStatements(stmt->statements());
943 scope_ = saved_scope;
944 __ bind(nested_block.break_label());
945 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
946
947 // Pop block context if necessary.
948 if (stmt->block_scope() != NULL) {
949 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
950 // Update local stack frame context field.
951 StoreToFrameField(StandardFrameConstants::kContextOffset,
952 context_register());
953 }
954 }
955
956
VisitExpressionStatement(ExpressionStatement * stmt)957 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
958 Comment cmnt(masm_, "[ ExpressionStatement");
959 SetStatementPosition(stmt);
960 VisitForEffect(stmt->expression());
961 }
962
963
VisitEmptyStatement(EmptyStatement * stmt)964 void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
965 Comment cmnt(masm_, "[ EmptyStatement");
966 SetStatementPosition(stmt);
967 }
968
969
VisitIfStatement(IfStatement * stmt)970 void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
971 Comment cmnt(masm_, "[ IfStatement");
972 SetStatementPosition(stmt);
973 Label then_part, else_part, done;
974
975 if (stmt->HasElseStatement()) {
976 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
977 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
978 __ bind(&then_part);
979 Visit(stmt->then_statement());
980 __ jmp(&done);
981
982 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
983 __ bind(&else_part);
984 Visit(stmt->else_statement());
985 } else {
986 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
987 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
988 __ bind(&then_part);
989 Visit(stmt->then_statement());
990
991 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
992 }
993 __ bind(&done);
994 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS);
995 }
996
997
VisitContinueStatement(ContinueStatement * stmt)998 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
999 Comment cmnt(masm_, "[ ContinueStatement");
1000 SetStatementPosition(stmt);
1001 NestedStatement* current = nesting_stack_;
1002 int stack_depth = 0;
1003 int context_length = 0;
1004 // When continuing, we clobber the unpredictable value in the accumulator
1005 // with one that's safe for GC. If we hit an exit from the try block of
1006 // try...finally on our way out, we will unconditionally preserve the
1007 // accumulator on the stack.
1008 ClearAccumulator();
1009 while (!current->IsContinueTarget(stmt->target())) {
1010 current = current->Exit(&stack_depth, &context_length);
1011 }
1012 __ Drop(stack_depth);
1013 if (context_length > 0) {
1014 while (context_length > 0) {
1015 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1016 --context_length;
1017 }
1018 StoreToFrameField(StandardFrameConstants::kContextOffset,
1019 context_register());
1020 }
1021
1022 __ jmp(current->AsIteration()->continue_label());
1023 }
1024
1025
VisitBreakStatement(BreakStatement * stmt)1026 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1027 Comment cmnt(masm_, "[ BreakStatement");
1028 SetStatementPosition(stmt);
1029 NestedStatement* current = nesting_stack_;
1030 int stack_depth = 0;
1031 int context_length = 0;
1032 // When breaking, we clobber the unpredictable value in the accumulator
1033 // with one that's safe for GC. If we hit an exit from the try block of
1034 // try...finally on our way out, we will unconditionally preserve the
1035 // accumulator on the stack.
1036 ClearAccumulator();
1037 while (!current->IsBreakTarget(stmt->target())) {
1038 current = current->Exit(&stack_depth, &context_length);
1039 }
1040 __ Drop(stack_depth);
1041 if (context_length > 0) {
1042 while (context_length > 0) {
1043 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1044 --context_length;
1045 }
1046 StoreToFrameField(StandardFrameConstants::kContextOffset,
1047 context_register());
1048 }
1049
1050 __ jmp(current->AsBreakable()->break_label());
1051 }
1052
1053
VisitReturnStatement(ReturnStatement * stmt)1054 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1055 Comment cmnt(masm_, "[ ReturnStatement");
1056 SetStatementPosition(stmt);
1057 Expression* expr = stmt->expression();
1058 VisitForAccumulatorValue(expr);
1059
1060 // Exit all nested statements.
1061 NestedStatement* current = nesting_stack_;
1062 int stack_depth = 0;
1063 int context_length = 0;
1064 while (current != NULL) {
1065 current = current->Exit(&stack_depth, &context_length);
1066 }
1067 __ Drop(stack_depth);
1068
1069 EmitReturnSequence();
1070 }
1071
1072
VisitWithStatement(WithStatement * stmt)1073 void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
1074 Comment cmnt(masm_, "[ WithStatement");
1075 SetStatementPosition(stmt);
1076
1077 VisitForStackValue(stmt->expression());
1078 PushFunctionArgumentForContextAllocation();
1079 __ CallRuntime(Runtime::kPushWithContext, 2);
1080 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
1081
1082 { WithOrCatch body(this);
1083 Visit(stmt->statement());
1084 }
1085
1086 // Pop context.
1087 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1088 // Update local stack frame context field.
1089 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
1090 }
1091
1092
VisitDoWhileStatement(DoWhileStatement * stmt)1093 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1094 Comment cmnt(masm_, "[ DoWhileStatement");
1095 SetStatementPosition(stmt);
1096 Label body, stack_check;
1097
1098 Iteration loop_statement(this, stmt);
1099 increment_loop_depth();
1100
1101 __ bind(&body);
1102 Visit(stmt->body());
1103
1104 // Record the position of the do while condition and make sure it is
1105 // possible to break on the condition.
1106 __ bind(loop_statement.continue_label());
1107 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
1108 SetExpressionPosition(stmt->cond(), stmt->condition_position());
1109 VisitForControl(stmt->cond(),
1110 &stack_check,
1111 loop_statement.break_label(),
1112 &stack_check);
1113
1114 // Check stack before looping.
1115 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
1116 __ bind(&stack_check);
1117 EmitStackCheck(stmt, &body);
1118 __ jmp(&body);
1119
1120 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1121 __ bind(loop_statement.break_label());
1122 decrement_loop_depth();
1123 }
1124
1125
VisitWhileStatement(WhileStatement * stmt)1126 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1127 Comment cmnt(masm_, "[ WhileStatement");
1128 Label test, body;
1129
1130 Iteration loop_statement(this, stmt);
1131 increment_loop_depth();
1132
1133 // Emit the test at the bottom of the loop.
1134 __ jmp(&test);
1135
1136 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1137 __ bind(&body);
1138 Visit(stmt->body());
1139
1140 // Emit the statement position here as this is where the while
1141 // statement code starts.
1142 __ bind(loop_statement.continue_label());
1143 SetStatementPosition(stmt);
1144
1145 // Check stack before looping.
1146 EmitStackCheck(stmt, &body);
1147
1148 __ bind(&test);
1149 VisitForControl(stmt->cond(),
1150 &body,
1151 loop_statement.break_label(),
1152 loop_statement.break_label());
1153
1154 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1155 __ bind(loop_statement.break_label());
1156 decrement_loop_depth();
1157 }
1158
1159
VisitForStatement(ForStatement * stmt)1160 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
1161 Comment cmnt(masm_, "[ ForStatement");
1162 Label test, body;
1163
1164 Iteration loop_statement(this, stmt);
1165
1166 // Set statement position for a break slot before entering the for-body.
1167 SetStatementPosition(stmt);
1168
1169 if (stmt->init() != NULL) {
1170 Visit(stmt->init());
1171 }
1172
1173 increment_loop_depth();
1174 // Emit the test at the bottom of the loop (even if empty).
1175 __ jmp(&test);
1176
1177 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1178 __ bind(&body);
1179 Visit(stmt->body());
1180
1181 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
1182 __ bind(loop_statement.continue_label());
1183 if (stmt->next() != NULL) {
1184 Visit(stmt->next());
1185 }
1186
1187 // Emit the statement position here as this is where the for
1188 // statement code starts.
1189 SetStatementPosition(stmt);
1190
1191 // Check stack before looping.
1192 EmitStackCheck(stmt, &body);
1193
1194 __ bind(&test);
1195 if (stmt->cond() != NULL) {
1196 VisitForControl(stmt->cond(),
1197 &body,
1198 loop_statement.break_label(),
1199 loop_statement.break_label());
1200 } else {
1201 __ jmp(&body);
1202 }
1203
1204 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1205 __ bind(loop_statement.break_label());
1206 decrement_loop_depth();
1207 }
1208
1209
VisitTryCatchStatement(TryCatchStatement * stmt)1210 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1211 Comment cmnt(masm_, "[ TryCatchStatement");
1212 SetStatementPosition(stmt);
1213 // The try block adds a handler to the exception handler chain before
1214 // entering, and removes it again when exiting normally. If an exception
1215 // is thrown during execution of the try block, the handler is consumed
1216 // and control is passed to the catch block with the exception in the
1217 // result register.
1218
1219 Label try_entry, handler_entry, exit;
1220 __ jmp(&try_entry);
1221 __ bind(&handler_entry);
1222 handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
1223 // Exception handler code, the exception is in the result register.
1224 // Extend the context before executing the catch block.
1225 { Comment cmnt(masm_, "[ Extend catch context");
1226 __ Push(stmt->variable()->name());
1227 __ push(result_register());
1228 PushFunctionArgumentForContextAllocation();
1229 __ CallRuntime(Runtime::kPushCatchContext, 3);
1230 StoreToFrameField(StandardFrameConstants::kContextOffset,
1231 context_register());
1232 }
1233
1234 Scope* saved_scope = scope();
1235 scope_ = stmt->scope();
1236 ASSERT(scope_->declarations()->is_empty());
1237 { WithOrCatch catch_body(this);
1238 Visit(stmt->catch_block());
1239 }
1240 // Restore the context.
1241 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1242 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
1243 scope_ = saved_scope;
1244 __ jmp(&exit);
1245
1246 // Try block code. Sets up the exception handler chain.
1247 __ bind(&try_entry);
1248 __ PushTryHandler(StackHandler::CATCH, stmt->index());
1249 { TryCatch try_body(this);
1250 Visit(stmt->try_block());
1251 }
1252 __ PopTryHandler();
1253 __ bind(&exit);
1254 }
1255
1256
VisitTryFinallyStatement(TryFinallyStatement * stmt)1257 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1258 Comment cmnt(masm_, "[ TryFinallyStatement");
1259 SetStatementPosition(stmt);
1260 // Try finally is compiled by setting up a try-handler on the stack while
1261 // executing the try body, and removing it again afterwards.
1262 //
1263 // The try-finally construct can enter the finally block in three ways:
1264 // 1. By exiting the try-block normally. This removes the try-handler and
1265 // calls the finally block code before continuing.
1266 // 2. By exiting the try-block with a function-local control flow transfer
1267 // (break/continue/return). The site of the, e.g., break removes the
1268 // try handler and calls the finally block code before continuing
1269 // its outward control transfer.
1270 // 3. By exiting the try-block with a thrown exception.
1271 // This can happen in nested function calls. It traverses the try-handler
1272 // chain and consumes the try-handler entry before jumping to the
1273 // handler code. The handler code then calls the finally-block before
1274 // rethrowing the exception.
1275 //
1276 // The finally block must assume a return address on top of the stack
1277 // (or in the link register on ARM chips) and a value (return value or
1278 // exception) in the result register (rax/eax/r0), both of which must
1279 // be preserved. The return address isn't GC-safe, so it should be
1280 // cooked before GC.
1281 Label try_entry, handler_entry, finally_entry;
1282
1283 // Jump to try-handler setup and try-block code.
1284 __ jmp(&try_entry);
1285 __ bind(&handler_entry);
1286 handler_table()->set(stmt->index(), Smi::FromInt(handler_entry.pos()));
1287 // Exception handler code. This code is only executed when an exception
1288 // is thrown. The exception is in the result register, and must be
1289 // preserved by the finally block. Call the finally block and then
1290 // rethrow the exception if it returns.
1291 __ Call(&finally_entry);
1292 __ push(result_register());
1293 __ CallRuntime(Runtime::kReThrow, 1);
1294
1295 // Finally block implementation.
1296 __ bind(&finally_entry);
1297 EnterFinallyBlock();
1298 { Finally finally_body(this);
1299 Visit(stmt->finally_block());
1300 }
1301 ExitFinallyBlock(); // Return to the calling code.
1302
1303 // Set up try handler.
1304 __ bind(&try_entry);
1305 __ PushTryHandler(StackHandler::FINALLY, stmt->index());
1306 { TryFinally try_body(this, &finally_entry);
1307 Visit(stmt->try_block());
1308 }
1309 __ PopTryHandler();
1310 // Execute the finally block on the way out. Clobber the unpredictable
1311 // value in the result register with one that's safe for GC because the
1312 // finally block will unconditionally preserve the result register on the
1313 // stack.
1314 ClearAccumulator();
1315 __ Call(&finally_entry);
1316 }
1317
1318
VisitDebuggerStatement(DebuggerStatement * stmt)1319 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1320 #ifdef ENABLE_DEBUGGER_SUPPORT
1321 Comment cmnt(masm_, "[ DebuggerStatement");
1322 SetStatementPosition(stmt);
1323
1324 __ DebugBreak();
1325 // Ignore the return value.
1326 #endif
1327 }
1328
1329
VisitConditional(Conditional * expr)1330 void FullCodeGenerator::VisitConditional(Conditional* expr) {
1331 Comment cmnt(masm_, "[ Conditional");
1332 Label true_case, false_case, done;
1333 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
1334
1335 PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS);
1336 __ bind(&true_case);
1337 SetExpressionPosition(expr->then_expression(),
1338 expr->then_expression_position());
1339 if (context()->IsTest()) {
1340 const TestContext* for_test = TestContext::cast(context());
1341 VisitForControl(expr->then_expression(),
1342 for_test->true_label(),
1343 for_test->false_label(),
1344 NULL);
1345 } else {
1346 VisitInDuplicateContext(expr->then_expression());
1347 __ jmp(&done);
1348 }
1349
1350 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
1351 __ bind(&false_case);
1352 SetExpressionPosition(expr->else_expression(),
1353 expr->else_expression_position());
1354 VisitInDuplicateContext(expr->else_expression());
1355 // If control flow falls through Visit, merge it with true case here.
1356 if (!context()->IsTest()) {
1357 __ bind(&done);
1358 }
1359 }
1360
1361
VisitLiteral(Literal * expr)1362 void FullCodeGenerator::VisitLiteral(Literal* expr) {
1363 Comment cmnt(masm_, "[ Literal");
1364 context()->Plug(expr->handle());
1365 }
1366
1367
VisitFunctionLiteral(FunctionLiteral * expr)1368 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1369 Comment cmnt(masm_, "[ FunctionLiteral");
1370
1371 // Build the function boilerplate and instantiate it.
1372 Handle<SharedFunctionInfo> function_info =
1373 Compiler::BuildFunctionInfo(expr, script());
1374 if (function_info.is_null()) {
1375 SetStackOverflow();
1376 return;
1377 }
1378 EmitNewClosure(function_info, expr->pretenure());
1379 }
1380
1381
VisitSharedFunctionInfoLiteral(SharedFunctionInfoLiteral * expr)1382 void FullCodeGenerator::VisitSharedFunctionInfoLiteral(
1383 SharedFunctionInfoLiteral* expr) {
1384 Comment cmnt(masm_, "[ SharedFunctionInfoLiteral");
1385 EmitNewClosure(expr->shared_function_info(), false);
1386 }
1387
1388
VisitThrow(Throw * expr)1389 void FullCodeGenerator::VisitThrow(Throw* expr) {
1390 Comment cmnt(masm_, "[ Throw");
1391 VisitForStackValue(expr->exception());
1392 __ CallRuntime(Runtime::kThrow, 1);
1393 // Never returns here.
1394 }
1395
1396
Exit(int * stack_depth,int * context_length)1397 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryCatch::Exit(
1398 int* stack_depth,
1399 int* context_length) {
1400 // The macros used here must preserve the result register.
1401 __ Drop(*stack_depth);
1402 __ PopTryHandler();
1403 *stack_depth = 0;
1404 return previous_;
1405 }
1406
1407
TryLiteralCompare(CompareOperation * expr)1408 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
1409 Expression* sub_expr;
1410 Handle<String> check;
1411 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
1412 EmitLiteralCompareTypeof(expr, sub_expr, check);
1413 return true;
1414 }
1415
1416 if (expr->IsLiteralCompareUndefined(&sub_expr)) {
1417 EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue);
1418 return true;
1419 }
1420
1421 if (expr->IsLiteralCompareNull(&sub_expr)) {
1422 EmitLiteralCompareNil(expr, sub_expr, kNullValue);
1423 return true;
1424 }
1425
1426 return false;
1427 }
1428
1429
1430 #undef __
1431
1432
1433 } } // namespace v8::internal
1434