| OLD | NEW |
| (Empty) |
| 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/lithium-codegen.h" | |
| 6 | |
| 7 #include <sstream> | |
| 8 | |
| 9 #if V8_TARGET_ARCH_IA32 | |
| 10 #include "src/ia32/lithium-ia32.h" // NOLINT | |
| 11 #include "src/ia32/lithium-codegen-ia32.h" // NOLINT | |
| 12 #elif V8_TARGET_ARCH_X64 | |
| 13 #include "src/x64/lithium-x64.h" // NOLINT | |
| 14 #include "src/x64/lithium-codegen-x64.h" // NOLINT | |
| 15 #elif V8_TARGET_ARCH_ARM | |
| 16 #include "src/arm/lithium-arm.h" // NOLINT | |
| 17 #include "src/arm/lithium-codegen-arm.h" // NOLINT | |
| 18 #elif V8_TARGET_ARCH_ARM64 | |
| 19 #include "src/arm64/lithium-arm64.h" // NOLINT | |
| 20 #include "src/arm64/lithium-codegen-arm64.h" // NOLINT | |
| 21 #elif V8_TARGET_ARCH_MIPS | |
| 22 #include "src/mips/lithium-mips.h" // NOLINT | |
| 23 #include "src/mips/lithium-codegen-mips.h" // NOLINT | |
| 24 #elif V8_TARGET_ARCH_MIPS64 | |
| 25 #include "src/mips64/lithium-mips64.h" // NOLINT | |
| 26 #include "src/mips64/lithium-codegen-mips64.h" // NOLINT | |
| 27 #elif V8_TARGET_ARCH_X87 | |
| 28 #include "src/x87/lithium-x87.h" // NOLINT | |
| 29 #include "src/x87/lithium-codegen-x87.h" // NOLINT | |
| 30 #elif V8_TARGET_ARCH_PPC | |
| 31 #include "src/ppc/lithium-ppc.h" // NOLINT | |
| 32 #include "src/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 deoptimization_literals_(8, info->zone()), | |
| 57 last_lazy_deopt_pc_(0) {} | |
| 58 | |
| 59 | |
| 60 bool LCodeGenBase::GenerateBody() { | |
| 61 DCHECK(is_generating()); | |
| 62 bool emit_instructions = true; | |
| 63 LCodeGen* codegen = static_cast<LCodeGen*>(this); | |
| 64 for (current_instruction_ = 0; | |
| 65 !is_aborted() && current_instruction_ < instructions_->length(); | |
| 66 current_instruction_++) { | |
| 67 LInstruction* instr = instructions_->at(current_instruction_); | |
| 68 | |
| 69 // Don't emit code for basic blocks with a replacement. | |
| 70 if (instr->IsLabel()) { | |
| 71 emit_instructions = !LLabel::cast(instr)->HasReplacement() && | |
| 72 (!FLAG_unreachable_code_elimination || | |
| 73 instr->hydrogen_value()->block()->IsReachable()); | |
| 74 if (FLAG_code_comments && !emit_instructions) { | |
| 75 Comment( | |
| 76 ";;; <@%d,#%d> -------------------- B%d (unreachable/replaced) " | |
| 77 "--------------------", | |
| 78 current_instruction_, | |
| 79 instr->hydrogen_value()->id(), | |
| 80 instr->hydrogen_value()->block()->block_id()); | |
| 81 } | |
| 82 } | |
| 83 if (!emit_instructions) continue; | |
| 84 | |
| 85 if (FLAG_code_comments && instr->HasInterestingComment(codegen)) { | |
| 86 Comment(";;; <@%d,#%d> %s", | |
| 87 current_instruction_, | |
| 88 instr->hydrogen_value()->id(), | |
| 89 instr->Mnemonic()); | |
| 90 } | |
| 91 | |
| 92 GenerateBodyInstructionPre(instr); | |
| 93 | |
| 94 HValue* value = instr->hydrogen_value(); | |
| 95 if (!value->position().IsUnknown()) { | |
| 96 RecordAndWritePosition( | |
| 97 chunk()->graph()->SourcePositionToScriptPosition(value->position())); | |
| 98 } | |
| 99 | |
| 100 instr->CompileToNative(codegen); | |
| 101 | |
| 102 GenerateBodyInstructionPost(instr); | |
| 103 } | |
| 104 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); | |
| 105 last_lazy_deopt_pc_ = masm()->pc_offset(); | |
| 106 return !is_aborted(); | |
| 107 } | |
| 108 | |
| 109 | |
| 110 void LCodeGenBase::CheckEnvironmentUsage() { | |
| 111 #ifdef DEBUG | |
| 112 bool dead_block = false; | |
| 113 for (int i = 0; i < instructions_->length(); i++) { | |
| 114 LInstruction* instr = instructions_->at(i); | |
| 115 HValue* hval = instr->hydrogen_value(); | |
| 116 if (instr->IsLabel()) dead_block = LLabel::cast(instr)->HasReplacement(); | |
| 117 if (dead_block || !hval->block()->IsReachable()) continue; | |
| 118 | |
| 119 HInstruction* hinstr = HInstruction::cast(hval); | |
| 120 if (!hinstr->CanDeoptimize() && instr->HasEnvironment()) { | |
| 121 V8_Fatal(__FILE__, __LINE__, "CanDeoptimize is wrong for %s (%s)", | |
| 122 hinstr->Mnemonic(), instr->Mnemonic()); | |
| 123 } | |
| 124 | |
| 125 if (instr->HasEnvironment() && !instr->environment()->has_been_used()) { | |
| 126 V8_Fatal(__FILE__, __LINE__, "unused environment for %s (%s)", | |
| 127 hinstr->Mnemonic(), instr->Mnemonic()); | |
| 128 } | |
| 129 } | |
| 130 #endif | |
| 131 } | |
| 132 | |
| 133 | |
| 134 void LCodeGenBase::Comment(const char* format, ...) { | |
| 135 if (!FLAG_code_comments) return; | |
| 136 char buffer[4 * KB]; | |
| 137 StringBuilder builder(buffer, arraysize(buffer)); | |
| 138 va_list arguments; | |
| 139 va_start(arguments, format); | |
| 140 builder.AddFormattedList(format, arguments); | |
| 141 va_end(arguments); | |
| 142 | |
| 143 // Copy the string before recording it in the assembler to avoid | |
| 144 // issues when the stack allocated buffer goes out of scope. | |
| 145 size_t length = builder.position(); | |
| 146 Vector<char> copy = Vector<char>::New(static_cast<int>(length) + 1); | |
| 147 MemCopy(copy.start(), builder.Finalize(), copy.length()); | |
| 148 masm()->RecordComment(copy.start()); | |
| 149 } | |
| 150 | |
| 151 | |
| 152 void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) { | |
| 153 masm()->RecordDeoptReason(deopt_info.deopt_reason, deopt_info.position); | |
| 154 } | |
| 155 | |
| 156 | |
| 157 int LCodeGenBase::GetNextEmittedBlock() const { | |
| 158 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { | |
| 159 if (!graph()->blocks()->at(i)->IsReachable()) continue; | |
| 160 if (!chunk_->GetLabel(i)->HasReplacement()) return i; | |
| 161 } | |
| 162 return -1; | |
| 163 } | |
| 164 | |
| 165 | |
| 166 void LCodeGenBase::Abort(BailoutReason reason) { | |
| 167 info()->AbortOptimization(reason); | |
| 168 status_ = ABORTED; | |
| 169 } | |
| 170 | |
| 171 | |
| 172 void LCodeGenBase::Retry(BailoutReason reason) { | |
| 173 info()->RetryOptimization(reason); | |
| 174 status_ = ABORTED; | |
| 175 } | |
| 176 | |
| 177 | |
| 178 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) { | |
| 179 if (map->is_deprecated()) return Retry(kMapBecameDeprecated); | |
| 180 chunk_->AddDeprecationDependency(map); | |
| 181 } | |
| 182 | |
| 183 | |
| 184 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) { | |
| 185 if (!map->is_stable()) return Retry(kMapBecameUnstable); | |
| 186 chunk_->AddStabilityDependency(map); | |
| 187 } | |
| 188 | |
| 189 | |
| 190 int LCodeGenBase::DefineDeoptimizationLiteral(Handle<Object> literal) { | |
| 191 int result = deoptimization_literals_.length(); | |
| 192 for (int i = 0; i < deoptimization_literals_.length(); ++i) { | |
| 193 if (deoptimization_literals_[i].is_identical_to(literal)) return i; | |
| 194 } | |
| 195 deoptimization_literals_.Add(literal, zone()); | |
| 196 return result; | |
| 197 } | |
| 198 | |
| 199 | |
| 200 void LCodeGenBase::WriteTranslationFrame(LEnvironment* environment, | |
| 201 Translation* translation) { | |
| 202 int translation_size = environment->translation_size(); | |
| 203 // The output frame height does not include the parameters. | |
| 204 int height = translation_size - environment->parameter_count(); | |
| 205 | |
| 206 switch (environment->frame_type()) { | |
| 207 case JS_FUNCTION: { | |
| 208 int shared_id = DefineDeoptimizationLiteral( | |
| 209 environment->entry() ? environment->entry()->shared() | |
| 210 : info()->shared_info()); | |
| 211 translation->BeginJSFrame(environment->ast_id(), shared_id, height); | |
| 212 if (info()->closure().is_identical_to(environment->closure())) { | |
| 213 translation->StoreJSFrameFunction(); | |
| 214 } else { | |
| 215 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
| 216 translation->StoreLiteral(closure_id); | |
| 217 } | |
| 218 break; | |
| 219 } | |
| 220 case JS_CONSTRUCT: { | |
| 221 int shared_id = DefineDeoptimizationLiteral( | |
| 222 environment->entry() ? environment->entry()->shared() | |
| 223 : info()->shared_info()); | |
| 224 translation->BeginConstructStubFrame(shared_id, translation_size); | |
| 225 if (info()->closure().is_identical_to(environment->closure())) { | |
| 226 translation->StoreJSFrameFunction(); | |
| 227 } else { | |
| 228 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
| 229 translation->StoreLiteral(closure_id); | |
| 230 } | |
| 231 break; | |
| 232 } | |
| 233 case JS_GETTER: { | |
| 234 DCHECK(translation_size == 1); | |
| 235 DCHECK(height == 0); | |
| 236 int shared_id = DefineDeoptimizationLiteral( | |
| 237 environment->entry() ? environment->entry()->shared() | |
| 238 : info()->shared_info()); | |
| 239 translation->BeginGetterStubFrame(shared_id); | |
| 240 if (info()->closure().is_identical_to(environment->closure())) { | |
| 241 translation->StoreJSFrameFunction(); | |
| 242 } else { | |
| 243 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
| 244 translation->StoreLiteral(closure_id); | |
| 245 } | |
| 246 break; | |
| 247 } | |
| 248 case JS_SETTER: { | |
| 249 DCHECK(translation_size == 2); | |
| 250 DCHECK(height == 0); | |
| 251 int shared_id = DefineDeoptimizationLiteral( | |
| 252 environment->entry() ? environment->entry()->shared() | |
| 253 : info()->shared_info()); | |
| 254 translation->BeginSetterStubFrame(shared_id); | |
| 255 if (info()->closure().is_identical_to(environment->closure())) { | |
| 256 translation->StoreJSFrameFunction(); | |
| 257 } else { | |
| 258 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
| 259 translation->StoreLiteral(closure_id); | |
| 260 } | |
| 261 break; | |
| 262 } | |
| 263 case ARGUMENTS_ADAPTOR: { | |
| 264 int shared_id = DefineDeoptimizationLiteral( | |
| 265 environment->entry() ? environment->entry()->shared() | |
| 266 : info()->shared_info()); | |
| 267 translation->BeginArgumentsAdaptorFrame(shared_id, translation_size); | |
| 268 if (info()->closure().is_identical_to(environment->closure())) { | |
| 269 translation->StoreJSFrameFunction(); | |
| 270 } else { | |
| 271 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
| 272 translation->StoreLiteral(closure_id); | |
| 273 } | |
| 274 break; | |
| 275 } | |
| 276 case STUB: | |
| 277 translation->BeginCompiledStubFrame(translation_size); | |
| 278 break; | |
| 279 } | |
| 280 } | |
| 281 | |
| 282 | |
| 283 Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo( | |
| 284 LInstruction* instr, Deoptimizer::DeoptReason deopt_reason) { | |
| 285 Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(), | |
| 286 instr->Mnemonic(), deopt_reason); | |
| 287 HEnterInlined* enter_inlined = instr->environment()->entry(); | |
| 288 deopt_info.inlining_id = enter_inlined ? enter_inlined->inlining_id() : 0; | |
| 289 return deopt_info; | |
| 290 } | |
| 291 } // namespace internal | |
| 292 } // namespace v8 | |
| OLD | NEW |