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