OLD | NEW |
| (Empty) |
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/lithium-codegen.h" | |
6 | |
7 #include <sstream> | |
8 | |
9 #if V8_TARGET_ARCH_IA32 | |
10 #include "src/ia32/lithium-ia32.h" // NOLINT | |
11 #include "src/ia32/lithium-codegen-ia32.h" // NOLINT | |
12 #elif V8_TARGET_ARCH_X64 | |
13 #include "src/x64/lithium-x64.h" // NOLINT | |
14 #include "src/x64/lithium-codegen-x64.h" // NOLINT | |
15 #elif V8_TARGET_ARCH_ARM | |
16 #include "src/arm/lithium-arm.h" // NOLINT | |
17 #include "src/arm/lithium-codegen-arm.h" // NOLINT | |
18 #elif V8_TARGET_ARCH_ARM64 | |
19 #include "src/arm64/lithium-arm64.h" // NOLINT | |
20 #include "src/arm64/lithium-codegen-arm64.h" // NOLINT | |
21 #elif V8_TARGET_ARCH_MIPS | |
22 #include "src/mips/lithium-mips.h" // NOLINT | |
23 #include "src/mips/lithium-codegen-mips.h" // NOLINT | |
24 #elif V8_TARGET_ARCH_MIPS64 | |
25 #include "src/mips64/lithium-mips64.h" // NOLINT | |
26 #include "src/mips64/lithium-codegen-mips64.h" // NOLINT | |
27 #elif V8_TARGET_ARCH_X87 | |
28 #include "src/x87/lithium-x87.h" // NOLINT | |
29 #include "src/x87/lithium-codegen-x87.h" // NOLINT | |
30 #elif V8_TARGET_ARCH_PPC | |
31 #include "src/ppc/lithium-ppc.h" // NOLINT | |
32 #include "src/ppc/lithium-codegen-ppc.h" // NOLINT | |
33 #else | |
34 #error Unsupported target architecture. | |
35 #endif | |
36 | |
37 namespace v8 { | |
38 namespace internal { | |
39 | |
40 | |
41 HGraph* LCodeGenBase::graph() const { | |
42 return chunk()->graph(); | |
43 } | |
44 | |
45 | |
46 LCodeGenBase::LCodeGenBase(LChunk* chunk, MacroAssembler* assembler, | |
47 CompilationInfo* info) | |
48 : chunk_(static_cast<LPlatformChunk*>(chunk)), | |
49 masm_(assembler), | |
50 info_(info), | |
51 zone_(info->zone()), | |
52 status_(UNUSED), | |
53 current_block_(-1), | |
54 current_instruction_(-1), | |
55 instructions_(chunk->instructions()), | |
56 deoptimization_literals_(8, info->zone()), | |
57 last_lazy_deopt_pc_(0) {} | |
58 | |
59 | |
60 bool LCodeGenBase::GenerateBody() { | |
61 DCHECK(is_generating()); | |
62 bool emit_instructions = true; | |
63 LCodeGen* codegen = static_cast<LCodeGen*>(this); | |
64 for (current_instruction_ = 0; | |
65 !is_aborted() && current_instruction_ < instructions_->length(); | |
66 current_instruction_++) { | |
67 LInstruction* instr = instructions_->at(current_instruction_); | |
68 | |
69 // Don't emit code for basic blocks with a replacement. | |
70 if (instr->IsLabel()) { | |
71 emit_instructions = !LLabel::cast(instr)->HasReplacement() && | |
72 (!FLAG_unreachable_code_elimination || | |
73 instr->hydrogen_value()->block()->IsReachable()); | |
74 if (FLAG_code_comments && !emit_instructions) { | |
75 Comment( | |
76 ";;; <@%d,#%d> -------------------- B%d (unreachable/replaced) " | |
77 "--------------------", | |
78 current_instruction_, | |
79 instr->hydrogen_value()->id(), | |
80 instr->hydrogen_value()->block()->block_id()); | |
81 } | |
82 } | |
83 if (!emit_instructions) continue; | |
84 | |
85 if (FLAG_code_comments && instr->HasInterestingComment(codegen)) { | |
86 Comment(";;; <@%d,#%d> %s", | |
87 current_instruction_, | |
88 instr->hydrogen_value()->id(), | |
89 instr->Mnemonic()); | |
90 } | |
91 | |
92 GenerateBodyInstructionPre(instr); | |
93 | |
94 HValue* value = instr->hydrogen_value(); | |
95 if (!value->position().IsUnknown()) { | |
96 RecordAndWritePosition( | |
97 chunk()->graph()->SourcePositionToScriptPosition(value->position())); | |
98 } | |
99 | |
100 instr->CompileToNative(codegen); | |
101 | |
102 GenerateBodyInstructionPost(instr); | |
103 } | |
104 EnsureSpaceForLazyDeopt(Deoptimizer::patch_size()); | |
105 last_lazy_deopt_pc_ = masm()->pc_offset(); | |
106 return !is_aborted(); | |
107 } | |
108 | |
109 | |
110 void LCodeGenBase::CheckEnvironmentUsage() { | |
111 #ifdef DEBUG | |
112 bool dead_block = false; | |
113 for (int i = 0; i < instructions_->length(); i++) { | |
114 LInstruction* instr = instructions_->at(i); | |
115 HValue* hval = instr->hydrogen_value(); | |
116 if (instr->IsLabel()) dead_block = LLabel::cast(instr)->HasReplacement(); | |
117 if (dead_block || !hval->block()->IsReachable()) continue; | |
118 | |
119 HInstruction* hinstr = HInstruction::cast(hval); | |
120 if (!hinstr->CanDeoptimize() && instr->HasEnvironment()) { | |
121 V8_Fatal(__FILE__, __LINE__, "CanDeoptimize is wrong for %s (%s)", | |
122 hinstr->Mnemonic(), instr->Mnemonic()); | |
123 } | |
124 | |
125 if (instr->HasEnvironment() && !instr->environment()->has_been_used()) { | |
126 V8_Fatal(__FILE__, __LINE__, "unused environment for %s (%s)", | |
127 hinstr->Mnemonic(), instr->Mnemonic()); | |
128 } | |
129 } | |
130 #endif | |
131 } | |
132 | |
133 | |
134 void LCodeGenBase::Comment(const char* format, ...) { | |
135 if (!FLAG_code_comments) return; | |
136 char buffer[4 * KB]; | |
137 StringBuilder builder(buffer, arraysize(buffer)); | |
138 va_list arguments; | |
139 va_start(arguments, format); | |
140 builder.AddFormattedList(format, arguments); | |
141 va_end(arguments); | |
142 | |
143 // Copy the string before recording it in the assembler to avoid | |
144 // issues when the stack allocated buffer goes out of scope. | |
145 size_t length = builder.position(); | |
146 Vector<char> copy = Vector<char>::New(static_cast<int>(length) + 1); | |
147 MemCopy(copy.start(), builder.Finalize(), copy.length()); | |
148 masm()->RecordComment(copy.start()); | |
149 } | |
150 | |
151 | |
152 void LCodeGenBase::DeoptComment(const Deoptimizer::DeoptInfo& deopt_info) { | |
153 masm()->RecordDeoptReason(deopt_info.deopt_reason, deopt_info.position); | |
154 } | |
155 | |
156 | |
157 int LCodeGenBase::GetNextEmittedBlock() const { | |
158 for (int i = current_block_ + 1; i < graph()->blocks()->length(); ++i) { | |
159 if (!graph()->blocks()->at(i)->IsReachable()) continue; | |
160 if (!chunk_->GetLabel(i)->HasReplacement()) return i; | |
161 } | |
162 return -1; | |
163 } | |
164 | |
165 | |
166 void LCodeGenBase::Abort(BailoutReason reason) { | |
167 info()->AbortOptimization(reason); | |
168 status_ = ABORTED; | |
169 } | |
170 | |
171 | |
172 void LCodeGenBase::Retry(BailoutReason reason) { | |
173 info()->RetryOptimization(reason); | |
174 status_ = ABORTED; | |
175 } | |
176 | |
177 | |
178 void LCodeGenBase::AddDeprecationDependency(Handle<Map> map) { | |
179 if (map->is_deprecated()) return Retry(kMapBecameDeprecated); | |
180 chunk_->AddDeprecationDependency(map); | |
181 } | |
182 | |
183 | |
184 void LCodeGenBase::AddStabilityDependency(Handle<Map> map) { | |
185 if (!map->is_stable()) return Retry(kMapBecameUnstable); | |
186 chunk_->AddStabilityDependency(map); | |
187 } | |
188 | |
189 | |
190 int LCodeGenBase::DefineDeoptimizationLiteral(Handle<Object> literal) { | |
191 int result = deoptimization_literals_.length(); | |
192 for (int i = 0; i < deoptimization_literals_.length(); ++i) { | |
193 if (deoptimization_literals_[i].is_identical_to(literal)) return i; | |
194 } | |
195 deoptimization_literals_.Add(literal, zone()); | |
196 return result; | |
197 } | |
198 | |
199 | |
200 void LCodeGenBase::WriteTranslationFrame(LEnvironment* environment, | |
201 Translation* translation) { | |
202 int translation_size = environment->translation_size(); | |
203 // The output frame height does not include the parameters. | |
204 int height = translation_size - environment->parameter_count(); | |
205 | |
206 switch (environment->frame_type()) { | |
207 case JS_FUNCTION: { | |
208 int shared_id = DefineDeoptimizationLiteral( | |
209 environment->entry() ? environment->entry()->shared() | |
210 : info()->shared_info()); | |
211 translation->BeginJSFrame(environment->ast_id(), shared_id, height); | |
212 if (info()->closure().is_identical_to(environment->closure())) { | |
213 translation->StoreJSFrameFunction(); | |
214 } else { | |
215 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
216 translation->StoreLiteral(closure_id); | |
217 } | |
218 break; | |
219 } | |
220 case JS_CONSTRUCT: { | |
221 int shared_id = DefineDeoptimizationLiteral( | |
222 environment->entry() ? environment->entry()->shared() | |
223 : info()->shared_info()); | |
224 translation->BeginConstructStubFrame(shared_id, translation_size); | |
225 if (info()->closure().is_identical_to(environment->closure())) { | |
226 translation->StoreJSFrameFunction(); | |
227 } else { | |
228 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
229 translation->StoreLiteral(closure_id); | |
230 } | |
231 break; | |
232 } | |
233 case JS_GETTER: { | |
234 DCHECK(translation_size == 1); | |
235 DCHECK(height == 0); | |
236 int shared_id = DefineDeoptimizationLiteral( | |
237 environment->entry() ? environment->entry()->shared() | |
238 : info()->shared_info()); | |
239 translation->BeginGetterStubFrame(shared_id); | |
240 if (info()->closure().is_identical_to(environment->closure())) { | |
241 translation->StoreJSFrameFunction(); | |
242 } else { | |
243 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
244 translation->StoreLiteral(closure_id); | |
245 } | |
246 break; | |
247 } | |
248 case JS_SETTER: { | |
249 DCHECK(translation_size == 2); | |
250 DCHECK(height == 0); | |
251 int shared_id = DefineDeoptimizationLiteral( | |
252 environment->entry() ? environment->entry()->shared() | |
253 : info()->shared_info()); | |
254 translation->BeginSetterStubFrame(shared_id); | |
255 if (info()->closure().is_identical_to(environment->closure())) { | |
256 translation->StoreJSFrameFunction(); | |
257 } else { | |
258 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
259 translation->StoreLiteral(closure_id); | |
260 } | |
261 break; | |
262 } | |
263 case ARGUMENTS_ADAPTOR: { | |
264 int shared_id = DefineDeoptimizationLiteral( | |
265 environment->entry() ? environment->entry()->shared() | |
266 : info()->shared_info()); | |
267 translation->BeginArgumentsAdaptorFrame(shared_id, translation_size); | |
268 if (info()->closure().is_identical_to(environment->closure())) { | |
269 translation->StoreJSFrameFunction(); | |
270 } else { | |
271 int closure_id = DefineDeoptimizationLiteral(environment->closure()); | |
272 translation->StoreLiteral(closure_id); | |
273 } | |
274 break; | |
275 } | |
276 case STUB: | |
277 translation->BeginCompiledStubFrame(translation_size); | |
278 break; | |
279 } | |
280 } | |
281 | |
282 | |
283 Deoptimizer::DeoptInfo LCodeGenBase::MakeDeoptInfo( | |
284 LInstruction* instr, Deoptimizer::DeoptReason deopt_reason) { | |
285 Deoptimizer::DeoptInfo deopt_info(instr->hydrogen_value()->position(), | |
286 instr->Mnemonic(), deopt_reason); | |
287 HEnterInlined* enter_inlined = instr->environment()->entry(); | |
288 deopt_info.inlining_id = enter_inlined ? enter_inlined->inlining_id() : 0; | |
289 return deopt_info; | |
290 } | |
291 } // namespace internal | |
292 } // namespace v8 | |
OLD | NEW |