104 lines
1.8 KiB
Go
104 lines
1.8 KiB
Go
package vm
|
|
|
|
import "strconv"
|
|
|
|
const staticBit = uint64(1) << 63
|
|
|
|
type object struct {
|
|
gen uint32
|
|
live bool
|
|
mark bool
|
|
str bool
|
|
s string
|
|
elems []Value
|
|
width int
|
|
mask uint32
|
|
size int
|
|
}
|
|
|
|
type heapFull struct {
|
|
limit int
|
|
}
|
|
|
|
func (f heapFull) Error() string {
|
|
return "the script heap is over its " + strconv.Itoa(f.limit>>20) + " MB limit"
|
|
}
|
|
|
|
type Heap struct {
|
|
objs []object
|
|
free []uint32
|
|
live int
|
|
bytes int
|
|
since int
|
|
limit int
|
|
armed int
|
|
}
|
|
|
|
func (h *Heap) charge(size int) {
|
|
if h.armed > 0 && h.limit > 0 && h.bytes+size > h.limit {
|
|
panic(heapFull{limit: h.limit})
|
|
}
|
|
}
|
|
|
|
func heapHandle(idx, gen uint32) uint64 {
|
|
return uint64(idx)<<32 | uint64(gen)
|
|
}
|
|
|
|
func (h *Heap) alloc(size int) (uint32, *object) {
|
|
h.charge(size)
|
|
var idx uint32
|
|
if n := len(h.free); n > 0 {
|
|
idx = h.free[n-1]
|
|
h.free = h.free[:n-1]
|
|
} else {
|
|
h.objs = append(h.objs, object{})
|
|
idx = uint32(len(h.objs) - 1)
|
|
}
|
|
o := &h.objs[idx]
|
|
o.gen++
|
|
if o.gen == 0 {
|
|
o.gen = 1
|
|
}
|
|
o.live, o.mark, o.size = true, false, size
|
|
h.live++
|
|
h.bytes += size
|
|
h.since += size
|
|
return idx, o
|
|
}
|
|
|
|
func (h *Heap) get(a uint64) *object {
|
|
if a == 0 || a&staticBit != 0 {
|
|
return nil
|
|
}
|
|
idx := uint32(a >> 32)
|
|
if int(idx) >= len(h.objs) {
|
|
return nil
|
|
}
|
|
o := &h.objs[idx]
|
|
if !o.live || o.gen != uint32(a) {
|
|
return nil
|
|
}
|
|
return o
|
|
}
|
|
|
|
func (h *Heap) newString(s string) Value {
|
|
idx, o := h.alloc(len(s) + 32)
|
|
o.str, o.s, o.elems, o.width, o.mask = true, s, nil, 0, 0
|
|
return Value{A: heapHandle(idx, o.gen)}
|
|
}
|
|
|
|
func (h *Heap) newSlice(width int, mask uint32, capacity int) Value {
|
|
idx, o := h.alloc(capacity*width*16 + 48)
|
|
o.str, o.s = false, ""
|
|
o.elems = make([]Value, 0, capacity*width)
|
|
o.width, o.mask = width, mask
|
|
return Value{A: heapHandle(idx, o.gen)}
|
|
}
|
|
|
|
func (h *Heap) grow(o *object, delta int) {
|
|
h.charge(delta)
|
|
o.size += delta
|
|
h.bytes += delta
|
|
h.since += delta
|
|
}
|