mirror of
https://github.com/golang/go
synced 2024-11-22 02:04: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
|
SymExported = 1<<2, // already written out by export
|
||||||
SymUniq = 1<<3,
|
SymUniq = 1<<3,
|
||||||
SymSiggen = 1<<4,
|
SymSiggen = 1<<4,
|
||||||
|
SymGcgen = 1<<5,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Sym
|
struct Sym
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include "go.h"
|
#include "go.h"
|
||||||
|
#include "../../pkg/runtime/mgc0.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* runtime interface and reflection data structures
|
* runtime interface and reflection data structures
|
||||||
@ -14,6 +15,7 @@ static NodeList* signatlist;
|
|||||||
static Sym* dtypesym(Type*);
|
static Sym* dtypesym(Type*);
|
||||||
static Sym* weaktypesym(Type*);
|
static Sym* weaktypesym(Type*);
|
||||||
static Sym* dalgsym(Type*);
|
static Sym* dalgsym(Type*);
|
||||||
|
static Sym* dgcsym(Type*);
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sigcmp(Sig *a, Sig *b)
|
sigcmp(Sig *a, Sig *b)
|
||||||
@ -586,7 +588,7 @@ dcommontype(Sym *s, int ot, Type *t)
|
|||||||
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
|
ot = dsymptr(s, ot, algarray, alg*sizeofAlg);
|
||||||
else
|
else
|
||||||
ot = dsymptr(s, ot, algsym, 0);
|
ot = dsymptr(s, ot, algsym, 0);
|
||||||
ot = duintptr(s, ot, 0); // gc
|
ot = dsymptr(s, ot, dgcsym(t), 0); // gc
|
||||||
p = smprint("%-uT", t);
|
p = smprint("%-uT", t);
|
||||||
//print("dcommontype: %s\n", p);
|
//print("dcommontype: %s\n", p);
|
||||||
ot = dgostringptr(s, ot, p); // string
|
ot = dgostringptr(s, ot, p); // string
|
||||||
@ -970,3 +972,177 @@ dalgsym(Type *t)
|
|||||||
return s;
|
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 {
|
func workthegc() []byte {
|
||||||
return make([]byte, 1029)
|
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