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