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