compiler: refactor goroutine code
Move the code from the compiler.go file to the goroutine.go file, which is a more appropriate place. This keeps all the goroutine related code in one file, to make it easier to find.
Этот коммит содержится в:
родитель
423cae86df
коммит
45cf2a5a1a
2 изменённых файлов: 56 добавлений и 56 удалений
|
@ -1048,52 +1048,8 @@ func (b *builder) createInstruction(instr ssa.Instruction) {
|
||||||
case *ssa.Defer:
|
case *ssa.Defer:
|
||||||
b.createDefer(instr)
|
b.createDefer(instr)
|
||||||
case *ssa.Go:
|
case *ssa.Go:
|
||||||
// Get all function parameters to pass to the goroutine.
|
|
||||||
var params []llvm.Value
|
|
||||||
for _, param := range instr.Call.Args {
|
|
||||||
params = append(params, b.getValue(param))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start a new goroutine.
|
// Start a new goroutine.
|
||||||
if callee := instr.Call.StaticCallee(); callee != nil {
|
b.createGo(instr)
|
||||||
// Static callee is known. This makes it easier to start a new
|
|
||||||
// goroutine.
|
|
||||||
var context llvm.Value
|
|
||||||
switch value := instr.Call.Value.(type) {
|
|
||||||
case *ssa.Function:
|
|
||||||
// Goroutine call is regular function call. No context is necessary.
|
|
||||||
context = llvm.Undef(b.i8ptrType)
|
|
||||||
case *ssa.MakeClosure:
|
|
||||||
// A goroutine call on a func value, but the callee is trivial to find. For
|
|
||||||
// example: immediately applied functions.
|
|
||||||
funcValue := b.getValue(value)
|
|
||||||
context = b.extractFuncContext(funcValue)
|
|
||||||
default:
|
|
||||||
panic("StaticCallee returned an unexpected value")
|
|
||||||
}
|
|
||||||
params = append(params, context) // context parameter
|
|
||||||
b.createGoInstruction(b.getFunction(callee), params, "", callee.Pos())
|
|
||||||
} else if !instr.Call.IsInvoke() {
|
|
||||||
// This is a function pointer.
|
|
||||||
// At the moment, two extra params are passed to the newly started
|
|
||||||
// goroutine:
|
|
||||||
// * The function context, for closures.
|
|
||||||
// * The function pointer (for tasks).
|
|
||||||
funcPtr, context := b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
|
|
||||||
params = append(params, context) // context parameter
|
|
||||||
switch b.Scheduler {
|
|
||||||
case "none", "coroutines":
|
|
||||||
// There are no additional parameters needed for the goroutine start operation.
|
|
||||||
case "tasks":
|
|
||||||
// Add the function pointer as a parameter to start the goroutine.
|
|
||||||
params = append(params, funcPtr)
|
|
||||||
default:
|
|
||||||
panic("unknown scheduler type")
|
|
||||||
}
|
|
||||||
b.createGoInstruction(funcPtr, params, b.fn.RelString(nil), instr.Pos())
|
|
||||||
} else {
|
|
||||||
b.addError(instr.Pos(), "todo: go on interface call")
|
|
||||||
}
|
|
||||||
case *ssa.If:
|
case *ssa.If:
|
||||||
cond := b.getValue(instr.Cond)
|
cond := b.getValue(instr.Cond)
|
||||||
block := instr.Block()
|
block := instr.Block()
|
||||||
|
|
|
@ -5,25 +5,70 @@ package compiler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"go/token"
|
"go/token"
|
||||||
|
"go/types"
|
||||||
|
|
||||||
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
"github.com/tinygo-org/tinygo/compiler/llvmutil"
|
||||||
"golang.org/x/tools/go/ssa"
|
"golang.org/x/tools/go/ssa"
|
||||||
"tinygo.org/x/go-llvm"
|
"tinygo.org/x/go-llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
// createGoInstruction starts a new goroutine with the provided function pointer
|
// createGo emits code to start a new goroutine.
|
||||||
// and parameters.
|
func (b *builder) createGo(instr *ssa.Go) {
|
||||||
// In general, you should pass all regular parameters plus the context parameter.
|
// Get all function parameters to pass to the goroutine.
|
||||||
// There is one exception: the task-based scheduler needs to have the function
|
var params []llvm.Value
|
||||||
// pointer passed in as a parameter too in addition to the context.
|
for _, param := range instr.Call.Args {
|
||||||
//
|
params = append(params, b.getValue(param))
|
||||||
// Because a go statement doesn't return anything, return undef.
|
}
|
||||||
func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, prefix string, pos token.Pos) llvm.Value {
|
|
||||||
|
var prefix string
|
||||||
|
var funcPtr llvm.Value
|
||||||
|
if callee := instr.Call.StaticCallee(); callee != nil {
|
||||||
|
// Static callee is known. This makes it easier to start a new
|
||||||
|
// goroutine.
|
||||||
|
var context llvm.Value
|
||||||
|
switch value := instr.Call.Value.(type) {
|
||||||
|
case *ssa.Function:
|
||||||
|
// Goroutine call is regular function call. No context is necessary.
|
||||||
|
context = llvm.Undef(b.i8ptrType)
|
||||||
|
case *ssa.MakeClosure:
|
||||||
|
// A goroutine call on a func value, but the callee is trivial to find. For
|
||||||
|
// example: immediately applied functions.
|
||||||
|
funcValue := b.getValue(value)
|
||||||
|
context = b.extractFuncContext(funcValue)
|
||||||
|
default:
|
||||||
|
panic("StaticCallee returned an unexpected value")
|
||||||
|
}
|
||||||
|
params = append(params, context) // context parameter
|
||||||
|
funcPtr = b.getFunction(callee)
|
||||||
|
} else if !instr.Call.IsInvoke() {
|
||||||
|
// This is a function pointer.
|
||||||
|
// At the moment, two extra params are passed to the newly started
|
||||||
|
// goroutine:
|
||||||
|
// * The function context, for closures.
|
||||||
|
// * The function pointer (for tasks).
|
||||||
|
var context llvm.Value
|
||||||
|
funcPtr, context = b.decodeFuncValue(b.getValue(instr.Call.Value), instr.Call.Value.Type().Underlying().(*types.Signature))
|
||||||
|
params = append(params, context) // context parameter
|
||||||
|
switch b.Scheduler {
|
||||||
|
case "none", "coroutines":
|
||||||
|
// There are no additional parameters needed for the goroutine start operation.
|
||||||
|
case "tasks":
|
||||||
|
// Add the function pointer as a parameter to start the goroutine.
|
||||||
|
params = append(params, funcPtr)
|
||||||
|
default:
|
||||||
|
panic("unknown scheduler type")
|
||||||
|
}
|
||||||
|
prefix = b.fn.RelString(nil)
|
||||||
|
} else {
|
||||||
|
b.addError(instr.Pos(), "todo: go on interface call")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
paramBundle := b.emitPointerPack(params)
|
paramBundle := b.emitPointerPack(params)
|
||||||
var callee, stackSize llvm.Value
|
var callee, stackSize llvm.Value
|
||||||
switch b.Scheduler {
|
switch b.Scheduler {
|
||||||
case "none", "tasks":
|
case "none", "tasks":
|
||||||
callee = b.createGoroutineStartWrapper(funcPtr, prefix, pos)
|
callee = b.createGoroutineStartWrapper(funcPtr, prefix, instr.Pos())
|
||||||
if b.AutomaticStackSize {
|
if b.AutomaticStackSize {
|
||||||
// The stack size is not known until after linking. Call a dummy
|
// The stack size is not known until after linking. Call a dummy
|
||||||
// function that will be replaced with a load from a special ELF
|
// function that will be replaced with a load from a special ELF
|
||||||
|
@ -35,7 +80,7 @@ func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, p
|
||||||
// The stack size is fixed at compile time. By emitting it here as a
|
// The stack size is fixed at compile time. By emitting it here as a
|
||||||
// constant, it can be optimized.
|
// constant, it can be optimized.
|
||||||
if b.Scheduler == "tasks" && b.DefaultStackSize == 0 {
|
if b.Scheduler == "tasks" && b.DefaultStackSize == 0 {
|
||||||
b.addError(pos, "default stack size for goroutines is not set")
|
b.addError(instr.Pos(), "default stack size for goroutines is not set")
|
||||||
}
|
}
|
||||||
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
stackSize = llvm.ConstInt(b.uintptrType, b.DefaultStackSize, false)
|
||||||
}
|
}
|
||||||
|
@ -49,7 +94,6 @@ func (b *builder) createGoInstruction(funcPtr llvm.Value, params []llvm.Value, p
|
||||||
}
|
}
|
||||||
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
|
start := b.getFunction(b.program.ImportedPackage("internal/task").Members["start"].(*ssa.Function))
|
||||||
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
|
b.createCall(start, []llvm.Value{callee, paramBundle, stackSize, llvm.Undef(b.i8ptrType), llvm.ConstPointerNull(b.i8ptrType)}, "")
|
||||||
return llvm.Undef(funcPtr.Type().ElementType().ReturnType())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// createGoroutineStartWrapper creates a wrapper for the task-based
|
// createGoroutineStartWrapper creates a wrapper for the task-based
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче