OLD | NEW |
1 // Copyright 2013 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/compiler/code-generator.h" | 5 #include "src/compiler/code-generator.h" |
6 | 6 |
7 #include "src/compiler/code-generator-impl.h" | 7 #include "src/compiler/code-generator-impl.h" |
8 #include "src/compiler/linkage.h" | 8 #include "src/compiler/linkage.h" |
9 #include "src/compiler/pipeline.h" | 9 #include "src/compiler/pipeline.h" |
10 | 10 |
11 namespace v8 { | 11 namespace v8 { |
12 namespace internal { | 12 namespace internal { |
13 namespace compiler { | 13 namespace compiler { |
14 | 14 |
15 CodeGenerator::CodeGenerator(InstructionSequence* code) | 15 CodeGenerator::CodeGenerator(InstructionSequence* code) |
16 : code_(code), | 16 : code_(code), |
17 current_block_(NULL), | 17 current_block_(NULL), |
18 current_source_position_(SourcePosition::Invalid()), | 18 current_source_position_(SourcePosition::Invalid()), |
19 masm_(code->zone()->isolate(), NULL, 0), | 19 masm_(code->zone()->isolate(), NULL, 0), |
20 resolver_(this), | 20 resolver_(this), |
21 safepoints_(code->zone()), | 21 safepoints_(code->zone()), |
22 lazy_deoptimization_entries_(code->zone()), | 22 deoptimization_points_(code->zone()), |
23 deoptimization_states_(code->zone()), | 23 deoptimization_states_(code->zone()), |
24 deoptimization_literals_(code->zone()), | 24 deoptimization_literals_(code->zone()), |
25 translations_(code->zone()) { | 25 translations_(code->zone()) {} |
26 deoptimization_states_.resize(code->GetDeoptimizationEntryCount(), NULL); | |
27 } | |
28 | 26 |
29 | 27 |
30 Handle<Code> CodeGenerator::GenerateCode() { | 28 Handle<Code> CodeGenerator::GenerateCode() { |
31 CompilationInfo* info = linkage()->info(); | 29 CompilationInfo* info = linkage()->info(); |
32 | 30 |
33 // Emit a code line info recording start event. | 31 // Emit a code line info recording start event. |
34 PositionsRecorder* recorder = masm()->positions_recorder(); | 32 PositionsRecorder* recorder = masm()->positions_recorder(); |
35 LOG_CODE_EVENT(isolate(), CodeStartLinePosInfoRecordEvent(recorder)); | 33 LOG_CODE_EVENT(isolate(), CodeStartLinePosInfoRecordEvent(recorder)); |
36 | 34 |
37 // Place function entry hook if requested to do so. | 35 // Place function entry hook if requested to do so. |
38 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { | 36 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { |
39 ProfileEntryHookStub::MaybeCallEntryHook(masm()); | 37 ProfileEntryHookStub::MaybeCallEntryHook(masm()); |
40 } | 38 } |
41 | 39 |
42 // Architecture-specific, linkage-specific prologue. | 40 // Architecture-specific, linkage-specific prologue. |
43 info->set_prologue_offset(masm()->pc_offset()); | 41 info->set_prologue_offset(masm()->pc_offset()); |
44 AssemblePrologue(); | 42 AssemblePrologue(); |
45 | 43 |
46 // Assemble all instructions. | 44 // Assemble all instructions. |
47 for (InstructionSequence::const_iterator i = code()->begin(); | 45 for (InstructionSequence::const_iterator i = code()->begin(); |
48 i != code()->end(); ++i) { | 46 i != code()->end(); ++i) { |
49 AssembleInstruction(*i); | 47 AssembleInstruction(*i); |
50 } | 48 } |
51 | 49 |
| 50 EmitLazyDeoptimizationCallTable(); |
| 51 |
52 FinishCode(masm()); | 52 FinishCode(masm()); |
53 | 53 |
54 UpdateSafepointsWithDeoptimizationPc(); | |
55 safepoints()->Emit(masm(), frame()->GetSpillSlotCount()); | 54 safepoints()->Emit(masm(), frame()->GetSpillSlotCount()); |
56 | 55 |
57 // TODO(titzer): what are the right code flags here? | 56 // TODO(titzer): what are the right code flags here? |
58 Code::Kind kind = Code::STUB; | 57 Code::Kind kind = Code::STUB; |
59 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { | 58 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { |
60 kind = Code::OPTIMIZED_FUNCTION; | 59 kind = Code::OPTIMIZED_FUNCTION; |
61 } | 60 } |
62 Handle<Code> result = v8::internal::CodeGenerator::MakeCodeEpilogue( | 61 Handle<Code> result = v8::internal::CodeGenerator::MakeCodeEpilogue( |
63 masm(), Code::ComputeFlags(kind), info); | 62 masm(), Code::ComputeFlags(kind), info); |
64 result->set_is_turbofanned(true); | 63 result->set_is_turbofanned(true); |
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
166 for (int i = GapInstruction::FIRST_INNER_POSITION; | 165 for (int i = GapInstruction::FIRST_INNER_POSITION; |
167 i <= GapInstruction::LAST_INNER_POSITION; i++) { | 166 i <= GapInstruction::LAST_INNER_POSITION; i++) { |
168 GapInstruction::InnerPosition inner_pos = | 167 GapInstruction::InnerPosition inner_pos = |
169 static_cast<GapInstruction::InnerPosition>(i); | 168 static_cast<GapInstruction::InnerPosition>(i); |
170 ParallelMove* move = instr->GetParallelMove(inner_pos); | 169 ParallelMove* move = instr->GetParallelMove(inner_pos); |
171 if (move != NULL) resolver()->Resolve(move); | 170 if (move != NULL) resolver()->Resolve(move); |
172 } | 171 } |
173 } | 172 } |
174 | 173 |
175 | 174 |
176 void CodeGenerator::UpdateSafepointsWithDeoptimizationPc() { | 175 void CodeGenerator::EmitLazyDeoptimizationCallTable() { |
177 int patch_count = static_cast<int>(lazy_deoptimization_entries_.size()); | 176 // ZoneDeque<DeoptimizationPoint*>::iterator iter; |
178 for (int i = 0; i < patch_count; ++i) { | 177 int i = 0; |
179 LazyDeoptimizationEntry entry = lazy_deoptimization_entries_[i]; | 178 for (ZoneDeque<DeoptimizationPoint*>::iterator |
180 // TODO(jarin) make sure that there is no code (other than nops) | 179 iter = deoptimization_points_.begin(); |
181 // between the call position and the continuation position. | 180 iter != deoptimization_points_.end(); iter++, i++) { |
182 safepoints()->SetDeoptimizationPc(entry.safepoint_id(), | 181 int pc_offset = masm()->pc_offset(); |
183 entry.deoptimization()->pos()); | 182 AssembleDeoptimizerCall((*iter)->lazy_state_id()); |
| 183 safepoints()->SetDeoptimizationPc((*iter)->safepoint(), pc_offset); |
184 } | 184 } |
185 } | 185 } |
186 | 186 |
187 | 187 |
188 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) { | 188 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) { |
189 CompilationInfo* info = linkage()->info(); | 189 CompilationInfo* info = linkage()->info(); |
190 int deopt_count = code()->GetDeoptimizationEntryCount(); | 190 int deopt_count = static_cast<int>(deoptimization_states_.size()); |
191 int patch_count = static_cast<int>(lazy_deoptimization_entries_.size()); | 191 if (deopt_count == 0) return; |
192 if (patch_count == 0 && deopt_count == 0) return; | |
193 Handle<DeoptimizationInputData> data = | 192 Handle<DeoptimizationInputData> data = |
194 DeoptimizationInputData::New(isolate(), deopt_count, TENURED); | 193 DeoptimizationInputData::New(isolate(), deopt_count, TENURED); |
195 | 194 |
196 Handle<ByteArray> translation_array = | 195 Handle<ByteArray> translation_array = |
197 translations_.CreateByteArray(isolate()->factory()); | 196 translations_.CreateByteArray(isolate()->factory()); |
198 | 197 |
199 data->SetTranslationByteArray(*translation_array); | 198 data->SetTranslationByteArray(*translation_array); |
200 data->SetInlinedFunctionCount(Smi::FromInt(0)); | 199 data->SetInlinedFunctionCount(Smi::FromInt(0)); |
201 data->SetOptimizationId(Smi::FromInt(info->optimization_id())); | 200 data->SetOptimizationId(Smi::FromInt(info->optimization_id())); |
202 // TODO(jarin) The following code was copied over from Lithium, not sure | 201 // TODO(jarin) The following code was copied over from Lithium, not sure |
(...skipping 16 matching lines...) Expand all Loading... |
219 data->SetLiteralArray(*literals); | 218 data->SetLiteralArray(*literals); |
220 } | 219 } |
221 | 220 |
222 // No OSR in Turbofan yet... | 221 // No OSR in Turbofan yet... |
223 BailoutId osr_ast_id = BailoutId::None(); | 222 BailoutId osr_ast_id = BailoutId::None(); |
224 data->SetOsrAstId(Smi::FromInt(osr_ast_id.ToInt())); | 223 data->SetOsrAstId(Smi::FromInt(osr_ast_id.ToInt())); |
225 data->SetOsrPcOffset(Smi::FromInt(-1)); | 224 data->SetOsrPcOffset(Smi::FromInt(-1)); |
226 | 225 |
227 // Populate deoptimization entries. | 226 // Populate deoptimization entries. |
228 for (int i = 0; i < deopt_count; i++) { | 227 for (int i = 0; i < deopt_count; i++) { |
229 FrameStateDescriptor* descriptor = code()->GetDeoptimizationEntry(i); | 228 DeoptimizationState* deoptimization_state = deoptimization_states_[i]; |
230 data->SetAstId(i, descriptor->bailout_id()); | 229 data->SetAstId(i, deoptimization_state->bailout_id()); |
231 CHECK_NE(NULL, deoptimization_states_[i]); | 230 CHECK_NE(NULL, deoptimization_states_[i]); |
232 data->SetTranslationIndex( | 231 data->SetTranslationIndex( |
233 i, Smi::FromInt(deoptimization_states_[i]->translation_id_)); | 232 i, Smi::FromInt(deoptimization_states_[i]->translation_id())); |
234 data->SetArgumentsStackHeight(i, Smi::FromInt(0)); | 233 data->SetArgumentsStackHeight(i, Smi::FromInt(0)); |
235 data->SetPc(i, Smi::FromInt(-1)); | 234 data->SetPc(i, Smi::FromInt(-1)); |
236 } | 235 } |
237 | 236 |
238 code_object->set_deoptimization_data(*data); | 237 code_object->set_deoptimization_data(*data); |
239 } | 238 } |
240 | 239 |
241 | 240 |
242 void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { | 241 void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { |
243 CallDescriptor::Flags flags(MiscField::decode(instr->opcode())); | 242 CallDescriptor::Flags flags(MiscField::decode(instr->opcode())); |
244 | 243 |
245 bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState); | 244 bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState); |
246 | 245 |
247 Safepoint::Id safepoint_id = RecordSafepoint( | 246 Safepoint::Id safepoint_id = RecordSafepoint( |
248 instr->pointer_map(), Safepoint::kSimple, 0, | 247 instr->pointer_map(), Safepoint::kSimple, 0, |
249 needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); | 248 needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); |
250 | 249 |
251 if (flags & CallDescriptor::kLazyDeoptimization) { | |
252 RecordLazyDeoptimizationEntry(instr, safepoint_id); | |
253 } | |
254 | |
255 if (needs_frame_state) { | 250 if (needs_frame_state) { |
256 // If the frame state is present, it starts at argument 1 | 251 // If the frame state is present, it starts at argument 1 |
257 // (just after the code address). | 252 // (just after the code address). |
258 InstructionOperandConverter converter(this, instr); | 253 InstructionOperandConverter converter(this, instr); |
259 // Deoptimization info starts at argument 1 | 254 // Deoptimization info starts at argument 1 |
260 int frame_state_offset = 1; | 255 int frame_state_offset = 1; |
261 int deoptimization_id = BuildTranslation(instr, frame_state_offset); | 256 FrameStateDescriptor* descriptor = |
| 257 GetFrameStateDescriptor(instr, frame_state_offset); |
| 258 int deopt_state_id = |
| 259 BuildTranslation(instr, frame_state_offset, IGNORE_OUTPUT); |
| 260 int lazy_deopt_state_id = deopt_state_id; |
| 261 if (descriptor->state_combine() != IGNORE_OUTPUT) { |
| 262 lazy_deopt_state_id = BuildTranslation(instr, frame_state_offset, |
| 263 descriptor->state_combine()); |
| 264 } |
| 265 deoptimization_points_.push_back(new (zone()) DeoptimizationPoint( |
| 266 deopt_state_id, lazy_deopt_state_id, descriptor, safepoint_id)); |
262 #if DEBUG | 267 #if DEBUG |
263 // Make sure all the values live in stack slots or they are immediates. | 268 // Make sure all the values live in stack slots or they are immediates. |
264 // (The values should not live in register because registers are clobbered | 269 // (The values should not live in register because registers are clobbered |
265 // by calls.) | 270 // by calls.) |
266 FrameStateDescriptor* descriptor = | |
267 code()->GetDeoptimizationEntry(deoptimization_id); | |
268 for (int i = 0; i < descriptor->size(); i++) { | 271 for (int i = 0; i < descriptor->size(); i++) { |
269 InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); | 272 InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); |
270 CHECK(op->IsStackSlot() || op->IsImmediate()); | 273 CHECK(op->IsStackSlot() || op->IsImmediate()); |
271 } | 274 } |
272 #endif | 275 #endif |
273 safepoints()->RecordLazyDeoptimizationIndex(deoptimization_id); | 276 safepoints()->RecordLazyDeoptimizationIndex(lazy_deopt_state_id); |
274 } | 277 } |
275 | 278 |
276 if (flags & CallDescriptor::kNeedsNopAfterCall) { | 279 if (flags & CallDescriptor::kNeedsNopAfterCall) { |
277 AddNopForSmiCodeInlining(); | 280 AddNopForSmiCodeInlining(); |
278 } | 281 } |
279 } | 282 } |
280 | 283 |
281 | 284 |
282 void CodeGenerator::RecordLazyDeoptimizationEntry(Instruction* instr, | |
283 Safepoint::Id safepoint_id) { | |
284 InstructionOperandConverter i(this, instr); | |
285 | |
286 Label after_call; | |
287 masm()->bind(&after_call); | |
288 | |
289 // The continuation and deoptimization are the last two inputs: | |
290 BasicBlock* cont_block = | |
291 i.InputBlock(static_cast<int>(instr->InputCount()) - 2); | |
292 BasicBlock* deopt_block = | |
293 i.InputBlock(static_cast<int>(instr->InputCount()) - 1); | |
294 | |
295 Label* cont_label = code_->GetLabel(cont_block); | |
296 Label* deopt_label = code_->GetLabel(deopt_block); | |
297 | |
298 lazy_deoptimization_entries_.push_back(LazyDeoptimizationEntry( | |
299 after_call.pos(), cont_label, deopt_label, safepoint_id)); | |
300 } | |
301 | |
302 | |
303 int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) { | 285 int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) { |
304 int result = static_cast<int>(deoptimization_literals_.size()); | 286 int result = static_cast<int>(deoptimization_literals_.size()); |
305 for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) { | 287 for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) { |
306 if (deoptimization_literals_[i].is_identical_to(literal)) return i; | 288 if (deoptimization_literals_[i].is_identical_to(literal)) return i; |
307 } | 289 } |
308 deoptimization_literals_.push_back(literal); | 290 deoptimization_literals_.push_back(literal); |
309 return result; | 291 return result; |
310 } | 292 } |
311 | 293 |
312 | 294 |
313 int CodeGenerator::BuildTranslation(Instruction* instr, | 295 FrameStateDescriptor* CodeGenerator::GetFrameStateDescriptor( |
314 int frame_state_offset) { | 296 Instruction* instr, int frame_state_offset) { |
315 InstructionOperandConverter i(this, instr); | 297 InstructionOperandConverter i(this, instr); |
316 int deoptimization_id = i.InputInt32(frame_state_offset); | 298 InstructionSequence::StateId state_id = |
| 299 InstructionSequence::StateId::FromInt(i.InputInt32(frame_state_offset)); |
| 300 return code()->GetFrameStateDescriptor(state_id); |
| 301 } |
| 302 |
| 303 |
| 304 int CodeGenerator::BuildTranslation(Instruction* instr, int frame_state_offset, |
| 305 OutputFrameStateCombine state_combine) { |
| 306 FrameStateDescriptor* descriptor = |
| 307 GetFrameStateDescriptor(instr, frame_state_offset); |
317 frame_state_offset++; | 308 frame_state_offset++; |
318 | 309 |
319 // We should build translation only once. | 310 int height = descriptor->size() - descriptor->parameters_count(); |
320 DCHECK_EQ(NULL, deoptimization_states_[deoptimization_id]); | 311 switch (state_combine) { |
| 312 case PUSH_OUTPUT: |
| 313 height++; |
| 314 break; |
| 315 case IGNORE_OUTPUT: |
| 316 break; |
| 317 } |
321 | 318 |
322 FrameStateDescriptor* descriptor = | 319 |
323 code()->GetDeoptimizationEntry(deoptimization_id); | |
324 Translation translation(&translations_, 1, 1, zone()); | 320 Translation translation(&translations_, 1, 1, zone()); |
325 translation.BeginJSFrame(descriptor->bailout_id(), | 321 translation.BeginJSFrame(descriptor->bailout_id(), |
326 Translation::kSelfLiteralId, | 322 Translation::kSelfLiteralId, height); |
327 descriptor->size() - descriptor->parameters_count()); | |
328 | 323 |
329 for (int i = 0; i < descriptor->size(); i++) { | 324 for (int i = 0; i < descriptor->size(); i++) { |
330 AddTranslationForOperand(&translation, instr, | 325 AddTranslationForOperand(&translation, instr, |
331 instr->InputAt(i + frame_state_offset)); | 326 instr->InputAt(i + frame_state_offset)); |
332 } | 327 } |
333 | 328 |
334 deoptimization_states_[deoptimization_id] = | 329 switch (state_combine) { |
335 new (zone()) DeoptimizationState(translation.index()); | 330 case PUSH_OUTPUT: |
| 331 DCHECK(instr->OutputCount() == 1); |
| 332 AddTranslationForOperand(&translation, instr, instr->OutputAt(0)); |
| 333 break; |
| 334 case IGNORE_OUTPUT: |
| 335 break; |
| 336 } |
| 337 |
| 338 int deoptimization_id = static_cast<int>(deoptimization_states_.size()); |
| 339 |
| 340 deoptimization_states_.push_back(new (zone()) DeoptimizationState( |
| 341 descriptor->bailout_id(), translation.index())); |
336 | 342 |
337 return deoptimization_id; | 343 return deoptimization_id; |
338 } | 344 } |
339 | 345 |
340 | 346 |
341 void CodeGenerator::AddTranslationForOperand(Translation* translation, | 347 void CodeGenerator::AddTranslationForOperand(Translation* translation, |
342 Instruction* instr, | 348 Instruction* instr, |
343 InstructionOperand* op) { | 349 InstructionOperand* op) { |
344 if (op->IsStackSlot()) { | 350 if (op->IsStackSlot()) { |
345 translation->StoreStackSlot(op->index()); | 351 translation->StoreStackSlot(op->index()); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
414 } | 420 } |
415 | 421 |
416 | 422 |
417 void CodeGenerator::AddNopForSmiCodeInlining() { UNIMPLEMENTED(); } | 423 void CodeGenerator::AddNopForSmiCodeInlining() { UNIMPLEMENTED(); } |
418 | 424 |
419 #endif // !V8_TURBOFAN_BACKEND | 425 #endif // !V8_TURBOFAN_BACKEND |
420 | 426 |
421 } // namespace compiler | 427 } // namespace compiler |
422 } // namespace internal | 428 } // namespace internal |
423 } // namespace v8 | 429 } // namespace v8 |
OLD | NEW |