mirror of
https://github.com/tinygo-org/tinygo.git
synced 2026-07-26 06:38:42 +00:00
wasm: add Boehm GC support
This adds support for `-gc=boehm` on `-target=wasip1` and `-target=wasm` (in a browser or NodeJS). Notably it does *not* add Boehm GC support for `-target=wasip2`, since that target doesn't have a real libc.
This commit is contained in:
committed by
Ron Evans
parent
9c3b706533
commit
c08b2dfe06
+4
-2
@@ -14,7 +14,7 @@ var BoehmGC = Library{
|
|||||||
name: "bdwgc",
|
name: "bdwgc",
|
||||||
cflags: func(target, headerPath string) []string {
|
cflags: func(target, headerPath string) []string {
|
||||||
libdir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
|
libdir := filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
|
||||||
return []string{
|
flags := []string{
|
||||||
// use a modern environment
|
// use a modern environment
|
||||||
"-DUSE_MMAP", // mmap is available
|
"-DUSE_MMAP", // mmap is available
|
||||||
"-DUSE_MUNMAP", // return memory to the OS using munmap
|
"-DUSE_MUNMAP", // return memory to the OS using munmap
|
||||||
@@ -30,6 +30,7 @@ var BoehmGC = Library{
|
|||||||
// Use a minimal environment.
|
// Use a minimal environment.
|
||||||
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
|
"-DNO_MSGBOX_ON_ERROR", // don't call MessageBoxA on Windows
|
||||||
"-DDONT_USE_ATEXIT",
|
"-DDONT_USE_ATEXIT",
|
||||||
|
"-DNO_GETENV",
|
||||||
|
|
||||||
// Special flag to work around the lack of __data_start in ld.lld.
|
// Special flag to work around the lack of __data_start in ld.lld.
|
||||||
// TODO: try to fix this in LLVM/lld directly so we don't have to
|
// TODO: try to fix this in LLVM/lld directly so we don't have to
|
||||||
@@ -49,12 +50,13 @@ var BoehmGC = Library{
|
|||||||
|
|
||||||
"-I" + libdir + "/include",
|
"-I" + libdir + "/include",
|
||||||
}
|
}
|
||||||
|
return flags
|
||||||
},
|
},
|
||||||
needsLibc: true,
|
needsLibc: true,
|
||||||
sourceDir: func() string {
|
sourceDir: func() string {
|
||||||
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
|
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/bdwgc")
|
||||||
},
|
},
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
sources := []string{
|
sources := []string{
|
||||||
"allchblk.c",
|
"allchblk.c",
|
||||||
"alloc.c",
|
"alloc.c",
|
||||||
|
|||||||
+1
-1
@@ -226,7 +226,7 @@ var libCompilerRT = Library{
|
|||||||
// Development build.
|
// Development build.
|
||||||
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
|
return filepath.Join(goenv.Get("TINYGOROOT"), "lib/compiler-rt-builtins")
|
||||||
},
|
},
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
builtins := append([]string{}, genericBuiltins...) // copy genericBuiltins
|
||||||
switch compileopts.CanonicalArchName(target) {
|
switch compileopts.CanonicalArchName(target) {
|
||||||
case "arm":
|
case "arm":
|
||||||
|
|||||||
+2
-2
@@ -38,7 +38,7 @@ type Library struct {
|
|||||||
sourceDir func() string
|
sourceDir func() string
|
||||||
|
|
||||||
// The source files, relative to sourceDir.
|
// The source files, relative to sourceDir.
|
||||||
librarySources func(target string) ([]string, error)
|
librarySources func(target string, libcNeedsMalloc bool) ([]string, error)
|
||||||
|
|
||||||
// The source code for the crt1.o file, relative to sourceDir.
|
// The source code for the crt1.o file, relative to sourceDir.
|
||||||
crt1Source string
|
crt1Source string
|
||||||
@@ -226,7 +226,7 @@ func (l *Library) load(config *compileopts.Config, tmpdir string) (job *compileJ
|
|||||||
|
|
||||||
// Create jobs to compile all sources. These jobs are depended upon by the
|
// Create jobs to compile all sources. These jobs are depended upon by the
|
||||||
// archive job above, so must be run first.
|
// archive job above, so must be run first.
|
||||||
paths, err := l.librarySources(target)
|
paths, err := l.librarySources(target, config.LibcNeedsMalloc())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ var libMinGW = Library{
|
|||||||
}
|
}
|
||||||
return flags
|
return flags
|
||||||
},
|
},
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
// These files are needed so that printf and the like are supported.
|
// These files are needed so that printf and the like are supported.
|
||||||
var sources []string
|
var sources []string
|
||||||
if strings.Split(target, "-")[0] == "i386" {
|
if strings.Split(target, "-")[0] == "i386" {
|
||||||
|
|||||||
+1
-1
@@ -121,7 +121,7 @@ var libMusl = Library{
|
|||||||
return cflags
|
return cflags
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/musl/src") },
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
arch := compileopts.MuslArchitecture(target)
|
arch := compileopts.MuslArchitecture(target)
|
||||||
globs := []string{
|
globs := []string{
|
||||||
"conf/*.c",
|
"conf/*.c",
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ var libPicolibc = Library{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/picolibc/newlib") },
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
sources := append([]string(nil), picolibcSources...)
|
sources := append([]string(nil), picolibcSources...)
|
||||||
if !strings.HasPrefix(target, "avr") {
|
if !strings.HasPrefix(target, "avr") {
|
||||||
// Small chips without long jumps can't compile many files (printf,
|
// Small chips without long jumps can't compile many files (printf,
|
||||||
|
|||||||
+6
-1
@@ -120,7 +120,7 @@ var libWasiLibc = Library{
|
|||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, libcNeedsMalloc bool) ([]string, error) {
|
||||||
type filePattern struct {
|
type filePattern struct {
|
||||||
glob string
|
glob string
|
||||||
exclude []string
|
exclude []string
|
||||||
@@ -169,6 +169,11 @@ var libWasiLibc = Library{
|
|||||||
{glob: "libc-bottom-half/sources/*.c"},
|
{glob: "libc-bottom-half/sources/*.c"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We're using the Boehm GC, so we need a heap implementation in the libc.
|
||||||
|
if libcNeedsMalloc {
|
||||||
|
globs = append(globs, filePattern{glob: "dlmalloc/src/dlmalloc.c"})
|
||||||
|
}
|
||||||
|
|
||||||
// See: LIBC_TOP_HALF_MUSL_SOURCES in the Makefile
|
// See: LIBC_TOP_HALF_MUSL_SOURCES in the Makefile
|
||||||
sources := []string{
|
sources := []string{
|
||||||
"libc-top-half/musl/src/misc/a64l.c",
|
"libc-top-half/musl/src/misc/a64l.c",
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ var libWasmBuiltins = Library{
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
sourceDir: func() string { return filepath.Join(goenv.Get("TINYGOROOT"), "lib/wasi-libc") },
|
||||||
librarySources: func(target string) ([]string, error) {
|
librarySources: func(target string, _ bool) ([]string, error) {
|
||||||
return []string{
|
return []string{
|
||||||
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
|
// memory builtins needed for llvm.memcpy.*, llvm.memmove.*, and
|
||||||
// llvm.memset.* LLVM intrinsics.
|
// llvm.memset.* LLVM intrinsics.
|
||||||
|
|||||||
+18
-3
@@ -22,7 +22,8 @@ import (
|
|||||||
// builder.Library struct but that's hard to do since we want to know the
|
// builder.Library struct but that's hard to do since we want to know the
|
||||||
// library path in advance in several places).
|
// library path in advance in several places).
|
||||||
var libVersions = map[string]int{
|
var libVersions = map[string]int{
|
||||||
"musl": 3,
|
"musl": 3,
|
||||||
|
"bdwgc": 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Config keeps all configuration affecting the build in a single struct.
|
// Config keeps all configuration affecting the build in a single struct.
|
||||||
@@ -138,7 +139,7 @@ func (c *Config) GC() string {
|
|||||||
// that can be traced by the garbage collector.
|
// that can be traced by the garbage collector.
|
||||||
func (c *Config) NeedsStackObjects() bool {
|
func (c *Config) NeedsStackObjects() bool {
|
||||||
switch c.GC() {
|
switch c.GC() {
|
||||||
case "conservative", "custom", "precise":
|
case "conservative", "custom", "precise", "boehm":
|
||||||
for _, tag := range c.BuildTags() {
|
for _, tag := range c.BuildTags() {
|
||||||
if tag == "tinygo.wasm" {
|
if tag == "tinygo.wasm" {
|
||||||
return true
|
return true
|
||||||
@@ -263,6 +264,15 @@ func MuslArchitecture(triple string) string {
|
|||||||
return CanonicalArchName(triple)
|
return CanonicalArchName(triple)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns true if the libc needs to include malloc, for the libcs where this
|
||||||
|
// matters.
|
||||||
|
func (c *Config) LibcNeedsMalloc() bool {
|
||||||
|
if c.GC() == "boehm" && c.Target.Libc == "wasi-libc" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// LibraryPath returns the path to the library build directory. The path will be
|
// LibraryPath returns the path to the library build directory. The path will be
|
||||||
// a library path in the cache directory (which might not yet be built).
|
// a library path in the cache directory (which might not yet be built).
|
||||||
func (c *Config) LibraryPath(name string) string {
|
func (c *Config) LibraryPath(name string) string {
|
||||||
@@ -286,9 +296,14 @@ func (c *Config) LibraryPath(name string) string {
|
|||||||
archname += "-v" + strconv.Itoa(v)
|
archname += "-v" + strconv.Itoa(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options := ""
|
||||||
|
if c.LibcNeedsMalloc() {
|
||||||
|
options += "+malloc"
|
||||||
|
}
|
||||||
|
|
||||||
// No precompiled library found. Determine the path name that will be used
|
// No precompiled library found. Determine the path name that will be used
|
||||||
// in the build cache.
|
// in the build cache.
|
||||||
return filepath.Join(goenv.Get("GOCACHE"), name+"-"+archname)
|
return filepath.Join(goenv.Get("GOCACHE"), name+options+"-"+archname)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DefaultBinaryExtension returns the default extension for binaries, such as
|
// DefaultBinaryExtension returns the default extension for binaries, such as
|
||||||
|
|||||||
@@ -470,6 +470,12 @@ func defaultTarget(options *Options) (*TargetSpec, error) {
|
|||||||
return nil, fmt.Errorf("unknown GOOS=%s", options.GOOS)
|
return nil, fmt.Errorf("unknown GOOS=%s", options.GOOS)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if spec.GC == "boehm" {
|
||||||
|
// Add this file only when needed. This fixes a build failure on
|
||||||
|
// Windows.
|
||||||
|
spec.ExtraFiles = append(spec.ExtraFiles, "src/runtime/gc_boehm.c")
|
||||||
|
}
|
||||||
|
|
||||||
// Target triples (which actually have four components, but are called
|
// Target triples (which actually have four components, but are called
|
||||||
// triples for historical reasons) have the form:
|
// triples for historical reasons) have the form:
|
||||||
// arch-vendor-os-environment
|
// arch-vendor-os-environment
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module github.com/tinygo-org/tinygo
|
|||||||
go 1.22.0
|
go 1.22.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982
|
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2
|
||||||
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
github.com/chromedp/cdproto v0.0.0-20220113222801-0725d94bb6ee
|
||||||
github.com/chromedp/chromedp v0.7.6
|
github.com/chromedp/chromedp v0.7.6
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982 h1:cD7QfvrJdYmBw2tFP/VyKPT8ZESlcrwSwo7SvH9Y4dc=
|
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139 h1:2O/WuAt8J5id3khcAtVB90czG80m+v0sfkLE07GrCVg=
|
||||||
github.com/aykevl/go-wasm v0.0.2-0.20240825160117-b76c3f9f0982/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
github.com/aykevl/go-wasm v0.0.2-0.20250317121156-42b86c494139/go.mod h1:7sXyiaA0WtSogCu67R2252fQpVmJMh9JWJ9ddtGkpWw=
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2 h1:oMCHnXa6CCCafdPDbMh/lWRhRByN0VFLvv+g+ayx1SI=
|
||||||
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
github.com/blakesmith/ar v0.0.0-20150311145944-8bd4349a67f2/go.mod h1:PkYb9DJNAwrSvRx5DYA+gUcOIgTGVMNkfSCbZM8cWpI=
|
||||||
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
github.com/chromedp/cdproto v0.0.0-20211126220118-81fa0469ad77/go.mod h1:At5TxYYdxkbQL0TSefRjhLE3Q0lgvqKKMSFUglJ7i1U=
|
||||||
|
|||||||
+1
-1
Submodule lib/bdwgc updated: d1ff06cc50...1166f11f7d
+17
-1
@@ -178,11 +178,27 @@ func TestBuild(t *testing.T) {
|
|||||||
|
|
||||||
t.Run("WebAssembly", func(t *testing.T) {
|
t.Run("WebAssembly", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
|
runPlatTests(optionsFromTarget("wasm", sema), tests, t)
|
||||||
|
// Test with -gc=boehm.
|
||||||
|
t.Run("gc.go-boehm", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
optionsBoehm := optionsFromTarget("wasm", sema)
|
||||||
|
optionsBoehm.GC = "boehm"
|
||||||
|
runTest("gc.go", optionsBoehm, t, nil, nil)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
t.Run("WASI", func(t *testing.T) {
|
t.Run("WASIp1", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
runPlatTests(optionsFromTarget("wasip1", sema), tests, t)
|
runPlatTests(optionsFromTarget("wasip1", sema), tests, t)
|
||||||
|
|
||||||
|
// Test with -gc=boehm.
|
||||||
|
t.Run("gc.go-boehm", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
optionsBoehm := optionsFromTarget("wasip1", sema)
|
||||||
|
optionsBoehm.GC = "boehm"
|
||||||
|
runTest("gc.go", optionsBoehm, t, nil, nil)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
t.Run("WASIp2", func(t *testing.T) {
|
t.Run("WASIp2", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build tinygo.wasm && !(custommalloc || wasm_unknown)
|
//go:build tinygo.wasm && !(custommalloc || wasm_unknown || gc.boehm)
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
//go:build none
|
||||||
|
|
||||||
|
// This file is included in the build on systems that support the Boehm GC,
|
||||||
|
// despite the //go:build line above.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef void (* GC_push_other_roots_proc)(void);
|
||||||
|
void GC_set_push_other_roots(GC_push_other_roots_proc);
|
||||||
|
|
||||||
|
typedef void(* GC_warn_proc)(const char *msg, uintptr_t arg);
|
||||||
|
void GC_set_warn_proc(GC_warn_proc p);
|
||||||
|
|
||||||
|
void tinygo_runtime_bdwgc_callback(void);
|
||||||
|
|
||||||
|
static void callback(void) {
|
||||||
|
tinygo_runtime_bdwgc_callback();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void warn_proc(const char *msg, uintptr_t arg) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void tinygo_runtime_bdwgc_init(void) {
|
||||||
|
GC_set_push_other_roots(callback);
|
||||||
|
#if defined(__wasm__)
|
||||||
|
// There are a lot of warnings on WebAssembly in the form:
|
||||||
|
//
|
||||||
|
// GC Warning: Repeated allocation of very large block (appr. size 68 KiB):
|
||||||
|
// May lead to memory leak and poor performance
|
||||||
|
//
|
||||||
|
// The usual advice is to use something like GC_malloc_ignore_off_page but
|
||||||
|
// unfortunately for most allocations that's not allowed: Go allocations can
|
||||||
|
// legitimately hold pointers further than one page in the allocation. So
|
||||||
|
// instead we just disable the warning.
|
||||||
|
GC_set_warn_proc(warn_proc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
+16
-9
@@ -20,7 +20,6 @@ package runtime
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/gclayout"
|
"internal/gclayout"
|
||||||
"internal/reflectlite"
|
|
||||||
"internal/task"
|
"internal/task"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
)
|
)
|
||||||
@@ -39,22 +38,30 @@ var needsResumeWorld bool
|
|||||||
func initHeap() {
|
func initHeap() {
|
||||||
libgc_init()
|
libgc_init()
|
||||||
|
|
||||||
libgc_set_push_other_roots(gcCallbackPtr)
|
// Call GC_set_push_other_roots(gcCallback) in C because of function
|
||||||
|
// signature differences that do matter in WebAssembly.
|
||||||
|
gcInit()
|
||||||
}
|
}
|
||||||
|
|
||||||
var gcCallbackPtr = reflectlite.ValueOf(gcCallback).UnsafePointer()
|
//export tinygo_runtime_bdwgc_init
|
||||||
|
func gcInit()
|
||||||
|
|
||||||
|
//export tinygo_runtime_bdwgc_callback
|
||||||
func gcCallback() {
|
func gcCallback() {
|
||||||
// Mark globals and all stacks, and stop the world if we're using threading.
|
// Mark globals and all stacks, and stop the world if we're using threading.
|
||||||
gcMarkReachable()
|
gcMarkReachable()
|
||||||
|
|
||||||
if needsResumeWorld {
|
// If we use a scheduler with parallelism (the threads scheduler for
|
||||||
// Should never happen, check for it anyway.
|
// example), we need to call gcResumeWorld() after scanning has finished.
|
||||||
runtimePanic("gc: world already stopped")
|
if hasParallelism {
|
||||||
}
|
if needsResumeWorld {
|
||||||
|
// Should never happen, check for it anyway.
|
||||||
|
runtimePanic("gc: world already stopped")
|
||||||
|
}
|
||||||
|
|
||||||
// Note that we need to resume the world after finishing the GC call.
|
// Note that we need to resume the world after finishing the GC call.
|
||||||
needsResumeWorld = true
|
needsResumeWorld = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func markRoots(start, end uintptr) {
|
func markRoots(start, end uintptr) {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
//go:build (gc.conservative || gc.custom || gc.precise) && tinygo.wasm
|
//go:build (gc.conservative || gc.custom || gc.precise || gc.boehm) && tinygo.wasm
|
||||||
|
|
||||||
package runtime
|
package runtime
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -23,7 +23,8 @@
|
|||||||
"--no-demangle"
|
"--no-demangle"
|
||||||
],
|
],
|
||||||
"extra-files": [
|
"extra-files": [
|
||||||
"src/runtime/asm_tinygowasm.S"
|
"src/runtime/asm_tinygowasm.S",
|
||||||
|
"src/runtime/gc_boehm.c"
|
||||||
],
|
],
|
||||||
"emulator": "wasmtime run --dir={tmpDir}::/tmp {}"
|
"emulator": "wasmtime run --dir={tmpDir}::/tmp {}"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -24,7 +24,8 @@
|
|||||||
"--no-demangle"
|
"--no-demangle"
|
||||||
],
|
],
|
||||||
"extra-files": [
|
"extra-files": [
|
||||||
"src/runtime/asm_tinygowasm.S"
|
"src/runtime/asm_tinygowasm.S",
|
||||||
|
"src/runtime/gc_boehm.c"
|
||||||
],
|
],
|
||||||
"emulator": "node {root}/targets/wasm_exec.js {}"
|
"emulator": "node {root}/targets/wasm_exec.js {}"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,32 +124,3 @@ func TestMallocFree(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMallocEmpty(t *testing.T) {
|
|
||||||
ptr := libc_malloc(0)
|
|
||||||
if ptr != nil {
|
|
||||||
t.Errorf("expected nil pointer, got %p", ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCallocEmpty(t *testing.T) {
|
|
||||||
ptr := libc_calloc(0, 1)
|
|
||||||
if ptr != nil {
|
|
||||||
t.Errorf("expected nil pointer, got %p", ptr)
|
|
||||||
}
|
|
||||||
ptr = libc_calloc(1, 0)
|
|
||||||
if ptr != nil {
|
|
||||||
t.Errorf("expected nil pointer, got %p", ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReallocEmpty(t *testing.T) {
|
|
||||||
ptr := libc_malloc(1)
|
|
||||||
if ptr == nil {
|
|
||||||
t.Error("expected pointer but was nil")
|
|
||||||
}
|
|
||||||
ptr = libc_realloc(ptr, 0)
|
|
||||||
if ptr != nil {
|
|
||||||
t.Errorf("expected nil pointer, got %p", ptr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user