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/full-codegen/full-codegen.h"
6
7 #include "src/ast/ast-numbering.h"
8 #include "src/ast/ast.h"
9 #include "src/ast/prettyprinter.h"
10 #include "src/ast/scopes.h"
11 #include "src/code-factory.h"
12 #include "src/codegen.h"
13 #include "src/compilation-info.h"
14 #include "src/compiler.h"
15 #include "src/debug/debug.h"
16 #include "src/debug/liveedit.h"
17 #include "src/frames-inl.h"
18 #include "src/globals.h"
19 #include "src/isolate-inl.h"
20 #include "src/macro-assembler.h"
21 #include "src/snapshot/snapshot.h"
22 #include "src/tracing/trace-event.h"
23
24 namespace v8 {
25 namespace internal {
26
27 #define __ ACCESS_MASM(masm())
28
29 class FullCodegenCompilationJob final : public CompilationJob {
30 public:
FullCodegenCompilationJob(CompilationInfo * info)31 explicit FullCodegenCompilationJob(CompilationInfo* info)
32 : CompilationJob(info->isolate(), info, "Full-Codegen") {}
33
can_execute_on_background_thread() const34 bool can_execute_on_background_thread() const override { return false; }
35
PrepareJobImpl()36 CompilationJob::Status PrepareJobImpl() final { return SUCCEEDED; }
37
ExecuteJobImpl()38 CompilationJob::Status ExecuteJobImpl() final {
39 DCHECK(ThreadId::Current().Equals(isolate()->thread_id()));
40 return FullCodeGenerator::MakeCode(info(), stack_limit()) ? SUCCEEDED
41 : FAILED;
42 }
43
FinalizeJobImpl()44 CompilationJob::Status FinalizeJobImpl() final { return SUCCEEDED; }
45
46 private:
47 DISALLOW_COPY_AND_ASSIGN(FullCodegenCompilationJob);
48 };
49
FullCodeGenerator(MacroAssembler * masm,CompilationInfo * info,uintptr_t stack_limit)50 FullCodeGenerator::FullCodeGenerator(MacroAssembler* masm,
51 CompilationInfo* info,
52 uintptr_t stack_limit)
53 : masm_(masm),
54 info_(info),
55 isolate_(info->isolate()),
56 zone_(info->zone()),
57 scope_(info->scope()),
58 nesting_stack_(NULL),
59 loop_depth_(0),
60 operand_stack_depth_(0),
61 globals_(NULL),
62 context_(NULL),
63 bailout_entries_(info->HasDeoptimizationSupport()
64 ? info->literal()->ast_node_count()
65 : 0,
66 info->zone()),
67 back_edges_(2, info->zone()),
68 source_position_table_builder_(info->zone(),
69 info->SourcePositionRecordingMode()),
70 ic_total_count_(0) {
71 DCHECK(!info->IsStub());
72 Initialize(stack_limit);
73 }
74
75 // static
NewCompilationJob(CompilationInfo * info)76 CompilationJob* FullCodeGenerator::NewCompilationJob(CompilationInfo* info) {
77 return new FullCodegenCompilationJob(info);
78 }
79
80 // static
MakeCode(CompilationInfo * info)81 bool FullCodeGenerator::MakeCode(CompilationInfo* info) {
82 return MakeCode(info, info->isolate()->stack_guard()->real_climit());
83 }
84
85 // static
MakeCode(CompilationInfo * info,uintptr_t stack_limit)86 bool FullCodeGenerator::MakeCode(CompilationInfo* info, uintptr_t stack_limit) {
87 Isolate* isolate = info->isolate();
88
89 DCHECK(!info->shared_info()->must_use_ignition_turbo());
90 DCHECK(!FLAG_minimal);
91 RuntimeCallTimerScope runtimeTimer(isolate,
92 &RuntimeCallStats::CompileFullCode);
93 TimerEventScope<TimerEventCompileFullCode> timer(info->isolate());
94 TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.compile"), "V8.CompileFullCode");
95
96 Handle<Script> script = info->script();
97 if (!script->IsUndefined(isolate) &&
98 !script->source()->IsUndefined(isolate)) {
99 int len = String::cast(script->source())->length();
100 isolate->counters()->total_full_codegen_source_size()->Increment(len);
101 }
102 CodeGenerator::MakeCodePrologue(info, "full");
103 const int kInitialBufferSize = 4 * KB;
104 MacroAssembler masm(info->isolate(), NULL, kInitialBufferSize,
105 CodeObjectRequired::kYes);
106 if (info->will_serialize()) masm.enable_serializer();
107
108 FullCodeGenerator cgen(&masm, info, stack_limit);
109 cgen.Generate();
110 if (cgen.HasStackOverflow()) {
111 DCHECK(!isolate->has_pending_exception());
112 return false;
113 }
114 unsigned table_offset = cgen.EmitBackEdgeTable();
115
116 Handle<Code> code =
117 CodeGenerator::MakeCodeEpilogue(&masm, nullptr, info, masm.CodeObject());
118 cgen.PopulateDeoptimizationData(code);
119 cgen.PopulateTypeFeedbackInfo(code);
120 code->set_has_deoptimization_support(info->HasDeoptimizationSupport());
121 code->set_has_reloc_info_for_serialization(info->will_serialize());
122 code->set_allow_osr_at_loop_nesting_level(0);
123 code->set_profiler_ticks(0);
124 code->set_back_edge_table_offset(table_offset);
125 Handle<ByteArray> source_positions =
126 cgen.source_position_table_builder_.ToSourcePositionTable(
127 isolate, Handle<AbstractCode>::cast(code));
128 code->set_source_position_table(*source_positions);
129 CodeGenerator::PrintCode(code, info);
130 info->SetCode(code);
131
132 #ifdef DEBUG
133 // Check that no context-specific object has been embedded.
134 code->VerifyEmbeddedObjects(Code::kNoContextSpecificPointers);
135 #endif // DEBUG
136 return true;
137 }
138
139
EmitBackEdgeTable()140 unsigned FullCodeGenerator::EmitBackEdgeTable() {
141 // The back edge table consists of a length (in number of entries)
142 // field, and then a sequence of entries. Each entry is a pair of AST id
143 // and code-relative pc offset.
144 masm()->Align(kPointerSize);
145 unsigned offset = masm()->pc_offset();
146 unsigned length = back_edges_.length();
147 __ dd(length);
148 for (unsigned i = 0; i < length; ++i) {
149 __ dd(back_edges_[i].id.ToInt());
150 __ dd(back_edges_[i].pc);
151 __ dd(back_edges_[i].loop_depth);
152 }
153 return offset;
154 }
155
156
PopulateDeoptimizationData(Handle<Code> code)157 void FullCodeGenerator::PopulateDeoptimizationData(Handle<Code> code) {
158 // Fill in the deoptimization information.
159 DCHECK(info_->HasDeoptimizationSupport() || bailout_entries_.is_empty());
160 if (!info_->HasDeoptimizationSupport()) return;
161 int length = bailout_entries_.length();
162 Handle<DeoptimizationOutputData> data =
163 DeoptimizationOutputData::New(isolate(), length, TENURED);
164 for (int i = 0; i < length; i++) {
165 data->SetAstId(i, bailout_entries_[i].id);
166 data->SetPcAndState(i, Smi::FromInt(bailout_entries_[i].pc_and_state));
167 }
168 code->set_deoptimization_data(*data);
169 }
170
171
PopulateTypeFeedbackInfo(Handle<Code> code)172 void FullCodeGenerator::PopulateTypeFeedbackInfo(Handle<Code> code) {
173 Handle<TypeFeedbackInfo> info = isolate()->factory()->NewTypeFeedbackInfo();
174 info->set_ic_total_count(ic_total_count_);
175 DCHECK(!isolate()->heap()->InNewSpace(*info));
176 code->set_type_feedback_info(*info);
177 }
178
179
MustCreateObjectLiteralWithRuntime(ObjectLiteral * expr) const180 bool FullCodeGenerator::MustCreateObjectLiteralWithRuntime(
181 ObjectLiteral* expr) const {
182 return masm()->serializer_enabled() || !expr->IsFastCloningSupported();
183 }
184
185
MustCreateArrayLiteralWithRuntime(ArrayLiteral * expr) const186 bool FullCodeGenerator::MustCreateArrayLiteralWithRuntime(
187 ArrayLiteral* expr) const {
188 return !expr->IsFastCloningSupported();
189 }
190
Initialize(uintptr_t stack_limit)191 void FullCodeGenerator::Initialize(uintptr_t stack_limit) {
192 InitializeAstVisitor(stack_limit);
193 masm_->set_emit_debug_code(FLAG_debug_code);
194 masm_->set_predictable_code_size(true);
195 }
196
PrepareForBailout(Expression * node,BailoutState state)197 void FullCodeGenerator::PrepareForBailout(Expression* node,
198 BailoutState state) {
199 PrepareForBailoutForId(node->id(), state);
200 }
201
CallIC(Handle<Code> code,TypeFeedbackId ast_id)202 void FullCodeGenerator::CallIC(Handle<Code> code, TypeFeedbackId ast_id) {
203 ic_total_count_++;
204 __ Call(code, RelocInfo::CODE_TARGET, ast_id);
205 }
206
CallLoadIC(FeedbackSlot slot,Handle<Object> name)207 void FullCodeGenerator::CallLoadIC(FeedbackSlot slot, Handle<Object> name) {
208 DCHECK(name->IsName());
209 __ Move(LoadDescriptor::NameRegister(), name);
210
211 EmitLoadSlot(LoadDescriptor::SlotRegister(), slot);
212
213 Handle<Code> code = CodeFactory::LoadIC(isolate()).code();
214 __ Call(code, RelocInfo::CODE_TARGET);
215 RestoreContext();
216 }
217
CallStoreIC(FeedbackSlot slot,Handle<Object> name,bool store_own_property)218 void FullCodeGenerator::CallStoreIC(FeedbackSlot slot, Handle<Object> name,
219 bool store_own_property) {
220 DCHECK(name->IsName());
221 __ Move(StoreDescriptor::NameRegister(), name);
222
223 STATIC_ASSERT(!StoreDescriptor::kPassLastArgsOnStack ||
224 StoreDescriptor::kStackArgumentsCount == 2);
225 if (StoreDescriptor::kPassLastArgsOnStack) {
226 __ Push(StoreDescriptor::ValueRegister());
227 EmitPushSlot(slot);
228 } else {
229 EmitLoadSlot(StoreDescriptor::SlotRegister(), slot);
230 }
231
232 Handle<Code> code;
233 if (store_own_property) {
234 DCHECK_EQ(FeedbackSlotKind::kStoreOwnNamed,
235 feedback_vector_spec()->GetKind(slot));
236 code = CodeFactory::StoreOwnIC(isolate()).code();
237 } else {
238 // Ensure that language mode is in sync with the IC slot kind.
239 DCHECK_EQ(
240 GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)),
241 language_mode());
242 code = CodeFactory::StoreIC(isolate(), language_mode()).code();
243 }
244 __ Call(code, RelocInfo::CODE_TARGET);
245 RestoreContext();
246 }
247
CallKeyedStoreIC(FeedbackSlot slot)248 void FullCodeGenerator::CallKeyedStoreIC(FeedbackSlot slot) {
249 STATIC_ASSERT(!StoreDescriptor::kPassLastArgsOnStack ||
250 StoreDescriptor::kStackArgumentsCount == 2);
251 if (StoreDescriptor::kPassLastArgsOnStack) {
252 __ Push(StoreDescriptor::ValueRegister());
253 EmitPushSlot(slot);
254 } else {
255 EmitLoadSlot(StoreDescriptor::SlotRegister(), slot);
256 }
257
258 // Ensure that language mode is in sync with the IC slot kind.
259 DCHECK_EQ(GetLanguageModeFromSlotKind(feedback_vector_spec()->GetKind(slot)),
260 language_mode());
261 Handle<Code> code =
262 CodeFactory::KeyedStoreIC(isolate(), language_mode()).code();
263 __ Call(code, RelocInfo::CODE_TARGET);
264 RestoreContext();
265 }
266
RecordJSReturnSite(Call * call)267 void FullCodeGenerator::RecordJSReturnSite(Call* call) {
268 // We record the offset of the function return so we can rebuild the frame
269 // if the function was inlined, i.e., this is the return address in the
270 // inlined function's frame.
271 //
272 // The bailout state is ignored. We defensively set it to TOS_REGISTER, which
273 // is the real state of the unoptimized code at the return site.
274 PrepareForBailoutForId(call->ReturnId(), BailoutState::TOS_REGISTER);
275 #ifdef DEBUG
276 // In debug builds, mark the return so we can verify that this function
277 // was called.
278 DCHECK(!call->return_is_recorded_);
279 call->return_is_recorded_ = true;
280 #endif
281 }
282
PrepareForBailoutForId(BailoutId id,BailoutState state)283 void FullCodeGenerator::PrepareForBailoutForId(BailoutId id,
284 BailoutState state) {
285 // There's no need to prepare this code for bailouts from already optimized
286 // code or code that can't be optimized.
287 if (!info_->HasDeoptimizationSupport()) return;
288 unsigned pc_and_state =
289 BailoutStateField::encode(state) | PcField::encode(masm_->pc_offset());
290 DCHECK(Smi::IsValid(pc_and_state));
291 #ifdef DEBUG
292 for (int i = 0; i < bailout_entries_.length(); ++i) {
293 DCHECK(bailout_entries_[i].id != id);
294 }
295 #endif
296 BailoutEntry entry = { id, pc_and_state };
297 bailout_entries_.Add(entry, zone());
298 }
299
300
RecordBackEdge(BailoutId ast_id)301 void FullCodeGenerator::RecordBackEdge(BailoutId ast_id) {
302 // The pc offset does not need to be encoded and packed together with a state.
303 DCHECK(masm_->pc_offset() > 0);
304 DCHECK(loop_depth() > 0);
305 uint8_t depth = Min(loop_depth(), AbstractCode::kMaxLoopNestingMarker);
306 BackEdgeEntry entry =
307 { ast_id, static_cast<unsigned>(masm_->pc_offset()), depth };
308 back_edges_.Add(entry, zone());
309 }
310
311
ShouldInlineSmiCase(Token::Value op)312 bool FullCodeGenerator::ShouldInlineSmiCase(Token::Value op) {
313 // Inline smi case inside loops, but not division and modulo which
314 // are too complicated and take up too much space.
315 if (op == Token::DIV ||op == Token::MOD) return false;
316 if (FLAG_always_inline_smi_code) return true;
317 return loop_depth_ > 0;
318 }
319
320
Plug(Variable * var) const321 void FullCodeGenerator::EffectContext::Plug(Variable* var) const {
322 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
323 }
324
325
Plug(Variable * var) const326 void FullCodeGenerator::AccumulatorValueContext::Plug(Variable* var) const {
327 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
328 codegen()->GetVar(result_register(), var);
329 }
330
331
Plug(Variable * var) const332 void FullCodeGenerator::TestContext::Plug(Variable* var) const {
333 DCHECK(var->IsStackAllocated() || var->IsContextSlot());
334 // For simplicity we always test the accumulator register.
335 codegen()->GetVar(result_register(), var);
336 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
337 codegen()->DoTest(this);
338 }
339
340
Plug(Register reg) const341 void FullCodeGenerator::EffectContext::Plug(Register reg) const {
342 }
343
344
Plug(Register reg) const345 void FullCodeGenerator::AccumulatorValueContext::Plug(Register reg) const {
346 __ Move(result_register(), reg);
347 }
348
349
Plug(Register reg) const350 void FullCodeGenerator::StackValueContext::Plug(Register reg) const {
351 codegen()->PushOperand(reg);
352 }
353
354
Plug(Register reg) const355 void FullCodeGenerator::TestContext::Plug(Register reg) const {
356 // For simplicity we always test the accumulator register.
357 __ Move(result_register(), reg);
358 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
359 codegen()->DoTest(this);
360 }
361
362
Plug(bool flag) const363 void FullCodeGenerator::EffectContext::Plug(bool flag) const {}
364
DropAndPlug(int count,Register reg) const365 void FullCodeGenerator::EffectContext::DropAndPlug(int count,
366 Register reg) const {
367 DCHECK(count > 0);
368 codegen()->DropOperands(count);
369 }
370
DropAndPlug(int count,Register reg) const371 void FullCodeGenerator::AccumulatorValueContext::DropAndPlug(
372 int count, Register reg) const {
373 DCHECK(count > 0);
374 codegen()->DropOperands(count);
375 __ Move(result_register(), reg);
376 }
377
DropAndPlug(int count,Register reg) const378 void FullCodeGenerator::TestContext::DropAndPlug(int count,
379 Register reg) const {
380 DCHECK(count > 0);
381 // For simplicity we always test the accumulator register.
382 codegen()->DropOperands(count);
383 __ Move(result_register(), reg);
384 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
385 codegen()->DoTest(this);
386 }
387
PlugTOS() const388 void FullCodeGenerator::EffectContext::PlugTOS() const {
389 codegen()->DropOperands(1);
390 }
391
392
PlugTOS() const393 void FullCodeGenerator::AccumulatorValueContext::PlugTOS() const {
394 codegen()->PopOperand(result_register());
395 }
396
397
PlugTOS() const398 void FullCodeGenerator::StackValueContext::PlugTOS() const {
399 }
400
401
PlugTOS() const402 void FullCodeGenerator::TestContext::PlugTOS() const {
403 // For simplicity we always test the accumulator register.
404 codegen()->PopOperand(result_register());
405 codegen()->PrepareForBailoutBeforeSplit(condition(), false, NULL, NULL);
406 codegen()->DoTest(this);
407 }
408
409
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const410 void FullCodeGenerator::EffectContext::PrepareTest(
411 Label* materialize_true,
412 Label* materialize_false,
413 Label** if_true,
414 Label** if_false,
415 Label** fall_through) const {
416 // In an effect context, the true and the false case branch to the
417 // same label.
418 *if_true = *if_false = *fall_through = materialize_true;
419 }
420
421
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const422 void FullCodeGenerator::AccumulatorValueContext::PrepareTest(
423 Label* materialize_true,
424 Label* materialize_false,
425 Label** if_true,
426 Label** if_false,
427 Label** fall_through) const {
428 *if_true = *fall_through = materialize_true;
429 *if_false = materialize_false;
430 }
431
432
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const433 void FullCodeGenerator::StackValueContext::PrepareTest(
434 Label* materialize_true,
435 Label* materialize_false,
436 Label** if_true,
437 Label** if_false,
438 Label** fall_through) const {
439 *if_true = *fall_through = materialize_true;
440 *if_false = materialize_false;
441 }
442
443
PrepareTest(Label * materialize_true,Label * materialize_false,Label ** if_true,Label ** if_false,Label ** fall_through) const444 void FullCodeGenerator::TestContext::PrepareTest(
445 Label* materialize_true,
446 Label* materialize_false,
447 Label** if_true,
448 Label** if_false,
449 Label** fall_through) const {
450 *if_true = true_label_;
451 *if_false = false_label_;
452 *fall_through = fall_through_;
453 }
454
455
DoTest(const TestContext * context)456 void FullCodeGenerator::DoTest(const TestContext* context) {
457 DoTest(context->condition(),
458 context->true_label(),
459 context->false_label(),
460 context->fall_through());
461 }
462
VisitDeclarations(Declaration::List * declarations)463 void FullCodeGenerator::VisitDeclarations(Declaration::List* declarations) {
464 ZoneList<Handle<Object> >* saved_globals = globals_;
465 ZoneList<Handle<Object> > inner_globals(10, zone());
466 globals_ = &inner_globals;
467
468 AstVisitor<FullCodeGenerator>::VisitDeclarations(declarations);
469
470 if (!globals_->is_empty()) {
471 // Invoke the platform-dependent code generator to do the actual
472 // declaration of the global functions and variables.
473 Handle<FixedArray> array =
474 isolate()->factory()->NewFixedArray(globals_->length(), TENURED);
475 for (int i = 0; i < globals_->length(); ++i)
476 array->set(i, *globals_->at(i));
477 DeclareGlobals(array);
478 }
479
480 globals_ = saved_globals;
481 }
482
483
VisitVariableProxy(VariableProxy * expr)484 void FullCodeGenerator::VisitVariableProxy(VariableProxy* expr) {
485 Comment cmnt(masm_, "[ VariableProxy");
486 EmitVariableLoad(expr);
487 }
488
EmitGlobalVariableLoad(VariableProxy * proxy,TypeofMode typeof_mode)489 void FullCodeGenerator::EmitGlobalVariableLoad(VariableProxy* proxy,
490 TypeofMode typeof_mode) {
491 Variable* var = proxy->var();
492 DCHECK(var->IsUnallocated());
493 __ Move(LoadDescriptor::NameRegister(), var->name());
494
495 FeedbackSlot slot = proxy->VariableFeedbackSlot();
496 // Ensure that typeof mode is in sync with the IC slot kind.
497 DCHECK_EQ(GetTypeofModeFromSlotKind(feedback_vector_spec()->GetKind(slot)),
498 typeof_mode);
499
500 EmitLoadSlot(LoadGlobalDescriptor::SlotRegister(), slot);
501 Handle<Code> code = CodeFactory::LoadGlobalIC(isolate(), typeof_mode).code();
502 __ Call(code, RelocInfo::CODE_TARGET);
503 RestoreContext();
504 }
505
VisitSloppyBlockFunctionStatement(SloppyBlockFunctionStatement * declaration)506 void FullCodeGenerator::VisitSloppyBlockFunctionStatement(
507 SloppyBlockFunctionStatement* declaration) {
508 Visit(declaration->statement());
509 }
510
511
DeclareGlobalsFlags()512 int FullCodeGenerator::DeclareGlobalsFlags() {
513 return info_->GetDeclareGlobalsFlags();
514 }
515
PushOperand(Handle<Object> handle)516 void FullCodeGenerator::PushOperand(Handle<Object> handle) {
517 OperandStackDepthIncrement(1);
518 __ Push(handle);
519 }
520
PushOperand(Smi * smi)521 void FullCodeGenerator::PushOperand(Smi* smi) {
522 OperandStackDepthIncrement(1);
523 __ Push(smi);
524 }
525
PushOperand(Register reg)526 void FullCodeGenerator::PushOperand(Register reg) {
527 OperandStackDepthIncrement(1);
528 __ Push(reg);
529 }
530
PopOperand(Register reg)531 void FullCodeGenerator::PopOperand(Register reg) {
532 OperandStackDepthDecrement(1);
533 __ Pop(reg);
534 }
535
DropOperands(int count)536 void FullCodeGenerator::DropOperands(int count) {
537 OperandStackDepthDecrement(count);
538 __ Drop(count);
539 }
540
CallRuntimeWithOperands(Runtime::FunctionId id)541 void FullCodeGenerator::CallRuntimeWithOperands(Runtime::FunctionId id) {
542 OperandStackDepthDecrement(Runtime::FunctionForId(id)->nargs);
543 __ CallRuntime(id);
544 }
545
OperandStackDepthIncrement(int count)546 void FullCodeGenerator::OperandStackDepthIncrement(int count) {
547 DCHECK_IMPLIES(!HasStackOverflow(), operand_stack_depth_ >= 0);
548 DCHECK_GE(count, 0);
549 operand_stack_depth_ += count;
550 }
551
OperandStackDepthDecrement(int count)552 void FullCodeGenerator::OperandStackDepthDecrement(int count) {
553 DCHECK_IMPLIES(!HasStackOverflow(), operand_stack_depth_ >= count);
554 DCHECK_GE(count, 0);
555 operand_stack_depth_ -= count;
556 }
557
EmitSubString(CallRuntime * expr)558 void FullCodeGenerator::EmitSubString(CallRuntime* expr) {
559 // Load the arguments on the stack and call the stub.
560 SubStringStub stub(isolate());
561 ZoneList<Expression*>* args = expr->arguments();
562 DCHECK(args->length() == 3);
563 VisitForStackValue(args->at(0));
564 VisitForStackValue(args->at(1));
565 VisitForStackValue(args->at(2));
566 __ CallStub(&stub);
567 RestoreContext();
568 OperandStackDepthDecrement(3);
569 context()->Plug(result_register());
570 }
571
572
EmitIntrinsicAsStubCall(CallRuntime * expr,const Callable & callable)573 void FullCodeGenerator::EmitIntrinsicAsStubCall(CallRuntime* expr,
574 const Callable& callable) {
575 ZoneList<Expression*>* args = expr->arguments();
576 int param_count = callable.descriptor().GetRegisterParameterCount();
577 DCHECK_EQ(args->length(), param_count);
578
579 if (param_count > 0) {
580 int last = param_count - 1;
581 // Put all but last arguments on stack.
582 for (int i = 0; i < last; i++) {
583 VisitForStackValue(args->at(i));
584 }
585 // The last argument goes to the accumulator.
586 VisitForAccumulatorValue(args->at(last));
587
588 // Move the arguments to the registers, as required by the stub.
589 __ Move(callable.descriptor().GetRegisterParameter(last),
590 result_register());
591 for (int i = last; i-- > 0;) {
592 PopOperand(callable.descriptor().GetRegisterParameter(i));
593 }
594 }
595 __ Call(callable.code(), RelocInfo::CODE_TARGET);
596
597 // Reload the context register after the call as i.e. TurboFan code stubs
598 // won't preserve the context register.
599 LoadFromFrameField(StandardFrameConstants::kContextOffset,
600 context_register());
601 context()->Plug(result_register());
602 }
603
604
EmitToString(CallRuntime * expr)605 void FullCodeGenerator::EmitToString(CallRuntime* expr) {
606 EmitIntrinsicAsStubCall(expr, CodeFactory::ToString(isolate()));
607 }
608
609
EmitToLength(CallRuntime * expr)610 void FullCodeGenerator::EmitToLength(CallRuntime* expr) {
611 EmitIntrinsicAsStubCall(expr, CodeFactory::ToLength(isolate()));
612 }
613
EmitToInteger(CallRuntime * expr)614 void FullCodeGenerator::EmitToInteger(CallRuntime* expr) {
615 EmitIntrinsicAsStubCall(expr, CodeFactory::ToInteger(isolate()));
616 }
617
EmitToNumber(CallRuntime * expr)618 void FullCodeGenerator::EmitToNumber(CallRuntime* expr) {
619 EmitIntrinsicAsStubCall(expr, CodeFactory::ToNumber(isolate()));
620 }
621
622
EmitToObject(CallRuntime * expr)623 void FullCodeGenerator::EmitToObject(CallRuntime* expr) {
624 EmitIntrinsicAsStubCall(expr, CodeFactory::ToObject(isolate()));
625 }
626
627
EmitHasProperty()628 void FullCodeGenerator::EmitHasProperty() {
629 Callable callable = CodeFactory::HasProperty(isolate());
630 PopOperand(callable.descriptor().GetRegisterParameter(1));
631 PopOperand(callable.descriptor().GetRegisterParameter(0));
632 __ Call(callable.code(), RelocInfo::CODE_TARGET);
633 RestoreContext();
634 }
635
RecordStatementPosition(int pos)636 void FullCodeGenerator::RecordStatementPosition(int pos) {
637 DCHECK_NE(kNoSourcePosition, pos);
638 source_position_table_builder_.AddPosition(masm_->pc_offset(),
639 SourcePosition(pos), true);
640 }
641
RecordPosition(int pos)642 void FullCodeGenerator::RecordPosition(int pos) {
643 DCHECK_NE(kNoSourcePosition, pos);
644 source_position_table_builder_.AddPosition(masm_->pc_offset(),
645 SourcePosition(pos), false);
646 }
647
648
SetFunctionPosition(FunctionLiteral * fun)649 void FullCodeGenerator::SetFunctionPosition(FunctionLiteral* fun) {
650 RecordPosition(fun->start_position());
651 }
652
653
SetReturnPosition(FunctionLiteral * fun)654 void FullCodeGenerator::SetReturnPosition(FunctionLiteral* fun) {
655 // For default constructors, start position equals end position, and there
656 // is no source code besides the class literal.
657 RecordStatementPosition(fun->return_position());
658 if (info_->is_debug()) {
659 // Always emit a debug break slot before a return.
660 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_RETURN);
661 }
662 }
663
664
SetStatementPosition(Statement * stmt,FullCodeGenerator::InsertBreak insert_break)665 void FullCodeGenerator::SetStatementPosition(
666 Statement* stmt, FullCodeGenerator::InsertBreak insert_break) {
667 if (stmt->position() == kNoSourcePosition) return;
668 RecordStatementPosition(stmt->position());
669 if (insert_break == INSERT_BREAK && info_->is_debug() &&
670 !stmt->IsDebuggerStatement()) {
671 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
672 }
673 }
674
SetExpressionPosition(Expression * expr)675 void FullCodeGenerator::SetExpressionPosition(Expression* expr) {
676 if (expr->position() == kNoSourcePosition) return;
677 RecordPosition(expr->position());
678 }
679
680
SetExpressionAsStatementPosition(Expression * expr)681 void FullCodeGenerator::SetExpressionAsStatementPosition(Expression* expr) {
682 if (expr->position() == kNoSourcePosition) return;
683 RecordStatementPosition(expr->position());
684 if (info_->is_debug()) {
685 DebugCodegen::GenerateSlot(masm_, RelocInfo::DEBUG_BREAK_SLOT_AT_POSITION);
686 }
687 }
688
SetCallPosition(Expression * expr,TailCallMode tail_call_mode)689 void FullCodeGenerator::SetCallPosition(Expression* expr,
690 TailCallMode tail_call_mode) {
691 if (expr->position() == kNoSourcePosition) return;
692 RecordPosition(expr->position());
693 if (info_->is_debug()) {
694 RelocInfo::Mode mode = (tail_call_mode == TailCallMode::kAllow)
695 ? RelocInfo::DEBUG_BREAK_SLOT_AT_TAIL_CALL
696 : RelocInfo::DEBUG_BREAK_SLOT_AT_CALL;
697 // Always emit a debug break slot before a call.
698 DebugCodegen::GenerateSlot(masm_, mode);
699 }
700 }
701
702
VisitSuperPropertyReference(SuperPropertyReference * super)703 void FullCodeGenerator::VisitSuperPropertyReference(
704 SuperPropertyReference* super) {
705 __ CallRuntime(Runtime::kThrowUnsupportedSuperError);
706 // Even though this expression doesn't produce a value, we need to simulate
707 // plugging of the value context to ensure stack depth tracking is in sync.
708 if (context()->IsStackValue()) OperandStackDepthIncrement(1);
709 }
710
711
VisitSuperCallReference(SuperCallReference * super)712 void FullCodeGenerator::VisitSuperCallReference(SuperCallReference* super) {
713 // Handled by VisitCall
714 UNREACHABLE();
715 }
716
717
EmitDebugBreakInOptimizedCode(CallRuntime * expr)718 void FullCodeGenerator::EmitDebugBreakInOptimizedCode(CallRuntime* expr) {
719 context()->Plug(handle(Smi::kZero, isolate()));
720 }
721
722
VisitBinaryOperation(BinaryOperation * expr)723 void FullCodeGenerator::VisitBinaryOperation(BinaryOperation* expr) {
724 switch (expr->op()) {
725 case Token::COMMA:
726 return VisitComma(expr);
727 case Token::OR:
728 case Token::AND:
729 return VisitLogicalExpression(expr);
730 default:
731 return VisitArithmeticExpression(expr);
732 }
733 }
734
735
VisitInDuplicateContext(Expression * expr)736 void FullCodeGenerator::VisitInDuplicateContext(Expression* expr) {
737 if (context()->IsEffect()) {
738 VisitForEffect(expr);
739 } else if (context()->IsAccumulatorValue()) {
740 VisitForAccumulatorValue(expr);
741 } else if (context()->IsStackValue()) {
742 VisitForStackValue(expr);
743 } else if (context()->IsTest()) {
744 const TestContext* test = TestContext::cast(context());
745 VisitForControl(expr, test->true_label(), test->false_label(),
746 test->fall_through());
747 }
748 }
749
750
VisitComma(BinaryOperation * expr)751 void FullCodeGenerator::VisitComma(BinaryOperation* expr) {
752 Comment cmnt(masm_, "[ Comma");
753 VisitForEffect(expr->left());
754 VisitInDuplicateContext(expr->right());
755 }
756
757
VisitLogicalExpression(BinaryOperation * expr)758 void FullCodeGenerator::VisitLogicalExpression(BinaryOperation* expr) {
759 bool is_logical_and = expr->op() == Token::AND;
760 Comment cmnt(masm_, is_logical_and ? "[ Logical AND" : "[ Logical OR");
761 Expression* left = expr->left();
762 Expression* right = expr->right();
763 BailoutId right_id = expr->RightId();
764 Label done;
765
766 if (context()->IsTest()) {
767 Label eval_right;
768 const TestContext* test = TestContext::cast(context());
769 if (is_logical_and) {
770 VisitForControl(left, &eval_right, test->false_label(), &eval_right);
771 } else {
772 VisitForControl(left, test->true_label(), &eval_right, &eval_right);
773 }
774 PrepareForBailoutForId(right_id, BailoutState::NO_REGISTERS);
775 __ bind(&eval_right);
776
777 } else if (context()->IsAccumulatorValue()) {
778 VisitForAccumulatorValue(left);
779 // We want the value in the accumulator for the test, and on the stack in
780 // case we need it.
781 __ Push(result_register());
782 Label discard, restore;
783 if (is_logical_and) {
784 DoTest(left, &discard, &restore, &restore);
785 } else {
786 DoTest(left, &restore, &discard, &restore);
787 }
788 __ bind(&restore);
789 __ Pop(result_register());
790 __ jmp(&done);
791 __ bind(&discard);
792 __ Drop(1);
793 PrepareForBailoutForId(right_id, BailoutState::NO_REGISTERS);
794
795 } else if (context()->IsStackValue()) {
796 VisitForAccumulatorValue(left);
797 // We want the value in the accumulator for the test, and on the stack in
798 // case we need it.
799 __ Push(result_register());
800 Label discard;
801 if (is_logical_and) {
802 DoTest(left, &discard, &done, &discard);
803 } else {
804 DoTest(left, &done, &discard, &discard);
805 }
806 __ bind(&discard);
807 __ Drop(1);
808 PrepareForBailoutForId(right_id, BailoutState::NO_REGISTERS);
809
810 } else {
811 DCHECK(context()->IsEffect());
812 Label eval_right;
813 if (is_logical_and) {
814 VisitForControl(left, &eval_right, &done, &eval_right);
815 } else {
816 VisitForControl(left, &done, &eval_right, &eval_right);
817 }
818 PrepareForBailoutForId(right_id, BailoutState::NO_REGISTERS);
819 __ bind(&eval_right);
820 }
821
822 VisitInDuplicateContext(right);
823 __ bind(&done);
824 }
825
826
VisitArithmeticExpression(BinaryOperation * expr)827 void FullCodeGenerator::VisitArithmeticExpression(BinaryOperation* expr) {
828 Token::Value op = expr->op();
829 Comment cmnt(masm_, "[ ArithmeticExpression");
830 Expression* left = expr->left();
831 Expression* right = expr->right();
832
833 VisitForStackValue(left);
834 VisitForAccumulatorValue(right);
835
836 SetExpressionPosition(expr);
837 if (ShouldInlineSmiCase(op)) {
838 EmitInlineSmiBinaryOp(expr, op, left, right);
839 } else {
840 EmitBinaryOp(expr, op);
841 }
842 }
843
VisitProperty(Property * expr)844 void FullCodeGenerator::VisitProperty(Property* expr) {
845 Comment cmnt(masm_, "[ Property");
846 SetExpressionPosition(expr);
847
848 Expression* key = expr->key();
849
850 if (key->IsPropertyName()) {
851 DCHECK(!expr->IsSuperAccess());
852 VisitForAccumulatorValue(expr->obj());
853 __ Move(LoadDescriptor::ReceiverRegister(), result_register());
854 EmitNamedPropertyLoad(expr);
855 } else {
856 DCHECK(!expr->IsSuperAccess());
857 VisitForStackValue(expr->obj());
858 VisitForAccumulatorValue(expr->key());
859 __ Move(LoadDescriptor::NameRegister(), result_register());
860 PopOperand(LoadDescriptor::ReceiverRegister());
861 EmitKeyedPropertyLoad(expr);
862 }
863 PrepareForBailoutForId(expr->LoadId(), BailoutState::TOS_REGISTER);
864 context()->Plug(result_register());
865 }
866
VisitForTypeofValue(Expression * expr)867 void FullCodeGenerator::VisitForTypeofValue(Expression* expr) {
868 VariableProxy* proxy = expr->AsVariableProxy();
869 DCHECK(!context()->IsEffect());
870 DCHECK(!context()->IsTest());
871
872 if (proxy != NULL && proxy->var()->IsUnallocated()) {
873 EmitVariableLoad(proxy, INSIDE_TYPEOF);
874 PrepareForBailout(proxy, BailoutState::TOS_REGISTER);
875 } else {
876 // This expression cannot throw a reference error at the top level.
877 VisitInDuplicateContext(expr);
878 }
879 }
880
881
VisitBlock(Block * stmt)882 void FullCodeGenerator::VisitBlock(Block* stmt) {
883 Comment cmnt(masm_, "[ Block");
884 NestedBlock nested_block(this, stmt);
885
886 {
887 EnterBlockScopeIfNeeded block_scope_state(
888 this, stmt->scope(), stmt->EntryId(), stmt->DeclsId(), stmt->ExitId());
889 VisitStatements(stmt->statements());
890 __ bind(nested_block.break_label());
891 }
892 }
893
894
VisitDoExpression(DoExpression * expr)895 void FullCodeGenerator::VisitDoExpression(DoExpression* expr) {
896 Comment cmnt(masm_, "[ Do Expression");
897 SetExpressionPosition(expr);
898 VisitBlock(expr->block());
899 VisitInDuplicateContext(expr->result());
900 }
901
902
VisitExpressionStatement(ExpressionStatement * stmt)903 void FullCodeGenerator::VisitExpressionStatement(ExpressionStatement* stmt) {
904 Comment cmnt(masm_, "[ ExpressionStatement");
905 SetStatementPosition(stmt);
906 VisitForEffect(stmt->expression());
907 }
908
909
VisitEmptyStatement(EmptyStatement * stmt)910 void FullCodeGenerator::VisitEmptyStatement(EmptyStatement* stmt) {
911 Comment cmnt(masm_, "[ EmptyStatement");
912 }
913
914
VisitIfStatement(IfStatement * stmt)915 void FullCodeGenerator::VisitIfStatement(IfStatement* stmt) {
916 Comment cmnt(masm_, "[ IfStatement");
917 SetStatementPosition(stmt);
918 Label then_part, else_part, done;
919
920 if (stmt->HasElseStatement()) {
921 VisitForControl(stmt->condition(), &then_part, &else_part, &then_part);
922 PrepareForBailoutForId(stmt->ThenId(), BailoutState::NO_REGISTERS);
923 __ bind(&then_part);
924 Visit(stmt->then_statement());
925 __ jmp(&done);
926
927 PrepareForBailoutForId(stmt->ElseId(), BailoutState::NO_REGISTERS);
928 __ bind(&else_part);
929 Visit(stmt->else_statement());
930 } else {
931 VisitForControl(stmt->condition(), &then_part, &done, &then_part);
932 PrepareForBailoutForId(stmt->ThenId(), BailoutState::NO_REGISTERS);
933 __ bind(&then_part);
934 Visit(stmt->then_statement());
935
936 PrepareForBailoutForId(stmt->ElseId(), BailoutState::NO_REGISTERS);
937 }
938 __ bind(&done);
939 PrepareForBailoutForId(stmt->IfId(), BailoutState::NO_REGISTERS);
940 }
941
EmitContinue(Statement * target)942 void FullCodeGenerator::EmitContinue(Statement* target) {
943 NestedStatement* current = nesting_stack_;
944 int context_length = 0;
945 // When continuing, we clobber the unpredictable value in the accumulator
946 // with one that's safe for GC.
947 ClearAccumulator();
948 while (!current->IsContinueTarget(target)) {
949 if (HasStackOverflow()) return;
950 current = current->Exit(&context_length);
951 }
952 int stack_depth = current->GetStackDepthAtTarget();
953 int stack_drop = operand_stack_depth_ - stack_depth;
954 DCHECK_GE(stack_drop, 0);
955 __ Drop(stack_drop);
956 if (context_length > 0) {
957 while (context_length > 0) {
958 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
959 --context_length;
960 }
961 StoreToFrameField(StandardFrameConstants::kContextOffset,
962 context_register());
963 }
964
965 __ jmp(current->AsIteration()->continue_label());
966 }
967
VisitContinueStatement(ContinueStatement * stmt)968 void FullCodeGenerator::VisitContinueStatement(ContinueStatement* stmt) {
969 Comment cmnt(masm_, "[ ContinueStatement");
970 SetStatementPosition(stmt);
971 EmitContinue(stmt->target());
972 }
973
EmitBreak(Statement * target)974 void FullCodeGenerator::EmitBreak(Statement* target) {
975 NestedStatement* current = nesting_stack_;
976 int context_length = 0;
977 // When breaking, we clobber the unpredictable value in the accumulator
978 // with one that's safe for GC.
979 ClearAccumulator();
980 while (!current->IsBreakTarget(target)) {
981 if (HasStackOverflow()) return;
982 current = current->Exit(&context_length);
983 }
984 int stack_depth = current->GetStackDepthAtTarget();
985 int stack_drop = operand_stack_depth_ - stack_depth;
986 DCHECK_GE(stack_drop, 0);
987 __ Drop(stack_drop);
988 if (context_length > 0) {
989 while (context_length > 0) {
990 LoadContextField(context_register(), Context::PREVIOUS_INDEX);
991 --context_length;
992 }
993 StoreToFrameField(StandardFrameConstants::kContextOffset,
994 context_register());
995 }
996
997 __ jmp(current->AsBreakable()->break_label());
998 }
999
VisitBreakStatement(BreakStatement * stmt)1000 void FullCodeGenerator::VisitBreakStatement(BreakStatement* stmt) {
1001 Comment cmnt(masm_, "[ BreakStatement");
1002 SetStatementPosition(stmt);
1003 EmitBreak(stmt->target());
1004 }
1005
EmitUnwindAndReturn()1006 void FullCodeGenerator::EmitUnwindAndReturn() {
1007 NestedStatement* current = nesting_stack_;
1008 int context_length = 0;
1009 while (current != NULL) {
1010 if (HasStackOverflow()) return;
1011 current = current->Exit(&context_length);
1012 }
1013 EmitReturnSequence();
1014 }
1015
EmitNewClosure(Handle<SharedFunctionInfo> info,FeedbackSlot slot,bool pretenure)1016 void FullCodeGenerator::EmitNewClosure(Handle<SharedFunctionInfo> info,
1017 FeedbackSlot slot, bool pretenure) {
1018 // If slot is invalid, then it's a native function literal and we
1019 // can pass the empty array or empty literal array, something like that...
1020
1021 // If we're running with the --always-opt or the --prepare-always-opt
1022 // flag, we need to use the runtime function so that the new function
1023 // we are creating here gets a chance to have its code optimized and
1024 // doesn't just get a copy of the existing unoptimized code.
1025 if (!FLAG_always_opt && !FLAG_prepare_always_opt && !pretenure &&
1026 scope()->is_function_scope()) {
1027 Callable callable = CodeFactory::FastNewClosure(isolate());
1028 __ Move(callable.descriptor().GetRegisterParameter(0), info);
1029 __ EmitLoadFeedbackVector(callable.descriptor().GetRegisterParameter(1));
1030 __ Move(callable.descriptor().GetRegisterParameter(2), SmiFromSlot(slot));
1031 __ Call(callable.code(), RelocInfo::CODE_TARGET);
1032 } else {
1033 __ Push(info);
1034 __ EmitLoadFeedbackVector(result_register());
1035 __ Push(result_register());
1036 __ Push(SmiFromSlot(slot));
1037 __ CallRuntime(pretenure ? Runtime::kNewClosure_Tenured
1038 : Runtime::kNewClosure);
1039 }
1040 context()->Plug(result_register());
1041 }
1042
EmitNamedPropertyLoad(Property * prop)1043 void FullCodeGenerator::EmitNamedPropertyLoad(Property* prop) {
1044 SetExpressionPosition(prop);
1045 Literal* key = prop->key()->AsLiteral();
1046 DCHECK(!key->value()->IsSmi());
1047 DCHECK(!prop->IsSuperAccess());
1048
1049 CallLoadIC(prop->PropertyFeedbackSlot(), key->value());
1050 }
1051
EmitKeyedPropertyLoad(Property * prop)1052 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
1053 SetExpressionPosition(prop);
1054
1055 EmitLoadSlot(LoadDescriptor::SlotRegister(), prop->PropertyFeedbackSlot());
1056
1057 Handle<Code> code = CodeFactory::KeyedLoadIC(isolate()).code();
1058 __ Call(code, RelocInfo::CODE_TARGET);
1059 RestoreContext();
1060 }
1061
EmitLoadSlot(Register destination,FeedbackSlot slot)1062 void FullCodeGenerator::EmitLoadSlot(Register destination, FeedbackSlot slot) {
1063 DCHECK(!slot.IsInvalid());
1064 __ Move(destination, SmiFromSlot(slot));
1065 }
1066
EmitPushSlot(FeedbackSlot slot)1067 void FullCodeGenerator::EmitPushSlot(FeedbackSlot slot) {
1068 __ Push(SmiFromSlot(slot));
1069 }
1070
VisitReturnStatement(ReturnStatement * stmt)1071 void FullCodeGenerator::VisitReturnStatement(ReturnStatement* stmt) {
1072 Comment cmnt(masm_, "[ ReturnStatement");
1073 SetStatementPosition(stmt);
1074 Expression* expr = stmt->expression();
1075 VisitForAccumulatorValue(expr);
1076 EmitUnwindAndReturn();
1077 }
1078
1079
VisitWithStatement(WithStatement * stmt)1080 void FullCodeGenerator::VisitWithStatement(WithStatement* stmt) {
1081 // Dynamic scoping is not supported.
1082 UNREACHABLE();
1083 }
1084
1085
VisitDoWhileStatement(DoWhileStatement * stmt)1086 void FullCodeGenerator::VisitDoWhileStatement(DoWhileStatement* stmt) {
1087 Comment cmnt(masm_, "[ DoWhileStatement");
1088 // Do not insert break location as we do that below.
1089 SetStatementPosition(stmt, SKIP_BREAK);
1090
1091 Label body, book_keeping;
1092
1093 Iteration loop_statement(this, stmt);
1094 increment_loop_depth();
1095
1096 __ bind(&body);
1097 Visit(stmt->body());
1098
1099 // Record the position of the do while condition and make sure it is
1100 // possible to break on the condition.
1101 __ bind(loop_statement.continue_label());
1102 PrepareForBailoutForId(stmt->ContinueId(), BailoutState::NO_REGISTERS);
1103
1104 // Here is the actual 'while' keyword.
1105 SetExpressionAsStatementPosition(stmt->cond());
1106 VisitForControl(stmt->cond(),
1107 &book_keeping,
1108 loop_statement.break_label(),
1109 &book_keeping);
1110
1111 // Check stack before looping.
1112 PrepareForBailoutForId(stmt->BackEdgeId(), BailoutState::NO_REGISTERS);
1113 __ bind(&book_keeping);
1114 EmitBackEdgeBookkeeping(stmt, &body);
1115 __ jmp(&body);
1116
1117 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
1118 __ bind(loop_statement.break_label());
1119 decrement_loop_depth();
1120 }
1121
1122
VisitWhileStatement(WhileStatement * stmt)1123 void FullCodeGenerator::VisitWhileStatement(WhileStatement* stmt) {
1124 Comment cmnt(masm_, "[ WhileStatement");
1125 Label loop, body;
1126
1127 Iteration loop_statement(this, stmt);
1128 increment_loop_depth();
1129
1130 __ bind(&loop);
1131
1132 SetExpressionAsStatementPosition(stmt->cond());
1133 VisitForControl(stmt->cond(),
1134 &body,
1135 loop_statement.break_label(),
1136 &body);
1137
1138 PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
1139 __ bind(&body);
1140 Visit(stmt->body());
1141
1142 __ bind(loop_statement.continue_label());
1143
1144 // Check stack before looping.
1145 EmitBackEdgeBookkeeping(stmt, &loop);
1146 __ jmp(&loop);
1147
1148 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
1149 __ bind(loop_statement.break_label());
1150 decrement_loop_depth();
1151 }
1152
1153
VisitForStatement(ForStatement * stmt)1154 void FullCodeGenerator::VisitForStatement(ForStatement* stmt) {
1155 Comment cmnt(masm_, "[ ForStatement");
1156 // Do not insert break location as we do it below.
1157 SetStatementPosition(stmt, SKIP_BREAK);
1158
1159 Label test, body;
1160
1161 Iteration loop_statement(this, stmt);
1162
1163 if (stmt->init() != NULL) {
1164 Visit(stmt->init());
1165 }
1166
1167 increment_loop_depth();
1168 // Emit the test at the bottom of the loop (even if empty).
1169 __ jmp(&test);
1170
1171 PrepareForBailoutForId(stmt->BodyId(), BailoutState::NO_REGISTERS);
1172 __ bind(&body);
1173 Visit(stmt->body());
1174
1175 PrepareForBailoutForId(stmt->ContinueId(), BailoutState::NO_REGISTERS);
1176 __ bind(loop_statement.continue_label());
1177 if (stmt->next() != NULL) {
1178 SetStatementPosition(stmt->next());
1179 Visit(stmt->next());
1180 }
1181
1182 // Check stack before looping.
1183 EmitBackEdgeBookkeeping(stmt, &body);
1184
1185 __ bind(&test);
1186 if (stmt->cond() != NULL) {
1187 SetExpressionAsStatementPosition(stmt->cond());
1188 VisitForControl(stmt->cond(),
1189 &body,
1190 loop_statement.break_label(),
1191 loop_statement.break_label());
1192 } else {
1193 __ jmp(&body);
1194 }
1195
1196 PrepareForBailoutForId(stmt->ExitId(), BailoutState::NO_REGISTERS);
1197 __ bind(loop_statement.break_label());
1198 decrement_loop_depth();
1199 }
1200
1201
VisitForOfStatement(ForOfStatement * stmt)1202 void FullCodeGenerator::VisitForOfStatement(ForOfStatement* stmt) {
1203 // Iterator looping is not supported.
1204 UNREACHABLE();
1205 }
1206
VisitThisFunction(ThisFunction * expr)1207 void FullCodeGenerator::VisitThisFunction(ThisFunction* expr) {
1208 LoadFromFrameField(JavaScriptFrameConstants::kFunctionOffset,
1209 result_register());
1210 context()->Plug(result_register());
1211 }
1212
VisitTryCatchStatement(TryCatchStatement * stmt)1213 void FullCodeGenerator::VisitTryCatchStatement(TryCatchStatement* stmt) {
1214 // Exception handling is not supported.
1215 UNREACHABLE();
1216 }
1217
1218
VisitTryFinallyStatement(TryFinallyStatement * stmt)1219 void FullCodeGenerator::VisitTryFinallyStatement(TryFinallyStatement* stmt) {
1220 // Exception handling is not supported.
1221 UNREACHABLE();
1222 }
1223
1224
VisitDebuggerStatement(DebuggerStatement * stmt)1225 void FullCodeGenerator::VisitDebuggerStatement(DebuggerStatement* stmt) {
1226 // Debugger statement is not supported.
1227 UNREACHABLE();
1228 }
1229
1230
VisitCaseClause(CaseClause * clause)1231 void FullCodeGenerator::VisitCaseClause(CaseClause* clause) {
1232 UNREACHABLE();
1233 }
1234
1235
VisitConditional(Conditional * expr)1236 void FullCodeGenerator::VisitConditional(Conditional* expr) {
1237 Comment cmnt(masm_, "[ Conditional");
1238 Label true_case, false_case, done;
1239 VisitForControl(expr->condition(), &true_case, &false_case, &true_case);
1240
1241 int original_stack_depth = operand_stack_depth_;
1242 PrepareForBailoutForId(expr->ThenId(), BailoutState::NO_REGISTERS);
1243 __ bind(&true_case);
1244 SetExpressionPosition(expr->then_expression());
1245 if (context()->IsTest()) {
1246 const TestContext* for_test = TestContext::cast(context());
1247 VisitForControl(expr->then_expression(),
1248 for_test->true_label(),
1249 for_test->false_label(),
1250 NULL);
1251 } else {
1252 VisitInDuplicateContext(expr->then_expression());
1253 __ jmp(&done);
1254 }
1255
1256 operand_stack_depth_ = original_stack_depth;
1257 PrepareForBailoutForId(expr->ElseId(), BailoutState::NO_REGISTERS);
1258 __ bind(&false_case);
1259 SetExpressionPosition(expr->else_expression());
1260 VisitInDuplicateContext(expr->else_expression());
1261 // If control flow falls through Visit, merge it with true case here.
1262 if (!context()->IsTest()) {
1263 __ bind(&done);
1264 }
1265 }
1266
1267
VisitLiteral(Literal * expr)1268 void FullCodeGenerator::VisitLiteral(Literal* expr) {
1269 Comment cmnt(masm_, "[ Literal");
1270 context()->Plug(expr->value());
1271 }
1272
1273
VisitFunctionLiteral(FunctionLiteral * expr)1274 void FullCodeGenerator::VisitFunctionLiteral(FunctionLiteral* expr) {
1275 Comment cmnt(masm_, "[ FunctionLiteral");
1276
1277 // Build the function boilerplate and instantiate it.
1278 Handle<SharedFunctionInfo> function_info =
1279 Compiler::GetSharedFunctionInfo(expr, script(), info_);
1280 if (function_info.is_null()) {
1281 SetStackOverflow();
1282 return;
1283 }
1284 EmitNewClosure(function_info, expr->LiteralFeedbackSlot(), expr->pretenure());
1285 }
1286
1287
VisitClassLiteral(ClassLiteral * lit)1288 void FullCodeGenerator::VisitClassLiteral(ClassLiteral* lit) {
1289 // Unsupported
1290 UNREACHABLE();
1291 }
1292
VisitRegExpLiteral(RegExpLiteral * expr)1293 void FullCodeGenerator::VisitRegExpLiteral(RegExpLiteral* expr) {
1294 Comment cmnt(masm_, "[ RegExpLiteral");
1295 Callable callable = CodeFactory::FastCloneRegExp(isolate());
1296 CallInterfaceDescriptor descriptor = callable.descriptor();
1297 LoadFromFrameField(JavaScriptFrameConstants::kFunctionOffset,
1298 descriptor.GetRegisterParameter(0));
1299 __ Move(descriptor.GetRegisterParameter(1),
1300 SmiFromSlot(expr->literal_slot()));
1301 __ Move(descriptor.GetRegisterParameter(2), expr->pattern());
1302 __ Move(descriptor.GetRegisterParameter(3), Smi::FromInt(expr->flags()));
1303 __ Call(callable.code(), RelocInfo::CODE_TARGET);
1304
1305 // Reload the context register after the call as i.e. TurboFan code stubs
1306 // won't preserve the context register.
1307 LoadFromFrameField(StandardFrameConstants::kContextOffset,
1308 context_register());
1309 context()->Plug(result_register());
1310 }
1311
VisitNativeFunctionLiteral(NativeFunctionLiteral * expr)1312 void FullCodeGenerator::VisitNativeFunctionLiteral(
1313 NativeFunctionLiteral* expr) {
1314 Comment cmnt(masm_, "[ NativeFunctionLiteral");
1315 Handle<SharedFunctionInfo> shared =
1316 Compiler::GetSharedFunctionInfoForNative(expr->extension(), expr->name());
1317 EmitNewClosure(shared, expr->LiteralFeedbackSlot(), false);
1318 }
1319
1320
VisitThrow(Throw * expr)1321 void FullCodeGenerator::VisitThrow(Throw* expr) {
1322 Comment cmnt(masm_, "[ Throw");
1323 VisitForStackValue(expr->exception());
1324 SetExpressionPosition(expr);
1325 CallRuntimeWithOperands(Runtime::kThrow);
1326 // Never returns here.
1327
1328 // Even though this expression doesn't produce a value, we need to simulate
1329 // plugging of the value context to ensure stack depth tracking is in sync.
1330 if (context()->IsStackValue()) OperandStackDepthIncrement(1);
1331 }
1332
1333
VisitCall(Call * expr)1334 void FullCodeGenerator::VisitCall(Call* expr) {
1335 #ifdef DEBUG
1336 // We want to verify that RecordJSReturnSite gets called on all paths
1337 // through this function. Avoid early returns.
1338 expr->return_is_recorded_ = false;
1339 #endif
1340
1341 Comment cmnt(masm_, (expr->tail_call_mode() == TailCallMode::kAllow)
1342 ? "[ TailCall"
1343 : "[ Call");
1344 Expression* callee = expr->expression();
1345 Call::CallType call_type = expr->GetCallType();
1346
1347 // Eval is unsupported.
1348 CHECK(!expr->is_possibly_eval());
1349
1350 switch (call_type) {
1351 case Call::GLOBAL_CALL:
1352 EmitCallWithLoadIC(expr);
1353 break;
1354 case Call::NAMED_PROPERTY_CALL: {
1355 Property* property = callee->AsProperty();
1356 VisitForStackValue(property->obj());
1357 EmitCallWithLoadIC(expr);
1358 break;
1359 }
1360 case Call::KEYED_PROPERTY_CALL: {
1361 Property* property = callee->AsProperty();
1362 VisitForStackValue(property->obj());
1363 EmitKeyedCallWithLoadIC(expr, property->key());
1364 break;
1365 }
1366 case Call::OTHER_CALL:
1367 // Call to an arbitrary expression not handled specially above.
1368 VisitForStackValue(callee);
1369 OperandStackDepthIncrement(1);
1370 __ PushRoot(Heap::kUndefinedValueRootIndex);
1371 // Emit function call.
1372 EmitCall(expr);
1373 break;
1374 case Call::NAMED_SUPER_PROPERTY_CALL:
1375 case Call::KEYED_SUPER_PROPERTY_CALL:
1376 case Call::SUPER_CALL:
1377 case Call::WITH_CALL:
1378 UNREACHABLE();
1379 }
1380
1381 #ifdef DEBUG
1382 // RecordJSReturnSite should have been called.
1383 DCHECK(expr->return_is_recorded_);
1384 #endif
1385 }
1386
VisitCallRuntime(CallRuntime * expr)1387 void FullCodeGenerator::VisitCallRuntime(CallRuntime* expr) {
1388 ZoneList<Expression*>* args = expr->arguments();
1389 int arg_count = args->length();
1390
1391 if (expr->is_jsruntime()) {
1392 Comment cmnt(masm_, "[ CallRuntime");
1393 EmitLoadJSRuntimeFunction(expr);
1394
1395 // Push the arguments ("left-to-right").
1396 for (int i = 0; i < arg_count; i++) {
1397 VisitForStackValue(args->at(i));
1398 }
1399
1400 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
1401 EmitCallJSRuntimeFunction(expr);
1402 context()->DropAndPlug(1, result_register());
1403
1404 } else {
1405 const Runtime::Function* function = expr->function();
1406 switch (function->function_id) {
1407 #define CALL_INTRINSIC_GENERATOR(Name) \
1408 case Runtime::kInline##Name: { \
1409 Comment cmnt(masm_, "[ Inline" #Name); \
1410 return Emit##Name(expr); \
1411 }
1412 FOR_EACH_FULL_CODE_INTRINSIC(CALL_INTRINSIC_GENERATOR)
1413 #undef CALL_INTRINSIC_GENERATOR
1414 default: {
1415 Comment cmnt(masm_, "[ CallRuntime for unhandled intrinsic");
1416 // Push the arguments ("left-to-right").
1417 for (int i = 0; i < arg_count; i++) {
1418 VisitForStackValue(args->at(i));
1419 }
1420
1421 // Call the C runtime function.
1422 PrepareForBailoutForId(expr->CallId(), BailoutState::NO_REGISTERS);
1423 __ CallRuntime(expr->function(), arg_count);
1424 OperandStackDepthDecrement(arg_count);
1425 context()->Plug(result_register());
1426 }
1427 }
1428 }
1429 }
1430
VisitSpread(Spread * expr)1431 void FullCodeGenerator::VisitSpread(Spread* expr) { UNREACHABLE(); }
1432
1433
VisitEmptyParentheses(EmptyParentheses * expr)1434 void FullCodeGenerator::VisitEmptyParentheses(EmptyParentheses* expr) {
1435 UNREACHABLE();
1436 }
1437
VisitGetIterator(GetIterator * expr)1438 void FullCodeGenerator::VisitGetIterator(GetIterator* expr) { UNREACHABLE(); }
1439
VisitRewritableExpression(RewritableExpression * expr)1440 void FullCodeGenerator::VisitRewritableExpression(RewritableExpression* expr) {
1441 Visit(expr->expression());
1442 }
1443
1444
TryLiteralCompare(CompareOperation * expr)1445 bool FullCodeGenerator::TryLiteralCompare(CompareOperation* expr) {
1446 Expression* sub_expr;
1447 Handle<String> check;
1448 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) {
1449 SetExpressionPosition(expr);
1450 EmitLiteralCompareTypeof(expr, sub_expr, check);
1451 return true;
1452 }
1453
1454 if (expr->IsLiteralCompareUndefined(&sub_expr)) {
1455 SetExpressionPosition(expr);
1456 EmitLiteralCompareNil(expr, sub_expr, kUndefinedValue);
1457 return true;
1458 }
1459
1460 if (expr->IsLiteralCompareNull(&sub_expr)) {
1461 SetExpressionPosition(expr);
1462 EmitLiteralCompareNil(expr, sub_expr, kNullValue);
1463 return true;
1464 }
1465
1466 return false;
1467 }
1468
1469
Patch(Isolate * isolate,Code * unoptimized)1470 void BackEdgeTable::Patch(Isolate* isolate, Code* unoptimized) {
1471 DisallowHeapAllocation no_gc;
1472 Code* patch = isolate->builtins()->builtin(Builtins::kOnStackReplacement);
1473
1474 // Increment loop nesting level by one and iterate over the back edge table
1475 // to find the matching loops to patch the interrupt
1476 // call to an unconditional call to the replacement code.
1477 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level() + 1;
1478 if (loop_nesting_level > AbstractCode::kMaxLoopNestingMarker) return;
1479
1480 BackEdgeTable back_edges(unoptimized, &no_gc);
1481 for (uint32_t i = 0; i < back_edges.length(); i++) {
1482 if (static_cast<int>(back_edges.loop_depth(i)) == loop_nesting_level) {
1483 DCHECK_EQ(INTERRUPT, GetBackEdgeState(isolate,
1484 unoptimized,
1485 back_edges.pc(i)));
1486 PatchAt(unoptimized, back_edges.pc(i), ON_STACK_REPLACEMENT, patch);
1487 }
1488 }
1489
1490 unoptimized->set_allow_osr_at_loop_nesting_level(loop_nesting_level);
1491 DCHECK(Verify(isolate, unoptimized));
1492 }
1493
1494
Revert(Isolate * isolate,Code * unoptimized)1495 void BackEdgeTable::Revert(Isolate* isolate, Code* unoptimized) {
1496 DisallowHeapAllocation no_gc;
1497 Code* patch = isolate->builtins()->builtin(Builtins::kInterruptCheck);
1498
1499 // Iterate over the back edge table and revert the patched interrupt calls.
1500 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
1501
1502 BackEdgeTable back_edges(unoptimized, &no_gc);
1503 for (uint32_t i = 0; i < back_edges.length(); i++) {
1504 if (static_cast<int>(back_edges.loop_depth(i)) <= loop_nesting_level) {
1505 DCHECK_NE(INTERRUPT, GetBackEdgeState(isolate,
1506 unoptimized,
1507 back_edges.pc(i)));
1508 PatchAt(unoptimized, back_edges.pc(i), INTERRUPT, patch);
1509 }
1510 }
1511
1512 unoptimized->set_allow_osr_at_loop_nesting_level(0);
1513 // Assert that none of the back edges are patched anymore.
1514 DCHECK(Verify(isolate, unoptimized));
1515 }
1516
1517
1518 #ifdef DEBUG
Verify(Isolate * isolate,Code * unoptimized)1519 bool BackEdgeTable::Verify(Isolate* isolate, Code* unoptimized) {
1520 DisallowHeapAllocation no_gc;
1521 int loop_nesting_level = unoptimized->allow_osr_at_loop_nesting_level();
1522 BackEdgeTable back_edges(unoptimized, &no_gc);
1523 for (uint32_t i = 0; i < back_edges.length(); i++) {
1524 uint32_t loop_depth = back_edges.loop_depth(i);
1525 CHECK_LE(static_cast<int>(loop_depth), AbstractCode::kMaxLoopNestingMarker);
1526 // Assert that all back edges for shallower loops (and only those)
1527 // have already been patched.
1528 CHECK_EQ((static_cast<int>(loop_depth) <= loop_nesting_level),
1529 GetBackEdgeState(isolate,
1530 unoptimized,
1531 back_edges.pc(i)) != INTERRUPT);
1532 }
1533 return true;
1534 }
1535 #endif // DEBUG
1536
1537
EnterBlockScopeIfNeeded(FullCodeGenerator * codegen,Scope * scope,BailoutId entry_id,BailoutId declarations_id,BailoutId exit_id)1538 FullCodeGenerator::EnterBlockScopeIfNeeded::EnterBlockScopeIfNeeded(
1539 FullCodeGenerator* codegen, Scope* scope, BailoutId entry_id,
1540 BailoutId declarations_id, BailoutId exit_id)
1541 : codegen_(codegen), exit_id_(exit_id) {
1542 saved_scope_ = codegen_->scope();
1543
1544 if (scope == NULL) {
1545 codegen_->PrepareForBailoutForId(entry_id, BailoutState::NO_REGISTERS);
1546 needs_block_context_ = false;
1547 } else {
1548 needs_block_context_ = scope->NeedsContext();
1549 codegen_->scope_ = scope;
1550 {
1551 if (needs_block_context_) {
1552 Comment cmnt(masm(), "[ Extend block context");
1553 codegen_->PushOperand(scope->scope_info());
1554 codegen_->PushFunctionArgumentForContextAllocation();
1555 codegen_->CallRuntimeWithOperands(Runtime::kPushBlockContext);
1556
1557 // Replace the context stored in the frame.
1558 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
1559 codegen_->context_register());
1560 }
1561 CHECK_EQ(0, scope->num_stack_slots());
1562 codegen_->PrepareForBailoutForId(entry_id, BailoutState::NO_REGISTERS);
1563 }
1564 {
1565 Comment cmnt(masm(), "[ Declarations");
1566 codegen_->VisitDeclarations(scope->declarations());
1567 codegen_->PrepareForBailoutForId(declarations_id,
1568 BailoutState::NO_REGISTERS);
1569 }
1570 }
1571 }
1572
1573
~EnterBlockScopeIfNeeded()1574 FullCodeGenerator::EnterBlockScopeIfNeeded::~EnterBlockScopeIfNeeded() {
1575 if (needs_block_context_) {
1576 codegen_->LoadContextField(codegen_->context_register(),
1577 Context::PREVIOUS_INDEX);
1578 // Update local stack frame context field.
1579 codegen_->StoreToFrameField(StandardFrameConstants::kContextOffset,
1580 codegen_->context_register());
1581 }
1582 codegen_->PrepareForBailoutForId(exit_id_, BailoutState::NO_REGISTERS);
1583 codegen_->scope_ = saved_scope_;
1584 }
1585
script()1586 Handle<Script> FullCodeGenerator::script() { return info_->script(); }
1587
language_mode()1588 LanguageMode FullCodeGenerator::language_mode() {
1589 return scope()->language_mode();
1590 }
1591
has_simple_parameters()1592 bool FullCodeGenerator::has_simple_parameters() {
1593 return info_->has_simple_parameters();
1594 }
1595
literal() const1596 FunctionLiteral* FullCodeGenerator::literal() const { return info_->literal(); }
1597
feedback_vector_spec() const1598 const FeedbackVectorSpec* FullCodeGenerator::feedback_vector_spec() const {
1599 return literal()->feedback_vector_spec();
1600 }
1601
1602 #undef __
1603
1604
1605 } // namespace internal
1606 } // namespace v8
1607