Merge pull request #4928 from kumpera/ptr_to_struct_intrinsic
authorRodrigo Kumpera <kumpera@users.noreply.github.com>
Sat, 27 May 2017 19:27:37 +0000 (12:27 -0700)
committerGitHub <noreply@github.com>
Sat, 27 May 2017 19:27:37 +0000 (12:27 -0700)
[mini] Intrinsify Marshal.PtrToStructure<T>

mono/mini/method-to-ir.c
mono/tests/marshal2.cs

index 78be8ee709af0aaf5317f5ff1b46daa91481a430..3817d2809f9e0acecb6c2857f0be4a0246017371 100644 (file)
@@ -4874,6 +4874,31 @@ mini_emit_inst_for_sharable_method (MonoCompile *cfg, MonoMethod *cmethod, MonoM
        return NULL;
 }
 
+
+static gboolean
+mono_type_is_native_blittable (MonoType *t)
+{
+       if (MONO_TYPE_IS_REFERENCE (t))
+               return FALSE;
+
+       if (MONO_TYPE_IS_PRIMITIVE_SCALAR (t))
+               return TRUE;
+
+       MonoClass *klass = mono_class_from_mono_type (t);
+
+       //MonoClass::blitable depends on mono_class_setup_fields being done.
+       mono_class_setup_fields (klass);
+       if (!klass->blittable)
+               return FALSE;
+
+       // If the native marshal size is different we can't convert PtrToStructure to a type load
+       if (mono_class_native_size (klass, NULL) != mono_class_value_size (klass, NULL))
+               return FALSE;
+
+       return TRUE;
+}
+
+
 static MonoInst*
 mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsig, MonoInst **args)
 {
@@ -5789,6 +5814,20 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        MONO_ADD_INS (cfg->cbb, ins);
                        return ins;
                }
+       } else if (cmethod->klass->image == mono_defaults.corlib &&
+                       (strcmp (cmethod->klass->name_space, "System.Runtime.InteropServices") == 0) &&
+                       (strcmp (cmethod->klass->name, "Marshal") == 0)) {
+               //Convert Marshal.PtrToStructure<T> of blittable T to direct loads
+               if (strcmp (cmethod->name, "PtrToStructure") == 0 &&
+                               cmethod->is_inflated &&
+                               fsig->param_count == 1 &&
+                               !mini_method_check_context_used (cfg, cmethod)) {
+
+                       MonoGenericContext *method_context = mono_method_get_context (cmethod);
+                       MonoType *arg0 = method_context->method_inst->type_argv [0];
+                       if (mono_type_is_native_blittable (arg0))
+                               return mini_emit_memory_load (cfg, arg0, args [0], 0, 0);
+               }
        }
 
 #ifdef MONO_ARCH_SIMD_INTRINSICS
index 8a0d43f3a3660255097fa2cb59e9e21a2f399697..05550ac2277e360581cabe68284d821f3fd55787 100644 (file)
@@ -277,4 +277,20 @@ public class Tests {
                        return 1;
                return 0;
        }
+
+       public static int test_0_generic_ptr_to_struct () {
+               int size = Marshal.SizeOf (typeof (SimpleStruct2));
+               IntPtr p = Marshal.AllocHGlobal (size);
+
+               Marshal.WriteInt32 (p, 0, 1); //a
+               Marshal.WriteInt32 (p, 4, 2); //a
+
+               var s = Marshal.PtrToStructure<SimpleStruct2> (p);
+
+               if (s.a != 1)
+                       return 1;
+               if (s.b != 2)
+                       return 2;
+               return 0;
+       }
 }