compiler: Add precise type information on the heap.

* go-gcc.cc (Gcc_backend::implicit_variable): Remove init
	parameter.  Add is_hidden parameter.
	(Gcc_backend::implicit_variable_set_init): New method.
	(Gcc_backend::implicit_variable_reference): New method.

From-SVN: r214894
This commit is contained in:
Chris Manghane 2014-09-03 22:56:09 +00:00 committed by Ian Lance Taylor
parent d2e4feca24
commit f1d2ac4f84
14 changed files with 892 additions and 96 deletions

View File

@ -1,3 +1,10 @@
2014-09-03 Chris Manghane <cmang@google.com>
* go-gcc.cc (Gcc_backend::implicit_variable): Remove init
parameter. Add is_hidden parameter.
(Gcc_backend::implicit_variable_set_init): New method.
(Gcc_backend::implicit_variable_reference): New method.
2014-08-08 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::compound_statement): Don't return

View File

@ -389,9 +389,16 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool,
implicit_variable(const std::string&, Btype*, bool, bool, bool,
size_t);
void
implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
bool, bool, bool, Bexpression*);
Bvariable*
implicit_variable_reference(const std::string&, Btype*);
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
@ -2505,45 +2512,101 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
Bvariable*
Gcc_backend::implicit_variable(const std::string& name, Btype* type,
Bexpression* init, bool is_constant,
bool is_hidden, bool is_constant,
bool is_common, size_t alignment)
{
tree type_tree = type->get_tree();
tree init_tree;
if (init == NULL)
init_tree = NULL_TREE;
else
init_tree = init->get_tree();
if (type_tree == error_mark_node || init_tree == error_mark_node)
if (type_tree == error_mark_node)
return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0;
TREE_PUBLIC(decl) = 0;
TREE_PUBLIC(decl) = !is_hidden;
TREE_STATIC(decl) = 1;
TREE_USED(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
if (is_common)
{
DECL_COMMON(decl) = 1;
TREE_PUBLIC(decl) = 1;
gcc_assert(init_tree == NULL_TREE);
// When the initializer for one implicit_variable refers to another,
// it needs to know the visibility of the referenced struct so that
// compute_reloc_for_constant will return the right value. On many
// systems calling make_decl_one_only will mark the decl as weak,
// which will change the return value of compute_reloc_for_constant.
// We can't reliably call make_decl_one_only yet, because we don't
// yet know the initializer. This issue doesn't arise in C because
// Go initializers, unlike C initializers, can be indirectly
// recursive. To ensure that compute_reloc_for_constant computes
// the right value if some other initializer refers to this one, we
// mark this symbol as weak here. We undo that below in
// immutable_struct_set_init before calling mark_decl_one_only.
DECL_WEAK(decl) = 1;
}
else if (is_constant)
if (is_constant)
{
TREE_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1;
}
DECL_INITIAL(decl) = init_tree;
if (alignment != 0)
{
DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
DECL_USER_ALIGN(decl) = 1;
}
rest_of_decl_compilation(decl, 1, 0);
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
// Set the initalizer for a variable created by implicit_variable.
// This is where we finish compiling the variable.
void
Gcc_backend::implicit_variable_set_init(Bvariable* var, const std::string&,
Btype*, bool, bool, bool is_common,
Bexpression* init)
{
tree decl = var->get_tree();
tree init_tree;
if (init == NULL)
init_tree = NULL_TREE;
else
init_tree = init->get_tree();
if (decl == error_mark_node || init_tree == error_mark_node)
return;
DECL_INITIAL(decl) = init_tree;
// Now that DECL_INITIAL is set, we can't call make_decl_one_only.
// See the comment where DECL_WEAK is set in implicit_variable.
if (is_common)
{
DECL_WEAK(decl) = 0;
make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
}
resolve_unique_section(decl, 2, 1);
rest_of_decl_compilation(decl, 1, 0);
}
// Return a reference to an implicit variable defined in another package.
Bvariable*
Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0;
TREE_PUBLIC(decl) = 1;
TREE_STATIC(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
go_preserve_from_gc(decl);
return new Bvariable(decl);
}

View File

@ -545,24 +545,55 @@ class Backend
Bstatement** pstatement) = 0;
// Create an implicit variable that is compiler-defined. This is
// used when generating GC root variables, when storing the values
// of a slice constructor, and for the zero value of types. NAME is
// the name of the variable, either gc# for GC roots or C# for slice
// initializers. TYPE is the type of the implicit variable with an
// initial value INIT. IS_CONSTANT is true if the implicit variable
// should be treated like it is immutable. For slice initializers,
// if the values must be copied to the heap, the variable
// IS_CONSTANT. IS_COMMON is true if the implicit variable should
// used when generating GC data and roots, when storing the values
// of a slice constructor, and for the zero value of types. This returns a
// Bvariable because it corresponds to an initialized variable in C.
//
// NAME is the name to use for the initialized variable this will create.
//
// TYPE is the type of the implicit variable.
//
// IS_HIDDEN will be true if the descriptor should only be visible
// within the current object.
//
// IS_CONSTANT is true if the implicit variable should be treated like it is
// immutable. For slice initializers, if the values must be copied to the
// heap, the variable IS_CONSTANT.
//
// IS_COMMON is true if the implicit variable should
// be treated as a common variable (multiple definitions with
// different sizes permitted in different object files, all merged
// into the largest definition at link time); this will be true for
// the zero value. If IS_COMMON is true, INIT will be NULL, and the
// variable should be initialized to all zeros. If ALIGNMENT is not
// zero, it is the desired alignment of the variable.
// the zero value. IS_HIDDEN and IS_COMMON will never both be true.
//
// If ALIGNMENT is not zero, it is the desired alignment of the variable.
virtual Bvariable*
implicit_variable(const std::string& name, Btype* type, Bexpression* init,
implicit_variable(const std::string& name, Btype* type, bool is_hidden,
bool is_constant, bool is_common, size_t alignment) = 0;
// Set the initial value of a variable created by implicit_variable.
// This must be called even if there is no initializer, i.e., INIT is NULL.
// The NAME, TYPE, IS_HIDDEN, IS_CONSTANT, and IS_COMMON parameters are
// the same ones passed to implicit_variable. INIT will be a composite
// literal of type TYPE. It will not contain any function calls or anything
// else that can not be put into a read-only data section.
// It may contain the address of variables created by implicit_variable.
//
// If IS_COMMON is true, INIT will be NULL, and the
// variable should be initialized to all zeros.
virtual void
implicit_variable_set_init(Bvariable*, const std::string& name, Btype* type,
bool is_hidden, bool is_constant, bool is_common,
Bexpression* init) = 0;
// Create a reference to a named implicit variable defined in some other
// package. This will be a variable created by a call to implicit_variable
// with the same NAME and TYPE and with IS_COMMON passed as false. This
// corresponds to an extern global variable in C.
virtual Bvariable*
implicit_variable_reference(const std::string& name, Btype* type) = 0;
// Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function
// descriptors. This returns a Bvariable because it corresponds to

View File

@ -3440,6 +3440,9 @@ class Unsafe_type_conversion_expression : public Expression
int
do_traverse(Traverse* traverse);
bool
do_is_immutable() const;
Type*
do_type()
{ return this->type_; }
@ -3480,6 +3483,27 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
// Return whether an unsafe type conversion is immutable.
bool
Unsafe_type_conversion_expression::do_is_immutable() const
{
Type* type = this->type_;
Type* expr_type = this->expr_->type();
if (type->interface_type() != NULL
|| expr_type->interface_type() != NULL)
return false;
if (!this->expr_->is_immutable())
return false;
if (Type::are_convertible(type, expr_type, NULL))
return true;
return type->is_basic_type() && expr_type->is_basic_type();
}
// Convert to backend representation.
Bexpression*
@ -4115,8 +4139,11 @@ Unary_expression::do_get_backend(Translate_context* context)
&& !context->is_const());
}
Bvariable* implicit =
gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap,
gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
false, 0);
gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
true, copy_to_heap, false,
bexpr);
bexpr = gogo->backend()->var_expression(implicit, loc);
}
else if ((this->expr_->is_composite_literal()
@ -13987,6 +14014,65 @@ Expression::make_type_descriptor(Type* type, Location location)
return new Type_descriptor_expression(type, location);
}
// An expression which evaluates to a pointer to the Garbage Collection symbol
// of a type.
class GC_symbol_expression : public Expression
{
public:
GC_symbol_expression(Type* type)
: Expression(EXPRESSION_GC_SYMBOL, Linemap::predeclared_location()),
type_(type)
{}
protected:
Type*
do_type()
{ return Type::make_pointer_type(Type::make_void_type()); }
bool
do_is_immutable() const
{ return true; }
void
do_determine_type(const Type_context*)
{ }
Expression*
do_copy()
{ return this; }
Bexpression*
do_get_backend(Translate_context* context)
{ return this->type_->gc_symbol_pointer(context->gogo()); }
void
do_dump_expression(Ast_dump_context*) const;
private:
// The type which this gc symbol describes.
Type* type_;
};
// Dump ast representation for a gc symbol expression.
void
GC_symbol_expression::do_dump_expression(
Ast_dump_context* ast_dump_context) const
{
ast_dump_context->ostream() << "gcdata(";
ast_dump_context->dump_type(this->type_);
ast_dump_context->ostream() << ")";
}
// Make a gc symbol expression.
Expression*
Expression::make_gc_symbol(Type* type)
{
return new GC_symbol_expression(type);
}
// An expression which evaluates to some characteristic of a type.
// This is only used to initialize fields of a type descriptor. Using
// a new expression class is slightly inefficient but gives us a good

View File

@ -103,6 +103,7 @@ class Expression
EXPRESSION_HEAP,
EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_GC_SYMBOL,
EXPRESSION_TYPE_INFO,
EXPRESSION_SLICE_INFO,
EXPRESSION_SLICE_VALUE,
@ -349,6 +350,11 @@ class Expression
static Expression*
make_type_descriptor(Type* type, Location);
// Make an expression which evaluates to the address of the gc
// symbol for TYPE.
static Expression*
make_gc_symbol(Type* type);
// Make an expression which evaluates to some characteristic of a
// type. These are only used for type descriptors, so there is no
// location parameter.
@ -1512,6 +1518,10 @@ class Binary_expression : public Expression
do_is_constant() const
{ return this->left_->is_constant() && this->right_->is_constant(); }
bool
do_is_immutable() const
{ return this->left_->is_immutable() && this->right_->is_immutable(); }
bool
do_numeric_constant_value(Numeric_constant*) const;

View File

@ -655,9 +655,13 @@ Gogo::backend_zero_value()
Btype* barray_type = this->backend()->array_type(bbtype_type, blength);
return this->backend()->implicit_variable(this->zero_value_->name(),
barray_type, NULL, true, true,
this->zero_value_align_);
std::string zname = this->zero_value_->name();
Bvariable* zvar =
this->backend()->implicit_variable(zname, barray_type, false,
true, true, this->zero_value_align_);
this->backend()->implicit_variable_set_init(zvar, zname, barray_type,
false, true, true, NULL);
return zvar;
}
// Add statements to INIT_STMTS which run the initialization
@ -6837,8 +6841,10 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
{
named_type->
type_descriptor_pointer(gogo, Linemap::predeclared_location());
named_type->gc_symbol_pointer(gogo);
Type* pn = Type::make_pointer_type(named_type);
pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
pn->gc_symbol_pointer(gogo);
}
}
break;

