Chromium Code Reviews| 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 |