Skip to content

Commit 98eee7c

Browse files
niaowaykevl
authored andcommitted
compiler: add support for async interface calls
1 parent 81199da commit 98eee7c

File tree

6 files changed

+62
-15
lines changed

6 files changed

+62
-15
lines changed

compiler/interface.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,9 @@ func (c *Compiler) getInterfaceInvokeWrapper(f *ir.Function) llvm.Value {
461461
paramTypes := append([]llvm.Type{c.i8ptrType}, fnType.ParamTypes()[len(expandedReceiverType):]...)
462462
wrapFnType := llvm.FunctionType(fnType.ReturnType(), paramTypes, false)
463463
wrapper = llvm.AddFunction(c.mod, wrapperName, wrapFnType)
464+
if f.LLVMFn.LastParam().Name() == "parentHandle" {
465+
wrapper.LastParam().SetName("parentHandle")
466+
}
464467
c.interfaceInvokeWrappers = append(c.interfaceInvokeWrappers, interfaceInvokeWrapper{
465468
fn: f,
466469
wrapper: wrapper,

testdata/interface.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package main
22

3+
import "time"
4+
35
func main() {
46
thing := &Thing{"foo"}
57
println("thing:", thing.String())
@@ -87,6 +89,14 @@ func main() {
8789
println("test", i, "of interfaceEqualTests failed")
8890
}
8991
}
92+
93+
// test interface blocking
94+
blockDynamic(NonBlocker{})
95+
println("non-blocking call on sometimes-blocking interface")
96+
blockDynamic(SleepBlocker(time.Millisecond))
97+
println("slept 1ms")
98+
blockStatic(SleepBlocker(time.Millisecond))
99+
println("slept 1ms")
90100
}
91101

92102
func printItf(val interface{}) {
@@ -134,6 +144,14 @@ func nestedSwitch(verb rune, arg interface{}) bool {
134144
return false
135145
}
136146

147+
func blockDynamic(blocker DynamicBlocker) {
148+
blocker.Block()
149+
}
150+
151+
func blockStatic(blocker StaticBlocker) {
152+
blocker.Sleep()
153+
}
154+
137155
type Thing struct {
138156
name string
139157
}
@@ -211,3 +229,25 @@ type Unmatched interface {
211229
type linkedList struct {
212230
addr *linkedList
213231
}
232+
233+
type DynamicBlocker interface {
234+
Block()
235+
}
236+
237+
type NonBlocker struct{}
238+
239+
func (b NonBlocker) Block() {}
240+
241+
type SleepBlocker time.Duration
242+
243+
func (s SleepBlocker) Block() {
244+
time.Sleep(time.Duration(s))
245+
}
246+
247+
func (s SleepBlocker) Sleep() {
248+
s.Block()
249+
}
250+
251+
type StaticBlocker interface {
252+
Sleep()
253+
}

testdata/interface.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ SmallPair.Print: 3 5
1919
Stringer.String(): foo
2020
Stringer.(*Thing).String(): foo
2121
nested switch: true
22+
non-blocking call on sometimes-blocking interface
23+
slept 1ms
24+
slept 1ms

transform/interface-lowering.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,7 @@ func (p *lowerInterfacesPass) run() {
336336

337337
// Replace the old lookup/inttoptr/call with the new call.
338338
p.builder.SetInsertPointBefore(call)
339-
retval := p.builder.CreateCall(redirector, params, "")
339+
retval := p.builder.CreateCall(redirector, append(params, llvm.ConstNull(llvm.PointerType(p.ctx.Int8Type(), 0))), "")
340340
if retval.Type().TypeKind() != llvm.VoidTypeKind {
341341
call.ReplaceAllUsesWith(retval)
342342
}
@@ -613,9 +613,10 @@ func (p *lowerInterfacesPass) getInterfaceMethodFunc(itf *interfaceInfo, signatu
613613
// Construct the function name, which is of the form:
614614
// (main.Stringer).String
615615
fnName := "(" + itf.id() + ")." + signature.methodName()
616-
fnType := llvm.FunctionType(returnType, params, false)
616+
fnType := llvm.FunctionType(returnType, append(params, llvm.PointerType(p.ctx.Int8Type(), 0)), false)
617617
fn := llvm.AddFunction(p.mod, fnName, fnType)
618-
fn.LastParam().SetName("actualType")
618+
llvm.PrevParam(fn.LastParam()).SetName("actualType")
619+
fn.LastParam().SetName("parentHandle")
619620
itf.methodFuncs[signature] = fn
620621
return fn
621622
}
@@ -644,13 +645,13 @@ func (p *lowerInterfacesPass) createInterfaceMethodFunc(itf *interfaceInfo, sign
644645

645646
// Create type switch in entry block.
646647
p.builder.SetInsertPointAtEnd(entry)
647-
actualType := fn.LastParam()
648+
actualType := llvm.PrevParam(fn.LastParam())
648649
sw := p.builder.CreateSwitch(actualType, defaultBlock, len(itf.types))
649650

650651
// Collect the params that will be passed to the functions to call.
651652
// These params exclude the receiver (which may actually consist of multiple
652653
// parts).
653-
params := make([]llvm.Value, fn.ParamsCount()-2)
654+
params := make([]llvm.Value, fn.ParamsCount()-3)
654655
for i := range params {
655656
params[i] = fn.Param(i + 1)
656657
}

transform/testdata/interface.ll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ target triple = "armv7m-none-eabi"
1313
@"Unmatched$interface" = private constant [1 x i8*] [i8* @"func NeverImplementedMethod()"]
1414
@"func Double() int" = external constant i8
1515
@"Doubler$interface" = private constant [1 x i8*] [i8* @"func Double() int"]
16-
@"Number$methodset" = private constant [1 x %runtime.interfaceMethodInfo] [%runtime.interfaceMethodInfo { i8* @"func Double() int", i32 ptrtoint (i32 (i8*)* @"(Number).Double$invoke" to i32) }]
16+
@"Number$methodset" = private constant [1 x %runtime.interfaceMethodInfo] [%runtime.interfaceMethodInfo { i8* @"func Double() int", i32 ptrtoint (i32 (i8*, i8*)* @"(Number).Double$invoke" to i32) }]
1717
@"reflect/types.type:named:Number" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i32 0 }
1818
@"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) }
1919

@@ -49,8 +49,8 @@ typeswitch.notUnmatched:
4949

5050
typeswitch.Doubler:
5151
%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")
52-
%doubler.func.cast = inttoptr i32 %doubler.func to i32 (i8*)*
53-
%doubler.result = call i32 %doubler.func.cast(i8* %value)
52+
%doubler.func.cast = inttoptr i32 %doubler.func to i32 (i8*, i8*)*
53+
%doubler.result = call i32 %doubler.func.cast(i8* %value, i8* null)
5454
call void @runtime.printint32(i32 %doubler.result)
5555
ret void
5656

@@ -68,13 +68,13 @@ typeswitch.notByte:
6868
ret void
6969
}
7070

71-
define i32 @"(Number).Double"(i32 %receiver) {
71+
define i32 @"(Number).Double"(i32 %receiver, i8* %parentHandle) {
7272
%ret = mul i32 %receiver, 2
7373
ret i32 %ret
7474
}
7575

76-
define i32 @"(Number).Double$invoke"(i8* %receiverPtr) {
76+
define i32 @"(Number).Double$invoke"(i8* %receiverPtr, i8* %parentHandle) {
7777
%receiver = ptrtoint i8* %receiverPtr to i32
78-
%ret = call i32 @"(Number).Double"(i32 %receiver)
78+
%ret = call i32 @"(Number).Double"(i32 %receiver, i8* null)
7979
ret i32 %ret
8080
}

transform/testdata/interface.out.ll

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ typeswitch.notUnmatched:
4747
br i1 %typeassert.ok, label %typeswitch.Doubler, label %typeswitch.notDoubler
4848

4949
typeswitch.Doubler:
50-
%doubler.result = call i32 @"(Number).Double$invoke"(i8* %value)
50+
%doubler.result = call i32 @"(Number).Double$invoke"(i8* %value, i8* null)
5151
call void @runtime.printint32(i32 %doubler.result)
5252
ret void
5353

@@ -65,14 +65,14 @@ typeswitch.notByte:
6565
ret void
6666
}
6767

68-
define i32 @"(Number).Double"(i32 %receiver) {
68+
define i32 @"(Number).Double"(i32 %receiver, i8* %parentHandle) {
6969
%ret = mul i32 %receiver, 2
7070
ret i32 %ret
7171
}
7272

73-
define i32 @"(Number).Double$invoke"(i8* %receiverPtr) {
73+
define i32 @"(Number).Double$invoke"(i8* %receiverPtr, i8* %parentHandle) {
7474
%receiver = ptrtoint i8* %receiverPtr to i32
75-
%ret = call i32 @"(Number).Double"(i32 %receiver)
75+
%ret = call i32 @"(Number).Double"(i32 %receiver, i8* null)
7676
ret i32 %ret
7777
}
7878

0 commit comments

Comments
 (0)