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/crankshaft/lithium-codegen.h" 6 7#include <sstream> 8 9#include "src/objects-inl.h" 10 11#if V8_TARGET_ARCH_IA32 12#include "src/crankshaft/ia32/lithium-ia32.h" // NOLINT 13#include "src/crankshaft/ia32/lithium-codegen-ia32.h" // NOLINT 14#elif V8_TARGET_ARCH_X64 15#include "src/crankshaft/x64/lithium-x64.h" // NOLINT 16#include "src/crankshaft/x64/lithium-codegen-x64.h" // NOLINT 17#elif V8_TARGET_ARCH_ARM 18#include "src/crankshaft/arm/lithium-arm.h" // NOLINT 19#include "src/crankshaft/arm/lithium-codegen-arm.h" // NOLINT 20#elif V8_TARGET_ARCH_ARM64 21#include "src/crankshaft/arm64/lithium-arm64.h" // NOLINT 22#include "src/crankshaft/arm64/lithium-codegen-arm64.h" // NOLINT 23#elif V8_TARGET_ARCH_MIPS 24#include "src/crankshaft/mips/lithium-mips.h" // NOLINT 25#include "src/crankshaft/mips/lithium-codegen-mips.h" // NOLINT 26#elif V8_TARGET_ARCH_MIPS64 27#include "src/crankshaft/mips64/lithium-mips64.h" // NOLINT 28#include "src/crankshaft/mips64/lithium-codegen-mips64.h" // NOLINT 29#elif V8_TARGET_ARCH_X87 30#include "src/crankshaft/x87/lithium-x87.h" // NOLINT 31#include "src/crankshaft/x87/lithium-codegen-x87.h" // NOLINT 32#elif V8_TARGET_ARCH_PPC 33#include "src/crankshaft/ppc/lithium-ppc.h" // NOLINT 34#include "src/crankshaft/ppc/lithium-codegen-ppc.h" // NOLINT 35#elif V8_TARGET_ARCH_S390 36#include "src/crankshaft/s390/lithium-s390.h" // NOLINT 37#include "src/crankshaft/s390/lithium-codegen-s390.h" // NOLINT 38#else 39#error Unsupported target architecture. 40#endif 41 42#include "src/globals.h" 43 44namespace v8 { 45namespace internal { 46 47 48HGraph* LCodeGenBase::graph() const { 49 return chunk()->graph(); 50} 51 52LCodeGenBase::LCodeGenBase(LChunk* chunk, MacroAssembler* assembler, 53 CompilationInfo* info) 54 : chunk_(static_cast<LPlatformChunk*>(chunk)), 55 masm_(assembler), 56 info_(info), 57 zone_(info->zone()), 58 status_(UNUSED), 59 current_block_(-1), 60 current_instruction_(-1), 61 instructions_(chunk->instructions()), 62 deoptimizations_(4, info->zone()), 63 deoptimization_literals_(8, info->zone()), 64 translations_(info->zone()), 65 inlined_function_count_(0), 66 last_lazy_deopt_pc_(0), 67 osr_pc_offset_(-1), 68 source_position_table_builder_(info->zone(), 69 info->SourcePositionRecordingMode()) {} 70 71Isolate* LCodeGenBase::isolate() const { return info_->isolate(); } 72 73bool LCodeGenBase::GenerateBody() { 74 DCHECK(is_generating()); 75 bool emit_instructions = true; 76 LCodeGen* codegen = static_cast<LCodeGen*>(this); 77 for (current_instruction_ = 0; 78 !is_aborted() && current_instruction_ < instructions_->length(); 79 current_instruction_++) { 80 LInstruction* instr = instructions_->at(current_instruction_); 81 82 // Don't emit code for basic blocks with a replacement. 83 if (instr->IsLabel()) { 84 emit_instructions = !LLabel::cast(instr)->HasReplacement() && 85 (!FLAG_unreachable_code_elimination || 86 instr->hydrogen_value()->block()->IsReachable()); 87 if (FLAG_code_comments && !emit_instructions) { 88 Comment( 89 ";;; <@%d,#%d> -------------------- B%d (unreachable/replaced) " 90 "--------------------", 91 current_instruction_, 92 instr->hydrogen_value()->id(), 93 instr->hydrogen_value()->block()->block_id()); 94 } 95 } 96 if (!emit_instructions) continue; 97 98 if (FLAG_code_comments && instr->HasInterestingComment(codegen)) { 99 Comment(";;; <@%d,#%d> %s", 100 current_instruction_, 101 instr->hydrogen_value()->id(), 102 instr->Mnemonic()); 103 } 104 105 GenerateBodyInstructionPre(instr); 106 107 HValue* value = instr->hydrogen_value(); 108 if (value->position().IsKnown()) { 109 RecordAndWritePosition(value->position()); 110 } 111 112 instr->CompileToNative(codegen); 113 114 GenerateBodyInstructionPost(instr); 115 } 116 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); 117 last_lazy_deopt_pc_ = masm()->pc_offset(); 118 return !is_aborted(); 119} 120 121 122void LCodeGenBase::CheckEnvironmentUsage() { 123#ifdef DEBUG 124 bool dead_block = false; 125 for (int i = 0; i < instructions_->length(); i++) { 126 LInstruction* instr = instructions_->at(i); 127 HValue* hval = instr->hydrogen_value(); 128 if (instr->IsLabel()) dead_block = LLabel::cast(instr)->HasReplacement(); 129 if (dead_block || !hval->block()->IsReachable()) continue; 130 131 HInstruction* hinstr = HInstruction::cast(hval); 132 if (!hinstr->CanDeoptimize() && instr->HasEnvironment()) { 133 V8_Fatal(__FILE__, __LINE__, "CanDeoptimize is wrong for %s (%s)", 134 hinstr->Mnemonic(), instr->Mnemonic()); 135 } 136 137 if (instr->HasEnvironment() && !instr->environment()->has_been_used()) { 138 V8_Fatal(__FILE__, __LINE__, "unused environment for %s (%s)", 139 hinstr->Mnemonic(), instr->Mnemonic()); 140 } 141 } 142#endif 143} 144 145void LCodeGenBase::RecordAndWritePosition(SourcePosition pos) { 146 if (!pos.IsKnown()) return; 147 source_position_table_builder_.AddPosition(masm_->pc_offset(), pos, false); 148} 149 150void LCodeGenBase::Comment(const char* format, ...) { 151 if (!FLAG_code_comments) return; 152 char buffer[4 * KB]; 153 StringBuilder builder(buffer, arraysize(buffer)); 154 va_list arguments; 155 va_start(arguments, format); 156 builder.AddFormattedList(format, arguments); 157 va_end(arguments); 158 159 // Copy the string before recording it in the assembler to avoid 160 // issues when the stack allocated buffer goes out of scope. 161 size_t length = builder.position(); 162 Vector<char> copy = Vector<char>::New(static_cast<int>(length) + 1); 163 MemCopy(copy.start(), builder.Finalize(), copy.length()); 164 masm()->RecordComment(copy.start()); 165} 166 167 168void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) { 169 SourcePosition position = deopt_info.position; 170 int deopt_id = deopt_info.deopt_id; 171 masm()->RecordDeoptReason(deopt_info.deopt_reason, position, deopt_id); 172} 173 174 175int LCodeGenBase::GetNextEmittedBlock() const { 176 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { 177 if (!graph()->blocks()->at(i)->IsReachable()) continue; 178 if (!chunk_->GetLabel(i)->HasReplacement()) return i; 179 } 180 return -1; 181} 182 183 184void LCodeGenBase::Abort(BailoutReason reason) { 185 info()->AbortOptimization(reason); 186 status_ = ABORTED; 187} 188 189 190void LCodeGenBase::Retry(BailoutReason reason) { 191 info()->RetryOptimization(reason); 192 status_ = ABORTED; 193} 194 195 196void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) { 197 if (map->is_deprecated()) return Retry(kMapBecameDeprecated); 198 chunk_->AddDeprecationDependency(map); 199} 200 201 202void LCodeGenBase::AddStabilityDependency(Handle<Map> map) { 203 if (!map->is_stable()) return Retry(kMapBecameUnstable); 204 chunk_->AddStabilityDependency(map); 205} 206 207 208int LCodeGenBase::DefineDeoptimizationLiteral(Handle<Object> literal) { 209 int result = deoptimization_literals_.length(); 210 for (int i = 0; i < deoptimization_literals_.length(); ++i) { 211 if (deoptimization_literals_[i].is_identical_to(literal)) return i; 212 } 213 deoptimization_literals_.Add(literal, zone()); 214 return result; 215} 216 217 218void LCodeGenBase::WriteTranslationFrame(LEnvironment* environment, 219 Translation* translation) { 220 int translation_size = environment->translation_size(); 221 // The output frame height does not include the parameters. 222 int height = translation_size - environment->parameter_count(); 223 224 switch (environment->frame_type()) { 225 case JS_FUNCTION: { 226 int shared_id = DefineDeoptimizationLiteral( 227 environment->entry() ? environment->entry()->shared() 228 : info()->shared_info()); 229 translation->BeginJSFrame(environment->ast_id(), shared_id, height); 230 if (info()->closure().is_identical_to(environment->closure())) { 231 translation->StoreJSFrameFunction(); 232 } else { 233 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 234 translation->StoreLiteral(closure_id); 235 } 236 break; 237 } 238 case JS_CONSTRUCT: { 239 int shared_id = DefineDeoptimizationLiteral( 240 environment->entry() ? environment->entry()->shared() 241 : info()->shared_info()); 242 translation->BeginConstructStubFrame(BailoutId::ConstructStubInvoke(), 243 shared_id, translation_size); 244 if (info()->closure().is_identical_to(environment->closure())) { 245 translation->StoreJSFrameFunction(); 246 } else { 247 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 248 translation->StoreLiteral(closure_id); 249 } 250 break; 251 } 252 case JS_GETTER: { 253 DCHECK_EQ(1, translation_size); 254 DCHECK_EQ(0, height); 255 int shared_id = DefineDeoptimizationLiteral( 256 environment->entry() ? environment->entry()->shared() 257 : info()->shared_info()); 258 translation->BeginGetterStubFrame(shared_id); 259 if (info()->closure().is_identical_to(environment->closure())) { 260 translation->StoreJSFrameFunction(); 261 } else { 262 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 263 translation->StoreLiteral(closure_id); 264 } 265 break; 266 } 267 case JS_SETTER: { 268 DCHECK_EQ(2, translation_size); 269 DCHECK_EQ(0, height); 270 int shared_id = DefineDeoptimizationLiteral( 271 environment->entry() ? environment->entry()->shared() 272 : info()->shared_info()); 273 translation->BeginSetterStubFrame(shared_id); 274 if (info()->closure().is_identical_to(environment->closure())) { 275 translation->StoreJSFrameFunction(); 276 } else { 277 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 278 translation->StoreLiteral(closure_id); 279 } 280 break; 281 } 282 case TAIL_CALLER_FUNCTION: { 283 DCHECK_EQ(0, translation_size); 284 int shared_id = DefineDeoptimizationLiteral( 285 environment->entry() ? environment->entry()->shared() 286 : info()->shared_info()); 287 translation->BeginTailCallerFrame(shared_id); 288 if (info()->closure().is_identical_to(environment->closure())) { 289 translation->StoreJSFrameFunction(); 290 } else { 291 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 292 translation->StoreLiteral(closure_id); 293 } 294 break; 295 } 296 case ARGUMENTS_ADAPTOR: { 297 int shared_id = DefineDeoptimizationLiteral( 298 environment->entry() ? environment->entry()->shared() 299 : info()->shared_info()); 300 translation->BeginArgumentsAdaptorFrame(shared_id, translation_size); 301 if (info()->closure().is_identical_to(environment->closure())) { 302 translation->StoreJSFrameFunction(); 303 } else { 304 int closure_id = DefineDeoptimizationLiteral(environment->closure()); 305 translation->StoreLiteral(closure_id); 306 } 307 break; 308 } 309 case STUB: 310 translation->BeginCompiledStubFrame(translation_size); 311 break; 312 } 313} 314 315namespace { 316 317Handle<PodArray<InliningPosition>> CreateInliningPositions( 318 CompilationInfo* info) { 319 const CompilationInfo::InlinedFunctionList& inlined_functions = 320 info->inlined_functions(); 321 if (inlined_functions.size() == 0) { 322 return Handle<PodArray<InliningPosition>>::cast( 323 info->isolate()->factory()->empty_byte_array()); 324 } 325 Handle<PodArray<InliningPosition>> inl_positions = 326 PodArray<InliningPosition>::New( 327 info->isolate(), static_cast<int>(inlined_functions.size()), TENURED); 328 for (size_t i = 0; i < inlined_functions.size(); ++i) { 329 inl_positions->set(static_cast<int>(i), inlined_functions[i].position); 330 } 331 return inl_positions; 332} 333 334} // namespace 335 336void LCodeGenBase::PopulateDeoptimizationData(Handle<Code> code) { 337 int length = deoptimizations_.length(); 338 if (length == 0) return; 339 Handle<DeoptimizationInputData> data = 340 DeoptimizationInputData::New(isolate(), length, TENURED); 341 342 Handle<ByteArray> translations = 343 translations_.CreateByteArray(isolate()->factory()); 344 data->SetTranslationByteArray(*translations); 345 data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_)); 346 data->SetOptimizationId(Smi::FromInt(info_->optimization_id())); 347 if (info_->IsOptimizing()) { 348 // Reference to shared function info does not change between phases. 349 AllowDeferredHandleDereference allow_handle_dereference; 350 data->SetSharedFunctionInfo(*info_->shared_info()); 351 } else { 352 data->SetSharedFunctionInfo(Smi::kZero); 353 } 354 data->SetWeakCellCache(Smi::kZero); 355 356 Handle<FixedArray> literals = 357 factory()->NewFixedArray(deoptimization_literals_.length(), TENURED); 358 { 359 AllowDeferredHandleDereference copy_handles; 360 for (int i = 0; i < deoptimization_literals_.length(); i++) { 361 literals->set(i, *deoptimization_literals_[i]); 362 } 363 data->SetLiteralArray(*literals); 364 } 365 366 Handle<PodArray<InliningPosition>> inl_pos = CreateInliningPositions(info_); 367 data->SetInliningPositions(*inl_pos); 368 369 data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt())); 370 data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_)); 371 372 // Populate the deoptimization entries. 373 for (int i = 0; i < length; i++) { 374 LEnvironment* env = deoptimizations_[i]; 375 data->SetAstId(i, env->ast_id()); 376 data->SetTranslationIndex(i, Smi::FromInt(env->translation_index())); 377 data->SetArgumentsStackHeight(i, 378 Smi::FromInt(env->arguments_stack_height())); 379 data->SetPc(i, Smi::FromInt(env->pc_offset())); 380 } 381 code->set_deoptimization_data(*data); 382} 383 384 385void LCodeGenBase::PopulateDeoptimizationLiteralsWithInlinedFunctions() { 386 DCHECK_EQ(0, deoptimization_literals_.length()); 387 for (CompilationInfo::InlinedFunctionHolder& inlined : 388 info()->inlined_functions()) { 389 if (!inlined.shared_info.is_identical_to(info()->shared_info())) { 390 int index = DefineDeoptimizationLiteral(inlined.shared_info); 391 inlined.RegisterInlinedFunctionId(index); 392 } 393 } 394 inlined_function_count_ = deoptimization_literals_.length(); 395 396 // Define deoptimization literals for all unoptimized code objects of inlined 397 // functions. This ensures unoptimized code is kept alive by optimized code. 398 for (const CompilationInfo::InlinedFunctionHolder& inlined : 399 info()->inlined_functions()) { 400 if (!inlined.shared_info.is_identical_to(info()->shared_info())) { 401 DefineDeoptimizationLiteral(inlined.inlined_code_object_root); 402 } 403 } 404} 405 406Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo( 407 LInstruction* instr, DeoptimizeReason deopt_reason, int deopt_id) { 408 Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(), 409 deopt_reason, deopt_id); 410 return deopt_info; 411} 412 413} // namespace internal 414} // namespace v8 415