Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/internal/task/task_asyncify.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ func (*stackState) unwind()
func (t *Task) Resume() {
// The current task must be saved and restored because this can nest on WASM with JS.
prevTask := currentTask
if prevTask == nil {
// Save the system stack pointer.
saveStackPointer()
}
t.gcData.swap()
currentTask = t
if !t.state.launched {
Expand All @@ -123,6 +127,9 @@ func (t *Task) Resume() {
}
}

//go:linkname saveStackPointer runtime.saveStackPointer
func saveStackPointer()

//export tinygo_rewind
func (*state) rewind()

Expand Down
8 changes: 8 additions & 0 deletions src/runtime/arch_tinygowasm.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ func align(ptr uintptr) uintptr {
//export tinygo_getCurrentStackPointer
func getCurrentStackPointer() uintptr

// savedStackPointer is used to save the system stack pointer while in a goroutine.
var savedStackPointer uintptr

// saveStackPointer is called by internal/task.state.Resume() to save the stack pointer before entering a goroutine from the system stack.
func saveStackPointer() {
savedStackPointer = getCurrentStackPointer()
}

// growHeap tries to grow the heap size. It returns true if it succeeds, false
// otherwise.
func growHeap() bool {
Expand Down
21 changes: 10 additions & 11 deletions src/runtime/gc_stack_portable.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,6 @@ type stackChainObject struct {
// - The system stack (aka startup stack) is not heap allocated, so even
// though it may be referenced it will not be scanned by default.
//
// Therefore, we only need to scan the system stack.
// It is relatively easy to scan the system stack while we're on it: we can
// simply read __stack_pointer and __global_base and scan the area in between.
// Unfortunately, it's hard to get the system stack pointer while we're on a
// goroutine stack. But when we're on a goroutine stack, the system stack is in
// the scheduler which means there shouldn't be anything on the system stack
// anyway.
// ...I hope this assumption holds, otherwise we will need to store the system
// stack in a global or something.
//
// The compiler also inserts code to store all globals in a chain via
// stackChainStart. Luckily we don't need to scan these, as these globals are
// stored on the goroutine stack and are therefore already getting scanned.
Expand All @@ -50,9 +40,18 @@ func markStack() {
// live.
volatile.LoadUint32((*uint32)(unsafe.Pointer(&stackChainStart)))

// Scan the system stack.
var sysSP uintptr
if task.OnSystemStack() {
markRoots(getCurrentStackPointer(), stackTop)
// We are on the system stack.
// Use the current stack pointer.
sysSP = getCurrentStackPointer()
} else {
// We are in a goroutine.
// Use the saved stack pointer.
sysSP = savedStackPointer
}
markRoots(sysSP, stackTop)
}

// trackPointer is a stub function call inserted by the compiler during IR
Expand Down
Loading