Compare commits

..

3 Commits

Author SHA1 Message Date
Ayke van Laethem f0391eac25 all: update to version 0.25.0 2022-08-02 18:25:51 +02:00
Phil Kedy 05cdde162c Set internal linkage and keeping default visibility for anonymous functions 2022-08-01 10:53:48 +02:00
sago35 25c8d3ec3a wasm,wasi: stub runtime.buffered, runtime.getchar 2022-07-30 17:41:54 +02:00
46 changed files with 366 additions and 231 deletions
+55
View File
@@ -1,3 +1,58 @@
0.25.0
---
* **command line**
- change to ignore PortReset failures
* **compiler**
- `compiler`: darwin/arm64 is aarch64, not arm
- `compiler`: don't clobber X18 and FP registers on darwin/arm64
- `compiler`: fix issue with methods on generic structs
- `compiler`: do not try to build generic functions
- `compiler`: fix type names for generic named structs
- `compiler`: fix multiple defined function issue for generic functions
- `compiler`: implement `unsafe.Alignof` and `unsafe.Sizeof` for generic code
* **standard library**
- `machine`: add DTR and RTS to Serialer interface
- `machine`: reorder pin definitions to improve pin list on tinygo.org
- `machine/usb`: add support for MIDI
- `machine/usb`: adjust buffer alignment (samd21, samd51, nrf52840)
- `machine/usb/midi`: add `NoteOn`, `NoteOff`, and `SendCC` methods
- `machine/usb/midi`: add definition of MIDI note number
- `runtime`: add benchmarks for memhash
- `runtime`: add support for printing slices via print/println
* **targets**
- `avr`: fix some apparent mistake in atmega1280/atmega2560 pin constants
- `esp32`: provide hardware pin constants
- `esp32`: fix WDT reset on the MCH2022 badge
- `esp32`: optimize SPI transmit
- `esp32c3`: provide hardware pin constants
- `esp8266`: provide hardware pin constants like `GPIO2`
- `nrf51`: define and use `P0_xx` constants
- `nrf52840`, `samd21`, `samd51`: unify bootloader entry process
- `nrf52840`, `samd21`, `samd51`: change usbSetup and sendZlp to public
- `nrf52840`, `samd21`, `samd51`: refactor handleStandardSetup and initEndpoint
- `nrf52840`, `samd21`, `samd51`: improve usb-device initialization
- `nrf52840`, `samd21`, `samd51`: move usbcdc to machine/usb/cdc
- `rp2040`: add usb serial vendor/product ID
- `rp2040`: add support for usb
- `rp2040`: change default for serial to usb
- `rp2040`: add support for `machine.EnterBootloader`
- `rp2040`: turn off pullup/down when input type is not specified
- `rp2040`: make picoprobe default openocd interface
- `samd51`: add support for `DAC1`
- `samd51`: improve TRNG
- `wasm`: stub `runtime.buffered`, `runtime.getchar`
- `wasi`: make leveldb runtime hash the default
* **boards**
- add Challenger RP2040 LoRa
- add MCH2022 badge
- add XIAO RP2040
- `clue`: remove pins `D21`..`D28`
- `feather-rp2040`, `macropad-rp2040`: fix qspi-flash settings
- `xiao-ble`: add support for flash-1200-bps-reset
- `gopherbot`, `gopherbot2`: add these aliases to simplify for newer users
0.24.0 0.24.0
--- ---
+3 -13
View File
@@ -1228,15 +1228,10 @@ func determineStackSizes(mod llvm.Module, executable string) ([]string, map[stri
// Goroutines need to be started and finished and take up some stack space // Goroutines need to be started and finished and take up some stack space
// that way. This can be measured by measuing the stack size of // that way. This can be measured by measuing the stack size of
// tinygo_startTask. // tinygo_startTask.
var baseStackSize uint64 if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
var baseStackSizeType stacksize.SizeType return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
var baseStackSizeFailedAt *stacksize.CallNode
if len(gowrappers) != 0 {
if numFuncs := len(functions["tinygo_startTask"]); numFuncs != 1 {
return nil, nil, fmt.Errorf("expected exactly one definition of tinygo_startTask, got %d", numFuncs)
}
baseStackSize, baseStackSizeType, baseStackSizeFailedAt = functions["tinygo_startTask"][0].StackSize()
} }
baseStackSize, baseStackSizeType, baseStackSizeFailedAt := functions["tinygo_startTask"][0].StackSize()
sizes := make(map[string]functionStackSize) sizes := make(map[string]functionStackSize)
@@ -1308,11 +1303,6 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
if err != nil { if err != nil {
return err return err
} }
if data == nil {
// The .tinygo_stacksizes section doesn't exist, so assume this
// modification isn't needed.
return nil
}
if len(stackSizeLoads)*4 != len(data) { if len(stackSizeLoads)*4 != len(data) {
// Note: while AVR should use 2 byte stack sizes, even 64-bit platforms // Note: while AVR should use 2 byte stack sizes, even 64-bit platforms
+1 -1
View File
@@ -15,7 +15,7 @@ func getElfSectionData(executable string, sectionName string) ([]byte, elf.FileH
section := elfFile.Section(sectionName) section := elfFile.Section(sectionName)
if section == nil { if section == nil {
return nil, elf.FileHeader{}, nil return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
} }
data, err := section.Data() data, err := section.Data()
+10 -1
View File
@@ -1039,9 +1039,17 @@ func (b *builder) createFunctionStart() {
b.addError(b.fn.Pos(), errValue) b.addError(b.fn.Pos(), errValue)
return return
} }
b.addStandardDefinedAttributes(b.llvmFn) b.addStandardDefinedAttributes(b.llvmFn)
if !b.info.exported { if !b.info.exported {
b.llvmFn.SetVisibility(llvm.HiddenVisibility) // Do not set visibility for local linkage (internal or private).
// Otherwise a "local linkage requires default visibility"
// assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236
// is thrown.
if b.llvmFn.Linkage() != llvm.InternalLinkage &&
b.llvmFn.Linkage() != llvm.PrivateLinkage {
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
}
b.llvmFn.SetUnnamedAddr(true) b.llvmFn.SetUnnamedAddr(true)
} }
if b.info.section != "" { if b.info.section != "" {
@@ -1265,6 +1273,7 @@ func (b *builder) createFunction() {
// Create anonymous functions (closures etc.). // Create anonymous functions (closures etc.).
for _, sub := range b.fn.AnonFuncs { for _, sub := range b.fn.AnonFuncs {
b := newBuilder(b.compilerContext, b.Builder, sub) b := newBuilder(b.compilerContext, b.Builder, sub)
b.llvmFn.SetLinkage(llvm.InternalLinkage)
b.createFunction() b.createFunction()
} }
} }
+1 -1
View File
@@ -196,7 +196,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 { define internal void @"main.foo$1"(%main.kv.0* dereferenceable_or_null(1) %b, i8* %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
+3 -3
View File
@@ -115,7 +115,7 @@ declare i8* @llvm.stacksave() #2
declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0 declare void @runtime.setupDeferFrame(%runtime.deferFrame* dereferenceable_or_null(24), i8*, i8*) #0
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 { define internal void @"main.deferSimple$1"(i8* %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printint32(i32 3, i8* undef) #3 call void @runtime.printint32(i32 3, i8* undef) #3
ret void ret void
@@ -246,14 +246,14 @@ rundefers.end9: ; preds = %rundefers.loophead1
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 { define internal void @"main.deferMultiple$1"(i8* %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printint32(i32 3, i8* undef) #3 call void @runtime.printint32(i32 3, i8* undef) #3
ret void ret void
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 { define internal void @"main.deferMultiple$2"(i8* %context) unnamed_addr #1 {
entry: entry:
call void @runtime.printint32(i32 5, i8* undef) #3 call void @runtime.printint32(i32 5, i8* undef) #3
ret void ret void
+2 -2
View File
@@ -51,7 +51,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
@@ -84,7 +84,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
entry: entry:
%unpack.ptr = bitcast i8* %context to i32* %unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4 store i32 7, i32* %unpack.ptr, align 4
+2 -2
View File
@@ -53,7 +53,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { define internal void @"main.inlineFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
entry: entry:
ret void ret void
} }
@@ -90,7 +90,7 @@ entry:
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
define hidden void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 { define internal void @"main.closureFunctionGoroutine$1"(i32 %x, i8* %context) unnamed_addr #1 {
entry: entry:
%unpack.ptr = bitcast i8* %context to i32* %unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4 store i32 7, i32* %unpack.ptr, align 4
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// Version of TinyGo. // Version of TinyGo.
// Update this value before release of new version of software. // Update this value before release of new version of software.
const Version = "0.25.0-dev" const Version = "0.25.0"
var ( var (
// This variable is set at build time using -ldflags parameters. // This variable is set at build time using -ldflags parameters.
+8 -2
View File
@@ -99,9 +99,9 @@ func Pause() {
//export tinygo_unwind //export tinygo_unwind
func (*stackState) unwind() func (*stackState) unwind()
// Switch to this task until it pauses or completes. // Resume the task until it pauses or completes.
// This may only be called from the scheduler. // This may only be called from the scheduler.
func (t *Task) Switch() { func (t *Task) Resume() {
// The current task must be saved and restored because this can nest on WASM with JS. // The current task must be saved and restored because this can nest on WASM with JS.
prevTask := currentTask prevTask := currentTask
t.gcData.swap() t.gcData.swap()
@@ -121,3 +121,9 @@ func (t *Task) Switch() {
//export tinygo_rewind //export tinygo_rewind
func (*state) rewind() func (*state) rewind()
// OnSystemStack returns whether the caller is running on the system stack.
func OnSystemStack() bool {
// If there is not an active goroutine, then this must be running on the system stack.
return Current() == nil
}
+3 -3
View File
@@ -28,12 +28,12 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
type state struct{} type state struct{}
func (t *Task) Switch() { func (t *Task) Resume() {
runtimePanic("scheduler is disabled") runtimePanic("scheduler is disabled")
} }
// MainTask returns whether the caller is running in the main goroutine. // OnSystemStack returns whether the caller is running on the system stack.
func MainTask() bool { func OnSystemStack() bool {
// This scheduler does not do any stack switching. // This scheduler does not do any stack switching.
return true return true
} }
+12 -23
View File
@@ -27,12 +27,8 @@ type state struct {
canaryPtr *uintptr canaryPtr *uintptr
} }
// The task struct for the main goroutine. // currentTask is the current running task, or nil if currently in the scheduler.
var mainTask Task var currentTask *Task
// currentTask is the current running task. The default value is the main
// goroutine.
var currentTask = &mainTask
// Current returns the current active task. // Current returns the current active task.
func Current() *Task { func Current() *Task {
@@ -40,36 +36,29 @@ func Current() *Task {
} }
// Pause suspends the current task and returns to the scheduler. // Pause suspends the current task and returns to the scheduler.
// This function may only be called when running on a goroutine stack, not when in an interrupt. // This function may only be called when running on a goroutine stack, not when running on the system stack or in an interrupt.
func Pause() { func Pause() {
// Check whether the canary (the lowest address of the stack) is still // Check whether the canary (the lowest address of the stack) is still
// valid. If it is not, a stack overflow has occured. // valid. If it is not, a stack overflow has occured.
if currentTask.state.canaryPtr != nil && *currentTask.state.canaryPtr != stackCanary { if *currentTask.state.canaryPtr != stackCanary {
runtimePanic("goroutine stack overflow") runtimePanic("goroutine stack overflow")
} }
scheduler() currentTask.state.pause()
} }
//go:linkname scheduler runtime.scheduler
func scheduler()
//export tinygo_pause //export tinygo_pause
func pause() { func pause() {
Pause() Pause()
} }
// Switch to the given task until it pauses or completes. // Resume the task until it pauses or completes.
// This may only be called from the scheduler. // This may only be called from the scheduler.
func (t *Task) Switch() { func (t *Task) Resume() {
current := currentTask
if current == t {
// Nothing to switch to: we're already in this task.
return
}
currentTask = t currentTask = t
t.gcData.swap() t.gcData.swap()
t.state.switchTo(current) t.state.resume()
t.gcData.swap() t.gcData.swap()
currentTask = nil
} }
// initialize the state and prepare to call the specified function with the specified argument bundle. // initialize the state and prepare to call the specified function with the specified argument bundle.
@@ -114,8 +103,8 @@ func start(fn uintptr, args unsafe.Pointer, stackSize uintptr) {
runqueuePushBack(t) runqueuePushBack(t)
} }
// MainTask returns whether the caller is running in the main goroutine. // OnSystemStack returns whether the caller is running on the system stack.
func MainTask() bool { func OnSystemStack() bool {
// If there is not an active goroutine, then this must be running on the system stack. // If there is not an active goroutine, then this must be running on the system stack.
return currentTask == &mainTask return Current() == nil
} }
+5 -2
View File
@@ -20,8 +20,11 @@ tinygo_startTask:
// Branch to the "goroutine start" function. // Branch to the "goroutine start" function.
calll *%ebx calll *%ebx
// After return, exit this goroutine. // Rebalance the stack (to undo the above push).
calll tinygo_pause addl $4, %esp
// After return, exit this goroutine. This is a tail call.
jmp tinygo_pause
.cfi_endproc .cfi_endproc
.global tinygo_swapTask .global tinygo_swapTask
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_386.S that relies on the exact // switching between tasks. Also see task_stack_386.S that relies on the exact
// layout of this struct. // layout of this struct.
@@ -44,12 +46,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.esi = uintptr(args) r.esi = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+3 -3
View File
@@ -28,11 +28,11 @@ tinygo_startTask:
// Branch to the "goroutine start" function. // Branch to the "goroutine start" function.
callq *%r12 callq *%r12
// After return, exit this goroutine. // After return, exit this goroutine. This is a tail call.
#ifdef __MACH__ #ifdef __MACH__
callq _tinygo_pause jmp _tinygo_pause
#else #else
callq tinygo_pause jmp tinygo_pause
#endif #endif
.cfi_endproc .cfi_endproc
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_amd64.S that relies on the exact // switching between tasks. Also see task_stack_amd64.S that relies on the exact
// layout of this struct. // layout of this struct.
@@ -43,12 +45,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r13 = uintptr(args) r.r13 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+2 -2
View File
@@ -17,8 +17,8 @@ tinygo_startTask:
// Branch to the "goroutine start" function. // Branch to the "goroutine start" function.
callq *%r12 callq *%r12
// After return, exit this goroutine. // After return, exit this goroutine. This is a tail call.
callq tinygo_pause jmp tinygo_pause
.global tinygo_swapTask .global tinygo_swapTask
.section .text.tinygo_swapTask,"ax" .section .text.tinygo_swapTask,"ax"
+11 -3
View File
@@ -8,6 +8,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_amd64_windows.S that relies on // switching between tasks. Also see task_stack_amd64_windows.S that relies on
// the exact layout of this struct. // the exact layout of this struct.
@@ -48,12 +50,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r13 = uintptr(args) r.r13 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_arm.S that relies on the exact // switching between tasks. Also see task_stack_arm.S that relies on the exact
// layout of this struct. // layout of this struct.
@@ -43,12 +45,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r5 = uintptr(args) r.r5 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_arm64.S that relies on the exact // switching between tasks. Also see task_stack_arm64.S that relies on the exact
// layout of this struct. // layout of this struct.
@@ -46,12 +48,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.x20 = uintptr(args) r.x20 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+6
View File
@@ -1,3 +1,9 @@
.section .bss.tinygo_systemStack
.global tinygo_systemStack
.type tinygo_systemStack, %object
tinygo_systemStack:
.short 0
.section .text.tinygo_startTask .section .text.tinygo_startTask
.global tinygo_startTask .global tinygo_startTask
.type tinygo_startTask, %function .type tinygo_startTask, %function
+12 -3
View File
@@ -5,6 +5,9 @@ package task
import "unsafe" import "unsafe"
//go:extern tinygo_systemStack
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_avr.S that relies on the exact // switching between tasks. Also see task_stack_avr.S that relies on the exact
// layout of this struct. // layout of this struct.
@@ -48,12 +51,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r4r5 = uintptr(args) r.r4r5 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
-12
View File
@@ -1,12 +0,0 @@
//go:build scheduler.tasks && baremetal
// +build scheduler.tasks,baremetal
package task
//go:extern _stack_bottom
var _stack_bottom uintptr
func init() {
mainTask.state.canaryPtr = &_stack_bottom
*mainTask.state.canaryPtr = stackCanary
}
+18 -75
View File
@@ -30,10 +30,10 @@ tinygo_startTask:
.cfi_endproc .cfi_endproc
.size tinygo_startTask, .-tinygo_startTask .size tinygo_startTask, .-tinygo_startTask
.section .text.tinygo_switchToMain .section .text.tinygo_switchToScheduler
.global tinygo_switchToMain .global tinygo_switchToScheduler
.type tinygo_switchToMain, %function .type tinygo_switchToScheduler, %function
tinygo_switchToMain: tinygo_switchToScheduler:
.cfi_startproc .cfi_startproc
// r0 = sp *uintptr // r0 = sp *uintptr
@@ -43,9 +43,9 @@ tinygo_switchToMain:
subs r1, #36 subs r1, #36
str r1, [r0] str r1, [r0]
b tinygo_swapTaskInternal b tinygo_swapTask
.cfi_endproc .cfi_endproc
.size tinygo_switchToMain, .-tinygo_switchToMain .size tinygo_switchToScheduler, .-tinygo_switchToScheduler
.section .text.tinygo_switchToTask .section .text.tinygo_switchToTask
.global tinygo_switchToTask .global tinygo_switchToTask
@@ -55,17 +55,17 @@ tinygo_switchToTask:
// r0 = sp uintptr // r0 = sp uintptr
// Currently on the scheduler stack (SP=MSP). We'll have to update the PSP, // Currently on the scheduler stack (SP=MSP). We'll have to update the PSP,
// and then we can invoke swapTaskInternal. // and then we can invoke swapTask.
msr PSP, r0 msr PSP, r0
b.n tinygo_swapTaskInternal b.n tinygo_swapTask
.cfi_endproc .cfi_endproc
.size tinygo_switchToTask, .-tinygo_switchToTask .size tinygo_switchToTask, .-tinygo_switchToTask
.section .text.tinygo_swapTaskInternal .section .text.tinygo_swapTask
.global tinygo_swapTaskInternal .global tinygo_swapTask
.type tinygo_swapTaskInternal, %function .type tinygo_swapTask, %function
tinygo_swapTaskInternal: tinygo_swapTask:
.cfi_startproc .cfi_startproc
// This function stores the current register state to the stack, switches to // This function stores the current register state to the stack, switches to
// the other stack (MSP/PSP), and loads the register state from the other // the other stack (MSP/PSP), and loads the register state from the other
@@ -77,15 +77,15 @@ tinygo_swapTaskInternal:
// used directly. Only very few operations work on them, such as mov. That's // used directly. Only very few operations work on them, such as mov. That's
// why the higher register values are first stored in the temporary register // why the higher register values are first stored in the temporary register
// r3 when loading/storing them. // r3 when loading/storing them.
// It is possible to reduce the swapTaskInternal by two instructions (~2 // It is possible to reduce the swapTask by two instructions (~2 cycles) on
// cycles) on Cortex-M0 by reordering the layout of the pushed registers // Cortex-M0 by reordering the layout of the pushed registers from {r4-r11,
// from {r4-r11, lr} to {r8-r11, r4-r8, lr}. However, that also requires a // lr} to {r8-r11, r4-r8, lr}. However, that also requires a change on the
// change on the Go side (depending on thumb1/thumb2!) and so is not really // Go side (depending on thumb1/thumb2!) and so is not really worth the
// worth the complexity. // complexity.
// Store state to old task. It saves the lr instead of the pc, because that // Store state to old task. It saves the lr instead of the pc, because that
// will be the pc after returning back to the old task (in a different // will be the pc after returning back to the old task (in a different
// invocation of swapTaskInternal). // invocation of swapTask).
#if defined(__thumb2__) #if defined(__thumb2__)
push {r4-r11, lr} push {r4-r11, lr}
.cfi_def_cfa_offset 9*4 .cfi_def_cfa_offset 9*4
@@ -108,63 +108,6 @@ tinygo_swapTaskInternal:
msr CONTROL, r0 // store CONTROL register msr CONTROL, r0 // store CONTROL register
isb // required to flush the pipeline isb // required to flush the pipeline
// Load state from new task and branch to the previous position in the
// program.
#if defined(__thumb2__)
pop {r4-r11, pc}
#else
pop {r4-r7}
.cfi_def_cfa_offset 5*9
pop {r0-r3}
.cfi_def_cfa_offset 1*9
mov r8, r0
mov r9, r1
mov r10, r2
mov r11, r3
pop {pc}
#endif
.cfi_endproc
.size tinygo_swapTaskInternal, .-tinygo_swapTaskInternal
.section .text.tinygo_swapTask
.global tinygo_swapTask
.type tinygo_swapTask, %function
tinygo_swapTask:
.cfi_startproc
// This function is like tinygo_swapTaskInternal but only switches the stack
// pointer without touching the SPSEL bit (to switch between MSP and PSP).
// Therefore, it is used to switch between two tasks that are not the main
// goroutine.
// Store state to old task. It saves the lr instead of the pc, because that
// will be the pc after returning back to the old task (in a different
// invocation of swapTask).
#if defined(__thumb2__)
push {r4-r11, lr}
.cfi_def_cfa_offset 9*4
#else
mov r0, r8
mov r1, r9
mov r2, r10
mov r3, r11
push {r0-r3, lr}
.cfi_def_cfa_offset 5*4
push {r4-r7}
.cfi_def_cfa_offset 9*4
#endif
// Save the current stack pointer in oldStack.
#if defined(__thumb2__)
str sp, [r1]
#else
mov r2, sp
str r2, [r1]
#endif
// Switch to the new stack pointer.
mov sp, r0
// Load state from new task and branch to the previous position in the // Load state from new task and branch to the previous position in the
// program. // program.
#if defined(__thumb2__) #if defined(__thumb2__)
+8 -12
View File
@@ -52,23 +52,19 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r5 = uintptr(args) r.r5 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
// This code is probably more complex than it needs to be. switchToTask(s.sp)
// TODO: simplify this, ideally to a single function call.
if s == &mainTask.state {
switchToMain(&current.state.sp)
} else if current == &mainTask {
switchToTask(s.sp)
} else {
swapTask(s.sp, &current.state.sp)
}
} }
//export tinygo_switchToTask //export tinygo_switchToTask
func switchToTask(uintptr) func switchToTask(uintptr)
//export tinygo_switchToMain //export tinygo_switchToScheduler
func switchToMain(*uintptr) func switchToScheduler(*uintptr)
func (s *state) pause() {
switchToScheduler(&s.sp)
}
// SystemStack returns the system stack pointer. On Cortex-M, it is always // SystemStack returns the system stack pointer. On Cortex-M, it is always
// available. // available.
+11 -3
View File
@@ -16,6 +16,8 @@ import (
"unsafe" "unsafe"
) )
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_esp8266.S that relies on the // switching between tasks. Also see task_stack_esp8266.S that relies on the
// exact layout of this struct. // exact layout of this struct.
@@ -58,12 +60,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.a2 = uintptr(args) r.a2 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+11 -3
View File
@@ -17,6 +17,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see task_stack_esp8266.S that relies on the // switching between tasks. Also see task_stack_esp8266.S that relies on the
// exact layout of this struct. // exact layout of this struct.
@@ -52,12 +54,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.a13 = uintptr(args) r.a13 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe" import "unsafe"
var systemStack uintptr
// calleeSavedRegs is the list of registers that must be saved and restored when // calleeSavedRegs is the list of registers that must be saved and restored when
// switching between tasks. Also see scheduler_riscv.S that relies on the // switching between tasks. Also see scheduler_riscv.S that relies on the
// exact layout of this struct. // exact layout of this struct.
@@ -48,12 +50,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.s1 = uintptr(args) r.s1 = uintptr(args)
} }
func (s *state) switchTo(current *Task) { func (s *state) resume() {
swapTask(s.sp, &current.state.sp) swapTask(s.sp, &systemStack)
}
func (s *state) pause() {
newStack := systemStack
systemStack = 0
swapTask(newStack, &s.sp)
} }
// SystemStack returns the system stack pointer when called from a task stack. // SystemStack returns the system stack pointer when called from a task stack.
// When called from the system stack, it returns 0. // When called from the system stack, it returns 0.
func SystemStack() uintptr { func SystemStack() uintptr {
return mainTask.state.sp return systemStack
} }
+2 -2
View File
@@ -14,7 +14,7 @@ func markStack() {
// Scan the current stack, and all current registers. // Scan the current stack, and all current registers.
scanCurrentStack() scanCurrentStack()
if !task.MainTask() { if !task.OnSystemStack() {
// Mark system stack. // Mark system stack.
markRoots(getSystemStackPointer(), stackTop) markRoots(getSystemStackPointer(), stackTop)
} }
@@ -28,7 +28,7 @@ func scanstack(sp uintptr) {
// Mark current stack. // Mark current stack.
// This function is called by scanCurrentStack, after pushing all registers onto the stack. // This function is called by scanCurrentStack, after pushing all registers onto the stack.
// Callee-saved registers have been pushed onto stack by tinygo_localscan, so this will scan them too. // Callee-saved registers have been pushed onto stack by tinygo_localscan, so this will scan them too.
if task.MainTask() { if task.OnSystemStack() {
// This is the system stack. // This is the system stack.
// Scan all words on the stack. // Scan all words on the stack.
markRoots(sp, stackTop) markRoots(sp, stackTop)
+10
View File
@@ -49,6 +49,16 @@ func putchar(c byte) {
} }
} }
func getchar() byte {
// dummy, TODO
return 0
}
func buffered() int {
// dummy, TODO
return 0
}
//go:linkname now time.now //go:linkname now time.now
func now() (sec int64, nsec int32, mono int64) { func now() (sec int64, nsec int32, mono int64) {
mono = nanotime() mono = nanotime()
+4 -6
View File
@@ -112,7 +112,9 @@ func addSleepTask(t *task.Task, duration timeUnit) {
*q = t *q = t
} }
// Run the scheduler until all tasks have finished.
func scheduler() { func scheduler() {
// Main scheduler loop.
var now timeUnit var now timeUnit
for !schedulerDone { for !schedulerDone {
scheduleLog("") scheduleLog("")
@@ -162,11 +164,7 @@ func scheduler() {
// Run the given task. // Run the given task.
scheduleLogTask(" run:", t) scheduleLogTask(" run:", t)
t.Switch() t.Resume()
if GOARCH != "wasm" {
// Don't return when using Asyncify.
return
}
} }
} }
@@ -183,7 +181,7 @@ func minSched() {
} }
scheduleLogTask(" run:", t) scheduleLogTask(" run:", t)
t.Switch() t.Resume()
} }
scheduleLog("stop nested scheduler") scheduleLog("stop nested scheduler")
} }
@@ -1,5 +1,5 @@
//go:build scheduler.asyncify //go:build !scheduler.none
// +build scheduler.asyncify // +build !scheduler.none
package runtime package runtime
-24
View File
@@ -16,27 +16,3 @@ func getSystemStackPointer() uintptr {
} }
return sp return sp
} }
// Pause the current task for a given time.
//
//go:linkname sleep time.Sleep
func sleep(duration int64) {
if duration <= 0 {
return
}
addSleepTask(task.Current(), nanosecondsToTicks(duration))
task.Pause()
}
// run is called by the program entry point to execute the go program.
// The main goroutine runs on the system stack, so initAll and callMain can be
// called directly.
func run() {
initHeap()
initAll()
callMain()
schedulerDone = true
}
const hasScheduler = true
-1
View File
@@ -27,7 +27,6 @@ SECTIONS
.stack (NOLOAD) : .stack (NOLOAD) :
{ {
. = ALIGN(4); . = ALIGN(4);
_stack_bottom = .;
. += _stack_size; . += _stack_size;
_stack_top = .; _stack_top = .;
} >RAM } >RAM
-1
View File
@@ -19,7 +19,6 @@ SECTIONS
.stack (NOLOAD) : .stack (NOLOAD) :
{ {
_stack_bottom = .;
. += _stack_size; . += _stack_size;
_stack_top = .; _stack_top = .;
} >RAM } >RAM
-1
View File
@@ -41,7 +41,6 @@ SECTIONS
.stack (NOLOAD) : .stack (NOLOAD) :
{ {
. = ALIGN(16); . = ALIGN(16);
_stack_bottom = .;
. += _stack_size; . += _stack_size;
_stack_top = .; _stack_top = .;
} >DRAM } >DRAM
-1
View File
@@ -70,7 +70,6 @@ SECTIONS
.stack (NOLOAD) : .stack (NOLOAD) :
{ {
. = ALIGN(16); . = ALIGN(16);
_stack_bottom = .;
. += _stack_size; . += _stack_size;
_stack_top = .; _stack_top = .;
} >DRAM } >DRAM
-5
View File
@@ -67,11 +67,6 @@ _heap_end = ORIGIN(DRAM) + LENGTH(DRAM);
*/ */
_stack_top = 0x40000000; _stack_top = 0x40000000;
/* This is the stack bottom according to this forum post:
* https://bbs.espressif.com/viewtopic.php?t=8879#p19038
*/
_stack_bottom = 0x3fffeb2c;
/* Functions normally provided by a libc. /* Functions normally provided by a libc.
* Source: * Source:
* https://github.com/espressif/ESP8266_NONOS_SDK/blob/master/ld/eagle.rom.addr.v6.ld * https://github.com/espressif/ESP8266_NONOS_SDK/blob/master/ld/eagle.rom.addr.v6.ld
-1
View File
@@ -57,7 +57,6 @@ SECTIONS
} }
PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM)); PROVIDE(_stack_top = ORIGIN(RAM) + LENGTH(RAM));
_stack_bottom = _stack_top - _stack_size;
/* For the memory allocator. */ /* For the memory allocator. */
_heap_start = _ebss; _heap_start = _ebss;
-1
View File
@@ -59,7 +59,6 @@ SECTIONS
.stack (NOLOAD) : { .stack (NOLOAD) : {
. = ALIGN(8); . = ALIGN(8);
_stack_bottom = .;
. += _stack_size; . += _stack_size;
_stack_top = .; _stack_top = .;
-1
View File
@@ -19,7 +19,6 @@ SECTIONS
.stack (NOLOAD) : .stack (NOLOAD) :
{ {
. = ALIGN(16); . = ALIGN(16);
_stack_bottom = .;
. += _stack_size; . += _stack_size;
_stack_top = .; _stack_top = .;
} >RAM } >RAM
+8
View File
@@ -1,11 +1,19 @@
package main package main
import (
"github.com/tinygo-org/tinygo/testdata/generics/testa"
"github.com/tinygo-org/tinygo/testdata/generics/testb"
)
func main() { func main() {
println("add:", Add(3, 5)) println("add:", Add(3, 5))
println("add:", Add(int8(3), 5)) println("add:", Add(int8(3), 5))
var c C[int] var c C[int]
c.F() // issue 2951 c.F() // issue 2951
testa.Test()
testb.Test()
} }
type Integer interface { type Integer interface {
+4
View File
@@ -1,2 +1,6 @@
add: 8 add: 8
add: 8 add: 8
value: 101
value: 101
value: 501
value: 501
+20
View File
@@ -0,0 +1,20 @@
package testa
import (
"github.com/tinygo-org/tinygo/testdata/generics/value"
)
func Test() {
v := value.New(1)
vm := value.Map(v, Plus100)
vm.Get(callback, callback)
}
func callback(v int) {
println("value:", v)
}
// Plus100 is a `Transform` that adds 100 to `value`.
func Plus100(value int) int {
return value + 100
}
+20
View File
@@ -0,0 +1,20 @@
package testb
import (
"github.com/tinygo-org/tinygo/testdata/generics/value"
)
func Test() {
v := value.New(1)
vm := value.Map(v, Plus500)
vm.Get(callback, callback)
}
func callback(v int) {
println("value:", v)
}
// Plus500 is a `Transform` that adds 500 to `value`.
func Plus500(value int) int {
return value + 500
}
+53
View File
@@ -0,0 +1,53 @@
package value
type (
Value[T any] interface {
Get(Callback[T], Callback[T])
}
Callback[T any] func(T)
Transform[S any, D any] func(S) D
)
func New[T any](v T) Value[T] {
return &value[T]{
v: v,
}
}
type value[T any] struct {
v T
}
func (v *value[T]) Get(fn1, fn2 Callback[T]) {
// For example purposes.
// Normally would be asynchronous callback.
fn1(v.v)
fn2(v.v)
}
func Map[S, D any](v Value[S], tx Transform[S, D]) Value[D] {
return &mapper[S, D]{
v: v,
tx: tx,
}
}
type mapper[S, D any] struct {
v Value[S]
tx Transform[S, D]
}
func (m *mapper[S, D]) Get(fn1, fn2 Callback[D]) {
// two callbacks are passed to generate more than
// one anonymous function symbol name.
m.v.Get(func(v S) {
// anonymous function inside of anonymous function.
func() {
fn1(m.tx(v))
}()
}, func(v S) {
fn2(m.tx(v))
})
}