vm_test.go 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. package goja
  2. import (
  3. "github.com/dop251/goja/parser"
  4. "github.com/dop251/goja/unistring"
  5. "testing"
  6. )
  7. func TestVM1(t *testing.T) {
  8. r := &Runtime{}
  9. r.init()
  10. vm := r.vm
  11. vm.prg = &Program{
  12. values: []Value{valueInt(2), valueInt(3), asciiString("test")},
  13. code: []instruction{
  14. &bindGlobal{vars: []unistring.String{"v"}},
  15. newObject,
  16. setGlobal("v"),
  17. loadVal(2),
  18. loadVal(1),
  19. loadVal(0),
  20. add,
  21. setElem,
  22. pop,
  23. loadDynamic("v"),
  24. halt,
  25. },
  26. }
  27. vm.run()
  28. rv := vm.pop()
  29. if obj, ok := rv.(*Object); ok {
  30. if v := obj.self.getStr("test", nil).ToInteger(); v != 5 {
  31. t.Fatalf("Unexpected property value: %v", v)
  32. }
  33. } else {
  34. t.Fatalf("Unexpected result: %v", rv)
  35. }
  36. }
  37. func TestEvalVar(t *testing.T) {
  38. const SCRIPT = `
  39. function test() {
  40. var a;
  41. return eval("var a = 'yes'; var z = 'no'; a;") === "yes" && a === "yes";
  42. }
  43. test();
  44. `
  45. testScript1(SCRIPT, valueTrue, t)
  46. }
  47. var jumptable = []func(*vm, *instr){
  48. f_jump,
  49. f_halt,
  50. }
  51. func f_jump(vm *vm, i *instr) {
  52. vm.pc += i.prim
  53. }
  54. func f_halt(vm *vm, i *instr) {
  55. vm.halt = true
  56. }
  57. func f_loadVal(vm *vm, i *instr) {
  58. vm.push(vm.prg.values[i.prim])
  59. vm.pc++
  60. }
  61. type instr struct {
  62. code int
  63. prim int
  64. arg interface{}
  65. }
  66. type jumparg struct {
  67. offset int
  68. other string
  69. }
  70. func BenchmarkVmNOP2(b *testing.B) {
  71. prg := []func(*vm){
  72. //loadVal(0).exec,
  73. //loadVal(1).exec,
  74. //add.exec,
  75. jump(1).exec,
  76. halt.exec,
  77. }
  78. r := &Runtime{}
  79. r.init()
  80. vm := r.vm
  81. vm.prg = &Program{
  82. values: []Value{intToValue(2), intToValue(3)},
  83. }
  84. for i := 0; i < b.N; i++ {
  85. vm.halt = false
  86. vm.pc = 0
  87. for !vm.halt {
  88. prg[vm.pc](vm)
  89. }
  90. //vm.sp--
  91. /*r := vm.pop()
  92. if r.ToInteger() != 5 {
  93. b.Fatalf("Unexpected result: %+v", r)
  94. }
  95. if vm.sp != 0 {
  96. b.Fatalf("Unexpected sp: %d", vm.sp)
  97. }*/
  98. }
  99. }
  100. func BenchmarkVmNOP1(b *testing.B) {
  101. prg := []instr{
  102. {code: 2, prim: 0},
  103. {code: 2, prim: 1},
  104. {code: 3},
  105. {code: 1},
  106. }
  107. r := &Runtime{}
  108. r.init()
  109. vm := r.vm
  110. vm.prg = &Program{
  111. values: []Value{intToValue(2), intToValue(3)},
  112. }
  113. for i := 0; i < b.N; i++ {
  114. vm.halt = false
  115. vm.pc = 0
  116. L:
  117. for {
  118. instr := &prg[vm.pc]
  119. //jumptable[instr.code](vm, instr)
  120. switch instr.code {
  121. case 10:
  122. vm.pc += 1
  123. case 11:
  124. vm.pc += 2
  125. case 12:
  126. vm.pc += 3
  127. case 13:
  128. vm.pc += 4
  129. case 14:
  130. vm.pc += 5
  131. case 15:
  132. vm.pc += 6
  133. case 16:
  134. vm.pc += 7
  135. case 17:
  136. vm.pc += 8
  137. case 18:
  138. vm.pc += 9
  139. case 19:
  140. vm.pc += 10
  141. case 20:
  142. vm.pc += 11
  143. case 21:
  144. vm.pc += 12
  145. case 22:
  146. vm.pc += 13
  147. case 23:
  148. vm.pc += 14
  149. case 24:
  150. vm.pc += 15
  151. case 25:
  152. vm.pc += 16
  153. case 0:
  154. //vm.pc += instr.prim
  155. f_jump(vm, instr)
  156. case 1:
  157. break L
  158. case 2:
  159. f_loadVal(vm, instr)
  160. default:
  161. jumptable[instr.code](vm, instr)
  162. }
  163. }
  164. r := vm.pop()
  165. if r.ToInteger() != 5 {
  166. b.Fatalf("Unexpected result: %+v", r)
  167. }
  168. if vm.sp != 0 {
  169. b.Fatalf("Unexpected sp: %d", vm.sp)
  170. }
  171. //vm.sp -= 1
  172. }
  173. }
  174. func BenchmarkVmNOP(b *testing.B) {
  175. r := &Runtime{}
  176. r.init()
  177. vm := r.vm
  178. vm.prg = &Program{
  179. code: []instruction{
  180. jump(1),
  181. //jump(1),
  182. halt,
  183. },
  184. }
  185. for i := 0; i < b.N; i++ {
  186. vm.pc = 0
  187. vm.run()
  188. }
  189. }
  190. func BenchmarkVm1(b *testing.B) {
  191. r := &Runtime{}
  192. r.init()
  193. vm := r.vm
  194. //ins1 := loadVal1(0)
  195. //ins2 := loadVal1(1)
  196. vm.prg = &Program{
  197. values: []Value{valueInt(2), valueInt(3)},
  198. code: []instruction{
  199. loadVal(0),
  200. loadVal(1),
  201. add,
  202. halt,
  203. },
  204. }
  205. for i := 0; i < b.N; i++ {
  206. vm.pc = 0
  207. vm.run()
  208. r := vm.pop()
  209. if r.ToInteger() != 5 {
  210. b.Fatalf("Unexpected result: %+v", r)
  211. }
  212. if vm.sp != 0 {
  213. b.Fatalf("Unexpected sp: %d", vm.sp)
  214. }
  215. }
  216. }
  217. func BenchmarkFib(b *testing.B) {
  218. const TEST_FIB = `
  219. function fib(n) {
  220. if (n < 2) return n;
  221. return fib(n - 2) + fib(n - 1);
  222. }
  223. fib(35);
  224. `
  225. b.StopTimer()
  226. prg, err := parser.ParseFile(nil, "test.js", TEST_FIB, 0)
  227. if err != nil {
  228. b.Fatal(err)
  229. }
  230. c := newCompiler()
  231. c.compile(prg, false, false, true)
  232. c.p.dumpCode(b.Logf)
  233. r := &Runtime{}
  234. r.init()
  235. vm := r.vm
  236. var expectedResult Value = valueInt(9227465)
  237. b.StartTimer()
  238. vm.prg = c.p
  239. vm.run()
  240. v := vm.pop()
  241. b.Logf("stack size: %d", len(vm.stack))
  242. b.Logf("stashAllocs: %d", vm.stashAllocs)
  243. if !v.SameAs(expectedResult) {
  244. b.Fatalf("Result: %+v, expected: %+v", v, expectedResult)
  245. }
  246. }
  247. func BenchmarkEmptyLoop(b *testing.B) {
  248. const SCRIPT = `
  249. function f() {
  250. for (var i = 0; i < 100; i++) {
  251. }
  252. }
  253. f()
  254. `
  255. b.StopTimer()
  256. vm := New()
  257. prg := MustCompile("test.js", SCRIPT, false)
  258. // prg.dumpCode(log.Printf)
  259. b.StartTimer()
  260. for i := 0; i < b.N; i++ {
  261. vm.RunProgram(prg)
  262. }
  263. }
  264. func BenchmarkVMAdd(b *testing.B) {
  265. vm := &vm{}
  266. vm.stack = append(vm.stack, nil, nil)
  267. vm.sp = len(vm.stack)
  268. var v1 Value = valueInt(3)
  269. var v2 Value = valueInt(5)
  270. for i := 0; i < b.N; i++ {
  271. vm.stack[0] = v1
  272. vm.stack[1] = v2
  273. add.exec(vm)
  274. vm.sp++
  275. }
  276. }
  277. func BenchmarkFuncCall(b *testing.B) {
  278. const SCRIPT = `
  279. function f(a, b, c, d) {
  280. }
  281. `
  282. b.StopTimer()
  283. vm := New()
  284. prg := MustCompile("test.js", SCRIPT, false)
  285. vm.RunProgram(prg)
  286. if f, ok := AssertFunction(vm.Get("f")); ok {
  287. b.StartTimer()
  288. for i := 0; i < b.N; i++ {
  289. f(nil, nil, intToValue(1), intToValue(2), intToValue(3), intToValue(4), intToValue(5), intToValue(6))
  290. }
  291. } else {
  292. b.Fatal("f is not a function")
  293. }
  294. }
  295. func BenchmarkAssertInt(b *testing.B) {
  296. var v Value
  297. v = intToValue(42)
  298. for i := 0; i < b.N; i++ {
  299. if i, ok := v.(valueInt); !ok || int64(i) != 42 {
  300. b.Fatal()
  301. }
  302. }
  303. }