Index: src/compiler/node.h |
diff --git a/src/compiler/node.h b/src/compiler/node.h |
index 9d3a2b039135dd66c7c1cdbfe5a4486128d6496d..f8b3329d039216dc46cad97a8f114e11813d47e3 100644 |
--- a/src/compiler/node.h |
+++ b/src/compiler/node.h |
@@ -5,14 +5,9 @@ |
#ifndef V8_COMPILER_NODE_H_ |
#define V8_COMPILER_NODE_H_ |
-#include <deque> |
-#include <vector> |
- |
#include "src/compiler/opcodes.h" |
#include "src/compiler/operator.h" |
#include "src/types-inl.h" |
-#include "src/zone.h" |
-#include "src/zone-allocator.h" |
#include "src/zone-containers.h" |
namespace v8 { |
@@ -46,11 +41,11 @@ typedef int32_t NodeId; |
// by the Node's id. |
class Node FINAL { |
public: |
- bool IsDead() const { return InputCount() > 0 && InputAt(0) == NULL; } |
- void Kill(); |
+ static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count, |
+ Node** inputs, bool has_extensible_inputs); |
- void CollectProjections(ZoneVector<Node*>* projections); |
- Node* FindProjection(size_t projection_index); |
+ bool IsDead() const { return InputCount() > 0 && !InputAt(0); } |
+ void Kill(); |
const Operator* op() const { return op_; } |
void set_op(const Operator* op) { op_ = op; } |
@@ -64,25 +59,25 @@ class Node FINAL { |
int InputCount() const { return input_count(); } |
Node* InputAt(int index) const { return GetInputRecordPtr(index)->to; } |
- inline void ReplaceInput(int index, Node* new_input); |
- inline void AppendInput(Zone* zone, Node* new_input); |
- inline void InsertInput(Zone* zone, int index, Node* new_input); |
- inline void RemoveInput(int index); |
+ inline void ReplaceInput(int index, Node* new_to); |
+ void AppendInput(Zone* zone, Node* new_to); |
+ void InsertInput(Zone* zone, int index, Node* new_to); |
+ void RemoveInput(int index); |
+ void RemoveAllInputs(); |
+ void TrimInputCount(int new_input_count); |
int UseCount() const; |
Node* UseAt(int index) const; |
- inline void ReplaceUses(Node* replace_to); |
- template <class UnaryPredicate> |
- inline void ReplaceUsesIf(UnaryPredicate pred, Node* replace_to); |
- inline void RemoveAllInputs(); |
- |
- inline void TrimInputCount(int input_count); |
+ void ReplaceUses(Node* replace_to); |
- class InputEdges { |
+ class InputEdges FINAL { |
public: |
+ typedef Edge value_type; |
+ |
class iterator; |
- iterator begin() const; |
- iterator end() const; |
+ inline iterator begin() const; |
+ inline iterator end() const; |
+ |
bool empty() const; |
explicit InputEdges(Node* node) : node_(node) {} |
@@ -91,11 +86,16 @@ class Node FINAL { |
Node* node_; |
}; |
- class Inputs { |
+ InputEdges input_edges() { return InputEdges(this); } |
+ |
+ class Inputs FINAL { |
public: |
- class iterator; |
- iterator begin() const; |
- iterator end() const; |
+ typedef Node* value_type; |
+ |
+ class const_iterator; |
+ inline const_iterator begin() const; |
+ inline const_iterator end() const; |
+ |
bool empty() const; |
explicit Inputs(Node* node) : node_(node) {} |
@@ -105,13 +105,15 @@ class Node FINAL { |
}; |
Inputs inputs() { return Inputs(this); } |
- InputEdges input_edges() { return InputEdges(this); } |
- class UseEdges { |
+ class UseEdges FINAL { |
public: |
+ typedef Edge value_type; |
+ |
class iterator; |
- iterator begin() const; |
- iterator end() const; |
+ inline iterator begin() const; |
+ inline iterator end() const; |
+ |
bool empty() const; |
explicit UseEdges(Node* node) : node_(node) {} |
@@ -120,11 +122,16 @@ class Node FINAL { |
Node* node_; |
}; |
- class Uses { |
+ UseEdges use_edges() { return UseEdges(this); } |
+ |
+ class Uses FINAL { |
public: |
- class iterator; |
- iterator begin() const; |
- iterator end() const; |
+ typedef Node* value_type; |
+ |
+ class const_iterator; |
+ inline const_iterator begin() const; |
+ inline const_iterator end() const; |
+ |
bool empty() const; |
explicit Uses(Node* node) : node_(node) {} |
@@ -134,26 +141,21 @@ class Node FINAL { |
}; |
Uses uses() { return Uses(this); } |
- UseEdges use_edges() { return UseEdges(this); } |
- |
- bool OwnedBy(Node* owner) const; |
- static Node* New(Zone* zone, NodeId id, const Operator* op, int input_count, |
- Node** inputs, bool has_extensible_inputs); |
- |
- protected: |
- friend class Graph; |
- friend class Edge; |
+ // Returns true if {owner} is the user of {this} node. |
+ bool OwnedBy(Node* owner) const { |
+ return first_use_ && first_use_->from == owner && !first_use_->next; |
+ } |
- class Use : public ZoneObject { |
- public: |
+ private: |
+ struct Use FINAL : public ZoneObject { |
Node* from; |
Use* next; |
Use* prev; |
int input_index; |
}; |
- class Input { |
+ class Input FINAL { |
public: |
Node* to; |
Use* use; |
@@ -161,7 +163,10 @@ class Node FINAL { |
void Update(Node* new_to); |
}; |
- void EnsureAppendableInputs(Zone* zone); |
+ inline Node(NodeId id, const Operator* op, int input_count, |
+ int reserve_input_count); |
+ |
+ inline void EnsureAppendableInputs(Zone* zone); |
Input* GetInputRecordPtr(int index) const { |
if (has_appendable_inputs()) { |
@@ -171,20 +176,13 @@ class Node FINAL { |
} |
} |
- inline void AppendUse(Use* use); |
- inline void RemoveUse(Use* use); |
+ inline void AppendUse(Use* const use); |
+ inline void RemoveUse(Use* const use); |
void* operator new(size_t, void* location) { return location; } |
- private: |
- inline Node(NodeId id, const Operator* op, int input_count, |
- int reserve_input_count); |
- |
typedef ZoneDeque<Input> InputDeque; |
- friend class NodeMarkerBase; |
- friend class NodeProperties; |
- |
// Only NodeProperties should manipulate the bounds. |
Bounds bounds() { return bounds_; } |
void set_bounds(Bounds b) { bounds_ = b; } |
@@ -224,7 +222,7 @@ class Node FINAL { |
const Operator* op_; |
Bounds bounds_; |
Mark mark_; |
- NodeId id_; |
+ NodeId const id_; |
unsigned bit_field_; |
union { |
// When a node is initially allocated, it uses a static buffer to hold its |
@@ -237,20 +235,40 @@ class Node FINAL { |
Use* first_use_; |
Use* last_use_; |
+ friend class Edge; |
+ friend class NodeMarkerBase; |
+ friend class NodeProperties; |
+ |
DISALLOW_COPY_AND_ASSIGN(Node); |
}; |
+std::ostream& operator<<(std::ostream& os, const Node& n); |
+ |
+ |
+// Typedefs to shorten commonly used Node containers. |
+typedef ZoneDeque<Node*> NodeDeque; |
+typedef ZoneVector<Node*> NodeVector; |
+typedef ZoneVector<NodeVector> NodeVectorVector; |
+ |
+ |
+// Helper to extract parameters from Operator1<*> nodes. |
+template <typename T> |
+static inline const T& OpParameter(const Node* node) { |
+ return OpParameter<T>(node->op()); |
+} |
+ |
+ |
// An encapsulation for information associated with a single use of node as a |
// input from another node, allowing access to both the defining node and |
// the node having the input. |
-class Edge { |
+class Edge FINAL { |
public: |
Node* from() const { return input_->use->from; } |
Node* to() const { return input_->to; } |
int index() const { |
- int index = input_->use->input_index; |
- DCHECK(index < input_->use->from->input_count()); |
+ int const index = input_->use->input_index; |
+ DCHECK_LT(index, input_->use->from->input_count()); |
return index; |
} |
@@ -260,59 +278,51 @@ class Edge { |
void UpdateTo(Node* new_to) { input_->Update(new_to); } |
private: |
- friend class Node::Uses::iterator; |
- friend class Node::Inputs::iterator; |
friend class Node::UseEdges::iterator; |
friend class Node::InputEdges::iterator; |
- explicit Edge(Node::Input* input) : input_(input) {} |
+ explicit Edge(Node::Input* input) : input_(input) { DCHECK_NOT_NULL(input); } |
- Node::Input* input_; |
+ Node::Input* const input_; |
}; |
-// A forward iterator to visit the edges for the input dependencies of a node.. |
-class Node::InputEdges::iterator { |
+// A forward iterator to visit the edges for the input dependencies of a node. |
+class Node::InputEdges::iterator FINAL { |
public: |
typedef std::forward_iterator_tag iterator_category; |
typedef int difference_type; |
typedef Edge value_type; |
typedef Edge* pointer; |
typedef Edge& reference; |
- iterator(const Node::InputEdges::iterator& other) // NOLINT |
- : input_(other.input_) {} |
- iterator() : input_(NULL) {} |
+ |
+ iterator() : input_(nullptr) {} |
+ iterator(const iterator& other) : input_(other.input_) {} |
Edge operator*() const { return Edge(input_); } |
- bool operator==(const iterator& other) const { return Equals(other); } |
- bool operator!=(const iterator& other) const { return !Equals(other); } |
+ bool operator==(const iterator& other) const { |
+ return input_ == other.input_; |
+ } |
+ bool operator!=(const iterator& other) const { return !(*this == other); } |
iterator& operator++() { |
- DCHECK(input_ != NULL); |
- Edge edge(input_); |
- Node* from = edge.from(); |
- SetInput(from, input_->use->input_index + 1); |
+ SetInput(Edge(input_).from(), input_->use->input_index + 1); |
return *this; |
} |
- iterator operator++(int) { |
- iterator result(*this); |
- ++(*this); |
- return result; |
- } |
+ iterator operator++(int); |
private: |
friend class Node; |
- explicit iterator(Node* from, int index = 0) : input_(NULL) { |
+ explicit iterator(Node* from, int index = 0) : input_(nullptr) { |
SetInput(from, index); |
} |
- bool Equals(const iterator& other) const { return other.input_ == input_; } |
void SetInput(Node* from, int index) { |
DCHECK(index >= 0 && index <= from->InputCount()); |
if (index < from->InputCount()) { |
input_ = from->GetInputRecordPtr(index); |
} else { |
- input_ = NULL; |
+ input_ = nullptr; |
} |
} |
@@ -320,8 +330,18 @@ class Node::InputEdges::iterator { |
}; |
+Node::InputEdges::iterator Node::InputEdges::begin() const { |
+ return Node::InputEdges::iterator(this->node_, 0); |
+} |
+ |
+ |
+Node::InputEdges::iterator Node::InputEdges::end() const { |
+ return Node::InputEdges::iterator(this->node_, this->node_->InputCount()); |
+} |
+ |
+ |
// A forward iterator to visit the inputs of a node. |
-class Node::Inputs::iterator { |
+class Node::Inputs::const_iterator FINAL { |
public: |
typedef std::forward_iterator_tag iterator_category; |
typedef int difference_type; |
@@ -329,319 +349,133 @@ class Node::Inputs::iterator { |
typedef Node** pointer; |
typedef Node*& reference; |
- iterator(const Node::Inputs::iterator& other) // NOLINT |
- : iter_(other.iter_) {} |
+ const_iterator(const const_iterator& other) : iter_(other.iter_) {} |
Node* operator*() const { return (*iter_).to(); } |
- bool operator==(const iterator& other) const { return Equals(other); } |
- bool operator!=(const iterator& other) const { return !Equals(other); } |
- iterator& operator++() { |
+ bool operator==(const const_iterator& other) const { |
+ return iter_ == other.iter_; |
+ } |
+ bool operator!=(const const_iterator& other) const { |
+ return !(*this == other); |
+ } |
+ const_iterator& operator++() { |
++iter_; |
return *this; |
} |
- iterator operator++(int) { |
- iterator result(*this); |
- ++(*this); |
- return result; |
- } |
- |
+ const_iterator operator++(int); |
private: |
friend class Node::Inputs; |
- explicit iterator(Node* node, int index) : iter_(node, index) {} |
- |
- bool Equals(const iterator& other) const { return other.iter_ == iter_; } |
+ const_iterator(Node* node, int index) : iter_(node, index) {} |
Node::InputEdges::iterator iter_; |
}; |
+ |
+Node::Inputs::const_iterator Node::Inputs::begin() const { |
+ return const_iterator(this->node_, 0); |
+} |
+ |
+ |
+Node::Inputs::const_iterator Node::Inputs::end() const { |
+ return const_iterator(this->node_, this->node_->InputCount()); |
+} |
+ |
+ |
// A forward iterator to visit the uses edges of a node. The edges are returned |
// in |
// the order in which they were added as inputs. |
-class Node::UseEdges::iterator { |
+class Node::UseEdges::iterator FINAL { |
public: |
- iterator(const Node::UseEdges::iterator& other) // NOLINT |
- : current_(other.current_), |
- next_(other.next_) {} |
+ iterator(const iterator& other) |
+ : current_(other.current_), next_(other.next_) {} |
- Edge operator*() const { return Edge(CurrentInput()); } |
+ Edge operator*() const { |
+ return Edge(current_->from->GetInputRecordPtr(current_->input_index)); |
+ } |
- bool operator==(const iterator& other) { return Equals(other); } |
- bool operator!=(const iterator& other) { return !Equals(other); } |
+ bool operator==(const iterator& other) const { |
+ return current_ == other.current_; |
+ } |
+ bool operator!=(const iterator& other) const { return !(*this == other); } |
iterator& operator++() { |
- DCHECK(current_ != NULL); |
+ DCHECK_NOT_NULL(current_); |
current_ = next_; |
- next_ = (current_ == NULL) ? NULL : current_->next; |
+ next_ = current_ ? current_->next : nullptr; |
return *this; |
} |
- iterator operator++(int) { |
- iterator result(*this); |
- ++(*this); |
- return result; |
- } |
+ iterator operator++(int); |
private: |
friend class Node::UseEdges; |
- iterator() : current_(NULL), next_(NULL) {} |
+ iterator() : current_(nullptr), next_(nullptr) {} |
explicit iterator(Node* node) |
: current_(node->first_use_), |
- next_(current_ == NULL ? NULL : current_->next) {} |
- |
- bool Equals(const iterator& other) const { |
- return other.current_ == current_; |
- } |
- |
- Input* CurrentInput() const { |
- return current_->from->GetInputRecordPtr(current_->input_index); |
- } |
+ next_(current_ ? current_->next : nullptr) {} |
Node::Use* current_; |
Node::Use* next_; |
}; |
-// A forward iterator to visit the uses of a node. The uses are returned in |
-// the order in which they were added as inputs. |
-class Node::Uses::iterator { |
- public: |
- iterator(const Node::Uses::iterator& other) // NOLINT |
- : current_(other.current_) {} |
- |
- Node* operator*() { return current_->from; } |
- |
- bool operator==(const iterator& other) { return other.current_ == current_; } |
- bool operator!=(const iterator& other) { return other.current_ != current_; } |
- iterator& operator++() { |
- DCHECK(current_ != NULL); |
- current_ = current_->next; |
- return *this; |
- } |
- |
- private: |
- friend class Node::Uses; |
- |
- iterator() : current_(NULL) {} |
- explicit iterator(Node* node) : current_(node->first_use_) {} |
- |
- Input* CurrentInput() const { |
- return current_->from->GetInputRecordPtr(current_->input_index); |
- } |
- |
- Node::Use* current_; |
-}; |
- |
- |
-std::ostream& operator<<(std::ostream& os, const Node& n); |
- |
-typedef ZoneDeque<Node*> NodeDeque; |
- |
-typedef ZoneVector<Node*> NodeVector; |
-typedef NodeVector::iterator NodeVectorIter; |
-typedef NodeVector::const_iterator NodeVectorConstIter; |
-typedef NodeVector::reverse_iterator NodeVectorRIter; |
- |
-typedef ZoneVector<NodeVector> NodeVectorVector; |
-typedef NodeVectorVector::iterator NodeVectorVectorIter; |
-typedef NodeVectorVector::reverse_iterator NodeVectorVectorRIter; |
- |
-typedef Node::Uses::iterator UseIter; |
-typedef Node::Inputs::iterator InputIter; |
- |
-// Helper to extract parameters from Operator1<*> nodes. |
-template <typename T> |
-static inline const T& OpParameter(const Node* node) { |
- return OpParameter<T>(node->op()); |
-} |
- |
-inline Node::InputEdges::iterator Node::InputEdges::begin() const { |
- return Node::InputEdges::iterator(this->node_, 0); |
-} |
- |
-inline Node::InputEdges::iterator Node::InputEdges::end() const { |
- return Node::InputEdges::iterator(this->node_, this->node_->InputCount()); |
-} |
- |
-inline Node::Inputs::iterator Node::Inputs::begin() const { |
- return Node::Inputs::iterator(this->node_, 0); |
-} |
- |
-inline Node::Inputs::iterator Node::Inputs::end() const { |
- return Node::Inputs::iterator(this->node_, this->node_->InputCount()); |
-} |
- |
-inline Node::UseEdges::iterator Node::UseEdges::begin() const { |
+Node::UseEdges::iterator Node::UseEdges::begin() const { |
return Node::UseEdges::iterator(this->node_); |
} |
-inline Node::UseEdges::iterator Node::UseEdges::end() const { |
- return Node::UseEdges::iterator(); |
-} |
-inline Node::Uses::iterator Node::Uses::begin() const { |
- return Node::Uses::iterator(this->node_); |
+Node::UseEdges::iterator Node::UseEdges::end() const { |
+ return Node::UseEdges::iterator(); |
} |
-inline Node::Uses::iterator Node::Uses::end() const { |
- return Node::Uses::iterator(); |
-} |
-inline bool Node::InputEdges::empty() const { return begin() == end(); } |
-inline bool Node::Uses::empty() const { return begin() == end(); } |
-inline bool Node::UseEdges::empty() const { return begin() == end(); } |
-inline bool Node::Inputs::empty() const { return begin() == end(); } |
+// A forward iterator to visit the uses of a node. The uses are returned in |
+// the order in which they were added as inputs. |
+class Node::Uses::const_iterator FINAL { |
+ public: |
+ typedef std::forward_iterator_tag iterator_category; |
+ typedef int difference_type; |
+ typedef Node* value_type; |
+ typedef Node** pointer; |
+ typedef Node*& reference; |
-inline void Node::ReplaceUses(Node* replace_to) { |
- for (Use* use = first_use_; use != NULL; use = use->next) { |
- use->from->GetInputRecordPtr(use->input_index)->to = replace_to; |
- } |
- if (replace_to->last_use_ == NULL) { |
- DCHECK_EQ(NULL, replace_to->first_use_); |
- replace_to->first_use_ = first_use_; |
- replace_to->last_use_ = last_use_; |
- } else if (first_use_ != NULL) { |
- DCHECK_NE(NULL, replace_to->first_use_); |
- replace_to->last_use_->next = first_use_; |
- first_use_->prev = replace_to->last_use_; |
- replace_to->last_use_ = last_use_; |
- } |
- first_use_ = NULL; |
- last_use_ = NULL; |
-} |
+ const_iterator(const const_iterator& other) : current_(other.current_) {} |
-template <class UnaryPredicate> |
-inline void Node::ReplaceUsesIf(UnaryPredicate pred, Node* replace_to) { |
- for (Use* use = first_use_; use != NULL;) { |
- Use* next = use->next; |
- if (pred(use->from)) { |
- RemoveUse(use); |
- replace_to->AppendUse(use); |
- use->from->GetInputRecordPtr(use->input_index)->to = replace_to; |
- } |
- use = next; |
+ Node* operator*() const { return current_->from; } |
+ bool operator==(const const_iterator& other) const { |
+ return other.current_ == current_; |
} |
-} |
- |
-inline void Node::RemoveAllInputs() { |
- for (Edge edge : input_edges()) { |
- edge.UpdateTo(NULL); |
+ bool operator!=(const const_iterator& other) const { |
+ return other.current_ != current_; |
} |
-} |
- |
-inline void Node::TrimInputCount(int new_input_count) { |
- if (new_input_count == input_count()) return; // Nothing to do. |
- |
- DCHECK(new_input_count < input_count()); |
- |
- // Update inline inputs. |
- for (int i = new_input_count; i < input_count(); i++) { |
- Node::Input* input = GetInputRecordPtr(i); |
- input->Update(NULL); |
+ const_iterator& operator++() { |
+ DCHECK_NOT_NULL(current_); |
+ current_ = current_->next; |
+ return *this; |
} |
- set_input_count(new_input_count); |
-} |
+ const_iterator operator++(int); |
-inline void Node::ReplaceInput(int index, Node* new_to) { |
- Input* input = GetInputRecordPtr(index); |
- input->Update(new_to); |
-} |
+ private: |
+ friend class Node::Uses; |
-inline void Node::Input::Update(Node* new_to) { |
- Node* old_to = this->to; |
- if (new_to == old_to) return; // Nothing to do. |
- // Snip out the use from where it used to be |
- if (old_to != NULL) { |
- old_to->RemoveUse(use); |
- } |
- to = new_to; |
- // And put it into the new node's use list. |
- if (new_to != NULL) { |
- new_to->AppendUse(use); |
- } else { |
- use->next = NULL; |
- use->prev = NULL; |
- } |
-} |
+ const_iterator() : current_(nullptr) {} |
+ explicit const_iterator(Node* node) : current_(node->first_use_) {} |
-inline void Node::EnsureAppendableInputs(Zone* zone) { |
- if (!has_appendable_inputs()) { |
- void* deque_buffer = zone->New(sizeof(InputDeque)); |
- InputDeque* deque = new (deque_buffer) InputDeque(zone); |
- for (int i = 0; i < input_count(); ++i) { |
- deque->push_back(inputs_.static_[i]); |
- } |
- inputs_.appendable_ = deque; |
- set_has_appendable_inputs(true); |
- } |
-} |
+ Node::Use* current_; |
+}; |
-inline void Node::AppendInput(Zone* zone, Node* to_append) { |
- Use* new_use = new (zone) Use; |
- Input new_input; |
- new_input.to = to_append; |
- new_input.use = new_use; |
- if (reserved_input_count() > 0) { |
- DCHECK(!has_appendable_inputs()); |
- set_reserved_input_count(reserved_input_count() - 1); |
- inputs_.static_[input_count()] = new_input; |
- } else { |
- EnsureAppendableInputs(zone); |
- inputs_.appendable_->push_back(new_input); |
- } |
- new_use->input_index = input_count(); |
- new_use->from = this; |
- to_append->AppendUse(new_use); |
- set_input_count(input_count() + 1); |
-} |
-inline void Node::InsertInput(Zone* zone, int index, Node* to_insert) { |
- DCHECK(index >= 0 && index < InputCount()); |
- // TODO(turbofan): Optimize this implementation! |
- AppendInput(zone, InputAt(InputCount() - 1)); |
- for (int i = InputCount() - 1; i > index; --i) { |
- ReplaceInput(i, InputAt(i - 1)); |
- } |
- ReplaceInput(index, to_insert); |
+Node::Uses::const_iterator Node::Uses::begin() const { |
+ return const_iterator(this->node_); |
} |
-inline void Node::RemoveInput(int index) { |
- DCHECK(index >= 0 && index < InputCount()); |
- // TODO(turbofan): Optimize this implementation! |
- for (; index < InputCount() - 1; ++index) { |
- ReplaceInput(index, InputAt(index + 1)); |
- } |
- TrimInputCount(InputCount() - 1); |
-} |
-inline void Node::AppendUse(Use* use) { |
- use->next = NULL; |
- use->prev = last_use_; |
- if (last_use_ == NULL) { |
- first_use_ = use; |
- } else { |
- last_use_->next = use; |
- } |
- last_use_ = use; |
-} |
+Node::Uses::const_iterator Node::Uses::end() const { return const_iterator(); } |
-inline void Node::RemoveUse(Use* use) { |
- if (last_use_ == use) { |
- last_use_ = use->prev; |
- } |
- if (use->prev != NULL) { |
- use->prev->next = use->next; |
- } else { |
- first_use_ = use->next; |
- } |
- if (use->next != NULL) { |
- use->next->prev = use->prev; |
- } |
-} |
-inline bool Node::OwnedBy(Node* owner) const { |
- return first_use_ != NULL && first_use_->from == owner && |
- first_use_->next == NULL; |
+void Node::ReplaceInput(int index, Node* new_to) { |
+ GetInputRecordPtr(index)->Update(new_to); |
} |
} // namespace compiler |