github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/regpool.go (about) 1 //go:build !noregpool 2 // +build !noregpool 3 4 package runtime 5 6 const ( 7 regPoolSize = 10 // Size of a pool of cell of value register sets. 8 regSetMaxAge = 10 // Age at which it's OK to discard a register set in the pool. 9 ) 10 11 // This is an experimental pool for re-using allocated sets of registers across 12 // different Lua continuations. Profiling showed allocating register sets for 13 // each continuation is costly, and it can easily be avoided in the case of e.g. 14 // a function repeatedly called in a loop, or a tail recursive function (or 15 // mutually tail recursive functions). 16 // 17 // The pool keeps up to regPoolSize register sets of each type (plain values and 18 // cells). A register set can be released into the pool and it will replace an 19 // old (> maxAge) register set if there is one. Age increase each time a new 20 // register set is requested. The idea is that in the common case where the 21 // same function keeps being called, the same register set can be re-used. 22 // 23 // Setting regPoolSize to 0 makes cellPool.get / valuePool.get allocate 24 // a new register set each time, and cellPool.release / valuePool.release 25 // be no-ops. 26 27 type cellPool struct { 28 cells [][]Cell // Pool of cell sets 29 exps []uint // Expiry generation of cell sets 30 gen uint // Current cell register set generation 31 maxAge uint 32 } 33 34 func mkCellPool(size, maxAge uint) cellPool { 35 return cellPool{ 36 cells: make([][]Cell, size), 37 exps: make([]uint, size), 38 maxAge: maxAge, 39 } 40 } 41 42 func (p *cellPool) get(sz int) []Cell { 43 p.gen++ 44 for i := 0; i < regPoolSize; i++ { 45 c := p.cells[i] 46 if len(c) == sz { 47 p.cells[i] = nil 48 p.exps[i] = 0 49 return c 50 } 51 } 52 return make([]Cell, sz) 53 } 54 55 func (p *cellPool) release(c []Cell) { 56 for i := 0; i < regPoolSize; i++ { 57 if p.exps[i] < p.gen { 58 for i := range c { 59 c[i] = Cell{} 60 } 61 p.cells[i] = c 62 p.exps[i] = p.gen + p.maxAge 63 return 64 } 65 } 66 } 67 68 type valuePool struct { 69 values [][]Value // Pool of value sets 70 exps []uint // Expiry generation of value sets 71 gen uint // Current cell register set generation 72 maxAge uint 73 } 74 75 func mkValuePool(size, maxAge uint) valuePool { 76 return valuePool{ 77 values: make([][]Value, size), 78 exps: make([]uint, size), 79 maxAge: maxAge, 80 } 81 } 82 83 func (p *valuePool) get(sz int) []Value { 84 p.gen++ 85 for i := 0; i < regPoolSize; i++ { 86 v := p.values[i] 87 if len(v) == sz { 88 p.values[i] = nil 89 p.exps[i] = 0 90 return v 91 } 92 } 93 return make([]Value, sz) 94 } 95 96 func (p *valuePool) release(v []Value) { 97 for i := 0; i < regPoolSize; i++ { 98 if p.exps[i] < p.gen { 99 for i := range v { 100 v[i] = Value{} 101 } 102 p.values[i] = v 103 p.exps[i] = p.gen + p.maxAge 104 return 105 } 106 } 107 }