Compare commits

..

7 Commits

Author SHA1 Message Date
deadprogram 559ba98319 all: build/test using Go 1.27-rc3
Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-08-14 11:28:58 -07:00
Damian Gryski c4219439eb runtime: make arrays and struct field hashes order dependent 2026-08-12 12:08:52 -07:00
Konstantin Sharlaimov 7a9c649268 fix(gc): pause all cores before scanning stack and globals.
In gcMarkReachable, busy-wait for other cores to enter the interrupt handler and pause before scanning the GC core's stack or globals. Prevents data race where a running core relocates heap references to globals during mark phase.
2026-08-09 12:11:59 -07:00
Konstantin Sharlaimov 213d10838f fix(gc): correct leaking allocator bounds and overflow checks.
Change heap-end comparison to > to prevent spurious OOM when heapptr exactly matches heapEnd. Add overflow check to prevent heap wrapping.
2026-08-09 12:11:59 -07:00
Konstantin Sharlaimov b573ef3813 fix(gc): correct old size calculation in block realloc.
Using blocksPerStateByte instead of bytesPerBlock caused the old size to be underestimated for multi-block allocations, leading to data truncation on growing reallocations.
2026-08-09 12:11:59 -07:00
Mohammed-Asad-Khan 854f91ecf2 Fix to allow -o flag to point to a directory
Previously, running 'tinygo build -o dist/ file.go' where dist/ already
exists as a directory failed with 'open dist/: is a directory', because
Build() only auto-derived a binary name when outpath was empty, not when
it pointed to an existing directory. This adds that check, matching the
behavior of 'go build -o dir/' with a package.

Note: only handles the case where the directory already exists; if the
directory doesn't exist yet, behavior is unchanged.
2026-08-05 07:17:00 -07:00
deadprogram c2346570fb targets/esp32*: add espradio tag for convenience
This add the `espradio` build tag to all ESP32C3,
ESP32S3, and ESP32 boards, since they all have support
for wireless communication using espradio. This
just makes it to people do not have to remember to use
the build tag, the same as we have done with both
`ninafw` and `cyw43439` build tags.

