Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT compiler + bugfixes #66

Open
wants to merge 219 commits into
base: master
Choose a base branch
from
Open

JIT compiler + bugfixes #66

wants to merge 219 commits into from

Conversation

eh-steve
Copy link

@eh-steve eh-steve commented Nov 2, 2022

This is mostly a rebased commit history of #62, plus the addition of a new jit package to allow compiling and loading Go files/packages/text, and recursively resolving their dependencies.

This allows users to build and load arbitrary Go files with any number of imports automatically.

You can simply do:

loadable, err = jit.BuildGoFiles(jit.BuildConfig{}, "./path/to/file1.go", "/path/to/file2.go")
// or
loadable, err = jit.BuildGoPackage(jit.BuildConfig{}, "./path/to/package")
// or
loadable, err = jit.BuildGoText(jit.BuildConfig{}, `
package mypackage

import "encoding/json"

func MyFunc(input []byte) (interface{}, error) {
	var output interface{}
	err := json.Unmarshal(input, &output)
	return output, err
}

`)

if err != nil {
    panic(err)
}

module, symbols, err = loadable.Load()

if err != nil {
    panic(err)
}

MyFunc := symbols["MyFunc"].(func([]byte) (interface{}, error))
result, err := MyFunc([]byte(`{"k":"v"}`))

The jit package and tests are early on in the commit history to demonstrate the purpose of each subsequent commit in fixing specific tests.

So far, testing has only been on linux/amd64, linux/arm64, darwin/amd64, darwin/arm64 (Apple M1 silicon), and windows/amd64 . Once the last few goloader bugs are ironed out, I will try to backport these changes for earlier Go versions where possible.

Versions:

OS/Arch amd64/+CGo arm64/+CGo amd64/-CGo arm64/-CGo
Linux/go-1.19.4 ✔️ ✔️ ✔️ ✔️
Darwin/go-1.19.4 ✔️ ✔️ ✔️ ✔️
Windows/go-1.19.4 ✔️ ⁉️ ✔️ ⁉️
Linux/go-1.18.8 ✔️ ✔️ ✔️ ✔️
Darwin/go-1.18.8 ✔️ ✔️ ✔️ ✔️
Windows/go-1.18.8 ⁉️ ✔️ ⁉️
Linux/go-1.17.13
Darwin/go-1.17.13
Windows/go-1.17.13
Linux/go-1.16.15
Darwin/go-1.16.15
Windows/go-1.16.15
Linux/go-1.15.15
Darwin/go-1.15.15
Windows/go-1.15.15
Linux/go-1.14.15
Darwin/go-1.14.15
Windows/go-1.14.15
Linux/go-1.13.15
Darwin/go-1.13.15
Windows/go-1.13.15
Linux/go-1.12.17
Darwin/go-1.12.17
Windows/go-1.12.17
Linux/go-1.11.13
Darwin/go-1.11.13
Windows/go-1.11.13
Linux/go-1.10.8
Darwin/go-1.10.8
Windows/go-1.10.8
Linux/go-1.9.7
Darwin/go-1.9.7
Windows/go-1.9.7

@eh-steve eh-steve changed the title [WIP] - JIT compiler [WIP] - JIT compiler + bugfixes Nov 2, 2022
@pkujhd
Copy link
Owner

pkujhd commented Nov 4, 2022

@eh-steve , thanks.
I will try to recurrence bugs and fix.

By the way, goloader does not test with cgo and asm.

@eh-steve
Copy link
Author

eh-steve commented Nov 4, 2022

By the way, goloader does not test with cgo and asm.

I appreciate that - my main motivation was getting common packages like net/http and math to build successfully (which directly or indirectly use CGo/asm), and my fixes do seem to work (as shown in the tests).

@pkujhd
Copy link
Owner

pkujhd commented Nov 5, 2022

@eh-steve
I try use your jit branch to run go test in jit dir on linux/amd64 , every test outputs same errors, e.g "jit_test.go:42: still have 17 unresolved external symbols despite building and linking dependencies..."

