5 ms·
This is more complex then just a target. Rust has to communicate to the Go Runtime Environment. Two main points: -Go uses a very small stack for GoRoutines to
by valarauca1 9y ago
This is more complex then just a target. Rust has to communicate to the Go Runtime Environment.
Two main points:
-Go uses a very small stack for GoRoutines to make them dirt cheap. When you exceed this stack, Go maps in more stack for you transparently. Rust generated ASM is running on the Go Stack, but it is expecting when it exceeds its stack to explode, like a C program. As that should be the OS Stack. Larger problem then you think, Rust likes to put a ton of stuff on the stack. This is one of the nice things about Rust is putting _a ton_ of data on the stack is cheap, and makes ownership simpler.
-Go's system calls, and concurrency primitives are cooperative with its runtime. When make they communicate the routine can yield to the runtime. Targeted Rust code would _also_ have to make these calls, as well as 3rd party crates.
Again none of this is impossible, linker directives and FFI magic could import these functions/symbols. But this would also require Go have a stabilized runtime environment for other languages to link against. Currently just stating Go has a runtime is controversial, so I expect this won't happen soon.
- vvanders 9y agoThings may have changed from when I last looked at it but there's another issue which is pinning. If you ever want to do more than the most trivial FFI you'll eventually want to be able to pass types back and forth(usually opaque to either side). AFAIK Go doesn't offer any pinning if it's GC'd types so you can have the collector move them from under you. C# has this beautiful thing where you can pass a delegate as a raw C fn pointer. It makes building interop a wonderful thing but you have to make sure to pin/GCHandle it appropriately.
- FiloSottile 9y agoFolks, stop, you are reinventing cgo now. Defining a Go target for Rust actually makes sense in the context of replacing assembly (which has no runtime, GC or concurrency connotations), I was just too lazy to do it that way :)
- vvanders 9y agoI mean, kinda but not? Based on https://github.com/golang/go/issues/12416 https://github.com/golang/go/issues/12416 / https://golang.org/cmd/cgo/ https://golang.org/cmd/cgo/ : > However, C code may not keep a copy of the Go pointer after the call returns. It looks like they've just punted on the pinning issue and not allowed code that does it. Having written a ton of FFI code across a wide range of languages this type of restriction means that you're not going to be able to implement certain things which is unfortunate.
- valarauca1 9y ago> Folks, stop, you are reinventing cgo now. This is a good thing because `cgo` is really bad. No ALSR, always forking. These are completely _insane_ defaults, it manages to be slower then the JNI [1] which is an FFI from a completely managed stack based VM universe! Not a _compiled_ language. Somehow a compile language calling a static binary manages to be slower then a dynamic language's runtime calling a static binary... `cgo` isn't doing _anything right_. It is doing a lot of things wrong. [1] https://lwn.net/Articles/446701/ https://lwn.net/Articles/446701/
- yumaikas 9y agoThat article comment is from 2011, is cgo still slower than JNI?
- masklinn 9y agoAccording to this old SO comment[0] JNI calls on x86_64 have an overhead of about 6ns. On my machine (2010 MBP @ 2.4GHz), cgo calls have an overhead of ~120ns. [0] https://stackoverflow.com/questions/13973035/what-is-the-quantitative-overhead-of-making-a-jni-call https://stackoverflow.com/questions/13973035/what-is-the-qua...
- uluyol 9y agoNo, if you think there are problems with cgo, the solution is to address those problems, not reinvent it. If you have performance concerns, file a bug or comment on an existing one. Also, I don't see any reason why jni should be slower than cgo. Go has its own scheduler that brings overhead to cgo and needs to switch stacks whereas Java doesn't have to deal with such things.
- masklinn 9y ago> This is more complex then just a target. Rust has to communicate to the Go Runtime Environment. If you want full Go embedding sure, but this discussion is in the context of TFA whose stated purpose is the ability to build optimised "pure" sub-functions without having to use plan9 assembly. In that case, what a Go target does is remove the need for a trampoline and manually fucking around with calling conventions.
- anonacct37 9y agoMaybe this would make more sense in llgo. I don't know how it's structured, but if it it uses the abi/calling convention of llvm and possibly llvm's segmented stack it might be (waves hands) a little easier to integrate with rust. As for concurrency and system calls, I'd say that go people probably would get a tremendous amount of value out of just single threaded rust code that didn't do I/O. Like parsers.
- weberc2 9y ago> -Go uses a very small stack for GoRoutines to make them dirt cheap. When you exceed this stack, Go maps in more stack for you transparently. Rust generated ASM is running on the Go Stack, but it is expecting when it exceeds its stack to explode, like a C program. As that should be the OS Stack. Larger problem then you think, Rust likes to put a ton of stuff on the stack. This is one of the nice things about Rust is putting _a ton_ of data on the stack is cheap, and makes ownership simpler. This point confuses me; if Rust expects to run on a limited stack, why would it expect to put a ton of data on the stack? > Currently just stating Go has a runtime is controversial I've never heard any controversy... The Go community certainly call it a runtime, and there's even a "runtime" package. Do folks from VM languages get grumpy because Go's runtime is statically linked?
- masklinn 9y ago> This point confuses me; if Rust expects to run on a limited stack, why would it expect to put a ton of data on the stack? Rust runs on a C stack, while it's not infinite[0] it's a whole other ballpark than a Go stack since it's non-growable (Rust used to use growable stacks before 1.0): the default C stack size is in the megabyte range (8MB virtual on most unices[1]), in Go the initial stack is 2kB (since 1.4, 8k before). [0] you can set the size to "unlimited", systems will vary in their behaviour there, on my OSX it sets the stack size to 64MB, Linux apparently allows actual unlimited stack sizes but I've no idea how it actually works to provide that [1] I think libpthread defines its own stack size circa 2MB so 8MB would be the stack of your main thread and 2MB for sub-threads, but I'm not actually sure
- deleted 9y ago[deleted]