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 2973168 : HGraph* LCodeGenBase::graph() const {
49 2973168 : return chunk()->graph();
50 : }
51 :
52 279085 : LCodeGenBase::LCodeGenBase(LChunk* chunk, MacroAssembler* assembler,
53 1116340 : 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 279085 : 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 1674510 : info->SourcePositionRecordingMode()) {}
70 :
71 20626105 : Isolate* LCodeGenBase::isolate() const { return info_->isolate(); }
72 :
73 45091981 : bool LCodeGenBase::GenerateBody() {
74 : DCHECK(is_generating());
75 : bool emit_instructions = true;
76 : LCodeGen* codegen = static_cast<LCodeGen*>(this);
77 88509452 : for (current_instruction_ = 0;
78 88509403 : !is_aborted() && current_instruction_ < instructions_->length();
79 : current_instruction_++) {
80 165489439 : LInstruction* instr = instructions_->at(current_instruction_);
81 :
82 : // Don't emit code for basic blocks with a replacement.
83 43975630 : if (instr->IsLabel()) {
84 6889008 : emit_instructions = !LLabel::cast(instr)->HasReplacement() &&
85 4895182 : (!FLAG_unreachable_code_elimination ||
86 2447591 : instr->hydrogen_value()->block()->IsReachable());
87 4441417 : 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 43975639 : if (!emit_instructions) continue;
97 :
98 30835952 : 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 30835952 : GenerateBodyInstructionPre(instr);
106 :
107 : HValue* value = instr->hydrogen_value();
108 61671769 : if (value->position().IsKnown()) {
109 20074562 : RecordAndWritePosition(value->position());
110 : }
111 :
112 30835906 : instr->CompileToNative(codegen);
113 :
114 30835973 : GenerateBodyInstructionPost(instr);
115 : }
116 279085 : EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
117 558168 : last_lazy_deopt_pc_ = masm()->pc_offset();
118 279084 : return !is_aborted();
119 : }
120 :
121 :
122 279048 : 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 279048 : }
144 :
145 20228691 : void LCodeGenBase::RecordAndWritePosition(SourcePosition pos) {
146 40457433 : if (!pos.IsKnown()) return;
147 40417962 : source_position_table_builder_.AddPosition(masm_->pc_offset(), pos, false);
148 : }
149 :
150 2819322 : void LCodeGenBase::Comment(const char* format, ...) {
151 5638644 : 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 1435909 : void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) {
169 635736 : SourcePosition position = deopt_info.position;
170 635736 : int deopt_id = deopt_info.deopt_id;
171 635736 : if (masm()->isolate()->NeedsSourcePositionsForProfiling()) {
172 328874 : masm()->RecordDeoptReason(deopt_info.deopt_reason, position, deopt_id);
173 : }
174 635736 : }
175 :
176 :
177 1550393 : int LCodeGenBase::GetNextEmittedBlock() const {
178 5946336 : for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) {
179 5945678 : if (!graph()->blocks()->at(i)->IsReachable()) continue;
180 2721407 : 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 32 : void LCodeGenBase::Retry(BailoutReason reason) {
193 : info()->RetryOptimization(reason);
194 32 : status_ = ABORTED;
195 0 : }
196 :
197 :
198 9704 : void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) {
199 19408 : if (map->is_deprecated()) return Retry(kMapBecameDeprecated);
200 9684 : chunk_->AddDeprecationDependency(map);
201 : }
202 :
203 :
204 110904 : void LCodeGenBase::AddStabilityDependency(Handle<Map> map) {
205 221808 : if (!map->is_stable()) return Retry(kMapBecameUnstable);
206 110892 : chunk_->AddStabilityDependency(map);
207 : }
208 :
209 :
210 20913753 : int LCodeGenBase::DefineDeoptimizationLiteral(Handle<Object> literal) {
211 303962127 : int result = deoptimization_literals_.length();
212 284406466 : for (int i = 0; i < deoptimization_literals_.length(); ++i) {
213 283727420 : if (deoptimization_literals_[i].is_identical_to(literal)) return i;
214 : }
215 : deoptimization_literals_.Add(literal, zone());
216 679045 : return result;
217 : }
218 :
219 :
220 13706907 : void LCodeGenBase::WriteTranslationFrame(LEnvironment* environment,
221 7346804 : Translation* translation) {
222 : int translation_size = environment->translation_size();
223 : // The output frame height does not include the parameters.
224 4587585 : int height = translation_size - environment->parameter_count();
225 :
226 4587585 : switch (environment->frame_type()) {
227 : case JS_FUNCTION: {
228 : int shared_id = DefineDeoptimizationLiteral(
229 : environment->entry() ? environment->entry()->shared()
230 10269423 : : info()->shared_info());
231 3995332 : translation->BeginJSFrame(environment->ast_id(), shared_id, height);
232 3995331 : if (info()->closure().is_identical_to(environment->closure())) {
233 2278755 : translation->StoreJSFrameFunction();
234 : } else {
235 1716576 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
236 1716576 : translation->StoreLiteral(closure_id);
237 : }
238 : break;
239 : }
240 : case JS_CONSTRUCT: {
241 : int shared_id = DefineDeoptimizationLiteral(
242 : environment->entry() ? environment->entry()->shared()
243 3606 : : info()->shared_info());
244 : translation->BeginConstructStubFrame(BailoutId::ConstructStubInvoke(),
245 1202 : shared_id, translation_size);
246 1202 : if (info()->closure().is_identical_to(environment->closure())) {
247 0 : translation->StoreJSFrameFunction();
248 : } else {
249 1202 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
250 1202 : 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 29049 : : info()->shared_info());
260 9683 : translation->BeginGetterStubFrame(shared_id);
261 9683 : if (info()->closure().is_identical_to(environment->closure())) {
262 0 : translation->StoreJSFrameFunction();
263 : } else {
264 9683 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
265 9683 : 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 379 : : info()->shared_info());
289 157 : translation->BeginTailCallerFrame(shared_id);
290 157 : if (info()->closure().is_identical_to(environment->closure())) {
291 65 : 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 1573662 : : info()->shared_info());
302 524554 : translation->BeginArgumentsAdaptorFrame(shared_id, translation_size);
303 524554 : if (info()->closure().is_identical_to(environment->closure())) {
304 0 : translation->StoreJSFrameFunction();
305 : } else {
306 524554 : int closure_id = DefineDeoptimizationLiteral(environment->closure());
307 524554 : translation->StoreLiteral(closure_id);
308 : }
309 : break;
310 : }
311 : case STUB:
312 55849 : translation->BeginCompiledStubFrame(translation_size);
313 55849 : break;
314 : }
315 4587583 : }
316 :
317 : namespace {
318 :
319 279047 : Handle<PodArray<InliningPosition>> CreateInliningPositions(
320 279047 : CompilationInfo* info) {
321 402525 : const CompilationInfo::InlinedFunctionList& inlined_functions =
322 : info->inlined_functions();
323 279047 : 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 18100 : info->isolate(), static_cast<int>(inlined_functions.size()), TENURED);
330 246956 : for (size_t i = 0; i < inlined_functions.size(); ++i) {
331 105378 : inl_positions->set(static_cast<int>(i), inlined_functions[i].position);
332 : }
333 18100 : return inl_positions;
334 : }
335 :
336 : } // namespace
337 :
338 558096 : void LCodeGenBase::PopulateDeoptimizationData(Handle<Code> code) {
339 2613259 : int length = deoptimizations_.length();
340 279048 : if (length == 0) return;
341 : Handle<DeoptimizationInputData> data =
342 279048 : DeoptimizationInputData::New(isolate(), length, TENURED);
343 :
344 : Handle<ByteArray> translations =
345 279048 : translations_.CreateByteArray(isolate()->factory());
346 : data->SetTranslationByteArray(*translations);
347 279048 : data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
348 558096 : data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
349 558096 : if (info_->IsOptimizing()) {
350 : // Reference to shared function info does not change between phases.
351 : AllowDeferredHandleDereference allow_handle_dereference;
352 511030 : data->SetSharedFunctionInfo(*info_->shared_info());
353 : } else {
354 : data->SetSharedFunctionInfo(Smi::kZero);
355 : }
356 : data->SetWeakCellCache(Smi::kZero);
357 :
358 : Handle<FixedArray> literals =
359 2194970 : factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
360 : {
361 : AllowDeferredHandleDereference copy_handles;
362 1915922 : for (int i = 0; i < deoptimization_literals_.length(); i++) {
363 678913 : literals->set(i, *deoptimization_literals_[i]);
364 : }
365 : data->SetLiteralArray(*literals);
366 : }
367 :
368 279047 : Handle<PodArray<InliningPosition>> inl_pos = CreateInliningPositions(info_);
369 : data->SetInliningPositions(*inl_pos);
370 :
371 279047 : data->SetOsrAstId(Smi::FromInt(info_->osr_ast_id().ToInt()));
372 279047 : data->SetOsrPcOffset(Smi::FromInt(osr_pc_offset_));
373 :
374 : // Populate the deoptimization entries.
375 2613259 : for (int i = 0; i < length; i++) {
376 9336846 : LEnvironment* env = deoptimizations_[i];
377 : data->SetAstId(i, env->ast_id());
378 2334212 : data->SetTranslationIndex(i, Smi::FromInt(env->translation_index()));
379 : data->SetArgumentsStackHeight(i,
380 2334212 : Smi::FromInt(env->arguments_stack_height()));
381 2334211 : data->SetPc(i, Smi::FromInt(env->pc_offset()));
382 : }
383 279048 : code->set_deoptimization_data(*data);
384 : }
385 :
386 :
387 769082 : void LCodeGenBase::PopulateDeoptimizationLiteralsWithInlinedFunctions() {
388 : DCHECK_EQ(0, deoptimization_literals_.length());
389 663626 : for (CompilationInfo::InlinedFunctionHolder& inlined :
390 : info()->inlined_functions()) {
391 210912 : if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
392 105431 : int index = DefineDeoptimizationLiteral(inlined.shared_info);
393 : inlined.RegisterInlinedFunctionId(index);
394 : }
395 : }
396 279085 : 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 663626 : for (const CompilationInfo::InlinedFunctionHolder& inlined :
401 : info()->inlined_functions()) {
402 210912 : if (!inlined.shared_info.is_identical_to(info()->shared_info())) {
403 105431 : DefineDeoptimizationLiteral(inlined.inlined_code_object_root);
404 : }
405 : }
406 279085 : }
407 :
408 779377 : Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo(
409 779377 : LInstruction* instr, DeoptimizeReason deopt_reason, int deopt_id) {
410 779377 : Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(),
411 779377 : deopt_reason, deopt_id);
412 779377 : return deopt_info;
413 : }
414 :
415 : } // namespace internal
416 : } // namespace v8
|