-
Notifications
You must be signed in to change notification settings - Fork 4.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add DOTNET_MODIFIABLE_ASSEMBLIES env var for hot reload support #48731
Conversation
src/coreclr/vm/ceeload.cpp
Outdated
@@ -1087,7 +1090,7 @@ void Module::SetDebuggerInfoBits(DebuggerAssemblyControlFlags newBits) | |||
} | |||
else | |||
{ | |||
if (!g_pConfig->ForceEnc()) | |||
if (!(g_pConfig->ForceEnc() || (g_pConfig->DebugAssembliesModifiable() && CORDisableJITOptimizations(GetDebuggerInfoBits())))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are adding more condition to disable EnC. What is actually going to enable EnC when this env variable is set?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this logic can be simplified:
- Delete
// If the program has the "ForceEnc" env variable set we ensure every eligible // module has EnC turned on. if (g_pConfig->ForceEnc() && IsEditAndContinueCapable()) EnableEditAndContinue();
inModule::Initialize
- Delete
DisableEditAndContinue
method - Enable EnC here for things that need EnC to be enabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SetDebuggerInfoBits is called from a lot of places including the ICorDebugModule API. So doesn't the debugger need to set or clear the ENC flag (EnableEditAndContinue and DisableEditAndContinue) depending on the DACF_ENC_ENABLED flag? What I think you are describing will only allow the debugger to enable ENC not disable it.
Something like this in SetDebuggerInfoBits?
BOOL setEnC = IsEditAndContinueCapable() &&
((newBits & DACF_ENC_ENABLED) != 0 ||
g_pConfig->ForceEnc() ||
(g_pConfig->DebugAssembliesModifiable() && CORDisableJITOptimizations(GetDebuggerInfoBits())));
if (setEnC)
{
EnableEditAndContinue();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or should there be the else clause?
if (setEnC)
{
EnableEditAndContinue();
}
else
{
DisableEditAndContinue();
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the end, I guess you are assuming that debuggers never enable then disable ENC on a module.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be odd. I think enabling EnC should be one way operation - once it is enable, it is cannot be disabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would change the semantics of a public debugger API if it doesn't allow disabling. Are we ok with that even though it would be old?
/cc: @noahfalk
Just to make sure - I assume that the env var does not actually have |
|
||
// The only way can change Enc is through debugger override. | ||
if (setEnC) | ||
if (IsEditAndContinueCapable()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code depends on IsEditAndContinueCapable
to be invariant, but it may actually change because of it depends on GetDebuggerInfoBits
that the debugger can change. There is commented out assert in BOOL IsEditAndContinueEnabled()
that suggest it may actually happen in some cases. I think that this can interact poorly with this change, depending on how the debugger decides to change the bits.
I think we should:
- Compute IsEditAndContinueCapable just once in
Module::Create
- Use immutable cached value of IsEditAndContinueCapable everywhere else. It can be achieve by changing
BOOL IsEditAndContinueCapable()
to virtual method that returns false inclass Module
and returns true inclass EditAndContinueModule
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, enable the assert in IsEditAndContinueEnabled
and change it to just return ((m_dwTransientFlags & IS_EDIT_AND_CONTINUE) != 0);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure that after Module::Create the DACF_ALLOW_JIT_OPTS in the Assembly will not change? What about the debugger API (via DacDbiInterfaceImpl::SetCompilerFlags)? Isn't the module already created by then? It is clear to me and it is confusing because Assembly, DomainAssembly and Module all have flags.
To double check what you are saying about IsEditAndContinueCapable():
Module:
virtual BOOL IsEditAndContinueCapable() const { return FALSE; }
EditAndContinueModule:
virtual BOOL IsEditAndContinueCapable() const { return TRUE; }
Module::Create() doesn't need any changes because it already creates an
EditAndContinueModule
instance if IsEditAndContinueCapable(pAssembly, file)
returns true.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that it is confusing and hard to reason about.
Module::Create() doesn't need any changes
Correct.
{ | ||
if (!g_pConfig->ForceEnc()) | ||
DisableEditAndContinue(); | ||
BOOL setEnC = (newBits & DACF_ENC_ENABLED) != 0 || g_pConfig->ForceEnc() || (g_pConfig->DebugAssembliesModifiable() && CORDisableJITOptimizations(GetDebuggerInfoBits())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that IsEditAndContinueCapable
returns false when the JIT optimizations are enabled for module.
It suggests that CORDisableJITOptimizations
is unnecessary here and this new setting behaves same as the existing ForceEnC switch for all practical purposes. It may be worth capturing this as a comment at least since it is not obvious by looking at the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assumed up to this point that when the ForceEnc env var was set all release and debug built binaries are ENC'able (except system, dynamic, resource and ready to run). If what you implied above that DACF_ALLOW_JIT_OPTS is already set when the Module or ENC module is created, then yes CORDisableJITOptimizations
will always return the same thing (except something about profiling or instrumentation). But I may be confusing between the flags set in the Assembly with the ones set in the Module/ENC Module. I need to dig deeper into this. This is a lot more messy and complicated than I was hoping.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
Issue #47274