Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(160)

Side by Side Diff: src/full-codegen.cc

Issue 1248443003: Move Full-codegen into its own folder. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: rename define Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/full-codegen.h ('k') | src/full-codegen/OWNERS » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/v8.h"
6
7 #include "src/ast.h"
8 #include "src/ast-numbering.h"
9 #include "src/code-factory.h"
10 #include "src/codegen.h"
11 #include "src/compiler.h"
12 #include "src/debug.h"
13 #include "src/full-codegen.h"
14 #include "src/liveedit.h"
15 #include "src/macro-assembler.h"
16 #include "src/prettyprinter.h"
17 #include "src/scopeinfo.h"
18 #include "src/scopes.h"
19 #include "src/snapshot/snapshot.h"
20
21 namespace v8 {
22 namespace internal {
23
24 #define __ ACCESS_MASM(masm())
25
26 bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
27 Isolate* isolate = info->isolate();
28
29 TimerEventScope<TimerEventCompileFullCode> timer(info->isolate());
30
31 // Ensure that the feedback vector is large enough.
32 info->EnsureFeedbackVector();
33
34 Handle<Script> script = info->script();
35 if (!script->IsUndefined() && !script->source()->IsUndefined()) {
36 int len = String::cast(script->source())->length();
37 isolate->counters()->total_full_codegen_source_size()->Increment(len);
38 }
39 CodeGenerator::MakeCodePrologue(info, "full");
40 const int kInitialBufferSize = 4 * KB;
41 MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize);
42 if (info->will_serialize()) masm.enable_serializer();
43
44 LOG_CODE_EVENT(isolate,
45 CodeStartLinePosInfoRecordEvent(masm.positions_recorder()));
46
47 FullCodeGenerator cgen(&masm, info);
48 cgen.Generate();
49 if (cgen.HasStackOverflow()) {
50 DCHECK(!isolate->has_pending_exception());
51 return false;
52 }
53 unsigned table_offset = cgen.EmitBackEdgeTable();
54
55 Code::Flags flags = Code::ComputeFlags(Code::FUNCTION);
56 Handle<Code> code = CodeGenerator::MakeCodeEpilogue(&masm, flags, info);
57 cgen.PopulateDeoptimizationData(code);
58 cgen.PopulateTypeFeedbackInfo(code);
59 cgen.PopulateHandlerTable(code);
60 code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
61 code->set_has_reloc_info_for_serialization(info->will_serialize());
62 code->set_compiled_optimizable(info->IsOptimizable());
63 code->set_allow_osr_at_loop_nesting_level(0);
64 code->set_profiler_ticks(0);
65 code->set_back_edge_table_offset(table_offset);
66 CodeGenerator::PrintCode(code, info);
67 info->SetCode(code);
68 void* line_info = masm.positions_recorder()->DetachJITHandlerData();
69 LOG_CODE_EVENT(isolate, CodeEndLinePosInfoRecordEvent(*code, line_info));
70
71 #ifdef DEBUG
72 // Check that no context-specific object has been embedded.
73 code->VerifyEmbeddedObjects(Code::kNoContextSpecificPointers);
74 #endif // DEBUG
75 return true;
76 }
77
78
79 unsigned FullCodeGenerator::EmitBackEdgeTable() {
80 // The back edge table consists of a length (in number of entries)
81 // field, and then a sequence of entries. Each entry is a pair of AST id
82 // and code-relative pc offset.
83 masm()->Align(kPointerSize);
84 unsigned offset = masm()->pc_offset();
85 unsigned length = back_edges_.length();
86 __ dd(length);
87 for (unsigned i = 0; i < length; ++i) {
88 __ dd(back_edges_[i].id.ToInt());
89 __ dd(back_edges_[i].pc);
90 __ dd(back_edges_[i].loop_depth);
91 }
92 return offset;
93 }
94
95
96 void FullCodeGenerator::EnsureSlotContainsAllocationSite(
97 FeedbackVectorSlot slot) {
98 Handle<TypeFeedbackVector> vector = FeedbackVector();
99 if (!vector->Get(slot)->IsAllocationSite()) {
100 Handle<AllocationSite> allocation_site =
101 isolate()->factory()->NewAllocationSite();
102 vector->Set(slot, *allocation_site);
103 }
104 }
105
106
107 void FullCodeGenerator::EnsureSlotContainsAllocationSite(
108 FeedbackVectorICSlot slot) {
109 Handle<TypeFeedbackVector> vector = FeedbackVector();
110 if (!vector->Get(slot)->IsAllocationSite()) {
111 Handle<AllocationSite> allocation_site =
112 isolate()->factory()->NewAllocationSite();
113 vector->Set(slot, *allocation_site);
114 }
115 }
116
117
118 void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
119 // Fill in the deoptimization information.
120 DCHECK(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty());
121 if (!info_->HasDeoptimizationSupport()) return;
122 int length = bailout_entries_.length();
123 Handle<DeoptimizationOutputData> data =
124 DeoptimizationOutputData::New(isolate(), length, TENURED);
125 for (int i = 0; i < length; i++) {
126 data->SetAstId(i, bailout_entries_[i].id);
127 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state));
128 }
129 code->set_deoptimization_data(*data);
130 }
131
132
133 void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) {
134 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo();
135 info->set_ic_total_count(ic_total_count_);
136 DCHECK(!isolate()->heap()->InNewSpace(*info));
137 code->set_type_feedback_info(*info);
138 }
139
140
141 void FullCodeGenerator::PopulateHandlerTable(Handle<Code> code) {
142 int handler_table_size = static_cast<int>(handler_table_.size());
143 Handle<HandlerTable> table =
144 Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
145 HandlerTable::LengthForRange(handler_table_size), TENURED));
146 for (int i = 0; i < handler_table_size; ++i) {
147 HandlerTable::CatchPrediction prediction =
148 handler_table_[i].try_catch_depth > 0 ? HandlerTable::CAUGHT
149 : HandlerTable::UNCAUGHT;
150 table->SetRangeStart(i, handler_table_[i].range_start);
151 table->SetRangeEnd(i, handler_table_[i].range_end);
152 table->SetRangeHandler(i, handler_table_[i].handler_offset, prediction);
153 table->SetRangeDepth(i, handler_table_[i].stack_depth);
154 }
155 code->set_handler_table(*table);
156 }
157
158
159 int FullCodeGenerator::NewHandlerTableEntry() {
160 int index = static_cast<int>(handler_table_.size());
161 HandlerTableEntry entry = {0, 0, 0, 0, 0};
162 handler_table_.push_back(entry);
163 return index;
164 }
165
166
167 bool FullCodeGenerator::MustCreateObjectLiteralWithRuntime(
168 ObjectLiteral* expr) const {
169 int literal_flags = expr->ComputeFlags();
170 // FastCloneShallowObjectStub doesn't copy elements, and object literals don't
171 // support copy-on-write (COW) elements for now.
172 // TODO(mvstanton): make object literals support COW elements.
173 return masm()->serializer_enabled() ||
174 literal_flags != ObjectLiteral::kShallowProperties ||
175 literal_flags != ObjectLiteral::kFastElements ||
176 expr->properties_count() >
177 FastCloneShallowObjectStub::kMaximumClonedProperties;
178 }
179
180
181 bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime(
182 ArrayLiteral* expr) const {
183 // TODO(rossberg): Teach strong mode to FastCloneShallowArrayStub.
184 return expr->depth() > 1 || expr->is_strong() ||
185 expr->values()->length() > JSObject::kInitialMaxFastElementArray;
186 }
187
188
189 void FullCodeGenerator::Initialize() {
190 InitializeAstVisitor(info_->isolate(), info_->zone());
191 // The generation of debug code must match between the snapshot code and the
192 // code that is generated later. This is assumed by the debugger when it is
193 // calculating PC offsets after generating a debug version of code. Therefore
194 // we disable the production of debug code in the full compiler if we are
195 // either generating a snapshot or we booted from a snapshot.
196 generate_debug_code_ = FLAG_debug_code && !masm_->serializer_enabled() &&
197 !info_->isolate()->snapshot_available();
198 masm_->set_emit_debug_code(generate_debug_code_);
199 masm_->set_predictable_code_size(true);
200 }
201
202
203 void FullCodeGenerator::PrepareForBailout(Expression* node, State state) {
204 PrepareForBailoutForId(node->id(), state);
205 }
206
207
208 void FullCodeGenerator::CallLoadIC(TypeofMode typeof_mode,
209 LanguageMode language_mode,
210 TypeFeedbackId id) {
211 Handle<Code> ic =
212 CodeFactory::LoadIC(isolate(), typeof_mode, language_mode).code();
213 CallIC(ic, id);
214 }
215
216
217 void FullCodeGenerator::CallStoreIC(TypeFeedbackId id) {
218 Handle<Code> ic = CodeFactory::StoreIC(isolate(), language_mode()).code();
219 CallIC(ic, id);
220 }
221
222
223 void FullCodeGenerator::RecordJSReturnSite(Call* call) {
224 // We record the offset of the function return so we can rebuild the frame
225 // if the function was inlined, i.e., this is the return address in the
226 // inlined function's frame.
227 //
228 // The state is ignored. We defensively set it to TOS_REG, which is the
229 // real state of the unoptimized code at the return site.
230 PrepareForBailoutForId(call->ReturnId(), TOS_REG);
231 #ifdef DEBUG
232 // In debug builds, mark the return so we can verify that this function
233 // was called.
234 DCHECK(!call->return_is_recorded_);
235 call->return_is_recorded_ = true;
236 #endif
237 }
238
239
240 void FullCodeGenerator::PrepareForBailoutForId(BailoutId id, State state) {
241 // There's no need to prepare this code for bailouts from already optimized
242 // code or code that can't be optimized.
243 if (!info_->HasDeoptimizationSupport()) return;
244 unsigned pc_and_state =
245 StateField::encode(state) | PcField::encode(masm_->pc_offset());
246 DCHECK(Smi::IsValid(pc_and_state));
247 #ifdef DEBUG
248 for (int i = 0; i < bailout_entries_.length(); ++i) {
249 DCHECK(bailout_entries_[i].id != id);
250 }
251 #endif
252 BailoutEntry entry = { id, pc_and_state };
253 bailout_entries_.Add(entry, zone());
254 }
255
256
257 void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) {
258 // The pc offset does not need to be encoded and packed together with a state.
259 DCHECK(masm_->pc_offset() > 0);
260 DCHECK(loop_depth() > 0);
261 uint8_t depth = Min(loop_depth(), Code::kMaxLoopNestingMarker);
262 BackEdgeEntry entry =
263 { ast_id, static_cast<unsigned>(masm_->pc_offset()), depth };
264 back_edges_.Add(entry, zone());
265 }
266
267
268 bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
269 // Inline smi case inside loops, but not division and modulo which
270 // are too complicated and take up too much space.
271 if (op == Token::DIV ||op == Token::MOD) return false;
272 if (FLAG_always_inline_smi_code) return true;
273 return loop_depth_ > 0;
274 }
275
276
277 void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
278 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
279 }
280
281
282 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
283 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
284 codegen()->GetVar(result_register(), var);
285 }
286
287
288 void FullCodeGenerator::TestContext::Plug(Variable* var) const {
289 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
290 // For simplicity we always test the accumulator register.
291 codegen()->GetVar(result_register(), var);
292 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
293 codegen()->DoTest(this);
294 }
295
296
297 void FullCodeGenerator::EffectContext::Plug(Register reg) const {
298 }
299
300
301 void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
302 __ Move(result_register(), reg);
303 }
304
305
306 void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
307 __ Push(reg);
308 }
309
310
311 void FullCodeGenerator::TestContext::Plug(Register reg) const {
312 // For simplicity we always test the accumulator register.
313 __ Move(result_register(), reg);
314 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
315 codegen()->DoTest(this);
316 }
317
318
319 void FullCodeGenerator::EffectContext::Plug(bool flag) const {}
320
321
322 void FullCodeGenerator::EffectContext::PlugTOS() const {
323 __ Drop(1);
324 }
325
326
327 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
328 __ Pop(result_register());
329 }
330
331
332 void FullCodeGenerator::StackValueContext::PlugTOS() const {
333 }
334
335
336 void FullCodeGenerator::TestContext::PlugTOS() const {
337 // For simplicity we always test the accumulator register.
338 __ Pop(result_register());
339 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
340 codegen()->DoTest(this);
341 }
342
343
344 void FullCodeGenerator::EffectContext::PrepareTest(
345 Label* materialize_true,
346 Label* materialize_false,
347 Label** if_true,
348 Label** if_false,
349 Label** fall_through) const {
350 // In an effect context, the true and the false case branch to the
351 // same label.
352 *if_true = *if_false = *fall_through = materialize_true;
353 }
354
355
356 void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
357 Label* materialize_true,
358 Label* materialize_false,
359 Label** if_true,
360 Label** if_false,
361 Label** fall_through) const {
362 *if_true = *fall_through = materialize_true;
363 *if_false = materialize_false;
364 }
365
366
367 void FullCodeGenerator::StackValueContext::PrepareTest(
368 Label* materialize_true,
369 Label* materialize_false,
370 Label** if_true,
371 Label** if_false,
372 Label** fall_through) const {
373 *if_true = *fall_through = materialize_true;
374 *if_false = materialize_false;
375 }
376
377
378 void FullCodeGenerator::TestContext::PrepareTest(
379 Label* materialize_true,
380 Label* materialize_false,
381 Label** if_true,
382 Label** if_false,
383 Label** fall_through) const {
384 *if_true = true_label_;
385 *if_false = false_label_;
386 *fall_through = fall_through_;
387 }
388
389
390 void FullCodeGenerator::DoTest(const TestContext* context) {
391 DoTest(context->condition(),
392 context->true_label(),
393 context->false_label(),
394 context->fall_through());
395 }
396
397
398 void FullCodeGenerator::VisitDeclarations(
399 ZoneList<Declaration*>* declarations) {
400 ZoneList<Handle<Object> >* saved_globals = globals_;
401 ZoneList<Handle<Object> > inner_globals(10, zone());
402 globals_ = &inner_globals;
403
404 AstVisitor::VisitDeclarations(declarations);
405
406 if (!globals_->is_empty()) {
407 // Invoke the platform-dependent code generator to do the actual
408 // declaration of the global functions and variables.
409 Handle<FixedArray> array =
410 isolate()->factory()->NewFixedArray(globals_->length(), TENURED);
411 for (int i = 0; i < globals_->length(); ++i)
412 array->set(i, *globals_->at(i));
413 DeclareGlobals(array);
414 }
415
416 globals_ = saved_globals;
417 }
418
419
420 void FullCodeGenerator::VisitImportDeclaration(ImportDeclaration* declaration) {
421 VariableProxy* proxy = declaration->proxy();
422 Variable* variable = proxy->var();
423 switch (variable->location()) {
424 case VariableLocation::GLOBAL:
425 case VariableLocation::UNALLOCATED:
426 // TODO(rossberg)
427 break;
428
429 case VariableLocation::CONTEXT: {
430 Comment cmnt(masm_, "[ ImportDeclaration");
431 EmitDebugCheckDeclarationContext(variable);
432 // TODO(rossberg)
433 break;
434 }
435
436 case VariableLocation::PARAMETER:
437 case VariableLocation::LOCAL:
438 case VariableLocation::LOOKUP:
439 UNREACHABLE();
440 }
441 }
442
443
444 void FullCodeGenerator::VisitExportDeclaration(ExportDeclaration* declaration) {
445 // TODO(rossberg)
446 }
447
448
449 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
450 Comment cmnt(masm_, "[ VariableProxy");
451 EmitVariableLoad(expr);
452 }
453
454
455 int FullCodeGenerator::DeclareGlobalsFlags() {
456 DCHECK(DeclareGlobalsLanguageMode::is_valid(language_mode()));
457 return DeclareGlobalsEvalFlag::encode(is_eval()) |
458 DeclareGlobalsNativeFlag::encode(is_native()) |
459 DeclareGlobalsLanguageMode::encode(language_mode());
460 }
461
462
463 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
464 // Load the arguments on the stack and call the stub.
465 SubStringStub stub(isolate());
466 ZoneList<Expression*>* args = expr->arguments();
467 DCHECK(args->length() == 3);
468 VisitForStackValue(args->at(0));
469 VisitForStackValue(args->at(1));
470 VisitForStackValue(args->at(2));
471 __ CallStub(&stub);
472 context()->Plug(result_register());
473 }
474
475
476 void FullCodeGenerator::EmitRegExpExec(CallRuntime* expr) {
477 // Load the arguments on the stack and call the stub.
478 RegExpExecStub stub(isolate());
479 ZoneList<Expression*>* args = expr->arguments();
480 DCHECK(args->length() == 4);
481 VisitForStackValue(args->at(0));
482 VisitForStackValue(args->at(1));
483 VisitForStackValue(args->at(2));
484 VisitForStackValue(args->at(3));
485 __ CallStub(&stub);
486 context()->Plug(result_register());
487 }
488
489
490 void FullCodeGenerator::EmitMathPow(CallRuntime* expr) {
491 // Load the arguments on the stack and call the runtime function.
492 ZoneList<Expression*>* args = expr->arguments();
493 DCHECK(args->length() == 2);
494 VisitForStackValue(args->at(0));
495 VisitForStackValue(args->at(1));
496
497 MathPowStub stub(isolate(), MathPowStub::ON_STACK);
498 __ CallStub(&stub);
499 context()->Plug(result_register());
500 }
501
502
503 void FullCodeGenerator::EmitStringCompare(CallRuntime* expr) {
504 ZoneList<Expression*>* args = expr->arguments();
505 DCHECK_EQ(2, args->length());
506
507 VisitForStackValue(args->at(0));
508 VisitForStackValue(args->at(1));
509
510 StringCompareStub stub(isolate());
511 __ CallStub(&stub);
512 context()->Plug(result_register());
513 }
514
515
516 bool RecordStatementPosition(MacroAssembler* masm, int pos) {
517 if (pos == RelocInfo::kNoPosition) return false;
518 masm->positions_recorder()->RecordStatementPosition(pos);
519 masm->positions_recorder()->RecordPosition(pos);
520 return masm->positions_recorder()->WriteRecordedPositions();
521 }
522
523
524 bool RecordPosition(MacroAssembler* masm, int pos) {
525 if (pos == RelocInfo::kNoPosition) return false;
526 masm->positions_recorder()->RecordPosition(pos);
527 return masm->positions_recorder()->WriteRecordedPositions();
528 }
529
530
531 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
532 RecordPosition(masm_, fun->start_position());
533 }
534
535
536 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
537 RecordStatementPosition(masm_, fun->end_position() - 1);
538 if (info_->is_debug()) {
539 // Always emit a debug break slot before a return.
540 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
541 }
542 }
543
544
545 void FullCodeGenerator::SetStatementPosition(
546 Statement* stmt, FullCodeGenerator::InsertBreak insert_break) {
547 if (stmt->position() == RelocInfo::kNoPosition) return;
548 bool recorded = RecordStatementPosition(masm_, stmt->position());
549 if (recorded && insert_break == INSERT_BREAK && info_->is_debug() &&
550 !stmt->IsDebuggerStatement()) {
551 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
552 }
553 }
554
555
556 void FullCodeGenerator::SetExpressionPosition(
557 Expression* expr, FullCodeGenerator::InsertBreak insert_break) {
558 if (expr->position() == RelocInfo::kNoPosition) return;
559 bool recorded = RecordPosition(masm_, expr->position());
560 if (recorded && insert_break == INSERT_BREAK && info_->is_debug()) {
561 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
562 }
563 }
564
565
566 void FullCodeGenerator::SetExpressionAsStatementPosition(Expression* expr) {
567 if (expr->position() == RelocInfo::kNoPosition) return;
568 bool recorded = RecordStatementPosition(masm_, expr->position());
569 if (recorded && info_->is_debug()) {
570 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
571 }
572 }
573
574
575 void FullCodeGenerator::SetCallPosition(Expression* expr, int argc) {
576 if (expr->position() == RelocInfo::kNoPosition) return;
577 RecordPosition(masm_, expr->position());
578 if (info_->is_debug()) {
579 // Always emit a debug break slot before a call.
580 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_CALL,
581 argc);
582 }
583 }
584
585
586 void FullCodeGenerator::SetConstructCallPosition(Expression* expr) {
587 if (expr->position() == RelocInfo::kNoPosition) return;
588 RecordPosition(masm_, expr->position());
589 if (info_->is_debug()) {
590 // Always emit a debug break slot before a construct call.
591 DebugCodegen::GenerateSlot(masm_,
592 RelocInfo::DEBUG_BREAK_SLOT_AT_CONSTRUCT_CALL);
593 }
594 }
595
596
597 void FullCodeGenerator::VisitSuperPropertyReference(
598 SuperPropertyReference* super) {
599 __ CallRuntime(Runtime::kThrowUnsupportedSuperError, 0);
600 }
601
602
603 void FullCodeGenerator::VisitSuperCallReference(SuperCallReference* super) {
604 __ CallRuntime(Runtime::kThrowUnsupportedSuperError, 0);
605 }
606
607
608 void FullCodeGenerator::EmitGeneratorNext(CallRuntime* expr) {
609 ZoneList<Expression*>* args = expr->arguments();
610 DCHECK(args->length() == 2);
611 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::NEXT);
612 }
613
614
615 void FullCodeGenerator::EmitGeneratorThrow(CallRuntime* expr) {
616 ZoneList<Expression*>* args = expr->arguments();
617 DCHECK(args->length() == 2);
618 EmitGeneratorResume(args->at(0), args->at(1), JSGeneratorObject::THROW);
619 }
620
621
622 void FullCodeGenerator::EmitDebugBreakInOptimizedCode(CallRuntime* expr) {
623 context()->Plug(handle(Smi::FromInt(0), isolate()));
624 }
625
626
627 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
628 switch (expr->op()) {
629 case Token::COMMA:
630 return VisitComma(expr);
631 case Token::OR:
632 case Token::AND:
633 return VisitLogicalExpression(expr);
634 default:
635 return VisitArithmeticExpression(expr);
636 }
637 }
638
639
640 void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
641 if (context()->IsEffect()) {
642 VisitForEffect(expr);
643 } else if (context()->IsAccumulatorValue()) {
644 VisitForAccumulatorValue(expr);
645 } else if (context()->IsStackValue()) {
646 VisitForStackValue(expr);
647 } else if (context()->IsTest()) {
648 const TestContext* test = TestContext::cast(context());
649 VisitForControl(expr, test->true_label(), test->false_label(),
650 test->fall_through());
651 }
652 }
653
654
655 void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
656 Comment cmnt(masm_, "[ Comma");
657 VisitForEffect(expr->left());
658 VisitInDuplicateContext(expr->right());
659 }
660
661
662 void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
663 bool is_logical_and = expr->op() == Token::AND;
664 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR");
665 Expression* left = expr->left();
666 Expression* right = expr->right();
667 BailoutId right_id = expr->RightId();
668 Label done;
669
670 if (context()->IsTest()) {
671 Label eval_right;
672 const TestContext* test = TestContext::cast(context());
673 if (is_logical_and) {
674 VisitForControl(left, &eval_right, test->false_label(), &eval_right);
675 } else {
676 VisitForControl(left, test->true_label(), &eval_right, &eval_right);
677 }
678 PrepareForBailoutForId(right_id, NO_REGISTERS);
679 __ bind(&eval_right);
680
681 } else if (context()->IsAccumulatorValue()) {
682 VisitForAccumulatorValue(left);
683 // We want the value in the accumulator for the test, and on the stack in
684 // case we need it.
685 __ Push(result_register());
686 Label discard, restore;
687 if (is_logical_and) {
688 DoTest(left, &discard, &restore, &restore);
689 } else {
690 DoTest(left, &restore, &discard, &restore);
691 }
692 __ bind(&restore);
693 __ Pop(result_register());
694 __ jmp(&done);
695 __ bind(&discard);
696 __ Drop(1);
697 PrepareForBailoutForId(right_id, NO_REGISTERS);
698
699 } else if (context()->IsStackValue()) {
700 VisitForAccumulatorValue(left);
701 // We want the value in the accumulator for the test, and on the stack in
702 // case we need it.
703 __ Push(result_register());
704 Label discard;
705 if (is_logical_and) {
706 DoTest(left, &discard, &done, &discard);
707 } else {
708 DoTest(left, &done, &discard, &discard);
709 }
710 __ bind(&discard);
711 __ Drop(1);
712 PrepareForBailoutForId(right_id, NO_REGISTERS);
713
714 } else {
715 DCHECK(context()->IsEffect());
716 Label eval_right;
717 if (is_logical_and) {
718 VisitForControl(left, &eval_right, &done, &eval_right);
719 } else {
720 VisitForControl(left, &done, &eval_right, &eval_right);
721 }
722 PrepareForBailoutForId(right_id, NO_REGISTERS);
723 __ bind(&eval_right);
724 }
725
726 VisitInDuplicateContext(right);
727 __ bind(&done);
728 }
729
730
731 void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
732 Token::Value op = expr->op();
733 Comment cmnt(masm_, "[ ArithmeticExpression");
734 Expression* left = expr->left();
735 Expression* right = expr->right();
736
737 VisitForStackValue(left);
738 VisitForAccumulatorValue(right);
739
740 SetExpressionPosition(expr);
741 if (ShouldInlineSmiCase(op)) {
742 EmitInlineSmiBinaryOp(expr, op, left, right);
743 } else {
744 EmitBinaryOp(expr, op);
745 }
746 }
747
748
749 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
750 VariableProxy* proxy = expr->AsVariableProxy();
751 DCHECK(!context()->IsEffect());
752 DCHECK(!context()->IsTest());
753
754 if (proxy != NULL && (proxy->var()->IsUnallocatedOrGlobalSlot() ||
755 proxy->var()->IsLookupSlot())) {
756 EmitVariableLoad(proxy, INSIDE_TYPEOF);
757 PrepareForBailout(proxy, TOS_REG);
758 } else {
759 // This expression cannot throw a reference error at the top level.
760 VisitInDuplicateContext(expr);
761 }
762 }
763
764
765 void FullCodeGenerator::VisitBlock(Block* stmt) {
766 Comment cmnt(masm_, "[ Block");
767 NestedBlock nested_block(this, stmt);
768 SetStatementPosition(stmt);
769
770 {
771 EnterBlockScopeIfNeeded block_scope_state(
772 this, stmt->scope(), stmt->EntryId(), stmt->DeclsId(), stmt->ExitId());
773 VisitStatements(stmt->statements());
774 __ bind(nested_block.break_label());
775 }
776 }
777
778
779 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
780 Comment cmnt(masm_, "[ ExpressionStatement");
781 SetStatementPosition(stmt);
782 VisitForEffect(stmt->expression());
783 }
784
785
786 void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
787 Comment cmnt(masm_, "[ EmptyStatement");
788 SetStatementPosition(stmt);
789 }
790
791
792 void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
793 Comment cmnt(masm_, "[ IfStatement");
794 SetStatementPosition(stmt);
795 Label then_part, else_part, done;
796
797 if (stmt->HasElseStatement()) {
798 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
799 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
800 __ bind(&then_part);
801 Visit(stmt->then_statement());
802 __ jmp(&done);
803
804 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
805 __ bind(&else_part);
806 Visit(stmt->else_statement());
807 } else {
808 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
809 PrepareForBailoutForId(stmt->ThenId(), NO_REGISTERS);
810 __ bind(&then_part);
811 Visit(stmt->then_statement());
812
813 PrepareForBailoutForId(stmt->ElseId(), NO_REGISTERS);
814 }
815 __ bind(&done);
816 PrepareForBailoutForId(stmt->IfId(), NO_REGISTERS);
817 }
818
819
820 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
821 Comment cmnt(masm_, "[ ContinueStatement");
822 SetStatementPosition(stmt);
823 NestedStatement* current = nesting_stack_;
824 int stack_depth = 0;
825 int context_length = 0;
826 // When continuing, we clobber the unpredictable value in the accumulator
827 // with one that's safe for GC. If we hit an exit from the try block of
828 // try...finally on our way out, we will unconditionally preserve the
829 // accumulator on the stack.
830 ClearAccumulator();
831 while (!current->IsContinueTarget(stmt->target())) {
832 current = current->Exit(&stack_depth, &context_length);
833 }
834 __ Drop(stack_depth);
835 if (context_length > 0) {
836 while (context_length > 0) {
837 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
838 --context_length;
839 }
840 StoreToFrameField(StandardFrameConstants::kContextOffset,
841 context_register());
842 }
843
844 __ jmp(current->AsIteration()->continue_label());
845 }
846
847
848 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
849 Comment cmnt(masm_, "[ BreakStatement");
850 SetStatementPosition(stmt);
851 NestedStatement* current = nesting_stack_;
852 int stack_depth = 0;
853 int context_length = 0;
854 // When breaking, we clobber the unpredictable value in the accumulator
855 // with one that's safe for GC. If we hit an exit from the try block of
856 // try...finally on our way out, we will unconditionally preserve the
857 // accumulator on the stack.
858 ClearAccumulator();
859 while (!current->IsBreakTarget(stmt->target())) {
860 current = current->Exit(&stack_depth, &context_length);
861 }
862 __ Drop(stack_depth);
863 if (context_length > 0) {
864 while (context_length > 0) {
865 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
866 --context_length;
867 }
868 StoreToFrameField(StandardFrameConstants::kContextOffset,
869 context_register());
870 }
871
872 __ jmp(current->AsBreakable()->break_label());
873 }
874
875
876 void FullCodeGenerator::EmitUnwindBeforeReturn() {
877 NestedStatement* current = nesting_stack_;
878 int stack_depth = 0;
879 int context_length = 0;
880 while (current != NULL) {
881 current = current->Exit(&stack_depth, &context_length);
882 }
883 __ Drop(stack_depth);
884 }
885
886
887 void FullCodeGenerator::EmitPropertyKey(ObjectLiteralProperty* property,
888 BailoutId bailout_id) {
889 VisitForStackValue(property->key());
890 __ InvokeBuiltin(Builtins::TO_NAME, CALL_FUNCTION);
891 PrepareForBailoutForId(bailout_id, NO_REGISTERS);
892 __ Push(result_register());
893 }
894
895
896 void FullCodeGenerator::EmitLoadSuperConstructor(SuperCallReference* ref) {
897 VisitForStackValue(ref->this_function_var());
898 __ CallRuntime(Runtime::kGetPrototype, 1);
899 }
900
901
902 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
903 Comment cmnt(masm_, "[ ReturnStatement");
904 SetStatementPosition(stmt);
905 Expression* expr = stmt->expression();
906 VisitForAccumulatorValue(expr);
907 EmitUnwindBeforeReturn();
908 EmitReturnSequence();
909 }
910
911
912 void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
913 Comment cmnt(masm_, "[ WithStatement");
914 SetStatementPosition(stmt);
915
916 VisitForStackValue(stmt->expression());
917 PushFunctionArgumentForContextAllocation();
918 __ CallRuntime(Runtime::kPushWithContext, 2);
919 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
920 PrepareForBailoutForId(stmt->EntryId(), NO_REGISTERS);
921
922 Scope* saved_scope = scope();
923 scope_ = stmt->scope();
924 { WithOrCatch body(this);
925 Visit(stmt->statement());
926 }
927 scope_ = saved_scope;
928
929 // Pop context.
930 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
931 // Update local stack frame context field.
932 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
933 }
934
935
936 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
937 Comment cmnt(masm_, "[ DoWhileStatement");
938 // Do not insert break location as we do that below.
939 SetStatementPosition(stmt, SKIP_BREAK);
940
941 Label body, book_keeping;
942
943 Iteration loop_statement(this, stmt);
944 increment_loop_depth();
945
946 __ bind(&body);
947 Visit(stmt->body());
948
949 // Record the position of the do while condition and make sure it is
950 // possible to break on the condition.
951 __ bind(loop_statement.continue_label());
952 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
953
954 // Here is the actual 'while' keyword.
955 SetExpressionAsStatementPosition(stmt->cond());
956 VisitForControl(stmt->cond(),
957 &book_keeping,
958 loop_statement.break_label(),
959 &book_keeping);
960
961 // Check stack before looping.
962 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
963 __ bind(&book_keeping);
964 EmitBackEdgeBookkeeping(stmt, &body);
965 __ jmp(&body);
966
967 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
968 __ bind(loop_statement.break_label());
969 decrement_loop_depth();
970 }
971
972
973 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
974 Comment cmnt(masm_, "[ WhileStatement");
975 Label loop, body;
976
977 Iteration loop_statement(this, stmt);
978 increment_loop_depth();
979
980 __ bind(&loop);
981
982 SetExpressionAsStatementPosition(stmt->cond());
983 VisitForControl(stmt->cond(),
984 &body,
985 loop_statement.break_label(),
986 &body);
987
988 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
989 __ bind(&body);
990 Visit(stmt->body());
991
992 __ bind(loop_statement.continue_label());
993
994 // Check stack before looping.
995 EmitBackEdgeBookkeeping(stmt, &loop);
996 __ jmp(&loop);
997
998 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
999 __ bind(loop_statement.break_label());
1000 decrement_loop_depth();
1001 }
1002
1003
1004 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
1005 Comment cmnt(masm_, "[ ForStatement");
1006 // Do not insert break location as we do it below.
1007 SetStatementPosition(stmt, SKIP_BREAK);
1008
1009 Label test, body;
1010
1011 Iteration loop_statement(this, stmt);
1012
1013 if (stmt->init() != NULL) {
1014 SetStatementPosition(stmt->init());
1015 Visit(stmt->init());
1016 }
1017
1018 increment_loop_depth();
1019 // Emit the test at the bottom of the loop (even if empty).
1020 __ jmp(&test);
1021
1022 PrepareForBailoutForId(stmt->BodyId(), NO_REGISTERS);
1023 __ bind(&body);
1024 Visit(stmt->body());
1025
1026 PrepareForBailoutForId(stmt->ContinueId(), NO_REGISTERS);
1027 __ bind(loop_statement.continue_label());
1028 if (stmt->next() != NULL) {
1029 SetStatementPosition(stmt->next());
1030 Visit(stmt->next());
1031 }
1032
1033 // Check stack before looping.
1034 EmitBackEdgeBookkeeping(stmt, &body);
1035
1036 __ bind(&test);
1037 if (stmt->cond() != NULL) {
1038 SetExpressionAsStatementPosition(stmt->cond());
1039 VisitForControl(stmt->cond(),
1040 &body,
1041 loop_statement.break_label(),
1042 loop_statement.break_label());
1043 } else {
1044 __ jmp(&body);
1045 }
1046
1047 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1048 __ bind(loop_statement.break_label());
1049 decrement_loop_depth();
1050 }
1051
1052
1053 void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1054 Comment cmnt(masm_, "[ ForOfStatement");
1055
1056 Iteration loop_statement(this, stmt);
1057 increment_loop_depth();
1058
1059 // var iterator = iterable[Symbol.iterator]();
1060 VisitForEffect(stmt->assign_iterator());
1061
1062 // Loop entry.
1063 __ bind(loop_statement.continue_label());
1064
1065 // result = iterator.next()
1066 SetExpressionAsStatementPosition(stmt->next_result());
1067 VisitForEffect(stmt->next_result());
1068
1069 // if (result.done) break;
1070 Label result_not_done;
1071 VisitForControl(stmt->result_done(), loop_statement.break_label(),
1072 &result_not_done, &result_not_done);
1073 __ bind(&result_not_done);
1074
1075 // each = result.value
1076 VisitForEffect(stmt->assign_each());
1077
1078 // Generate code for the body of the loop.
1079 Visit(stmt->body());
1080
1081 // Check stack before looping.
1082 PrepareForBailoutForId(stmt->BackEdgeId(), NO_REGISTERS);
1083 EmitBackEdgeBookkeeping(stmt, loop_statement.continue_label());
1084 __ jmp(loop_statement.continue_label());
1085
1086 // Exit and decrement the loop depth.
1087 PrepareForBailoutForId(stmt->ExitId(), NO_REGISTERS);
1088 __ bind(loop_statement.break_label());
1089 decrement_loop_depth();
1090 }
1091
1092
1093 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1094 Comment cmnt(masm_, "[ TryCatchStatement");
1095 SetStatementPosition(stmt, SKIP_BREAK);
1096
1097 // The try block adds a handler to the exception handler chain before
1098 // entering, and removes it again when exiting normally. If an exception
1099 // is thrown during execution of the try block, the handler is consumed
1100 // and control is passed to the catch block with the exception in the
1101 // result register.
1102
1103 Label try_entry, handler_entry, exit;
1104 __ jmp(&try_entry);
1105 __ bind(&handler_entry);
1106 PrepareForBailoutForId(stmt->HandlerId(), NO_REGISTERS);
1107 ClearPendingMessage();
1108
1109 // Exception handler code, the exception is in the result register.
1110 // Extend the context before executing the catch block.
1111 { Comment cmnt(masm_, "[ Extend catch context");
1112 __ Push(stmt->variable()->name());
1113 __ Push(result_register());
1114 PushFunctionArgumentForContextAllocation();
1115 __ CallRuntime(Runtime::kPushCatchContext, 3);
1116 StoreToFrameField(StandardFrameConstants::kContextOffset,
1117 context_register());
1118 }
1119
1120 Scope* saved_scope = scope();
1121 scope_ = stmt->scope();
1122 DCHECK(scope_->declarations()->is_empty());
1123 { WithOrCatch catch_body(this);
1124 Visit(stmt->catch_block());
1125 }
1126 // Restore the context.
1127 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
1128 StoreToFrameField(StandardFrameConstants::kContextOffset, context_register());
1129 scope_ = saved_scope;
1130 __ jmp(&exit);
1131
1132 // Try block code. Sets up the exception handler chain.
1133 __ bind(&try_entry);
1134
1135 try_catch_depth_++;
1136 int handler_index = NewHandlerTableEntry();
1137 EnterTryBlock(handler_index, &handler_entry);
1138 { TryCatch try_body(this);
1139 Visit(stmt->try_block());
1140 }
1141 ExitTryBlock(handler_index);
1142 try_catch_depth_--;
1143 __ bind(&exit);
1144 }
1145
1146
1147 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1148 Comment cmnt(masm_, "[ TryFinallyStatement");
1149 SetStatementPosition(stmt, SKIP_BREAK);
1150
1151 // Try finally is compiled by setting up a try-handler on the stack while
1152 // executing the try body, and removing it again afterwards.
1153 //
1154 // The try-finally construct can enter the finally block in three ways:
1155 // 1. By exiting the try-block normally. This removes the try-handler and
1156 // calls the finally block code before continuing.
1157 // 2. By exiting the try-block with a function-local control flow transfer
1158 // (break/continue/return). The site of the, e.g., break removes the
1159 // try handler and calls the finally block code before continuing
1160 // its outward control transfer.
1161 // 3. By exiting the try-block with a thrown exception.
1162 // This can happen in nested function calls. It traverses the try-handler
1163 // chain and consumes the try-handler entry before jumping to the
1164 // handler code. The handler code then calls the finally-block before
1165 // rethrowing the exception.
1166 //
1167 // The finally block must assume a return address on top of the stack
1168 // (or in the link register on ARM chips) and a value (return value or
1169 // exception) in the result register (rax/eax/r0), both of which must
1170 // be preserved. The return address isn't GC-safe, so it should be
1171 // cooked before GC.
1172 Label try_entry, handler_entry, finally_entry;
1173
1174 // Jump to try-handler setup and try-block code.
1175 __ jmp(&try_entry);
1176 __ bind(&handler_entry);
1177 PrepareForBailoutForId(stmt->HandlerId(), NO_REGISTERS);
1178
1179 // Exception handler code. This code is only executed when an exception
1180 // is thrown. The exception is in the result register, and must be
1181 // preserved by the finally block. Call the finally block and then
1182 // rethrow the exception if it returns.
1183 __ Call(&finally_entry);
1184 __ Push(result_register());
1185 __ CallRuntime(Runtime::kReThrow, 1);
1186
1187 // Finally block implementation.
1188 __ bind(&finally_entry);
1189 EnterFinallyBlock();
1190 { Finally finally_body(this);
1191 Visit(stmt->finally_block());
1192 }
1193 ExitFinallyBlock(); // Return to the calling code.
1194
1195 // Set up try handler.
1196 __ bind(&try_entry);
1197 int handler_index = NewHandlerTableEntry();
1198 EnterTryBlock(handler_index, &handler_entry);
1199 { TryFinally try_body(this, &finally_entry);
1200 Visit(stmt->try_block());
1201 }
1202 ExitTryBlock(handler_index);
1203 // Execute the finally block on the way out. Clobber the unpredictable
1204 // value in the result register with one that's safe for GC because the
1205 // finally block will unconditionally preserve the result register on the
1206 // stack.
1207 ClearAccumulator();
1208 __ Call(&finally_entry);
1209 }
1210
1211
1212 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1213 Comment cmnt(masm_, "[ DebuggerStatement");
1214 SetStatementPosition(stmt);
1215
1216 __ DebugBreak();
1217 // Ignore the return value.
1218
1219 PrepareForBailoutForId(stmt->DebugBreakId(), NO_REGISTERS);
1220 }
1221
1222
1223 void FullCodeGenerator::VisitCaseClause(CaseClause* clause) {
1224 UNREACHABLE();
1225 }
1226
1227
1228 void FullCodeGenerator::VisitConditional(Conditional* expr) {
1229 Comment cmnt(masm_, "[ Conditional");
1230 Label true_case, false_case, done;
1231 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
1232
1233 PrepareForBailoutForId(expr->ThenId(), NO_REGISTERS);
1234 __ bind(&true_case);
1235 SetExpressionPosition(expr->then_expression());
1236 if (context()->IsTest()) {
1237 const TestContext* for_test = TestContext::cast(context());
1238 VisitForControl(expr->then_expression(),
1239 for_test->true_label(),
1240 for_test->false_label(),
1241 NULL);
1242 } else {
1243 VisitInDuplicateContext(expr->then_expression());
1244 __ jmp(&done);
1245 }
1246
1247 PrepareForBailoutForId(expr->ElseId(), NO_REGISTERS);
1248 __ bind(&false_case);
1249 SetExpressionPosition(expr->else_expression());
1250 VisitInDuplicateContext(expr->else_expression());
1251 // If control flow falls through Visit, merge it with true case here.
1252 if (!context()->IsTest()) {
1253 __ bind(&done);
1254 }
1255 }
1256
1257
1258 void FullCodeGenerator::VisitLiteral(Literal* expr) {
1259 Comment cmnt(masm_, "[ Literal");
1260 context()->Plug(expr->value());
1261 }
1262
1263
1264 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1265 Comment cmnt(masm_, "[ FunctionLiteral");
1266
1267 // Build the function boilerplate and instantiate it.
1268 Handle<SharedFunctionInfo> function_info =
1269 Compiler::GetSharedFunctionInfo(expr, script(), info_);
1270 if (function_info.is_null()) {
1271 SetStackOverflow();
1272 return;
1273 }
1274 EmitNewClosure(function_info, expr->pretenure());
1275 }
1276
1277
1278 void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
1279 Comment cmnt(masm_, "[ ClassLiteral");
1280
1281 {
1282 EnterBlockScopeIfNeeded block_scope_state(
1283 this, lit->scope(), lit->EntryId(), lit->DeclsId(), lit->ExitId());
1284
1285 if (lit->raw_name() != NULL) {
1286 __ Push(lit->name());
1287 } else {
1288 __ Push(isolate()->factory()->undefined_value());
1289 }
1290
1291 if (lit->extends() != NULL) {
1292 VisitForStackValue(lit->extends());
1293 } else {
1294 __ Push(isolate()->factory()->the_hole_value());
1295 }
1296
1297 VisitForStackValue(lit->constructor());
1298
1299 __ Push(script());
1300 __ Push(Smi::FromInt(lit->start_position()));
1301 __ Push(Smi::FromInt(lit->end_position()));
1302
1303 __ CallRuntime(is_strong(language_mode()) ? Runtime::kDefineClassStrong
1304 : Runtime::kDefineClass,
1305 6);
1306 PrepareForBailoutForId(lit->CreateLiteralId(), TOS_REG);
1307
1308 int store_slot_index = 0;
1309 EmitClassDefineProperties(lit, &store_slot_index);
1310
1311 if (lit->scope() != NULL) {
1312 DCHECK_NOT_NULL(lit->class_variable_proxy());
1313 FeedbackVectorICSlot slot = FLAG_vector_stores
1314 ? lit->GetNthSlot(store_slot_index++)
1315 : FeedbackVectorICSlot::Invalid();
1316 EmitVariableAssignment(lit->class_variable_proxy()->var(),
1317 Token::INIT_CONST, slot);
1318 }
1319
1320 // Verify that compilation exactly consumed the number of store ic slots
1321 // that the ClassLiteral node had to offer.
1322 DCHECK(!FLAG_vector_stores || store_slot_index == lit->slot_count());
1323 }
1324
1325 context()->Plug(result_register());
1326 }
1327
1328
1329 void FullCodeGenerator::VisitNativeFunctionLiteral(
1330 NativeFunctionLiteral* expr) {
1331 Comment cmnt(masm_, "[ NativeFunctionLiteral");
1332
1333 v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate());
1334
1335 // Compute the function template for the native function.
1336 Handle<String> name = expr->name();
1337 v8::Local<v8::FunctionTemplate> fun_template =
1338 expr->extension()->GetNativeFunctionTemplate(v8_isolate,
1339 v8::Utils::ToLocal(name));
1340 DCHECK(!fun_template.IsEmpty());
1341
1342 // Instantiate the function and create a shared function info from it.
1343 Handle<JSFunction> fun = Utils::OpenHandle(
1344 *fun_template->GetFunction(v8_isolate->GetCurrentContext())
1345 .ToLocalChecked());
1346 const int literals = fun->NumberOfLiterals();
1347 Handle<Code> code = Handle<Code>(fun->shared()->code());
1348 Handle<Code> construct_stub = Handle<Code>(fun->shared()->construct_stub());
1349 Handle<SharedFunctionInfo> shared =
1350 isolate()->factory()->NewSharedFunctionInfo(
1351 name, literals, FunctionKind::kNormalFunction, code,
1352 Handle<ScopeInfo>(fun->shared()->scope_info()),
1353 Handle<TypeFeedbackVector>(fun->shared()->feedback_vector()));
1354 shared->set_construct_stub(*construct_stub);
1355
1356 // Copy the function data to the shared function info.
1357 shared->set_function_data(fun->shared()->function_data());
1358 int parameters = fun->shared()->internal_formal_parameter_count();
1359 shared->set_internal_formal_parameter_count(parameters);
1360
1361 EmitNewClosure(shared, false);
1362 }
1363
1364
1365 void FullCodeGenerator::VisitThrow(Throw* expr) {
1366 Comment cmnt(masm_, "[ Throw");
1367 VisitForStackValue(expr->exception());
1368 SetExpressionPosition(expr);
1369 __ CallRuntime(Runtime::kThrow, 1);
1370 // Never returns here.
1371 }
1372
1373
1374 void FullCodeGenerator::EnterTryBlock(int handler_index, Label* handler) {
1375 HandlerTableEntry* entry = &handler_table_[handler_index];
1376 entry->range_start = masm()->pc_offset();
1377 entry->handler_offset = handler->pos();
1378 entry->try_catch_depth = try_catch_depth_;
1379
1380 // Determine expression stack depth of try statement.
1381 int stack_depth = info_->scope()->num_stack_slots(); // Include stack locals.
1382 for (NestedStatement* current = nesting_stack_; current != NULL; /*nop*/) {
1383 current = current->AccumulateDepth(&stack_depth);
1384 }
1385 entry->stack_depth = stack_depth;
1386
1387 // Push context onto operand stack.
1388 STATIC_ASSERT(TryBlockConstant::kElementCount == 1);
1389 __ Push(context_register());
1390 }
1391
1392
1393 void FullCodeGenerator::ExitTryBlock(int handler_index) {
1394 HandlerTableEntry* entry = &handler_table_[handler_index];
1395 entry->range_end = masm()->pc_offset();
1396
1397 // Drop context from operand stack.
1398 __ Drop(TryBlockConstant::kElementCount);
1399 }
1400
1401
1402 void FullCodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
1403
1404
1405 FullCodeGenerator::NestedStatement* FullCodeGenerator::TryFinally::Exit(
1406 int* stack_depth, int* context_length) {
1407 // The macros used here must preserve the result register.
1408
1409 // Because the handler block contains the context of the finally
1410 // code, we can restore it directly from there for the finally code
1411 // rather than iteratively unwinding contexts via their previous
1412 // links.
1413 if (*context_length > 0) {
1414 __ Drop(*stack_depth); // Down to the handler block.
1415 // Restore the context to its dedicated register and the stack.
1416 STATIC_ASSERT(TryFinally::kElementCount == 1);
1417 __ Pop(codegen_->context_register());
1418 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
1419 codegen_->context_register());
1420 } else {
1421 // Down to the handler block and also drop context.
1422 __ Drop(*stack_depth + kElementCount);
1423 }
1424 __ Call(finally_entry_);
1425
1426 *stack_depth = 0;
1427 *context_length = 0;
1428 return previous_;
1429 }
1430
1431
1432 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
1433 Expression* sub_expr;
1434 Handle<String> check;
1435 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
1436 EmitLiteralCompareTypeof(expr, sub_expr, check);
1437 return true;
1438 }
1439
1440 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) {
1441 EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue);
1442 return true;
1443 }
1444
1445 if (expr->IsLiteralCompareNull(&sub_expr)) {
1446 EmitLiteralCompareNil(expr, sub_expr, kNullValue);
1447 return true;
1448 }
1449
1450 return false;
1451 }
1452
1453
1454 void BackEdgeTable::Patch(Isolate* isolate, Code* unoptimized) {
1455 DisallowHeapAllocation no_gc;
1456 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement);
1457
1458 // Increment loop nesting level by one and iterate over the back edge table
1459 // to find the matching loops to patch the interrupt
1460 // call to an unconditional call to the replacement code.
1461 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level() + 1;
1462 if (loop_nesting_level > Code::kMaxLoopNestingMarker) return;
1463
1464 BackEdgeTable back_edges(unoptimized, &no_gc);
1465 for (uint32_t i = 0; i < back_edges.length(); i++) {
1466 if (static_cast<int>(back_edges.loop_depth(i)) == loop_nesting_level) {
1467 DCHECK_EQ(INTERRUPT, GetBackEdgeState(isolate,
1468 unoptimized,
1469 back_edges.pc(i)));
1470 PatchAt(unoptimized, back_edges.pc(i), ON_STACK_REPLACEMENT, patch);
1471 }
1472 }
1473
1474 unoptimized->set_allow_osr_at_loop_nesting_level(loop_nesting_level);
1475 DCHECK(Verify(isolate, unoptimized));
1476 }
1477
1478
1479 void BackEdgeTable::Revert(Isolate* isolate, Code* unoptimized) {
1480 DisallowHeapAllocation no_gc;
1481 Code* patch = isolate->builtins()->builtin(Builtins::kInterruptCheck);
1482
1483 // Iterate over the back edge table and revert the patched interrupt calls.
1484 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
1485
1486 BackEdgeTable back_edges(unoptimized, &no_gc);
1487 for (uint32_t i = 0; i < back_edges.length(); i++) {
1488 if (static_cast<int>(back_edges.loop_depth(i)) <= loop_nesting_level) {
1489 DCHECK_NE(INTERRUPT, GetBackEdgeState(isolate,
1490 unoptimized,
1491 back_edges.pc(i)));
1492 PatchAt(unoptimized, back_edges.pc(i), INTERRUPT, patch);
1493 }
1494 }
1495
1496 unoptimized->set_allow_osr_at_loop_nesting_level(0);
1497 // Assert that none of the back edges are patched anymore.
1498 DCHECK(Verify(isolate, unoptimized));
1499 }
1500
1501
1502 void BackEdgeTable::AddStackCheck(Handle<Code> code, uint32_t pc_offset) {
1503 DisallowHeapAllocation no_gc;
1504 Isolate* isolate = code->GetIsolate();
1505 Address pc = code->instruction_start() + pc_offset;
1506 Code* patch = isolate->builtins()->builtin(Builtins::kOsrAfterStackCheck);
1507 PatchAt(*code, pc, OSR_AFTER_STACK_CHECK, patch);
1508 }
1509
1510
1511 void BackEdgeTable::RemoveStackCheck(Handle<Code> code, uint32_t pc_offset) {
1512 DisallowHeapAllocation no_gc;
1513 Isolate* isolate = code->GetIsolate();
1514 Address pc = code->instruction_start() + pc_offset;
1515
1516 if (OSR_AFTER_STACK_CHECK == GetBackEdgeState(isolate, *code, pc)) {
1517 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement);
1518 PatchAt(*code, pc, ON_STACK_REPLACEMENT, patch);
1519 }
1520 }
1521
1522
1523 #ifdef DEBUG
1524 bool BackEdgeTable::Verify(Isolate* isolate, Code* unoptimized) {
1525 DisallowHeapAllocation no_gc;
1526 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
1527 BackEdgeTable back_edges(unoptimized, &no_gc);
1528 for (uint32_t i = 0; i < back_edges.length(); i++) {
1529 uint32_t loop_depth = back_edges.loop_depth(i);
1530 CHECK_LE(static_cast<int>(loop_depth), Code::kMaxLoopNestingMarker);
1531 // Assert that all back edges for shallower loops (and only those)
1532 // have already been patched.
1533 CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level),
1534 GetBackEdgeState(isolate,
1535 unoptimized,
1536 back_edges.pc(i)) != INTERRUPT);
1537 }
1538 return true;
1539 }
1540 #endif // DEBUG
1541
1542
1543 FullCodeGenerator::EnterBlockScopeIfNeeded::EnterBlockScopeIfNeeded(
1544 FullCodeGenerator* codegen, Scope* scope, BailoutId entry_id,
1545 BailoutId declarations_id, BailoutId exit_id)
1546 : codegen_(codegen), exit_id_(exit_id) {
1547 saved_scope_ = codegen_->scope();
1548
1549 if (scope == NULL) {
1550 codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS);
1551 needs_block_context_ = false;
1552 } else {
1553 needs_block_context_ = scope->ContextLocalCount() > 0;
1554 codegen_->scope_ = scope;
1555 {
1556 if (needs_block_context_) {
1557 Comment cmnt(masm(), "[ Extend block context");
1558 __ Push(scope->GetScopeInfo(codegen->isolate()));
1559 codegen_->PushFunctionArgumentForContextAllocation();
1560 __ CallRuntime(Runtime::kPushBlockContext, 2);
1561
1562 // Replace the context stored in the frame.
1563 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
1564 codegen_->context_register());
1565 }
1566 CHECK_EQ(0, scope->num_stack_slots());
1567 codegen_->PrepareForBailoutForId(entry_id, NO_REGISTERS);
1568 }
1569 {
1570 Comment cmnt(masm(), "[ Declarations");
1571 codegen_->VisitDeclarations(scope->declarations());
1572 codegen_->PrepareForBailoutForId(declarations_id, NO_REGISTERS);
1573 }
1574 }
1575 }
1576
1577
1578 FullCodeGenerator::EnterBlockScopeIfNeeded::~EnterBlockScopeIfNeeded() {
1579 if (needs_block_context_) {
1580 codegen_->LoadContextField(codegen_->context_register(),
1581 Context::PREVIOUS_INDEX);
1582 // Update local stack frame context field.
1583 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
1584 codegen_->context_register());
1585 }
1586 codegen_->PrepareForBailoutForId(exit_id_, NO_REGISTERS);
1587 codegen_->scope_ = saved_scope_;
1588 }
1589
1590
1591 #undef __
1592
1593
1594 } // namespace internal
1595 } // namespace v8
OLDNEW
« no previous file with comments | « src/full-codegen.h ('k') | src/full-codegen/OWNERS » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698