The interface lowering pass used a separate formatter for method
signatures. Same-named local aliases could therefore make distinct generic
methods compare equal. Reuse getTypeCodeName so interface checks preserve
type identity.
x/tools SSA names and go/types strings can preserve the source spelling of
type arguments, so aliases can make distinct instances collide. Use the
canonical type encoding for function names, synthetic local type owners,
instantiated named types, and method sets.
Add cases where same-named local aliases instantiate generic functions,
local types, and methods with float32 and float64. Record the current
collisions and incorrect results.
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.
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.
* wasm: patch wasm_exec.js and wasm_exec_node.js from Go 1.18+
Port this commit https://github.com/golang/go/commit/680caf15355057ca84857a2a291b6f5c44e73329 removing polyfills from `wasm_exec.js`, now the environment is expected to provide all the required polyfills.
`wasm_exec.js` now only provides stub fallbacks for globalThis.fs and globalThis.process.
All NodeJS specific code is now in a separate file `wasm_exec_node.js` with its required polyfills.
* feat: bump minimum node version to 22
Drops official support for NodeJS 18 for WASM by removing the provided polyfills in the `wasm_exec.js`.
Now the environment is expected to provide the polyfill if it is running on older NodeJS versions
The new minimum required version for WASM is NodeJS 22+.
* chore: removed wrong comment
`wasm_exec_node.js` no longer contains the polyfill for NodeJS 18
* 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>
* 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
Modify the Unix signal handler to redirect execution to a Go sigpanic
function instead of printing an error and re-raising the signal.
The C signal handler modifies the ucontext to make the faulting
instruction appear to have called tinygo_sigpanic, which then calls
runtimePanic with the appropriate message.
Supported on all architectures TinyGo targets on Linux and Darwin:
x86_64, i386, aarch64, ARM, and MIPS. Also registers SIGFPE, which
was previously not handled at all.
Change hashmap set operations and channel send/close from
createRuntimeCall to createRuntimeInvoke. This places a setjmp
checkpoint before each call, allowing runtimePanicAt to safely
longjmp when these operations panic.
Emit fault checkpoints around compiler-generated runtime assertions so
runtimePanicAt can unwind through the existing defer/recover machinery
instead of aborting. This lets panics from bounds checks, type checks,
and other compiler-inserted runtime checks be recovered by deferred
functions.
Mark functions that call recover as noinline. Inlining such a function
into a deferred closure can make recover observe the wrong call context
and report success when it should return nil.
Addresses tinygo-org/tinygo issues 2759 and 3510.
* 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.
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>
Ticker.Stop does not drain already-buffered ticks from the channel,
so on slow CI runners a tick may already be queued before Stop takes
effect, causing a spurious "fail: ticker should have stopped!" failure.
Drain the channel immediately after Stop before checking that no new
ticks arrive.
Signed-off-by: deadprogram <ron@hybridgroup.com>
* reflect: implement method-set based AssignableTo and Implements
Based on the design from #4376 by aykevl.
Fixes#4277, fixes#3580.
Co-authored-by: Ayke van Laethem <aykevanlaethem@gmail.com>
* builder: update expected binary sizes for reflect changes
* Make interface checks similar to invoke, allowing typeImplementsMethodSet and method info to be dropped when reflect is not present
* Add more tests that BigGo reflect tests
* Even more pruning
* Add go/token and net/url to passing tests
* Prune even further, I am less happy with this, though
* Update size test now that we are smaller
* Skip some tests
* elide method lists
* format, oops
* fix tests
* Add a panic, pull out constant to keep in sync
* Add debug info
* Remove code that was leftover from a previous refactor
---------
Co-authored-by: Ayke van Laethem <aykevanlaethem@gmail.com>
This fixes issue #5037. A few more wasip1 syscalls needed to be present,
and in particular fd_prestat_get needed to return EBADF on invalid file
descriptors.
The "all:" prefix in //go:embed directives instructs the compiler to
include hidden files (starting with "." or "_") when embedding a
directory. Previously, the prefix was passed literally to path.Match,
which would never match.
Introduce an embedPattern struct that parses and validates the pattern
at construction time via newEmbedPattern(). The "all:" prefix is
stripped once and stored along with the glob pattern, avoiding repeated
string prefix checks. Pattern validation is absorbed into the
constructor, guaranteeing that any embedPattern value is valid and
eliminating the need for separate validation loops.
Fixes embedding with patterns like "//go:embed all:static".
This fixes two edge cases for min/max:
min/max(+0.0, -0.0) = -0.0, +0.0
min/max(number, NaN) = NaN, NaN
The compare and select method does not work here.
I switched to the llvm.minimum/llvm.maximum intrinsics which match the intended behavior.
The integer min/max were also swapped over to using intrinsics.
The compare and select path is now only used by strings.
ahocorasick no longer times out during interp. I don't believe
this is because we fixed a bug in interp but rather because "something"
(garbage collector fixes?) has moved the tree building to runtime.
Since we switched to OS threads for goroutines, the
testdata/goroutines.go test has been flaky. Not surprising, if threads
need to be scheduled within 1ms on a busy CI system. This PR makes the
test a bit less flaky (hopefully) by increasing the time to 100ms.
A race condition was possible because the 'acquire' goroutine might not
have started in 4 milliseconds which changed the ordering of the test.
This patch fixes it by making sure the goroutine has started (and locked
the mutex) before continuing with the test.
I don't think this is used anywhere right now, and it would need to be
updated to work with multithreading. So instead of fixing it, I think we
can remove it.
My original intention was to have something like this that could be used
in the machine package, but since this is in the runtime package (and
the runtime package imports the machine package on baremetal) it can't
actually be used that way.
I checked the TinyGo repo and the drivers repo, and `runtime.Cond` isn't
used anywhere except in that one test.
This ensures that calls to print/println happening in different threads
are not interleaved. It's a task.PMutex, so this should only change
things when threading is used.
This matches the Go compiler, which does the same thing:
https://godbolt.org/z/na5KzE7en
The locks are not recursive, which means that we need to be careful to
not call `print` or `println` inside a runtime.print* implementation,
inside putchar (recursively), and inside signal handlers. Making them
recursive might be useful to do in the future, but it's not really
necessary.
Making this work on all targets was interesting but there's now a test
in place to make sure this works on all targets that have the CGo test
enabled (which is almost all targets).
compiler: align with current wasm types proposal
https://github.com/golang/go/issues/66984
- Remove int and uint as allowed types in params, results, pointers, or struct fields
- Only allow small integers in pointers, arrays, or struct fields
- enforce structs.HostLayout usage per wasm types proposal
https://github.com/golang/go/issues/66984
- require go1.23 for structs.HostLayout
- use an interface to check if GoVersion() exists
This permits TinyGo to compile with Go 1.21.
- use goenv.Compare instead of WantGoVersion
- testdata/wasmexport: use int32 instead of int
- compiler/testdata: add structs.HostLayout
- compiler/testdata: improve tests for structs.HostLayout
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.
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.
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.