func testSimple(name string, t *testing.T, cases []simple) { buf, e := gojit.Alloc(gojit.PageSize) if e != nil { t.Fatalf(e.Error()) } defer gojit.Release(buf) for i, tc := range cases { asm := &Assembler{Buf: buf} begin(asm) tc.f(asm) f := finish(asm) runtime.GC() for j := 0; j < len(tc.inout); j += 2 { in := tc.inout[j] out := tc.inout[j+1] got := f(in) if out != got { t.Errorf("f(%s)[%d](%x) = %x, expect %x", name, i, in, got, out) } } } }
func TestGCInCallback(t *testing.T) { asm := newAsm(t) defer gojit.Release(asm.Buf) gof := func(i int) { runtime.GC() } var jitf func() asm.CallFunc(gof) asm.Ret() asm.BuildTo(&jitf) jitf() }
func TestCallFunc(t *testing.T) { asm := newAsm(t) defer gojit.Release(asm.Buf) called := false asm.CallFunc(func() { called = true }) asm.Ret() var f func() asm.BuildTo(&f) f() if !called { t.Error("CallFunc did not call the function") } }
func TestMovEsp(t *testing.T) { asm := newAsm(t) defer gojit.Release(asm.Buf) begin(asm) // 48 c7 44 24 f8 69 7a movq $0x7a69,-0x8(%rsp) // 00 00 mov_rsp := []byte{0x48, 0xc7, 0x44, 0x24, 0xf8, 0x69, 0x7a, 0x00, 0x00} copy(asm.Buf[asm.Off:], mov_rsp) asm.Off += len(mov_rsp) asm.Mov(Indirect{Rsp, -8, 64}, Rax) f := finish(asm) got := f(0) if got != 31337 { t.Errorf("Fatal: mov from esp: got %d != %d", got, 31337) } }
func TestRecursion(t *testing.T) { asm := newAsm(t) defer gojit.Release(asm.Buf) var jitf func(i int) gof := func(i int) { if i > 0 { jitf(i - 1) } } asm.Mov(Indirect{Rdi, 0, 64}, Rax) asm.Push(Rax) asm.CallFunc(gof) asm.Pop(Rax) asm.Ret() asm.BuildTo(&jitf) jitf(1024) }
func TestArith(t *testing.T) { cases := []struct { insn *Instruction lhs, rhs int32 out uintptr }{ {InstAdd, 20, 30, 50}, {InstAdd, 0x7fffffff, 0x70000001, 0xf0000000}, {InstAnd, 0x77777777, U32(0xffffffff), 0x77777777}, {InstAnd, 0x77777777, U32(0x88888888), 0}, {InstOr, 0x77777777, U32(0x88888888), 0xffffffff}, {InstOr, 1, 0, 1}, {InstSub, 5, 10, 5}, {InstSub, 10, 5, 0xfffffffffffffffb}, } buf, e := gojit.Alloc(gojit.PageSize) if e != nil { t.Fatalf(e.Error()) } defer gojit.Release(buf) for _, tc := range cases { asm := &Assembler{buf, 0, CgoABI} var funcs []func(uintptr) uintptr if tc.insn.imm_r.ok() { begin(asm) asm.Mov(Imm{tc.rhs}, Rax) asm.Arithmetic(tc.insn, Imm{tc.lhs}, Rax) funcs = append(funcs, finish(asm)) } if tc.insn.imm_rm.op.ok() { begin(asm) asm.Mov(Imm{0}, Indirect{Rdi, 0, 0}) asm.Mov(Imm{tc.rhs}, Indirect{Rdi, 0, 32}) asm.Arithmetic(tc.insn, Imm{tc.lhs}, Indirect{Rdi, 0, 64}) asm.Mov(Indirect{Rdi, 0, 64}, Rax) funcs = append(funcs, finish(asm)) } if tc.insn.r_rm.ok() { begin(asm) asm.Mov(Imm{tc.lhs}, R10) asm.Mov(Imm{0}, Indirect{Rdi, 0, 0}) asm.Mov(Imm{tc.rhs}, Indirect{Rdi, 0, 32}) asm.Arithmetic(tc.insn, R10, Indirect{Rdi, 0, 64}) asm.Mov(Indirect{Rdi, 0, 64}, Rax) funcs = append(funcs, finish(asm)) } if tc.insn.rm_r.ok() { begin(asm) asm.Mov(Imm{0}, Indirect{Rdi, 0, 0}) asm.Mov(Imm{tc.lhs}, Indirect{Rdi, 0, 32}) asm.Mov(Imm{tc.rhs}, R10) asm.Arithmetic(tc.insn, Indirect{Rdi, 0, 64}, R10) asm.Mov(R10, Rax) funcs = append(funcs, finish(asm)) } for i, f := range funcs { got := f(gojit.Addr(mem)) if got != tc.out { t.Errorf("%s(0x%x,0x%x) [%d] = 0x%x (expect 0x%x)", tc.insn.Mnemonic, tc.lhs, tc.rhs, i, got, tc.out) } else if testing.Verbose() { // We don't use `testing.Logf` because // if we panic inside JIT'd code, the // runtime dies horrible (rightfully // so!), and so the `testing` cleanup // code never runs, and we never see // log messages. We want to get these // out as soon as possible, so we // write them directly. fmt.Printf("OK %d %s(0x%x,0x%x) = 0x%x\n", i, tc.insn.Mnemonic, tc.lhs, tc.rhs, got) } } } }
func (a *Assembler) Release() { gojit.Release(a.Buf) }