diff options
author | Ayke van Laethem <[email protected]> | 2022-09-08 13:44:48 +0200 |
---|---|---|
committer | Ayke van Laethem <[email protected]> | 2022-09-15 11:36:26 +0200 |
commit | 7e7814a0872c079d82d2f1837078e7eb5db06798 (patch) | |
tree | 6839ab169ce4966647f192491d62c5b75998f638 | |
parent | 03d1c44265e1f628b2730b9c214db2390a745ee6 (diff) | |
download | tinygo-7e7814a0872c079d82d2f1837078e7eb5db06798.tar.gz tinygo-7e7814a0872c079d82d2f1837078e7eb5db06798.zip |
wasm: do not export malloc, calloc, realloc, free
These functions were exported by accident, because the compiler had no
way of saying these functions shouldn't be exported.
This can be a big code size reduction for small programs. Before:
$ tinygo build -o test.wasm -target=wasi -no-debug -scheduler=none ./testdata/alias.go && ls -l test.wasm
-rwxrwxr-x 1 ayke ayke 2947 8 sep 13:47 test.wasm
After:
$ tinygo build -o test.wasm -target=wasi -no-debug -scheduler=none ./testdata/alias.go && ls -l test.wasm
-rwxrwxr-x 1 ayke ayke 968 8 sep 13:47 test.wasm
This is all because the GC isn't needed anymore.
This commit also adds support for using //go:wasm-module to set the
module name of an exported function (the default remains env).
-rw-r--r-- | compiler/compiler.go | 7 | ||||
-rw-r--r-- | compiler/symbol.go | 32 | ||||
-rw-r--r-- | compiler/testdata/pragma.ll | 4 | ||||
-rw-r--r-- | src/runtime/arch_tinygowasm.go | 4 |
4 files changed, 21 insertions, 26 deletions
diff --git a/compiler/compiler.go b/compiler/compiler.go index bbaf6432f..179a0928e 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1059,11 +1059,12 @@ func (b *builder) createFunctionStart(intrinsic bool) { if b.info.section != "" { b.llvmFn.SetSection(b.info.section) } - if b.info.exported && strings.HasPrefix(b.Triple, "wasm") { + if b.info.exported && b.info.module != "" && strings.HasPrefix(b.Triple, "wasm") { // Set the exported name. This is necessary for WebAssembly because // otherwise the function is not exported. - functionAttr := b.ctx.CreateStringAttribute("wasm-export-name", b.info.linkName) - b.llvmFn.AddFunctionAttr(functionAttr) + b.llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("wasm-export-name", b.info.linkName)) + // Set the export module. + b.llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("wasm-export-module", b.info.module)) } // Some functions have a pragma controlling the inlining level. diff --git a/compiler/symbol.go b/compiler/symbol.go index c4ce6f21d..491b845c6 100644 --- a/compiler/symbol.go +++ b/compiler/symbol.go @@ -210,8 +210,9 @@ func (c *compilerContext) getFunction(fn *ssa.Function) llvm.Value { // exported. func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo { info := functionInfo{ - // Pick the default linkName. - linkName: f.RelString(nil), + module: "env", + importName: f.Name(), + linkName: f.RelString(nil), // pick the default linkName } // Check for //go: pragmas, which may change the link name (among others). info.parsePragmas(f) @@ -225,10 +226,6 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) { return } if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil { - - // Our importName for a wasm module (if we are compiling to wasm), or llvm link name - var importName string - for _, comment := range decl.Doc.List { text := comment.Text if strings.HasPrefix(text, "//export ") { @@ -246,7 +243,8 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) { continue } - importName = parts[1] + info.importName = parts[1] + info.linkName = parts[1] info.exported = true case "//go:interrupt": if hasUnsafeImport(f.Pkg.Pkg) { @@ -254,10 +252,13 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) { } case "//go:wasm-module": // Alternative comment for setting the import module. - if len(parts) != 2 { - continue + if len(parts) == 1 { + // Function must not be exported outside of the WebAssembly + // module (but only be made available for linking). + info.module = "" + } else if len(parts) == 2 { + info.module = parts[1] } - info.module = parts[1] case "//go:inline": info.inline = inlineHint case "//go:noinline": @@ -297,17 +298,6 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) { } } } - - // Set the importName for our exported function if we have one - if importName != "" { - if info.module == "" { - info.linkName = importName - } else { - // WebAssembly import - info.importName = importName - } - } - } } diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll index b243602d3..403f4f4a0 100644 --- a/compiler/testdata/pragma.ll +++ b/compiler/testdata/pragma.ll @@ -62,7 +62,7 @@ declare void @main.undefinedFunctionNotInSection(i8*) #0 attributes #0 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #1 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } -attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" } +attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-module"="env" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" } attributes #3 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } attributes #4 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" } -attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" } +attributes #5 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-module"="env" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" } diff --git a/src/runtime/arch_tinygowasm.go b/src/runtime/arch_tinygowasm.go index 910858be6..eb5ba5b58 100644 --- a/src/runtime/arch_tinygowasm.go +++ b/src/runtime/arch_tinygowasm.go @@ -68,6 +68,7 @@ func growHeap() bool { var allocs = make(map[uintptr][]byte) //export malloc +//go:wasm-module func libc_malloc(size uintptr) unsafe.Pointer { buf := make([]byte, size) ptr := unsafe.Pointer(&buf[0]) @@ -76,6 +77,7 @@ func libc_malloc(size uintptr) unsafe.Pointer { } //export free +//go:wasm-module func libc_free(ptr unsafe.Pointer) { if ptr == nil { return @@ -88,12 +90,14 @@ func libc_free(ptr unsafe.Pointer) { } //export calloc +//go:wasm-module func libc_calloc(nmemb, size uintptr) unsafe.Pointer { // No difference between calloc and malloc. return libc_malloc(nmemb * size) } //export realloc +//go:wasm-module func libc_realloc(oldPtr unsafe.Pointer, size uintptr) unsafe.Pointer { // It's hard to optimize this to expand the current buffer with our GC, but // it is theoretically possible. For now, just always allocate fresh. |