mirror of
https://github.com/golang/go
synced 2024-11-22 02:34:40 -07:00
gc: generate garbage collection info for types
R=rsc, nigeltao, minux.ma CC=golang-dev https://golang.org/cl/6290043
This commit is contained in:
parent
792518c656
commit
d09afc2efb
@ -347,6 +347,7 @@ enum
|
||||
SymExported = 1<<2, // already written out by export
|
||||
SymUniq = 1<<3,
|
||||
SymSiggen = 1<<4,
|
||||
SymGcgen = 1<<5,
|
||||
};
|
||||
|
||||
struct Sym
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
42
src/pkg/runtime/mgc0.h
Normal file
42
src/pkg/runtime/mgc0.h
Normal file
@ -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,
|
||||
};
|
Loading…
Reference in New Issue
Block a user