116 Commits

Author SHA1 Message Date
Damian Gryski 1e3baff966 compiler: fix hasMethodSet to account for filtered generic methods
hasMethodSet was computed from the raw, unfiltered method set length
(ms.Len() != 0), before generic methods were excluded from numMethods
and the method set value. For a type whose only method is generic
(e.g. "func (t T) M[X int](n X) X"), this left hasMethodSet true even
though the actual (filtered) method set is empty, causing an
unnecessary empty method-set global and methodSet field to be emitted
for that type's type descriptor.

Compute hasMethodSet from the same filtered loop that produces
numMethods, so it's true only when at least one non-generic method
exists.
2026-07-23 10:14:10 +02:00
Damian Gryski 4fcf03414c compiler: exclude generic methods from runtime method sets
Go 1.27 promoted "generic methods" (methods with their own type
parameters, independent of any type parameters on the receiver) out
of the GenericMethods experiment, e.g.:

    func (r *Rand) N[Int intType](n Int) Int

Boxing a value of a type with such a method into an interface caused
tinygo to panic while building the runtime type's method table:

    getTypeCode -> getMethodSetValue -> getTypeCodeName

getTypeCodeName's type switch has no case for *types.TypeParam, and a
generic method's Signature carries the method's own type parameters
in its parameter/result types (e.g. "Int" above), so encoding it into
a type code name panicked with "unknown type: <param name>".

This affected any package using math/rand/v2.Rand.N, including much of
the math/rand/v2 test suite, since printing or otherwise boxing a
*Rand into an interface is common.

Upstream reflect deliberately excludes generic methods from
Type.NumMethod()/Type.Method() (they can't be instantiated implicitly,
and a generic method can never satisfy an interface method), so mirror
that behavior: add isGenericMethod, which checks whether a method's
Signature has its own type parameters, and skip such methods when
building the runtime method count, method set value, and method set
in compiler/interface.go.

Fixes a panic isolated to:

    package main

    type T struct{}

    func (t T) M[X int](n X) X { return n }

    func main() {
    	var t T
    	var i interface{} = t
    	_ = i
    }
2026-07-23 10:14:10 +02:00
Jake Bailey 9e7d89d4d5 compiler: pass large aggregates by pointer
LLVM ComputeValueVTs recursively expands arrays and structs into one
value type per scalar leaf. SelectionDAG call lowering allocates data
structures proportional to this count, which makes very large values
exhaust memory or crash LLVM.

Count scalar leaves and use pointers for internal parameters and results
when the count exceeds 1024. A result pointer is the first parameter,
and aggregate parameters point to read-only memory. Exported function
types are unchanged.

