state_test.go 19 KB

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