Skip to content

Commit d627208

Browse files
aykevldeadprogram
authored andcommitted
all: make WebAssembly initial linear memory size configurable
When the target supports it, allow the (initial) heap size to be configured. Currently only supported in WebAssembly. This also changes the default heap size of WebAssembly from 64kB to 1MB.
1 parent 152caa3 commit d627208

File tree

2 files changed

+44
-2
lines changed

2 files changed

+44
-2
lines changed

main.go

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type BuildConfig struct {
5555
ldFlags []string
5656
tags string
5757
wasmAbi string
58+
heapSize int64
5859
testConfig compiler.TestConfig
5960
}
6061

@@ -240,10 +241,16 @@ func Compile(pkgName, outpath string, spec *TargetSpec, config *BuildConfig, act
240241
// Prepare link command.
241242
executable := filepath.Join(dir, "main")
242243
tmppath := executable // final file
243-
ldflags := append(ldflags, "-o", executable, objfile, "-L", root)
244+
ldflags = append(ldflags, "-o", executable, objfile, "-L", root)
244245
if spec.RTLib == "compiler-rt" {
245246
ldflags = append(ldflags, librt)
246247
}
248+
if spec.GOARCH == "wasm" {
249+
// Round heap size to next multiple of 65536 (the WebAssembly page
250+
// size).
251+
heapSize := (config.heapSize + (65536 - 1)) &^ (65536 - 1)
252+
ldflags = append(ldflags, "--initial-memory="+strconv.FormatInt(heapSize, 10))
253+
}
247254

248255
// Compile extra files.
249256
for i, path := range spec.ExtraFiles {
@@ -540,6 +547,30 @@ func Run(pkgName, target string, config *BuildConfig) error {
540547
})
541548
}
542549

550+
// parseSize converts a human-readable size (with k/m/g suffix) into a plain
551+
// number.
552+
func parseSize(s string) (int64, error) {
553+
s = strings.ToLower(strings.TrimSpace(s))
554+
if len(s) == 0 {
555+
return 0, errors.New("no size provided")
556+
}
557+
multiply := int64(1)
558+
switch s[len(s)-1] {
559+
case 'k':
560+
multiply = 1 << 10
561+
case 'm':
562+
multiply = 1 << 20
563+
case 'g':
564+
multiply = 1 << 30
565+
}
566+
if multiply != 1 {
567+
s = s[:len(s)-1]
568+
}
569+
n, err := strconv.ParseInt(s, 0, 64)
570+
n *= multiply
571+
return n, err
572+
}
573+
543574
func usage() {
544575
fmt.Fprintln(os.Stderr, "TinyGo is a Go compiler for small places.")
545576
fmt.Fprintln(os.Stderr, "version:", version)
@@ -598,6 +629,7 @@ func main() {
598629
cFlags := flag.String("cflags", "", "additional cflags for compiler")
599630
ldFlags := flag.String("ldflags", "", "additional ldflags for linker")
600631
wasmAbi := flag.String("wasm-abi", "js", "WebAssembly ABI conventions: js (no i64 params) or generic")
632+
heapSize := flag.String("heap-size", "1M", "default heap size in bytes (only supported by WebAssembly)")
601633

602634
if len(os.Args) < 2 {
603635
fmt.Fprintln(os.Stderr, "No command-line arguments supplied.")
@@ -633,6 +665,13 @@ func main() {
633665
os.Exit(1)
634666
}
635667

668+
var err error
669+
if config.heapSize, err = parseSize(*heapSize); err != nil {
670+
fmt.Fprintln(os.Stderr, "Could not read heap size:", *heapSize)
671+
usage()
672+
os.Exit(1)
673+
}
674+
636675
os.Setenv("CC", "clang -target="+*target)
637676

638677
switch command {

src/runtime/arch_wasm.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ const TargetBits = 32
1414
//go:extern __heap_base
1515
var heapStartSymbol unsafe.Pointer
1616

17+
//go:export llvm.wasm.memory.size.i32
18+
func wasm_memory_size(index int32) int32
19+
1720
var (
1821
heapStart = uintptr(unsafe.Pointer(&heapStartSymbol))
19-
heapEnd = (heapStart + wasmPageSize - 1) &^ (wasmPageSize - 1) // conservative guess: one page of heap memory
22+
heapEnd = uintptr(wasm_memory_size(0) * wasmPageSize)
2023
)
2124

2225
const wasmPageSize = 64 * 1024

0 commit comments

Comments
 (0)