View File

@ -36,7 +36,8 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
// Class Type.
Type::Type(Type_classification classification)
: classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
: classification_(classification), btype_(NULL), type_descriptor_var_(NULL),
gc_symbol_var_(NULL)
{
}
@ -1236,7 +1237,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
Type::type_descriptor_vars.insert(std::make_pair(this, bvnull));
if (!ins.second)
{
// We've already build a type descriptor for this type.
// We've already built a type descriptor for this type.
this->type_descriptor_var_ = ins.first->second;
return;
}
@ -1405,6 +1406,18 @@ Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name)
return type->do_type_descriptor(gogo, name);
}
// Generate the GC symbol for this TYPE. VALS is the data so far in this
// symbol; extra values will be appended in do_gc_symbol. OFFSET is the
// offset into the symbol where the GC data is located. STACK_SIZE is the
// size of the GC stack when dealing with array types.
void
Type::gc_symbol(Gogo* gogo, Type* type, Expression_list** vals,
Expression** offset, int stack_size)
{
type->do_gc_symbol(gogo, vals, offset, stack_size);
}
// Make a builtin struct type from a list of fields. The fields are
// pairs of a name and a type.
@ -1519,14 +1532,15 @@ Type::make_type_descriptor_type()
// The type descriptor type.
Struct_type* type_descriptor_type =
Type::make_builtin_struct_type(11,
"Kind", uint8_type,
Type::make_builtin_struct_type(12,
"kind", uint8_type,
"align", uint8_type,
"fieldAlign", uint8_type,
"size", uintptr_type,
"hash", uint32_type,
"hashfn", uintptr_type,
"equalfn", uintptr_type,
"gc", unsafe_pointer_type,
"string", pointer_string_type,
"", pointer_uncommon_type,
"ptrToThis",
@ -1973,7 +1987,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
if (!this->has_pointer())
runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS;
Struct_field_list::const_iterator p = fields->begin();
go_assert(p->is_field_name("Kind"));
go_assert(p->is_field_name("kind"));
mpz_t iv;
mpz_init_set_ui(iv, runtime_type_kind);
vals->push_back(Expression::make_integer(&iv, p->type(), bloc));
@ -2018,6 +2032,10 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
vals->push_back(Expression::make_func_code_reference(hash_fn, bloc));
vals->push_back(Expression::make_func_code_reference(equal_fn, bloc));
++p;
go_assert(p->is_field_name("gc"));
vals->push_back(Expression::make_gc_symbol(this));
++p;
go_assert(p->is_field_name("string"));
Expression* s = Expression::make_string((name != NULL
@ -2067,6 +2085,160 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind,
return Expression::make_struct_composite_literal(td_type, vals, bloc);
}
// Return a pointer to the Garbage Collection information for this type.
Bexpression*
Type::gc_symbol_pointer(Gogo* gogo)
{
Type* t = this->forwarded();
if (t->named_type() != NULL && t->named_type()->is_alias())
t = t->named_type()->real_type();
if (t->gc_symbol_var_ == NULL)
{
t->make_gc_symbol_var(gogo);
go_assert(t->gc_symbol_var_ != NULL);
}
Location bloc = Linemap::predeclared_location();
Bexpression* var_expr =
gogo->backend()->var_expression(t->gc_symbol_var_, bloc);
return gogo->backend()->address_expression(var_expr, bloc);
}
// A mapping from unnamed types to GC symbol variables.
Type::GC_symbol_vars Type::gc_symbol_vars;
// Build the GC symbol for this type.
void
Type::make_gc_symbol_var(Gogo* gogo)
{
go_assert(this->gc_symbol_var_ == NULL);
Named_type* nt = this->named_type();
// We can have multiple instances of unnamed types and similar to type
// descriptors, we only want to the emit the GC data once, so we use a
// hash table.
Bvariable** phash = NULL;
if (nt == NULL)
{
Bvariable* bvnull = NULL;
std::pair<GC_symbol_vars::iterator, bool> ins =
Type::gc_symbol_vars.insert(std::make_pair(this, bvnull));
if (!ins.second)
{
// We've already built a gc symbol for this type.
this->gc_symbol_var_ = ins.first->second;
return;
}
phash = &ins.first->second;
}
std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
// Build the contents of the gc symbol.
Expression* sym_init = this->gc_symbol_constructor(gogo);
Btype* sym_btype = sym_init->type()->get_backend(gogo);
// If the type descriptor for this type is defined somewhere else, so is the
// GC symbol.
const Package* dummy;
if (this->type_descriptor_defined_elsewhere(nt, &dummy))
{
this->gc_symbol_var_ =
gogo->backend()->implicit_variable_reference(sym_name, sym_btype);
if (phash != NULL)
*phash = this->gc_symbol_var_;
return;
}
// See if this gc symbol can appear in multiple packages.
bool is_common = false;
if (nt != NULL)
{
// We create the symbol for a builtin type whenever we need
// it.
is_common = nt->is_builtin();
}
else
{
// This is an unnamed type. The descriptor could be defined in
// any package where it is needed, and the linker will pick one
// descriptor to keep.
is_common = true;
}
// Since we are building the GC symbol in this package, we must create the
// variable before converting the initializer to its backend representation
// because the initializer may refer to the GC symbol for this type.
this->gc_symbol_var_ =
gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0);
if (phash != NULL)
*phash = this->gc_symbol_var_;
Translate_context context(gogo, NULL, NULL, NULL);
context.set_is_const();
Bexpression* sym_binit = sym_init->get_backend(&context);
gogo->backend()->implicit_variable_set_init(this->gc_symbol_var_, sym_name,
sym_btype, false, true, is_common,
sym_binit);
}
// Return an array literal for the Garbage Collection information for this type.
Expression*
Type::gc_symbol_constructor(Gogo* gogo)
{
Location bloc = Linemap::predeclared_location();
// The common GC Symbol data starts with the width of the type and ends
// with the GC Opcode GC_END.
// However, for certain types, the GC symbol may include extra information
// before the ending opcode, so we pass the expression list into
// Type::gc_symbol to allow it to add extra information as is necessary.
Expression_list* vals = new Expression_list;
Type* uintptr_t = Type::lookup_integer_type("uintptr");
// width
vals->push_back(Expression::make_type_info(this,
Expression::TYPE_INFO_SIZE));
mpz_t off;
mpz_init_set_ui(off, 0UL);
Expression* offset = Expression::make_integer(&off, uintptr_t, bloc);
mpz_clear(off);
this->do_gc_symbol(gogo, &vals, &offset, 0);
mpz_t end;
mpz_init_set_ui(end, GC_END);
vals->push_back(Expression::make_integer(&end, uintptr_t, bloc));
mpz_clear(end);
mpz_t lenval;
mpz_init_set_ui(lenval, vals->size() + 1);
Expression* len = Expression::make_integer(&lenval, NULL, bloc);
mpz_clear(lenval);
Array_type* gc_symbol_type = Type::make_array_type(uintptr_t, len);
return Expression::make_array_composite_literal(gc_symbol_type, vals, bloc);
}
// Advance the OFFSET of the GC symbol by this type's width.
void
Type::advance_gc_offset(Expression** offset)
{
if (this->is_error_type())
return;
Location bloc = Linemap::predeclared_location();
Expression* width =
Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
*offset = Expression::make_binary(OPERATOR_PLUS, *offset, width, bloc);
}
// Return a composite literal for the uncommon type information for
// this type. UNCOMMON_STRUCT_TYPE is the type of the uncommon type
// struct. If name is not NULL, it is the name of the type. If
@ -2497,6 +2669,10 @@ class Error_type : public Type
do_reflection(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
{ go_assert(saw_errors()); }
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('E'); }
@ -2535,6 +2711,10 @@ class Void_type : public Type
do_reflection(Gogo*, std::string*) const
{ }
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
{ }
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('v'); }
@ -2573,6 +2753,9 @@ class Boolean_type : public Type
do_reflection(Gogo*, std::string* ret) const
{ ret->append("bool"); }
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('b'); }
@ -2593,6 +2776,12 @@ Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name)
}
}
// Update the offset of the GC symbol.
void
Boolean_type::do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
Type*
Type::make_boolean_type()
{
@ -3102,6 +3291,22 @@ String_type::do_reflection(Gogo*, std::string* ret) const
ret->append("string");
}
// Generate GC symbol for strings.
void
String_type::do_gc_symbol(Gogo*, Expression_list** vals,
Expression** offset, int)
{
Location bloc = Linemap::predeclared_location();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t opval;
mpz_init_set_ui(opval, GC_STRING);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
mpz_clear(opval);
(*vals)->push_back(*offset);
this->advance_gc_offset(offset);
}
// Mangled name of a string type.
void
@ -3172,6 +3377,10 @@ class Sink_type : public Type
do_reflection(Gogo*, std::string*) const
{ go_unreachable(); }
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
{ go_unreachable(); }
void
do_mangled_name(Gogo*, std::string*) const
{ go_unreachable(); }
@ -3754,6 +3963,25 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const
}
}
// Generate GC symbol for a function type.
void
Function_type::do_gc_symbol(Gogo*, Expression_list** vals,
Expression** offset, int)
{
Location bloc = Linemap::predeclared_location();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
// We use GC_APTR here because we do not currently have a way to describe the
// the type of the possible function closure. FIXME.
mpz_t opval;
mpz_init_set_ui(opval, GC_APTR);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
mpz_clear(opval);
(*vals)->push_back(*offset);
this->advance_gc_offset(offset);
}
// Mangled name.
void
@ -4156,6 +4384,26 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->to_type_, gogo, ret);
}
// Generate GC symbol for pointer types.
void
Pointer_type::do_gc_symbol(Gogo*, Expression_list** vals,
Expression** offset, int)
{
Location loc = Linemap::predeclared_location();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t opval;
mpz_init_set_ui(opval, this->to_type_->has_pointer() ? GC_PTR : GC_APTR);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, loc));
mpz_clear(opval);
(*vals)->push_back(*offset);
if (this->to_type_->has_pointer())
(*vals)->push_back(Expression::make_gc_symbol(this->to_type_));
this->advance_gc_offset(offset);
}
// Mangled name.
void
@ -4235,6 +4483,10 @@ class Nil_type : public Type
do_reflection(Gogo*, std::string*) const
{ go_unreachable(); }
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
{ go_unreachable(); }
void
do_mangled_name(Gogo*, std::string* ret) const
{ ret->push_back('n'); }
@ -4292,6 +4544,10 @@ class Call_multiple_result_type : public Type
do_reflection(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int)
{ go_unreachable(); }
void
do_mangled_name(Gogo*, std::string*) const
{ go_assert(saw_errors()); }
@ -5319,6 +5575,27 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->push_back('}');
}
// Generate GC symbol for struct types.
void
Struct_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
Expression** offset, int stack_size)
{
Location bloc = Linemap::predeclared_location();
const Struct_field_list* sfl = this->fields();
for (Struct_field_list::const_iterator p = sfl->begin();
p != sfl->end();
++p)
{
Expression* field_offset =
Expression::make_struct_field_offset(this, &*p);
Expression* o =
Expression::make_binary(OPERATOR_PLUS, *offset, field_offset, bloc);
Type::gc_symbol(gogo, p->type(), vals, &o, stack_size);
}
this->advance_gc_offset(offset);
}
// Mangled name.
void
@ -6204,6 +6481,115 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->element_type_, gogo, ret);
}
// GC Symbol construction for array types.
void
Array_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
Expression** offset, int stack_size)
{
if (this->length_ == NULL)
this->slice_gc_symbol(gogo, vals, offset, stack_size);
else
this->array_gc_symbol(gogo, vals, offset, stack_size);
}
// Generate the GC Symbol for a slice.
void
Array_type::slice_gc_symbol(Gogo* gogo, Expression_list** vals,
Expression** offset, int)
{
Location bloc = Linemap::predeclared_location();
// Differentiate between slices with zero-length and non-zero-length values.
Type* element_type = this->element_type();
Btype* ebtype = element_type->get_backend(gogo);
size_t element_size = gogo->backend()->type_size(ebtype);
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t opval;
mpz_init_set_ui(opval, element_size == 0 ? GC_APTR : GC_SLICE);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
mpz_clear(opval);
(*vals)->push_back(*offset);
if (element_size != 0)
(*vals)->push_back(Expression::make_gc_symbol(element_type));
this->advance_gc_offset(offset);
}
// Generate the GC symbol for an array.
void
Array_type::array_gc_symbol(Gogo* gogo, Expression_list** vals,
Expression** offset, int stack_size)
{
Location bloc = Linemap::predeclared_location();
Numeric_constant nc;
unsigned long bound;
if (!this->length_->numeric_constant_value(&nc)
|| nc.to_unsigned_long(&bound) == Numeric_constant::NC_UL_NOTINT)
go_assert(saw_errors());
Btype* pbtype = gogo->backend()->pointer_type(gogo->backend()->void_type());
size_t pwidth = gogo->backend()->type_size(pbtype);
size_t iwidth = gogo->backend()->type_size(this->get_backend(gogo));
Type* element_type = this->element_type();
if (bound < 1 || !element_type->has_pointer())
this->advance_gc_offset(offset);
else if (bound == 1 || iwidth <= 4 * pwidth)
{
for (unsigned int i = 0; i < bound; ++i)
Type::gc_symbol(gogo, element_type, vals, offset, stack_size);
}
else
{
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t op;
if (stack_size < GC_STACK_CAPACITY)
{
mpz_init_set_ui(op, GC_ARRAY_START);
(*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
mpz_clear(op);
(*vals)->push_back(*offset);
Expression* uintptr_len =
Expression::make_cast(uintptr_type, this->length_, bloc);
(*vals)->push_back(uintptr_len);
Expression* width =
Expression::make_type_info(element_type,
Expression::TYPE_INFO_SIZE);
(*vals)->push_back(width);
mpz_t zero;
mpz_init_set_ui(zero, 0UL);
Expression* offset2 =
Expression::make_integer(&zero, uintptr_type, bloc);
mpz_clear(zero);
Type::gc_symbol(gogo, element_type, vals, &offset2, stack_size + 1);
mpz_init_set_ui(op, GC_ARRAY_NEXT);
(*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
}
else
{
mpz_init_set_ui(op, GC_REGION);
(*vals)->push_back(Expression::make_integer(&op, uintptr_type, bloc));
(*vals)->push_back(*offset);
Expression* width =
Expression::make_type_info(this, Expression::TYPE_INFO_SIZE);
(*vals)->push_back(width);
(*vals)->push_back(Expression::make_gc_symbol(this));
}
mpz_clear(op);
this->advance_gc_offset(offset);
}
}
// Mangled name.
void
@ -6513,6 +6899,24 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->val_type_, gogo, ret);
}
// Generate GC symbol for a map.
void
Map_type::do_gc_symbol(Gogo*, Expression_list** vals,
Expression** offset, int)
{
// TODO(cmang): Generate GC data for the Map elements.
Location bloc = Linemap::predeclared_location();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t opval;
mpz_init_set_ui(opval, GC_APTR);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
mpz_clear(opval);
(*vals)->push_back(*offset);
this->advance_gc_offset(offset);
}
// Mangled name for a map.
void
@ -6686,6 +7090,30 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->element_type_, gogo, ret);
}
// Generate GC symbol for channels.
void
Channel_type::do_gc_symbol(Gogo*, Expression_list** vals,
Expression** offset, int)
{
Location bloc = Linemap::predeclared_location();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t opval;
mpz_init_set_ui(opval, GC_CHAN_PTR);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type, bloc));
mpz_clear(opval);
(*vals)->push_back(*offset);
Type* unsafeptr_type = Type::make_pointer_type(Type::make_void_type());
Expression* type_descriptor =
Expression::make_type_descriptor(this, bloc);
type_descriptor =
Expression::make_unsafe_cast(unsafeptr_type, type_descriptor, bloc);
(*vals)->push_back(type_descriptor);
this->advance_gc_offset(offset);
}
// Mangled name.
void
@ -7574,6 +8002,24 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->append("}");
}
// Generate GC symbol for interface types.
void
Interface_type::do_gc_symbol(Gogo*, Expression_list** vals,
Expression** offset, int)
{
Location bloc = Linemap::predeclared_location();
Type* uintptr_type = Type::lookup_integer_type("uintptr");
mpz_t opval;
mpz_init_set_ui(opval, this->is_empty() ? GC_EFACE : GC_IFACE);
(*vals)->push_back(Expression::make_integer(&opval, uintptr_type,
bloc));
mpz_clear(opval);
(*vals)->push_back(*offset);
this->advance_gc_offset(offset);
}
// Mangled name.
void
@ -8810,6 +9256,20 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
}
// Generate GC symbol for named types.
void
Named_type::do_gc_symbol(Gogo* gogo, Expression_list** vals,
Expression** offset, int stack)
{
if (!this->seen_)
{
this->seen_ = true;
Type::gc_symbol(gogo, this->real_type(), vals, offset, stack);
this->seen_ = false;
}
}
// Get the mangled name.
void

