Home | History | Annotate | Download | only in crankshaft
      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 
     44 namespace v8 {
     45 namespace internal {
     46 
     47 
     48 HGraph* LCodeGenBase::graph() const {
     49   return chunk()->graph();
     50 }
     51 
     52 LCodeGenBase::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 
     71 Isolate* LCodeGenBase::isolate() const { return info_->isolate(); }
     72 
     73 bool 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 
    122 void 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 
    145 void LCodeGenBase::RecordAndWritePosition(SourcePosition pos) {
    146   if (!pos.IsKnown()) return;
    147   source_position_table_builder_.AddPosition(masm_->pc_offset(), pos, false);
    148 }
    149 
    150 void 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 
    168 void 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 
    175 int 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 
    184 void LCodeGenBase::Abort(BailoutReason reason) {
    185   info()->AbortOptimization(reason);
    186   status_ = ABORTED;
    187 }
    188 
    189 
    190 void LCodeGenBase::Retry(BailoutReason reason) {
    191   info()->RetryOptimization(reason);
    192   status_ = ABORTED;
    193 }
    194 
    195 
    196 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
    197   if (map->is_deprecated()) return Retry(kMapBecameDeprecated);
    198   chunk_->AddDeprecationDependency(map);
    199 }
    200 
    201 
    202 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
    203   if (!map->is_stable()) return Retry(kMapBecameUnstable);
    204   chunk_->AddStabilityDependency(map);
    205 }
    206 
    207 
    208 int 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 
    218 void 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 
    315 namespace {
    316 
    317 Handle<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 
    336 void 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 
    385 void 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 
    406 Deoptimizer::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