Skip to content

Add non-intrinsic implementation for CreateSpan<T>. #60451

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ public static partial class RuntimeHelpers
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void InitializeArray(Array array, RuntimeFieldHandle fldHandle);

[MethodImpl(MethodImplOptions.InternalCall)]
private static extern unsafe void GetSpanDataFrom(
RuntimeFieldHandle fldHandle,
RuntimeTypeHandle targetTypeHandle,
void** data,
int* count);

// GetObjectValue is intended to allow value classes to be manipulated as 'Object'
// but have aliasing behavior of a value class. The intent is that you would use
// this function just before an assignment to a variable of type 'Object'. If the
Expand Down
37 changes: 37 additions & 0 deletions src/coreclr/classlibnative/bcltype/arraynative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1153,3 +1153,40 @@ FCIMPL2_IV(void, ArrayNative::InitializeArray, ArrayBase* pArrayRef, FCALLRuntim
HELPER_METHOD_FRAME_END();
}
FCIMPLEND

FCIMPL4(void, ArrayNative::GetSpanDataFrom, FCALLRuntimeFieldHandle structField, FCALLRuntimeTypeHandle targetType, void** data, INT32* count)
{
FCALL_CONTRACT;
struct
{
REFLECTFIELDREF refField;
} gc;
gc.refField = (REFLECTFIELDREF)ObjectToOBJECTREF(FCALL_RFH_TO_REFLECTFIELD(structField));
HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);

FieldDesc* pField = (FieldDesc*)gc.refField->GetField();

if (!pField->IsRVA())
COMPlusThrow(kArgumentException);

TypeHandle targetTypeHandle = FCALL_RTH_TO_REFLECTCLASS(targetType)->GetType();
if (!CorTypeInfo::IsPrimitiveType(targetTypeHandle.GetSignatureCorElementType()) && !targetTypeHandle.IsEnum())
COMPlusThrow(kArgumentException);

DWORD totalSize = pField->LoadSize();
DWORD targetTypeSize = targetTypeHandle.GetSize();

// Report the RVA field to the logger.
g_IBCLogger.LogRVADataAccess(pField);

_ASSERTE(data != NULL && count != NULL);
*data = pField->GetStaticAddressHandle(NULL);
*count = (INT32)totalSize / targetTypeSize;

#if BIGENDIAN
COMPlusThrow(kPlatformNotSupportedException);
#endif

HELPER_METHOD_FRAME_END();
}
FCIMPLEND
5 changes: 5 additions & 0 deletions src/coreclr/classlibnative/bcltype/arraynative.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#define _ARRAYNATIVE_H_

#include "fcall.h"
#include "runtimehandles.h"

