compiler, runtime: include ptrmask in GC roots

Change the list of registered GC roots to include a ptrmask,
and change the data structures to be easily used from Go code.
The new ptrmask will be used by the Go 1.8 GC to only scan pointers.
Tweak the current GC to use the new structures, but ignore the new
ptrmask information for now.

The new GC root data includes the size of the variable.  The size is
not currently used, but will be used later by the cgo checking code.

Change-Id: I9307f21a9fedc8c88e7afd5c1284675ed77fd406
Reviewed-on: https://go-review.googlesource.com/41075
Reviewed-by: Than McIntosh <thanm@google.com>
diff --git a/go/gogo.cc b/go/gogo.cc
index cae4f7d..bea2e29 100644
--- a/go/gogo.cc
+++ b/go/gogo.cc
@@ -720,15 +720,18 @@
 // roots during the mark phase.  We build a struct that is easy to
 // hook into a list of roots.
 
-// struct __go_gc_root_list
-// {
-//   struct __go_gc_root_list* __next;
-//   struct __go_gc_root
-//   {
-//     void* __decl;
-//     size_t __size;
-//   } __roots[];
-// };
+// type gcRoot struct {
+// 	decl    unsafe.Pointer // Pointer to variable.
+//	size    uintptr        // Total size of variable.
+// 	ptrdata uintptr        // Length of variable's gcdata.
+// 	gcdata  *byte          // Pointer mask.
+// }
+//
+// type gcRootList struct {
+// 	next  *gcRootList
+// 	count int
+// 	roots [...]gcRoot
+// }
 
 // The last entry in the roots array has a NULL decl field.
 
@@ -737,28 +740,35 @@
 		       std::vector<Bstatement*>& init_stmts,
                        Bfunction* init_bfn)
 {
-  if (var_gc.empty())
+  if (var_gc.empty() && this->gc_roots_.empty())
     return;
 
   Type* pvt = Type::make_pointer_type(Type::make_void_type());
-  Type* uint_type = Type::lookup_integer_type("uint");
-  Struct_type* root_type = Type::make_builtin_struct_type(2,
-                                                          "__decl", pvt,
-                                                          "__size", uint_type);
+  Type* uintptr_type = Type::lookup_integer_type("uintptr");
+  Type* byte_type = this->lookup_global("byte")->type_value();
+  Type* pointer_byte_type = Type::make_pointer_type(byte_type);
+  Struct_type* root_type =
+    Type::make_builtin_struct_type(4,
+				   "decl", pvt,
+				   "size", uintptr_type,
+				   "ptrdata", uintptr_type,
+				   "gcdata", pointer_byte_type);
 
   Location builtin_loc = Linemap::predeclared_location();
-  unsigned roots_len = var_gc.size() + this->gc_roots_.size() + 1;
+  unsigned long roots_len = var_gc.size() + this->gc_roots_.size();
   Expression* length = Expression::make_integer_ul(roots_len, NULL,
                                                    builtin_loc);
   Array_type* root_array_type = Type::make_array_type(root_type, length);
   root_array_type->set_is_array_incomparable();
-  Type* ptdt = Type::make_type_descriptor_ptr_type();
-  Struct_type* root_list_type =
-      Type::make_builtin_struct_type(2,
-                                     "__next", ptdt,
-                                     "__roots", root_array_type);
 
-  // Build an initializer for the __roots array.
+  Type* int_type = Type::lookup_integer_type("int");
+  Struct_type* root_list_type =
+      Type::make_builtin_struct_type(3,
+                                     "next", pvt,
+				     "count", int_type,
+                                     "roots", root_array_type);
+
+  // Build an initializer for the roots array.
 
   Expression_list* roots_init = new Expression_list();
 
@@ -772,11 +782,22 @@
       Expression* decl = Expression::make_var_reference(*p, no_loc);
       Expression* decl_addr =
           Expression::make_unary(OPERATOR_AND, decl, no_loc);
+      decl_addr->unary_expression()->set_does_not_escape();
+      decl_addr = Expression::make_cast(pvt, decl_addr, no_loc);
       init->push_back(decl_addr);
 
-      Expression* decl_size =
-          Expression::make_type_info(decl->type(), Expression::TYPE_INFO_SIZE);
-      init->push_back(decl_size);
+      Expression* size =
+	Expression::make_type_info(decl->type(),
+				   Expression::TYPE_INFO_SIZE);
+      init->push_back(size);
+
+      Expression* ptrdata =
+	Expression::make_type_info(decl->type(),
+				   Expression::TYPE_INFO_BACKEND_PTRDATA);
+      init->push_back(ptrdata);
+
+      Expression* gcdata = Expression::make_ptrmask_symbol(decl->type());
+      init->push_back(gcdata);
 
       Expression* root_ctor =
           Expression::make_struct_composite_literal(root_type, init, no_loc);
@@ -791,37 +812,35 @@
 
       Expression* expr = *p;
       Location eloc = expr->location();
-      init->push_back(expr);
+      init->push_back(Expression::make_cast(pvt, expr, eloc));
 
       Type* type = expr->type()->points_to();
       go_assert(type != NULL);
+
       Expression* size =
-	Expression::make_type_info(type, Expression::TYPE_INFO_SIZE);
+	Expression::make_type_info(type,
+				   Expression::TYPE_INFO_SIZE);
       init->push_back(size);
 
+      Expression* ptrdata =
+	Expression::make_type_info(type,
+				   Expression::TYPE_INFO_BACKEND_PTRDATA);
+      init->push_back(ptrdata);
+
+      Expression* gcdata = Expression::make_ptrmask_symbol(type);
+      init->push_back(gcdata);
+
       Expression* root_ctor =
 	Expression::make_struct_composite_literal(root_type, init, eloc);
       roots_init->push_back(root_ctor);
     }
 
