Skip to content

Compiler feedback for 'target=wasm'+'gc=none' #2495

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

Closed
jzabinski-dolios opened this issue Jan 7, 2022 · 12 comments
Closed

Compiler feedback for 'target=wasm'+'gc=none' #2495

jzabinski-dolios opened this issue Jan 7, 2022 · 12 comments
Labels
wasm WebAssembly

Comments

@jzabinski-dolios
Copy link

jzabinski-dolios commented Jan 7, 2022

TinyGo v0.21.0

When I compile like this:

tinygo build -o tinygo.wasm -target=wasm -gc=none -scheduler=none -no-debug ./findJD.go

And then convert the WASM to WAT to look at the output (using another tool), I can see that the following is created (among other things):

(import "env" "runtime.alloc" (func $fimport$0 (param i32 i32 i32 i32) (result i32)))
(import "env" "main.main" (func $fimport$1 (param i32 i32)))

If I then instantiate this file using WebAssembly.instantiateStreaming (and RXJS):

switchMap(() => fetch('assets/tinygo.wasm')),
switchMap(wasmBytes => WebAssembly.instantiateStreaming(wasmBytes, (new Go()).importObject)),

Then I get this error:
Uncaught LinkError: WebAssembly.instantiate(): Import #0 module="env" function="runtime.alloc" error: function import requires a callable

The root cause appears to be that wasm_exec.js has no env["runtime.alloc"] function. This is true of the current version (0.21.0), as well as the dev branch. The documentation mentions that wasm_exec.js comes from $GOROOT/misc/wasm/wasm_exec.js. Checking this for my local installation of Go v1.17, env["runtime.alloc"] does not appear there either.
The same conditions apply for env["main.main"].

Troubleshooting a bit, I tried a few compiler options, and found that main.main seemed to be expected regardless of setting (although I didn't try every setting). runtime.alloc begins to appear with the compiler setting gc=none.

The issue has a workaround: stub the functions in Javascript to satisfy the Javascript-WebAssembly linker, and then otherwise ignore them.

In Javascript, this should work:

const tinygoImportObj = (new Go()).importObject;
tinygoImportObj.env['runtime.alloc'] = (a, b, c, d) => 0;
tinygoImportObj.env['main.main'] = (a, b) => void 0;
...
WebAssembly.instantiateStreaming(wasmBytes, tinygoImportObj)

Possibly related to this issue

@deadprogram deadprogram added the wasm WebAssembly label Jan 7, 2022
@aykevl
Copy link
Member

aykevl commented Jan 19, 2022

(import "env" "runtime.alloc" (func $fimport$0 (param i32 i32 i32 i32) (result i32)))

This is because you have passed -gc=none. You should probably omit this flag, to leave it at the default (conservative).

(import "env" "main.main" (func $fimport$1 (param i32 i32)))

This is because you didn't define a main function. You should have one, even if it is empty.
Also, note that you must call _start before calling any other exported function. Otherwise many parts will not be initialized, such as the heap.

@jzabinski-dolios
Copy link
Author

Thanks, that resolves the immediate problem.

I think that wasm_exec.js is intended to be a static file: that is, developers are not expected to need to add anything to what is supplied in wasm_exec.js. It would be possible for developers to create their own runtime.alloc and main.main functions, but it doesn't sound like that is a goal of TinyGo.

As such:

  1. Should the combination of target=wasm and gc=none result in a compiler error?
  2. Should the lack of a func main() in the source file result in a compiler error?

@aykevl
Copy link
Member

aykevl commented Jan 21, 2022

I think that wasm_exec.js is intended to be a static file: that is, developers are not expected to need to add anything to what is supplied in wasm_exec.js.

Correct.

It would be possible for developers to create their own runtime.alloc and main.main functions, but it doesn't sound like that is a goal of TinyGo.

Why would you want to replace runtime.alloc? There is a heap/GC implementation already in TinyGo.

As such:

  1. Should the combination of target=wasm and gc=none result in a compiler error?

Probably. It doesn't at the moment because we have the flag --allow-undefined.

  1. Should the lack of a func main() in the source file result in a compiler error?

Yes. It did in the past, but apparently this got removed at some point. This would be fixed by removing --allow-undefined.

@codefromthecrypt
Copy link
Contributor

@jzabinski-dolios is it ok to close this issue? it sounds like you are working now, even if some of the defaults are a bit confusing.

@jzabinski-dolios
Copy link
Author

Yes, things are working now. I think that there are a few issues described in this comment that should be spun off to separate issues. (target=wasm+gc=none probably should result in a compiler error. Inputting a TInygo program without a func main() should result in a compiler error.)

@codefromthecrypt
Copy link
Contributor

Thanks for the tips @jzabinski-dolios! Here's some spin-offs, preferring re-use of tickets as there are so many :p

target=wasm+gc=none probably should result in a compiler error

I think maybe you can rename this issue to "target=wasm+gc=none probably should result in a compiler error" and keep it as it the best description of the problem.

Inputting a TInygo program without a func main() should result in a compiler error.

re-using #2703

@aykevl
Copy link
Member

aykevl commented Sep 8, 2022

This is working as intended, especially now with #3133. The intention of -gc=none is to result in a compiler error if you use a GC at all (unlike -gc=leaking, which simply disables collecting memory).

@codefromthecrypt
Copy link
Contributor

To help make sure we can close out issues, I just tried this. It is true that it fails, just hard to decipher why. Do we have any other argument incompatibility validation anywhere?

Ex.

$ ~/oss/tinygo/build/tinygo build -gc=none -target=wasm -o main.wasm main.go
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main.o: undefined symbol: runtime.alloc
tinygo:wasm-ld: error: too many errors emitted, stopping now (use -error-limit=0 to see all errors)
failed to run tool: wasm-ld
error: failed to link /var/folders/vd/1cf8zdb1721f4z5rjggy8bp40000gn/T/tinygo2023991394/main: exit status 1

@aykevl
Copy link
Member

aykevl commented Sep 8, 2022

Yes it fails in your case, but it doesn't necessarily have to fail. If you have a very small program with -scheduler=none, it may in fact pass (if you use #3142, without it it will always fail). Here is an example:

$ tinygo run -target=wasi -scheduler=none -gc=none ./testdata/alias.go
x
apple
true
false

(Sidenote: sadly wasm-ld doesn't seem to be able to find the source location of the link error, LLD is usually able to do that for ELF etc).

@jzabinski-dolios
Copy link
Author

So:

  1. "Inputting a TInygo program without a func main() should result in a compiler error"
    -Abandoning the issue in this ticket in favor of Don't require main function in wasm builds #2703
  2. "target=wasm+gc=none probably should result in a compiler error"
    -scheduler=none needs to be taken into account. The issue also partially depends on the fate of wasm: do not export malloc, calloc, realloc, free #3142.

I'll change the title to reflect these details. Let me know if I missed something.

@jzabinski-dolios jzabinski-dolios changed the title Uncaught LinkError: WebAssembly.instantiate(): Import #0 module="env" function="runtime.alloc" error: function import requires a callable Compiler feedback for 'target=wasm'+'gc=none' Sep 8, 2022
@dgryski
Copy link
Member

dgryski commented Oct 21, 2024

I think you want the new wasm-unknown target that should allow building just a wasm file with no imports (like memory allocation). Please close if that works for you.

@deadprogram
Copy link
Member

Closing since this question appears to have been answered. Thank you everyone!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
wasm WebAssembly
Projects
None yet
Development

No branches or pull requests

5 participants