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
---
+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
// that way. This can be measured by measuing the stack size of
// tinygo_startTask.
var baseStackSize uint64
var baseStackSizeType stacksize.SizeType
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()
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()
sizes := make(map[string]functionStackSize)
@@ -1308,11 +1303,6 @@ func modifyStackSizes(executable string, stackSizeLoads []string, stackSizes map
if err != nil {
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) {
// 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)
if section == nil {
return nil, elf.FileHeader{}, nil
return nil, elf.FileHeader{}, fmt.Errorf("could not find %s section", sectionName)
}
data, err := section.Data()
+10 -1
View File
@@ -1039,9 +1039,17 @@ func (b *builder) createFunctionStart() {
b.addError(b.fn.Pos(), errValue)
return
}
b.addStandardDefinedAttributes(b.llvmFn)
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)
}
if b.info.section != "" {
@@ -1265,6 +1273,7 @@ func (b *builder) createFunction() {
// Create anonymous functions (closures etc.).
for _, sub := range b.fn.AnonFuncs {
b := newBuilder(b.compilerContext, b.Builder, sub)
b.llvmFn.SetLinkage(llvm.InternalLinkage)
b.createFunction()
}
}
+1 -1
View File
@@ -196,7 +196,7 @@ entry:
}
; 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:
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
; 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:
call void @runtime.printint32(i32 3, i8* undef) #3
ret void
@@ -246,14 +246,14 @@ rundefers.end9: ; preds = %rundefers.loophead1
}
; 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:
call void @runtime.printint32(i32 3, i8* undef) #3
ret void
}
; 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:
call void @runtime.printint32(i32 5, i8* undef) #3
ret void
+2 -2
View File
@@ -51,7 +51,7 @@ entry:
}
; 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:
ret void
}
@@ -84,7 +84,7 @@ entry:
}
; 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:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
+2 -2
View File
@@ -53,7 +53,7 @@ entry:
}
; 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:
ret void
}
@@ -90,7 +90,7 @@ entry:
}
; 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:
%unpack.ptr = bitcast i8* %context to i32*
store i32 7, i32* %unpack.ptr, align 4
+1 -1
View File
@@ -12,7 +12,7 @@ import (
// Version of TinyGo.
// Update this value before release of new version of software.
const Version = "0.25.0-dev"
const Version = "0.25.0"
var (
// This variable is set at build time using -ldflags parameters.
+8 -2
View File
@@ -99,9 +99,9 @@ func Pause() {
//export tinygo_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.
func (t *Task) Switch() {
func (t *Task) Resume() {
// The current task must be saved and restored because this can nest on WASM with JS.
prevTask := currentTask
t.gcData.swap()
@@ -121,3 +121,9 @@ func (t *Task) Switch() {
//export tinygo_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{}
func (t *Task) Switch() {
func (t *Task) Resume() {
runtimePanic("scheduler is disabled")
}
// MainTask returns whether the caller is running in the main goroutine.
func MainTask() bool {
// OnSystemStack returns whether the caller is running on the system stack.
func OnSystemStack() bool {
// This scheduler does not do any stack switching.
return true
}
+12 -23
View File
@@ -27,12 +27,8 @@ type state struct {
canaryPtr *uintptr
}
// The task struct for the main goroutine.
var mainTask Task
// currentTask is the current running task. The default value is the main
// goroutine.
var currentTask = &mainTask
// currentTask is the current running task, or nil if currently in the scheduler.
var currentTask *Task
// Current returns the current active task.
func Current() *Task {
@@ -40,36 +36,29 @@ func Current() *Task {
}
// 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() {
// Check whether the canary (the lowest address of the stack) is still
// 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")
}
scheduler()
currentTask.state.pause()
}
//go:linkname scheduler runtime.scheduler
func scheduler()
//export tinygo_pause
func 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.
func (t *Task) Switch() {
current := currentTask
if current == t {
// Nothing to switch to: we're already in this task.
return
}
func (t *Task) Resume() {
currentTask = t
t.gcData.swap()
t.state.switchTo(current)
t.state.resume()
t.gcData.swap()
currentTask = nil
}
// 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)
}
// MainTask returns whether the caller is running in the main goroutine.
func MainTask() bool {
// 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 currentTask == &mainTask
return Current() == nil
}
+5 -2
View File
@@ -20,8 +20,11 @@ tinygo_startTask:
// Branch to the "goroutine start" function.
calll *%ebx
// After return, exit this goroutine.
calll tinygo_pause
// Rebalance the stack (to undo the above push).
addl $4, %esp
// After return, exit this goroutine. This is a tail call.
jmp tinygo_pause
.cfi_endproc
.global tinygo_swapTask
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// layout of this struct.
@@ -44,12 +46,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.esi = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
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.
callq *%r12
// After return, exit this goroutine.
// After return, exit this goroutine. This is a tail call.
#ifdef __MACH__
callq _tinygo_pause
jmp _tinygo_pause
#else
callq tinygo_pause
jmp tinygo_pause
#endif
.cfi_endproc
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// layout of this struct.
@@ -43,12 +45,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r13 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
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.
callq *%r12
// After return, exit this goroutine.
callq tinygo_pause
// After return, exit this goroutine. This is a tail call.
jmp tinygo_pause
.global tinygo_swapTask
.section .text.tinygo_swapTask,"ax"
+11 -3
View File
@@ -8,6 +8,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// 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)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
func SystemStack() uintptr {
return mainTask.state.sp
return systemStack
}
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// layout of this struct.
@@ -43,12 +45,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r5 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
func SystemStack() uintptr {
return mainTask.state.sp
return systemStack
}
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// layout of this struct.
@@ -46,12 +48,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.x20 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
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
.global tinygo_startTask
.type tinygo_startTask, %function
+12 -3
View File
@@ -5,6 +5,9 @@ package task
import "unsafe"
//go:extern tinygo_systemStack
var systemStack uintptr
// 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
// layout of this struct.
@@ -48,12 +51,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.r4r5 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
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
.size tinygo_startTask, .-tinygo_startTask
.section .text.tinygo_switchToMain
.global tinygo_switchToMain
.type tinygo_switchToMain, %function
tinygo_switchToMain:
.section .text.tinygo_switchToScheduler
.global tinygo_switchToScheduler
.type tinygo_switchToScheduler, %function
tinygo_switchToScheduler:
.cfi_startproc
// r0 = sp *uintptr
@@ -43,9 +43,9 @@ tinygo_switchToMain:
subs r1, #36
str r1, [r0]
b tinygo_swapTaskInternal
b tinygo_swapTask
.cfi_endproc
.size tinygo_switchToMain, .-tinygo_switchToMain
.size tinygo_switchToScheduler, .-tinygo_switchToScheduler
.section .text.tinygo_switchToTask
.global tinygo_switchToTask
@@ -55,17 +55,17 @@ tinygo_switchToTask:
// r0 = sp uintptr
// 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
b.n tinygo_swapTaskInternal
b.n tinygo_swapTask
.cfi_endproc
.size tinygo_switchToTask, .-tinygo_switchToTask
.section .text.tinygo_swapTaskInternal
.global tinygo_swapTaskInternal
.type tinygo_swapTaskInternal, %function
tinygo_swapTaskInternal:
.section .text.tinygo_swapTask
.global tinygo_swapTask
.type tinygo_swapTask, %function
tinygo_swapTask:
.cfi_startproc
// 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
@@ -77,15 +77,15 @@ tinygo_swapTaskInternal:
// 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
// r3 when loading/storing them.
// It is possible to reduce the swapTaskInternal by two instructions (~2
// cycles) on Cortex-M0 by reordering the layout of the pushed registers
// from {r4-r11, lr} to {r8-r11, r4-r8, lr}. However, that also requires a
// change on the Go side (depending on thumb1/thumb2!) and so is not really
// worth the complexity.
// It is possible to reduce the swapTask by two instructions (~2 cycles) on
// Cortex-M0 by reordering the layout of the pushed registers from {r4-r11,
// lr} to {r8-r11, r4-r8, lr}. However, that also requires a change on the
// Go side (depending on thumb1/thumb2!) and so is not really worth the
// complexity.
// 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 swapTaskInternal).
// invocation of swapTask).
#if defined(__thumb2__)
push {r4-r11, lr}
.cfi_def_cfa_offset 9*4
@@ -108,63 +108,6 @@ tinygo_swapTaskInternal:
msr CONTROL, r0 // store CONTROL register
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
// program.
#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)
}
func (s *state) switchTo(current *Task) {
// This code is probably more complex than it needs to be.
// 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)
}
func (s *state) resume() {
switchToTask(s.sp)
}
//export tinygo_switchToTask
func switchToTask(uintptr)
//export tinygo_switchToMain
func switchToMain(*uintptr)
//export tinygo_switchToScheduler
func switchToScheduler(*uintptr)
func (s *state) pause() {
switchToScheduler(&s.sp)
}
// SystemStack returns the system stack pointer. On Cortex-M, it is always
// available.
+11 -3
View File
@@ -16,6 +16,8 @@ import (
"unsafe"
)
var systemStack uintptr
// 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
// exact layout of this struct.
@@ -58,12 +60,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.a2 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
func SystemStack() uintptr {
return mainTask.state.sp
return systemStack
}
+11 -3
View File
@@ -17,6 +17,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// exact layout of this struct.
@@ -52,12 +54,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.a13 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
func SystemStack() uintptr {
return mainTask.state.sp
return systemStack
}
+11 -3
View File
@@ -5,6 +5,8 @@ package task
import "unsafe"
var systemStack uintptr
// 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
// exact layout of this struct.
@@ -48,12 +50,18 @@ func (s *state) archInit(r *calleeSavedRegs, fn uintptr, args unsafe.Pointer) {
r.s1 = uintptr(args)
}
func (s *state) switchTo(current *Task) {
swapTask(s.sp, &current.state.sp)
func (s *state) resume() {
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.
// When called from the system stack, it returns 0.
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.
scanCurrentStack()
if !task.MainTask() {
if !task.OnSystemStack() {
// Mark system stack.
markRoots(getSystemStackPointer(), stackTop)
}
@@ -28,7 +28,7 @@ func scanstack(sp uintptr) {
// Mark current 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.
if task.MainTask() {
if task.OnSystemStack() {
// This is the system stack.
// Scan all words on the stack.
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
func now() (sec int64, nsec int32, mono int64) {
mono = nanotime()
+4 -6
View File
@@ -112,7 +112,9 @@ func addSleepTask(t *task.Task, duration timeUnit) {
*q = t
}
// Run the scheduler until all tasks have finished.
func scheduler() {
// Main scheduler loop.
var now timeUnit
for !schedulerDone {
scheduleLog("")
@@ -162,11 +164,7 @@ func scheduler() {
// Run the given task.
scheduleLogTask(" run:", t)
t.Switch()
if GOARCH != "wasm" {
// Don't return when using Asyncify.
return
}
t.Resume()
}
}
@@ -183,7 +181,7 @@ func minSched() {
}
scheduleLogTask(" run:", t)
t.Switch()
t.Resume()
}
scheduleLog("stop nested scheduler")
}
@@ -1,5 +1,5 @@
//go:build scheduler.asyncify
// +build scheduler.asyncify
//go:build !scheduler.none
// +build !scheduler.none
package runtime
-24
View File
@@ -16,27 +16,3 @@ func getSystemStackPointer() uintptr {
}
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) :
{
. = ALIGN(4);
_stack_bottom = .;
. += _stack_size;
_stack_top = .;
} >RAM
-1
View File
@@ -19,7 +19,6 @@ SECTIONS
.stack (NOLOAD) :
{
_stack_bottom = .;
. += _stack_size;
_stack_top = .;
} >RAM
-1
View File
@@ -41,7 +41,6 @@ SECTIONS
.stack (NOLOAD) :
{
. = ALIGN(16);
_stack_bottom = .;
. += _stack_size;
_stack_top = .;
} >DRAM
-1
View File
@@ -70,7 +70,6 @@ SECTIONS
.stack (NOLOAD) :
{
. = ALIGN(16);
_stack_bottom = .;
. += _stack_size;
_stack_top = .;
} >DRAM
-5
View File
@@ -67,11 +67,6 @@ _heap_end = ORIGIN(DRAM) + LENGTH(DRAM);
*/
_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.
* Source:
* 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));
_stack_bottom = _stack_top - _stack_size;
/* For the memory allocator. */
_heap_start = _ebss;
-1
View File
@@ -59,7 +59,6 @@ SECTIONS
.stack (NOLOAD) : {
. = ALIGN(8);
_stack_bottom = .;
. += _stack_size;
_stack_top = .;
-1
View File
@@ -19,7 +19,6 @@ SECTIONS
.stack (NOLOAD) :
{
. = ALIGN(16);
_stack_bottom = .;
. += _stack_size;
_stack_top = .;
} >RAM
+8
View File
@@ -1,11 +1,19 @@
package main
import (
"github.com/tinygo-org/tinygo/testdata/generics/testa"
"github.com/tinygo-org/tinygo/testdata/generics/testb"
)
func main() {
println("add:", Add(3, 5))
println("add:", Add(int8(3), 5))
var c C[int]
c.F() // issue 2951
testa.Test()
testb.Test()
}
type Integer interface {
+4
View File
@@ -1,2 +1,6 @@
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))
})
}