compiler: add support for async interface calls
Этот коммит содержится в:
родитель
81199da3f1
коммит
98eee7c22a
6 изменённых файлов: 62 добавлений и 15 удалений
|
@ -461,6 +461,9 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
|
|||
paramTypes := append([]llvm.Type{c.i8ptrType}, fnType.ParamTypes()[len(expandedReceiverType):]...)
|
||||
wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
|
||||
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
|
||||
if f.LLVMFn.LastParam().Name() == "parentHandle" {
|
||||
wrapper.LastParam().SetName("parentHandle")
|
||||
}
|
||||
c.interfaceInvokeWrappers = append(c.interfaceInvokeWrappers, interfaceInvokeWrapper{
|
||||
fn: f,
|
||||
wrapper: wrapper,
|
||||
|
|
40
testdata/interface.go
предоставленный
40
testdata/interface.go
предоставленный
|
@ -1,5 +1,7 @@
|
|||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
thing := &Thing{"foo"}
|
||||
println("thing:", thing.String())
|
||||
|
@ -87,6 +89,14 @@ func main() {
|
|||
println("test", i, "of interfaceEqualTests failed")
|
||||
}
|
||||
}
|
||||
|
||||
// test interface blocking
|
||||
blockDynamic(NonBlocker{})
|
||||
println("non-blocking call on sometimes-blocking interface")
|
||||
blockDynamic(SleepBlocker(time.Millisecond))
|
||||
println("slept 1ms")
|
||||
blockStatic(SleepBlocker(time.Millisecond))
|
||||
println("slept 1ms")
|
||||
}
|
||||
|
||||
func printItf(val interface{}) {
|
||||
|
@ -134,6 +144,14 @@ func nestedSwitch(verb rune, arg interface{}) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func blockDynamic(blocker DynamicBlocker) {
|
||||
blocker.Block()
|
||||
}
|
||||
|
||||
func blockStatic(blocker StaticBlocker) {
|
||||
blocker.Sleep()
|
||||
}
|
||||
|
||||
type Thing struct {
|
||||
name string
|
||||
}
|
||||
|
@ -211,3 +229,25 @@ type Unmatched interface {
|
|||
type linkedList struct {
|
||||
addr *linkedList
|
||||
}
|
||||
|
||||
type DynamicBlocker interface {
|
||||
Block()
|
||||
}
|
||||
|
||||
type NonBlocker struct{}
|
||||
|
||||
func (b NonBlocker) Block() {}
|
||||
|
||||
type SleepBlocker time.Duration
|
||||
|
||||
func (s SleepBlocker) Block() {
|
||||
time.Sleep(time.Duration(s))
|
||||
}
|
||||
|
||||
func (s SleepBlocker) Sleep() {
|
||||
s.Block()
|
||||
}
|
||||
|
||||
type StaticBlocker interface {
|
||||
Sleep()
|
||||
}
|
||||
|
|
3
testdata/interface.txt
предоставленный
3
testdata/interface.txt
предоставленный
|
@ -19,3 +19,6 @@ SmallPair.Print: 3 5
|
|||
Stringer.String(): foo
|
||||
Stringer.(*Thing).String(): foo
|
||||
nested switch: true
|
||||
non-blocking call on sometimes-blocking interface
|
||||
slept 1ms
|
||||
slept 1ms
|
||||
|
|
|
@ -336,7 +336,7 @@ func (p *lowerInterfacesPass) run() {
|
|||
|
||||
// Replace the old lookup/inttoptr/call with the new call.
|
||||
p.builder.SetInsertPointBefore(call)
|
||||
retval := p.builder.CreateCall(redirector, params, "")
|
||||
retval := p.builder.CreateCall(redirector, append(params, llvm.ConstNull(llvm.PointerType(p.ctx.Int8Type(), 0))), "")
|
||||
if retval.Type().TypeKind() != llvm.VoidTypeKind {
|
||||
call.ReplaceAllUsesWith(retval)
|
||||
}
|
||||
|
@ -613,9 +613,10 @@ func (p *lowerInterfacesPass) getInterfaceMethodFunc(itf *interfaceInfo, signatu
|
|||
// Construct the function name, which is of the form:
|
||||
// (main.Stringer).String
|
||||
fnName := "(" + itf.id() + ")." + signature.methodName()
|
||||
fnType := llvm.FunctionType(returnType, params, false)
|
||||
fnType := llvm.FunctionType(returnType, append(params, llvm.PointerType(p.ctx.Int8Type(), 0)), false)
|
||||
fn := llvm.AddFunction(p.mod, fnName, fnType)
|
||||
fn.LastParam().SetName("actualType")
|
||||
llvm.PrevParam(fn.LastParam()).SetName("actualType")
|
||||
fn.LastParam().SetName("parentHandle")
|
||||
itf.methodFuncs[signature] = fn
|
||||
return fn
|
||||
}
|
||||
|
@ -644,13 +645,13 @@ func (p *lowerInterfacesPass) createInterfaceMethodFunc(itf *interfaceInfo, sign
|
|||
|
||||
// Create type switch in entry block.
|
||||
p.builder.SetInsertPointAtEnd(entry)
|
||||
actualType := fn.LastParam()
|
||||
actualType := llvm.PrevParam(fn.LastParam())
|
||||
sw := p.builder.CreateSwitch(actualType, defaultBlock, len(itf.types))
|
||||
|
||||
// Collect the params that will be passed to the functions to call.
|
||||
// These params exclude the receiver (which may actually consist of multiple
|
||||
// parts).
|
||||
params := make([]llvm.Value, fn.ParamsCount()-2)
|
||||
params := make([]llvm.Value, fn.ParamsCount()-3)
|
||||
for i := range params {
|
||||
params[i] = fn.Param(i + 1)
|
||||
}
|
||||
|
|
12
transform/testdata/interface.ll
предоставленный
12
transform/testdata/interface.ll
предоставленный
|
@ -13,7 +13,7 @@ target triple = "armv7m-none-eabi"
|
|||
@"Unmatched$interface" = private constant [1 x i8*] [i8* @"func NeverImplementedMethod()"]
|
||||
@"func Double() int" = external constant i8
|
||||
@"Doubler$interface" = private constant [1 x i8*] [i8* @"func Double() int"]
|
||||
@"Number$methodset" = private constant [1 x %runtime.interfaceMethodInfo] [%runtime.interfaceMethodInfo { i8* @"func Double() int", i32 ptrtoint (i32 (i8*)* @"(Number).Double$invoke" to i32) }]
|
||||
@"Number$methodset" = private constant [1 x %runtime.interfaceMethodInfo] [%runtime.interfaceMethodInfo { i8* @"func Double() int", i32 ptrtoint (i32 (i8*, i8*)* @"(Number).Double$invoke" to i32) }]
|
||||
@"reflect/types.type:named:Number" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0 }
|
||||
@"typeInInterface:reflect/types.type:named:Number" = private constant %runtime.typeInInterface { %runtime.typecodeID* @"reflect/types.type:named:Number", %runtime.interfaceMethodInfo* getelementptr inbounds ([1 x %runtime.interfaceMethodInfo], [1 x %runtime.interfaceMethodInfo]* @"Number$methodset", i32 0, i32 0) }
|
||||
|
||||
|
@ -49,8 +49,8 @@ typeswitch.notUnmatched:
|
|||
|
||||
typeswitch.Doubler:
|
||||
%doubler.func = call i32 @runtime.interfaceMethod(i32 %typecode, i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @"Doubler$interface", i32 0, i32 0), i8* nonnull @"func Double() int")
|
||||
%doubler.func.cast = inttoptr i32 %doubler.func to i32 (i8*)*
|
||||
%doubler.result = call i32 %doubler.func.cast(i8* %value)
|
||||
%doubler.func.cast = inttoptr i32 %doubler.func to i32 (i8*, i8*)*
|
||||
%doubler.result = call i32 %doubler.func.cast(i8* %value, i8* null)
|
||||
call void @runtime.printint32(i32 %doubler.result)
|
||||
ret void
|
||||
|
||||
|
@ -68,13 +68,13 @@ typeswitch.notByte:
|
|||
ret void
|
||||
}
|
||||
|
||||
define i32 @"(Number).Double"(i32 %receiver) {
|
||||
define i32 @"(Number).Double"(i32 %receiver, i8* %parentHandle) {
|
||||
%ret = mul i32 %receiver, 2
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @"(Number).Double$invoke"(i8* %receiverPtr) {
|
||||
define i32 @"(Number).Double$invoke"(i8* %receiverPtr, i8* %parentHandle) {
|
||||
%receiver = ptrtoint i8* %receiverPtr to i32
|
||||
%ret = call i32 @"(Number).Double"(i32 %receiver)
|
||||
%ret = call i32 @"(Number).Double"(i32 %receiver, i8* null)
|
||||
ret i32 %ret
|
||||
}
|
||||
|
|
8
transform/testdata/interface.out.ll
предоставленный
8
transform/testdata/interface.out.ll
предоставленный
|
@ -47,7 +47,7 @@ typeswitch.notUnmatched:
|
|||
br i1 %typeassert.ok, label %typeswitch.Doubler, label %typeswitch.notDoubler
|
||||
|
||||
typeswitch.Doubler:
|
||||
%doubler.result = call i32 @"(Number).Double$invoke"(i8* %value)
|
||||
%doubler.result = call i32 @"(Number).Double$invoke"(i8* %value, i8* null)
|
||||
call void @runtime.printint32(i32 %doubler.result)
|
||||
ret void
|
||||
|
||||
|
@ -65,14 +65,14 @@ typeswitch.notByte:
|
|||
ret void
|
||||
}
|
||||
|
||||
define i32 @"(Number).Double"(i32 %receiver) {
|
||||
define i32 @"(Number).Double"(i32 %receiver, i8* %parentHandle) {
|
||||
%ret = mul i32 %receiver, 2
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
define i32 @"(Number).Double$invoke"(i8* %receiverPtr) {
|
||||
define i32 @"(Number).Double$invoke"(i8* %receiverPtr, i8* %parentHandle) {
|
||||
%receiver = ptrtoint i8* %receiverPtr to i32
|
||||
%ret = call i32 @"(Number).Double"(i32 %receiver)
|
||||
%ret = call i32 @"(Number).Double"(i32 %receiver, i8* null)
|
||||
ret i32 %ret
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче