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