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