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