View File

@ -83,6 +83,28 @@ static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7);
// GC instruction opcodes. These must match the values in libgo/runtime/mgc0.h.
enum GC_Opcode
{
GC_END = 0, // End of object, loop or subroutine.
GC_PTR, // A typed pointer.
GC_APTR, // Pointer to an arbitrary object.
GC_ARRAY_START, // Start an array with a fixed length.
GC_ARRAY_NEXT, // The next element of an array.
GC_CALL, // Call a subroutine.
GC_CHAN_PTR, // Go channel.
GC_STRING, // Go string.
GC_EFACE, // interface{}.
GC_IFACE, // interface{...}.
GC_SLICE, // Go slice.
GC_REGION, // A region/part of the current object.
GC_NUM_INSTR // Number of instruction opcodes
};
// The GC Stack Capacity must match the value in libgo/runtime/mgc0.h.
static const int GC_STACK_CAPACITY = 8;
// To build the complete list of methods for a named type we need to
// gather all methods from anonymous fields. Those methods may
// require an arbitrary set of indirections and field offsets. There
@ -911,6 +933,10 @@ class Type
Bexpression*
type_descriptor_pointer(Gogo* gogo, Location);
// Build the Garbage Collection symbol for this type. Return a pointer to it.
Bexpression*
gc_symbol_pointer(Gogo* gogo);
// Return the type reflection string for this type.
std::string
reflection(Gogo*) const;
@ -995,6 +1021,9 @@ class Type
virtual Expression*
do_type_descriptor(Gogo*, Named_type* name) = 0;
virtual void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int) = 0;
virtual void
do_reflection(Gogo*, std::string*) const = 0;
@ -1050,6 +1079,22 @@ class Type
type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
const Methods*, bool only_value_methods);
// Generate the GC symbol for this TYPE. VALS is the data so far in this
// symbol; extra values will be appended in do_gc_symbol. OFFSET is the
// offset into the symbol where the GC data is located. STACK_SIZE is the
// size of the GC stack when dealing with array types.
static void
gc_symbol(Gogo*, Type* type, Expression_list** vals, Expression** offset,
int stack_size);
// Build a composite literal for the GC symbol of this type.
Expression*
gc_symbol_constructor(Gogo*);
// Advance the OFFSET of the GC symbol by the size of this type.
void
advance_gc_offset(Expression** offset);
// For the benefit of child class reflection string generation.
void
append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
@ -1126,6 +1171,16 @@ class Type
void
make_type_descriptor_var(Gogo*);
// Map unnamed types to type descriptor decls.
typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
Type_identical) GC_symbol_vars;
static GC_symbol_vars gc_symbol_vars;
// Build the GC symbol for this type.
void
make_gc_symbol_var(Gogo*);
// Return the name of the type descriptor variable. If NAME is not
// NULL, it is the name to use.
std::string
@ -1253,6 +1308,9 @@ class Type
// The type descriptor for this type. This starts out as NULL and
// is filled in as needed.
Bvariable* type_descriptor_var_;
// The GC symbol for this type. This starts out as NULL and
// is filled in as needed.
Bvariable* gc_symbol_var_;
};
// Type hash table operations.
@ -1506,6 +1564,10 @@ protected:
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
void
do_mangled_name(Gogo*, std::string*) const;
@ -1583,6 +1645,10 @@ class Float_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
void
do_mangled_name(Gogo*, std::string*) const;
@ -1652,6 +1718,10 @@ class Complex_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
void
do_mangled_name(Gogo*, std::string*) const;
@ -1701,6 +1771,9 @@ class String_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string* ret) const;
@ -1836,6 +1909,9 @@ class Function_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -1952,6 +2028,9 @@ class Pointer_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -2250,6 +2329,9 @@ class Struct_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -2392,6 +2474,9 @@ class Array_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -2408,6 +2493,12 @@ class Array_type : public Type
Expression*
slice_type_descriptor(Gogo*, Named_type*);
void
slice_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
array_gc_symbol(Gogo*, Expression_list**, Expression**, int);
// The type of elements of the array.
Type* element_type_;
// The number of elements. This may be NULL.
@ -2484,6 +2575,9 @@ class Map_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -2570,6 +2664,9 @@ class Channel_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -2703,6 +2800,9 @@ class Interface_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const;
@ -2988,6 +3088,10 @@ class Named_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
int stack);
void
do_mangled_name(Gogo*, std::string* ret) const;
@ -3132,6 +3236,11 @@ class Forward_declaration_type : public Type
void
do_reflection(Gogo*, std::string*) const;
void
do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
int stack_size)
{ Type::gc_symbol(gogo, this->real_type(), vals, offset, stack_size); }
void
do_mangled_name(Gogo*, std::string* ret) const;