Signed-off-by: deadprogram <ron@hybridgroup.com>
2026-07-30 02:03:13 +02:00
17 changed files with 41 additions and 101 deletions
+2 -2
View File
@@ -40,7 +40,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v5
@@ -131,7 +131,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Build TinyGo (LLVM ${{ matrix.version }}) - name: Build TinyGo (LLVM ${{ matrix.version }})
run: go install -tags=llvm${{ matrix.version }} run: go install -tags=llvm${{ matrix.version }}
+5 -5
View File
@@ -23,7 +23,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Run go mod tidy - name: Run go mod tidy
run: go mod tidy run: go mod tidy
@@ -36,7 +36,7 @@ jobs:
# statically linked binary. # statically linked binary.
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: golang:1.27rc2-alpine image: golang:1.27rc3-alpine
outputs: outputs:
version: ${{ steps.version.outputs.version }} version: ${{ steps.version.outputs.version }}
steps: steps:
@@ -160,7 +160,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Install wasmtime - name: Install wasmtime
uses: bytecodealliance/actions/wasmtime/setup@v1 uses: bytecodealliance/actions/wasmtime/setup@v1
@@ -204,7 +204,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Install Node.js - name: Install Node.js
uses: actions/setup-node@v6 uses: actions/setup-node@v6
@@ -323,7 +323,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Restore LLVM source cache - name: Restore LLVM source cache
uses: actions/cache/restore@v5 uses: actions/cache/restore@v5
+4 -4
View File
@@ -34,7 +34,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Restore cached LLVM source - name: Restore cached LLVM source
uses: actions/cache/restore@v5 uses: actions/cache/restore@v5
@@ -129,7 +129,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
@@ -150,7 +150,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
@@ -176,7 +176,7 @@ jobs:
- name: Install Go - name: Install Go
uses: actions/setup-go@v6 uses: actions/setup-go@v6
with: with:
go-version: '1.27.0-rc.2' go-version: '1.27.0-rc.3'
cache: true cache: true
- name: Download TinyGo build - name: Download TinyGo build
uses: actions/download-artifact@v8 uses: actions/download-artifact@v8
+2 -2
View File
@@ -1,5 +1,5 @@
# tinygo-llvm stage obtains the llvm source for TinyGo # tinygo-llvm stage obtains the llvm source for TinyGo
FROM golang:1.27rc2 AS tinygo-llvm FROM golang:1.27rc3 AS tinygo-llvm
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y apt-utils make cmake clang-17 ninja-build && \ apt-get install -y apt-utils make cmake clang-17 ninja-build && \
@@ -33,7 +33,7 @@ RUN cd /tinygo/ && \
# tinygo-compiler copies the compiler build over to a base Go container (without # tinygo-compiler copies the compiler build over to a base Go container (without
# all the build tools etc). # all the build tools etc).
FROM golang:1.27rc2 AS tinygo-compiler FROM golang:1.27rc3 AS tinygo-compiler
# Copy tinygo build. # Copy tinygo build.
COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo COPY --from=tinygo-compiler-build /tinygo/build/release/tinygo /tinygo
+8 -1
View File
@@ -177,8 +177,15 @@ func Build(pkgName, outpath string, config *compileopts.Config) error {
// Pick a default output path based on the main directory. // Pick a default output path based on the main directory.
outpath = filepath.Base(result.MainDir) + config.DefaultBinaryExtension() outpath = filepath.Base(result.MainDir) + config.DefaultBinaryExtension()
} }
} else if fi, statErr := os.Stat(outpath); statErr == nil && fi.IsDir() {
var name string
if strings.HasSuffix(pkgName, ".go") {
name = filepath.Base(pkgName[:len(pkgName)-3]) + config.DefaultBinaryExtension()
} else {
name = filepath.Base(result.MainDir) + config.DefaultBinaryExtension()
}
outpath = filepath.Join(outpath, name)
} }
if err := os.Rename(result.Binary, outpath); err != nil { if err := os.Rename(result.Binary, outpath); err != nil {
// Moving failed. Do a file copy. // Moving failed. Do a file copy.
inf, err := os.Open(result.Binary) inf, err := os.Open(result.Binary)
-14
View File
@@ -68,20 +68,6 @@ func (dev *USBDevice) Configure(config UARTConfig) {
dev.initcomplete = true dev.initcomplete = true
} }
// Attach connects the device to the USB bus, allowing the host to detect and
// enumerate it. It can be used together with Detach to delay enumeration
// until the USB configuration (device identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
}
// Detach disconnects the device from the USB bus. To the host this appears
// as if the device was unplugged. A subsequent Attach makes the host
// enumerate the device again.
func (dev *USBDevice) Detach() {
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_DETACH)
}
func handlePadCalibration() { func handlePadCalibration() {
// Load Pad Calibration data from non-volatile memory // Load Pad Calibration data from non-volatile memory
// This requires registers that are not included in the SVD file. // This requires registers that are not included in the SVD file.
-14
View File
@@ -71,20 +71,6 @@ func (dev *USBDevice) Configure(config UARTConfig) {
dev.initcomplete = true dev.initcomplete = true
} }
// Attach connects the device to the USB bus, allowing the host to detect and
// enumerate it. It can be used together with Detach to delay enumeration
// until the USB configuration (device identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
sam.USB_DEVICE.CTRLB.ClearBits(sam.USB_DEVICE_CTRLB_DETACH)
}
// Detach disconnects the device from the USB bus. To the host this appears
// as if the device was unplugged. A subsequent Attach makes the host
// enumerate the device again.
func (dev *USBDevice) Detach() {
sam.USB_DEVICE.CTRLB.SetBits(sam.USB_DEVICE_CTRLB_DETACH)
}
func handlePadCalibration() { func handlePadCalibration() {
// Load Pad Calibration data from non-volatile memory // Load Pad Calibration data from non-volatile memory
// This requires registers that are not included in the SVD file. // This requires registers that are not included in the SVD file.
-15
View File
@@ -89,21 +89,6 @@ func (dev *USBDevice) Configure(config UARTConfig) {
dev.initcomplete = true dev.initcomplete = true
} }
// Attach connects the device to the USB bus by enabling the DP pull-up,
// allowing the host to detect and enumerate it. It can be used together with
// Detach to delay enumeration until the USB configuration (device
// identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
nrf.USBD.USBPULLUP.Set(1)
}
// Detach disconnects the device from the USB bus by disabling the DP pull-up.
// To the host this appears as if the device was unplugged. A subsequent
// Attach makes the host enumerate the device again.
func (dev *USBDevice) Detach() {
nrf.USBD.USBPULLUP.Set(0)
}
func handleUSBIRQ(interrupt.Interrupt) { func handleUSBIRQ(interrupt.Interrupt) {
if nrf.USBD.EVENTS_SOF.Get() == 1 { if nrf.USBD.EVENTS_SOF.Get() == 1 {
nrf.USBD.EVENTS_SOF.Set(0) nrf.USBD.EVENTS_SOF.Set(0)
-15
View File
@@ -46,21 +46,6 @@ func (dev *USBDevice) Configure(config UARTConfig) {
rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN) rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
} }
// Attach connects the device to the USB bus by enabling the DP pull-up,
// allowing the host to detect and enumerate it. It can be used together with
// Detach to delay enumeration until the USB configuration (device
// identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
rp.USBCTRL_REGS.SIE_CTRL.SetBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
}
// Detach disconnects the device from the USB bus by disabling the DP pull-up.
// To the host this appears as if the device was unplugged. A subsequent
// Attach makes the host enumerate the device again.
func (dev *USBDevice) Detach() {
rp.USBCTRL_REGS.SIE_CTRL.ClearBits(rp.USBCTRL_REGS_SIE_CTRL_PULLUP_EN)
}
func handleUSBIRQ(intr interrupt.Interrupt) { func handleUSBIRQ(intr interrupt.Interrupt) {
status := rp.USBCTRL_REGS.INTS.Get() status := rp.USBCTRL_REGS.INTS.Get()
-15
View File
@@ -49,21 +49,6 @@ func (dev *USBDevice) Configure(config UARTConfig) {
rp.USB.SetMAIN_CTRL_PHY_ISO(0x0) rp.USB.SetMAIN_CTRL_PHY_ISO(0x0)
} }
// Attach connects the device to the USB bus by enabling the DP pull-up,
// allowing the host to detect and enumerate it. It can be used together with
// Detach to delay enumeration until the USB configuration (device
// identifiers, classes, ...) is complete.
func (dev *USBDevice) Attach() {
rp.USB.SIE_CTRL.SetBits(rp.USB_SIE_CTRL_PULLUP_EN)
}
// Detach disconnects the device from the USB bus by disabling the DP pull-up.
// To the host this appears as if the device was unplugged. A subsequent
// Attach makes the host enumerate the device again.
func (dev *USBDevice) Detach() {
rp.USB.SIE_CTRL.ClearBits(rp.USB_SIE_CTRL_PULLUP_EN)
}
func handleUSBIRQ(intr interrupt.Interrupt) { func handleUSBIRQ(intr interrupt.Interrupt) {
status := rp.USB.INTS.Get() status := rp.USB.INTS.Get()
+1 -1
View File
@@ -510,7 +510,7 @@ func realloc(ptr unsafe.Pointer, size uintptr) unsafe.Pointer {
lastBlock := firstBlock.findHead() lastBlock := firstBlock.findHead()
// Calculate the size of the original allocation body. // Calculate the size of the original allocation body.
oldSize := uintptr(lastBlock-firstBlock)*blocksPerStateByte + (bytesPerBlock - unsafe.Sizeof(objHeader{})) oldSize := uintptr(lastBlock-firstBlock)*bytesPerBlock + (bytesPerBlock - unsafe.Sizeof(objHeader{}))
if size <= oldSize { if size <= oldSize {
// The requested size is less than the old size. // The requested size is less than the old size.
+7 -1
View File
@@ -47,8 +47,14 @@ func alloc(size uintptr, layout unsafe.Pointer) unsafe.Pointer {
gcTotalAlloc += uint64(size) gcTotalAlloc += uint64(size)
gcMallocs++ gcMallocs++
heapptr += size heapptr += size
for heapptr >= heapEnd { if heapptr < addr {
// The allocation size overflowed the heap pointer.
runtimePanic("out of memory")
}
for heapptr > heapEnd {
// Try to increase the heap and check again. // Try to increase the heap and check again.
// Use > instead of >= because an allocation that exactly
// ends at heapEnd is still within heap boundaries.
if growHeap() { if growHeap() {
continue continue
} }
+6 -7
View File
@@ -43,6 +43,12 @@ func gcMarkReachable() {
gcPauseCore(i) gcPauseCore(i)
} }
// Busy-wait until all the other cores are ready.
for gcScanState.Load() != numCPU {
spinLoopWait()
}
gcScanState.Store(0)
// Scan the stack(s) of the current core. // Scan the stack(s) of the current core.
scanCurrentStack() scanCurrentStack()
if !task.OnSystemStack() { if !task.OnSystemStack() {
@@ -53,13 +59,6 @@ func gcMarkReachable() {
// Scan globals. // Scan globals.
findGlobals(markRoots) findGlobals(markRoots)
// Busy-wait until all the other cores are ready. They certainly should be,
// after the scanning we did above.
for gcScanState.Load() != numCPU {
spinLoopWait()
}
gcScanState.Store(0)
// Signal each core in turn that they can scan the stack. // Signal each core in turn that they can scan the stack.
for i := uint32(0); i < numCPU; i++ { for i := uint32(0); i < numCPU; i++ {
if i == core { if i == core {
+2 -2
View File
@@ -807,13 +807,13 @@ func hashmapInterfaceHash(itf interface{}, seed uintptr) uint32 {
case reflectlite.Array: case reflectlite.Array:
var hash uint32 var hash uint32
for i := 0; i < x.Len(); i++ { for i := 0; i < x.Len(); i++ {
hash ^= hashmapInterfaceHash(valueInterfaceUnsafe(x.Index(i)), seed) hash = (hash * 31) ^ hashmapInterfaceHash(valueInterfaceUnsafe(x.Index(i)), seed)
} }
return hash return hash
case reflectlite.Struct: case reflectlite.Struct:
var hash uint32 var hash uint32
for i := 0; i < x.NumField(); i++ { for i := 0; i < x.NumField(); i++ {
hash ^= hashmapInterfaceHash(valueInterfaceUnsafe(x.Field(i)), seed) hash = (hash * 31) ^ hashmapInterfaceHash(valueInterfaceUnsafe(x.Field(i)), seed)
} }
return hash return hash
default: default:
+1 -1
View File
@@ -3,7 +3,7 @@
"inheritable-only": true, "inheritable-only": true,
"cpu": "esp32", "cpu": "esp32",
"features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+dfpaccel,+div32,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed", "features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+dfpaccel,+div32,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed",
"build-tags": ["esp32", "esp"], "build-tags": ["esp32", "esp", "espradio"],
"scheduler": "tasks", "scheduler": "tasks",
"serial": "uart", "serial": "uart",
"linker": "ld.lld", "linker": "ld.lld",
+2 -1
View File
@@ -6,7 +6,8 @@
"features": "+32bit,+c,+m,+zmmul,-relax", "features": "+32bit,+c,+m,+zmmul,-relax",
"build-tags": [ "build-tags": [
"esp32c3", "esp32c3",
"esp" "esp",
"espradio"
], ],
"serial": "usb", "serial": "usb",
"rtlib": "compiler-rt", "rtlib": "compiler-rt",
+1 -1
View File
@@ -3,7 +3,7 @@
"inheritable-only": true, "inheritable-only": true,
"cpu": "esp32s3", "cpu": "esp32s3",
"features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+div32,+esp32s3,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed", "features": "+atomctl,+bool,+clamps,+coprocessor,+debug,+density,+div32,+esp32s3,+exception,+fp,+highpriinterrupts,+interrupt,+loop,+mac16,+memctl,+minmax,+miscsr,+mul32,+mul32high,+nsa,+prid,+regprotect,+rvector,+s32c1i,+sext,+threadptr,+timerint,+windowed",
"build-tags": ["esp32s3", "esp"], "build-tags": ["esp32s3", "esp", "espradio"],
"scheduler": "tasks", "scheduler": "tasks",
"serial": "usb", "serial": "usb",
"linker": "ld.lld", "linker": "ld.lld",