[netcore] Intrinsify Buffer.IsPrimitiveTypeArray (mono/mono#17438)
authorEgor Bogatov <egorbo@gmail.com>
Tue, 5 Nov 2019 06:50:37 +0000 (09:50 +0300)
committerZoltan Varga <vargaz@gmail.com>
Tue, 5 Nov 2019 06:50:37 +0000 (01:50 -0500)
* Improve IsPrimitive intrinsic

* Implement it for interpreter

* clean up

* clean up

Commit migrated from https://github.com/mono/mono/commit/fdc6495a549fbd3a4b222b888a7a72ba7b65330c

src/mono/mono/metadata/class-internals.h
src/mono/mono/metadata/icall-def-netcore.h
src/mono/mono/metadata/icall.c
src/mono/mono/metadata/object.c
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/interp/mintops.def
src/mono/mono/mini/interp/transform.c
src/mono/mono/mini/intrinsics.c
src/mono/netcore/System.Private.CoreLib/src/System/Array.Mono.cs
src/mono/netcore/System.Private.CoreLib/src/System/Buffer.Mono.cs

index d4b52bf..294d6f4 100644 (file)
@@ -335,7 +335,8 @@ typedef gpointer MonoRuntimeGenericContext;
 typedef enum {
        /* array or string */
        MONO_VT_FLAG_ARRAY_OR_STRING = (1 << 0),
-       MONO_VT_FLAG_HAS_REFERENCES = (1 << 1)
+       MONO_VT_FLAG_HAS_REFERENCES = (1 << 1),
+       MONO_VT_FLAG_ARRAY_IS_PRIMITIVE = (1 << 2),
 } MonoVTableFlags;
 
 /* the interface_offsets array is stored in memory before this struct */
index 5f33179..b5498c7 100644 (file)
@@ -54,7 +54,6 @@ HANDLES(ARRAY_14, "SetValueRelaxedImpl",  ves_icall_System_Array_SetValueRelaxed
 
 ICALL_TYPE(BUFFER, "System.Buffer", BUFFER_0)
 NOHANDLES(ICALL(BUFFER_0, "BulkMoveWithWriteBarrier", ves_icall_System_Runtime_RuntimeImports_RhBulkMoveWithWriteBarrier))
-HANDLES(BUFFER_1, "IsPrimitiveTypeArray", ves_icall_System_Buffer_IsPrimitiveTypeArray, MonoBoolean, 1, (MonoArray))
 NOHANDLES(ICALL(BUFFER_2, "__Memmove", ves_icall_System_Runtime_RuntimeImports_Memmove))
 NOHANDLES(ICALL(BUFFER_3, "__ZeroMemory", ves_icall_System_Runtime_RuntimeImports_ZeroMemory))
 
index 8417b08..c575ccd 100644 (file)
@@ -7335,15 +7335,6 @@ mono_array_get_byte_length (MonoArrayHandle array)
        }
 }
 
