• 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 #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 
graph() const44 HGraph* LCodeGenBase::graph() const {
45   return chunk()->graph();
46 }
47 
48 
LCodeGenBase(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)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 
GenerateBody()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 
CheckEnvironmentUsage()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 
Comment(const char * format,...)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 
DeoptComment(const Deoptimizer::DeoptInfo & deopt_info)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 
GetNextEmittedBlock() const167 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 
Abort(BailoutReason reason)176 void LCodeGenBase::Abort(BailoutReason reason) {
177   info()->AbortOptimization(reason);
178   status_ = ABORTED;
179 }
180 
181 
Retry(BailoutReason reason)182 void LCodeGenBase::Retry(BailoutReason reason) {
183   info()->RetryOptimization(reason);
184   status_ = ABORTED;
185 }
186 
187 
AddDeprecationDependency(Handle<Map> map)188 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
189   if (map->is_deprecated()) return Retry(kMapBecameDeprecated);
190   chunk_->AddDeprecationDependency(map);
191 }
192 
193 
AddStabilityDependency(Handle<Map> map)194 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
195   if (!map->is_stable()) return Retry(kMapBecameUnstable);
196   chunk_->AddStabilityDependency(map);
197 }
198 
199 
DefineDeoptimizationLiteral(Handle<Object> literal)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 
WriteTranslationFrame(LEnvironment * environment,Translation * translation)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 
PopulateDeoptimizationData(Handle<Code> code)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 
PopulateDeoptimizationLiteralsWithInlinedFunctions()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 
MakeDeoptInfo(LInstruction * instr,Deoptimizer::DeoptReason deopt_reason,int deopt_id)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