summaryrefslogtreecommitdiff
path: root/src/vm/method.hpp
diff options
context:
space:
mode:
authorDavid Wrighton <davidwr@microsoft.com>2017-09-13 14:50:39 -0700
committerDavid Wrighton <davidwr@microsoft.com>2017-09-13 14:50:39 -0700
commitd68f0916d0a2bf3787bc85261ef4a4f1f27f1f24 (patch)
tree6c21ac239ae268096f20d98a8db16a4b80394fd9 /src/vm/method.hpp
parent96fa98525e0d64459148228cde5211c475b0c25c (diff)
parente866d072042f4ad9e0811aa36e338dac781c09a5 (diff)
downloadcoreclr-d68f0916d0a2bf3787bc85261ef4a4f1f27f1f24.tar.gz
coreclr-d68f0916d0a2bf3787bc85261ef4a4f1f27f1f24.tar.bz2
coreclr-d68f0916d0a2bf3787bc85261ef4a4f1f27f1f24.zip
Merge branch 'master' into update_from_master
Diffstat (limited to 'src/vm/method.hpp')
-rw-r--r--src/vm/method.hpp408
1 files changed, 187 insertions, 221 deletions
diff --git a/src/vm/method.hpp b/src/vm/method.hpp
index 336260cae3..08318ec5b5 100644
--- a/src/vm/method.hpp
+++ b/src/vm/method.hpp
@@ -25,6 +25,7 @@
#include <stddef.h>
#include "eeconfig.h"
#include "precode.h"
+#include "codeversion.h"
#ifndef FEATURE_PREJIT
#include "fixuppointer.h"
@@ -42,6 +43,8 @@ class Dictionary;
class GCCoverageInfo;
class DynamicMethodDesc;
class ReJitManager;
+class CodeVersionManager;
+class PrepareCodeConfig;
typedef DPTR(FCallMethodDesc) PTR_FCallMethodDesc;
typedef DPTR(ArrayMethodDesc) PTR_ArrayMethodDesc;
@@ -143,29 +146,10 @@ enum MethodDescClassification
// Method is static
mdcStatic = 0x0020,
- // Temporary Security Interception.
- // Methods can now be intercepted by security. An intercepted method behaves
- // like it was an interpreted method. The Prestub at the top of the method desc
- // is replaced by an interception stub. Therefore, no back patching will occur.
- // We picked this approach to minimize the number variations given IL and native
- // code with edit and continue. E&C will need to find the real intercepted method
- // and if it is intercepted change the real stub. If E&C is enabled then there
- // is no back patching and needs to fix the pre-stub.
- mdcIntercepted = 0x0040,
-
- // Method requires linktime security checks.
- mdcRequiresLinktimeCheck = 0x0080,
-
- // Method requires inheritance security checks.
- // If this bit is set, then this method demands inheritance permissions
- // or a method that this method overrides demands inheritance permissions
- // or both.
- mdcRequiresInheritanceCheck = 0x0100,
-
- // The method that this method overrides requires an inheritance security check.
- // This bit is used as an optimization to avoid looking up overridden methods
- // during the inheritance check.
- mdcParentRequiresInheritanceCheck = 0x0200,
+ // unused = 0x0040,
+ // unused = 0x0080,
+ // unused = 0x0100,
+ // unused = 0x0200,
// Duplicate method. When a method needs to be placed in multiple slots in the
// method table, because it could not be packed into one slot. For eg, a method
@@ -268,10 +252,6 @@ public:
BOOL SetStableEntryPointInterlocked(PCODE addr);
-#ifdef FEATURE_INTERPRETER
- BOOL SetEntryPointInterlocked(PCODE addr);
-#endif // FEATURE_INTERPRETER
-
BOOL HasTemporaryEntryPoint();
PCODE GetTemporaryEntryPoint();
@@ -507,7 +487,12 @@ public:
BaseDomain *GetDomain();
- ReJitManager * GetReJitManager();
+#ifdef FEATURE_CODE_VERSIONING
+ CodeVersionManager* GetCodeVersionManager();
+#endif
+#ifdef FEATURE_TIERED_COMPILATION
+ CallCounter* GetCallCounter();
+#endif
PTR_LoaderAllocator GetLoaderAllocator();
@@ -669,7 +654,6 @@ public:
}
void ComputeSuppressUnmanagedCodeAccessAttr(IMDInternalImport *pImport);
- BOOL HasSuppressUnmanagedCodeAccessAttr();
BOOL HasNativeCallableAttribute();
#ifdef FEATURE_COMINTEROP
@@ -697,32 +681,6 @@ public:
// Update flags in a thread safe manner.
WORD InterlockedUpdateFlags(WORD wMask, BOOL fSet);
- inline DWORD IsInterceptedForDeclSecurity()
- {
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
- return m_wFlags & mdcIntercepted;
- }
-
- inline void SetInterceptedForDeclSecurity()
- {
- LIMITED_METHOD_CONTRACT;
- m_wFlags |= mdcIntercepted;
- }
-
- inline DWORD IsInterceptedForDeclSecurityCASDemandsOnly()
- {
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
- return m_bFlags2 & enum_flag2_CASDemandsOnly;
- }
-
- inline void SetInterceptedForDeclSecurityCASDemandsOnly()
- {
- LIMITED_METHOD_CONTRACT;
- m_bFlags2 |= enum_flag2_CASDemandsOnly;
- }
-
// If the method is in an Edit and Contine (EnC) module, then
// we DON'T want to backpatch this, ever. We MUST always call
// through the precode so that we can update the method.
@@ -746,7 +704,6 @@ public:
InterlockedUpdateFlags(mdcNotInline, set);
}
-
BOOL IsIntrospectionOnly();
#ifndef DACCESS_COMPILE
VOID EnsureActive();
@@ -811,50 +768,11 @@ public:
BOOL IsQCall();
//================================================================
- // Has the method been verified?
- // This does not mean that the IL is verifiable, just that we have
- // determined if the IL is verfiable or unverifiable.
- // (Is this is dead code since the JIT now does verification?)
-
- inline BOOL IsVerified()
- {
- LIMITED_METHOD_CONTRACT;
- return m_wFlags & mdcVerifiedState;
- }
-
- inline void SetIsVerified(BOOL isVerifiable)
- {
- WRAPPER_NO_CONTRACT;
-
- WORD flags = isVerifiable ? (WORD(mdcVerifiedState) | WORD(mdcVerifiable))
- : (WORD(mdcVerifiedState));
- InterlockedUpdateFlags(flags, TRUE);
- }
-
- inline void ResetIsVerified()
- {
- WRAPPER_NO_CONTRACT;
- InterlockedUpdateFlags(mdcVerifiedState | mdcVerifiable, FALSE);
- }
-
- BOOL IsVerifiable();
-
- // fThrowException is used to prevent Verifier from
- // throwin an exception on error
- // fForceVerify is to be used by tools that need to
- // force verifier to verify code even if the code is fully trusted.
- HRESULT Verify(COR_ILMETHOD_DECODER* ILHeader,
- BOOL fThrowException,
- BOOL fForceVerify);
-
-
- //================================================================
//
inline void ClearFlagsOnUpdate()
{
WRAPPER_NO_CONTRACT;
- ResetIsVerified();
SetNotInline(FALSE);
}
@@ -1229,45 +1147,6 @@ protected:
}
public:
- //==================================================================
- // Security...
-
- inline DWORD RequiresLinktimeCheck()
- {
- LIMITED_METHOD_CONTRACT;
- return m_wFlags & mdcRequiresLinktimeCheck;
- }
-
- inline DWORD RequiresInheritanceCheck()
- {
- LIMITED_METHOD_CONTRACT;
- return m_wFlags & mdcRequiresInheritanceCheck;
- }
-
- inline DWORD ParentRequiresInheritanceCheck()
- {
- LIMITED_METHOD_CONTRACT;
- return m_wFlags & mdcParentRequiresInheritanceCheck;
- }
-
- void SetRequiresLinktimeCheck()
- {
- LIMITED_METHOD_CONTRACT;
- m_wFlags |= mdcRequiresLinktimeCheck;
- }
-
- void SetRequiresInheritanceCheck()
- {
- LIMITED_METHOD_CONTRACT;
- m_wFlags |= mdcRequiresInheritanceCheck;
- }
-
- void SetParentRequiresInheritanceCheck()
- {
- LIMITED_METHOD_CONTRACT;
- m_wFlags |= mdcParentRequiresInheritanceCheck;
- }
-
mdMethodDef GetMemberDef() const;
mdMethodDef GetMemberDef_NoLogging() const;
@@ -1286,12 +1165,73 @@ public:
void SetChunkIndex(MethodDescChunk *pChunk);
BOOL IsPointingToPrestub();
-#ifdef FEATURE_INTERPRETER
- BOOL IsReallyPointingToPrestub();
-#endif // FEATURE_INTERPRETER
public:
+ // TRUE iff it is possible to change the code this method will run using
+ // the CodeVersionManager.
+ // Note: EnC currently returns FALSE here because it uses its own seperate
+ // scheme to manage versionability. We will likely want to converge them
+ // at some point.
+ BOOL IsVersionable()
+ {
+#ifndef FEATURE_CODE_VERSIONING
+ return FALSE;
+#else
+ return IsVersionableWithPrecode() || IsVersionableWithJumpStamp();
+#endif
+ }
+
+ // If true, these methods version using the CodeVersionManager and
+ // switch between different code versions by updating the target of the precode.
+ // Note: EnC returns FALSE - even though it uses precode updates it does not
+ // use the CodeVersionManager right now
+ BOOL IsVersionableWithPrecode()
+ {
+#ifdef FEATURE_CODE_VERSIONING
+ return
+ // policy: which things do we want to version with a precode if possible
+ IsEligibleForTieredCompilation() &&
+
+ // functional requirements:
+ !IsZapped() && // NGEN directly invokes the pre-generated native code.
+ // without necessarily going through the prestub or
+ // precode
+ HasNativeCodeSlot(); // the stable entry point will need to point at our
+ // precode and not directly contain the native code.
+#else
+ return FALSE;
+#endif
+ }
+
+ // If true, these methods version using the CodeVersionManager and switch between
+ // different code versions by overwriting the first bytes of the method's initial
+ // native code with a jmp instruction.
+ BOOL IsVersionableWithJumpStamp()
+ {
+#if defined(FEATURE_CODE_VERSIONING) && defined(FEATURE_JUMPSTAMP)
+ return
+ // for native image code this is policy, but for jitted code it is a functional requirement
+ // to ensure the prolog is sufficiently large
+ ReJitManager::IsReJITEnabled() &&
+
+ // functional requirement - the runtime doesn't expect both options to be possible
+ !IsVersionableWithPrecode() &&
+
+ // functional requirement - we must be able to evacuate the prolog and the prolog must be big
+ // enough, both of which are only designed to work on jitted code
+ (IsIL() || IsNoMetadata()) &&
+ !IsUnboxingStub() &&
+ !IsInstantiatingStub() &&
+
+ // functional requirement - code version manager can't handle what would happen if the code
+ // was collected
+ !GetLoaderAllocator()->IsCollectible();
+#else
+ return FALSE;
+#endif
+ }
+
#ifdef FEATURE_TIERED_COMPILATION
// Is this method allowed to be recompiled and the entrypoint redirected so that we
// can optimize its performance? Eligibility is invariant for the lifetime of a method.
@@ -1301,20 +1241,31 @@ public:
// This policy will need to change some more before tiered compilation feature
// can be properly supported across a broad range of scenarios. For instance it
- // wouldn't interact correctly debugging or profiling at the moment because we
- // enable it too aggresively and it conflicts with the operations of those features.
+ // wouldn't interact correctly with debugging at the moment because we enable
+ // it too aggresively and it conflicts with the operations of those features.
- //Keep in-sync with MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
- //In the future we might want mutable vtable slots too, but that would require
- //more work around the runtime to prevent those mutable pointers from leaking
+ // Keep in-sync with MethodTableBuilder::NeedsNativeCodeSlot(bmtMDMethod * pMDMethod)
+ // to ensure native slots are available where needed.
return g_pConfig->TieredCompilation() &&
- !GetModule()->HasNativeOrReadyToRunImage() &&
+ !IsZapped() &&
!IsEnCMethod() &&
- HasNativeCodeSlot();
+ HasNativeCodeSlot() &&
+ !IsUnboxingStub() &&
+ !IsInstantiatingStub();
+
+ // We should add an exclusion for modules with debuggable code gen flags
}
#endif
+ // Returns a code version that represents the first (default)
+ // code body that this method would have.
+ NativeCodeVersion GetInitialCodeVersion()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return NativeCodeVersion(dac_cast<PTR_MethodDesc>(this));
+ }
+
// Does this method force the NativeCodeSlot to stay fixed after it
// is first initialized to native code? Consumers of the native code
// pointer need to be very careful about if and when they cache it
@@ -1326,6 +1277,12 @@ public:
BOOL IsNativeCodeStableAfterInit()
{
LIMITED_METHOD_DAC_CONTRACT;
+
+#if defined(FEATURE_JIT_PITCHING)
+ if (IsPitchable())
+ return false;
+#endif
+
return
#ifdef FEATURE_TIERED_COMPILATION
!IsEligibleForTieredCompilation() &&
@@ -1371,11 +1328,7 @@ public:
return GetNativeCode() != NULL;
}
-#ifdef FEATURE_INTERPRETER
- BOOL SetNativeCodeInterlocked(PCODE addr, PCODE pExpected, BOOL fStable);
-#else // FEATURE_INTERPRETER
BOOL SetNativeCodeInterlocked(PCODE addr, PCODE pExpected = NULL);
-#endif // FEATURE_INTERPRETER
TADDR GetAddrOfNativeCodeSlot();
@@ -1442,6 +1395,11 @@ public:
// - ngened code if IsPreImplemented()
PCODE GetNativeCode();
+#if defined(FEATURE_JIT_PITCHING)
+ bool IsPitchable();
+ void PitchNativeCode();
+#endif
+
//================================================================
// FindOrCreateAssociatedMethodDesc
//
@@ -1685,69 +1643,11 @@ public:
PCODE DoPrestub(MethodTable *pDispatchingMT);
- PCODE MakeJitWorker(COR_ILMETHOD_DECODER* ILHeader, CORJIT_FLAGS flags);
-
VOID GetMethodInfo(SString &namespaceOrClassName, SString &methodName, SString &methodSignature);
VOID GetMethodInfoWithNewSig(SString &namespaceOrClassName, SString &methodName, SString &methodSignature);
VOID GetMethodInfoNoSig(SString &namespaceOrClassName, SString &methodName);
VOID GetFullMethodInfo(SString& fullMethodSigName);
- BOOL IsCritical()
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(HasCriticalTransparentInfo());
- return (m_bFlags2 & enum_flag2_Transparency_Mask) != enum_flag2_Transparency_Transparent;
- }
-
- BOOL IsTreatAsSafe()
- {
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(HasCriticalTransparentInfo());
- return (m_bFlags2 & enum_flag2_Transparency_Mask) == enum_flag2_Transparency_TreatAsSafe;
- }
-
- BOOL IsTransparent()
- {
- WRAPPER_NO_CONTRACT;
- _ASSERTE(HasCriticalTransparentInfo());
- return !IsCritical();
- }
-
- BOOL HasCriticalTransparentInfo()
- {
- LIMITED_METHOD_CONTRACT;
- return (m_bFlags2 & enum_flag2_Transparency_Mask) != enum_flag2_Transparency_Unknown;
- }
-
- void SetCriticalTransparentInfo(BOOL fIsCritical, BOOL fIsTreatAsSafe)
- {
- WRAPPER_NO_CONTRACT;
-
- // TreatAsSafe has to imply critical
- _ASSERTE(fIsCritical || !fIsTreatAsSafe);
-
- EnsureWritablePages(this);
- InterlockedUpdateFlags2(
- static_cast<BYTE>(fIsTreatAsSafe ? enum_flag2_Transparency_TreatAsSafe :
- fIsCritical ? enum_flag2_Transparency_Critical :
- enum_flag2_Transparency_Transparent),
- TRUE);
-
- _ASSERTE(HasCriticalTransparentInfo());
- }
-
- BOOL RequiresLinkTimeCheckHostProtectionOnly()
- {
- LIMITED_METHOD_CONTRACT;
- return (m_bFlags2 & enum_flag2_HostProtectionLinkCheckOnly) != 0;
- }
-
- void SetRequiresLinkTimeCheckHostProtectionOnly()
- {
- LIMITED_METHOD_CONTRACT;
- m_bFlags2 |= enum_flag2_HostProtectionLinkCheckOnly;
- }
-
BOOL HasTypeEquivalentStructParameters()
#ifndef FEATURE_TYPEEQUIVALENCE
{
@@ -1797,21 +1697,11 @@ protected:
enum_flag2_IsUnboxingStub = 0x04,
enum_flag2_HasNativeCodeSlot = 0x08, // Has slot for native code
- enum_flag2_Transparency_Mask = 0x30,
- enum_flag2_Transparency_Unknown = 0x00, // The transparency has not been computed yet
- enum_flag2_Transparency_Transparent = 0x10, // Method is transparent
- enum_flag2_Transparency_Critical = 0x20, // Method is critical
- enum_flag2_Transparency_TreatAsSafe = 0x30, // Method is treat as safe. Also implied critical.
-
- // CAS Demands: Demands for Permissions that are CAS Permissions. CAS Perms are those
- // that derive from CodeAccessPermission and need a stackwalk to evaluate demands
- // Non-CAS perms are those that don't need a stackwalk and don't derive from CodeAccessPermission. The implementor
- // specifies the behavior on a demand. Examples: CAS: FileIOPermission. Non-CAS: PrincipalPermission.
- // This bit gets set if the demands are BCL CAS demands only. Even if there are non-BCL CAS demands, we don't set this
- // bit.
- enum_flag2_CASDemandsOnly = 0x40,
-
- enum_flag2_HostProtectionLinkCheckOnly = 0x80, // Method has LinkTime check due to HP only.
+ enum_flag2_IsJitIntrinsic = 0x10, // Jit may expand method as an intrinsic
+
+ // unused = 0x20,
+ // unused = 0x40,
+ // unused = 0x80,
};
BYTE m_bFlags2;
@@ -1861,6 +1751,18 @@ public:
m_bFlags2 |= enum_flag2_HasNativeCodeSlot;
}
+ inline BOOL IsJitIntrinsic()
+ {
+ LIMITED_METHOD_DAC_CONTRACT;
+ return (m_bFlags2 & enum_flag2_IsJitIntrinsic) != 0;
+ }
+
+ inline void SetIsJitIntrinsic()
+ {
+ LIMITED_METHOD_CONTRACT;
+ m_bFlags2 |= enum_flag2_IsJitIntrinsic;
+ }
+
static const SIZE_T s_ClassificationSizeTable[];
static SIZE_T GetBaseSize(DWORD classification)
@@ -1949,8 +1851,72 @@ public:
REFLECTMETHODREF GetStubMethodInfo();
PrecodeType GetPrecodeType();
+
+
+ // ---------------------------------------------------------------------------------
+ // IL based Code generation pipeline
+ // ---------------------------------------------------------------------------------
+
+#ifndef DACCESS_COMPILE
+public:
+ PCODE PrepareInitialCode();
+ PCODE PrepareCode(NativeCodeVersion codeVersion);
+ PCODE PrepareCode(PrepareCodeConfig* pConfig);
+
+private:
+ PCODE PrepareILBasedCode(PrepareCodeConfig* pConfig);
+ PCODE GetPrecompiledCode(PrepareCodeConfig* pConfig);
+ PCODE GetPrecompiledNgenCode();
+ PCODE GetPrecompiledR2RCode();
+ PCODE GetMulticoreJitCode();
+ COR_ILMETHOD_DECODER* GetAndVerifyILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory);
+ COR_ILMETHOD_DECODER* GetAndVerifyMetadataILHeader(PrepareCodeConfig* pConfig, COR_ILMETHOD_DECODER* pIlDecoderMemory);
+ COR_ILMETHOD_DECODER* GetAndVerifyNoMetadataILHeader();
+ PCODE JitCompileCode(PrepareCodeConfig* pConfig);
+ PCODE JitCompileCodeLockedEventWrapper(PrepareCodeConfig* pConfig, JitListLockEntry* pEntry);
+ PCODE JitCompileCodeLocked(PrepareCodeConfig* pConfig, JitListLockEntry* pLockEntry, ULONG* pSizeOfCode, CORJIT_FLAGS* pFlags);
+#endif // DACCESS_COMPILE
};
+#ifndef DACCESS_COMPILE
+class PrepareCodeConfig
+{
+public:
+ PrepareCodeConfig();
+ PrepareCodeConfig(NativeCodeVersion nativeCodeVersion, BOOL needsMulticoreJitNotification, BOOL mayUsePrecompiledCode);
+ MethodDesc* GetMethodDesc();
+ NativeCodeVersion GetCodeVersion();
+ BOOL NeedsMulticoreJitNotification();
+ BOOL MayUsePrecompiledCode();
+ virtual PCODE IsJitCancellationRequested();
+ virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse);
+ virtual COR_ILMETHOD* GetILHeader();
+ virtual CORJIT_FLAGS GetJitCompilationFlags();
+
+protected:
+ MethodDesc* m_pMethodDesc;
+ NativeCodeVersion m_nativeCodeVersion;
+ BOOL m_needsMulticoreJitNotification;
+ BOOL m_mayUsePrecompiledCode;
+};
+
+#ifdef FEATURE_CODE_VERSIONING
+class VersionedPrepareCodeConfig : public PrepareCodeConfig
+{
+public:
+ VersionedPrepareCodeConfig();
+ VersionedPrepareCodeConfig(NativeCodeVersion codeVersion);
+ HRESULT FinishConfiguration();
+ virtual PCODE IsJitCancellationRequested();
+ virtual BOOL SetNativeCode(PCODE pCode, PCODE * ppAlternateCodeToUse);
+ virtual COR_ILMETHOD* GetILHeader();
+ virtual CORJIT_FLAGS GetJitCompilationFlags();
+private:
+ ILCodeVersion m_ilCodeVersion;
+};
+#endif // FEATURE_CODE_VERSIONING
+#endif // DACCESS_COMPILE
+
/******************************************************************/
// A code:MethodDescChunk is a container that holds one or more code:MethodDesc. Logically it is just