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