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 13 namespace v8 { 14 namespace internal { 15 namespace compiler { 16 17 class 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 34 CodeGenerator::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 62 void CodeGenerator::CreateFrameAccessState(Frame* frame) { 63 FinishFrame(frame); 64 frame_access_state_ = new (code()->zone()) FrameAccessState(frame); 65 } 66 67 Handle<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 246 bool 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 254 void 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 279 bool 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 294 bool 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 309 CodeGenerator::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 319 CodeGenerator::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 394 void 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 421 void 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 432 void 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 488 Label* 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 494 void 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 544 int 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 554 FrameStateDescriptor* 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 563 void 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 581 void 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 626 void 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 677 int 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 700 void 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 788 void CodeGenerator::MarkLazyDeoptSite() { 789 last_lazy_deopt_pc_ = masm()->pc_offset(); 790 } 791 792 DeoptimizationExit* 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 802 int 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 814 OutOfLineCode::OutOfLineCode(CodeGenerator* gen) 815 : frame_(gen->frame()), masm_(gen->masm()), next_(gen->ools_) { 816 gen->ools_ = this; 817 } 818 819 820 OutOfLineCode::~OutOfLineCode() {} 821 822 } // namespace compiler 823 } // namespace internal 824 } // namespace v8 825