• Home
  • History
  • Annotate
  • 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 #include "src/globals.h"
41 
42 namespace v8 {
43 namespace internal {
44 
45 
graph() const46 HGraph* LCodeGenBase::graph() const {
47   return chunk()->graph();
48 }
49 
LCodeGenBase(LChunk * chunk,MacroAssembler * assembler,CompilationInfo * info)50 LCodeGenBase::LCodeGenBase(LChunk* chunk, MacroAssembler* assembler,
51                            CompilationInfo* info)
52     : chunk_(static_cast<LPlatformChunk*>(chunk)),
53       masm_(assembler),
54       info_(info),
55       zone_(info->zone()),
56       status_(UNUSED),
57       current_block_(-1),
58       current_instruction_(-1),
59       instructions_(chunk->instructions()),
60       deoptimizations_(4, info->zone()),
61       deoptimization_literals_(8, info->zone()),
62       translations_(info->zone()),
63       inlined_function_count_(0),
64       last_lazy_deopt_pc_(0),
65       osr_pc_offset_(-1),
66       source_position_table_builder_(info->zone(),
67                                      info->SourcePositionRecordingMode()) {}
68 
isolate() const69 Isolate* LCodeGenBase::isolate() const { return info_->isolate(); }
70 
GenerateBody()71 bool LCodeGenBase::GenerateBody() {
72   DCHECK(is_generating());
73   bool emit_instructions = true;
74   LCodeGen* codegen = static_cast<LCodeGen*>(this);
75   for (current_instruction_ = 0;
76        !is_aborted() && current_instruction_ < instructions_->length();
77        current_instruction_++) {
78     LInstruction* instr = instructions_->at(current_instruction_);
79 
80     // Don't emit code for basic blocks with a replacement.
81     if (instr->IsLabel()) {
82       emit_instructions = !LLabel::cast(instr)->HasReplacement() &&
83           (!FLAG_unreachable_code_elimination ||
84            instr->hydrogen_value()->block()->IsReachable());
85       if (FLAG_code_comments && !emit_instructions) {
86         Comment(
87             ";;; <@%d,#%d> -------------------- B%d (unreachable/replaced) "
88             "--------------------",
89             current_instruction_,
90             instr->hydrogen_value()->id(),
91             instr->hydrogen_value()->block()->block_id());
92       }
93     }
94     if (!emit_instructions) continue;
95 
96     if (FLAG_code_comments && instr->HasInterestingComment(codegen)) {
97       Comment(";;; <@%d,#%d> %s",
98               current_instruction_,
99               instr->hydrogen_value()->id(),
100               instr->Mnemonic());
101     }
102 
103     GenerateBodyInstructionPre(instr);
104 
105     HValue* value = instr->hydrogen_value();
106     if (value->position().IsKnown()) {
107       RecordAndWritePosition(value->position());
108     }
109 
110     instr->CompileToNative(codegen);
111 
112     GenerateBodyInstructionPost(instr);
113   }
114   EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
115   last_lazy_deopt_pc_ = masm()->pc_offset();
116   return !is_aborted();
117 }
118 
119 
CheckEnvironmentUsage()120 void LCodeGenBase::CheckEnvironmentUsage() {
121 #ifdef DEBUG
122   bool dead_block = false;
123   for (int i = 0; i < instructions_->length(); i++) {
124     LInstruction* instr = instructions_->at(i);
125     HValue* hval = instr->hydrogen_value();
126     if (instr->IsLabel()) dead_block = LLabel::cast(instr)->HasReplacement();
127     if (dead_block || !hval->block()->IsReachable()) continue;
128 
129     HInstruction* hinstr = HInstruction::cast(hval);
130     if (!hinstr->CanDeoptimize() && instr->HasEnvironment()) {
131       V8_Fatal(__FILE__, __LINE__, "CanDeoptimize is wrong for %s (%s)",
132                hinstr->Mnemonic(), instr->Mnemonic());
133     }
134 
135     if (instr->HasEnvironment() && !instr->environment()->has_been_used()) {
136       V8_Fatal(__FILE__, __LINE__, "unused environment for %s (%s)",
137                hinstr->Mnemonic(), instr->Mnemonic());
138     }
139   }
140 #endif
141 }
142 
RecordAndWritePosition(SourcePosition pos)143 void LCodeGenBase::RecordAndWritePosition(SourcePosition pos) {
144   if (!pos.IsKnown()) return;
145   source_position_table_builder_.AddPosition(masm_->pc_offset(), pos, false);
146 }
147 
Comment(const char * format,...)148 void LCodeGenBase::Comment(const char* format, ...) {
149   if (!FLAG_code_comments) return;
150   char buffer[4 * KB];
151   StringBuilder builder(buffer, arraysize(buffer));
152   va_list arguments;
153   va_start(arguments, format);
154   builder.AddFormattedList(format, arguments);
155   va_end(arguments);
156 
157   // Copy the string before recording it in the assembler to avoid
158   // issues when the stack allocated buffer goes out of scope.
159   size_t length = builder.position();
160   Vector<char> copy = Vector<char>::New(static_cast<int>(length) + 1);
161   MemCopy(copy.start(), builder.Finalize(), copy.length());
162   masm()->RecordComment(copy.start());
163 }
164 
165 
DeoptComment(const Deoptimizer::DeoptInfo & deopt_info)166 void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
167   SourcePosition position = deopt_info.position;
168   int deopt_id = deopt_info.deopt_id;
169   masm()->RecordDeoptReason(deopt_info.deopt_reason, position, deopt_id);
170 }
171 
172 
GetNextEmittedBlock() const173 int LCodeGenBase::GetNextEmittedBlock() const {
174   for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) {
175     if (!graph()->blocks()->at(i)->IsReachable()) continue;
176     if (!chunk_->GetLabel(i)->HasReplacement()) return i;
177   }
178   return -1;
179 }
180 
181 
Abort(BailoutReason reason)182 void LCodeGenBase::Abort(BailoutReason reason) {
183   info()->AbortOptimization(reason);
184   status_ = ABORTED;
185 }
186 
187 
Retry(BailoutReason reason)188 void LCodeGenBase::Retry(BailoutReason reason) {
189   info()->RetryOptimization(reason);
190   status_ = ABORTED;
191 }
192 
193 
AddDeprecationDependency(Handle<Map> map)194 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
195   if (map->is_deprecated()) return Retry(kMapBecameDeprecated);
196   chunk_->AddDeprecationDependency(map);
197 }
198 
199 
AddStabilityDependency(Handle<Map> map)200 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
201   if (!map->is_stable()) return Retry(kMapBecameUnstable);
202   chunk_->AddStabilityDependency(map);
203 }
204 
205 
DefineDeoptimizationLiteral(Handle<Object> literal)206 int LCodeGenBase::DefineDeoptimizationLiteral(Handle<Object> literal) {
207   int result = deoptimization_literals_.length();
208   for (int i = 0; i < deoptimization_literals_.length(); ++i) {
209     if (deoptimization_literals_[i].is_identical_to(literal)) return i;
210   }
211   deoptimization_literals_.Add(literal, zone());
212   return result;
213 }
214 
215 
WriteTranslationFrame(LEnvironment * environment,Translation * translation)216 void LCodeGenBase::WriteTranslationFrame(LEnvironment* environment,
217                                          Translation* translation) {
218   int translation_size = environment->translation_size();
219   // The output frame height does not include the parameters.
220   int height = translation_size - environment->parameter_count();
221 
222   switch (environment->frame_type()) {
223     case JS_FUNCTION: {
224       int shared_id = DefineDeoptimizationLiteral(
225           environment->entry() ? environment->entry()->shared()
226                                : info()->shared_info());
227       translation->BeginJSFrame(environment->ast_id(), shared_id, height);
228       if (info()->closure().is_identical_to(environment->closure())) {
229         translation->StoreJSFrameFunction();
230       } else {
231         int closure_id = DefineDeoptimizationLiteral(environment->closure());
232         translation->StoreLiteral(closure_id);
233       }
234       break;
235     }
236     case JS_CONSTRUCT: {
237       int shared_id = DefineDeoptimizationLiteral(
238           environment->entry() ? environment->entry()->shared()
239                                : info()->shared_info());
240       translation->BeginConstructStubFrame(shared_id, translation_size);
241       if (info()->closure().is_identical_to(environment->closure())) {
242         translation->StoreJSFrameFunction();
243       } else {
244         int closure_id = DefineDeoptimizationLiteral(environment->closure());
245         translation->StoreLiteral(closure_id);
246       }
247       break;
248     }
249     case JS_GETTER: {
250       DCHECK_EQ(1, translation_size);
251       DCHECK_EQ(0, height);
252       int shared_id = DefineDeoptimizationLiteral(
253           environment->entry() ? environment->entry()->shared()
254                                : info()->shared_info());
255       translation->BeginGetterStubFrame(shared_id);
256       if (info()->closure().is_identical_to(environment->closure())) {
257         translation->StoreJSFrameFunction();
258       } else {
259         int closure_id = DefineDeoptimizationLiteral(environment->closure());
260         translation->StoreLiteral(closure_id);
261       }
262       break;
263     }
264     case JS_SETTER: {
265       DCHECK_EQ(2, translation_size);
266       DCHECK_EQ(0, height);
267       int shared_id = DefineDeoptimizationLiteral(
268           environment->entry() ? environment->entry()->shared()
269                                : info()->shared_info());
270       translation->BeginSetterStubFrame(shared_id);
271       if (info()->closure().is_identical_to(environment->closure())) {
272         translation->StoreJSFrameFunction();
273       } else {
274         int closure_id = DefineDeoptimizationLiteral(environment->closure());
275         translation->StoreLiteral(closure_id);
276       }
277       break;
278     }
279     case TAIL_CALLER_FUNCTION: {
280       DCHECK_EQ(0, translation_size);
281       int shared_id = DefineDeoptimizationLiteral(
282           environment->entry() ? environment->entry()->shared()
283                                : info()->shared_info());
284       translation->BeginTailCallerFrame(shared_id);
285       if (info()->closure().is_identical_to(environment->closure())) {
286         translation->StoreJSFrameFunction();
287       } else {
288         int closure_id = DefineDeoptimizationLiteral(environment->closure());
289         translation->StoreLiteral(closure_id);
290       }
291       break;
292     }
293     case ARGUMENTS_ADAPTOR: {
294       int shared_id = DefineDeoptimizationLiteral(
295           environment->entry() ? environment->entry()->shared()
296                                : info()->shared_info());
297       translation->BeginArgumentsAdaptorFrame(shared_id, translation_size);
298       if (info()->closure().is_identical_to(environment->closure())) {
299         translation->StoreJSFrameFunction();
300       } else {
301         int closure_id = DefineDeoptimizationLiteral(environment->closure());
302         translation->StoreLiteral(closure_id);
303       }
304       break;
305     }
306     case STUB:
307       translation->BeginCompiledStubFrame(translation_size);
308       break;
309   }
310 }
311 
312 namespace {
313 
CreateInliningPositions(CompilationInfo * info)314 Handle<PodArray<InliningPosition>> CreateInliningPositions(
315     CompilationInfo* info) {
316   const CompilationInfo::InlinedFunctionList& inlined_functions =
317       info->inlined_functions();
318   if (inlined_functions.size() == 0) {
319     return Handle<PodArray<InliningPosition>>::cast(
320         info->isolate()->factory()->empty_byte_array());
321   }
322   Handle<PodArray<InliningPosition>> inl_positions =
323       PodArray<InliningPosition>::New(
324           info->isolate(), static_cast<int>(inlined_functions.size()), TENURED);
325   for (size_t i = 0; i < inlined_functions.size(); ++i) {
326     inl_positions->set(static_cast<int>(i), inlined_functions[i].position);
327   }
328   return inl_positions;
329 }
330 
331 }  // namespace
332 
PopulateDeoptimizationData(Handle<Code> code)333 void LCodeGenBase::PopulateDeoptimizationData(Handle<Code> code) {
334   int length = deoptimizations_.length();
335   if (length == 0) return;
336   Handle<DeoptimizationInputData> data =
337       DeoptimizationInputData::New(isolate(), length, TENURED);
338 
339   Handle<ByteArray> translations =
340       translations_.CreateByteArray(isolate()->factory());
341   data->SetTranslationByteArray(*translations);
342   data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
343   data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
344   if (info_->IsOptimizing()) {
345     // Reference to shared function info does not change between phases.
346     AllowDeferredHandleDereference allow_handle_dereference;
347     data->SetSharedFunctionInfo(*info_->shared_info());
348   } else {
349     data->SetSharedFunctionInfo(Smi::kZero);
350   }
351   data->SetWeakCellCache(Smi::kZero);
352 
353   Handle<FixedArray> literals =
354       factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
355   {
356     AllowDeferredHandleDereference copy_handles;
357     for (int i = 0; i < deoptimization_literals_.length(); i++) {
358       literals->set(i, *deoptimization_literals_[i]);
359     }
360     data->SetLiteralArray(*literals);
361   }
362 
363   Handle<PodArray<InliningPosition>> inl_pos = CreateInliningPositions(info_);
364   data->SetInliningPositions(*inl_pos);
365 
366   data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
367   data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
368 
369   // Populate the deoptimization entries.
370   for (int i = 0; i < length; i++) {
371     LEnvironment* env = deoptimizations_[i];
372     data->SetAstId(i, env->ast_id());
373     data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
374     data->SetArgumentsStackHeight(i,
375                                   Smi::FromInt(env->arguments_stack_height()));
376     data->SetPc(i, Smi::FromInt(env->pc_offset()));
377   }
378   code->set_deoptimization_data(*data);
379 }
380 
381 
PopulateDeoptimizationLiteralsWithInlinedFunctions()382 void LCodeGenBase::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
383   DCHECK_EQ(0, deoptimization_literals_.length());
384   for (CompilationInfo::InlinedFunctionHolder& inlined :
385        info()->inlined_functions()) {
386     if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
387       int index = DefineDeoptimizationLiteral(inlined.shared_info);
388       inlined.RegisterInlinedFunctionId(index);
389     }
390   }
391   inlined_function_count_ = deoptimization_literals_.length();
392 
393   // Define deoptimization literals for all unoptimized code objects of inlined
394   // functions. This ensures unoptimized code is kept alive by optimized code.
395   for (const CompilationInfo::InlinedFunctionHolder& inlined :
396        info()->inlined_functions()) {
397     if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
398       DefineDeoptimizationLiteral(inlined.inlined_code_object_root);
399     }
400   }
401 }
402 
MakeDeoptInfo(LInstruction * instr,DeoptimizeReason deopt_reason,int deopt_id)403 Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo(
404     LInstruction* instr, DeoptimizeReason deopt_reason, int deopt_id) {
405   Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(),
406                                     deopt_reason, deopt_id);
407   return deopt_info;
408 }
409 
410 }  // namespace internal
411 }  // namespace v8
412