The JIT now invokes the debugger's JITComplete callback on every jitting of a method
}
CONTRACTL_END;
+ LOG((LF_CORDB, LL_INFO100000, "D::JITComplete: md:0x%x (%s::%s), address:0x%x.\n",
+ fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName,
+ newAddress));
+
#ifdef _TARGET_ARM_
newAddress = newAddress|THUMB_CODE;
#endif
{
goto Exit;
}
- DebuggerJitInfo * ji = dmi->CreateInitAndAddJitInfo(fd, newAddress);
+ BOOL jiWasCreated = FALSE;
+ DebuggerJitInfo * ji = dmi->CreateInitAndAddJitInfo(fd, newAddress, &jiWasCreated);
+ if (!jiWasCreated)
+ {
+ // we've already been notified about this code, no work remains.
+ // The JIT is occasionally asked to generate code for the same
+ // method on two threads. When this occurs both threads will
+ // return the same code pointer and this callback is invoked
+ // multiple times.
+ LOG((LF_CORDB, LL_INFO1000000, "D::JITComplete: md:0x%x (%s::%s), address:0x%x. Already created\n",
+ fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName,
+ newAddress));
+ goto Exit;
+ }
+
+ LOG((LF_CORDB, LL_INFO1000000, "D::JITComplete: md:0x%x (%s::%s), address:0x%x. Created ji:0x%x\n",
+ fd, fd->m_pszDebugClassName, fd->m_pszDebugMethodName,
+ newAddress, ji));
// Bind any IL patches to the newly jitted native code.
HRESULT hr;
// Creating the Jit-infos.
DebuggerJitInfo *FindOrCreateInitAndAddJitInfo(MethodDesc* fd);
- DebuggerJitInfo *CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr);
+ DebuggerJitInfo *CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr, BOOL* jitInfoWasCreated);
void DeleteJitInfo(DebuggerJitInfo *dji);
// CreateInitAndAddJitInfo takes a lock and checks the list again, which
// makes this thread-safe.
- return CreateInitAndAddJitInfo(fd, addr);
+ BOOL unused;
+ return CreateInitAndAddJitInfo(fd, addr, &unused);
}
// Create a DJI around a method-desc. The EE already has all the information we need for a DJI,
// the DJI just serves as a cache of the information for the debugger.
// Caller makes no guarantees about whether the DJI is already in the table. (Caller should avoid this if
// it knows it's in the table, but b/c we can't expect caller to synchronize w/ the other threads).
-DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr)
+DebuggerJitInfo *DebuggerMethodInfo::CreateInitAndAddJitInfo(MethodDesc* fd, TADDR startAddr, BOOL* jitInfoWasCreated)
{
CONTRACTL
{
// May or may-not be jitted, that's why we passed in the start addr & size explicitly.
_ASSERTE(startAddr != NULL);
+ *jitInfoWasCreated = FALSE;
// No support for light-weight codegen methods.
if (fd->IsDynamicMethod())
DeleteInteropSafe(dji);
return pResult;
}
+ else
+ {
+ *jitInfoWasCreated = TRUE;
+ }
}
// We know it's not in the table. Go add it!
//
// Notify the debugger that we have successfully jitted the function
//
- if (ftn->HasNativeCode())
+ if (g_pDebugInterface)
{
- //
- // Nothing to do here (don't need to notify the debugger
- // because the function has already been successfully jitted)
- //
- // This is the case where we aborted the jit because of a deadlock cycle
- // in initClass.
- //
- }
- else
- {
- if (g_pDebugInterface)
+ if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
{
- if (param.res == CORJIT_OK && !((CEEJitInfo*)param.comp)->JitAgain())
- {
- g_pDebugInterface->JITComplete(ftn, (TADDR) *nativeEntry);
- }
+ g_pDebugInterface->JITComplete(ftn, (TADDR)*nativeEntry);
}
}
}