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  }