Index: src/compiler/structured-machine-assembler.h |
diff --git a/src/compiler/structured-machine-assembler.h b/src/compiler/structured-machine-assembler.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..383c3af56d4fc53f73d7e01e09172162e2d34f23 |
--- /dev/null |
+++ b/src/compiler/structured-machine-assembler.h |
@@ -0,0 +1,312 @@ |
+// Copyright 2014 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_STRUCTURED_MACHINE_ASSEMBLER_H_ |
+#define V8_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_ |
+ |
+#include "src/v8.h" |
+ |
+#include "src/compiler/common-operator.h" |
+#include "src/compiler/graph-builder.h" |
+#include "src/compiler/machine-node-factory.h" |
+#include "src/compiler/machine-operator.h" |
+#include "src/compiler/node.h" |
+#include "src/compiler/operator.h" |
+ |
+ |
+namespace v8 { |
+namespace internal { |
+namespace compiler { |
+ |
+class BasicBlock; |
+class Schedule; |
+class StructuredMachineAssembler; |
+ |
+ |
+class Variable : public ZoneObject { |
+ public: |
+ Node* Get() const; |
+ void Set(Node* value) const; |
+ |
+ private: |
+ Variable(StructuredMachineAssembler* smasm, int offset) |
+ : smasm_(smasm), offset_(offset) {} |
+ |
+ friend class StructuredMachineAssembler; |
+ friend class StructuredMachineAssemblerFriend; |
+ StructuredMachineAssembler* const smasm_; |
+ const int offset_; |
+}; |
+ |
+ |
+class StructuredMachineAssembler |
+ : public GraphBuilder, |
+ public MachineNodeFactory<StructuredMachineAssembler> { |
+ public: |
+ class Environment : public ZoneObject { |
+ public: |
+ Environment(Zone* zone, BasicBlock* block, bool is_dead_); |
+ |
+ private: |
+ BasicBlock* block_; |
+ NodeVector variables_; |
+ bool is_dead_; |
+ friend class StructuredMachineAssembler; |
+ DISALLOW_COPY_AND_ASSIGN(Environment); |
+ }; |
+ |
+ class IfBuilder; |
+ friend class IfBuilder; |
+ class LoopBuilder; |
+ friend class LoopBuilder; |
+ |
+ StructuredMachineAssembler( |
+ Graph* graph, MachineCallDescriptorBuilder* call_descriptor_builder, |
+ MachineRepresentation word = MachineOperatorBuilder::pointer_rep()); |
+ virtual ~StructuredMachineAssembler() {} |
+ |
+ Isolate* isolate() const { return zone()->isolate(); } |
+ Zone* zone() const { return graph()->zone(); } |
+ MachineOperatorBuilder* machine() { return &machine_; } |
+ CommonOperatorBuilder* common() { return &common_; } |
+ CallDescriptor* call_descriptor() const { |
+ return call_descriptor_builder_->BuildCallDescriptor(zone()); |
+ } |
+ int parameter_count() const { |
+ return call_descriptor_builder_->parameter_count(); |
+ } |
+ const MachineRepresentation* parameter_types() const { |
+ return call_descriptor_builder_->parameter_types(); |
+ } |
+ |
+ // Parameters. |
+ Node* Parameter(int index); |
+ // Variables. |
+ Variable NewVariable(Node* initial_value); |
+ // Control flow. |
+ void Return(Node* value); |
+ |
+ // MachineAssembler is invalid after export. |
+ Schedule* Export(); |
+ |
+ protected: |
+ virtual Node* MakeNode(Operator* op, int input_count, Node** inputs); |
+ |
+ Schedule* schedule() { |
+ ASSERT(ScheduleValid()); |
+ return schedule_; |
+ } |
+ |
+ private: |
+ bool ScheduleValid() { return schedule_ != NULL; } |
+ |
+ typedef std::vector<Environment*, zone_allocator<Environment*> > |
+ EnvironmentVector; |
+ |
+ NodeVector* CurrentVars() { return ¤t_environment_->variables_; } |
+ Node*& VariableAt(Environment* environment, int offset); |
+ Node* GetVariable(int offset); |
+ void SetVariable(int offset, Node* value); |
+ |
+ void AddBranch(Environment* environment, Node* condition, |
+ Environment* true_val, Environment* false_val); |
+ void AddGoto(Environment* from, Environment* to); |
+ BasicBlock* TrampolineFor(BasicBlock* block); |
+ |
+ void CopyCurrentAsDead(); |
+ Environment* Copy(Environment* environment) { |
+ return Copy(environment, static_cast<int>(environment->variables_.size())); |
+ } |
+ Environment* Copy(Environment* environment, int truncate_at); |
+ void Merge(EnvironmentVector* environments, int truncate_at); |
+ Environment* CopyForLoopHeader(Environment* environment); |
+ void MergeBackEdgesToLoopHeader(Environment* header, |
+ EnvironmentVector* environments); |
+ |
+ typedef std::vector<MachineRepresentation, |
+ zone_allocator<MachineRepresentation> > |
+ RepresentationVector; |
+ |
+ Schedule* schedule_; |
+ MachineOperatorBuilder machine_; |
+ CommonOperatorBuilder common_; |
+ MachineCallDescriptorBuilder* call_descriptor_builder_; |
+ Node** parameters_; |
+ Environment* current_environment_; |
+ int number_of_variables_; |
+ |
+ friend class Variable; |
+ // For testing only. |
+ friend class StructuredMachineAssemblerFriend; |
+ DISALLOW_COPY_AND_ASSIGN(StructuredMachineAssembler); |
+}; |
+ |
+// IfBuilder constructs of nested if-else expressions which more or less follow |
+// C semantics. Foe example: |
+// |
+// if (x) {do_x} else if (y) {do_y} else {do_z} |
+// |
+// would look like this: |
+// |
+// IfBuilder b; |
+// b.If(x).Then(); |
+// do_x |
+// b.Else(); |
+// b.If().Then(); |
+// do_y |
+// b.Else(); |
+// do_z |
+// b.End(); |
+// |
+// Then() and Else() can be skipped, representing an empty block in C. |
+// Combinations like If(x).Then().If(x).Then() are legitimate, but |
+// Else().Else() is not. That is, once you've nested an If(), you can't get to a |
+// higher level If() branch. |
+// TODO(dcarney): describe expressions once the api is finalized. |
+class StructuredMachineAssembler::IfBuilder { |
+ public: |
+ explicit IfBuilder(StructuredMachineAssembler* smasm); |
+ ~IfBuilder() { |
+ if (!IsDone()) End(); |
+ } |
+ |
+ IfBuilder& If(); // TODO(dcarney): this should take an expression. |
+ IfBuilder& If(Node* condition); |
+ void Then(); |
+ void Else(); |
+ void End(); |
+ |
+ // The next 4 functions are exposed for expression support. |
+ // They will be private once I have a nice expression api. |
+ void And(); |
+ void Or(); |
+ IfBuilder& OpenParen() { |
+ ASSERT(smasm_->current_environment_ != NULL); |
+ CurrentClause()->PushNewExpressionState(); |
+ return *this; |
+ } |
+ IfBuilder& CloseParen() { |
+ ASSERT(smasm_->current_environment_ == NULL); |
+ CurrentClause()->PopExpressionState(); |
+ return *this; |
+ } |
+ |
+ private: |
+ // UnresolvedBranch represents the chain of environments created while |
+ // generating an expression. At this point, a branch Node |
+ // cannot be created, as the target environments of the branch are not yet |
+ // available, so everything required to create the branch Node is |
+ // stored in this structure until the target environments are resolved. |
+ struct UnresolvedBranch : public ZoneObject { |
+ UnresolvedBranch(Environment* environment, Node* condition, |
+ UnresolvedBranch* next) |
+ : environment_(environment), condition_(condition), next_(next) {} |
+ // environment_ will eventually be terminated by a branch on condition_. |
+ Environment* environment_; |
+ Node* condition_; |
+ // next_ is the next link in the UnresolvedBranch chain, and will be |
+ // either the true or false branch jumped to from environment_. |
+ UnresolvedBranch* next_; |
+ }; |
+ |
+ struct ExpressionState { |
+ int pending_then_size_; |
+ int pending_else_size_; |
+ }; |
+ |
+ typedef std::vector<ExpressionState, zone_allocator<ExpressionState> > |
+ ExpressionStates; |
+ typedef std::vector<UnresolvedBranch*, zone_allocator<UnresolvedBranch*> > |
+ PendingMergeStack; |
+ struct IfClause; |
+ typedef std::vector<IfClause*, zone_allocator<IfClause*> > IfClauses; |
+ |
+ struct PendingMergeStackRange { |
+ PendingMergeStack* merge_stack_; |
+ int start_; |
+ int size_; |
+ }; |
+ |
+ enum CombineType { kCombineThen, kCombineElse }; |
+ enum ResolutionType { kExpressionTerm, kExpressionDone }; |
+ |
+ // IfClause represents one level of if-then-else nesting plus the associated |
+ // expression. |
+ // A call to If() triggers creation of a new nesting level after expression |
+ // creation is complete - ie Then() or Else() has been called. |
+ struct IfClause : public ZoneObject { |
+ IfClause(Zone* zone, int initial_environment_size); |
+ void CopyEnvironments(const PendingMergeStackRange& data, |
+ EnvironmentVector* environments); |
+ void ResolvePendingMerges(StructuredMachineAssembler* smasm, |
+ CombineType combine_type, |
+ ResolutionType resolution_type); |
+ PendingMergeStackRange ComputeRelevantMerges(CombineType combine_type); |
+ void FinalizeBranches(StructuredMachineAssembler* smasm, |
+ const PendingMergeStackRange& offset_data, |
+ CombineType combine_type, |
+ Environment* then_environment, |
+ Environment* else_environment); |
+ void PushNewExpressionState(); |
+ void PopExpressionState(); |
+ |
+ // Each invocation of And or Or creates a new UnresolvedBranch. |
+ // These form a singly-linked list, of which we only need to keep track of |
+ // the tail. On creation of an UnresolvedBranch, pending_then_merges_ and |
+ // pending_else_merges_ each push a copy, which are removed on merges to the |
+ // respective environment. |
+ UnresolvedBranch* unresolved_list_tail_; |
+ int initial_environment_size_; |
+ // expression_states_ keeps track of the state of pending_*_merges_, |
+ // pushing and popping the lengths of these on |
+ // OpenParend() and CloseParend() respectively. |
+ ExpressionStates expression_states_; |
+ PendingMergeStack pending_then_merges_; |
+ PendingMergeStack pending_else_merges_; |
+ // then_environment_ is created iff there is a call to Then(), otherwise |
+ // branches which would merge to it merge to the exit environment instead. |
+ // Likewise for else_environment_. |
+ Environment* then_environment_; |
+ Environment* else_environment_; |
+ }; |
+ |
+ IfClause* CurrentClause() { return if_clauses_.back(); } |
+ void AddCurrentToPending(); |
+ void PushNewIfClause(); |
+ bool IsDone() { return if_clauses_.empty(); } |
+ |
+ StructuredMachineAssembler* smasm_; |
+ IfClauses if_clauses_; |
+ EnvironmentVector pending_exit_merges_; |
+ DISALLOW_COPY_AND_ASSIGN(IfBuilder); |
+}; |
+ |
+ |
+class StructuredMachineAssembler::LoopBuilder { |
+ public: |
+ explicit LoopBuilder(StructuredMachineAssembler* smasm); |
+ ~LoopBuilder() { |
+ if (!IsDone()) End(); |
+ } |
+ |
+ void Break(); |
+ void Continue(); |
+ void End(); |
+ |
+ private: |
+ friend class StructuredMachineAssembler; |
+ bool IsDone() { return header_environment_ == NULL; } |
+ |
+ StructuredMachineAssembler* smasm_; |
+ Environment* header_environment_; |
+ EnvironmentVector pending_header_merges_; |
+ EnvironmentVector pending_exit_merges_; |
+ DISALLOW_COPY_AND_ASSIGN(LoopBuilder); |
+}; |
+ |
+} // namespace compiler |
+} // namespace internal |
+} // namespace v8 |
+ |
+#endif // V8_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_ |