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/assembler-inl.h" 9 #include "src/base/adapters.h" 10 #include "src/compiler/code-generator-impl.h" 11 #include "src/compiler/linkage.h" 12 #include "src/compiler/pipeline.h" 13 #include "src/compiler/wasm-compiler.h" 14 #include "src/eh-frame.h" 15 #include "src/frames.h" 16 #include "src/lsan.h" 17 #include "src/macro-assembler-inl.h" 18 #include "src/optimized-compilation-info.h" 19 20 namespace v8 { 21 namespace internal { 22 namespace compiler { 23 24 class CodeGenerator::JumpTable final : public ZoneObject { 25 public: 26 JumpTable(JumpTable* next, Label** targets, size_t target_count) 27 : next_(next), targets_(targets), target_count_(target_count) {} 28 29 Label* label() { return &label_; } 30 JumpTable* next() const { return next_; } 31 Label** targets() const { return targets_; } 32 size_t target_count() const { return target_count_; } 33 34 private: 35 Label label_; 36 JumpTable* const next_; 37 Label** const targets_; 38 size_t const target_count_; 39 }; 40 41 CodeGenerator::CodeGenerator( 42 Zone* codegen_zone, Frame* frame, Linkage* linkage, 43 InstructionSequence* code, OptimizedCompilationInfo* info, Isolate* isolate, 44 base::Optional<OsrHelper> osr_helper, int start_source_position, 45 JumpOptimizationInfo* jump_opt, PoisoningMitigationLevel poisoning_level, 46 const AssemblerOptions& options, int32_t builtin_index) 47 : zone_(codegen_zone), 48 isolate_(isolate), 49 frame_access_state_(nullptr), 50 linkage_(linkage), 51 code_(code), 52 unwinding_info_writer_(zone()), 53 info_(info), 54 labels_(zone()->NewArray<Label>(code->InstructionBlockCount())), 55 current_block_(RpoNumber::Invalid()), 56 start_source_position_(start_source_position), 57 current_source_position_(SourcePosition::Unknown()), 58 tasm_(isolate, options, nullptr, 0, CodeObjectRequired::kNo), 59 resolver_(this), 60 safepoints_(zone()), 61 handlers_(zone()), 62 deoptimization_exits_(zone()), 63 deoptimization_states_(zone()), 64 deoptimization_literals_(zone()), 65 inlined_function_count_(0), 66 translations_(zone()), 67 handler_table_offset_(0), 68 last_lazy_deopt_pc_(0), 69 caller_registers_saved_(false), 70 jump_tables_(nullptr), 71 ools_(nullptr), 72 osr_helper_(osr_helper), 73 osr_pc_offset_(-1), 74 optimized_out_literal_id_(-1), 75 source_position_table_builder_( 76 SourcePositionTableBuilder::RECORD_SOURCE_POSITIONS), 77 protected_instructions_(zone()), 78 result_(kSuccess), 79 poisoning_level_(poisoning_level), 80 block_starts_(zone()), 81 instr_starts_(zone()) { 82 for (int i = 0; i < code->InstructionBlockCount(); ++i) { 83 new (&labels_[i]) Label; 84 } 85 CreateFrameAccessState(frame); 86 CHECK_EQ(info->is_osr(), osr_helper_.has_value()); 87 tasm_.set_jump_optimization_info(jump_opt); 88 Code::Kind code_kind = info->code_kind(); 89 if (code_kind == Code::WASM_FUNCTION || 90 code_kind == Code::WASM_TO_JS_FUNCTION || 91 code_kind == Code::WASM_INTERPRETER_ENTRY || 92 (Builtins::IsBuiltinId(builtin_index) && 93 Builtins::IsWasmRuntimeStub(builtin_index))) { 94 tasm_.set_abort_hard(true); 95 } 96 tasm_.set_builtin_index(builtin_index); 97 } 98 99 bool CodeGenerator::wasm_runtime_exception_support() const { 100 DCHECK_NOT_NULL(info_); 101 return info_->wasm_runtime_exception_support(); 102 } 103 104 void CodeGenerator::AddProtectedInstructionLanding(uint32_t instr_offset, 105 uint32_t landing_offset) { 106 protected_instructions_.push_back({instr_offset, landing_offset}); 107 } 108 109 void CodeGenerator::CreateFrameAccessState(Frame* frame) { 110 FinishFrame(frame); 111 frame_access_state_ = new (zone()) FrameAccessState(frame); 112 } 113 114 CodeGenerator::CodeGenResult CodeGenerator::AssembleDeoptimizerCall( 115 int deoptimization_id, SourcePosition pos) { 116 DeoptimizeKind deopt_kind = GetDeoptimizationKind(deoptimization_id); 117 DeoptimizeReason deoptimization_reason = 118 GetDeoptimizationReason(deoptimization_id); 119 Address deopt_entry = Deoptimizer::GetDeoptimizationEntry( 120 tasm()->isolate(), deoptimization_id, deopt_kind); 121 if (deopt_entry == kNullAddress) return kTooManyDeoptimizationBailouts; 122 if (info()->is_source_positions_enabled()) { 123 tasm()->RecordDeoptReason(deoptimization_reason, pos, deoptimization_id); 124 } 125 tasm()->CallForDeoptimization(deopt_entry, deoptimization_id, 126 RelocInfo::RUNTIME_ENTRY); 127 return kSuccess; 128 } 129 130 void CodeGenerator::AssembleCode() { 131 OptimizedCompilationInfo* info = this->info(); 132 133 // Open a frame scope to indicate that there is a frame on the stack. The 134 // MANUAL indicates that the scope shouldn't actually generate code to set up 135 // the frame (that is done in AssemblePrologue). 136 FrameScope frame_scope(tasm(), StackFrame::MANUAL); 137 138 if (info->is_source_positions_enabled()) { 139 AssembleSourcePosition(start_source_position()); 140 } 141 142 // Place function entry hook if requested to do so. 143 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { 144 ProfileEntryHookStub::MaybeCallEntryHookDelayed(tasm(), zone()); 145 } 146 147 // Check that {kJavaScriptCallCodeStartRegister} has been set correctly. 148 if (FLAG_debug_code & (info->code_kind() == Code::OPTIMIZED_FUNCTION || 149 info->code_kind() == Code::BYTECODE_HANDLER)) { 150 tasm()->RecordComment("-- Prologue: check code start register --"); 151 AssembleCodeStartRegisterCheck(); 152 } 153 154 // TODO(jupvfranco): This should be the first thing in the code, otherwise 155 // MaybeCallEntryHookDelayed may happen twice (for optimized and deoptimized 156 // code). We want to bailout only from JS functions, which are the only ones 157 // that are optimized. 158 if (info->IsOptimizing()) { 159 DCHECK(linkage()->GetIncomingDescriptor()->IsJSFunctionCall()); 160 tasm()->RecordComment("-- Prologue: check for deoptimization --"); 161 BailoutIfDeoptimized(); 162 } 163 164 InitializeSpeculationPoison(); 165 166 // Define deoptimization literals for all inlined functions. 167 DCHECK_EQ(0u, deoptimization_literals_.size()); 168 for (OptimizedCompilationInfo::InlinedFunctionHolder& inlined : 169 info->inlined_functions()) { 170 if (!inlined.shared_info.equals(info->shared_info())) { 171 int index = DefineDeoptimizationLiteral( 172 DeoptimizationLiteral(inlined.shared_info)); 173 inlined.RegisterInlinedFunctionId(index); 174 } 175 } 176 inlined_function_count_ = deoptimization_literals_.size(); 177 178 unwinding_info_writer_.SetNumberOfInstructionBlocks( 179 code()->InstructionBlockCount()); 180 181 if (info->trace_turbo_json_enabled()) { 182 block_starts_.assign(code()->instruction_blocks().size(), -1); 183 instr_starts_.assign(code()->instructions().size(), -1); 184 } 185 // Assemble all non-deferred blocks, followed by deferred ones. 186 for (int deferred = 0; deferred < 2; ++deferred) { 187 for (const InstructionBlock* block : code()->instruction_blocks()) { 188 if (block->IsDeferred() == (deferred == 0)) { 189 continue; 190 } 191 192 // Align loop headers on 16-byte boundaries. 193 if (block->IsLoopHeader() && !tasm()->jump_optimization_info()) { 194 tasm()->Align(16); 195 } 196 if (info->trace_turbo_json_enabled()) { 197 block_starts_[block->rpo_number().ToInt()] = tasm()->pc_offset(); 198 } 199 // Bind a label for a block. 200 current_block_ = block->rpo_number(); 201 unwinding_info_writer_.BeginInstructionBlock(tasm()->pc_offset(), block); 202 if (FLAG_code_comments) { 203 Vector<char> buffer = Vector<char>::New(200); 204 char* buffer_start = buffer.start(); 205 LSAN_IGNORE_OBJECT(buffer_start); 206 207 int next = SNPrintF( 208 buffer, "-- B%d start%s%s%s%s", block->rpo_number().ToInt(), 209 block->IsDeferred() ? " (deferred)" : "", 210 block->needs_frame() ? "" : " (no frame)", 211 block->must_construct_frame() ? " (construct frame)" : "", 212 block->must_deconstruct_frame() ? " (deconstruct frame)" : ""); 213 214 buffer = buffer.SubVector(next, buffer.length()); 215 216 if (block->IsLoopHeader()) { 217 next = 218 SNPrintF(buffer, " (loop up to %d)", block->loop_end().ToInt()); 219 buffer = buffer.SubVector(next, buffer.length()); 220 } 221 if (block->loop_header().IsValid()) { 222 next = 223 SNPrintF(buffer, " (in loop %d)", block->loop_header().ToInt()); 224 buffer = buffer.SubVector(next, buffer.length()); 225 } 226 SNPrintF(buffer, " --"); 227 tasm()->RecordComment(buffer_start); 228 } 229 230 frame_access_state()->MarkHasFrame(block->needs_frame()); 231 232 tasm()->bind(GetLabel(current_block_)); 233 234 TryInsertBranchPoisoning(block); 235 236 if (block->must_construct_frame()) { 237 AssembleConstructFrame(); 238 // We need to setup the root register after we assemble the prologue, to 239 // avoid clobbering callee saved registers in case of C linkage and 240 // using the roots. 241 // TODO(mtrofin): investigate how we can avoid doing this repeatedly. 242 if (linkage()->GetIncomingDescriptor()->InitializeRootRegister()) { 243 tasm()->InitializeRootRegister(); 244 } 245 } 246 247 if (FLAG_enable_embedded_constant_pool && !block->needs_frame()) { 248 ConstantPoolUnavailableScope constant_pool_unavailable(tasm()); 249 result_ = AssembleBlock(block); 250 } else { 251 result_ = AssembleBlock(block); 252 } 253 if (result_ != kSuccess) return; 254 unwinding_info_writer_.EndInstructionBlock(block); 255 } 256 } 257 258 // Assemble all out-of-line code. 259 if (ools_) { 260 tasm()->RecordComment("-- Out of line code --"); 261 for (OutOfLineCode* ool = ools_; ool; ool = ool->next()) { 262 tasm()->bind(ool->entry()); 263 ool->Generate(); 264 if (ool->exit()->is_bound()) tasm()->jmp(ool->exit()); 265 } 266 } 267 268 // This nop operation is needed to ensure that the trampoline is not 269 // confused with the pc of the call before deoptimization. 270 // The test regress/regress-259 is an example of where we need it. 271 tasm()->nop(); 272 273 // Assemble deoptimization exits. 274 int last_updated = 0; 275 for (DeoptimizationExit* exit : deoptimization_exits_) { 276 tasm()->bind(exit->label()); 277 int trampoline_pc = tasm()->pc_offset(); 278 int deoptimization_id = exit->deoptimization_id(); 279 DeoptimizationState* ds = deoptimization_states_[deoptimization_id]; 280 281 if (ds->kind() == DeoptimizeKind::kLazy) { 282 last_updated = safepoints()->UpdateDeoptimizationInfo( 283 ds->pc_offset(), trampoline_pc, last_updated); 284 } 285 result_ = AssembleDeoptimizerCall(deoptimization_id, exit->pos()); 286 if (result_ != kSuccess) return; 287 } 288 289 FinishCode(); 290 291 // Emit the jump tables. 292 if (jump_tables_) { 293 tasm()->Align(kPointerSize); 294 for (JumpTable* table = jump_tables_; table; table = table->next()) { 295 tasm()->bind(table->label()); 296 AssembleJumpTable(table->targets(), table->target_count()); 297 } 298 } 299 300 // The PerfJitLogger logs code up until here, excluding the safepoint 301 // table. Resolve the unwinding info now so it is aware of the same code size 302 // as reported by perf. 303 unwinding_info_writer_.Finish(tasm()->pc_offset()); 304 305 safepoints()->Emit(tasm(), frame()->GetTotalFrameSlotCount()); 306 307 // Emit the exception handler table. 308 if (!handlers_.empty()) { 309 handler_table_offset_ = HandlerTable::EmitReturnTableStart( 310 tasm(), static_cast<int>(handlers_.size())); 311 for (size_t i = 0; i < handlers_.size(); ++i) { 312 HandlerTable::EmitReturnEntry(tasm(), handlers_[i].pc_offset, 313 handlers_[i].handler->pos()); 314 } 315 } 316 317 result_ = kSuccess; 318 } 319 320 void CodeGenerator::TryInsertBranchPoisoning(const InstructionBlock* block) { 321 // See if our predecessor was a basic block terminated by a branch_and_poison 322 // instruction. If yes, then perform the masking based on the flags. 323 if (block->PredecessorCount() != 1) return; 324 RpoNumber pred_rpo = (block->predecessors())[0]; 325 const InstructionBlock* pred = code()->InstructionBlockAt(pred_rpo); 326 if (pred->code_start() == pred->code_end()) return; 327 Instruction* instr = code()->InstructionAt(pred->code_end() - 1); 328 FlagsMode mode = FlagsModeField::decode(instr->opcode()); 329 switch (mode) { 330 case kFlags_branch_and_poison: { 331 BranchInfo branch; 332 RpoNumber target = ComputeBranchInfo(&branch, instr); 333 if (!target.IsValid()) { 334 // Non-trivial branch, add the masking code. 335 FlagsCondition condition = branch.condition; 336 if (branch.false_label == GetLabel(block->rpo_number())) { 337 condition = NegateFlagsCondition(condition); 338 } 339 AssembleBranchPoisoning(condition, instr); 340 } 341 break; 342 } 343 case kFlags_deoptimize_and_poison: { 344 UNREACHABLE(); 345 break; 346 } 347 default: 348 break; 349 } 350 } 351 352 void CodeGenerator::AssembleArchBinarySearchSwitchRange( 353 Register input, RpoNumber def_block, std::pair<int32_t, Label*>* begin, 354 std::pair<int32_t, Label*>* end) { 355 if (end - begin < kBinarySearchSwitchMinimalCases) { 356 while (begin != end) { 357 tasm()->JumpIfEqual(input, begin->first, begin->second); 358 ++begin; 359 } 360 AssembleArchJump(def_block); 361 return; 362 } 363 auto middle = begin + (end - begin) / 2; 364 Label less_label; 365 tasm()->JumpIfLessThan(input, middle->first, &less_label); 366 AssembleArchBinarySearchSwitchRange(input, def_block, middle, end); 367 tasm()->bind(&less_label); 368 AssembleArchBinarySearchSwitchRange(input, def_block, begin, middle); 369 } 370 371 OwnedVector<byte> CodeGenerator::GetSourcePositionTable() { 372 return source_position_table_builder_.ToSourcePositionTableVector(); 373 } 374 375 OwnedVector<trap_handler::ProtectedInstructionData> 376 CodeGenerator::GetProtectedInstructions() { 377 return OwnedVector<trap_handler::ProtectedInstructionData>::Of( 378 protected_instructions_); 379 } 380 381 MaybeHandle<Code> CodeGenerator::FinalizeCode() { 382 if (result_ != kSuccess) { 383 tasm()->AbortedCodeGeneration(); 384 return MaybeHandle<Code>(); 385 } 386 387 // Allocate the source position table. 388 Handle<ByteArray> source_positions = 389 source_position_table_builder_.ToSourcePositionTable(isolate()); 390 391 // Allocate deoptimization data. 392 Handle<DeoptimizationData> deopt_data = GenerateDeoptimizationData(); 393 394 // Allocate and install the code. 395 CodeDesc desc; 396 tasm()->GetCode(isolate(), &desc); 397 if (unwinding_info_writer_.eh_frame_writer()) { 398 unwinding_info_writer_.eh_frame_writer()->GetEhFrame(&desc); 399 } 400 401 MaybeHandle<Code> maybe_code = isolate()->factory()->TryNewCode( 402 desc, info()->code_kind(), Handle<Object>(), info()->builtin_index(), 403 source_positions, deopt_data, kMovable, info()->stub_key(), true, 404 frame()->GetTotalFrameSlotCount(), safepoints()->GetCodeOffset(), 405 handler_table_offset_); 406 407 Handle<Code> code; 408 if (!maybe_code.ToHandle(&code)) { 409 tasm()->AbortedCodeGeneration(); 410 return MaybeHandle<Code>(); 411 } 412 isolate()->counters()->total_compiled_code_size()->Increment( 413 code->raw_instruction_size()); 414 415 LOG_CODE_EVENT(isolate(), 416 CodeLinePosInfoRecordEvent(code->raw_instruction_start(), 417 *source_positions)); 418 419 return code; 420 } 421 422 423 bool CodeGenerator::IsNextInAssemblyOrder(RpoNumber block) const { 424 return code() 425 ->InstructionBlockAt(current_block_) 426 ->ao_number() 427 .IsNext(code()->InstructionBlockAt(block)->ao_number()); 428 } 429 430 431 void CodeGenerator::RecordSafepoint(ReferenceMap* references, 432 Safepoint::Kind kind, int arguments, 433 Safepoint::DeoptMode deopt_mode) { 434 Safepoint safepoint = 435 safepoints()->DefineSafepoint(tasm(), kind, arguments, deopt_mode); 436 int stackSlotToSpillSlotDelta = 437 frame()->GetTotalFrameSlotCount() - frame()->GetSpillSlotCount(); 438 for (const InstructionOperand& operand : references->reference_operands()) { 439 if (operand.IsStackSlot()) { 440 int index = LocationOperand::cast(operand).index(); 441 DCHECK_LE(0, index); 442 // We might index values in the fixed part of the frame (i.e. the 443 // closure pointer or the context pointer); these are not spill slots 444 // and therefore don't work with the SafepointTable currently, but 445 // we also don't need to worry about them, since the GC has special 446 // knowledge about those fields anyway. 447 if (index < stackSlotToSpillSlotDelta) continue; 448 safepoint.DefinePointerSlot(index); 449 } else if (operand.IsRegister() && (kind & Safepoint::kWithRegisters)) { 450 Register reg = LocationOperand::cast(operand).GetRegister(); 451 safepoint.DefinePointerRegister(reg); 452 } 453 } 454 } 455 456 bool CodeGenerator::IsMaterializableFromRoot( 457 Handle<HeapObject> object, Heap::RootListIndex* index_return) { 458 const CallDescriptor* incoming_descriptor = 459 linkage()->GetIncomingDescriptor(); 460 if (incoming_descriptor->flags() & CallDescriptor::kCanUseRoots) { 461 Heap* heap = isolate()->heap(); 462 return heap->IsRootHandle(object, index_return) && 463 !heap->RootCanBeWrittenAfterInitialization(*index_return); 464 } 465 return false; 466 } 467 468 CodeGenerator::CodeGenResult CodeGenerator::AssembleBlock( 469 const InstructionBlock* block) { 470 for (int i = block->code_start(); i < block->code_end(); ++i) { 471 if (info()->trace_turbo_json_enabled()) { 472 instr_starts_[i] = tasm()->pc_offset(); 473 } 474 Instruction* instr = code()->InstructionAt(i); 475 CodeGenResult result = AssembleInstruction(instr, block); 476 if (result != kSuccess) return result; 477 } 478 return kSuccess; 479 } 480 481 bool CodeGenerator::IsValidPush(InstructionOperand source, 482 CodeGenerator::PushTypeFlags push_type) { 483 if (source.IsImmediate() && 484 ((push_type & CodeGenerator::kImmediatePush) != 0)) { 485 return true; 486 } 487 if (source.IsRegister() && 488 ((push_type & CodeGenerator::kRegisterPush) != 0)) { 489 return true; 490 } 491 if (source.IsStackSlot() && 492 ((push_type & CodeGenerator::kStackSlotPush) != 0)) { 493 return true; 494 } 495 return false; 496 } 497 498 void CodeGenerator::GetPushCompatibleMoves(Instruction* instr, 499 PushTypeFlags push_type, 500 ZoneVector<MoveOperands*>* pushes) { 501 pushes->clear(); 502 for (int i = Instruction::FIRST_GAP_POSITION; 503 i <= Instruction::LAST_GAP_POSITION; ++i) { 504 Instruction::GapPosition inner_pos = 505 static_cast<Instruction::GapPosition>(i); 506 ParallelMove* parallel_move = instr->GetParallelMove(inner_pos); 507 if (parallel_move != nullptr) { 508 for (auto move : *parallel_move) { 509 InstructionOperand source = move->source(); 510 InstructionOperand destination = move->destination(); 511 int first_push_compatible_index = 512 V8_TARGET_ARCH_STORES_RETURN_ADDRESS_ON_STACK ? 1 : 0; 513 // If there are any moves from slots that will be overridden by pushes, 514 // then the full gap resolver must be used since optimization with 515 // pushes don't participate in the parallel move and might clobber 516 // values needed for the gap resolve. 517 if (source.IsStackSlot() && 518 LocationOperand::cast(source).index() >= 519 first_push_compatible_index) { 520 pushes->clear(); 521 return; 522 } 523 // TODO(danno): Right now, only consider moves from the FIRST gap for 524 // pushes. Theoretically, we could extract pushes for both gaps (there 525 // are cases where this happens), but the logic for that would also have 526 // to check to make sure that non-memory inputs to the pushes from the 527 // LAST gap don't get clobbered in the FIRST gap. 528 if (i == Instruction::FIRST_GAP_POSITION) { 529 if (destination.IsStackSlot() && 530 LocationOperand::cast(destination).index() >= 531 first_push_compatible_index) { 532 int index = LocationOperand::cast(destination).index(); 533 if (IsValidPush(source, push_type)) { 534 if (index >= static_cast<int>(pushes->size())) { 535 pushes->resize(index + 1); 536 } 537 (*pushes)[index] = move; 538 } 539 } 540 } 541 } 542 } 543 } 544 545 // For now, only support a set of continuous pushes at the end of the list. 546 size_t push_count_upper_bound = pushes->size(); 547 size_t push_begin = push_count_upper_bound; 548 for (auto move : base::Reversed(*pushes)) { 549 if (move == nullptr) break; 550 push_begin--; 551 } 552 size_t push_count = pushes->size() - push_begin; 553 std::copy(pushes->begin() + push_begin, 554 pushes->begin() + push_begin + push_count, pushes->begin()); 555 pushes->resize(push_count); 556 } 557 558 CodeGenerator::MoveType::Type CodeGenerator::MoveType::InferMove( 559 InstructionOperand* source, InstructionOperand* destination) { 560 if (source->IsConstant()) { 561 if (destination->IsAnyRegister()) { 562 return MoveType::kConstantToRegister; 563 } else { 564 DCHECK(destination->IsAnyStackSlot()); 565 return MoveType::kConstantToStack; 566 } 567 } 568 DCHECK(LocationOperand::cast(source)->IsCompatible( 569 LocationOperand::cast(destination))); 570 if (source->IsAnyRegister()) { 571 if (destination->IsAnyRegister()) { 572 return MoveType::kRegisterToRegister; 573 } else { 574 DCHECK(destination->IsAnyStackSlot()); 575 return MoveType::kRegisterToStack; 576 } 577 } else { 578 DCHECK(source->IsAnyStackSlot()); 579 if (destination->IsAnyRegister()) { 580 return MoveType::kStackToRegister; 581 } else { 582 DCHECK(destination->IsAnyStackSlot()); 583 return MoveType::kStackToStack; 584 } 585 } 586 } 587 588 CodeGenerator::MoveType::Type CodeGenerator::MoveType::InferSwap( 589 InstructionOperand* source, InstructionOperand* destination) { 590 DCHECK(LocationOperand::cast(source)->IsCompatible( 591 LocationOperand::cast(destination))); 592 if (source->IsAnyRegister()) { 593 if (destination->IsAnyRegister()) { 594 return MoveType::kRegisterToRegister; 595 } else { 596 DCHECK(destination->IsAnyStackSlot()); 597 return MoveType::kRegisterToStack; 598 } 599 } else { 600 DCHECK(source->IsAnyStackSlot()); 601 DCHECK(destination->IsAnyStackSlot()); 602 return MoveType::kStackToStack; 603 } 604 } 605 606 RpoNumber CodeGenerator::ComputeBranchInfo(BranchInfo* branch, 607 Instruction* instr) { 608 // Assemble a branch after this instruction. 609 InstructionOperandConverter i(this, instr); 610 RpoNumber true_rpo = i.InputRpo(instr->InputCount() - 2); 611 RpoNumber false_rpo = i.InputRpo(instr->InputCount() - 1); 612 613 if (true_rpo == false_rpo) { 614 return true_rpo; 615 } 616 FlagsCondition condition = FlagsConditionField::decode(instr->opcode()); 617 if (IsNextInAssemblyOrder(true_rpo)) { 618 // true block is next, can fall through if condition negated. 619 std::swap(true_rpo, false_rpo); 620 condition = NegateFlagsCondition(condition); 621 } 622 branch->condition = condition; 623 branch->true_label = GetLabel(true_rpo); 624 branch->false_label = GetLabel(false_rpo); 625 branch->fallthru = IsNextInAssemblyOrder(false_rpo); 626 return RpoNumber::Invalid(); 627 } 628 629 CodeGenerator::CodeGenResult CodeGenerator::AssembleInstruction( 630 Instruction* instr, const InstructionBlock* block) { 631 int first_unused_stack_slot; 632 FlagsMode mode = FlagsModeField::decode(instr->opcode()); 633 if (mode != kFlags_trap) { 634 AssembleSourcePosition(instr); 635 } 636 bool adjust_stack = 637 GetSlotAboveSPBeforeTailCall(instr, &first_unused_stack_slot); 638 if (adjust_stack) AssembleTailCallBeforeGap(instr, first_unused_stack_slot); 639 AssembleGaps(instr); 640 if (adjust_stack) AssembleTailCallAfterGap(instr, first_unused_stack_slot); 641 DCHECK_IMPLIES( 642 block->must_deconstruct_frame(), 643 instr != code()->InstructionAt(block->last_instruction_index()) || 644 instr->IsRet() || instr->IsJump()); 645 if (instr->IsJump() && block->must_deconstruct_frame()) { 646 AssembleDeconstructFrame(); 647 } 648 // Assemble architecture-specific code for the instruction. 649 CodeGenResult result = AssembleArchInstruction(instr); 650 if (result != kSuccess) return result; 651 652 FlagsCondition condition = FlagsConditionField::decode(instr->opcode()); 653 switch (mode) { 654 case kFlags_branch: 655 case kFlags_branch_and_poison: { 656 BranchInfo branch; 657 RpoNumber target = ComputeBranchInfo(&branch, instr); 658 if (target.IsValid()) { 659 // redundant branch. 660 if (!IsNextInAssemblyOrder(target)) { 661 AssembleArchJump(target); 662 } 663 return kSuccess; 664 } 665 // Assemble architecture-specific branch. 666 AssembleArchBranch(instr, &branch); 667 break; 668 } 669 case kFlags_deoptimize: 670 case kFlags_deoptimize_and_poison: { 671 // Assemble a conditional eager deoptimization after this instruction. 672 InstructionOperandConverter i(this, instr); 673 size_t frame_state_offset = MiscField::decode(instr->opcode()); 674 DeoptimizationExit* const exit = 675 AddDeoptimizationExit(instr, frame_state_offset); 676 Label continue_label; 677 BranchInfo branch; 678 branch.condition = condition; 679 branch.true_label = exit->label(); 680 branch.false_label = &continue_label; 681 branch.fallthru = true; 682 // Assemble architecture-specific branch. 683 AssembleArchDeoptBranch(instr, &branch); 684 tasm()->bind(&continue_label); 685 if (mode == kFlags_deoptimize_and_poison) { 686 AssembleBranchPoisoning(NegateFlagsCondition(branch.condition), instr); 687 } 688 break; 689 } 690 case kFlags_set: { 691 // Assemble a boolean materialization after this instruction. 692 AssembleArchBoolean(instr, condition); 693 break; 694 } 695 case kFlags_trap: { 696 AssembleArchTrap(instr, condition); 697 break; 698 } 699 case kFlags_none: { 700 break; 701 } 702 } 703 704 // TODO(jarin) We should thread the flag through rather than set it. 705 if (instr->IsCall()) { 706 ResetSpeculationPoison(); 707 } 708 709 return kSuccess; 710 } 711 712 void CodeGenerator::AssembleSourcePosition(Instruction* instr) { 713 SourcePosition source_position = SourcePosition::Unknown(); 714 if (instr->IsNop() && instr->AreMovesRedundant()) return; 715 if (!code()->GetSourcePosition(instr, &source_position)) return; 716 AssembleSourcePosition(source_position); 717 } 718 719 void CodeGenerator::AssembleSourcePosition(SourcePosition source_position) { 720 if (source_position == current_source_position_) return; 721 current_source_position_ = source_position; 722 if (!source_position.IsKnown()) return; 723 source_position_table_builder_.AddPosition(tasm()->pc_offset(), 724 source_position, false); 725 if (FLAG_code_comments) { 726 OptimizedCompilationInfo* info = this->info(); 727 if (info->IsStub()) return; 728 std::ostringstream buffer; 729 buffer << "-- "; 730 // Turbolizer only needs the source position, as it can reconstruct 731 // the inlining stack from other information. 732 if (info->trace_turbo_json_enabled() || !tasm()->isolate() || 733 tasm()->isolate()->concurrent_recompilation_enabled()) { 734 buffer << source_position; 735 } else { 736 AllowHeapAllocation allocation; 737 AllowHandleAllocation handles; 738 AllowHandleDereference deref; 739 buffer << source_position.InliningStack(info); 740 } 741 buffer << " --"; 742 char* str = StrDup(buffer.str().c_str()); 743 LSAN_IGNORE_OBJECT(str); 744 tasm()->RecordComment(str); 745 } 746 } 747 748 bool CodeGenerator::GetSlotAboveSPBeforeTailCall(Instruction* instr, 749 int* slot) { 750 if (instr->IsTailCall()) { 751 InstructionOperandConverter g(this, instr); 752 *slot = g.InputInt32(instr->InputCount() - 1); 753 return true; 754 } else { 755 return false; 756 } 757 } 758 759 StubCallMode CodeGenerator::DetermineStubCallMode() const { 760 Code::Kind code_kind = info()->code_kind(); 761 return (code_kind == Code::WASM_FUNCTION || 762 code_kind == Code::WASM_TO_JS_FUNCTION) 763 ? StubCallMode::kCallWasmRuntimeStub 764 : StubCallMode::kCallOnHeapBuiltin; 765 } 766 767 void CodeGenerator::AssembleGaps(Instruction* instr) { 768 for (int i = Instruction::FIRST_GAP_POSITION; 769 i <= Instruction::LAST_GAP_POSITION; i++) { 770 Instruction::GapPosition inner_pos = 771 static_cast<Instruction::GapPosition>(i); 772 ParallelMove* move = instr->GetParallelMove(inner_pos); 773 if (move != nullptr) resolver()->Resolve(move); 774 } 775 } 776 777 namespace { 778 779 Handle<PodArray<InliningPosition>> CreateInliningPositions( 780 OptimizedCompilationInfo* info, Isolate* isolate) { 781 const OptimizedCompilationInfo::InlinedFunctionList& inlined_functions = 782 info->inlined_functions(); 783 if (inlined_functions.size() == 0) { 784 return Handle<PodArray<InliningPosition>>::cast( 785 isolate->factory()->empty_byte_array()); 786 } 787 Handle<PodArray<InliningPosition>> inl_positions = 788 PodArray<InliningPosition>::New( 789 isolate, static_cast<int>(inlined_functions.size()), TENURED); 790 for (size_t i = 0; i < inlined_functions.size(); ++i) { 791 inl_positions->set(static_cast<int>(i), inlined_functions[i].position); 792 } 793 return inl_positions; 794 } 795 796 } // namespace 797 798 Handle<DeoptimizationData> CodeGenerator::GenerateDeoptimizationData() { 799 OptimizedCompilationInfo* info = this->info(); 800 int deopt_count = static_cast<int>(deoptimization_states_.size()); 801 if (deopt_count == 0 && !info->is_osr()) { 802 return DeoptimizationData::Empty(isolate()); 803 } 804 Handle<DeoptimizationData> data = 805 DeoptimizationData::New(isolate(), deopt_count, TENURED); 806 807 Handle<ByteArray> translation_array = 808 translations_.CreateByteArray(isolate()->factory()); 809 810 data->SetTranslationByteArray(*translation_array); 811 data->SetInlinedFunctionCount( 812 Smi::FromInt(static_cast<int>(inlined_function_count_))); 813 data->SetOptimizationId(Smi::FromInt(info->optimization_id())); 814 815 if (info->has_shared_info()) { 816 data->SetSharedFunctionInfo(*info->shared_info()); 817 } else { 818 data->SetSharedFunctionInfo(Smi::kZero); 819 } 820 821 Handle<FixedArray> literals = isolate()->factory()->NewFixedArray( 822 static_cast<int>(deoptimization_literals_.size()), TENURED); 823 for (unsigned i = 0; i < deoptimization_literals_.size(); i++) { 824 Handle<Object> object = deoptimization_literals_[i].Reify(isolate()); 825 literals->set(i, *object); 826 } 827 data->SetLiteralArray(*literals); 828 829 Handle<PodArray<InliningPosition>> inl_pos = 830 CreateInliningPositions(info, isolate()); 831 data->SetInliningPositions(*inl_pos); 832 833 if (info->is_osr()) { 834 DCHECK_LE(0, osr_pc_offset_); 835 data->SetOsrBytecodeOffset(Smi::FromInt(info_->osr_offset().ToInt())); 836 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); 837 } else { 838 BailoutId osr_offset = BailoutId::None(); 839 data->SetOsrBytecodeOffset(Smi::FromInt(osr_offset.ToInt())); 840 data->SetOsrPcOffset(Smi::FromInt(-1)); 841 } 842 843 // Populate deoptimization entries. 844 for (int i = 0; i < deopt_count; i++) { 845 DeoptimizationState* deoptimization_state = deoptimization_states_[i]; 846 data->SetBytecodeOffset(i, deoptimization_state->bailout_id()); 847 CHECK(deoptimization_state); 848 data->SetTranslationIndex( 849 i, Smi::FromInt(deoptimization_state->translation_id())); 850 data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset())); 851 } 852 853 return data; 854 } 855 856 857 Label* CodeGenerator::AddJumpTable(Label** targets, size_t target_count) { 858 jump_tables_ = new (zone()) JumpTable(jump_tables_, targets, target_count); 859 return jump_tables_->label(); 860 } 861 862 863 void CodeGenerator::RecordCallPosition(Instruction* instr) { 864 CallDescriptor::Flags flags(MiscField::decode(instr->opcode())); 865 866 bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState); 867 868 RecordSafepoint( 869 instr->reference_map(), Safepoint::kSimple, 0, 870 needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); 871 872 if (flags & CallDescriptor::kHasExceptionHandler) { 873 InstructionOperandConverter i(this, instr); 874 RpoNumber handler_rpo = i.InputRpo(instr->InputCount() - 1); 875 handlers_.push_back({GetLabel(handler_rpo), tasm()->pc_offset()}); 876 } 877 878 if (needs_frame_state) { 879 MarkLazyDeoptSite(); 880 // If the frame state is present, it starts at argument 2 - after 881 // the code address and the poison-alias index. 882 size_t frame_state_offset = 2; 883 FrameStateDescriptor* descriptor = 884 GetDeoptimizationEntry(instr, frame_state_offset).descriptor(); 885 int pc_offset = tasm()->pc_offset(); 886 int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset, 887 descriptor->state_combine()); 888 889 DeoptimizationExit* const exit = new (zone()) 890 DeoptimizationExit(deopt_state_id, current_source_position_); 891 deoptimization_exits_.push_back(exit); 892 safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id); 893 } 894 } 895 896 int CodeGenerator::DefineDeoptimizationLiteral(DeoptimizationLiteral literal) { 897 int result = static_cast<int>(deoptimization_literals_.size()); 898 for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) { 899 if (deoptimization_literals_[i] == literal) return i; 900 } 901 deoptimization_literals_.push_back(literal); 902 return result; 903 } 904 905 DeoptimizationEntry const& CodeGenerator::GetDeoptimizationEntry( 906 Instruction* instr, size_t frame_state_offset) { 907 InstructionOperandConverter i(this, instr); 908 int const state_id = i.InputInt32(frame_state_offset); 909 return code()->GetDeoptimizationEntry(state_id); 910 } 911 912 DeoptimizeKind CodeGenerator::GetDeoptimizationKind( 913 int deoptimization_id) const { 914 size_t const index = static_cast<size_t>(deoptimization_id); 915 DCHECK_LT(index, deoptimization_states_.size()); 916 return deoptimization_states_[index]->kind(); 917 } 918 919 DeoptimizeReason CodeGenerator::GetDeoptimizationReason( 920 int deoptimization_id) const { 921 size_t const index = static_cast<size_t>(deoptimization_id); 922 DCHECK_LT(index, deoptimization_states_.size()); 923 return deoptimization_states_[index]->reason(); 924 } 925 926 void CodeGenerator::TranslateStateValueDescriptor( 927 StateValueDescriptor* desc, StateValueList* nested, 928 Translation* translation, InstructionOperandIterator* iter) { 929 // Note: 930 // If translation is null, we just skip the relevant instruction operands. 931 if (desc->IsNested()) { 932 if (translation != nullptr) { 933 translation->BeginCapturedObject(static_cast<int>(nested->size())); 934 } 935 for (auto field : *nested) { 936 TranslateStateValueDescriptor(field.desc, field.nested, translation, 937 iter); 938 } 939 } else if (desc->IsArgumentsElements()) { 940 if (translation != nullptr) { 941 translation->ArgumentsElements(desc->arguments_type()); 942 } 943 } else if (desc->IsArgumentsLength()) { 944 if (translation != nullptr) { 945 translation->ArgumentsLength(desc->arguments_type()); 946 } 947 } else if (desc->IsDuplicate()) { 948 if (translation != nullptr) { 949 translation->DuplicateObject(static_cast<int>(desc->id())); 950 } 951 } else if (desc->IsPlain()) { 952 InstructionOperand* op = iter->Advance(); 953 if (translation != nullptr) { 954 AddTranslationForOperand(translation, iter->instruction(), op, 955 desc->type()); 956 } 957 } else { 958 DCHECK(desc->IsOptimizedOut()); 959 if (translation != nullptr) { 960 if (optimized_out_literal_id_ == -1) { 961 optimized_out_literal_id_ = DefineDeoptimizationLiteral( 962 DeoptimizationLiteral(isolate()->factory()->optimized_out())); 963 } 964 translation->StoreLiteral(optimized_out_literal_id_); 965 } 966 } 967 } 968 969 970 void CodeGenerator::TranslateFrameStateDescriptorOperands( 971 FrameStateDescriptor* desc, InstructionOperandIterator* iter, 972 OutputFrameStateCombine combine, Translation* translation) { 973 size_t index = 0; 974 StateValueList* values = desc->GetStateValueDescriptors(); 975 for (StateValueList::iterator it = values->begin(); it != values->end(); 976 ++it, ++index) { 977 StateValueDescriptor* value_desc = (*it).desc; 978 if (!combine.IsOutputIgnored()) { 979 // The result of the call should be placed at position 980 // [index_from_top] in the stack (overwriting whatever was 981 // previously there). 982 size_t index_from_top = desc->GetSize() - 1 - combine.GetOffsetToPokeAt(); 983 if (index >= index_from_top && 984 index < index_from_top + iter->instruction()->OutputCount()) { 985 DCHECK_NOT_NULL(translation); 986 AddTranslationForOperand( 987 translation, iter->instruction(), 988 iter->instruction()->OutputAt(index - index_from_top), 989 MachineType::AnyTagged()); 990 // Skip the instruction operands. 991 TranslateStateValueDescriptor(value_desc, (*it).nested, nullptr, iter); 992 continue; 993 } 994 } 995 TranslateStateValueDescriptor(value_desc, (*it).nested, translation, iter); 996 } 997 DCHECK_EQ(desc->GetSize(), index); 998 } 999 1000 1001 void CodeGenerator::BuildTranslationForFrameStateDescriptor( 1002 FrameStateDescriptor* descriptor, InstructionOperandIterator* iter, 1003 Translation* translation, OutputFrameStateCombine state_combine) { 1004 // Outer-most state must be added to translation first. 1005 if (descriptor->outer_state() != nullptr) { 1006 BuildTranslationForFrameStateDescriptor(descriptor->outer_state(), iter, 1007 translation, 1008 OutputFrameStateCombine::Ignore()); 1009 } 1010 1011 Handle<SharedFunctionInfo> shared_info; 1012 if (!descriptor->shared_info().ToHandle(&shared_info)) { 1013 if (!info()->has_shared_info()) { 1014 return; // Stub with no SharedFunctionInfo. 1015 } 1016 shared_info = info()->shared_info(); 1017 } 1018 int shared_info_id = 1019 DefineDeoptimizationLiteral(DeoptimizationLiteral(shared_info)); 1020 1021 switch (descriptor->type()) { 1022 case FrameStateType::kInterpretedFunction: 1023 translation->BeginInterpretedFrame( 1024 descriptor->bailout_id(), shared_info_id, 1025 static_cast<unsigned int>(descriptor->locals_count() + 1)); 1026 break; 1027 case FrameStateType::kArgumentsAdaptor: 1028 translation->BeginArgumentsAdaptorFrame( 1029 shared_info_id, 1030 static_cast<unsigned int>(descriptor->parameters_count())); 1031 break; 1032 case FrameStateType::kConstructStub: 1033 DCHECK(descriptor->bailout_id().IsValidForConstructStub()); 1034 translation->BeginConstructStubFrame( 1035 descriptor->bailout_id(), shared_info_id, 1036 static_cast<unsigned int>(descriptor->parameters_count())); 1037 break; 1038 case FrameStateType::kBuiltinContinuation: { 1039 BailoutId bailout_id = descriptor->bailout_id(); 1040 int parameter_count = 1041 static_cast<unsigned int>(descriptor->parameters_count()); 1042 translation->BeginBuiltinContinuationFrame(bailout_id, shared_info_id, 1043 parameter_count); 1044 break; 1045 } 1046 case FrameStateType::kJavaScriptBuiltinContinuation: { 1047 BailoutId bailout_id = descriptor->bailout_id(); 1048 int parameter_count = 1049 static_cast<unsigned int>(descriptor->parameters_count()); 1050 translation->BeginJavaScriptBuiltinContinuationFrame( 1051 bailout_id, shared_info_id, parameter_count); 1052 break; 1053 } 1054 case FrameStateType::kJavaScriptBuiltinContinuationWithCatch: { 1055 BailoutId bailout_id = descriptor->bailout_id(); 1056 int parameter_count = 1057 static_cast<unsigned int>(descriptor->parameters_count()); 1058 translation->BeginJavaScriptBuiltinContinuationWithCatchFrame( 1059 bailout_id, shared_info_id, parameter_count); 1060 break; 1061 } 1062 } 1063 1064 TranslateFrameStateDescriptorOperands(descriptor, iter, state_combine, 1065 translation); 1066 } 1067 1068 1069 int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset, 1070 size_t frame_state_offset, 1071 OutputFrameStateCombine state_combine) { 1072 DeoptimizationEntry const& entry = 1073 GetDeoptimizationEntry(instr, frame_state_offset); 1074 FrameStateDescriptor* const descriptor = entry.descriptor(); 1075 frame_state_offset++; 1076 1077 int update_feedback_count = entry.feedback().IsValid() ? 1 : 0; 1078 Translation translation(&translations_, 1079 static_cast<int>(descriptor->GetFrameCount()), 1080 static_cast<int>(descriptor->GetJSFrameCount()), 1081 update_feedback_count, zone()); 1082 if (entry.feedback().IsValid()) { 1083 DeoptimizationLiteral literal = 1084 DeoptimizationLiteral(entry.feedback().vector()); 1085 int literal_id = DefineDeoptimizationLiteral(literal); 1086 translation.AddUpdateFeedback(literal_id, entry.feedback().slot().ToInt()); 1087 } 1088 InstructionOperandIterator iter(instr, frame_state_offset); 1089 BuildTranslationForFrameStateDescriptor(descriptor, &iter, &translation, 1090 state_combine); 1091 1092 int deoptimization_id = static_cast<int>(deoptimization_states_.size()); 1093 1094 deoptimization_states_.push_back(new (zone()) DeoptimizationState( 1095 descriptor->bailout_id(), translation.index(), pc_offset, entry.kind(), 1096 entry.reason())); 1097 1098 return deoptimization_id; 1099 } 1100 1101 void CodeGenerator::AddTranslationForOperand(Translation* translation, 1102 Instruction* instr, 1103 InstructionOperand* op, 1104 MachineType type) { 1105 if (op->IsStackSlot()) { 1106 if (type.representation() == MachineRepresentation::kBit) { 1107 translation->StoreBoolStackSlot(LocationOperand::cast(op)->index()); 1108 } else if (type == MachineType::Int8() || type == MachineType::Int16() || 1109 type == MachineType::Int32()) { 1110 translation->StoreInt32StackSlot(LocationOperand::cast(op)->index()); 1111 } else if (type == MachineType::Uint8() || type == MachineType::Uint16() || 1112 type == MachineType::Uint32()) { 1113 translation->StoreUint32StackSlot(LocationOperand::cast(op)->index()); 1114 } else { 1115 CHECK_EQ(MachineRepresentation::kTagged, type.representation()); 1116 translation->StoreStackSlot(LocationOperand::cast(op)->index()); 1117 } 1118 } else if (op->IsFPStackSlot()) { 1119 if (type.representation() == MachineRepresentation::kFloat64) { 1120 translation->StoreDoubleStackSlot(LocationOperand::cast(op)->index()); 1121 } else { 1122 CHECK_EQ(MachineRepresentation::kFloat32, type.representation()); 1123 translation->StoreFloatStackSlot(LocationOperand::cast(op)->index()); 1124 } 1125 } else if (op->IsRegister()) { 1126 InstructionOperandConverter converter(this, instr); 1127 if (type.representation() == MachineRepresentation::kBit) { 1128 translation->StoreBoolRegister(converter.ToRegister(op)); 1129 } else if (type == MachineType::Int8() || type == MachineType::Int16() || 1130 type == MachineType::Int32()) { 1131 translation->StoreInt32Register(converter.ToRegister(op)); 1132 } else if (type == MachineType::Uint8() || type == MachineType::Uint16() || 1133 type == MachineType::Uint32()) { 1134 translation->StoreUint32Register(converter.ToRegister(op)); 1135 } else { 1136 CHECK_EQ(MachineRepresentation::kTagged, type.representation()); 1137 translation->StoreRegister(converter.ToRegister(op)); 1138 } 1139 } else if (op->IsFPRegister()) { 1140 InstructionOperandConverter converter(this, instr); 1141 if (type.representation() == MachineRepresentation::kFloat64) { 1142 translation->StoreDoubleRegister(converter.ToDoubleRegister(op)); 1143 } else { 1144 CHECK_EQ(MachineRepresentation::kFloat32, type.representation()); 1145 translation->StoreFloatRegister(converter.ToFloatRegister(op)); 1146 } 1147 } else { 1148 CHECK(op->IsImmediate()); 1149 InstructionOperandConverter converter(this, instr); 1150 Constant constant = converter.ToConstant(op); 1151 DeoptimizationLiteral literal; 1152 switch (constant.type()) { 1153 case Constant::kInt32: 1154 if (type.representation() == MachineRepresentation::kTagged) { 1155 // When pointers are 4 bytes, we can use int32 constants to represent 1156 // Smis. 1157 DCHECK_EQ(4, kPointerSize); 1158 Smi* smi = reinterpret_cast<Smi*>(constant.ToInt32()); 1159 DCHECK(smi->IsSmi()); 1160 literal = DeoptimizationLiteral(smi->value()); 1161 } else if (type.representation() == MachineRepresentation::kBit) { 1162 if (constant.ToInt32() == 0) { 1163 literal = 1164 DeoptimizationLiteral(isolate()->factory()->false_value()); 1165 } else { 1166 DCHECK_EQ(1, constant.ToInt32()); 1167 literal = DeoptimizationLiteral(isolate()->factory()->true_value()); 1168 } 1169 } else { 1170 DCHECK(type == MachineType::Int32() || 1171 type == MachineType::Uint32() || 1172 type.representation() == MachineRepresentation::kWord32 || 1173 type.representation() == MachineRepresentation::kNone); 1174 DCHECK(type.representation() != MachineRepresentation::kNone || 1175 constant.ToInt32() == FrameStateDescriptor::kImpossibleValue); 1176 if (type == MachineType::Uint32()) { 1177 literal = DeoptimizationLiteral( 1178 static_cast<uint32_t>(constant.ToInt32())); 1179 } else { 1180 literal = DeoptimizationLiteral(constant.ToInt32()); 1181 } 1182 } 1183 break; 1184 case Constant::kInt64: 1185 // When pointers are 8 bytes, we can use int64 constants to represent 1186 // Smis. 1187 DCHECK(type.representation() == MachineRepresentation::kWord64 || 1188 type.representation() == MachineRepresentation::kTagged); 1189 DCHECK_EQ(8, kPointerSize); 1190 { 1191 Smi* smi = reinterpret_cast<Smi*>(constant.ToInt64()); 1192 DCHECK(smi->IsSmi()); 1193 literal = DeoptimizationLiteral(smi->value()); 1194 } 1195 break; 1196 case Constant::kFloat32: 1197 DCHECK(type.representation() == MachineRepresentation::kFloat32 || 1198 type.representation() == MachineRepresentation::kTagged); 1199 literal = DeoptimizationLiteral(constant.ToFloat32()); 1200 break; 1201 case Constant::kFloat64: 1202 DCHECK(type.representation() == MachineRepresentation::kFloat64 || 1203 type.representation() == MachineRepresentation::kTagged); 1204 literal = DeoptimizationLiteral(constant.ToFloat64().value()); 1205 break; 1206 case Constant::kHeapObject: 1207 DCHECK_EQ(MachineRepresentation::kTagged, type.representation()); 1208 literal = DeoptimizationLiteral(constant.ToHeapObject()); 1209 break; 1210 default: 1211 UNREACHABLE(); 1212 } 1213 if (literal.object().equals(info()->closure())) { 1214 translation->StoreJSFrameFunction(); 1215 } else { 1216 int literal_id = DefineDeoptimizationLiteral(literal); 1217 translation->StoreLiteral(literal_id); 1218 } 1219 } 1220 } 1221 1222 void CodeGenerator::MarkLazyDeoptSite() { 1223 last_lazy_deopt_pc_ = tasm()->pc_offset(); 1224 } 1225 1226 DeoptimizationExit* CodeGenerator::AddDeoptimizationExit( 1227 Instruction* instr, size_t frame_state_offset) { 1228 int const deoptimization_id = BuildTranslation( 1229 instr, -1, frame_state_offset, OutputFrameStateCombine::Ignore()); 1230 1231 DeoptimizationExit* const exit = new (zone()) 1232 DeoptimizationExit(deoptimization_id, current_source_position_); 1233 deoptimization_exits_.push_back(exit); 1234 return exit; 1235 } 1236 1237 void CodeGenerator::InitializeSpeculationPoison() { 1238 if (poisoning_level_ == PoisoningMitigationLevel::kDontPoison) return; 1239 1240 // Initialize {kSpeculationPoisonRegister} either by comparing the expected 1241 // with the actual call target, or by unconditionally using {-1} initially. 1242 // Masking register arguments with it only makes sense in the first case. 1243 if (info()->called_with_code_start_register()) { 1244 tasm()->RecordComment("-- Prologue: generate speculation poison --"); 1245 GenerateSpeculationPoisonFromCodeStartRegister(); 1246 if (info()->is_poisoning_register_arguments()) { 1247 AssembleRegisterArgumentPoisoning(); 1248 } 1249 } else { 1250 ResetSpeculationPoison(); 1251 } 1252 } 1253 1254 void CodeGenerator::ResetSpeculationPoison() { 1255 if (poisoning_level_ != PoisoningMitigationLevel::kDontPoison) { 1256 tasm()->ResetSpeculationPoisonRegister(); 1257 } 1258 } 1259 1260 OutOfLineCode::OutOfLineCode(CodeGenerator* gen) 1261 : frame_(gen->frame()), tasm_(gen->tasm()), next_(gen->ools_) { 1262 gen->ools_ = this; 1263 } 1264 1265 OutOfLineCode::~OutOfLineCode() {} 1266 1267 Handle<Object> DeoptimizationLiteral::Reify(Isolate* isolate) const { 1268 return object_.is_null() ? isolate->factory()->NewNumber(number_) : object_; 1269 } 1270 1271 } // namespace compiler 1272 } // namespace internal 1273 } // namespace v8 1274