diff options
Diffstat (limited to 'deps/v8/src/compiler/bytecode-graph-builder.cc')
-rw-r--r-- | deps/v8/src/compiler/bytecode-graph-builder.cc | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc new file mode 100644 index 0000000000..5ba18ffc97 --- /dev/null +++ b/deps/v8/src/compiler/bytecode-graph-builder.cc @@ -0,0 +1,547 @@ +// Copyright 2015 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "src/compiler/bytecode-graph-builder.h" + +#include "src/compiler/linkage.h" +#include "src/compiler/operator-properties.h" +#include "src/interpreter/bytecode-array-iterator.h" + +namespace v8 { +namespace internal { +namespace compiler { + +// Issues: +// - Need to deal with FrameState / FrameStateBeforeAndAfter / StateValue. +// - Scopes - intimately tied to AST. Need to eval what is needed. +// - Need to resolve closure parameter treatment. +BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder, + int register_count, + int parameter_count, + Node* control_dependency, + Node* context) + : builder_(builder), + register_count_(register_count), + parameter_count_(parameter_count), + context_(context), + control_dependency_(control_dependency), + effect_dependency_(control_dependency), + values_(builder->local_zone()) { + // The layout of values_ is: + // + // [receiver] [parameters] [registers] + // + // parameter[0] is the receiver (this), parameters 1..N are the + // parameters supplied to the method (arg0..argN-1). The accumulator + // is stored separately. + + // Parameters including the receiver + for (int i = 0; i < parameter_count; i++) { + const char* debug_name = (i == 0) ? "%this" : nullptr; + const Operator* op = common()->Parameter(i, debug_name); + Node* parameter = builder->graph()->NewNode(op, graph()->start()); + values()->push_back(parameter); + } + + // Registers + register_base_ = static_cast<int>(values()->size()); + Node* undefined_constant = builder->jsgraph()->UndefinedConstant(); + values()->insert(values()->end(), register_count, undefined_constant); + + // Accumulator + accumulator_ = undefined_constant; +} + + +int BytecodeGraphBuilder::Environment::RegisterToValuesIndex( + interpreter::Register the_register) const { + if (the_register.is_parameter()) { + return the_register.ToParameterIndex(parameter_count()); + } else { + return the_register.index() + register_base(); + } +} + + +void BytecodeGraphBuilder::Environment::BindRegister( + interpreter::Register the_register, Node* node) { + int values_index = RegisterToValuesIndex(the_register); + values()->at(values_index) = node; +} + + +Node* BytecodeGraphBuilder::Environment::LookupRegister( + interpreter::Register the_register) const { + int values_index = RegisterToValuesIndex(the_register); + return values()->at(values_index); +} + + +void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) { + accumulator_ = node; +} + + +Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const { + return accumulator_; +} + + +bool BytecodeGraphBuilder::Environment::IsMarkedAsUnreachable() const { + return GetControlDependency()->opcode() == IrOpcode::kDead; +} + + +void BytecodeGraphBuilder::Environment::MarkAsUnreachable() { + UpdateControlDependency(builder()->jsgraph()->Dead()); +} + + +BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone, + CompilationInfo* compilation_info, + JSGraph* jsgraph) + : local_zone_(local_zone), + info_(compilation_info), + jsgraph_(jsgraph), + input_buffer_size_(0), + input_buffer_(nullptr), + exit_controls_(local_zone) { + bytecode_array_ = handle(info()->shared_info()->bytecode_array()); +} + + +Node* BytecodeGraphBuilder::GetFunctionContext() { + if (!function_context_.is_set()) { + // Parameter (arity + 1) is special for the outer context of the function + const Operator* op = + common()->Parameter(bytecode_array()->parameter_count(), "%context"); + Node* node = NewNode(op, graph()->start()); + function_context_.set(node); + } + return function_context_.get(); +} + + +bool BytecodeGraphBuilder::CreateGraph(bool stack_check) { + // Set up the basic structure of the graph. Outputs for {Start} are + // the formal parameters (including the receiver) plus context and + // closure. + + // The additional count items are for the context and closure. + int actual_parameter_count = bytecode_array()->parameter_count() + 2; + graph()->SetStart(graph()->NewNode(common()->Start(actual_parameter_count))); + + Environment env(this, bytecode_array()->register_count(), + bytecode_array()->parameter_count(), graph()->start(), + GetFunctionContext()); + set_environment(&env); + + // Build function context only if there are context allocated variables. + if (info()->num_heap_slots() > 0) { + UNIMPLEMENTED(); // TODO(oth): Write ast-graph-builder equivalent. + } else { + // Simply use the outer function context in building the graph. + CreateGraphBody(stack_check); + } + + // Finish the basic structure of the graph. + DCHECK_NE(0u, exit_controls_.size()); + int const input_count = static_cast<int>(exit_controls_.size()); + Node** const inputs = &exit_controls_.front(); + Node* end = graph()->NewNode(common()->End(input_count), input_count, inputs); + graph()->SetEnd(end); + + return true; +} + + +void BytecodeGraphBuilder::CreateGraphBody(bool stack_check) { + // TODO(oth): Review ast-graph-builder equivalent, i.e. arguments + // object setup, this function variable if used, tracing hooks. + VisitBytecodes(); +} + + +void BytecodeGraphBuilder::VisitBytecodes() { + interpreter::BytecodeArrayIterator iterator(bytecode_array()); + while (!iterator.done()) { + switch (iterator.current_bytecode()) { +#define BYTECODE_CASE(name, ...) \ + case interpreter::Bytecode::k##name: \ + Visit##name(iterator); \ + break; + BYTECODE_LIST(BYTECODE_CASE) +#undef BYTECODE_CODE + } + iterator.Advance(); + } +} + + +void BytecodeGraphBuilder::VisitLdaZero( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->ZeroConstant(); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaSmi8( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->Constant(iterator.GetSmi8Operand(0)); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaConstant( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->Constant(iterator.GetConstantForIndexOperand(0)); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaUndefined( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->UndefinedConstant(); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaNull( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->NullConstant(); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaTheHole( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->TheHoleConstant(); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaTrue( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->TrueConstant(); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdaFalse( + const interpreter::BytecodeArrayIterator& iterator) { + Node* node = jsgraph()->FalseConstant(); + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitLdar( + const interpreter::BytecodeArrayIterator& iterator) { + Node* value = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + environment()->BindAccumulator(value); +} + + +void BytecodeGraphBuilder::VisitStar( + const interpreter::BytecodeArrayIterator& iterator) { + Node* value = environment()->LookupAccumulator(); + environment()->BindRegister(iterator.GetRegisterOperand(0), value); +} + + +void BytecodeGraphBuilder::VisitLdaGlobal( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitLoadIC( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitKeyedLoadIC( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitStoreIC( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitKeyedStoreIC( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitCall( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::BuildBinaryOp( + const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) { + Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0)); + Node* right = environment()->LookupAccumulator(); + Node* node = NewNode(js_op, left, right); + + // TODO(oth): Real frame state and environment check pointing. + int frame_state_count = + OperatorProperties::GetFrameStateInputCount(node->op()); + for (int i = 0; i < frame_state_count; i++) { + NodeProperties::ReplaceFrameStateInput(node, i, + jsgraph()->EmptyFrameState()); + } + environment()->BindAccumulator(node); +} + + +void BytecodeGraphBuilder::VisitAdd( + const interpreter::BytecodeArrayIterator& iterator) { + BuildBinaryOp(javascript()->Add(language_mode()), iterator); +} + + +void BytecodeGraphBuilder::VisitSub( + const interpreter::BytecodeArrayIterator& iterator) { + BuildBinaryOp(javascript()->Subtract(language_mode()), iterator); +} + + +void BytecodeGraphBuilder::VisitMul( + const interpreter::BytecodeArrayIterator& iterator) { + BuildBinaryOp(javascript()->Multiply(language_mode()), iterator); +} + + +void BytecodeGraphBuilder::VisitDiv( + const interpreter::BytecodeArrayIterator& iterator) { + BuildBinaryOp(javascript()->Divide(language_mode()), iterator); +} + + +void BytecodeGraphBuilder::VisitMod( + const interpreter::BytecodeArrayIterator& iterator) { + BuildBinaryOp(javascript()->Modulus(language_mode()), iterator); +} + + +void BytecodeGraphBuilder::VisitTestEqual( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestNotEqual( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestEqualStrict( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestNotEqualStrict( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestLessThan( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestGreaterThan( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestLessThanOrEqual( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestIn( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitTestInstanceOf( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitToBoolean( + const interpreter::BytecodeArrayIterator& ToBoolean) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitJump( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitJumpConstant( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitJumpIfTrue( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitJumpIfTrueConstant( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitJumpIfFalse( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitJumpIfFalseConstant( + const interpreter::BytecodeArrayIterator& iterator) { + UNIMPLEMENTED(); +} + + +void BytecodeGraphBuilder::VisitReturn( + const interpreter::BytecodeArrayIterator& iterator) { + Node* control = + NewNode(common()->Return(), environment()->LookupAccumulator()); + UpdateControlDependencyToLeaveFunction(control); +} + + +Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) { + if (size > input_buffer_size_) { + size = size + kInputBufferSizeIncrement + input_buffer_size_; + input_buffer_ = local_zone()->NewArray<Node*>(size); + input_buffer_size_ = size; + } + return input_buffer_; +} + + +Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count, + Node** value_inputs, bool incomplete) { + DCHECK_EQ(op->ValueInputCount(), value_input_count); + + bool has_context = OperatorProperties::HasContextInput(op); + int frame_state_count = OperatorProperties::GetFrameStateInputCount(op); + bool has_control = op->ControlInputCount() == 1; + bool has_effect = op->EffectInputCount() == 1; + + DCHECK_LT(op->ControlInputCount(), 2); + DCHECK_LT(op->EffectInputCount(), 2); + + Node* result = NULL; + if (!has_context && frame_state_count == 0 && !has_control && !has_effect) { + result = graph()->NewNode(op, value_input_count, value_inputs, incomplete); + } else { + int input_count_with_deps = value_input_count; + if (has_context) ++input_count_with_deps; + input_count_with_deps += frame_state_count; + if (has_control) ++input_count_with_deps; + if (has_effect) ++input_count_with_deps; + Node** buffer = EnsureInputBufferSize(input_count_with_deps); + memcpy(buffer, value_inputs, kPointerSize * value_input_count); + Node** current_input = buffer + value_input_count; + if (has_context) { + *current_input++ = environment()->Context(); + } + for (int i = 0; i < frame_state_count; i++) { + // The frame state will be inserted later. Here we misuse + // the {Dead} node as a sentinel to be later overwritten + // with the real frame state. + *current_input++ = jsgraph()->Dead(); + } + if (has_effect) { + *current_input++ = environment()->GetEffectDependency(); + } + if (has_control) { + *current_input++ = environment()->GetControlDependency(); + } + result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete); + if (!environment()->IsMarkedAsUnreachable()) { + // Update the current control dependency for control-producing nodes. + if (NodeProperties::IsControl(result)) { + environment()->UpdateControlDependency(result); + } + // Update the current effect dependency for effect-producing nodes. + if (result->op()->EffectOutputCount() > 0) { + environment()->UpdateEffectDependency(result); + } + // Add implicit success continuation for throwing nodes. + if (!result->op()->HasProperty(Operator::kNoThrow)) { + const Operator* if_success = common()->IfSuccess(); + Node* on_success = graph()->NewNode(if_success, result); + environment_->UpdateControlDependency(on_success); + } + } + } + + return result; +} + + +Node* BytecodeGraphBuilder::MergeControl(Node* control, Node* other) { + int inputs = control->op()->ControlInputCount() + 1; + if (control->opcode() == IrOpcode::kLoop) { + // Control node for loop exists, add input. + const Operator* op = common()->Loop(inputs); + control->AppendInput(graph_zone(), other); + NodeProperties::ChangeOp(control, op); + } else if (control->opcode() == IrOpcode::kMerge) { + // Control node for merge exists, add input. + const Operator* op = common()->Merge(inputs); + control->AppendInput(graph_zone(), other); + NodeProperties::ChangeOp(control, op); + } else { + // Control node is a singleton, introduce a merge. + const Operator* op = common()->Merge(inputs); + Node* merge_inputs[] = {control, other}; + control = graph()->NewNode(op, arraysize(merge_inputs), merge_inputs, true); + } + return control; +} + + +void BytecodeGraphBuilder::UpdateControlDependencyToLeaveFunction(Node* exit) { + if (environment()->IsMarkedAsUnreachable()) return; + environment()->MarkAsUnreachable(); + exit_controls_.push_back(exit); +} + +} // namespace compiler +} // namespace internal +} // namespace v8 |