Commit f1d2ac4f by Chris Manghane Committed by Ian Lance Taylor

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
parent d2e4feca
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> 2014-08-08 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::compound_statement): Don't return * go-gcc.cc (Gcc_backend::compound_statement): Don't return
......
...@@ -389,9 +389,16 @@ class Gcc_backend : public Backend ...@@ -389,9 +389,16 @@ class Gcc_backend : public Backend
Location, Bstatement**); Location, Bstatement**);
Bvariable* Bvariable*
implicit_variable(const std::string&, Btype*, Bexpression*, bool, bool, implicit_variable(const std::string&, Btype*, bool, bool, bool,
size_t); 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* Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location); immutable_struct(const std::string&, bool, bool, Btype*, Location);
...@@ -2505,45 +2512,101 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, ...@@ -2505,45 +2512,101 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
Bvariable* Bvariable*
Gcc_backend::implicit_variable(const std::string& name, Btype* type, 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) bool is_common, size_t alignment)
{ {
tree type_tree = type->get_tree(); tree type_tree = type->get_tree();
tree init_tree; if (type_tree == error_mark_node)
if (init == NULL)
init_tree = NULL_TREE;
else
init_tree = init->get_tree();
if (type_tree == error_mark_node || init_tree == error_mark_node)
return this->error_variable(); return this->error_variable();
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
get_identifier_from_string(name), type_tree); get_identifier_from_string(name), type_tree);
DECL_EXTERNAL(decl) = 0; DECL_EXTERNAL(decl) = 0;
TREE_PUBLIC(decl) = 0; TREE_PUBLIC(decl) = !is_hidden;
TREE_STATIC(decl) = 1; TREE_STATIC(decl) = 1;
TREE_USED(decl) = 1;
DECL_ARTIFICIAL(decl) = 1; DECL_ARTIFICIAL(decl) = 1;
if (is_common) if (is_common)
{ {
DECL_COMMON(decl) = 1; 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_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1; TREE_CONSTANT(decl) = 1;
} }
DECL_INITIAL(decl) = init_tree;
if (alignment != 0) if (alignment != 0)
{ {
DECL_ALIGN(decl) = alignment * BITS_PER_UNIT; DECL_ALIGN(decl) = alignment * BITS_PER_UNIT;
DECL_USER_ALIGN(decl) = 1; DECL_USER_ALIGN(decl) = 1;
} }
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); 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); return new Bvariable(decl);
} }
......
...@@ -545,24 +545,55 @@ class Backend ...@@ -545,24 +545,55 @@ class Backend
Bstatement** pstatement) = 0; Bstatement** pstatement) = 0;
// Create an implicit variable that is compiler-defined. This is // Create an implicit variable that is compiler-defined. This is
// used when generating GC root variables, when storing the values // used when generating GC data and roots, when storing the values
// of a slice constructor, and for the zero value of types. NAME is // of a slice constructor, and for the zero value of types. This returns a
// the name of the variable, either gc# for GC roots or C# for slice // Bvariable because it corresponds to an initialized variable in C.
// initializers. TYPE is the type of the implicit variable with an //
// initial value INIT. IS_CONSTANT is true if the implicit variable // NAME is the name to use for the initialized variable this will create.
// should be treated like it is immutable. For slice initializers, //
// if the values must be copied to the heap, the variable // TYPE is the type of the implicit variable.
// IS_CONSTANT. IS_COMMON is true if the implicit variable should //
// 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 // be treated as a common variable (multiple definitions with
// different sizes permitted in different object files, all merged // different sizes permitted in different object files, all merged
// into the largest definition at link time); this will be true for // 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 // the zero value. IS_HIDDEN and IS_COMMON will never both be true.
// variable should be initialized to all zeros. If ALIGNMENT is not //
// zero, it is the desired alignment of the variable. // If ALIGNMENT is not zero, it is the desired alignment of the variable.
virtual Bvariable* 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; 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 // Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function // used for type descriptors, map descriptors, and function
// descriptors. This returns a Bvariable because it corresponds to // descriptors. This returns a Bvariable because it corresponds to
......
...@@ -3440,6 +3440,9 @@ class Unsafe_type_conversion_expression : public Expression ...@@ -3440,6 +3440,9 @@ class Unsafe_type_conversion_expression : public Expression
int int
do_traverse(Traverse* traverse); do_traverse(Traverse* traverse);
bool
do_is_immutable() const;
Type* Type*
do_type() do_type()
{ return this->type_; } { return this->type_; }
...@@ -3480,6 +3483,27 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse) ...@@ -3480,6 +3483,27 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE; 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. // Convert to backend representation.
Bexpression* Bexpression*
...@@ -4115,8 +4139,11 @@ Unary_expression::do_get_backend(Translate_context* context) ...@@ -4115,8 +4139,11 @@ Unary_expression::do_get_backend(Translate_context* context)
&& !context->is_const()); && !context->is_const());
} }
Bvariable* implicit = Bvariable* implicit =
gogo->backend()->implicit_variable(buf, btype, bexpr, copy_to_heap, gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
false, 0); false, 0);
gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
true, copy_to_heap, false,
bexpr);
bexpr = gogo->backend()->var_expression(implicit, loc); bexpr = gogo->backend()->var_expression(implicit, loc);
} }
else if ((this->expr_->is_composite_literal() else if ((this->expr_->is_composite_literal()
...@@ -13987,6 +14014,65 @@ Expression::make_type_descriptor(Type* type, Location location) ...@@ -13987,6 +14014,65 @@ Expression::make_type_descriptor(Type* type, Location location)
return new Type_descriptor_expression(type, 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. // An expression which evaluates to some characteristic of a type.
// This is only used to initialize fields of a type descriptor. Using // This is only used to initialize fields of a type descriptor. Using
// a new expression class is slightly inefficient but gives us a good // a new expression class is slightly inefficient but gives us a good
......
...@@ -103,6 +103,7 @@ class Expression ...@@ -103,6 +103,7 @@ class Expression
EXPRESSION_HEAP, EXPRESSION_HEAP,
EXPRESSION_RECEIVE, EXPRESSION_RECEIVE,
EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_GC_SYMBOL,
EXPRESSION_TYPE_INFO, EXPRESSION_TYPE_INFO,
EXPRESSION_SLICE_INFO, EXPRESSION_SLICE_INFO,
EXPRESSION_SLICE_VALUE, EXPRESSION_SLICE_VALUE,
...@@ -349,6 +350,11 @@ class Expression ...@@ -349,6 +350,11 @@ class Expression
static Expression* static Expression*
make_type_descriptor(Type* type, Location); 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 // Make an expression which evaluates to some characteristic of a
// type. These are only used for type descriptors, so there is no // type. These are only used for type descriptors, so there is no
// location parameter. // location parameter.
...@@ -1513,6 +1519,10 @@ class Binary_expression : public Expression ...@@ -1513,6 +1519,10 @@ class Binary_expression : public Expression
{ return this->left_->is_constant() && this->right_->is_constant(); } { return this->left_->is_constant() && this->right_->is_constant(); }
bool bool
do_is_immutable() const
{ return this->left_->is_immutable() && this->right_->is_immutable(); }
bool
do_numeric_constant_value(Numeric_constant*) const; do_numeric_constant_value(Numeric_constant*) const;
bool bool
......
...@@ -655,9 +655,13 @@ Gogo::backend_zero_value() ...@@ -655,9 +655,13 @@ Gogo::backend_zero_value()
Btype* barray_type = this->backend()->array_type(bbtype_type, blength); Btype* barray_type = this->backend()->array_type(bbtype_type, blength);
return this->backend()->implicit_variable(this->zero_value_->name(), std::string zname = this->zero_value_->name();
barray_type, NULL, true, true, Bvariable* zvar =
this->zero_value_align_); 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 // Add statements to INIT_STMTS which run the initialization
...@@ -6837,8 +6841,10 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls, ...@@ -6837,8 +6841,10 @@ Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
{ {
named_type-> named_type->
type_descriptor_pointer(gogo, Linemap::predeclared_location()); type_descriptor_pointer(gogo, Linemap::predeclared_location());
named_type->gc_symbol_pointer(gogo);
Type* pn = Type::make_pointer_type(named_type); Type* pn = Type::make_pointer_type(named_type);
pn->type_descriptor_pointer(gogo, Linemap::predeclared_location()); pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
pn->gc_symbol_pointer(gogo);
} }
} }
break; break;
......
...@@ -83,6 +83,28 @@ static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26; ...@@ -83,6 +83,28 @@ static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
static const int RUNTIME_TYPE_KIND_NO_POINTERS = (1 << 7); 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 // To build the complete list of methods for a named type we need to
// gather all methods from anonymous fields. Those methods may // gather all methods from anonymous fields. Those methods may
// require an arbitrary set of indirections and field offsets. There // require an arbitrary set of indirections and field offsets. There
...@@ -911,6 +933,10 @@ class Type ...@@ -911,6 +933,10 @@ class Type
Bexpression* Bexpression*
type_descriptor_pointer(Gogo* gogo, Location); 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. // Return the type reflection string for this type.
std::string std::string
reflection(Gogo*) const; reflection(Gogo*) const;
...@@ -996,6 +1022,9 @@ class Type ...@@ -996,6 +1022,9 @@ class Type
do_type_descriptor(Gogo*, Named_type* name) = 0; do_type_descriptor(Gogo*, Named_type* name) = 0;
virtual void virtual void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int) = 0;
virtual void
do_reflection(Gogo*, std::string*) const = 0; do_reflection(Gogo*, std::string*) const = 0;
virtual void virtual void
...@@ -1050,6 +1079,22 @@ class Type ...@@ -1050,6 +1079,22 @@ class Type
type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*, type_descriptor_constructor(Gogo*, int runtime_type_kind, Named_type*,
const Methods*, bool only_value_methods); 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. // For the benefit of child class reflection string generation.
void void
append_reflection(const Type* type, Gogo* gogo, std::string* ret) const append_reflection(const Type* type, Gogo* gogo, std::string* ret) const
...@@ -1126,6 +1171,16 @@ class Type ...@@ -1126,6 +1171,16 @@ class Type
void void
make_type_descriptor_var(Gogo*); 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 // Return the name of the type descriptor variable. If NAME is not
// NULL, it is the name to use. // NULL, it is the name to use.
std::string std::string
...@@ -1253,6 +1308,9 @@ class Type ...@@ -1253,6 +1308,9 @@ class Type
// The type descriptor for this type. This starts out as NULL and // The type descriptor for this type. This starts out as NULL and
// is filled in as needed. // is filled in as needed.
Bvariable* type_descriptor_var_; 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. // Type hash table operations.
...@@ -1507,6 +1565,10 @@ protected: ...@@ -1507,6 +1565,10 @@ protected:
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
private: private:
...@@ -1584,6 +1646,10 @@ class Float_type : public Type ...@@ -1584,6 +1646,10 @@ class Float_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
private: private:
...@@ -1653,6 +1719,10 @@ class Complex_type : public Type ...@@ -1653,6 +1719,10 @@ class Complex_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression** offset, int)
{ this->advance_gc_offset(offset); }
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
private: private:
...@@ -1702,6 +1772,9 @@ class String_type : public Type ...@@ -1702,6 +1772,9 @@ class String_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string* ret) const; do_mangled_name(Gogo*, std::string* ret) const;
private: private:
...@@ -1837,6 +1910,9 @@ class Function_type : public Type ...@@ -1837,6 +1910,9 @@ class Function_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -1953,6 +2029,9 @@ class Pointer_type : public Type ...@@ -1953,6 +2029,9 @@ class Pointer_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -2251,6 +2330,9 @@ class Struct_type : public Type ...@@ -2251,6 +2330,9 @@ class Struct_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -2393,6 +2475,9 @@ class Array_type : public Type ...@@ -2393,6 +2475,9 @@ class Array_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -2408,6 +2493,12 @@ class Array_type : public Type ...@@ -2408,6 +2493,12 @@ class Array_type : public Type
Expression* Expression*
slice_type_descriptor(Gogo*, Named_type*); 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. // The type of elements of the array.
Type* element_type_; Type* element_type_;
// The number of elements. This may be NULL. // The number of elements. This may be NULL.
...@@ -2485,6 +2576,9 @@ class Map_type : public Type ...@@ -2485,6 +2576,9 @@ class Map_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -2571,6 +2665,9 @@ class Channel_type : public Type ...@@ -2571,6 +2665,9 @@ class Channel_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -2704,6 +2801,9 @@ class Interface_type : public Type ...@@ -2704,6 +2801,9 @@ class Interface_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo*, Expression_list**, Expression**, int);
void
do_mangled_name(Gogo*, std::string*) const; do_mangled_name(Gogo*, std::string*) const;
void void
...@@ -2989,6 +3089,10 @@ class Named_type : public Type ...@@ -2989,6 +3089,10 @@ class Named_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void void
do_gc_symbol(Gogo* gogo, Expression_list** vals, Expression** offset,
int stack);
void
do_mangled_name(Gogo*, std::string* ret) const; do_mangled_name(Gogo*, std::string* ret) const;
void void
...@@ -3133,6 +3237,11 @@ class Forward_declaration_type : public Type ...@@ -3133,6 +3237,11 @@ class Forward_declaration_type : public Type
do_reflection(Gogo*, std::string*) const; do_reflection(Gogo*, std::string*) const;
void 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; do_mangled_name(Gogo*, std::string* ret) const;
void void
......
...@@ -255,6 +255,7 @@ type rtype struct { ...@@ -255,6 +255,7 @@ type rtype struct {
hashfn uintptr // hash function code hashfn uintptr // hash function code
equalfn uintptr // equality function code equalfn uintptr // equality function code
gc unsafe.Pointer // garbage collection data
string *string // string form; unnecessary but undeniably useful string *string // string form; unnecessary but undeniably useful
*uncommonType // (relatively) uncommon fields *uncommonType // (relatively) uncommon fields
ptrToThis *rtype // type for pointer to this type, if used in binary or has methods ptrToThis *rtype // type for pointer to this type, if used in binary or has methods
...@@ -1130,6 +1131,18 @@ func (t *rtype) ptrTo() *rtype { ...@@ -1130,6 +1131,18 @@ func (t *rtype) ptrTo() *rtype {
p.zero = unsafe.Pointer(&make([]byte, p.size)[0]) p.zero = unsafe.Pointer(&make([]byte, p.size)[0])
p.elem = t 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) q := canonicalize(&p.rtype)
p = (*ptrType)(unsafe.Pointer(q.(*rtype))) p = (*ptrType)(unsafe.Pointer(q.(*rtype)))
...@@ -1471,8 +1484,16 @@ func ChanOf(dir ChanDir, t Type) Type { ...@@ -1471,8 +1484,16 @@ func ChanOf(dir ChanDir, t Type) Type {
ch.ptrToThis = nil ch.ptrToThis = nil
ch.zero = unsafe.Pointer(&make([]byte, ch.size)[0]) 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. // 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) return cachePut(ckey, &ch.rtype)
} }
...@@ -1524,10 +1545,13 @@ func MapOf(key, elem Type) Type { ...@@ -1524,10 +1545,13 @@ func MapOf(key, elem Type) Type {
// width: unsafe.Sizeof(uintptr(0)), // width: unsafe.Sizeof(uintptr(0)),
// op: _GC_PTR, // op: _GC_PTR,
// off: 0, // off: 0,
// elemgc: mt.hmap.gc, // elemgc: nil,
// end: _GC_END, // end: _GC_END,
// }) // })
// TODO(cmang): Generate GC data for Map elements.
mt.gc = unsafe.Pointer(&ptrDataGCProg)
// INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues // INCORRECT. Uncomment to check that TestMapOfGC and TestMapOfGCValues
// fail when mt.gc is wrong. // fail when mt.gc is wrong.
//mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END}) //mt.gc = unsafe.Pointer(&badGC{width: mt.size, end: _GC_END})
...@@ -1593,8 +1617,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype { ...@@ -1593,8 +1617,7 @@ func bucketOf(ktyp, etyp *rtype) *rtype {
// Take the GC program for "t" and append it to the GC program "gc". // Take the GC program for "t" and append it to the GC program "gc".
func appendGCProgram(gc []uintptr, t *rtype) []uintptr { func appendGCProgram(gc []uintptr, t *rtype) []uintptr {
// p := t.gc p := t.gc
var p unsafe.Pointer
p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size p = unsafe.Pointer(uintptr(p) + unsafe.Sizeof(uintptr(0))) // skip size
loop: loop:
for { for {
...@@ -1707,8 +1730,20 @@ func SliceOf(t Type) Type { ...@@ -1707,8 +1730,20 @@ func SliceOf(t Type) Type {
slice.ptrToThis = nil slice.ptrToThis = nil
slice.zero = unsafe.Pointer(&make([]byte, slice.size)[0]) 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. // 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) return cachePut(ckey, &slice.rtype)
} }
......
...@@ -15,7 +15,7 @@ package runtime ...@@ -15,7 +15,7 @@ package runtime
import "unsafe" import "unsafe"
type rtype struct { type rtype struct {
Kind uint8 kind uint8
align uint8 align uint8
fieldAlign uint8 fieldAlign uint8
size uintptr size uintptr
...@@ -24,6 +24,7 @@ type rtype struct { ...@@ -24,6 +24,7 @@ type rtype struct {
hashfn func(unsafe.Pointer, uintptr) uintptr hashfn func(unsafe.Pointer, uintptr) uintptr
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr) bool
gc unsafe.Pointer
string *string string *string
*uncommonType *uncommonType
ptrToThis *rtype ptrToThis *rtype
......
...@@ -59,7 +59,7 @@ struct String; ...@@ -59,7 +59,7 @@ struct String;
#define GO_CODE_MASK 0x7f #define GO_CODE_MASK 0x7f
/* For each Go type the compiler constructs one of these structures. /* 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. */ counting. */
struct __go_type_descriptor struct __go_type_descriptor
...@@ -93,6 +93,9 @@ struct __go_type_descriptor ...@@ -93,6 +93,9 @@ struct __go_type_descriptor
size of this type, and returns whether the values are equal. */ size of this type, and returns whether the values are equal. */
_Bool (*__equalfn) (const void *, const void *, uintptr_t); _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 /* A string describing this type. This is only used for
debugging. */ debugging. */
const struct String *__reflection; const struct String *__reflection;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "runtime.h" #include "runtime.h"
#include "go-type.h" #include "go-type.h"
#include "mgc0.h"
/* A pointer with a zero value. */ /* A pointer with a zero value. */
static void *zero_pointer; static void *zero_pointer;
...@@ -20,6 +21,9 @@ static void *zero_pointer; ...@@ -20,6 +21,9 @@ static void *zero_pointer;
extern const struct __go_type_descriptor unsafe_Pointer extern const struct __go_type_descriptor unsafe_Pointer
__asm__ (GOSYM_PREFIX "__go_tdn_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. */ /* Used to determine the field alignment. */
struct field_align struct field_align
{ {
...@@ -35,6 +39,8 @@ static const String reflection_string = ...@@ -35,6 +39,8 @@ static const String reflection_string =
sizeof REFLECTION - 1 sizeof REFLECTION - 1
}; };
const uintptr unsafe_Pointer_gc[] = {8, GC_APTR, 0, GC_END};
const struct __go_type_descriptor unsafe_Pointer = const struct __go_type_descriptor unsafe_Pointer =
{ {
/* __code */ /* __code */
...@@ -51,6 +57,8 @@ const struct __go_type_descriptor unsafe_Pointer = ...@@ -51,6 +57,8 @@ const struct __go_type_descriptor unsafe_Pointer =
__go_type_hash_identity, __go_type_hash_identity,
/* __equalfn */ /* __equalfn */
__go_type_equal_identity, __go_type_equal_identity,
/* __gc */
unsafe_Pointer_gc,
/* __reflection */ /* __reflection */
&reflection_string, &reflection_string,
/* __uncommon */ /* __uncommon */
...@@ -94,6 +102,8 @@ const struct __go_ptr_type pointer_unsafe_Pointer = ...@@ -94,6 +102,8 @@ const struct __go_ptr_type pointer_unsafe_Pointer =
__go_type_hash_identity, __go_type_hash_identity,
/* __equalfn */ /* __equalfn */
__go_type_equal_identity, __go_type_equal_identity,
/* __gc */
unsafe_Pointer_gc,
/* __reflection */ /* __reflection */
&preflection_string, &preflection_string,
/* __uncommon */ /* __uncommon */
......
...@@ -181,7 +181,7 @@ struct Finalizer ...@@ -181,7 +181,7 @@ struct Finalizer
FuncVal *fn; FuncVal *fn;
void *arg; void *arg;
const struct __go_func_type *ft; const struct __go_func_type *ft;
const struct __go_ptr_type *ot; const PtrType *ot;
}; };
typedef struct FinBlock FinBlock; typedef struct FinBlock FinBlock;
...@@ -403,8 +403,6 @@ struct BufferList ...@@ -403,8 +403,6 @@ struct BufferList
}; };
static BufferList bufferList[MaxGcproc]; static BufferList bufferList[MaxGcproc];
static Type *itabtype;
static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj); static void enqueue(Obj obj, Workbuf **_wbuf, Obj **_wp, uintptr *_nobj);
// flushptrbuf moves data from the PtrTarget buffer to the work buffer. // flushptrbuf moves data from the PtrTarget buffer to the work buffer.
...@@ -649,23 +647,22 @@ flushobjbuf(Scanbuf *sbuf) ...@@ -649,23 +647,22 @@ flushobjbuf(Scanbuf *sbuf)
// Program that scans the whole block and treats every block element as a potential pointer // Program that scans the whole block and treats every block element as a potential pointer
static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR}; static uintptr defaultProg[2] = {PtrSize, GC_DEFAULT_PTR};
#if 0
// Hchan program // Hchan program
static uintptr chanProg[2] = {0, GC_CHAN}; static uintptr chanProg[2] = {0, GC_CHAN};
#endif
// Local variables of a program fragment or loop // Local variables of a program fragment or loop
typedef struct Frame Frame; typedef struct Frame Frame;
struct Frame { struct Frame {
uintptr count, elemsize, b; uintptr count, elemsize, b;
uintptr *loop_or_ret; const uintptr *loop_or_ret;
}; };
// Sanity check for the derived type info objti. // Sanity check for the derived type info objti.
static void static void
checkptr(void *obj, uintptr objti) checkptr(void *obj, uintptr objti)
{ {
uintptr type, tisize, i, x; uintptr *pc1, type, tisize, i, j, x;
const uintptr *pc2;
byte *objstart; byte *objstart;
Type *t; Type *t;
MSpan *s; MSpan *s;
...@@ -703,9 +700,8 @@ checkptr(void *obj, uintptr objti) ...@@ -703,9 +700,8 @@ checkptr(void *obj, uintptr objti)
(runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") && (runtime_strcmp((const char *)t->string->str, (const char*)"unsafe.Pointer") &&
// Runtime and gc think differently about closures. // Runtime and gc think differently about closures.
runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) { runtime_strstr((const char *)t->string->str, (const char*)"struct { F uintptr") != (const char *)t->string->str)) {
#if 0
pc1 = (uintptr*)objti; pc1 = (uintptr*)objti;
pc2 = (uintptr*)t->gc; pc2 = (const uintptr*)t->__gc;
// A simple best-effort check until first GC_END. // A simple best-effort check until first GC_END.
for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) { for(j = 1; pc1[j] != GC_END && pc2[j] != GC_END; j++) {
if(pc1[j] != pc2[j]) { if(pc1[j] != pc2[j]) {
...@@ -714,7 +710,6 @@ checkptr(void *obj, uintptr objti) ...@@ -714,7 +710,6 @@ checkptr(void *obj, uintptr objti)
runtime_throw("invalid gc type info"); runtime_throw("invalid gc type info");
} }
} }
#endif
} }
} }
...@@ -728,11 +723,10 @@ static void ...@@ -728,11 +723,10 @@ static void
scanblock(Workbuf *wbuf, bool keepworking) scanblock(Workbuf *wbuf, bool keepworking)
{ {
byte *b, *arena_start, *arena_used; byte *b, *arena_start, *arena_used;
uintptr n, i, end_b, elemsize, size, ti, objti, count, /* type, */ nobj; uintptr n, i, end_b, elemsize, size, ti, objti, count, type, nobj;
uintptr *pc, precise_type, nominal_size; uintptr precise_type, nominal_size;
#if 0 const uintptr *pc, *chan_ret;
uintptr *chan_ret, chancap; uintptr chancap;
#endif
void *obj; void *obj;
const Type *t, *et; const Type *t, *et;
Slice *sliceptr; Slice *sliceptr;
...@@ -742,10 +736,8 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -742,10 +736,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
Scanbuf sbuf; Scanbuf sbuf;
Eface *eface; Eface *eface;
Iface *iface; Iface *iface;
#if 0
Hchan *chan; Hchan *chan;
ChanType *chantype; const ChanType *chantype;
#endif
Obj *wp; Obj *wp;
if(sizeof(Workbuf) % WorkbufSize != 0) if(sizeof(Workbuf) % WorkbufSize != 0)
...@@ -782,11 +774,9 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -782,11 +774,9 @@ scanblock(Workbuf *wbuf, bool keepworking)
sbuf.nobj = nobj; sbuf.nobj = nobj;
// (Silence the compiler) // (Silence the compiler)
#if 0
chan = nil; chan = nil;
chantype = nil; chantype = nil;
chan_ret = nil; chan_ret = nil;
#endif
goto next_block; goto next_block;
...@@ -800,7 +790,7 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -800,7 +790,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
runtime_xadd64(&gcstats.obj.cnt, 1); runtime_xadd64(&gcstats.obj.cnt, 1);
} }
if(ti != 0 && false) { if(ti != 0) {
if(Debug > 1) { if(Debug > 1) {
runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti); runtime_printf("scanblock %p %D ti %p\n", b, (int64)n, ti);
} }
...@@ -826,11 +816,10 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -826,11 +816,10 @@ scanblock(Workbuf *wbuf, bool keepworking)
runtime_throw("invalid gc type info"); runtime_throw("invalid gc type info");
} }
} }
} else if(UseSpanType && false) { } else if(UseSpanType) {
if(CollectStats) if(CollectStats)
runtime_xadd64(&gcstats.obj.notype, 1); runtime_xadd64(&gcstats.obj.notype, 1);
#if 0
type = runtime_gettype(b); type = runtime_gettype(b);
if(type != 0) { if(type != 0) {
if(CollectStats) if(CollectStats)
...@@ -839,13 +828,13 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -839,13 +828,13 @@ scanblock(Workbuf *wbuf, bool keepworking)
t = (Type*)(type & ~(uintptr)(PtrSize-1)); t = (Type*)(type & ~(uintptr)(PtrSize-1));
switch(type & (PtrSize-1)) { switch(type & (PtrSize-1)) {
case TypeInfo_SingleObject: case TypeInfo_SingleObject:
pc = (uintptr*)t->gc; pc = (const uintptr*)t->__gc;
precise_type = true; // type information about 'b' is precise precise_type = true; // type information about 'b' is precise
stack_top.count = 1; stack_top.count = 1;
stack_top.elemsize = pc[0]; stack_top.elemsize = pc[0];
break; break;
case TypeInfo_Array: case TypeInfo_Array:
pc = (uintptr*)t->gc; pc = (const uintptr*)t->__gc;
if(pc[0] == 0) if(pc[0] == 0)
goto next_block; goto next_block;
precise_type = true; // type information about 'b' is precise precise_type = true; // type information about 'b' is precise
...@@ -855,7 +844,7 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -855,7 +844,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
break; break;
case TypeInfo_Chan: case TypeInfo_Chan:
chan = (Hchan*)b; chan = (Hchan*)b;
chantype = (ChanType*)t; chantype = (const ChanType*)t;
chan_ret = nil; chan_ret = nil;
pc = chanProg; pc = chanProg;
break; break;
...@@ -872,7 +861,6 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -872,7 +861,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
if(Debug > 1) if(Debug > 1)
runtime_printf("scanblock %p %D unknown type\n", b, (int64)n); runtime_printf("scanblock %p %D unknown type\n", b, (int64)n);
} }
#endif
} else { } else {
pc = defaultProg; pc = defaultProg;
if(Debug > 1) if(Debug > 1)
...@@ -954,7 +942,7 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -954,7 +942,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
// eface->__object // eface->__object
if((byte*)eface->__object >= arena_start && (byte*)eface->__object < arena_used) { 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)) if((t->__code & KindNoPointers))
continue; continue;
...@@ -965,13 +953,11 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -965,13 +953,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
// dgcsym1 in case TPTR32/case TPTR64. See rationale there. // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem; et = ((const PtrType*)t)->elem;
if(!(et->__code & KindNoPointers)) if(!(et->__code & KindNoPointers))
// objti = (uintptr)((const PtrType*)t)->elem->gc; objti = (uintptr)((const PtrType*)t)->elem->__gc;
objti = 0;
} }
} else { } else {
obj = eface->__object; obj = eface->__object;
// objti = (uintptr)t->gc; objti = (uintptr)t->__gc;
objti = 0;
} }
} }
break; break;
...@@ -986,16 +972,15 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -986,16 +972,15 @@ scanblock(Workbuf *wbuf, bool keepworking)
// iface->tab // iface->tab
if((byte*)iface->tab >= arena_start && (byte*)iface->tab < arena_used) { 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) if(sbuf.ptr.pos == sbuf.ptr.end)
flushptrbuf(&sbuf); flushptrbuf(&sbuf);
} }
// iface->data // iface->data
if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) { if((byte*)iface->__object >= arena_start && (byte*)iface->__object < arena_used) {
// t = iface->tab->type; t = (const Type*)iface->tab[0];
t = nil; if(__go_is_pointer_type(t)) {
if(t->__size <= sizeof(void*)) {
if((t->__code & KindNoPointers)) if((t->__code & KindNoPointers))
continue; continue;
...@@ -1006,13 +991,11 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -1006,13 +991,11 @@ scanblock(Workbuf *wbuf, bool keepworking)
// dgcsym1 in case TPTR32/case TPTR64. See rationale there. // dgcsym1 in case TPTR32/case TPTR64. See rationale there.
et = ((const PtrType*)t)->elem; et = ((const PtrType*)t)->elem;
if(!(et->__code & KindNoPointers)) if(!(et->__code & KindNoPointers))
// objti = (uintptr)((const PtrType*)t)->elem->gc; objti = (uintptr)((const PtrType*)t)->elem->__gc;
objti = 0;
} }
} else { } else {
obj = iface->__object; obj = iface->__object;
// objti = (uintptr)t->gc; objti = (uintptr)t->__gc;
objti = 0;
} }
} }
break; break;
...@@ -1092,7 +1075,7 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -1092,7 +1075,7 @@ scanblock(Workbuf *wbuf, bool keepworking)
// Stack push. // Stack push.
*stack_ptr-- = stack_top; *stack_ptr-- = stack_top;
stack_top = (Frame){1, 0, stack_top.b + pc[1], pc+3 /*return address*/}; 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; continue;
case GC_REGION: case GC_REGION:
...@@ -1108,7 +1091,6 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -1108,7 +1091,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
flushobjbuf(&sbuf); flushobjbuf(&sbuf);
continue; continue;
#if 0
case GC_CHAN_PTR: case GC_CHAN_PTR:
chan = *(Hchan**)(stack_top.b + pc[1]); chan = *(Hchan**)(stack_top.b + pc[1]);
if(Debug > 2 && chan != nil) if(Debug > 2 && chan != nil)
...@@ -1141,8 +1123,8 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -1141,8 +1123,8 @@ scanblock(Workbuf *wbuf, bool keepworking)
// in-use part of the circular buffer is scanned. // in-use part of the circular buffer is scanned.
// (Channel routines zero the unused part, so the current // (Channel routines zero the unused part, so the current
// code does not lead to leaks, it's just a little inefficient.) // code does not lead to leaks, it's just a little inefficient.)
*sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->size, *sbuf.obj.pos++ = (Obj){(byte*)chan+runtime_Hchansize, chancap*chantype->elem->__size,
(uintptr)chantype->elem->gc | PRECISE | LOOP}; (uintptr)chantype->elem->__gc | PRECISE | LOOP};
if(sbuf.obj.pos == sbuf.obj.end) if(sbuf.obj.pos == sbuf.obj.end)
flushobjbuf(&sbuf); flushobjbuf(&sbuf);
} }
...@@ -1151,7 +1133,6 @@ scanblock(Workbuf *wbuf, bool keepworking) ...@@ -1151,7 +1133,6 @@ scanblock(Workbuf *wbuf, bool keepworking)
goto next_block; goto next_block;
pc = chan_ret; pc = chan_ret;
continue; continue;
#endif
default: default:
runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc); runtime_printf("runtime: invalid GC instruction %p at %p\n", pc[0], pc);
...@@ -1828,7 +1809,7 @@ runtime_MSpan_Sweep(MSpan *s) ...@@ -1828,7 +1809,7 @@ runtime_MSpan_Sweep(MSpan *s)
} }
// State of background sweep. // State of background sweep.
// Pretected by gclock. // Protected by gclock.
static struct static struct
{ {
G* g; G* g;
...@@ -2260,12 +2241,6 @@ gc(struct gc_args *args) ...@@ -2260,12 +2241,6 @@ gc(struct gc_args *args)
work.markfor = runtime_parforalloc(MaxGcproc); work.markfor = runtime_parforalloc(MaxGcproc);
m->locks--; 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; t1 = 0;
if(runtime_debug.gctrace) if(runtime_debug.gctrace)
t1 = runtime_nanotime(); t1 = runtime_nanotime();
......
...@@ -800,7 +800,7 @@ uintptr runtime_memlimit(void); ...@@ -800,7 +800,7 @@ uintptr runtime_memlimit(void);
enum enum
{ {
UseSpanType = 0, UseSpanType = 1,
}; };
#define runtime_setitimer setitimer #define runtime_setitimer setitimer
......
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