// 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_CCTEST_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_ #define V8_CCTEST_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 { 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, MachineSignature* machine_sig, MachineType word = kMachPtr); 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_; } size_t parameter_count() const { return machine_sig_->parameter_count(); } MachineSignature* machine_sig() const { return machine_sig_; } // Parameters. Node* Parameter(size_t 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() { DCHECK(ScheduleValid()); return schedule_; } private: bool ScheduleValid() { return schedule_ != NULL; } typedef ZoneVector 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(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); Schedule* schedule_; MachineOperatorBuilder machine_; CommonOperatorBuilder common_; MachineSignature* machine_sig_; CallDescriptor* call_descriptor_; 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() { DCHECK(smasm_->current_environment_ != NULL); CurrentClause()->PushNewExpressionState(); return *this; } IfBuilder& CloseParen() { DCHECK(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 ZoneVector ExpressionStates; typedef ZoneVector PendingMergeStack; struct IfClause; typedef ZoneVector 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_CCTEST_COMPILER_STRUCTURED_MACHINE_ASSEMBLER_H_