Skip to content
Closed
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
[wasm] PInvokeTableGenerator: Add support for variadic functions
Currently, for a variadic function like:

`int sqlite3_config(int, ...);`

.. and multiple pinvokes like:

```csharp
[DllImport(SQLITE_DLL, ExactSpelling=true, EntryPoint = "sqlite3_config", CallingConvention = CALLING_CONVENTION)]
public static extern unsafe int sqlite3_config_none(int op);

[DllImport(SQLITE_DLL, ExactSpelling=true, EntryPoint = "sqlite3_config", CallingConvention = CALLING_CONVENTION)]
public static extern unsafe int sqlite3_config_int(int op, int val);

[DllImport(SQLITE_DLL, ExactSpelling=true, EntryPoint = "sqlite3_config", CallingConvention = CALLING_CONVENTION)]
public static extern unsafe int sqlite3_config_log(int op, NativeMethods.callback_log func, hook_handle pvUser);
```

.. we generate:

```c
int sqlite3_config (int);
int sqlite3_config (int,int);
int sqlite3_config (int,int,int);
```

.. which fails to compile.

Instead, this patch will generate a variadic declaration with one fixed
parameter:

```c
// Variadic signature created for
//   System.Int32 sqlite3_config_none(System.Int32)
//   System.Int32 sqlite3_config_int(System.Int32, System.Int32)
//   System.Int32 sqlite3_config_log(System.Int32, SQLitePCL.SQLite3Provider_e_sqlite3+NativeMethods+callback_log, SQLitePCL.hook_handle)
int sqlite3_config (int, ...);
```

TODO: functions with different first argument
  • Loading branch information
radical committed Sep 24, 2021
commit 3f7acdca26ca62fff67a6026900715a26a1a10f8
41 changes: 31 additions & 10 deletions src/tasks/WasmAppBuilder/PInvokeTableGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,23 @@ private void EmitPInvokeTable(StreamWriter w, Dictionary<string, string> modules
w.WriteLine();

var decls = new HashSet<string>();
foreach (var pinvoke in pinvokes.OrderBy(l => l.EntryPoint))
// FIXME: handle sigs with different first args
foreach (var group in pinvokes.OrderBy(l => l.EntryPoint).GroupBy(l => l.EntryPoint))
{
IEnumerable<string?>? uniqueSigs = group.Select(l => l.Method.ToString()).Distinct();
bool treatAsVariadic = uniqueSigs.Count() > 1;
if (treatAsVariadic)
{
w.WriteLine($"// Variadic signature created for");
foreach (string? method in uniqueSigs)
w.WriteLine($"// {method}");
}

PInvoke pinvoke = group.First();
if (modules.ContainsKey(pinvoke.Module)) {
try
{
var decl = GenPInvokeDecl(pinvoke);
var decl = GenPInvokeDecl(pinvoke, treatAsVariadic);
if (decls.Contains(decl))
continue;

Expand Down Expand Up @@ -205,7 +216,7 @@ private string MapType (Type t)
return "int";
}

private string GenPInvokeDecl(PInvoke pinvoke)
private string GenPInvokeDecl(PInvoke pinvoke, bool treatAsVariadic=false)
{
var sb = new StringBuilder();
var method = pinvoke.Method;
Expand All @@ -215,15 +226,25 @@ private string GenPInvokeDecl(PInvoke pinvoke)
sb.Append($"int {pinvoke.EntryPoint} (int, int, int, int, int);");
return sb.ToString();
}

sb.Append(MapType(method.ReturnType));
sb.Append($" {pinvoke.EntryPoint} (");
int pindex = 0;
var pars = method.GetParameters();
foreach (var p in pars) {
if (pindex > 0)
sb.Append(',');
sb.Append(MapType(pars[pindex].ParameterType));
pindex++;
if (!treatAsVariadic)
{
int pindex = 0;
var pars = method.GetParameters();
foreach (var p in pars) {
if (pindex > 0)
sb.Append(',');
sb.Append(MapType(pars[pindex].ParameterType));
pindex++;
}
}
else
{
ParameterInfo firstParam = method.GetParameters()[0];
sb.Append(MapType(firstParam.ParameterType));
sb.Append(", ...");
}
sb.Append(");");
return sb.ToString();
Expand Down