Keep these SSA values in memory and copy them with memcpy when needed.
Handle calls, interfaces, maps, channels, selects, defers, goroutines,
phis, and multiple results. Update the expected compiler IR and re-enable
the native compress/flate tests.
2026-07-22 11:22:03 -07:00
Jake Bailey 3071e339cd compiler: key deferInvokeFuncs on distinct name 2026-07-22 12:30:34 +02:00
Nia Waldvogel cd4e479dd5 compiler: consistently pass layout and alignment to createAlloc 2026-07-21 07:15:43 +02:00
Jake Bailey 047ed57005 compiler: canonicalize method signature identities
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.
2026-07-13 07:33:32 +02:00
Jake Bailey c7923d1c64 compiler: canonicalize generic instance identities
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.
2026-07-13 07:33:32 +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
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 278aa09819 compiler: share recoverable fault blocks 2026-06-04 19:25:47 +02:00
Jake Bailey eed4afda63 compiler, runtime: make runtime panics recoverable
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.
2026-06-04 19:25:47 +02:00
Jake Bailey 5ba8766cbc compiler: implement method-set based AssignableTo and Implements (#5304)
* 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>
2026-04-17 21:57:03 +02:00
Nia Waldvogel 852dde671e compiler: use Tarjan's SCC algorithm to detect loops for defer
The compiler needs to know whether a defer is in a loop to determine whether to allocate stack or heap memory.
Previously, this performed a DFS of the CFG every time a defer was found.
This resulted in time complexity jointly proportional to the number of defers and the number of blocks in the function.

Now, the compiler will instead use Tarjan's strongly connected components algorithm to find cycles in linear time.
The search is performed lazily, so this has minimal performance impact on functions without defers.

In order to implement Tarjan's SCC algorithm, additional state needed to be attached to the blocks.
I chose to merge all of the per-block state into a single slice to simplify memory management.
2025-11-10 07:27:40 +01:00
Ayke van Laethem 2e043c7fbc compiler: add support for GODEBUG=gotypesalias=1
Since we now require Go 1.22, this became a lot simpler (since we can
now refer to `types.Alias` and `types.Unalias`).
2025-05-24 19:49:49 +02:00
dkegel-fastly 8135be4e90 GNUmakefile: add spellfix target, use it. (#4387)
TODO: Remove the go.mod/go.sum in internal/tools once doing so doesn't break CI (e.g. once we drop support for go 1.19)

* builder/cc1as.h: fix typo found by 'make spell'
* GNUmakefile: remove exception for inbetween, fix instance now found by 'make spell'
* GNUmakefile: remove exception for programmmer, fix instance now found by 'make spell'
* go.mod: use updated misspell. GNUmakefile: add spellfix target, use it.
* ignore directories properly when invoking spellchecker.
* make spell: give internal/tools its own go.mod, as misspell requires newer go
* make lint: depend on tools and run the installed revive
(which was perhaps implied by the change that added revive to internal/tools,
but not required in GNUmakefile until we gave internal/tools its own temporary go.mod)
* .github: now that 'make spell' works well, run it from CI
* GNUmakefile: make spell now aborts if it finds misspelt words, so what it finds doesn't get lost in CI logs
* GNUmakefile: tools: avoid -C option on go generate to make test-llvm15-go119 circleci job happy, see
https://cs.opensource.google/go/go/+/2af48cbb7d85e5fdc635e75b99f949010c607786
* internal/tools/go.mod: fix format of go version to leave out patchlevel, else go complains.
2024-08-12 14:24:38 -07:00
Ayke van Laethem 077b35e9ad all: drop support for Go 1.18
Go 1.18 has been unsupported for quite a while now (the oldest supported
version is Go 1.21). But more importantly, the golang.org/x/tools module
now requires Go 1.19 or later. So we'll drop this older version.
2024-06-12 14:46:47 +02:00
frenkel26 f7c0466f78 compiler,reflect: fix NumMethods for Interface type 2024-05-28 14:09:59 +02:00
Damian Gryski 777048cfa9 compiler: fix crash on type assert on interfaces with no methods 2023-11-08 19:41:25 +01:00
Ayke van Laethem 1da1abe314 all: remove LLVM 14 support
This is a big change: apart from removing LLVM 14 it also removes typed
pointer support (which was only fully supported in LLVM up to version
14). This removes about 200 lines of code, but more importantly removes
a ton of special cases for LLVM 14.
2023-10-01 18:32:15 +02:00
Ayke van Laethem 42da7654ec compiler: don't use types in the global context
This usually works by chance, but leads to crashes. So we should never
ever do this.

I'm pretty sure this is the crash behind this issue: https://github.com/tinygo-org/tinygo/issues/3894

It may also have caused this crash: https://github.com/tinygo-org/tinygo/issues/3874

I have a suspicion this is also behind the rather crash-prone CircleCI
jobs, that we haven't been able to find the source of. But we'll find
out soon enough once this fix is merged.

To avoid hitting this issue again in the future, I've created a PR to
remove these dangerous functions altogether from the go-llvm API:
https://github.com/tinygo-org/go-llvm/pull/54
2023-09-19 09:21:51 +02:00
Damian Gryski 0042bf62a5 compiler,reflect: add support for [...]T -> []T in reflect 2023-09-10 13:05:18 +02:00
Damian Gryski acba0748f1 compiler,reflect: NumMethods reports exported methods only
Fixes #3796
2023-07-02 15:35:42 +02:00
Damian Gryski 0212f0c008 compiler: limit level of pointer-to-pointer-to-... types 2023-06-09 17:30:02 +02:00
Damian Gryski f5f4751088 compiler,transform: fix for pointer-to-pointer type switches from @aykevl 2023-06-09 17:30:02 +02:00
Damian Gryski 62fb386d57 compiler,reflect: add tagged pointers for **T etc 2023-06-09 17:30:02 +02:00
Damian Gryski 37849c4897 compiler,reflect: use two bits of the meta byte for comparable/isBinary
Fixes #3683
2023-06-08 07:55:37 +02:00
Damian Gryski 07fb3a0cad compiler,reflect: make field offsets varints
Fixes #3686
2023-05-16 19:02:08 +02:00
Damian Gryski 4c0fbbfc7f add struct size and field offsets to reflect data 2023-04-27 11:15:41 +02:00
cui fliter 4e9f9e2773 fix some comments
Signed-off-by: cui fliter <imcusg@gmail.com>
2023-04-18 22:51:49 +02:00
Damian Gryski 3fbd3c4d93 compiler,reflect: support channel directions 2023-03-30 21:10:54 +02:00
Ayke van Laethem 523c6c0e3b compiler: correctly generate code for local named types
It is possible to create function-local named types:

    func foo() any {
        type named int
        return named(0)
    }

This patch makes sure they don't alias with named types declared at the
package scope.

Bug originally found by Damian Gryski while working on reflect support.
2023-03-21 22:22:03 +01:00
Damian Gryski 876f08979f compiler,reflect: sort out pkg path vs pkg name for named types 2023-03-19 17:45:43 +01:00
Damian Gryski f2cc98caa5 compiler,reflect: adjust struct layout for type info 2023-03-19 17:45:43 +01:00
Damian Gryski 0d65b4dd26 compiler: only define the package path once
Adding https://github.com/tinygo-org/tinygo/pull/3534 by hand to avoid conflicts when I rebase.
2023-03-19 17:45:43 +01:00
Damian Gryski 7a96f0f609 compiler,reflect: add reflect.Type.NumMethods() 2023-03-19 17:45:43 +01:00
Damian Gryski 344e493ac8 compiler,reflect: fix pkgpath for struct fields 2023-03-15 21:53:57 +01:00
Damian Gryski 93fb897feb compiler, reflect: properly handle embedded structs 2023-03-15 21:53:57 +01:00
Damian Gryski 6a45b73fcb compiler, reflect: replace package and name length with null-byte termination 2023-03-08 09:38:49 -08:00
Damian Gryski 2de64d3f4e compiler, reflect: add Type.PkgPath 2023-03-08 09:38:49 -08:00
Damian Gryski 7654d86d2c compiler, reflect: add support for named types 2023-03-08 09:38:49 -08:00
Ayke van Laethem 0ce539ad42 compiler; add position information to createConstant
Non-functional change. The position information will be used later to
emit debug info locations to string constants.
2023-03-05 17:13:16 -08:00
Damian Gryski 60a93e8e2d compiler, reflect: add map key and element type info 2023-02-28 13:10:40 -08:00
Ayke van Laethem 4e8453167f all: refactor reflect package
This is a big commit that changes the way runtime type information is stored in
the binary. Instead of compressing it and storing it in a number of sidetables,
it is stored similar to how the Go compiler toolchain stores it (but still more
compactly).

This has a number of advantages:

  * It is much easier to add new features to reflect support. They can simply
    be added to these structs without requiring massive changes (especially in
    the reflect lowering pass).
  * It removes the reflect lowering pass, which was a large amount of hard to
    understand and debug code.
  * The reflect lowering pass also required merging all LLVM IR into one
    module, which is terrible for performance especially when compiling large
    amounts of code. See issue 2870 for details.
  * It is (probably!) easier to reason about for the compiler.

The downside is that it increases code size a bit, especially when reflect is
involved. I hope to fix some of that in later patches.
2023-02-17 22:54:34 +01:00
Ayke van Laethem 62df1d7490 all: remove pointer ElementType calls
This is needed for opaque pointers, which are enabled by default in
LLVM 15.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 09ec846c9f all: replace llvm.Const* calls with builder.Create* calls
A number of llvm.Const* functions (in particular extractvalue and
insertvalue) were removed in LLVM 15, so we have to use a builder
instead. This builder will create the same constant values, it simply
uses a different API.
2022-10-19 22:23:19 +02:00
Ayke van Laethem f57cffce2d all: add type parameter to *GEP calls
This is necessary for LLVM 15.
2022-10-19 22:23:19 +02:00
Ayke van Laethem 6bc6de8f82 all: add type parameter to CreateCall
This uses LLVMBuildCall2 in the background, which is the replacement for
the deprecated LLVMBuildCall function.
2022-10-19 22:23:19 +02:00
Ayke van Laethem b79bf29c11 compiler: return a FunctionType (not a PointerType) in getRawFuncType
This is necessary for opaque pointer support (in LLVM 15).
2022-10-19 22:23:19 +02:00
Ayke van Laethem c7a23183e8 all: format code according to Go 1.19 rules
Go 1.19 started reformatting code in a way that makes it more obvious
how it will be rendered on pkg.go.dev. It gets it almost right, but not
entirely. Therefore, I had to modify some of the comments so that they
are formatted correctly.
2022-08-04 12:18:32 +02:00
Ayke van Laethem 79ba6a50c3 compiler: insert basic blocks at an appropriate location
For example, this commit moves the 'throw' branch of an assertion (nil
check, slice index check, etc) to the end of the function while
inserting the "continue" branch right after the insert location. This
makes the resulting IR easier to follow.

For some reason, this also reduces code size a bit on average. The
TinyGo smoke tests saw a reduction of 0.22%, mainly from WebAssembly.
The drivers repo saw little average change in code size (-0.01%).

This commit also adds a few compiler tests for the defer keyword.
2022-06-16 07:59:21 +02:00