123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762 |
- package lua
- import (
- "context"
- "strings"
- "testing"
- "time"
- )
- func TestLStateIsClosed(t *testing.T) {
- L := NewState()
- L.Close()
- errorIfNotEqual(t, true, L.IsClosed())
- }
- func TestCallStackOverflowWhenFixed(t *testing.T) {
- L := NewState(Options{
- CallStackSize: 3,
- })
- defer L.Close()
- // expect fixed stack implementation by default (for backwards compatibility)
- stack := L.stack
- if _, ok := stack.(*fixedCallFrameStack); !ok {
- t.Errorf("expected fixed callframe stack by default")
- }
- errorIfScriptNotFail(t, L, `
- local function recurse(count)
- if count > 0 then
- recurse(count - 1)
- end
- end
- local function c()
- print(_printregs())
- recurse(9)
- end
- c()
- `, "stack overflow")
- }
- func TestCallStackOverflowWhenAutoGrow(t *testing.T) {
- L := NewState(Options{
- CallStackSize: 3,
- MinimizeStackMemory: true,
- })
- defer L.Close()
- // expect auto growing stack implementation when MinimizeStackMemory is set
- stack := L.stack
- if _, ok := stack.(*autoGrowingCallFrameStack); !ok {
- t.Errorf("expected fixed callframe stack by default")
- }
- errorIfScriptNotFail(t, L, `
- local function recurse(count)
- if count > 0 then
- recurse(count - 1)
- end
- end
- local function c()
- print(_printregs())
- recurse(9)
- end
- c()
- `, "stack overflow")
- }
- func TestSkipOpenLibs(t *testing.T) {
- L := NewState(Options{SkipOpenLibs: true})
- defer L.Close()
- errorIfScriptNotFail(t, L, `print("")`,
- "attempt to call a non-function object")
- L2 := NewState()
- defer L2.Close()
- errorIfScriptFail(t, L2, `print("")`)
- }
- func TestGetAndReplace(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LString("a"))
- L.Replace(1, LString("b"))
- L.Replace(0, LString("c"))
- errorIfNotEqual(t, LNil, L.Get(0))
- errorIfNotEqual(t, LNil, L.Get(-10))
- errorIfNotEqual(t, L.Env, L.Get(EnvironIndex))
- errorIfNotEqual(t, LString("b"), L.Get(1))
- L.Push(LString("c"))
- L.Push(LString("d"))
- L.Replace(-2, LString("e"))
- errorIfNotEqual(t, LString("e"), L.Get(-2))
- registry := L.NewTable()
- L.Replace(RegistryIndex, registry)
- L.G.Registry = registry
- errorIfGFuncNotFail(t, L, func(L *LState) int {
- L.Replace(RegistryIndex, LNil)
- return 0
- }, "registry must be a table")
- errorIfGFuncFail(t, L, func(L *LState) int {
- env := L.NewTable()
- L.Replace(EnvironIndex, env)
- errorIfNotEqual(t, env, L.Get(EnvironIndex))
- return 0
- })
- errorIfGFuncNotFail(t, L, func(L *LState) int {
- L.Replace(EnvironIndex, LNil)
- return 0
- }, "environment must be a table")
- errorIfGFuncFail(t, L, func(L *LState) int {
- gbl := L.NewTable()
- L.Replace(GlobalsIndex, gbl)
- errorIfNotEqual(t, gbl, L.G.Global)
- return 0
- })
- errorIfGFuncNotFail(t, L, func(L *LState) int {
- L.Replace(GlobalsIndex, LNil)
- return 0
- }, "_G must be a table")
- L2 := NewState()
- defer L2.Close()
- clo := L2.NewClosure(func(L2 *LState) int {
- L2.Replace(UpvalueIndex(1), LNumber(3))
- errorIfNotEqual(t, LNumber(3), L2.Get(UpvalueIndex(1)))
- return 0
- }, LNumber(1), LNumber(2))
- L2.SetGlobal("clo", clo)
- errorIfScriptFail(t, L2, `clo()`)
- }
- func TestRemove(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LString("a"))
- L.Push(LString("b"))
- L.Push(LString("c"))
- L.Remove(4)
- errorIfNotEqual(t, LString("a"), L.Get(1))
- errorIfNotEqual(t, LString("b"), L.Get(2))
- errorIfNotEqual(t, LString("c"), L.Get(3))
- errorIfNotEqual(t, 3, L.GetTop())
- L.Remove(3)
- errorIfNotEqual(t, LString("a"), L.Get(1))
- errorIfNotEqual(t, LString("b"), L.Get(2))
- errorIfNotEqual(t, LNil, L.Get(3))
- errorIfNotEqual(t, 2, L.GetTop())
- L.Push(LString("c"))
- L.Remove(-10)
- errorIfNotEqual(t, LString("a"), L.Get(1))
- errorIfNotEqual(t, LString("b"), L.Get(2))
- errorIfNotEqual(t, LString("c"), L.Get(3))
- errorIfNotEqual(t, 3, L.GetTop())
- L.Remove(2)
- errorIfNotEqual(t, LString("a"), L.Get(1))
- errorIfNotEqual(t, LString("c"), L.Get(2))
- errorIfNotEqual(t, LNil, L.Get(3))
- errorIfNotEqual(t, 2, L.GetTop())
- }
- func TestToInt(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewTable())
- errorIfNotEqual(t, 10, L.ToInt(1))
- errorIfNotEqual(t, 99, L.ToInt(2))
- errorIfNotEqual(t, 0, L.ToInt(3))
- }
- func TestToInt64(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewTable())
- errorIfNotEqual(t, int64(10), L.ToInt64(1))
- errorIfNotEqual(t, int64(99), L.ToInt64(2))
- errorIfNotEqual(t, int64(0), L.ToInt64(3))
- }
- func TestToNumber(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewTable())
- errorIfNotEqual(t, LNumber(10), L.ToNumber(1))
- errorIfNotEqual(t, LNumber(99.9), L.ToNumber(2))
- errorIfNotEqual(t, LNumber(0), L.ToNumber(3))
- }
- func TestToString(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewTable())
- errorIfNotEqual(t, "10", L.ToString(1))
- errorIfNotEqual(t, "99.9", L.ToString(2))
- errorIfNotEqual(t, "", L.ToString(3))
- }
- func TestToTable(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewTable())
- errorIfFalse(t, L.ToTable(1) == nil, "index 1 must be nil")
- errorIfFalse(t, L.ToTable(2) == nil, "index 2 must be nil")
- errorIfNotEqual(t, L.Get(3), L.ToTable(3))
- }
- func TestToFunction(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewFunction(func(L *LState) int { return 0 }))
- errorIfFalse(t, L.ToFunction(1) == nil, "index 1 must be nil")
- errorIfFalse(t, L.ToFunction(2) == nil, "index 2 must be nil")
- errorIfNotEqual(t, L.Get(3), L.ToFunction(3))
- }
- func TestToUserData(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- L.Push(L.NewUserData())
- errorIfFalse(t, L.ToUserData(1) == nil, "index 1 must be nil")
- errorIfFalse(t, L.ToUserData(2) == nil, "index 2 must be nil")
- errorIfNotEqual(t, L.Get(3), L.ToUserData(3))
- }
- func TestToChannel(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Push(LNumber(10))
- L.Push(LString("99.9"))
- var ch chan LValue
- L.Push(LChannel(ch))
- errorIfFalse(t, L.ToChannel(1) == nil, "index 1 must be nil")
- errorIfFalse(t, L.ToChannel(2) == nil, "index 2 must be nil")
- errorIfNotEqual(t, ch, L.ToChannel(3))
- }
- func TestObjLen(t *testing.T) {
- L := NewState()
- defer L.Close()
- errorIfNotEqual(t, 3, L.ObjLen(LString("abc")))
- tbl := L.NewTable()
- tbl.Append(LTrue)
- tbl.Append(LTrue)
- errorIfNotEqual(t, 2, L.ObjLen(tbl))
- mt := L.NewTable()
- L.SetField(mt, "__len", L.NewFunction(func(L *LState) int {
- tbl := L.CheckTable(1)
- L.Push(LNumber(tbl.Len() + 1))
- return 1
- }))
- L.SetMetatable(tbl, mt)
- errorIfNotEqual(t, 3, L.ObjLen(tbl))
- errorIfNotEqual(t, 0, L.ObjLen(LNumber(10)))
- }
- func TestConcat(t *testing.T) {
- L := NewState()
- defer L.Close()
- errorIfNotEqual(t, "a1c", L.Concat(LString("a"), LNumber(1), LString("c")))
- }
- func TestPCall(t *testing.T) {
- L := NewState()
- defer L.Close()
- L.Register("f1", func(L *LState) int {
- panic("panic!")
- return 0
- })
- errorIfScriptNotFail(t, L, `f1()`, "panic!")
- L.Push(L.GetGlobal("f1"))
- err := L.PCall(0, 0, L.NewFunction(func(L *LState) int {
- L.Push(LString("by handler"))
- return 1
- }))
- errorIfFalse(t, strings.Contains(err.Error(), "by handler"), "")
- L.Push(L.GetGlobal("f1"))
- err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
- L.RaiseError("error!")
- return 1
- }))
- errorIfFalse(t, strings.Contains(err.Error(), "error!"), "")
- L.Push(L.GetGlobal("f1"))
- err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
- panic("panicc!")
- return 1
- }))
- errorIfFalse(t, strings.Contains(err.Error(), "panicc!"), "")
- // Issue #452, expected to be revert back to previous call stack after any error.
- currentFrame, currentTop, currentSp := L.currentFrame, L.GetTop(), L.stack.Sp()
- L.Push(L.GetGlobal("f1"))
- err = L.PCall(0, 0, nil)
- errorIfFalse(t, err != nil, "")
- errorIfFalse(t, L.currentFrame == currentFrame, "")
- errorIfFalse(t, L.GetTop() == currentTop, "")
- errorIfFalse(t, L.stack.Sp() == currentSp, "")
- currentFrame, currentTop, currentSp = L.currentFrame, L.GetTop(), L.stack.Sp()
- L.Push(L.GetGlobal("f1"))
- err = L.PCall(0, 0, L.NewFunction(func(L *LState) int {
- L.RaiseError("error!")
- return 1
- }))
- errorIfFalse(t, err != nil, "")
- errorIfFalse(t, L.currentFrame == currentFrame, "")
- errorIfFalse(t, L.GetTop() == currentTop, "")
- errorIfFalse(t, L.stack.Sp() == currentSp, "")
- }
- func TestCoroutineApi1(t *testing.T) {
- L := NewState()
- defer L.Close()
- co, _ := L.NewThread()
- errorIfScriptFail(t, L, `
- function coro(v)
- assert(v == 10)
- local ret1, ret2 = coroutine.yield(1,2,3)
- assert(ret1 == 11)
- assert(ret2 == 12)
- coroutine.yield(4)
- return 5
- end
- `)
- fn := L.GetGlobal("coro").(*LFunction)
- st, err, values := L.Resume(co, fn, LNumber(10))
- errorIfNotEqual(t, ResumeYield, st)
- errorIfNotNil(t, err)
- errorIfNotEqual(t, 3, len(values))
- errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
- errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
- errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
- st, err, values = L.Resume(co, fn, LNumber(11), LNumber(12))
- errorIfNotEqual(t, ResumeYield, st)
- errorIfNotNil(t, err)
- errorIfNotEqual(t, 1, len(values))
- errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
- st, err, values = L.Resume(co, fn)
- errorIfNotEqual(t, ResumeOK, st)
- errorIfNotNil(t, err)
- errorIfNotEqual(t, 1, len(values))
- errorIfNotEqual(t, LNumber(5), values[0].(LNumber))
- L.Register("myyield", func(L *LState) int {
- return L.Yield(L.ToNumber(1))
- })
- errorIfScriptFail(t, L, `
- function coro_error()
- coroutine.yield(1,2,3)
- myyield(4)
- assert(false, "--failed--")
- end
- `)
- fn = L.GetGlobal("coro_error").(*LFunction)
- co, _ = L.NewThread()
- st, err, values = L.Resume(co, fn)
- errorIfNotEqual(t, ResumeYield, st)
- errorIfNotNil(t, err)
- errorIfNotEqual(t, 3, len(values))
- errorIfNotEqual(t, LNumber(1), values[0].(LNumber))
- errorIfNotEqual(t, LNumber(2), values[1].(LNumber))
- errorIfNotEqual(t, LNumber(3), values[2].(LNumber))
- st, err, values = L.Resume(co, fn)
- errorIfNotEqual(t, ResumeYield, st)
- errorIfNotNil(t, err)
- errorIfNotEqual(t, 1, len(values))
- errorIfNotEqual(t, LNumber(4), values[0].(LNumber))
- st, err, values = L.Resume(co, fn)
- errorIfNotEqual(t, ResumeError, st)
- errorIfNil(t, err)
- errorIfFalse(t, strings.Contains(err.Error(), "--failed--"), "error message must be '--failed--'")
- st, err, values = L.Resume(co, fn)
- errorIfNotEqual(t, ResumeError, st)
- errorIfNil(t, err)
- errorIfFalse(t, strings.Contains(err.Error(), "can not resume a dead thread"), "can not resume a dead thread")
- }
- func TestContextTimeout(t *testing.T) {
- L := NewState()
- defer L.Close()
- ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
- defer cancel()
- L.SetContext(ctx)
- errorIfNotEqual(t, ctx, L.Context())
- err := L.DoString(`
- local clock = os.clock
- function sleep(n) -- seconds
- local t0 = clock()
- while clock() - t0 <= n do end
- end
- sleep(3)
- `)
- errorIfNil(t, err)
- errorIfFalse(t, strings.Contains(err.Error(), "context deadline exceeded"), "execution must be canceled")
- oldctx := L.RemoveContext()
- errorIfNotEqual(t, ctx, oldctx)
- errorIfNotNil(t, L.ctx)
- }
- func TestContextCancel(t *testing.T) {
- L := NewState()
- defer L.Close()
- ctx, cancel := context.WithCancel(context.Background())
- errch := make(chan error, 1)
- L.SetContext(ctx)
- go func() {
- errch <- L.DoString(`
- local clock = os.clock
- function sleep(n) -- seconds
- local t0 = clock()
- while clock() - t0 <= n do end
- end
- sleep(3)
- `)
- }()
- time.Sleep(1 * time.Second)
- cancel()
- err := <-errch
- errorIfNil(t, err)
- errorIfFalse(t, strings.Contains(err.Error(), "context canceled"), "execution must be canceled")
- }
- func TestContextWithCroutine(t *testing.T) {
- L := NewState()
- defer L.Close()
- ctx, cancel := context.WithCancel(context.Background())
- L.SetContext(ctx)
- defer cancel()
- L.DoString(`
- function coro()
- local i = 0
- while true do
- coroutine.yield(i)
- i = i+1
- end
- return i
- end
- `)
- co, cocancel := L.NewThread()
- defer cocancel()
- fn := L.GetGlobal("coro").(*LFunction)
- _, err, values := L.Resume(co, fn)
- errorIfNotNil(t, err)
- errorIfNotEqual(t, LNumber(0), values[0])
- // cancel the parent context
- cancel()
- _, err, values = L.Resume(co, fn)
- errorIfNil(t, err)
- errorIfFalse(t, strings.Contains(err.Error(), "context canceled"), "coroutine execution must be canceled when the parent context is canceled")
- }
- func TestPCallAfterFail(t *testing.T) {
- L := NewState()
- defer L.Close()
- errFn := L.NewFunction(func(L *LState) int {
- L.RaiseError("error!")
- return 0
- })
- changeError := L.NewFunction(func(L *LState) int {
- L.Push(errFn)
- err := L.PCall(0, 0, nil)
- if err != nil {
- L.RaiseError("A New Error")
- }
- return 0
- })
- L.Push(changeError)
- err := L.PCall(0, 0, nil)
- errorIfFalse(t, strings.Contains(err.Error(), "A New Error"), "error not propogated correctly")
- }
- func TestRegistryFixedOverflow(t *testing.T) {
- state := NewState()
- defer state.Close()
- reg := state.reg
- expectedPanic := false
- // should be non auto grow by default
- errorIfFalse(t, reg.maxSize == 0, "state should default to non-auto growing implementation")
- // fill the stack and check we get a panic
- test := LString("test")
- for i := 0; i < len(reg.array); i++ {
- reg.Push(test)
- }
- defer func() {
- rcv := recover()
- if rcv != nil {
- if expectedPanic {
- errorIfFalse(t, rcv.(error).Error() != "registry overflow", "expected registry overflow exception, got "+rcv.(error).Error())
- } else {
- t.Errorf("did not expect registry overflow")
- }
- } else if expectedPanic {
- t.Errorf("expected registry overflow exception, but didn't get panic")
- }
- }()
- expectedPanic = true
- reg.Push(test)
- }
- func TestRegistryAutoGrow(t *testing.T) {
- state := NewState(Options{RegistryMaxSize: 300, RegistrySize: 200, RegistryGrowStep: 25})
- defer state.Close()
- expectedPanic := false
- defer func() {
- rcv := recover()
- if rcv != nil {
- if expectedPanic {
- errorIfFalse(t, rcv.(error).Error() != "registry overflow", "expected registry overflow exception, got "+rcv.(error).Error())
- } else {
- t.Errorf("did not expect registry overflow")
- }
- } else if expectedPanic {
- t.Errorf("expected registry overflow exception, but didn't get panic")
- }
- }()
- reg := state.reg
- test := LString("test")
- for i := 0; i < 300; i++ {
- reg.Push(test)
- }
- expectedPanic = true
- reg.Push(test)
- }
- // This test exposed a panic caused by accessing an unassigned var in the lua registry.
- // The panic was caused by initCallFrame. It was calling resize() on the registry after it had written some values
- // directly to the reg's array, but crucially, before it had updated "top". This meant when the resize occurred, the
- // values beyond top where not copied, and were lost, leading to a later uninitialised value being found in the registry.
- func TestUninitializedVarAccess(t *testing.T) {
- L := NewState(Options{
- RegistrySize: 128,
- RegistryMaxSize: 256,
- })
- defer L.Close()
- // This test needs to trigger a resize when the local vars are allocated, so we need it to
- // be 128 for the padding amount in the test function to work. If it's larger, we will need
- // more padding to force the error.
- errorIfNotEqual(t, cap(L.reg.array), 128)
- ctx, cancel := context.WithCancel(context.Background())
- L.SetContext(ctx)
- defer cancel()
- errorIfScriptFail(t, L, `
- local function test(arg1, arg2, arg3)
- -- padding to cause a registry resize when the local vars for this func are reserved
- local a0,b0,c0,d0,e0,f0,g0,h0,i0,j0,k0,l0,m0,n0,o0,p0,q0,r0,s0,t0,u0,v0,w0,x0,y0,z0
- local a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,o1,p1,q1,r1,s1,t1,u1,v1,w1,x1,y1,z1
- local a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,o2,p2,q2,r2,s2,t2,u2,v2,w2,x2,y2,z2
- local a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,o3,p3,q3,r3,s3,t3,u3,v3,w3,x3,y3,z3
- local a4,b4,c4,d4,e4,f4,g4,h4,i4,j4,k4,l4,m4,n4,o4,p4,q4,r4,s4,t4,u4,v4,w4,x4,y4,z4
- if arg3 == nil then
- return 1
- end
- return 0
- end
- test(1,2)
- `)
- }
- func BenchmarkCallFrameStackPushPopAutoGrow(t *testing.B) {
- stack := newAutoGrowingCallFrameStack(256)
- t.ResetTimer()
- const Iterations = 256
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- for i := 0; i < Iterations; i++ {
- stack.Pop()
- }
- }
- }
- func BenchmarkCallFrameStackPushPopFixed(t *testing.B) {
- stack := newFixedCallFrameStack(256)
- t.ResetTimer()
- const Iterations = 256
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- for i := 0; i < Iterations; i++ {
- stack.Pop()
- }
- }
- }
- // this test will intentionally not incur stack growth in order to bench the performance when no allocations happen
- func BenchmarkCallFrameStackPushPopShallowAutoGrow(t *testing.B) {
- stack := newAutoGrowingCallFrameStack(256)
- t.ResetTimer()
- const Iterations = 8
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- for i := 0; i < Iterations; i++ {
- stack.Pop()
- }
- }
- }
- func BenchmarkCallFrameStackPushPopShallowFixed(t *testing.B) {
- stack := newFixedCallFrameStack(256)
- t.ResetTimer()
- const Iterations = 8
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- for i := 0; i < Iterations; i++ {
- stack.Pop()
- }
- }
- }
- func BenchmarkCallFrameStackPushPopFixedNoInterface(t *testing.B) {
- stack := newFixedCallFrameStack(256).(*fixedCallFrameStack)
- t.ResetTimer()
- const Iterations = 256
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- for i := 0; i < Iterations; i++ {
- stack.Pop()
- }
- }
- }
- func BenchmarkCallFrameStackUnwindAutoGrow(t *testing.B) {
- stack := newAutoGrowingCallFrameStack(256)
- t.ResetTimer()
- const Iterations = 256
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- stack.SetSp(0)
- }
- }
- func BenchmarkCallFrameStackUnwindFixed(t *testing.B) {
- stack := newFixedCallFrameStack(256)
- t.ResetTimer()
- const Iterations = 256
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- stack.SetSp(0)
- }
- }
- func BenchmarkCallFrameStackUnwindFixedNoInterface(t *testing.B) {
- stack := newFixedCallFrameStack(256).(*fixedCallFrameStack)
- t.ResetTimer()
- const Iterations = 256
- for j := 0; j < t.N; j++ {
- for i := 0; i < Iterations; i++ {
- stack.Push(callFrame{})
- }
- stack.SetSp(0)
- }
- }
- type registryTestHandler int
- func (registryTestHandler) registryOverflow() {
- panic("registry overflow")
- }
- // test pushing and popping from the registry
- func BenchmarkRegistryPushPopAutoGrow(t *testing.B) {
- al := newAllocator(32)
- sz := 256 * 20
- reg := newRegistry(registryTestHandler(0), sz/2, 64, sz, al)
- value := LString("test")
- t.ResetTimer()
- for j := 0; j < t.N; j++ {
- for i := 0; i < sz; i++ {
- reg.Push(value)
- }
- for i := 0; i < sz; i++ {
- reg.Pop()
- }
- }
- }
- func BenchmarkRegistryPushPopFixed(t *testing.B) {
- al := newAllocator(32)
- sz := 256 * 20
- reg := newRegistry(registryTestHandler(0), sz, 0, sz, al)
- value := LString("test")
- t.ResetTimer()
- for j := 0; j < t.N; j++ {
- for i := 0; i < sz; i++ {
- reg.Push(value)
- }
- for i := 0; i < sz; i++ {
- reg.Pop()
- }
- }
- }
- func BenchmarkRegistrySetTop(t *testing.B) {
- al := newAllocator(32)
- sz := 256 * 20
- reg := newRegistry(registryTestHandler(0), sz, 32, sz*2, al)
- t.ResetTimer()
- for j := 0; j < t.N; j++ {
- reg.SetTop(sz)
- reg.SetTop(0)
- }
- }
|