Commit 2c418e1f by Ian Lance Taylor

escape: Add escape graph nodes.

    
    Introduces the nodes used to model connectivity in the escape graph
    and related state: a node's escape level and an encoding that will
    be added to import and export data.
    
    Reviewed-on: https://go-review.googlesource.com/18268

From-SVN: r235988
parent 5e5b938a
33f1d1d151721305ba37f3e23652d21310f868af 7f5a9fde801eb755a5252fd4ff588b0a47475bd3
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -4,9 +4,263 @@ ...@@ -4,9 +4,263 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include <limits>
#include <stack>
#include "gogo.h" #include "gogo.h"
#include "types.h"
#include "expressions.h"
#include "statements.h"
#include "escape.h" #include "escape.h"
// class Node.
// Return the node's type, if it makes sense for it to have one.
Type*
Node::type() const
{
if (this->object() != NULL
&& this->object()->is_variable())
return this->object()->var_value()->type();
else if (this->object() != NULL
&& this->object()->is_function())
return this->object()->func_value()->type();
else if (this->expr() != NULL)
return this->expr()->type();
else
return NULL;
}
// A helper for reporting; return this node's location.
Location
Node::location() const
{
if (this->object() != NULL && !this->object()->is_sink())
return this->object()->location();
else if (this->expr() != NULL)
return this->expr()->location();
else if (this->statement() != NULL)
return this->statement()->location();
else
return Linemap::unknown_location();
}
// Return this node's state, creating it if has not been initialized.
Node::Escape_state*
Node::state(Escape_context* context, Named_object* fn)
{
if (this->state_ == NULL)
{
if (this->expr() != NULL && this->expr()->var_expression() != NULL)
{
// Tie state of variable references to underlying variables.
Named_object* var_no = this->expr()->var_expression()->named_object();
Node* var_node = Node::make_node(var_no);
this->state_ = var_node->state(context, fn);
}
else
{
this->state_ = new Node::Escape_state;
if (fn == NULL)
fn = context->current_function();
this->state_->fn = fn;
}
}
go_assert(this->state_ != NULL);
return this->state_;
}
void
Node::set_encoding(int enc)
{
this->encoding_ = enc;
if (this->expr() != NULL
&& this->expr()->var_expression() != NULL)
{
// Set underlying object as well.
Named_object* no = this->expr()->var_expression()->named_object();
Node::make_node(no)->set_encoding(enc);
}
}
bool
Node::is_sink() const
{
if (this->object() != NULL
&& this->object()->is_sink())
return true;
else if (this->expr() != NULL
&& this->expr()->is_sink_expression())
return true;
return false;
}
std::map<Named_object*, Node*> Node::objects;
std::map<Expression*, Node*> Node::expressions;
std::map<Statement*, Node*> Node::statements;
// Make a object node or return a cached node for this object.
Node*
Node::make_node(Named_object* no)
{
if (Node::objects.find(no) != Node::objects.end())
return Node::objects[no];
Node* n = new Node(no);
std::pair<Named_object*, Node*> val(no, n);
Node::objects.insert(val);
return n;
}
// Make an expression node or return a cached node for this expression.
Node*
Node::make_node(Expression* e)
{
if (Node::expressions.find(e) != Node::expressions.end())
return Node::expressions[e];
Node* n = new Node(e);
std::pair<Expression*, Node*> val(e, n);
Node::expressions.insert(val);
return n;
}
// Make a statement node or return a cached node for this statement.
Node*
Node::make_node(Statement* s)
{
if (Node::statements.find(s) != Node::statements.end())
return Node::statements[s];
Node* n = new Node(s);
std::pair<Statement*, Node*> val(s, n);
Node::statements.insert(val);
return n;
}
// Returns the maximum of an exisiting escape value
// (and its additional parameter flow flags) and a new escape type.
int
Node::max_encoding(int e, int etype)
{
if ((e & ESCAPE_MASK) >= etype)
return e;
if (etype == Node::ESCAPE_NONE || etype == Node::ESCAPE_RETURN)
return (e & ~ESCAPE_MASK) | etype;
return etype;
}
// Return a modified encoding for an input parameter that flows into an
// output parameter.
// Class Escape_context.
Escape_context::Escape_context(Gogo* gogo, bool recursive)
: gogo_(gogo), current_function_(NULL), recursive_(recursive),
sink_(Node::make_node(Named_object::make_sink())), loop_depth_(0)
{
// The sink always escapes to heap and strictly lives outside of the
// current function i.e. loop_depth == -1.
this->sink_->set_encoding(Node::ESCAPE_HEAP);
Node::Escape_state* state = this->sink_->state(this, NULL);
state->loop_depth = -1;
}
// Initialize the dummy return values for this Node N using the results
// in FNTYPE.
void
Escape_context::init_retvals(Node* n, Function_type* fntype)
{
if (fntype == NULL || fntype->results() == NULL)
return;
Node::Escape_state* state = n->state(this, NULL);
Location loc = n->location();
int i = 0;
char buf[50];
for (Typed_identifier_list::const_iterator p = fntype->results()->begin();
p != fntype->results()->end();
++p, ++i)
{
snprintf(buf, sizeof buf, ".out%d", i);
Variable* dummy_var = new Variable(p->type(), NULL, false, false,
false, loc);
dummy_var->set_is_used();
Named_object* dummy_no =
Named_object::make_variable(buf, NULL, dummy_var);
Node* dummy_node = Node::make_node(dummy_no);
// Initialize the state of the dummy output node.
dummy_node->state(this, NULL);
// Add dummy node to the retvals of n.
state->retvals.push_back(dummy_node);
}
}
// Apply an indirection to N and return the result.
// This really only works if N is an expression node; it essentially becomes
// Node::make_node(n->expr()->deref()). We need the escape context to set the
// correct loop depth, however.
Node*
Escape_context::add_dereference(Node* n)
{
// Just return the original node if we can't add an indirection.
if (n->object() != NULL || n->statement() != NULL)
return n;
Node* ind = Node::make_node(n->expr()->deref());
// Initialize the state if this node doesn't already exist.
ind->state(this, NULL);
return ind;
}
void
Escape_context::track(Node* n)
{
n->set_encoding(Node::ESCAPE_NONE);
// Initialize this node's state if it hasn't been encountered
// before.
Node::Escape_state* state = n->state(this, NULL);
state->loop_depth = this->loop_depth_;
this->noesc_.push_back(n);
}
// Return the string representation of an escapement encoding.
std::string
Escape_note::make_tag(int encoding)
{
char buf[50];
snprintf(buf, sizeof buf, "esc:0x%x", encoding);
return buf;
}
// Return the escapement encoding for a string tag.
int
Escape_note::parse_tag(std::string* tag)
{
if (tag == NULL || tag->substr(0, 4) != "esc:")
return Node::ESCAPE_UNKNOWN;
int encoding = (int)strtol(tag->substr(4).c_str(), NULL, 0);
if (encoding == 0)
return Node::ESCAPE_UNKNOWN;
return encoding;
}
// Analyze the program flow for escape information. // Analyze the program flow for escape information.
void void
...@@ -21,7 +275,7 @@ Gogo::analyze_escape() ...@@ -21,7 +275,7 @@ Gogo::analyze_escape()
++p) ++p)
{ {
std::vector<Named_object*> stack = p->first; std::vector<Named_object*> stack = p->first;
Escape_context* context = new Escape_context(p->second); Escape_context* context = new Escape_context(this, p->second);
// Analyze the flow of each function; build the connection graph. // Analyze the flow of each function; build the connection graph.
// This is the assign phase. // This is the assign phase.
...@@ -33,13 +287,12 @@ Gogo::analyze_escape() ...@@ -33,13 +287,12 @@ Gogo::analyze_escape()
this->assign_connectivity(context, *fn); this->assign_connectivity(context, *fn);
} }
// TODO(cmang): Introduce escape node.
// Propagate levels across each dst. This is the flood phase. // Propagate levels across each dst. This is the flood phase.
// std::vector<Node*> dsts = context->dsts(); std::set<Node*> dsts = context->dsts();
// for (std::vector<Node*>::iterator n = dsts.begin(); for (std::set<Node*>::iterator n = dsts.begin();
// n != dsts.end(); n != dsts.end();
// ++n) ++n)
// this->propagate_escape(context, *n); this->propagate_escape(context, *n);
// Tag each exported function's parameters with escape information. // Tag each exported function's parameters with escape information.
for (std::vector<Named_object*>::iterator fn = stack.begin(); for (std::vector<Named_object*>::iterator fn = stack.begin();
...@@ -71,11 +324,10 @@ Gogo::assign_connectivity(Escape_context*, Named_object*) ...@@ -71,11 +324,10 @@ Gogo::assign_connectivity(Escape_context*, Named_object*)
// TODO(cmang): Analyze the current function's body. // TODO(cmang): Analyze the current function's body.
} }
// Propagate escape information across the nodes modeled in this Analysis_set, // Propagate escape information across the nodes modeled in this Analysis_set.
// TODO(cmang): Introduce escape analysis node.
void void
Gogo::propagate_escape(Escape_context*) Gogo::propagate_escape(Escape_context*, Node*)
{ {
// TODO(cmang): Do a breadth-first traversal of a node's upstream, adjusting // TODO(cmang): Do a breadth-first traversal of a node's upstream, adjusting
// the Level appropriately. // the Level appropriately.
......
...@@ -7,16 +7,324 @@ ...@@ -7,16 +7,324 @@
#ifndef GO_ESCAPE_H #ifndef GO_ESCAPE_H
#define GO_ESCAPE_H #define GO_ESCAPE_H
#include "gogo.h"
class Named_object; class Named_object;
class Expression;
class Statement;
class Escape_context;
// There can be loops in the escape graph that lead to arbitrary recursions.
// See comment in gc/esc.go.
static const int MIN_LEVEL = -2;
// Level models the escapement of a Node using two integers that are computed
// by backwards-analyzing the flow of a function from its sink and increasing or
// decreasing based on dereferences and addressing, respectively.
// One integer, known as the level's VALUE (think absolute value), is just the
// sum of indirections (via referencing or dereferencing) applied to the Node.
// The second, known as the level's SUFFIX_VALUE, is the amount of indirections
// applied after some data has been copied from the node. When accessing a
// field F of an object O and then applying indirections, for example, the field
// access O.F is assumed to copy that data from O before applying indirections.
// With this, even if O.F escapes, it might mean that the content of O escape,
// but not the object O itself.
class Level
{
public:
Level()
: value_(0), suffix_value_(0)
{ }
Level(int value, int suffix)
: value_(value), suffix_value_(suffix)
{ }
// Return this level's value.
int
value() const
{ return this->value_; }
// Return this level's suffix value.
int
suffix_value() const
{ return this->suffix_value_; }
// Increase the level because a node is referenced.
Level
increase() const
{
if (this->value_ <= MIN_LEVEL)
return Level(MIN_LEVEL, 0);
return Level(this->value_ + 1, this->suffix_value_ + 1);
}
// Decrease the level because a node is dereferenced.
Level
decrease() const
{
if (this->value_ <= MIN_LEVEL)
return Level(MIN_LEVEL, 0);
return Level(this->value_ - 1, this->suffix_value_ - 1);
}
// Model a node being copied.
Level
copy() const
{
return Level(this->value_, std::max(this->suffix_value_, 0));
}
// Return a level with the minimum values of this level and l.
Level
min(const Level& l) const
{
return Level(std::min(this->value_, l.value()),
std::min(this->suffix_value_, l.suffix_value()));
}
// Compare two levels for equality.
bool
operator==(const Level& l) const
{
return (this->value_ == l.value()
&& this->suffix_value_ == l.suffix_value());
}
// Create a level from an integer value.
static Level
From(int i)
{
if (i <= MIN_LEVEL)
return Level(MIN_LEVEL, 0);
return Level(i, 0);
}
private:
// The sum of all indirects (-1) and references (+1) applied to a Node.
int value_;
// The sum of all indirects (-1) abd references (+1) applied to a copied Node.
int suffix_value_;
};
// A node in the escape graph. This node is an alias to a particular node
// in the Go parse tree. Specifically, it can represent an expression node,
// a statement node, or a named object node (a variable or function).
class Node
{
public:
// This classification represents type of nodes in the Go parse tree that are
// interesting during the analysis.
enum Node_classification
{
NODE_OBJECT,
NODE_EXPRESSION,
NODE_STATEMENT
};
// The state necessary to keep track of how a node escapes.
struct Escape_state
{
// The current function.
Named_object* fn;
// A list of source nodes that flow into this node.
std::set<Node*> flows;
// If the node is a function call, the list of nodes returned.
std::vector<Node*> retvals;
// The node's loop depth.
int loop_depth;
// There is an extra loop depth in the flood phase used to account for
// variables referenced across closures. This is the maximum value of the
// extra loop depth seen during the flood that touches this node.
int max_extra_loop_depth;
// The node's level.
Level level;
// An ID given to a node when it is encountered as a flow from the current
// dst node. This is used to avoid infinite recursion of cyclic nodes.
int flood_id;
Escape_state()
: fn(NULL), loop_depth(0), max_extra_loop_depth(0), flood_id(0)
{ }
};
// Note: values in this enum appear in export data, and therefore MUST NOT
// change.
enum Escapement_encoding
{
ESCAPE_UNKNOWN,
// Does not escape to heap, result, or parameters.
ESCAPE_NONE,
// Is returned or reachable from a return statement.
ESCAPE_RETURN,
// Allocated in an inner loop, assigned to an outer loop,
// which allows construction of non-escaping but arbitrarily large linked
// data structures (i.e., not eligible for allocation in a fixed-size stack
// stack frame).
ESCAPE_SCOPE,
// Reachable from the heap.
ESCAPE_HEAP,
// By construction will not escape.
ESCAPE_NEVER
};
// Multiple constructors for each classification.
Node(Named_object* no)
: classification_(NODE_OBJECT), state_(NULL), encoding_(ESCAPE_UNKNOWN)
{ this->u_.object_val = no; }
Node(Expression* e)
: classification_(NODE_EXPRESSION), state_(NULL), encoding_(ESCAPE_UNKNOWN)
{ this->u_.expression_val = e; }
Node(Statement* s)
: classification_(NODE_STATEMENT), state_(NULL), encoding_(ESCAPE_UNKNOWN)
{ this->u_.statement_val = s; }
// Return this node's type.
Type*
type() const;
// Return this node's location.
Location
location() const;
// Return this node's escape state.
Escape_state*
state(Escape_context* context, Named_object* fn);
// Return this node's escape encoding.
int
encoding() const
{ return this->encoding_; }
// Set the node's escape encoding.
void
set_encoding(int enc);
// Is this node a sink?
bool
is_sink() const;
// Methods to return the underlying value in the Node union.
Named_object*
object() const
{
return (this->classification_ == NODE_OBJECT
? this->u_.object_val
: NULL);
}
Expression*
expr() const
{
return (this->classification_ == NODE_EXPRESSION
? this->u_.expression_val
: NULL);
}
Statement*
statement() const
{
return (this->classification_ == NODE_STATEMENT
? this->u_.statement_val
: NULL);
}
// Static creation methods for each value supported in the union.
static Node*
make_node(Named_object*);
static Node*
make_node(Expression*);
static Node*
make_node(Statement*);
// Return the maximum of an existing escape encoding E and a new
// escape type.
static int
max_encoding(int e, int etype);
private:
// The classification of this Node.
Node_classification classification_;
// The value union.
union
{
// If NODE_OBJECT.
Named_object* object_val;
// If NODE_EXPRESSION.
Expression* expression_val;
// If NODE_STATEMENT.
Statement* statement_val;
} u_;
// The node's escape state.
Escape_state* state_;
// The node's escape encoding.
// The encoding:
// | Return Encoding: (width - ESCAPE_RETURN_BITS) |
// | Content Escapes bit: 1 |
// | Escapement_encoding: ESCAPE_BITS |
int encoding_;
// Cache all the Nodes created via Node::make_node to make the API simpler.
static std::map<Named_object*, Node*> objects;
static std::map<Expression*, Node*> expressions;
static std::map<Statement*, Node*> statements;
};
// The amount of bits used for the escapement encoding.
static const int ESCAPE_BITS = 3;
// Mask used to extract encoding.
static const int ESCAPE_MASK = (1 << ESCAPE_BITS) - 1;
// Value obtained by indirect of parameter escapes to heap.
static const int ESCAPE_CONTENT_ESCAPES = 1 << ESCAPE_BITS;
// The amount of bits used in encoding of return values.
static const int ESCAPE_RETURN_BITS = ESCAPE_BITS + 1;
// For each output, the number of bits for a tag.
static const int ESCAPE_BITS_PER_OUTPUT_IN_TAG = 3;
// The bit max to extract a single tag.
static const int ESCAPE_BITS_MASK_FOR_TAG = (1 << ESCAPE_BITS_PER_OUTPUT_IN_TAG) - 1;
// The largest level that can be stored in a tag.
static const int ESCAPE_MAX_ENCODED_LEVEL = ESCAPE_BITS_MASK_FOR_TAG - 1;
// A helper for converting escape notes from encoded integers to a
// textual format and vice-versa.
class Escape_note
{
public:
// Return the string representation of an escapement encoding.
static std::string
make_tag(int encoding);
// Return the escapement encoding for a string tag.
static int
parse_tag(std::string* tag);
};
// The escape context for a set of functions being analyzed. // The escape context for a set of functions being analyzed.
class Escape_context class Escape_context
{ {
public: public:
Escape_context(bool recursive) Escape_context(Gogo* gogo, bool recursive);
: current_function_(NULL), recursive_(recursive)
{ } // Return the Go IR.
Gogo*
gogo() const
{ return this->gogo_; }
// Return the current function being analyzed. // Return the current function being analyzed.
Named_object* Named_object*
...@@ -33,12 +341,102 @@ class Escape_context ...@@ -33,12 +341,102 @@ class Escape_context
recursive() const recursive() const
{ return this->recursive_; } { return this->recursive_; }
// Return the special sink node for this context.
Node*
sink()
{ return this->sink_; }
// Return the current loop depth.
int
loop_depth() const
{ return this->loop_depth_; }
// Increase the loop depth.
void
increase_loop_depth()
{ this->loop_depth_++; }
// Decrease the loop depth.
void
decrease_loop_depth()
{ this->loop_depth_--; }
void
set_loop_depth(int depth)
{ this->loop_depth_ = depth; }
// Return the destination nodes encountered in this context.
const std::set<Node*>&
dsts() const
{ return this->dsts_; }
// Add a destination node.
void
add_dst(Node* dst)
{ this->dsts_.insert(dst); }
// Return the nodes initially marked as non-escaping before flooding.
const std::vector<Node*>&
non_escaping_nodes() const
{ return this->noesc_; }
// Initialize the dummy return values for this Node N using the results
// in FNTYPE.
void
init_retvals(Node* n, Function_type* fntype);
// Return the indirection of Node N.
Node*
add_dereference(Node* n);
// Keep track of possibly non-escaping node N.
void
track(Node* n);
int
flood_id() const
{ return this->flood_id_; }
void
increase_flood_id()
{ this->flood_id_++; }
int
pdepth() const
{ return this->pdepth_; }
void
increase_pdepth()
{ this->pdepth_++; }
void
decrease_pdepth()
{ this->pdepth_--; }
private: private:
// The Go IR.
Gogo* gogo_;
// The current function being analyzed. // The current function being analyzed.
Named_object* current_function_; Named_object* current_function_;
// Return whether this is the context for a recursive function or a group of mutually // Return whether this is the context for a recursive function or a group of mutually
// recursive functions. // recursive functions.
bool recursive_; bool recursive_;
// The sink for this escape context. Nodes whose reference objects created
// outside the current function are assigned to the sink as well as nodes that
// the analysis loses track of.
Node* sink_;
// Used to detect nested loop scopes.
int loop_depth_;
// All the destination nodes considered in this set of analyzed functions.
std::set<Node*> dsts_;
// All the nodes that were noted as possibly not escaping in this context.
std::vector<Node*> noesc_;
// An ID given to each dst and the flows discovered through DFS of that dst.
// This is used to avoid infinite recursion from nodes that point to each
// other within the flooding phase.
int flood_id_;
// The current level of recursion within a flooded section; used to debug.
int pdepth_;
}; };
#endif // !defined(GO_ESCAPE_H) #endif // !defined(GO_ESCAPE_H)
...@@ -51,6 +51,7 @@ class Bvariable; ...@@ -51,6 +51,7 @@ class Bvariable;
class Blabel; class Blabel;
class Bfunction; class Bfunction;
class Escape_context; class Escape_context;
class Node;
// This file declares the basic classes used to hold the internal // This file declares the basic classes used to hold the internal
// representation of Go which is built by the parser. // representation of Go which is built by the parser.
...@@ -570,7 +571,7 @@ class Gogo ...@@ -570,7 +571,7 @@ class Gogo
// Traverse the objects in the connecitivty graph from the sink, adjusting the // Traverse the objects in the connecitivty graph from the sink, adjusting the
// escape levels of each object. // escape levels of each object.
void void
propagate_escape(Escape_context*); propagate_escape(Escape_context*, Node*);
// Add notes about the escape level of a function's input and output // Add notes about the escape level of a function's input and output
// parameters for exporting and importing top level functions. // parameters for exporting and importing top level functions.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define GO_TYPES_H #define GO_TYPES_H
#include "go-linemap.h" #include "go-linemap.h"
#include "escape.h"
class Gogo; class Gogo;
class Package; class Package;
...@@ -1324,7 +1325,7 @@ class Typed_identifier ...@@ -1324,7 +1325,7 @@ class Typed_identifier
public: public:
Typed_identifier(const std::string& name, Type* type, Typed_identifier(const std::string& name, Type* type,
Location location) Location location)
: name_(name), type_(type), location_(location) : name_(name), type_(type), location_(location), note_(NULL)
{ } { }
// Get the name. // Get the name.
...@@ -1351,6 +1352,16 @@ class Typed_identifier ...@@ -1351,6 +1352,16 @@ class Typed_identifier
this->type_ = type; this->type_ = type;
} }
// Get the escape note.
std::string*
note() const
{ return this->note_; }
// Set the escape note.
void
set_note(const std::string& note)
{ this->note_ = new std::string(note); }
private: private:
// Identifier name. // Identifier name.
std::string name_; std::string name_;
...@@ -1358,6 +1369,9 @@ class Typed_identifier ...@@ -1358,6 +1369,9 @@ class Typed_identifier
Type* type_; Type* type_;
// The location where the name was seen. // The location where the name was seen.
Location location_; Location location_;
// Escape note for this typed identifier. Used when importing and exporting
// functions.
std::string* note_;
}; };
// A list of Typed_identifiers. // A list of Typed_identifiers.
...@@ -1422,6 +1436,10 @@ class Typed_identifier_list ...@@ -1422,6 +1436,10 @@ class Typed_identifier_list
back() const back() const
{ return this->entries_.back(); } { return this->entries_.back(); }
Typed_identifier&
at(size_t i)
{ return this->entries_.at(i); }
const Typed_identifier& const Typed_identifier&
at(size_t i) const at(size_t i) const
{ return this->entries_.at(i); } { return this->entries_.at(i); }
...@@ -1778,7 +1796,7 @@ class Function_type : public Type ...@@ -1778,7 +1796,7 @@ class Function_type : public Type
: Type(TYPE_FUNCTION), : Type(TYPE_FUNCTION),
receiver_(receiver), parameters_(parameters), results_(results), receiver_(receiver), parameters_(parameters), results_(results),
location_(location), is_varargs_(false), is_builtin_(false), location_(location), is_varargs_(false), is_builtin_(false),
fnbtype_(NULL) fnbtype_(NULL), is_tagged_(false)
{ } { }
// Get the receiver. // Get the receiver.
...@@ -1786,6 +1804,11 @@ class Function_type : public Type ...@@ -1786,6 +1804,11 @@ class Function_type : public Type
receiver() const receiver() const
{ return this->receiver_; } { return this->receiver_; }
// Add an escape note for the receiver.
void
add_receiver_note(int encoding)
{ this->receiver_->set_note(Escape_note::make_tag(encoding)); }
// Get the return names and types. // Get the return names and types.
const Typed_identifier_list* const Typed_identifier_list*
results() const results() const
...@@ -1796,6 +1819,21 @@ class Function_type : public Type ...@@ -1796,6 +1819,21 @@ class Function_type : public Type
parameters() const parameters() const
{ return this->parameters_; } { return this->parameters_; }
// Add an escape note for the ith parameter.
void
add_parameter_note(int index, int encoding)
{ this->parameters_->at(index).set_note(Escape_note::make_tag(encoding)); }
// Whether this function has been tagged during escape analysis.
bool
is_tagged() const
{ return this->is_tagged_; }
// Mark this function as tagged after analyzing its escape.
void
set_is_tagged()
{ this->is_tagged_ = true; }
// Whether this is a varargs function. // Whether this is a varargs function.
bool bool
is_varargs() const is_varargs() const
...@@ -1950,6 +1988,9 @@ class Function_type : public Type ...@@ -1950,6 +1988,9 @@ class Function_type : public Type
// The backend representation of this type for backend function // The backend representation of this type for backend function
// declarations and definitions. // declarations and definitions.
Btype* fnbtype_; Btype* fnbtype_;
// Whether this function has been analyzed by escape analysis. If this is
// TRUE, this function type's parameters contain a summary of the analysis.
bool is_tagged_;
}; };
// The type of a function's backend representation. // The type of a function's backend representation.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment