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