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  }