From 6896b0014b62f7e8618b879cd2004582d5f7a672 Mon Sep 17 00:00:00 2001 From: Jaden Weiss Date: Wed, 26 Feb 2020 15:54:00 -0500 Subject: [PATCH] compiler: fix deferred calls to exported functions Previously using defer with an exported function generated an invalid function call due to differences between TinyGo's calling convention and the C calling convention. --- compiler/defer.go | 14 +++++++++----- testdata/calls.go | 7 +++++++ testdata/calls.txt | 1 + 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/compiler/defer.go b/compiler/defer.go index 72131121..bc826032 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -295,12 +295,16 @@ func (c *Compiler) emitRunDefers(frame *Frame) { forwardParams = append(forwardParams, forwardParam) } - // Add the context parameter. We know it is ignored by the receiving - // function, but we have to pass one anyway. - forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType)) + // Plain TinyGo functions add some extra parameters to implement async functionality and function recievers. + // These parameters should not be supplied when calling into an external C/ASM function. + if !callback.IsExported() { + // Add the context parameter. We know it is ignored by the receiving + // function, but we have to pass one anyway. + forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType)) - // Parent coroutine handle. - forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType)) + // Parent coroutine handle. + forwardParams = append(forwardParams, llvm.Undef(c.i8ptrType)) + } // Call real function. c.createCall(callback.LLVMFn, forwardParams, "") diff --git a/testdata/calls.go b/testdata/calls.go index 509d47b3..a3dfa807 100644 --- a/testdata/calls.go +++ b/testdata/calls.go @@ -72,6 +72,8 @@ func hello(n int) { } func testDefer() { + defer exportedDefer() + i := 1 defer deferred("...run as defer", i) i++ @@ -98,6 +100,11 @@ func deferred(msg string, i int) { println(msg, i) } +//go:export __exportedDefer +func exportedDefer() { + println("...exported defer") +} + func testBound(f func() string) { println("bound method:", f()) } diff --git a/testdata/calls.txt b/testdata/calls.txt index 875f54a0..b65e7d9a 100644 --- a/testdata/calls.txt +++ b/testdata/calls.txt @@ -4,6 +4,7 @@ Thing.Print: foo arg: bar ...run as defer 3 ...run closure deferred: 4 ...run as defer 1 +...exported defer loop 3 loop 2 loop 1