View File

@ -255,6 +255,7 @@ type rtype struct {
hashfn uintptr // hash function code
equalfn uintptr // equality function code
gc unsafe.Pointer // garbage collection data
string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
@ -1130,6 +1131,18 @@ func (t *rtype) ptrTo() *rtype {
p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t
if t.kind&kindNoPointers != 0 {
p.gc = unsafe.Pointer(&ptrDataGCProg)
} else {
p.gc = unsafe.Pointer(&ptrGC{
width: p.size,
op: _GC_PTR,
off: 0,
elemgc: t.gc,
end: _GC_END,
})
}
q := canonicalize(&p.rtype)
p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
@ -1471,8 +1484,16 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.ptrToThis = nil
ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0])
ch.gc = unsafe.Pointer(&chanGC{
width: ch.size,
op: _GC_CHAN_PTR,
off: 0,
typ: &ch.rtype,
end: _GC_END,
})
// INCORRECT. Uncomment to check that TestChanOfGC fails when ch.gc is wrong.
//ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
// ch.gc = unsafe.Pointer(&badGC{width: ch.size, end: _GC_END})
return cachePut(ckey, &ch.rtype)
}
@ -1524,10 +1545,13 @@ func MapOf(key, elem Type) Type {
// width: unsafe.Sizeof(uintptr(0)),
// op: _GC_PTR,
// off: 0,
// elemgc: mt.hmap.gc,
// elemgc: nil,
// end: _GC_END,
// })
// TODO(cmang): Generate GC data for Map elements.
mt.gc = unsafe.Pointer(&ptrDataGCProg)
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong.
//mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
@ -1593,8 +1617,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
// Take the GC program for "t" and append it to the GC program "gc".
func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
// p := t.gc
var p unsafe.Pointer
p := t.gc
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop:
for {
@ -1707,8 +1730,20 @@ func SliceOf(t Type) Type {
slice.ptrToThis = nil
slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0])
if typ.size == 0 {
slice.gc = unsafe.Pointer(&sliceEmptyGCProg)
} else {
slice.gc = unsafe.Pointer(&sliceGC{
width: slice.size,
op: _GC_SLICE,
off: 0,
elemgc: typ.gc,
end: _GC_END,
})
}
// INCORRECT. Uncomment to check that TestSliceOfOfGC fails when slice.gc is wrong.
//slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
// slice.gc = unsafe.Pointer(&badGC{width: slice.size, end: _GC_END})
return cachePut(ckey, &slice.rtype)
}

