| 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 |