-#ifdef ENABLE_NETCORE
-MonoBoolean
-ves_icall_System_Buffer_IsPrimitiveTypeArray (MonoArrayHandle array, MonoError* error)
-{
-       MonoClass * const klass = m_class_get_element_class (MONO_HANDLE_GETVAL (array, obj.vtable)->klass);
-       return m_class_is_primitive (klass);
-}
-#endif
-
 gint32
 ves_icall_System_Buffer_ByteLengthInternal (MonoArrayHandle array, MonoError* error)
 {
index 0197ba2..f666b3b 100644 (file)
@@ -2009,6 +2009,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
        guint32 vtable_size, class_size;
        gpointer iter;
        gpointer *interface_offsets;
+       gboolean is_primitive_type_array = FALSE;
        gboolean use_interpreter = callbacks.is_interpreter_enabled ();
 
        mono_loader_lock (); /*FIXME mono_class_init_internal acquires it*/
@@ -2033,6 +2034,7 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
        /* Array types require that their element type be valid*/
        if (m_class_get_byval_arg (klass)->type == MONO_TYPE_ARRAY || m_class_get_byval_arg (klass)->type == MONO_TYPE_SZARRAY) {
                MonoClass *element_class = m_class_get_element_class (klass);
+               is_primitive_type_array = m_class_is_primitive (element_class);
                if (!m_class_is_inited (element_class))
                        mono_class_init_internal (element_class);
 
@@ -2109,6 +2111,9 @@ mono_class_create_runtime_vtable (MonoDomain *domain, MonoClass *klass, MonoErro
        if (m_class_has_references (klass))
                vt->flags |= MONO_VT_FLAG_HAS_REFERENCES;
 
+       if (is_primitive_type_array)
+               vt->flags |= MONO_VT_FLAG_ARRAY_IS_PRIMITIVE;
+
        MONO_PROFILER_RAISE (vtable_loading, (vt));
 
        mono_class_compute_gc_descriptor (klass);
index 2c7dc9d..2eaa272 100644 (file)
@@ -5576,6 +5576,13 @@ common_vcall:
                        ip++;
                        MINT_IN_BREAK;
                }
+               MINT_IN_CASE(MINT_ARRAY_IS_PRIMITIVE) {
+                       MonoObject* const o = sp [-1].data.o;
+                       NULL_CHECK (o);
+                       sp [-1].data.i = m_class_is_primitive (m_class_get_element_class (mono_object_class (o)));
+                       ip++;
+                       MINT_IN_BREAK;
+               }
                MINT_IN_CASE(MINT_LDELEMA1) {
                        /* No bounds, one direction */
                        MonoArray *ao = (MonoArray*)sp [-2].data.o;
index 093d335..04def43 100644 (file)
@@ -704,6 +704,7 @@ OPDEF(MINT_GETCHR, "getchr", 1, Pop2, Push1, MintOpNoArgs)
 OPDEF(MINT_STRLEN, "strlen", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ARRAY_RANK, "array_rank", 1, Pop1, Push1, MintOpNoArgs)
 OPDEF(MINT_ARRAY_ELEMENT_SIZE, "array_element_size", 1, Pop1, Push1, MintOpNoArgs)
+OPDEF(MINT_ARRAY_IS_PRIMITIVE, "array_is_primitive", 1, Pop1, Push1, MintOpNoArgs)
 
 /* Calls */
 OPDEF(MINT_CALL, "call", 3, VarPop, Push1, MintOpMethodToken)
index 096992e..1c455c3 100644 (file)
@@ -1527,6 +1527,8 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas
                        *op = MINT_LDLEN;
                } else if (!strcmp (tm, "GetElementSize")) {
                        *op = MINT_ARRAY_ELEMENT_SIZE;
+               } else if (!strcmp (tm, "IsPrimitive")) {
+                       *op = MINT_ARRAY_IS_PRIMITIVE;
                } else if (!strcmp (tm, "Address")) {
                        MonoClass *check_class = readonly ? NULL : m_class_get_element_class (target_method->klass);
                        interp_emit_ldelema (td, target_method->klass, check_class);
index a9ef42a..0bf26e6 100644 (file)
@@ -770,6 +770,15 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOAD_MEMBASE, class_reg, vt_reg, MONO_STRUCT_OFFSET (MonoVTable, klass));
                        EMIT_NEW_LOAD_MEMBASE (cfg, ins, OP_LOADI4_MEMBASE, sizes_reg, class_reg, m_class_offsetof_sizes ());
                        return ins;
+               } else if (!strcmp (cmethod->name, "IsPrimitive")) {
+                       int dreg = alloc_ireg (cfg);
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOAD_MEMBASE, dreg, args [0]->dreg, MONO_STRUCT_OFFSET (MonoObject, vtable));
+                       MONO_EMIT_NEW_LOAD_MEMBASE_OP (cfg, OP_LOADU1_MEMBASE, dreg, dreg, MONO_STRUCT_OFFSET (MonoVTable, flags));
+                       MONO_EMIT_NEW_BIALU_IMM (cfg, OP_IAND_IMM, dreg, dreg, MONO_VT_FLAG_ARRAY_IS_PRIMITIVE);
+                       EMIT_NEW_BIALU_IMM (cfg, ins, OP_COMPARE_IMM, -1, dreg, 0);
+                       EMIT_NEW_UNALU (cfg, ins, OP_ICGT, dreg, -1);
+                       ins->type = STACK_I4;
+                       return ins;
                }
 
 #ifndef MONO_BIG_ARRAYS
index 6f4b24f..9320c96 100644 (file)
@@ -5,6 +5,7 @@
 using Internal.Runtime.CompilerServices;
 using System.Collections;
 using System.Collections.Generic;
+using System.Reflection;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using Mono;
@@ -493,6 +494,13 @@ namespace System
                        return 0;
                }
 
+               [Intrinsic]
+               public bool IsPrimitive ()
+               {
+                       ThrowHelper.ThrowNotSupportedException ();
+                       return false;
+               }
+
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                extern static bool CanChangePrimitive (Type srcType, Type dstType, bool reliable);
 
index 847a9e2..c22504a 100644 (file)
@@ -14,8 +14,7 @@ namespace System
 {
        partial class Buffer
        {
-               [MethodImpl (MethodImplOptions.InternalCall)]
-               static extern bool IsPrimitiveTypeArray (Array array);
+               static bool IsPrimitiveTypeArray (Array array) => array.IsPrimitive ();
 
                internal static unsafe void Memcpy (byte* dest, byte* src, int len) => Memmove (dest, src, (nuint) len);