1// Copyright 2013 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/compiler/code-generator.h"
6
7#include "src/address-map.h"
8#include "src/compiler/code-generator-impl.h"
9#include "src/compiler/linkage.h"
10#include "src/compiler/pipeline.h"
11#include "src/frames-inl.h"
12
13namespace v8 {
14namespace internal {
15namespace compiler {
16
17class CodeGenerator::JumpTable final : public ZoneObject {
18 public:
19  JumpTable(JumpTable* next, Label** targets, size_t target_count)
20      : next_(next), targets_(targets), target_count_(target_count) {}
21
22  Label* label() { return &label_; }
23  JumpTable* next() const { return next_; }
24  Label** targets() const { return targets_; }
25  size_t target_count() const { return target_count_; }
26
27 private:
28  Label label_;
29  JumpTable* const next_;
30  Label** const targets_;
31  size_t const target_count_;
32};
33
34CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage,
35                             InstructionSequence* code, CompilationInfo* info)
36    : frame_access_state_(nullptr),
37      linkage_(linkage),
38      code_(code),
39      info_(info),
40      labels_(zone()->NewArray<Label>(code->InstructionBlockCount())),
41      current_block_(RpoNumber::Invalid()),
42      current_source_position_(SourcePosition::Unknown()),
43      masm_(info->isolate(), nullptr, 0, CodeObjectRequired::kYes),
44      resolver_(this),
45      safepoints_(code->zone()),
46      handlers_(code->zone()),
47      deoptimization_exits_(code->zone()),
48      deoptimization_states_(code->zone()),
49      deoptimization_literals_(code->zone()),
50      inlined_function_count_(0),
51      translations_(code->zone()),
52      last_lazy_deopt_pc_(0),
53      jump_tables_(nullptr),
54      ools_(nullptr),
55      osr_pc_offset_(-1) {
56  for (int i = 0; i < code->InstructionBlockCount(); ++i) {
57    new (&labels_[i]) Label;
58  }
59  CreateFrameAccessState(frame);
60}
61
62void CodeGenerator::CreateFrameAccessState(Frame* frame) {
63  FinishFrame(frame);
64  frame_access_state_ = new (code()->zone()) FrameAccessState(frame);
65}
66
67Handle<Code> CodeGenerator::GenerateCode() {
68  CompilationInfo* info = this->info();
69
70  // Open a frame scope to indicate that there is a frame on the stack.  The
71  // MANUAL indicates that the scope shouldn't actually generate code to set up
72  // the frame (that is done in AssemblePrologue).
73  FrameScope frame_scope(masm(), StackFrame::MANUAL);
74
75  // Emit a code line info recording start event.
76  PositionsRecorder* recorder = masm()->positions_recorder();
77  LOG_CODE_EVENT(isolate(), CodeStartLinePosInfoRecordEvent(recorder));
78
79  // Place function entry hook if requested to do so.
80  if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) {
81    ProfileEntryHookStub::MaybeCallEntryHook(masm());
82  }
83  // Architecture-specific, linkage-specific prologue.
84  info->set_prologue_offset(masm()->pc_offset());
85
86  // Define deoptimization literals for all inlined functions.
87  DCHECK_EQ(0u, deoptimization_literals_.size());
88  for (const CompilationInfo::InlinedFunctionHolder& inlined :
89       info->inlined_functions()) {
90    if (!inlined.shared_info.is_identical_to(info->shared_info())) {
91      DefineDeoptimizationLiteral(inlined.shared_info);
92    }
93  }
94  inlined_function_count_ = deoptimization_literals_.size();
95
96  // Define deoptimization literals for all unoptimized code objects of inlined
97  // functions. This ensures unoptimized code is kept alive by optimized code.
98  for (const CompilationInfo::InlinedFunctionHolder& inlined :
99       info->inlined_functions()) {
100    if (!inlined.shared_info.is_identical_to(info->shared_info())) {
101      DefineDeoptimizationLiteral(inlined.inlined_code_object_root);
102    }
103  }
104
105  // Assemble all non-deferred blocks, followed by deferred ones.
106  for (int deferred = 0; deferred < 2; ++deferred) {
107    for (const InstructionBlock* block : code()->instruction_blocks()) {
108      if (block->IsDeferred() == (deferred == 0)) {
109        continue;
110      }
111      // Align loop headers on 16-byte boundaries.
112      if (block->IsLoopHeader()) masm()->Align(16);
113      // Ensure lazy deopt doesn't patch handler entry points.
114      if (block->IsHandler()) EnsureSpaceForLazyDeopt();
115      // Bind a label for a block.
116      current_block_ = block->rpo_number();
117      if (FLAG_code_comments) {
118        // TODO(titzer): these code comments are a giant memory leak.
119        Vector<char> buffer = Vector<char>::New(200);
120        char* buffer_start = buffer.start();
121
122        int next = SNPrintF(
123            buffer, "-- B%d start%s%s%s%s", block->rpo_number().ToInt(),
124            block->IsDeferred() ? " (deferred)" : "",
125            block->needs_frame() ? "" : " (no frame)",
126            block->must_construct_frame() ? " (construct frame)" : "",
127            block->must_deconstruct_frame() ? " (deconstruct frame)" : "");
128
129        buffer = buffer.SubVector(next, buffer.length());
130
131        if (block->IsLoopHeader()) {
132          next =
133              SNPrintF(buffer, " (loop up to %d)", block->loop_end().ToInt());
134          buffer = buffer.SubVector(next, buffer.length());
135        }
136        if (block->loop_header().IsValid()) {
137          next =
138              SNPrintF(buffer, " (in loop %d)", block->loop_header().ToInt());
139          buffer = buffer.SubVector(next, buffer.length());
140        }
141        SNPrintF(buffer, " --");
142        masm()->RecordComment(buffer_start);
143      }
144
145      frame_access_state()->MarkHasFrame(block->needs_frame());
146
147      masm()->bind(GetLabel(current_block_));
148      if (block->must_construct_frame()) {
149        AssembleConstructFrame();
150        // We need to setup the root register after we assemble the prologue, to
151        // avoid clobbering callee saved registers in case of C linkage and
152        // using the roots.
153        // TODO(mtrofin): investigate how we can avoid doing this repeatedly.
154        if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) {
155          masm()->InitializeRootRegister();
156        }
157      }
158
159      CodeGenResult result;
160      if (FLAG_enable_embedded_constant_pool && !block->needs_frame()) {
161        ConstantPoolUnavailableScope constant_pool_unavailable(masm());
162        result = AssembleBlock(block);
163      } else {
164        result = AssembleBlock(block);
165      }
166      if (result != kSuccess) return Handle<Code>();
167    }
168  }
169
170  // Assemble all out-of-line code.
171  if (ools_) {
172    masm()->RecordComment("-- Out of line code --");
173    for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) {
174      masm()->bind(ool->entry());
175      ool->Generate();
176      if (ool->exit()->is_bound()) masm()->jmp(ool->exit());
177    }
178  }
179
180  // Assemble all eager deoptimization exits.
181  for (DeoptimizationExit* exit : deoptimization_exits_) {
182    masm()->bind(exit->label());
183    AssembleDeoptimizerCall(exit->deoptimization_id(), Deoptimizer::EAGER);
184  }
185
186  // Ensure there is space for lazy deoptimization in the code.
187  if (info->ShouldEnsureSpaceForLazyDeopt()) {
188    int target_offset = masm()->pc_offset() + Deoptimizer::patch_size();
189    while (masm()->pc_offset() < target_offset) {
190      masm()->nop();
191    }
192  }
193
194  FinishCode(masm());
195
196  // Emit the jump tables.
197  if (jump_tables_) {
198    masm()->Align(kPointerSize);
199    for (JumpTable* table = jump_tables_; table; table = table->next()) {
200      masm()->bind(table->label());
201      AssembleJumpTable(table->targets(), table->target_count());
202    }
203  }
204
205  safepoints()->Emit(masm(), frame()->GetTotalFrameSlotCount());
206
207  Handle<Code> result =
208      v8::internal::CodeGenerator::MakeCodeEpilogue(masm(), info);
209  result->set_is_turbofanned(true);
210  result->set_stack_slots(frame()->GetTotalFrameSlotCount());
211  result->set_safepoint_table_offset(safepoints()->GetCodeOffset());
212
213  // Emit exception handler table.
214  if (!handlers_.empty()) {
215    Handle<HandlerTable> table =
216        Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray(
217            HandlerTable::LengthForReturn(static_cast<int>(handlers_.size())),
218            TENURED));
219    for (size_t i = 0; i < handlers_.size(); ++i) {
220      int position = handlers_[i].handler->pos();
221      HandlerTable::CatchPrediction prediction = handlers_[i].caught_locally
222                                                     ? HandlerTable::CAUGHT
223                                                     : HandlerTable::UNCAUGHT;
224      table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset);
225      table->SetReturnHandler(static_cast<int>(i), position, prediction);
226    }
227    result->set_handler_table(*table);
228  }
229
230  PopulateDeoptimizationData(result);
231
232  // Ensure there is space for lazy deoptimization in the relocation info.
233  if (info->ShouldEnsureSpaceForLazyDeopt()) {
234    Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(result);
235  }
236
237  // Emit a code line info recording stop event.
238  void* line_info = recorder->DetachJITHandlerData();
239  LOG_CODE_EVENT(isolate(), CodeEndLinePosInfoRecordEvent(
240                                AbstractCode::cast(*result), line_info));
241
242  return result;
243}
244
245
246bool CodeGenerator::IsNextInAssemblyOrder(RpoNumber block) const {
247  return code()
248      ->InstructionBlockAt(current_block_)
249      ->ao_number()
250      .IsNext(code()->InstructionBlockAt(block)->ao_number());
251}
252
253
254void CodeGenerator::RecordSafepoint(ReferenceMap* references,
255                                    Safepoint::Kind kind, int arguments,
256                                    Safepoint::DeoptMode deopt_mode) {
257  Safepoint safepoint =
258      safepoints()->DefineSafepoint(masm(), kind, arguments, deopt_mode);
259  int stackSlotToSpillSlotDelta =
260      frame()->GetTotalFrameSlotCount() - frame()->GetSpillSlotCount();
261  for (const InstructionOperand& operand : references->reference_operands()) {
262    if (operand.IsStackSlot()) {
263      int index = LocationOperand::cast(operand).index();
264      DCHECK(index >= 0);
265      // We might index values in the fixed part of the frame (i.e. the
266      // closure pointer or the context pointer); these are not spill slots
267      // and therefore don't work with the SafepointTable currently, but
268      // we also don't need to worry about them, since the GC has special
269      // knowledge about those fields anyway.
270      if (index < stackSlotToSpillSlotDelta) continue;
271      safepoint.DefinePointerSlot(index, zone());
272    } else if (operand.IsRegister() && (kind & Safepoint::kWithRegisters)) {
273      Register reg = LocationOperand::cast(operand).GetRegister();
274      safepoint.DefinePointerRegister(reg, zone());
275    }
276  }
277}
278
279bool CodeGenerator::IsMaterializableFromFrame(Handle<HeapObject> object,
280                                              int* slot_return) {
281  if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) {
282    if (object.is_identical_to(info()->context()) && !info()->is_osr()) {
283      *slot_return = Frame::kContextSlot;
284      return true;
285    } else if (object.is_identical_to(info()->closure())) {
286      *slot_return = Frame::kJSFunctionSlot;
287      return true;
288    }
289  }
290  return false;
291}
292
293
294bool CodeGenerator::IsMaterializableFromRoot(
295    Handle<HeapObject> object, Heap::RootListIndex* index_return) {
296  const CallDescriptor* incoming_descriptor =
297      linkage()->GetIncomingDescriptor();
298  if (incoming_descriptor->flags() & CallDescriptor::kCanUseRoots) {
299    RootIndexMap map(isolate());
300    int root_index = map.Lookup(*object);
301    if (root_index != RootIndexMap::kInvalidRootIndex) {
302      *index_return = static_cast<Heap::RootListIndex>(root_index);
303      return true;
304    }
305  }
306  return false;
307}
308
309CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock(
310    const InstructionBlock* block) {
311  for (int i = block->code_start(); i < block->code_end(); ++i) {
312    Instruction* instr = code()->InstructionAt(i);
313    CodeGenResult result = AssembleInstruction(instr, block);
314    if (result != kSuccess) return result;
315  }
316  return kSuccess;
317}
318
319CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction(
320    Instruction* instr, const InstructionBlock* block) {
321  AssembleGaps(instr);
322  DCHECK_IMPLIES(
323      block->must_deconstruct_frame(),
324      instr != code()->InstructionAt(block->last_instruction_index()) ||
325          instr->IsRet() || instr->IsJump());
326  if (instr->IsJump() && block->must_deconstruct_frame()) {
327    AssembleDeconstructFrame();
328  }
329  AssembleSourcePosition(instr);
330  // Assemble architecture-specific code for the instruction.
331  CodeGenResult result = AssembleArchInstruction(instr);
332  if (result != kSuccess) return result;
333
334  FlagsMode mode = FlagsModeField::decode(instr->opcode());
335  FlagsCondition condition = FlagsConditionField::decode(instr->opcode());
336  switch (mode) {
337    case kFlags_branch: {
338      // Assemble a branch after this instruction.
339      InstructionOperandConverter i(this, instr);
340      RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2);
341      RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1);
342
343      if (true_rpo == false_rpo) {
344        // redundant branch.
345        if (!IsNextInAssemblyOrder(true_rpo)) {
346          AssembleArchJump(true_rpo);
347        }
348        return kSuccess;
349      }
350      if (IsNextInAssemblyOrder(true_rpo)) {
351        // true block is next, can fall through if condition negated.
352        std::swap(true_rpo, false_rpo);
353        condition = NegateFlagsCondition(condition);
354      }
355      BranchInfo branch;
356      branch.condition = condition;
357      branch.true_label = GetLabel(true_rpo);
358      branch.false_label = GetLabel(false_rpo);
359      branch.fallthru = IsNextInAssemblyOrder(false_rpo);
360      // Assemble architecture-specific branch.
361      AssembleArchBranch(instr, &branch);
362      break;
363    }
364    case kFlags_deoptimize: {
365      // Assemble a conditional eager deoptimization after this instruction.
366      InstructionOperandConverter i(this, instr);
367      size_t frame_state_offset = MiscField::decode(instr->opcode());
368      DeoptimizationExit* const exit =
369          AddDeoptimizationExit(instr, frame_state_offset);
370      Label continue_label;
371      BranchInfo branch;
372      branch.condition = condition;
373      branch.true_label = exit->label();
374      branch.false_label = &continue_label;
375      branch.fallthru = true;
376      // Assemble architecture-specific branch.
377      AssembleArchBranch(instr, &branch);
378      masm()->bind(&continue_label);
379      break;
380    }
381    case kFlags_set: {
382      // Assemble a boolean materialization after this instruction.
383      AssembleArchBoolean(instr, condition);
384      break;
385    }
386    case kFlags_none: {
387      break;
388    }
389  }
390  return kSuccess;
391}
392
393
394void CodeGenerator::AssembleSourcePosition(Instruction* instr) {
395  SourcePosition source_position;
396  if (!code()->GetSourcePosition(instr, &source_position)) return;
397  if (source_position == current_source_position_) return;
398  current_source_position_ = source_position;
399  if (source_position.IsUnknown()) return;
400  int code_pos = source_position.raw();
401  masm()->positions_recorder()->RecordPosition(code_pos);
402  if (FLAG_code_comments) {
403    CompilationInfo* info = this->info();
404    if (!info->parse_info()) return;
405    Vector<char> buffer = Vector<char>::New(256);
406    int ln = Script::GetLineNumber(info->script(), code_pos);
407    int cn = Script::GetColumnNumber(info->script(), code_pos);
408    if (info->script()->name()->IsString()) {
409      Handle<String> file(String::cast(info->script()->name()));
410      base::OS::SNPrintF(buffer.start(), buffer.length(), "-- %s:%d:%d --",
411                         file->ToCString().get(), ln, cn);
412    } else {
413      base::OS::SNPrintF(buffer.start(), buffer.length(),
414                         "-- <unknown>:%d:%d --", ln, cn);
415    }
416    masm()->RecordComment(buffer.start());
417  }
418}
419
420
421void CodeGenerator::AssembleGaps(Instruction* instr) {
422  for (int i = Instruction::FIRST_GAP_POSITION;
423       i <= Instruction::LAST_GAP_POSITION; i++) {
424    Instruction::GapPosition inner_pos =
425        static_cast<Instruction::GapPosition>(i);
426    ParallelMove* move = instr->GetParallelMove(inner_pos);
427    if (move != nullptr) resolver()->Resolve(move);
428  }
429}
430
431
432void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) {
433  CompilationInfo* info = this->info();
434  int deopt_count = static_cast<int>(deoptimization_states_.size());
435  if (deopt_count == 0 && !info->is_osr()) return;
436  Handle<DeoptimizationInputData> data =
437      DeoptimizationInputData::New(isolate(), deopt_count, TENURED);
438
439  Handle<ByteArray> translation_array =
440      translations_.CreateByteArray(isolate()->factory());
441
442  data->SetTranslationByteArray(*translation_array);
443  data->SetInlinedFunctionCount(
444      Smi::FromInt(static_cast<int>(inlined_function_count_)));
445  data->SetOptimizationId(Smi::FromInt(info->optimization_id()));
446
447  if (info->has_shared_info()) {
448    data->SetSharedFunctionInfo(*info->shared_info());
449  } else {
450    data->SetSharedFunctionInfo(Smi::FromInt(0));
451  }
452
453  Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(
454      static_cast<int>(deoptimization_literals_.size()), TENURED);
455  {
456    AllowDeferredHandleDereference copy_handles;
457    for (unsigned i = 0; i < deoptimization_literals_.size(); i++) {
458      literals->set(i, *deoptimization_literals_[i]);
459    }
460    data->SetLiteralArray(*literals);
461  }
462
463  if (info->is_osr()) {
464    DCHECK(osr_pc_offset_ >= 0);
465    data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
466    data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
467  } else {
468    BailoutId osr_ast_id = BailoutId::None();
469    data->SetOsrAstId(Smi::FromInt(osr_ast_id.ToInt()));
470    data->SetOsrPcOffset(Smi::FromInt(-1));
471  }
472
473  // Populate deoptimization entries.
474  for (int i = 0; i < deopt_count; i++) {
475    DeoptimizationState* deoptimization_state = deoptimization_states_[i];
476    data->SetAstId(i, deoptimization_state->bailout_id());
477    CHECK(deoptimization_states_[i]);
478    data->SetTranslationIndex(
479        i, Smi::FromInt(deoptimization_states_[i]->translation_id()));
480    data->SetArgumentsStackHeight(i, Smi::FromInt(0));
481    data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset()));
482  }
483
484  code_object->set_deoptimization_data(*data);
485}
486
487
488Label* CodeGenerator::AddJumpTable(Label** targets, size_t target_count) {
489  jump_tables_ = new (zone()) JumpTable(jump_tables_, targets, target_count);
490  return jump_tables_->label();
491}
492
493
494void CodeGenerator::RecordCallPosition(Instruction* instr) {
495  CallDescriptor::Flags flags(MiscField::decode(instr->opcode()));
496
497  bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState);
498
499  RecordSafepoint(
500      instr->reference_map(), Safepoint::kSimple, 0,
501      needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt);
502
503  if (flags & CallDescriptor::kHasExceptionHandler) {
504    InstructionOperandConverter i(this, instr);
505    bool caught = flags & CallDescriptor::kHasLocalCatchHandler;
506    RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1);
507    handlers_.push_back({caught, GetLabel(handler_rpo), masm()->pc_offset()});
508  }
509
510  if (needs_frame_state) {
511    MarkLazyDeoptSite();
512    // If the frame state is present, it starts at argument 1 (just after the
513    // code address).
514    size_t frame_state_offset = 1;
515    FrameStateDescriptor* descriptor =
516        GetFrameStateDescriptor(instr, frame_state_offset);
517    int pc_offset = masm()->pc_offset();
518    int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset,
519                                          descriptor->state_combine());
520    // If the pre-call frame state differs from the post-call one, produce the
521    // pre-call frame state, too.
522    // TODO(jarin) We might want to avoid building the pre-call frame state
523    // because it is only used to get locals and arguments (by the debugger and
524    // f.arguments), and those are the same in the pre-call and post-call
525    // states.
526    if (!descriptor->state_combine().IsOutputIgnored()) {
527      deopt_state_id = BuildTranslation(instr, -1, frame_state_offset,
528                                        OutputFrameStateCombine::Ignore());
529    }
530#if DEBUG
531    // Make sure all the values live in stack slots or they are immediates.
532    // (The values should not live in register because registers are clobbered
533    // by calls.)
534    for (size_t i = 0; i < descriptor->GetSize(); i++) {
535      InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i);
536      CHECK(op->IsStackSlot() || op->IsFPStackSlot() || op->IsImmediate());
537    }
538#endif
539    safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id);
540  }
541}
542
543
544int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) {
545  int result = static_cast<int>(deoptimization_literals_.size());
546  for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) {
547    if (deoptimization_literals_[i].is_identical_to(literal)) return i;
548  }
549  deoptimization_literals_.push_back(literal);
550  return result;
551}
552
553
554FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor(
555    Instruction* instr, size_t frame_state_offset) {
556  InstructionOperandConverter i(this, instr);
557  InstructionSequence::StateId state_id =
558      InstructionSequence::StateId::FromInt(i.InputInt32(frame_state_offset));
559  return code()->GetFrameStateDescriptor(state_id);
560}
561
562
563void CodeGenerator::TranslateStateValueDescriptor(
564    StateValueDescriptor* desc, Translation* translation,
565    InstructionOperandIterator* iter) {
566  if (desc->IsNested()) {
567    translation->BeginCapturedObject(static_cast<int>(desc->size()));
568    for (size_t index = 0; index < desc->fields().size(); index++) {
569      TranslateStateValueDescriptor(&desc->fields()[index], translation, iter);
570    }
571  } else if (desc->IsDuplicate()) {
572    translation->DuplicateObject(static_cast<int>(desc->id()));
573  } else {
574    DCHECK(desc->IsPlain());
575    AddTranslationForOperand(translation, iter->instruction(), iter->Advance(),
576                             desc->type());
577  }
578}
579
580
581void CodeGenerator::TranslateFrameStateDescriptorOperands(
582    FrameStateDescriptor* desc, InstructionOperandIterator* iter,
583    OutputFrameStateCombine combine, Translation* translation) {
584  for (size_t index = 0; index < desc->GetSize(combine); index++) {
585    switch (combine.kind()) {
586      case OutputFrameStateCombine::kPushOutput: {
587        DCHECK(combine.GetPushCount() <= iter->instruction()->OutputCount());
588        size_t size_without_output =
589            desc->GetSize(OutputFrameStateCombine::Ignore());
590        // If the index is past the existing stack items in values_.
591        if (index >= size_without_output) {
592          // Materialize the result of the call instruction in this slot.
593          AddTranslationForOperand(
594              translation, iter->instruction(),
595              iter->instruction()->OutputAt(index - size_without_output),
596              MachineType::AnyTagged());
597          continue;
598        }
599        break;
600      }
601      case OutputFrameStateCombine::kPokeAt:
602        // The result of the call should be placed at position
603        // [index_from_top] in the stack (overwriting whatever was
604        // previously there).
605        size_t index_from_top =
606            desc->GetSize(combine) - 1 - combine.GetOffsetToPokeAt();
607        if (index >= index_from_top &&
608            index < index_from_top + iter->instruction()->OutputCount()) {
609          AddTranslationForOperand(
610              translation, iter->instruction(),
611              iter->instruction()->OutputAt(index - index_from_top),
612              MachineType::AnyTagged());
613          iter->Advance();  // We do not use this input, but we need to
614                            // advace, as the input got replaced.
615          continue;
616        }
617        break;
618    }
619    StateValueDescriptor* value_desc = desc->GetStateValueDescriptor();
620    TranslateStateValueDescriptor(&value_desc->fields()[index], translation,
621                                  iter);
622  }
623}
624
625
626void CodeGenerator::BuildTranslationForFrameStateDescriptor(
627    FrameStateDescriptor* descriptor, InstructionOperandIterator* iter,
628    Translation* translation, OutputFrameStateCombine state_combine) {
629  // Outer-most state must be added to translation first.
630  if (descriptor->outer_state() != nullptr) {
631    BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), iter,
632                                            translation,
633                                            OutputFrameStateCombine::Ignore());
634  }
635
636  Handle<SharedFunctionInfo> shared_info;
637  if (!descriptor->shared_info().ToHandle(&shared_info)) {
638    if (!info()->has_shared_info()) {
639      return;  // Stub with no SharedFunctionInfo.
640    }
641    shared_info = info()->shared_info();
642  }
643  int shared_info_id = DefineDeoptimizationLiteral(shared_info);
644
645  switch (descriptor->type()) {
646    case FrameStateType::kJavaScriptFunction:
647      translation->BeginJSFrame(
648          descriptor->bailout_id(), shared_info_id,
649          static_cast<unsigned int>(descriptor->GetSize(state_combine) -
650                                    (1 + descriptor->parameters_count())));
651      break;
652    case FrameStateType::kInterpretedFunction:
653      translation->BeginInterpretedFrame(
654          descriptor->bailout_id(), shared_info_id,
655          static_cast<unsigned int>(descriptor->locals_count() + 1));
656      break;
657    case FrameStateType::kArgumentsAdaptor:
658      translation->BeginArgumentsAdaptorFrame(
659          shared_info_id,
660          static_cast<unsigned int>(descriptor->parameters_count()));
661      break;
662    case FrameStateType::kTailCallerFunction:
663      translation->BeginTailCallerFrame(shared_info_id);
664      break;
665    case FrameStateType::kConstructStub:
666      translation->BeginConstructStubFrame(
667          shared_info_id,
668          static_cast<unsigned int>(descriptor->parameters_count()));
669      break;
670  }
671
672  TranslateFrameStateDescriptorOperands(descriptor, iter, state_combine,
673                                        translation);
674}
675
676
677int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset,
678                                    size_t frame_state_offset,
679                                    OutputFrameStateCombine state_combine) {
680  FrameStateDescriptor* descriptor =
681      GetFrameStateDescriptor(instr, frame_state_offset);
682  frame_state_offset++;
683
684  Translation translation(
685      &translations_, static_cast<int>(descriptor->GetFrameCount()),
686      static_cast<int>(descriptor->GetJSFrameCount()), zone());
687  InstructionOperandIterator iter(instr, frame_state_offset);
688  BuildTranslationForFrameStateDescriptor(descriptor, &iter, &translation,
689                                          state_combine);
690
691  int deoptimization_id = static_cast<int>(deoptimization_states_.size());
692
693  deoptimization_states_.push_back(new (zone()) DeoptimizationState(
694      descriptor->bailout_id(), translation.index(), pc_offset));
695
696  return deoptimization_id;
697}
698
699
700void CodeGenerator::AddTranslationForOperand(Translation* translation,
701                                             Instruction* instr,
702                                             InstructionOperand* op,
703                                             MachineType type) {
704  if (op->IsStackSlot()) {
705    if (type.representation() == MachineRepresentation::kBit) {
706      translation->StoreBoolStackSlot(LocationOperand::cast(op)->index());
707    } else if (type == MachineType::Int8() || type == MachineType::Int16() ||
708               type == MachineType::Int32()) {
709      translation->StoreInt32StackSlot(LocationOperand::cast(op)->index());
710    } else if (type == MachineType::Uint8() || type == MachineType::Uint16() ||
711               type == MachineType::Uint32()) {
712      translation->StoreUint32StackSlot(LocationOperand::cast(op)->index());
713    } else if (type.representation() == MachineRepresentation::kTagged) {
714      translation->StoreStackSlot(LocationOperand::cast(op)->index());
715    } else {
716      CHECK(false);
717    }
718  } else if (op->IsFPStackSlot()) {
719    if (type.representation() == MachineRepresentation::kFloat64) {
720      translation->StoreDoubleStackSlot(LocationOperand::cast(op)->index());
721    } else {
722      DCHECK_EQ(MachineRepresentation::kFloat32, type.representation());
723      translation->StoreFloatStackSlot(LocationOperand::cast(op)->index());
724    }
725  } else if (op->IsRegister()) {
726    InstructionOperandConverter converter(this, instr);
727    if (type.representation() == MachineRepresentation::kBit) {
728      translation->StoreBoolRegister(converter.ToRegister(op));
729    } else if (type == MachineType::Int8() || type == MachineType::Int16() ||
730               type == MachineType::Int32()) {
731      translation->StoreInt32Register(converter.ToRegister(op));
732    } else if (type == MachineType::Uint8() || type == MachineType::Uint16() ||
733               type == MachineType::Uint32()) {
734      translation->StoreUint32Register(converter.ToRegister(op));
735    } else if (type.representation() == MachineRepresentation::kTagged) {
736      translation->StoreRegister(converter.ToRegister(op));
737    } else {
738      CHECK(false);
739    }
740  } else if (op->IsFPRegister()) {
741    InstructionOperandConverter converter(this, instr);
742    if (type.representation() == MachineRepresentation::kFloat64) {
743      translation->StoreDoubleRegister(converter.ToDoubleRegister(op));
744    } else {
745      DCHECK_EQ(MachineRepresentation::kFloat32, type.representation());
746      translation->StoreFloatRegister(converter.ToFloatRegister(op));
747    }
748  } else if (op->IsImmediate()) {
749    InstructionOperandConverter converter(this, instr);
750    Constant constant = converter.ToConstant(op);
751    Handle<Object> constant_object;
752    switch (constant.type()) {
753      case Constant::kInt32:
754        DCHECK(type == MachineType::Int32() || type == MachineType::Uint32() ||
755               type.representation() == MachineRepresentation::kBit);
756        constant_object =
757            isolate()->factory()->NewNumberFromInt(constant.ToInt32());
758        break;
759      case Constant::kFloat32:
760        DCHECK(type.representation() == MachineRepresentation::kFloat32 ||
761               type.representation() == MachineRepresentation::kTagged);
762        constant_object = isolate()->factory()->NewNumber(constant.ToFloat32());
763        break;
764      case Constant::kFloat64:
765        DCHECK(type.representation() == MachineRepresentation::kFloat64 ||
766               type.representation() == MachineRepresentation::kTagged);
767        constant_object = isolate()->factory()->NewNumber(constant.ToFloat64());
768        break;
769      case Constant::kHeapObject:
770        DCHECK(type.representation() == MachineRepresentation::kTagged);
771        constant_object = constant.ToHeapObject();
772        break;
773      default:
774        CHECK(false);
775    }
776    if (constant_object.is_identical_to(info()->closure())) {
777      translation->StoreJSFrameFunction();
778    } else {
779      int literal_id = DefineDeoptimizationLiteral(constant_object);
780      translation->StoreLiteral(literal_id);
781    }
782  } else {
783    CHECK(false);
784  }
785}
786
787
788void CodeGenerator::MarkLazyDeoptSite() {
789  last_lazy_deopt_pc_ = masm()->pc_offset();
790}
791
792DeoptimizationExit* CodeGenerator::AddDeoptimizationExit(
793    Instruction* instr, size_t frame_state_offset) {
794  int const deoptimization_id = BuildTranslation(
795      instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore());
796  DeoptimizationExit* const exit =
797      new (zone()) DeoptimizationExit(deoptimization_id);
798  deoptimization_exits_.push_back(exit);
799  return exit;
800}
801
802int CodeGenerator::TailCallFrameStackSlotDelta(int stack_param_delta) {
803  // Leave the PC on the stack on platforms that have that as part of their ABI
804  int pc_slots = V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0;
805  int sp_slot_delta = frame_access_state()->has_frame()
806                          ? (frame()->GetTotalFrameSlotCount() - pc_slots)
807                          : 0;
808  // Discard only slots that won't be used by new parameters.
809  sp_slot_delta += stack_param_delta;
810  return sp_slot_delta;
811}
812
813
814OutOfLineCode::OutOfLineCode(CodeGenerator* gen)
815    : frame_(gen->frame()), masm_(gen->masm()), next_(gen->ools_) {
816  gen->ools_ = this;
817}
818
819
820OutOfLineCode::~OutOfLineCode() {}
821
822}  // namespace compiler
823}  // namespace internal
824}  // namespace v8
825