Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomáš Rylek <trylek@microsoft.com>2020-12-08 05:19:44 +0300
committerGitHub <noreply@github.com>2020-12-08 05:19:44 +0300
commit69e114c1abf91241a0eeecf1ecceab4711b8aa62 (patch)
treeb81a0b35748f5e598412bcc504335cdbd322cd43 /src/coreclr/classlibnative
parent0ec07945a9759a72a689edbb01e69b232e26e05a (diff)
December infra rollout - remove duplicated 'src' from coreclr subrepo (src/coreclr/src becomes src/coreclr) (#44973)
* Move src/coreclr/src/Directory.Build.targets to src/coreclr Merge src/coreclr/src/CMakeLists.txt into src/coreclr/CMakeLists.txt * Mechanical move of src/coreclr/src to src/coreclr * Scripts adjustments to reflect the changed paths
Diffstat (limited to 'src/coreclr/classlibnative')
-rw-r--r--src/coreclr/classlibnative/CMakeLists.txt8
-rw-r--r--src/coreclr/classlibnative/bcltype/CMakeLists.txt20
-rw-r--r--src/coreclr/classlibnative/bcltype/arraynative.cpp1168
-rw-r--r--src/coreclr/classlibnative/bcltype/arraynative.h71
-rw-r--r--src/coreclr/classlibnative/bcltype/arraynative.inl325
-rw-r--r--src/coreclr/classlibnative/bcltype/oavariant.cpp429
-rw-r--r--src/coreclr/classlibnative/bcltype/oavariant.h45
-rw-r--r--src/coreclr/classlibnative/bcltype/objectnative.cpp336
-rw-r--r--src/coreclr/classlibnative/bcltype/objectnative.h43
-rw-r--r--src/coreclr/classlibnative/bcltype/stringnative.cpp99
-rw-r--r--src/coreclr/classlibnative/bcltype/stringnative.h67
-rw-r--r--src/coreclr/classlibnative/bcltype/system.cpp606
-rw-r--r--src/coreclr/classlibnative/bcltype/system.h98
-rw-r--r--src/coreclr/classlibnative/bcltype/varargsnative.cpp638
-rw-r--r--src/coreclr/classlibnative/bcltype/varargsnative.h32
-rw-r--r--src/coreclr/classlibnative/bcltype/variant.cpp289
-rw-r--r--src/coreclr/classlibnative/bcltype/variant.h44
-rw-r--r--src/coreclr/classlibnative/float/CMakeLists.txt18
-rw-r--r--src/coreclr/classlibnative/float/floatdouble.cpp331
-rw-r--r--src/coreclr/classlibnative/float/floatsingle.cpp318
-rw-r--r--src/coreclr/classlibnative/inc/floatdouble.h42
-rw-r--r--src/coreclr/classlibnative/inc/floatsingle.h42
-rw-r--r--src/coreclr/classlibnative/inc/nls.h33
23 files changed, 5102 insertions, 0 deletions
diff --git a/src/coreclr/classlibnative/CMakeLists.txt b/src/coreclr/classlibnative/CMakeLists.txt
new file mode 100644
index 00000000000..aeaba89b82b
--- /dev/null
+++ b/src/coreclr/classlibnative/CMakeLists.txt
@@ -0,0 +1,8 @@
+include_directories(BEFORE "../vm")
+include_directories("../inc")
+include_directories(BEFORE "../vm/${ARCH_SOURCES_DIR}")
+include_directories("../debug/inc")
+include_directories("../debug/inc/dump")
+
+add_subdirectory(bcltype)
+add_subdirectory(float)
diff --git a/src/coreclr/classlibnative/bcltype/CMakeLists.txt b/src/coreclr/classlibnative/bcltype/CMakeLists.txt
new file mode 100644
index 00000000000..fdcf344c16a
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/CMakeLists.txt
@@ -0,0 +1,20 @@
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(BCLTYPE_SOURCES
+ arraynative.cpp
+ oavariant.cpp
+ objectnative.cpp
+ stringnative.cpp
+ system.cpp
+ varargsnative.cpp
+ variant.cpp
+)
+
+add_library_clr(bcltype_obj
+ OBJECT
+ ${BCLTYPE_SOURCES}
+)
+
+add_dependencies(bcltype_obj eventing_headers)
+add_library(bcltype INTERFACE)
+target_sources(bcltype INTERFACE $<TARGET_OBJECTS:bcltype_obj>)
diff --git a/src/coreclr/classlibnative/bcltype/arraynative.cpp b/src/coreclr/classlibnative/bcltype/arraynative.cpp
new file mode 100644
index 00000000000..50e652b5b66
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/arraynative.cpp
@@ -0,0 +1,1168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: ArrayNative.cpp
+//
+
+//
+// This file contains the native methods that support the Array class
+//
+
+
+#include "common.h"
+#include "arraynative.h"
+#include "excep.h"
+#include "field.h"
+#include "invokeutil.h"
+
+#include "arraynative.inl"
+
+// Returns a bool to indicate if the array is of primitive types or not.
+FCIMPL1(INT32, ArrayNative::GetCorElementTypeOfElementType, ArrayBase* arrayUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ _ASSERTE(arrayUNSAFE != NULL);
+
+ return arrayUNSAFE->GetArrayElementTypeHandle().GetVerifierCorElementType();
+}
+FCIMPLEND
+
+// array is GC protected by caller
+void ArrayInitializeWorker(ARRAYBASEREF * arrayRef,
+ MethodTable* pArrayMT,
+ MethodTable* pElemMT)
+{
+ STATIC_CONTRACT_MODE_COOPERATIVE;
+
+ // Ensure that the array element type is fully loaded before executing its code
+ pElemMT->EnsureInstanceActive();
+
+ //can not use contract here because of SEH
+ _ASSERTE(IsProtectedByGCFrame (arrayRef));
+
+ SIZE_T offset = ArrayBase::GetDataPtrOffset(pArrayMT);
+ SIZE_T size = pArrayMT->GetComponentSize();
+ SIZE_T cElements = (*arrayRef)->GetNumComponents();
+
+ MethodTable * pCanonMT = pElemMT->GetCanonicalMethodTable();
+ WORD slot = pCanonMT->GetDefaultConstructorSlot();
+
+ PCODE ctorFtn = pCanonMT->GetSlot(slot);
+
+#if defined(TARGET_X86) && !defined(TARGET_UNIX)
+ BEGIN_CALL_TO_MANAGED();
+
+
+ for (SIZE_T i = 0; i < cElements; i++)
+ {
+ // Since GetSlot() is not idempotent and may have returned
+ // a non-optimal entry-point the first time round.
+ if (i == 1)
+ {
+ ctorFtn = pCanonMT->GetSlot(slot);
+ }
+
+ BYTE* thisPtr = (((BYTE*) OBJECTREFToObject (*arrayRef)) + offset);
+
+#ifdef _DEBUG
+ __asm {
+ mov ECX, thisPtr
+ mov EDX, pElemMT // Instantiation argument if the type is generic
+ call [ctorFtn]
+ nop // Mark the fact that we can call managed code
+ }
+#else // _DEBUG
+ typedef void (__fastcall * CtorFtnType)(BYTE*, BYTE*);
+ (*(CtorFtnType)ctorFtn)(thisPtr, (BYTE*)pElemMT);
+#endif // _DEBUG
+
+ offset += size;
+ }
+
+ END_CALL_TO_MANAGED();
+#else // TARGET_X86 && !TARGET_UNIX
+ //
+ // This is quite a bit slower, but it is portable.
+ //
+
+ for (SIZE_T i =0; i < cElements; i++)
+ {
+ // Since GetSlot() is not idempotent and may have returned
+ // a non-optimal entry-point the first time round.
+ if (i == 1)
+ {
+ ctorFtn = pCanonMT->GetSlot(slot);
+ }
+
+ BYTE* thisPtr = (((BYTE*) OBJECTREFToObject (*arrayRef)) + offset);
+
+ PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(ctorFtn);
+ DECLARE_ARGHOLDER_ARRAY(args, 2);
+ args[ARGNUM_0] = PTR_TO_ARGHOLDER(thisPtr);
+ args[ARGNUM_1] = PTR_TO_ARGHOLDER(pElemMT); // Instantiation argument if the type is generic
+ CALL_MANAGED_METHOD_NORET(args);
+
+ offset += size;
+ }
+#endif // !TARGET_X86 || TARGET_UNIX
+}
+
+
+FCIMPL1(void, ArrayNative::Initialize, ArrayBase* array)
+{
+ FCALL_CONTRACT;
+
+ if (array == NULL)
+ {
+ FCThrowVoid(kNullReferenceException);
+ }
+
+
+ MethodTable* pArrayMT = array->GetMethodTable();
+
+ TypeHandle thElem = pArrayMT->GetArrayElementTypeHandle();
+ if (thElem.IsTypeDesc())
+ return;
+
+ MethodTable * pElemMT = thElem.AsMethodTable();
+ if (!pElemMT->HasDefaultConstructor() || !pElemMT->IsValueType())
+ return;
+
+ ARRAYBASEREF arrayRef (array);
+ HELPER_METHOD_FRAME_BEGIN_1(arrayRef);
+
+ ArrayInitializeWorker(&arrayRef, pArrayMT, pElemMT);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+ // Returns whether you can directly copy an array of srcType into destType.
+FCIMPL2(FC_BOOL_RET, ArrayNative::IsSimpleCopy, ArrayBase* pSrc, ArrayBase* pDst)
+{
+ FCALL_CONTRACT;
+
+ _ASSERTE(pSrc != NULL);
+ _ASSERTE(pDst != NULL);
+
+ // This case is expected to be handled by the fast path
+ _ASSERTE(pSrc->GetMethodTable() != pDst->GetMethodTable());
+
+ TypeHandle srcTH = pSrc->GetMethodTable()->GetArrayElementTypeHandle();
+ TypeHandle destTH = pDst->GetMethodTable()->GetArrayElementTypeHandle();
+ if (srcTH == destTH) // This check kicks for different array kind or dimensions
+ FC_RETURN_BOOL(true);
+
+ if (srcTH.IsValueType())
+ {
+ // Value class boxing
+ if (!destTH.IsValueType())
+ FC_RETURN_BOOL(false);
+
+ const CorElementType srcElType = srcTH.GetVerifierCorElementType();
+ const CorElementType destElType = destTH.GetVerifierCorElementType();
+ _ASSERTE(srcElType < ELEMENT_TYPE_MAX);
+ _ASSERTE(destElType < ELEMENT_TYPE_MAX);
+
+ // Copying primitives from one type to another
+ if (CorTypeInfo::IsPrimitiveType_NoThrow(srcElType) && CorTypeInfo::IsPrimitiveType_NoThrow(destElType))
+ {
+ if (GetNormalizedIntegralArrayElementType(srcElType) == GetNormalizedIntegralArrayElementType(destElType))
+ FC_RETURN_BOOL(true);
+ }
+ }
+ else
+ {
+ // Value class unboxing
+ if (destTH.IsValueType())
+ FC_RETURN_BOOL(false);
+ }
+
+ TypeHandle::CastResult r = srcTH.CanCastToCached(destTH);
+ if (r != TypeHandle::MaybeCast)
+ {
+ FC_RETURN_BOOL(r);
+ }
+
+ struct
+ {
+ OBJECTREF src;
+ OBJECTREF dst;
+ } gc;
+
+ gc.src = ObjectToOBJECTREF(pSrc);
+ gc.dst = ObjectToOBJECTREF(pDst);
+
+ BOOL iRetVal = FALSE;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
+ iRetVal = srcTH.CanCastTo(destTH);
+ HELPER_METHOD_FRAME_END();
+
+ FC_RETURN_BOOL(iRetVal);
+}
+FCIMPLEND
+
+
+// Returns an enum saying whether you can copy an array of srcType into destType.
+ArrayNative::AssignArrayEnum ArrayNative::CanAssignArrayType(const BASEARRAYREF pSrc, const BASEARRAYREF pDest)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pSrc != NULL);
+ PRECONDITION(pDest != NULL);
+ }
+ CONTRACTL_END;
+
+ // This first bit is a minor optimization: e.g. when copying byte[] to byte[]
+ // we do not need to call GetArrayElementTypeHandle().
+ MethodTable *pSrcMT = pSrc->GetMethodTable();
+ MethodTable *pDestMT = pDest->GetMethodTable();
+ _ASSERTE(pSrcMT != pDestMT); // Handled by fast path
+
+ TypeHandle srcTH = pSrcMT->GetArrayElementTypeHandle();
+ TypeHandle destTH = pDestMT->GetArrayElementTypeHandle();
+ _ASSERTE(srcTH != destTH); // Handled by fast path
+
+ // Value class boxing
+ if (srcTH.IsValueType() && !destTH.IsValueType())
+ {
+ if (srcTH.CanCastTo(destTH))
+ return AssignBoxValueClassOrPrimitive;
+ else
+ return AssignWrongType;
+ }
+
+ // Value class unboxing.
+ if (!srcTH.IsValueType() && destTH.IsValueType())
+ {
+ if (srcTH.CanCastTo(destTH))
+ return AssignUnboxValueClass;
+ else if (destTH.CanCastTo(srcTH)) // V extends IV. Copying from IV to V, or Object to V.
+ return AssignUnboxValueClass;
+ else
+ return AssignWrongType;
+ }
+
+ const CorElementType srcElType = srcTH.GetVerifierCorElementType();
+ const CorElementType destElType = destTH.GetVerifierCorElementType();
+ _ASSERTE(srcElType < ELEMENT_TYPE_MAX);
+ _ASSERTE(destElType < ELEMENT_TYPE_MAX);
+
+ // Copying primitives from one type to another
+ if (CorTypeInfo::IsPrimitiveType_NoThrow(srcElType) && CorTypeInfo::IsPrimitiveType_NoThrow(destElType))
+ {
+ _ASSERTE(srcElType != destElType); // Handled by fast path
+ if (InvokeUtil::CanPrimitiveWiden(destElType, srcElType))
+ return AssignPrimitiveWiden;
+ else
+ return AssignWrongType;
+ }
+
+ // dest Object extends src
+ _ASSERTE(!srcTH.CanCastTo(destTH)); // Handled by fast path
+
+ // src Object extends dest
+ if (destTH.CanCastTo(srcTH))
+ return AssignMustCast;
+
+ // class X extends/implements src and implements dest.
+ if (destTH.IsInterface() && srcElType != ELEMENT_TYPE_VALUETYPE)
+ return AssignMustCast;
+
+ // class X implements src and extends/implements dest
+ if (srcTH.IsInterface() && destElType != ELEMENT_TYPE_VALUETYPE)
+ return AssignMustCast;
+
+ return AssignWrongType;
+}
+
+
+// Casts and assigns each element of src array to the dest array type.
+void ArrayNative::CastCheckEachElement(const BASEARRAYREF pSrcUnsafe, const unsigned int srcIndex, BASEARRAYREF pDestUnsafe, unsigned int destIndex, const unsigned int len)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pSrcUnsafe != NULL);
+ PRECONDITION(srcIndex >= 0);
+ PRECONDITION(pDestUnsafe != NULL);
+ PRECONDITION(len > 0);
+ }
+ CONTRACTL_END;
+
+ // pSrc is either a PTRARRAYREF or a multidimensional array.
+ TypeHandle destTH = pDestUnsafe->GetArrayElementTypeHandle();
+
+ struct _gc
+ {
+ OBJECTREF obj;
+ BASEARRAYREF pDest;
+ BASEARRAYREF pSrc;
+ } gc;
+
+ gc.obj = NULL;
+ gc.pDest = pDestUnsafe;
+ gc.pSrc = pSrcUnsafe;
+
+ GCPROTECT_BEGIN(gc);
+
+ for(unsigned int i=srcIndex; i<srcIndex + len; ++i)
+ {
+ gc.obj = ObjectToOBJECTREF(*((Object**) gc.pSrc->GetDataPtr() + i));
+
+ // Now that we have grabbed obj, we are no longer subject to races from another
+ // mutator thread.
+ if (gc.obj != NULL && !ObjIsInstanceOf(OBJECTREFToObject(gc.obj), destTH))
+ COMPlusThrow(kInvalidCastException, W("InvalidCast_DownCastArrayElement"));
+
+ OBJECTREF * destData = (OBJECTREF*)(gc.pDest->GetDataPtr()) + i - srcIndex + destIndex;
+ SetObjectReference(destData, gc.obj);
+ }
+
+ GCPROTECT_END();
+
+ return;
+}
+
+
+// Will box each element in an array of value classes or primitives into an array of Objects.
+void ArrayNative::BoxEachElement(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pSrc != NULL);
+ PRECONDITION(srcIndex >= 0);
+ PRECONDITION(pDest != NULL);
+ PRECONDITION(length > 0);
+ }
+ CONTRACTL_END;
+
+ // pDest is either a PTRARRAYREF or a multidimensional array.
+ _ASSERTE(pSrc!=NULL && srcIndex>=0 && pDest!=NULL && destIndex>=0 && length>=0);
+ TypeHandle srcTH = pSrc->GetArrayElementTypeHandle();
+#ifdef _DEBUG
+ TypeHandle destTH = pDest->GetArrayElementTypeHandle();
+#endif
+ _ASSERTE(srcTH.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS || srcTH.GetSignatureCorElementType() == ELEMENT_TYPE_VALUETYPE || CorTypeInfo::IsPrimitiveType(pSrc->GetArrayElementType()));
+ _ASSERTE(!destTH.GetMethodTable()->IsValueType());
+
+ // Get method table of type we're copying from - we need to allocate objects of that type.
+ MethodTable * pSrcMT = srcTH.AsMethodTable();
+ PREFIX_ASSUME(pSrcMT != NULL);
+
+ if (!pSrcMT->IsClassInited())
+ {
+ BASEARRAYREF pSrcTmp = pSrc;
+ BASEARRAYREF pDestTmp = pDest;
+ GCPROTECT_BEGIN (pSrcTmp);
+ GCPROTECT_BEGIN (pDestTmp);
+ pSrcMT->CheckRunClassInitThrowing();
+ pSrc = pSrcTmp;
+ pDest = pDestTmp;
+ GCPROTECT_END ();
+ GCPROTECT_END ();
+ }
+
+ const unsigned int srcSize = pSrcMT->GetNumInstanceFieldBytes();
+ unsigned int srcArrayOffset = srcIndex * srcSize;
+
+ struct _gc
+ {
+ BASEARRAYREF src;
+ BASEARRAYREF dest;
+ OBJECTREF obj;
+ } gc;
+
+ gc.src = pSrc;
+ gc.dest = pDest;
+ gc.obj = NULL;
+
+ void* srcPtr = 0;
+ GCPROTECT_BEGIN(gc);
+ GCPROTECT_BEGININTERIOR(srcPtr);
+ for (unsigned int i=destIndex; i < destIndex+length; i++, srcArrayOffset += srcSize)
+ {
+ srcPtr = (BYTE*)gc.src->GetDataPtr() + srcArrayOffset;
+ gc.obj = pSrcMT->FastBox(&srcPtr);
+
+ OBJECTREF * destData = (OBJECTREF*)((gc.dest)->GetDataPtr()) + i;
+ SetObjectReference(destData, gc.obj);
+ }
+ GCPROTECT_END();
+ GCPROTECT_END();
+}
+
+
+// Unboxes from an Object[] into a value class or primitive array.
+void ArrayNative::UnBoxEachElement(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ PRECONDITION(pSrc != NULL);
+ PRECONDITION(srcIndex >= 0);
+ PRECONDITION(pDest != NULL);
+ PRECONDITION(destIndex >= 0);
+ PRECONDITION(length > 0);
+ }
+ CONTRACTL_END;
+
+#ifdef _DEBUG
+ TypeHandle srcTH = pSrc->GetArrayElementTypeHandle();
+#endif
+ TypeHandle destTH = pDest->GetArrayElementTypeHandle();
+ _ASSERTE(destTH.GetSignatureCorElementType() == ELEMENT_TYPE_CLASS || destTH.GetSignatureCorElementType() == ELEMENT_TYPE_VALUETYPE || CorTypeInfo::IsPrimitiveType(pDest->GetArrayElementType()));
+ _ASSERTE(!srcTH.GetMethodTable()->IsValueType());
+
+ MethodTable * pDestMT = destTH.AsMethodTable();
+ PREFIX_ASSUME(pDestMT != NULL);
+
+ SIZE_T destSize = pDest->GetComponentSize();
+ BYTE* srcData = (BYTE*) pSrc->GetDataPtr() + srcIndex * sizeof(OBJECTREF);
+ BYTE* data = (BYTE*) pDest->GetDataPtr() + destIndex * destSize;
+
+ for(; length>0; length--, srcData += sizeof(OBJECTREF), data += destSize)
+ {
+ OBJECTREF obj = ObjectToOBJECTREF(*(Object**)srcData);
+
+ // Now that we have retrieved the element, we are no longer subject to race
+ // conditions from another array mutator.
+
+ if (!pDestMT->UnBoxInto(data, obj))
+ goto fail;
+ }
+ return;
+
+fail:
+ COMPlusThrow(kInvalidCastException, W("InvalidCast_DownCastArrayElement"));
+}
+
+
+// Widen primitive types to another primitive type.
+void ArrayNative::PrimitiveWiden(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ PRECONDITION(pSrc != NULL);
+ PRECONDITION(srcIndex >= 0);
+ PRECONDITION(pDest != NULL);
+ PRECONDITION(destIndex >= 0);
+ PRECONDITION(length > 0);
+ }
+ CONTRACTL_END;
+
+ // Get appropriate sizes, which requires method tables.
+ TypeHandle srcTH = pSrc->GetArrayElementTypeHandle();
+ TypeHandle destTH = pDest->GetArrayElementTypeHandle();
+
+ const CorElementType srcElType = srcTH.GetVerifierCorElementType();
+ const CorElementType destElType = destTH.GetVerifierCorElementType();
+ const unsigned int srcSize = GetSizeForCorElementType(srcElType);
+ const unsigned int destSize = GetSizeForCorElementType(destElType);
+
+ BYTE* srcData = (BYTE*) pSrc->GetDataPtr() + srcIndex * srcSize;
+ BYTE* data = (BYTE*) pDest->GetDataPtr() + destIndex * destSize;
+
+ _ASSERTE(srcElType != destElType); // We shouldn't be here if these are the same type.
+ _ASSERTE(CorTypeInfo::IsPrimitiveType_NoThrow(srcElType) && CorTypeInfo::IsPrimitiveType_NoThrow(destElType));
+
+ for(; length>0; length--, srcData += srcSize, data += destSize)
+ {
+ // We pretty much have to do some fancy datatype mangling every time here, for
+ // converting w/ sign extension and floating point conversions.
+ switch (srcElType)
+ {
+ case ELEMENT_TYPE_U1:
+ switch (destElType)
+ {
+ case ELEMENT_TYPE_R4:
+ *(float*)data = *(UINT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R8:
+ *(double*)data = *(UINT8*)srcData;
+ break;
+#ifndef BIGENDIAN
+ default:
+ *(UINT8*)data = *(UINT8*)srcData;
+ memset(data+1, 0, destSize - 1);
+ break;
+#else // BIGENDIAN
+ case ELEMENT_TYPE_CHAR:
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ *(INT16*)data = *(UINT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ *(INT32*)data = *(UINT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ *(INT64*)data = *(UINT8*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Array.Copy from U1 to another type hit unsupported widening conversion");
+#endif // BIGENDIAN
+ }
+ break;
+
+
+ case ELEMENT_TYPE_I1:
+ switch (destElType)
+ {
+ case ELEMENT_TYPE_I2:
+ *(INT16*)data = *(INT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I4:
+ *(INT32*)data = *(INT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I8:
+ *(INT64*)data = *(INT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R4:
+ *(float*)data = *(INT8*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R8:
+ *(double*)data = *(INT8*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Array.Copy from I1 to another type hit unsupported widening conversion");
+ }
+ break;
+
+
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_CHAR:
+ switch (destElType)
+ {
+ case ELEMENT_TYPE_R4:
+ *(float*)data = *(UINT16*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R8:
+ *(double*)data = *(UINT16*)srcData;
+ break;
+#ifndef BIGENDIAN
+ default:
+ *(UINT16*)data = *(UINT16*)srcData;
+ memset(data+2, 0, destSize - 2);
+ break;
+#else // BIGENDIAN
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_CHAR:
+ *(UINT16*)data = *(UINT16*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ *(UINT32*)data = *(UINT16*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ *(UINT64*)data = *(UINT16*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Array.Copy from U1 to another type hit unsupported widening conversion");
+#endif // BIGENDIAN
+ }
+ break;
+
+
+ case ELEMENT_TYPE_I2:
+ switch (destElType)
+ {
+ case ELEMENT_TYPE_I4:
+ *(INT32*)data = *(INT16*)srcData;
+ break;
+
+ case ELEMENT_TYPE_I8:
+ *(INT64*)data = *(INT16*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R4:
+ *(float*)data = *(INT16*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R8:
+ *(double*)data = *(INT16*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Array.Copy from I2 to another type hit unsupported widening conversion");
+ }
+ break;
+
+
+ case ELEMENT_TYPE_I4:
+ switch (destElType)
+ {
+ case ELEMENT_TYPE_I8:
+ *(INT64*)data = *(INT32*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R4:
+ *(float*)data = (float)*(INT32*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R8:
+ *(double*)data = *(INT32*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Array.Copy from I4 to another type hit unsupported widening conversion");
+ }
+ break;
+
+
+ case ELEMENT_TYPE_U4:
+ switch (destElType)
+ {
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ *(INT64*)data = *(UINT32*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R4:
+ *(float*)data = (float)*(UINT32*)srcData;
+ break;
+
+ case ELEMENT_TYPE_R8:
+ *(double*)data = *(UINT32*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Array.Copy from U4 to another type hit unsupported widening conversion");
+ }
+ break;
+
+
+ case ELEMENT_TYPE_I8:
+ if (destElType == ELEMENT_TYPE_R4)
+ {
+ *(float*) data = (float) *(INT64*)srcData;
+ }
+ else
+ {
+ _ASSERTE(destElType==ELEMENT_TYPE_R8);
+ *(double*) data = (double) *(INT64*)srcData;
+ }
+ break;
+
+
+ case ELEMENT_TYPE_U8:
+ if (destElType == ELEMENT_TYPE_R4)
+ {
+ //*(float*) data = (float) *(UINT64*)srcData;
+ INT64 srcVal = *(INT64*)srcData;
+ float f = (float) srcVal;
+ if (srcVal < 0)
+ f += 4294967296.0f * 4294967296.0f; // This is 2^64
+
+ *(float*) data = f;
+ }
+ else
+ {
+ _ASSERTE(destElType==ELEMENT_TYPE_R8);
+ //*(double*) data = (double) *(UINT64*)srcData;
+ INT64 srcVal = *(INT64*)srcData;
+ double d = (double) srcVal;
+ if (srcVal < 0)
+ d += 4294967296.0 * 4294967296.0; // This is 2^64
+
+ *(double*) data = d;
+ }
+ break;
+
+
+ case ELEMENT_TYPE_R4:
+ *(double*) data = *(float*)srcData;
+ break;
+
+ default:
+ _ASSERTE(!"Fell through outer switch in PrimitiveWiden! Unknown primitive type for source array!");
+ }
+ }
+}
+
+//
+// This is a GC safe variant of the memmove intrinsic. It sets the cards, and guarantees that the object references in the GC heap are
+// updated atomically.
+//
+// The CRT version of memmove does not always guarantee that updates of aligned fields stay atomic (e.g. it is using "rep movsb" in some cases).
+// Type safety guarantees and background GC scanning requires object references in GC heap to be updated atomically.
+//
+void memmoveGCRefs(void *dest, const void *src, size_t len)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(dest != nullptr);
+ _ASSERTE(src != nullptr);
+
+ // Make sure everything is pointer aligned
+ _ASSERTE(IS_ALIGNED(dest, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(src, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(len, sizeof(SIZE_T)));
+
+ _ASSERTE(CheckPointer(dest));
+ _ASSERTE(CheckPointer(src));
+
+ if (len != 0 && dest != src)
+ {
+ InlinedMemmoveGCRefsHelper(dest, src, len);
+ }
+}
+
+FCIMPL5(void, ArrayNative::CopySlow, ArrayBase* pSrc, INT32 iSrcIndex, ArrayBase* pDst, INT32 iDstIndex, INT32 iLength)
+{
+ FCALL_CONTRACT;
+
+ struct _gc
+ {
+ BASEARRAYREF pSrc;
+ BASEARRAYREF pDst;
+ } gc;
+
+ gc.pSrc = (BASEARRAYREF)pSrc;
+ gc.pDst = (BASEARRAYREF)pDst;
+
+ // cannot pass null for source or destination
+ _ASSERTE(gc.pSrc != NULL && gc.pDst != NULL);
+
+ // source and destination must be arrays
+ _ASSERTE(gc.pSrc->GetMethodTable()->IsArray());
+ _ASSERTE(gc.pDst->GetMethodTable()->IsArray());
+
+ _ASSERTE(gc.pSrc->GetRank() == gc.pDst->GetRank());
+
+ // array bounds checking
+ _ASSERTE(iLength >= 0);
+ _ASSERTE(iSrcIndex >= 0);
+ _ASSERTE(iDstIndex >= 0);
+ _ASSERTE((DWORD)(iSrcIndex + iLength) <= gc.pSrc->GetNumComponents());
+ _ASSERTE((DWORD)(iDstIndex + iLength) <= gc.pDst->GetNumComponents());
+
+ HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
+
+ int r = CanAssignArrayType(gc.pSrc, gc.pDst);
+
+ if (r == AssignWrongType)
+ COMPlusThrow(kArrayTypeMismatchException, W("ArrayTypeMismatch_CantAssignType"));
+
+ if (iLength > 0)
+ {
+ switch (r)
+ {
+ case AssignUnboxValueClass:
+ UnBoxEachElement(gc.pSrc, iSrcIndex, gc.pDst, iDstIndex, iLength);
+ break;
+
+ case AssignBoxValueClassOrPrimitive:
+ BoxEachElement(gc.pSrc, iSrcIndex, gc.pDst, iDstIndex, iLength);
+ break;
+
+ case AssignMustCast:
+ CastCheckEachElement(gc.pSrc, iSrcIndex, gc.pDst, iDstIndex, iLength);
+ break;
+
+ case AssignPrimitiveWiden:
+ PrimitiveWiden(gc.pSrc, iSrcIndex, gc.pDst, iDstIndex, iLength);
+ break;
+
+ default:
+ _ASSERTE(!"Fell through switch in Array.Copy!");
+ }
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+// Check we're allowed to create an array with the given element type.
+void ArrayNative::CheckElementType(TypeHandle elementType)
+{
+ // Checks apply recursively for arrays of arrays etc.
+ if (elementType.IsArray())
+ {
+ CheckElementType(elementType.GetArrayElementTypeHandle());
+ return;
+ }
+
+ // Check for simple types first.
+ if (!elementType.IsTypeDesc())
+ {
+ MethodTable *pMT = elementType.AsMethodTable();
+
+ // Check for byref-like types.
+ if (pMT->IsByRefLike())
+ COMPlusThrow(kNotSupportedException, W("NotSupported_ByRefLikeArray"));
+
+ // Check for open generic types.
+ if (pMT->IsGenericTypeDefinition() || pMT->ContainsGenericVariables())
+ COMPlusThrow(kNotSupportedException, W("NotSupported_OpenType"));
+
+ // Check for Void.
+ if (elementType.GetSignatureCorElementType() == ELEMENT_TYPE_VOID)
+ COMPlusThrow(kNotSupportedException, W("NotSupported_VoidArray"));
+
+ // That's all the dangerous simple types we know, it must be OK.
+ return;
+ }
+
+ // ByRefs and generic type variables are never allowed.
+ if (elementType.IsByRef() || elementType.IsGenericVariable())
+ COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
+
+ // We can create pointers and function pointers, but it requires skip verification permission.
+ CorElementType etType = elementType.GetSignatureCorElementType();
+ if (etType == ELEMENT_TYPE_PTR || etType == ELEMENT_TYPE_FNPTR)
+ {
+ return;
+ }
+
+ // We shouldn't get here (it means we've encountered a new type of typehandle if we do).
+ _ASSERTE(!"Shouldn't get here, unknown type handle type");
+ COMPlusThrow(kNotSupportedException);
+}
+
+FCIMPL4(Object*, ArrayNative::CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pLowerBounds)
+{
+ CONTRACTL {
+ FCALL_CHECK;
+ PRECONDITION(rank > 0);
+ PRECONDITION(CheckPointer(pLengths));
+ PRECONDITION(CheckPointer(pLowerBounds, NULL_OK));
+ } CONTRACTL_END;
+
+ OBJECTREF pRet = NULL;
+ TypeHandle elementType = TypeHandle::FromPtr(elementTypeHandle);
+
+ _ASSERTE(!elementType.IsNull());
+
+ // pLengths and pLowerBounds are pinned buffers. No need to protect them.
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
+
+ CheckElementType(elementType);
+
+ CorElementType CorType = elementType.GetSignatureCorElementType();
+
+ CorElementType kind = ELEMENT_TYPE_ARRAY;
+
+ // Is it ELEMENT_TYPE_SZARRAY array?
+ if (rank == 1 && (pLowerBounds == NULL || pLowerBounds[0] == 0)
+#ifdef FEATURE_64BIT_ALIGNMENT
+ // On platforms where 64-bit types require 64-bit alignment and don't obtain it naturally force us
+ // through the slow path where this will be handled.
+ && (CorType != ELEMENT_TYPE_I8)
+ && (CorType != ELEMENT_TYPE_U8)
+ && (CorType != ELEMENT_TYPE_R8)
+#endif
+ )
+ {
+ // Shortcut for common cases
+ if (CorTypeInfo::IsPrimitiveType(CorType))
+ {
+ pRet = AllocatePrimitiveArray(CorType,pLengths[0]);
+ goto Done;
+ }
+ else
+ if (CorTypeInfo::IsObjRef(CorType))
+ {
+ pRet = AllocateObjectArray(pLengths[0],elementType);
+ goto Done;
+ }
+
+ kind = ELEMENT_TYPE_SZARRAY;
+ pLowerBounds = NULL;
+ }
+
+ {
+ // Find the Array class...
+ TypeHandle typeHnd = ClassLoader::LoadArrayTypeThrowing(elementType, kind, rank);
+
+ DWORD boundsSize = 0;
+ INT32* bounds;
+ if (pLowerBounds != NULL) {
+ if (!ClrSafeInt<DWORD>::multiply(rank, 2, boundsSize))
+ COMPlusThrowOM();
+ DWORD dwAllocaSize = 0;
+ if (!ClrSafeInt<DWORD>::multiply(boundsSize, sizeof(INT32), dwAllocaSize))
+ COMPlusThrowOM();
+
+ bounds = (INT32*) _alloca(dwAllocaSize);
+
+ for (int i=0;i<rank;i++) {
+ bounds[2*i] = pLowerBounds[i];
+ bounds[2*i+1] = pLengths[i];
+ }
+ }
+ else {
+ boundsSize = rank;
+
+ DWORD dwAllocaSize = 0;
+ if (!ClrSafeInt<DWORD>::multiply(boundsSize, sizeof(INT32), dwAllocaSize))
+ COMPlusThrowOM();
+
+ bounds = (INT32*) _alloca(dwAllocaSize);
+
+ // We need to create a private copy of pLengths to avoid holes caused
+ // by caller mutating the array
+ for (int i=0;i<rank;i++)
+ bounds[i] = pLengths[i];
+ }
+
+ pRet = AllocateArrayEx(typeHnd, bounds, boundsSize);
+ }
+
+Done: ;
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(pRet);
+}
+FCIMPLEND
+
+
+FCIMPL4(void, ArrayNative::GetReference, ArrayBase* refThisUNSAFE, TypedByRef* elemRef, INT32 rank, INT32* pIndices)
+{
+ CONTRACTL {
+ FCALL_CHECK;
+ PRECONDITION(rank >= 0);
+ } CONTRACTL_END;
+
+ // FC_GC_POLL not necessary. We poll for GC in Array.Rank that's always called
+ // right before this function
+ FC_GC_POLL_NOT_NEEDED();
+
+ BASEARRAYREF refThis = (BASEARRAYREF) refThisUNSAFE;
+
+ _ASSERTE(rank == (INT32)refThis->GetRank());
+
+ SIZE_T Offset = 0;
+ const INT32 *pBoundsPtr = refThis->GetBoundsPtr();
+
+ if (rank == 1)
+ {
+ Offset = pIndices[0] - refThis->GetLowerBoundsPtr()[0];
+
+ // Bounds check each index
+ // Casting to unsigned allows us to use one compare for [0..limit-1]
+ if (((UINT32) Offset) >= ((UINT32) pBoundsPtr[0]))
+ FCThrowVoid(kIndexOutOfRangeException);
+ }
+ else
+ {
+ // Avoid redundant computation in GetLowerBoundsPtr
+ const INT32 *pLowerBoundsPtr = pBoundsPtr + rank;
+ _ASSERTE(refThis->GetLowerBoundsPtr() == pLowerBoundsPtr);
+
+ SIZE_T Multiplier = 1;
+
+ for (int i = rank; i >= 1; i--) {
+ INT32 curIndex = pIndices[i-1] - pLowerBoundsPtr[i-1];
+
+ // Bounds check each index
+ // Casting to unsigned allows us to use one compare for [0..limit-1]
+ if (((UINT32) curIndex) >= ((UINT32) pBoundsPtr[i-1]))
+ FCThrowVoid(kIndexOutOfRangeException);
+
+ Offset += curIndex * Multiplier;
+ Multiplier *= pBoundsPtr[i-1];
+ }
+ }
+
+ TypeHandle arrayElementType = refThis->GetArrayElementTypeHandle();
+
+ // Legacy behavior
+ if (arrayElementType.IsTypeDesc())
+ {
+ CorElementType elemtype = arrayElementType.AsTypeDesc()->GetInternalCorElementType();
+ if (elemtype == ELEMENT_TYPE_PTR || elemtype == ELEMENT_TYPE_FNPTR)
+ FCThrowResVoid(kNotSupportedException, W("NotSupported_Type"));
+ }
+#ifdef _DEBUG
+ CorElementType elemtype = arrayElementType.GetInternalCorElementType();
+ _ASSERTE(elemtype != ELEMENT_TYPE_PTR && elemtype != ELEMENT_TYPE_FNPTR);
+#endif
+
+ elemRef->data = refThis->GetDataPtr() + (Offset * refThis->GetComponentSize());
+ elemRef->type = arrayElementType;
+}
+FCIMPLEND
+
+FCIMPL2(void, ArrayNative::SetValue, TypedByRef * target, Object* objUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ OBJECTREF obj = ObjectToOBJECTREF(objUNSAFE);
+
+ TypeHandle thTarget(target->type);
+
+ MethodTable* pTargetMT = thTarget.AsMethodTable();
+ PREFIX_ASSUME(NULL != pTargetMT);
+
+ if (obj == NULL)
+ {
+ // Null is the universal zero...
+ if (pTargetMT->IsValueType())
+ InitValueClass(target->data,pTargetMT);
+ else
+ ClearObjectReference((OBJECTREF*)target->data);
+ }
+ else
+ if (thTarget == TypeHandle(g_pObjectClass))
+ {
+ // Everything is compatible with Object
+ SetObjectReference((OBJECTREF*)target->data,(OBJECTREF)obj);
+ }
+ else
+ if (!pTargetMT->IsValueType())
+ {
+ if (ObjIsInstanceOfCached(OBJECTREFToObject(obj), thTarget) != TypeHandle::CanCast)
+ {
+ // target->data is protected by the caller
+ HELPER_METHOD_FRAME_BEGIN_1(obj);
+
+ if (!ObjIsInstanceOf(OBJECTREFToObject(obj), thTarget))
+ COMPlusThrow(kInvalidCastException,W("InvalidCast_StoreArrayElement"));
+
+ HELPER_METHOD_FRAME_END();
+ }
+
+ SetObjectReference((OBJECTREF*)target->data,obj);
+ }
+ else
+ {
+ // value class or primitive type
+
+ if (!pTargetMT->UnBoxInto(target->data, obj))
+ {
+ // target->data is protected by the caller
+ HELPER_METHOD_FRAME_BEGIN_1(obj);
+
+ ARG_SLOT value = 0;
+
+ // Allow enum -> primitive conversion, disallow primitive -> enum conversion
+ TypeHandle thSrc = obj->GetTypeHandle();
+ CorElementType srcType = thSrc.GetVerifierCorElementType();
+ CorElementType targetType = thTarget.GetSignatureCorElementType();
+
+ if (!InvokeUtil::IsPrimitiveType(srcType) || !InvokeUtil::IsPrimitiveType(targetType))
+ COMPlusThrow(kInvalidCastException, W("InvalidCast_StoreArrayElement"));
+
+ // Get a properly widened type
+ InvokeUtil::CreatePrimitiveValue(targetType,srcType,obj,&value);
+
+ UINT cbSize = CorTypeInfo::Size(targetType);
+ memcpyNoGCRefs(target->data, ArgSlotEndianessFixup(&value, cbSize), cbSize);
+
+ HELPER_METHOD_FRAME_END();
+ }
+ }
+}
+FCIMPLEND
+
+// This method will initialize an array from a TypeHandle to a field.
+
+FCIMPL2_IV(void, ArrayNative::InitializeArray, ArrayBase* pArrayRef, FCALLRuntimeFieldHandle structField)
+{
+ FCALL_CONTRACT;
+
+ BASEARRAYREF arr = BASEARRAYREF(pArrayRef);
+ REFLECTFIELDREF refField = (REFLECTFIELDREF)ObjectToOBJECTREF(FCALL_RFH_TO_REFLECTFIELD(structField));
+ HELPER_METHOD_FRAME_BEGIN_2(arr, refField);
+
+ if ((arr == 0) || (refField == NULL))
+ COMPlusThrow(kArgumentNullException);
+
+ FieldDesc* pField = (FieldDesc*) refField->GetField();
+
+ if (!pField->IsRVA())
+ COMPlusThrow(kArgumentException);
+
+ // Report the RVA field to the logger.
+ g_IBCLogger.LogRVADataAccess(pField);
+
+ // Note that we do not check that the field is actually in the PE file that is initializing
+ // the array. Basically the data being published is can be accessed by anyone with the proper
+ // permissions (C# marks these as assembly visibility, and thus are protected from outside
+ // snooping)
+
+ if (!CorTypeInfo::IsPrimitiveType(arr->GetArrayElementType()) && !arr->GetArrayElementTypeHandle().IsEnum())
+ COMPlusThrow(kArgumentException);
+
+ SIZE_T dwCompSize = arr->GetComponentSize();
+ SIZE_T dwElemCnt = arr->GetNumComponents();
+ SIZE_T dwTotalSize = dwCompSize * dwElemCnt;
+
+ DWORD size = pField->LoadSize();
+
+ // make certain you don't go off the end of the rva static
+ if (dwTotalSize > size)
+ COMPlusThrow(kArgumentException);
+
+ void *src = pField->GetStaticAddressHandle(NULL);
+ void *dest = arr->GetDataPtr();
+
+#if BIGENDIAN
+ DWORD i;
+ switch (dwCompSize) {
+ case 1:
+ memcpyNoGCRefs(dest, src, dwElemCnt);
+ break;
+ case 2:
+ for (i = 0; i < dwElemCnt; i++)
+ *((UINT16*)dest + i) = GET_UNALIGNED_VAL16((UINT16*)src + i);
+ break;
+ case 4:
+ for (i = 0; i < dwElemCnt; i++)
+ *((UINT32*)dest + i) = GET_UNALIGNED_VAL32((UINT32*)src + i);
+ break;
+ case 8:
+ for (i = 0; i < dwElemCnt; i++)
+ *((UINT64*)dest + i) = GET_UNALIGNED_VAL64((UINT64*)src + i);
+ break;
+ default:
+ // should not reach here.
+ UNREACHABLE_MSG("Incorrect primitive type size!");
+ break;
+ }
+#else
+ memcpyNoGCRefs(dest, src, dwTotalSize);
+#endif
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
diff --git a/src/coreclr/classlibnative/bcltype/arraynative.h b/src/coreclr/classlibnative/bcltype/arraynative.h
new file mode 100644
index 00000000000..c5be8403a8e
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/arraynative.h
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: ArrayNative.h
+//
+
+//
+// ArrayNative
+// This file defines the native methods for the Array
+//
+
+
+#ifndef _ARRAYNATIVE_H_
+#define _ARRAYNATIVE_H_
+
+#include "fcall.h"
+
+struct FCALLRuntimeFieldHandle
+{
+ ReflectFieldObject *pFieldDONOTUSEDIRECTLY;
+};
+#define FCALL_RFH_TO_REFLECTFIELD(x) (x).pFieldDONOTUSEDIRECTLY
+
+class ArrayNative
+{
+public:
+ static FCDECL1(INT32, GetCorElementTypeOfElementType, ArrayBase* arrayUNSAFE);
+
+ static FCDECL1(void, Initialize, ArrayBase* pArray);
+
+ static FCDECL2(FC_BOOL_RET, IsSimpleCopy, ArrayBase* pSrc, ArrayBase* pDst);
+ static FCDECL5(void, CopySlow, ArrayBase* pSrc, INT32 iSrcIndex, ArrayBase* pDst, INT32 iDstIndex, INT32 iLength);
+
+ // This method will create a new array of type type, with zero lower
+ // bounds and rank.
+ static FCDECL4(Object*, CreateInstance, void* elementTypeHandle, INT32 rank, INT32* pLengths, INT32* pBounds);
+
+ // This method will return a TypedReference to the array element
+ static FCDECL4(void, GetReference, ArrayBase* refThisUNSAFE, TypedByRef* elemRef, INT32 rank, INT32* pIndices);
+
+ // This set of methods will set a value in an array
+ static FCDECL2(void, SetValue, TypedByRef* target, Object* objUNSAFE);
+
+ // This method will initialize an array from a TypeHandle
+ // to a field.
+ static FCDECL2_IV(void, InitializeArray, ArrayBase* vArrayRef, FCALLRuntimeFieldHandle structField);
+
+private:
+ // Helper for CreateInstance
+ static void CheckElementType(TypeHandle elementType);
+
+ // Return values for CanAssignArrayType
+ enum AssignArrayEnum
+ {
+ AssignWrongType,
+ AssignMustCast,
+ AssignBoxValueClassOrPrimitive,
+ AssignUnboxValueClass,
+ AssignPrimitiveWiden,
+ };
+
+ // The following functions are all helpers for ArrayCopy
+ static AssignArrayEnum CanAssignArrayType(const BASEARRAYREF pSrc, const BASEARRAYREF pDest);
+ static void CastCheckEachElement(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length);
+ static void BoxEachElement(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length);
+ static void UnBoxEachElement(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length);
+ static void PrimitiveWiden(BASEARRAYREF pSrc, unsigned int srcIndex, BASEARRAYREF pDest, unsigned int destIndex, unsigned int length);
+
+};
+
+#endif // _ARRAYNATIVE_H_
diff --git a/src/coreclr/classlibnative/bcltype/arraynative.inl b/src/coreclr/classlibnative/bcltype/arraynative.inl
new file mode 100644
index 00000000000..913b8c64939
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/arraynative.inl
@@ -0,0 +1,325 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: ArrayNative.cpp
+//
+
+//
+// This file contains the native methods that support the Array class
+//
+
+#ifndef _ARRAYNATIVE_INL_
+#define _ARRAYNATIVE_INL_
+
+#include "gchelpers.inl"
+
+FORCEINLINE void InlinedForwardGCSafeCopyHelper(void *dest, const void *src, size_t len)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(dest != nullptr);
+ _ASSERTE(src != nullptr);
+ _ASSERTE(dest != src);
+ _ASSERTE(len != 0);
+
+ // To be able to copy forwards, the destination buffer cannot start inside the source buffer
+ _ASSERTE((SIZE_T)dest - (SIZE_T)src >= len);
+
+ // Make sure everything is pointer aligned
+ _ASSERTE(IS_ALIGNED(dest, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(src, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(len, sizeof(SIZE_T)));
+
+ _ASSERTE(CheckPointer(dest));
+ _ASSERTE(CheckPointer(src));
+
+ SIZE_T *dptr = (SIZE_T *)dest;
+ SIZE_T *sptr = (SIZE_T *)src;
+
+ while (true)
+ {
+ if ((len & sizeof(SIZE_T)) != 0)
+ {
+ *dptr = *sptr;
+
+ len ^= sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ ++sptr;
+ ++dptr;
+ }
+
+#if defined(HOST_AMD64) && (defined(_MSC_VER) || defined(__GNUC__))
+ if ((len & (2 * sizeof(SIZE_T))) != 0)
+ {
+ __m128 v = _mm_loadu_ps((float *)sptr);
+ _mm_storeu_ps((float *)dptr, v);
+
+ len ^= 2 * sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ sptr += 2;
+ dptr += 2;
+ }
+
+ // Align the destination pointer to 16 bytes for the next set of 16-byte copies
+ if (((SIZE_T)dptr & sizeof(SIZE_T)) != 0)
+ {
+ *dptr = *sptr;
+
+ ++sptr;
+ ++dptr;
+ len -= sizeof(SIZE_T);
+ if (len < 4 * sizeof(SIZE_T))
+ {
+ continue;
+ }
+ }
+
+ // Copy 32 bytes at a time
+ _ASSERTE(len >= 4 * sizeof(SIZE_T));
+ do
+ {
+ __m128 v = _mm_loadu_ps((float *)sptr);
+ _mm_store_ps((float *)dptr, v);
+ v = _mm_loadu_ps((float *)(sptr + 2));
+ _mm_store_ps((float *)(dptr + 2), v);
+
+ sptr += 4;
+ dptr += 4;
+ len -= 4 * sizeof(SIZE_T);
+ } while (len >= 4 * sizeof(SIZE_T));
+ if (len == 0)
+ {
+ return;
+ }
+#else // !(defined(HOST_AMD64) && (defined(_MSC_VER) || defined(__GNUC__)))
+ if ((len & (2 * sizeof(SIZE_T))) != 0)
+ {
+ // Read two values and write two values to hint the use of wide loads and stores
+ SIZE_T p0 = sptr[0];
+ SIZE_T p1 = sptr[1];
+ dptr[0] = p0;
+ dptr[1] = p1;
+
+ len ^= 2 * sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ sptr += 2;
+ dptr += 2;
+ }
+
+ // Copy 16 (on 32-bit systems) or 32 (on 64-bit systems) bytes at a time
+ _ASSERTE(len >= 4 * sizeof(SIZE_T));
+ while (true)
+ {
+ // Read two values and write two values to hint the use of wide loads and stores
+ SIZE_T p0 = sptr[0];
+ SIZE_T p1 = sptr[1];
+ dptr[0] = p0;
+ dptr[1] = p1;
+ p0 = sptr[2];
+ p1 = sptr[3];
+ dptr[2] = p0;
+ dptr[3] = p1;
+
+ len -= 4 * sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ sptr += 4;
+ dptr += 4;
+ }
+#endif // defined(HOST_AMD64) && (defined(_MSC_VER) || defined(__GNUC__))
+ }
+}
+
+FORCEINLINE void InlinedBackwardGCSafeCopyHelper(void *dest, const void *src, size_t len)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(dest != nullptr);
+ _ASSERTE(src != nullptr);
+ _ASSERTE(dest != src);
+ _ASSERTE(len != 0);
+
+ // To be able to copy backwards, the source buffer cannot start inside the destination buffer
+ _ASSERTE((SIZE_T)src - (SIZE_T)dest >= len);
+
+ // Make sure everything is pointer aligned
+ _ASSERTE(IS_ALIGNED(dest, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(src, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(len, sizeof(SIZE_T)));
+
+ _ASSERTE(CheckPointer(dest));
+ _ASSERTE(CheckPointer(src));
+
+ SIZE_T *dptr = (SIZE_T *)((BYTE *)dest + len);
+ SIZE_T *sptr = (SIZE_T *)((BYTE *)src + len);
+
+ while (true)
+ {
+ if ((len & sizeof(SIZE_T)) != 0)
+ {
+ --sptr;
+ --dptr;
+
+ *dptr = *sptr;
+
+ len ^= sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ }
+
+#if defined(HOST_AMD64) && (defined(_MSC_VER) || defined(__GNUC__))
+ if ((len & (2 * sizeof(SIZE_T))) != 0)
+ {
+ sptr -= 2;
+ dptr -= 2;
+
+ __m128 v = _mm_loadu_ps((float *)sptr);
+ _mm_storeu_ps((float *)dptr, v);
+
+ len ^= 2 * sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ }
+
+ // Align the destination pointer to 16 bytes for the next set of 16-byte copies
+ if (((SIZE_T)dptr & sizeof(SIZE_T)) != 0)
+ {
+ --sptr;
+ --dptr;
+
+ *dptr = *sptr;
+
+ len -= sizeof(SIZE_T);
+ if (len < 4 * sizeof(SIZE_T))
+ {
+ continue;
+ }
+ }
+
+ // Copy 32 bytes at a time
+ _ASSERTE(len >= 4 * sizeof(SIZE_T));
+ do
+ {
+ sptr -= 4;
+ dptr -= 4;
+
+ __m128 v = _mm_loadu_ps((float *)(sptr + 2));
+ _mm_store_ps((float *)(dptr + 2), v);
+ v = _mm_loadu_ps((float *)sptr);
+ _mm_store_ps((float *)dptr, v);
+
+ len -= 4 * sizeof(SIZE_T);
+ } while (len >= 4 * sizeof(SIZE_T));
+ if (len == 0)
+ {
+ return;
+ }
+#else // !(defined(HOST_AMD64) && (defined(_MSC_VER) || defined(__GNUC__)))
+ if ((len & (2 * sizeof(SIZE_T))) != 0)
+ {
+ sptr -= 2;
+ dptr -= 2;
+
+ // Read two values and write two values to hint the use of wide loads and stores
+ SIZE_T p1 = sptr[1];
+ SIZE_T p0 = sptr[0];
+ dptr[1] = p1;
+ dptr[0] = p0;
+
+ len ^= 2 * sizeof(SIZE_T);
+ if (len == 0)
+ {
+ return;
+ }
+ }
+
+ // Copy 16 (on 32-bit systems) or 32 (on 64-bit systems) bytes at a time
+ _ASSERTE(len >= 4 * sizeof(SIZE_T));
+ do
+ {
+ sptr -= 4;
+ dptr -= 4;
+
+ // Read two values and write two values to hint the use of wide loads and stores
+ SIZE_T p0 = sptr[2];
+ SIZE_T p1 = sptr[3];
+ dptr[2] = p0;
+ dptr[3] = p1;
+ p0 = sptr[0];
+ p1 = sptr[1];
+ dptr[0] = p0;
+ dptr[1] = p1;
+
+ len -= 4 * sizeof(SIZE_T);
+ } while (len != 0);
+ return;
+#endif // defined(HOST_AMD64) && (defined(_MSC_VER) || defined(__GNUC__))
+ }
+}
+
+FORCEINLINE void InlinedMemmoveGCRefsHelper(void *dest, const void *src, size_t len)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_COOPERATIVE;
+ }
+ CONTRACTL_END;
+
+ _ASSERTE(dest != nullptr);
+ _ASSERTE(src != nullptr);
+ _ASSERTE(dest != src);
+ _ASSERTE(len != 0);
+
+ // Make sure everything is pointer aligned
+ _ASSERTE(IS_ALIGNED(dest, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(src, sizeof(SIZE_T)));
+ _ASSERTE(IS_ALIGNED(len, sizeof(SIZE_T)));
+
+ _ASSERTE(CheckPointer(dest));
+ _ASSERTE(CheckPointer(src));
+
+ GCHeapMemoryBarrier();
+
+ // To be able to copy forwards, the destination buffer cannot start inside the source buffer
+ if ((size_t)dest - (size_t)src >= len)
+ {
+ InlinedForwardGCSafeCopyHelper(dest, src, len);
+ }
+ else
+ {
+ InlinedBackwardGCSafeCopyHelper(dest, src, len);
+ }
+
+ InlinedSetCardsAfterBulkCopyHelper((Object**)dest, len);
+}
+
+#endif // !_ARRAYNATIVE_INL_
diff --git a/src/coreclr/classlibnative/bcltype/oavariant.cpp b/src/coreclr/classlibnative/bcltype/oavariant.cpp
new file mode 100644
index 00000000000..fd8a2948820
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/oavariant.cpp
@@ -0,0 +1,429 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: OAVariant.cpp
+//
+
+//
+// Purpose: Wrapper for Ole Automation compatable math ops.
+// Calls through to OleAut.dll
+//
+
+//
+
+#include <common.h>
+
+#ifdef FEATURE_COMINTEROP
+
+#include <oleauto.h>
+#include "excep.h"
+#include "oavariant.h"
+#include "comdatetime.h" // DateTime <-> OleAut date conversions
+#include "interoputil.h"
+#include "interopconverter.h"
+#include "excep.h"
+#include "string.h"
+#include "comutilnative.h" // for COMDate
+
+#define INVALID_MAPPING (BYTE)(-1)
+
+static const BYTE CVtoVTTable [] =
+{
+ VT_EMPTY, // CV_EMPTY
+ VT_VOID, // CV_VOID
+ VT_BOOL, // CV_BOOLEAN
+ VT_UI2, // CV_CHAR
+ VT_I1, // CV_I1
+ VT_UI1, // CV_U1
+ VT_I2, // CV_I2
+ VT_UI2, // CV_U2
+ VT_I4, // CV_I4
+ VT_UI4, // CV_U4
+ VT_I8, // CV_I8
+ VT_UI8, // CV_U8
+ VT_R4, // CV_R4
+ VT_R8, // CV_R8
+ VT_BSTR, // CV_STRING
+ INVALID_MAPPING, // CV_PTR
+ VT_DATE, // CV_DATETIME
+ INVALID_MAPPING, // CV_TIMESPAN
+ VT_UNKNOWN, // CV_OBJECT
+ VT_DECIMAL, // CV_DECIMAL
+ VT_CY, // CV_CURRENCY
+ INVALID_MAPPING, // CV_ENUM
+ INVALID_MAPPING, // CV_MISSING
+ VT_NULL, // CV_NULL
+ INVALID_MAPPING // CV_LAST
+};
+
+static const BYTE VTtoCVTable[] =
+{
+ CV_EMPTY, // VT_EMPTY
+ CV_NULL, // VT_NULL
+ CV_I2, // VT_I2
+ CV_I4, // VT_I4
+ CV_R4, // VT_R4
+ CV_R8, // VT_R8
+ CV_CURRENCY,// VT_CY
+ CV_DATETIME,// VT_DATE
+ CV_STRING, // VT_BSTR
+ INVALID_MAPPING, // VT_DISPATCH
+ INVALID_MAPPING, // VT_ERROR
+ CV_BOOLEAN, // VT_BOOL
+ CV_OBJECT, // VT_VARIANT
+ CV_OBJECT, // VT_UNKNOWN
+ CV_DECIMAL, // VT_DECIMAL
+ INVALID_MAPPING, // An unused enum table entry
+ CV_I1, // VT_I1
+ CV_U1, // VT_UI1
+ CV_U2, // VT_UI2
+ CV_U4, // VT_UI4
+ CV_I8, // VT_I8
+ CV_U8, // VT_UI8
+ CV_I4, // VT_INT
+ CV_U4, // VT_UINT
+ CV_VOID // VT_VOID
+};
+
+// Need translations from CVType to VARENUM and vice versa. CVTypes
+// is defined in COMVariant.h. VARENUM is defined in OleAut's variant.h
+// Assumption here is we will only deal with VARIANTs and not other OLE
+// constructs such as property sets or safe arrays.
+VARENUM COMOAVariant::CVtoVT(const CVTypes cv)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(cv >= 0 && cv < CV_LAST);
+ }
+ CONTRACTL_END;
+
+ if (CVtoVTTable[cv] == INVALID_MAPPING)
+ COMPlusThrow(kNotSupportedException, W("NotSupported_ChangeType"));
+
+ return (VARENUM) CVtoVTTable[cv];
+}
+
+// Need translations from CVType to VARENUM and vice versa. CVTypes
+// is defined in COMVariant.h. VARENUM is defined in OleAut's variant.h
+CVTypes COMOAVariant::VTtoCV(const VARENUM vt)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(vt < VT_VOID);
+ }
+ CONTRACTL_END;
+
+ if (vt <0 || vt > VT_VOID || VTtoCVTable[vt]==INVALID_MAPPING)
+ COMPlusThrow(kNotSupportedException, W("NotSupported_ChangeType"));
+
+ return (CVTypes) VTtoCVTable[vt];
+}
+
+
+// Converts a COM+ Variant to an OleAut Variant. Returns true if
+// there was a native object allocated by this method that must be freed,
+// else false.
+bool COMOAVariant::ToOAVariant(const VariantData * const var, VARIANT * oa)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(var));
+ PRECONDITION(CheckPointer(oa));
+ }
+ CONTRACTL_END;
+
+ SafeVariantInit(oa);
+ UINT64 * dest = (UINT64*) &V_UI1(oa);
+ *dest = 0;
+
+ WCHAR * chars;
+ int strLen;
+
+ // Set the data field of the OA Variant to be either the object reference
+ // or the data (ie int) that it needs.
+
+ switch (var->GetType())
+ {
+ case CV_STRING:
+ if (var->GetObjRef() == NULL)
+ {
+ V_BSTR(oa) = NULL;
+ V_VT(oa) = static_cast<VARTYPE>(CVtoVT(var->GetType()));
+
+ // OA perf feature: VarClear calls SysFreeString(null), which access violates.
+ return false;
+ }
+
+ ((STRINGREF) (var->GetObjRef()))->RefInterpretGetStringValuesDangerousForGC(&chars, &strLen);
+ V_BSTR(oa) = SysAllocStringLen(chars, strLen);
+ if (V_BSTR(oa) == NULL)
+ COMPlusThrowOM();
+
+ V_VT(oa) = static_cast<VARTYPE>(CVtoVT(var->GetType()));
+
+ return true;
+
+ case CV_CHAR:
+ chars = (WCHAR*) var->GetData();
+ V_BSTR(oa) = SysAllocStringLen(chars, 1);
+ if (V_BSTR(oa) == NULL)
+ COMPlusThrowOM();
+
+ // We should override the VTtoVT default of VT_UI2 for this case.
+ V_VT(oa) = VT_BSTR;
+
+ return true;
+
+ case CV_DATETIME:
+ V_DATE(oa) = COMDateTime::TicksToDoubleDate(var->GetDataAsInt64());
+ V_VT(oa) = static_cast<VARTYPE>(CVtoVT(var->GetType()));
+ return false;
+
+ case CV_BOOLEAN:
+ V_BOOL(oa) = (var->GetDataAsInt64()==0 ? VARIANT_FALSE : VARIANT_TRUE);
+ V_VT(oa) = static_cast<VARTYPE>(CVtoVT(var->GetType()));
+ return false;
+
+ case CV_DECIMAL:
+ {
+ OBJECTREF obj = var->GetObjRef();
+ DECIMAL * d = (DECIMAL*) obj->GetData();
+ // DECIMALs and Variants are the same size. Variants are a union between
+ // all the normal Variant fields (vt, bval, etc) and a Decimal. Decimals
+ // also have the first 2 bytes reserved, for a VT field.
+
+ V_DECIMAL(oa) = *d;
+ V_VT(oa) = VT_DECIMAL;
+ return false;
+ }
+
+ case CV_OBJECT:
+ {
+ OBJECTREF obj = var->GetObjRef();
+ GCPROTECT_BEGIN(obj)
+ {
+ IUnknown *pUnk = NULL;
+
+ // Convert the object to an IDispatch/IUnknown pointer.
+ ComIpType FetchedIpType = ComIpType_None;
+ pUnk = GetComIPFromObjectRef(&obj, ComIpType_Both, &FetchedIpType);
+ V_UNKNOWN(oa) = pUnk;
+ V_VT(oa) = static_cast<VARTYPE>(FetchedIpType == ComIpType_Dispatch ? VT_DISPATCH : VT_UNKNOWN);
+ }
+ GCPROTECT_END();
+ return true;
+ }
+
+ default:
+ *dest = var->GetDataAsInt64();
+ V_VT(oa) = static_cast<VARTYPE>(CVtoVT(var->GetType()));
+ return false;
+ }
+}
+
+// Converts an OleAut Variant into a COM+ Variant.
+// NOte that we pass the VariantData Byref so that if GC happens, 'var' gets updated
+void COMOAVariant::FromOAVariant(const VARIANT * const oa, VariantData * const& var)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ INJECT_FAULT(COMPlusThrowOM());
+ PRECONDITION(CheckPointer(oa));
+ }
+ CONTRACTL_END;
+
+ // Clear the return variant value. It's allocated on
+ // the stack and we only want valid state data in there.
+ memset(var, 0, sizeof(VariantData));
+
+ CVTypes type = VTtoCV((VARENUM) V_VT(oa));
+ var->SetType(type);
+
+ switch (type)
+ {
+ case CV_STRING:
+ {
+ // BSTRs have an int with the string buffer length (not the string length)
+ // followed by the data. The pointer to the BSTR points to the start of the
+ // characters, NOT the start of the BSTR.
+ WCHAR * chars = V_BSTR(oa);
+ int strLen = SysStringLen(V_BSTR(oa));
+ STRINGREF str = StringObject::NewString(chars, strLen);
+ var->SetObjRef((OBJECTREF)str);
+ break;
+ }
+ case CV_DATETIME:
+ var->SetDataAsInt64(COMDateTime::DoubleDateToTicks(V_DATE(oa)));
+ break;
+
+ case CV_BOOLEAN:
+ var->SetDataAsInt64(V_BOOL(oa)==VARIANT_FALSE ? 0 : 1);
+ break;
+
+ case CV_DECIMAL:
+ {
+ MethodTable * pDecimalMT = GetTypeHandleForCVType(CV_DECIMAL).GetMethodTable();
+ _ASSERTE(pDecimalMT);
+ OBJECTREF pDecimalRef = AllocateObject(pDecimalMT);
+
+ *(DECIMAL *) pDecimalRef->GetData() = V_DECIMAL(oa);
+ var->SetObjRef(pDecimalRef);
+ break;
+ }
+
+
+ // All types less than 4 bytes need an explicit cast from their original
+ // type to be sign extended to 8 bytes. This makes Variant's ToInt32
+ // function simpler for these types.
+ case CV_I1:
+ var->SetDataAsInt64(V_I1(oa));
+ break;
+
+ case CV_U1:
+ var->SetDataAsInt64(V_UI1(oa));
+ break;
+
+ case CV_I2:
+ var->SetDataAsInt64(V_I2(oa));
+ break;
+
+ case CV_U2:
+ var->SetDataAsInt64(V_UI2(oa));
+ break;
+
+ case CV_EMPTY:
+ case CV_NULL:
+ // Must set up the Variant's m_or to the appropriate classes.
+ // Note that OleAut doesn't have any VT_MISSING.
+ VariantData::NewVariant(var, type, NULL
+ DEBUG_ARG(TRUE));
+ break;
+
+ case CV_OBJECT:
+ {
+ // Convert the IUnknown pointer to an OBJECTREF.
+ OBJECTREF oref = NULL;
+ GCPROTECT_BEGIN(oref);
+ GetObjectRefFromComIP(&oref, V_UNKNOWN(oa));
+ var->SetObjRef(oref);
+ GCPROTECT_END();
+ break;
+ }
+ default:
+ // Copy all the bits there, and make sure we don't do any float to int conversions.
+ void * src = (void*) &(V_UI1(oa));
+ var->SetData(src);
+ }
+}
+
+void COMOAVariant::OAFailed(const HRESULT hr)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(FAILED(hr));
+ }
+ CONTRACTL_END;
+
+ switch (hr)
+ {
+ case E_OUTOFMEMORY:
+ COMPlusThrowOM();
+
+ case DISP_E_BADVARTYPE:
+ COMPlusThrow(kNotSupportedException, W("NotSupported_OleAutBadVarType"));
+
+ case DISP_E_DIVBYZERO:
+ COMPlusThrow(kDivideByZeroException);
+
+ case DISP_E_OVERFLOW:
+ COMPlusThrow(kOverflowException);
+
+ case DISP_E_TYPEMISMATCH:
+ COMPlusThrow(kInvalidCastException, W("InvalidCast_OATypeMismatch"));
+
+ case E_INVALIDARG:
+ COMPlusThrow(kArgumentException);
+ break;
+
+ default:
+ _ASSERTE(!"Unrecognized HResult - OAVariantLib routine failed in an unexpected way!");
+ COMPlusThrowHR(hr);
+ }
+}
+
+FCIMPL6(void, COMOAVariant::ChangeTypeEx, VariantData *result, VariantData *op, LCID lcid, void *targetType, int cvType, INT16 flags)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(result));
+ }
+ CONTRACTL_END;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+ GCPROTECT_BEGININTERIOR (result);
+
+ BOOL fConverted = FALSE;
+
+ TypeHandle thTarget = TypeHandle::FromPtr(targetType);
+ if (cvType == CV_OBJECT && IsTypeRefOrDef(g_ColorClassName, thTarget.GetModule(), thTarget.GetCl()))
+ {
+ if (op->GetType() == CV_I4 || op->GetType() == CV_U4)
+ {
+ // Int32/UInt32 can be converted to System.Drawing.Color
+ SYSTEMCOLOR SystemColor;
+ ConvertOleColorToSystemColor(op->GetDataAsUInt32(), &SystemColor);
+
+ result->SetObjRef(thTarget.AsMethodTable()->Box(&SystemColor));
+ result->SetType(CV_OBJECT);
+
+ fConverted = TRUE;
+ }
+ }
+
+ if (!fConverted)
+ {
+ VariantHolder ret;
+ VariantHolder vOp;
+
+ VARENUM vt = CVtoVT((CVTypes) cvType);
+ ToOAVariant(op, &vOp);
+
+ HRESULT hr = SafeVariantChangeTypeEx(&ret, &vOp, lcid, flags, static_cast<VARTYPE>(vt));
+
+ if (FAILED(hr))
+ OAFailed(hr);
+
+ if ((CVTypes) cvType == CV_CHAR)
+ {
+ result->SetType(CV_CHAR);
+ result->SetDataAsUInt16(V_UI2(&ret));
+ }
+ else
+ {
+ FromOAVariant(&ret, result);
+ }
+ }
+
+ GCPROTECT_END ();
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+#endif // FEATURE_COMINTEROP
diff --git a/src/coreclr/classlibnative/bcltype/oavariant.h b/src/coreclr/classlibnative/bcltype/oavariant.h
new file mode 100644
index 00000000000..de09ae7f873
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/oavariant.h
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: OAVariant.h
+//
+
+//
+// Purpose: Wrapper for Ole Automation compatable math ops.
+// Calls through to OleAut.dll
+//
+
+//
+
+#ifndef _OAVARIANT_H_
+#define _OAVARIANT_H_
+
+#ifndef FEATURE_COMINTEROP
+#error FEATURE_COMINTEROP is required for this file
+#endif // FEATURE_COMINTEROP
+
+#include "variant.h"
+
+class COMOAVariant
+{
+public:
+
+ // Utility Functions
+ // Conversion between COM+ variant type field & OleAut Variant enumeration
+ // WinCE doesn't support Variants entirely.
+ static VARENUM CVtoVT(const CVTypes cv);
+ static CVTypes VTtoCV(const VARENUM vt);
+
+ // Conversion between COM+ Variant & OleAut Variant. ToOAVariant
+ // returns true if the conversion process allocated an object (like a BSTR).
+ static bool ToOAVariant(const VariantData * const var, VARIANT * oa);
+ static void FromOAVariant(const VARIANT * const oa, VariantData * const& var);
+
+ // Throw a specific exception for a failure, specified by a given HRESULT.
+ static void OAFailed(const HRESULT hr);
+
+ static FCDECL6(void, ChangeTypeEx, VariantData *result, VariantData *op, LCID lcid, void *targetType, int cvType, INT16 flags);
+};
+
+
+#endif // _OAVARIANT_H_
diff --git a/src/coreclr/classlibnative/bcltype/objectnative.cpp b/src/coreclr/classlibnative/bcltype/objectnative.cpp
new file mode 100644
index 00000000000..80023e27a9d
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/objectnative.cpp
@@ -0,0 +1,336 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: ObjectNative.cpp
+//
+
+//
+// Purpose: Native methods on System.Object
+//
+//
+
+#include "common.h"
+
+#include "objectnative.h"
+#include "excep.h"
+#include "vars.hpp"
+#include "field.h"
+#include "object.h"
+#include "comsynchronizable.h"
+#include "eeconfig.h"
+
+
+/********************************************************************/
+/* gets an object's 'value'. For normal classes, with reference
+ based semantics, this means the object's pointer. For boxed
+ primitive types, it also means just returning the pointer (because
+ they are immutable), for other value class, it means returning
+ a boxed copy. */
+
+FCIMPL1(Object*, ObjectNative::GetObjectValue, Object* obj)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ INJECT_FAULT(FCThrow(kOutOfMemoryException););
+ }
+ CONTRACTL_END;
+
+ VALIDATEOBJECT(obj);
+
+ if (obj == 0)
+ return(obj);
+
+ MethodTable* pMT = obj->GetMethodTable();
+ // optimize for primitive types since GetVerifierCorElementType is slow.
+ if (pMT->IsTruePrimitive() || TypeHandle(pMT).GetVerifierCorElementType() != ELEMENT_TYPE_VALUETYPE) {
+ return(obj);
+ }
+
+ Object* retVal = NULL;
+ OBJECTREF objRef(obj);
+ HELPER_METHOD_FRAME_BEGIN_RET_1(objRef); // Set up a frame
+
+ // Technically we could return boxed DateTimes and Decimals without
+ // copying them here, but VB realized that this would be a breaking change
+ // for their customers. So copy them.
+ //
+ // MethodTable::Box is a cleaner way to copy value class, but it is slower than following code.
+ //
+ retVal = OBJECTREFToObject(AllocateObject(pMT));
+ CopyValueClass(retVal->GetData(), objRef->GetData(), pMT);
+ HELPER_METHOD_FRAME_END();
+
+ return(retVal);
+}
+FCIMPLEND
+
+
+NOINLINE static INT32 GetHashCodeHelper(OBJECTREF objRef)
+{
+ DWORD idx = 0;
+
+ FC_INNER_PROLOG(ObjectNative::GetHashCode);
+
+ HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, objRef);
+
+ idx = objRef->GetHashCodeEx();
+
+ HELPER_METHOD_FRAME_END();
+ FC_INNER_EPILOG();
+ return idx;
+}
+
+// Note that we obtain a sync block index without actually building a sync block.
+// That's because a lot of objects are hashed, without requiring support for
+FCIMPL1(INT32, ObjectNative::GetHashCode, Object* obj) {
+
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ INJECT_FAULT(FCThrow(kOutOfMemoryException););
+ }
+ CONTRACTL_END;
+
+ VALIDATEOBJECT(obj);
+
+ if (obj == 0)
+ return 0;
+
+ OBJECTREF objRef(obj);
+
+ {
+ DWORD bits = objRef->GetHeader()->GetBits();
+
+ if (bits & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)
+ {
+ if (bits & BIT_SBLK_IS_HASHCODE)
+ {
+ // Common case: the object already has a hash code
+ return bits & MASK_HASHCODE;
+ }
+ else
+ {
+ // We have a sync block index. This means if we already have a hash code,
+ // it is in the sync block, otherwise we generate a new one and store it there
+ SyncBlock *psb = objRef->PassiveGetSyncBlock();
+ if (psb != NULL)
+ {
+ DWORD hashCode = psb->GetHashCode();
+ if (hashCode != 0)
+ return hashCode;
+ }
+ }
+ }
+ }
+
+ FC_INNER_RETURN(INT32, GetHashCodeHelper(objRef));
+}
+FCIMPLEND
+
+//
+// Compare by ref for normal classes, by value for value types.
+//
+// <TODO>@todo: it would be nice to customize this method based on the
+// defining class rather than doing a runtime check whether it is
+// a value type.</TODO>
+//
+
+FCIMPL2(FC_BOOL_RET, ObjectNative::Equals, Object *pThisRef, Object *pCompareRef)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ INJECT_FAULT(FCThrow(kOutOfMemoryException););
+ }
+ CONTRACTL_END;
+
+ if (pThisRef == pCompareRef)
+ FC_RETURN_BOOL(TRUE);
+
+ // Since we are in FCALL, we must handle NULL specially.
+ if (pThisRef == NULL || pCompareRef == NULL)
+ FC_RETURN_BOOL(FALSE);
+
+ MethodTable *pThisMT = pThisRef->GetMethodTable();
+
+ // If it's not a value class, don't compare by value
+ if (!pThisMT->IsValueType())
+ FC_RETURN_BOOL(FALSE);
+
+ // Make sure they are the same type.
+ if (pThisMT != pCompareRef->GetMethodTable())
+ FC_RETURN_BOOL(FALSE);
+
+ // Compare the contents (size - vtable - sync block index).
+ DWORD dwBaseSize = pThisRef->GetMethodTable()->GetBaseSize();
+ if(pThisRef->GetMethodTable() == g_pStringClass)
+ dwBaseSize -= sizeof(WCHAR);
+ BOOL ret = memcmp(
+ (void *) (pThisRef+1),
+ (void *) (pCompareRef+1),
+ dwBaseSize - sizeof(Object) - sizeof(int)) == 0;
+
+ FC_GC_POLL_RET();
+
+ FC_RETURN_BOOL(ret);
+}
+FCIMPLEND
+
+NOINLINE static Object* GetClassHelper(OBJECTREF objRef)
+{
+ FC_INNER_PROLOG(ObjectNative::GetClass);
+ _ASSERTE(objRef != NULL);
+ TypeHandle typeHandle = objRef->GetTypeHandle();
+ OBJECTREF refType = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_1(Frame::FRAME_ATTR_EXACT_DEPTH|Frame::FRAME_ATTR_CAPTURE_DEPTH_2, refType);
+
+ refType = typeHandle.GetManagedClassObject();
+
+ HELPER_METHOD_FRAME_END();
+ FC_INNER_EPILOG();
+ return OBJECTREFToObject(refType);
+}
+
+// This routine is called by the Object.GetType() routine. It is a major way to get the Sytem.Type
+FCIMPL1(Object*, ObjectNative::GetClass, Object* pThis)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ INJECT_FAULT(FCThrow(kOutOfMemoryException););
+ }
+ CONTRACTL_END;
+
+ OBJECTREF objRef = ObjectToOBJECTREF(pThis);
+ if (objRef != NULL)
+ {
+ MethodTable* pMT = objRef->GetMethodTable();
+ OBJECTREF typePtr = pMT->GetManagedClassObjectIfExists();
+ if (typePtr != NULL)
+ {
+ return OBJECTREFToObject(typePtr);
+ }
+ }
+ else
+ FCThrow(kNullReferenceException);
+
+ FC_INNER_RETURN(Object*, GetClassHelper(objRef));
+}
+FCIMPLEND
+
+FCIMPL1(Object*, ObjectNative::AllocateUninitializedClone, Object* pObjUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ // Delegate error handling to managed side (it will throw NullRefenceException)
+ if (pObjUNSAFE == NULL)
+ return NULL;
+
+ OBJECTREF refClone = ObjectToOBJECTREF(pObjUNSAFE);
+
+ HELPER_METHOD_FRAME_BEGIN_RET_1(refClone);
+
+ MethodTable* pMT = refClone->GetMethodTable();
+
+ // assert that String has overloaded the Clone() method
+ _ASSERTE(pMT != g_pStringClass);
+
+ if (pMT->IsArray()) {
+ refClone = DupArrayForCloning((BASEARRAYREF)refClone);
+ } else {
+ // We don't need to call the <cinit> because we know
+ // that it has been called....(It was called before this was created)
+ refClone = AllocateObject(pMT);
+ }
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(refClone);
+}
+FCIMPLEND
+
+FCIMPL2(FC_BOOL_RET, ObjectNative::WaitTimeout, INT32 Timeout, Object* pThisUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ BOOL retVal = FALSE;
+ OBJECTREF pThis = (OBJECTREF) pThisUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_RET_1(pThis);
+
+ // Arguments validated on managed side
+ _ASSERTE(pThis != NULL);
+ _ASSERTE(Timeout >= INFINITE_TIMEOUT);
+
+ retVal = pThis->Wait(Timeout);
+
+ HELPER_METHOD_FRAME_END();
+ FC_RETURN_BOOL(retVal);
+}
+FCIMPLEND
+
+FCIMPL1(void, ObjectNative::Pulse, Object* pThisUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ OBJECTREF pThis = (OBJECTREF) pThisUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_1(pThis);
+
+ if (pThis == NULL)
+ COMPlusThrow(kNullReferenceException, W("NullReference_This"));
+
+ pThis->Pulse();
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL1(void, ObjectNative::PulseAll, Object* pThisUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ OBJECTREF pThis = (OBJECTREF) pThisUNSAFE;
+ HELPER_METHOD_FRAME_BEGIN_1(pThis);
+
+ if (pThis == NULL)
+ COMPlusThrow(kNullReferenceException, W("NullReference_This"));
+
+ pThis->PulseAll();
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL1(FC_BOOL_RET, ObjectNative::IsLockHeld, Object* pThisUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ BOOL retVal;
+ DWORD owningThreadId;
+ DWORD acquisitionCount;
+
+ //
+ // If the lock is held, check if it's held by the current thread.
+ //
+ retVal = pThisUNSAFE->GetThreadOwningMonitorLock(&owningThreadId, &acquisitionCount);
+ if (retVal)
+ retVal = GetThread()->GetThreadId() == owningThreadId;
+
+ FC_RETURN_BOOL(retVal);
+}
+FCIMPLEND
+
+INT64 QCALLTYPE ObjectNative::GetMonitorLockContentionCount()
+{
+ QCALL_CONTRACT;
+
+ INT64 result = 0;
+
+ BEGIN_QCALL;
+
+ result = (INT64)Thread::GetTotalMonitorLockContentionCount();
+
+ END_QCALL;
+ return result;
+}
diff --git a/src/coreclr/classlibnative/bcltype/objectnative.h b/src/coreclr/classlibnative/bcltype/objectnative.h
new file mode 100644
index 00000000000..cc084e4d3b5
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/objectnative.h
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: ObjectNative.h
+//
+
+//
+// Purpose: Native methods on System.Object
+//
+//
+
+#ifndef _OBJECTNATIVE_H_
+#define _OBJECTNATIVE_H_
+
+#include "fcall.h"
+
+
+//
+// Each function that we call through native only gets one argument,
+// which is actually a pointer to it's stack of arguments. Our structs
+// for accessing these are defined below.
+//
+
+class ObjectNative
+{
+public:
+
+ // This method will return a Class object for the object
+ // iff the Class object has already been created.
+ // If the Class object doesn't exist then you must call the GetClass() method.
+ static FCDECL1(Object*, GetObjectValue, Object* vThisRef);
+ static FCDECL1(INT32, GetHashCode, Object* vThisRef);
+ static FCDECL2(FC_BOOL_RET, Equals, Object *pThisRef, Object *pCompareRef);
+ static FCDECL1(Object*, AllocateUninitializedClone, Object* pObjUNSAFE);
+ static FCDECL1(Object*, GetClass, Object* pThis);
+ static FCDECL2(FC_BOOL_RET, WaitTimeout, INT32 Timeout, Object* pThisUNSAFE);
+ static FCDECL1(void, Pulse, Object* pThisUNSAFE);
+ static FCDECL1(void, PulseAll, Object* pThisUNSAFE);
+ static FCDECL1(FC_BOOL_RET, IsLockHeld, Object* pThisUNSAFE);
+ static INT64 QCALLTYPE GetMonitorLockContentionCount();
+};
+
+#endif // _OBJECTNATIVE_H_
diff --git a/src/coreclr/classlibnative/bcltype/stringnative.cpp b/src/coreclr/classlibnative/bcltype/stringnative.cpp
new file mode 100644
index 00000000000..0c3ec4f8dc7
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/stringnative.cpp
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: StringNative.cpp
+//
+
+//
+// Purpose: The implementation of the String class.
+//
+
+//
+
+#include "common.h"
+
+#include "object.h"
+#include "utilcode.h"
+#include "excep.h"
+#include "frames.h"
+#include "field.h"
+#include "vars.hpp"
+#include "stringnative.h"
+#include "comutilnative.h"
+#include "metasig.h"
+#include "excep.h"
+
+// Compile the string functionality with these pragma flags (equivalent of the command line /Ox flag)
+// Compiling this functionality differently gives us significant throughout gain in some cases.
+#if defined(_MSC_VER) && defined(TARGET_X86)
+#pragma optimize("tgy", on)
+#endif
+
+
+/*==================================GETCHARAT===================================
+**Returns the character at position index. Thows IndexOutOfRangeException as
+**appropriate.
+**This method is not actually used. JIT will generate code for indexer method on string class.
+**
+==============================================================================*/
+FCIMPL2(FC_CHAR_RET, COMString::GetCharAt, StringObject* str, INT32 index) {
+ FCALL_CONTRACT;
+
+ FC_GC_POLL_NOT_NEEDED();
+ VALIDATEOBJECT(str);
+ if (str == NULL) {
+ FCThrow(kNullReferenceException);
+ }
+ _ASSERTE(str->GetMethodTable() == g_pStringClass);
+
+ if (index >=0 && index < (INT32)str->GetStringLength()) {
+ //Return the appropriate character.
+ return str->GetBuffer()[index];
+ }
+
+ FCThrow(kIndexOutOfRangeException);
+}
+FCIMPLEND
+
+
+/*==================================LENGTH=================================== */
+
+FCIMPL1(INT32, COMString::Length, StringObject* str) {
+ FCALL_CONTRACT;
+
+ FC_GC_POLL_NOT_NEEDED();
+ if (str == NULL)
+ FCThrow(kNullReferenceException);
+
+ FCUnique(0x11);
+ return str->GetStringLength();
+}
+FCIMPLEND
+
+
+FCIMPL2(FC_BOOL_RET, COMString::FCTryGetTrailByte, StringObject* thisRefUNSAFE, UINT8 *pbData)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF thisRef = ObjectToSTRINGREF(thisRefUNSAFE);
+ FC_RETURN_BOOL(thisRef->GetTrailByte(pbData));
+}
+FCIMPLEND
+
+FCIMPL2(VOID, COMString::FCSetTrailByte, StringObject* thisRefUNSAFE, UINT8 bData)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF thisRef = ObjectToSTRINGREF(thisRefUNSAFE);
+ HELPER_METHOD_FRAME_BEGIN_1(thisRef);
+
+ thisRef->SetTrailByte(bData);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+// Revert to command line compilation flags
+#if defined(_MSC_VER) && defined(TARGET_X86)
+#pragma optimize ("", on)
+#endif
diff --git a/src/coreclr/classlibnative/bcltype/stringnative.h b/src/coreclr/classlibnative/bcltype/stringnative.h
new file mode 100644
index 00000000000..1396564aef9
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/stringnative.h
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: StringNative.h
+//
+
+//
+// Purpose: Contains types and method signatures for the String class
+//
+
+//
+
+#include "fcall.h"
+#include "qcall.h"
+#include "excep.h"
+
+#ifndef _STRINGNATIVE_H_
+#define _STRINGNATIVE_H_
+//
+// Each function that we call through native only gets one argument,
+// which is actually a pointer to it's stack of arguments. Our structs
+// for accessing these are defined below.
+//
+
+//
+//These are the type signatures for String
+//
+//
+// The method signatures for each of the methods we define.
+// N.B.: There's a one-to-one mapping between the method signatures and the
+// type definitions given above.
+//
+
+
+// Compile the string functionality with these pragma flags (equivalent of the command line /Ox flag)
+// Compiling this functionality differently gives us significant throughout gain in some cases.
+#if defined(_MSC_VER) && defined(TARGET_X86)
+#pragma optimize("tgy", on)
+#endif
+
+class COMString {
+public:
+ //
+ // Query Methods
+ //
+ static FCDECL2(FC_CHAR_RET, GetCharAt, StringObject* pThisRef, INT32 index);
+ static FCDECL1(INT32, Length, StringObject* pThisRef);
+
+ //
+ // Interop
+ //
+ static FCDECL2(FC_BOOL_RET, FCTryGetTrailByte, StringObject* thisRefUNSAFE, UINT8 *pbData);
+ static FCDECL2(VOID, FCSetTrailByte, StringObject* thisRefUNSAFE, UINT8 bData);
+};
+
+// Revert to command line compilation flags
+#if defined(_MSC_VER) && defined(TARGET_X86)
+#pragma optimize ("", on)
+#endif
+
+#endif // _STRINGNATIVE_H_
+
+
+
+
+
+
diff --git a/src/coreclr/classlibnative/bcltype/system.cpp b/src/coreclr/classlibnative/bcltype/system.cpp
new file mode 100644
index 00000000000..3660c14963d
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/system.cpp
@@ -0,0 +1,606 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: System.cpp
+//
+
+//
+// Purpose: Native methods on System.Environment & Array
+//
+
+//
+
+#include "common.h"
+
+#include <object.h>
+
+#include "ceeload.h"
+
+#include "excep.h"
+#include "frames.h"
+#include "vars.hpp"
+#include "classnames.h"
+#include "system.h"
+#include "string.h"
+#include "sstring.h"
+#include "eeconfig.h"
+#include "assemblynative.hpp"
+#include "generics.h"
+#include "invokeutil.h"
+#include "array.h"
+#include "eepolicy.h"
+
+#ifndef TARGET_UNIX
+typedef void(WINAPI *pfnGetSystemTimeAsFileTime)(LPFILETIME lpSystemTimeAsFileTime);
+extern pfnGetSystemTimeAsFileTime g_pfnGetSystemTimeAsFileTime;
+
+void WINAPI InitializeGetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime)
+{
+ pfnGetSystemTimeAsFileTime func = NULL;
+
+ HMODULE hKernel32 = WszLoadLibrary(W("kernel32.dll"));
+ if (hKernel32 != NULL)
+ {
+ func = (pfnGetSystemTimeAsFileTime)GetProcAddress(hKernel32, "GetSystemTimePreciseAsFileTime");
+ if (func != NULL)
+ {
+ // GetSystemTimePreciseAsFileTime exists and we'd like to use it. However, on
+ // misconfigured systems, it's possible for the "precise" time to be inaccurate:
+ // https://github.com/dotnet/runtime/issues/9014
+ // If it's inaccurate, though, we expect it to be wildly inaccurate, so as a
+ // workaround/heuristic, we get both the "normal" and "precise" times, and as
+ // long as they're close, we use the precise one. This workaround can be removed
+ // when we better understand what's causing the drift and the issue is no longer
+ // a problem or can be better worked around on all targeted OSes.
+
+ FILETIME systemTimeResult;
+ ::GetSystemTimeAsFileTime(&systemTimeResult);
+
+ FILETIME preciseSystemTimeResult;
+ func(&preciseSystemTimeResult);
+
+ LONG64 systemTimeLong100ns = (LONG64)((((ULONG64)systemTimeResult.dwHighDateTime) << 32) | (ULONG64)systemTimeResult.dwLowDateTime);
+ LONG64 preciseSystemTimeLong100ns = (LONG64)((((ULONG64)preciseSystemTimeResult.dwHighDateTime) << 32) | (ULONG64)preciseSystemTimeResult.dwLowDateTime);
+
+ const INT32 THRESHOLD_100NS = 1000000; // 100ms
+ if (abs(preciseSystemTimeLong100ns - systemTimeLong100ns) > THRESHOLD_100NS)
+ {
+ // Too much difference. Don't use GetSystemTimePreciseAsFileTime.
+ func = NULL;
+ }
+ }
+ }
+ if (func == NULL)
+ {
+ func = &::GetSystemTimeAsFileTime;
+ }
+
+ InterlockedCompareExchangeT(&g_pfnGetSystemTimeAsFileTime, func, &InitializeGetSystemTimeAsFileTime);
+
+ g_pfnGetSystemTimeAsFileTime(lpSystemTimeAsFileTime);
+}
+
+pfnGetSystemTimeAsFileTime g_pfnGetSystemTimeAsFileTime = &InitializeGetSystemTimeAsFileTime;
+#endif // TARGET_UNIX
+
+FCIMPL0(INT64, SystemNative::__GetSystemTimeAsFileTime)
+{
+ FCALL_CONTRACT;
+
+ INT64 timestamp;
+#ifndef TARGET_UNIX
+ g_pfnGetSystemTimeAsFileTime((FILETIME*)&timestamp);
+#else
+ GetSystemTimeAsFileTime((FILETIME*)&timestamp);
+#endif
+
+#if BIGENDIAN
+ timestamp = (INT64)(((UINT64)timestamp >> 32) | ((UINT64)timestamp << 32));
+#endif
+
+ return timestamp;
+}
+FCIMPLEND;
+
+
+#ifndef TARGET_UNIX
+
+FCIMPL1(VOID, SystemNative::GetSystemTimeWithLeapSecondsHandling, FullSystemTime *time)
+{
+ FCALL_CONTRACT;
+ INT64 timestamp;
+
+ g_pfnGetSystemTimeAsFileTime((FILETIME*)&timestamp);
+
+ if (::FileTimeToSystemTime((FILETIME*)&timestamp, &(time->systemTime)))
+ {
+ // to keep the time precision
+ time->hundredNanoSecond = timestamp % 10000; // 10000 is the number of 100-nano seconds per Millisecond
+ }
+ else
+ {
+ ::GetSystemTime(&(time->systemTime));
+ time->hundredNanoSecond = 0;
+ }
+
+ if (time->systemTime.wSecond > 59)
+ {
+ // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation.
+ // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds
+ time->systemTime.wSecond = 59;
+ time->systemTime.wMilliseconds = 999;
+ time->hundredNanoSecond = 9999;
+ }
+}
+FCIMPLEND;
+
+FCIMPL2(FC_BOOL_RET, SystemNative::FileTimeToSystemTime, INT64 fileTime, FullSystemTime *time)
+{
+ FCALL_CONTRACT;
+ if (::FileTimeToSystemTime((FILETIME*)&fileTime, (LPSYSTEMTIME) time))
+ {
+ // to keep the time precision
+ time->hundredNanoSecond = fileTime % 10000; // 10000 is the number of 100-nano seconds per Millisecond
+ if (time->systemTime.wSecond > 59)
+ {
+ // we have a leap second, force it to last second in the minute as DateTime doesn't account for leap seconds in its calculation.
+ // we use the maxvalue from the milliseconds and the 100-nano seconds to avoid reporting two out of order 59 seconds
+ time->systemTime.wSecond = 59;
+ time->systemTime.wMilliseconds = 999;
+ time->hundredNanoSecond = 9999;
+ }
+ FC_RETURN_BOOL(TRUE);
+ }
+ FC_RETURN_BOOL(FALSE);
+}
+FCIMPLEND;
+
+FCIMPL2(FC_BOOL_RET, SystemNative::ValidateSystemTime, SYSTEMTIME *time, CLR_BOOL localTime)
+{
+ FCALL_CONTRACT;
+
+ if (localTime)
+ {
+ SYSTEMTIME st;
+ FC_RETURN_BOOL(::TzSpecificLocalTimeToSystemTime(NULL, time, &st));
+ }
+ else
+ {
+ FILETIME timestamp;
+ FC_RETURN_BOOL(::SystemTimeToFileTime(time, &timestamp));
+ }
+}
+FCIMPLEND;
+
+FCIMPL2(FC_BOOL_RET, SystemNative::SystemTimeToFileTime, SYSTEMTIME *time, INT64 *pFileTime)
+{
+ FCALL_CONTRACT;
+
+ BOOL ret = ::SystemTimeToFileTime(time, (LPFILETIME) pFileTime);
+ FC_RETURN_BOOL(ret);
+}
+FCIMPLEND;
+#endif // TARGET_UNIX
+
+
+FCIMPL0(UINT32, SystemNative::GetTickCount)
+{
+ FCALL_CONTRACT;
+
+ return ::GetTickCount();
+}
+FCIMPLEND;
+
+FCIMPL0(UINT64, SystemNative::GetTickCount64)
+{
+ FCALL_CONTRACT;
+
+ return ::GetTickCount64();
+}
+FCIMPLEND;
+
+
+
+
+VOID QCALLTYPE SystemNative::Exit(INT32 exitcode)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ // The exit code for the process is communicated in one of two ways. If the
+ // entrypoint returns an 'int' we take that. Otherwise we take a latched
+ // process exit code. This can be modified by the app via setting
+ // Environment's ExitCode property.
+ SetLatchedExitCode(exitcode);
+
+ ForceEEShutdown();
+
+ END_QCALL;
+}
+
+FCIMPL1(VOID,SystemNative::SetExitCode,INT32 exitcode)
+{
+ FCALL_CONTRACT;
+
+ // The exit code for the process is communicated in one of two ways. If the
+ // entrypoint returns an 'int' we take that. Otherwise we take a latched
+ // process exit code. This can be modified by the app via setting
+ // Environment's ExitCode property.
+ SetLatchedExitCode(exitcode);
+}
+FCIMPLEND
+
+FCIMPL0(INT32, SystemNative::GetExitCode)
+{
+ FCALL_CONTRACT;
+
+ // Return whatever has been latched so far. This is uninitialized to 0.
+ return GetLatchedExitCode();
+}
+FCIMPLEND
+
+void QCALLTYPE SystemNative::_GetCommandLine(QCall::StringHandleOnStack retString)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ LPCWSTR commandLine;
+
+ commandLine = WszGetCommandLine();
+ if (commandLine==NULL)
+ COMPlusThrowOM();
+
+ retString.Set(commandLine);
+
+ END_QCALL;
+}
+
+FCIMPL0(Object*, SystemNative::GetCommandLineArgs)
+{
+ FCALL_CONTRACT;
+
+ PTRARRAYREF strArray = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_1(strArray);
+
+ LPWSTR commandLine;
+
+ commandLine = WszGetCommandLine();
+ if (commandLine==NULL)
+ COMPlusThrowOM();
+
+ DWORD numArgs = 0;
+ LPWSTR* argv = SegmentCommandLine(commandLine, &numArgs);
+ if (!argv)
+ COMPlusThrowOM();
+
+ _ASSERTE(numArgs > 0);
+
+ strArray = (PTRARRAYREF) AllocateObjectArray(numArgs, g_pStringClass);
+ // Copy each argument into new Strings.
+ for(unsigned int i=0; i<numArgs; i++)
+ {
+ STRINGREF str = StringObject::NewString(argv[i]);
+ STRINGREF * destData = ((STRINGREF*)(strArray->GetDataPtr())) + i;
+ SetObjectReference((OBJECTREF*)destData, (OBJECTREF)str);
+ }
+ delete [] argv;
+
+ HELPER_METHOD_FRAME_END();
+
+ return OBJECTREFToObject(strArray);
+}
+FCIMPLEND
+
+// Return a method info for the method were the exception was thrown
+FCIMPL1(ReflectMethodObject*, SystemNative::GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ I1ARRAYREF pArray(static_cast<I1Array *>(pStackTraceUNSAFE));
+ StackTraceArray stackArray(pArray);
+
+ if (!stackArray.Size())
+ return NULL;
+
+ // The managed stacktrace classes always returns typical method definition, so we don't need to bother providing exact instantiation.
+ // Generics::GetExactInstantiationsOfMethodAndItsClassFromCallInformation(pElements[0].pFunc, pElements[0].pExactGenericArgsToken, pTypeHandle, &pMD);
+
+ MethodDesc* pFunc = stackArray[0].pFunc;
+
+ // Strip the instantiation to make sure that the reflection never gets a bad method desc back.
+ REFLECTMETHODREF refRet = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_0()
+ pFunc = pFunc->LoadTypicalMethodDefinition();
+ refRet = pFunc->GetStubMethodInfo();
+ _ASSERTE(pFunc->IsRuntimeMethodHandle());
+
+ HELPER_METHOD_FRAME_END();
+
+ return (ReflectMethodObject*)OBJECTREFToObject(refRet);
+}
+FCIMPLEND
+
+INT32 QCALLTYPE SystemNative::GetProcessorCount()
+{
+ QCALL_CONTRACT;
+
+ INT32 processorCount = 0;
+
+ BEGIN_QCALL;
+
+#ifndef TARGET_UNIX
+ CPUGroupInfo::EnsureInitialized();
+
+ if(CPUGroupInfo::CanEnableThreadUseAllCpuGroups())
+ {
+ processorCount = CPUGroupInfo::GetNumActiveProcessors();
+ }
+#endif // !TARGET_UNIX
+ // Processor count will be 0 if CPU groups are disabled/not supported
+ if(processorCount == 0)
+ {
+ SYSTEM_INFO systemInfo;
+ ZeroMemory(&systemInfo, sizeof(systemInfo));
+
+ GetSystemInfo(&systemInfo);
+
+ processorCount = systemInfo.dwNumberOfProcessors;
+ }
+
+#ifdef TARGET_UNIX
+ uint32_t cpuLimit;
+
+ if (PAL_GetCpuLimit(&cpuLimit) && cpuLimit < (uint32_t)processorCount)
+ processorCount = cpuLimit;
+#endif
+
+ END_QCALL;
+
+ return processorCount;
+}
+
+// FailFast is supported in BCL.small as internal to support failing fast in places where EEE used to be thrown.
+//
+// Static message buffer used by SystemNative::FailFast to avoid reliance on a
+// managed string object buffer. This buffer is not always used, see comments in
+// the method below.
+WCHAR g_szFailFastBuffer[256];
+#define FAIL_FAST_STATIC_BUFFER_LENGTH (sizeof(g_szFailFastBuffer) / sizeof(WCHAR))
+
+// This is the common code for FailFast processing that is wrapped by the two
+// FailFast FCalls below.
+void SystemNative::GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode, STRINGREF refErrorSourceString)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_COOPERATIVE;
+ }CONTRACTL_END;
+
+ struct
+ {
+ STRINGREF refMesgString;
+ EXCEPTIONREF refExceptionForWatsonBucketing;
+ STRINGREF refErrorSourceString;
+ } gc;
+ ZeroMemory(&gc, sizeof(gc));
+
+ GCPROTECT_BEGIN(gc);
+
+ gc.refMesgString = refMesgString;
+ gc.refExceptionForWatsonBucketing = refExceptionForWatsonBucketing;
+ gc.refErrorSourceString = refErrorSourceString;
+
+ // Managed code injected FailFast maps onto the unmanaged version
+ // (EEPolicy::HandleFatalError) in the following manner: the exit code is
+ // always set to COR_E_FAILFAST and the address passed (usually a failing
+ // EIP) is in fact the address of a unicode message buffer (explaining the
+ // reason for the fault).
+ // The message string comes from a managed string object so we can't rely on
+ // the buffer remaining in place below our feet. But equally we don't want
+ // to inject failure points (by, for example, allocating a heap buffer or a
+ // pinning handle) when we have a much higher chance than usual of actually
+ // tripping those failure points and eradicating useful debugging info.
+ // We employ various strategies to deal with this:
+ // o If the message is small enough we copy it into a static buffer
+ // (g_szFailFastBuffer).
+ // o Otherwise we try to allocate a buffer of the required size on the
+ // heap. This buffer will be leaked.
+ // o If the allocation above fails we return to the static buffer and
+ // truncate the message.
+ //
+ // Another option would seem to be to implement a new frame type that
+ // protects object references as pinned, but that seems like overkill for
+ // just this problem.
+ WCHAR *pszMessage = NULL;
+ DWORD cchMessage = (gc.refMesgString == NULL) ? 0 : gc.refMesgString->GetStringLength();
+
+ WCHAR * errorSourceString = NULL;
+
+ if (gc.refErrorSourceString != NULL)
+ {
+ DWORD cchErrorSource = gc.refErrorSourceString->GetStringLength();
+ errorSourceString = new (nothrow) WCHAR[cchErrorSource + 1];
+
+ if (errorSourceString != NULL)
+ {
+ memcpyNoGCRefs(errorSourceString, gc.refErrorSourceString->GetBuffer(), cchErrorSource * sizeof(WCHAR));
+ errorSourceString[cchErrorSource] = W('\0');
+ }
+ }
+
+ if (cchMessage < FAIL_FAST_STATIC_BUFFER_LENGTH)
+ {
+ pszMessage = g_szFailFastBuffer;
+ }
+ else
+ {
+ // We can fail here, but we can handle the fault.
+ CONTRACT_VIOLATION(FaultViolation);
+ pszMessage = new (nothrow) WCHAR[cchMessage + 1];
+ if (pszMessage == NULL)
+ {
+ // Truncate the message to what will fit in the static buffer.
+ cchMessage = FAIL_FAST_STATIC_BUFFER_LENGTH - 1;
+ pszMessage = g_szFailFastBuffer;
+ }
+ }
+
+ if (cchMessage > 0)
+ memcpyNoGCRefs(pszMessage, gc.refMesgString->GetBuffer(), cchMessage * sizeof(WCHAR));
+ pszMessage[cchMessage] = W('\0');
+
+ if (cchMessage == 0) {
+ WszOutputDebugString(W("CLR: Managed code called FailFast without specifying a reason.\r\n"));
+ }
+ else {
+ WszOutputDebugString(W("CLR: Managed code called FailFast, saying \""));
+ WszOutputDebugString(pszMessage);
+ WszOutputDebugString(W("\"\r\n"));
+ }
+
+ LPCWSTR argExceptionString = NULL;
+ StackSString msg;
+ if (gc.refExceptionForWatsonBucketing != NULL)
+ {
+ GetExceptionMessage(gc.refExceptionForWatsonBucketing, msg);
+ argExceptionString = msg.GetUnicode();
+ }
+
+ Thread *pThread = GetThread();
+
+#ifndef TARGET_UNIX
+ // If we have the exception object, then try to setup
+ // the watson bucket if it has any details.
+ // On CoreCLR, Watson may not be enabled. Thus, we should
+ // skip this, if required.
+ if (IsWatsonEnabled())
+ {
+ if ((gc.refExceptionForWatsonBucketing == NULL) || !SetupWatsonBucketsForFailFast(gc.refExceptionForWatsonBucketing))
+ {
+ PTR_EHWatsonBucketTracker pUEWatsonBucketTracker = pThread->GetExceptionState()->GetUEWatsonBucketTracker();
+ _ASSERTE(pUEWatsonBucketTracker != NULL);
+ pUEWatsonBucketTracker->SaveIpForWatsonBucket(retAddress);
+ pUEWatsonBucketTracker->CaptureUnhandledInfoForWatson(TypeOfReportedError::FatalError, pThread, NULL);
+ if (pUEWatsonBucketTracker->RetrieveWatsonBuckets() == NULL)
+ {
+ pUEWatsonBucketTracker->ClearWatsonBucketDetails();
+ }
+ }
+ }
+#endif // !TARGET_UNIX
+
+ // stash the user-provided exception object. this will be used as
+ // the inner exception object to the FatalExecutionEngineException.
+ if (gc.refExceptionForWatsonBucketing != NULL)
+ pThread->SetLastThrownObject(gc.refExceptionForWatsonBucketing);
+
+ EEPolicy::HandleFatalError(exitCode, retAddress, pszMessage, NULL, errorSourceString, argExceptionString);
+
+ GCPROTECT_END();
+}
+
+// Note: Do not merge this FCALL method with any other FailFast overloads.
+// Watson uses the managed FailFast method with one String for crash dump bucketization.
+FCIMPL1(VOID, SystemNative::FailFast, StringObject* refMessageUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_1(refMessage);
+
+ // The HelperMethodFrame knows how to get the return address.
+ UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
+
+ // Call the actual worker to perform failfast
+ GenericFailFast(refMessage, NULL, retaddr, COR_E_FAILFAST, NULL);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL2(VOID, SystemNative::FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_1(refMessage);
+
+ // The HelperMethodFrame knows how to get the return address.
+ UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
+
+ // Call the actual worker to perform failfast
+ GenericFailFast(refMessage, NULL, retaddr, exitCode, NULL);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL2(VOID, SystemNative::FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
+ EXCEPTIONREF refException = (EXCEPTIONREF)refExceptionUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_2(refMessage, refException);
+
+ // The HelperMethodFrame knows how to get the return address.
+ UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
+
+ // Call the actual worker to perform failfast
+ GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, NULL);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL3(VOID, SystemNative::FailFastWithExceptionAndSource, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE, StringObject* errorSourceUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ STRINGREF refMessage = (STRINGREF)refMessageUNSAFE;
+ EXCEPTIONREF refException = (EXCEPTIONREF)refExceptionUNSAFE;
+ STRINGREF errorSource = (STRINGREF)errorSourceUNSAFE;
+
+ HELPER_METHOD_FRAME_BEGIN_3(refMessage, refException, errorSource);
+
+ // The HelperMethodFrame knows how to get the return address.
+ UINT_PTR retaddr = HELPER_METHOD_FRAME_GET_RETURN_ADDRESS();
+
+ // Call the actual worker to perform failfast
+ GenericFailFast(refMessage, refException, retaddr, COR_E_FAILFAST, errorSource);
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+FCIMPL0(FC_BOOL_RET, SystemNative::IsServerGC)
+{
+ FCALL_CONTRACT;
+
+ FC_RETURN_BOOL(GCHeapUtilities::IsServerHeap());
+}
+FCIMPLEND
+
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+
+void QCALLTYPE SystemNative::X86BaseCpuId(int cpuInfo[4], int functionId, int subFunctionId)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ __cpuidex(cpuInfo, functionId, subFunctionId);
+
+ END_QCALL;
+}
+
+#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
diff --git a/src/coreclr/classlibnative/bcltype/system.h b/src/coreclr/classlibnative/bcltype/system.h
new file mode 100644
index 00000000000..5bbf73d4a10
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/system.h
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: System.h
+//
+
+//
+// Purpose: Native methods on System.System
+//
+
+#ifndef _SYSTEM_H_
+#define _SYSTEM_H_
+
+#include "fcall.h"
+#include "qcall.h"
+
+struct FullSystemTime
+{
+ SYSTEMTIME systemTime;
+ INT64 hundredNanoSecond;
+};
+
+class SystemNative
+{
+ friend class DebugStackTrace;
+
+private:
+ struct CaptureStackTraceData
+ {
+ // Used for the integer-skip version
+ INT32 skip;
+
+ INT32 cElementsAllocated;
+ INT32 cElements;
+ StackTraceElement* pElements;
+ void* pStopStack; // use to limit the crawl
+
+ CaptureStackTraceData() : skip(0), cElementsAllocated(0), cElements(0), pElements(NULL), pStopStack((void*)-1)
+ {
+ LIMITED_METHOD_CONTRACT;
+ }
+ };
+
+public:
+ // Functions on the System.Environment class
+#ifndef TARGET_UNIX
+ static FCDECL1(VOID, GetSystemTimeWithLeapSecondsHandling, FullSystemTime *time);
+ static FCDECL2(FC_BOOL_RET, ValidateSystemTime, SYSTEMTIME *time, CLR_BOOL localTime);
+ static FCDECL2(FC_BOOL_RET, FileTimeToSystemTime, INT64 fileTime, FullSystemTime *time);
+ static FCDECL2(FC_BOOL_RET, SystemTimeToFileTime, SYSTEMTIME *time, INT64 *pFileTime);
+#endif // TARGET_UNIX
+ static FCDECL0(INT64, __GetSystemTimeAsFileTime);
+ static FCDECL0(UINT32, GetTickCount);
+ static FCDECL0(UINT64, GetTickCount64);
+
+ static
+ void QCALLTYPE Exit(INT32 exitcode);
+
+ static FCDECL1(VOID,SetExitCode,INT32 exitcode);
+ static FCDECL0(INT32, GetExitCode);
+
+ static
+ void QCALLTYPE _GetCommandLine(QCall::StringHandleOnStack retString);
+
+ static FCDECL0(Object*, GetCommandLineArgs);
+ static FCDECL1(VOID, FailFast, StringObject* refMessageUNSAFE);
+ static FCDECL2(VOID, FailFastWithExitCode, StringObject* refMessageUNSAFE, UINT exitCode);
+ static FCDECL2(VOID, FailFastWithException, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE);
+ static FCDECL3(VOID, FailFastWithExceptionAndSource, StringObject* refMessageUNSAFE, ExceptionObject* refExceptionUNSAFE, StringObject* errorSourceUNSAFE);
+
+ // Returns the number of logical processors that can be used by managed code
+ static INT32 QCALLTYPE GetProcessorCount();
+
+ static FCDECL0(FC_BOOL_RET, IsServerGC);
+
+ // Return a method info for the method were the exception was thrown
+ static FCDECL1(ReflectMethodObject*, GetMethodFromStackTrace, ArrayBase* pStackTraceUNSAFE);
+
+#if defined(TARGET_X86) || defined(TARGET_AMD64)
+ static void QCALLTYPE X86BaseCpuId(int cpuInfo[4], int functionId, int subFunctionId);
+#endif // defined(TARGET_X86) || defined(TARGET_AMD64)
+
+private:
+ // Common processing code for FailFast
+ static void GenericFailFast(STRINGREF refMesgString, EXCEPTIONREF refExceptionForWatsonBucketing, UINT_PTR retAddress, UINT exitCode, STRINGREF errorSource);
+};
+
+/* static */
+void QCALLTYPE GetTypeLoadExceptionMessage(UINT32 resId, QCall::StringHandleOnStack retString);
+
+/* static */
+void QCALLTYPE GetFileLoadExceptionMessage(UINT32 hr, QCall::StringHandleOnStack retString);
+
+/* static */
+void QCALLTYPE FileLoadException_GetMessageForHR(UINT32 hresult, QCall::StringHandleOnStack retString);
+
+#endif // _SYSTEM_H_
+
diff --git a/src/coreclr/classlibnative/bcltype/varargsnative.cpp b/src/coreclr/classlibnative/bcltype/varargsnative.cpp
new file mode 100644
index 00000000000..55dd48bf280
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/varargsnative.cpp
@@ -0,0 +1,638 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: VarArgsNative.cpp
+//
+
+//
+// This module contains the implementation of the native methods for the
+// varargs class(es)..
+//
+
+
+#include "common.h"
+#include "object.h"
+#include "excep.h"
+#include "frames.h"
+#include "vars.hpp"
+#include "varargsnative.h"
+
+// Some platforms have additional alignment requirements for arguments. This function adjusts the given arg
+// pointer to achieve such an alignment for the next argument on those platforms (otherwise it is a no-op).
+// NOTE: the debugger has its own implementation of this algorithm in Debug\DI\RsType.cpp, CordbType::RequiresAlign8()
+// so if you change this implementation be sure to update the debugger's version as well.
+static void AdjustArgPtrForAlignment(VARARGS *pData, size_t cbArg)
+{
+#ifdef TARGET_ARM
+ // Only 64-bit primitives or value types with embedded 64-bit primitives are aligned on 64-bit boundaries.
+ if (cbArg < 8)
+ return;
+
+ // For the value type case we have to dig deeper and ask the typeloader whether the type requires
+ // alignment.
+ SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic.
+ CorElementType et = pData->SigPtr.PeekElemTypeClosed(pData->ArgCookie->pModule, &typeContext);
+ if (et == ELEMENT_TYPE_TYPEDBYREF)
+ {
+ return;
+ }
+ else
+ if (et == ELEMENT_TYPE_VALUETYPE)
+ {
+ SigPointer tempSig(pData->SigPtr);
+ TypeHandle valueType = tempSig.GetTypeHandleThrowing(pData->ArgCookie->pModule, &typeContext);
+ if (!valueType.AsMethodTable()->RequiresAlign8())
+ return;
+ }
+ else
+ {
+ // One of the primitive 64-bit types
+ }
+ pData->ArgPtr = (BYTE*)ALIGN_UP(pData->ArgPtr, 8);
+#endif // TARGET_ARM
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Initialize the basic info for processing a varargs parameter list.
+////////////////////////////////////////////////////////////////////////////////
+static void InitCommon(VARARGS *data, VASigCookie** cookie)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(data));
+ PRECONDITION(CheckPointer(cookie));
+ } CONTRACTL_END;
+
+ // Save the cookie and a copy of the signature.
+ data->ArgCookie = *cookie;
+ data->SigPtr = data->ArgCookie->signature.CreateSigPointer();
+
+ // Skip the calling convention, get the # of args and skip the return type.
+ ULONG callConv;
+ IfFailThrow(data->SigPtr.GetCallingConvInfo(&callConv));
+
+ ULONG sigData;
+ IfFailThrow(data->SigPtr.GetData(&sigData));
+ data->RemainingArgs = sigData;
+
+ IfFailThrow(data->SigPtr.SkipExactlyOne());
+
+ // Get a pointer to the cookie arg.
+ data->ArgPtr = (BYTE *) cookie;
+
+#if defined(TARGET_X86)
+ // STACK_GROWS_DOWN_ON_ARGS_WALK
+
+ // <return address> ;; lower memory
+ // <varargs_cookie> '\'
+ // <argN> '\'
+ // += sizeOfArgs
+ // /
+ // <arg1> /
+ // * <this> ;; if an instance method (note: <this> is usally passed in
+ // ;; a register and wouldn't appear on the stack frame)
+ // ;; higher memory
+ //
+ // When the stack grows down, ArgPtr always points to the end of the next
+ // argument passed. So we initialize it to the address that is the
+ // end of the first fixed arg (arg1) (marked with a '*').
+
+ data->ArgPtr += data->ArgCookie->sizeOfArgs;
+#else
+ // STACK_GROWS_UP_ON_ARGS_WALK
+
+ // <this> ;; lower memory
+ // <varargs_cookie> ;; if an instance method
+ // * <arg1>
+ //
+ // <argN> ;; higher memory
+ //
+ // When the stack grows up, ArgPtr always points to the start of the next
+ // argument passed. So we initialize it to the address marked with a '*',
+ // which is the start of the first fixed arg (arg1).
+
+ // Always skip over the varargs_cookie.
+ data->ArgPtr += StackElemSize(sizeof(LPVOID));
+#endif
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// After initialization advance the next argument pointer to the first optional
+// argument.
+////////////////////////////////////////////////////////////////////////////////
+void AdvanceArgPtr(VARARGS *data)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(data));
+ } CONTRACTL_END;
+
+ // Advance to the first optional arg.
+ while (data->RemainingArgs > 0)
+ {
+ if (data->SigPtr.AtSentinel())
+ break;
+
+ SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
+ SIZE_T cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule, &typeContext);
+ SIZE_T cbArg = StackElemSize(cbRaw);
+
+#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
+ if (ArgIterator::IsVarArgPassedByRef(cbRaw))
+ cbArg = sizeof(void*);
+#endif
+
+ // Adjust the frame pointer and the signature info.
+ AdjustArgPtrForAlignment(data, cbArg);
+#ifdef STACK_GROWS_DOWN_ON_ARGS_WALK
+ data->ArgPtr -= cbArg;
+#else // STACK_GROWS_UP_ON_ARGS_WALK
+ data->ArgPtr += cbArg;
+#endif // STACK_GROWS_**_ON_ARGS_WALK
+
+ IfFailThrow(data->SigPtr.SkipExactlyOne());
+ --data->RemainingArgs;
+ }
+} // AdvanceArgPtr
+
+////////////////////////////////////////////////////////////////////////////////
+// ArgIterator constructor that initializes the state to support iteration
+// of the args starting at the first optional argument.
+////////////////////////////////////////////////////////////////////////////////
+FCIMPL2(void, VarArgsNative::Init, VARARGS* _this, LPVOID cookie)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ _ASSERTE(_this != NULL);
+ VARARGS* data = _this;
+ if (cookie == 0)
+ COMPlusThrow(kArgumentException, W("InvalidOperation_HandleIsNotInitialized"));
+
+ VASigCookie* pCookie = *(VASigCookie**)(cookie);
+
+ if (pCookie->signature.IsEmpty())
+ {
+ data->SigPtr = SigPointer(NULL, 0);
+ data->ArgCookie = NULL;
+ data->ArgPtr = (BYTE*)((VASigCookieEx*)pCookie)->m_pArgs;
+ }
+ else
+ {
+ // Use common code to pick the cookie apart and advance to the ...
+ InitCommon(data, (VASigCookie**)cookie);
+ AdvanceArgPtr(data);
+ }
+
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+////////////////////////////////////////////////////////////////////////////////
+// ArgIterator constructor that initializes the state to support iteration
+// of the args starting at the argument following the supplied argument pointer.
+// Specifying NULL as the firstArg parameter causes it to start at the first
+// argument to the call.
+////////////////////////////////////////////////////////////////////////////////
+FCIMPL3(
+void,
+VarArgsNative::Init2,
+ VARARGS * _this,
+ LPVOID cookie,
+ LPVOID firstArg)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_0();
+
+ _ASSERTE(_this != NULL);
+ VARARGS* data = _this;
+ if (cookie == 0)
+ COMPlusThrow(kArgumentException, W("InvalidOperation_HandleIsNotInitialized"));
+
+ // Init most of the structure.
+ InitCommon(data, (VASigCookie**)cookie);
+
+ // If it is NULL, start at the first arg.
+ if (firstArg != NULL)
+ {
+ //
+ // The expectation made by VarArgsNative is that:
+#ifdef STACK_GROWS_DOWN_ON_ARGS_WALK
+ // data->ArgPtr points to the end of the next argument.
+ // <varargs_cookie>
+ // <argN> <-- data->ArgPtr after InitCommon
+ //
+ // <argM 1st optional arg>
+ // *@ <arg2> <-- firstArg, data->ArgPtr leaving Init2()
+ // <arg1>
+ // <this> ;; if an instance method
+ // ;; higher memory
+ //
+#else // STACK_GROWS_UP_ON_ARGS_WALK
+ // data->ArgPtr points to the beginning of the next argument
+ // <this> ;; if an instance method
+ // <varargs_cookie>
+ // <arg1> <-- data->ArgPtr after InitCommon
+ // * <arg2> <-- firstArg
+ // @ <argM - 1st optional arg> <-- data->ArgPtr leaving Init2()
+ //
+ // <argN>
+ // ;; higher memory
+#endif // STACK_GROWS_**_ON_ARGS_WALK
+ // where * indicates the place on the stack that firstArg points upon
+ // entry to Init2. We need to correct in the STACK_GROWS_UP... case since
+ // we actually want to point at the argument after firstArg. This confusion
+ // comes from the difference in expectation of whether ArgPtr is pointing
+ // at the beginning or end of the argument on the stack.
+ //
+ // @ indicates where we want data->ArgPtr to point to after we're done with Init2
+ //
+
+ // Advance to the specified arg.
+ while (data->RemainingArgs > 0)
+ {
+ if (data->SigPtr.AtSentinel())
+ {
+ COMPlusThrow(kArgumentException);
+ }
+
+ SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
+ SIZE_T cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule,&typeContext);
+ SIZE_T cbArg = StackElemSize(cbRaw);
+
+#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
+ if (ArgIterator::IsVarArgPassedByRef(cbRaw))
+ cbArg = sizeof(void*);
+#endif
+
+ // Adjust the frame pointer and the signature info.
+ AdjustArgPtrForAlignment(data, cbArg);
+ IfFailThrow(data->SigPtr.SkipExactlyOne());
+ data->RemainingArgs--;
+
+#ifdef STACK_GROWS_DOWN_ON_ARGS_WALK
+ data->ArgPtr -= cbArg;
+ bool atFirstArg = (data->ArgPtr == firstArg);
+#else // STACK_GROWS_UP_ON_ARGS_WALK
+ bool atFirstArg = (data->ArgPtr == firstArg);
+ data->ArgPtr += cbArg;
+#endif // STACK_GROWS_**_ON_ARGS_WALK
+
+ if (atFirstArg)
+ break;
+ }
+ }
+ HELPER_METHOD_FRAME_END();
+} // VarArgsNative::Init2
+FCIMPLEND
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Return the number of unprocessed args in the argument iterator.
+////////////////////////////////////////////////////////////////////////////////
+FCIMPL1(int, VarArgsNative::GetRemainingCount, VARARGS* _this)
+{
+ FCALL_CONTRACT;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
+
+ _ASSERTE(_this != NULL);
+ if (!(_this->ArgCookie))
+ {
+ // this argiterator was created by marshaling from an unmanaged va_list -
+ // can't do this operation
+ COMPlusThrow(kNotSupportedException);
+ }
+ HELPER_METHOD_FRAME_END();
+ return (_this->RemainingArgs);
+}
+FCIMPLEND
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Retrieve the type of the next argument without consuming it.
+////////////////////////////////////////////////////////////////////////////////
+FCIMPL1(void*, VarArgsNative::GetNextArgType, VARARGS* _this)
+{
+ FCALL_CONTRACT;
+
+ TypedByRef value;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_0();
+
+ PREFIX_ASSUME(_this != NULL);
+ VARARGS data = *_this;
+
+ if (!(_this->ArgCookie))
+ {
+ // this argiterator was created by marshaling from an unmanaged va_list -
+ // can't do this operation
+ COMPlusThrow(kNotSupportedException);
+ }
+
+
+ // Make sure there are remaining args.
+ if (data.RemainingArgs == 0)
+ COMPlusThrow(kInvalidOperationException, W("InvalidOperation_EnumEnded"));
+
+ GetNextArgHelper(&data, &value, FALSE);
+ HELPER_METHOD_FRAME_END();
+ return value.type.AsPtr();
+}
+FCIMPLEND
+
+////////////////////////////////////////////////////////////////////////////////
+// Retrieve the next argument and return it in a TypedByRef and advance the
+// next argument pointer.
+////////////////////////////////////////////////////////////////////////////////
+FCIMPL2(void, VarArgsNative::DoGetNextArg, VARARGS* _this, void * value)
+{
+ FCALL_CONTRACT;
+
+ TypedByRef * result = (TypedByRef *)value;
+ HELPER_METHOD_FRAME_BEGIN_0();
+ GCPROTECT_BEGININTERIOR (result);
+
+ _ASSERTE(_this != NULL);
+ if (!(_this->ArgCookie))
+ {
+ // this argiterator was created by marshaling from an unmanaged va_list -
+ // can't do this operation
+ COMPlusThrow(kInvalidOperationException);
+ }
+
+ // Make sure there are remaining args.
+ if (_this->RemainingArgs == 0)
+ COMPlusThrow(kInvalidOperationException, W("InvalidOperation_EnumEnded"));
+
+ GetNextArgHelper(_this, result, TRUE);
+ GCPROTECT_END ();
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Retrieve the next argument and return it in a TypedByRef and advance the
+// next argument pointer.
+////////////////////////////////////////////////////////////////////////////////
+FCIMPL3(void, VarArgsNative::GetNextArg2, VARARGS* _this, void * value, ReflectClassBaseObject *pTypeUNSAFE)
+{
+ FCALL_CONTRACT;
+
+ TypedByRef * result = (TypedByRef *)value;
+ REFLECTCLASSBASEREF refType = (REFLECTCLASSBASEREF)ObjectToOBJECTREF(pTypeUNSAFE);
+
+ if (refType == NULL)
+ FCThrowResVoid(kArgumentNullException, W("Arg_InvalidHandle"));
+
+ HELPER_METHOD_FRAME_BEGIN_1(refType);
+ GCPROTECT_BEGININTERIOR (result);
+
+ // IJW
+
+ TypeHandle typehandle = refType->GetType();
+
+ _ASSERTE(_this != NULL);
+ UINT size = 0;
+
+ CorElementType typ = typehandle.GetInternalCorElementType();
+ if (CorTypeInfo::IsPrimitiveType(typ))
+ {
+ size = CorTypeInfo::Size(typ);
+ }
+ else if (typ == ELEMENT_TYPE_PTR)
+ {
+ size = sizeof(LPVOID);
+ }
+ else if (typ == ELEMENT_TYPE_VALUETYPE)
+ {
+ size = typehandle.AsMethodTable()->GetNativeSize();
+ }
+ else
+ {
+ COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
+ }
+
+ size = StackElemSize(size);
+
+ AdjustArgPtrForAlignment(_this, size);
+
+#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
+ if (ArgIterator::IsVarArgPassedByRef(size))
+ {
+ result->data = *(void**)_this->ArgPtr;
+ size = sizeof(void*);
+ }
+ else
+#endif
+ {
+ result->data = (void*)_this->ArgPtr;
+ }
+
+ result->type = typehandle;
+ _this->ArgPtr += size;
+
+ GCPROTECT_END ();
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+
+////////////////////////////////////////////////////////////////////////////////
+// This is a helper that uses a VARARGS tracking data structure to retrieve
+// the next argument out of a varargs function call. This does not check if
+// there are any args remaining (it assumes it has been checked).
+////////////////////////////////////////////////////////////////////////////////
+void
+VarArgsNative::GetNextArgHelper(
+ VARARGS * data,
+ TypedByRef * value,
+ BOOL fData)
+{
+ CONTRACTL {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ PRECONDITION(CheckPointer(data));
+ PRECONDITION(CheckPointer(value));
+ } CONTRACTL_END;
+
+ GCPROTECT_BEGININTERIOR (value);
+ CorElementType elemType;
+
+ _ASSERTE(data->RemainingArgs != 0);
+
+ SigTypeContext typeContext; // This is an empty type context. This is OK because the vararg methods may not be generic
+ SIZE_T cbRaw = data->SigPtr.SizeOf(data->ArgCookie->pModule,&typeContext);
+ SIZE_T cbArg = StackElemSize(cbRaw);
+
+ AdjustArgPtrForAlignment(data, cbArg);
+
+ // Get a pointer to the beginning of the argument.
+#ifdef STACK_GROWS_DOWN_ON_ARGS_WALK
+ data->ArgPtr -= cbArg;
+#endif
+
+ // Assume the ref pointer points directly at the arg on the stack.
+ void* origArgPtr = data->ArgPtr;
+ value->data = origArgPtr;
+
+#ifndef STACK_GROWS_DOWN_ON_ARGS_WALK
+ data->ArgPtr += cbArg;
+#endif // STACK_GROWS_**_ON_ARGS_WALK
+
+
+TryAgain:
+ switch (elemType = data->SigPtr.PeekElemTypeClosed(data->ArgCookie->pModule, &typeContext))
+ {
+ case ELEMENT_TYPE_BOOLEAN:
+ case ELEMENT_TYPE_I1:
+ case ELEMENT_TYPE_U1:
+#if BIGENDIAN
+ if ( origArgPtr == value->data ) {
+ value->data = (BYTE*)origArgPtr + (sizeof(void*)-1);
+ }
+#endif
+ value->type = CoreLibBinder::GetElementType(elemType);
+ break;
+
+ case ELEMENT_TYPE_I2:
+ case ELEMENT_TYPE_U2:
+ case ELEMENT_TYPE_CHAR:
+#if BIGENDIAN
+ if ( origArgPtr == value->data ) {
+ value->data = (BYTE*)origArgPtr + (sizeof(void*)-2);
+ }
+#endif
+ value->type = CoreLibBinder::GetElementType(elemType);
+ break;
+
+ case ELEMENT_TYPE_I4:
+ case ELEMENT_TYPE_U4:
+ case ELEMENT_TYPE_R4:
+ case ELEMENT_TYPE_STRING:
+ case ELEMENT_TYPE_I:
+ case ELEMENT_TYPE_U:
+ value->type = CoreLibBinder::GetElementType(elemType);
+ break;
+
+ case ELEMENT_TYPE_I8:
+ case ELEMENT_TYPE_U8:
+ case ELEMENT_TYPE_R8:
+ value->type = CoreLibBinder::GetElementType(elemType);
+#if !defined(HOST_64BIT) && (DATA_ALIGNMENT > 4)
+ if ( fData && origArgPtr == value->data ) {
+ // allocate an aligned copy of the value
+ value->data = value->type.AsMethodTable()->Box(origArgPtr, FALSE)->UnBox();
+ }
+#endif
+ break;
+
+ case ELEMENT_TYPE_PTR:
+ value->type = data->SigPtr.GetTypeHandleThrowing(data->ArgCookie->pModule, &typeContext);
+ break;
+
+ case ELEMENT_TYPE_BYREF:
+ // Check if we have already processed a by-ref.
+ if (value->data != origArgPtr)
+ {
+ _ASSERTE(!"Can't have a ByRef of a ByRef");
+ COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
+ }
+
+ // Dereference the argument to remove the indirection of the ByRef.
+ value->data = *((void **) value->data);
+
+ // Consume and discard the element type.
+ IfFailThrow(data->SigPtr.GetElemType(NULL));
+ goto TryAgain;
+
+ case ELEMENT_TYPE_VALUETYPE:
+
+#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
+ if (origArgPtr == value->data && ArgIterator::IsVarArgPassedByRef(cbRaw))
+ {
+ // Adjust the arg pointer so only one word has been skipped
+ data->ArgPtr = (BYTE *)origArgPtr + sizeof(void*);
+ // Dereference the argument because the valuetype is passed by reference
+ value->data = *((void **) origArgPtr);
+ }
+#endif
+
+#if BIGENDIAN
+ // Adjust the pointer for small valuetypes
+ if (origArgPtr == value->data) {
+ value->data = StackElemEndianessFixup(origArgPtr, cbRaw);
+ }
+#endif
+
+ FALLTHROUGH;
+
+ case ELEMENT_TYPE_CLASS: {
+ value->type = data->SigPtr.GetTypeHandleThrowing(data->ArgCookie->pModule, &typeContext);
+
+ if (value->type.AsMethodTable()->IsByRefLike())
+ {
+ COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
+ }
+
+ if (elemType == ELEMENT_TYPE_CLASS && value->type.AsMethodTable()->IsValueType())
+ value->type = g_pObjectClass;
+ } break;
+
+ case ELEMENT_TYPE_TYPEDBYREF:
+ if (value->data != origArgPtr)
+ {
+ //<TODO>@todo: Is this really an error?</TODO>
+ _ASSERTE(!"Can't have a ByRef of a TypedByRef");
+ COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
+ }
+#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
+ if (ArgIterator::IsVarArgPassedByRef(sizeof(TypedByRef)))
+ {
+ // Adjust the arg pointer so only one word has been skipped
+ data->ArgPtr = (BYTE *)origArgPtr + sizeof(void *);
+ // Dereference the argument because the valuetypes are always passed by reference
+ value->data = *((void **)origArgPtr);
+ }
+#endif // ENREGISTERED_PARAMTYPE_MAXSIZE
+ // Load the TypedByRef
+ value->type = ((TypedByRef*)value->data)->type;
+ value->data = ((TypedByRef*)value->data)->data;
+ break;
+
+ case ELEMENT_TYPE_SZARRAY:
+ case ELEMENT_TYPE_ARRAY:
+ {
+ value->type = data->SigPtr.GetTypeHandleThrowing(data->ArgCookie->pModule,&typeContext);
+
+ break;
+ }
+
+ case ELEMENT_TYPE_FNPTR:
+ case ELEMENT_TYPE_OBJECT:
+ _ASSERTE(!"Not implemented");
+ COMPlusThrow(kNotSupportedException);
+ break;
+
+ case ELEMENT_TYPE_SENTINEL:
+ default:
+ _ASSERTE(!"Should be unreachable");
+ COMPlusThrow(kNotSupportedException, W("NotSupported_Type"));
+ break;
+ }
+
+ // Update the tracking stuff to move past the argument.
+ --data->RemainingArgs;
+ IfFailThrow(data->SigPtr.SkipExactlyOne());
+ GCPROTECT_END ();
+} // VarArgsNative::GetNextArgHelper
diff --git a/src/coreclr/classlibnative/bcltype/varargsnative.h b/src/coreclr/classlibnative/bcltype/varargsnative.h
new file mode 100644
index 00000000000..b3692015035
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/varargsnative.h
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: VarArgsNative.h
+//
+
+//
+// This module contains the implementation of the native methods for the
+// varargs class(es)..
+//
+
+#ifndef _VARARGSNATIVE_H_
+#define _VARARGSNATIVE_H_
+
+#include "clrvarargs.h"
+
+class VarArgsNative
+{
+public:
+ static FCDECL3(void, Init2, VARARGS* _this, LPVOID cookie, LPVOID firstArg);
+ static FCDECL2(void, Init, VARARGS* _this, LPVOID cookie);
+ static FCDECL1(int, GetRemainingCount, VARARGS* _this);
+ static FCDECL1(void*, GetNextArgType, VARARGS* _this);
+ //TypedByRef can not be passed by ref, so has to pass it as void pointer
+ static FCDECL2(void, DoGetNextArg, VARARGS* _this, void * value);
+ //TypedByRef can not be passed by ref, so has to pass it as void pointer
+ static FCDECL3(void, GetNextArg2, VARARGS* _this, void * value, ReflectClassBaseObject *pTypeUNSAFE);
+
+ static void GetNextArgHelper(VARARGS *data, TypedByRef *value, BOOL fData);
+};
+
+#endif // _VARARGSNATIVE_H_
diff --git a/src/coreclr/classlibnative/bcltype/variant.cpp b/src/coreclr/classlibnative/bcltype/variant.cpp
new file mode 100644
index 00000000000..a269644d797
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/variant.cpp
@@ -0,0 +1,289 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: Variant.cpp
+//
+
+//
+// Purpose: Native Implementation of the Variant Class
+//
+
+//
+
+#include "common.h"
+
+#ifdef FEATURE_COMINTEROP
+
+#include "object.h"
+#include "excep.h"
+#include "frames.h"
+#include "vars.hpp"
+#include "variant.h"
+#include "string.h"
+#include "field.h"
+
+// The following values are used to represent underlying
+// type of the Enum..
+#define EnumI1 0x100000
+#define EnumU1 0x200000
+#define EnumI2 0x300000
+#define EnumU2 0x400000
+#define EnumI4 0x500000
+#define EnumU4 0x600000
+#define EnumI8 0x700000
+#define EnumU8 0x800000
+#define EnumMask 0xF00000
+
+
+/*===============================SetFieldsObject================================
+**
+==============================================================================*/
+FCIMPL2(void, COMVariant::SetFieldsObject, VariantData* var, Object* vVal)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(var));
+ PRECONDITION(CheckPointer(vVal));
+ }
+ CONTRACTL_END;
+
+ OBJECTREF val = ObjectToOBJECTREF(vVal);
+
+ HELPER_METHOD_FRAME_BEGIN_1(val);
+ GCPROTECT_BEGININTERIOR(var)
+
+ CVTypes cvt = CV_EMPTY;
+ TypeHandle typeHandle;
+
+ MethodTable *valMT = val->GetMethodTable();
+
+ //If this isn't a value class, we should just skip out because we're not going
+ //to do anything special with it.
+ if (!valMT->IsValueType())
+ {
+ var->SetObjRef(val);
+ typeHandle = TypeHandle(valMT);
+
+ if (typeHandle==GetTypeHandleForCVType(CV_MISSING))
+ {
+ var->SetType(CV_MISSING);
+ }
+ else if (typeHandle==GetTypeHandleForCVType(CV_NULL))
+ {
+ var->SetType(CV_NULL);
+ }
+ else if (typeHandle==GetTypeHandleForCVType(CV_EMPTY))
+ {
+ var->SetType(CV_EMPTY);
+ var->SetObjRef(NULL);
+ }
+ else
+ {
+ var->SetType(CV_OBJECT);
+ }
+ }
+ else if (IsTypeRefOrDef(g_ColorClassName, valMT->GetModule(), valMT->GetCl()))
+ {
+ // System.Drawing.Color is converted to UInt32
+ var->SetDataAsUInt32(ConvertSystemColorToOleColor(&val));
+ var->SetType(CV_U4);
+ }
+ else
+ {
+ //If this is a primitive type, we need to unbox it, get the value and create a variant
+ //with just those values.
+ void *UnboxData = val->UnBox();
+
+ ClearObjectReference(var->GetObjRefPtr());
+ typeHandle = TypeHandle(valMT);
+ CorElementType cet = typeHandle.GetSignatureCorElementType();
+
+ if (cet>=ELEMENT_TYPE_BOOLEAN && cet<=ELEMENT_TYPE_STRING)
+ {
+ cvt = (CVTypes)cet;
+ }
+ else
+ {
+ cvt = GetCVTypeFromClass(valMT);
+ }
+ var->SetType(cvt);
+
+
+ //copy all of the data.
+ // Copies must be done based on the exact number of bytes to copy.
+ // We don't want to read garbage from other blocks of memory.
+ //CV_I8 --> CV_R8, CV_DATETIME, CV_TIMESPAN, & CV_CURRENCY are all of the 8 byte quantities
+ //If we don't find one of those ranges, we've found a value class
+ //of which we don't have inherent knowledge, so just slam that into an
+ //ObjectRef.
+ if (cvt>=CV_BOOLEAN && cvt<=CV_U1 && cvt != CV_CHAR)
+ {
+ var->SetDataAsInt64(*((UINT8 *)UnboxData));
+ }
+ else if (cvt==CV_CHAR || cvt>=CV_I2 && cvt<=CV_U2)
+ {
+ var->SetDataAsInt64(*((UINT16 *)UnboxData));
+ }
+ else if (cvt>=CV_I4 && cvt<=CV_U4 || cvt==CV_R4)
+ {
+ var->SetDataAsInt64(*((UINT32 *)UnboxData));
+ }
+ else if ((cvt>=CV_I8 && cvt<=CV_R8) || (cvt==CV_DATETIME) || (cvt==CV_TIMESPAN) || (cvt==CV_CURRENCY))
+ {
+ var->SetDataAsInt64(*((INT64 *)UnboxData));
+ }
+ else if (cvt==CV_EMPTY || cvt==CV_NULL || cvt==CV_MISSING)
+ {
+ var->SetType(cvt);
+ }
+ else if (cvt==CV_ENUM)
+ {
+ var->SetDataAsInt64(*((INT32 *)UnboxData));
+ var->SetObjRef(typeHandle.GetManagedClassObject());
+ var->SetType(GetEnumFlags(typeHandle));
+ }
+ else
+ {
+ // Decimals and other boxed value classes get handled here.
+ var->SetObjRef(val);
+ }
+ }
+
+ GCPROTECT_END();
+ HELPER_METHOD_FRAME_END();
+}
+FCIMPLEND
+
+
+FCIMPL1(Object*, COMVariant::BoxEnum, VariantData* var)
+{
+ CONTRACTL
+ {
+ FCALL_CHECK;
+ PRECONDITION(CheckPointer(var));
+ PRECONDITION(var->GetObjRef() != NULL);
+ }
+ CONTRACTL_END;
+
+ OBJECTREF retO = NULL;
+
+ HELPER_METHOD_FRAME_BEGIN_RET_1(retO);
+
+#ifdef _DEBUG
+ CVTypes vType = (CVTypes) var->GetType();
+#endif
+
+ _ASSERTE(vType == CV_ENUM);
+
+ MethodTable* mt = ((REFLECTCLASSBASEREF) var->GetObjRef())->GetType().GetMethodTable();
+ _ASSERTE(mt);
+
+ retO = mt->Box(var->GetData());
+
+ HELPER_METHOD_FRAME_END();
+ return OBJECTREFToObject(retO);
+}
+FCIMPLEND
+
+
+/*===============================GetTypeFromClass===============================
+**Action: Takes an MethodTable * and returns the associated CVType.
+**Arguments: MethodTable * -- a pointer to the class for which we want the CVType.
+**Returns: The CVType associated with the MethodTable or CV_OBJECT if this can't be
+** determined.
+**Exceptions: None
+==============================================================================*/
+
+CVTypes COMVariant::GetCVTypeFromClass(TypeHandle th)
+{
+ CONTRACTL
+ {
+ THROWS;
+ GC_TRIGGERS;
+ MODE_ANY;
+ }
+ CONTRACTL_END;
+
+ if (th.IsNull())
+ return CV_EMPTY;
+
+ //We'll start looking from Variant. Empty and Void are handled below.
+ for (int i=CV_EMPTY; i<CV_LAST; i++)
+ {
+ if (th == GetTypeHandleForCVType((CVTypes)i))
+ return (CVTypes)i;
+ }
+
+ if (th.IsEnum())
+ return CV_ENUM;
+
+ return CV_OBJECT;
+}
+
+
+int COMVariant::GetEnumFlags(TypeHandle th)
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ GC_NOTRIGGER;
+ MODE_ANY;
+ PRECONDITION(!th.IsNull());
+ PRECONDITION(th.IsEnum());
+ }
+ CONTRACTL_END;
+
+ // <TODO> check this approximation - we may be losing exact type information </TODO>
+ ApproxFieldDescIterator fdIterator(th.GetMethodTable(), ApproxFieldDescIterator::INSTANCE_FIELDS);
+ FieldDesc* p = fdIterator.Next();
+ if (NULL == p)
+ {
+ _ASSERTE(!"NULL FieldDesc returned");
+ return 0;
+ }
+
+#ifdef _DEBUG
+ WORD fldCnt = th.GetMethodTable()->GetNumInstanceFields();
+#endif
+
+ _ASSERTE(fldCnt == 1);
+
+ CorElementType cet = p[0].GetFieldType();
+ switch (cet)
+ {
+ case ELEMENT_TYPE_I1:
+ return (CV_ENUM | EnumI1);
+
+ case ELEMENT_TYPE_U1:
+ return (CV_ENUM | EnumU1);
+
+ case ELEMENT_TYPE_I2:
+ return (CV_ENUM | EnumI2);
+
+ case ELEMENT_TYPE_U2:
+ return (CV_ENUM | EnumU2);
+
+ IN_TARGET_32BIT(case ELEMENT_TYPE_I:)
+ case ELEMENT_TYPE_I4:
+ return (CV_ENUM | EnumI4);
+
+ IN_TARGET_32BIT(case ELEMENT_TYPE_U:)
+ case ELEMENT_TYPE_U4:
+ return (CV_ENUM | EnumU4);
+
+ IN_TARGET_64BIT(case ELEMENT_TYPE_I:)
+ case ELEMENT_TYPE_I8:
+ return (CV_ENUM | EnumI8);
+
+ IN_TARGET_64BIT(case ELEMENT_TYPE_U:)
+ case ELEMENT_TYPE_U8:
+ return (CV_ENUM | EnumU8);
+
+ default:
+ _ASSERTE(!"UNknown Type");
+ return 0;
+ }
+}
+
+#endif // FEATURE_COMINTEROP
diff --git a/src/coreclr/classlibnative/bcltype/variant.h b/src/coreclr/classlibnative/bcltype/variant.h
new file mode 100644
index 00000000000..aae0a5f9741
--- /dev/null
+++ b/src/coreclr/classlibnative/bcltype/variant.h
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: Variant.h
+//
+
+//
+// Purpose: Headers for the Variant class.
+//
+
+//
+
+#ifndef _VARIANT_H_
+#define _VARIANT_H_
+
+#ifndef FEATURE_COMINTEROP
+#error FEATURE_COMINTEROP is required for this file
+#endif // FEATURE_COMINTEROP
+
+#include <cor.h>
+#include "fcall.h"
+#include "olevariant.h"
+
+class COMVariant
+{
+ friend class OleVariant;
+
+public:
+ //
+ // Helper Routines
+ //
+
+ static FCDECL2(void, SetFieldsObject, VariantData* vThisRef, Object* vVal);
+ static FCDECL1(Object*, BoxEnum, VariantData* var);
+
+private:
+ // GetCVTypeFromClass
+ // This method will return the CVTypes from the Variant instance
+ static CVTypes GetCVTypeFromClass(TypeHandle th);
+ static int GetEnumFlags(TypeHandle th);
+};
+
+#endif // _VARIANT_H_
+
diff --git a/src/coreclr/classlibnative/float/CMakeLists.txt b/src/coreclr/classlibnative/float/CMakeLists.txt
new file mode 100644
index 00000000000..b2c47ea39b6
--- /dev/null
+++ b/src/coreclr/classlibnative/float/CMakeLists.txt
@@ -0,0 +1,18 @@
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+include_directories("../inc")
+
+set(FLOAT_SOURCES
+ floatdouble.cpp
+ floatsingle.cpp
+)
+
+add_library_clr(comfloat_wks_obj
+ OBJECT
+ ${FLOAT_SOURCES}
+)
+
+add_dependencies(comfloat_wks_obj eventing_headers)
+
+add_library(comfloat_wks INTERFACE)
+target_sources(comfloat_wks INTERFACE $<TARGET_OBJECTS:comfloat_wks_obj>) \ No newline at end of file
diff --git a/src/coreclr/classlibnative/float/floatdouble.cpp b/src/coreclr/classlibnative/float/floatdouble.cpp
new file mode 100644
index 00000000000..a2a00b0628b
--- /dev/null
+++ b/src/coreclr/classlibnative/float/floatdouble.cpp
@@ -0,0 +1,331 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: FloatDouble.cpp
+//
+
+#include <common.h>
+
+#include "floatdouble.h"
+
+// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This
+// default compilation mode has previously caused performance regressions in floating-point code.
+// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance
+// and is really unlikely to cause any other code regressions.
+
+// Sin, Cos, and Tan on AMD64 Windows were previously implemented in vm\amd64\JitHelpers_Fast.asm
+// by calling x87 floating point code (fsin, fcos, fptan) because the CRT helpers were too slow. This
+// is no longer the case and the CRT call is used on all platforms.
+
+// Log, Log10 and Exp were previously slower with /fp:fast on SSE2 enabled hardware (see #500373).
+// This is no longer the case and they now consume use the /fp:fast versions.
+
+// Exp(+/-INFINITY) did not previously return the expected results of +0.0 (for -INFINITY)
+// and +INFINITY (for +INFINITY) so these cases were handled specially. As this is no longer
+// the case and the expected results are now returned, the special handling has been removed.
+
+// Previously there was more special handling for the x86 Windows version of Pow.
+// This additional handling was unnecessary and has since been removed.
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// beginning of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+#pragma float_control(push)
+#pragma float_control(precise, off)
+#endif
+
+/*=====================================Abs======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Abs, double x)
+ FCALL_CONTRACT;
+
+ return (double)fabs(x);
+FCIMPLEND
+
+/*=====================================Acos=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Acos, double x)
+ FCALL_CONTRACT;
+
+ return (double)acos(x);
+FCIMPLEND
+
+/*=====================================Acosh====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Acosh, double x)
+ FCALL_CONTRACT;
+
+ return (double)acosh(x);
+FCIMPLEND
+
+/*=====================================Asin=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Asin, double x)
+ FCALL_CONTRACT;
+
+ return (double)asin(x);
+FCIMPLEND
+
+/*=====================================Asinh====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Asinh, double x)
+ FCALL_CONTRACT;
+
+ return (double)asinh(x);
+FCIMPLEND
+
+/*=====================================Atan=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Atan, double x)
+ FCALL_CONTRACT;
+
+ return (double)atan(x);
+FCIMPLEND
+
+/*=====================================Atanh====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Atanh, double x)
+ FCALL_CONTRACT;
+
+ return (double)atanh(x);
+FCIMPLEND
+
+/*=====================================Atan2====================================
+**
+==============================================================================*/
+FCIMPL2_VV(double, COMDouble::Atan2, double y, double x)
+ FCALL_CONTRACT;
+
+ return (double)atan2(y, x);
+FCIMPLEND
+
+/*====================================Cbrt======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Cbrt, double x)
+ FCALL_CONTRACT;
+
+ return (double)cbrt(x);
+FCIMPLEND
+
+#if defined(_MSC_VER) && defined(TARGET_AMD64)
+// The /fp:fast form of `ceil` for AMD64 does not correctly handle: `-1.0 < value <= -0.0`
+// https://github.com/dotnet/runtime/issues/11003
+#pragma float_control(push)
+#pragma float_control(precise, on)
+#endif
+
+/*====================================Ceil======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Ceil, double x)
+ FCALL_CONTRACT;
+
+ return (double)ceil(x);
+FCIMPLEND
+
+#if defined(_MSC_VER) && defined(TARGET_AMD64)
+#pragma float_control(pop)
+#endif
+
+/*=====================================Cos======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Cos, double x)
+ FCALL_CONTRACT;
+
+ return (double)cos(x);
+FCIMPLEND
+
+/*=====================================Cosh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Cosh, double x)
+ FCALL_CONTRACT;
+
+ return (double)cosh(x);
+FCIMPLEND
+
+/*=====================================Exp======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Exp, double x)
+ FCALL_CONTRACT;
+
+ return (double)exp(x);
+FCIMPLEND
+
+#if defined(_MSC_VER) && defined(TARGET_X86)
+// The /fp:fast form of `floor` for x86 does not correctly handle: `-0.0`
+// https://github.com/dotnet/runtime/issues/11003
+#pragma float_control(push)
+#pragma float_control(precise, on)
+#endif
+
+/*====================================Floor=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Floor, double x)
+ FCALL_CONTRACT;
+
+ return (double)floor(x);
+FCIMPLEND
+
+#if defined(_MSC_VER) && defined(TARGET_X86)
+#pragma float_control(pop)
+#endif
+
+/*=====================================FMod=====================================
+**
+==============================================================================*/
+FCIMPL2_VV(double, COMDouble::FMod, double x, double y)
+ FCALL_CONTRACT;
+
+ return (double)fmod(x, y);
+FCIMPLEND
+
+/*=====================================FusedMultiplyAdd==========================
+**
+==============================================================================*/
+FCIMPL3_VVV(double, COMDouble::FusedMultiplyAdd, double x, double y, double z)
+ FCALL_CONTRACT;
+
+ return (double)fma(x, y, z);
+FCIMPLEND
+
+/*=====================================Ilog2====================================
+**
+==============================================================================*/
+FCIMPL1_V(int, COMDouble::ILogB, double x)
+ FCALL_CONTRACT;
+
+ return (int)ilogb(x);
+FCIMPLEND
+
+/*=====================================Log======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Log, double x)
+ FCALL_CONTRACT;
+
+ return (double)log(x);
+FCIMPLEND
+
+/*=====================================Log2=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Log2, double x)
+ FCALL_CONTRACT;
+
+ return (double)log2(x);
+FCIMPLEND
+
+/*====================================Log10=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Log10, double x)
+ FCALL_CONTRACT;
+
+ return (double)log10(x);
+FCIMPLEND
+
+/*=====================================ModF=====================================
+**
+==============================================================================*/
+FCIMPL2_VI(double, COMDouble::ModF, double x, double* intptr)
+ FCALL_CONTRACT;
+
+ return (double)modf(x, intptr);
+FCIMPLEND
+
+/*=====================================Pow======================================
+**
+==============================================================================*/
+FCIMPL2_VV(double, COMDouble::Pow, double x, double y)
+ FCALL_CONTRACT;
+
+ return (double)pow(x, y);
+FCIMPLEND
+
+/*=====================================ScaleB===================================
+**
+==============================================================================*/
+FCIMPL2_VI(double, COMDouble::ScaleB, double x, int n)
+ FCALL_CONTRACT;
+
+ return (double)scalbn(x, n);
+FCIMPLEND
+
+/*=====================================Sin======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Sin, double x)
+ FCALL_CONTRACT;
+
+ return (double)sin(x);
+FCIMPLEND
+
+/*=====================================Sinh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Sinh, double x)
+ FCALL_CONTRACT;
+
+ return (double)sinh(x);
+FCIMPLEND
+
+/*=====================================Sqrt=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Sqrt, double x)
+ FCALL_CONTRACT;
+
+ return (double)sqrt(x);
+FCIMPLEND
+
+/*=====================================Tan======================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Tan, double x)
+ FCALL_CONTRACT;
+
+ return (double)tan(x);
+FCIMPLEND
+
+/*=====================================Tanh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(double, COMDouble::Tanh, double x)
+ FCALL_CONTRACT;
+
+ return (double)tanh(x);
+FCIMPLEND
+
+#ifdef _MSC_VER
+#pragma float_control(pop)
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// End of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/classlibnative/float/floatsingle.cpp b/src/coreclr/classlibnative/float/floatsingle.cpp
new file mode 100644
index 00000000000..9972e17c690
--- /dev/null
+++ b/src/coreclr/classlibnative/float/floatsingle.cpp
@@ -0,0 +1,318 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+//
+// File: FloatSingle.cpp
+//
+
+#include <common.h>
+
+#include "floatsingle.h"
+
+// Windows x86 and Windows ARM/ARM64 may not define _isnanf() or _copysignf() but they do
+// define _isnan() and _copysign(). We will redirect the macros to these other functions if
+// the macro is not defined for the platform. This has the side effect of a possible implicit
+// upcasting for arguments passed in and an explicit downcasting for the _copysign() call.
+#if (defined(TARGET_X86) || defined(TARGET_ARM) || defined(TARGET_ARM64)) && !defined(TARGET_UNIX)
+
+#if !defined(_copysignf)
+#define _copysignf (float)_copysign
+#endif
+
+#endif
+
+// The default compilation mode is /fp:precise, which disables floating-point intrinsics. This
+// default compilation mode has previously caused performance regressions in floating-point code.
+// We enable /fp:fast semantics for the majority of the math functions, as it will speed up performance
+// and is really unlikely to cause any other code regressions.
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// beginning of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+
+#ifdef _MSC_VER
+#pragma float_control(push)
+#pragma float_control(precise, off)
+#endif
+
+/*=====================================Abs=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Abs, float x)
+ FCALL_CONTRACT;
+
+ return (float)fabsf(x);
+FCIMPLEND
+
+/*=====================================Acos=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Acos, float x)
+ FCALL_CONTRACT;
+
+ return (float)acosf(x);
+FCIMPLEND
+
+/*=====================================Acosh====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Acosh, float x)
+ FCALL_CONTRACT;
+
+ return (float)acoshf(x);
+FCIMPLEND
+
+/*=====================================Asin=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Asin, float x)
+ FCALL_CONTRACT;
+
+ return (float)asinf(x);
+FCIMPLEND
+
+/*=====================================Asinh====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Asinh, float x)
+ FCALL_CONTRACT;
+
+ return (float)asinhf(x);
+FCIMPLEND
+
+/*=====================================Atan=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Atan, float x)
+ FCALL_CONTRACT;
+
+ return (float)atanf(x);
+FCIMPLEND
+
+/*=====================================Atanh====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Atanh, float x)
+ FCALL_CONTRACT;
+
+ return (float)atanhf(x);
+FCIMPLEND
+
+/*=====================================Atan2====================================
+**
+==============================================================================*/
+FCIMPL2_VV(float, COMSingle::Atan2, float y, float x)
+ FCALL_CONTRACT;
+
+ return (float)atan2f(y, x);
+FCIMPLEND
+
+/*====================================Cbrt======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Cbrt, float x)
+ FCALL_CONTRACT;
+
+ return (float)cbrtf(x);
+FCIMPLEND
+
+#if defined(_MSC_VER) && defined(TARGET_AMD64)
+// The /fp:fast form of `ceilf` for AMD64 does not correctly handle: `-1.0 < value <= -0.0`
+// https://github.com/dotnet/runtime/issues/11003
+#pragma float_control(push)
+#pragma float_control(precise, on)
+#endif
+
+/*====================================Ceil======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Ceil, float x)
+ FCALL_CONTRACT;
+
+ return (float)ceilf(x);
+FCIMPLEND
+
+#if defined(_MSC_VER) && defined(TARGET_AMD64)
+#pragma float_control(pop)
+#endif
+
+/*=====================================Cos======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Cos, float x)
+ FCALL_CONTRACT;
+
+ return (float)cosf(x);
+FCIMPLEND
+
+/*=====================================Cosh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Cosh, float x)
+ FCALL_CONTRACT;
+
+ return (float)coshf(x);
+FCIMPLEND
+
+/*=====================================Exp======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Exp, float x)
+ FCALL_CONTRACT;
+
+ return (float)expf(x);
+FCIMPLEND
+
+/*====================================Floor=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Floor, float x)
+ FCALL_CONTRACT;
+
+ return (float)floorf(x);
+FCIMPLEND
+
+/*=====================================FMod=====================================
+**
+==============================================================================*/
+FCIMPL2_VV(float, COMSingle::FMod, float x, float y)
+ FCALL_CONTRACT;
+
+ return (float)fmodf(x, y);
+FCIMPLEND
+
+/*=====================================FusedMultiplyAdd==========================
+**
+==============================================================================*/
+FCIMPL3_VVV(float, COMSingle::FusedMultiplyAdd, float x, float y, float z)
+ FCALL_CONTRACT;
+
+ return (float)fmaf(x, y, z);
+FCIMPLEND
+
+/*=====================================Ilog2====================================
+**
+==============================================================================*/
+FCIMPL1_V(int, COMSingle::ILogB, float x)
+ FCALL_CONTRACT;
+
+ return (int)ilogbf(x);
+FCIMPLEND
+
+/*=====================================Log======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Log, float x)
+ FCALL_CONTRACT;
+
+ return (float)logf(x);
+FCIMPLEND
+
+/*=====================================Log2=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Log2, float x)
+ FCALL_CONTRACT;
+
+ return (float)log2f(x);
+FCIMPLEND
+
+/*====================================Log10=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Log10, float x)
+ FCALL_CONTRACT;
+
+ return (float)log10f(x);
+FCIMPLEND
+
+/*=====================================ModF=====================================
+**
+==============================================================================*/
+FCIMPL2_VI(float, COMSingle::ModF, float x, float* intptr)
+ FCALL_CONTRACT;
+
+ return (float)modff(x, intptr);
+FCIMPLEND
+
+/*=====================================Pow======================================
+**
+==============================================================================*/
+FCIMPL2_VV(float, COMSingle::Pow, float x, float y)
+ FCALL_CONTRACT;
+
+ return (float)powf(x, y);
+FCIMPLEND
+
+/*=====================================ScaleB===================================
+**
+==============================================================================*/
+FCIMPL2_VI(float, COMSingle::ScaleB, float x, int n)
+ FCALL_CONTRACT;
+
+ return (float)scalbnf(x, n);
+FCIMPLEND
+
+/*=====================================Sin======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Sin, float x)
+ FCALL_CONTRACT;
+
+ return (float)sinf(x);
+FCIMPLEND
+
+/*=====================================Sinh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Sinh, float x)
+ FCALL_CONTRACT;
+
+ return (float)sinhf(x);
+FCIMPLEND
+
+/*=====================================Sqrt=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Sqrt, float x)
+ FCALL_CONTRACT;
+
+ return (float)sqrtf(x);
+FCIMPLEND
+
+/*=====================================Tan======================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Tan, float x)
+ FCALL_CONTRACT;
+
+ return (float)tanf(x);
+FCIMPLEND
+
+/*=====================================Tanh=====================================
+**
+==============================================================================*/
+FCIMPL1_V(float, COMSingle::Tanh, float x)
+ FCALL_CONTRACT;
+
+ return (float)tanhf(x);
+FCIMPLEND
+
+#ifdef _MSC_VER
+#pragma float_control(pop)
+#endif
+
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+///
+/// End of /fp:fast scope
+///
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/coreclr/classlibnative/inc/floatdouble.h b/src/coreclr/classlibnative/inc/floatdouble.h
new file mode 100644
index 00000000000..eb430409b6f
--- /dev/null
+++ b/src/coreclr/classlibnative/inc/floatdouble.h
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef _FLOATDOUBLE_H_
+#define _FLOATDOUBLE_H_
+
+#include <object.h>
+#include <fcall.h>
+
+class COMDouble {
+public:
+ FCDECL1_V(static double, Abs, double x);
+ FCDECL1_V(static double, Acos, double x);
+ FCDECL1_V(static double, Acosh, double x);
+ FCDECL1_V(static double, Asin, double x);
+ FCDECL1_V(static double, Asinh, double x);
+ FCDECL1_V(static double, Atan, double x);
+ FCDECL1_V(static double, Atanh, double x);
+ FCDECL2_VV(static double, Atan2, double y, double x);
+ FCDECL1_V(static double, Cbrt, double x);
+ FCDECL1_V(static double, Ceil, double x);
+ FCDECL1_V(static double, Cos, double x);
+ FCDECL1_V(static double, Cosh, double x);
+ FCDECL1_V(static double, Exp, double x);
+ FCDECL1_V(static double, Floor, double x);
+ FCDECL2_VV(static double, FMod, double x, double y);
+ FCDECL3_VVV(static double, FusedMultiplyAdd, double x, double y, double z);
+ FCDECL1_V(static int, ILogB, double x);
+ FCDECL1_V(static double, Log, double x);
+ FCDECL1_V(static double, Log2, double x);
+ FCDECL1_V(static double, Log10, double x);
+ FCDECL2_VI(static double, ModF, double x, double* intptr);
+ FCDECL2_VV(static double, Pow, double x, double y);
+ FCDECL2_VI(static double, ScaleB, double x, int n);
+ FCDECL1_V(static double, Sin, double x);
+ FCDECL1_V(static double, Sinh, double x);
+ FCDECL1_V(static double, Sqrt, double x);
+ FCDECL1_V(static double, Tan, double x);
+ FCDECL1_V(static double, Tanh, double x);
+};
+
+#endif // _FLOATDOUBLE_H_
diff --git a/src/coreclr/classlibnative/inc/floatsingle.h b/src/coreclr/classlibnative/inc/floatsingle.h
new file mode 100644
index 00000000000..2658cb08edd
--- /dev/null
+++ b/src/coreclr/classlibnative/inc/floatsingle.h
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+#ifndef _FLOATSINGLE_H_
+#define _FLOATSINGLE_H_
+
+#include <object.h>
+#include <fcall.h>
+
+class COMSingle {
+public:
+ FCDECL1_V(static float, Abs, float x);
+ FCDECL1_V(static float, Acos, float x);
+ FCDECL1_V(static float, Acosh, float x);
+ FCDECL1_V(static float, Asin, float x);
+ FCDECL1_V(static float, Asinh, float x);
+ FCDECL1_V(static float, Atan, float x);
+ FCDECL1_V(static float, Atanh, float x);
+ FCDECL2_VV(static float, Atan2, float y, float x);
+ FCDECL1_V(static float, Cbrt, float x);
+ FCDECL1_V(static float, Ceil, float x);
+ FCDECL1_V(static float, Cos, float x);
+ FCDECL1_V(static float, Cosh, float x);
+ FCDECL1_V(static float, Exp, float x);
+ FCDECL1_V(static float, Floor, float x);
+ FCDECL2_VV(static float, FMod, float x, float y);
+ FCDECL3_VVV(static float, FusedMultiplyAdd, float x, float y, float z);
+ FCDECL1_V(static int, ILogB, float x);
+ FCDECL1_V(static float, Log, float x);
+ FCDECL1_V(static float, Log2, float x);
+ FCDECL1_V(static float, Log10, float x);
+ FCDECL2_VI(static float, ModF, float x, float* intptr);
+ FCDECL2_VV(static float, Pow, float x, float y);
+ FCDECL2_VI(static float, ScaleB, float x, int n);
+ FCDECL1_V(static float, Sin, float x);
+ FCDECL1_V(static float, Sinh, float x);
+ FCDECL1_V(static float, Sqrt, float x);
+ FCDECL1_V(static float, Tan, float x);
+ FCDECL1_V(static float, Tanh, float x);
+};
+
+#endif // _FLOATSINGLE_H_
diff --git a/src/coreclr/classlibnative/inc/nls.h b/src/coreclr/classlibnative/inc/nls.h
new file mode 100644
index 00000000000..b453aa843fc
--- /dev/null
+++ b/src/coreclr/classlibnative/inc/nls.h
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+////////////////////////////////////////////////////////////////////////////
+//
+// Module: NLS
+//
+
+//
+// Purpose: This module defines the common header information for
+// the Globalization classes.
+//
+// Date: August 12, 1998
+//
+////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef _NLS_H_
+#define _NLS_H_
+
+
+//
+// Constant Declarations.
+//
+
+#define HIGH_SURROGATE_START 0xd800
+#define HIGH_SURROGATE_END 0xdbff
+#define LOW_SURROGATE_START 0xdc00
+#define LOW_SURROGATE_END 0xdfff
+
+#define PRIVATE_USE_BEGIN 0xe000
+#define PRIVATE_USE_END 0xf8ff
+
+#endif // _NLS_H_