Line data Source code
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 :
48 2965576 : HGraph* LCodeGenBase::graph() const {
49 2965576 : return chunk()->graph();
50 : }
51 :
52 278815 : LCodeGenBase::LCodeGenBase(LChunk* chunk, MacroAssembler* assembler,
53 1115263 : 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 278815 : 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 1672893 : info->SourcePositionRecordingMode()) {}
70 :
71 20604120 : Isolate* LCodeGenBase::isolate() const { return info_->isolate(); }
72 :
73 44984624 : bool LCodeGenBase::GenerateBody() {
74 : DCHECK(is_generating());
75 : bool emit_instructions = true;
76 : LCodeGen* codegen = static_cast<LCodeGen*>(this);
77 88296352 : for (current_instruction_ = 0;
78 88296311 : !is_aborted() && current_instruction_ < instructions_->length();
79 : current_instruction_++) {
80 165112532 : LInstruction* instr = instructions_->at(current_instruction_);
81 :
82 : // Don't emit code for basic blocks with a replacement.
83 43869355 : if (instr->IsLabel()) {
84 6863609 : emit_instructions = !LLabel::cast(instr)->HasReplacement() &&
85 4876036 : (!FLAG_unreachable_code_elimination ||
86 2438018 : instr->hydrogen_value()->block()->IsReachable());
87 4425591 : 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 0 : instr->hydrogen_value()->block()->block_id());
94 : }
95 : }
96 43869366 : if (!emit_instructions) continue;
97 :
98 30787700 : if (FLAG_code_comments && instr->HasInterestingComment(codegen)) {
99 : Comment(";;; <@%d,#%d> %s",
100 : current_instruction_,
101 : instr->hydrogen_value()->id(),
102 0 : instr->Mnemonic());
103 : }
104 :
105 30787700 : GenerateBodyInstructionPre(instr);
106 :
107 : HValue* value = instr->hydrogen_value();
108 61575319 : if (value->position().IsKnown()) {
109 20038634 : RecordAndWritePosition(value->position());
110 : }
111 :
112 30787678 : instr->CompileToNative(codegen);
113 :
114 30787706 : GenerateBodyInstructionPost(instr);
115 : }
116 278816 : EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
117 557630 : last_lazy_deopt_pc_ = masm()->pc_offset();
118 278815 : return !is_aborted();
119 : }
120 :
121 :
122 278782 : 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 278782 : }
144 :
145 20192469 : void LCodeGenBase::RecordAndWritePosition(SourcePosition pos) {
146 40384964 : if (!pos.IsKnown()) return;
147 40345530 : source_position_table_builder_.AddPosition(masm_->pc_offset(), pos, false);
148 : }
149 :
150 2812077 : void LCodeGenBase::Comment(const char* format, ...) {
151 5624154 : if (!FLAG_code_comments) return;
152 : char buffer[4 * KB];
153 : StringBuilder builder(buffer, arraysize(buffer));
154 : va_list arguments;
155 0 : va_start(arguments, format);
156 0 : builder.AddFormattedList(format, arguments);
157 0 : 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 0 : size_t length = builder.position();
162 0 : Vector<char> copy = Vector<char>::New(static_cast<int>(length) + 1);
163 0 : MemCopy(copy.start(), builder.Finalize(), copy.length());
164 0 : masm()->RecordComment(copy.start());
165 : }
166 :
167 :
168 1432028 : void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
169 634033 : SourcePosition position = deopt_info.position;
170 634033 : int deopt_id = deopt_info.deopt_id;
171 634033 : if (masm()->isolate()->NeedsSourcePositionsForProfiling()) {
172 327924 : masm()->RecordDeoptReason(deopt_info.deopt_reason, position, deopt_id);
173 : }
174 634033 : }
175 :
176 :
177 1545323 : int LCodeGenBase::GetNextEmittedBlock() const {
178 5931152 : for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) {
179 5930498 : if (!graph()->blocks()->at(i)->IsReachable()) continue;
180 2714087 : if (!chunk_->GetLabel(i)->HasReplacement()) return i;
181 : }
182 : return -1;
183 : }
184 :
185 :
186 5 : void LCodeGenBase::Abort(BailoutReason reason) {
187 : info()->AbortOptimization(reason);
188 5 : status_ = ABORTED;
189 5 : }
190 :
191 :
192 28 : void LCodeGenBase::Retry(BailoutReason reason) {
193 : info()->RetryOptimization(reason);
194 28 : status_ = ABORTED;
195 0 : }
196 :
197 :
198 9257 : void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
199 18514 : if (map->is_deprecated()) return Retry(kMapBecameDeprecated);
200 9237 : chunk_->AddDeprecationDependency(map);
201 : }
202 :
203 :
204 110510 : void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
205 221020 : if (!map->is_stable()) return Retry(kMapBecameUnstable);
206 110502 : chunk_->AddStabilityDependency(map);
207 : }
208 :
209 :
210 20889605 : int LCodeGenBase::DefineDeoptimizationLiteral(Handle<Object> literal) {
211 303575066 : int result = deoptimization_literals_.length();
212 284041911 : for (int i = 0; i < deoptimization_literals_.length(); ++i) {
213 283363686 : if (deoptimization_literals_[i].is_identical_to(literal)) return i;
214 : }
215 : deoptimization_literals_.Add(literal, zone());
216 678225 : return result;
217 : }
218 :
219 :
220 13685797 : void LCodeGenBase::WriteTranslationFrame(LEnvironment* environment,
221 7336210 : Translation* translation) {
222 : int translation_size = environment->translation_size();
223 : // The output frame height does not include the parameters.
224 4580506 : int height = translation_size - environment->parameter_count();
225 :
226 4580506 : switch (environment->frame_type()) {
227 : case JS_FUNCTION: {
228 : int shared_id = DefineDeoptimizationLiteral(
229 : environment->entry() ? environment->entry()->shared()
230 10251925 : : info()->shared_info());
231 3988399 : translation->BeginJSFrame(environment->ast_id(), shared_id, height);
232 3988401 : if (info()->closure().is_identical_to(environment->closure())) {
233 2275130 : translation->StoreJSFrameFunction();
234 : } else {
235 1713271 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
236 1713271 : translation->StoreLiteral(closure_id);
237 : }
238 : break;
239 : }
240 : case JS_CONSTRUCT: {
241 : int shared_id = DefineDeoptimizationLiteral(
242 : environment->entry() ? environment->entry()->shared()
243 3564 : : info()->shared_info());
244 : translation->BeginConstructStubFrame(BailoutId::ConstructStubInvoke(),
245 1188 : shared_id, translation_size);
246 1188 : if (info()->closure().is_identical_to(environment->closure())) {
247 0 : translation->StoreJSFrameFunction();
248 : } else {
249 1188 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
250 1188 : translation->StoreLiteral(closure_id);
251 : }
252 : break;
253 : }
254 : case JS_GETTER: {
255 : DCHECK_EQ(1, translation_size);
256 : DCHECK_EQ(0, height);
257 : int shared_id = DefineDeoptimizationLiteral(
258 : environment->entry() ? environment->entry()->shared()
259 29121 : : info()->shared_info());
260 9707 : translation->BeginGetterStubFrame(shared_id);
261 9707 : if (info()->closure().is_identical_to(environment->closure())) {
262 0 : translation->StoreJSFrameFunction();
263 : } else {
264 9707 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
265 9707 : translation->StoreLiteral(closure_id);
266 : }
267 : break;
268 : }
269 : case JS_SETTER: {
270 : DCHECK_EQ(2, translation_size);
271 : DCHECK_EQ(0, height);
272 : int shared_id = DefineDeoptimizationLiteral(
273 : environment->entry() ? environment->entry()->shared()
274 2424 : : info()->shared_info());
275 808 : translation->BeginSetterStubFrame(shared_id);
276 808 : if (info()->closure().is_identical_to(environment->closure())) {
277 0 : translation->StoreJSFrameFunction();
278 : } else {
279 808 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
280 808 : translation->StoreLiteral(closure_id);
281 : }
282 : break;
283 : }
284 : case TAIL_CALLER_FUNCTION: {
285 : DCHECK_EQ(0, translation_size);
286 : int shared_id = DefineDeoptimizationLiteral(
287 : environment->entry() ? environment->entry()->shared()
288 385 : : info()->shared_info());
289 159 : translation->BeginTailCallerFrame(shared_id);
290 159 : if (info()->closure().is_identical_to(environment->closure())) {
291 67 : translation->StoreJSFrameFunction();
292 : } else {
293 92 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
294 92 : translation->StoreLiteral(closure_id);
295 : }
296 : break;
297 : }
298 : case ARGUMENTS_ADAPTOR: {
299 : int shared_id = DefineDeoptimizationLiteral(
300 : environment->entry() ? environment->entry()->shared()
301 1573575 : : info()->shared_info());
302 524525 : translation->BeginArgumentsAdaptorFrame(shared_id, translation_size);
303 524525 : if (info()->closure().is_identical_to(environment->closure())) {
304 0 : translation->StoreJSFrameFunction();
305 : } else {
306 524525 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
307 524525 : translation->StoreLiteral(closure_id);
308 : }
309 : break;
310 : }
311 : case STUB:
312 55720 : translation->BeginCompiledStubFrame(translation_size);
313 55720 : break;
314 : }
315 4580507 : }
316 :
317 : namespace {
318 :
319 278783 : Handle<PodArray<InliningPosition>> CreateInliningPositions(
320 278783 : CompilationInfo* info) {
321 402307 : const CompilationInfo::InlinedFunctionList& inlined_functions =
322 : info->inlined_functions();
323 278783 : if (inlined_functions.size() == 0) {
324 : return Handle<PodArray<InliningPosition>>::cast(
325 : info->isolate()->factory()->empty_byte_array());
326 : }
327 : Handle<PodArray<InliningPosition>> inl_positions =
328 : PodArray<InliningPosition>::New(
329 18066 : info->isolate(), static_cast<int>(inlined_functions.size()), TENURED);
330 247048 : for (size_t i = 0; i < inlined_functions.size(); ++i) {
331 105458 : inl_positions->set(static_cast<int>(i), inlined_functions[i].position);
332 : }
333 18066 : return inl_positions;
334 : }
335 :
336 : } // namespace
337 :
338 557566 : void LCodeGenBase::PopulateDeoptimizationData(Handle<Code> code) {
339 2609337 : int length = deoptimizations_.length();
340 278783 : if (length == 0) return;
341 : Handle<DeoptimizationInputData> data =
342 278783 : DeoptimizationInputData::New(isolate(), length, TENURED);
343 :
344 : Handle<ByteArray> translations =
345 278783 : translations_.CreateByteArray(isolate()->factory());
346 : data->SetTranslationByteArray(*translations);
347 278783 : data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
348 557566 : data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
349 557566 : if (info_->IsOptimizing()) {
350 : // Reference to shared function info does not change between phases.
351 : AllowDeferredHandleDereference allow_handle_dereference;
352 510600 : data->SetSharedFunctionInfo(*info_->shared_info());
353 : } else {
354 : data->SetSharedFunctionInfo(Smi::kZero);
355 : }
356 : data->SetWeakCellCache(Smi::kZero);
357 :
358 : Handle<FixedArray> literals =
359 2192625 : factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
360 : {
361 : AllowDeferredHandleDereference copy_handles;
362 1913842 : for (int i = 0; i < deoptimization_literals_.length(); i++) {
363 678138 : literals->set(i, *deoptimization_literals_[i]);
364 : }
365 : data->SetLiteralArray(*literals);
366 : }
367 :
368 278783 : Handle<PodArray<InliningPosition>> inl_pos = CreateInliningPositions(info_);
369 : data->SetInliningPositions(*inl_pos);
370 :
371 278783 : data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
372 278783 : data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
373 :
374 : // Populate the deoptimization entries.
375 2609337 : for (int i = 0; i < length; i++) {
376 9322216 : LEnvironment* env = deoptimizations_[i];
377 : data->SetAstId(i, env->ast_id());
378 2330554 : data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
379 : data->SetArgumentsStackHeight(i,
380 2330554 : Smi::FromInt(env->arguments_stack_height()));
381 2330554 : data->SetPc(i, Smi::FromInt(env->pc_offset()));
382 : }
383 278783 : code->set_deoptimization_data(*data);
384 : }
385 :
386 :
387 768582 : void LCodeGenBase::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
388 : DCHECK_EQ(0, deoptimization_literals_.length());
389 663106 : for (CompilationInfo::InlinedFunctionHolder& inlined :
390 : info()->inlined_functions()) {
391 210952 : if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
392 105451 : int index = DefineDeoptimizationLiteral(inlined.shared_info);
393 : inlined.RegisterInlinedFunctionId(index);
394 : }
395 : }
396 278815 : inlined_function_count_ = deoptimization_literals_.length();
397 :
398 : // Define deoptimization literals for all unoptimized code objects of inlined
399 : // functions. This ensures unoptimized code is kept alive by optimized code.
400 663106 : for (const CompilationInfo::InlinedFunctionHolder& inlined :
401 : info()->inlined_functions()) {
402 210952 : if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
403 105451 : DefineDeoptimizationLiteral(inlined.inlined_code_object_root);
404 : }
405 : }
406 278815 : }
407 :
408 777716 : Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo(
409 777716 : LInstruction* instr, DeoptimizeReason deopt_reason, int deopt_id) {
410 777716 : Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(),
411 777716 : deopt_reason, deopt_id);
412 777716 : return deopt_info;
413 : }
414 :
415 : } // namespace internal
416 : } // namespace v8
|