2015-09-10 16:21:34 +00:00
|
|
|
// 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.
|
|
|
|
|
|
|
|
#ifndef V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|
|
|
|
#define V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|
|
|
|
|
|
|
|
#include "src/compiler.h"
|
2015-12-16 16:29:09 +00:00
|
|
|
#include "src/compiler/bytecode-branch-analysis.h"
|
2015-09-10 16:21:34 +00:00
|
|
|
#include "src/compiler/js-graph.h"
|
|
|
|
#include "src/interpreter/bytecode-array-iterator.h"
|
|
|
|
#include "src/interpreter/bytecodes.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
|
|
|
// The BytecodeGraphBuilder produces a high-level IR graph based on
|
|
|
|
// interpreter bytecodes.
|
|
|
|
class BytecodeGraphBuilder {
|
|
|
|
public:
|
|
|
|
BytecodeGraphBuilder(Zone* local_zone, CompilationInfo* info,
|
|
|
|
JSGraph* jsgraph);
|
|
|
|
|
|
|
|
// Creates a graph by visiting bytecodes.
|
|
|
|
bool CreateGraph(bool stack_check = true);
|
|
|
|
|
|
|
|
Graph* graph() const { return jsgraph_->graph(); }
|
|
|
|
|
|
|
|
private:
|
|
|
|
class Environment;
|
|
|
|
|
|
|
|
void CreateGraphBody(bool stack_check);
|
|
|
|
void VisitBytecodes();
|
|
|
|
|
|
|
|
Node* LoadAccumulator(Node* value);
|
|
|
|
|
2015-11-17 09:05:37 +00:00
|
|
|
// Get or create the node that represents the outer function closure.
|
|
|
|
Node* GetFunctionClosure();
|
|
|
|
|
|
|
|
// Get or create the node that represents the outer function context.
|
2015-09-10 16:21:34 +00:00
|
|
|
Node* GetFunctionContext();
|
|
|
|
|
2015-12-01 17:28:43 +00:00
|
|
|
// Get or create the node that represents the incoming new target value.
|
|
|
|
Node* GetNewTarget();
|
|
|
|
|
2015-11-20 09:25:13 +00:00
|
|
|
// Builder for accessing a (potentially immutable) object field.
|
|
|
|
Node* BuildLoadObjectField(Node* object, int offset);
|
2015-11-17 09:05:37 +00:00
|
|
|
Node* BuildLoadImmutableObjectField(Node* object, int offset);
|
|
|
|
|
|
|
|
// Builder for accessing type feedback vector.
|
|
|
|
Node* BuildLoadFeedbackVector();
|
|
|
|
|
2015-11-20 09:25:13 +00:00
|
|
|
// Builder for loading the a native context field.
|
|
|
|
Node* BuildLoadNativeContextField(int index);
|
|
|
|
|
2015-11-17 09:05:37 +00:00
|
|
|
// Helper function for creating a pair containing type feedback vector and
|
|
|
|
// a feedback slot.
|
|
|
|
VectorSlotPair CreateVectorSlotPair(int slot_id);
|
|
|
|
|
|
|
|
// Replaces the frame state inputs with empty frame states.
|
|
|
|
void AddEmptyFrameStateInputs(Node* node);
|
|
|
|
|
2015-09-10 16:21:34 +00:00
|
|
|
void set_environment(Environment* env) { environment_ = env; }
|
|
|
|
const Environment* environment() const { return environment_; }
|
|
|
|
Environment* environment() { return environment_; }
|
|
|
|
|
|
|
|
// Node creation helpers
|
|
|
|
Node* NewNode(const Operator* op, bool incomplete = false) {
|
|
|
|
return MakeNode(op, 0, static_cast<Node**>(NULL), incomplete);
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* NewNode(const Operator* op, Node* n1) {
|
|
|
|
Node* buffer[] = {n1};
|
|
|
|
return MakeNode(op, arraysize(buffer), buffer, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* NewNode(const Operator* op, Node* n1, Node* n2) {
|
|
|
|
Node* buffer[] = {n1, n2};
|
|
|
|
return MakeNode(op, arraysize(buffer), buffer, false);
|
|
|
|
}
|
|
|
|
|
2015-11-17 09:05:37 +00:00
|
|
|
Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3) {
|
|
|
|
Node* buffer[] = {n1, n2, n3};
|
|
|
|
return MakeNode(op, arraysize(buffer), buffer, false);
|
|
|
|
}
|
|
|
|
|
2015-11-19 14:16:36 +00:00
|
|
|
Node* NewNode(const Operator* op, Node* n1, Node* n2, Node* n3, Node* n4) {
|
|
|
|
Node* buffer[] = {n1, n2, n3, n4};
|
|
|
|
return MakeNode(op, arraysize(buffer), buffer, false);
|
|
|
|
}
|
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
// Helpers to create new control nodes.
|
|
|
|
Node* NewIfTrue() { return NewNode(common()->IfTrue()); }
|
|
|
|
Node* NewIfFalse() { return NewNode(common()->IfFalse()); }
|
|
|
|
Node* NewMerge() { return NewNode(common()->Merge(1), true); }
|
|
|
|
Node* NewLoop() { return NewNode(common()->Loop(1), true); }
|
|
|
|
Node* NewBranch(Node* condition, BranchHint hint = BranchHint::kNone) {
|
|
|
|
return NewNode(common()->Branch(hint), condition);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Creates a new Phi node having {count} input values.
|
|
|
|
Node* NewPhi(int count, Node* input, Node* control);
|
|
|
|
Node* NewEffectPhi(int count, Node* input, Node* control);
|
2015-09-10 16:21:34 +00:00
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
// Helpers for merging control, effect or value dependencies.
|
2015-09-10 16:21:34 +00:00
|
|
|
Node* MergeControl(Node* control, Node* other);
|
2015-12-16 16:29:09 +00:00
|
|
|
Node* MergeEffect(Node* effect, Node* other_effect, Node* control);
|
|
|
|
Node* MergeValue(Node* value, Node* other_value, Node* control);
|
2015-09-10 16:21:34 +00:00
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
// The main node creation chokepoint. Adds context, frame state, effect,
|
|
|
|
// and control dependencies depending on the operator.
|
|
|
|
Node* MakeNode(const Operator* op, int value_input_count, Node** value_inputs,
|
|
|
|
bool incomplete);
|
2015-09-10 16:21:34 +00:00
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
// Helper to indicate a node exits the function body.
|
2015-09-10 16:21:34 +00:00
|
|
|
void UpdateControlDependencyToLeaveFunction(Node* exit);
|
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
Node** EnsureInputBufferSize(int size);
|
|
|
|
|
2015-11-20 09:25:13 +00:00
|
|
|
Node* ProcessCallArguments(const Operator* call_op, Node* callee,
|
2015-11-17 12:18:25 +00:00
|
|
|
interpreter::Register receiver, size_t arity);
|
2015-11-20 09:25:13 +00:00
|
|
|
Node* ProcessCallNewArguments(const Operator* call_new_op,
|
|
|
|
interpreter::Register callee,
|
|
|
|
interpreter::Register first_arg, size_t arity);
|
|
|
|
Node* ProcessCallRuntimeArguments(const Operator* call_runtime_op,
|
|
|
|
interpreter::Register first_arg,
|
|
|
|
size_t arity);
|
2015-11-17 12:18:25 +00:00
|
|
|
|
2015-12-09 11:53:07 +00:00
|
|
|
void BuildCreateLiteral(const Operator* op);
|
|
|
|
void BuildCreateRegExpLiteral(
|
|
|
|
const interpreter::BytecodeArrayIterator& iterator);
|
|
|
|
void BuildCreateArrayLiteral(
|
|
|
|
const interpreter::BytecodeArrayIterator& iterator);
|
|
|
|
void BuildCreateObjectLiteral(
|
|
|
|
const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-17 15:06:41 +00:00
|
|
|
void BuildLoadGlobal(const interpreter::BytecodeArrayIterator& iterator,
|
|
|
|
TypeofMode typeof_mode);
|
|
|
|
void BuildStoreGlobal(const interpreter::BytecodeArrayIterator& iterator);
|
|
|
|
void BuildNamedLoad(const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-19 14:16:36 +00:00
|
|
|
void BuildKeyedLoad(const interpreter::BytecodeArrayIterator& iterator);
|
|
|
|
void BuildNamedStore(const interpreter::BytecodeArrayIterator& iterator);
|
|
|
|
void BuildKeyedStore(const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-17 12:18:25 +00:00
|
|
|
void BuildCall(const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-17 15:06:41 +00:00
|
|
|
void BuildBinaryOp(const Operator* op,
|
|
|
|
const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-25 15:21:14 +00:00
|
|
|
void BuildCompareOp(const Operator* op,
|
|
|
|
const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-19 09:38:32 +00:00
|
|
|
void BuildDelete(const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-30 13:49:57 +00:00
|
|
|
void BuildCastOperator(const Operator* js_op,
|
|
|
|
const interpreter::BytecodeArrayIterator& iterator);
|
2015-11-17 12:18:25 +00:00
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
// Control flow plumbing.
|
|
|
|
void BuildJump(int source_offset, int target_offset);
|
|
|
|
void BuildJump();
|
|
|
|
void BuildConditionalJump(Node* condition);
|
|
|
|
|
|
|
|
// Helpers for building conditions for conditional jumps.
|
|
|
|
Node* BuildCondition(Node* comperand);
|
|
|
|
Node* BuildToBooleanCondition(Node* comperand);
|
|
|
|
|
|
|
|
// Constructing merge and loop headers.
|
|
|
|
void MergeEnvironmentsOfBackwardBranches(int source_offset,
|
|
|
|
int target_offset);
|
|
|
|
void MergeEnvironmentsOfForwardBranches(int source_offset);
|
|
|
|
void BuildLoopHeaderForBackwardBranches(int source_offset);
|
|
|
|
|
2015-09-10 16:21:34 +00:00
|
|
|
// Growth increment for the temporary buffer used to construct input lists to
|
|
|
|
// new nodes.
|
|
|
|
static const int kInputBufferSizeIncrement = 64;
|
|
|
|
|
|
|
|
// Field accessors
|
|
|
|
CommonOperatorBuilder* common() const { return jsgraph_->common(); }
|
|
|
|
Zone* graph_zone() const { return graph()->zone(); }
|
|
|
|
CompilationInfo* info() const { return info_; }
|
|
|
|
JSGraph* jsgraph() const { return jsgraph_; }
|
|
|
|
JSOperatorBuilder* javascript() const { return jsgraph_->javascript(); }
|
|
|
|
Zone* local_zone() const { return local_zone_; }
|
|
|
|
const Handle<BytecodeArray>& bytecode_array() const {
|
|
|
|
return bytecode_array_;
|
|
|
|
}
|
|
|
|
|
|
|
|
LanguageMode language_mode() const {
|
2015-11-17 09:05:37 +00:00
|
|
|
// TODO(mythria): Don't rely on parse information to get language mode.
|
|
|
|
return info()->language_mode();
|
2015-09-10 16:21:34 +00:00
|
|
|
}
|
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
const interpreter::BytecodeArrayIterator* bytecode_iterator() const {
|
|
|
|
return bytecode_iterator_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_bytecode_iterator(
|
|
|
|
const interpreter::BytecodeArrayIterator* bytecode_iterator) {
|
|
|
|
bytecode_iterator_ = bytecode_iterator;
|
|
|
|
}
|
|
|
|
|
|
|
|
const BytecodeBranchAnalysis* branch_analysis() const {
|
|
|
|
return branch_analysis_;
|
|
|
|
}
|
|
|
|
|
|
|
|
void set_branch_analysis(const BytecodeBranchAnalysis* branch_analysis) {
|
|
|
|
branch_analysis_ = branch_analysis;
|
|
|
|
}
|
|
|
|
|
2015-09-10 16:21:34 +00:00
|
|
|
#define DECLARE_VISIT_BYTECODE(name, ...) \
|
|
|
|
void Visit##name(const interpreter::BytecodeArrayIterator& iterator);
|
|
|
|
BYTECODE_LIST(DECLARE_VISIT_BYTECODE)
|
|
|
|
#undef DECLARE_VISIT_BYTECODE
|
|
|
|
|
|
|
|
Zone* local_zone_;
|
|
|
|
CompilationInfo* info_;
|
|
|
|
JSGraph* jsgraph_;
|
|
|
|
Handle<BytecodeArray> bytecode_array_;
|
2015-12-16 16:29:09 +00:00
|
|
|
const interpreter::BytecodeArrayIterator* bytecode_iterator_;
|
|
|
|
const BytecodeBranchAnalysis* branch_analysis_;
|
2015-09-10 16:21:34 +00:00
|
|
|
Environment* environment_;
|
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
// Merge environments are snapshots of the environment at a particular
|
|
|
|
// bytecode offset to be merged into a later environment.
|
|
|
|
ZoneMap<int, Environment*> merge_environments_;
|
|
|
|
|
|
|
|
// Loop header environments are environments created for bytecodes
|
|
|
|
// where it is known there are back branches, ie a loop header.
|
|
|
|
ZoneMap<int, Environment*> loop_header_environments_;
|
|
|
|
|
2015-09-10 16:21:34 +00:00
|
|
|
// Temporary storage for building node input lists.
|
|
|
|
int input_buffer_size_;
|
|
|
|
Node** input_buffer_;
|
|
|
|
|
|
|
|
// Nodes representing values in the activation record.
|
|
|
|
SetOncePointer<Node> function_context_;
|
2015-11-17 09:05:37 +00:00
|
|
|
SetOncePointer<Node> function_closure_;
|
2015-12-01 17:28:43 +00:00
|
|
|
SetOncePointer<Node> new_target_;
|
2015-11-17 09:05:37 +00:00
|
|
|
|
|
|
|
// Optimization to cache loaded feedback vector.
|
|
|
|
SetOncePointer<Node> feedback_vector_;
|
2015-09-10 16:21:34 +00:00
|
|
|
|
|
|
|
// Control nodes that exit the function body.
|
|
|
|
ZoneVector<Node*> exit_controls_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(BytecodeGraphBuilder);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
class BytecodeGraphBuilder::Environment : public ZoneObject {
|
|
|
|
public:
|
|
|
|
Environment(BytecodeGraphBuilder* builder, int register_count,
|
|
|
|
int parameter_count, Node* control_dependency, Node* context);
|
|
|
|
|
|
|
|
int parameter_count() const { return parameter_count_; }
|
|
|
|
int register_count() const { return register_count_; }
|
|
|
|
|
|
|
|
void BindRegister(interpreter::Register the_register, Node* node);
|
|
|
|
Node* LookupRegister(interpreter::Register the_register) const;
|
|
|
|
|
|
|
|
void BindAccumulator(Node* node);
|
|
|
|
Node* LookupAccumulator() const;
|
|
|
|
|
|
|
|
bool IsMarkedAsUnreachable() const;
|
|
|
|
void MarkAsUnreachable();
|
|
|
|
|
|
|
|
// Effect dependency tracked by this environment.
|
|
|
|
Node* GetEffectDependency() { return effect_dependency_; }
|
|
|
|
void UpdateEffectDependency(Node* dependency) {
|
|
|
|
effect_dependency_ = dependency;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Control dependency tracked by this environment.
|
|
|
|
Node* GetControlDependency() const { return control_dependency_; }
|
|
|
|
void UpdateControlDependency(Node* dependency) {
|
|
|
|
control_dependency_ = dependency;
|
|
|
|
}
|
|
|
|
|
|
|
|
Node* Context() const { return context_; }
|
2015-12-01 17:28:43 +00:00
|
|
|
void SetContext(Node* new_context) { context_ = new_context; }
|
2015-09-10 16:21:34 +00:00
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
Environment* CopyForConditional() const;
|
|
|
|
Environment* CopyForLoop();
|
|
|
|
void Merge(Environment* other);
|
|
|
|
|
2015-09-10 16:21:34 +00:00
|
|
|
private:
|
2015-12-16 16:29:09 +00:00
|
|
|
explicit Environment(const Environment* copy);
|
|
|
|
void PrepareForLoop();
|
2015-09-10 16:21:34 +00:00
|
|
|
|
2015-12-16 16:29:09 +00:00
|
|
|
int RegisterToValuesIndex(interpreter::Register the_register) const;
|
2015-09-10 16:21:34 +00:00
|
|
|
Zone* zone() const { return builder_->local_zone(); }
|
|
|
|
Graph* graph() const { return builder_->graph(); }
|
|
|
|
CommonOperatorBuilder* common() const { return builder_->common(); }
|
|
|
|
BytecodeGraphBuilder* builder() const { return builder_; }
|
|
|
|
const NodeVector* values() const { return &values_; }
|
|
|
|
NodeVector* values() { return &values_; }
|
|
|
|
Node* accumulator() { return accumulator_; }
|
|
|
|
int register_base() const { return register_base_; }
|
|
|
|
|
|
|
|
BytecodeGraphBuilder* builder_;
|
|
|
|
int register_count_;
|
|
|
|
int parameter_count_;
|
|
|
|
Node* accumulator_;
|
|
|
|
Node* context_;
|
|
|
|
Node* control_dependency_;
|
|
|
|
Node* effect_dependency_;
|
|
|
|
NodeVector values_;
|
|
|
|
int register_base_;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|
|
|
|
|
|
|
|
#endif // V8_COMPILER_BYTECODE_GRAPH_BUILDER_H_
|