Could you give me a simple case for TestStackSplit and TestJitPanicRecoveryStackTrace this issue mentioned?
Or tell me how to run your test.

Thx

@eh-steve
Copy link
Author

eh-steve commented Nov 5, 2022

What version of Go are you using, and which symbols remain unresolved? (I'm using 1.19.3 and it's working fine)

Can you try

go test -c
./jit.test -test.v -test.run TestStackSplit

./jit.test -test.v -test.run TestJitPanicRecovery

I've made certain core packages forbidden for re-inclusion in the JIT compiler to prevent duplication of certain atomic, reflect or runtime packages, are the missing symbols from these forbidden packages?

If so, they just need to be included in the test binary by declaring some global variables which use them.

Also I recently rebased and force pushed so you might wanna delete and re-checkout if you pulled before the rebase.

EDIT:

I just tried running via go test and got the same problem as you. It seems that when running tests directly via go test rather than through a pre-built binary, these symbols don't get included into the main binary, whereas they do if you build the test binary using -c:

        internal/cpu.X86
        internal/poll.runtime_isPollServerDescriptor
        internal/poll.runtime_pollWaitCanceled
        reflect..inittask
        reflect.bytesType
        reflect.dummy
        runtime..inittask
        runtime.defaultGOROOT
        runtime.vdsoGettimeofdaySym
        runtime.writeBarrier
        runtime.x86HasSSE41
        runtime.zerobase
        syscall.cgocaller
        syscall.runtime_AfterExec
        syscall.runtime_BeforeExec
        syscall.runtime_doAllThreadsSyscall
        time.modTimer

I could fix this by forcing the symbols to be included by importing more things in jit_test.go if you want? In the meantime it should work with -c

@eh-steve
Copy link
Author

eh-steve commented Nov 9, 2022

Edit:
Fixed this now

Some tests are still failing randomly (e.g. TestStackSplit and TestJitPanicRecoveryStackTrace) due to some outstanding bugs in goloader which still need to be fixed.

Specifically:
Things which trigger stack copies/stack splits while a dynamically loaded function is running can cause an incomplete stack unwinding (fatal error: traceback did not unwind completely) , possibly because the g's stack pointer was incorrectly incremented twice somewhere, so the unwinding doesn't ever reach the stack start. Unclear whether this is a TLS relocation issue or something else causing the sp to be incremented by the same frame size twice when calling dynamic code?

Example:

=== RUN   TestJitPanicRecoveryStackTrace/BuildGoFiles
runtime: g808: frame.sp=0xc004befd60 top=0xc004beffe0
	stack=[0xc004bec000-0xc004bf0000] n=4 max=2147483647
fatal error: traceback did not unwind completely

runtime stack:
runtime.throw({0x849c62?, 0xc00024e000?})
	/usr/local/go/src/runtime/panic.go:1047 +0x5d fp=0x7fb3f6ffca88 sp=0x7fb3f6ffca58 pc=0x439e7d
runtime.gentraceback(0x7fb40c71400b?, 0xb94c30?, 0xc00003ef00?, 0x7fb3f6ffce60?, 0x0, 0x0, 0x7fffffff, 0x7fb3f6ffce48, 0x1?, 0x0)
	/usr/local/go/src/runtime/traceback.go:561 +0x1385 fp=0x7fb3f6ffcdf8 sp=0x7fb3f6ffca88 pc=0x460d85
runtime.addOneOpenDeferFrame.func1()
	/usr/local/go/src/runtime/panic.go:645 +0x6b fp=0x7fb3f6ffce70 sp=0x7fb3f6ffcdf8 pc=0x43900b
runtime.systemstack()
	/usr/local/go/src/runtime/asm_amd64.s:492 +0x49 fp=0x7fb3f6ffce78 sp=0x7fb3f6ffce70 pc=0x46c269

