]> Cypherpunks repositories - gostls13.git/commitdiff
gc: generate garbage collection info for types
authorJan Ziak <0xe2.0x9a.0x9b@gmail.com>
Wed, 12 Sep 2012 16:08:27 +0000 (12:08 -0400)
committerRuss Cox <rsc@golang.org>
Wed, 12 Sep 2012 16:08:27 +0000 (12:08 -0400)
R=rsc, nigeltao, minux.ma
CC=golang-dev
https://golang.org/cl/6290043

src/cmd/gc/go.h
src/cmd/gc/reflect.c
src/pkg/runtime/gc_test.go
src/pkg/runtime/mgc0.h [new file with mode: 0644]

index 4a8d191dc7b6c2ea850a85e3d51914ffb5b3144f..5ce9fb9e94e5bcc82afdb9ea67728ac29a2a2ede 100644 (file)
@@ -347,6 +347,7 @@ enum
        SymExported     = 1<<2, // already written out by export
        SymUniq         = 1<<3,
        SymSiggen       = 1<<4,
+       SymGcgen        = 1<<5,
 };
 
 struct Sym
index 7496b71bf2b98cb91c652e45e87024e177c5e21a..9dbf1ec596624a5cba72a9d8924e8685d31b5652 100644 (file)
@@ -5,6 +5,7 @@
 #include <u.h>
 #include <libc.h>
 #include "go.h"
