[wasm] Fix linker dependency in the pinvoke callback table. (#39070)
authorZoltan Varga <vargaz@gmail.com>
Fri, 10 Jul 2020 14:26:46 +0000 (10:26 -0400)
committerGitHub <noreply@github.com>
Fri, 10 Jul 2020 14:26:46 +0000 (16:26 +0200)
Encode methods as class name+method name instead of their token.

src/mono/wasm/Makefile
src/mono/wasm/runtime/driver.c
tools-local/tasks/mobile.tasks/WasmAppBuilder/PInvokeTableGenerator.cs

index 6fd3203..23f96d6 100644 (file)
@@ -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)
index f9d190e..4643790 100644 (file)
@@ -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] == '.')
index 0447fc8..7523894 100644 (file)
@@ -156,120 +156,130 @@ public class PInvokeTableGenerator : Task
         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)
     {