2024-09-20 16:50:35 +08:00
|
|
|
package goja
|
|
|
|
|
|
|
|
import (
|
2024-09-24 13:34:32 +08:00
|
|
|
"apigo.cc/ai/ai/goja/file"
|
|
|
|
"apigo.cc/ai/ai/goja/parser"
|
|
|
|
"apigo.cc/ai/ai/goja/unistring"
|
2024-09-20 16:50:35 +08:00
|
|
|
"testing"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestTaggedTemplateArgExport(t *testing.T) {
|
|
|
|
vm := New()
|
|
|
|
vm.Set("f", func(v Value) {
|
|
|
|
v.Export()
|
|
|
|
})
|
|
|
|
vm.RunString("f`test`")
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestVM1(t *testing.T) {
|
|
|
|
r := &Runtime{}
|
|
|
|
r.init()
|
|
|
|
|
|
|
|
vm := r.vm
|
|
|
|
|
|
|
|
vm.prg = &Program{
|
|
|
|
src: file.NewFile("dummy", "", 1),
|
|
|
|
code: []instruction{
|
|
|
|
&bindGlobal{vars: []unistring.String{"v"}},
|
|
|
|
newObject,
|
|
|
|
setGlobal("v"),
|
|
|
|
loadVal{asciiString("test")},
|
|
|
|
loadVal{valueInt(3)},
|
|
|
|
loadVal{valueInt(2)},
|
|
|
|
add,
|
|
|
|
setElem,
|
|
|
|
pop,
|
|
|
|
loadDynamic("v"),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
vm.run()
|
|
|
|
|
|
|
|
rv := vm.pop()
|
|
|
|
|
|
|
|
if obj, ok := rv.(*Object); ok {
|
|
|
|
if v := obj.self.getStr("test", nil).ToInteger(); v != 5 {
|
|
|
|
t.Fatalf("Unexpected property value: %v", v)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
t.Fatalf("Unexpected result: %v", rv)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestEvalVar(t *testing.T) {
|
|
|
|
const SCRIPT = `
|
|
|
|
function test() {
|
|
|
|
var a;
|
|
|
|
return eval("var a = 'yes'; var z = 'no'; a;") === "yes" && a === "yes";
|
|
|
|
}
|
|
|
|
test();
|
|
|
|
`
|
|
|
|
|
|
|
|
testScript(SCRIPT, valueTrue, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestResolveMixedStack1(t *testing.T) {
|
|
|
|
const SCRIPT = `
|
|
|
|
function test(arg) {
|
|
|
|
var a = 1;
|
|
|
|
var scope = {};
|
|
|
|
(function() {return arg})(); // move arguments to stash
|
|
|
|
with (scope) {
|
|
|
|
a++; // resolveMixedStack1 here
|
|
|
|
return a + arg;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
test(40);
|
|
|
|
`
|
|
|
|
|
|
|
|
testScript(SCRIPT, valueInt(42), t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNewArrayFromIterClosed(t *testing.T) {
|
|
|
|
const SCRIPT = `
|
|
|
|
const [a, ...other] = [];
|
|
|
|
assert.sameValue(a, undefined);
|
|
|
|
assert(Array.isArray(other));
|
|
|
|
assert.sameValue(other.length, 0);
|
|
|
|
`
|
|
|
|
testScriptWithTestLib(SCRIPT, _undefined, t)
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkVmNOP2(b *testing.B) {
|
|
|
|
prg := []func(*vm){
|
|
|
|
//loadVal(0).exec,
|
|
|
|
//loadVal(1).exec,
|
|
|
|
//add.exec,
|
|
|
|
jump(1).exec,
|
|
|
|
}
|
|
|
|
|
|
|
|
r := &Runtime{}
|
|
|
|
r.init()
|
|
|
|
|
|
|
|
vm := r.vm
|
|
|
|
vm.prg = &Program{}
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
vm.pc = 0
|
|
|
|
for !vm.halted() {
|
|
|
|
prg[vm.pc](vm)
|
|
|
|
}
|
|
|
|
//vm.sp--
|
|
|
|
/*r := vm.pop()
|
|
|
|
if r.ToInteger() != 5 {
|
|
|
|
b.Fatalf("Unexpected result: %+v", r)
|
|
|
|
}
|
|
|
|
if vm.sp != 0 {
|
|
|
|
b.Fatalf("Unexpected sp: %d", vm.sp)
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkVmNOP(b *testing.B) {
|
|
|
|
r := &Runtime{}
|
|
|
|
r.init()
|
|
|
|
|
|
|
|
vm := r.vm
|
|
|
|
vm.prg = &Program{
|
|
|
|
code: []instruction{
|
|
|
|
jump(1),
|
|
|
|
//jump(1),
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
vm.pc = 0
|
|
|
|
vm.run()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkVm1(b *testing.B) {
|
|
|
|
r := &Runtime{}
|
|
|
|
r.init()
|
|
|
|
|
|
|
|
vm := r.vm
|
|
|
|
|
|
|
|
//ins1 := loadVal1(0)
|
|
|
|
//ins2 := loadVal1(1)
|
|
|
|
|
|
|
|
vm.prg = &Program{
|
|
|
|
code: []instruction{
|
|
|
|
loadVal{valueInt(2)},
|
|
|
|
loadVal{valueInt(3)},
|
|
|
|
add,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
vm.pc = 0
|
|
|
|
vm.run()
|
|
|
|
r := vm.pop()
|
|
|
|
if r.ToInteger() != 5 {
|
|
|
|
b.Fatalf("Unexpected result: %+v", r)
|
|
|
|
}
|
|
|
|
if vm.sp != 0 {
|
|
|
|
b.Fatalf("Unexpected sp: %d", vm.sp)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkFib(b *testing.B) {
|
|
|
|
const TEST_FIB = `
|
|
|
|
function fib(n) {
|
|
|
|
if (n < 2) return n;
|
|
|
|
return fib(n - 2) + fib(n - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
fib(35);
|
|
|
|
`
|
|
|
|
b.StopTimer()
|
|
|
|
prg, err := parser.ParseFile(nil, "test.js", TEST_FIB, 0)
|
|
|
|
if err != nil {
|
|
|
|
b.Fatal(err)
|
|
|
|
}
|
|
|
|
|
|
|
|
c := newCompiler()
|
|
|
|
c.compile(prg, false, true, nil)
|
|
|
|
c.p.dumpCode(b.Logf)
|
|
|
|
|
|
|
|
r := &Runtime{}
|
|
|
|
r.init()
|
|
|
|
|
|
|
|
vm := r.vm
|
|
|
|
|
|
|
|
var expectedResult Value = valueInt(9227465)
|
|
|
|
|
|
|
|
b.StartTimer()
|
|
|
|
|
|
|
|
vm.prg = c.p
|
|
|
|
vm.run()
|
|
|
|
v := vm.result
|
|
|
|
|
|
|
|
b.Logf("stack size: %d", len(vm.stack))
|
|
|
|
b.Logf("stashAllocs: %d", vm.stashAllocs)
|
|
|
|
|
|
|
|
if !v.SameAs(expectedResult) {
|
|
|
|
b.Fatalf("Result: %+v, expected: %+v", v, expectedResult)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkEmptyLoop(b *testing.B) {
|
|
|
|
const SCRIPT = `
|
|
|
|
function f() {
|
|
|
|
for (var i = 0; i < 100; i++) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f()
|
|
|
|
`
|
|
|
|
b.StopTimer()
|
|
|
|
vm := New()
|
|
|
|
prg := MustCompile("test.js", SCRIPT, false)
|
|
|
|
// prg.dumpCode(log.Printf)
|
|
|
|
b.StartTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
vm.RunProgram(prg)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkVMAdd(b *testing.B) {
|
|
|
|
vm := &vm{}
|
|
|
|
vm.stack = append(vm.stack, nil, nil)
|
|
|
|
vm.sp = len(vm.stack)
|
|
|
|
|
|
|
|
var v1 Value = valueInt(3)
|
|
|
|
var v2 Value = valueInt(5)
|
|
|
|
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
vm.stack[0] = v1
|
|
|
|
vm.stack[1] = v2
|
|
|
|
add.exec(vm)
|
|
|
|
vm.sp++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkFuncCall(b *testing.B) {
|
|
|
|
const SCRIPT = `
|
|
|
|
function f(a, b, c, d) {
|
|
|
|
}
|
|
|
|
`
|
|
|
|
|
|
|
|
b.StopTimer()
|
|
|
|
|
|
|
|
vm := New()
|
|
|
|
prg := MustCompile("test.js", SCRIPT, false)
|
|
|
|
|
|
|
|
vm.RunProgram(prg)
|
|
|
|
if f, ok := AssertFunction(vm.Get("f")); ok {
|
|
|
|
b.StartTimer()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
f(nil, nil, intToValue(1), intToValue(2), intToValue(3), intToValue(4), intToValue(5), intToValue(6))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
b.Fatal("f is not a function")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkAssertInt(b *testing.B) {
|
|
|
|
v := intToValue(42)
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
if i, ok := v.(valueInt); !ok || int64(i) != 42 {
|
|
|
|
b.Fatal()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func BenchmarkLoadVal(b *testing.B) {
|
|
|
|
var ins instruction
|
|
|
|
b.ReportAllocs()
|
|
|
|
for i := 0; i < b.N; i++ {
|
|
|
|
ins = loadVal{valueInt(1)}
|
|
|
|
_ = ins
|
|
|
|
}
|
|
|
|
}
|