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 #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