goroutine 808 [running]:
runtime.systemstack_switch()
	/usr/local/go/src/runtime/asm_amd64.s:459 fp=0xc004befb20 sp=0xc004befb18 pc=0x46c200
runtime.addOneOpenDeferFrame(0x41c3e6?, 0xbac840?, 0xc004befbe8?)
	/usr/local/go/src/runtime/panic.go:644 +0x69 fp=0xc004befb60 sp=0xc004befb20 pc=0x438f49
panic({0x7a6480, 0x8dd510})
	/usr/local/go/src/runtime/panic.go:844 +0x112 fp=0xc004befc20 sp=0xc004befb60 pc=0x439792
command-line-arguments.(*SomeType).callSite4(0xc00027bd20?, {{0x7a6480, 0x8dd510}, 0x0, {0x0, 0x0, 0x0}, {0x0, 0x0}, 0x0})
	/tmp/file1_1093370123/file4.go:16 +0x25 fp=0xc004befc40 sp=0xc004befc20 pc=0x417352ad
command-line-arguments.(*SomeType).callSite3(0x4e2e73746e656d75?, {{0x7a6480, 0x8dd510}, 0x0, {0x0, 0x0, 0x0}, {0x0, 0x0}, 0x0})
	/tmp/file1_1093370123/file3.go:13 +0x50 fp=0xc004befca0 sp=0xc004befc40 pc=0x41735268
command-line-arguments.(*SomeType).callSite2(0xc000028034?, {{0x7a6480, 0x8dd510}, 0x0, {0x0, 0x0, 0x0}, {0x0, 0x0}, 0x0})
	/tmp/file1_1093370123/file2.go:11 +0x50 fp=0xc004befd00 sp=0xc004befca0 pc=0x417351f8
command-line-arguments.(*SomeType).callSite1(0x0?, {{0x7a6480, 0x8dd510}, 0x0, {0x0, 0x0, 0x0}, {0x0, 0x0}, 0x0})
	/tmp/file1_1093370123/file1.go:7 +0x50 fp=0xc004befd60 sp=0xc004befd00 pc=0x41735188
created by testing.(*T).Run
	/usr/local/go/src/testing/testing.go:1493 +0x35f

@eh-steve
Copy link
Author

eh-steve commented Nov 9, 2022

@pkujhd All tests are passing on my machine now, I think it's ready for review

@pkujhd
Copy link
Owner

pkujhd commented Nov 14, 2022

Edit: Fixed this now

Some tests are still failing randomly (e.g. TestStackSplit and TestJitPanicRecoveryStackTrace) due to some outstanding bugs in goloader which still need to be fixed.

how to fixed it? I don't find the code change for goloader.

@pkujhd
Copy link
Owner

pkujhd commented Nov 14, 2022

@eh-steve

For commit 31f8f2b, the pclntable does not split for adapter golang version < 1.16

For commit 3cd5a08, plugin use deduplicate function to deal it, but in goloader it will be lead to far address relocate error on R_ADDROFF & R_METHODOFF. By modifying read-only memory. used first module type descriptor. it could avoid it, but I worried it will be forbidden on MacOSX. I think maybe the best way are use deduplicate function to deal it and copy type descriptor with far address relocated from the first module into data segment. (it maybe means a lots of workload, because a far address type descriptor maybe is an interface)

By the way,
I cannot merge pr because the current version cannot pass all tests. I will wait for the newer commit.

Anonymous added 30 commits July 31, 2023 17:33
… hijack firstmoduledata.typemap to allow resolveTypeOff to find JIT types using a firstmodule base address
… fix bug where inittask package names containing a dot were not properly escaped
…est which involves mutating C initialised data and C calling Go
… wraps handwritten asm with a PUSH/POP BP to create frames for you
…en JMP (back from epilogue) instead of CALL (into epilogue) then JMP (into target func), since if a traceback hits while we're in the epilogue, the funcForPC for the current PC will not be aligned with the link register (regardless whether the LR is virtual or real), and it will appear that the callee and caller are the same `_func`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants