gitee.com/yfmps/gopher-lua@v0.0.3/state_test.go (about)

     1  package lua
     2  
     3  import (
     4  	"context"
     5  	"strings"
     6  	"testing"
     7  	"time"
     8  )
     9  
    10  func TestLStateIsClosed(t *testing.T) {
    11  	L := NewState()
    12  	L.Close()
    13  	errorIfNotEqual(t, true, L.IsClosed())
    14  }
    15  
    16  func TestCallStackOverflowWhenFixed(t *testing.T) {
    17  	L := NewState(Options{
    18  		CallStackSize: 3,
    19  	})
    20  	defer L.Close()
    21  
    22  	// expect fixed stack implementation by default (for backwards compatibility)
    23  	stack := L.stack
    24  	if _, ok := stack.(*fixedCallFrameStack); !ok {
    25  		t.Errorf("expected fixed callframe stack by default")
    26  	}
    27  
    28  	errorIfScriptNotFail(t, L, `
    29      local function recurse(count)
    30        if count > 0 then
    31          recurse(count - 1)
    32        end
    33      end
    34      local function c()
    35        print(_printregs())
    36        recurse(9)
    37      end
    38      c()
    39      `, "stack overflow")
    40  }
    41  
    42  func TestCallStackOverflowWhenAutoGrow(t *testing.T) {
    43  	L := NewState(Options{
    44  		CallStackSize:       3,
    45  		MinimizeStackMemory: true,
    46  	})
    47  	defer L.Close()
    48  
    49  	// expect auto growing stack implementation when MinimizeStackMemory is set
    50  	stack := L.stack
    51  	if _, ok := stack.(*autoGrowingCallFrameStack); !ok {
    52  		t.Errorf("expected fixed callframe stack by default")
    53  	}
    54  
    55  	errorIfScriptNotFail(t, L, `
    56      local function recurse(count)
    57        if count > 0 then
    58          recurse(count - 1)
    59        end
    60      end
    61      local function c()
    62        print(_printregs())
    63        recurse(9)
    64      end
    65      c()
    66      `, "stack overflow")
    67  }
    68  
    69  func TestSkipOpenLibs(t *testing.T) {
    70  	L := NewState(Options{SkipOpenLibs: true})
    71  	defer L.Close()
    72  	errorIfScriptNotFail(t, L, `print("")`,
    73  		"attempt to call a non-function object")
    74  	L2 := NewState()
    75  	defer L2.Close()
    76  	errorIfScriptFail(t, L2, `print("")`)
    77  }
    78  
    79  func TestGetAndReplace(t *testing.T) {
    80  	L := NewState()
    81  	defer L.Close()
    82  	L.Push(LString("a"))
    83  	L.Replace(1, LString("b"))
    84  	L.Replace(0, LString("c"))
    85  	errorIfNotEqual(t, LNil, L.Get(0))
    86  	errorIfNotEqual(t, LNil, L.Get(-10))
    87  	errorIfNotEqual(t, L.Env, L.Get(EnvironIndex))
    88  	errorIfNotEqual(t, LString("b"), L.Get(1))
    89  	L.Push(LString("c"))
    90  	L.Push(LString("d"))
    91  	L.Replace(-2, LString("e"))
    92  	errorIfNotEqual(t, LString("e"), L.Get(-2))
    93  	registry := L.NewTable()
    94  	L.Replace(RegistryIndex, registry)
    95  	L.G.Registry = registry
    96  	errorIfGFuncNotFail(t, L, func(L *LState) int {
    97  		L.Replace(RegistryIndex, LNil)
    98  		return 0
    99  	}, "registry must be a table")
   100  	errorIfGFuncFail(t, L, func(L *LState) int {
   101  		env := L.NewTable()
   102  		L.Replace(EnvironIndex, env)
   103  		errorIfNotEqual(t, env, L.Get(EnvironIndex))
   104  		return 0
   105  	})
   106  	errorIfGFuncNotFail(t, L, func(L *LState) int {
   107  		L.Replace(EnvironIndex, LNil)
   108  		return 0
   109  	}, "environment must be a table")
   110  	errorIfGFuncFail(t, L, func(L *LState) int {
   111  		gbl := L.NewTable()
   112  		L.Replace(GlobalsIndex, gbl)
   113  		errorIfNotEqual(t, gbl, L.G.Global)
   114  		return 0
   115  	})
   116  	errorIfGFuncNotFail(t, L, func(L *LState) int {
   117  		L.Replace(GlobalsIndex, LNil)
   118  		return 0
   119  	}, "_G must be a table")
   120  
   121  	L2 := NewState()
   122  	defer L2.Close()
   123  	clo := L2.NewClosure(func(L2 *LState) int {
   124  		L2.Replace(UpvalueIndex(1), LNumber(3))
   125  		errorIfNotEqual(t, LNumber(3), L2.Get(UpvalueIndex(1)))
   126  		return 0
   127  	}, LNumber(1), LNumber(2))
   128  	L2.SetGlobal("clo", clo)
   129  	errorIfScriptFail(t, L2, `clo()`)
   130  }
   131  
   132  func TestRemove(t *testing.T) {
   133  	L := NewState()
   134  	defer L.Close()
   135  	L.Push(LString("a"))
   136  	L.Push(LString("b"))
   137  	L.Push(LString("c"))
   138  
   139  	L.Remove(4)
   140  	errorIfNotEqual(t, LString("a"), L.Get(1))
   141  	errorIfNotEqual(t, LString("b"), L.Get(2))
   142  	errorIfNotEqual(t, LString("c"), L.Get(3))
   143  	errorIfNotEqual(t, 3, L.GetTop())
   144  
   145  	L.Remove(3)
   146  	errorIfNotEqual(t, LString("a"), L.Get(1))
   147  	errorIfNotEqual(t, LString("b"), L.Get(2))
   148  	errorIfNotEqual(t, LNil, L.Get(3))
   149  	errorIfNotEqual(t, 2, L.GetTop())
   150  	L.Push(LString("c"))
   151  
   152  	L.Remove(-10)
   153  	errorIfNotEqual(t, LString("a"), L.Get(1))
   154  	errorIfNotEqual(t, LString("b"), L.Get(2))
   155  	errorIfNotEqual(t, LString("c"), L.Get(3))
   156  	errorIfNotEqual(t, 3, L.GetTop())
   157  
   158  	L.Remove(2)
   159  	errorIfNotEqual(t, LString("a"), L.Get(1))
   160  	errorIfNotEqual(t, LString("c"), L.Get(2))
   161  	errorIfNotEqual(t, LNil, L.Get(3))
   162  	errorIfNotEqual(t, 2, L.GetTop())
   163  }
   164  
   165  func TestToInt(t *testing.T) {
   166  	L := NewState()
   167  	defer L.Close()
   168  	L.Push(LNumber(10))
   169  	L.Push(LString("99.9"))
   170  	L.Push(L.NewTable())
   171  	errorIfNotEqual(t, 10, L.ToInt(1))
   172  	errorIfNotEqual(t, 99, L.ToInt(2))
   173  	errorIfNotEqual(t, 0, L.ToInt(3))
   174  }
   175  
   176  func TestToInt64(t *testing.T) {
   177  	L := NewState()
   178  	defer L.Close()
   179  	L.Push(LNumber(10))
   180  	L.Push(LString("99.9"))
   181  	L.Push(L.NewTable())
   182  	errorIfNotEqual(t, int64(10), L.ToInt64(1))
   183  	errorIfNotEqual(t, int64(99), L.ToInt64(2))
   184  	errorIfNotEqual(t, int64(0), L.ToInt64(3))
   185  }
   186  
   187  func TestToNumber(t *testing.T) {
   188  	L := NewState()
   189  	defer L.Close()
   190  	L.Push(LNumber(10))
   191  	L.Push(LString("99.9"))
   192  	L.Push(L.NewTable())
   193  	errorIfNotEqual(t, LNumber(10), L.ToNumber(1))
   194  	errorIfNotEqual(t, LNumber(99.9), L.ToNumber(2))
   195  	errorIfNotEqual(t, LNumber(0), L.ToNumber(3))
   196  }
   197  
   198  func TestToString(t *testing.T) {
   199  	L := NewState()
   200  	defer L.Close()
   201  	L.Push(LNumber(10))
   202  	L.Push(LString("99.9"))
   203  	L.Push(L.NewTable())
   204  	errorIfNotEqual(t, "10", L.ToString(1))
   205  	errorIfNotEqual(t, "99.9", L.ToString(2))
   206  	errorIfNotEqual(t, "", L.ToString(3))
   207  }
   208  
   209  func TestToTable(t *testing.T) {
   210  	L := NewState()
   211  	defer L.Close()
   212  	L.Push(LNumber(10))
   213  	L.Push(LString("99.9"))
   214  	L.Push(L.NewTable())
   215  	errorIfFalse(t, L.ToTable(1) == nil, "index 1 must be nil")
   216  	errorIfFalse(t, L.ToTable(2) == nil, "index 2 must be nil")
   217  	errorIfNotEqual(t, L.Get(3), L.ToTable(3))
   218  }
   219  
   220  func TestToFunction(t *testing.T) {
   221  	L := NewState()
   222  	defer L.Close()
   223  	L.Push(LNumber(10))
   224  	L.Push(LString("99.9"))
   225  	L.Push(L.NewFunction(func(L *LState) int { return 0 }))
   226  	errorIfFalse(t, L.ToFunction(1) == nil, "index 1 must be nil")
   227  	errorIfFalse(t, L.ToFunction(2) == nil, "index 2 must be nil")
   228  	errorIfNotEqual(t, L.Get(3), L.ToFunction(3))
   229  }
   230  
   231  func TestToUserData(t *testing.T) {
   232  	L := NewState()
   233  	defer L.Close()
   234  	L.Push(LNumber(10))
   235  	L.Push(LString("99.9"))
   236  	L.Push(L.NewUserData())
   237  	errorIfFalse(t, L.ToUserData(1) == nil, "index 1 must be nil")
   238  	errorIfFalse(t, L.ToUserData(2) == nil, "index 2 must be nil")
   239  	errorIfNotEqual(t, L.Get(3), L.ToUserData(3))
   240  }
   241  
   242  func TestToChannel(t *testing.T) {
   243  	L := NewState()
   244  	defer L.Close()
   245  	L.Push(LNumber(10))
   246  	L.Push(LString("99.9"))
   247  	var ch chan LValue
   248  	L.Push(LChannel(ch))
   249  	errorIfFalse(t, L.ToChannel(1) == nil, "index 1 must be nil")
   250  	errorIfFalse(t, L.ToChannel(2) == nil, "index 2 must be nil")
   251  	errorIfNotEqual(t, ch, L.ToChannel(3))
   252  }
   253  
   254  func TestObjLen(t *testing.T) {
   255  	L := NewState()
   256  	defer L.Close()
   257  	errorIfNotEqual(t, 3, L.ObjLen(LString("abc")))
   258  	tbl := L.NewTable()
   259  	tbl.Append(LTrue)
   260  	tbl.Append(LTrue)
   261  	errorIfNotEqual(t, 2, L.ObjLen(tbl))
   262  	mt := L.NewTable()
   263  	L.SetField(mt, "__len", L.NewFunction(func(L *LState) int {
   264  		tbl := L.CheckTable(1)
   265  		L.Push(LNumber(tbl.Len() + 1))
   266  		return 1
   267  	}))
   268  	L.SetMetatable(tbl, mt)
   269  	errorIfNotEqual(t, 3, L.ObjLen(tbl))
   270  	errorIfNotEqual(t, 0, L.ObjLen(LNumber(10)))
   271  }
   272  
   273  func TestConcat(t *testing.T) {
   274  	L := NewState()
   275  	defer L.Close()
   276  	errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c")))
   277  }
   278  
   279  func TestPCall(t *testing.T) {
   280  	L := NewState()
   281  	defer L.Close()
   282  	L.Register("f1", func(L *LState) int {
   283  		panic("panic!")
   284  		return 0
   285  	})
   286  	errorIfScriptNotFail(t, L, `f1()`, "panic!")
   287  	L.Push(L.GetGlobal("f1"))
   288  	err := L.PCall(0, 0, L.NewFunction(func(L *LState) int {
   289  		L.Push(LString("by handler"))
   290  		return 1
   291  	}))
   292  	errorIfFalse(t, strings.Contains(err.Error(), "by handler"), "")
   293  
   294  	err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
   295  		L.RaiseError("error!")
   296  		return 1
   297  	}))
   298  	errorIfFalse(t, strings.Contains(err.Error(), "error!"), "")
   299  
   300  	err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
   301  		panic("panicc!")
   302  		return 1
   303  	}))
   304  	errorIfFalse(t, strings.Contains(err.Error(), "panicc!"), "")
   305  }
   306  
   307  func TestCoroutineApi1(t *testing.T) {
   308  	L := NewState()
   309  	defer L.Close()
   310  	co, _ := L.NewThread()
   311  	errorIfScriptFail(t, L, `
   312        function coro(v)
   313          assert(v == 10)
   314          local ret1, ret2 = coroutine.yield(1,2,3)
   315          assert(ret1 == 11)
   316          assert(ret2 == 12)
   317          coroutine.yield(4)
   318          return 5
   319        end
   320      `)
   321  	fn := L.GetGlobal("coro").(*LFunction)
   322  	st, err, values := L.Resume(co, fn, LNumber(10))
   323  	errorIfNotEqual(t, ResumeYield, st)
   324  	errorIfNotNil(t, err)
   325  	errorIfNotEqual(t, 3, len(values))
   326  	errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
   327  	errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
   328  	errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
   329  
   330  	st, err, values = L.Resume(co, fn, LNumber(11), LNumber(12))
   331  	errorIfNotEqual(t, ResumeYield, st)
   332  	errorIfNotNil(t, err)
   333  	errorIfNotEqual(t, 1, len(values))
   334  	errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
   335  
   336  	st, err, values = L.Resume(co, fn)
   337  	errorIfNotEqual(t, ResumeOK, st)
   338  	errorIfNotNil(t, err)
   339  	errorIfNotEqual(t, 1, len(values))
   340  	errorIfNotEqual(t, LNumber(5), values[0].(LNumber))
   341  
   342  	L.Register("myyield", func(L *LState) int {
   343  		return L.Yield(L.ToNumber(1))
   344  	})
   345  	errorIfScriptFail(t, L, `
   346        function coro_error()
   347          coroutine.yield(1,2,3)
   348          myyield(4)
   349          assert(false, "--failed--")
   350        end
   351      `)
   352  	fn = L.GetGlobal("coro_error").(*LFunction)
   353  	co, _ = L.NewThread()
   354  	st, err, values = L.Resume(co, fn)
   355  	errorIfNotEqual(t, ResumeYield, st)
   356  	errorIfNotNil(t, err)
   357  	errorIfNotEqual(t, 3, len(values))
   358  	errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
   359  	errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
   360  	errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
   361  
   362  	st, err, values = L.Resume(co, fn)
   363  	errorIfNotEqual(t, ResumeYield, st)
   364  	errorIfNotNil(t, err)
   365  	errorIfNotEqual(t, 1, len(values))
   366  	errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
   367  
   368  	st, err, values = L.Resume(co, fn)
   369  	errorIfNotEqual(t, ResumeError, st)
   370  	errorIfNil(t, err)
   371  	errorIfFalse(t, strings.Contains(err.Error(), "--failed--"), "error message must be '--failed--'")
   372  	st, err, values = L.Resume(co, fn)
   373  	errorIfNotEqual(t, ResumeError, st)
   374  	errorIfNil(t, err)
   375  	errorIfFalse(t, strings.Contains(err.Error(), "can not resume a dead thread"), "can not resume a dead thread")
   376  
   377  }
   378  
   379  func TestContextTimeout(t *testing.T) {
   380  	L := NewState()
   381  	defer L.Close()
   382  	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   383  	defer cancel()
   384  	L.SetContext(ctx)
   385  	errorIfNotEqual(t, ctx, L.Context())
   386  	err := L.DoString(`
   387  	  local clock = os.clock
   388        function sleep(n)  -- seconds
   389          local t0 = clock()
   390          while clock() - t0 <= n do end
   391        end
   392  	  sleep(3)
   393  	`)
   394  	errorIfNil(t, err)
   395  	errorIfFalse(t, strings.Contains(err.Error(), "context deadline exceeded"), "execution must be canceled")
   396  
   397  	oldctx := L.RemoveContext()
   398  	errorIfNotEqual(t, ctx, oldctx)
   399  	errorIfNotNil(t, L.ctx)
   400  }
   401  
   402  func TestContextCancel(t *testing.T) {
   403  	L := NewState()
   404  	defer L.Close()
   405  	ctx, cancel := context.WithCancel(context.Background())
   406  	errch := make(chan error, 1)
   407  	L.SetContext(ctx)
   408  	go func() {
   409  		errch <- L.DoString(`
   410  	    local clock = os.clock
   411          function sleep(n)  -- seconds
   412            local t0 = clock()
   413            while clock() - t0 <= n do end
   414          end
   415  	    sleep(3)
   416  	  `)
   417  	}()
   418  	time.Sleep(1 * time.Second)
   419  	cancel()
   420  	err := <-errch
   421  	errorIfNil(t, err)
   422  	errorIfFalse(t, strings.Contains(err.Error(), "context canceled"), "execution must be canceled")
   423  }
   424  
   425  func TestContextWithCroutine(t *testing.T) {
   426  	L := NewState()
   427  	defer L.Close()
   428  	ctx, cancel := context.WithCancel(context.Background())
   429  	L.SetContext(ctx)
   430  	defer cancel()
   431  	L.DoString(`
   432  	    function coro()
   433  		  local i = 0
   434  		  while true do
   435  		    coroutine.yield(i)
   436  			i = i+1
   437  		  end
   438  		  return i
   439  	    end
   440  	`)
   441  	co, cocancel := L.NewThread()
   442  	defer cocancel()
   443  	fn := L.GetGlobal("coro").(*LFunction)
   444  	_, err, values := L.Resume(co, fn)
   445  	errorIfNotNil(t, err)
   446  	errorIfNotEqual(t, LNumber(0), values[0])
   447  	// cancel the parent context
   448  	cancel()
   449  	_, err, values = L.Resume(co, fn)
   450  	errorIfNil(t, err)
   451  	errorIfFalse(t, strings.Contains(err.Error(), "context canceled"), "coroutine execution must be canceled when the parent context is canceled")
   452  
   453  }
   454  
   455  func TestPCallAfterFail(t *testing.T) {
   456  	L := NewState()
   457  	defer L.Close()
   458  	errFn := L.NewFunction(func(L *LState) int {
   459  		L.RaiseError("error!")
   460  		return 0
   461  	})
   462  	changeError := L.NewFunction(func(L *LState) int {
   463  		L.Push(errFn)
   464  		err := L.PCall(0, 0, nil)
   465  		if err != nil {
   466  			L.RaiseError("A New Error")
   467  		}
   468  		return 0
   469  	})
   470  	L.Push(changeError)
   471  	err := L.PCall(0, 0, nil)
   472  	errorIfFalse(t, strings.Contains(err.Error(), "A New Error"), "error not propogated correctly")
   473  }
   474  
   475  func TestRegistryFixedOverflow(t *testing.T) {
   476  	state := NewState()
   477  	defer state.Close()
   478  	reg := state.reg
   479  	expectedPanic := false
   480  	// should be non auto grow by default
   481  	errorIfFalse(t, reg.maxSize == 0, "state should default to non-auto growing implementation")
   482  	// fill the stack and check we get a panic
   483  	test := LString("test")
   484  	for i := 0; i < len(reg.array); i++ {
   485  		reg.Push(test)
   486  	}
   487  	defer func() {
   488  		rcv := recover()
   489  		if rcv != nil {
   490  			if expectedPanic {
   491  				errorIfFalse(t, rcv.(error).Error() != "registry overflow", "expected registry overflow exception, got "+rcv.(error).Error())
   492  			} else {
   493  				t.Errorf("did not expect registry overflow")
   494  			}
   495  		} else if expectedPanic {
   496  			t.Errorf("expected registry overflow exception, but didn't get panic")
   497  		}
   498  	}()
   499  	expectedPanic = true
   500  	reg.Push(test)
   501  }
   502  
   503  func TestRegistryAutoGrow(t *testing.T) {
   504  	state := NewState(Options{RegistryMaxSize: 300, RegistrySize: 200, RegistryGrowStep: 25})
   505  	defer state.Close()
   506  	expectedPanic := false
   507  	defer func() {
   508  		rcv := recover()
   509  		if rcv != nil {
   510  			if expectedPanic {
   511  				errorIfFalse(t, rcv.(error).Error() != "registry overflow", "expected registry overflow exception, got "+rcv.(error).Error())
   512  			} else {
   513  				t.Errorf("did not expect registry overflow")
   514  			}
   515  		} else if expectedPanic {
   516  			t.Errorf("expected registry overflow exception, but didn't get panic")
   517  		}
   518  	}()
   519  	reg := state.reg
   520  	test := LString("test")
   521  	for i := 0; i < 300; i++ {
   522  		reg.Push(test)
   523  	}
   524  	expectedPanic = true
   525  	reg.Push(test)
   526  }
   527  
   528  func BenchmarkCallFrameStackPushPopAutoGrow(t *testing.B) {
   529  	stack := newAutoGrowingCallFrameStack(256)
   530  
   531  	t.ResetTimer()
   532  
   533  	const Iterations = 256
   534  	for j := 0; j < t.N; j++ {
   535  		for i := 0; i < Iterations; i++ {
   536  			stack.Push(callFrame{})
   537  		}
   538  		for i := 0; i < Iterations; i++ {
   539  			stack.Pop()
   540  		}
   541  	}
   542  }
   543  
   544  func BenchmarkCallFrameStackPushPopFixed(t *testing.B) {
   545  	stack := newFixedCallFrameStack(256)
   546  
   547  	t.ResetTimer()
   548  
   549  	const Iterations = 256
   550  	for j := 0; j < t.N; j++ {
   551  		for i := 0; i < Iterations; i++ {
   552  			stack.Push(callFrame{})
   553  		}
   554  		for i := 0; i < Iterations; i++ {
   555  			stack.Pop()
   556  		}
   557  	}
   558  }
   559  
   560  // this test will intentionally not incur stack growth in order to bench the performance when no allocations happen
   561  func BenchmarkCallFrameStackPushPopShallowAutoGrow(t *testing.B) {
   562  	stack := newAutoGrowingCallFrameStack(256)
   563  
   564  	t.ResetTimer()
   565  
   566  	const Iterations = 8
   567  	for j := 0; j < t.N; j++ {
   568  		for i := 0; i < Iterations; i++ {
   569  			stack.Push(callFrame{})
   570  		}
   571  		for i := 0; i < Iterations; i++ {
   572  			stack.Pop()
   573  		}
   574  	}
   575  }
   576  
   577  func BenchmarkCallFrameStackPushPopShallowFixed(t *testing.B) {
   578  	stack := newFixedCallFrameStack(256)
   579  
   580  	t.ResetTimer()
   581  
   582  	const Iterations = 8
   583  	for j := 0; j < t.N; j++ {
   584  		for i := 0; i < Iterations; i++ {
   585  			stack.Push(callFrame{})
   586  		}
   587  		for i := 0; i < Iterations; i++ {
   588  			stack.Pop()
   589  		}
   590  	}
   591  }
   592  
   593  func BenchmarkCallFrameStackPushPopFixedNoInterface(t *testing.B) {
   594  	stack := newFixedCallFrameStack(256).(*fixedCallFrameStack)
   595  
   596  	t.ResetTimer()
   597  
   598  	const Iterations = 256
   599  	for j := 0; j < t.N; j++ {
   600  		for i := 0; i < Iterations; i++ {
   601  			stack.Push(callFrame{})
   602  		}
   603  		for i := 0; i < Iterations; i++ {
   604  			stack.Pop()
   605  		}
   606  	}
   607  }
   608  
   609  func BenchmarkCallFrameStackUnwindAutoGrow(t *testing.B) {
   610  	stack := newAutoGrowingCallFrameStack(256)
   611  
   612  	t.ResetTimer()
   613  
   614  	const Iterations = 256
   615  	for j := 0; j < t.N; j++ {
   616  		for i := 0; i < Iterations; i++ {
   617  			stack.Push(callFrame{})
   618  		}
   619  		stack.SetSp(0)
   620  	}
   621  }
   622  
   623  func BenchmarkCallFrameStackUnwindFixed(t *testing.B) {
   624  	stack := newFixedCallFrameStack(256)
   625  
   626  	t.ResetTimer()
   627  
   628  	const Iterations = 256
   629  	for j := 0; j < t.N; j++ {
   630  		for i := 0; i < Iterations; i++ {
   631  			stack.Push(callFrame{})
   632  		}
   633  		stack.SetSp(0)
   634  	}
   635  }
   636  
   637  func BenchmarkCallFrameStackUnwindFixedNoInterface(t *testing.B) {
   638  	stack := newFixedCallFrameStack(256).(*fixedCallFrameStack)
   639  
   640  	t.ResetTimer()
   641  
   642  	const Iterations = 256
   643  	for j := 0; j < t.N; j++ {
   644  		for i := 0; i < Iterations; i++ {
   645  			stack.Push(callFrame{})
   646  		}
   647  		stack.SetSp(0)
   648  	}
   649  }
   650  
   651  type registryTestHandler int
   652  
   653  func (registryTestHandler) registryOverflow() {
   654  	panic("registry overflow")
   655  }
   656  
   657  // test pushing and popping from the registry
   658  func BenchmarkRegistryPushPopAutoGrow(t *testing.B) {
   659  	al := newAllocator(32)
   660  	sz := 256 * 20
   661  	reg := newRegistry(registryTestHandler(0), sz/2, 64, sz, al)
   662  	value := LString("test")
   663  
   664  	t.ResetTimer()
   665  
   666  	for j := 0; j < t.N; j++ {
   667  		for i := 0; i < sz; i++ {
   668  			reg.Push(value)
   669  		}
   670  		for i := 0; i < sz; i++ {
   671  			reg.Pop()
   672  		}
   673  	}
   674  }
   675  
   676  func BenchmarkRegistryPushPopFixed(t *testing.B) {
   677  	al := newAllocator(32)
   678  	sz := 256 * 20
   679  	reg := newRegistry(registryTestHandler(0), sz, 0, sz, al)
   680  	value := LString("test")
   681  
   682  	t.ResetTimer()
   683  
   684  	for j := 0; j < t.N; j++ {
   685  		for i := 0; i < sz; i++ {
   686  			reg.Push(value)
   687  		}
   688  		for i := 0; i < sz; i++ {
   689  			reg.Pop()
   690  		}
   691  	}
   692  }
   693  
   694  func BenchmarkRegistrySetTop(t *testing.B) {
   695  	al := newAllocator(32)
   696  	sz := 256 * 20
   697  	reg := newRegistry(registryTestHandler(0), sz, 32, sz*2, al)
   698  
   699  	t.ResetTimer()
   700  
   701  	for j := 0; j < t.N; j++ {
   702  		reg.SetTop(sz)
   703  		reg.SetTop(0)
   704  	}
   705  }