struct FCALLRuntimeFieldHandle
{
Expand Down Expand Up @@ -45,6 +46,10 @@ class ArrayNative
// to a field.
static FCDECL2_IV(void, InitializeArray, ArrayBase* vArrayRef, FCALLRuntimeFieldHandle structField);

// This method will acquire data to create a span from a TypeHandle
// to a field.
static FCDECL4(void, GetSpanDataFrom, FCALLRuntimeFieldHandle structField, FCALLRuntimeTypeHandle targetType, void** data, INT32* count);

private:
// Helper for CreateInstance
static void CheckElementType(TypeHandle elementType);
Expand Down
1 change: 1 addition & 0 deletions src/coreclr/vm/ecalllist.h
Original file line number Diff line number Diff line change
Expand Up @@ -856,6 +856,7 @@ FCFuncEnd()
FCFuncStart(gRuntimeHelpers)
FCFuncElement("GetObjectValue", ObjectNative::GetObjectValue)
FCIntrinsic("InitializeArray", ArrayNative::InitializeArray, CORINFO_INTRINSIC_InitializeArray)
FCFuncElement("GetSpanDataFrom", ArrayNative::GetSpanDataFrom)
QCFuncElement("RunClassConstructor", ReflectionInvocation::RunClassConstructor)
QCFuncElement("RunModuleConstructor", ReflectionInvocation::RunModuleConstructor)
QCFuncElement("CompileMethod", ReflectionInvocation::CompileMethod)
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/vm/runtimehandles.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ typedef RuntimeTypeHandle FCALLRuntimeTypeHandle;
#define FCALL_RTH_TO_REFLECTCLASS(x) (x).pRuntimeTypeDONOTUSEDIRECTLY

class RuntimeTypeHandle {
ReflectClassBaseObject *pRuntimeTypeDONOTUSEDIRECTLY;
public:
ReflectClassBaseObject *pRuntimeTypeDONOTUSEDIRECTLY;

// Static method on RuntimeTypeHandle

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,5 +113,16 @@ internal static bool IsPrimitiveType(this CorElementType et)
[Intrinsic]
[CLSCompliant(false)]
public static Span<T> StackAlloc<T>(int length) { throw new InvalidProgramException(); }

public static ReadOnlySpan<T> CreateSpan<T>(RuntimeFieldHandle fldHandle)
{
unsafe
{
void* data = default;
int count = default;
GetSpanDataFrom(fldHandle, typeof(T).TypeHandle, &data, &count);
return new ReadOnlySpan<T>(data, count);
}
}
}
}
1 change: 1 addition & 0 deletions src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13134,6 +13134,7 @@ public static void ExecuteCodeWithGuaranteedCleanup(System.Runtime.CompilerServi
public static T[] GetSubArray<T>(T[] array, System.Range range) { throw null; }
public static object GetUninitializedObject([System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute(System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.NonPublicConstructors | System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes.PublicConstructors)] System.Type type) { throw null; }
public static void InitializeArray(System.Array array, System.RuntimeFieldHandle fldHandle) { }
public static ReadOnlySpan<T> CreateSpan<T>(System.RuntimeFieldHandle fldHandle) { throw null; }
public static bool IsReferenceOrContainsReferences<T>() { throw null; }
[System.ObsoleteAttribute("The Constrained Execution Region (CER) feature is not supported.", DiagnosticId = "SYSLIB0004", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public static void PrepareConstrainedRegions() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ public static void InitializeArray(Array array, RuntimeFieldHandle fldHandle)
InitializeArray(array, fldHandle.Value);
}

private static unsafe void GetSpanDataFrom(
RuntimeFieldHandle fldHandle,
RuntimeTypeHandle targetTypeHandle,
void** data,
int* count)
{
GetSpanDataFrom(fldHandle.Value, targetTypeHandle.Value, new IntPtr(data), new IntPtr(count));
}

public static int OffsetToStringData
{
[Intrinsic]
Expand Down Expand Up @@ -165,6 +174,13 @@ public static object GetUninitializedObject(
[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void InitializeArray(Array array, IntPtr fldHandle);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern unsafe void GetSpanDataFrom(
IntPtr fldHandle,
IntPtr targetTypeHandle,
IntPtr data,
IntPtr count);

[MethodImplAttribute(MethodImplOptions.InternalCall)]
private static extern void RunClassConstructor(IntPtr type);

Expand Down
32 changes: 31 additions & 1 deletion src/mono/mono/metadata/class-accessors.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ typedef enum {
PROP_FIELD_DEF_VALUES = 7, /* MonoFieldDefaultValue* */
PROP_DECLSEC_FLAGS = 8, /* guint32 */
PROP_WEAK_BITMAP = 9,
PROP_DIM_CONFLICTS = 10 /* GSList of MonoMethod* */
PROP_DIM_CONFLICTS = 10, /* GSList of MonoMethod* */
PROP_FIELD_DEF_VALUES_2BYTESWIZZLE = 11, /* MonoFieldDefaultValue* with default values swizzled at 2 byte boundaries*/
PROP_FIELD_DEF_VALUES_4BYTESWIZZLE = 12, /* MonoFieldDefaultValue* with default values swizzled at 4 byte boundaries*/
PROP_FIELD_DEF_VALUES_8BYTESWIZZLE = 13 /* MonoFieldDefaultValue* with default values swizzled at 8 byte boundaries*/
} InfrequentDataKind;

/* Accessors based on class kind*/
Expand Down Expand Up @@ -382,12 +385,39 @@ mono_class_get_field_def_values (MonoClass *klass)
return (MonoFieldDefaultValue*)get_pointer_property (klass, PROP_FIELD_DEF_VALUES);
}

MonoFieldDefaultValue*
mono_class_get_field_def_values_with_swizzle (MonoClass *klass, int swizzle)
{
InfrequentDataKind dataKind = PROP_FIELD_DEF_VALUES;
if (swizzle == 2)
dataKind = PROP_FIELD_DEF_VALUES_2BYTESWIZZLE;
else if (swizzle == 4)
dataKind = PROP_FIELD_DEF_VALUES_4BYTESWIZZLE;
else
dataKind = PROP_FIELD_DEF_VALUES_8BYTESWIZZLE;
return (MonoFieldDefaultValue*)get_pointer_property (klass, dataKind);
}


void
mono_class_set_field_def_values (MonoClass *klass, MonoFieldDefaultValue *values)
{
set_pointer_property (klass, PROP_FIELD_DEF_VALUES, values);
}

void
mono_class_set_field_def_values_with_swizzle (MonoClass *klass, MonoFieldDefaultValue *values, int swizzle)
{
InfrequentDataKind dataKind = PROP_FIELD_DEF_VALUES;
if (swizzle == 2)
dataKind = PROP_FIELD_DEF_VALUES_2BYTESWIZZLE;
else if (swizzle == 4)
dataKind = PROP_FIELD_DEF_VALUES_4BYTESWIZZLE;
else
dataKind = PROP_FIELD_DEF_VALUES_8BYTESWIZZLE;
set_pointer_property (klass, dataKind, values);
}

guint32
mono_class_get_declsec_flags (MonoClass *klass)
{
Expand Down
9 changes: 9 additions & 0 deletions src/mono/mono/metadata/class-internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -1406,9 +1406,15 @@ mono_class_set_event_info (MonoClass *klass, MonoClassEventInfo *info);
MonoFieldDefaultValue*
mono_class_get_field_def_values (MonoClass *klass);

MonoFieldDefaultValue*
mono_class_get_field_def_values_with_swizzle (MonoClass *klass, int swizzle);

void
mono_class_set_field_def_values (MonoClass *klass, MonoFieldDefaultValue *values);

void
mono_class_set_field_def_values_with_swizzle (MonoClass *klass, MonoFieldDefaultValue *values, int swizzle);

guint32
mono_class_get_declsec_flags (MonoClass *klass);

Expand Down Expand Up @@ -1467,6 +1473,9 @@ mono_class_get_object_finalize_slot (void);
MonoMethod *
mono_class_get_default_finalize_method (void);

const char *
mono_field_get_rva (MonoClassField *field, int swizzle);

void
mono_field_resolve_type (MonoClassField *field, MonoError *error);

Expand Down
71 changes: 60 additions & 11 deletions src/mono/mono/metadata/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -5435,8 +5435,8 @@ mono_field_get_offset (MonoClassField *field)
return field->offset;
}

static const char *
mono_field_get_rva (MonoClassField *field)
const char *
mono_field_get_rva (MonoClassField *field, int swizzle)
{
guint32 rva;
int field_index;
Expand All @@ -5445,21 +5445,70 @@ mono_field_get_rva (MonoClassField *field)

g_assert (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA);

def_values = mono_class_get_field_def_values (klass);
def_values = mono_class_get_field_def_values_with_swizzle (klass, swizzle);
if (!def_values) {
def_values = (MonoFieldDefaultValue *)mono_class_alloc0 (klass, sizeof (MonoFieldDefaultValue) * mono_class_get_field_count (klass));

mono_class_set_field_def_values (klass, def_values);
mono_class_set_field_def_values_with_swizzle (klass, def_values, swizzle);
}

field_index = mono_field_get_index (field);

if (!def_values [field_index].data && !image_is_dynamic (m_class_get_image (klass))) {
int first_field_idx = mono_class_get_first_field_idx (klass);
mono_metadata_field_info (m_class_get_image (field->parent), first_field_idx + field_index, NULL, &rva, NULL);
if (!rva)
g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), m_class_get_name (field->parent));
def_values [field_index].data = mono_image_rva_map (m_class_get_image (field->parent), rva);
if (!def_values [field_index].data) {
const char *rvaData;

if (!image_is_dynamic (m_class_get_image (klass)))
{
int first_field_idx = mono_class_get_first_field_idx (klass);
mono_metadata_field_info (m_class_get_image (field->parent), first_field_idx + field_index, NULL, &rva, NULL);
if (!rva)
g_warning ("field %s in %s should have RVA data, but hasn't", mono_field_get_name (field), m_class_get_name (field->parent));

rvaData = mono_image_rva_map (m_class_get_image (field->parent), rva);
}
else
{
rvaData = mono_field_get_data (field);
}

if (rvaData == NULL)
return NULL;

if (swizzle != 1)
{
int dummy;
int dataSizeInBytes = mono_type_size (field->type, &dummy);
char *swizzledRvaData = mono_class_alloc0 (klass, dataSizeInBytes);

#define SWAP(n) { \
guint ## n *data = (guint ## n *) swizzledRvaData; \
guint ## n *src = (guint ## n *) rvaData; \
int i, \
nEnt = (dataSizeInBytes / sizeof(guint ## n)); \
\
for (i = 0; i < nEnt; i++) { \
data[i] = read ## n (&src[i]); \
} \
}
if (swizzle == 2)
{
SWAP (16);
}
else if (swizzle == 4)
{
SWAP (32);
}
else
{
SWAP (64);
}
def_values [field_index].data = swizzledRvaData;
}
else
#undef SWAP
{
def_values [field_index].data = rvaData;
}
}

return def_values [field_index].data;
Expand All @@ -5480,7 +5529,7 @@ mono_field_get_data (MonoClassField *field)

return mono_class_get_field_default_value (field, &def_type);
} else if (field->type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA) {
return mono_field_get_rva (field);
return mono_field_get_rva (field, 1);
} else {
return NULL;
}
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/metadata/icall-def-netcore.h
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ HANDLES(MPROP_5, "internal_from_handle_type", ves_icall_System_Reflection_Runtim

ICALL_TYPE(RUNH, "System.Runtime.CompilerServices.RuntimeHelpers", RUNH_1)
HANDLES(RUNH_1, "GetObjectValue", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetObjectValue, MonoObject, 1, (MonoObject))
HANDLES(RUNH_6, "GetSpanDataFrom", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetSpanDataFrom, void, 4, (MonoClassField_ptr, MonoType_ptr, gpointer, gpointer))
HANDLES(RUNH_2, "GetUninitializedObjectInternal", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetUninitializedObjectInternal, MonoObject, 1, (MonoType_ptr))
HANDLES(RUNH_3, "InitializeArray", ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray, void, 2, (MonoArray, MonoClassField_ptr))
HANDLES(RUNH_7, "InternalGetHashCode", mono_object_hash_icall, int, 1, (MonoObject))
Expand Down
31 changes: 31 additions & 0 deletions src/mono/mono/metadata/icall.c
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,37 @@ ves_icall_System_Runtime_RuntimeImports_ZeroMemory (guint8 *p, size_t byte_lengt
memset (p, 0, byte_length);
}

void
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_GetSpanDataFrom (MonoClassField *field_handle, MonoType_ptr targetTypeHandle, gpointer dataPtr, gpointer countPtr, MonoError *error)
{
gint32* count = (gint32*)countPtr;
const char **data = (const char **)dataPtr;
MonoType *field_type = mono_field_get_type_checked (field_handle, error);
if (!field_type)
return;

if (!(field_type->attrs & FIELD_ATTRIBUTE_HAS_FIELD_RVA)) {
mono_error_set_argument_format (error, "field_handle", "Field '%s' doesn't have an RVA", mono_field_get_name (field_handle));
return;
}

MonoType *type = targetTypeHandle;
if (MONO_TYPE_IS_REFERENCE (type) || type->type == MONO_TYPE_VALUETYPE) {
mono_error_set_argument (error, "array", "Cannot initialize array of non-primitive type");
return;
}

int swizzle = 1;
int align;
#if G_BYTE_ORDER != G_LITTLE_ENDIAN
swizzle = mono_type_size (type, &align);
#endif

*data = mono_field_get_rva (field_handle, swizzle);
int dummy;
*count = mono_type_size (field_type, &dummy)/mono_type_size (type, &align);
}

void
ves_icall_System_Runtime_CompilerServices_RuntimeHelpers_InitializeArray (MonoArrayHandle array, MonoClassField *field_handle, MonoError *error)
{
Expand Down
19 changes: 19 additions & 0 deletions src/tests/JIT/Intrinsics/CreateSpan.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
//

using System;

class CreateSpanTest
{
static int Main()
{
ReadOnlySpan<int> intSpan = (ReadOnlySpan<int>)new int[]{25,15,35,25};
int result = 0;
foreach (int i in intSpan)
{
result += i;
}
return result;
}
}
Loading