@@ -16,6 +16,7 @@ package compiler
16
16
import (
17
17
"github.com/tinygo-org/tinygo/compiler/llvmutil"
18
18
"github.com/tinygo-org/tinygo/ir"
19
+ "go/types"
19
20
"golang.org/x/tools/go/ssa"
20
21
"tinygo.org/x/go-llvm"
21
22
)
@@ -28,6 +29,8 @@ func (b *builder) deferInitFunc() {
28
29
b .deferFuncs = make (map [* ir.Function ]int )
29
30
b .deferInvokeFuncs = make (map [string ]int )
30
31
b .deferClosureFuncs = make (map [* ir.Function ]int )
32
+ b .deferExprFuncs = make (map [ssa.Value ]int )
33
+ b .deferBuiltinFuncs = make (map [ssa.Value ]deferBuiltin )
31
34
32
35
// Create defer list pointer.
33
36
deferType := llvm .PointerType (b .getLLVMRuntimeType ("_defer" ), 0 )
@@ -151,9 +154,54 @@ func (b *builder) createDefer(instr *ssa.Defer) {
151
154
values = append (values , context )
152
155
valueTypes = append (valueTypes , context .Type ())
153
156
157
+ } else if builtin , ok := instr .Call .Value .(* ssa.Builtin ); ok {
158
+ var funcName string
159
+ switch builtin .Name () {
160
+ case "close" :
161
+ funcName = "chanClose"
162
+ default :
163
+ b .addError (instr .Pos (), "todo: Implement defer for " + builtin .Name ())
164
+ return
165
+ }
166
+
167
+ if _ , ok := b .deferBuiltinFuncs [instr .Call .Value ]; ! ok {
168
+ b .deferBuiltinFuncs [instr .Call .Value ] = deferBuiltin {
169
+ funcName ,
170
+ len (b .allDeferFuncs ),
171
+ }
172
+ b .allDeferFuncs = append (b .allDeferFuncs , instr .Call .Value )
173
+ }
174
+ callback := llvm .ConstInt (b .uintptrType , uint64 (b .deferBuiltinFuncs [instr .Call .Value ].callback ), false )
175
+
176
+ // Collect all values to be put in the struct (starting with
177
+ // runtime._defer fields).
178
+ values = []llvm.Value {callback , next }
179
+ for _ , param := range instr .Call .Args {
180
+ llvmParam := b .getValue (param )
181
+ values = append (values , llvmParam )
182
+ valueTypes = append (valueTypes , llvmParam .Type ())
183
+ }
184
+
154
185
} else {
155
- b .addError (instr .Pos (), "todo: defer on uncommon function call type" )
156
- return
186
+ funcValue := b .getValue (instr .Call .Value )
187
+
188
+ if _ , ok := b .deferExprFuncs [instr .Call .Value ]; ! ok {
189
+ b .deferExprFuncs [instr .Call .Value ] = len (b .allDeferFuncs )
190
+ b .allDeferFuncs = append (b .allDeferFuncs , & instr .Call )
191
+ }
192
+
193
+ callback := llvm .ConstInt (b .uintptrType , uint64 (b .deferExprFuncs [instr .Call .Value ]), false )
194
+
195
+ // Collect all values to be put in the struct (starting with
196
+ // runtime._defer fields, followed by all parameters including the
197
+ // context pointer).
198
+ values = []llvm.Value {callback , next , funcValue }
199
+ valueTypes = append (valueTypes , funcValue .Type ())
200
+ for _ , param := range instr .Call .Args {
201
+ llvmParam := b .getValue (param )
202
+ values = append (values , llvmParam )
203
+ valueTypes = append (valueTypes , llvmParam .Type ())
204
+ }
157
205
}
158
206
159
207
// Make a struct out of the collected values to put in the defer frame.
@@ -243,16 +291,23 @@ func (b *builder) createRunDefers() {
243
291
b .SetInsertPointAtEnd (block )
244
292
switch callback := callback .(type ) {
245
293
case * ssa.CallCommon :
246
- // Call on an interface value.
294
+ // Call on an value or interface value.
295
+
296
+ // Get the real defer struct type and cast to it.
297
+ valueTypes := []llvm.Type {b .uintptrType , llvm .PointerType (b .getLLVMRuntimeType ("_defer" ), 0 )}
298
+
247
299
if ! callback .IsInvoke () {
248
- panic ("expected an invoke call, not a direct call" )
300
+ //Expect funcValue to be passed through the defer frame.
301
+ valueTypes = append (valueTypes , b .getFuncType (callback .Signature ()))
302
+ } else {
303
+ //Expect typecode
304
+ valueTypes = append (valueTypes , b .uintptrType , b .i8ptrType )
249
305
}
250
306
251
- // Get the real defer struct type and cast to it.
252
- valueTypes := []llvm.Type {b .uintptrType , llvm .PointerType (b .getLLVMRuntimeType ("_defer" ), 0 ), b .uintptrType , b .i8ptrType }
253
307
for _ , arg := range callback .Args {
254
308
valueTypes = append (valueTypes , b .getLLVMType (arg .Type ()))
255
309
}
310
+
256
311
deferFrameType := b .ctx .StructType (valueTypes , false )
257
312
deferFramePtr := b .CreateBitCast (deferData , llvm .PointerType (deferFrameType , 0 ), "deferFrame" )
258
313
@@ -265,18 +320,34 @@ func (b *builder) createRunDefers() {
265
320
forwardParams = append (forwardParams , forwardParam )
266
321
}
267
322
268
- // Isolate the typecode.
269
- typecode , forwardParams := forwardParams [0 ], forwardParams [1 :]
323
+ var fnPtr llvm.Value
270
324
271
- // Add the context parameter. An interface call cannot also be a
272
- // closure but we have to supply the parameter anyway for platforms
273
- // with a strict calling convention.
274
- forwardParams = append (forwardParams , llvm .Undef (b .i8ptrType ))
325
+ if ! callback .IsInvoke () {
326
+ // Isolate the func value.
327
+ funcValue := forwardParams [0 ]
328
+ forwardParams = forwardParams [1 :]
329
+
330
+ //Get function pointer and context
331
+ fp , context := b .decodeFuncValue (funcValue , callback .Signature ())
332
+ fnPtr = fp
333
+
334
+ //Pass context
335
+ forwardParams = append (forwardParams , context )
336
+ } else {
337
+ // Isolate the typecode.
338
+ typecode := forwardParams [0 ]
339
+ forwardParams = forwardParams [1 :]
340
+ fnPtr = b .getInvokePtr (callback , typecode )
341
+
342
+ // Add the context parameter. An interface call cannot also be a
343
+ // closure but we have to supply the parameter anyway for platforms
344
+ // with a strict calling convention.
345
+ forwardParams = append (forwardParams , llvm .Undef (b .i8ptrType ))
346
+ }
275
347
276
348
// Parent coroutine handle.
277
349
forwardParams = append (forwardParams , llvm .Undef (b .i8ptrType ))
278
350
279
- fnPtr := b .getInvokePtr (callback , typecode )
280
351
b .createCall (fnPtr , forwardParams , "" )
281
352
282
353
case * ir.Function :
@@ -339,7 +410,31 @@ func (b *builder) createRunDefers() {
339
410
340
411
// Call deferred function.
341
412
b .createCall (fn .LLVMFn , forwardParams , "" )
413
+ case * ssa.Builtin :
414
+ db := b .deferBuiltinFuncs [callback ]
415
+
416
+ //Get parameter types
417
+ valueTypes := []llvm.Type {b .uintptrType , llvm .PointerType (b .getLLVMRuntimeType ("_defer" ), 0 )}
418
+
419
+ //Get signature from call results
420
+ params := callback .Type ().Underlying ().(* types.Signature ).Params ()
421
+ for i := 0 ; i < params .Len (); i ++ {
422
+ valueTypes = append (valueTypes , b .getLLVMType (params .At (i ).Type ()))
423
+ }
424
+
425
+ deferFrameType := b .ctx .StructType (valueTypes , false )
426
+ deferFramePtr := b .CreateBitCast (deferData , llvm .PointerType (deferFrameType , 0 ), "deferFrame" )
427
+
428
+ // Extract the params from the struct.
429
+ var forwardParams []llvm.Value
430
+ zero := llvm .ConstInt (b .ctx .Int32Type (), 0 , false )
431
+ for i := 0 ; i < params .Len (); i ++ {
432
+ gep := b .CreateInBoundsGEP (deferFramePtr , []llvm.Value {zero , llvm .ConstInt (b .ctx .Int32Type (), uint64 (i + 2 ), false )}, "gep" )
433
+ forwardParam := b .CreateLoad (gep , "param" )
434
+ forwardParams = append (forwardParams , forwardParam )
435
+ }
342
436
437
+ b .createRuntimeCall (db .funcName , forwardParams , "" )
343
438
default :
344
439
panic ("unknown deferred function type" )
345
440
}
0 commit comments