View File

@ -15,7 +15,7 @@ package runtime
import "unsafe"
type rtype struct {
Kind uint8
kind uint8
align uint8
fieldAlign uint8
size uintptr
@ -24,6 +24,7 @@ type rtype struct {
hashfn func(unsafe.Pointer, uintptr) uintptr
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
gc unsafe.Pointer
string *string
*uncommonType
ptrToThis *rtype

View File

@ -59,7 +59,7 @@ struct String;
#define GO_CODE_MASK 0x7f
/* For each Go type the compiler constructs one of these structures.
This is used for type reflectin, interfaces, maps, and reference
This is used for type reflection, interfaces, maps, and reference
counting. */
struct __go_type_descriptor
@ -93,6 +93,9 @@ struct __go_type_descriptor
size of this type, and returns whether the values are equal. */
_Bool (*__equalfn) (const void *, const void *, uintptr_t);
/* The garbage collection data. */
const uintptr *__gc;
/* A string describing this type. This is only used for
debugging. */
const struct String *__reflection;

View File

@ -8,6 +8,7 @@
#include "runtime.h"
#include "go-type.h"
#include "mgc0.h"
/* A pointer with a zero value. */
static void *zero_pointer;
@ -20,6 +21,9 @@ static void *zero_pointer;
extern const struct __go_type_descriptor unsafe_Pointer
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer");
extern const uintptr unsafe_Pointer_gc[]
__asm__ (GOSYM_PREFIX "__go_tdn_unsafe.Pointer$gc");
/* Used to determine the field alignment. */
struct field_align
{
@ -35,6 +39,8 @@ static const String reflection_string =
sizeof REFLECTION - 1
};
const uintptr unsafe_Pointer_gc[] = {8, GC_APTR, 0, GC_END};
const struct __go_type_descriptor unsafe_Pointer =
{
/* __code */
@ -51,6 +57,8 @@ const struct __go_type_descriptor unsafe_Pointer =
__go_type_hash_identity,
/* __equalfn */
__go_type_equal_identity,
/* __gc */
unsafe_Pointer_gc,
/* __reflection */
&reflection_string,
/* __uncommon */
@ -94,6 +102,8 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
__go_type_hash_identity,
/* __equalfn */
__go_type_equal_identity,
/* __gc */
unsafe_Pointer_gc,
/* __reflection */
&preflection_string,
/* __uncommon */

View File

@ -181,7 +181,7 @@ struct Finalizer
FuncVal *fn;
void *arg;
const struct __go_func_type *ft;
const struct __go_ptr_type *ot;
const PtrType *ot;
};
typedef struct FinBlock FinBlock;
@ -403,8 +403,6 @@ struct BufferList
};
static BufferList bufferList[MaxGcproc];
static Type *itabtype;
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// flushptrbuf moves data from the PtrTarget buffer to the work buffer.
@ -649,23 +647,22 @@ flushobjbuf(Scanbuf *sbuf)
// Program that scans the whole block and treats every block element as a potential pointer
static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
#if 0
// Hchan program
static uintptr chanProg[2] = {0, GC_CHAN};
#endif
// Local variables of a program fragment or loop
typedef struct Frame Frame;
struct Frame {
uintptr count, elemsize, b;
uintptr *loop_or_ret;
const uintptr *loop_or_ret;
};
// Sanity check for the derived type info objti.
static void
checkptr(void *obj, uintptr objti)
{
uintptr type, tisize, i, x;
uintptr *pc1, type, tisize, i, j, x;
const uintptr *pc2;
byte *objstart;
Type *t;
MSpan *s;
@ -703,9 +700,8 @@ checkptr(void *obj, uintptr objti)
(runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") &&
// Runtime and gc think differently about closures.
runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
#if 0
pc1 = (uintptr*)objti;
pc2 = (uintptr*)t->gc;
pc2 = (const uintptr*)t->__gc;
// A simple best-effort check until first GC_END.
for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
if(pc1[j] != pc2[j]) {
@ -714,7 +710,6 @@ checkptr(void *obj, uintptr objti)
runtime_throw("invalid gc type info");
}
}
#endif
}
}
@ -728,11 +723,10 @@ static void
scanblock(Workbuf *wbuf, bool keepworking)
{
byte *b, *arena_start, *arena_used;
uintptr n, i, end_b, elemsize, size, ti, objti, count, /* type, */ nobj;
uintptr *pc, precise_type, nominal_size;
#if 0
uintptr *chan_ret, chancap;
#endif
uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
uintptr precise_type, nominal_size;
const uintptr *pc, *chan_ret;
uintptr chancap;
void *obj;
const Type *t, *et;
Slice *sliceptr;
@ -742,10 +736,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
Scanbuf sbuf;
Eface *eface;
Iface *iface;
#if 0
Hchan *chan;
ChanType *chantype;
#endif
const ChanType *chantype;
Obj *wp;
if(sizeof(Workbuf) % WorkbufSize != 0)
@ -782,11 +774,9 @@ scanblock(Workbuf *wbuf, bool keepworking)
sbuf.nobj = nobj;
// (Silence the compiler)
#if 0
chan = nil;
chantype = nil;
chan_ret = nil;
#endif
goto next_block;
@ -800,7 +790,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
runtime_xadd64(&gcstats.obj.cnt, 1);
}
if(ti != 0 && false) {
if(ti != 0) {
if(Debug > 1) {
runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
}
@ -826,11 +816,10 @@ scanblock(Workbuf *wbuf, bool keepworking)
runtime_throw("invalid gc type info");
}
}
} else if(UseSpanType && false) {
} else if(UseSpanType) {
if(CollectStats)
runtime_xadd64(&gcstats.obj.notype, 1);
#if 0
type = runtime_gettype(b);
if(type != 0) {
if(CollectStats)
@ -839,13 +828,13 @@ scanblock(Workbuf *wbuf, bool keepworking)
t = (Type*)(type & ~(uintptr)(PtrSize-1));
switch(type & (PtrSize-1)) {
case TypeInfo_SingleObject:
pc = (uintptr*)t->gc;
pc = (const uintptr*)t->__gc;
precise_type = true; // type information about 'b' is precise
stack_top.count = 1;
stack_top.elemsize = pc[0];
break;
case TypeInfo_Array:
pc = (uintptr*)t->gc;
pc = (const uintptr*)t->__gc;
if(pc[0] == 0)
goto next_block;
precise_type = true; // type information about 'b' is precise
@ -855,7 +844,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
break;
case TypeInfo_Chan:
chan = (Hchan*)b;
chantype = (ChanType*)t;
chantype = (const ChanType*)t;
chan_ret = nil;
pc = chanProg;
break;
@ -872,7 +861,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
if(Debug > 1)
runtime_printf("scanblock %p %D unknown type\n", b, (int64)n);
}
#endif
} else {
pc = defaultProg;
if(Debug > 1)
@ -954,7 +942,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
// eface->__object
if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) {
if(t->__size <= sizeof(void*)) {
if(__go_is_pointer_type(t)) {
if((t->__code & KindNoPointers))
continue;
@ -965,13 +953,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem;
if(!(et->__code & KindNoPointers))
// objti = (uintptr)((const PtrType*)t)->elem->gc;
objti = 0;
objti = (uintptr)((const PtrType*)t)->elem->__gc;
}
} else {
obj = eface->__object;
// objti = (uintptr)t->gc;
objti = 0;
objti = (uintptr)t->__gc;
}
}
break;
@ -986,16 +972,15 @@ scanblock(Workbuf *wbuf, bool keepworking)
// iface->tab
if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) {
*sbuf.ptr.pos++ = (PtrTarget){iface->tab, /* (uintptr)itabtype->gc */ 0};
*sbuf.ptr.pos++ = (PtrTarget){iface->tab, 0};
if(sbuf.ptr.pos == sbuf.ptr.end)
flushptrbuf(&sbuf);
}
// iface->data
if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
// t = iface->tab->type;
t = nil;
if(t->__size <= sizeof(void*)) {
t = (const Type*)iface->tab[0];
if(__go_is_pointer_type(t)) {
if((t->__code & KindNoPointers))
continue;
@ -1006,13 +991,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
// dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem;
if(!(et->__code & KindNoPointers))
// objti = (uintptr)((const PtrType*)t)->elem->gc;
objti = 0;
objti = (uintptr)((const PtrType*)t)->elem->__gc;
}
} else {
obj = iface->__object;
// objti = (uintptr)t->gc;
objti = 0;
objti = (uintptr)t->__gc;
}
}
break;
@ -1092,7 +1075,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
// Stack push.
*stack_ptr-- = stack_top;
stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/};
pc = (uintptr*)((byte*)pc + *(int32*)(pc+2)); // target of the CALL instruction
pc = (const uintptr*)((const byte*)pc + *(const int32*)(pc+2)); // target of the CALL instruction
continue;
case GC_REGION:
@ -1108,7 +1091,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
flushobjbuf(&sbuf);
continue;
#if 0
case GC_CHAN_PTR:
chan = *(Hchan**)(stack_top.b + pc[1]);
if(Debug > 2 && chan != nil)
@ -1141,8 +1123,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
// in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.)
*sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size,
(uintptr)chantype->elem->gc | PRECISE | LOOP};
*sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
(uintptr)chantype->elem->__gc | PRECISE | LOOP};
if(sbuf.obj.pos == sbuf.obj.end)
flushobjbuf(&sbuf);
}
@ -1151,7 +1133,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
goto next_block;
pc = chan_ret;
continue;
#endif
default:
runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
@ -1828,7 +1809,7 @@ runtime_MSpan_Sweep(MSpan *s)
}
// State of background sweep.
// Pretected by gclock.
// Protected by gclock.
static struct
{
G* g;
@ -2260,12 +2241,6 @@ gc(struct gc_args *args)
work.markfor = runtime_parforalloc(MaxGcproc);
m->locks--;
if(itabtype == nil) {
// get C pointer to the Go type "itab"
// runtime_gc_itab_ptr(&eface);
// itabtype = ((PtrType*)eface.__type_descriptor)->elem;
}
t1 = 0;
if(runtime_debug.gctrace)
t1 = runtime_nanotime();

View File

@ -800,7 +800,7 @@ uintptr runtime_memlimit(void);
enum
{
UseSpanType = 0,
UseSpanType = 1,
};
#define runtime_setitimer setitimer