12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- package lua
- import (
- "reflect"
- "unsafe"
- )
- // iface is an internal representation of the go-interface.
- type iface struct {
- itab unsafe.Pointer
- word unsafe.Pointer
- }
- const preloadLimit LNumber = 128
- var _fv float64
- var _uv uintptr
- var preloads [int(preloadLimit)]LValue
- func init() {
- for i := 0; i < int(preloadLimit); i++ {
- preloads[i] = LNumber(i)
- }
- }
- // allocator is a fast bulk memory allocator for the LValue.
- type allocator struct {
- size int
- fptrs []float64
- fheader *reflect.SliceHeader
- scratchValue LValue
- scratchValueP *iface
- }
- func newAllocator(size int) *allocator {
- al := &allocator{
- size: size,
- fptrs: make([]float64, 0, size),
- fheader: nil,
- }
- al.fheader = (*reflect.SliceHeader)(unsafe.Pointer(&al.fptrs))
- al.scratchValue = LNumber(0)
- al.scratchValueP = (*iface)(unsafe.Pointer(&al.scratchValue))
- return al
- }
- // LNumber2I takes a number value and returns an interface LValue representing the same number.
- // Converting an LNumber to a LValue naively, by doing:
- // `var val LValue = myLNumber`
- // will result in an individual heap alloc of 8 bytes for the float value. LNumber2I amortizes the cost and memory
- // overhead of these allocs by allocating blocks of floats instead.
- // The downside of this is that all of the floats on a given block have to become eligible for gc before the block
- // as a whole can be gc-ed.
- func (al *allocator) LNumber2I(v LNumber) LValue {
- // first check for shared preloaded numbers
- if v >= 0 && v < preloadLimit && float64(v) == float64(int64(v)) {
- return preloads[int(v)]
- }
- // check if we need a new alloc page
- if cap(al.fptrs) == len(al.fptrs) {
- al.fptrs = make([]float64, 0, al.size)
- al.fheader = (*reflect.SliceHeader)(unsafe.Pointer(&al.fptrs))
- }
- // alloc a new float, and store our value into it
- al.fptrs = append(al.fptrs, float64(v))
- fptr := &al.fptrs[len(al.fptrs)-1]
- // hack our scratch LValue to point to our allocated value
- // this scratch lvalue is copied when this function returns meaning the scratch value can be reused
- // on the next call
- al.scratchValueP.word = unsafe.Pointer(fptr)
- return al.scratchValue
- }
|