-  // The list ends with a NULL entry.
-
-  Expression_list* null_init = new Expression_list();
-  Expression* nil = Expression::make_nil(builtin_loc);
-  null_init->push_back(nil);
-
-  Expression *zero = Expression::make_integer_ul(0, NULL, builtin_loc);
-  null_init->push_back(zero);
-
-  Expression* null_root_ctor =
-      Expression::make_struct_composite_literal(root_type, null_init,
-                                                builtin_loc);
-  roots_init->push_back(null_root_ctor);
-
   // Build a constructor for the struct.
 
   Expression_list* root_list_init = new Expression_list();
-  root_list_init->push_back(nil);
+  root_list_init->push_back(Expression::make_nil(builtin_loc));
+  root_list_init->push_back(Expression::make_integer_ul(roots_len, int_type,
+							builtin_loc));
 
   Expression* roots_ctor =
       Expression::make_array_composite_literal(root_array_type, roots_init,
@@ -1432,8 +1451,18 @@
 	      var_inits.push_back(Var_init(no, zero_stmt));
 	    }
 
+	  // Collect a list of all global variables with pointers,
+	  // to register them for the garbage collector.
 	  if (!is_sink && var->type()->has_pointer())
-	    var_gc.push_back(no);
+	    {
+	      // Avoid putting runtime.gcRoots itself on the list.
+	      if (this->compiling_runtime()
+		  && this->package_name() == "runtime"
+		  && Gogo::unpack_hidden_name(no->name()) == "gcRoots")
+		;
+	      else
+		var_gc.push_back(no);
+	    }
 	}
     }
 
diff --git a/libgo/runtime/mgc0.c b/libgo/runtime/mgc0.c
index 0178507..357641d 100644
--- a/libgo/runtime/mgc0.c
+++ b/libgo/runtime/mgc0.c
@@ -1150,10 +1150,10 @@
 	}
 }
 
-static struct root_list* roots;
+static struct gcRootList* roots;
 
 void
-__go_register_gc_roots (struct root_list* r)
+__go_register_gc_roots (struct gcRootList* r)
 {
 	// FIXME: This needs locking if multiple goroutines can call
 	// dlopen simultaneously.
@@ -1245,15 +1245,16 @@
 	case RootData:
 		// For gccgo this is both data and bss.
 		{
-			struct root_list *pl;
+			struct gcRootList *pl;
 
 			for(pl = roots; pl != nil; pl = pl->next) {
-				struct root *pr = &pl->roots[0];
-				while(1) {
+				struct gcRoot *pr = &pl->roots[0];
+				intgo count = pl->count;
+				intgo i;
+
+				for (i = 0; i < count; i++) {
 					void *decl = pr->decl;
-					if(decl == nil)
-						break;
-					enqueue1(&wbuf, (Obj){decl, pr->size, 0});
+					enqueue1(&wbuf, (Obj){decl, pr->ptrdata, 0});
 					pr++;
 				}
 			}
diff --git a/libgo/runtime/runtime.h b/libgo/runtime/runtime.h
index e12d506..b3bc03a 100644
--- a/libgo/runtime/runtime.h
+++ b/libgo/runtime/runtime.h
@@ -516,15 +516,20 @@
   __asm__ (GOSYM_PREFIX "runtime.check");
 
 // A list of global variables that the garbage collector must scan.
-struct root_list {
-	struct root_list *next;
-	struct root {
-		void *decl;
-		size_t size;
-	} roots[];
+struct gcRoot {
+	void*   decl;
+	uintptr size;
+	uintptr ptrdata;
+	void*   gcdata; // Not yet used.
 };
 
-void	__go_register_gc_roots(struct root_list*);
+struct gcRootList {
+	struct gcRootList* next;
+	intgo              count;
+	struct gcRoot      roots[];
+};
+
+void	__go_register_gc_roots(struct gcRootList*);
 
 // Size of stack space allocated using Go's allocator.
 // This will be 0 when using split stacks, as in that case