wasm: fix functions exported through //export
When a function is exported using //export, but also had a //go:wasm-module pragma, the //export name was ignored. The //go:wasm-module doesn't actually do anything besides breaking the export (exported functions don't have a module name). I've refactored and cleaned up the code, and in the process removed this weird edge case.
Этот коммит содержится в:
родитель
00d46bd25d
коммит
d845f1e1b2
3 изменённых файлов: 39 добавлений и 35 удалений
|
@ -23,9 +23,9 @@ import (
|
||||||
// The linkName value contains a valid link name, even if //go:linkname is not
|
// The linkName value contains a valid link name, even if //go:linkname is not
|
||||||
// present.
|
// present.
|
||||||
type functionInfo struct {
|
type functionInfo struct {
|
||||||
module string // go:wasm-module
|
wasmModule string // go:wasm-module
|
||||||
importName string // go:linkname, go:export - The name the developer assigns
|
wasmName string // wasm-export-name or wasm-import-name in the IR
|
||||||
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
|
linkName string // go:linkname, go:export - the IR function name
|
||||||
section string // go:section - object file section name
|
section string // go:section - object file section name
|
||||||
exported bool // go:export, CGo
|
exported bool // go:export, CGo
|
||||||
interrupt bool // go:interrupt
|
interrupt bool // go:interrupt
|
||||||
|
@ -194,20 +194,14 @@ func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value)
|
||||||
// External/exported functions may not retain pointer values.
|
// External/exported functions may not retain pointer values.
|
||||||
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
// https://golang.org/cmd/cgo/#hdr-Passing_pointers
|
||||||
if info.exported {
|
if info.exported {
|
||||||
if c.archFamily() == "wasm32" {
|
if c.archFamily() == "wasm32" && len(fn.Blocks) == 0 {
|
||||||
// We need to add the wasm-import-module and the wasm-import-name
|
// We need to add the wasm-import-module and the wasm-import-name
|
||||||
// attributes.
|
// attributes.
|
||||||
module := info.module
|
if info.wasmModule != "" {
|
||||||
if module == "" {
|
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", info.wasmModule))
|
||||||
module = "env"
|
|
||||||
}
|
}
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", module))
|
|
||||||
|
|
||||||
name := info.importName
|
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", info.wasmName))
|
||||||
if name == "" {
|
|
||||||
name = info.linkName
|
|
||||||
}
|
|
||||||
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", name))
|
|
||||||
}
|
}
|
||||||
nocaptureKind := llvm.AttributeKindID("nocapture")
|
nocaptureKind := llvm.AttributeKindID("nocapture")
|
||||||
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
|
||||||
|
@ -260,10 +254,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
|
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 {
|
for _, comment := range decl.Doc.List {
|
||||||
text := comment.Text
|
text := comment.Text
|
||||||
if strings.HasPrefix(text, "//export ") {
|
if strings.HasPrefix(text, "//export ") {
|
||||||
|
@ -281,7 +271,8 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
importName = parts[1]
|
info.linkName = parts[1]
|
||||||
|
info.wasmName = info.linkName
|
||||||
info.exported = true
|
info.exported = true
|
||||||
case "//go:interrupt":
|
case "//go:interrupt":
|
||||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
|
@ -289,10 +280,11 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||||
}
|
}
|
||||||
case "//go:wasm-module":
|
case "//go:wasm-module":
|
||||||
// Alternative comment for setting the import module.
|
// Alternative comment for setting the import module.
|
||||||
|
// This is deprecated, use //go:wasmimport instead.
|
||||||
if len(parts) != 2 {
|
if len(parts) != 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
info.module = parts[1]
|
info.wasmModule = parts[1]
|
||||||
case "//go:wasmimport":
|
case "//go:wasmimport":
|
||||||
// Import a WebAssembly function, for example a WASI function.
|
// Import a WebAssembly function, for example a WASI function.
|
||||||
// Original proposal: https://github.com/golang/go/issues/38248
|
// Original proposal: https://github.com/golang/go/issues/38248
|
||||||
|
@ -302,8 +294,8 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
|
||||||
}
|
}
|
||||||
c.checkWasmImport(f, comment.Text)
|
c.checkWasmImport(f, comment.Text)
|
||||||
info.exported = true
|
info.exported = true
|
||||||
info.module = parts[1]
|
info.wasmModule = parts[1]
|
||||||
info.importName = parts[2]
|
info.wasmName = parts[2]
|
||||||
case "//go:inline":
|
case "//go:inline":
|
||||||
info.inline = inlineHint
|
info.inline = inlineHint
|
||||||
case "//go:noinline":
|
case "//go:noinline":
|
||||||
|
@ -347,17 +339,6 @@ func (c *compilerContext) parsePragmas(info *functionInfo, 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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
compiler/testdata/pragma.go
предоставленный
13
compiler/testdata/pragma.go
предоставленный
|
@ -62,6 +62,19 @@ func exportedFunctionInSection() {
|
||||||
//go:wasmimport modulename import1
|
//go:wasmimport modulename import1
|
||||||
func declaredImport()
|
func declaredImport()
|
||||||
|
|
||||||
|
// Legacy way of importing a function.
|
||||||
|
//
|
||||||
|
//go:wasm-module foobar
|
||||||
|
//export imported
|
||||||
|
func foobarImport()
|
||||||
|
|
||||||
|
// The wasm-module pragma is not functional here, but it should be safe.
|
||||||
|
//
|
||||||
|
//go:wasm-module foobar
|
||||||
|
//export exported
|
||||||
|
func foobarExportModule() {
|
||||||
|
}
|
||||||
|
|
||||||
// This function should not: it's only a declaration and not a definition.
|
// This function should not: it's only a declaration and not a definition.
|
||||||
//
|
//
|
||||||
//go:section .special_function_section
|
//go:section .special_function_section
|
||||||
|
|
16
compiler/testdata/pragma.ll
предоставленный
16
compiler/testdata/pragma.ll
предоставленный
|
@ -6,7 +6,7 @@ target triple = "wasm32-unknown-wasi"
|
||||||
@extern_global = external global [0 x i8], align 1
|
@extern_global = external global [0 x i8], align 1
|
||||||
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
||||||
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
||||||
@llvm.used = appending global [2 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection]
|
@llvm.used = appending global [3 x ptr] [ptr @extern_func, ptr @exportedFunctionInSection, ptr @exported]
|
||||||
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
||||||
@undefinedGlobalNotInSection = external global i32, align 4
|
@undefinedGlobalNotInSection = external global i32, align 4
|
||||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||||
|
@ -62,13 +62,23 @@ entry:
|
||||||
|
|
||||||
declare void @main.declaredImport() #7
|
declare void @main.declaredImport() #7
|
||||||
|
|
||||||
|
declare void @imported() #8
|
||||||
|
|
||||||
|
; Function Attrs: nounwind
|
||||||
|
define void @exported() #9 {
|
||||||
|
entry:
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
declare void @main.undefinedFunctionNotInSection(ptr) #1
|
||||||
|
|
||||||
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #0 = { allockind("alloc,zeroed") allocsize(0) "alloc-family"="runtime.alloc" "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #1 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #2 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" "wasm-import-module"="env" "wasm-import-name"="extern_func" }
|
attributes #3 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="extern_func" }
|
||||||
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #4 = { inlinehint nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
attributes #5 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" }
|
||||||
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" "wasm-import-module"="env" "wasm-import-name"="exportedFunctionInSection" }
|
attributes #6 = { noinline nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exportedFunctionInSection" }
|
||||||
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
attributes #7 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="modulename" "wasm-import-name"="import1" }
|
||||||
|
attributes #8 = { "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-import-module"="foobar" "wasm-import-name"="imported" }
|
||||||
|
attributes #9 = { nounwind "target-features"="+bulk-memory,+nontrapping-fptoint,+sign-ext" "wasm-export-name"="exported" }
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче