160 Commits

Author SHA1 Message Date
Jake Bailey 16fc1ea2bb runtime: make fatal failures unrecoverable
Match the Go runtime by terminating for deadlocks, stack overflows,
runtime and GC invariants, invalid lock operations, and platform
initialization failures instead of routing them through panic/recover.

Keep language-level runtime errors and unsupported user operations
recoverable. Add crash coverage that verifies fatal errors bypass deferred
recover calls.
2026-07-25 07:14:00 +02:00
Jake Bailey 7756941f39 main_test: skip flaky goroutines test on threaded schedulers 2026-07-24 20:50:26 +02:00
felipegenef 7994d2e912 runtime: implement SetFinalizer to fix syscall/js finalizeRef leak 2026-07-17 08:12:46 +02:00
Jake Bailey ec184e90c1 main_test: skip json on Cortex-M QEMU with Go 1.27
Go 1.27 jsonv2 pushes testdata/json.go beyond the LM3S6965 flash
budget. Keep coverage on larger emulated targets while skipping only the
too-small Cortex-M QEMU configuration.
2026-07-14 11:52:59 +02:00
Jake Bailey 432ebe13ed runtime: make Goexit exit host threads
The threads scheduler handled runtime.Goexit using the generic deadlock
path, which parked the current pthread forever. Add a scheduler-specific
goexit hook so it can remove the current task and exit the pthread while
ordinary blocking deadlocks still block.

Track main goroutine Goexit so the last remaining goroutine reports the
expected deadlock instead of letting the process exit successfully.
Expand the crash coverage with the Goexit cases covered by Big Go's
runtime tests.
2026-07-11 11:53:33 +02:00
Jake Bailey 16eefc59eb runtime, testing: support Goexit, SkipNow, FailNow
Keep a pending Goexit separate from the active panic state so recovered
deferred panics do not cancel the original Goexit unwind. Goexit should
also ignore -panic=trap, since it is not a panic.

Wire testing.FailNow and SkipNow through runtime.Goexit, and run tests
and benchmarks in goroutines. This lets Goexit terminate the user
function without skipping test bookkeeping. Add Goexit/recover coverage
and enable crypto/ecdh in the Linux stdlib test list.
2026-07-11 11:53:33 +02:00
Jake Bailey 7c3dc05117 all: modernize (#5498)
* modernize string cut usage

* modernize string cut prefix usage

* modernize slices helper usage

* modernize min and max usage

* modernize loop variable copies

* modernize integer range loops

* modernize map copy loops

* modernize go types iterator usage

* modernize empty interface usage

* modernize atomic type usage

* modernize string builders

* modernize string split iteration

* modernize remaining loop variable copies

* modernize usb cdc min usage

* modernize src integer range loops

* modernize example empty interface usage

* modernize src min and max usage

* modernize src integer range loops

* modernize src empty interface usage

* modernize src atomic type usage

* modernize reflect type lookups

* modernize review nits
2026-07-06 21:58:48 +02:00
Ron Evans e569dcfe38 runtime: fix ticker not stopping when Stop races with its callback (#5487)
* runtime: fix ticker not stopping when Stop races with its callback

On the threads and cores schedulers, timer callbacks run concurrently
with user goroutines.

If Stop (or Reset) was called in the window after the node was popped
but before its callback re-added it, removeTimer would not find the
timer in the queue, so it would be re-added to timer anyway.

Track timers whose callback is currently running in a firing list, and
have removeTimer mark a firing timer as stopped so its callback does not
re-add it.

Also make the timers test drain robust: allow a possible in-flight tick
delivered concurrently with Stop to settle before draining the channel.

Signed-off-by: deadprogram <ron@hybridgroup.com>

* runtime: fix Stop/Reset semantics when racing a firing timer callback

Address review feedback on the ticker Stop-race fix. On the threads and
cores schedulers a timer callback runs concurrently with user goroutines,
which left several problems:

- removeTimer reported a firing timer as successfully removed, so
  Stop/Reset could return true even though the callback had already
  started (wrong semantics, notably for AfterFunc). firingTimerStop now
  returns a bool and removeTimer no longer hands the still-firing node
  back to resetTimer.

- The periodic advance (when += period) ran in timerCallback outside the
  scheduler timer lock. Move it into each scheduler's reAddTimer, under
  the lock and after the stopped check, so a concurrent Reset can't have
  its freshly-queued deadline corrupted.

- resetTimer now sets when/period after removeTimer for the same reason.

Add testdata/timer_stop_reset_race.go and TestTimerStopResetRace, which
reproduce the stop-while-firing and reset-while-firing races via the
runtime timer linkname hooks.

Signed-off-by: deadprogram <ron@hybridgroup.com>

* runtime: fix timer Stop/Reset race with firing periodic timers

Signed-off-by: deadprogram <ron@hybridgroup.com>

---------

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-07-06 20:14:53 +02:00
Jake Bailey 5c15a68d18 tests: support simavr 1.8+ 2026-07-05 13:57:05 +02:00
Jake Bailey e79edb58b2 all: clean up code with Go 1.24+ in mind (#5489)
* all: clean up code with Go 1.24+ in mind

* all: more old go cleanup

* all: even remove rand_fastrand64

* runtime: revert rand changes

* runtime: re-drop rand_fastrand64
2026-07-03 19:10:55 +02:00
Jake Bailey 1b9bb143bf compiler: disambiguate function-local named types (#5336)
* compiler: make getTypeCodeName a method on compilerContext

* testdata: add regression tests for function-local named types

* compiler: disambiguate function-local named types

* Some PR feedback
2026-06-05 11:04:44 +02:00
Jake Bailey 18033ebc36 compiler, runtime, reflect: generate type-specific hash/equal (#5359)
* compiler, runtime, reflect: generate type-specific hash/equal for composite map keys

For map keys that are not trivially binary-comparable, the compiler now
generates type-specific hash and equal functions as LLVM IR instead of
going through the interface+reflection path. This covers comparable
types: strings, floats, complex numbers, interfaces, channels, and
composites containing any mix of these.

Previously, maps with composite keys containing strings or floats
converted the key to interface{}, hashed via reflection, and compared
through interface equality. Now the compiler walks struct fields and
array elements directly, dispatching to the right runtime helper for
each field type and storing keys at their actual type.

Struct keys are always handled field-by-field so padding bytes do not
affect equality or hashing. Blank fields are ignored, matching Go
equality. Generated hash/equal function names use canonical underlying
type structure so structurally identical key types can share generated
functions. Padding zeroing before map operations is no longer needed
because structs no longer use the binary key path.

Also fix reflect map iteration for interface-keyed maps: MapIter.Key
returns an interface Value for map[interface{}] keys instead of
unpacking to the concrete key kind.

* compiler: generate loops for array map key hash/equal

Previously, array key hash and equal functions were unrolled at compile
time, generating one block of IR per element. For large arrays like
[1000]int inside a struct with non-binary fields, this caused code
explosion.

Now, binary-element arrays dispatch directly to hash32/memequal for the
whole array. Non-binary-element arrays generate an LLVM IR loop. The
equal loop short-circuits on the first mismatch.

Small arrays are still unrolled instead of looping, keeping the simple
cases compact.

* reflect: fix at-runtime map issues from review, and more found locally

Maps created through reflect.MakeMap need hash/equal behavior that
matches compiler-created maps. Add hashmapMakeReflect for composite key
types, using runtime closures that reconstruct interface{} values from
raw key bytes and delegate to the interface hash and equality paths.

Interface-keyed maps are already stored as interface values, so use the
existing interface hash/equal helpers directly for those. This keeps
reflect insert, lookup, delete, and compiled lookup paths consistent.

Also fix addressable small values used as interface map keys or
interface map values. loadSmallValue puts small indirect values back in
the pointer-sized interface data field the same way valueInterfaceUnsafe
does.

* compiler, interp, reflect: fix pointer map literals; remove interface fallback

Package-level map literals with pointer keys (both *T and
unsafe.Pointer) crash the compiler: the interp pass panics when trying
to hash pointer data as raw bytes, because pointer values in the interp
memory model are symbolic identities that do not fit in a byte.

Fix this by setting a recoverable error flag instead of panicking. The
interp detects the error after each instruction and defers the map
insert to runtime init code, where real addresses are available for
hashing. This matches how the interp already handles other operations
it cannot evaluate at compile time.

With this fix, unsafe.Pointer can also be classified as a binary map
key, which was the last type requiring the interface-based fallback.
Since all comparable types now use either the binary or the
compiler-generated hash/equal path, remove the interface fallback from
the compiler and reflect packages.

* compiler, transform: always pass hash/equal function pointers to hashmapMakeGeneric

The compiler now always resolves the hash and equal functions at compile
time and passes them directly to hashmapMakeGeneric, instead of passing
an algorithm enum to hashmapMake and resolving at runtime. For string
keys, the runtime hashmapStringPtrHash/hashmapStringEqual functions are
referenced directly. For binary keys, hash32/memequal are referenced.

The old hashmapMake with alg enum is retained for reflect, which still
needs runtime resolution when creating maps dynamically.

The OptimizeMaps transform pass is updated to handle both hashmapMake
and hashmapMakeGeneric, and to recognize hashmapGenericSet in addition
to hashmapBinarySet and hashmapStringSet. The now-unused
hashmapCanGenerateHashEqual helper is removed.

* runtime: store large map keys and values indirectly

When a map key or value exceeds 128 bytes, the bucket now stores a
pointer to separately allocated memory instead of the data inline. This
matches Go's MapMaxKeyBytes/MapMaxElemBytes threshold and prevents
bucket sizes from exploding for large key/value types.

For example, map[[256]byte]int previously used 2128 bytes per bucket
(16 header + 256*8 keys + 8*8 values); now it uses 144 bytes per bucket
(16 header + 8*8 pointers + 8*8 values).

The indirection is fully encapsulated in the runtime via helper
functions. Store the computed key and value slot sizes on the hashmap so
all runtime and reflect paths use the same bucket layout, including
non-indirect keys and values.

Add big-key golden coverage and benchmarks. Make the benchmark vary
enough key bytes to exercise hashing.
2026-05-18 13:31:27 +02:00
deadprogram 1a1506ef79 builder,loader: fix -ldflags -X not overriding variables with default values
When a string variable already had a source-level default value, the -ldflags
"-X" flag was silently ignored and the variable remained the default value
at runtime.

Fix by stripping the InitOrder entry for each -X variable before
LoadSSA() is called. With no entry in InitOrder, go/ssa emits no init
store, so the global stays zero-valued in the IR. makeGlobalsModule
still injects the actual -X values at final link time.

The -X values remain out of the per-package build cache with only the
variable names appearing in the cache key.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-04-28 11:06:48 +01:00
deadprogram 1b4ab772d2 test: increase default timeout from 1 to 2 minutes to prevent spurious fails in CI from slow runners
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-04-18 10:20:25 +01:00
Jake Bailey 12d41ba0c1 go.mod, compiler: bump minimum Go version to 1.23
This enables gotypesalias=1 by default, which is needed for
generic type aliases to work correctly in go/types.
2026-04-17 19:18:17 +01:00
Nia Waldvogel 72f667cac9 main (test): skips mipsle test if the emulator is missing
This one specific case was missing a call to emucheck.
2026-01-08 10:52:05 +00:00
Elias Naur 1b5d312c68 tests: de-flake goroutines test 2025-07-17 15:40:01 +02:00
Ayke van Laethem c08b2dfe06 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.
2025-06-13 14:42:23 +02:00
Ayke van Laethem 612a38e363 wasm: don't block //go:wasmexport because of running goroutines
This fixes bug https://github.com/tinygo-org/tinygo/issues/4874.
2025-04-29 14:19:17 +02:00
Ayke van Laethem f542717992 windows: add windows/386 support 2025-04-22 17:45:29 +02:00
deadprogram 17bb1fec44 feature: add buildmode=wasi-legacy to support existing base of users who expected the
older behavior for wasi modules to not return an exit code as if they were reactors.

See #4726 for some details on what this is intended to address.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-02-21 13:06:14 +01:00
Ayke van Laethem 9b3eb3fe59 ci: run at least some tests on older Go/LLVM versions
These should make sure basic functionality is still working.
Using the `-short` flag to avoid taking too long to run all tests (and
to install all the necessary emulators), and because some targets might
not work in older Go/LLVM versions (such as WASI).

This does _not_ run tests and checks against expected IR, because LLVM
IR changes a lot across versions.
2024-11-18 16:42:14 +01:00
Ayke van Laethem ceb7891986 wasm: correctly return from run() in wasm_exec.js
Instead of hanging forever, it should return the exit code from os.Exit.
2024-11-08 11:55:38 +01:00
Ayke van Laethem 4b706ae25c test: show output even when a test binary didn't exit cleanly
This was a problem on wasm, where node would exit with a non-zero exit
code when there was a panic.
2024-11-01 08:49:00 +01:00
Ayke van Laethem 1ac26d3d2f test: run TestWasmExportJS tests in parallel 2024-11-01 08:48:19 +01:00
Ayke van Laethem b8fe75a9dd runtime: add support for os/signal
This adds support for enabling and listening to signals on Linux and
MacOS.
2024-10-23 12:25:27 +01:00
Ayke van Laethem cd2bb8333d wasm: add test for js.FuncOf
While there are some browser tests, Node.js is just a lot better for
testing this kind of stuff because it's much faster and we don't need a
browser for this.
2024-10-19 16:00:45 +01:00
Ayke van Laethem 4ef5109a07 wasm: add //go:wasmexport support to js/wasm
This adds support for //go:wasmexport with `-target=wasm` (in the
browser). This follows the //go:wasmexport proposal, meaning that
blocking functions are not allowed.

Both `-buildmode=default` and `-buildmode=c-shared` are supported. The
latter allows calling exported functions after `go.run()` has returned.
2024-10-18 10:07:21 +01:00
Ayke van Laethem 6016d0c739 main_test: refactor output comparison into separate function
This shouldn't affect anything, just make the code a bit better
(especially for the next commit).
2024-10-18 10:07:21 +01:00
Ayke 9da8b5c786 wasm: add //go:wasmexport support (#4451)
This adds support for the `//go:wasmexport` pragma as proposed here:
https://github.com/golang/go/issues/65199

It is currently implemented only for wasip1 and wasm-unknown, but it is
certainly possible to extend it to other targets like GOOS=js and
wasip2.
2024-10-04 15:33:47 -07:00
Damian Gryski 9d14489547 TestWebAssembly: use wasm-unknown for panic=trap test 2024-10-02 12:40:07 +02:00
Ayke van Laethem 4f1b69827d reflect: support big-endian systems
The reflect package needs to know the endianness of the system in a few
places. Before this patch, it assumed little-endian systems. But with
GOARCH=mips we now have a big-endian system which also needs to be
supported. So this patch fixes the reflect package to work on big-endian
systems.

Also, I've updated the tests for MIPS: instead of running the
little-endian tests, I've changed it to run the big-endian tests
instead. The two are very similar except for endianness so this should
be fine. To be sure we won't accidentally break little-endian support,
I've kept a single MIPS little-endian test (the CGo test, which doesn't
yet work on big-endian systems anyway).
2024-09-05 10:06:30 +02:00
Ayke van Laethem 73f519b589 interp: support big-endian targets
The interp package was assuming that all targets were little-endian. But
that's not true: we now have a big-endian target (GOARCH=mips).

This fixes the interp package to use the appropriate byte order for a
given target.
2024-09-05 10:06:30 +02:00
Ayke van Laethem 1ef1aa7862 mips: fix big-endian (GOARCH=mips) support
I made an awkward mistake, mixing up GOOS and GOARCH. So here is a fix,
with an associated test.
2024-08-22 16:36:40 +02:00
Ayke van Laethem 7e284a37fc ci: use Go 1.23 2024-08-17 11:49:14 +02:00
Ayke van Laethem 8b626e6ea7 compiler: add support for Go 1.23 range-over-func 2024-08-17 11:49:14 +02:00
Ayke van Laethem f188eaf5f9 mips: add GOMIPS=softfloat support
Previously, the compiler would default to hardfloat. This is not
supported by some MIPS CPUs.

This took me much longer than it should have because of a quirk in the
LLVM Mips backend: if the target-features string is not set (like during
LTO), the Mips backend picks the first function in the module and uses
that. Unfortunately, in the case of TinyGo this first function is
`llvm.dbg.value`, which is an LLVM intrinsic and doesn't have the
target-features string. I fixed it by adding a `-mllvm -mattr=` flag to
the linker.
2024-08-12 13:23:32 +02:00
Ayke van Laethem 2e76cd3687 builder: interpret linker error messages
This shows nicely formatted error messages for missing symbol names and
for out-of-flash, out-of-RAM conditions (on microcontrollers with
limited flash/RAM).

Unfortunately the missing symbol name errors aren't available on Windows
and WebAssembly because the linker doesn't report source locations yet.
This is something that I could perhaps improve in LLD.
2024-08-11 01:48:11 -07:00
Ayke van Laethem 725518f007 all: add linux/mipsle support
This adds linux/mipsle (little endian Mips) support to TinyGo.

It also adds experimental linux/mips (big-endian) support. It doesn't
quite work yet, some parts of the standard library (like the reflect
package) currently seem to assume a little-endian system.
2024-07-22 16:21:26 +02:00
Ayke van Laethem 80269b98ba diagnostics: move diagnostic printing to a new package
This is a refactor, which should (in theory) not change the behavior of
the compiler. But since this is a pretty large change, there is a chance
there will be some regressions. For that reason, the previous commits
added a bunch of tests to make sure most error messages will not be
changed due to this refactor.
2024-07-20 14:30:34 +02:00
Ayke van Laethem 8a357af3d8 all: add testing for compiler error messages
This is needed for some improvements I'm going to make next.

This commit also refactors error handling slightly to make it more
easily testable, this should hopefully not result in any actual changes
in behavior.
2024-07-13 13:26:26 +02:00
L. Pereira ac396708da main_test: Diff expected and actual results when tests fail (#4288)
Uses a vendored "internal/diff" from Big Go to show the differences
between the expected and actual outputs when tests fail.

Signed-off-by: L. Pereira <l.pereira@fastly.com>
2024-07-08 16:35:06 -07:00
Damian Gryski 9cb263479c wasi preview 2 support (#4027)
* all: wasip2 support

Co-authored-by: Randy Reddig <randy.reddig@fastly.com>
2024-07-02 07:02:03 -07:00
Ayke van Laethem f18c6e342f test: support GOOS/GOARCH pairs in the -target flag
This means it's possible to test just a particular OS/arch with a
command like this:

    go test -run=Build -target=linux/arm

I found it useful while working on MIPS support.
2024-06-28 12:31:38 +02:00
Randy Reddig 055950421a all: change references of 'wasi' to 'wasip1'; test hygiene 2024-03-27 16:01:40 +01:00
Ayke van Laethem ad4d722f54 all: move -panic=trap support to the compiler/runtime
Support for `-panic=trap` was previously a pass in the optimization
pipeline. This change moves it to the compiler and runtime, which in my
opinion is a much better place.

As a side effect, it also fixes
https://github.com/tinygo-org/tinygo/issues/4161 by trapping inside
runtime.runtimePanicAt and not just runtime.runtimePanic.

This change also adds a test for the list of imported functions. This is
a more generic test where it's easy to add more tests for WebAssembly
file properties, such as exported functions.
2024-03-19 07:10:51 +01:00
Ayke van Laethem 57f49af726 loader: make sure Go version is plumbed through
This fixes the new loop variable behavior in Go 1.22.

Specifically:
  * The compiler (actually, the x/tools/go/ssa package) now correctly
    picks up the Go version.
  * If a module doesn't specify the Go version, the current Go version
    (from the `go` tool and standard library) is used. This fixes
    `go run`.
  * The tests in testdata/ that use a separate directory are now
    actually run in that directory. This makes it possible to use a
    go.mod file there.
  * There is a test to make sure old Go modules still work with the old
    Go behavior, even on a newer Go version.
2024-01-19 21:23:58 +01:00
Ayke van Laethem 0ad15551c8 compiler: update golang.org/x/tools/go/ssa package
This update includes support for the new range loops over integers.
2024-01-18 19:51:52 +01:00
Ayke van Laethem a545f17d2e wasm: add support for GOOS=wasip1
This adds true GOOS=wasip1 support in addition to our existing
-target=wasi support. The old support for WASI isn't removed, but should
be treated as deprecated and will likely be removed eventually to reduce
the test burden.
2023-08-17 18:16:54 +02:00
Ayke van Laethem f791c821ff compiler: add min and max builtin support 2023-08-04 11:59:11 +02:00