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 deoptimization_points_(code->zone()), | |
23 deoptimization_states_(code->zone()), | 22 deoptimization_states_(code->zone()), |
24 deoptimization_literals_(code->zone()), | 23 deoptimization_literals_(code->zone()), |
25 translations_(code->zone()) {} | 24 translations_(code->zone()) {} |
26 | 25 |
27 | 26 |
28 Handle<Code> CodeGenerator::GenerateCode() { | 27 Handle<Code> CodeGenerator::GenerateCode() { |
29 CompilationInfo* info = linkage()->info(); | 28 CompilationInfo* info = linkage()->info(); |
30 | 29 |
31 // Emit a code line info recording start event. | 30 // Emit a code line info recording start event. |
32 PositionsRecorder* recorder = masm()->positions_recorder(); | 31 PositionsRecorder* recorder = masm()->positions_recorder(); |
33 LOG_CODE_EVENT(isolate(), CodeStartLinePosInfoRecordEvent(recorder)); | 32 LOG_CODE_EVENT(isolate(), CodeStartLinePosInfoRecordEvent(recorder)); |
34 | 33 |
35 // Place function entry hook if requested to do so. | 34 // Place function entry hook if requested to do so. |
36 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { | 35 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { |
37 ProfileEntryHookStub::MaybeCallEntryHook(masm()); | 36 ProfileEntryHookStub::MaybeCallEntryHook(masm()); |
38 } | 37 } |
39 | 38 |
40 // Architecture-specific, linkage-specific prologue. | 39 // Architecture-specific, linkage-specific prologue. |
41 info->set_prologue_offset(masm()->pc_offset()); | 40 info->set_prologue_offset(masm()->pc_offset()); |
42 AssemblePrologue(); | 41 AssemblePrologue(); |
43 | 42 |
44 // Assemble all instructions. | 43 // Assemble all instructions. |
45 for (InstructionSequence::const_iterator i = code()->begin(); | 44 for (InstructionSequence::const_iterator i = code()->begin(); |
46 i != code()->end(); ++i) { | 45 i != code()->end(); ++i) { |
47 AssembleInstruction(*i); | 46 AssembleInstruction(*i); |
48 } | 47 } |
49 | 48 |
50 EmitLazyDeoptimizationCallTable(); | 49 FinishCode(masm()); |
51 | 50 |
52 FinishCode(masm()); | 51 // Ensure there is space for lazy deopt. |
52 if (!info->IsStub()) { | |
Benedikt Meurer
2014/09/15 08:23:14
Do we really need/want this check here?
| |
53 int target_offset = masm()->pc_offset() + Deoptimizer::patch_size(); | |
54 while (masm()->pc_offset() < target_offset) { | |
55 masm()->nop(); | |
56 } | |
57 } | |
53 | 58 |
54 safepoints()->Emit(masm(), frame()->GetSpillSlotCount()); | 59 safepoints()->Emit(masm(), frame()->GetSpillSlotCount()); |
55 | 60 |
56 // TODO(titzer): what are the right code flags here? | 61 // TODO(titzer): what are the right code flags here? |
57 Code::Kind kind = Code::STUB; | 62 Code::Kind kind = Code::STUB; |
58 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { | 63 if (linkage()->GetIncomingDescriptor()->IsJSFunctionCall()) { |
59 kind = Code::OPTIMIZED_FUNCTION; | 64 kind = Code::OPTIMIZED_FUNCTION; |
60 } | 65 } |
61 Handle<Code> result = v8::internal::CodeGenerator::MakeCodeEpilogue( | 66 Handle<Code> result = v8::internal::CodeGenerator::MakeCodeEpilogue( |
62 masm(), Code::ComputeFlags(kind), info); | 67 masm(), Code::ComputeFlags(kind), info); |
63 result->set_is_turbofanned(true); | 68 result->set_is_turbofanned(true); |
64 result->set_stack_slots(frame()->GetSpillSlotCount()); | 69 result->set_stack_slots(frame()->GetSpillSlotCount()); |
65 result->set_safepoint_table_offset(safepoints()->GetCodeOffset()); | 70 result->set_safepoint_table_offset(safepoints()->GetCodeOffset()); |
66 | 71 |
67 PopulateDeoptimizationData(result); | 72 PopulateDeoptimizationData(result); |
68 | 73 |
69 // Emit a code line info recording stop event. | 74 // Emit a code line info recording stop event. |
70 void* line_info = recorder->DetachJITHandlerData(); | 75 void* line_info = recorder->DetachJITHandlerData(); |
71 LOG_CODE_EVENT(isolate(), CodeEndLinePosInfoRecordEvent(*result, line_info)); | 76 LOG_CODE_EVENT(isolate(), CodeEndLinePosInfoRecordEvent(*result, line_info)); |
72 | 77 |
73 return result; | 78 return result; |
74 } | 79 } |
75 | 80 |
76 | 81 |
77 Safepoint::Id CodeGenerator::RecordSafepoint(PointerMap* pointers, | 82 void CodeGenerator::RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind, |
78 Safepoint::Kind kind, | 83 int arguments, |
79 int arguments, | 84 Safepoint::DeoptMode deopt_mode) { |
80 Safepoint::DeoptMode deopt_mode) { | |
81 const ZoneList<InstructionOperand*>* operands = | 85 const ZoneList<InstructionOperand*>* operands = |
82 pointers->GetNormalizedOperands(); | 86 pointers->GetNormalizedOperands(); |
83 Safepoint safepoint = | 87 Safepoint safepoint = |
84 safepoints()->DefineSafepoint(masm(), kind, arguments, deopt_mode); | 88 safepoints()->DefineSafepoint(masm(), kind, arguments, deopt_mode); |
85 for (int i = 0; i < operands->length(); i++) { | 89 for (int i = 0; i < operands->length(); i++) { |
86 InstructionOperand* pointer = operands->at(i); | 90 InstructionOperand* pointer = operands->at(i); |
87 if (pointer->IsStackSlot()) { | 91 if (pointer->IsStackSlot()) { |
88 safepoint.DefinePointerSlot(pointer->index(), zone()); | 92 safepoint.DefinePointerSlot(pointer->index(), zone()); |
89 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { | 93 } else if (pointer->IsRegister() && (kind & Safepoint::kWithRegisters)) { |
90 Register reg = Register::FromAllocationIndex(pointer->index()); | 94 Register reg = Register::FromAllocationIndex(pointer->index()); |
91 safepoint.DefinePointerRegister(reg, zone()); | 95 safepoint.DefinePointerRegister(reg, zone()); |
92 } | 96 } |
93 } | 97 } |
94 return safepoint.id(); | |
95 } | 98 } |
96 | 99 |
97 | 100 |
98 void CodeGenerator::AssembleInstruction(Instruction* instr) { | 101 void CodeGenerator::AssembleInstruction(Instruction* instr) { |
99 if (instr->IsBlockStart()) { | 102 if (instr->IsBlockStart()) { |
100 // Bind a label for a block start and handle parallel moves. | 103 // Bind a label for a block start and handle parallel moves. |
101 BlockStartInstruction* block_start = BlockStartInstruction::cast(instr); | 104 BlockStartInstruction* block_start = BlockStartInstruction::cast(instr); |
102 current_block_ = block_start->block(); | 105 current_block_ = block_start->block(); |
103 if (FLAG_code_comments) { | 106 if (FLAG_code_comments) { |
104 // TODO(titzer): these code comments are a giant memory leak. | 107 // TODO(titzer): these code comments are a giant memory leak. |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
165 for (int i = GapInstruction::FIRST_INNER_POSITION; | 168 for (int i = GapInstruction::FIRST_INNER_POSITION; |
166 i <= GapInstruction::LAST_INNER_POSITION; i++) { | 169 i <= GapInstruction::LAST_INNER_POSITION; i++) { |
167 GapInstruction::InnerPosition inner_pos = | 170 GapInstruction::InnerPosition inner_pos = |
168 static_cast<GapInstruction::InnerPosition>(i); | 171 static_cast<GapInstruction::InnerPosition>(i); |
169 ParallelMove* move = instr->GetParallelMove(inner_pos); | 172 ParallelMove* move = instr->GetParallelMove(inner_pos); |
170 if (move != NULL) resolver()->Resolve(move); | 173 if (move != NULL) resolver()->Resolve(move); |
171 } | 174 } |
172 } | 175 } |
173 | 176 |
174 | 177 |
175 void CodeGenerator::EmitLazyDeoptimizationCallTable() { | |
176 // ZoneDeque<DeoptimizationPoint*>::iterator iter; | |
177 int i = 0; | |
178 for (ZoneDeque<DeoptimizationPoint*>::iterator | |
179 iter = deoptimization_points_.begin(); | |
180 iter != deoptimization_points_.end(); iter++, i++) { | |
181 int pc_offset = masm()->pc_offset(); | |
182 AssembleDeoptimizerCall((*iter)->lazy_state_id()); | |
183 safepoints()->SetDeoptimizationPc((*iter)->safepoint(), pc_offset); | |
184 } | |
185 } | |
186 | |
187 | |
188 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) { | 178 void CodeGenerator::PopulateDeoptimizationData(Handle<Code> code_object) { |
189 CompilationInfo* info = linkage()->info(); | 179 CompilationInfo* info = linkage()->info(); |
190 int deopt_count = static_cast<int>(deoptimization_states_.size()); | 180 int deopt_count = static_cast<int>(deoptimization_states_.size()); |
191 if (deopt_count == 0) return; | 181 if (deopt_count == 0) return; |
192 Handle<DeoptimizationInputData> data = | 182 Handle<DeoptimizationInputData> data = |
193 DeoptimizationInputData::New(isolate(), deopt_count, TENURED); | 183 DeoptimizationInputData::New(isolate(), deopt_count, TENURED); |
194 | 184 |
195 Handle<ByteArray> translation_array = | 185 Handle<ByteArray> translation_array = |
196 translations_.CreateByteArray(isolate()->factory()); | 186 translations_.CreateByteArray(isolate()->factory()); |
197 | 187 |
(...skipping 26 matching lines...) Expand all Loading... | |
224 data->SetOsrPcOffset(Smi::FromInt(-1)); | 214 data->SetOsrPcOffset(Smi::FromInt(-1)); |
225 | 215 |
226 // Populate deoptimization entries. | 216 // Populate deoptimization entries. |
227 for (int i = 0; i < deopt_count; i++) { | 217 for (int i = 0; i < deopt_count; i++) { |
228 DeoptimizationState* deoptimization_state = deoptimization_states_[i]; | 218 DeoptimizationState* deoptimization_state = deoptimization_states_[i]; |
229 data->SetAstId(i, deoptimization_state->bailout_id()); | 219 data->SetAstId(i, deoptimization_state->bailout_id()); |
230 CHECK_NE(NULL, deoptimization_states_[i]); | 220 CHECK_NE(NULL, deoptimization_states_[i]); |
231 data->SetTranslationIndex( | 221 data->SetTranslationIndex( |
232 i, Smi::FromInt(deoptimization_states_[i]->translation_id())); | 222 i, Smi::FromInt(deoptimization_states_[i]->translation_id())); |
233 data->SetArgumentsStackHeight(i, Smi::FromInt(0)); | 223 data->SetArgumentsStackHeight(i, Smi::FromInt(0)); |
234 data->SetPc(i, Smi::FromInt(-1)); | 224 data->SetPc(i, Smi::FromInt(deoptimization_state->pc_offset())); |
235 } | 225 } |
236 | 226 |
237 code_object->set_deoptimization_data(*data); | 227 code_object->set_deoptimization_data(*data); |
238 } | 228 } |
239 | 229 |
240 | 230 |
241 void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { | 231 void CodeGenerator::AddSafepointAndDeopt(Instruction* instr) { |
242 CallDescriptor::Flags flags(MiscField::decode(instr->opcode())); | 232 CallDescriptor::Flags flags(MiscField::decode(instr->opcode())); |
243 | 233 |
244 bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState); | 234 bool needs_frame_state = (flags & CallDescriptor::kNeedsFrameState); |
245 | 235 |
246 Safepoint::Id safepoint_id = RecordSafepoint( | 236 RecordSafepoint( |
247 instr->pointer_map(), Safepoint::kSimple, 0, | 237 instr->pointer_map(), Safepoint::kSimple, 0, |
248 needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); | 238 needs_frame_state ? Safepoint::kLazyDeopt : Safepoint::kNoLazyDeopt); |
249 | 239 |
240 if (flags & CallDescriptor::kNeedsNopAfterCall) { | |
241 AddNopForSmiCodeInlining(); | |
242 } | |
243 | |
250 if (needs_frame_state) { | 244 if (needs_frame_state) { |
251 // If the frame state is present, it starts at argument 1 | 245 // If the frame state is present, it starts at argument 1 |
252 // (just after the code address). | 246 // (just after the code address). |
253 InstructionOperandConverter converter(this, instr); | 247 InstructionOperandConverter converter(this, instr); |
254 // Deoptimization info starts at argument 1 | 248 // Deoptimization info starts at argument 1 |
255 int frame_state_offset = 1; | 249 int frame_state_offset = 1; |
256 FrameStateDescriptor* descriptor = | 250 FrameStateDescriptor* descriptor = |
257 GetFrameStateDescriptor(instr, frame_state_offset); | 251 GetFrameStateDescriptor(instr, frame_state_offset); |
258 int deopt_state_id = | 252 int pc_offset = masm()->pc_offset(); |
259 BuildTranslation(instr, frame_state_offset, kIgnoreOutput); | 253 int deopt_state_id = BuildTranslation(instr, pc_offset, frame_state_offset, |
260 int lazy_deopt_state_id = deopt_state_id; | 254 descriptor->state_combine()); |
255 // If the pre-call frame state differs from the post-call one, produce the | |
256 // pre-call frame state, too. | |
257 // TODO(jarin) We might want to avoid building the pre-call frame state | |
258 // because it is only used to get locals and arguments (by the debugger and | |
259 // f.arguments), and those are the same in the pre-call and post-call | |
260 // states. | |
261 if (descriptor->state_combine() != kIgnoreOutput) { | 261 if (descriptor->state_combine() != kIgnoreOutput) { |
262 lazy_deopt_state_id = BuildTranslation(instr, frame_state_offset, | 262 deopt_state_id = |
263 descriptor->state_combine()); | 263 BuildTranslation(instr, -1, frame_state_offset, kIgnoreOutput); |
264 } | 264 } |
265 deoptimization_points_.push_back(new (zone()) DeoptimizationPoint( | |
266 deopt_state_id, lazy_deopt_state_id, descriptor, safepoint_id)); | |
267 #if DEBUG | 265 #if DEBUG |
268 // Make sure all the values live in stack slots or they are immediates. | 266 // Make sure all the values live in stack slots or they are immediates. |
269 // (The values should not live in register because registers are clobbered | 267 // (The values should not live in register because registers are clobbered |
270 // by calls.) | 268 // by calls.) |
271 for (int i = 0; i < descriptor->size(); i++) { | 269 for (int i = 0; i < descriptor->size(); i++) { |
272 InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); | 270 InstructionOperand* op = instr->InputAt(frame_state_offset + 1 + i); |
273 CHECK(op->IsStackSlot() || op->IsImmediate()); | 271 CHECK(op->IsStackSlot() || op->IsImmediate()); |
274 } | 272 } |
275 #endif | 273 #endif |
276 safepoints()->RecordLazyDeoptimizationIndex(lazy_deopt_state_id); | 274 safepoints()->RecordLazyDeoptimizationIndex(deopt_state_id); |
277 } | |
278 | |
279 if (flags & CallDescriptor::kNeedsNopAfterCall) { | |
280 AddNopForSmiCodeInlining(); | |
281 } | 275 } |
282 } | 276 } |
283 | 277 |
284 | 278 |
285 int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) { | 279 int CodeGenerator::DefineDeoptimizationLiteral(Handle<Object> literal) { |
286 int result = static_cast<int>(deoptimization_literals_.size()); | 280 int result = static_cast<int>(deoptimization_literals_.size()); |
287 for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) { | 281 for (unsigned i = 0; i < deoptimization_literals_.size(); ++i) { |
288 if (deoptimization_literals_[i].is_identical_to(literal)) return i; | 282 if (deoptimization_literals_[i].is_identical_to(literal)) return i; |
289 } | 283 } |
290 deoptimization_literals_.push_back(literal); | 284 deoptimization_literals_.push_back(literal); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
333 case kPushOutput: | 327 case kPushOutput: |
334 DCHECK(instr->OutputCount() == 1); | 328 DCHECK(instr->OutputCount() == 1); |
335 AddTranslationForOperand(translation, instr, instr->OutputAt(0)); | 329 AddTranslationForOperand(translation, instr, instr->OutputAt(0)); |
336 break; | 330 break; |
337 case kIgnoreOutput: | 331 case kIgnoreOutput: |
338 break; | 332 break; |
339 } | 333 } |
340 } | 334 } |
341 | 335 |
342 | 336 |
343 int CodeGenerator::BuildTranslation(Instruction* instr, int frame_state_offset, | 337 int CodeGenerator::BuildTranslation(Instruction* instr, int pc_offset, |
338 int frame_state_offset, | |
344 OutputFrameStateCombine state_combine) { | 339 OutputFrameStateCombine state_combine) { |
345 FrameStateDescriptor* descriptor = | 340 FrameStateDescriptor* descriptor = |
346 GetFrameStateDescriptor(instr, frame_state_offset); | 341 GetFrameStateDescriptor(instr, frame_state_offset); |
347 frame_state_offset++; | 342 frame_state_offset++; |
348 | 343 |
349 int frame_count = descriptor->GetFrameCount(); | 344 int frame_count = descriptor->GetFrameCount(); |
350 Translation translation(&translations_, frame_count, frame_count, zone()); | 345 Translation translation(&translations_, frame_count, frame_count, zone()); |
351 BuildTranslationForFrameStateDescriptor(descriptor, instr, &translation, | 346 BuildTranslationForFrameStateDescriptor(descriptor, instr, &translation, |
352 frame_state_offset, state_combine); | 347 frame_state_offset, state_combine); |
353 | 348 |
354 int deoptimization_id = static_cast<int>(deoptimization_states_.size()); | 349 int deoptimization_id = static_cast<int>(deoptimization_states_.size()); |
355 | 350 |
356 deoptimization_states_.push_back(new (zone()) DeoptimizationState( | 351 deoptimization_states_.push_back(new (zone()) DeoptimizationState( |
357 descriptor->bailout_id(), translation.index())); | 352 descriptor->bailout_id(), translation.index(), pc_offset)); |
358 | 353 |
359 return deoptimization_id; | 354 return deoptimization_id; |
360 } | 355 } |
361 | 356 |
362 | 357 |
363 void CodeGenerator::AddTranslationForOperand(Translation* translation, | 358 void CodeGenerator::AddTranslationForOperand(Translation* translation, |
364 Instruction* instr, | 359 Instruction* instr, |
365 InstructionOperand* op) { | 360 InstructionOperand* op) { |
366 if (op->IsStackSlot()) { | 361 if (op->IsStackSlot()) { |
367 translation->StoreStackSlot(op->index()); | 362 translation->StoreStackSlot(op->index()); |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
441 } | 436 } |
442 | 437 |
443 | 438 |
444 void CodeGenerator::AddNopForSmiCodeInlining() { UNIMPLEMENTED(); } | 439 void CodeGenerator::AddNopForSmiCodeInlining() { UNIMPLEMENTED(); } |
445 | 440 |
446 #endif // !V8_TURBOFAN_BACKEND | 441 #endif // !V8_TURBOFAN_BACKEND |
447 | 442 |
448 } // namespace compiler | 443 } // namespace compiler |
449 } // namespace internal | 444 } // namespace internal |
450 } // namespace v8 | 445 } // namespace v8 |
OLD | NEW |