mirror of git://gcc.gnu.org/git/gcc.git
compiler, runtime: Track fields with tag go:"track".
* go-gcc.cc: Include "output.h". (global_variable): Add is_unique_section parameter. (global_variable_set_init): Adjust unique section if necessary. * Make-lang.in (go/go-gcc.o): Add dependency on output.h. From-SVN: r193945
This commit is contained in:
parent
53750ab003
commit
744c3195ef
|
|
@ -1,3 +1,10 @@
|
||||||
|
2012-11-29 Ian Lance Taylor <iant@google.com>
|
||||||
|
|
||||||
|
* go-gcc.cc: Include "output.h".
|
||||||
|
(global_variable): Add is_unique_section parameter.
|
||||||
|
(global_variable_set_init): Adjust unique section if necessary.
|
||||||
|
* Make-lang.in (go/go-gcc.o): Add dependency on output.h.
|
||||||
|
|
||||||
2012-11-17 Diego Novillo <dnovillo@google.com>
|
2012-11-17 Diego Novillo <dnovillo@google.com>
|
||||||
|
|
||||||
Adjust for new vec API (http://gcc.gnu.org/wiki/cxx-conversion/cxx-vec)
|
Adjust for new vec API (http://gcc.gnu.org/wiki/cxx-conversion/cxx-vec)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend.
|
# Make-lang.in -- Top level -*- makefile -*- fragment for gcc Go frontend.
|
||||||
|
|
||||||
# Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
|
# Copyright (C) 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
|
||||||
|
|
||||||
# This file is part of GCC.
|
# This file is part of GCC.
|
||||||
|
|
||||||
|
|
@ -254,7 +254,7 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
|
||||||
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
|
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
|
||||||
|
|
||||||
go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
|
go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
|
||||||
$(GIMPLE_H) toplev.h $(GO_C_H) $(GO_GOGO_H) \
|
$(GIMPLE_H) toplev.h output.h $(GO_C_H) $(GO_GOGO_H) \
|
||||||
go/gofrontend/backend.h
|
go/gofrontend/backend.h
|
||||||
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
|
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@
|
||||||
#include "tree-iterator.h"
|
#include "tree-iterator.h"
|
||||||
#include "gimple.h"
|
#include "gimple.h"
|
||||||
#include "toplev.h"
|
#include "toplev.h"
|
||||||
|
#include "output.h"
|
||||||
|
|
||||||
#include "go-c.h"
|
#include "go-c.h"
|
||||||
|
|
||||||
|
|
@ -267,6 +268,7 @@ class Gcc_backend : public Backend
|
||||||
Btype* btype,
|
Btype* btype,
|
||||||
bool is_external,
|
bool is_external,
|
||||||
bool is_hidden,
|
bool is_hidden,
|
||||||
|
bool in_unique_section,
|
||||||
Location location);
|
Location location);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1277,6 +1279,7 @@ Gcc_backend::global_variable(const std::string& package_name,
|
||||||
Btype* btype,
|
Btype* btype,
|
||||||
bool is_external,
|
bool is_external,
|
||||||
bool is_hidden,
|
bool is_hidden,
|
||||||
|
bool in_unique_section,
|
||||||
Location location)
|
Location location)
|
||||||
{
|
{
|
||||||
tree type_tree = btype->get_tree();
|
tree type_tree = btype->get_tree();
|
||||||
|
|
@ -1308,6 +1311,9 @@ Gcc_backend::global_variable(const std::string& package_name,
|
||||||
}
|
}
|
||||||
TREE_USED(decl) = 1;
|
TREE_USED(decl) = 1;
|
||||||
|
|
||||||
|
if (in_unique_section)
|
||||||
|
resolve_unique_section (decl, 0, 1);
|
||||||
|
|
||||||
go_preserve_from_gc(decl);
|
go_preserve_from_gc(decl);
|
||||||
|
|
||||||
return new Bvariable(decl);
|
return new Bvariable(decl);
|
||||||
|
|
@ -1326,6 +1332,16 @@ Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr)
|
||||||
if (var_decl == error_mark_node)
|
if (var_decl == error_mark_node)
|
||||||
return;
|
return;
|
||||||
DECL_INITIAL(var_decl) = expr_tree;
|
DECL_INITIAL(var_decl) = expr_tree;
|
||||||
|
|
||||||
|
// If this variable goes in a unique section, it may need to go into
|
||||||
|
// a different one now that DECL_INITIAL is set.
|
||||||
|
if (DECL_HAS_IMPLICIT_SECTION_NAME_P (var_decl))
|
||||||
|
{
|
||||||
|
DECL_SECTION_NAME (var_decl) = NULL_TREE;
|
||||||
|
resolve_unique_section (var_decl,
|
||||||
|
compute_reloc_for_constant (expr_tree),
|
||||||
|
1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a local variable.
|
// Make a local variable.
|
||||||
|
|
|
||||||
|
|
@ -326,8 +326,11 @@ class Backend
|
||||||
// option. NAME is the name of the variable. BTYPE is the type of
|
// option. NAME is the name of the variable. BTYPE is the type of
|
||||||
// the variable. IS_EXTERNAL is true if the variable is defined in
|
// the variable. IS_EXTERNAL is true if the variable is defined in
|
||||||
// some other package. IS_HIDDEN is true if the variable is not
|
// some other package. IS_HIDDEN is true if the variable is not
|
||||||
// exported (name begins with a lower case letter). LOCATION is
|
// exported (name begins with a lower case letter).
|
||||||
// where the variable was defined.
|
// IN_UNIQUE_SECTION is true if the variable should be put into a
|
||||||
|
// unique section if possible; this is intended to permit the linker
|
||||||
|
// to garbage collect the variable if it is not referenced.
|
||||||
|
// LOCATION is where the variable was defined.
|
||||||
virtual Bvariable*
|
virtual Bvariable*
|
||||||
global_variable(const std::string& package_name,
|
global_variable(const std::string& package_name,
|
||||||
const std::string& pkgpath,
|
const std::string& pkgpath,
|
||||||
|
|
@ -335,6 +338,7 @@ class Backend
|
||||||
Btype* btype,
|
Btype* btype,
|
||||||
bool is_external,
|
bool is_external,
|
||||||
bool is_hidden,
|
bool is_hidden,
|
||||||
|
bool in_unique_section,
|
||||||
Location location) = 0;
|
Location location) = 0;
|
||||||
|
|
||||||
// A global variable will 1) be initialized to zero, or 2) be
|
// A global variable will 1) be initialized to zero, or 2) be
|
||||||
|
|
|
||||||
|
|
@ -10580,6 +10580,102 @@ Expression::make_map_index(Expression* map, Expression* index,
|
||||||
|
|
||||||
// Class Field_reference_expression.
|
// Class Field_reference_expression.
|
||||||
|
|
||||||
|
// Lower a field reference expression. There is nothing to lower, but
|
||||||
|
// this is where we generate the tracking information for fields with
|
||||||
|
// the magic go:"track" tag.
|
||||||
|
|
||||||
|
Expression*
|
||||||
|
Field_reference_expression::do_lower(Gogo* gogo, Named_object* function,
|
||||||
|
Statement_inserter* inserter, int)
|
||||||
|
{
|
||||||
|
Struct_type* struct_type = this->expr_->type()->struct_type();
|
||||||
|
if (struct_type == NULL)
|
||||||
|
{
|
||||||
|
// Error will be reported elsewhere.
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
const Struct_field* field = struct_type->field(this->field_index_);
|
||||||
|
if (field == NULL)
|
||||||
|
return this;
|
||||||
|
if (!field->has_tag())
|
||||||
|
return this;
|
||||||
|
if (field->tag().find("go:\"track\"") == std::string::npos)
|
||||||
|
return this;
|
||||||
|
|
||||||
|
// We have found a reference to a tracked field. Build a call to
|
||||||
|
// the runtime function __go_fieldtrack with a string that describes
|
||||||
|
// the field. FIXME: We should only call this once per referenced
|
||||||
|
// field per function, not once for each reference to the field.
|
||||||
|
|
||||||
|
if (this->called_fieldtrack_)
|
||||||
|
return this;
|
||||||
|
this->called_fieldtrack_ = true;
|
||||||
|
|
||||||
|
Location loc = this->location();
|
||||||
|
|
||||||
|
std::string s = "fieldtrack \"";
|
||||||
|
Named_type* nt = this->expr_->type()->named_type();
|
||||||
|
if (nt == NULL || nt->named_object()->package() == NULL)
|
||||||
|
s.append(gogo->pkgpath());
|
||||||
|
else
|
||||||
|
s.append(nt->named_object()->package()->pkgpath());
|
||||||
|
s.push_back('.');
|
||||||
|
if (nt != NULL)
|
||||||
|
s.append(nt->name());
|
||||||
|
s.push_back('.');
|
||||||
|
s.append(field->field_name());
|
||||||
|
s.push_back('"');
|
||||||
|
|
||||||
|
// We can't use a string here, because internally a string holds a
|
||||||
|
// pointer to the actual bytes; when the linker garbage collects the
|
||||||
|
// string, it won't garbage collect the bytes. So we use a
|
||||||
|
// [...]byte.
|
||||||
|
|
||||||
|
mpz_t val;
|
||||||
|
mpz_init_set_ui(val, s.length());
|
||||||
|
Expression* length_expr = Expression::make_integer(&val, NULL, loc);
|
||||||
|
mpz_clear(val);
|
||||||
|
|
||||||
|
Type* byte_type = gogo->lookup_global("byte")->type_value();
|
||||||
|
Type* array_type = Type::make_array_type(byte_type, length_expr);
|
||||||
|
|
||||||
|
Expression_list* bytes = new Expression_list();
|
||||||
|
for (std::string::const_iterator p = s.begin(); p != s.end(); p++)
|
||||||
|
{
|
||||||
|
mpz_init_set_ui(val, *p);
|
||||||
|
Expression* byte = Expression::make_integer(&val, NULL, loc);
|
||||||
|
mpz_clear(val);
|
||||||
|
bytes->push_back(byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* e = Expression::make_composite_literal(array_type, 0, false,
|
||||||
|
bytes, loc);
|
||||||
|
|
||||||
|
Variable* var = new Variable(array_type, e, true, false, false, loc);
|
||||||
|
|
||||||
|
static int count;
|
||||||
|
char buf[50];
|
||||||
|
snprintf(buf, sizeof buf, "fieldtrack.%d", count);
|
||||||
|
++count;
|
||||||
|
|
||||||
|
Named_object* no = gogo->add_variable(buf, var);
|
||||||
|
e = Expression::make_var_reference(no, loc);
|
||||||
|
e = Expression::make_unary(OPERATOR_AND, e, loc);
|
||||||
|
|
||||||
|
Expression* call = Runtime::make_call(Runtime::FIELDTRACK, loc, 1, e);
|
||||||
|
inserter->insert(Statement::make_statement(call, false));
|
||||||
|
|
||||||
|
// Put this function, and the global variable we just created, into
|
||||||
|
// unique sections. This will permit the linker to garbage collect
|
||||||
|
// them if they are not referenced. The effect is that the only
|
||||||
|
// strings, indicating field references, that will wind up in the
|
||||||
|
// executable will be those for functions that are actually needed.
|
||||||
|
function->func_value()->set_in_unique_section();
|
||||||
|
var->set_in_unique_section();
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the type of a field reference.
|
// Return the type of a field reference.
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
|
|
|
||||||
|
|
@ -1842,7 +1842,7 @@ class Field_reference_expression : public Expression
|
||||||
Field_reference_expression(Expression* expr, unsigned int field_index,
|
Field_reference_expression(Expression* expr, unsigned int field_index,
|
||||||
Location location)
|
Location location)
|
||||||
: Expression(EXPRESSION_FIELD_REFERENCE, location),
|
: Expression(EXPRESSION_FIELD_REFERENCE, location),
|
||||||
expr_(expr), field_index_(field_index)
|
expr_(expr), field_index_(field_index), called_fieldtrack_(false)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
// Return the struct expression.
|
// Return the struct expression.
|
||||||
|
|
@ -1868,6 +1868,9 @@ class Field_reference_expression : public Expression
|
||||||
do_traverse(Traverse* traverse)
|
do_traverse(Traverse* traverse)
|
||||||
{ return Expression::traverse(&this->expr_, traverse); }
|
{ return Expression::traverse(&this->expr_, traverse); }
|
||||||
|
|
||||||
|
Expression*
|
||||||
|
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
|
||||||
|
|
||||||
Type*
|
Type*
|
||||||
do_type();
|
do_type();
|
||||||
|
|
||||||
|
|
@ -1906,6 +1909,8 @@ class Field_reference_expression : public Expression
|
||||||
Expression* expr_;
|
Expression* expr_;
|
||||||
// The zero-based index of the field we are retrieving.
|
// The zero-based index of the field we are retrieving.
|
||||||
unsigned int field_index_;
|
unsigned int field_index_;
|
||||||
|
// Whether we have already emitted a fieldtrack call.
|
||||||
|
bool called_fieldtrack_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A reference to a field of an interface.
|
// A reference to a field of an interface.
|
||||||
|
|
|
||||||
|
|
@ -1316,6 +1316,9 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id)
|
||||||
DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
|
DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this->in_unique_section_)
|
||||||
|
resolve_unique_section (decl, 0, 1);
|
||||||
|
|
||||||
go_preserve_from_gc(decl);
|
go_preserve_from_gc(decl);
|
||||||
|
|
||||||
if (this->closure_var_ != NULL)
|
if (this->closure_var_ != NULL)
|
||||||
|
|
|
||||||
|
|
@ -3075,7 +3075,8 @@ Function::Function(Function_type* type, Function* enclosing, Block* block,
|
||||||
closure_var_(NULL), block_(block), location_(location), labels_(),
|
closure_var_(NULL), block_(block), location_(location), labels_(),
|
||||||
local_type_count_(0), fndecl_(NULL), defer_stack_(NULL),
|
local_type_count_(0), fndecl_(NULL), defer_stack_(NULL),
|
||||||
results_are_named_(false), nointerface_(false), calls_recover_(false),
|
results_are_named_(false), nointerface_(false), calls_recover_(false),
|
||||||
is_recover_thunk_(false), has_recover_thunk_(false)
|
is_recover_thunk_(false), has_recover_thunk_(false),
|
||||||
|
in_unique_section_(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3896,7 +3897,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
|
||||||
seen_(false), init_is_lowered_(false), type_from_init_tuple_(false),
|
seen_(false), init_is_lowered_(false), type_from_init_tuple_(false),
|
||||||
type_from_range_index_(false), type_from_range_value_(false),
|
type_from_range_index_(false), type_from_range_value_(false),
|
||||||
type_from_chan_element_(false), is_type_switch_var_(false),
|
type_from_chan_element_(false), is_type_switch_var_(false),
|
||||||
determined_type_(false)
|
determined_type_(false), in_unique_section_(false)
|
||||||
{
|
{
|
||||||
go_assert(type != NULL || init != NULL);
|
go_assert(type != NULL || init != NULL);
|
||||||
go_assert(!is_parameter || init == NULL);
|
go_assert(!is_parameter || init == NULL);
|
||||||
|
|
@ -4315,6 +4316,7 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
|
||||||
btype,
|
btype,
|
||||||
package != NULL,
|
package != NULL,
|
||||||
Gogo::is_hidden_name(name),
|
Gogo::is_hidden_name(name),
|
||||||
|
this->in_unique_section_,
|
||||||
this->location_);
|
this->location_);
|
||||||
else if (function == NULL)
|
else if (function == NULL)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1032,6 +1032,11 @@ class Function
|
||||||
set_has_recover_thunk()
|
set_has_recover_thunk()
|
||||||
{ this->has_recover_thunk_ = true; }
|
{ this->has_recover_thunk_ = true; }
|
||||||
|
|
||||||
|
// Mark the function as going into a unique section.
|
||||||
|
void
|
||||||
|
set_in_unique_section()
|
||||||
|
{ this->in_unique_section_ = true; }
|
||||||
|
|
||||||
// Swap with another function. Used only for the thunk which calls
|
// Swap with another function. Used only for the thunk which calls
|
||||||
// recover.
|
// recover.
|
||||||
void
|
void
|
||||||
|
|
@ -1139,6 +1144,9 @@ class Function
|
||||||
bool is_recover_thunk_;
|
bool is_recover_thunk_;
|
||||||
// True if this function already has a recover thunk.
|
// True if this function already has a recover thunk.
|
||||||
bool has_recover_thunk_;
|
bool has_recover_thunk_;
|
||||||
|
// True if this function should be put in a unique section. This is
|
||||||
|
// turned on for field tracking.
|
||||||
|
bool in_unique_section_ : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A snapshot of the current binding state.
|
// A snapshot of the current binding state.
|
||||||
|
|
@ -1414,6 +1422,14 @@ class Variable
|
||||||
set_is_type_switch_var()
|
set_is_type_switch_var()
|
||||||
{ this->is_type_switch_var_ = true; }
|
{ this->is_type_switch_var_ = true; }
|
||||||
|
|
||||||
|
// Mark the variable as going into a unique section.
|
||||||
|
void
|
||||||
|
set_in_unique_section()
|
||||||
|
{
|
||||||
|
go_assert(this->is_global_);
|
||||||
|
this->in_unique_section_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Traverse the initializer expression.
|
// Traverse the initializer expression.
|
||||||
int
|
int
|
||||||
traverse_expression(Traverse*, unsigned int traverse_mask);
|
traverse_expression(Traverse*, unsigned int traverse_mask);
|
||||||
|
|
@ -1504,6 +1520,9 @@ class Variable
|
||||||
bool is_type_switch_var_ : 1;
|
bool is_type_switch_var_ : 1;
|
||||||
// True if we have determined types.
|
// True if we have determined types.
|
||||||
bool determined_type_ : 1;
|
bool determined_type_ : 1;
|
||||||
|
// True if this variable should be put in a unique section. This is
|
||||||
|
// used for field tracking.
|
||||||
|
bool in_unique_section_ : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
// A variable which is really the name for a function return value, or
|
// A variable which is really the name for a function return value, or
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,10 @@ DEF_GO_RUNTIME(PRINT_SPACE, "__go_print_space", P0(), R0())
|
||||||
DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0())
|
DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0())
|
||||||
|
|
||||||
|
|
||||||
|
// Used for field tracking for data analysis.
|
||||||
|
DEF_GO_RUNTIME(FIELDTRACK, "__go_fieldtrack", P1(POINTER), R0())
|
||||||
|
|
||||||
|
|
||||||
// Remove helper macros.
|
// Remove helper macros.
|
||||||
#undef ABFT6
|
#undef ABFT6
|
||||||
#undef ABFT2
|
#undef ABFT2
|
||||||
|
|
|
||||||
|
|
@ -450,6 +450,7 @@ runtime_files = \
|
||||||
runtime/go-deferred-recover.c \
|
runtime/go-deferred-recover.c \
|
||||||
runtime/go-eface-compare.c \
|
runtime/go-eface-compare.c \
|
||||||
runtime/go-eface-val-compare.c \
|
runtime/go-eface-val-compare.c \
|
||||||
|
runtime/go-fieldtrack.c \
|
||||||
runtime/go-getgoroot.c \
|
runtime/go-getgoroot.c \
|
||||||
runtime/go-int-array-to-string.c \
|
runtime/go-int-array-to-string.c \
|
||||||
runtime/go-int-to-string.c \
|
runtime/go-int-to-string.c \
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ am__objects_5 = go-append.lo go-assert.lo go-assert-interface.lo \
|
||||||
go-check-interface.lo go-construct-map.lo \
|
go-check-interface.lo go-construct-map.lo \
|
||||||
go-convert-interface.lo go-copy.lo go-defer.lo \
|
go-convert-interface.lo go-copy.lo go-defer.lo \
|
||||||
go-deferred-recover.lo go-eface-compare.lo \
|
go-deferred-recover.lo go-eface-compare.lo \
|
||||||
go-eface-val-compare.lo go-getgoroot.lo \
|
go-eface-val-compare.lo go-fieldtrack.lo go-getgoroot.lo \
|
||||||
go-int-array-to-string.lo go-int-to-string.lo \
|
go-int-array-to-string.lo go-int-to-string.lo \
|
||||||
go-interface-compare.lo go-interface-eface-compare.lo \
|
go-interface-compare.lo go-interface-eface-compare.lo \
|
||||||
go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \
|
go-interface-val-compare.lo go-make-slice.lo go-map-delete.lo \
|
||||||
|
|
@ -781,6 +781,7 @@ runtime_files = \
|
||||||
runtime/go-deferred-recover.c \
|
runtime/go-deferred-recover.c \
|
||||||
runtime/go-eface-compare.c \
|
runtime/go-eface-compare.c \
|
||||||
runtime/go-eface-val-compare.c \
|
runtime/go-eface-val-compare.c \
|
||||||
|
runtime/go-fieldtrack.c \
|
||||||
runtime/go-getgoroot.c \
|
runtime/go-getgoroot.c \
|
||||||
runtime/go-int-array-to-string.c \
|
runtime/go-int-array-to-string.c \
|
||||||
runtime/go-int-to-string.c \
|
runtime/go-int-to-string.c \
|
||||||
|
|
@ -2421,6 +2422,7 @@ distclean-compile:
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-deferred-recover.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-compare.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-eface-val-compare.Plo@am__quote@
|
||||||
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-fieldtrack.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-getgoroot.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-getgoroot.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-array-to-string.Plo@am__quote@
|
||||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-to-string.Plo@am__quote@
|
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-int-to-string.Plo@am__quote@
|
||||||
|
|
@ -2657,6 +2659,13 @@ go-eface-val-compare.lo: runtime/go-eface-val-compare.c
|
||||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
|
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-eface-val-compare.lo `test -f 'runtime/go-eface-val-compare.c' || echo '$(srcdir)/'`runtime/go-eface-val-compare.c
|
||||||
|
|
||||||
|
go-fieldtrack.lo: runtime/go-fieldtrack.c
|
||||||
|
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-fieldtrack.lo -MD -MP -MF $(DEPDIR)/go-fieldtrack.Tpo -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
|
||||||
|
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-fieldtrack.Tpo $(DEPDIR)/go-fieldtrack.Plo
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-fieldtrack.c' object='go-fieldtrack.lo' libtool=yes @AMDEPBACKSLASH@
|
||||||
|
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||||
|
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-fieldtrack.lo `test -f 'runtime/go-fieldtrack.c' || echo '$(srcdir)/'`runtime/go-fieldtrack.c
|
||||||
|
|
||||||
go-getgoroot.lo: runtime/go-getgoroot.c
|
go-getgoroot.lo: runtime/go-getgoroot.c
|
||||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-getgoroot.lo -MD -MP -MF $(DEPDIR)/go-getgoroot.Tpo -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
|
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-getgoroot.lo -MD -MP -MF $(DEPDIR)/go-getgoroot.Tpo -c -o go-getgoroot.lo `test -f 'runtime/go-getgoroot.c' || echo '$(srcdir)/'`runtime/go-getgoroot.c
|
||||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-getgoroot.Tpo $(DEPDIR)/go-getgoroot.Plo
|
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-getgoroot.Tpo $(DEPDIR)/go-getgoroot.Plo
|
||||||
|
|
|
||||||
|
|
@ -168,3 +168,10 @@ func BlockProfile(p []BlockProfileRecord) (n int, ok bool)
|
||||||
// If all is true, Stack formats stack traces of all other goroutines
|
// If all is true, Stack formats stack traces of all other goroutines
|
||||||
// into buf after the trace for the current goroutine.
|
// into buf after the trace for the current goroutine.
|
||||||
func Stack(buf []byte, all bool) int
|
func Stack(buf []byte, all bool) int
|
||||||
|
|
||||||
|
// Get field tracking information. Only fields with a tag go:"track"
|
||||||
|
// are tracked. This function will add every such field that is
|
||||||
|
// referenced to the map. The keys in the map will be
|
||||||
|
// PkgPath.Name.FieldName. The value will be true for each field
|
||||||
|
// added.
|
||||||
|
func Fieldtrack(map[string]bool)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
/* go-fieldtrack.c -- structure field data analysis.
|
||||||
|
|
||||||
|
Copyright 2012 The Go Authors. All rights reserved.
|
||||||
|
Use of this source code is governed by a BSD-style
|
||||||
|
license that can be found in the LICENSE file. */
|
||||||
|
|
||||||
|
#include "runtime.h"
|
||||||
|
#include "go-type.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
|
/* The compiler will track fields that have the tag go:"track". Any
|
||||||
|
function that refers to such a field will call this function with a
|
||||||
|
string
|
||||||
|
fieldtrack "package.type.field"
|
||||||
|
|
||||||
|
This function does not actually do anything. Instead, we gather
|
||||||
|
the field tracking information by looking for strings of that form
|
||||||
|
in the read-only data section. This is, of course, a horrible
|
||||||
|
hack, but it's good enough for now. We can improve it, e.g., by a
|
||||||
|
linker plugin, if this turns out to be useful. */
|
||||||
|
|
||||||
|
void
|
||||||
|
__go_fieldtrack (byte *p __attribute__ ((unused)))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A runtime function to add all the tracked fields to a
|
||||||
|
map[string]bool. */
|
||||||
|
|
||||||
|
extern const char _etext[] __attribute__ ((weak));
|
||||||
|
extern const char __etext[] __attribute__ ((weak));
|
||||||
|
extern const char __data_start[] __attribute__ ((weak));
|
||||||
|
extern const char _edata[] __attribute__ ((weak));
|
||||||
|
extern const char __edata[] __attribute__ ((weak));
|
||||||
|
extern const char __bss_start[] __attribute__ ((weak));
|
||||||
|
|
||||||
|
void runtime_Fieldtrack (struct __go_map *) __asm__ ("runtime.Fieldtrack");
|
||||||
|
|
||||||
|
void
|
||||||
|
runtime_Fieldtrack (struct __go_map *m)
|
||||||
|
{
|
||||||
|
const char *p;
|
||||||
|
const char *pend;
|
||||||
|
const char *prefix;
|
||||||
|
size_t prefix_len;
|
||||||
|
|
||||||
|
p = __data_start;
|
||||||
|
if (p == NULL)
|
||||||
|
p = __etext;
|
||||||
|
if (p == NULL)
|
||||||
|
p = _etext;
|
||||||
|
if (p == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pend = __edata;
|
||||||
|
if (pend == NULL)
|
||||||
|
pend = _edata;
|
||||||
|
if (pend == NULL)
|
||||||
|
pend = __bss_start;
|
||||||
|
if (pend == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
prefix = "fieldtrack ";
|
||||||
|
prefix_len = __builtin_strlen (prefix);
|
||||||
|
|
||||||
|
while (p < pend)
|
||||||
|
{
|
||||||
|
const char *q1;
|
||||||
|
const char *q2;
|
||||||
|
|
||||||
|
q1 = __builtin_memchr (p + prefix_len, '"', pend - (p + prefix_len));
|
||||||
|
if (q1 == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (__builtin_memcmp (q1 - prefix_len, prefix, prefix_len) != 0)
|
||||||
|
{
|
||||||
|
p = q1 + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
q1++;
|
||||||
|
q2 = __builtin_memchr (q1, '"', pend - q1);
|
||||||
|
if (q2 == NULL)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (__builtin_memchr (q1, '\0', q2 - q1) == NULL)
|
||||||
|
{
|
||||||
|
String s;
|
||||||
|
void *v;
|
||||||
|
_Bool *pb;
|
||||||
|
|
||||||
|
s.str = (const byte *) q1;
|
||||||
|
s.len = q2 - q1;
|
||||||
|
v = __go_map_index (m, &s, 1);
|
||||||
|
pb = (_Bool *) v;
|
||||||
|
*pb = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p = q2;
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue