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/base/adapters.h" 9 #include "src/compilation-info.h" 10 #include "src/compiler/code-generator-impl.h" 11 #include "src/compiler/linkage.h" 12 #include "src/compiler/pipeline.h" 13 #include "src/frames-inl.h" 14 15 namespace v8 { 16 namespace internal { 17 namespace compiler { 18 19 class CodeGenerator::JumpTable final : public ZoneObject { 20 public: 21 JumpTable(JumpTable* next, Label** targets, size_t target_count) 22 : next_(next), targets_(targets), target_count_(target_count) {} 23 24 Label* label() { return &label_; } 25 JumpTable* next() const { return next_; } 26 Label** targets() const { return targets_; } 27 size_t target_count() const { return target_count_; } 28 29 private: 30 Label label_; 31 JumpTable* const next_; 32 Label** const targets_; 33 size_t const target_count_; 34 }; 35 36 CodeGenerator::CodeGenerator(Frame* frame, Linkage* linkage, 37 InstructionSequence* code, CompilationInfo* info) 38 : frame_access_state_(nullptr), 39 linkage_(linkage), 40 code_(code), 41 unwinding_info_writer_(zone()), 42 info_(info), 43 labels_(zone()->NewArray<Label>(code->InstructionBlockCount())), 44 current_block_(RpoNumber::Invalid()), 45 current_source_position_(SourcePosition::Unknown()), 46 masm_(info->isolate(), nullptr, 0, CodeObjectRequired::kNo), 47 resolver_(this), 48 safepoints_(code->zone()), 49 handlers_(code->zone()), 50 deoptimization_exits_(code->zone()), 51 deoptimization_states_(code->zone()), 52 deoptimization_literals_(code->zone()), 53 inlined_function_count_(0), 54 translations_(code->zone()), 55 last_lazy_deopt_pc_(0), 56 jump_tables_(nullptr), 57 ools_(nullptr), 58 osr_pc_offset_(-1), 59 optimized_out_literal_id_(-1), 60 source_position_table_builder_(code->zone(), 61 info->SourcePositionRecordingMode()) { 62 for (int i = 0; i < code->InstructionBlockCount(); ++i) { 63 new (&labels_[i]) Label; 64 } 65 CreateFrameAccessState(frame); 66 } 67 68 Isolate* CodeGenerator::isolate() const { return info_->isolate(); } 69 70 void CodeGenerator::CreateFrameAccessState(Frame* frame) { 71 FinishFrame(frame); 72 frame_access_state_ = new (code()->zone()) FrameAccessState(frame); 73 } 74 75 76 Handle<Code> CodeGenerator::GenerateCode() { 77 CompilationInfo* info = this->info(); 78 79 // Open a frame scope to indicate that there is a frame on the stack. The 80 // MANUAL indicates that the scope shouldn't actually generate code to set up 81 // the frame (that is done in AssemblePrologue). 82 FrameScope frame_scope(masm(), StackFrame::MANUAL); 83 84 if (info->is_source_positions_enabled()) { 85 SourcePosition source_position(info->shared_info()->start_position()); 86 AssembleSourcePosition(source_position); 87 } 88 89 // Place function entry hook if requested to do so. 90 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { 91 ProfileEntryHookStub::MaybeCallEntryHook(masm()); 92 } 93 // Architecture-specific, linkage-specific prologue. 94 info->set_prologue_offset(masm()->pc_offset()); 95 96 // Define deoptimization literals for all inlined functions. 97 DCHECK_EQ(0u, deoptimization_literals_.size()); 98 for (CompilationInfo::InlinedFunctionHolder& inlined : 99 info->inlined_functions()) { 100 if (!inlined.shared_info.is_identical_to(info->shared_info())) { 101 int index = DefineDeoptimizationLiteral(inlined.shared_info); 102 inlined.RegisterInlinedFunctionId(index); 103 } 104 } 105 inlined_function_count_ = deoptimization_literals_.size(); 106 107 // Define deoptimization literals for all unoptimized code objects of inlined 108 // functions. This ensures unoptimized code is kept alive by optimized code. 109 for (const CompilationInfo::InlinedFunctionHolder& inlined : 110 info->inlined_functions()) { 111 if (!inlined.shared_info.is_identical_to(info->shared_info())) { 112 DefineDeoptimizationLiteral(inlined.inlined_code_object_root); 113 } 114 } 115 116 unwinding_info_writer_.SetNumberOfInstructionBlocks( 117 code()->InstructionBlockCount()); 118 119 // Assemble all non-deferred blocks, followed by deferred ones. 120 for (int deferred = 0; deferred < 2; ++deferred) { 121 for (const InstructionBlock* block : code()->instruction_blocks()) { 122 if (block->IsDeferred() == (deferred == 0)) { 123 continue; 124 } 125 // Align loop headers on 16-byte boundaries. 126 if (block->IsLoopHeader()) masm()->Align(16); 127 // Ensure lazy deopt doesn't patch handler entry points. 128 if (block->IsHandler()) EnsureSpaceForLazyDeopt(); 129 // Bind a label for a block. 130 current_block_ = block->rpo_number(); 131 unwinding_info_writer_.BeginInstructionBlock(masm()->pc_offset(), block); 132 if (FLAG_code_comments) { 133 // TODO(titzer): these code comments are a giant memory leak. 134 Vector<char> buffer = Vector<char>::New(200); 135 char* buffer_start = buffer.start(); 136 137 int next = SNPrintF( 138 buffer, "-- B%d start%s%s%s%s", block->rpo_number().ToInt(), 139 block->IsDeferred() ? " (deferred)" : "", 140 block->needs_frame() ? "" : " (no frame)", 141 block->must_construct_frame() ? " (construct frame)" : "", 142 block->must_deconstruct_frame() ? " (deconstruct frame)" : ""); 143 144 buffer = buffer.SubVector(next, buffer.length()); 145 146 if (block->IsLoopHeader()) { 147 next = 148 SNPrintF(buffer, " (loop up to %d)", block->loop_end().ToInt()); 149 buffer = buffer.SubVector(next, buffer.length()); 150 } 151 if (block->loop_header().IsValid()) { 152 next = 153 SNPrintF(buffer, " (in loop %d)", block->loop_header().ToInt()); 154 buffer = buffer.SubVector(next, buffer.length()); 155 } 156 SNPrintF(buffer, " --"); 157 masm()->RecordComment(buffer_start); 158 } 159 160 frame_access_state()->MarkHasFrame(block->needs_frame()); 161 162 masm()->bind(GetLabel(current_block_)); 163 if (block->must_construct_frame()) { 164 AssembleConstructFrame(); 165 // We need to setup the root register after we assemble the prologue, to 166 // avoid clobbering callee saved registers in case of C linkage and 167 // using the roots. 168 // TODO(mtrofin): investigate how we can avoid doing this repeatedly. 169 if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) { 170 masm()->InitializeRootRegister(); 171 } 172 } 173 174 CodeGenResult result; 175 if (FLAG_enable_embedded_constant_pool && !block->needs_frame()) { 176 ConstantPoolUnavailableScope constant_pool_unavailable(masm()); 177 result = AssembleBlock(block); 178 } else { 179 result = AssembleBlock(block); 180 } 181 if (result != kSuccess) return Handle<Code>(); 182 unwinding_info_writer_.EndInstructionBlock(block); 183 } 184 } 185 186 // Assemble all out-of-line code. 187 if (ools_) { 188 masm()->RecordComment("-- Out of line code --"); 189 for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) { 190 masm()->bind(ool->entry()); 191 ool->Generate(); 192 if (ool->exit()->is_bound()) masm()->jmp(ool->exit()); 193 } 194 } 195 196 // Assemble all eager deoptimization exits. 197 for (DeoptimizationExit* exit : deoptimization_exits_) { 198 masm()->bind(exit->label()); 199 AssembleDeoptimizerCall(exit->deoptimization_id(), exit->pos()); 200 } 201 202 // Ensure there is space for lazy deoptimization in the code. 203 if (info->ShouldEnsureSpaceForLazyDeopt()) { 204 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size(); 205 while (masm()->pc_offset() < target_offset) { 206 masm()->nop(); 207 } 208 } 209 210 FinishCode(masm()); 211 212 // Emit the jump tables. 213 if (jump_tables_) { 214 masm()->Align(kPointerSize); 215 for (JumpTable* table = jump_tables_; table; table = table->next()) { 216 masm()->bind(table->label()); 217 AssembleJumpTable(table->targets(), table->target_count()); 218 } 219 } 220 221 safepoints()->Emit(masm(), frame()->GetTotalFrameSlotCount()); 222 223 unwinding_info_writer_.Finish(masm()->pc_offset()); 224 225 Handle<Code> result = v8::internal::CodeGenerator::MakeCodeEpilogue( 226 masm(), unwinding_info_writer_.eh_frame_writer(), info, Handle<Object>()); 227 result->set_is_turbofanned(true); 228 result->set_stack_slots(frame()->GetTotalFrameSlotCount()); 229 result->set_safepoint_table_offset(safepoints()->GetCodeOffset()); 230 Handle<ByteArray> source_positions = 231 source_position_table_builder_.ToSourcePositionTable( 232 isolate(), Handle<AbstractCode>::cast(result)); 233 result->set_source_position_table(*source_positions); 234 235 // Emit exception handler table. 236 if (!handlers_.empty()) { 237 Handle<HandlerTable> table = 238 Handle<HandlerTable>::cast(isolate()->factory()->NewFixedArray( 239 HandlerTable::LengthForReturn(static_cast<int>(handlers_.size())), 240 TENURED)); 241 for (size_t i = 0; i < handlers_.size(); ++i) { 242 table->SetReturnOffset(static_cast<int>(i), handlers_[i].pc_offset); 243 table->SetReturnHandler(static_cast<int>(i), handlers_[i].handler->pos()); 244 } 245 result->set_handler_table(*table); 246 } 247 248 PopulateDeoptimizationData(result); 249 250 // Ensure there is space for lazy deoptimization in the relocation info. 251 if (info->ShouldEnsureSpaceForLazyDeopt()) { 252 Deoptimizer::EnsureRelocSpaceForLazyDeoptimization(result); 253 } 254 255 return result; 256 } 257 258 259 bool CodeGenerator::IsNextInAssemblyOrder(RpoNumber block) const { 260 return code() 261 ->InstructionBlockAt(current_block_) 262 ->ao_number() 263 .IsNext(code()->InstructionBlockAt(block)->ao_number()); 264 } 265 266 267 void CodeGenerator::RecordSafepoint(ReferenceMap* references, 268 Safepoint::Kind kind, int arguments, 269 Safepoint::DeoptMode deopt_mode) { 270 Safepoint safepoint = 271 safepoints()->DefineSafepoint(masm(), kind, arguments, deopt_mode); 272 int stackSlotToSpillSlotDelta = 273 frame()->GetTotalFrameSlotCount() - frame()->GetSpillSlotCount(); 274 for (const InstructionOperand& operand : references->reference_operands()) { 275 if (operand.IsStackSlot()) { 276 int index = LocationOperand::cast(operand).index(); 277 DCHECK(index >= 0); 278 // We might index values in the fixed part of the frame (i.e. the 279 // closure pointer or the context pointer); these are not spill slots 280 // and therefore don't work with the SafepointTable currently, but 281 // we also don't need to worry about them, since the GC has special 282 // knowledge about those fields anyway. 283 if (index < stackSlotToSpillSlotDelta) continue; 284 safepoint.DefinePointerSlot(index, zone()); 285 } else if (operand.IsRegister() && (kind & Safepoint::kWithRegisters)) { 286 Register reg = LocationOperand::cast(operand).GetRegister(); 287 safepoint.DefinePointerRegister(reg, zone()); 288 } 289 } 290 } 291 292 bool CodeGenerator::IsMaterializableFromRoot( 293 Handle<HeapObject> object, Heap::RootListIndex* index_return) { 294 const CallDescriptor* incoming_descriptor = 295 linkage()->GetIncomingDescriptor(); 296 if (incoming_descriptor->flags() & CallDescriptor::kCanUseRoots) { 297 RootIndexMap map(isolate()); 298 int root_index = map.Lookup(*object); 299 if (root_index != RootIndexMap::kInvalidRootIndex) { 300 *index_return = static_cast<Heap::RootListIndex>(root_index); 301 return true; 302 } 303 } 304 return false; 305 } 306 307 CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock( 308 const InstructionBlock* block) { 309 for (int i = block->code_start(); i < block->code_end(); ++i) { 310 Instruction* instr = code()->InstructionAt(i); 311 CodeGenResult result = AssembleInstruction(instr, block); 312 if (result != kSuccess) return result; 313 } 314 return kSuccess; 315 } 316 317 bool CodeGenerator::IsValidPush(InstructionOperand source, 318 CodeGenerator::PushTypeFlags push_type) { 319 if (source.IsImmediate() && 320 ((push_type & CodeGenerator::kImmediatePush) != 0)) { 321 return true; 322 } 323 if ((source.IsRegister() || source.IsStackSlot()) && 324 ((push_type & CodeGenerator::kScalarPush) != 0)) { 325 return true; 326 } 327 if ((source.IsFloatRegister() || source.IsFloatStackSlot()) && 328 ((push_type & CodeGenerator::kFloat32Push) != 0)) { 329 return true; 330 } 331 if ((source.IsDoubleRegister() || source.IsFloatStackSlot()) && 332 ((push_type & CodeGenerator::kFloat64Push) != 0)) { 333 return true; 334 } 335 return false; 336 } 337 338 void CodeGenerator::GetPushCompatibleMoves(Instruction* instr, 339 PushTypeFlags push_type, 340 ZoneVector<MoveOperands*>* pushes) { 341 pushes->clear(); 342 for (int i = Instruction::FIRST_GAP_POSITION; 343 i <= Instruction::LAST_GAP_POSITION; ++i) { 344 Instruction::GapPosition inner_pos = 345 static_cast<Instruction::GapPosition>(i); 346 ParallelMove* parallel_move = instr->GetParallelMove(inner_pos); 347 if (parallel_move != nullptr) { 348 for (auto move : *parallel_move) { 349 InstructionOperand source = move->source(); 350 InstructionOperand destination = move->destination(); 351 int first_push_compatible_index = 352 V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0; 353 // If there are any moves from slots that will be overridden by pushes, 354 // then the full gap resolver must be used since optimization with 355 // pushes don't participate in the parallel move and might clobber 356 // values needed for the gap resolve. 357 if (source.IsStackSlot() && 358 LocationOperand::cast(source).index() >= 359 first_push_compatible_index) { 360 pushes->clear(); 361 return; 362 } 363 // TODO(danno): Right now, only consider moves from the FIRST gap for 364 // pushes. Theoretically, we could extract pushes for both gaps (there 365 // are cases where this happens), but the logic for that would also have 366 // to check to make sure that non-memory inputs to the pushes from the 367 // LAST gap don't get clobbered in the FIRST gap. 368 if (i == Instruction::FIRST_GAP_POSITION) { 369 if (destination.IsStackSlot() && 370 LocationOperand::cast(destination).index() >= 371 first_push_compatible_index) { 372 int index = LocationOperand::cast(destination).index(); 373 if (IsValidPush(source, push_type)) { 374 if (index >= static_cast<int>(pushes->size())) { 375 pushes->resize(index + 1); 376 } 377 (*pushes)[index] = move; 378 } 379 } 380 } 381 } 382 } 383 } 384 385 // For now, only support a set of continuous pushes at the end of the list. 386 size_t push_count_upper_bound = pushes->size(); 387 size_t push_begin = push_count_upper_bound; 388 for (auto move : base::Reversed(*pushes)) { 389 if (move == nullptr) break; 390 push_begin--; 391 } 392 size_t push_count = pushes->size() - push_begin; 393 std::copy(pushes->begin() + push_begin, 394 pushes->begin() + push_begin + push_count, pushes->begin()); 395 pushes->resize(push_count); 396 } 397 398 CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction( 399 Instruction* instr, const InstructionBlock* block) { 400 int first_unused_stack_slot; 401 FlagsMode mode = FlagsModeField::decode(instr->opcode()); 402 if (mode != kFlags_trap) { 403 AssembleSourcePosition(instr); 404 } 405 bool adjust_stack = 406 GetSlotAboveSPBeforeTailCall(instr, &first_unused_stack_slot); 407 if (adjust_stack) AssembleTailCallBeforeGap(instr, first_unused_stack_slot); 408 AssembleGaps(instr); 409 if (adjust_stack) AssembleTailCallAfterGap(instr, first_unused_stack_slot); 410 DCHECK_IMPLIES( 411 block->must_deconstruct_frame(), 412 instr != code()->InstructionAt(block->last_instruction_index()) || 413 instr->IsRet() || instr->IsJump()); 414 if (instr->IsJump() && block->must_deconstruct_frame()) { 415 AssembleDeconstructFrame(); 416 } 417 // Assemble architecture-specific code for the instruction. 418 CodeGenResult result = AssembleArchInstruction(instr); 419 if (result != kSuccess) return result; 420 421 FlagsCondition condition = FlagsConditionField::decode(instr->opcode()); 422 switch (mode) { 423 case kFlags_branch: { 424 // Assemble a branch after this instruction. 425 InstructionOperandConverter i(this, instr); 426 RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2); 427 RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1); 428 429 if (true_rpo == false_rpo) { 430 // redundant branch. 431 if (!IsNextInAssemblyOrder(true_rpo)) { 432 AssembleArchJump(true_rpo); 433 } 434 return kSuccess; 435 } 436 if (IsNextInAssemblyOrder(true_rpo)) { 437 // true block is next, can fall through if condition negated. 438 std::swap(true_rpo, false_rpo); 439 condition = NegateFlagsCondition(condition); 440 } 441 BranchInfo branch; 442 branch.condition = condition; 443 branch.true_label = GetLabel(true_rpo); 444 branch.false_label = GetLabel(false_rpo); 445 branch.fallthru = IsNextInAssemblyOrder(false_rpo); 446 // Assemble architecture-specific branch. 447 AssembleArchBranch(instr, &branch); 448 break; 449 } 450 case kFlags_deoptimize: { 451 // Assemble a conditional eager deoptimization after this instruction. 452 InstructionOperandConverter i(this, instr); 453 size_t frame_state_offset = MiscField::decode(instr->opcode()); 454 DeoptimizationExit* const exit = 455 AddDeoptimizationExit(instr, frame_state_offset); 456 Label continue_label; 457 BranchInfo branch; 458 branch.condition = condition; 459 branch.true_label = exit->label(); 460 branch.false_label = &continue_label; 461 branch.fallthru = true; 462 // Assemble architecture-specific branch. 463 AssembleArchBranch(instr, &branch); 464 masm()->bind(&continue_label); 465 break; 466 } 467 case kFlags_set: { 468 // Assemble a boolean materialization after this instruction. 469 AssembleArchBoolean(instr, condition); 470 break; 471 } 472 case kFlags_trap: { 473 AssembleArchTrap(instr, condition); 474 break; 475 } 476 case kFlags_none: { 477 break; 478 } 479 } 480 return kSuccess; 481 } 482 483 void CodeGenerator::AssembleSourcePosition(Instruction* instr) { 484 SourcePosition source_position = SourcePosition::Unknown(); 485 if (instr->IsNop() && instr->AreMovesRedundant()) return; 486 if (!code()->GetSourcePosition(instr, &source_position)) return; 487 AssembleSourcePosition(source_position); 488 } 489 490 void CodeGenerator::AssembleSourcePosition(SourcePosition source_position) { 491 if (source_position == current_source_position_) return; 492 current_source_position_ = source_position; 493 if (!source_position.IsKnown()) return; 494 source_position_table_builder_.AddPosition(masm()->pc_offset(), 495 source_position, false); 496 if (FLAG_code_comments) { 497 CompilationInfo* info = this->info(); 498 if (!info->parse_info()) return; 499 std::ostringstream buffer; 500 buffer << "-- "; 501 if (FLAG_trace_turbo) { 502 buffer << source_position; 503 } else { 504 buffer << source_position.InliningStack(info); 505 } 506 buffer << " --"; 507 masm()->RecordComment(StrDup(buffer.str().c_str())); 508 } 509 } 510 511 bool CodeGenerator::GetSlotAboveSPBeforeTailCall(Instruction* instr, 512 int* slot) { 513 if (instr->IsTailCall()) { 514 InstructionOperandConverter g(this, instr); 515 *slot = g.InputInt32(instr->InputCount() - 1); 516 return true; 517 } else { 518 return false; 519 } 520 } 521 522 void CodeGenerator::AssembleGaps(Instruction* instr) { 523 for (int i = Instruction::FIRST_GAP_POSITION; 524 i <= Instruction::LAST_GAP_POSITION; i++) { 525 Instruction::GapPosition inner_pos = 526 static_cast<Instruction::GapPosition>(i); 527 ParallelMove* move = instr->GetParallelMove(inner_pos); 528 if (move != nullptr) resolver()->Resolve(move); 529 } 530 } 531 532 namespace { 533 534 Handle<PodArray<InliningPosition>> CreateInliningPositions( 535 CompilationInfo* info) { 536 const CompilationInfo::InlinedFunctionList& inlined_functions = 537 info->inlined_functions(); 538 if (inlined_functions.size() == 0) { 539 return Handle<PodArray<InliningPosition>>::cast( 540 info->isolate()->factory()->empty_byte_array()); 541 } 542 Handle<PodArray<InliningPosition>> inl_positions = 543 PodArray<InliningPosition>::New( 544 info->isolate(), static_cast<int>(inlined_functions.size()), TENURED); 545 for (size_t i = 0; i < inlined_functions.size(); ++i) { 546 inl_positions->set(static_cast<int>(i), inlined_functions[i].position); 547 } 548 return inl_positions; 549 } 550 551 } // namespace 552 553 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) { 554 CompilationInfo* info = this->info(); 555 int deopt_count = static_cast<int>(deoptimization_states_.size()); 556 if (deopt_count == 0 && !info->is_osr()) return; 557 Handle<DeoptimizationInputData> data = 558 DeoptimizationInputData::New(isolate(), deopt_count, TENURED); 559 560 Handle<ByteArray> translation_array = 561 translations_.CreateByteArray(isolate()->factory()); 562 563 data->SetTranslationByteArray(*translation_array); 564 data->SetInlinedFunctionCount( 565 Smi::FromInt(static_cast<int>(inlined_function_count_))); 566 data->SetOptimizationId(Smi::FromInt(info->optimization_id())); 567 568 if (info->has_shared_info()) { 569 data->SetSharedFunctionInfo(*info->shared_info()); 570 } else { 571 data->SetSharedFunctionInfo(Smi::kZero); 572 } 573 574 Handle<FixedArray> literals = isolate()->factory()->NewFixedArray( 575 static_cast<int>(deoptimization_literals_.size()), TENURED); 576 { 577 AllowDeferredHandleDereference copy_handles; 578 for (unsigned i = 0; i < deoptimization_literals_.size(); i++) { 579 literals->set(i, *deoptimization_literals_[i]); 580 } 581 data->SetLiteralArray(*literals); 582 } 583 584 Handle<PodArray<InliningPosition>> inl_pos = CreateInliningPositions(info); 585 data->SetInliningPositions(*inl_pos); 586 587 if (info->is_osr()) { 588 DCHECK(osr_pc_offset_ >= 0); 589 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt())); 590 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); 591 } else { 592 BailoutId osr_ast_id = BailoutId::None(); 593 data->SetOsrAstId(Smi::FromInt(osr_ast_id.ToInt())); 594 data->SetOsrPcOffset(Smi::FromInt(-1)); 595 } 596 597 // Populate deoptimization entries. 598 for (int i = 0; i < deopt_count; i++) { 599 DeoptimizationState* deoptimization_state = deoptimization_states_[i]; 600 data->SetAstId(i, deoptimization_state->bailout_id()); 601 CHECK(deoptimization_states_[i]); 602 data->SetTranslationIndex( 603 i, Smi::FromInt(deoptimization_states_[i]->translation_id())); 604 data->SetArgumentsStackHeight(i, Smi::kZero); 605 data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset())); 606 } 607 608 code_object->set_deoptimization_data(*data); 609 } 610 611 612 Label* CodeGenerator::AddJumpTable(Label** targets, size_t target_count) { 613 jump_tables_ = new (zone()) JumpTable(jump_tables_, targets, target_count); 614 return jump_tables_->label(); 615 } 616 617 618 void CodeGenerator::RecordCallPosition(Instruction* instr) { 619 CallDescriptor::Flags flags(MiscField::decode(instr->opcode())); 620 621 bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState); 622 623 RecordSafepoint( 624 instr->reference_map(), Safepoint::kSimple, 0, 625 needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); 626 627 if (flags & CallDescriptor::kHasExceptionHandler) { 628 InstructionOperandConverter i(this, instr); 629 RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1); 630 handlers_.push_back({GetLabel(handler_rpo), masm()->pc_offset()}); 631 } 632 633 if (needs_frame_state) { 634 MarkLazyDeoptSite(); 635 // If the frame state is present, it starts at argument 1 (just after the 636 // code address). 637 size_t frame_state_offset = 1; 638 FrameStateDescriptor* descriptor = 639 GetDeoptimizationEntry(instr, frame_state_offset).descriptor(); 640 int pc_offset = masm()->pc_offset(); 641 int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset, 642 descriptor->state_combine()); 643 // If the pre-call frame state differs from the post-call one, produce the 644 // pre-call frame state, too. 645 // TODO(jarin) We might want to avoid building the pre-call frame state 646 // because it is only used to get locals and arguments (by the debugger and 647 // f.arguments), and those are the same in the pre-call and post-call 648 // states. 649 if (!descriptor->state_combine().IsOutputIgnored()) { 650 deopt_state_id = BuildTranslation(instr, -1, frame_state_offset, 651 OutputFrameStateCombine::Ignore()); 652 } 653 safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id); 654 } 655 } 656 657 658 int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) { 659 int result = static_cast<int>(deoptimization_literals_.size()); 660 for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) { 661 if (deoptimization_literals_[i].is_identical_to(literal)) return i; 662 } 663 deoptimization_literals_.push_back(literal); 664 return result; 665 } 666 667 DeoptimizationEntry const& CodeGenerator::GetDeoptimizationEntry( 668 Instruction* instr, size_t frame_state_offset) { 669 InstructionOperandConverter i(this, instr); 670 int const state_id = i.InputInt32(frame_state_offset); 671 return code()->GetDeoptimizationEntry(state_id); 672 } 673 674 DeoptimizeKind CodeGenerator::GetDeoptimizationKind( 675 int deoptimization_id) const { 676 size_t const index = static_cast<size_t>(deoptimization_id); 677 DCHECK_LT(index, deoptimization_states_.size()); 678 return deoptimization_states_[index]->kind(); 679 } 680 681 DeoptimizeReason CodeGenerator::GetDeoptimizationReason( 682 int deoptimization_id) const { 683 size_t const index = static_cast<size_t>(deoptimization_id); 684 DCHECK_LT(index, deoptimization_states_.size()); 685 return deoptimization_states_[index]->reason(); 686 } 687 688 void CodeGenerator::TranslateStateValueDescriptor( 689 StateValueDescriptor* desc, StateValueList* nested, 690 Translation* translation, InstructionOperandIterator* iter) { 691 // Note: 692 // If translation is null, we just skip the relevant instruction operands. 693 if (desc->IsNested()) { 694 if (translation != nullptr) { 695 translation->BeginCapturedObject(static_cast<int>(nested->size())); 696 } 697 for (auto field : *nested) { 698 TranslateStateValueDescriptor(field.desc, field.nested, translation, 699 iter); 700 } 701 } else if (desc->IsArguments()) { 702 if (translation != nullptr) { 703 translation->BeginArgumentsObject(0); 704 } 705 } else if (desc->IsDuplicate()) { 706 if (translation != nullptr) { 707 translation->DuplicateObject(static_cast<int>(desc->id())); 708 } 709 } else if (desc->IsPlain()) { 710 InstructionOperand* op = iter->Advance(); 711 if (translation != nullptr) { 712 AddTranslationForOperand(translation, iter->instruction(), op, 713 desc->type()); 714 } 715 } else { 716 DCHECK(desc->IsOptimizedOut()); 717 if (translation != nullptr) { 718 if (optimized_out_literal_id_ == -1) { 719 optimized_out_literal_id_ = 720 DefineDeoptimizationLiteral(isolate()->factory()->optimized_out()); 721 } 722 translation->StoreLiteral(optimized_out_literal_id_); 723 } 724 } 725 } 726 727 728 void CodeGenerator::TranslateFrameStateDescriptorOperands( 729 FrameStateDescriptor* desc, InstructionOperandIterator* iter, 730 OutputFrameStateCombine combine, Translation* translation) { 731 size_t index = 0; 732 StateValueList* values = desc->GetStateValueDescriptors(); 733 for (StateValueList::iterator it = values->begin(); it != values->end(); 734 ++it, ++index) { 735 StateValueDescriptor* value_desc = (*it).desc; 736 if (combine.kind() == OutputFrameStateCombine::kPokeAt) { 737 // The result of the call should be placed at position 738 // [index_from_top] in the stack (overwriting whatever was 739 // previously there). 740 size_t index_from_top = 741 desc->GetSize(combine) - 1 - combine.GetOffsetToPokeAt(); 742 if (index >= index_from_top && 743 index < index_from_top + iter->instruction()->OutputCount()) { 744 DCHECK_NOT_NULL(translation); 745 AddTranslationForOperand( 746 translation, iter->instruction(), 747 iter->instruction()->OutputAt(index - index_from_top), 748 MachineType::AnyTagged()); 749 // Skip the instruction operands. 750 TranslateStateValueDescriptor(value_desc, (*it).nested, nullptr, iter); 751 continue; 752 } 753 } 754 TranslateStateValueDescriptor(value_desc, (*it).nested, translation, iter); 755 } 756 DCHECK_EQ(desc->GetSize(OutputFrameStateCombine::Ignore()), index); 757 758 if (combine.kind() == OutputFrameStateCombine::kPushOutput) { 759 DCHECK(combine.GetPushCount() <= iter->instruction()->OutputCount()); 760 for (size_t output = 0; output < combine.GetPushCount(); output++) { 761 // Materialize the result of the call instruction in this slot. 762 AddTranslationForOperand(translation, iter->instruction(), 763 iter->instruction()->OutputAt(output), 764 MachineType::AnyTagged()); 765 } 766 } 767 } 768 769 770 void CodeGenerator::BuildTranslationForFrameStateDescriptor( 771 FrameStateDescriptor* descriptor, InstructionOperandIterator* iter, 772 Translation* translation, OutputFrameStateCombine state_combine) { 773 // Outer-most state must be added to translation first. 774 if (descriptor->outer_state() != nullptr) { 775 BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), iter, 776 translation, 777 OutputFrameStateCombine::Ignore()); 778 } 779 780 Handle<SharedFunctionInfo> shared_info; 781 if (!descriptor->shared_info().ToHandle(&shared_info)) { 782 if (!info()->has_shared_info()) { 783 return; // Stub with no SharedFunctionInfo. 784 } 785 shared_info = info()->shared_info(); 786 } 787 int shared_info_id = DefineDeoptimizationLiteral(shared_info); 788 789 switch (descriptor->type()) { 790 case FrameStateType::kJavaScriptFunction: 791 translation->BeginJSFrame( 792 descriptor->bailout_id(), shared_info_id, 793 static_cast<unsigned int>(descriptor->GetSize(state_combine) - 794 (1 + descriptor->parameters_count()))); 795 break; 796 case FrameStateType::kInterpretedFunction: 797 translation->BeginInterpretedFrame( 798 descriptor->bailout_id(), shared_info_id, 799 static_cast<unsigned int>(descriptor->locals_count() + 1)); 800 break; 801 case FrameStateType::kArgumentsAdaptor: 802 translation->BeginArgumentsAdaptorFrame( 803 shared_info_id, 804 static_cast<unsigned int>(descriptor->parameters_count())); 805 break; 806 case FrameStateType::kTailCallerFunction: 807 translation->BeginTailCallerFrame(shared_info_id); 808 break; 809 case FrameStateType::kConstructStub: 810 DCHECK(descriptor->bailout_id().IsValidForConstructStub()); 811 translation->BeginConstructStubFrame( 812 descriptor->bailout_id(), shared_info_id, 813 static_cast<unsigned int>(descriptor->parameters_count())); 814 break; 815 case FrameStateType::kGetterStub: 816 translation->BeginGetterStubFrame(shared_info_id); 817 break; 818 case FrameStateType::kSetterStub: 819 translation->BeginSetterStubFrame(shared_info_id); 820 break; 821 } 822 823 TranslateFrameStateDescriptorOperands(descriptor, iter, state_combine, 824 translation); 825 } 826 827 828 int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset, 829 size_t frame_state_offset, 830 OutputFrameStateCombine state_combine) { 831 DeoptimizationEntry const& entry = 832 GetDeoptimizationEntry(instr, frame_state_offset); 833 FrameStateDescriptor* const descriptor = entry.descriptor(); 834 frame_state_offset++; 835 836 Translation translation( 837 &translations_, static_cast<int>(descriptor->GetFrameCount()), 838 static_cast<int>(descriptor->GetJSFrameCount()), zone()); 839 InstructionOperandIterator iter(instr, frame_state_offset); 840 BuildTranslationForFrameStateDescriptor(descriptor, &iter, &translation, 841 state_combine); 842 843 int deoptimization_id = static_cast<int>(deoptimization_states_.size()); 844 845 deoptimization_states_.push_back(new (zone()) DeoptimizationState( 846 descriptor->bailout_id(), translation.index(), pc_offset, entry.kind(), 847 entry.reason())); 848 849 return deoptimization_id; 850 } 851 852 853 void CodeGenerator::AddTranslationForOperand(Translation* translation, 854 Instruction* instr, 855 InstructionOperand* op, 856 MachineType type) { 857 if (op->IsStackSlot()) { 858 if (type.representation() == MachineRepresentation::kBit) { 859 translation->StoreBoolStackSlot(LocationOperand::cast(op)->index()); 860 } else if (type == MachineType::Int8() || type == MachineType::Int16() || 861 type == MachineType::Int32()) { 862 translation->StoreInt32StackSlot(LocationOperand::cast(op)->index()); 863 } else if (type == MachineType::Uint8() || type == MachineType::Uint16() || 864 type == MachineType::Uint32()) { 865 translation->StoreUint32StackSlot(LocationOperand::cast(op)->index()); 866 } else { 867 CHECK_EQ(MachineRepresentation::kTagged, type.representation()); 868 translation->StoreStackSlot(LocationOperand::cast(op)->index()); 869 } 870 } else if (op->IsFPStackSlot()) { 871 if (type.representation() == MachineRepresentation::kFloat64) { 872 translation->StoreDoubleStackSlot(LocationOperand::cast(op)->index()); 873 } else { 874 CHECK_EQ(MachineRepresentation::kFloat32, type.representation()); 875 translation->StoreFloatStackSlot(LocationOperand::cast(op)->index()); 876 } 877 } else if (op->IsRegister()) { 878 InstructionOperandConverter converter(this, instr); 879 if (type.representation() == MachineRepresentation::kBit) { 880 translation->StoreBoolRegister(converter.ToRegister(op)); 881 } else if (type == MachineType::Int8() || type == MachineType::Int16() || 882 type == MachineType::Int32()) { 883 translation->StoreInt32Register(converter.ToRegister(op)); 884 } else if (type == MachineType::Uint8() || type == MachineType::Uint16() || 885 type == MachineType::Uint32()) { 886 translation->StoreUint32Register(converter.ToRegister(op)); 887 } else { 888 CHECK_EQ(MachineRepresentation::kTagged, type.representation()); 889 translation->StoreRegister(converter.ToRegister(op)); 890 } 891 } else if (op->IsFPRegister()) { 892 InstructionOperandConverter converter(this, instr); 893 if (type.representation() == MachineRepresentation::kFloat64) { 894 translation->StoreDoubleRegister(converter.ToDoubleRegister(op)); 895 } else { 896 CHECK_EQ(MachineRepresentation::kFloat32, type.representation()); 897 translation->StoreFloatRegister(converter.ToFloatRegister(op)); 898 } 899 } else { 900 CHECK(op->IsImmediate()); 901 InstructionOperandConverter converter(this, instr); 902 Constant constant = converter.ToConstant(op); 903 Handle<Object> constant_object; 904 switch (constant.type()) { 905 case Constant::kInt32: 906 if (type.representation() == MachineRepresentation::kTagged) { 907 // When pointers are 4 bytes, we can use int32 constants to represent 908 // Smis. 909 DCHECK_EQ(4, kPointerSize); 910 constant_object = 911 handle(reinterpret_cast<Smi*>(constant.ToInt32()), isolate()); 912 DCHECK(constant_object->IsSmi()); 913 } else if (type.representation() == MachineRepresentation::kBit) { 914 if (constant.ToInt32() == 0) { 915 constant_object = isolate()->factory()->false_value(); 916 } else { 917 DCHECK_EQ(1, constant.ToInt32()); 918 constant_object = isolate()->factory()->true_value(); 919 } 920 } else { 921 // TODO(jarin,bmeurer): We currently pass in raw pointers to the 922 // JSFunction::entry here. We should really consider fixing this. 923 DCHECK(type == MachineType::Int32() || 924 type == MachineType::Uint32() || 925 type.representation() == MachineRepresentation::kWord32 || 926 type.representation() == MachineRepresentation::kNone); 927 DCHECK(type.representation() != MachineRepresentation::kNone || 928 constant.ToInt32() == FrameStateDescriptor::kImpossibleValue); 929 if (type == MachineType::Uint32()) { 930 constant_object = 931 isolate()->factory()->NewNumberFromUint(constant.ToInt32()); 932 } else { 933 constant_object = 934 isolate()->factory()->NewNumberFromInt(constant.ToInt32()); 935 } 936 } 937 break; 938 case Constant::kInt64: 939 // When pointers are 8 bytes, we can use int64 constants to represent 940 // Smis. 941 // TODO(jarin,bmeurer): We currently pass in raw pointers to the 942 // JSFunction::entry here. We should really consider fixing this. 943 DCHECK(type.representation() == MachineRepresentation::kWord64 || 944 type.representation() == MachineRepresentation::kTagged); 945 DCHECK_EQ(8, kPointerSize); 946 constant_object = 947 handle(reinterpret_cast<Smi*>(constant.ToInt64()), isolate()); 948 DCHECK(constant_object->IsSmi()); 949 break; 950 case Constant::kFloat32: 951 DCHECK(type.representation() == MachineRepresentation::kFloat32 || 952 type.representation() == MachineRepresentation::kTagged); 953 constant_object = isolate()->factory()->NewNumber(constant.ToFloat32()); 954 break; 955 case Constant::kFloat64: 956 DCHECK(type.representation() == MachineRepresentation::kFloat64 || 957 type.representation() == MachineRepresentation::kTagged); 958 constant_object = isolate()->factory()->NewNumber(constant.ToFloat64()); 959 break; 960 case Constant::kHeapObject: 961 DCHECK_EQ(MachineRepresentation::kTagged, type.representation()); 962 constant_object = constant.ToHeapObject(); 963 break; 964 default: 965 UNREACHABLE(); 966 } 967 if (constant_object.is_identical_to(info()->closure())) { 968 translation->StoreJSFrameFunction(); 969 } else { 970 int literal_id = DefineDeoptimizationLiteral(constant_object); 971 translation->StoreLiteral(literal_id); 972 } 973 } 974 } 975 976 977 void CodeGenerator::MarkLazyDeoptSite() { 978 last_lazy_deopt_pc_ = masm()->pc_offset(); 979 } 980 981 DeoptimizationExit* CodeGenerator::AddDeoptimizationExit( 982 Instruction* instr, size_t frame_state_offset) { 983 int const deoptimization_id = BuildTranslation( 984 instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore()); 985 DeoptimizationExit* const exit = new (zone()) 986 DeoptimizationExit(deoptimization_id, current_source_position_); 987 deoptimization_exits_.push_back(exit); 988 return exit; 989 } 990 991 OutOfLineCode::OutOfLineCode(CodeGenerator* gen) 992 : frame_(gen->frame()), masm_(gen->masm()), next_(gen->ools_) { 993 gen->ools_ = this; 994 } 995 996 997 OutOfLineCode::~OutOfLineCode() {} 998 999 } // namespace compiler 1000 } // namespace internal 1001 } // namespace v8 1002