summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Soldatov <soldatov.a@samsung.com>2018-06-09 20:56:03 +0300
committerAlexander Soldatov <soldatov.a@samsung.com>2018-06-09 20:56:03 +0300
commit52d9b3a052cdf2e486879396e03be44474d3db74 (patch)
treeed97947d8f78a6de9d85703d793feae7ea909db4
parent2258e6eda8ce5e1fa97dc4d7b6d4c231285cba94 (diff)
downloadcoreclr-52d9b3a052cdf2e486879396e03be44474d3db74.tar.gz
coreclr-52d9b3a052cdf2e486879396e03be44474d3db74.tar.bz2
coreclr-52d9b3a052cdf2e486879396e03be44474d3db74.zip
Optimizations for 2nd level of Vtable + different fixes for JIT and runtimesubmit/tizen_4.0_base/20180609.183627accepted/tizen/4.0/base/20180615.171456
- Fix for Memory Profiler on x86 emulator - Remove relocations for second-level indirection of Vtable - PEImageLayout: flush instruction cache only for pages with relocations - Improved collected delegate diagnostic - Different fixes for stability (correct shootdown, correct signal handling, fixed value type box optimization, fix to defer removing statements during opt CSE) Change-Id: Ic6186a717c8c2b5ceb2c9e48fb5216f3b5a415d9
-rw-r--r--packaging/0001-Improve-UMEntryThunkCode-Poison-method.patch175
-rw-r--r--packaging/0002-UMEntryThunk-store-freed-thunks-into-FIFO-free-list.patch158
-rw-r--r--packaging/0003-dllimportcallback-remove-code-for-CallbackOnCollecte.patch153
-rw-r--r--packaging/0004-LoaderHeap-remove-LHF_ZEROINIT-option.patch178
-rw-r--r--packaging/0019-JIT-Fix-value-type-box-optimization.patch1215
-rw-r--r--packaging/0020-JIT-port-fix-to-defer-removing-statements-during-opt.patch132
-rw-r--r--packaging/0021-Revert-ExecuteHandlerOnOriginalStack-handle-case-whe.patch143
-rw-r--r--packaging/0022-CatchHardwareExceptionHolder-use-GetCurrentPalThread.patch35
-rw-r--r--packaging/0023-vm-threads-change-tls-model-for-gCurrentThreadInfo-v.patch29
-rw-r--r--packaging/0024-sigsegv_handler-handle-case-when-it-is-called-on-ori.patch71
-rw-r--r--packaging/0025-Revert-TLS-model-change-of-the-gCurrentThreadInfo.patch28
-rw-r--r--packaging/0026-Prevent-memory-allocation-in-signal-handler.patch68
-rw-r--r--packaging/0027-Revert-Prevent-memory-allocation-in-signal-handler.patch65
-rw-r--r--packaging/0028-Do-not-allocate-exception-for-signal-from-non-manage.patch174
-rw-r--r--packaging/0029-Move-exception-allocation-to-PAL_SEHException.patch179
-rw-r--r--packaging/0030-Remove-exception-records-allocation-from-pal.h.patch116
-rw-r--r--packaging/0031-Fix-preventing-memory-allocation-in-signal-handler.patch74
-rw-r--r--packaging/0032-Fix-Use-of-EventPipeConfiguration-After-it-has-Been-.patch53
-rw-r--r--packaging/0033-Revert-clear-cache-after-NI-reloc.patch26
-rw-r--r--packaging/0034-PEImageLayout-clear-instruction-cache-after-relocati.patch81
-rw-r--r--packaging/0035-PEImageLayout-flush-instruction-cache-only-for-pages.patch117
-rw-r--r--packaging/0036-Separate-sections-READONLY_VCHUNKS-and-READONLY_DICT.patch59
-rw-r--r--packaging/0037-Remove-relocations-for-second-level-indirection-of-V.patch1134
-rw-r--r--packaging/0038-Replace-PLATFORM_UNIX-_TARGET_ARM_-for-NGEN-relocati.patch112
-rw-r--r--packaging/0039-Fix-formatting.patch41
-rw-r--r--packaging/0040-Update-GUID.patch33
-rw-r--r--packaging/0041-Move-IAT_RELPVALUE-to-the-end-of-enum-InfoAccessType.patch27
-rw-r--r--packaging/0042-Add-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-true-as-defaul.patch22
-rw-r--r--packaging/0043-Fix-setup-of-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-for-U.patch25
-rw-r--r--packaging/0044-Replace-push-pop-of-R11-in-stubs-with.patch182
-rw-r--r--packaging/0045-Replace-push-pop-of-R11-for-function-epilog-with-usa.patch93
-rw-r--r--packaging/0046-Remove-ifdef.patch32
-rw-r--r--packaging/0047-Launching-the-Memory-Profiler-on-x86-emulator-may-le.patch43
-rw-r--r--packaging/coreclr.spec68
34 files changed, 5140 insertions, 1 deletions
diff --git a/packaging/0001-Improve-UMEntryThunkCode-Poison-method.patch b/packaging/0001-Improve-UMEntryThunkCode-Poison-method.patch
new file mode 100644
index 0000000000..49525b0b59
--- /dev/null
+++ b/packaging/0001-Improve-UMEntryThunkCode-Poison-method.patch
@@ -0,0 +1,175 @@
+From ce9c04e177ad80997aa0824aaa112ef51f9d0a3b Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Wed, 10 Jan 2018 18:26:01 +0300
+Subject: [PATCH 01/47] Improve UMEntryThunkCode::Poison method.
+
+Improve UMEntryThunkCode::Poison to produce diagnostic message
+when collected delegate was called.
+---
+ src/vm/amd64/cgenamd64.cpp | 13 ++++++++++++-
+ src/vm/arm/stubs.cpp | 14 ++++++++++++--
+ src/vm/arm64/stubs.cpp | 9 +++++++++
+ src/vm/dllimportcallback.cpp | 36 ++++++++++++++++++++++++++++++++++++
+ src/vm/dllimportcallback.h | 2 ++
+ src/vm/i386/cgenx86.cpp | 7 ++++++-
+ 6 files changed, 77 insertions(+), 4 deletions(-)
+
+diff --git a/src/vm/amd64/cgenamd64.cpp b/src/vm/amd64/cgenamd64.cpp
+index 20dca22..1b20b32 100644
+--- a/src/vm/amd64/cgenamd64.cpp
++++ b/src/vm/amd64/cgenamd64.cpp
+@@ -680,7 +680,18 @@ void UMEntryThunkCode::Poison()
+ }
+ CONTRACTL_END;
+
+- m_movR10[0] = X86_INSTR_INT3;
++ m_execstub = (BYTE *)UMEntryThunk::ReportViolation;
++
++ m_movR10[0] = REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT;
++#ifdef _WIN32
++ // mov rcx, pUMEntryThunk // 48 b9 xx xx xx xx xx xx xx xx
++ m_movR10[1] = 0xB9;
++#else
++ // mov rdi, pUMEntryThunk // 48 bf xx xx xx xx xx xx xx xx
++ m_movR10[1] = 0xBF;
++#endif
++
++ ClrFlushInstructionCache(&m_movR10[0], &m_jmpRAX[3]-&m_movR10[0]);
+ }
+
+ UMEntryThunk* UMEntryThunk::Decode(LPVOID pCallback)
+diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp
+index 70cc900..a52f0c8 100644
+--- a/src/vm/arm/stubs.cpp
++++ b/src/vm/arm/stubs.cpp
+@@ -2523,12 +2523,22 @@ void UMEntryThunkCode::Encode(BYTE* pTargetCode, void* pvSecretParam)
+ FlushInstructionCache(GetCurrentProcess(),&m_code,sizeof(m_code));
+ }
+
++#ifndef DACCESS_COMPILE
++
+ void UMEntryThunkCode::Poison()
+ {
+- // Insert 'udf 0xff' at the entry point
+- m_code[0] = 0xdeff;
++ m_pTargetCode = (TADDR)UMEntryThunk::ReportViolation;
++
++ // ldr r0, [pc + 8]
++ m_code[0] = 0x4802;
++ // nop
++ m_code[1] = 0xbf00;
++
++ ClrFlushInstructionCache(&m_code,sizeof(m_code));
+ }
+
++#endif // DACCESS_COMPILE
++
+ ///////////////////////////// UNIMPLEMENTED //////////////////////////////////
+
+ #ifndef DACCESS_COMPILE
+diff --git a/src/vm/arm64/stubs.cpp b/src/vm/arm64/stubs.cpp
+index df2124d..a0d90de 100644
+--- a/src/vm/arm64/stubs.cpp
++++ b/src/vm/arm64/stubs.cpp
+@@ -1244,11 +1244,20 @@ void UMEntryThunkCode::Encode(BYTE* pTargetCode, void* pvSecretParam)
+ FlushInstructionCache(GetCurrentProcess(),&m_code,sizeof(m_code));
+ }
+
++#ifndef DACCESS_COMPILE
++
+ void UMEntryThunkCode::Poison()
+ {
++ m_pTargetCode = (TADDR)UMEntryThunk::ReportViolation;
++
++ // ldp x16, x0, [x12]
++ m_code[1] = 0xa9400190;
+
++ ClrFlushInstructionCache(&m_code,sizeof(m_code));
+ }
+
++#endif // DACCESS_COMPILE
++
+ #ifdef PROFILING_SUPPORTED
+ #include "proftoeeinterfaceimpl.h"
+
+diff --git a/src/vm/dllimportcallback.cpp b/src/vm/dllimportcallback.cpp
+index 8684c12..c3e6a4e 100644
+--- a/src/vm/dllimportcallback.cpp
++++ b/src/vm/dllimportcallback.cpp
+@@ -1167,6 +1167,42 @@ VOID UMEntryThunk::FreeUMEntryThunk(UMEntryThunk* p)
+
+ #endif // CROSSGEN_COMPILE
+
++//-------------------------------------------------------------------------
++// This function is used to report error when we call collected delegate.
++// But memory that was allocated for thunk can be reused, due to it this
++// function will not be called in all cases of the collected delegate call,
++// also it may crash while trying to report the problem.
++//-------------------------------------------------------------------------
++VOID __fastcall UMEntryThunk::ReportViolation(UMEntryThunk* pEntryThunk)
++{
++ CONTRACTL
++ {
++ THROWS;
++ GC_TRIGGERS;
++ MODE_COOPERATIVE;
++ PRECONDITION(CheckPointer(pEntryThunk));
++ }
++ CONTRACTL_END;
++
++ MethodDesc* pMethodDesc = pEntryThunk->GetMethod();
++
++ SString namespaceOrClassName;
++ SString methodName;
++ SString moduleName;
++
++ pMethodDesc->GetMethodInfoNoSig(namespaceOrClassName, methodName);
++ moduleName.SetUTF8(pMethodDesc->GetModule()->GetSimpleName());
++
++ SString message;
++
++ message.Printf(W("A callback was made on a garbage collected delegate of type '%s!%s::%s'."),
++ moduleName.GetUnicode(),
++ namespaceOrClassName.GetUnicode(),
++ methodName.GetUnicode());
++
++ EEPOLICY_HANDLE_FATAL_ERROR_WITH_MESSAGE(COR_E_FAILFAST, message.GetUnicode());
++}
++
+ UMThunkMarshInfo::~UMThunkMarshInfo()
+ {
+ CONTRACTL
+diff --git a/src/vm/dllimportcallback.h b/src/vm/dllimportcallback.h
+index e79c5f0..5838e49 100644
+--- a/src/vm/dllimportcallback.h
++++ b/src/vm/dllimportcallback.h
+@@ -511,6 +511,8 @@ public:
+ }
+ #endif
+
++ static VOID __fastcall ReportViolation(UMEntryThunk* p);
++
+ private:
+ // The start of the managed code.
+ // if m_pObjectHandle is non-NULL, this field is still set to help with diagnostic of call on collected delegate crashes
+diff --git a/src/vm/i386/cgenx86.cpp b/src/vm/i386/cgenx86.cpp
+index b4277db..8db4073 100644
+--- a/src/vm/i386/cgenx86.cpp
++++ b/src/vm/i386/cgenx86.cpp
+@@ -1614,7 +1614,12 @@ void UMEntryThunkCode::Poison()
+ {
+ LIMITED_METHOD_CONTRACT;
+
+- m_movEAX = X86_INSTR_INT3;
++ m_execstub = (BYTE*) ((BYTE*)UMEntryThunk::ReportViolation - (4+((BYTE*)&m_execstub)));
++
++ // mov ecx, imm32
++ m_movEAX = 0xb9;
++
++ ClrFlushInstructionCache(GetEntryPoint(),sizeof(UMEntryThunkCode));
+ }
+
+ UMEntryThunk* UMEntryThunk::Decode(LPVOID pCallback)
+--
+2.7.4
+
diff --git a/packaging/0002-UMEntryThunk-store-freed-thunks-into-FIFO-free-list.patch b/packaging/0002-UMEntryThunk-store-freed-thunks-into-FIFO-free-list.patch
new file mode 100644
index 0000000000..8ee6d76e31
--- /dev/null
+++ b/packaging/0002-UMEntryThunk-store-freed-thunks-into-FIFO-free-list.patch
@@ -0,0 +1,158 @@
+From 51ffa6ba338dded7be2a0147a8e477d28b35b159 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Fri, 12 Jan 2018 18:55:10 +0300
+Subject: [PATCH 02/47] UMEntryThunk: store freed thunks into FIFO free list
+
+Use free list to delay reusing deleted thunks. It improves
+collected delegate calls diagnostic.
+---
+ src/vm/dllimportcallback.cpp | 87 ++++++++++++++++++++++++++++++++++++++++++--
+ src/vm/dllimportcallback.h | 10 ++++-
+ 2 files changed, 91 insertions(+), 6 deletions(-)
+
+diff --git a/src/vm/dllimportcallback.cpp b/src/vm/dllimportcallback.cpp
+index c3e6a4e..fe03f47 100644
+--- a/src/vm/dllimportcallback.cpp
++++ b/src/vm/dllimportcallback.cpp
+@@ -33,6 +33,79 @@ struct UM2MThunk_Args
+ int argLen;
+ };
+
++class UMEntryThunkFreeList
++{
++public:
++ UMEntryThunkFreeList(size_t threshold) :
++ m_threshold(threshold),
++ m_count(0),
++ m_pHead(NULL),
++ m_pTail(NULL)
++ {
++ WRAPPER_NO_CONTRACT;
++
++ m_crst.Init(CrstLeafLock, CRST_UNSAFE_ANYMODE);
++ }
++
++ UMEntryThunk *GetUMEntryThunk()
++ {
++ WRAPPER_NO_CONTRACT;
++
++ if (m_count < m_threshold)
++ return NULL;
++
++ CrstHolder ch(&m_crst);
++
++ UMEntryThunk *pThunk = m_pHead;
++
++ if (pThunk == NULL)
++ return NULL;
++
++ m_pHead = m_pHead->m_pNextFreeThunk;
++ --m_count;
++
++ return pThunk;
++ }
++
++ void AddToList(UMEntryThunk *pThunk)
++ {
++ CONTRACTL
++ {
++ NOTHROW;
++ }
++ CONTRACTL_END;
++
++ CrstHolder ch(&m_crst);
++
++ if (m_pHead == NULL)
++ {
++ m_pHead = pThunk;
++ m_pTail = pThunk;
++ }
++ else
++ {
++ m_pTail->m_pNextFreeThunk = pThunk;
++ m_pTail = pThunk;
++ }
++
++ pThunk->m_pNextFreeThunk = NULL;
++
++ ++m_count;
++ }
++
++private:
++ // Used to delay reusing freed thunks
++ size_t m_threshold;
++ size_t m_count;
++ UMEntryThunk *m_pHead;
++ UMEntryThunk *m_pTail;
++ CrstStatic m_crst;
++};
++
++#define DEFAULT_THUNK_FREE_LIST_THRESHOLD 64
++
++static UMEntryThunkFreeList s_thunkFreeList(DEFAULT_THUNK_FREE_LIST_THRESHOLD);
++
+ EXTERN_C void STDCALL UM2MThunk_WrapperHelper(void *pThunkArgs,
+ int argLen,
+ void *pAddr,
+@@ -1111,20 +1184,26 @@ UMEntryThunk* UMEntryThunk::CreateUMEntryThunk()
+
+ UMEntryThunk * p;
+
+- // On the phone, use loader heap to save memory commit of regular executable heap
+- p = (UMEntryThunk *)(void *)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(sizeof(UMEntryThunk)));
++ p = s_thunkFreeList.GetUMEntryThunk();
++
++ if (p == NULL)
++ p = (UMEntryThunk *)(void *)SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->AllocMem(S_SIZE_T(sizeof(UMEntryThunk)));
+
+ RETURN p;
+ }
+
+ void UMEntryThunk::Terminate()
+ {
+- WRAPPER_NO_CONTRACT;
++ CONTRACTL
++ {
++ NOTHROW;
++ }
++ CONTRACTL_END;
+
+ _ASSERTE(!SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->IsZeroInit());
+ m_code.Poison();
+
+- SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->BackoutMem(this, sizeof(UMEntryThunk));
++ s_thunkFreeList.AddToList(this);
+ }
+
+ VOID UMEntryThunk::FreeUMEntryThunk(UMEntryThunk* p)
+diff --git a/src/vm/dllimportcallback.h b/src/vm/dllimportcallback.h
+index 5838e49..d820a76 100644
+--- a/src/vm/dllimportcallback.h
++++ b/src/vm/dllimportcallback.h
+@@ -250,6 +250,7 @@ class UMEntryThunk
+ {
+ friend class CheckAsmOffsets;
+ friend class NDirectStubLinker;
++ friend class UMEntryThunkFreeList;
+
+ private:
+ #ifdef _DEBUG
+@@ -526,8 +527,13 @@ private:
+ // Field is NULL for a static method.
+ OBJECTHANDLE m_pObjectHandle;
+
+- // Pointer to the shared structure containing everything else
+- PTR_UMThunkMarshInfo m_pUMThunkMarshInfo;
++ union
++ {
++ // Pointer to the shared structure containing everything else
++ PTR_UMThunkMarshInfo m_pUMThunkMarshInfo;
++ // Pointer to the next UMEntryThunk in the free list. Used when it is freed.
++ UMEntryThunk *m_pNextFreeThunk;
++ };
+
+ ADID m_dwDomainId; // appdomain of module (cached for fast access)
+ #ifdef _DEBUG
+--
+2.7.4
+
diff --git a/packaging/0003-dllimportcallback-remove-code-for-CallbackOnCollecte.patch b/packaging/0003-dllimportcallback-remove-code-for-CallbackOnCollecte.patch
new file mode 100644
index 0000000000..f7b650569f
--- /dev/null
+++ b/packaging/0003-dllimportcallback-remove-code-for-CallbackOnCollecte.patch
@@ -0,0 +1,153 @@
+From 7244ba7107daea201faac0b6c71b545d77fbcb57 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Fri, 12 Jan 2018 11:46:48 +0300
+Subject: [PATCH 03/47] dllimportcallback: remove code for
+ CallbackOnCollectedDelegate MDA
+
+---
+ src/vm/dllimportcallback.cpp | 71 --------------------------------------------
+ src/vm/dllimportcallback.h | 19 ------------
+ 2 files changed, 90 deletions(-)
+
+diff --git a/src/vm/dllimportcallback.cpp b/src/vm/dllimportcallback.cpp
+index fe03f47..8623d46 100644
+--- a/src/vm/dllimportcallback.cpp
++++ b/src/vm/dllimportcallback.cpp
+@@ -112,34 +112,6 @@ EXTERN_C void STDCALL UM2MThunk_WrapperHelper(void *pThunkArgs,
+ UMEntryThunk *pEntryThunk,
+ Thread *pThread);
+
+-#ifdef MDA_SUPPORTED
+-EXTERN_C void __fastcall CallbackOnCollectedDelegateHelper(UMEntryThunk *pEntryThunk)
+-{
+- CONTRACTL
+- {
+- THROWS;
+- GC_TRIGGERS;
+- MODE_COOPERATIVE;
+- SO_TOLERANT;
+- PRECONDITION(CheckPointer(pEntryThunk));
+- }
+- CONTRACTL_END;
+-
+- MdaCallbackOnCollectedDelegate* pProbe = MDA_GET_ASSISTANT(CallbackOnCollectedDelegate);
+-
+- // This MDA must be active if we generated a call to CallbackOnCollectedDelegateHelper
+- _ASSERTE(pProbe);
+-
+- if (pEntryThunk->IsCollected())
+- {
+- INSTALL_UNWIND_AND_CONTINUE_HANDLER;
+- pProbe->ReportViolation(pEntryThunk->GetMethod());
+- COMPlusThrow(kNullReferenceException);
+- UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
+- }
+-}
+-#endif // MDA_SUPPORTED
+-
+ // This is used as target of callback from DoADCallBack. It sets up the environment and effectively
+ // calls back into the thunk that needed to switch ADs.
+ void UM2MThunk_Wrapper(LPVOID ptr) // UM2MThunk_Args
+@@ -412,25 +384,6 @@ VOID UMEntryThunk::CompileUMThunkWorker(UMThunkStubInfo *pInfo,
+ // would deadlock).
+ pcpusl->EmitLabel(pDoADCallBackStartLabel);
+
+-
+-#ifdef MDA_SUPPORTED
+- if ((pInfo->m_wFlags & umtmlSkipStub) && !(pInfo->m_wFlags & umtmlIsStatic) &&
+- MDA_GET_ASSISTANT(CallbackOnCollectedDelegate))
+- {
+- // save registers
+- pcpusl->X86EmitPushReg(kEAXentryThunk);
+- pcpusl->X86EmitPushReg(kECXthread);
+-
+- // CallbackOnCollectedDelegateHelper is a fast call
+- pcpusl->X86EmitMovRegReg(kECX, kEAXentryThunk);
+- pcpusl->X86EmitCall(pcpusl->NewExternalCodeLabel((LPVOID)CallbackOnCollectedDelegateHelper), 0);
+-
+- // restore registers
+- pcpusl->X86EmitPopReg(kECXthread);
+- pcpusl->X86EmitPopReg(kEAXentryThunk);
+- }
+-#endif
+-
+ // save the thread pointer
+ pcpusl->X86EmitPushReg(kECXthread);
+
+@@ -1217,30 +1170,6 @@ VOID UMEntryThunk::FreeUMEntryThunk(UMEntryThunk* p)
+ }
+ CONTRACTL_END;
+
+-#ifdef MDA_SUPPORTED
+- MdaCallbackOnCollectedDelegate* pProbe = MDA_GET_ASSISTANT(CallbackOnCollectedDelegate);
+- if (pProbe)
+- {
+- if (p->GetObjectHandle())
+- {
+- DestroyLongWeakHandle(p->GetObjectHandle());
+- p->m_pObjectHandle = NULL;
+-
+- // We are intentionally not reseting m_pManagedTarget here so that
+- // it is available for diagnostics of call on collected delegate crashes.
+- }
+- else
+- {
+- p->m_pManagedTarget = NULL;
+- }
+-
+- // Add this to the array of delegates to be cleaned up.
+- pProbe->AddToList(p);
+-
+- return;
+- }
+-#endif
+-
+ p->Terminate();
+ }
+
+diff --git a/src/vm/dllimportcallback.h b/src/vm/dllimportcallback.h
+index d820a76..555b737 100644
+--- a/src/vm/dllimportcallback.h
++++ b/src/vm/dllimportcallback.h
+@@ -424,13 +424,7 @@ public:
+ MODE_ANY;
+ SUPPORTS_DAC;
+ PRECONDITION(m_state == kRunTimeInited || m_state == kLoadTimeInited);
+-#ifdef MDA_SUPPORTED
+- // We can return NULL here if the CollectedDelegate probe is on because
+- // a collected delegate will have set this field to NULL.
+- POSTCONDITION(g_pDebugInterface->ThisIsHelperThread() || MDA_GET_ASSISTANT(CallbackOnCollectedDelegate) || CheckPointer(RETVAL));
+-#else
+ POSTCONDITION(CheckPointer(RETVAL));
+-#endif
+ }
+ CONTRACT_END;
+
+@@ -503,15 +497,6 @@ public:
+
+ static UMEntryThunk* Decode(LPVOID pCallback);
+
+-#ifdef MDA_SUPPORTED
+- BOOL IsCollected() const
+- {
+- LIMITED_METHOD_CONTRACT;
+- _ASSERTE(m_pMD != NULL && m_pMD->IsEEImpl());
+- return m_pObjectHandle == NULL;
+- }
+-#endif
+-
+ static VOID __fastcall ReportViolation(UMEntryThunk* p);
+
+ private:
+@@ -613,8 +598,4 @@ EXTERN_C void UMThunkStub(void);
+ void STDCALL LogUMTransition(UMEntryThunk* thunk);
+ #endif
+
+-#ifdef MDA_SUPPORTED
+-EXTERN_C void __fastcall CallbackOnCollectedDelegateHelper(UMEntryThunk *pEntryThunk);
+-#endif // MDA_SUPPORTED
+-
+ #endif //__dllimportcallback_h__
+--
+2.7.4
+
diff --git a/packaging/0004-LoaderHeap-remove-LHF_ZEROINIT-option.patch b/packaging/0004-LoaderHeap-remove-LHF_ZEROINIT-option.patch
new file mode 100644
index 0000000000..f104f98e8b
--- /dev/null
+++ b/packaging/0004-LoaderHeap-remove-LHF_ZEROINIT-option.patch
@@ -0,0 +1,178 @@
+From 81116227de9850ea4ef4a3aefa911bdea6127d07 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Fri, 12 Jan 2018 19:11:05 +0300
+Subject: [PATCH 04/47] LoaderHeap: remove LHF_ZEROINIT option.
+
+This option was used for UMEntryThunkCode::Poison. Now we use own free list
+to store freed thunks and don't return allocated memory to the LoaderHeap.
+So reused thunks are always uninitialized.
+---
+ src/inc/loaderheap.h | 17 +++++------------
+ src/utilcode/loaderheap.cpp | 19 ++++---------------
+ src/vm/dllimportcallback.cpp | 1 -
+ src/vm/loaderallocator.cpp | 3 +--
+ 4 files changed, 10 insertions(+), 30 deletions(-)
+
+diff --git a/src/inc/loaderheap.h b/src/inc/loaderheap.h
+index 4333505..5bdbe8c 100644
+--- a/src/inc/loaderheap.h
++++ b/src/inc/loaderheap.h
+@@ -288,8 +288,7 @@ protected:
+ SIZE_T dwReservedRegionSize,
+ size_t *pPrivatePerfCounter_LoaderBytes = NULL,
+ RangeList *pRangeList = NULL,
+- BOOL fMakeExecutable = FALSE,
+- BOOL fZeroInit = TRUE);
++ BOOL fMakeExecutable = FALSE);
+
+ ~UnlockedLoaderHeap();
+ #endif
+@@ -400,8 +399,6 @@ public:
+ }
+
+ BOOL IsExecutable();
+- BOOL IsZeroInit();
+-
+
+ public:
+ #ifdef _DEBUG
+@@ -446,16 +443,14 @@ public:
+ DWORD dwCommitBlockSize,
+ size_t *pPrivatePerfCounter_LoaderBytes = NULL,
+ RangeList *pRangeList = NULL,
+- BOOL fMakeExecutable = FALSE,
+- BOOL fZeroInit = TRUE
++ BOOL fMakeExecutable = FALSE
+ )
+ : UnlockedLoaderHeap(dwReserveBlockSize,
+ dwCommitBlockSize,
+ NULL, 0,
+ pPrivatePerfCounter_LoaderBytes,
+ pRangeList,
+- fMakeExecutable,
+- fZeroInit)
++ fMakeExecutable)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_CriticalSection = NULL;
+@@ -470,8 +465,7 @@ public:
+ SIZE_T dwReservedRegionSize,
+ size_t *pPrivatePerfCounter_LoaderBytes = NULL,
+ RangeList *pRangeList = NULL,
+- BOOL fMakeExecutable = FALSE,
+- BOOL fZeroInit = TRUE
++ BOOL fMakeExecutable = FALSE
+ )
+ : UnlockedLoaderHeap(dwReserveBlockSize,
+ dwCommitBlockSize,
+@@ -479,8 +473,7 @@ public:
+ dwReservedRegionSize,
+ pPrivatePerfCounter_LoaderBytes,
+ pRangeList,
+- fMakeExecutable,
+- fZeroInit)
++ fMakeExecutable)
+ {
+ WRAPPER_NO_CONTRACT;
+ m_CriticalSection = NULL;
+diff --git a/src/utilcode/loaderheap.cpp b/src/utilcode/loaderheap.cpp
+index 21aa150..4033c86 100644
+--- a/src/utilcode/loaderheap.cpp
++++ b/src/utilcode/loaderheap.cpp
+@@ -11,7 +11,6 @@
+ #include "eventtracebase.h"
+
+ #define LHF_EXECUTABLE 0x1
+-#define LHF_ZEROINIT 0x2
+
+ #ifndef DACCESS_COMPILE
+
+@@ -906,8 +905,7 @@ UnlockedLoaderHeap::UnlockedLoaderHeap(DWORD dwReserveBlockSize,
+ SIZE_T dwReservedRegionSize,
+ size_t *pPrivatePerfCounter_LoaderBytes,
+ RangeList *pRangeList,
+- BOOL fMakeExecutable,
+- BOOL fZeroInit)
++ BOOL fMakeExecutable)
+ {
+ CONTRACTL
+ {
+@@ -946,9 +944,6 @@ UnlockedLoaderHeap::UnlockedLoaderHeap(DWORD dwReserveBlockSize,
+ m_Options = 0;
+ if (fMakeExecutable)
+ m_Options |= LHF_EXECUTABLE;
+- if (fZeroInit)
+- m_Options |= LHF_ZEROINIT;
+-
+ m_pFirstFreeBlock = NULL;
+
+ if (dwReservedRegionAddress != NULL && dwReservedRegionSize > 0)
+@@ -1356,7 +1351,7 @@ again:
+ // Don't fill the memory we allocated - it is assumed to be zeroed - fill the memory after it
+ memset(pAllocatedBytes + dwRequestedSize, 0xEE, LOADER_HEAP_DEBUG_BOUNDARY);
+ #endif
+- if ((dwRequestedSize > 0) && (m_Options & LHF_ZEROINIT))
++ if (dwRequestedSize > 0)
+ {
+ _ASSERTE_MSG(pAllocatedBytes[0] == 0 && memcmp(pAllocatedBytes, pAllocatedBytes + 1, dwRequestedSize - 1) == 0,
+ "LoaderHeap must return zero-initialized memory");
+@@ -1534,8 +1529,7 @@ void UnlockedLoaderHeap::UnlockedBackoutMem(void *pMem,
+ {
+ // Cool. This was the last block allocated. We can just undo the allocation instead
+ // of going to the freelist.
+- if (m_Options & LHF_ZEROINIT)
+- memset(pMem, 0x00, dwSize); // Fill freed region with 0
++ memset(pMem, 0x00, dwSize); // Fill freed region with 0
+ m_pAllocPtr = (BYTE*)pMem;
+ }
+ else
+@@ -1653,7 +1647,7 @@ void *UnlockedLoaderHeap::UnlockedAllocAlignedMem_NoThrow(size_t dwRequestedSiz
+ memset(pAllocatedBytes + dwRequestedSize, 0xee, LOADER_HEAP_DEBUG_BOUNDARY);
+ #endif
+
+- if ((dwRequestedSize != 0) && (m_Options & LHF_ZEROINIT))
++ if (dwRequestedSize != 0)
+ {
+ _ASSERTE_MSG(pAllocatedBytes[0] == 0 && memcmp(pAllocatedBytes, pAllocatedBytes + 1, dwRequestedSize - 1) == 0,
+ "LoaderHeap must return zero-initialized memory");
+@@ -1778,11 +1772,6 @@ BOOL UnlockedLoaderHeap::IsExecutable()
+ return (m_Options & LHF_EXECUTABLE);
+ }
+
+-BOOL UnlockedLoaderHeap::IsZeroInit()
+-{
+- return (m_Options & LHF_ZEROINIT);
+-}
+-
+ #ifdef DACCESS_COMPILE
+
+ void UnlockedLoaderHeap::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
+diff --git a/src/vm/dllimportcallback.cpp b/src/vm/dllimportcallback.cpp
+index 8623d46..2becba5 100644
+--- a/src/vm/dllimportcallback.cpp
++++ b/src/vm/dllimportcallback.cpp
+@@ -1153,7 +1153,6 @@ void UMEntryThunk::Terminate()
+ }
+ CONTRACTL_END;
+
+- _ASSERTE(!SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap()->IsZeroInit());
+ m_code.Poison();
+
+ s_thunkFreeList.AddToList(this);
+diff --git a/src/vm/loaderallocator.cpp b/src/vm/loaderallocator.cpp
+index 5a3f8f5..2264dc1 100644
+--- a/src/vm/loaderallocator.cpp
++++ b/src/vm/loaderallocator.cpp
+@@ -1005,8 +1005,7 @@ void LoaderAllocator::Init(BaseDomain *pDomain, BYTE *pExecutableHeapMemory)
+ dwExecutableHeapReserveSize,
+ LOADERHEAP_PROFILE_COUNTER,
+ NULL,
+- TRUE /* Make heap executable */,
+- FALSE /* Disable zero-initialization (needed by UMEntryThunkCode::Poison) */
++ TRUE /* Make heap executable */
+ );
+ initReservedMem += dwExecutableHeapReserveSize;
+ }
+--
+2.7.4
+
diff --git a/packaging/0019-JIT-Fix-value-type-box-optimization.patch b/packaging/0019-JIT-Fix-value-type-box-optimization.patch
new file mode 100644
index 0000000000..db31e3ff8f
--- /dev/null
+++ b/packaging/0019-JIT-Fix-value-type-box-optimization.patch
@@ -0,0 +1,1215 @@
+From dc2e9cc4c21e0cf565dbb1b4d4f029157779ddcc Mon Sep 17 00:00:00 2001
+From: Andy Ayers <andya@microsoft.com>
+Date: Sat, 22 Jul 2017 09:16:29 -0700
+Subject: [PATCH 19/47] JIT: Fix value type box optimization
+
+Boxing a value type produces a non-null result. If the result of the box is
+only used to feed a compare against null, the jit tries to optimize the box
+away entirely since the result of the comparison is known. Such idiomatic
+expressions arise fairly often in generics instantiated over value types.
+
+In the current implementation the box expands into two parts. The first is
+an upstream statement to allocate a boxed object and assign a reference to
+the boxed object to a local var known as the "box temp". The second is an
+expression tree whose value is the box temp that also contains an an
+encapsulated copy from the value being boxed to the payload section of the
+boxed object. The box node also contains a pointer back to the first
+statement (more on this later).
+
+In the examples being discussed here this second tree is a child of a compare
+node whose other child is a null pointer. When the optimization fires, the
+upstream allocation statement is located via the pointer in the box node and
+removed, and the entire compare is replaced with a constant 0 or 1 as
+appropriate. Unfortunately the encapsulated copy in the box subtree may
+include side effects that should be preserved, and so this transformation is
+unsafe.
+
+Note that the copy subtree as a whole will always contain side effects, since
+the copy is storing values into the heap, and that copy now will not happen.
+But the side effects that happen when producing the value to box must remain.
+
+In the initial example from #12949 the side effects in question were
+introduced by the jit's optimizer to capure a CSE definition. #13016 gives
+several other examples where the side effects are present in the initial user
+code. For instance the value being boxed might come from an array, in which
+case the encapsulated copy in the box expression tree would contain the array
+null check and bounds check. So removing the entire tree can alter behavior.
+
+This fix attempts to carefully preserve the important side effects by
+reworking how a box is imported. The copy is now moved out from under the box
+into a second upstream statement. The box itself is then just a trivial
+side-effect-free reference to the box temp. To ensure proper ordering of side
+effects the jit spills the evaluation stack before appending the copy
+statement.
+
+When the optimization fires the jit removes the upstream heap allocation
+as before, as well as the now-trivial compare tree. It analyzes the source
+side of the upstream copy. If it is side effect free, the copy is removed
+entirely. If not, the jit modifies the copy into a minimal load of the
+boxed value, and this load should reproduce the necessary side effects.
+
+The optimization is only performed when the tree shape of the copy matches
+expected patterns.
+
+There are some expected cases where the tree won't match, for instance if the
+optimization is invoked while the jit is inlining. Because this optimization
+runs at several points the jit can catch these cases once inlining completes.
+There is one case that is not handled that could be -- if the assignment part
+of the copy is itself a subtree of a comma. This doesn't happen often.
+
+The optimization is now also extended to handle the case where the comparision
+operation is `cgt.un`. This doesn't catch any new cases but causes the
+optimization to happen earlier, typically during importation, which should
+reduce jit time slightly.
+
+Generally the split of the box into two upstream statements reduces code size,
+especially when the box expression is incorporated into a larger tree -- for
+example a call. However in some cases where the value being boxed comes from
+an array, preserving the array bounds check now causes loop cloning to kick
+in and increase code size. Hence the overall size impact on the jit-diff set is
+essentially zero.
+
+Added a number of new test cases showing the variety of situations that must
+be handled and the need to spill before appending the copy statement.
+
+Fixes #12949.
+---
+ src/jit/gentree.cpp | 167 +++++++++++++++++++--
+ src/jit/gentree.h | 13 +-
+ src/jit/importer.cpp | 15 +-
+ .../JitBlue/GitHub_12949/GitHub_12949_1.cs | 51 +++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_1.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_2.cs | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_2.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_3.cs | 41 +++++
+ .../JitBlue/GitHub_12949/GitHub_12949_3.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_4.cs | 41 +++++
+ .../JitBlue/GitHub_12949/GitHub_12949_4.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_5.cs | 46 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_5.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_6.cs | 60 ++++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_6.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_7.cs | 58 +++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_7.csproj | 43 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_8.cs | 42 ++++++
+ .../JitBlue/GitHub_12949/GitHub_12949_8.csproj | 43 ++++++
+ 19 files changed, 902 insertions(+), 19 deletions(-)
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.csproj
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.csproj
+
+diff --git a/src/jit/gentree.cpp b/src/jit/gentree.cpp
+index 25e9e10..3736f7a 100644
+--- a/src/jit/gentree.cpp
++++ b/src/jit/gentree.cpp
+@@ -8050,7 +8050,8 @@ GenTreePtr Compiler::gtCloneExpr(
+
+ case GT_BOX:
+ copy = new (this, GT_BOX)
+- GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue);
++ GenTreeBox(tree->TypeGet(), tree->gtOp.gtOp1, tree->gtBox.gtAsgStmtWhenInlinedBoxValue,
++ tree->gtBox.gtCopyStmtWhenInlinedBoxValue);
+ break;
+
+ case GT_INTRINSIC:
+@@ -12459,32 +12460,168 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
+
+ switch (oper)
+ {
+-
+ case GT_EQ:
+ case GT_NE:
++ case GT_GT:
+ // Optimize boxed value classes; these are always false. This IL is
+ // generated when a generic value is tested against null:
+ // <T> ... foo(T x) { ... if ((object)x == null) ...
+ if (val == 0 && op->IsBoxedValue())
+ {
+- // Change the assignment node so we don't generate any code for it.
++ // The tree under the box must be side effect free
++ // since we drop it if we optimize the compare.
++ assert(!gtTreeHasSideEffects(op->gtBox.gtOp.gtOp1, GTF_SIDE_EFFECT));
+
++ // grab related parts for the optimization
+ GenTreePtr asgStmt = op->gtBox.gtAsgStmtWhenInlinedBoxValue;
+ assert(asgStmt->gtOper == GT_STMT);
+- GenTreePtr asg = asgStmt->gtStmt.gtStmtExpr;
+- assert(asg->gtOper == GT_ASG);
++ GenTreePtr copyStmt = op->gtBox.gtCopyStmtWhenInlinedBoxValue;
++ assert(copyStmt->gtOper == GT_STMT);
+ #ifdef DEBUG
+ if (verbose)
+ {
+- printf("Bashing ");
+- printTreeID(asg);
+- printf(" to NOP as part of dead box operation\n");
++ printf("\nAttempting to optimize BOX(valueType) %s null\n", GenTree::OpName(oper));
+ gtDispTree(tree);
++ printf("\nWith assign\n");
++ gtDispTree(asgStmt);
++ printf("\nAnd copy\n");
++ gtDispTree(copyStmt);
+ }
+ #endif
++
++ // We don't expect GT_GT with signed compares, and we
++ // can't predict the result if we do see it, since the
++ // boxed object addr could have its high bit set.
++ if ((oper == GT_GT) && !tree->IsUnsigned())
++ {
++ JITDUMP(" bailing; unexpected signed compare via GT_GT\n");
++ goto FAIL;
++ }
++
++ // If we don't recognize the form of the assign, bail.
++ GenTreePtr asg = asgStmt->gtStmt.gtStmtExpr;
++ if (asg->gtOper != GT_ASG)
++ {
++ JITDUMP(" bailing; unexpected assignment op %s\n", GenTree::OpName(asg->gtOper));
++ goto FAIL;
++ }
++
++ // If we don't recognize the form of the copy, bail.
++ GenTree* copy = copyStmt->gtStmt.gtStmtExpr;
++ if (copy->gtOper != GT_ASG)
++ {
++ // GT_RET_EXPR is a tolerable temporary failure.
++ // The jit will revisit this optimization after
++ // inlining is done.
++ if (copy->gtOper == GT_RET_EXPR)
++ {
++ JITDUMP(" bailing; must wait for replacement of copy %s\n", GenTree::OpName(copy->gtOper));
++ }
++ else
++ {
++ // Anything else is a missed case we should
++ // figure out how to handle. One known case
++ // is GT_COMMAs enclosing the GT_ASG we are
++ // looking for.
++ JITDUMP(" bailing; unexpected copy op %s\n", GenTree::OpName(copy->gtOper));
++ }
++ goto FAIL;
++ }
++
++ // If the copy is a struct copy, make sure we know how to isolate
++ // any source side effects.
++ GenTreePtr copySrc = copy->gtOp.gtOp2;
++
++ // If the copy source is from a pending inline, wait for it to resolve.
++ if (copySrc->gtOper == GT_RET_EXPR)
++ {
++ JITDUMP(" bailing; must wait for replacement of copy source %s\n",
++ GenTree::OpName(copySrc->gtOper));
++ goto FAIL;
++ }
++
++ bool hasSrcSideEffect = false;
++ bool isStructCopy = false;
++
++ if (gtTreeHasSideEffects(copySrc, GTF_SIDE_EFFECT))
++ {
++ hasSrcSideEffect = true;
++
++ if (copySrc->gtType == TYP_STRUCT)
++ {
++ isStructCopy = true;
++
++ if ((copySrc->gtOper != GT_OBJ) && (copySrc->gtOper != GT_IND) && (copySrc->gtOper != GT_FIELD))
++ {
++ // We don't know how to handle other cases, yet.
++ JITDUMP(" bailing; unexpected copy source struct op with side effect %s\n",
++ GenTree::OpName(copySrc->gtOper));
++ goto FAIL;
++ }
++ }
++ }
++
++ // Proceed with the optimization
++ //
++ // Change the assignment expression to a NOP.
++ JITDUMP("\nBashing NEWOBJ [%06u] to NOP\n", dspTreeID(asg));
+ asg->gtBashToNOP();
+
+- op = gtNewIconNode(oper == GT_NE);
++ // Change the copy expression so it preserves key
++ // source side effects.
++ JITDUMP("\nBashing COPY [%06u]", dspTreeID(copy));
++
++ if (!hasSrcSideEffect)
++ {
++ // If there were no copy source side effects just bash
++ // the copy to a NOP.
++ copy->gtBashToNOP();
++ JITDUMP(" to NOP\n");
++ }
++ else if (!isStructCopy)
++ {
++ // For scalar types, go ahead and produce the
++ // value as the copy is fairly cheap and likely
++ // the optimizer can trim things down to just the
++ // minimal side effect parts.
++ copyStmt->gtStmt.gtStmtExpr = copySrc;
++ JITDUMP(" to scalar read via [%06u]\n", dspTreeID(copySrc));
++ }
++ else
++ {
++ // For struct types read the first byte of the
++ // source struct; there's no need to read the
++ // entire thing, and no place to put it.
++ assert(copySrc->gtOper == GT_OBJ || copySrc->gtOper == GT_IND || copySrc->gtOper == GT_FIELD);
++ copySrc->ChangeOper(GT_IND);
++ copySrc->gtType = TYP_BYTE;
++ copyStmt->gtStmt.gtStmtExpr = copySrc;
++ JITDUMP(" to read first byte of struct via modified [%06u]\n", dspTreeID(copySrc));
++ }
++
++ // Set up the result of the compare.
++ int compareResult = 0;
++ if (oper == GT_GT)
++ {
++ // GT_GT(null, box) == false
++ // GT_GT(box, null) == true
++ compareResult = (op1 == op);
++ }
++ else if (oper == GT_EQ)
++ {
++ // GT_EQ(box, null) == false
++ // GT_EQ(null, box) == false
++ compareResult = 0;
++ }
++ else
++ {
++ assert(oper == GT_NE);
++ // GT_NE(box, null) == true
++ // GT_NE(null, box) == true
++ compareResult = 1;
++ }
++ op = gtNewIconNode(compareResult);
++
+ if (fgGlobalMorph)
+ {
+ if (!fgIsInlining())
+@@ -12497,9 +12634,15 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
+ op->gtNext = tree->gtNext;
+ op->gtPrev = tree->gtPrev;
+ }
+- fgSetStmtSeq(asgStmt);
++
++ if (fgStmtListThreaded)
++ {
++ fgSetStmtSeq(asgStmt);
++ fgSetStmtSeq(copyStmt);
++ }
+ return op;
+ }
++
+ break;
+
+ case GT_ADD:
+@@ -12667,7 +12810,9 @@ GenTreePtr Compiler::gtFoldExprSpecial(GenTreePtr tree)
+ break;
+ }
+
+- /* The node is not foldable */
++/* The node is not foldable */
++
++FAIL:
+
+ return tree;
+
+diff --git a/src/jit/gentree.h b/src/jit/gentree.h
+index 1833a39..41f65f0 100644
+--- a/src/jit/gentree.h
++++ b/src/jit/gentree.h
+@@ -2848,9 +2848,16 @@ struct GenTreeBox : public GenTreeUnOp
+ // This is the statement that contains the assignment tree when the node is an inlined GT_BOX on a value
+ // type
+ GenTreePtr gtAsgStmtWhenInlinedBoxValue;
+-
+- GenTreeBox(var_types type, GenTreePtr boxOp, GenTreePtr asgStmtWhenInlinedBoxValue)
+- : GenTreeUnOp(GT_BOX, type, boxOp), gtAsgStmtWhenInlinedBoxValue(asgStmtWhenInlinedBoxValue)
++ // And this is the statement that copies from the value being boxed to the box payload
++ GenTreePtr gtCopyStmtWhenInlinedBoxValue;
++
++ GenTreeBox(var_types type,
++ GenTreePtr boxOp,
++ GenTreePtr asgStmtWhenInlinedBoxValue,
++ GenTreePtr copyStmtWhenInlinedBoxValue)
++ : GenTreeUnOp(GT_BOX, type, boxOp)
++ , gtAsgStmtWhenInlinedBoxValue(asgStmtWhenInlinedBoxValue)
++ , gtCopyStmtWhenInlinedBoxValue(copyStmtWhenInlinedBoxValue)
+ {
+ }
+ #if DEBUGGABLE_GENTREE
+diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
+index 62f1c13..b4ee1d0 100644
+--- a/src/jit/importer.cpp
++++ b/src/jit/importer.cpp
+@@ -5225,7 +5225,7 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
+ gtNewArgList(op2));
+ }
+
+- /* Remember that this basic block contains 'new' of an array */
++ /* Remember that this basic block contains 'new' of an object */
+ compCurBB->bbFlags |= BBF_HAS_NEWOBJ;
+
+ GenTreePtr asg = gtNewTempAssign(impBoxTemp, op1);
+@@ -5267,11 +5267,16 @@ void Compiler::impImportAndPushBox(CORINFO_RESOLVED_TOKEN* pResolvedToken)
+ op1 = gtNewAssignNode(gtNewOperNode(GT_IND, lclTyp, op1), exprToBox);
+ }
+
+- op2 = gtNewLclvNode(impBoxTemp, TYP_REF);
+- op1 = gtNewOperNode(GT_COMMA, TYP_REF, op1, op2);
++ // Spill eval stack to flush out any pending side effects.
++ impSpillSideEffects(true, (unsigned)CHECK_SPILL_ALL DEBUGARG("impImportAndPushBox"));
+
+- // Record that this is a "box" node.
+- op1 = new (this, GT_BOX) GenTreeBox(TYP_REF, op1, asgStmt);
++ // Set up this copy as a second assignment.
++ GenTreePtr copyStmt = impAppendTree(op1, (unsigned)CHECK_SPILL_NONE, impCurStmtOffs);
++
++ op1 = gtNewLclvNode(impBoxTemp, TYP_REF);
++
++ // Record that this is a "box" node and keep track of the matching parts.
++ op1 = new (this, GT_BOX) GenTreeBox(TYP_REF, op1, asgStmt, copyStmt);
+
+ // If it is a value class, mark the "box" node. We can use this information
+ // to optimise several cases:
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.cs
+new file mode 100644
+index 0000000..c436802
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.cs
+@@ -0,0 +1,51 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++// See the LICENSE file in the project root for more information.
++
++using System;
++
++public struct S<K>
++{
++ public int x;
++ public int y;
++ public K val;
++}
++
++public class X<K,V>
++{
++ public X(K k)
++ {
++ a = new S<K>[2];
++ a[1].val = k;
++ a[1].x = 3;
++ a[1].y = 4;
++ }
++
++ public void Assert(bool b)
++ {
++ if (!b) throw new Exception("bad!");
++ }
++
++ public int Test()
++ {
++ int r = 0;
++ for (int i = 0; i < a.Length; i++)
++ {
++ Assert(a[i].val != null);
++ r += a[i].val.GetHashCode();
++ }
++ return r;
++ }
++
++ S<K>[] a;
++}
++
++class B
++{
++ public static int Main()
++ {
++ var a = new X<int, string>(11);
++ int z = a.Test();
++ return (z == 11 ? 100 : 0);
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_1.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.cs
+new file mode 100644
+index 0000000..bbdc67d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.cs
+@@ -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.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Runtime.CompilerServices;
++
++public class X<K>
++{
++ public X(K k1)
++ {
++ k = k1;
++ }
++
++ [MethodImpl(MethodImplOptions.NoInlining)]
++ public K Get()
++ {
++ Console.WriteLine("Get called");
++ count++;
++ return k;
++ }
++
++ public bool Test()
++ {
++ bool x = Get() != null;
++ bool y = (count == 1);
++ return x && y;
++ }
++
++ K k;
++ int count;
++}
++
++class B
++{
++ public static int Main()
++ {
++ var a = new X<int>(11);
++ bool result = a.Test();
++ Console.WriteLine("Passed: {0}", result);
++ return result ? 100 : 0;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_2.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.cs
+new file mode 100644
+index 0000000..b7247c1
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.cs
+@@ -0,0 +1,41 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Runtime.CompilerServices;
++
++public class X<K>
++{
++ public X(K k1)
++ {
++ k = k1;
++ }
++
++ [MethodImpl(MethodImplOptions.NoInlining)]
++ public static bool Test(X<K> a)
++ {
++ return (a.k != null);
++ }
++
++ public K k;
++}
++
++class B
++{
++ public static int Main()
++ {
++ X<int> a = null;
++ bool result = false;
++ try
++ {
++ X<int>.Test(a);
++ }
++ catch (Exception)
++ {
++ result = true;
++ }
++ Console.WriteLine("Passed: {0}", result);
++ return result ? 100 : 0;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_3.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.cs
+new file mode 100644
+index 0000000..126cdb9
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.cs
+@@ -0,0 +1,41 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Runtime.CompilerServices;
++
++public class X<K>
++{
++ public X(K k1)
++ {
++ k = k1;
++ }
++
++ [MethodImpl(MethodImplOptions.NoInlining)]
++ public static bool Test(X<K> a)
++ {
++ return (a.k == null);
++ }
++
++ public K k;
++}
++
++class B
++{
++ public static int Main()
++ {
++ X<int> a = null;
++ bool result = false;
++ try
++ {
++ X<int>.Test(a);
++ }
++ catch (Exception)
++ {
++ result = true;
++ }
++ Console.WriteLine("Passed: {0}", result);
++ return result ? 100 : 0;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_4.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.cs
+new file mode 100644
+index 0000000..95a8945
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.cs
+@@ -0,0 +1,46 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Runtime.CompilerServices;
++
++struct R
++{
++ int a;
++}
++
++public class X<K>
++{
++ public X(K k1)
++ {
++ k = k1;
++ }
++
++ [MethodImpl(MethodImplOptions.NoInlining)]
++ public static bool Test(X<K> a)
++ {
++ return (a.k != null);
++ }
++
++ public K k;
++}
++
++class B
++{
++ public static int Main()
++ {
++ X<R> a = null;
++ bool result = false;
++ try
++ {
++ X<R>.Test(a);
++ }
++ catch (Exception)
++ {
++ result = true;
++ }
++ Console.WriteLine("Passed: {0}", result);
++ return result ? 100 : 0;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_5.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.cs
+new file mode 100644
+index 0000000..1371dbb
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.cs
+@@ -0,0 +1,60 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Runtime.CompilerServices;
++
++public interface IGet
++{
++ int Get();
++}
++
++public struct R : IGet
++{
++ public double d;
++ public int a;
++
++ public int Get() { return a; }
++}
++
++public class X<K> where K: IGet
++{
++ public X(K r)
++ {
++ a = new K[2];
++ a[0] = r;
++ }
++
++ public void Assert(bool b)
++ {
++ if (!b) throw new Exception("bad!");
++ }
++
++ public int Test()
++ {
++ int r = 0;
++ for (int i = 0; i < a.Length; i++)
++ {
++ Assert(a[i] != null);
++ r += a[i].Get();
++ }
++ return r;
++ }
++
++ K[] a;
++}
++
++class B
++{
++ public static int Main()
++ {
++ var r = new R();
++ r.a = 3;
++ var a = new X<R>(r);
++ int result = a.Test();
++ bool passed = result == 3;
++ Console.WriteLine("Passed: {0}", passed);
++ return passed ? 100 : 0;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_6.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.cs
+new file mode 100644
+index 0000000..3ba6cd2
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.cs
+@@ -0,0 +1,58 @@
++// Licensed to the .NET Foundation under one or more agreements.
++// The .NET Foundation licenses this file to you under the MIT license.
++// See the LICENSE file in the project root for more information.
++
++using System;
++
++public struct V
++{
++ public V(int x)
++ {
++ Token = x;
++ }
++
++ public int Token;
++}
++
++class M
++{
++ static int F(int x, object a)
++ {
++ int result = 0;
++
++ if (a is V)
++ {
++ int token = ((V)a).Token;
++ Console.WriteLine("F: Token is {0}", token);
++ result = x + token;
++ }
++
++ return result;
++ }
++
++ static int G(object a, int x)
++ {
++ return F(x, a);
++ }
++
++ static int Trouble(ref V v)
++ {
++ Console.WriteLine("T: Token is {0}", v.Token);
++ int result = v.Token;
++ v.Token++;
++ return result;
++ }
++
++ public static int Main()
++ {
++ // Ensure we get right order of side effects from boxes
++ // now that we are splitting them into multiple statments.
++ V v1 = new V(11);
++ int result1 = F(Trouble(ref v1), v1);
++ V v2 = new V(11);
++ int result2 = G(v2, Trouble(ref v2));
++ Console.WriteLine("Result1 = {0}; Result2 = {1}", result1, result2);
++ return result1 + result2 + 55;
++ }
++}
++
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_7.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.cs b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.cs
+new file mode 100644
+index 0000000..d5daa43
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.cs
+@@ -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.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Runtime.CompilerServices;
++using System.Numerics;
++
++public class X<K>
++{
++ public X(K k1)
++ {
++ k = k1;
++ }
++
++ [MethodImpl(MethodImplOptions.NoInlining)]
++ public static bool Test(X<K> a)
++ {
++ return (a.k != null);
++ }
++
++ public K k;
++}
++
++class B
++{
++ public static int Main()
++ {
++ X<Vector3> a = null;
++ bool result = false;
++ try
++ {
++ X<Vector3>.Test(a);
++ }
++ catch (Exception)
++ {
++ result = true;
++ }
++ Console.WriteLine("Passed: {0}", result);
++ return result ? 100 : 0;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.csproj
+new file mode 100644
+index 0000000..5cd573d
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_12949/GitHub_12949_8.csproj
+@@ -0,0 +1,43 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{7B521917-193E-48BB-86C6-FE013F3DFF35}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
++ </PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
++ </PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="$(MSBuildProjectName).cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' ">
++ </PropertyGroup>
++</Project>
+--
+2.7.4
+
diff --git a/packaging/0020-JIT-port-fix-to-defer-removing-statements-during-opt.patch b/packaging/0020-JIT-port-fix-to-defer-removing-statements-during-opt.patch
new file mode 100644
index 0000000000..db0d267dc2
--- /dev/null
+++ b/packaging/0020-JIT-port-fix-to-defer-removing-statements-during-opt.patch
@@ -0,0 +1,132 @@
+From 240ffdf43611fda5d22672f56be5760803d1a011 Mon Sep 17 00:00:00 2001
+From: Andy Ayers <andya@microsoft.com>
+Date: Mon, 4 Dec 2017 11:22:26 -0800
+Subject: [PATCH 20/47] JIT: port fix to defer removing statements during opt
+ CSE to release/2.0.0
+
+Port of #15323.
+Related issue #15319.
+---
+ src/jit/morph.cpp | 8 +++-
+ .../JitBlue/GitHub_15319/GitHub_15319.cs | 44 ++++++++++++++++++++++
+ .../JitBlue/GitHub_15319/GitHub_15319.csproj | 38 +++++++++++++++++++
+ 3 files changed, 89 insertions(+), 1 deletion(-)
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.cs
+ create mode 100644 tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.csproj
+
+diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
+index 79b3fef..993ce53 100644
+--- a/src/jit/morph.cpp
++++ b/src/jit/morph.cpp
+@@ -15695,7 +15695,13 @@ bool Compiler::fgMorphBlockStmt(BasicBlock* block, GenTreeStmt* stmt DEBUGARG(co
+ }
+
+ // Can the entire tree be removed?
+- bool removedStmt = fgCheckRemoveStmt(block, stmt);
++ bool removedStmt = false;
++
++ // Defer removing statements during CSE so we don't inadvertently remove any CSE defs.
++ if (!optValnumCSE_phase)
++ {
++ removedStmt = fgCheckRemoveStmt(block, stmt);
++ }
+
+ // Or this is the last statement of a conditional branch that was just folded?
+ if (!removedStmt && (stmt->getNextStmt() == nullptr) && !fgRemoveRestOfBlock)
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.cs b/tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.cs
+new file mode 100644
+index 0000000..af7419f
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.cs
+@@ -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.
++// See the LICENSE file in the project root for more information.
++
++using System;
++using System.Linq;
++
++// Bug where interacting CSEs of N - Old.Length and Old.Length
++// were not handled properly in optCSE
++
++class P
++{
++ private static int Main(string[] args)
++ {
++ var ar = new double[]
++ {
++ 100
++ };
++
++ FillTo1(ref ar, 5);
++ Console.WriteLine(string.Join(",", ar.Select(a => a.ToString()).ToArray()));
++ return (int)ar[4];
++ }
++
++ public static void FillTo1(ref double[] dd, int N)
++ {
++ if (dd.Length >= N)
++ return;
++
++ double[] Old = dd;
++ double d = double.NaN;
++ if (Old.Length > 0)
++ d = Old[0];
++
++ dd = new double[N];
++
++ for (int i = 0; i < Old.Length; i++)
++ {
++ dd[N - Old.Length + i] = Old[i];
++ }
++ for (int i = 0; i < N - Old.Length; i++)
++ dd[i] = d;
++ }
++}
+diff --git a/tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.csproj b/tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.csproj
+new file mode 100644
+index 0000000..c3a87c1
+--- /dev/null
++++ b/tests/src/JIT/Regression/JitBlue/GitHub_15319/GitHub_15319.csproj
+@@ -0,0 +1,38 @@
++<?xml version="1.0" encoding="utf-8"?>
++<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
++ <PropertyGroup>
++ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
++ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
++ <AssemblyName>$(MSBuildProjectName)</AssemblyName>
++ <SchemaVersion>2.0</SchemaVersion>
++ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
++ <OutputType>Exe</OutputType>
++ <AppDesignerFolder>Properties</AppDesignerFolder>
++ <FileAlignment>512</FileAlignment>
++ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
++ <ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\11.0\UITestExtensionPackages</ReferencePath>
++ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
++ <NuGetPackageImportStamp>7a9bfb7d</NuGetPackageImportStamp>
++ </PropertyGroup>
++ <!-- Default configurations to help VS understand the configurations -->
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
++ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "></PropertyGroup>
++ <ItemGroup>
++ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
++ <Visible>False</Visible>
++ </CodeAnalysisDependentAssemblyPaths>
++ </ItemGroup>
++ <PropertyGroup>
++ <DebugType></DebugType>
++ <Optimize>True</Optimize>
++ </PropertyGroup>
++ <ItemGroup>
++ <Compile Include="GitHub_15319.cs" />
++ </ItemGroup>
++ <ItemGroup>
++ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
++ </ItemGroup>
++ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
++ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
++</Project>
+--
+2.7.4
+
diff --git a/packaging/0021-Revert-ExecuteHandlerOnOriginalStack-handle-case-whe.patch b/packaging/0021-Revert-ExecuteHandlerOnOriginalStack-handle-case-whe.patch
new file mode 100644
index 0000000000..57e06008d2
--- /dev/null
+++ b/packaging/0021-Revert-ExecuteHandlerOnOriginalStack-handle-case-whe.patch
@@ -0,0 +1,143 @@
+From 911fcce99ad77f5bb18de8141a3b80f9f2823041 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Wed, 30 May 2018 19:23:03 +0300
+Subject: [PATCH 21/47] Revert "ExecuteHandlerOnOriginalStack: handle case when
+ it is called on original stack."
+
+This reverts commit a8465f60548ed4b10f13f5ace8ea99e07fc2aeba.
+---
+ src/pal/src/arch/amd64/signalhandlerhelper.cpp | 20 ++------------------
+ src/pal/src/arch/arm/signalhandlerhelper.cpp | 18 +-----------------
+ src/pal/src/arch/arm64/signalhandlerhelper.cpp | 19 +------------------
+ src/pal/src/arch/i386/signalhandlerhelper.cpp | 18 +-----------------
+ 4 files changed, 5 insertions(+), 70 deletions(-)
+
+diff --git a/src/pal/src/arch/amd64/signalhandlerhelper.cpp b/src/pal/src/arch/amd64/signalhandlerhelper.cpp
+index 803479c..8789f5a 100644
+--- a/src/pal/src/arch/amd64/signalhandlerhelper.cpp
++++ b/src/pal/src/arch/amd64/signalhandlerhelper.cpp
+@@ -27,23 +27,7 @@ Parameters :
+ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+ {
+ ucontext_t *ucontext = (ucontext_t *)context;
+- size_t faultSp;
+-
+- // check whether this function is called on alternate stack or not. In the second case we already
+- // on original stack and we should use faultSp from this frame otherwise stackframe of the caller
+- // function will be corrupted.
+- char fakeStackFrame[128 /* redzone */ + 16 /* aligment */ + 4 * sizeof(size_t) /* registers */];
+- stack_t oss;
+- int st = sigaltstack(NULL, &oss);
+- if ((st == 0) && ((oss.ss_flags == SS_DISABLE) ||
+- ((size_t)oss.ss_sp > (size_t)&faultSp) || (((size_t)oss.ss_sp + oss.ss_size) < (size_t)&faultSp)))
+- {
+- faultSp = (size_t)&fakeStackFrame[sizeof(fakeStackFrame)];
+- }
+- else
+- {
+- faultSp = (size_t)MCREG_Rsp(ucontext->uc_mcontext);
+- }
++ size_t faultSp = (size_t)MCREG_Rsp(ucontext->uc_mcontext);
+
+ _ASSERTE(IS_ALIGNED(faultSp, 8));
+
+@@ -74,7 +58,7 @@ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context,
+ // We don't care about the other registers state since the stack unwinding restores
+ // them for the target frame directly from the signal context.
+ context2.Rsp = (size_t)sp;
+- context2.Rbx = (size_t)MCREG_Rsp(ucontext->uc_mcontext);
++ context2.Rbx = (size_t)faultSp;
+ context2.Rbp = (size_t)fp;
+ context2.Rip = (size_t)signal_handler_worker;
+ context2.Rdi = code;
+diff --git a/src/pal/src/arch/arm/signalhandlerhelper.cpp b/src/pal/src/arch/arm/signalhandlerhelper.cpp
+index fbf33e3..3936204 100644
+--- a/src/pal/src/arch/arm/signalhandlerhelper.cpp
++++ b/src/pal/src/arch/arm/signalhandlerhelper.cpp
+@@ -27,23 +27,7 @@ Parameters :
+ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+ {
+ ucontext_t *ucontext = (ucontext_t *)context;
+- size_t faultSp;
+-
+- // check whether this function is called on alternate stack or not. In the second case we already
+- // on original stack and we should use faultSp from this frame otherwise stackframe of the caller
+- // function will be corrupted.
+- char fakeStackFrame[8 /* redzone */ + 8 /* aligment */ + sizeof(ucontext->uc_mcontext) + 8 /* registers */];
+- stack_t oss;
+- int st = sigaltstack(NULL, &oss);
+- if ((st == 0) && ((oss.ss_flags == SS_DISABLE) ||
+- ((size_t)oss.ss_sp > (size_t)&faultSp) || (((size_t)oss.ss_sp + oss.ss_size) < (size_t)&faultSp)))
+- {
+- faultSp = (size_t)&fakeStackFrame[sizeof(fakeStackFrame)];
+- }
+- else
+- {
+- faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
+- }
++ size_t faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
+
+ _ASSERTE(IS_ALIGNED(faultSp, 4));
+
+diff --git a/src/pal/src/arch/arm64/signalhandlerhelper.cpp b/src/pal/src/arch/arm64/signalhandlerhelper.cpp
+index 958b8af..c35c629 100644
+--- a/src/pal/src/arch/arm64/signalhandlerhelper.cpp
++++ b/src/pal/src/arch/arm64/signalhandlerhelper.cpp
+@@ -27,24 +27,7 @@ Parameters :
+ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+ {
+ ucontext_t *ucontext = (ucontext_t *)context;
+- size_t faultSp;
+-
+- // check whether this function is called on alternate stack or not. In the second case we already
+- // on original stack and we should use faultSp from this frame otherwise stackframe of the caller
+- // function will be corrupted.
+- char fakeStackFrame[128 /* redzone */ + 16 /* aligment */ + 3 * sizeof(size_t) /* registers */];
+- stack_t oss;
+- int st = sigaltstack(NULL, &oss);
+- if ((st == 0) && ((oss.ss_flags == SS_DISABLE) ||
+- ((size_t)oss.ss_sp > (size_t)&faultSp) || (((size_t)oss.ss_sp + oss.ss_size) < (size_t)&faultSp)))
+- {
+- faultSp = (size_t)&fakeStackFrame[sizeof(fakeStackFrame)];
+- }
+- else
+- {
+- faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
+- }
+-
++ size_t faultSp = (size_t)MCREG_Sp(ucontext->uc_mcontext);
+ _ASSERTE(IS_ALIGNED(faultSp, 8));
+
+ size_t fakeFrameReturnAddress;
+diff --git a/src/pal/src/arch/i386/signalhandlerhelper.cpp b/src/pal/src/arch/i386/signalhandlerhelper.cpp
+index d534f96..a7d418a 100644
+--- a/src/pal/src/arch/i386/signalhandlerhelper.cpp
++++ b/src/pal/src/arch/i386/signalhandlerhelper.cpp
+@@ -27,23 +27,7 @@ Parameters :
+ void ExecuteHandlerOnOriginalStack(int code, siginfo_t *siginfo, void *context, SignalHandlerWorkerReturnPoint* returnPoint)
+ {
+ ucontext_t *ucontext = (ucontext_t *)context;
+- size_t faultSp;
+-
+- // check whether this function is called on alternate stack or not. In the second case we already
+- // on original stack and we should use faultSp from this frame otherwise stackframe of the caller
+- // function will be corrupted.
+- char fakeStackFrame[16 /* aligment */ + 10 * sizeof(size_t) /* registers */];
+- stack_t oss;
+- int st = sigaltstack(NULL, &oss);
+- if ((st == 0) && ((oss.ss_flags == SS_DISABLE) ||
+- ((size_t)oss.ss_sp > (size_t)&faultSp) || (((size_t)oss.ss_sp + oss.ss_size) < (size_t)&faultSp)))
+- {
+- faultSp = (size_t)&fakeStackFrame[sizeof(fakeStackFrame)];
+- }
+- else
+- {
+- faultSp = (size_t)MCREG_Esp(ucontext->uc_mcontext);
+- }
++ size_t faultSp = (size_t)MCREG_Esp(ucontext->uc_mcontext);
+
+ _ASSERTE(IS_ALIGNED(faultSp, 4));
+
+--
+2.7.4
+
diff --git a/packaging/0022-CatchHardwareExceptionHolder-use-GetCurrentPalThread.patch b/packaging/0022-CatchHardwareExceptionHolder-use-GetCurrentPalThread.patch
new file mode 100644
index 0000000000..5431ee0c0a
--- /dev/null
+++ b/packaging/0022-CatchHardwareExceptionHolder-use-GetCurrentPalThread.patch
@@ -0,0 +1,35 @@
+From 7c577d168dfc4b76516437c3220a5ccbd8607e37 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Tue, 13 Feb 2018 15:56:58 +0300
+Subject: [PATCH 22/47] CatchHardwareExceptionHolder: use GetCurrentPalThread
+ instead of InternalGetCurrentThread in IsEnabled method.
+
+InternalGetCurrentThread tries to create pal thread if it doesn't
+exist for the current thread. It's unnecessary because in this case
+there are no hardware exception handlers for such thread.
+
+Also CatchHardwareExceptionHolder::IsEnable is called from signal
+handlers and during pal thread creation non-async-signal-safe
+function are called.
+---
+ src/pal/src/exception/seh.cpp | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
+index 2d1c182..0574fad 100644
+--- a/src/pal/src/exception/seh.cpp
++++ b/src/pal/src/exception/seh.cpp
+@@ -374,8 +374,8 @@ CatchHardwareExceptionHolder::~CatchHardwareExceptionHolder()
+
+ bool CatchHardwareExceptionHolder::IsEnabled()
+ {
+- CPalThread *pThread = InternalGetCurrentThread();
+- return pThread->IsHardwareExceptionsEnabled();
++ CPalThread *pThread = GetCurrentPalThread();
++ return pThread ? pThread->IsHardwareExceptionsEnabled() : false;
+ }
+
+ /*++
+--
+2.7.4
+
diff --git a/packaging/0023-vm-threads-change-tls-model-for-gCurrentThreadInfo-v.patch b/packaging/0023-vm-threads-change-tls-model-for-gCurrentThreadInfo-v.patch
new file mode 100644
index 0000000000..9976ee1fb9
--- /dev/null
+++ b/packaging/0023-vm-threads-change-tls-model-for-gCurrentThreadInfo-v.patch
@@ -0,0 +1,29 @@
+From df179b357e12c57b5e0caa8a1427a344bdae812f Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Tue, 13 Feb 2018 16:14:37 +0300
+Subject: [PATCH 23/47] vm/threads: change tls model for gCurrentThreadInfo
+ variable
+
+We should use initial-exec tls model to avoid memory allocations
+during first access to this variable because it may ocuur in
+signal handlers.
+---
+ src/vm/threads.inl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/vm/threads.inl b/src/vm/threads.inl
+index 26682ec..0105955 100644
+--- a/src/vm/threads.inl
++++ b/src/vm/threads.inl
+@@ -27,7 +27,7 @@
+ #ifndef __llvm__
+ EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
+ #else // !__llvm__
+-EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo;
++EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo __attribute__ ((tls_model("initial-exec")));
+ #endif // !__llvm__
+
+ EXTERN_C inline Thread* STDCALL GetThread()
+--
+2.7.4
+
diff --git a/packaging/0024-sigsegv_handler-handle-case-when-it-is-called-on-ori.patch b/packaging/0024-sigsegv_handler-handle-case-when-it-is-called-on-ori.patch
new file mode 100644
index 0000000000..08678dd416
--- /dev/null
+++ b/packaging/0024-sigsegv_handler-handle-case-when-it-is-called-on-ori.patch
@@ -0,0 +1,71 @@
+From 8b1bff743895942364a26df78ad1dd2f14760f28 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Tue, 13 Feb 2018 16:27:01 +0300
+Subject: [PATCH 24/47] sigsegv_handler: handle case when it is called on
+ original stack
+
+If sigsegv_handler is called on original stack (for example, if segmentation
+fault occurs in native application's thread that hasn't alternate signal stack)
+we should call common_signal_handler directly othersize sigsegv_handler's
+stackframe will be corrupted.
+---
+ src/pal/src/exception/signal.cpp | 38 ++++++++++++++++++++++++++------------
+ 1 file changed, 26 insertions(+), 12 deletions(-)
+
+diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
+index f795b81..bf48619 100644
+--- a/src/pal/src/exception/signal.cpp
++++ b/src/pal/src/exception/signal.cpp
+@@ -472,23 +472,37 @@ static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
+
+ // Establish a return point in case the common_signal_handler returns
+
+- volatile bool contextInitialization = true;
++ if (GetCurrentPalThread())
++ {
++ volatile bool contextInitialization = true;
+
+- SignalHandlerWorkerReturnPoint returnPoint;
+- RtlCaptureContext(&returnPoint.context);
++ void *ptr = alloca(sizeof(SignalHandlerWorkerReturnPoint) + alignof(SignalHandlerWorkerReturnPoint) - 1);
++ SignalHandlerWorkerReturnPoint *pReturnPoint = (SignalHandlerWorkerReturnPoint *)ALIGN_UP(ptr, alignof(SignalHandlerWorkerReturnPoint));
++ RtlCaptureContext(&pReturnPoint->context);
+
+- // When the signal handler worker completes, it uses setcontext to return to this point
++ // When the signal handler worker completes, it uses setcontext to return to this point
+
+- if (contextInitialization)
+- {
+- contextInitialization = false;
+- ExecuteHandlerOnOriginalStack(code, siginfo, context, &returnPoint);
+- _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
++ if (contextInitialization)
++ {
++ contextInitialization = false;
++ ExecuteHandlerOnOriginalStack(code, siginfo, context, pReturnPoint);
++ _ASSERTE(FALSE); // The ExecuteHandlerOnOriginalStack should never return
++ }
++
++ if (pReturnPoint->returnFromHandler)
++ {
++ return;
++ }
+ }
+-
+- if (returnPoint.returnFromHandler)
++ else
+ {
+- return;
++ // If thread isn't created by coreclr and has alternate signal stack GetCurrentPalThread() will return NULL too.
++ // But since in this case we don't handle hardware exceptions (IsSafeToHandleHardwareException returns false)
++ // we can call common_signal_handler on the alternate stack.
++ if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
++ {
++ return;
++ }
+ }
+ }
+
+--
+2.7.4
+
diff --git a/packaging/0025-Revert-TLS-model-change-of-the-gCurrentThreadInfo.patch b/packaging/0025-Revert-TLS-model-change-of-the-gCurrentThreadInfo.patch
new file mode 100644
index 0000000000..38d416720f
--- /dev/null
+++ b/packaging/0025-Revert-TLS-model-change-of-the-gCurrentThreadInfo.patch
@@ -0,0 +1,28 @@
+From 459e054044ede83560f9295bce5556f64b00e5c2 Mon Sep 17 00:00:00 2001
+From: Jan Vorlicek <janvorli@microsoft.com>
+Date: Wed, 21 Feb 2018 02:02:30 +0100
+Subject: [PATCH 25/47] Revert TLS model change of the gCurrentThreadInfo
+
+This change causes crashes due to incorrect TLS variable initialization
+on Alpine Linux. The initial-exec model that the variable was modified
+to use recently cannot be safely used in shared libraries.
+---
+ src/vm/threads.inl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/vm/threads.inl b/src/vm/threads.inl
+index 0105955..26682ec 100644
+--- a/src/vm/threads.inl
++++ b/src/vm/threads.inl
+@@ -27,7 +27,7 @@
+ #ifndef __llvm__
+ EXTERN_C __declspec(thread) ThreadLocalInfo gCurrentThreadInfo;
+ #else // !__llvm__
+-EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo __attribute__ ((tls_model("initial-exec")));
++EXTERN_C __thread ThreadLocalInfo gCurrentThreadInfo;
+ #endif // !__llvm__
+
+ EXTERN_C inline Thread* STDCALL GetThread()
+--
+2.7.4
+
diff --git a/packaging/0026-Prevent-memory-allocation-in-signal-handler.patch b/packaging/0026-Prevent-memory-allocation-in-signal-handler.patch
new file mode 100644
index 0000000000..b3617fa8c3
--- /dev/null
+++ b/packaging/0026-Prevent-memory-allocation-in-signal-handler.patch
@@ -0,0 +1,68 @@
+From 97b80457b091641dd6fb366038b8e362b1409a58 Mon Sep 17 00:00:00 2001
+From: Mikhail Labiuk <m.labiuk@samsung.com>
+Date: Tue, 13 Feb 2018 15:02:12 +0300
+Subject: [PATCH 26/47] Prevent memory allocation in signal handler
+
+If the signal occurs when heap being inconsistent we should not
+use heap. We should call signal-safe functions only from signal handler.
+
+fix https://github.com/dotnet/coreclr/issues/16338
+---
+ src/pal/src/exception/seh-unwind.cpp | 6 ++++--
+ src/pal/src/exception/signal.cpp | 2 +-
+ src/pal/src/include/pal/seh.hpp | 3 ++-
+ 3 files changed, 7 insertions(+), 4 deletions(-)
+
+diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
+index 7746bbb..eba2c80 100644
+--- a/src/pal/src/exception/seh-unwind.cpp
++++ b/src/pal/src/exception/seh-unwind.cpp
+@@ -620,12 +620,14 @@ Function:
+ Parameters:
+ exceptionRecord - output pointer to the allocated exception record
+ contextRecord - output pointer to the allocated context record
++ allocationProhibited - input flag to avoid memory allocation in critical situations
+ --*/
+ VOID
+-AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
++AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord, BOOL allocationProhibited)
+ {
+ ExceptionRecords* records;
+- if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
++ if (allocationProhibited ||
++ (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0) )
+ {
+ size_t bitmap;
+ size_t newBitmap;
+diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
+index bf48619..90da207 100644
+--- a/src/pal/src/exception/signal.cpp
++++ b/src/pal/src/exception/signal.cpp
+@@ -808,7 +808,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ ucontext = (native_context_t *)sigcontext;
+ g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
+
+- AllocateExceptionRecords(&exceptionRecord, &contextRecord);
++ AllocateExceptionRecords(&exceptionRecord, &contextRecord, true);
+
+ exceptionRecord->ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+ exceptionRecord->ExceptionFlags = EXCEPTION_IS_SIGNAL;
+diff --git a/src/pal/src/include/pal/seh.hpp b/src/pal/src/include/pal/seh.hpp
+index 3ac93d6..5edc214 100644
+--- a/src/pal/src/include/pal/seh.hpp
++++ b/src/pal/src/include/pal/seh.hpp
+@@ -84,9 +84,10 @@ Function:
+ Parameters:
+ exceptionRecord - output pointer to the allocated Windows exception record
+ contextRecord - output pointer to the allocated Windows context record
++ allocationProhibited - input flag to avoid memory allocation in critical situations
+ --*/
+ VOID
+-AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord);
++AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord, BOOL allocationProhibited=false);
+
+ #if !HAVE_MACH_EXCEPTIONS
+ // TODO: Implement for Mach exceptions. Not in CoreCLR surface area.
+--
+2.7.4
+
diff --git a/packaging/0027-Revert-Prevent-memory-allocation-in-signal-handler.patch b/packaging/0027-Revert-Prevent-memory-allocation-in-signal-handler.patch
new file mode 100644
index 0000000000..2d88908ac5
--- /dev/null
+++ b/packaging/0027-Revert-Prevent-memory-allocation-in-signal-handler.patch
@@ -0,0 +1,65 @@
+From a01acb182005e85a766fe05bdc5ce81c78b49586 Mon Sep 17 00:00:00 2001
+From: Mikhail Labiuk <m.labiuk@samsung.com>
+Date: Mon, 19 Feb 2018 19:08:50 +0300
+Subject: [PATCH 27/47] Revert "Prevent memory allocation in signal handler"
+
+This reverts commit fa6087f0c2856215e7141259b56e75b46746f74d.
+---
+ src/pal/src/exception/seh-unwind.cpp | 6 ++----
+ src/pal/src/exception/signal.cpp | 2 +-
+ src/pal/src/include/pal/seh.hpp | 3 +--
+ 3 files changed, 4 insertions(+), 7 deletions(-)
+
+diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
+index eba2c80..7746bbb 100644
+--- a/src/pal/src/exception/seh-unwind.cpp
++++ b/src/pal/src/exception/seh-unwind.cpp
+@@ -620,14 +620,12 @@ Function:
+ Parameters:
+ exceptionRecord - output pointer to the allocated exception record
+ contextRecord - output pointer to the allocated context record
+- allocationProhibited - input flag to avoid memory allocation in critical situations
+ --*/
+ VOID
+-AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord, BOOL allocationProhibited)
++AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
+ {
+ ExceptionRecords* records;
+- if (allocationProhibited ||
+- (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0) )
++ if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
+ {
+ size_t bitmap;
+ size_t newBitmap;
+diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
+index 90da207..bf48619 100644
+--- a/src/pal/src/exception/signal.cpp
++++ b/src/pal/src/exception/signal.cpp
+@@ -808,7 +808,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ ucontext = (native_context_t *)sigcontext;
+ g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
+
+- AllocateExceptionRecords(&exceptionRecord, &contextRecord, true);
++ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+
+ exceptionRecord->ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+ exceptionRecord->ExceptionFlags = EXCEPTION_IS_SIGNAL;
+diff --git a/src/pal/src/include/pal/seh.hpp b/src/pal/src/include/pal/seh.hpp
+index 5edc214..3ac93d6 100644
+--- a/src/pal/src/include/pal/seh.hpp
++++ b/src/pal/src/include/pal/seh.hpp
+@@ -84,10 +84,9 @@ Function:
+ Parameters:
+ exceptionRecord - output pointer to the allocated Windows exception record
+ contextRecord - output pointer to the allocated Windows context record
+- allocationProhibited - input flag to avoid memory allocation in critical situations
+ --*/
+ VOID
+-AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord, BOOL allocationProhibited=false);
++AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord);
+
+ #if !HAVE_MACH_EXCEPTIONS
+ // TODO: Implement for Mach exceptions. Not in CoreCLR surface area.
+--
+2.7.4
+
diff --git a/packaging/0028-Do-not-allocate-exception-for-signal-from-non-manage.patch b/packaging/0028-Do-not-allocate-exception-for-signal-from-non-manage.patch
new file mode 100644
index 0000000000..e313dab764
--- /dev/null
+++ b/packaging/0028-Do-not-allocate-exception-for-signal-from-non-manage.patch
@@ -0,0 +1,174 @@
+From 88c5af565882264c129816bdba94fed25c83f2de Mon Sep 17 00:00:00 2001
+From: Mikhail Labiuk <m.labiuk@samsung.com>
+Date: Mon, 19 Feb 2018 18:56:15 +0300
+Subject: [PATCH 28/47] Do not allocate exception for signal from non managed
+ code
+
+If the signal occurs in not managed code we cannot use heap.
+We should call signal-safe functions only from signal handler.
+
+Create exception object on stack for checking source of signal.
+If signal is from managed code we can use memory allocation to create
+persistent exception on heap as copy of volatile exception on stack.
+
+If signal from unmanaged code we do nothing and call base signal handler.
+
+fix https://github.com/dotnet/coreclr/issues/16338
+---
+ src/pal/inc/pal.h | 5 ++++-
+ src/pal/src/exception/seh.cpp | 23 +++++++++++++++++++++++
+ src/pal/src/exception/signal.cpp | 30 +++++++++++++++---------------
+ 3 files changed, 42 insertions(+), 16 deletions(-)
+
+diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
+index 0a00b67..e3bfa40 100644
+--- a/src/pal/inc/pal.h
++++ b/src/pal/inc/pal.h
+@@ -3888,6 +3888,8 @@ PAL_BindResources(IN LPCSTR lpDomain);
+
+ #define EXCEPTION_IS_SIGNAL 0x100
+
++#define EXCEPTION_ON_STACK 0x400
++
+ #define EXCEPTION_MAXIMUM_PARAMETERS 15
+
+ // Index in the ExceptionInformation array where we will keep the reference
+@@ -5814,7 +5816,8 @@ private:
+
+ void FreeRecords()
+ {
+- if (ExceptionPointers.ExceptionRecord != NULL)
++ if (ExceptionPointers.ExceptionRecord != NULL &&
++ ! (ExceptionPointers.ExceptionRecord->ExceptionFlags | EXCEPTION_ON_STACK) )
+ {
+ PAL_FreeExceptionRecords(ExceptionPointers.ExceptionRecord, ExceptionPointers.ContextRecord);
+ ExceptionPointers.ExceptionRecord = NULL;
+diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
+index 0574fad..a7d4ad9 100644
+--- a/src/pal/src/exception/seh.cpp
++++ b/src/pal/src/exception/seh.cpp
+@@ -232,6 +232,23 @@ void ThrowExceptionHelper(PAL_SEHException* ex)
+ throw std::move(*ex);
+ }
+
++static PAL_SEHException copyPAL_SEHException(PAL_SEHException* src)
++{
++ CONTEXT* contextRecord = src->GetContextRecord();
++ EXCEPTION_RECORD* exceptionRecord = src->GetExceptionRecord();
++
++ CONTEXT* contextRecordCopy;
++ EXCEPTION_RECORD* exceptionRecordCopy;
++ AllocateExceptionRecords(&exceptionRecordCopy, &contextRecordCopy);
++
++ *exceptionRecordCopy = *exceptionRecord;
++ exceptionRecordCopy->ExceptionFlags &= ~EXCEPTION_ON_STACK;
++ *contextRecordCopy = *contextRecord;
++ return PAL_SEHException(exceptionRecordCopy, contextRecordCopy);
++}
++
++
++
+ /*++
+ Function:
+ SEHProcessException
+@@ -279,6 +296,9 @@ SEHProcessException(PAL_SEHException* exception)
+ PROCAbort();
+ }
+ }
++
++ if(exceptionRecord->ExceptionFlags | EXCEPTION_ON_STACK)
++ *exception = copyPAL_SEHException(exception);
+
+ if (g_hardwareExceptionHandler(exception))
+ {
+@@ -292,6 +312,9 @@ SEHProcessException(PAL_SEHException* exception)
+
+ if (CatchHardwareExceptionHolder::IsEnabled())
+ {
++ if(exceptionRecord->ExceptionFlags | EXCEPTION_ON_STACK)
++ *exception = copyPAL_SEHException(exception);
++
+ PAL_ThrowExceptionFromContext(exception->GetContextRecord(), exception);
+ }
+ }
+diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
+index bf48619..d42ba38 100644
+--- a/src/pal/src/exception/signal.cpp
++++ b/src/pal/src/exception/signal.cpp
+@@ -801,32 +801,32 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ {
+ sigset_t signal_set;
+ CONTEXT signalContextRecord;
+- CONTEXT *contextRecord;
+- EXCEPTION_RECORD *exceptionRecord;
++ CONTEXT contextRecord;
++ EXCEPTION_RECORD exceptionRecord;
+ native_context_t *ucontext;
+
+ ucontext = (native_context_t *)sigcontext;
+ g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
+
+- AllocateExceptionRecords(&exceptionRecord, &contextRecord);
++ //AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+
+- exceptionRecord->ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+- exceptionRecord->ExceptionFlags = EXCEPTION_IS_SIGNAL;
+- exceptionRecord->ExceptionRecord = NULL;
+- exceptionRecord->ExceptionAddress = GetNativeContextPC(ucontext);
+- exceptionRecord->NumberParameters = numParams;
++ exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
++ exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL | EXCEPTION_ON_STACK;
++ exceptionRecord.ExceptionRecord = NULL;
++ exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext);
++ exceptionRecord.NumberParameters = numParams;
+
+ va_list params;
+ va_start(params, numParams);
+
+ for (int i = 0; i < numParams; i++)
+ {
+- exceptionRecord->ExceptionInformation[i] = va_arg(params, size_t);
++ exceptionRecord.ExceptionInformation[i] = va_arg(params, size_t);
+ }
+
+ // Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
+ // which is required for restoring context
+- RtlCaptureContext(contextRecord);
++ RtlCaptureContext(&contextRecord);
+
+ ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
+
+@@ -837,7 +837,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ // Fill context record with required information. from pal.h:
+ // On non-Win32 platforms, the CONTEXT pointer in the
+ // PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
+- CONTEXTFromNativeContext(ucontext, contextRecord, contextFlags);
++ CONTEXTFromNativeContext(ucontext, &contextRecord, contextFlags);
+
+ /* Unmask signal so we can receive it again */
+ sigemptyset(&signal_set);
+@@ -848,17 +848,17 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
+ }
+
+- contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
++ contextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+
+- memcpy_s(&signalContextRecord, sizeof(CONTEXT), contextRecord, sizeof(CONTEXT));
++ memcpy_s(&signalContextRecord, sizeof(CONTEXT), &contextRecord, sizeof(CONTEXT));
+
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+- PAL_SEHException exception(exceptionRecord, contextRecord);
++ PAL_SEHException exception(&exceptionRecord, &contextRecord);
+
+ if (SEHProcessException(&exception))
+ {
+ // Exception handling may have modified the context, so update it.
+- CONTEXTToNativeContext(contextRecord, ucontext);
++ CONTEXTToNativeContext(&contextRecord, ucontext);
+ return true;
+ }
+
+--
+2.7.4
+
diff --git a/packaging/0029-Move-exception-allocation-to-PAL_SEHException.patch b/packaging/0029-Move-exception-allocation-to-PAL_SEHException.patch
new file mode 100644
index 0000000000..67e9f9e5e4
--- /dev/null
+++ b/packaging/0029-Move-exception-allocation-to-PAL_SEHException.patch
@@ -0,0 +1,179 @@
+From d7ea540ec5ffa7e44627b61f0cfa480341ec64ec Mon Sep 17 00:00:00 2001
+From: Mikhail Labiuk <m.labiuk@samsung.com>
+Date: Tue, 20 Feb 2018 14:26:35 +0300
+Subject: [PATCH 29/47] Move exception allocation to PAL_SEHException
+
+PAL_SEHException::EnsureExceptionRecordsOnHeap() moves exception record
+to heap if needed.
+
+fix https://github.com/dotnet/coreclr/issues/16338
+---
+ src/pal/inc/pal.h | 35 ++++++++++++++++++++++++++++++-----
+ src/pal/src/exception/seh.cpp | 25 ++-----------------------
+ src/pal/src/exception/signal.cpp | 6 ++----
+ 3 files changed, 34 insertions(+), 32 deletions(-)
+
+diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
+index e3bfa40..e241219 100644
+--- a/src/pal/inc/pal.h
++++ b/src/pal/inc/pal.h
+@@ -3888,8 +3888,6 @@ PAL_BindResources(IN LPCSTR lpDomain);
+
+ #define EXCEPTION_IS_SIGNAL 0x100
+
+-#define EXCEPTION_ON_STACK 0x400
+-
+ #define EXCEPTION_MAXIMUM_PARAMETERS 15
+
+ // Index in the ExceptionInformation array where we will keep the reference
+@@ -5796,6 +5794,11 @@ PAL_FreeExceptionRecords(
+ IN EXCEPTION_RECORD *exceptionRecord,
+ IN CONTEXT *contextRecord);
+
++VOID
++AllocateExceptionRecords(
++ EXCEPTION_RECORD** exceptionRecord,
++ CONTEXT** contextRecord);
++
+ #define EXCEPTION_CONTINUE_SEARCH 0
+ #define EXCEPTION_EXECUTE_HANDLER 1
+ #define EXCEPTION_CONTINUE_EXECUTION -1
+@@ -5810,14 +5813,14 @@ private:
+ ExceptionPointers.ExceptionRecord = ex.ExceptionPointers.ExceptionRecord;
+ ExceptionPointers.ContextRecord = ex.ExceptionPointers.ContextRecord;
+ TargetFrameSp = ex.TargetFrameSp;
++ RecordsOnStack = ex.RecordsOnStack;
+
+ ex.Clear();
+ }
+
+ void FreeRecords()
+ {
+- if (ExceptionPointers.ExceptionRecord != NULL &&
+- ! (ExceptionPointers.ExceptionRecord->ExceptionFlags | EXCEPTION_ON_STACK) )
++ if (ExceptionPointers.ExceptionRecord != NULL && !RecordsOnStack )
+ {
+ PAL_FreeExceptionRecords(ExceptionPointers.ExceptionRecord, ExceptionPointers.ContextRecord);
+ ExceptionPointers.ExceptionRecord = NULL;
+@@ -5829,12 +5832,14 @@ public:
+ EXCEPTION_POINTERS ExceptionPointers;
+ // Target frame stack pointer set before the 2nd pass.
+ SIZE_T TargetFrameSp;
++ bool RecordsOnStack;
+
+- PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord)
++ PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord, bool onStack = false)
+ {
+ ExceptionPointers.ExceptionRecord = pExceptionRecord;
+ ExceptionPointers.ContextRecord = pContextRecord;
+ TargetFrameSp = NoTargetFrameSp;
++ RecordsOnStack = onStack;
+ }
+
+ PAL_SEHException()
+@@ -5870,6 +5875,26 @@ public:
+ ExceptionPointers.ExceptionRecord = NULL;
+ ExceptionPointers.ContextRecord = NULL;
+ TargetFrameSp = NoTargetFrameSp;
++ RecordsOnStack = false;
++ }
++
++ void EnsureExceptionRecordsOnHeap()
++ {
++ if( !RecordsOnStack || ExceptionPointers.ExceptionRecord == NULL)
++ {
++ return;
++ }
++
++ CONTEXT* contextRecordCopy;
++ EXCEPTION_RECORD* exceptionRecordCopy;
++ AllocateExceptionRecords(&exceptionRecordCopy, &contextRecordCopy);
++
++ *exceptionRecordCopy = *ExceptionPointers.ExceptionRecord;
++ ExceptionPointers.ExceptionRecord = exceptionRecordCopy;
++ *contextRecordCopy = *ExceptionPointers.ContextRecord;
++ ExceptionPointers.ContextRecord = contextRecordCopy;
++
++ RecordsOnStack = false;
+ }
+
+ CONTEXT* GetContextRecord()
+diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
+index a7d4ad9..27766f2 100644
+--- a/src/pal/src/exception/seh.cpp
++++ b/src/pal/src/exception/seh.cpp
+@@ -232,23 +232,6 @@ void ThrowExceptionHelper(PAL_SEHException* ex)
+ throw std::move(*ex);
+ }
+
+-static PAL_SEHException copyPAL_SEHException(PAL_SEHException* src)
+-{
+- CONTEXT* contextRecord = src->GetContextRecord();
+- EXCEPTION_RECORD* exceptionRecord = src->GetExceptionRecord();
+-
+- CONTEXT* contextRecordCopy;
+- EXCEPTION_RECORD* exceptionRecordCopy;
+- AllocateExceptionRecords(&exceptionRecordCopy, &contextRecordCopy);
+-
+- *exceptionRecordCopy = *exceptionRecord;
+- exceptionRecordCopy->ExceptionFlags &= ~EXCEPTION_ON_STACK;
+- *contextRecordCopy = *contextRecord;
+- return PAL_SEHException(exceptionRecordCopy, contextRecordCopy);
+-}
+-
+-
+-
+ /*++
+ Function:
+ SEHProcessException
+@@ -296,10 +279,8 @@ SEHProcessException(PAL_SEHException* exception)
+ PROCAbort();
+ }
+ }
+-
+- if(exceptionRecord->ExceptionFlags | EXCEPTION_ON_STACK)
+- *exception = copyPAL_SEHException(exception);
+
++ exception->EnsureExceptionRecordsOnHeap();
+ if (g_hardwareExceptionHandler(exception))
+ {
+ // The exception happened in managed code and the execution should continue.
+@@ -312,9 +293,7 @@ SEHProcessException(PAL_SEHException* exception)
+
+ if (CatchHardwareExceptionHolder::IsEnabled())
+ {
+- if(exceptionRecord->ExceptionFlags | EXCEPTION_ON_STACK)
+- *exception = copyPAL_SEHException(exception);
+-
++ exception->EnsureExceptionRecordsOnHeap();
+ PAL_ThrowExceptionFromContext(exception->GetContextRecord(), exception);
+ }
+ }
+diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
+index d42ba38..3b4bec8 100644
+--- a/src/pal/src/exception/signal.cpp
++++ b/src/pal/src/exception/signal.cpp
+@@ -808,10 +808,8 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ ucontext = (native_context_t *)sigcontext;
+ g_common_signal_handler_context_locvar_offset = (int)((char*)&signalContextRecord - (char*)__builtin_frame_address(0));
+
+- //AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+-
+ exceptionRecord.ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+- exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL | EXCEPTION_ON_STACK;
++ exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
+ exceptionRecord.ExceptionRecord = NULL;
+ exceptionRecord.ExceptionAddress = GetNativeContextPC(ucontext);
+ exceptionRecord.NumberParameters = numParams;
+@@ -853,7 +851,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ memcpy_s(&signalContextRecord, sizeof(CONTEXT), &contextRecord, sizeof(CONTEXT));
+
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+- PAL_SEHException exception(&exceptionRecord, &contextRecord);
++ PAL_SEHException exception(&exceptionRecord, &contextRecord, true);
+
+ if (SEHProcessException(&exception))
+ {
+--
+2.7.4
+
diff --git a/packaging/0030-Remove-exception-records-allocation-from-pal.h.patch b/packaging/0030-Remove-exception-records-allocation-from-pal.h.patch
new file mode 100644
index 0000000000..cf099e3a6e
--- /dev/null
+++ b/packaging/0030-Remove-exception-records-allocation-from-pal.h.patch
@@ -0,0 +1,116 @@
+From 318d7a2dff13634670ef005c4af8115e5c780eb3 Mon Sep 17 00:00:00 2001
+From: Mikhail Labiuk <m.labiuk@samsung.com>
+Date: Tue, 20 Feb 2018 16:59:27 +0300
+Subject: [PATCH 30/47] Remove exception records allocation from pal.h
+
+---
+ src/pal/inc/pal.h | 24 ------------------------
+ src/pal/src/exception/seh.cpp | 36 ++++++++++++++++++++++++++++++++++--
+ 2 files changed, 34 insertions(+), 26 deletions(-)
+
+diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
+index e241219..199ab94 100644
+--- a/src/pal/inc/pal.h
++++ b/src/pal/inc/pal.h
+@@ -5794,11 +5794,6 @@ PAL_FreeExceptionRecords(
+ IN EXCEPTION_RECORD *exceptionRecord,
+ IN CONTEXT *contextRecord);
+
+-VOID
+-AllocateExceptionRecords(
+- EXCEPTION_RECORD** exceptionRecord,
+- CONTEXT** contextRecord);
+-
+ #define EXCEPTION_CONTINUE_SEARCH 0
+ #define EXCEPTION_EXECUTE_HANDLER 1
+ #define EXCEPTION_CONTINUE_EXECUTION -1
+@@ -5878,25 +5873,6 @@ public:
+ RecordsOnStack = false;
+ }
+
+- void EnsureExceptionRecordsOnHeap()
+- {
+- if( !RecordsOnStack || ExceptionPointers.ExceptionRecord == NULL)
+- {
+- return;
+- }
+-
+- CONTEXT* contextRecordCopy;
+- EXCEPTION_RECORD* exceptionRecordCopy;
+- AllocateExceptionRecords(&exceptionRecordCopy, &contextRecordCopy);
+-
+- *exceptionRecordCopy = *ExceptionPointers.ExceptionRecord;
+- ExceptionPointers.ExceptionRecord = exceptionRecordCopy;
+- *contextRecordCopy = *ExceptionPointers.ContextRecord;
+- ExceptionPointers.ContextRecord = contextRecordCopy;
+-
+- RecordsOnStack = false;
+- }
+-
+ CONTEXT* GetContextRecord()
+ {
+ return ExceptionPointers.ContextRecord;
+diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
+index 27766f2..8477fd6 100644
+--- a/src/pal/src/exception/seh.cpp
++++ b/src/pal/src/exception/seh.cpp
+@@ -234,6 +234,38 @@ void ThrowExceptionHelper(PAL_SEHException* ex)
+
+ /*++
+ Function:
++ EnsureExceptionRecordsOnHeap
++
++ Helper function to move records from stack to heap.
++
++Parameters:
++ PAL_SEHException* exception
++--*/
++static void EnsureExceptionRecordsOnHeap(PAL_SEHException* exception)
++{
++ if( !exception->RecordsOnStack ||
++ exception->ExceptionPointers.ExceptionRecord == NULL )
++ {
++ return;
++ }
++
++ CONTEXT* contextRecord = exception->ExceptionPointers.ContextRecord;
++ EXCEPTION_RECORD* exceptionRecord = exception->ExceptionPointers.ExceptionRecord;
++
++ CONTEXT* contextRecordCopy;
++ EXCEPTION_RECORD* exceptionRecordCopy;
++ AllocateExceptionRecords(&exceptionRecordCopy, &contextRecordCopy);
++
++ *exceptionRecordCopy = *exceptionRecord;
++ *contextRecordCopy = *contextRecord;
++
++ exception->ExceptionPointers.ExceptionRecord = exceptionRecordCopy;
++ exception->ExceptionPointers.ContextRecord = contextRecordCopy;
++ exception->RecordsOnStack = false;
++}
++
++/*++
++Function:
+ SEHProcessException
+
+ Send the PAL exception to any handler registered.
+@@ -280,7 +312,7 @@ SEHProcessException(PAL_SEHException* exception)
+ }
+ }
+
+- exception->EnsureExceptionRecordsOnHeap();
++ EnsureExceptionRecordsOnHeap(exception);
+ if (g_hardwareExceptionHandler(exception))
+ {
+ // The exception happened in managed code and the execution should continue.
+@@ -293,7 +325,7 @@ SEHProcessException(PAL_SEHException* exception)
+
+ if (CatchHardwareExceptionHolder::IsEnabled())
+ {
+- exception->EnsureExceptionRecordsOnHeap();
++ EnsureExceptionRecordsOnHeap(exception);
+ PAL_ThrowExceptionFromContext(exception->GetContextRecord(), exception);
+ }
+ }
+--
+2.7.4
+
diff --git a/packaging/0031-Fix-preventing-memory-allocation-in-signal-handler.patch b/packaging/0031-Fix-preventing-memory-allocation-in-signal-handler.patch
new file mode 100644
index 0000000000..8520d2608d
--- /dev/null
+++ b/packaging/0031-Fix-preventing-memory-allocation-in-signal-handler.patch
@@ -0,0 +1,74 @@
+From 53c2a4bb7536cb6273e5ba58ee15f007978ba742 Mon Sep 17 00:00:00 2001
+From: Jan Vorlicek <janvorli@microsoft.com>
+Date: Thu, 22 Feb 2018 01:48:43 +0100
+Subject: [PATCH 31/47] Fix preventing memory allocation in signal handler
+
+There was a subtle bug. When the hardware exception handler returns back
+to the signal handler, the exception's CONTEXT record may contain
+modified registers and so the changes need to be propagated back to the
+signal context. But the recent change #16384 was restoring the signal
+context from the originally grabbed context instead of the one that's
+pointed to by the exception, which is different.
+
+I have also added a little optimization - the contextRecord that was
+added is not needed, since the signalContextRecord can be used as the
+initial context record for the exception. So we can save the
+contextRecord and also copying to the signalContextRecord from it.
+---
+ src/pal/src/exception/signal.cpp | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
+index 3b4bec8..430cd05 100644
+--- a/src/pal/src/exception/signal.cpp
++++ b/src/pal/src/exception/signal.cpp
+@@ -801,7 +801,6 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ {
+ sigset_t signal_set;
+ CONTEXT signalContextRecord;
+- CONTEXT contextRecord;
+ EXCEPTION_RECORD exceptionRecord;
+ native_context_t *ucontext;
+
+@@ -824,7 +823,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+
+ // Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
+ // which is required for restoring context
+- RtlCaptureContext(&contextRecord);
++ RtlCaptureContext(&signalContextRecord);
+
+ ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
+
+@@ -835,7 +834,7 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ // Fill context record with required information. from pal.h:
+ // On non-Win32 platforms, the CONTEXT pointer in the
+ // PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
+- CONTEXTFromNativeContext(ucontext, &contextRecord, contextFlags);
++ CONTEXTFromNativeContext(ucontext, &signalContextRecord, contextFlags);
+
+ /* Unmask signal so we can receive it again */
+ sigemptyset(&signal_set);
+@@ -846,17 +845,15 @@ static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext
+ ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
+ }
+
+- contextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+-
+- memcpy_s(&signalContextRecord, sizeof(CONTEXT), &contextRecord, sizeof(CONTEXT));
++ signalContextRecord.ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+- PAL_SEHException exception(&exceptionRecord, &contextRecord, true);
++ PAL_SEHException exception(&exceptionRecord, &signalContextRecord, true);
+
+ if (SEHProcessException(&exception))
+ {
+ // Exception handling may have modified the context, so update it.
+- CONTEXTToNativeContext(&contextRecord, ucontext);
++ CONTEXTToNativeContext(exception.ExceptionPointers.ContextRecord, ucontext);
+ return true;
+ }
+
+--
+2.7.4
+
diff --git a/packaging/0032-Fix-Use-of-EventPipeConfiguration-After-it-has-Been-.patch b/packaging/0032-Fix-Use-of-EventPipeConfiguration-After-it-has-Been-.patch
new file mode 100644
index 0000000000..79ad1e0bd1
--- /dev/null
+++ b/packaging/0032-Fix-Use-of-EventPipeConfiguration-After-it-has-Been-.patch
@@ -0,0 +1,53 @@
+From 10f02e5641055b97eca8964dda85542885fa753b Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Wed, 30 May 2018 19:34:11 +0300
+Subject: [PATCH 32/47] Fix Use of EventPipeConfiguration After it has Been
+ Freed on Shutdown
+
+Port #16704 for release/2.0.0
+---
+ src/vm/eventpipe.cpp | 26 ++++++++++++++++----------
+ 1 file changed, 16 insertions(+), 10 deletions(-)
+
+diff --git a/src/vm/eventpipe.cpp b/src/vm/eventpipe.cpp
+index 50909a1..5ef3ec7 100644
+--- a/src/vm/eventpipe.cpp
++++ b/src/vm/eventpipe.cpp
+@@ -91,18 +91,24 @@ void EventPipe::Shutdown()
+ }
+ CONTRACTL_END;
+
++ // Mark tracing as no longer initialized.
++ s_tracingInitialized = false;
++
+ Disable();
+
+- if(s_pConfig != NULL)
+- {
+- delete(s_pConfig);
+- s_pConfig = NULL;
+- }
+- if(s_pBufferManager != NULL)
+- {
+- delete(s_pBufferManager);
+- s_pBufferManager = NULL;
+- }
++ // Save pointers to the configuration and buffer manager.
++ EventPipeConfiguration *pConfig = s_pConfig;
++ EventPipeBufferManager *pBufferManager = s_pBufferManager;
++
++ // Set the static pointers to NULL so that the rest of the EventPipe knows that they are no longer available.
++ // Flush process write buffers to make sure other threads can see the change.
++ s_pConfig = NULL;
++ s_pBufferManager = NULL;
++ FlushProcessWriteBuffers();
++
++ // Free the configuration and buffer manager.
++ delete(pConfig);
++ delete(pBufferManager);
+ }
+
+ void EventPipe::Enable(
+--
+2.7.4
+
diff --git a/packaging/0033-Revert-clear-cache-after-NI-reloc.patch b/packaging/0033-Revert-clear-cache-after-NI-reloc.patch
new file mode 100644
index 0000000000..b0e06f776c
--- /dev/null
+++ b/packaging/0033-Revert-clear-cache-after-NI-reloc.patch
@@ -0,0 +1,26 @@
+From 8badee4404fe637bd9a8625785cd86fd3e310590 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Fri, 1 Jun 2018 17:54:18 +0300
+Subject: [PATCH 33/47] Revert "clear cache after NI reloc"
+
+This reverts commit 2427902ddfff7dd868b79d95865afee5c3a257c4.
+---
+ src/vm/peimagelayout.cpp | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/src/vm/peimagelayout.cpp b/src/vm/peimagelayout.cpp
+index 5dc0e64..34ba4d8 100644
+--- a/src/vm/peimagelayout.cpp
++++ b/src/vm/peimagelayout.cpp
+@@ -227,8 +227,6 @@ void PEImageLayout::ApplyBaseRelocations()
+ #ifdef _TARGET_ARM_
+ case IMAGE_REL_BASED_THUMB_MOV32:
+ PutThumb2Mov32((UINT16 *)address, GetThumb2Mov32((UINT16 *)address) + delta);
+-
+- ClrFlushInstructionCache(address, 8);
+ break;
+ #endif
+
+--
+2.7.4
+
diff --git a/packaging/0034-PEImageLayout-clear-instruction-cache-after-relocati.patch b/packaging/0034-PEImageLayout-clear-instruction-cache-after-relocati.patch
new file mode 100644
index 0000000000..297d62797f
--- /dev/null
+++ b/packaging/0034-PEImageLayout-clear-instruction-cache-after-relocati.patch
@@ -0,0 +1,81 @@
+From 3aa9a0340557631f60b1ded4d5c629cf381092aa Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Fri, 30 Mar 2018 10:18:04 +0300
+Subject: [PATCH 34/47] PEImageLayout: clear instruction cache after
+ relocations
+
+It fixes crashes on arm when using AOT images.
+---
+ src/vm/peimagelayout.cpp | 22 ++++++++++++++++++++++
+ 1 file changed, 22 insertions(+)
+
+diff --git a/src/vm/peimagelayout.cpp b/src/vm/peimagelayout.cpp
+index 34ba4d8..4bfbe40 100644
+--- a/src/vm/peimagelayout.cpp
++++ b/src/vm/peimagelayout.cpp
+@@ -150,6 +150,8 @@ void PEImageLayout::ApplyBaseRelocations()
+ SIZE_T cbWriteableRegion = 0;
+ DWORD dwOldProtection = 0;
+
++ BOOL bRelocDone = FALSE;
++
+ COUNT_T dirPos = 0;
+ while (dirPos < dirSize)
+ {
+@@ -176,10 +178,20 @@ void PEImageLayout::ApplyBaseRelocations()
+ // Restore the protection
+ if (dwOldProtection != 0)
+ {
++ BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
++ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
++
+ if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
+ dwOldProtection, &dwOldProtection))
+ ThrowLastError();
+
++ if (bRelocDone && bExecRegion)
++ {
++ ClrFlushInstructionCache(pWriteableRegion, cbWriteableRegion);
++ }
++
++ bRelocDone = FALSE;
++
+ dwOldProtection = 0;
+ }
+
+@@ -222,11 +234,13 @@ void PEImageLayout::ApplyBaseRelocations()
+ {
+ case IMAGE_REL_BASED_PTR:
+ *(TADDR *)address += delta;
++ bRelocDone = TRUE;
+ break;
+
+ #ifdef _TARGET_ARM_
+ case IMAGE_REL_BASED_THUMB_MOV32:
+ PutThumb2Mov32((UINT16 *)address, GetThumb2Mov32((UINT16 *)address) + delta);
++ bRelocDone = TRUE;
+ break;
+ #endif
+
+@@ -245,10 +259,18 @@ void PEImageLayout::ApplyBaseRelocations()
+
+ if (dwOldProtection != 0)
+ {
++ BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
++ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
++
+ // Restore the protection
+ if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
+ dwOldProtection, &dwOldProtection))
+ ThrowLastError();
++
++ if (bRelocDone && bExecRegion)
++ {
++ ClrFlushInstructionCache(pWriteableRegion, cbWriteableRegion);
++ }
+ }
+ }
+ #endif // FEATURE_PREJIT
+--
+2.7.4
+
diff --git a/packaging/0035-PEImageLayout-flush-instruction-cache-only-for-pages.patch b/packaging/0035-PEImageLayout-flush-instruction-cache-only-for-pages.patch
new file mode 100644
index 0000000000..e986952668
--- /dev/null
+++ b/packaging/0035-PEImageLayout-flush-instruction-cache-only-for-pages.patch
@@ -0,0 +1,117 @@
+From c5539d864c61476446542bee351af3a125118ef3 Mon Sep 17 00:00:00 2001
+From: Konstantin Baladurin <k.baladurin@partner.samsung.com>
+Date: Mon, 14 May 2018 12:35:09 +0300
+Subject: [PATCH 35/47] PEImageLayout: flush instruction cache only for pages
+ with relocs.
+
+We need to flush instruction cache only for pages that have relocations
+instead of full sections because otherwise application's shared clean
+memory is increased in some cases on Linux.
+---
+ src/vm/peimagelayout.cpp | 46 +++++++++++++++++++++++++++++-----------------
+ 1 file changed, 29 insertions(+), 17 deletions(-)
+
+diff --git a/src/vm/peimagelayout.cpp b/src/vm/peimagelayout.cpp
+index 4bfbe40..5e0243b 100644
+--- a/src/vm/peimagelayout.cpp
++++ b/src/vm/peimagelayout.cpp
+@@ -150,7 +150,10 @@ void PEImageLayout::ApplyBaseRelocations()
+ SIZE_T cbWriteableRegion = 0;
+ DWORD dwOldProtection = 0;
+
+- BOOL bRelocDone = FALSE;
++ BYTE * pFlushRegion = NULL;
++ SIZE_T cbFlushRegion = 0;
++ // The page size of PE file relocs is always 4096 bytes
++ const SIZE_T cbPageSize = 4096;
+
+ COUNT_T dirPos = 0;
+ while (dirPos < dirSize)
+@@ -185,13 +188,6 @@ void PEImageLayout::ApplyBaseRelocations()
+ dwOldProtection, &dwOldProtection))
+ ThrowLastError();
+
+- if (bRelocDone && bExecRegion)
+- {
+- ClrFlushInstructionCache(pWriteableRegion, cbWriteableRegion);
+- }
+-
+- bRelocDone = FALSE;
+-
+ dwOldProtection = 0;
+ }
+
+@@ -224,6 +220,7 @@ void PEImageLayout::ApplyBaseRelocations()
+ }
+ }
+
++ BYTE* pEndAddressToFlush = NULL;
+ for (COUNT_T fixupIndex = 0; fixupIndex < fixupsCount; fixupIndex++)
+ {
+ USHORT fixup = VAL16(fixups[fixupIndex]);
+@@ -234,13 +231,13 @@ void PEImageLayout::ApplyBaseRelocations()
+ {
+ case IMAGE_REL_BASED_PTR:
+ *(TADDR *)address += delta;
+- bRelocDone = TRUE;
++ pEndAddressToFlush = max(pEndAddressToFlush, address + sizeof(TADDR));
+ break;
+
+ #ifdef _TARGET_ARM_
+ case IMAGE_REL_BASED_THUMB_MOV32:
+ PutThumb2Mov32((UINT16 *)address, GetThumb2Mov32((UINT16 *)address) + delta);
+- bRelocDone = TRUE;
++ pEndAddressToFlush = max(pEndAddressToFlush, address + 8);
+ break;
+ #endif
+
+@@ -253,24 +250,39 @@ void PEImageLayout::ApplyBaseRelocations()
+ }
+ }
+
++ BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
++ PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
++
++ if (bExecRegion && pEndAddressToFlush != NULL)
++ {
++ // If the current page is not next to the pending region to flush, flush the current pending region and start a new one
++ if (pageAddress >= pFlushRegion + cbFlushRegion + cbPageSize || pageAddress < pFlushRegion)
++ {
++ if (pFlushRegion != NULL)
++ {
++ ClrFlushInstructionCache(pFlushRegion, cbFlushRegion);
++ }
++ pFlushRegion = pageAddress;
++ }
++
++ cbFlushRegion = pEndAddressToFlush - pFlushRegion;
++ }
++
+ dirPos += fixupsSize;
+ }
+ _ASSERTE(dirSize == dirPos);
+
+ if (dwOldProtection != 0)
+ {
+- BOOL bExecRegion = (dwOldProtection & (PAGE_EXECUTE | PAGE_EXECUTE_READ |
+- PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)) != 0;
+-
+ // Restore the protection
+ if (!ClrVirtualProtect(pWriteableRegion, cbWriteableRegion,
+ dwOldProtection, &dwOldProtection))
+ ThrowLastError();
++ }
+
+- if (bRelocDone && bExecRegion)
+- {
+- ClrFlushInstructionCache(pWriteableRegion, cbWriteableRegion);
+- }
++ if (pFlushRegion != NULL)
++ {
++ ClrFlushInstructionCache(pFlushRegion, cbFlushRegion);
+ }
+ }
+ #endif // FEATURE_PREJIT
+--
+2.7.4
+
diff --git a/packaging/0036-Separate-sections-READONLY_VCHUNKS-and-READONLY_DICT.patch b/packaging/0036-Separate-sections-READONLY_VCHUNKS-and-READONLY_DICT.patch
new file mode 100644
index 0000000000..de86c9ba41
--- /dev/null
+++ b/packaging/0036-Separate-sections-READONLY_VCHUNKS-and-READONLY_DICT.patch
@@ -0,0 +1,59 @@
+From 305bac1e1c272a45ed0682b8bfa871b6099496ae Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Wed, 28 Feb 2018 16:28:00 +0300
+Subject: [PATCH 36/47] Separate sections READONLY_VCHUNKS and
+ READONLY_DICTIONARY
+
+---
+ src/inc/corcompile.h | 3 ++-
+ src/vm/dataimage.cpp | 4 +++-
+ src/zap/zapimage.cpp | 3 ++-
+ 3 files changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/src/inc/corcompile.h b/src/inc/corcompile.h
+index 17fdfcb..1d1f0e4 100644
+--- a/src/inc/corcompile.h
++++ b/src/inc/corcompile.h
+@@ -1329,7 +1329,8 @@ class ICorCompilePreloader
+ CORCOMPILE_SECTION(READONLY_HOT) \
+ CORCOMPILE_SECTION(READONLY_WARM) \
+ CORCOMPILE_SECTION(READONLY_COLD) \
+- CORCOMPILE_SECTION(READONLY_VCHUNKS_AND_DICTIONARY) \
++ CORCOMPILE_SECTION(READONLY_VCHUNKS) \
++ CORCOMPILE_SECTION(READONLY_DICTIONARY) \
+ CORCOMPILE_SECTION(CLASS_COLD) \
+ CORCOMPILE_SECTION(CROSS_DOMAIN_INFO) \
+ CORCOMPILE_SECTION(METHOD_PRECODE_COLD) \
+diff --git a/src/vm/dataimage.cpp b/src/vm/dataimage.cpp
+index 4e276fe..854f214 100644
+--- a/src/vm/dataimage.cpp
++++ b/src/vm/dataimage.cpp
+@@ -749,8 +749,10 @@ FORCEINLINE static CorCompileSection GetSectionForNodeType(ZapNodeType type)
+ return CORCOMPILE_SECTION_READONLY_WARM;
+
+ case NodeTypeForItemKind(DataImage::ITEM_DICTIONARY):
++ return CORCOMPILE_SECTION_READONLY_DICTIONARY;
++
+ case NodeTypeForItemKind(DataImage::ITEM_VTABLE_CHUNK):
+- return CORCOMPILE_SECTION_READONLY_VCHUNKS_AND_DICTIONARY;
++ return CORCOMPILE_SECTION_READONLY_VCHUNKS;
+
+ // SECTION_CLASS_COLD
+ case NodeTypeForItemKind(DataImage::ITEM_PARAM_TYPEDESC):
+diff --git a/src/zap/zapimage.cpp b/src/zap/zapimage.cpp
+index 4c26946..4c1838f 100644
+--- a/src/zap/zapimage.cpp
++++ b/src/zap/zapimage.cpp
+@@ -572,7 +572,8 @@ void ZapImage::AllocateVirtualSections()
+ #endif // defined(WIN64EXCEPTIONS)
+
+ m_pPreloadSections[CORCOMPILE_SECTION_READONLY_WARM] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, sizeof(TADDR));
+- m_pPreloadSections[CORCOMPILE_SECTION_READONLY_VCHUNKS_AND_DICTIONARY] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, sizeof(TADDR));
++ m_pPreloadSections[CORCOMPILE_SECTION_READONLY_VCHUNKS] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, sizeof(TADDR));
++ m_pPreloadSections[CORCOMPILE_SECTION_READONLY_DICTIONARY] = NewVirtualSection(pTextSection, IBCProfiledSection | WarmRange | ReadonlySection, sizeof(TADDR));
+
+ //
+ // GC Info for methods which were not touched in profiling
+--
+2.7.4
+
diff --git a/packaging/0037-Remove-relocations-for-second-level-indirection-of-V.patch b/packaging/0037-Remove-relocations-for-second-level-indirection-of-V.patch
new file mode 100644
index 0000000000..10b9f79891
--- /dev/null
+++ b/packaging/0037-Remove-relocations-for-second-level-indirection-of-V.patch
@@ -0,0 +1,1134 @@
+From 3170d91efb07798e9562a172de2355e6b3851cff Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Thu, 22 Mar 2018 21:14:16 +0300
+Subject: [PATCH 37/47] Remove relocations for second-level indirection of
+ Vtable in case FEATURE_NGEN_RELOCS_OPTIMIZATIONS is enabled.
+
+Introduce FEATURE_NGEN_RELOCS_OPTIMIZATIONS, under which NGEN specific relocations optimizations are enabled
+---
+ clrdefinitions.cmake | 3 ++
+ src/debug/daccess/nidump.cpp | 43 ++++++++++++++++------
+ src/debug/daccess/nidump.h | 9 +++--
+ src/inc/corinfo.h | 14 ++++---
+ src/inc/fixuppointer.h | 33 +++++++++++++++++
+ src/inc/stdmacros.h | 2 +
+ src/jit/codegencommon.cpp | 23 ++++++++++++
+ src/jit/codegenlegacy.cpp | 83 ++++++++++++++++++++++++++++++++++++-----
+ src/jit/importer.cpp | 7 ++--
+ src/jit/lower.cpp | 51 ++++++++++++++++++++-----
+ src/jit/lower.h | 6 +++
+ src/jit/morph.cpp | 17 +++++++--
+ src/vm/arm/stubs.cpp | 26 +++++++++++++
+ src/vm/array.cpp | 4 +-
+ src/vm/generics.cpp | 4 +-
+ src/vm/jitinterface.cpp | 16 ++++++--
+ src/vm/method.cpp | 86 +++++++++++++++++++++++++++++++++++++------
+ src/vm/method.hpp | 11 +++++-
+ src/vm/methodtable.cpp | 27 +++++++++++---
+ src/vm/methodtable.h | 39 ++++++++++++--------
+ src/vm/methodtable.inl | 4 +-
+ src/vm/methodtablebuilder.cpp | 4 +-
+ 22 files changed, 424 insertions(+), 88 deletions(-)
+
+diff --git a/clrdefinitions.cmake b/clrdefinitions.cmake
+index 6db2b24..8ba01c5 100644
+--- a/clrdefinitions.cmake
++++ b/clrdefinitions.cmake
+@@ -171,6 +171,9 @@ add_definitions(-DFEATURE_STRONGNAME_MIGRATION)
+ if (CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_TARGET_ARCH_ARM64)
+ add_definitions(-DFEATURE_STUBS_AS_IL)
+ endif ()
++if (FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++ add_definitions(-DFEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++endif(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ add_definitions(-DFEATURE_SVR_GC)
+ add_definitions(-DFEATURE_SYMDIFF)
+ if (CLR_CMAKE_PLATFORM_ARCH_AMD64)
+diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp
+index 18bef97..2dde08f 100644
+--- a/src/debug/daccess/nidump.cpp
++++ b/src/debug/daccess/nidump.cpp
+@@ -5973,7 +5973,9 @@ void NativeImageDumper::DumpTypes(PTR_Module module)
+
+ for (COUNT_T i = 0; i < slotChunkCount; ++i)
+ {
+- DumpMethodTableSlotChunk(m_discoveredSlotChunks[i].addr, m_discoveredSlotChunks[i].nSlots);
++ DumpMethodTableSlotChunk(m_discoveredSlotChunks[i].addr,
++ m_discoveredSlotChunks[i].nSlots,
++ m_discoveredSlotChunks[i].isRelative);
+ }
+ }
+ DisplayEndArray( "Total MethodTableSlotChunks", METHODTABLES );
+@@ -7239,8 +7241,9 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
+ while (itIndirect.Next())
+ {
+ SlotChunk sc;
+- sc.addr = itIndirect.GetIndirectionSlot();
++ sc.addr = dac_cast<TADDR>(itIndirect.GetIndirectionSlot());
+ sc.nSlots = (WORD)itIndirect.GetNumSlots();
++ sc.isRelative = MethodTable::VTableIndir2_t::isRelative;
+ m_discoveredSlotChunks.AppendEx(sc);
+ }
+
+@@ -7252,7 +7255,7 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
+ DisplayStartElement( "Slot", ALWAYS );
+ DisplayWriteElementInt( "Index", i, ALWAYS );
+ TADDR base = dac_cast<TADDR>(&(mt->GetVtableIndirections()[i]));
+- PTR_PCODE tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base);
++ DPTR(MethodTable::VTableIndir2_t) tgt = MethodTable::VTableIndir_t::GetValueMaybeNullAtPtr(base);
+ DisplayWriteElementPointer( "Pointer",
+ DataPtrToDisplay(dac_cast<TADDR>(tgt)),
+ ALWAYS );
+@@ -7274,8 +7277,9 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
+ DisplayEndElement( ALWAYS ); //Slot
+
+ SlotChunk sc;
+- sc.addr = tgt;
++ sc.addr = dac_cast<TADDR>(tgt);
+ sc.nSlots = (mt->GetNumVtableSlots() - mt->GetNumVirtuals());
++ sc.isRelative = false;
+ m_discoveredSlotChunks.AppendEx(sc);
+ }
+ else if (mt->HasSingleNonVirtualSlot())
+@@ -7411,25 +7415,42 @@ NativeImageDumper::DumpMethodTable( PTR_MethodTable mt, const char * name,
+ #endif
+
+ void
+-NativeImageDumper::DumpMethodTableSlotChunk( PTR_PCODE slotChunk, COUNT_T numSlots )
++NativeImageDumper::DumpMethodTableSlotChunk( TADDR slotChunk, COUNT_T numSlots, bool isRelative )
+ {
+ IF_OPT( METHODTABLES )
+ {
+- DisplayStartStructure( "MethodTableSlotChunk", DPtrToPreferredAddr(slotChunk), numSlots * sizeof(PCODE),
+- METHODTABLES );
++ COUNT_T slotsSize;
++ if (isRelative)
++ {
++ slotsSize = numSlots * sizeof(RelativePointer<PCODE>);
++ }
++ else
++ {
++ slotsSize = numSlots * sizeof(PCODE);
++ }
++ DisplayStartStructure( "MethodTableSlotChunk", DataPtrToDisplay(slotChunk), slotsSize, METHODTABLES );
+
+ IF_OPT(VERBOSE_TYPES)
+ {
+ DisplayStartList( W("[%-4s]: %s (%s)"), ALWAYS );
+ for( unsigned i = 0; i < numSlots; ++i )
+ {
+- DumpSlot(i, slotChunk[i]);
++ PCODE target;
++ if (isRelative)
++ {
++ target = RelativePointer<PCODE>::GetValueMaybeNullAtPtr(slotChunk + i * sizeof(RelativePointer<PCODE>));
++ }
++ else
++ {
++ target = dac_cast<PTR_PCODE>(slotChunk)[i];
++ }
++
++ DumpSlot(i, target);
+ }
+ DisplayEndList( ALWAYS ); //Slot list
+ }
+ else
+- CoverageRead( PTR_TO_TADDR(slotChunk),
+- numSlots * sizeof(PCODE) );
++ CoverageRead( slotChunk, slotsSize );
+ DisplayEndStructure(ALWAYS); //Slot chunk
+ }
+ }
+@@ -7802,7 +7823,7 @@ void NativeImageDumper::DumpMethodDesc( PTR_MethodDesc md, PTR_Module module )
+ }
+ if ( md->HasNonVtableSlot() )
+ {
+- DisplayWriteElementInt( "Slot", (DWORD)(PTR_TO_TADDR(md->GetAddrOfSlot()) - PTR_TO_TADDR(md)), ALWAYS);
++ DisplayWriteElementInt( "Slot", (DWORD)(md->GetAddrOfSlot() - PTR_TO_TADDR(md)), ALWAYS);
+ }
+ if (md->HasNativeCodeSlot())
+ {
+diff --git a/src/debug/daccess/nidump.h b/src/debug/daccess/nidump.h
+index d14eb89..f0c8e7f 100644
+--- a/src/debug/daccess/nidump.h
++++ b/src/debug/daccess/nidump.h
+@@ -195,7 +195,7 @@ public:
+ PTR_Module module );
+
+ #ifndef STUB_DISPATCH_ALL
+- void DumpMethodTableSlotChunk( PTR_PCODE slotChunk, COUNT_T size );
++ void DumpMethodTableSlotChunk( TADDR slotChunk, COUNT_T size, bool );
+ #endif
+
+ void DumpSlot( unsigned index, PCODE tgt );
+@@ -479,6 +479,8 @@ private:
+ template<typename T>
+ TADDR DPtrToPreferredAddr( T ptr );
+
++ TADDR DPtrToPreferredAddr( TADDR tptr );
++
+ void DumpAssemblySignature(CORCOMPILE_ASSEMBLY_SIGNATURE & assemblySignature);
+
+ SIZE_T CountFields( PTR_MethodTable mt );
+@@ -501,12 +503,13 @@ private:
+
+ struct SlotChunk
+ {
+- PTR_PCODE addr;
++ TADDR addr;
+ WORD nSlots;
++ bool isRelative;
+
+ inline bool operator==(const SlotChunk& sc) const
+ {
+- return (addr == sc.addr) && (nSlots == sc.nSlots);
++ return (addr == sc.addr) && (nSlots == sc.nSlots) && (isRelative == sc.isRelative);
+ }
+
+ inline bool operator<(const SlotChunk& sc) const
+diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
+index 63ade7f..1a6843c 100644
+--- a/src/inc/corinfo.h
++++ b/src/inc/corinfo.h
+@@ -970,8 +970,9 @@ enum CorInfoIntrinsics
+ enum InfoAccessType
+ {
+ IAT_VALUE, // The info value is directly available
+- IAT_PVALUE, // The value needs to be accessed via an indirection
+- IAT_PPVALUE // The value needs to be accessed via a double indirection
++ IAT_PVALUE, // The value needs to be accessed via an indirection
++ IAT_RELPVALUE, // The value needs to be accessed via a relative indirection
++ IAT_PPVALUE // The value needs to be accessed via a double indirection
+ };
+
+ enum CorInfoGCType
+@@ -1236,6 +1237,7 @@ struct CORINFO_METHOD_INFO
+ // Constant Lookups are either:
+ // IAT_VALUE: immediate (relocatable) values,
+ // IAT_PVALUE: immediate values access via an indirection through an immediate (relocatable) address
++// IAT_RELPVALUE: immediate values access via a relative indirection through an immediate offset
+ // IAT_PPVALUE: immediate values access via a double indirection through an immediate (relocatable) address
+ //
+ // Runtime Lookups
+@@ -1261,9 +1263,10 @@ struct CORINFO_CONST_LOOKUP
+ // If the handle is obtained at compile-time, then this handle is the "exact" handle (class, method, or field)
+ // Otherwise, it's a representative...
+ // If accessType is
+- // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address
+- // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle
+- // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle
++ // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address
++ // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle
++ // IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle
++ // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle
+
+ InfoAccessType accessType;
+ union
+@@ -1354,6 +1357,7 @@ struct CORINFO_LOOKUP
+ // Otherwise, it's a representative... If accessType is
+ // IAT_VALUE --> "handle" stores the real handle or "addr " stores the computed address
+ // IAT_PVALUE --> "addr" stores a pointer to a location which will hold the real handle
++ // IAT_RELPVALUE --> "addr" stores a relative pointer to a location which will hold the real handle
+ // IAT_PPVALUE --> "addr" stores a double indirection to a location which will hold the real handle
+ CORINFO_CONST_LOOKUP constLookup;
+ };
+diff --git a/src/inc/fixuppointer.h b/src/inc/fixuppointer.h
+index 5a897e4..abed1f9 100644
+--- a/src/inc/fixuppointer.h
++++ b/src/inc/fixuppointer.h
+@@ -156,6 +156,26 @@ public:
+ }
+ #endif // DACCESS_COMPILE
+
++ static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ if (addr == NULL)
++ {
++ return NULL;
++ }
++ else
++ {
++ return addr - base;
++ }
++ }
++
++ static TADDR GetRelative(TADDR base, TADDR addr)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ PRECONDITION(addr != NULL);
++ return addr - base;
++ }
++
+ private:
+ #ifndef DACCESS_COMPILE
+ Volatile<TADDR> m_delta;
+@@ -721,6 +741,19 @@ public:
+ }
+ #endif
+
++ static TADDR GetRelativeMaybeNull(TADDR base, TADDR addr)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ return addr;
++ }
++
++ static TADDR GetRelative(TADDR base, TADDR addr)
++ {
++ LIMITED_METHOD_DAC_CONTRACT;
++ PRECONDITION(addr != NULL);
++ return addr;
++ }
++
+ private:
+ TADDR m_ptr;
+ };
+diff --git a/src/inc/stdmacros.h b/src/inc/stdmacros.h
+index 3ec8bec..6cef412 100644
+--- a/src/inc/stdmacros.h
++++ b/src/inc/stdmacros.h
+@@ -87,12 +87,14 @@
+ #ifdef _TARGET_ARM_
+ #define ARM_FIRST_ARG(x) x ,
+ #define ARM_ARG(x) , x
++#define ARM_ARG_OR_ZERO(x) , x
+ #define ARM_ONLY(x) x
+ #define NOT_ARM(x)
+ #define NOT_ARM_ARG(x)
+ #else
+ #define ARM_FIRST_ARG(x)
+ #define ARM_ARG(x)
++#define ARM_ARG_OR_ZERO(x) , 0
+ #define ARM_ONLY(x)
+ #define NOT_ARM(x) x
+ #define NOT_ARM_ARG(x) , x
+diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
+index 9613e4d..51cc777 100644
+--- a/src/jit/codegencommon.cpp
++++ b/src/jit/codegencommon.cpp
+@@ -9495,6 +9495,29 @@ void CodeGen::genFnEpilog(BasicBlock* block)
+ regTracker.rsTrackRegTrash(indCallReg);
+ }
+ break;
++
++ case IAT_RELPVALUE:
++ {
++ // Load the address into a register, load relative indirect and call through a register
++ // We have to use R12 since we assume the argument registers are in use
++ callType = emitter::EC_INDIR_R;
++ indCallReg = REG_R12;
++ addr = NULL;
++
++ regNumber vptrReg1 = REG_R11;
++ regMaskTP vptrReg1Mask = genRegMask(vptrReg1);
++ inst_IV(INS_push, (int)vptrReg1Mask);
++
++ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr);
++ getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, vptrReg1, indCallReg);
++ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
++ getEmitter()->emitIns_R_R(INS_add, EA_PTRSIZE, indCallReg, vptrReg1);
++
++ inst_IV(INS_pop, (int)vptrReg1Mask);
++
++ regTracker.rsTrackRegTrash(indCallReg);
++ break;
++ }
+
+ case IAT_PPVALUE:
+ default:
+diff --git a/src/jit/codegenlegacy.cpp b/src/jit/codegenlegacy.cpp
+index 53c8f8d..aec5bba 100644
+--- a/src/jit/codegenlegacy.cpp
++++ b/src/jit/codegenlegacy.cpp
+@@ -18958,13 +18958,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed)
+ {
+ if (isRelative)
+ {
+-#if defined(_TARGET_ARM_)
+- /* Load the function address: "[vptrReg1 + vptrReg] -> reg_intret" */
+- getEmitter()->emitIns_R_ARR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, REG_TAILCALL_ADDR, vptrReg1,
+- vptrReg, 0);
+-#else
+- unreached();
+-#endif
++ getEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, vptrReg1, vptrReg1, vptrReg);
++ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg1, 0);
++ getEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, REG_TAILCALL_ADDR, vptrReg1, vptrReg);
+ }
+ else
+ {
+@@ -18978,8 +18974,9 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed)
+ #if CPU_LOAD_STORE_ARCH
+ if (isRelative)
+ {
+- getEmitter()->emitIns_R_ARR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg1, vptrReg,
+- 0);
++ getEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, vptrReg1, vptrReg1, vptrReg);
++ getEmitter()->emitIns_R_AR(ins_Load(TYP_I_IMPL), EA_PTRSIZE, vptrReg, vptrReg1, 0);
++ getEmitter()->emitIns_R_R_R(INS_add, EA_PTRSIZE, vptrReg, vptrReg1, vptrReg);
+ }
+ else
+ {
+@@ -19387,6 +19384,34 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed)
+ #endif
+ break;
+
++ case IAT_RELPVALUE:
++ //------------------------------------------------------
++ // Non-virtual direct calls to addresses accessed by
++ // a single relative indirection.
++ //
++ // For tailcalls we place the target address in REG_TAILCALL_ADDR
++ CLANG_FORMAT_COMMENT_ANCHOR;
++
++#if CPU_LOAD_STORE_ARCH
++ {
++ regNumber indReg = REG_TAILCALL_ADDR;
++ regNumber vptrReg1 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(indReg));
++ regMaskTP vptrMask1 = genRegMask(vptrReg1);
++
++ gcInfo.gcMarkRegSetNpt(vptrMask1);
++ regTracker.rsTrackRegTrash(vptrReg1);
++
++ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indReg, (ssize_t)addr);
++ getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, vptrReg1, indReg);
++ getEmitter()->emitIns_R_R_I(INS_ldr, EA_4BYTE, indReg, indReg, 0);
++ getEmitter()->emitIns_R_R(INS_add, EA_4BYTE, indReg, vptrReg1);
++ regTracker.rsTrackRegTrash(indReg);
++ }
++#else
++ unreached();
++#endif
++ break;
++
+ default:
+ noway_assert(!"Bad accessType");
+ break;
+@@ -19530,6 +19555,46 @@ regMaskTP CodeGen::genCodeForCall(GenTreeCall* call, bool valUsed)
+ }
+ break;
+
++ case IAT_RELPVALUE:
++ {
++ //------------------------------------------------------
++ // Non-virtual direct calls to addresses accessed by
++ // a single relative indirection.
++ //
++
++ // Load the address into a register, load indirect and call through a register
++ CLANG_FORMAT_COMMENT_ANCHOR;
++
++ regMaskTP indCallMask = RBM_ALLINT;
++
++ // Grab an available register to use for the CALL indirection
++ indCallReg = regSet.rsGrabReg(indCallMask);
++
++ regNumber vptrReg1 = regSet.rsGrabReg(RBM_ALLINT & ~genRegMask(indCallReg));
++ regMaskTP vptrMask1 = genRegMask(vptrReg1);
++
++ gcInfo.gcMarkRegSetNpt(vptrMask1);
++ regTracker.rsTrackRegTrash(vptrReg1);
++
++ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addr);
++ getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, vptrReg1, indCallReg);
++ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
++ getEmitter()->emitIns_R_R(INS_add, EA_PTRSIZE, indCallReg, vptrReg1);
++ regTracker.rsTrackRegTrash(indCallReg);
++
++ emitCallType = emitter::EC_INDIR_R;
++ addr = NULL;
++
++ getEmitter()->emitIns_Call(emitCallType, methHnd, INDEBUG_LDISASM_COMMA(sigInfo) addr, args,
++ retSize, gcInfo.gcVarPtrSetCur, gcInfo.gcRegGCrefSetCur,
++ gcInfo.gcRegByrefSetCur, ilOffset,
++ indCallReg, // ireg
++ REG_NA, 0, 0, // xreg, xmul, disp
++ false, /* isJump */
++ emitter::emitNoGChelper(helperNum));
++ }
++ break;
++
+ default:
+ noway_assert(!"Bad accessType");
+ break;
+diff --git a/src/jit/importer.cpp b/src/jit/importer.cpp
+index b4ee1d0..e9dca90 100644
+--- a/src/jit/importer.cpp
++++ b/src/jit/importer.cpp
+@@ -1768,7 +1768,7 @@ GenTreePtr Compiler::impLookupToTree(CORINFO_RESOLVED_TOKEN* pResolvedToken,
+
+ CORINFO_GENERIC_HANDLE handle = nullptr;
+ void* pIndirection = nullptr;
+- assert(pLookup->constLookup.accessType != IAT_PPVALUE);
++ assert(pLookup->constLookup.accessType != IAT_PPVALUE && pLookup->constLookup.accessType != IAT_RELPVALUE);
+
+ if (pLookup->constLookup.accessType == IAT_VALUE)
+ {
+@@ -1803,7 +1803,7 @@ GenTreePtr Compiler::impReadyToRunLookupToTree(CORINFO_CONST_LOOKUP* pLookup,
+ {
+ CORINFO_GENERIC_HANDLE handle = nullptr;
+ void* pIndirection = nullptr;
+- assert(pLookup->accessType != IAT_PPVALUE);
++ assert(pLookup->accessType != IAT_PPVALUE && pLookup->accessType != IAT_RELPVALUE);
+
+ if (pLookup->accessType == IAT_VALUE)
+ {
+@@ -6828,7 +6828,8 @@ var_types Compiler::impImportCall(OPCODE opcode,
+ call = gtNewCallNode(CT_USER_FUNC, callInfo->hMethod, callRetTyp, nullptr, ilOffset);
+ call->gtCall.gtStubCallStubAddr = callInfo->stubLookup.constLookup.addr;
+ call->gtFlags |= GTF_CALL_VIRT_STUB;
+- assert(callInfo->stubLookup.constLookup.accessType != IAT_PPVALUE);
++ assert(callInfo->stubLookup.constLookup.accessType != IAT_PPVALUE &&
++ callInfo->stubLookup.constLookup.accessType != IAT_RELPVALUE);
+ if (callInfo->stubLookup.constLookup.accessType == IAT_PVALUE)
+ {
+ call->gtCall.gtCallMoreFlags |= GTF_CALL_M_VIRTSTUB_REL_INDIRECT;
+diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
+index c06dcb6..5c0cf69 100644
+--- a/src/jit/lower.cpp
++++ b/src/jit/lower.cpp
+@@ -2567,6 +2567,16 @@ GenTree* Lowering::LowerDirectCall(GenTreeCall* call)
+ result = Ind(Ind(result));
+ break;
+
++ case IAT_RELPVALUE:
++ {
++ // Non-virtual direct calls to addresses accessed by
++ // a single relative indirection.
++ GenTree* cellAddr = AddrGen(addr);
++ GenTree* indir = Ind(cellAddr);
++ result = comp->gtNewOperNode(GT_ADD, TYP_I_IMPL, indir, AddrGen(addr));
++ break;
++ }
++
+ default:
+ noway_assert(!"Bad accessType");
+ break;
+@@ -3339,6 +3349,9 @@ GenTree* Lowering::LowerNonvirtPinvokeCall(GenTreeCall* call)
+ case IAT_PPVALUE:
+ result = Ind(Ind(AddrGen(addr)));
+ break;
++
++ case IAT_RELPVALUE:
++ unreached();
+ }
+ }
+
+@@ -3433,19 +3446,24 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
+ //
+ // Save relative offset to tmp (vtab is virtual table pointer, vtabOffsOfIndirection is offset of
+ // vtable-1st-level-indirection):
+- // tmp = [vtab + vtabOffsOfIndirection]
++ // tmp = vtab
+ //
+ // Save address of method to result (vtabOffsAfterIndirection is offset of vtable-2nd-level-indirection):
+- // result = [vtab + vtabOffsOfIndirection + vtabOffsAfterIndirection + tmp]
++ // result = [tmp + vtabOffsOfIndirection + vtabOffsAfterIndirection + [tmp + vtabOffsOfIndirection]]
++ //
++ //
++ // If relative pointers are also in second level indirection, additional temporary is used:
++ // tmp1 = vtab
++ // tmp2 = tmp1 + vtabOffsOfIndirection + vtabOffsAfterIndirection + [tmp1 + vtabOffsOfIndirection]
++ // result = tmp2 + [tmp2]
++ //
+ unsigned lclNumTmp = comp->lvaGrabTemp(true DEBUGARG("lclNumTmp"));
+-
+ comp->lvaTable[lclNumTmp].incRefCnts(comp->compCurBB->getBBWeight(comp), comp);
+- GenTree* lclvNodeStore = comp->gtNewTempAssign(lclNumTmp, result);
+
+- LIR::Range range = LIR::SeqTree(comp, lclvNodeStore);
+- JITDUMP("result of obtaining pointer to virtual table:\n");
+- DISPRANGE(range);
+- BlockRange().InsertBefore(call, std::move(range));
++ unsigned lclNumTmp2 = comp->lvaGrabTemp(true DEBUGARG("lclNumTmp2"));
++ comp->lvaTable[lclNumTmp2].incRefCnts(comp->compCurBB->getBBWeight(comp), comp);
++
++ GenTree* lclvNodeStore = comp->gtNewTempAssign(lclNumTmp, result);
+
+ GenTree* tmpTree = comp->gtNewLclvNode(lclNumTmp, result->TypeGet());
+ tmpTree = Offset(tmpTree, vtabOffsOfIndirection);
+@@ -3454,7 +3472,22 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
+ GenTree* offs = comp->gtNewIconNode(vtabOffsOfIndirection + vtabOffsAfterIndirection, TYP_INT);
+ result = comp->gtNewOperNode(GT_ADD, TYP_I_IMPL, comp->gtNewLclvNode(lclNumTmp, result->TypeGet()), offs);
+
+- result = Ind(OffsetByIndex(result, tmpTree));
++ GenTree* base = OffsetByIndexWithScale(result, tmpTree, 1);
++ GenTree* lclvNodeStore2 = comp->gtNewTempAssign(lclNumTmp2, base);
++
++ LIR::Range range = LIR::SeqTree(comp, lclvNodeStore);
++ JITDUMP("result of obtaining pointer to virtual table:\n");
++ DISPRANGE(range);
++ BlockRange().InsertBefore(call, std::move(range));
++
++ LIR::Range range2 = LIR::SeqTree(comp, lclvNodeStore2);
++ JITDUMP("result of obtaining pointer to virtual table 2nd level indirection:\n");
++ DISPRANGE(range2);
++ BlockRange().InsertAfter(lclvNodeStore, std::move(range2));
++
++ result = Ind(comp->gtNewLclvNode(lclNumTmp2, result->TypeGet()));
++ result =
++ comp->gtNewOperNode(GT_ADD, TYP_I_IMPL, result, comp->gtNewLclvNode(lclNumTmp2, result->TypeGet()));
+ }
+ else
+ {
+diff --git a/src/jit/lower.h b/src/jit/lower.h
+index 92d9cfe..af80fdd 100644
+--- a/src/jit/lower.h
++++ b/src/jit/lower.h
+@@ -128,6 +128,12 @@ private:
+
+ // returns true if the tree can use the read-modify-write memory instruction form
+ bool isRMWRegOper(GenTreePtr tree);
++
++ GenTree* OffsetByIndexWithScale(GenTree* base, GenTree* index, unsigned scale)
++ {
++ var_types resultType = (base->TypeGet() == TYP_REF) ? TYP_BYREF : base->TypeGet();
++ return new (comp, GT_LEA) GenTreeAddrMode(resultType, base, index, scale, 0);
++ }
+
+ // return true if this call target is within range of a pc-rel call on the machine
+ bool IsCallTargetInRange(void* addr);
+diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
+index 993ce53..3f57191 100644
+--- a/src/jit/morph.cpp
++++ b/src/jit/morph.cpp
+@@ -7124,7 +7124,7 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
+
+ add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsOfIndirection, TYP_I_IMPL));
+
+- GenTreePtr indOffTree;
++ GenTreePtr indOffTree = nullptr;
+
+ if (isRelative)
+ {
+@@ -7141,8 +7141,19 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
+
+ /* Now the appropriate vtable slot */
+
+- add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsAfterIndirection, TYP_I_IMPL));
+- vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
++ add = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, gtNewIconNode(vtabOffsAfterIndirection, TYP_I_IMPL));
++
++ if (isRelative)
++ {
++ indOffTree = impCloneExpr(add, &add, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
++ nullptr DEBUGARG("virtual table call 2"));
++ vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
++ vtbl = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, indOffTree);
++ }
++ else
++ {
++ vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
++ }
+
+ // Switch this to a plain indirect call
+ call->gtFlags &= ~GTF_CALL_VIRT_KIND_MASK;
+diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp
+index a52f0c8..ec0a1e7 100644
+--- a/src/vm/arm/stubs.cpp
++++ b/src/vm/arm/stubs.cpp
+@@ -1732,8 +1732,34 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall)
+ // mov r12, #slotaddress
+ ThumbEmitMovConstant(ThumbReg(12), (TADDR)pMD->GetAddrOfSlot());
+
++ bool isRelative = MethodTable::VTableIndir2_t::isRelative
++ && pMD->IsVtableSlot();
++ if (isRelative)
++ {
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++ // push r11
++ ThumbEmitPush(ThumbReg(11).Mask());
++ // mov r11, r12
++ ThumbEmitMovRegReg(ThumbReg(11), ThumbReg(12));
++#else
++ _ASSERTE(false);
++#endif
++ }
++
+ // ldr r12, [r12]
+ ThumbEmitLoadRegIndirect(ThumbReg(12), ThumbReg(12), 0);
++
++ if (isRelative)
++ {
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++ // add r12, r11
++ ThumbEmitAddReg(ThumbReg(12), ThumbReg(11));
++ // pop r11
++ ThumbEmitPop(ThumbReg(11).Mask());
++#else
++ _ASSERTE(false);
++#endif
++ }
+ }
+
+ if (fTailcall)
+diff --git a/src/vm/array.cpp b/src/vm/array.cpp
+index 3a33aff..ac0e2c6 100644
+--- a/src/vm/array.cpp
++++ b/src/vm/array.cpp
+@@ -374,7 +374,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
+ // If none, we need to allocate space for the slots
+ if (!canShareVtableChunks)
+ {
+- cbMT += numVirtuals * sizeof(PCODE);
++ cbMT += numVirtuals * sizeof(MethodTable::VTableIndir2_t);
+ }
+
+ // Canonical methodtable has an array of non virtual slots pointed to by the optional member
+@@ -544,7 +544,7 @@ MethodTable* Module::CreateArrayMethodTable(TypeHandle elemTypeHnd, CorElementTy
+ else
+ {
+ // Use the locally allocated chunk
+- it.SetIndirectionSlot((PTR_PCODE)(pMemory+cbArrayClass+offsetOfUnsharedVtableChunks));
++ it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pMemory+cbArrayClass+offsetOfUnsharedVtableChunks));
+ offsetOfUnsharedVtableChunks += it.GetSize();
+ }
+ }
+diff --git a/src/vm/generics.cpp b/src/vm/generics.cpp
+index 61a1de5..d45578b 100644
+--- a/src/vm/generics.cpp
++++ b/src/vm/generics.cpp
+@@ -324,7 +324,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
+ // If none, we need to allocate space for the slots
+ if (!canShareVtableChunks)
+ {
+- allocSize += S_SIZE_T( cSlots ) * S_SIZE_T( sizeof(PCODE) );
++ allocSize += S_SIZE_T( cSlots ) * S_SIZE_T( sizeof(MethodTable::VTableIndir2_t) );
+ }
+
+ if (allocSize.IsOverflow())
+@@ -446,7 +446,7 @@ ClassLoader::CreateTypeHandleForNonCanonicalGenericInstantiation(
+ else
+ {
+ // Use the locally allocated chunk
+- it.SetIndirectionSlot((PTR_PCODE)(pMemory+offsetOfUnsharedVtableChunks));
++ it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pMemory+offsetOfUnsharedVtableChunks));
+ offsetOfUnsharedVtableChunks += it.GetSize();
+ }
+ }
+diff --git a/src/vm/jitinterface.cpp b/src/vm/jitinterface.cpp
+index 9cefd10..9e5d625 100644
+--- a/src/vm/jitinterface.cpp
++++ b/src/vm/jitinterface.cpp
+@@ -8747,8 +8747,9 @@ void CEEInfo::getMethodVTableOffset (CORINFO_METHOD_HANDLE methodHnd,
+ _ASSERTE(method->GetSlot() < method->GetMethodTable()->GetNumVirtuals());
+
+ *pOffsetOfIndirection = MethodTable::GetVtableOffset() + MethodTable::GetIndexOfVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir_t);
+- *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(PCODE);
++ *pOffsetAfterIndirection = MethodTable::GetIndexAfterVtableIndirection(method->GetSlot()) * sizeof(MethodTable::VTableIndir2_t);
+ *isRelative = MethodTable::VTableIndir_t::isRelative ? 1 : 0;
++ _ASSERTE(MethodTable::VTableIndir_t::isRelative == MethodTable::VTableIndir2_t::isRelative);
+
+ EE_TO_JIT_TRANSITION_LEAF();
+ }
+@@ -8945,8 +8946,17 @@ void CEEInfo::getFunctionEntryPoint(CORINFO_METHOD_HANDLE ftnHnd,
+
+ _ASSERTE((accessFlags & CORINFO_ACCESS_THIS) || !ftn->IsRemotingInterceptedViaVirtualDispatch());
+
+- ret = ftn->GetAddrOfSlot();
+- accessType = IAT_PVALUE;
++ ret = (void *)ftn->GetAddrOfSlot();
++
++ if (MethodTable::VTableIndir2_t::isRelative
++ && ftn->IsVtableSlot())
++ {
++ accessType = IAT_RELPVALUE;
++ }
++ else
++ {
++ accessType = IAT_PVALUE;
++ }
+ }
+
+
+diff --git a/src/vm/method.cpp b/src/vm/method.cpp
+index 6bd49fb..36d51fd 100644
+--- a/src/vm/method.cpp
++++ b/src/vm/method.cpp
+@@ -568,7 +568,7 @@ PCODE MethodDesc::GetMethodEntryPoint()
+ return GetMethodTable_NoLogging()->GetSlot(GetSlot());
+ }
+
+-PTR_PCODE MethodDesc::GetAddrOfSlot()
++TADDR MethodDesc::GetAddrOfSlot()
+ {
+ CONTRACTL
+ {
+@@ -589,7 +589,7 @@ PTR_PCODE MethodDesc::GetAddrOfSlot()
+
+ SIZE_T size = GetBaseSize();
+
+- return PTR_PCODE(dac_cast<TADDR>(this) + size);
++ return dac_cast<TADDR>(this) + size;
+ }
+
+ _ASSERTE(GetMethodTable()->IsCanonicalMethodTable());
+@@ -2489,7 +2489,15 @@ void MethodDesc::Reset()
+
+ InterlockedUpdateFlags2(enum_flag2_HasStableEntryPoint | enum_flag2_HasPrecode, FALSE);
+
+- *GetAddrOfSlot() = GetTemporaryEntryPoint();
++ TADDR slot = GetAddrOfSlot();
++ if (IsVtableSlot())
++ {
++ ((MethodTable::VTableIndir2_t *) slot)->SetValue(GetTemporaryEntryPoint());
++ }
++ else
++ {
++ *((PCODE *) slot) = GetTemporaryEntryPoint();
++ }
+ }
+
+ if (HasNativeCodeSlot())
+@@ -5008,9 +5016,19 @@ void MethodDesc::SetTemporaryEntryPoint(LoaderAllocator *pLoaderAllocator, Alloc
+
+ GetMethodDescChunk()->EnsureTemporaryEntryPointsCreated(pLoaderAllocator, pamTracker);
+
+- PTR_PCODE pSlot = GetAddrOfSlot();
+- _ASSERTE(*pSlot == NULL);
+- *pSlot = GetTemporaryEntryPoint();
++ TADDR slot = GetAddrOfSlot();
++ if (IsVtableSlot())
++ {
++ MethodTable::VTableIndir2_t *slotPtr = ((MethodTable::VTableIndir2_t *) slot);
++ _ASSERTE(slotPtr->IsNull());
++ slotPtr->SetValue(GetTemporaryEntryPoint());
++ }
++ else
++ {
++ PCODE *slotPtr = (PCODE *) slot;
++ _ASSERTE(*slotPtr == NULL);
++ *slotPtr = GetTemporaryEntryPoint();
++ }
+
+ if (RequiresStableEntryPoint())
+ {
+@@ -5073,7 +5091,7 @@ Precode* MethodDesc::GetOrCreatePrecode()
+ return GetPrecode();
+ }
+
+- PTR_PCODE pSlot = GetAddrOfSlot();
++ TADDR pSlot = GetAddrOfSlot();
+ PCODE tempEntry = GetTemporaryEntryPoint();
+
+ PrecodeType requiredType = GetPrecodeType();
+@@ -5093,14 +5111,40 @@ Precode* MethodDesc::GetOrCreatePrecode()
+
+ AllocMemTracker amt;
+ Precode* pPrecode = Precode::Allocate(requiredType, this, GetLoaderAllocator(), &amt);
+- if (FastInterlockCompareExchangePointer(EnsureWritablePages(pSlot), pPrecode->GetEntryPoint(), tempEntry) == tempEntry)
++ PCODE newVal;
++ PCODE oldVal;
++ TADDR *slotAddr;
++
++ if (IsVtableSlot())
++ {
++ newVal = MethodTable::VTableIndir2_t::GetRelative(pSlot, pPrecode->GetEntryPoint());
++ oldVal = MethodTable::VTableIndir2_t::GetRelative(pSlot, tempEntry);
++ slotAddr = (TADDR *) EnsureWritablePages((MethodTable::VTableIndir2_t *) pSlot);
++ }
++ else
++ {
++ newVal = pPrecode->GetEntryPoint();
++ oldVal = tempEntry;
++ slotAddr = (TADDR *) EnsureWritablePages((PCODE *) pSlot);
++ }
++
++ if (FastInterlockCompareExchangePointer(slotAddr, (TADDR) newVal, (TADDR) oldVal) == oldVal)
+ amt.SuppressRelease();
+ }
+
+ // Set the flags atomically
+ InterlockedUpdateFlags2(enum_flag2_HasStableEntryPoint | enum_flag2_HasPrecode, TRUE);
+
+- return Precode::GetPrecodeFromEntryPoint(*pSlot);
++ PCODE addr;
++ if (IsVtableSlot())
++ {
++ addr = ((MethodTable::VTableIndir2_t *)pSlot)->GetValue();
++ }
++ else
++ {
++ addr = *((PCODE *)pSlot);
++ }
++ return Precode::GetPrecodeFromEntryPoint(addr);
+ }
+
+ //*******************************************************************************
+@@ -5182,10 +5226,28 @@ BOOL MethodDesc::SetStableEntryPointInterlocked(PCODE addr)
+ _ASSERTE(!HasPrecode());
+
+ PCODE pExpected = GetTemporaryEntryPoint();
+- PTR_PCODE pSlot = GetAddrOfSlot();
+- EnsureWritablePages(pSlot);
++ TADDR pSlot = GetAddrOfSlot();
+
+- BOOL fResult = FastInterlockCompareExchangePointer(pSlot, addr, pExpected) == pExpected;
++ BOOL fResult;
++
++ TADDR *slotAddr;
++ PCODE newVal;
++ PCODE oldVal;
++
++ if (IsVtableSlot())
++ {
++ newVal = MethodTable::VTableIndir2_t::GetRelative(pSlot, addr);
++ oldVal = MethodTable::VTableIndir2_t::GetRelative(pSlot, pExpected);
++ slotAddr = (TADDR *) EnsureWritablePages((MethodTable::VTableIndir2_t *) pSlot);
++ }
++ else
++ {
++ newVal = addr;
++ oldVal = pExpected;
++ slotAddr = (TADDR *) EnsureWritablePages((PCODE *) pSlot);
++ }
++
++ fResult = FastInterlockCompareExchangePointer(slotAddr, (TADDR) newVal, (TADDR) oldVal) == oldVal;
+
+ InterlockedUpdateFlags2(enum_flag2_HasStableEntryPoint, TRUE);
+
+diff --git a/src/vm/method.hpp b/src/vm/method.hpp
+index 9023a1b..92fbdee 100644
+--- a/src/vm/method.hpp
++++ b/src/vm/method.hpp
+@@ -1203,7 +1203,16 @@ public:
+ }
+ }
+
+- PTR_PCODE GetAddrOfSlot();
++ inline BOOL IsVirtualSlot()
++ {
++ return GetSlot() < GetMethodTable()->GetNumVirtuals();
++ }
++ inline BOOL IsVtableSlot()
++ {
++ return IsVirtualSlot() && !HasNonVtableSlot();
++ }
++
++ TADDR GetAddrOfSlot();
+
+ PTR_MethodDesc GetDeclMethodDesc(UINT32 slotNumber);
+
+diff --git a/src/vm/methodtable.cpp b/src/vm/methodtable.cpp
+index b097406..eeffc96 100644
+--- a/src/vm/methodtable.cpp
++++ b/src/vm/methodtable.cpp
+@@ -4267,7 +4267,8 @@ void MethodTable::Save(DataImage *image, DWORD profilingFlags)
+ {
+ if (!image->IsStored(it.GetIndirectionSlot()))
+ {
+- if (CanInternVtableChunk(image, it))
++ if (!MethodTable::VTableIndir2_t::isRelative
++ && CanInternVtableChunk(image, it))
+ image->StoreInternedStructure(it.GetIndirectionSlot(), it.GetSize(), DataImage::ITEM_VTABLE_CHUNK);
+ else
+ image->StoreStructure(it.GetIndirectionSlot(), it.GetSize(), DataImage::ITEM_VTABLE_CHUNK);
+@@ -4955,7 +4956,7 @@ void MethodTable::Fixup(DataImage *image)
+ // Virtual slots live in chunks pointed to by vtable indirections
+
+ slotBase = (PVOID) GetVtableIndirections()[GetIndexOfVtableIndirection(slotNumber)].GetValueMaybeNull();
+- slotOffset = GetIndexAfterVtableIndirection(slotNumber) * sizeof(PCODE);
++ slotOffset = GetIndexAfterVtableIndirection(slotNumber) * sizeof(MethodTable::VTableIndir2_t);
+ }
+ else if (HasSingleNonVirtualSlot())
+ {
+@@ -4982,7 +4983,7 @@ void MethodTable::Fixup(DataImage *image)
+ if (pMD->GetMethodTable() == this)
+ {
+ ZapRelocationType relocType;
+- if (slotNumber >= GetNumVirtuals())
++ if (slotNumber >= GetNumVirtuals() || MethodTable::VTableIndir2_t::isRelative)
+ relocType = IMAGE_REL_BASED_RelativePointer;
+ else
+ relocType = IMAGE_REL_BASED_PTR;
+@@ -5005,9 +5006,15 @@ void MethodTable::Fixup(DataImage *image)
+ _ASSERTE(pSourceMT->GetMethodDescForSlot(slotNumber) == pMD);
+ #endif
+
++ ZapRelocationType relocType;
++ if (MethodTable::VTableIndir2_t::isRelative)
++ relocType = IMAGE_REL_BASED_RELPTR;
++ else
++ relocType = IMAGE_REL_BASED_PTR;
++
+ if (image->CanEagerBindToMethodDesc(pMD) && pMD->GetLoaderModule() == pZapModule)
+ {
+- pMD->FixupSlot(image, slotBase, slotOffset);
++ pMD->FixupSlot(image, slotBase, slotOffset, relocType);
+ }
+ else
+ {
+@@ -5016,7 +5023,7 @@ void MethodTable::Fixup(DataImage *image)
+ ZapNode * importThunk = image->GetVirtualImportThunk(pMD->GetMethodTable(), pMD, slotNumber);
+ // On ARM, make sure that the address to the virtual thunk that we write into the
+ // vtable "chunk" has the Thumb bit set.
+- image->FixupFieldToNode(slotBase, slotOffset, importThunk ARM_ARG(THUMB_CODE));
++ image->FixupFieldToNode(slotBase, slotOffset, importThunk ARM_ARG_OR_ZERO(THUMB_CODE), relocType);
+ }
+ else
+ {
+@@ -9463,7 +9470,15 @@ void MethodTable::SetSlot(UINT32 slotNumber, PCODE slotCode)
+ _ASSERTE(IsThumbCode(slotCode));
+ #endif
+
+- *GetSlotPtrRaw(slotNumber) = slotCode;
++ TADDR slot = GetSlotPtrRaw(slotNumber);
++ if (slotNumber < GetNumVirtuals())
++ {
++ ((MethodTable::VTableIndir2_t *) slot)->SetValueMaybeNull(slotCode);
++ }
++ else
++ {
++ *((PCODE *)slot) = slotCode;
++ }
+ }
+
+ //==========================================================================================
+diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
+index 9dc24d8..5cc6f45 100644
+--- a/src/vm/methodtable.h
++++ b/src/vm/methodtable.h
+@@ -1497,13 +1497,18 @@ public:
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+ CONSISTENCY_CHECK(slotNumber < GetNumVtableSlots());
+- PTR_PCODE pSlot = GetSlotPtrRaw(slotNumber);
+- if (IsZapped() && slotNumber >= GetNumVirtuals())
++
++ TADDR pSlot = GetSlotPtrRaw(slotNumber);
++ if (slotNumber < GetNumVirtuals())
++ {
++ return VTableIndir2_t::GetValueMaybeNullAtPtr(pSlot);
++ }
++ else if (IsZapped() && slotNumber >= GetNumVirtuals())
+ {
+ // Non-virtual slots in NGened images are relative pointers
+- return RelativePointer<PCODE>::GetValueAtPtr(dac_cast<TADDR>(pSlot));
++ return RelativePointer<PCODE>::GetValueAtPtr(pSlot);
+ }
+- return *pSlot;
++ return *dac_cast<PTR_PCODE>(pSlot);
+ }
+
+ // Special-case for when we know that the slot number corresponds
+@@ -1517,10 +1522,11 @@ public:
+
+ DWORD index = GetIndexOfVtableIndirection(slotNum);
+ TADDR base = dac_cast<TADDR>(&(GetVtableIndirections()[index]));
+- return *(VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum));
++ DPTR(VTableIndir2_t) baseAfterInd = VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum);
++ return VTableIndir2_t::GetValueMaybeNullAtPtr(dac_cast<TADDR>(baseAfterInd));
+ }
+
+- PTR_PCODE GetSlotPtrRaw(UINT32 slotNum)
++ TADDR GetSlotPtrRaw(UINT32 slotNum)
+ {
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+@@ -1531,25 +1537,26 @@ public:
+ // Virtual slots live in chunks pointed to by vtable indirections
+ DWORD index = GetIndexOfVtableIndirection(slotNum);
+ TADDR base = dac_cast<TADDR>(&(GetVtableIndirections()[index]));
+- return VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum);
++ DPTR(VTableIndir2_t) baseAfterInd = VTableIndir_t::GetValueMaybeNullAtPtr(base) + GetIndexAfterVtableIndirection(slotNum);
++ return dac_cast<TADDR>(baseAfterInd);
+ }
+ else if (HasSingleNonVirtualSlot())
+ {
+ // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member,
+ // except when there is only one in which case it lives in the optional member itself
+ _ASSERTE(slotNum == GetNumVirtuals());
+- return dac_cast<PTR_PCODE>(GetNonVirtualSlotsPtr());
++ return GetNonVirtualSlotsPtr();
+ }
+ else
+ {
+ // Non-virtual slots < GetNumVtableSlots live in a single chunk pointed to by an optional member
+ _ASSERTE(HasNonVirtualSlotsArray());
+ g_IBCLogger.LogMethodTableNonVirtualSlotsAccess(this);
+- return GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals());
++ return dac_cast<TADDR>(GetNonVirtualSlotsArray() + (slotNum - GetNumVirtuals()));
+ }
+ }
+
+- PTR_PCODE GetSlotPtr(UINT32 slotNum)
++ TADDR GetSlotPtr(UINT32 slotNum)
+ {
+ WRAPPER_NO_CONTRACT;
+ STATIC_CONTRACT_SO_TOLERANT;
+@@ -1615,10 +1622,12 @@ public:
+ #define VTABLE_SLOTS_PER_CHUNK 8
+ #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
+
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
+- typedef RelativePointer<PTR_PCODE> VTableIndir_t;
++#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_) && defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++ typedef RelativePointer<PCODE> VTableIndir2_t;
++ typedef RelativePointer<DPTR(VTableIndir2_t)> VTableIndir_t;
+ #else
+- typedef PlainPointer<PTR_PCODE> VTableIndir_t;
++ typedef PlainPointer<PCODE> VTableIndir2_t;
++ typedef PlainPointer<DPTR(VTableIndir2_t)> VTableIndir_t;
+ #endif
+
+ static DWORD GetIndexOfVtableIndirection(DWORD slotNum);
+@@ -1647,10 +1656,10 @@ public:
+ BOOL Finished();
+ DWORD GetIndex();
+ DWORD GetOffsetFromMethodTable();
+- PTR_PCODE GetIndirectionSlot();
++ DPTR(VTableIndir2_t) GetIndirectionSlot();
+
+ #ifndef DACCESS_COMPILE
+- void SetIndirectionSlot(PTR_PCODE pChunk);
++ void SetIndirectionSlot(DPTR(VTableIndir2_t) pChunk);
+ #endif
+
+ DWORD GetStartSlot();
+diff --git a/src/vm/methodtable.inl b/src/vm/methodtable.inl
+index 0d0acda..4fe3d83 100644
+--- a/src/vm/methodtable.inl
++++ b/src/vm/methodtable.inl
+@@ -956,7 +956,7 @@ inline DWORD MethodTable::VtableIndirectionSlotIterator::GetOffsetFromMethodTabl
+ }
+
+ //==========================================================================================
+-inline PTR_PCODE MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot()
++inline DPTR(MethodTable::VTableIndir2_t) MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ PRECONDITION(m_i != (DWORD) -1 && m_i < m_count);
+@@ -966,7 +966,7 @@ inline PTR_PCODE MethodTable::VtableIndirectionSlotIterator::GetIndirectionSlot(
+
+ //==========================================================================================
+ #ifndef DACCESS_COMPILE
+-inline void MethodTable::VtableIndirectionSlotIterator::SetIndirectionSlot(PTR_PCODE pChunk)
++inline void MethodTable::VtableIndirectionSlotIterator::SetIndirectionSlot(DPTR(MethodTable::VTableIndir2_t) pChunk)
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_pSlot->SetValueMaybeNull(pChunk);
+diff --git a/src/vm/methodtablebuilder.cpp b/src/vm/methodtablebuilder.cpp
+index 970166d..67e12bc 100644
+--- a/src/vm/methodtablebuilder.cpp
++++ b/src/vm/methodtablebuilder.cpp
+@@ -10160,7 +10160,7 @@ MethodTable * MethodTableBuilder::AllocateNewMT(Module *pLoaderModule,
+ else
+ {
+ // Use the locally allocated chunk
+- it.SetIndirectionSlot((PTR_PCODE)(pData+dwCurrentUnsharedSlotOffset));
++ it.SetIndirectionSlot((MethodTable::VTableIndir2_t *)(pData+dwCurrentUnsharedSlotOffset));
+ dwCurrentUnsharedSlotOffset += it.GetSize();
+ }
+ }
+@@ -10726,7 +10726,7 @@ MethodTableBuilder::SetupMethodTable2(
+
+ if (pMD->HasNonVtableSlot())
+ {
+- *pMD->GetAddrOfSlot() = addr;
++ *((PCODE *)pMD->GetAddrOfSlot()) = addr;
+ }
+ else
+ {
+--
+2.7.4
+
diff --git a/packaging/0038-Replace-PLATFORM_UNIX-_TARGET_ARM_-for-NGEN-relocati.patch b/packaging/0038-Replace-PLATFORM_UNIX-_TARGET_ARM_-for-NGEN-relocati.patch
new file mode 100644
index 0000000000..08f45e3734
--- /dev/null
+++ b/packaging/0038-Replace-PLATFORM_UNIX-_TARGET_ARM_-for-NGEN-relocati.patch
@@ -0,0 +1,112 @@
+From dc692676bb385477d702f173c04e9ff5af015126 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Fri, 20 Apr 2018 11:54:18 +0300
+Subject: [PATCH 38/47] Replace PLATFORM_UNIX && _TARGET_ARM_ for NGEN
+ relocations optimizations with FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+
+---
+ src/vm/method.hpp | 4 ++--
+ src/vm/methodtable.h | 16 ++++++++--------
+ 2 files changed, 10 insertions(+), 10 deletions(-)
+
+diff --git a/src/vm/method.hpp b/src/vm/method.hpp
+index 92fbdee..d60984c 100644
+--- a/src/vm/method.hpp
++++ b/src/vm/method.hpp
+@@ -2599,7 +2599,7 @@ public:
+ };
+
+ // The writeable part of the methoddesc.
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ RelativePointer<PTR_NDirectWriteableData> m_pWriteableData;
+ #else
+ PlainPointer<PTR_NDirectWriteableData> m_pWriteableData;
+@@ -3415,7 +3415,7 @@ public: // <TODO>make private: JITinterface.cpp accesses through this </TODO>
+ //
+ // For generic method definitions that are not the typical method definition (e.g. C<int>.m<U>)
+ // this field is null; to obtain the instantiation use LoadMethodInstantiation
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ RelativePointer<PTR_Dictionary> m_pPerInstInfo; //SHARED
+ #else
+ PlainPointer<PTR_Dictionary> m_pPerInstInfo; //SHARED
+diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
+index 5cc6f45..32b4ca4 100644
+--- a/src/vm/methodtable.h
++++ b/src/vm/methodtable.h
+@@ -112,7 +112,7 @@ struct InterfaceInfo_t
+ #endif
+
+ // Method table of the interface
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ RelativeFixupPointer<PTR_MethodTable> m_pMethodTable;
+ #else
+ FixupPointer<PTR_MethodTable> m_pMethodTable;
+@@ -1622,7 +1622,7 @@ public:
+ #define VTABLE_SLOTS_PER_CHUNK 8
+ #define VTABLE_SLOTS_PER_CHUNK_LOG2 3
+
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_) && defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ typedef RelativePointer<PCODE> VTableIndir2_t;
+ typedef RelativePointer<DPTR(VTableIndir2_t)> VTableIndir_t;
+ #else
+@@ -2136,7 +2136,7 @@ public:
+ // THE METHOD TABLE PARENT (SUPERCLASS/BASE CLASS)
+ //
+
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ #define PARENT_MT_FIXUP_OFFSET (-FIXUP_POINTER_INDIRECTION)
+ typedef RelativeFixupPointer<PTR_MethodTable> ParentMT_t;
+ #else
+@@ -2168,7 +2168,7 @@ public:
+ inline static PTR_VOID GetParentMethodTableOrIndirection(PTR_VOID pMT)
+ {
+ WRAPPER_NO_CONTRACT;
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ PTR_MethodTable pMethodTable = dac_cast<PTR_MethodTable>(pMT);
+ PTR_MethodTable pParentMT = ReadPointerMaybeNull((MethodTable*) pMethodTable, &MethodTable::m_pParentMethodTable);
+ return dac_cast<PTR_VOID>(pParentMT);
+@@ -3066,7 +3066,7 @@ public:
+ // must have a dictionary entry. On the other hand, for instantiations shared with Dict<string,double> the opposite holds.
+ //
+
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ typedef RelativePointer<PTR_Dictionary> PerInstInfoElem_t;
+ typedef RelativePointer<DPTR(PerInstInfoElem_t)> PerInstInfo_t;
+ #else
+@@ -4151,7 +4151,7 @@ private:
+
+ RelativePointer<PTR_Module> m_pLoaderModule; // LoaderModule. It is equal to the ZapModule in ngened images
+
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ RelativePointer<PTR_MethodTableWriteableData> m_pWriteableData;
+ #else
+ PlainPointer<PTR_MethodTableWriteableData> m_pWriteableData;
+@@ -4167,7 +4167,7 @@ private:
+ static const TADDR UNION_MASK = 3;
+
+ union {
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ RelativePointer<DPTR(EEClass)> m_pEEClass;
+ RelativePointer<TADDR> m_pCanonMT;
+ #else
+@@ -4202,7 +4202,7 @@ private:
+ public:
+ union
+ {
+-#if defined(PLATFORM_UNIX) && defined(_TARGET_ARM_)
++#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+ RelativePointer<PTR_InterfaceInfo> m_pInterfaceMap;
+ #else
+ PlainPointer<PTR_InterfaceInfo> m_pInterfaceMap;
+--
+2.7.4
+
diff --git a/packaging/0039-Fix-formatting.patch b/packaging/0039-Fix-formatting.patch
new file mode 100644
index 0000000000..57fceb0646
--- /dev/null
+++ b/packaging/0039-Fix-formatting.patch
@@ -0,0 +1,41 @@
+From 2d85d36b77315341add87724be5a04869cba5693 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Fri, 20 Apr 2018 17:39:02 +0300
+Subject: [PATCH 39/47] Fix formatting
+
+---
+ src/jit/lower.cpp | 4 ++--
+ src/jit/morph.cpp | 2 +-
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/src/jit/lower.cpp b/src/jit/lower.cpp
+index 5c0cf69..4897107 100644
+--- a/src/jit/lower.cpp
++++ b/src/jit/lower.cpp
+@@ -3472,8 +3472,8 @@ GenTree* Lowering::LowerVirtualVtableCall(GenTreeCall* call)
+ GenTree* offs = comp->gtNewIconNode(vtabOffsOfIndirection + vtabOffsAfterIndirection, TYP_INT);
+ result = comp->gtNewOperNode(GT_ADD, TYP_I_IMPL, comp->gtNewLclvNode(lclNumTmp, result->TypeGet()), offs);
+
+- GenTree* base = OffsetByIndexWithScale(result, tmpTree, 1);
+- GenTree* lclvNodeStore2 = comp->gtNewTempAssign(lclNumTmp2, base);
++ GenTree* base = OffsetByIndexWithScale(result, tmpTree, 1);
++ GenTree* lclvNodeStore2 = comp->gtNewTempAssign(lclNumTmp2, base);
+
+ LIR::Range range = LIR::SeqTree(comp, lclvNodeStore);
+ JITDUMP("result of obtaining pointer to virtual table:\n");
+diff --git a/src/jit/morph.cpp b/src/jit/morph.cpp
+index 3f57191..3207fd4 100644
+--- a/src/jit/morph.cpp
++++ b/src/jit/morph.cpp
+@@ -7145,7 +7145,7 @@ void Compiler::fgMorphTailCall(GenTreeCall* call)
+
+ if (isRelative)
+ {
+- indOffTree = impCloneExpr(add, &add, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
++ GenTree* indOffTree = impCloneExpr(add, &add, NO_CLASS_HANDLE, (unsigned)CHECK_SPILL_ALL,
+ nullptr DEBUGARG("virtual table call 2"));
+ vtbl = gtNewOperNode(GT_IND, TYP_I_IMPL, add);
+ vtbl = gtNewOperNode(GT_ADD, TYP_I_IMPL, vtbl, indOffTree);
+--
+2.7.4
+
diff --git a/packaging/0040-Update-GUID.patch b/packaging/0040-Update-GUID.patch
new file mode 100644
index 0000000000..d3a97bffc7
--- /dev/null
+++ b/packaging/0040-Update-GUID.patch
@@ -0,0 +1,33 @@
+From 843b1817c7ebea7c999f7327c6d4425d31f62615 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Mon, 23 Apr 2018 20:57:13 +0300
+Subject: [PATCH 40/47] Update GUID
+
+---
+ src/inc/corinfo.h | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
+index 1a6843c..76a7a7c 100644
+--- a/src/inc/corinfo.h
++++ b/src/inc/corinfo.h
+@@ -213,11 +213,11 @@ TODO: Talk about initializing strutures before use
+ #define SELECTANY extern __declspec(selectany)
+ #endif
+
+-SELECTANY const GUID JITEEVersionIdentifier = { /* 5a1cfc89-a84a-4642-b01d-ead88e60c1ee */
+- 0x5a1cfc89,
+- 0xa84a,
+- 0x4642,
+- { 0xb0, 0x1d, 0xea, 0xd8, 0x8e, 0x60, 0xc1, 0xee }
++SELECTANY const GUID JITEEVersionIdentifier = { /* 02d3cb99-cc44-463e-b47d-c94a90daf271 */
++ 0x02d3cb99,
++ 0xcc44,
++ 0x463e,
++ {0xb4, 0x7d, 0xc9, 0x4a, 0x90, 0xda, 0xf2, 0x71}
+ };
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////
+--
+2.7.4
+
diff --git a/packaging/0041-Move-IAT_RELPVALUE-to-the-end-of-enum-InfoAccessType.patch b/packaging/0041-Move-IAT_RELPVALUE-to-the-end-of-enum-InfoAccessType.patch
new file mode 100644
index 0000000000..3421c5edf6
--- /dev/null
+++ b/packaging/0041-Move-IAT_RELPVALUE-to-the-end-of-enum-InfoAccessType.patch
@@ -0,0 +1,27 @@
+From aac7c8a3ed3c9670bacfa80a0c0c71df12a5d997 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Thu, 10 May 2018 16:21:22 +0300
+Subject: [PATCH 41/47] Move IAT_RELPVALUE to the end of enum InfoAccessType
+
+---
+ src/inc/corinfo.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/inc/corinfo.h b/src/inc/corinfo.h
+index 76a7a7c..32fce05 100644
+--- a/src/inc/corinfo.h
++++ b/src/inc/corinfo.h
+@@ -971,8 +971,8 @@ enum InfoAccessType
+ {
+ IAT_VALUE, // The info value is directly available
+ IAT_PVALUE, // The value needs to be accessed via an indirection
+- IAT_RELPVALUE, // The value needs to be accessed via a relative indirection
+- IAT_PPVALUE // The value needs to be accessed via a double indirection
++ IAT_PPVALUE, // The value needs to be accessed via a double indirection
++ IAT_RELPVALUE // The value needs to be accessed via a relative indirection
+ };
+
+ enum CorInfoGCType
+--
+2.7.4
+
diff --git a/packaging/0042-Add-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-true-as-defaul.patch b/packaging/0042-Add-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-true-as-defaul.patch
new file mode 100644
index 0000000000..e4c57fdc09
--- /dev/null
+++ b/packaging/0042-Add-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-true-as-defaul.patch
@@ -0,0 +1,22 @@
+From 3cf6e8b85d478470088313be6d31bc1f20387205 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Fri, 1 Jun 2018 20:44:46 +0300
+Subject: [PATCH 42/47] Add FEATURE_NGEN_RELOCS_OPTIMIZATIONS=true as default
+ value
+
+---
+ clrdefinitions.cmake | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/clrdefinitions.cmake b/clrdefinitions.cmake
+index 8ba01c5..76acb50 100644
+--- a/clrdefinitions.cmake
++++ b/clrdefinitions.cmake
+@@ -201,3 +201,4 @@ add_definitions(-DFEATURE_WINMD_RESILIENT)
+ add_definitions(-D_SECURE_SCL=0)
+ add_definitions(-DUNICODE)
+ add_definitions(-D_UNICODE)
++add_definitions(-DFEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+--
+2.7.4
+
diff --git a/packaging/0043-Fix-setup-of-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-for-U.patch b/packaging/0043-Fix-setup-of-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-for-U.patch
new file mode 100644
index 0000000000..9be1c44be7
--- /dev/null
+++ b/packaging/0043-Fix-setup-of-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-for-U.patch
@@ -0,0 +1,25 @@
+From 8d26c1c7ca45337363284baeeb80f5c381b46b13 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Tue, 5 Jun 2018 17:43:41 +0300
+Subject: [PATCH 43/47] Fix setup of FEATURE_NGEN_RELOCS_OPTIMIZATIONS for Unix
+ ARM only
+
+---
+ clrdefinitions.cmake | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/clrdefinitions.cmake b/clrdefinitions.cmake
+index 76acb50..1fb80a2 100644
+--- a/clrdefinitions.cmake
++++ b/clrdefinitions.cmake
+@@ -201,4 +201,6 @@ add_definitions(-DFEATURE_WINMD_RESILIENT)
+ add_definitions(-D_SECURE_SCL=0)
+ add_definitions(-DUNICODE)
+ add_definitions(-D_UNICODE)
+-add_definitions(-DFEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++if (CLR_CMAKE_PLATFORM_UNIX AND CLR_CMAKE_TARGET_ARCH_ARM)
++ add_definitions(-DFEATURE_NGEN_RELOCS_OPTIMIZATIONS)
++endif()
+--
+2.7.4
+
diff --git a/packaging/0044-Replace-push-pop-of-R11-in-stubs-with.patch b/packaging/0044-Replace-push-pop-of-R11-in-stubs-with.patch
new file mode 100644
index 0000000000..6c37a505cf
--- /dev/null
+++ b/packaging/0044-Replace-push-pop-of-R11-in-stubs-with.patch
@@ -0,0 +1,182 @@
+From 1c31fc93e3a1acc7c0671837e0c25fe389a8415f Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Thu, 7 Jun 2018 17:51:53 +0300
+Subject: [PATCH 44/47] Replace push/pop of R11 in stubs with - str/ldr of R4
+ in space reserved in epilog for non-tail calls - usage of R4 with
+ hybrid-tail calls (same as for EmitShuffleThunk)
+
+---
+ src/vm/arm/stubs.cpp | 98 +++++++++++++++++++++++++++++++++++++++++-----------
+ 1 file changed, 77 insertions(+), 21 deletions(-)
+
+diff --git a/src/vm/arm/stubs.cpp b/src/vm/arm/stubs.cpp
+index ec0a1e7..950dc7d 100644
+--- a/src/vm/arm/stubs.cpp
++++ b/src/vm/arm/stubs.cpp
+@@ -1721,6 +1721,13 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray)
+
+ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall)
+ {
++ bool isRelative = MethodTable::VTableIndir2_t::isRelative
++ && pMD->IsVtableSlot();
++
++#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
++ _ASSERTE(!isRelative);
++#endif
++
+ // Use direct call if possible.
+ if (pMD->HasStableEntryPoint())
+ {
+@@ -1732,18 +1739,16 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall)
+ // mov r12, #slotaddress
+ ThumbEmitMovConstant(ThumbReg(12), (TADDR)pMD->GetAddrOfSlot());
+
+- bool isRelative = MethodTable::VTableIndir2_t::isRelative
+- && pMD->IsVtableSlot();
+ if (isRelative)
+ {
+-#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+- // push r11
+- ThumbEmitPush(ThumbReg(11).Mask());
+- // mov r11, r12
+- ThumbEmitMovRegReg(ThumbReg(11), ThumbReg(12));
+-#else
+- _ASSERTE(false);
+-#endif
++ if (!fTailcall)
++ {
++ // str r4, [sp, 0]
++ ThumbEmitStoreRegIndirect(ThumbReg(4), thumbRegSp, 0);
++ }
++
++ // mov r4, r12
++ ThumbEmitMovRegReg(ThumbReg(4), ThumbReg(12));
+ }
+
+ // ldr r12, [r12]
+@@ -1751,21 +1756,30 @@ void StubLinkerCPU::ThumbEmitCallManagedMethod(MethodDesc *pMD, bool fTailcall)
+
+ if (isRelative)
+ {
+-#if defined(FEATURE_NGEN_RELOCS_OPTIMIZATIONS)
+- // add r12, r11
+- ThumbEmitAddReg(ThumbReg(12), ThumbReg(11));
+- // pop r11
+- ThumbEmitPop(ThumbReg(11).Mask());
+-#else
+- _ASSERTE(false);
+-#endif
++ // add r12, r4
++ ThumbEmitAddReg(ThumbReg(12), ThumbReg(4));
++
++ if (!fTailcall)
++ {
++ // ldr r4, [sp, 0]
++ ThumbEmitLoadRegIndirect(ThumbReg(4), thumbRegSp, 0);
++ }
+ }
+ }
+
+ if (fTailcall)
+ {
+- // bx r12
+- ThumbEmitJumpRegister(ThumbReg(12));
++ if (!isRelative)
++ {
++ // bx r12
++ ThumbEmitJumpRegister(ThumbReg(12));
++ }
++ else
++ {
++ // Replace LR with R12 on stack: hybrid-tail call, same as for EmitShuffleThunk
++ // str r12, [sp, 4]
++ ThumbEmitStoreRegIndirect(ThumbReg(12), thumbRegSp, 4);
++ }
+ }
+ else
+ {
+@@ -1902,6 +1916,13 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
+ }
+ }
+
++ bool isRelative = MethodTable::VTableIndir2_t::isRelative
++ && pMD->IsVtableSlot();
++
++#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
++ _ASSERTE(!isRelative);
++#endif
++
+ // Update descriptor count to the actual number used.
+ cArgDescriptors = idxCurrentDesc;
+
+@@ -1994,7 +2015,17 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
+ }
+
+ // Emit a tail call to the target method.
++ if (isRelative)
++ {
++ ThumbEmitProlog(1, 0, FALSE);
++ }
++
+ ThumbEmitCallManagedMethod(pMD, true);
++
++ if (isRelative)
++ {
++ ThumbEmitEpilog();
++ }
+ }
+ else
+ {
+@@ -2003,7 +2034,9 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
+ // Calculate the size of the new stack frame:
+ //
+ // +------------+
+- // SP -> | | <-+
++ // SP -> | | <-- Space for helper arg, if isRelative is true
++ // +------------+
++ // | | <-+
+ // : : | Outgoing arguments
+ // | | <-+
+ // +------------+
+@@ -2034,6 +2067,12 @@ void StubLinkerCPU::ThumbEmitCallWithGenericInstantiationParameter(MethodDesc *p
+ DWORD cbStackArgs = (pLastArg->m_idxDst + 1) * 4;
+ DWORD cbStackFrame = cbStackArgs + sizeof(GSCookie) + sizeof(StubHelperFrame);
+ cbStackFrame = ALIGN_UP(cbStackFrame, 8);
++
++ if (isRelative)
++ {
++ cbStackFrame += 4;
++ }
++
+ DWORD cbStackFrameWithoutSavedRegs = cbStackFrame - (13 * 4); // r0-r11,lr
+
+ // Prolog:
+@@ -2242,8 +2281,25 @@ void StubLinkerCPU::EmitUnboxMethodStub(MethodDesc *pMD)
+ // add r0, #4
+ ThumbEmitIncrement(ThumbReg(0), 4);
+
++ bool isRelative = MethodTable::VTableIndir2_t::isRelative
++ && pMD->IsVtableSlot();
++
++#ifndef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
++ _ASSERTE(!isRelative);
++#endif
++
++ if (isRelative)
++ {
++ ThumbEmitProlog(1, 0, FALSE);
++ }
++
+ // Tail call the real target.
+ ThumbEmitCallManagedMethod(pMD, true /* tail call */);
++
++ if (isRelative)
++ {
++ ThumbEmitEpilog();
++ }
+ }
+ }
+
+--
+2.7.4
+
diff --git a/packaging/0045-Replace-push-pop-of-R11-for-function-epilog-with-usa.patch b/packaging/0045-Replace-push-pop-of-R11-for-function-epilog-with-usa.patch
new file mode 100644
index 0000000000..314cd00eba
--- /dev/null
+++ b/packaging/0045-Replace-push-pop-of-R11-for-function-epilog-with-usa.patch
@@ -0,0 +1,93 @@
+From 777191a4bb6197f29d04889698c167aec4b49d39 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Fri, 8 Jun 2018 19:16:11 +0300
+Subject: [PATCH 45/47] Replace push/pop of R11 for function epilog with usage
+ of LR as helper register right before its restore from stack
+
+---
+ src/jit/codegencommon.cpp | 52 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 41 insertions(+), 11 deletions(-)
+
+diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
+index 51cc777..3084582 100644
+--- a/src/jit/codegencommon.cpp
++++ b/src/jit/codegencommon.cpp
+@@ -9433,6 +9433,43 @@ void CodeGen::genFnEpilog(BasicBlock* block)
+ unwindStarted = true;
+ }
+
++#ifdef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
++ if (jmpEpilog)
++ {
++ // In case of FEATURE_NGEN_RELOCS_OPTIMIZATIONS and IAT_RELPVALUE jump at the end is done using
++ // relative indirection, so, additional helper register is required.
++ // We use LR just before it is going to be restored from stack, i.e.
++ //
++ // movw r12, laddr
++ // movt r12, haddr
++ // mov lr, r12
++ // ldr r12, [r12]
++ // add r12, r12, lr
++ // pop {lr}
++ // ...
++ // bx r12
++
++ GenTree* jmpNode = block->lastNode();
++
++ noway_assert(jmpNode->gtOper == GT_JMP);
++
++ CORINFO_METHOD_HANDLE methHnd = (CORINFO_METHOD_HANDLE)jmpNode->gtVal.gtVal1;
++ CORINFO_CONST_LOOKUP addrInfo;
++ compiler->info.compCompHnd->getFunctionEntryPoint(methHnd, &addrInfo);
++
++ if (addrInfo.accessType == IAT_RELPVALUE)
++ {
++ regNumber indCallReg = REG_R12;
++ regNumber vptrReg1 = REG_LR;
++
++ instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr);
++ getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, vptrReg1, indCallReg);
++ getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
++ getEmitter()->emitIns_R_R(INS_add, EA_PTRSIZE, indCallReg, vptrReg1);
++ }
++ }
++#endif // FEATURE_NGEN_RELOCS_OPTIMIZATIONS
++
+ genPopCalleeSavedRegisters(jmpEpilog);
+
+ if (regSet.rsMaskPreSpillRegs(true) != RBM_NONE)
+@@ -9497,27 +9534,20 @@ void CodeGen::genFnEpilog(BasicBlock* block)
+ break;
+
+ case IAT_RELPVALUE:
++#ifdef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+ {
+ // Load the address into a register, load relative indirect and call through a register
+ // We have to use R12 since we assume the argument registers are in use
++ // LR is used as helper register right before it is restored from stack, thus,
++ // all relative address calculations are performed before LR is restored.
+ callType = emitter::EC_INDIR_R;
+ indCallReg = REG_R12;
+ addr = NULL;
+
+- regNumber vptrReg1 = REG_R11;
+- regMaskTP vptrReg1Mask = genRegMask(vptrReg1);
+- inst_IV(INS_push, (int)vptrReg1Mask);
+-
+- instGen_Set_Reg_To_Imm(EA_HANDLE_CNS_RELOC, indCallReg, (ssize_t)addrInfo.addr);
+- getEmitter()->emitIns_R_R(INS_mov, EA_PTRSIZE, vptrReg1, indCallReg);
+- getEmitter()->emitIns_R_R_I(INS_ldr, EA_PTRSIZE, indCallReg, indCallReg, 0);
+- getEmitter()->emitIns_R_R(INS_add, EA_PTRSIZE, indCallReg, vptrReg1);
+-
+- inst_IV(INS_pop, (int)vptrReg1Mask);
+-
+ regTracker.rsTrackRegTrash(indCallReg);
+ break;
+ }
++#endif // FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+
+ case IAT_PPVALUE:
+ default:
+--
+2.7.4
+
diff --git a/packaging/0046-Remove-ifdef.patch b/packaging/0046-Remove-ifdef.patch
new file mode 100644
index 0000000000..2208fea075
--- /dev/null
+++ b/packaging/0046-Remove-ifdef.patch
@@ -0,0 +1,32 @@
+From 9cc43901915b2fb5eface2fc9b733544b52e4ee0 Mon Sep 17 00:00:00 2001
+From: Gleb Balykov <g.balykov@samsung.com>
+Date: Fri, 8 Jun 2018 20:00:03 +0300
+Subject: [PATCH 46/47] Remove ifdef
+
+---
+ src/jit/codegencommon.cpp | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/src/jit/codegencommon.cpp b/src/jit/codegencommon.cpp
+index 3084582..fce9a0c 100644
+--- a/src/jit/codegencommon.cpp
++++ b/src/jit/codegencommon.cpp
+@@ -9534,7 +9534,6 @@ void CodeGen::genFnEpilog(BasicBlock* block)
+ break;
+
+ case IAT_RELPVALUE:
+-#ifdef FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+ {
+ // Load the address into a register, load relative indirect and call through a register
+ // We have to use R12 since we assume the argument registers are in use
+@@ -9547,7 +9546,6 @@ void CodeGen::genFnEpilog(BasicBlock* block)
+ regTracker.rsTrackRegTrash(indCallReg);
+ break;
+ }
+-#endif // FEATURE_NGEN_RELOCS_OPTIMIZATIONS
+
+ case IAT_PPVALUE:
+ default:
+--
+2.7.4
+
diff --git a/packaging/0047-Launching-the-Memory-Profiler-on-x86-emulator-may-le.patch b/packaging/0047-Launching-the-Memory-Profiler-on-x86-emulator-may-le.patch
new file mode 100644
index 0000000000..bdbbc7bfc3
--- /dev/null
+++ b/packaging/0047-Launching-the-Memory-Profiler-on-x86-emulator-may-le.patch
@@ -0,0 +1,43 @@
+From 2f6cf609fe91270a416219c95e7f512108f34185 Mon Sep 17 00:00:00 2001
+From: Sergey Ignatov <sergign60@mail.ru>
+Date: Fri, 8 Jun 2018 19:50:47 +0300
+Subject: [PATCH 47/47] Launching the Memory Profiler on x86 emulator may lead
+ to crash in coreclr (xmm bug)
+
+---
+ src/pal/src/CMakeLists.txt | 2 ++
+ src/utilcode/CMakeLists.txt | 5 +++++
+ 2 files changed, 7 insertions(+)
+
+diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt
+index b8a9fe9..2f877ac 100644
+--- a/src/pal/src/CMakeLists.txt
++++ b/src/pal/src/CMakeLists.txt
+@@ -91,6 +91,8 @@ elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
+ elseif(PAL_CMAKE_PLATFORM_ARCH_I386)
+ add_definitions(-DBIT32=1)
+ set(PAL_ARCH_SOURCES_DIR i386)
++ # Workaround to avoid generating sse insts for profiler
++ add_compile_options(-mno-sse -mno-avx)
+ endif()
+
+ if(PAL_CMAKE_PLATFORM_ARCH_AMD64 AND CMAKE_SYSTEM_NAME STREQUAL Linux AND NOT CLR_CMAKE_PLATFORM_ALPINE_LINUX)
+diff --git a/src/utilcode/CMakeLists.txt b/src/utilcode/CMakeLists.txt
+index dfe830d..90cb584 100644
+--- a/src/utilcode/CMakeLists.txt
++++ b/src/utilcode/CMakeLists.txt
+@@ -126,6 +126,11 @@ if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+ endif(CLR_CMAKE_PLATFORM_UNIX)
+
++if(CLR_CMAKE_PLATFORM_ARCH_I386)
++ # Workaround to avoid generating sse insts for profiler
++ add_compile_options(-mno-sse -mno-avx)
++endif(CLR_CMAKE_PLATFORM_ARCH_I386)
++
+ add_subdirectory(dac)
+ add_subdirectory(dyncrt)
+ add_subdirectory(staticnohost)
+--
+2.7.4
+
diff --git a/packaging/coreclr.spec b/packaging/coreclr.spec
index e92c3fcc54..35bce027b6 100644
--- a/packaging/coreclr.spec
+++ b/packaging/coreclr.spec
@@ -23,7 +23,7 @@ Source1000: downloaded_files.tar.gz
Source1001: %{name}.manifest
Source1002: libicu.tar.gz
Source1003: dep_libs.tar.gz
-# Gbp-Ignore-Patches: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
+# Gbp-Ignore-Patches: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
Patch0: 0001-Add-project.assets.json-files.patch
Patch1: 0001-ARM-Linux-Support-unaligned-struct-read-write-11290.patch
Patch2: 0002-x86-Linux-Thread-safe-UMThunkMarshInfo-RunTimeInit-1.patch
@@ -116,6 +116,39 @@ Patch88: 0011-Enable-thread-abort-reraise-loop-prevention.patch
Patch89: 0012-16-byte-Stack-Aligned-StubDispatchFixupStub.patch
Patch90: 0013-Fix-EECodeManager-GetAmbientSP-on-x86-Linux.patch
Patch91: 0014-Fix-OOPStackUnwinderX86-Unwind-crash-when-Eip-is-inv.patch
+Patch92: 0001-Improve-UMEntryThunkCode-Poison-method.patch
+Patch93: 0002-UMEntryThunk-store-freed-thunks-into-FIFO-free-list.patch
+Patch94: 0003-dllimportcallback-remove-code-for-CallbackOnCollecte.patch
+Patch95: 0004-LoaderHeap-remove-LHF_ZEROINIT-option.patch
+Patch96: 0019-JIT-Fix-value-type-box-optimization.patch
+Patch97: 0020-JIT-port-fix-to-defer-removing-statements-during-opt.patch
+Patch98: 0021-Revert-ExecuteHandlerOnOriginalStack-handle-case-whe.patch
+Patch99: 0022-CatchHardwareExceptionHolder-use-GetCurrentPalThread.patch
+Patch100: 0023-vm-threads-change-tls-model-for-gCurrentThreadInfo-v.patch
+Patch101: 0024-sigsegv_handler-handle-case-when-it-is-called-on-ori.patch
+Patch102: 0025-Revert-TLS-model-change-of-the-gCurrentThreadInfo.patch
+Patch103: 0026-Prevent-memory-allocation-in-signal-handler.patch
+Patch104: 0027-Revert-Prevent-memory-allocation-in-signal-handler.patch
+Patch105: 0028-Do-not-allocate-exception-for-signal-from-non-manage.patch
+Patch106: 0029-Move-exception-allocation-to-PAL_SEHException.patch
+Patch107: 0030-Remove-exception-records-allocation-from-pal.h.patch
+Patch108: 0031-Fix-preventing-memory-allocation-in-signal-handler.patch
+Patch109: 0032-Fix-Use-of-EventPipeConfiguration-After-it-has-Been-.patch
+Patch110: 0033-Revert-clear-cache-after-NI-reloc.patch
+Patch111: 0034-PEImageLayout-clear-instruction-cache-after-relocati.patch
+Patch112: 0035-PEImageLayout-flush-instruction-cache-only-for-pages.patch
+Patch113: 0036-Separate-sections-READONLY_VCHUNKS-and-READONLY_DICT.patch
+Patch114: 0037-Remove-relocations-for-second-level-indirection-of-V.patch
+Patch115: 0038-Replace-PLATFORM_UNIX-_TARGET_ARM_-for-NGEN-relocati.patch
+Patch116: 0039-Fix-formatting.patch
+Patch117: 0040-Update-GUID.patch
+Patch118: 0041-Move-IAT_RELPVALUE-to-the-end-of-enum-InfoAccessType.patch
+Patch119: 0042-Add-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-true-as-defaul.patch
+Patch120: 0043-Fix-setup-of-FEATURE_NGEN_RELOCS_OPTIMIZATIONS-for-U.patch
+Patch121: 0044-Replace-push-pop-of-R11-in-stubs-with.patch
+Patch122: 0045-Replace-push-pop-of-R11-for-function-epilog-with-usa.patch
+Patch123: 0046-Remove-ifdef.patch
+Patch124: 0047-Launching-the-Memory-Profiler-on-x86-emulator-may-le.patch
ExcludeArch: aarch64
@@ -309,6 +342,39 @@ cp %{SOURCE1001} .
%patch89 -p1
%patch90 -p1
%patch91 -p1
+%patch92 -p1
+%patch93 -p1
+%patch94 -p1
+%patch95 -p1
+%patch96 -p1
+%patch97 -p1
+%patch98 -p1
+%patch99 -p1
+%patch100 -p1
+%patch101 -p1
+%patch102 -p1
+%patch103 -p1
+%patch104 -p1
+%patch105 -p1
+%patch106 -p1
+%patch107 -p1
+%patch108 -p1
+%patch109 -p1
+%patch110 -p1
+%patch111 -p1
+%patch112 -p1
+%patch113 -p1
+%patch114 -p1
+%patch115 -p1
+%patch116 -p1
+%patch117 -p1
+%patch118 -p1
+%patch119 -p1
+%patch120 -p1
+%patch121 -p1
+%patch122 -p1
+%patch123 -p1
+%patch124 -p1
%if 0%{skipmscorlib}