summaryrefslogtreecommitdiff
path: root/packaging/0012-Replace-array-type-handle-with-method-table-in-argum.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packaging/0012-Replace-array-type-handle-with-method-table-in-argum.patch')
-rw-r--r--packaging/0012-Replace-array-type-handle-with-method-table-in-argum.patch1214
1 files changed, 1214 insertions, 0 deletions
diff --git a/packaging/0012-Replace-array-type-handle-with-method-table-in-argum.patch b/packaging/0012-Replace-array-type-handle-with-method-table-in-argum.patch
new file mode 100644
index 0000000000..348709c38e
--- /dev/null
+++ b/packaging/0012-Replace-array-type-handle-with-method-table-in-argum.patch
@@ -0,0 +1,1214 @@
+From a0dc56413e9e5c61c0f6617e1ef091966b2f7a1d Mon Sep 17 00:00:00 2001
+From: Ruben Ayrapetyan <ruben-ayrapetyan@users.noreply.github.com>
+Date: Tue, 27 Jun 2017 00:18:19 +0300
+Subject: [PATCH 12/32] Replace array type handle with method table in
+ arguments of array allocation helpers (#12369)
+
+* Remove direct usage of type handle in JIT_NewArr1, with except of retrieving template method table.
+
+* Assert that array type descriptor is loaded when array object's method table is set.
+
+* Pass template method tables instead of array type descriptors to array allocation helpers.
+---
+ src/vm/amd64/JitHelpers_InlineGetThread.asm | 39 ++++------------
+ src/vm/amd64/JitHelpers_Slow.asm | 69 ++++++++---------------------
+ src/vm/amd64/asmconstants.h | 4 --
+ src/vm/arm/asmconstants.h | 3 --
+ src/vm/arm/patchedcode.asm | 42 ++++--------------
+ src/vm/arm/stubs.cpp | 4 +-
+ src/vm/compile.cpp | 8 ++++
+ src/vm/gchelpers.cpp | 50 ++++++++++++++-------
+ src/vm/gchelpers.h | 8 ++--
+ src/vm/i386/jitinterfacex86.cpp | 24 +++-------
+ src/vm/interpreter.cpp | 7 ++-
+ src/vm/jithelpers.cpp | 52 +++++++++++-----------
+ src/vm/jitinterface.cpp | 12 ++++-
+ src/vm/jitinterface.h | 10 ++---
+ src/vm/jitinterfacegen.cpp | 12 ++---
+ src/vm/methodtable.cpp | 13 ++++++
+ src/vm/object.cpp | 18 ++++++++
+ src/vm/object.h | 50 ++++++++++++++++++---
+ src/vm/object.inl | 27 +++++++++++
+ src/vm/prestub.cpp | 4 +-
+ 20 files changed, 245 insertions(+), 211 deletions(-)
+
+diff --git a/src/vm/amd64/JitHelpers_InlineGetThread.asm b/src/vm/amd64/JitHelpers_InlineGetThread.asm
+index 700c3b3..022ec67 100644
+--- a/src/vm/amd64/JitHelpers_InlineGetThread.asm
++++ b/src/vm/amd64/JitHelpers_InlineGetThread.asm
+@@ -147,15 +147,6 @@ align 16
+ jmp JIT_Box
+ NESTED_END JIT_BoxFastMP_InlineGetThread, _TEXT
+
+-FIX_INDIRECTION macro Reg
+-ifdef FEATURE_PREJIT
+- test Reg, 1
+- jz @F
+- mov Reg, [Reg-1]
+- @@:
+-endif
+-endm
+-
+ LEAF_ENTRY AllocateStringFastMP_InlineGetThread, _TEXT
+ ; We were passed the number of characters in ECX
+
+@@ -203,10 +194,9 @@ endif ; _DEBUG
+ jmp FramedAllocateString
+ LEAF_END AllocateStringFastMP_InlineGetThread, _TEXT
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1VC_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread, _TEXT
+- ; We were passed a type descriptor in RCX, which contains the (shared)
+- ; array method table and the element type.
++ ; We were passed a (shared) method table in RCX, which contains the element type.
+
+ ; The element count is in RDX
+
+@@ -223,17 +213,12 @@ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread, _TEXT
+
+ ; In both cases we do a final overflow check after adding to the alloc_ptr.
+
+- ; we need to load the true method table from the type desc
+- mov r9, [rcx + OFFSETOF__ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r9
+-
+ cmp rdx, (65535 - 256)
+ jae OversizedArray
+
+- movzx r8d, word ptr [r9 + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
++ movzx r8d, word ptr [rcx + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
+ imul r8d, edx
+- add r8d, dword ptr [r9 + OFFSET__MethodTable__m_BaseSize]
++ add r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
+
+ ; round the size to a multiple of 8
+
+@@ -252,7 +237,7 @@ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread, _TEXT
+ ja AllocFailed
+
+ mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
+- mov [rax], r9
++ mov [rax], rcx
+
+ mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
+
+@@ -268,10 +253,9 @@ endif ; _DEBUG
+ LEAF_END JIT_NewArr1VC_MP_InlineGetThread, _TEXT
+
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread, _TEXT
+- ; We were passed a type descriptor in RCX, which contains the (shared)
+- ; array method table and the element type.
++ ; We were passed a (shared) method table in RCX, which contains the element type.
+
+ ; The element count is in RDX
+
+@@ -285,16 +269,11 @@ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread, _TEXT
+ cmp rdx, (ASM_LARGE_OBJECT_SIZE - 256)/8 ; sizeof(void*)
+ jae OversizedArray
+
+- ; we need to load the true method table from the type desc
+- mov r9, [rcx + OFFSETOF__ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r9
+-
+ ; In this case we know the element size is sizeof(void *), or 8 for x64
+ ; This helps us in two ways - we can shift instead of multiplying, and
+ ; there's no need to align the size either
+
+- mov r8d, dword ptr [r9 + OFFSET__MethodTable__m_BaseSize]
++ mov r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
+ lea r8d, [r8d + edx * 8]
+
+ ; No need for rounding in this case - element size is 8, and m_BaseSize is guaranteed
+@@ -310,7 +289,7 @@ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread, _TEXT
+ ja AllocFailed
+
+ mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
+- mov [rax], r9
++ mov [rax], rcx
+
+ mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
+
+diff --git a/src/vm/amd64/JitHelpers_Slow.asm b/src/vm/amd64/JitHelpers_Slow.asm
+index 293e447..448bcb2 100644
+--- a/src/vm/amd64/JitHelpers_Slow.asm
++++ b/src/vm/amd64/JitHelpers_Slow.asm
+@@ -321,22 +321,12 @@ endif ; _DEBUG
+ jmp FramedAllocateString
+ NESTED_END AllocateStringFastMP, _TEXT
+
+-FIX_INDIRECTION macro Reg
+-ifdef FEATURE_PREJIT
+- test Reg, 1
+- jz @F
+- mov Reg, [Reg-1]
+- @@:
+-endif
+-endm
+-
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1VC_MP, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ NESTED_ENTRY JIT_NewArr1VC_MP, _TEXT
+ alloc_stack MIN_SIZE
+ END_PROLOGUE
+
+- ; We were passed a type descriptor in RCX, which contains the (shared)
+- ; array method table and the element type.
++ ; We were passed a (shared) method table in RCX, which contains the element type.
+
+ ; The element count is in RDX
+
+@@ -356,17 +346,12 @@ NESTED_ENTRY JIT_NewArr1VC_MP, _TEXT
+ CALL_GETTHREAD
+ mov r11, rax
+
+- ; we need to load the true method table from the type desc
+- mov r9, [rcx + OFFSETOF__ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r9
+-
+ cmp rdx, (65535 - 256)
+ jae OversizedArray
+
+- movzx r8d, word ptr [r9 + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
++ movzx r8d, word ptr [rcx + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
+ imul r8d, edx ; signed mul, but won't overflow due to length restriction above
+- add r8d, dword ptr [r9 + OFFSET__MethodTable__m_BaseSize]
++ add r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
+
+ ; round the size to a multiple of 8
+
+@@ -383,7 +368,7 @@ NESTED_ENTRY JIT_NewArr1VC_MP, _TEXT
+ ja AllocFailed
+
+ mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
+- mov [rax], r9
++ mov [rax], rcx
+
+ mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
+
+@@ -401,13 +386,12 @@ endif ; _DEBUG
+ NESTED_END JIT_NewArr1VC_MP, _TEXT
+
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1OBJ_MP, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ NESTED_ENTRY JIT_NewArr1OBJ_MP, _TEXT
+ alloc_stack MIN_SIZE
+ END_PROLOGUE
+
+- ; We were passed a type descriptor in RCX, which contains the (shared)
+- ; array method table and the element type.
++ ; We were passed a (shared) method table in RCX, which contains the element type.
+
+ ; The element count is in RDX
+
+@@ -424,16 +408,11 @@ NESTED_ENTRY JIT_NewArr1OBJ_MP, _TEXT
+ CALL_GETTHREAD
+ mov r11, rax
+
+- ; we need to load the true method table from the type desc
+- mov r9, [rcx + OFFSETOF__ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r9
+-
+ ; In this case we know the element size is sizeof(void *), or 8 for x64
+ ; This helps us in two ways - we can shift instead of multiplying, and
+ ; there's no need to align the size either
+
+- mov r8d, dword ptr [r9 + OFFSET__MethodTable__m_BaseSize]
++ mov r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
+ lea r8d, [r8d + edx * 8]
+
+ ; No need for rounding in this case - element size is 8, and m_BaseSize is guaranteed
+@@ -448,7 +427,7 @@ NESTED_ENTRY JIT_NewArr1OBJ_MP, _TEXT
+ ja AllocFailed
+
+ mov [r11 + OFFSET__Thread__m_alloc_context__alloc_ptr], r8
+- mov [rax], r9
++ mov [rax], rcx
+
+ mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
+
+@@ -626,11 +605,10 @@ endif ; _DEBUG
+ jmp FramedAllocateString
+ LEAF_END AllocateStringFastUP, _TEXT
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1VC_UP, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT
+
+- ; We were passed a type descriptor in RCX, which contains the (shared)
+- ; array method table and the element type.
++ ; We were passed a (shared) method table in RCX, which contains the element type.
+
+ ; The element count is in RDX
+
+@@ -647,17 +625,12 @@ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT
+
+ ; In both cases we do a final overflow check after adding to the alloc_ptr.
+
+- ; we need to load the true method table from the type desc
+- mov r9, [rcx + OFFSETOF__ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r9
+-
+ cmp rdx, (65535 - 256)
+ jae JIT_NewArr1
+
+- movzx r8d, word ptr [r9 + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
++ movzx r8d, word ptr [rcx + OFFSETOF__MethodTable__m_dwFlags] ; component size is low 16 bits
+ imul r8d, edx ; signed mul, but won't overflow due to length restriction above
+- add r8d, dword ptr [r9 + OFFSET__MethodTable__m_BaseSize]
++ add r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
+
+ ; round the size to a multiple of 8
+
+@@ -677,7 +650,7 @@ LEAF_ENTRY JIT_NewArr1VC_UP, _TEXT
+ ja AllocFailed
+
+ mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
+- mov [rax], r9
++ mov [rax], rcx
+ mov [g_global_alloc_lock], -1
+
+ mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
+@@ -694,11 +667,10 @@ endif ; _DEBUG
+ LEAF_END JIT_NewArr1VC_UP, _TEXT
+
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1OBJ_UP, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ LEAF_ENTRY JIT_NewArr1OBJ_UP, _TEXT
+
+- ; We were passed a type descriptor in RCX, which contains the (shared)
+- ; array method table and the element type.
++ ; We were passed a (shared) method table in RCX, which contains the element type.
+
+ ; The element count is in RDX
+
+@@ -712,16 +684,11 @@ LEAF_ENTRY JIT_NewArr1OBJ_UP, _TEXT
+ cmp rdx, (ASM_LARGE_OBJECT_SIZE - 256)/8 ; sizeof(void*)
+ jae OversizedArray
+
+- ; we need to load the true method table from the type desc
+- mov r9, [rcx + OFFSETOF__ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r9
+-
+ ; In this case we know the element size is sizeof(void *), or 8 for x64
+ ; This helps us in two ways - we can shift instead of multiplying, and
+ ; there's no need to align the size either
+
+- mov r8d, dword ptr [r9 + OFFSET__MethodTable__m_BaseSize]
++ mov r8d, dword ptr [rcx + OFFSET__MethodTable__m_BaseSize]
+ lea r8d, [r8d + edx * 8]
+
+ ; No need for rounding in this case - element size is 8, and m_BaseSize is guaranteed
+@@ -739,7 +706,7 @@ LEAF_ENTRY JIT_NewArr1OBJ_UP, _TEXT
+ ja AllocFailed
+
+ mov qword ptr [g_global_alloc_context + OFFSETOF__gc_alloc_context__alloc_ptr], r8 ; update the alloc ptr
+- mov [rax], r9
++ mov [rax], rcx
+ mov [g_global_alloc_lock], -1
+
+ mov dword ptr [rax + OFFSETOF__ArrayBase__m_NumComponents], edx
+diff --git a/src/vm/amd64/asmconstants.h b/src/vm/amd64/asmconstants.h
+index e4f77de..4a100c1 100644
+--- a/src/vm/amd64/asmconstants.h
++++ b/src/vm/amd64/asmconstants.h
+@@ -609,10 +609,6 @@ ASMCONSTANTS_C_ASSERT(OFFSETOF__ArrayBase__m_NumComponents
+ ASMCONSTANTS_C_ASSERT(OFFSETOF__StringObject__m_StringLength
+ == offsetof(StringObject, m_StringLength));
+
+-#define OFFSETOF__ArrayTypeDesc__m_TemplateMT 8
+-ASMCONSTANTS_C_ASSERT(OFFSETOF__ArrayTypeDesc__m_TemplateMT
+- == offsetof(ArrayTypeDesc, m_TemplateMT));
+-
+ #define OFFSETOF__ArrayTypeDesc__m_Arg 0x10
+ ASMCONSTANTS_C_ASSERT(OFFSETOF__ArrayTypeDesc__m_Arg
+ == offsetof(ArrayTypeDesc, m_Arg));
+diff --git a/src/vm/arm/asmconstants.h b/src/vm/arm/asmconstants.h
+index 41597b2..704fa28 100644
+--- a/src/vm/arm/asmconstants.h
++++ b/src/vm/arm/asmconstants.h
+@@ -110,9 +110,6 @@ ASMCONSTANTS_C_ASSERT(SIZEOF__ArrayOfValueType == ObjSizeOf(ArrayBase));
+ #define ArrayBase__m_NumComponents 0x4
+ ASMCONSTANTS_C_ASSERT(ArrayBase__m_NumComponents == offsetof(ArrayBase, m_NumComponents));
+
+-#define ArrayTypeDesc__m_TemplateMT 0x4
+-ASMCONSTANTS_C_ASSERT(ArrayTypeDesc__m_TemplateMT == offsetof(ArrayTypeDesc, m_TemplateMT));
+-
+ #define ArrayTypeDesc__m_Arg 0x8
+ ASMCONSTANTS_C_ASSERT(ArrayTypeDesc__m_Arg == offsetof(ArrayTypeDesc, m_Arg));
+
+diff --git a/src/vm/arm/patchedcode.asm b/src/vm/arm/patchedcode.asm
+index 2ef175e..9fdd609 100644
+--- a/src/vm/arm/patchedcode.asm
++++ b/src/vm/arm/patchedcode.asm
+@@ -63,17 +63,6 @@ $label
+ TEXTAREA
+
+
+- MACRO
+- FIX_INDIRECTION $Reg, $label
+-#ifdef FEATURE_PREJIT
+- tst $Reg, #1
+- beq $label
+- ldr $Reg, [$Reg, #-1]
+-$label
+-#endif
+- MEND
+-
+-
+ ; ------------------------------------------------------------------
+ ; Start of the writeable code region
+ LEAF_ENTRY JIT_PatchedCodeStart
+@@ -336,11 +325,11 @@ AllocFailed3
+ LEAF_END
+
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1VC_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ ;---------------------------------------------------------------------------
+-; IN: r0: type descriptor which contains the (shared) array method table and the element type.
++; IN: r0: a (shared) array method table, which contains the element type.
+ ; IN: r1: number of array elements
+-;; OUT: r0: address of newly allocated string
++;; OUT: r0: address of newly allocated object
+
+ LEAF_ENTRY JIT_NewArr1VC_MP_InlineGetThread
+
+@@ -358,13 +347,8 @@ AllocFailed3
+ cmp r1, #MAX_FAST_ALLOCATE_ARRAY_VC_SIZE
+ bhs OverSizedArray3
+
+- ;load MethodTable from ArrayTypeDesc
+- ldr r3, [r0, #ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r3, label1
+-
+ ;get element size - stored in low 16bits of m_dwFlags
+- ldrh r12, [r3, #MethodTable__m_dwFlags]
++ ldrh r12, [r0, #MethodTable__m_dwFlags]
+
+ ; getting size of object to allocate
+
+@@ -398,11 +382,7 @@ AllocFailed3
+ str r1, [r2, #ArrayBase__m_NumComponents]
+
+ ;store methodtable
+- ldr r3, [r0, #ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r3, label2
+-
+- str r3, [r2]
++ str r0, [r2]
+
+ ;copy return value
+ mov r0, r2
+@@ -426,11 +406,11 @@ OverSizedArray3
+
+
+
+-; HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++; HCIMPL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ ;---------------------------------------------------------------------------
+-; IN: r0: type descriptor which contains the (shared) array method table and the element type.
++; IN: r0: a (shared) array method table, which contains the element type.
+ ; IN: r1: number of array elements
+-;; OUT: r0: address of newly allocated string
++;; OUT: r0: address of newly allocated object
+
+ LEAF_ENTRY JIT_NewArr1OBJ_MP_InlineGetThread
+
+@@ -466,11 +446,7 @@ OverSizedArray3
+ str r1, [r2, #ArrayBase__m_NumComponents]
+
+ ;store methodtable
+- ldr r3, [r0, #ArrayTypeDesc__m_TemplateMT - 2]
+-
+- FIX_INDIRECTION r3, label3
+-
+- str r3, [r2]
++ str r0, [r2]
+
+ ;copy return value
+ mov r0, r2
+diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp
+index c832911..70cc900 100644
+--- a/src/vm/arm/stubs.cpp
++++ b/src/vm/arm/stubs.cpp
+@@ -2567,9 +2567,9 @@ static const LPVOID InlineGetThreadLocations[] = {
+
+ //EXTERN_C Object* JIT_TrialAllocSFastMP(CORINFO_CLASS_HANDLE typeHnd_);
+ Object* JIT_TrialAllocSFastMP(CORINFO_CLASS_HANDLE typeHnd_);
+-EXTERN_C Object* JIT_NewArr1OBJ_MP(CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1OBJ_MP(CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+ EXTERN_C Object* AllocateStringFastMP(CLR_I4 cch);
+-EXTERN_C Object* JIT_NewArr1VC_MP(CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1VC_MP(CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+ EXTERN_C Object* JIT_BoxFastMP(CORINFO_CLASS_HANDLE type, void* unboxedData);
+
+
+diff --git a/src/vm/compile.cpp b/src/vm/compile.cpp
+index 9727430..22b8203 100644
+--- a/src/vm/compile.cpp
++++ b/src/vm/compile.cpp
+@@ -1857,6 +1857,14 @@ void EncodeTypeInDictionarySignature(
+
+ return;
+ }
++ else if((CorElementTypeZapSig)typ == ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG)
++ {
++ pSigBuilder->AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
++
++ IfFailThrow(ptr.GetElemType(&typ));
++
++ _ASSERTE(typ == ELEMENT_TYPE_SZARRAY || typ == ELEMENT_TYPE_ARRAY);
++ }
+
+ pSigBuilder->AppendElementType(typ);
+
+diff --git a/src/vm/gchelpers.cpp b/src/vm/gchelpers.cpp
+index 9669f98..046f06e 100644
+--- a/src/vm/gchelpers.cpp
++++ b/src/vm/gchelpers.cpp
+@@ -439,11 +439,31 @@ void ThrowOutOfMemoryDimensionsExceeded()
+ //
+ // Handles arrays of arbitrary dimensions
+ //
++// This is wrapper overload to handle TypeHandle arrayType
++//
++OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap
++ DEBUG_ARG(BOOL bDontSetAppDomain))
++{
++ CONTRACTL
++ {
++ WRAPPER_NO_CONTRACT;
++ } CONTRACTL_END;
++
++ ArrayTypeDesc* arrayDesc = arrayType.AsArray();
++ MethodTable* pArrayMT = arrayDesc->GetMethodTable();
++
++ return AllocateArrayEx(pArrayMT, pArgs, dwNumArgs, bAllocateInLargeHeap
++ DEBUG_ARG(bDontSetAppDomain));
++}
++
++//
++// Handles arrays of arbitrary dimensions
++//
+ // If dwNumArgs is set to greater than 1 for a SZARRAY this function will recursively
+ // allocate sub-arrays and fill them in.
+ //
+ // For arrays with lower bounds, pBounds is <lower bound 1>, <count 1>, <lower bound 2>, ...
+-OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap
++OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap
+ DEBUG_ARG(BOOL bDontSetAppDomain))
+ {
+ CONTRACTL {
+@@ -464,14 +484,12 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+ }
+ #endif
+
+- ArrayTypeDesc* arrayDesc = arrayType.AsArray();
+- MethodTable* pArrayMT = arrayDesc->GetMethodTable();
+- _ASSERTE(pArrayMT->CheckInstanceActivated());
++ _ASSERTE(pArrayMT->CheckInstanceActivated());
+ PREFIX_ASSUME(pArrayMT != NULL);
+- CorElementType kind = arrayType.GetInternalCorElementType();
++ CorElementType kind = pArrayMT->GetInternalCorElementType();
+ _ASSERTE(kind == ELEMENT_TYPE_ARRAY || kind == ELEMENT_TYPE_SZARRAY);
+
+- CorElementType elemType = arrayDesc->GetTypeParam().GetInternalCorElementType();
++ CorElementType elemType = pArrayMT->GetArrayElementType();
+ // Disallow the creation of void[,] (a multi-dim array of System.Void)
+ if (elemType == ELEMENT_TYPE_VOID)
+ COMPlusThrow(kArgumentException);
+@@ -481,7 +499,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+
+ // IBC Log MethodTable access
+ g_IBCLogger.LogMethodTableAccess(pArrayMT);
+- SetTypeHandleOnThreadForAlloc(arrayType);
++ SetTypeHandleOnThreadForAlloc(TypeHandle(pArrayMT));
+
+ SIZE_T componentSize = pArrayMT->GetComponentSize();
+ bool maxArrayDimensionLengthOverflow = false;
+@@ -489,7 +507,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+
+ if (kind == ELEMENT_TYPE_ARRAY)
+ {
+- unsigned rank = arrayDesc->GetRank();
++ unsigned rank = pArrayMT->GetRank();
+ _ASSERTE(dwNumArgs == rank || dwNumArgs == 2*rank);
+
+ // Morph a ARRAY rank 1 with 0 lower bound into an SZARRAY
+@@ -498,7 +516,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+
+ // This recursive call doesn't go any farther, because the dwNumArgs will be 1,
+ // so don't bother with stack probe.
+- TypeHandle szArrayType = ClassLoader::LoadArrayTypeThrowing(arrayDesc->GetArrayElementTypeHandle(), ELEMENT_TYPE_SZARRAY, 1);
++ TypeHandle szArrayType = ClassLoader::LoadArrayTypeThrowing(pArrayMT->GetApproxArrayElementTypeHandle(), ELEMENT_TYPE_SZARRAY, 1);
+ return AllocateArrayEx(szArrayType, &pArgs[dwNumArgs - 1], 1, bAllocateInLargeHeap DEBUG_ARG(bDontSetAppDomain));
+ }
+
+@@ -561,12 +579,12 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+ if (bAllocateInLargeHeap)
+ {
+ orArray = (ArrayBase *) AllocLHeap(totalSize, FALSE, pArrayMT->ContainsPointers());
+- orArray->SetMethodTableForLargeObject(pArrayMT);
++ orArray->SetArrayMethodTableForLargeObject(pArrayMT);
+ }
+ else
+ {
+ #ifdef FEATURE_64BIT_ALIGNMENT
+- MethodTable *pElementMT = arrayDesc->GetTypeParam().GetMethodTable();
++ MethodTable *pElementMT = pArrayMT->GetApproxArrayElementTypeHandle().GetMethodTable();
+ if (pElementMT->RequiresAlign8() && pElementMT->IsValueType())
+ {
+ // This platform requires that certain fields are 8-byte aligned (and the runtime doesn't provide
+@@ -582,7 +600,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+ {
+ orArray = (ArrayBase *) Alloc(totalSize, FALSE, pArrayMT->ContainsPointers());
+ }
+- orArray->SetMethodTable(pArrayMT);
++ orArray->SetArrayMethodTable(pArrayMT);
+ }
+
+ // Initialize Object
+@@ -655,7 +673,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+ GCStressPolicy::InhibitHolder iholder;
+
+ // Allocate dwProvidedBounds arrays
+- if (!arrayDesc->GetArrayElementTypeHandle().IsArray())
++ if (!pArrayMT->GetApproxArrayElementTypeHandle().IsArray())
+ {
+ orArray = NULL;
+ }
+@@ -666,7 +684,7 @@ OBJECTREF AllocateArrayEx(TypeHandle arrayType, INT32 *pArgs, DWORD dwNumArgs, B
+ _ASSERTE(GetThread());
+ INTERIOR_STACK_PROBE(GetThread());
+
+- TypeHandle subArrayType = arrayDesc->GetArrayElementTypeHandle();
++ TypeHandle subArrayType = pArrayMT->GetApproxArrayElementTypeHandle();
+ for (UINT32 i = 0; i < cElements; i++)
+ {
+ OBJECTREF obj = AllocateArrayEx(subArrayType, &pArgs[1], dwNumArgs-1, bAllocateInLargeHeap DEBUG_ARG(bDontSetAppDomain));
+@@ -809,7 +827,7 @@ OBJECTREF FastAllocatePrimitiveArray(MethodTable* pMT, DWORD cElements, BOOL b
+ }
+
+ // Initialize Object
+- orObject->SetMethodTable( pMT );
++ orObject->SetArrayMethodTable( pMT );
+ _ASSERTE(orObject->GetMethodTable() != NULL);
+ orObject->m_NumComponents = cElements;
+
+@@ -931,7 +949,7 @@ OBJECTREF AllocateObjectArray(DWORD cElements, TypeHandle ElementType)
+ Thread::DisableSOCheckInHCALL disableSOCheckInHCALL;
+ #endif // FEATURE_STACK_PROBE
+ #endif // _DEBUG
+- return OBJECTREF( HCCALL2(fastObjectArrayAllocator, ArrayType.AsPtr(), cElements));
++ return OBJECTREF( HCCALL2(fastObjectArrayAllocator, ArrayType.AsArray()->GetTemplateMethodTable(), cElements));
+ }
+
+ STRINGREF AllocateString( DWORD cchStringLength )
+diff --git a/src/vm/gchelpers.h b/src/vm/gchelpers.h
+index 449524a..73933f6 100644
+--- a/src/vm/gchelpers.h
++++ b/src/vm/gchelpers.h
+@@ -22,6 +22,8 @@
+
+ OBJECTREF AllocateValueSzArray(TypeHandle elementType, INT32 length);
+ // The main Array allocation routine, can do multi-dimensional
++OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap = FALSE
++ DEBUG_ARG(BOOL bDontSetAppDomain = FALSE));
+ OBJECTREF AllocateArrayEx(TypeHandle arrayClass, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap = FALSE
+ DEBUG_ARG(BOOL bDontSetAppDomain = FALSE));
+ // Optimized verion of above
+@@ -47,10 +49,8 @@ OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements);
+ OBJECTREF AllocatePrimitiveArray(CorElementType type, DWORD cElements, BOOL bAllocateInLargeHeap);
+
+
+-// Allocate SD array of object pointers. StubLinker-generated asm code might
+-// implement this, so the element TypeHandle is passed as a PVOID to avoid any
+-// struct calling convention weirdness.
+-typedef HCCALL2_PTR(Object*, FastObjectArrayAllocatorFuncPtr, /*TypeHandle*/PVOID ArrayType, DWORD cElements);
++// Allocate SD array of object pointers.
++typedef HCCALL2_PTR(Object*, FastObjectArrayAllocatorFuncPtr, MethodTable *pArrayMT, DWORD cElements);
+
+ extern FastObjectArrayAllocatorFuncPtr fastObjectArrayAllocator;
+
+diff --git a/src/vm/i386/jitinterfacex86.cpp b/src/vm/i386/jitinterfacex86.cpp
+index 18acbf0..cdabb52 100644
+--- a/src/vm/i386/jitinterfacex86.cpp
++++ b/src/vm/i386/jitinterfacex86.cpp
+@@ -855,7 +855,7 @@ void *JIT_TrialAlloc::GenBox(Flags flags)
+ }
+
+
+-HCIMPL2_RAW(Object*, UnframedAllocateObjectArray, /*TypeHandle*/PVOID ArrayType, DWORD cElements)
++HCIMPL2_RAW(Object*, UnframedAllocateObjectArray, MethodTable *pArrayMT, DWORD cElements)
+ {
+ // This isn't _really_ an FCALL and therefore shouldn't have the
+ // SO_TOLERANT part of the FCALL_CONTRACT b/c it is not entered
+@@ -867,7 +867,7 @@ HCIMPL2_RAW(Object*, UnframedAllocateObjectArray, /*TypeHandle*/PVOID ArrayType,
+ SO_INTOLERANT;
+ } CONTRACTL_END;
+
+- return OBJECTREFToObject(AllocateArrayEx(TypeHandle::FromPtr(ArrayType),
++ return OBJECTREFToObject(AllocateArrayEx(pArrayMT,
+ (INT32 *)(&cElements),
+ 1,
+ FALSE
+@@ -902,8 +902,7 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
+ CodeLabel *noLock = sl.NewCodeLabel();
+ CodeLabel *noAlloc = sl.NewCodeLabel();
+
+- // We were passed a type descriptor in ECX, which contains the (shared)
+- // array method table and the element type.
++ // We were passed a (shared) method table in RCX, which contains the element type.
+
+ // If this is the allocator for use from unmanaged code, ECX contains the
+ // element type descriptor, or the CorElementType.
+@@ -920,12 +919,7 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
+
+ if (flags & NO_FRAME)
+ {
+- if (flags & OBJ_ARRAY)
+- {
+- // we need to load the true method table from the type desc
+- sl.X86EmitIndexRegLoad(kECX, kECX, offsetof(ArrayTypeDesc,m_TemplateMT)-2);
+- }
+- else
++ if ((flags & OBJ_ARRAY) == 0)
+ {
+ // mov ecx,[g_pPredefinedArrayTypes+ecx*4]
+ sl.Emit8(0x8b);
+@@ -937,16 +931,10 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
+
+ // je noLock
+ sl.X86EmitCondJump(noLock, X86CondCode::kJZ);
+-
+- // we need to load the true method table from the type desc
+- sl.X86EmitIndexRegLoad(kECX, kECX, offsetof(ArrayTypeDesc,m_TemplateMT));
+ }
+ }
+ else
+ {
+- // we need to load the true method table from the type desc
+- sl.X86EmitIndexRegLoad(kECX, kECX, offsetof(ArrayTypeDesc,m_TemplateMT)-2);
+-
+ #ifdef FEATURE_PREJIT
+ CodeLabel *indir = sl.NewCodeLabel();
+
+@@ -1064,7 +1052,7 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
+ // pop edx - element count
+ sl.X86EmitPopReg(kEDX);
+
+- // pop ecx - array type descriptor
++ // pop ecx - array method table
+ sl.X86EmitPopReg(kECX);
+
+ // mov dword ptr [eax]ArrayBase.m_NumComponents, edx
+@@ -1089,7 +1077,7 @@ void *JIT_TrialAlloc::GenAllocArray(Flags flags)
+ // pop edx - element count
+ sl.X86EmitPopReg(kEDX);
+
+- // pop ecx - array type descriptor
++ // pop ecx - array method table
+ sl.X86EmitPopReg(kECX);
+
+ CodeLabel * target;
+diff --git a/src/vm/interpreter.cpp b/src/vm/interpreter.cpp
+index 010fee6..4e39efb 100644
+--- a/src/vm/interpreter.cpp
++++ b/src/vm/interpreter.cpp
+@@ -6068,13 +6068,12 @@ void Interpreter::NewArr()
+ }
+ #endif
+
+- TypeHandle typeHnd(elemClsHnd);
+- ArrayTypeDesc* pArrayClassRef = typeHnd.AsArray();
++ MethodTable *pArrayMT = (MethodTable *) elemClsHnd;
+
+- pArrayClassRef->GetMethodTable()->CheckRunClassInitThrowing();
++ pArrayMT->CheckRunClassInitThrowing();
+
+ INT32 size32 = (INT32)sz;
+- Object* newarray = OBJECTREFToObject(AllocateArrayEx(typeHnd, &size32, 1));
++ Object* newarray = OBJECTREFToObject(AllocateArrayEx(pArrayMT, &size32, 1));
+
+ GCX_FORBID();
+ OpStackTypeSet(stkInd, InterpreterType(CORINFO_TYPE_CLASS));
+diff --git a/src/vm/jithelpers.cpp b/src/vm/jithelpers.cpp
+index aaab589..2552b01 100644
+--- a/src/vm/jithelpers.cpp
++++ b/src/vm/jithelpers.cpp
+@@ -3002,7 +3002,7 @@ HCIMPLEND
+ //*************************************************************
+ // Array allocation fast path for arrays of value type elements
+ //
+-HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ {
+ FCALL_CONTRACT;
+
+@@ -3028,16 +3028,14 @@ HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeHn
+ // some reshuffling of intermediate values into nonvolatile registers around the call.
+ Thread *thread = GetThread();
+
+- TypeHandle arrayTypeHandle(arrayTypeHnd_);
+- ArrayTypeDesc *arrayTypeDesc = arrayTypeHandle.AsArray();
+- MethodTable *arrayMethodTable = arrayTypeDesc->GetTemplateMethodTable();
++ MethodTable *pArrayMT = (MethodTable *)arrayMT;
+
+- _ASSERTE(arrayMethodTable->HasComponentSize());
+- SIZE_T componentSize = arrayMethodTable->RawGetComponentSize();
++ _ASSERTE(pArrayMT->HasComponentSize());
++ SIZE_T componentSize = pArrayMT->RawGetComponentSize();
+ SIZE_T totalSize = componentCount * componentSize;
+ _ASSERTE(totalSize / componentSize == componentCount);
+
+- SIZE_T baseSize = arrayMethodTable->GetBaseSize();
++ SIZE_T baseSize = pArrayMT->GetBaseSize();
+ totalSize += baseSize;
+ _ASSERTE(totalSize >= baseSize);
+
+@@ -3056,7 +3054,7 @@ HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeHn
+
+ _ASSERTE(allocPtr != nullptr);
+ ArrayBase *array = reinterpret_cast<ArrayBase *>(allocPtr);
+- array->SetMethodTable(arrayMethodTable);
++ array->SetArrayMethodTable(pArrayMT);
+ _ASSERTE(static_cast<DWORD>(componentCount) == componentCount);
+ array->m_NumComponents = static_cast<DWORD>(componentCount);
+
+@@ -3072,14 +3070,14 @@ HCIMPL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeHn
+
+ // Tail call to the slow helper
+ ENDFORBIDGC();
+- return HCCALL2(JIT_NewArr1, arrayTypeHnd_, size);
++ return HCCALL2(JIT_NewArr1, arrayMT, size);
+ }
+ HCIMPLEND
+
+ //*************************************************************
+ // Array allocation fast path for arrays of object elements
+ //
+-HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ {
+ FCALL_CONTRACT;
+
+@@ -3100,14 +3098,12 @@ HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeH
+ // some reshuffling of intermediate values into nonvolatile registers around the call.
+ Thread *thread = GetThread();
+
+- TypeHandle arrayTypeHandle(arrayTypeHnd_);
+- ArrayTypeDesc *arrayTypeDesc = arrayTypeHandle.AsArray();
+- MethodTable *arrayMethodTable = arrayTypeDesc->GetTemplateMethodTable();
+-
+ SIZE_T totalSize = componentCount * sizeof(void *);
+ _ASSERTE(totalSize / sizeof(void *) == componentCount);
+
+- SIZE_T baseSize = arrayMethodTable->GetBaseSize();
++ MethodTable *pArrayMT = (MethodTable *)arrayMT;
++
++ SIZE_T baseSize = pArrayMT->GetBaseSize();
+ totalSize += baseSize;
+ _ASSERTE(totalSize >= baseSize);
+
+@@ -3124,7 +3120,7 @@ HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeH
+
+ _ASSERTE(allocPtr != nullptr);
+ ArrayBase *array = reinterpret_cast<ArrayBase *>(allocPtr);
+- array->SetMethodTable(arrayMethodTable);
++ array->SetArrayMethodTable(pArrayMT);
+ _ASSERTE(static_cast<DWORD>(componentCount) == componentCount);
+ array->m_NumComponents = static_cast<DWORD>(componentCount);
+
+@@ -3140,14 +3136,14 @@ HCIMPL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayTypeH
+
+ // Tail call to the slow helper
+ ENDFORBIDGC();
+- return HCCALL2(JIT_NewArr1, arrayTypeHnd_, size);
++ return HCCALL2(JIT_NewArr1, arrayMT, size);
+ }
+ HCIMPLEND
+
+ #include <optdefault.h>
+
+ /*************************************************************/
+-HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
++HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size)
+ {
+ FCALL_CONTRACT;
+
+@@ -3155,11 +3151,11 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
+
+ HELPER_METHOD_FRAME_BEGIN_RET_0(); // Set up a frame
+
+- TypeHandle typeHnd(arrayTypeHnd_);
++ MethodTable *pArrayMT = (MethodTable *)arrayMT;
+
+- _ASSERTE(typeHnd.GetInternalCorElementType() == ELEMENT_TYPE_SZARRAY);
+- typeHnd.CheckRestore();
+- ArrayTypeDesc* pArrayClassRef = typeHnd.AsArray();
++ _ASSERTE(pArrayMT->IsFullyLoaded());
++ _ASSERTE(pArrayMT->IsArray());
++ _ASSERTE(!pArrayMT->IsMultiDimArray());
+
+ if (size < 0)
+ COMPlusThrow(kOverflowException);
+@@ -3176,7 +3172,7 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
+ // is this a primitive type?
+ //
+
+- CorElementType elemType = pArrayClassRef->GetArrayElementTypeHandle().GetSignatureCorElementType();
++ CorElementType elemType = pArrayMT->GetInternalCorElementType();
+
+ if (CorTypeInfo::IsPrimitiveType(elemType)
+ #ifdef FEATURE_64BIT_ALIGNMENT
+@@ -3209,9 +3205,13 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
+ #endif
+
+ if (g_pPredefinedArrayTypes[elemType] == NULL)
+- g_pPredefinedArrayTypes[elemType] = pArrayClassRef;
++ {
++ TypeHandle elemTypeHnd = TypeHandle(MscorlibBinder::GetElementType(elemType));
++
++ g_pPredefinedArrayTypes[elemType] = ClassLoader::LoadArrayTypeThrowing(elemTypeHnd, ELEMENT_TYPE_SZARRAY, 0).AsArray();
++ }
+
+- newArray = FastAllocatePrimitiveArray(pArrayClassRef->GetMethodTable(), static_cast<DWORD>(size), bAllocateInLargeHeap);
++ newArray = FastAllocatePrimitiveArray(pArrayMT, static_cast<DWORD>(size), bAllocateInLargeHeap);
+ }
+ else
+ {
+@@ -3221,7 +3221,7 @@ HCIMPL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size)
+ }
+ #endif // _DEBUG
+ INT32 size32 = (INT32)size;
+- newArray = AllocateArrayEx(typeHnd, &size32, 1);
++ newArray = AllocateArrayEx(pArrayMT, &size32, 1);
+ }
+
+ HELPER_METHOD_FRAME_END();
+diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
+index 84f635a..f756c90 100644
+--- a/src/vm/jitinterface.cpp
++++ b/src/vm/jitinterface.cpp
+@@ -2726,7 +2726,14 @@ void CEEInfo::embedGenericHandle(
+
+ pResult->handleType = CORINFO_HANDLETYPE_CLASS;
+
+- pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
++ if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
++ {
++ pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsArray()->GetTemplateMethodTable();
++ }
++ else
++ {
++ pResult->compileTimeHandle = (CORINFO_GENERIC_HANDLE)th.AsPtr();
++ }
+
+ if (fEmbedParent && pResolvedToken->hMethod != NULL)
+ {
+@@ -3404,7 +3411,10 @@ NoSpecialCase:
+ case TypeHandleSlot:
+ {
+ if (pResolvedToken->tokenType == CORINFO_TOKENKIND_Newarr)
++ {
++ sigBuilder.AppendElementType((CorElementType)ELEMENT_TYPE_NATIVE_ARRAY_TEMPLATE_ZAPSIG);
+ sigBuilder.AppendElementType(ELEMENT_TYPE_SZARRAY);
++ }
+
+ // Note that we can come here with pResolvedToken->pTypeSpec == NULL for invalid IL that
+ // directly references __Canon
+diff --git a/src/vm/jitinterface.h b/src/vm/jitinterface.h
+index d287248..a3017ef 100644
+--- a/src/vm/jitinterface.h
++++ b/src/vm/jitinterface.h
+@@ -215,9 +215,9 @@ extern FCDECL1(StringObject*, AllocateString_MP_FastPortable, DWORD stringLength
+ extern FCDECL1(StringObject*, UnframedAllocateString, DWORD stringLength);
+ extern FCDECL1(StringObject*, FramedAllocateString, DWORD stringLength);
+
+-extern FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
+-extern FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
+-extern FCDECL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
++extern FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++extern FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++extern FCDECL2(Object*, JIT_NewArr1, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+
+ #ifndef JIT_Stelem_Ref
+ #define JIT_Stelem_Ref JIT_Stelem_Ref_Portable
+@@ -326,8 +326,8 @@ private:
+ #ifdef _WIN64
+ EXTERN_C FCDECL1(Object*, JIT_TrialAllocSFastMP_InlineGetThread, CORINFO_CLASS_HANDLE typeHnd_);
+ EXTERN_C FCDECL2(Object*, JIT_BoxFastMP_InlineGetThread, CORINFO_CLASS_HANDLE type, void* data);
+-EXTERN_C FCDECL2(Object*, JIT_NewArr1VC_MP_InlineGetThread, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
+-EXTERN_C FCDECL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
++EXTERN_C FCDECL2(Object*, JIT_NewArr1VC_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++EXTERN_C FCDECL2(Object*, JIT_NewArr1OBJ_MP_InlineGetThread, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+
+ #endif // _WIN64
+
+diff --git a/src/vm/jitinterfacegen.cpp b/src/vm/jitinterfacegen.cpp
+index 8d1c8cd..2638740 100644
+--- a/src/vm/jitinterfacegen.cpp
++++ b/src/vm/jitinterfacegen.cpp
+@@ -30,8 +30,8 @@
+ EXTERN_C Object* JIT_TrialAllocSFastMP_InlineGetThread(CORINFO_CLASS_HANDLE typeHnd_);
+ EXTERN_C Object* JIT_BoxFastMP_InlineGetThread (CORINFO_CLASS_HANDLE type, void* unboxedData);
+ EXTERN_C Object* AllocateStringFastMP_InlineGetThread (CLR_I4 cch);
+-EXTERN_C Object* JIT_NewArr1OBJ_MP_InlineGetThread (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
+-EXTERN_C Object* JIT_NewArr1VC_MP_InlineGetThread (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1OBJ_MP_InlineGetThread (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1VC_MP_InlineGetThread (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+
+ // This next set is the fast version that invoke GetThread but is still faster than the VM implementation (i.e.
+ // the "slow" versions).
+@@ -42,10 +42,10 @@ EXTERN_C Object* JIT_BoxFastUP (CORINFO_CLASS_HANDLE type, void* unboxedData);
+ EXTERN_C Object* AllocateStringFastMP (CLR_I4 cch);
+ EXTERN_C Object* AllocateStringFastUP (CLR_I4 cch);
+
+-EXTERN_C Object* JIT_NewArr1OBJ_MP (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
+-EXTERN_C Object* JIT_NewArr1OBJ_UP (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
+-EXTERN_C Object* JIT_NewArr1VC_MP (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
+-EXTERN_C Object* JIT_NewArr1VC_UP (CORINFO_CLASS_HANDLE arrayTypeHnd_, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1OBJ_MP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1OBJ_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1VC_MP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++EXTERN_C Object* JIT_NewArr1VC_UP (CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+
+ //For the optimized JIT_Mon helpers
+ #if defined(_TARGET_AMD64_)
+diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp
+index 21fab72..598759a 100644
+--- a/src/vm/methodtable.cpp
++++ b/src/vm/methodtable.cpp
+@@ -5903,6 +5903,19 @@ void MethodTable::DoFullyLoad(Generics::RecursionGraph * const pVisited, const
+
+ }
+
++ if (level >= CLASS_DEPENDENCIES_LOADED && IsArray())
++ {
++ // The array type should be loaded, if template method table is loaded
++ // See also: ArrayBase::SetArrayMethodTable, ArrayBase::SetArrayMethodTableForLargeObject
++ TypeHandle th = ClassLoader::LoadArrayTypeThrowing(GetApproxArrayElementTypeHandle(),
++ GetInternalCorElementType(),
++ GetRank(),
++ ClassLoader::LoadTypes,
++ level);
++ _ASSERTE(th.IsTypeDesc() && th.IsArray());
++ _ASSERTE(!(level == CLASS_LOADED && !th.IsFullyLoaded()));
++ }
++
+ END_SO_INTOLERANT_CODE;
+
+ #endif //!DACCESS_COMPILE
+diff --git a/src/vm/object.cpp b/src/vm/object.cpp
+index 4c08f02..daa20e7 100644
+--- a/src/vm/object.cpp
++++ b/src/vm/object.cpp
+@@ -1818,6 +1818,24 @@ VOID Object::ValidateInner(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncB
+
+ #endif // VERIFY_HEAP
+
++#ifndef DACCESS_COMPILE
++#ifdef _DEBUG
++void ArrayBase::AssertArrayTypeDescLoaded()
++{
++ _ASSERTE (m_pMethTab->IsArray());
++
++ // The type should already be loaded
++ // See also: MethodTable::DoFullyLoad
++ TypeHandle th = ClassLoader::LoadArrayTypeThrowing(m_pMethTab->GetApproxArrayElementTypeHandle(),
++ m_pMethTab->GetInternalCorElementType(),
++ m_pMethTab->GetRank(),
++ ClassLoader::DontLoadTypes);
++
++ _ASSERTE(!th.IsNull());
++}
++#endif // DEBUG
++#endif // !DACCESS_COMPILE
++
+ /*==================================NewString===================================
+ **Action: Creates a System.String object.
+ **Returns:
+diff --git a/src/vm/object.h b/src/vm/object.h
+index cb3743c..00def1d 100644
+--- a/src/vm/object.h
++++ b/src/vm/object.h
+@@ -207,19 +207,34 @@ class Object
+ m_pMethTab = pMT;
+ }
+
+- VOID SetMethodTable(MethodTable *pMT)
++ VOID SetMethodTable(MethodTable *pMT
++ DEBUG_ARG(BOOL bAllowArray = FALSE))
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pMethTab = pMT;
++
++#ifdef _DEBUG
++ if (!bAllowArray)
++ {
++ AssertNotArray();
++ }
++#endif // _DEBUG
+ }
+
+- VOID SetMethodTableForLargeObject(MethodTable *pMT)
++ VOID SetMethodTableForLargeObject(MethodTable *pMT
++ DEBUG_ARG(BOOL bAllowArray = FALSE))
+ {
+ // This function must be used if the allocation occurs on the large object heap, and the method table might be a collectible type
+ WRAPPER_NO_CONTRACT;
+ ErectWriteBarrierForMT(&m_pMethTab, pMT);
++
++#ifdef _DEBUG
++ if (!bAllowArray)
++ {
++ AssertNotArray();
++ }
++#endif // _DEBUG
+ }
+-
+ #endif //!DACCESS_COMPILE
+
+ // An object might be a proxy of some sort, with a thunking VTable. If so, we can
+@@ -664,6 +679,15 @@ class Object
+ BOOL ShouldCheckAppDomainAgile(BOOL raiseAssert, BOOL *pfResult);
+ #endif
+
++#ifdef _DEBUG
++ void AssertNotArray()
++ {
++ if (m_pMethTab->IsArray())
++ {
++ _ASSERTE(!"ArrayBase::SetArrayMethodTable/ArrayBase::SetArrayMethodTableForLargeObject should be used for arrays");
++ }
++ }
++#endif // _DEBUG
+ };
+
+ /*
+@@ -745,10 +769,10 @@ class ArrayBase : public Object
+ friend class GCHeap;
+ friend class CObjectHeader;
+ friend class Object;
+- friend OBJECTREF AllocateArrayEx(TypeHandle arrayClass, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap DEBUG_ARG(BOOL bDontSetAppDomain));
++ friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap DEBUG_ARG(BOOL bDontSetAppDomain));
+ friend OBJECTREF FastAllocatePrimitiveArray(MethodTable* arrayType, DWORD cElements, BOOL bAllocateInLargeHeap);
+- friend FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
+- friend FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE typeHnd_, INT_PTR size);
++ friend FCDECL2(Object*, JIT_NewArr1VC_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
++ friend FCDECL2(Object*, JIT_NewArr1OBJ_MP_FastPortable, CORINFO_CLASS_HANDLE arrayMT, INT_PTR size);
+ friend class JIT_TrialAlloc;
+ friend class CheckAsmOffsets;
+ friend struct _DacGlobals;
+@@ -790,6 +814,11 @@ public:
+ // Total element count for the array
+ inline DWORD GetNumComponents() const;
+
++#ifndef DACCESS_COMPILE
++ inline void SetArrayMethodTable(MethodTable *pArrayMT);
++ inline void SetArrayMethodTableForLargeObject(MethodTable *pArrayMT);
++#endif // !DACCESS_COMPILE
++
+ // Get pointer to elements, handles any number of dimensions
+ PTR_BYTE GetDataPtr(BOOL inGC = FALSE) const {
+ LIMITED_METHOD_CONTRACT;
+@@ -865,6 +894,13 @@ public:
+
+ inline static unsigned GetBoundsOffset(MethodTable* pMT);
+ inline static unsigned GetLowerBoundsOffset(MethodTable* pMT);
++
++private:
++#ifndef DACCESS_COMPILE
++#ifdef _DEBUG
++ void AssertArrayTypeDescLoaded();
++#endif // _DEBUG
++#endif // !DACCESS_COMPILE
+ };
+
+ //
+@@ -905,7 +941,7 @@ class PtrArray : public ArrayBase
+ {
+ friend class GCHeap;
+ friend class ClrDataAccess;
+- friend OBJECTREF AllocateArrayEx(TypeHandle arrayClass, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap);
++ friend OBJECTREF AllocateArrayEx(MethodTable *pArrayMT, INT32 *pArgs, DWORD dwNumArgs, BOOL bAllocateInLargeHeap);
+ friend class JIT_TrialAlloc;
+ friend class CheckAsmOffsets;
+
+diff --git a/src/vm/object.inl b/src/vm/object.inl
+index 5698321..5dc3d6d 100644
+--- a/src/vm/object.inl
++++ b/src/vm/object.inl
+@@ -146,6 +146,7 @@ inline /* static */ TypeHandle ArrayBase::GetTypeHandle(MethodTable * pMT)
+ // for T[] is available and restored
+
+ // @todo This should be turned into a probe with a hard SO when we have one
++ // See also: ArrayBase::SetArrayMethodTable, ArrayBase::SetArrayMethodTableForLargeObject and MethodTable::DoFullyLoad
+ CONTRACT_VIOLATION(SOToleranceViolation);
+ // == FailIfNotLoadedOrNotRestored
+ TypeHandle arrayType = ClassLoader::LoadArrayTypeThrowing(pMT->GetApproxArrayElementTypeHandle(), kind, rank, ClassLoader::DontLoadTypes);
+@@ -174,6 +175,32 @@ inline DWORD ArrayBase::GetNumComponents() const
+ return m_NumComponents;
+ }
+
++#ifndef DACCESS_COMPILE
++inline void ArrayBase::SetArrayMethodTable(MethodTable *pArrayMT)
++{
++ LIMITED_METHOD_CONTRACT;
++
++ SetMethodTable(pArrayMT
++ DEBUG_ARG(TRUE));
++
++#ifdef _DEBUG
++ AssertArrayTypeDescLoaded();
++#endif // _DEBUG
++}
++
++inline void ArrayBase::SetArrayMethodTableForLargeObject(MethodTable *pArrayMT)
++{
++ LIMITED_METHOD_CONTRACT;
++
++ SetMethodTableForLargeObject(pArrayMT
++ DEBUG_ARG(TRUE));
++
++#ifdef _DEBUG
++ AssertArrayTypeDescLoaded();
++#endif // _DEBUG
++}
++#endif // !DACCESS_COMPILE
++
+ inline /* static */ unsigned ArrayBase::GetDataPtrOffset(MethodTable* pMT)
+ {
+ LIMITED_METHOD_CONTRACT;
+diff --git a/src/vm/prestub.cpp b/src/vm/prestub.cpp
+index af3f190..746e415 100644
+--- a/src/vm/prestub.cpp
++++ b/src/vm/prestub.cpp
+@@ -2764,7 +2764,9 @@ PCODE DynamicHelperFixup(TransitionBlock * pTransitionBlock, TADDR * pCell, DWOR
+ case ENCODE_NEW_ARRAY_HELPER:
+ {
+ CorInfoHelpFunc helpFunc = CEEInfo::getNewArrHelperStatic(th);
+- pHelper = DynamicHelpers::CreateHelperArgMove(pModule->GetLoaderAllocator(), th.AsTAddr(), CEEJitInfo::getHelperFtnStatic(helpFunc));
++ ArrayTypeDesc *pArrayTypeDesc = th.AsArray();
++ MethodTable *pArrayMT = pArrayTypeDesc->GetTemplateMethodTable();
++ pHelper = DynamicHelpers::CreateHelperArgMove(pModule->GetLoaderAllocator(), dac_cast<TADDR>(pArrayMT), CEEJitInfo::getHelperFtnStatic(helpFunc));
+ }
+ break;
+
+--
+2.7.4
+