未验证 提交 4dccf9a5 编写于 作者: Z Zoltan Varga 提交者: GitHub

[wasm] Fix linker dependency in the pinvoke callback table. (#39070)

Encode methods as class name+method name instead of their token.
上级 f4d39134
......@@ -100,7 +100,7 @@ $(eval $(call InterpBuildTemplate,$(EMCC_RELEASE_FLAGS),$(MONO_LIBS)))
endif
build:
EMSDK_PATH=$(PWD)/src/mono/wasm/emsdk $(DOTNET) build /p:TargetArchitecture=wasm /p:TargetOS=Browser /p:Configuration=$(CONFIG) $(TOP)/src/libraries/src.proj /t:NativeBinPlace
EMSDK_PATH=$(PWD)/emsdk $(DOTNET) build /p:TargetArchitecture=wasm /p:TargetOS=Browser /p:Configuration=$(CONFIG) $(TOP)/src/libraries/src.proj /t:NativeBinPlace
clean-emsdk:
$(RM) -rf $(EMSDK_LOCAL_PATH)
......
......@@ -305,17 +305,18 @@ icall_table_lookup_symbol (void *func)
void*
get_native_to_interp (MonoMethod *method, void *extra_arg)
{
uint32_t token = mono_method_get_token (method);
MonoClass *klass = mono_method_get_class (method);
MonoImage *image = mono_class_get_image (klass);
MonoAssembly *assembly = mono_image_get_assembly (image);
MonoAssemblyName *aname = mono_assembly_get_name (assembly);
const char *name = mono_assembly_name_get_name (aname);
const char *class_name = mono_class_get_name (klass);
const char *method_name = mono_method_get_name (method);
char key [128];
int len;
assert (strlen (name) < 100);
sprintf (key, "%s_%d", name, token);
sprintf (key, "%s_%s_%s", name, class_name, method_name);
len = strlen (key);
for (int i = 0; i < len; ++i) {
if (key [i] == '.')
......
......@@ -156,120 +156,130 @@ private string GenPInvokeDecl(PInvoke pinvoke)
return sb.ToString();
}
void EmitNativeToInterp(StreamWriter w, List<PInvokeCallback> callbacks)
void EmitNativeToInterp(StreamWriter w, List<PInvokeCallback> callbacks)
{
// 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
w.WriteLine("InterpFtnDesc wasm_native_to_interp_ftndescs[" + callbacks.Count + "];");
foreach (var cb in callbacks) {
var method = cb.Method;
if (method.ReturnType != typeof(void) && !IsBlittable(method.ReturnType))
Error("The return type of pinvoke callback method '" + method + "' needs to be blittable.");
foreach (var p in method.GetParameters()) {
if (!IsBlittable(p.ParameterType))
Error("Parameter types of pinvoke callback method '" + method + "' 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.GetParameters()) {
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!.GetName()!.Name!.Replace(".", "_");
uint token = (uint)method.MetadataToken;
string entry_name = $"wasm_native_to_interp_{module_symbol}_{token}";
// 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
w.WriteLine("InterpFtnDesc wasm_native_to_interp_ftndescs[" + callbacks.Count + "];");
foreach (var cb in callbacks) {
var method = cb.Method;
if (method.ReturnType != typeof(void) && !IsBlittable(method.ReturnType))
Error("The return type of pinvoke callback method '" + method + "' needs to be blittable.");
foreach (var p in method.GetParameters()) {
if (!IsBlittable(p.ParameterType))
Error("Parameter types of pinvoke callback method '" + method + "' needs to be blittable.");
}
}
var callbackNames = new HashSet<string>();
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.GetParameters()) {
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!.GetName()!.Name!.Replace(".", "_");
uint token = (uint)method.MetadataToken;
string class_name = method.DeclaringType.Name;
string method_name = method.Name;
string entry_name = $"wasm_native_to_interp_{module_symbol}_{class_name}_{method_name}";
if (callbackNames.Contains (entry_name))
{
Error($"Two callbacks with the same name '{method_name}' are not supported.");
}
callbackNames.Add (entry_name);
cb.EntryName = entry_name;
sb.Append(MapType(method.ReturnType));
sb.Append($" {entry_name} (");
pindex = 0;
foreach (var p in method.GetParameters()) {
if (pindex > 0)
sb.Append(",");
sb.Append(MapType(method.GetParameters()[pindex].ParameterType));
sb.Append(" arg" + pindex);
pindex ++;
}
sb.Append(") { \n");
if (!is_void)
sb.Append(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.GetParameters()) {
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("}");
w.WriteLine(sb);
cb_index ++;
}
// Array of function pointers
w.Write ("static void *wasm_native_to_interp_funcs[] = { ");
foreach (var cb in callbacks) {
w.Write (cb.EntryName + ",");
}
w.WriteLine ("};");
// Lookup table from method->interp entry
// The key is a string of the form <assembly name>_<method token>
// FIXME: Use a better encoding
w.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!.GetName()!.Name!.Replace(".", "_");
uint token = (uint)method.MetadataToken;
w.WriteLine ($"\"{module_symbol}_{token}\",");
}
w.WriteLine ("};");
}
sb.Append(MapType(method.ReturnType));
sb.Append($" {entry_name} (");
pindex = 0;
foreach (var p in method.GetParameters()) {
if (pindex > 0)
sb.Append(",");
sb.Append(MapType(method.GetParameters()[pindex].ParameterType));
sb.Append(" arg" + pindex);
pindex ++;
}
sb.Append(") { \n");
if (!is_void)
sb.Append(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.GetParameters()) {
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("}");
w.WriteLine(sb);
cb_index ++;
}
// Array of function pointers
w.Write ("static void *wasm_native_to_interp_funcs[] = { ");
foreach (var cb in callbacks) {
w.Write (cb.EntryName + ",");
}
w.WriteLine ("};");
// Lookup table from method->interp entry
// The key is a string of the form <assembly name>_<method token>
// FIXME: Use a better encoding
w.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!.GetName()!.Name!.Replace(".", "_");
string class_name = method.DeclaringType.Name;
string method_name = method.Name;
w.WriteLine ($"\"{module_symbol}_{class_name}_{method_name}\",");
}
w.WriteLine ("};");
}
static bool IsBlittable (Type type)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册