+#include "../../pkg/runtime/mgc0.h"
 
 /*
  * runtime interface and reflection data structures
@@ -14,6 +15,7 @@ static        NodeList*       signatlist;
 static Sym*    dtypesym(Type*);
 static Sym*    weaktypesym(Type*);
 static Sym*    dalgsym(Type*);
+static Sym*    dgcsym(Type*);
 
 static int
 sigcmp(Sig *a, Sig *b)
@@ -586,7 +588,7 @@ dcommontype(Sym *s, int ot, Type *t)
                ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
        else
                ot = dsymptr(s, ot, algsym, 0);
-       ot = duintptr(s, ot, 0);  // gc
+       ot = dsymptr(s, ot, dgcsym(t), 0);  // gc
        p = smprint("%-uT", t);
        //print("dcommontype: %s\n", p);
        ot = dgostringptr(s, ot, p);    // string
@@ -970,3 +972,177 @@ dalgsym(Type *t)
        return s;
 }
 
+static int
+dgcsym1(Sym *s, int ot, Type *t, vlong *off, int stack_size)
+{
+       Type *t1;
+       vlong o, off2, fieldoffset;
+
+       if(t->align > 0 && (*off % t->align) != 0)
+               fatal("dgcsym1: invalid initial alignment, %T", t);
+       
+       switch(t->etype) {
+       case TINT8:
+       case TUINT8:
+       case TINT16:
+       case TUINT16:
+       case TINT32:
+       case TUINT32:
+       case TINT64:
+       case TUINT64:
+       case TINT:
+       case TUINT:
+       case TUINTPTR:
+       case TBOOL:
+       case TFLOAT32:
+       case TFLOAT64:
+       case TCOMPLEX64:
+       case TCOMPLEX128:
+               *off += t->width;
+               break;
+
+       case TPTR32:
+       case TPTR64:
+               if(*off % widthptr != 0)
+                       fatal("dgcsym1: invalid alignment, %T", t);
+               if(!haspointers(t->type) || t->type->etype == TUINT8) {
+                       ot = duintptr(s, ot, GC_APTR);
+                       ot = duintptr(s, ot, *off);
+               } else {
+                       ot = duintptr(s, ot, GC_PTR);
+                       ot = duintptr(s, ot, *off);
+                       ot = dsymptr(s, ot, dgcsym(t->type), 0);
+               }
+               *off += t->width;
+               break;
+
+       case TCHAN:
+       case TUNSAFEPTR:
+       case TFUNC:
+               if(*off % widthptr != 0)
+                       fatal("dgcsym1: invalid alignment, %T", t);
+               ot = duintptr(s, ot, GC_APTR);
+               ot = duintptr(s, ot, *off);
+               *off += t->width;
+               break;
+
+       // struct Hmap*
+       case TMAP:
+               if(*off % widthptr != 0)
+                       fatal("dgcsym1: invalid alignment, %T", t);
+               ot = duintptr(s, ot, GC_MAP_PTR);
+               ot = duintptr(s, ot, *off);
+               ot = dsymptr(s, ot, dtypesym(t), 0);
+               *off += t->width;
+               break;
+
+       // struct { byte *str; int32 len; }
+       case TSTRING:
+               if(*off % widthptr != 0)
+                       fatal("dgcsym1: invalid alignment, %T", t);
+               ot = duintptr(s, ot, GC_STRING);
+               ot = duintptr(s, ot, *off);
+               *off += t->width;
+               break;
+
+       // struct { Itab* tab;  void* data; }
+       // struct { Type* type; void* data; }   // When isnilinter(t)==true
+       case TINTER:
+               if(*off % widthptr != 0)
+                       fatal("dgcsym1: invalid alignment, %T", t);
+               if(isnilinter(t)) {
+                       ot = duintptr(s, ot, GC_EFACE);
+                       ot = duintptr(s, ot, *off);
+               } else {
+                       ot = duintptr(s, ot, GC_IFACE);
+                       ot = duintptr(s, ot, *off);
+               }
+               *off += t->width;
+               break;
+
+       case TARRAY:
+               if(t->bound < -1)
+                       fatal("dgcsym1: invalid bound, %T", t);
+               if(isslice(t)) {
+                       // struct { byte* array; uint32 len; uint32 cap; }
+                       if(*off % widthptr != 0)
+                               fatal("dgcsym1: invalid alignment, %T", t);
+                       if(t->type->width != 0) {
+                               ot = duintptr(s, ot, GC_SLICE);
+                               ot = duintptr(s, ot, *off);
+                               ot = dsymptr(s, ot, dgcsym(t->type), 0);
+                       } else {
+                               ot = duintptr(s, ot, GC_APTR);
+                               ot = duintptr(s, ot, *off);
+                       }
+                       *off += t->width;
+               } else {
+                       if(t->bound < 1 || !haspointers(t->type)) {
+                               *off += t->width;
+                       } else if(t->bound == 1) {
+                               ot = dgcsym1(s, ot, t->type, off, stack_size);  // recursive call of dgcsym1
+                       } else {
+                               if(stack_size < GC_STACK_CAPACITY) {
+                                       ot = duintptr(s, ot, GC_ARRAY_START);  // a stack push during GC
+                                       ot = duintptr(s, ot, *off);
+                                       ot = duintptr(s, ot, t->bound);
+                                       ot = duintptr(s, ot, t->type->width);
+                                       off2 = 0;
+                                       ot = dgcsym1(s, ot, t->type, &off2, stack_size+1);  // recursive call of dgcsym1
+                                       ot = duintptr(s, ot, GC_ARRAY_NEXT);  // a stack pop during GC
+                               } else {
+                                       ot = duintptr(s, ot, GC_REGION);
+                                       ot = duintptr(s, ot, *off);
+                                       ot = duintptr(s, ot, t->width);
+                                       ot = dsymptr(s, ot, dgcsym(t), 0);
+                               }
+                               *off += t->width;
+                       }
+               }
+               break;
+
+       case TSTRUCT:
+               o = 0;
+               for(t1=t->type; t1!=T; t1=t1->down) {
+                       fieldoffset = t1->width;
+                       *off += fieldoffset - o;
+                       ot = dgcsym1(s, ot, t1->type, off, stack_size);  // recursive call of dgcsym1
+                       o = fieldoffset + t1->type->width;
+               }
+               *off += t->width - o;
+               break;
+
+       default:
+               fatal("dgcsym1: unexpected type %T", t);
+       }
+
+       return ot;
+}
+
+static Sym*
+dgcsym(Type *t)
+{
+       int ot;
+       vlong off;
+       Sym *s;
+
+       s = typesymprefix(".gc", t);
+       if(s->flags & SymGcgen)
+               return s;
+       s->flags |= SymGcgen;
+
+       ot = 0;
+       off = 0;
+       ot = duintptr(s, ot, t->width);
+       ot = dgcsym1(s, ot, t, &off, 0);
+       ot = duintptr(s, ot, GC_END);
+       ggloblsym(s, ot, 1, 1);
+
+       if(t->align > 0)
+               off = rnd(off, t->align);
+       if(off != t->width)
+               fatal("dgcsym: off=%lld, size=%lld, type %T", off, t->width, t);
+
+       return s;
+}
+
index 783409b689aaefe0f96641630527381621d6f709..56dd93819e179f1e4a8c65140cfd6fd0203c2d82 100644 (file)
@@ -42,3 +42,19 @@ func TestGcSys(t *testing.T) {
 func workthegc() []byte {
        return make([]byte, 1029)
 }
+
+func TestGcDeepNesting(t *testing.T) {
+       type T [2][2][2][2][2][2][2][2][2][2]*int
+       a := new(T)
+
+       // Prevent the compiler from applying escape analysis.
+       // This makes sure new(T) is allocated on heap, not on the stack.
+       t.Logf("%p", a)
+
+       a[0][0][0][0][0][0][0][0][0][0] = new(int)
+       *a[0][0][0][0][0][0][0][0][0][0] = 13
+       runtime.GC()
+       if *a[0][0][0][0][0][0][0][0][0][0] != 13 {
+               t.Fail()
+       }
+}
diff --git a/src/pkg/runtime/mgc0.h b/src/pkg/runtime/mgc0.h
new file mode 100644 (file)
index 0000000..a2798ef
--- /dev/null
@@ -0,0 +1,42 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Garbage collector (GC)
+
+// GC instruction opcodes.
+//
+// The opcode of an instruction is followed by zero or more
+// arguments to the instruction.
+//
+// Meaning of arguments:
+//   off      Offset (in bytes) from the start of the current object
+//   objgc    Pointer to GC info of an object
+//   len      Length of an array
+//   elemsize Size (in bytes) of an element
+//   size     Size (in bytes)
+enum {
+       GC_END,         // End of object, loop or subroutine. Args: none
+       GC_PTR,         // A typed pointer. Args: (off, objgc)
+       GC_APTR,        // Pointer to an arbitrary object. Args: (off)
+       GC_ARRAY_START, // Start an array with a fixed length. Args: (off, len, elemsize)
+       GC_ARRAY_NEXT,  // The next element of an array. Args: none
+       GC_CALL,        // Call a subroutine. Args: (off, objgc)
+       GC_MAP_PTR,     // Go map. Args: (off, MapType*)
+       GC_STRING,      // Go string. Args: (off)
+       GC_EFACE,       // interface{}. Args: (off)
+       GC_IFACE,       // interface{...}. Args: (off)
+       GC_SLICE,       // Go slice. Args: (off, objgc)
+       GC_REGION,      // A region/part of the current object. Args: (off, size, objgc)
+
+       GC_NUM_INSTR,   // Number of instruction opcodes
+};
+
+enum {
+       // Size of GC's fixed stack.
+       //
+       // The current GC implementation permits:
+       //  - at most 1 stack allocation because of GC_CALL
+       //  - at most GC_STACK_CAPACITY allocations because of GC_ARRAY_START
+       GC_STACK_CAPACITY = 8,  
+};