Commit Graph

830 Commits

Author SHA1 Message Date
Nia Waldvogel 5c37d1ba61 runtime: implement fminimum/fmaximum
The compiler may generate calls to fminimum/fmaximum on some platforms.
Neither of the libm implementations we statically link against have these functions yet.
Implement them ourselves.
2026-02-18 15:13:01 -05:00
Dima Jolkin 610dd19c40 esp32s3-usbserial: move InitSerial to init method 2026-02-17 20:42:23 +01:00
Dima Jolkin 9bbad6700b esp32s3-usbserial: added usbserial printing 2026-02-17 20:42:23 +01:00
deadprogram 934d5f41bf fix: init heap before random number seed on wasm platforms
This changes the order for initialization of the random number
seed generation on wasm platforms until after the heap has been
initialized. Should fix #5198

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-02-16 08:38:17 +01:00
Dima 4b0e858964 Esp32s3 implement spi (#5169)
* esp32s3 spi

* stabilization freq cpu

* cheange clacl freq for spi

* fix linters

* esp32s3-spi: change default pins for esp32s3 xiao

* set default configuration

* esp32s3-spi: extends smoketests for esp32s3
2026-02-15 14:50:39 +01:00
deadprogram 743bf45e00 runtime: make timeoffset atomic
Make timeoffset atomic to be able to handle changing the system
time. Otherwise the scheduler can gets rather confused if you call
AdjustTimeOffset when there are multiple goroutines already running.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-01-09 23:20:47 +00:00
Damian Gryski 9bc5d21185 src/runtime: add MemStats.HeapObjects 2026-01-09 13:46:28 +00:00
Amken USA cfd74c2954 Add stm32g0b1 support (#5150)
* Add STM32G0B1 target support

Introduce support for STM32G0B1 microcontrollers, including target-specific JSON files, linker scripts, and runtime initialization. This update adds hardware support for GPIO, UART, SPI, I2C, timers, and additional board-specific configurations like Nucleo-G0B1RE.

* Update STM32G0 clock initialization to 64MHz and adjust related configurations

Reconfigure STM32G0 to use a 64MHz system clock via PLL with HSI16 as the source. Update flash latency, prescaler settings, and I2C timing values to reflect the new frequency.

* Cleanup

* Cleanup

* Add STM32G0-specific UART implementation

Introduce a new UART implementation for the STM32G0 series with chip-specific setup and configuration methods. Update the generic STM32 UART code to exclude STM32G0.

* Refactor STM32G0 runtime and machine code to utilize chip-specific register access functions

Simplify and standardize register operations with dedicated setter methods in the STM32G0 runtime and machine code and cleanup redundant syntax.

* Remove redundant commented-out APBENR1 register operations in STM32G0 machine code

* Introduce FDCAN support for STM32G0B1 series

Add FDCAN peripheral implementation targeting STM32G0B1, including support for standard, extended identifiers, and bit rate configuration. Update board files to include FDCAN pins, instances, and clock configuration for Nucleo-G0B1RE and Amken Trio boards.
2026-01-06 23:12:02 +01:00
Nia Waldvogel a40586d092 compiler: implement copy directly
The compiler now implements the copy builtin directly instead of calling sliceCopy.
The length is calculated with the llvm.umax.* intrinsics, and the move is performed by llvm.memmove.*.
Both of these operations are easily understood by LLVM's optimization passes.
The type's alignment is also provided to llvm.memmove.*, which is useful when rewriting the move.

Interp no longer needs to reimplement sliceCopy.
Some edge case handling was implemented by sliceCopy but not llvm.memmove.*/llvm.memcpy.*.
I copied this over, so copies of external slices should work now.
Volatile moves/copies are now run at runtime by interp.

There is a 4-byte size increase due to some confusing length logic in sendUSBPacket.
I will look at sendUSBPacket in a future PR.
2026-01-05 15:10:31 -05:00
Nia Waldvogel 266d70816f compiler/runtime: add element layout to sliceAppend
Attach the memory layout of the element type to newly created slices via append when using the precise collector.
2025-12-26 21:27:24 -05:00
MakKi (makki_d) f7fd5cf2d8 runtime: use rand_hwrng hardwareRand for RP2040/RP2350 (#5135)
* runtime: use rand_hwrng hardwareRand for RP2040/RP2350

* add a comment

* insert 'implementations'
2025-12-18 20:52:12 +01:00
deadprogram 82deccac40 runtime: call initRand() before initHeap() during initialization.
The reason is that allocating without a heap is usually more visible
than using an uninitialized random generator which is subtle and may
lead to security vulnerabilities.

Based on suggestion from @eliasnaur

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-18 16:42:46 +00:00
deadprogram 0e540dc3da runtime: add calls to initRand() during run() for all schedulers.
Intended to ensure that the random number seed used is always initialized on startup.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2025-12-18 16:42:46 +00:00
MakKi (makki_d) 897f2bc5fd runtime: avoid fixed math/rand sequence on RP2040/RP2350 (#5124)
* runtime: avoid fixed math/rand sequence on RP2040/RP2350

* fix typo
2025-12-17 20:05:43 +01:00
Nia Waldvogel d01d0bb358 runtime (gc_blocks.go): make sweep branchless
Instead of looping over each block, we can use bit hacks to operate on an entire state byte.
I deinterleaved the state bits in order to enable these tricks.

Sweep used to count free/freed allocations/blocks.
I managed to move/remove all of these counters:
- The free space is now calculated in buildFreeRanges by adding the range lengths.
- ReadMemStats counts freed objects by subtracting live objects from allocated objects.
- gcFreedBlocks was never necessary because MemStats.HeapAlloc is the same as MemStats.HeapInUse.
2025-12-10 18:39:50 -05:00
Nia Waldvogel 8fcf3658b1 runtime (gc_blocks.go): use best-fit allocation
The allocator originally just looped through the blocks until it found a sufficiently-long range.
This is simple, but it fragments very easily and can degrade to a full heap scan for long requests.

Instead, we now maintain a sorted nested list of free ranges by size.
The allocator will select the shortest sufficient-length range, generally reducing fragmentation.
This data structure can find a range in time directly proportional to the requested length.
2025-12-10 06:58:07 +00:00
Nia Waldvogel ee0a10ec51 runtime (wasm): scan the system stack
This saves the system stack pointer into a global and uses it to scan.
It should fix some use-after-free issues?
2025-12-08 17:27:20 +00:00
Ayke van Laethem 908fa84d49 runtime: remove copied code for nrf52840
We really shouldn't have copies around like that, instead the code
should be factored out.
In this case, it's a single import that's needed.
2025-12-05 20:50:06 +00:00
Ayke van Laethem 571f34e0e6 machine: only enable USB-CDC when needed
Enabling USB consumes a lot of power. So it's better to keep it disabled
by default when the serial port is set to something other than "usb"
(USB-CDC).

On my nice!nano clone, it reduces current consumption from 1mA to
0.13mA (and most of the rest is probably consumed by a connected SCD41
sensor).

This change might break some expectations, when a board uses USB but not
USB-CDC (I think this is rare, but I didn't check specifically).
2025-12-05 20:50:06 +00:00
Nia Waldvogel 01723025d7 runtime (avr): fix infinite longjmp loop if stack is aligned to 256 bytes
The setjmp code sets r24 to 0 and checks if it is still 0 when it finishes.
This usually works because tinygo_longjmp stores the lower half of the stack pointer into r24.
However, r24 will be set to 0 if the stack is aligned to 256 bytes when entering the setjmp.

Manually set r24 to 1 in tinygo_longjmp to fix this issue.
2025-12-05 13:22:37 -05:00
Nia Waldvogel 26ac03a3f6 runtime (gc_blocks.go): simplify scanning logic
Loop over valid pointer locations in heap objects instead of checking if each location is valid.
The conservative scanning code is now shared between markRoots and the heap scan.

This also removes the ending alignment requirement from markRoots, since the new scan* functions do not require an aligned length.
This requirement was occasionally violated by the linux global marking code.

This saves some code space and has negligible impact on performance.
2025-12-05 10:16:38 +00:00
Nia Waldvogel c9aa88b8ef runtime (gc_blocks.go): use a linked stack to scan marked objects
The blocks GC originally used a fixed-size stack to hold objects to scan.
When this stack overflowed, the GC would fully rescan all marked objects.
This could cause the GC to degrade to O(n^2) when scanning large linked data structures.

Instead of using a fixed-size stack, we now add a pointer field to the start of each object.
This pointer field is used to implement an unbounded linked stack.
This also consolidates the heap object scanning into one place, which simplifies the process.

This comes at the cost of introducing a pointer field to the start of the object, plus the cost of aligning the result.
This translates to:
- 16 bytes of overhead on x86/arm64 with the conservative collector
- 0 bytes of overhead on x86/arm64 with the precise collector (the layout field cost gets aligned up to 16 bytes anyway)
- 8 bytes of overhead on other 64-bit systems
- 4 bytes of overhead on 32-bit systems
- 2 bytes of overhead on AVR
2025-12-05 10:16:38 +00:00
Nia Waldvogel 9404bb8712 internal/task (threads): save stack bounds instead of scanning under a lock
In order to scan stacks, the GC preempts all other threads and has them scan their own stack.
This is somewhat expensive since all of these threads have to fight over a single lock.
Instead, save the stack bounds and let the GC thread perform the scan.

This also fixes a few other bugs I ran into:
1. The GC starts scanning before the world stops. This can cause it to miss some objects (and mistakenly free them) if memory is modified while stopping.
2. The GC does not wait for threads to resume. This can cause notifications to be misinterpreted due to signal nesting if the GC is re-run before all threads wake.
2025-12-04 11:22:46 +00:00
Nia Waldvogel 20e22d4507 runtime (gc_blocks.go): clear full size of allocation
This fixes a bug where runtime.alloc would not clear the padding from rounding the allocation up to a multiple of the block size.
The GC still has to scan this, and this could result in permanent false positives (and therefore memory leaks).

It also handles overflow in the size calculation.
2025-11-30 08:46:20 +00:00
cjpeterson fbbaa5e580 Add ESP32-S3 support (#5091)
* feat: add initial support for ESP32-S3 (#3442)

* feat: add initial support for esp32-s3

* esp32s3: fix merge errors

* esp32s3: Fix Watchdog registers bad names

* esp32s3: fix linker relocation errors and support for ESP binary

* esp32s3: fix memory section overlap

* esp32s3: correct clock frequencies

* esp32s3: more stable cpu

* esp32s3: enable basic gpio support

* esp32s3: simplify loading and check extensions

* esp32s3: synchronize cpu features with clang

* esp32s3: correct iram origin

---------

Co-authored-by: Denys Vitali <denys@denv.it>
Co-authored-by: Olivier Fauchon <ofauchon2204@gmail.com>
2025-11-24 12:11:47 +01:00
Ayke van Laethem 484ccf830a nrf: refactor SoftDevice enabled check
Share the code with the runtime.
2025-11-16 19:25:14 +01:00
Nia Waldvogel c80da7eb0d runtime (gc_boehm.go): fix world already stopped check
This fixes the "gc: world already stopped" check by moving it before gcMarkReachable.
Previously the check did not work because gcMarkReachable would hang while waiting for activeTaskLock.
2025-11-10 11:19:31 +01:00
Ayke van Laethem 26ee3fb93e wasm: fix C realloc and optimize it a bit
- Do not use make([]byte, ...) to allocate, instead call the allocator
    directly with a nil (undefined) layout. This makes sure the precise
    GC will scan the contents of the allocation, since C could very well
    put pointers in there.
  - Simplify the map to use the pointer as the key and the size as the
    value, instead of storing the slices directly in the map.
2025-10-20 12:58:11 +02:00
Ayke van Laethem 8872d5ebfc runtime: fix sleep duration for long sleeps
Long sleep durations weren't implemented correctly, by simply casting to
a smaller number of bits. What we want is a saturating downcast, which
is what I've used here instead.

This should fix https://github.com/tinygo-org/tinygo/issues/3356.
2025-10-16 17:20:50 +02:00
Ayke van Laethem 0a87846bd8 cortexm: optimize code size for the HardFault_Handler
This function is called when a hard fault occurs. Hard faults happen
when something really bad happens - like writing to unwritable memory or
an unaligned memory access on Cortex-M0. It is not generally possible to
recover from these.

This commit optimizes the code size overhead of hard fault handling:

  * It removes the stack overflow checking code.
    This may seem like a bad thing, but the only thing this could check
    were stack overflows outside goroutines. In practice, this could
    only really happen on a stack overflow in the scheduler (unlikely),
    or in interrupt code (possible, but interrupts are small so still
    unlikely). Most stack overflows happen in regular goroutines, and
    weren't caught in the HardFault.
  * It makes the panic message similar to a regular panic. This has two
    advantages:
      * It reduces code size, because the string can be reused between
        the HardFault handler and the runtime panic function.
      * Using the same pattern automatically makes `-monitor` print the
        source address for the hard fault. Not a big benefit as we could
        trivially add any other pattern but a nice benefit nonetheless.

Result:

    $ tinygo flash -target=microbit -size=short -programmer=openocd -monitor examples/serial
       code    data     bss |   flash     ram
       3036       8    2256 |    3044    2264
    [...snip]
    Connected to /dev/ttyACM0. Press Ctrl-C to exit.
    panic: runtime error at 0x00000344: HardFault with sp=0x200007d0
    [tinygo: panic at /home/ayke/src/tinygo/tinygo/src/internal/task/task_stack_cortexm.go:48:4]

(This is with https://github.com/tinygo-org/tinygo/pull/3680 not yet
fixed and some local changes to configure the UART so I can actually see
the panic).

For atsamd21/nrf51 chips this results in a binary size reduction of
around 100 bytes. For other Cortex-M chips it's around 24 bytes but I
hope to change this in the future because a lot of the fault decoding in
runtime_cortexm_hardfault_debug.go should IMHO be done by the TinyGo
monitor instead (I estimate that this would save around 800 bytes on
these chips).
2025-10-03 13:20:18 +02:00
Ben Krieger 821f2aeae0 Fix linker errors for runtime.vgetrandom and crypto/internal/sysrand.fatal 2025-09-19 15:32:01 +02:00
Michael Smith 310df7acb5 fix(rp2): reset spinlocks at startup 2025-09-19 02:22:36 -04:00
Michael Smith b9387febe0 fix(rp2): use side-effect-free spinlocks 2025-09-19 02:22:36 -04:00
Michael Smith 3dce224183 fix(rp2): switch spinlock busy loop to wfe 2025-09-19 02:22:36 -04:00
Michael Smith 64caab1ade feat: enable multi-core scheduler for rp2350 2025-08-08 13:09:38 +02:00
Elias Naur 78914382c3 runtime: ensure time.Sleep(d) sleeps at least d
Account for the sleep queue base time in the computation of the wakeup
time.

Tested with the following program on pico2.

  func main() {
  	go func() {
  		for i := range 60 {
  			const delay = 20 * time.Millisecond
  			before := time.Now()
  			time.Sleep(delay)
  			if d := time.Since(before); true || d < delay {
  				log.Println(i, "actual", d, "delay", delay)
  			}
  		}
  	}()
  	time.Sleep(500 * time.Millisecond)
  	log.Println("******** done sleeping ********")
  	select {}
  }

Without this change, the program would print lines such as:

  17 actual 15.494ms delay 20ms
  18 actual 15.49ms delay 20ms
  19 actual 15.585ms delay 20ms
  20 actual 15.493ms delay 20ms
  21 actual 15.494ms delay 20ms
  22 actual 15.487ms delay 20ms
  23 actual 15.498ms delay 20ms
  ******** done sleeping ********
  24 actual 15.548ms delay 20ms
  25 actual 20.011ms delay 20ms
  26 actual 20.01ms delay 20ms
  27 actual 20.011ms delay 20ms
  28 actual 20.015ms delay 20ms

Note that while more than one sleeping goroutine is in the timer queue,
the sleep duration is 5ms short.
2025-08-08 01:32:42 +02:00
Ayke van Laethem b33b6ce293 all: add Go 1.25 support 2025-08-06 17:08:26 +02:00
Ayke van Laethem 8911abbc6d runtime: stub out weak pointer support 2025-08-06 17:08:26 +02:00
Ayke van Laethem 5c46efb4d1 runtime: implement dummy AddCleanup 2025-08-06 17:08:26 +02:00
Damian Gryski 8c5886060f internal/gclayout: make gclayout values constants
The previous versions calculated at init() prevented `interp` from running
in many cases, increasing compile times due to the increased need to revert
the partially interpreted results and also increasing binary runtime because
fewer optimizations had happened during interp.
2025-07-22 18:57:55 +02:00
Ayke van Laethem e238eb2242 rp2040: add multicore support 2025-06-13 16:19:10 +02:00
Ayke van Laethem 5625f68d51 runtime: don't lock the print output inside interrupts
This should avoid a deadlock when trying to print inside an interrupt,
if the interrupted code is also printing (and therefore has the print
lock taken).
2025-06-13 16:19:10 +02:00
Ayke van Laethem f7d8502572 runtime: don't try to interrupt other cores before they are started
The GC shouldn't try to interrupt other cores before they are started.
For example, it would be possible for the GC to run in a package
initializer (which is currently run on a single core). That would
suggest questionable program design, but it is something that should
work. So this commit makes sure the GC only tries to scan the stack of
other cores when those other cores have in fact started.
2025-06-13 16:19:10 +02:00
Ayke van Laethem e395c94e5f runtime: implement NumCPU for the multicore scheduler
I forgot to add it in the first PR, here:
https://github.com/tinygo-org/tinygo/pull/4851
2025-06-13 16:19:10 +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 60f8a62978 all: add support for multicore scheduler
This commit adds support for a scheduler that runs a scheduler on all
available cores. It is meant to be used on baremetal systems with a
fixed number of cores, such as the RP2040.

The initial implementation adds support for multicore scheduling to the
riscv-qemu target as a convenient testing target. This means that this
new multicore scheduler is tested in CI, including a bunch of standard
library tests (`make tinygo-test-baremetal`). This should ensure the new
scheduler is reasonably well tested before trying to use it on
harder-to-debug targets like the RP2040.
2025-06-12 21:04:36 +02:00
Ayke van Laethem 0c7c2926f9 runtime: refactor obtaining the system stack
The system stack is only needed when we're not on it. So we can directly
call task.SystemStack() without problems.

This also saves a tiny bit of binary size.
2025-06-12 21:04:36 +02:00
Ayke van Laethem 3a2188fc7b runtime/interrupt: add Checkpoint type
This type can be used to jump back to a previous position in a program
from inside an interrupt. This is useful for baremetal systems that
implement wfi but not wfe, and therefore have no easy (race-free) way to
wait until a flag gets changed inside an interrupt. This is an issue on
RISC-V, where this is racy (the interrupt might happen after the check
but before the wfi instruction):

    configureInterrupt()
    for flag.Load() != 0 {
        riscv.Asm("wfi")
    }
2025-06-12 21:04:36 +02:00
Ayke van Laethem 64a30424da runtime: add exportedFuncPtr
This function isn't used yet, but will be used for the "cores" scheduler
for RISC-V.
2025-06-12 21:04:36 +02:00
Ömer Faruk IRMAK f19b288717 runtime/debug: add GC related stubs 2025-06-11 09:57:46 +02:00