Chromium Code Reviews| Index: src/compiler/frame-states.cc |
| diff --git a/src/compiler/frame-states.cc b/src/compiler/frame-states.cc |
| index b9ea010cccdb38e7caf98b337879db996d497e36..fb3740d06256b551fc383ca8df3dd6e4745fe204 100644 |
| --- a/src/compiler/frame-states.cc |
| +++ b/src/compiler/frame-states.cc |
| @@ -2,8 +2,13 @@ |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| -#include "src/base/functional.h" |
| #include "src/compiler/frame-states.h" |
| + |
| +#include "src/base/functional.h" |
| +#include "src/compiler/code-generator.h" |
| +#include "src/compiler/instruction-selector-impl.h" |
| +#include "src/compiler/node.h" |
| +#include "src/compiler/state-values-utils.h" |
| #include "src/handles-inl.h" |
| namespace v8 { |
| @@ -72,6 +77,225 @@ std::ostream& operator<<(std::ostream& os, FrameStateInfo const& info) { |
| return os; |
| } |
| + |
| +FrameStateDescriptor::FrameStateDescriptor( |
| + Zone* zone, FrameStateType type, BailoutId bailout_id, |
| + OutputFrameStateCombine state_combine, size_t parameters_count, |
| + size_t locals_count, size_t stack_count, |
| + MaybeHandle<SharedFunctionInfo> shared_info, |
| + FrameStateDescriptor* outer_state) |
| + : type_(type), |
| + bailout_id_(bailout_id), |
| + frame_state_combine_(state_combine), |
| + parameters_count_(parameters_count), |
| + locals_count_(locals_count), |
| + stack_count_(stack_count), |
| + values_(zone, kMachAnyTagged), |
| + shared_info_(shared_info), |
| + outer_state_(outer_state) {} |
| + |
| + |
| +size_t FrameStateDescriptor::GetSize(OutputFrameStateCombine combine) const { |
| + size_t size = 1 + parameters_count() + locals_count() + stack_count() + |
| + (HasContext() ? 1 : 0); |
| + switch (combine.kind()) { |
| + case OutputFrameStateCombine::kPushOutput: |
| + size += combine.GetPushCount(); |
| + break; |
| + case OutputFrameStateCombine::kPokeAt: |
| + break; |
| + } |
| + return size; |
| +} |
| + |
| + |
| +size_t FrameStateDescriptor::GetTotalSize() const { |
| + size_t total_size = 0; |
| + for (const FrameStateDescriptor* iter = this; iter != NULL; |
| + iter = iter->outer_state_) { |
| + total_size += iter->GetSize(); |
| + } |
| + return total_size; |
| +} |
| + |
| + |
| +size_t FrameStateDescriptor::GetFrameCount() const { |
| + size_t count = 0; |
| + for (const FrameStateDescriptor* iter = this; iter != NULL; |
| + iter = iter->outer_state_) { |
| + ++count; |
| + } |
| + return count; |
| +} |
| + |
| + |
| +size_t FrameStateDescriptor::GetJSFrameCount() const { |
| + size_t count = 0; |
| + for (const FrameStateDescriptor* iter = this; iter != NULL; |
| + iter = iter->outer_state_) { |
| + if (iter->type_ == FrameStateType::kJavaScriptFunction) { |
| + ++count; |
| + } |
| + } |
| + return count; |
| +} |
| + |
| + |
| +size_t StateValueDescriptor::AddOperand(InstructionOperandVector* inputs, |
|
Jarin
2015/12/02 12:24:34
Could we have a comment explaining what the return
sigurds
2015/12/02 16:35:13
Done.
|
| + OperandGenerator* g, |
| + StateObjectCache* cache, Node* input, |
| + MachineType type, |
| + FrameStateInputKind kind, Zone* zone) { |
| + switch (input->opcode()) { |
| + case IrOpcode::kObjectState: { |
| + size_t id = cache->GetObjectId(input); |
| + if (id == StateObjectCache::kNotCached) { |
| + size_t entries = 0; |
| + id = cache->InsertObject(input); |
| + fields_.push_back(StateValueDescriptor(zone, kMachAnyTagged, id)); |
| + StateValueDescriptor& desc = fields_.back(); |
| + for (Edge edge : input->input_edges()) { |
| + entries += desc.AddOperand(inputs, g, cache, edge.to(), |
| + kMachAnyTagged, kind, zone); |
| + } |
| + return entries; |
| + } else { |
| + fields_.push_back(StateValueDescriptor(zone, kMachAnyTagged, id)); |
|
Jarin
2015/12/02 12:24:34
I think it would be nice to somehow signal in the
sigurds
2015/12/02 16:35:13
Great idea, thanks.
|
| + return 0; |
| + } |
| + } break; |
|
Jarin
2015/12/02 12:24:34
The "break;" should go before the brace.
sigurds
2015/12/02 16:35:12
Done.
|
| + default: |
| + inputs->push_back(g->UseForDeopt(input, kind)); |
| + fields_.push_back(StateValueDescriptor(zone, type)); |
| + return 1; |
| + } |
| +} |
| + |
| + |
| +size_t FrameStateDescriptor::AddInputs(Node* state, OperandGenerator* g, |
| + StateObjectCache* cache, |
| + InstructionOperandVector* inputs, |
| + FrameStateInputKind kind, Zone* zone) { |
| + DCHECK_EQ(IrOpcode::kFrameState, state->op()->opcode()); |
| + |
| + size_t entries = 0; |
| + size_t initial_size = inputs->size(); |
| + |
| + if (outer_state()) { |
| + entries += |
| + outer_state()->AddInputs(state->InputAt(kFrameStateOuterStateInput), g, |
| + cache, inputs, kind, zone); |
| + } |
| + |
| + Node* parameters = state->InputAt(kFrameStateParametersInput); |
| + Node* locals = state->InputAt(kFrameStateLocalsInput); |
| + Node* stack = state->InputAt(kFrameStateStackInput); |
| + Node* context = state->InputAt(kFrameStateContextInput); |
| + Node* function = state->InputAt(kFrameStateFunctionInput); |
| + |
| + DCHECK_EQ(parameters_count(), StateValuesAccess(parameters).size()); |
| + DCHECK_EQ(locals_count(), StateValuesAccess(locals).size()); |
| + DCHECK_EQ(stack_count(), StateValuesAccess(stack).size()); |
| + |
| + StateValueDescriptor* desc = GetStateValueDescriptor(); |
| + entries += |
| + desc->AddOperand(inputs, g, cache, function, kMachAnyTagged, kind, zone); |
| + for (StateValuesAccess::TypedNode input_node : |
| + StateValuesAccess(parameters)) { |
| + entries += desc->AddOperand(inputs, g, cache, input_node.node, |
| + input_node.type, kind, zone); |
| + } |
| + if (HasContext()) { |
| + entries += |
| + desc->AddOperand(inputs, g, cache, context, kMachAnyTagged, kind, zone); |
| + } |
| + for (StateValuesAccess::TypedNode input_node : StateValuesAccess(locals)) { |
| + entries += desc->AddOperand(inputs, g, cache, input_node.node, |
| + input_node.type, kind, zone); |
| + } |
| + for (StateValuesAccess::TypedNode input_node : StateValuesAccess(stack)) { |
| + entries += desc->AddOperand(inputs, g, cache, input_node.node, |
| + input_node.type, kind, zone); |
| + } |
| + DCHECK_EQ(initial_size + entries, inputs->size()); |
| + return entries; |
| +} |
| + |
| + |
| +size_t StateValueDescriptor::Translate(CodeGenerator* gen, |
|
Jarin
2015/12/02 12:24:34
Description of return value, please. (Number of co
sigurds
2015/12/02 16:35:13
Done.
|
| + Translation* translation, |
| + Instruction* instr, |
| + size_t frame_state_offset) { |
| + if (IsRecursive()) { |
| + size_t entries = 0; |
| + translation->BeginCapturedObject(static_cast<int>(size())); |
| + for (size_t index = 0; index < fields_.size(); index++) { |
| + entries += fields_[index].Translate(gen, translation, instr, |
| + frame_state_offset + index); |
| + } |
| + return entries; |
| + } else if (IsDuplicate()) { |
| + translation->DuplicateObject(static_cast<int>(id_)); |
| + return 0; |
| + } else { |
| + gen->AddTranslationForOperand(translation, instr, |
| + instr->InputAt(frame_state_offset), type_); |
| + return 1; |
| + } |
| +} |
| + |
| + |
| +size_t StateValueDescriptor::TranslateOperand(size_t index, CodeGenerator* gen, |
| + Translation* translation, |
| + Instruction* instr, |
| + size_t frame_state_offset) { |
| + return fields_[index].Translate(gen, translation, instr, |
| + frame_state_offset + index); |
| +} |
| + |
| + |
| +void FrameStateDescriptor::TranslateOperands(CodeGenerator* gen, |
| + Instruction* instr, |
| + size_t frame_state_offset, |
| + OutputFrameStateCombine combine, |
| + Translation* translation) { |
| + for (size_t index = 0; index < GetSize(combine); index++) { |
| + switch (combine.kind()) { |
| + case OutputFrameStateCombine::kPushOutput: { |
| + DCHECK(combine.GetPushCount() <= instr->OutputCount()); |
| + size_t size_without_output = GetSize(OutputFrameStateCombine::Ignore()); |
| + // If the index is past the existing stack items in values_. |
| + if (index >= size_without_output) { |
| + // Materialize the result of the call instruction in this slot. |
| + gen->AddTranslationForOperand( |
| + translation, instr, instr->OutputAt(index - size_without_output), |
| + kMachAnyTagged); |
| + continue; |
| + } |
| + break; |
| + } |
| + case OutputFrameStateCombine::kPokeAt: |
| + // The result of the call should be placed at position |
| + // [index_from_top] in the stack (overwriting whatever was |
| + // previously there). |
| + size_t index_from_top = |
| + GetSize(combine) - 1 - combine.GetOffsetToPokeAt(); |
| + if (index >= index_from_top && |
| + index < index_from_top + instr->OutputCount()) { |
| + gen->AddTranslationForOperand(translation, instr, |
| + instr->OutputAt(index - index_from_top), |
| + kMachAnyTagged); |
| + continue; |
| + } |
| + break; |
| + } |
| + // Add the additional fields we read during materialization. |
| + frame_state_offset += values_.TranslateOperand(index, gen, translation, |
| + instr, frame_state_offset) - |
| + 1; |
| + } |
| +} |
| + |
| } // namespace compiler |
| } // namespace internal |
| } // namespace v8 |