static string GenPinvokeDecl(Pinvoke pinvoke) { var sb = new StringBuilder(); var method = pinvoke.Method; sb.Append(WasmTuner.MapType(method.ReturnType)); sb.Append($" {pinvoke.EntryPoint} ("); int pindex = 0; foreach (var p in method.Parameters) { if (pindex > 0) { sb.Append(","); } sb.Append(WasmTuner.MapType(method.Parameters [pindex].ParameterType)); pindex++; } sb.Append(");"); return(sb.ToString()); }
void GenNativeToInterp() { // Generate native->interp entry functions // These are called by native code, so they need to obtain // the interp entry function/arg from a global array // They also need to have a signature matching what the // native code expects, which is the native signature // of the delegate invoke in the [MonoPInvokeCallback] // attribute. // Only blittable parameter/return types are supposed. int cb_index = 0; // Arguments to interp entry functions in the runtime Console.WriteLine("InterpFtnDesc wasm_native_to_interp_ftndescs[" + callbacks.Count + "];"); foreach (var cb in callbacks) { var method = cb.Method; if (!IsBlittable(method.ReturnType)) { Error("The return type of pinvoke callback method '" + method.FullName + "' needs to be blittable."); } foreach (var p in method.Parameters) { if (!IsBlittable(p.ParameterType)) { Error("Parameter types of pinvoke callback method '" + method.FullName + "' needs to be blittable."); } } } foreach (var cb in callbacks) { var sb = new StringBuilder(); var method = cb.Method; // The signature of the interp entry function // This is a gsharedvt_in signature sb.Append("typedef void "); sb.Append(" (*WasmInterpEntrySig_" + cb_index + ") ("); int pindex = 0; if (method.ReturnType.Name != "Void") { sb.Append("int"); pindex++; } foreach (var p in method.Parameters) { if (pindex > 0) { sb.Append(","); } sb.Append("int"); pindex++; } if (pindex > 0) { sb.Append(","); } // Extra arg sb.Append("int"); sb.Append(");\n"); bool is_void = method.ReturnType.Name == "Void"; string module_symbol = method.DeclaringType.Module.Assembly.Name.Name.Replace(".", "_"); var token = method.MetadataToken.ToUInt32(); string entry_name = $"wasm_native_to_interp_{module_symbol}_{token}"; cb.EntryName = entry_name; sb.Append(WasmTuner.MapType(method.ReturnType)); sb.Append($" {entry_name} ("); pindex = 0; foreach (var p in method.Parameters) { if (pindex > 0) { sb.Append(","); } sb.Append(WasmTuner.MapType(method.Parameters [pindex].ParameterType)); sb.Append(" arg" + pindex); pindex++; } sb.Append(") { \n"); if (!is_void) { sb.Append(WasmTuner.MapType(method.ReturnType) + " res;\n"); } sb.Append("((WasmInterpEntrySig_" + cb_index + ")wasm_native_to_interp_ftndescs [" + cb_index + "].func) ("); pindex = 0; if (!is_void) { sb.Append("&res"); pindex++; } int aindex = 0; foreach (var p in method.Parameters) { if (pindex > 0) { sb.Append(", "); } sb.Append("&arg" + aindex); pindex++; aindex++; } if (pindex > 0) { sb.Append(", "); } sb.Append($"wasm_native_to_interp_ftndescs [{cb_index}].arg"); sb.Append(");\n"); if (!is_void) { sb.Append("return res;\n"); } sb.Append("}"); Console.WriteLine(sb); cb_index++; } // Array of function pointers Console.Write("static void *wasm_native_to_interp_funcs[] = { "); foreach (var cb in callbacks) { Console.Write(cb.EntryName + ","); } Console.WriteLine("};"); // Lookup table from method->interp entry // The key is a string of the form <assembly name>_<method token> // FIXME: Use a better encoding Console.Write("static const char *wasm_native_to_interp_map[] = { "); foreach (var cb in callbacks) { var method = cb.Method; string module_symbol = method.DeclaringType.Module.Assembly.Name.Name.Replace(".", "_"); var token = method.MetadataToken.ToUInt32(); Console.WriteLine($"\"{module_symbol}_{token}\","); } Console.WriteLine("};"); }