• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
graph() const41 HGraph* LCodeGenBase::graph() const {
42   return chunk()->graph();
43 }
44 
45 
LCodeGenBase(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)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 
GenerateBody()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 
CheckEnvironmentUsage()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 
Comment(const char * format,...)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 
DeoptComment(const Deoptimizer::DeoptInfo & deopt_info)156 void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
157   masm()->RecordDeoptReason(deopt_info.deopt_reason, deopt_info.position);
158 }
159 
160 
GetNextEmittedBlock() const161 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 
Abort(BailoutReason reason)170 void LCodeGenBase::Abort(BailoutReason reason) {
171   info()->AbortOptimization(reason);
172   status_ = ABORTED;
173 }
174 
175 
Retry(BailoutReason reason)176 void LCodeGenBase::Retry(BailoutReason reason) {
177   info()->RetryOptimization(reason);
178   status_ = ABORTED;
179 }
180 
181 
AddDeprecationDependency(Handle<Map> map)182 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
183   if (map->is_deprecated()) return Retry(kMapBecameDeprecated);
184   chunk_->AddDeprecationDependency(map);
185 }
186 
187 
AddStabilityDependency(Handle<Map> map)188 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
189   if (!map->is_stable()) return Retry(kMapBecameUnstable);
190   chunk_->AddStabilityDependency(map);
191 }
192 
193 
DefineDeoptimizationLiteral(Handle<Object> literal)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 
WriteTranslationFrame(LEnvironment * environment,Translation * translation)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 
PopulateDeoptimizationData(Handle<Code> code)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 
PopulateDeoptimizationLiteralsWithInlinedFunctions()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 
MakeDeoptInfo(LInstruction * instr,Deoptimizer::DeoptReason deopt_reason)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