summaryrefslogtreecommitdiff
path: root/src/vm
diff options
context:
space:
mode:
authorDan Moseley <danmose@microsoft.com>2017-02-13 16:56:52 -0800
committerGitHub <noreply@github.com>2017-02-13 16:56:52 -0800
commit5c0cf068303c5bb9439d46cb7eafd5fdeb1a718a (patch)
tree956f52bc9d4d8dc064a0b5ec5f0c79c2baab3059 /src/vm
parent8f09876611179ea96b7b0988230b500d8e850020 (diff)
parent01656a9802c4885058a9da831f6e819688a799ed (diff)
downloadcoreclr-5c0cf068303c5bb9439d46cb7eafd5fdeb1a718a.tar.gz
coreclr-5c0cf068303c5bb9439d46cb7eafd5fdeb1a718a.tar.bz2
coreclr-5c0cf068303c5bb9439d46cb7eafd5fdeb1a718a.zip
Merge pull request #9551 from danmosemsft/dead2
Remove dead source files in vm\**
Diffstat (limited to 'src/vm')
-rw-r--r--src/vm/amd64/remotingamd64.cpp672
-rw-r--r--src/vm/appdomain.cpp1
-rw-r--r--src/vm/appdomainhelper.cpp546
-rw-r--r--src/vm/appdomainhelper.h371
-rw-r--r--src/vm/appdomainnative.cpp1
-rw-r--r--src/vm/assembly.cpp1
-rw-r--r--src/vm/assemblynamesconfigfactory.cpp264
-rw-r--r--src/vm/assemblynamesconfigfactory.h72
-rw-r--r--src/vm/assemblynative.cpp1
-rw-r--r--src/vm/ceeload.cpp3
-rw-r--r--src/vm/clrprivbinderfusion.cpp819
-rw-r--r--src/vm/clrprivbinderfusion.h228
-rw-r--r--src/vm/clrprivbinderreflectiononlywinrt.cpp497
-rw-r--r--src/vm/clrprivbinderreflectiononlywinrt.h295
-rw-r--r--src/vm/clrprivtypecachereflectiononlywinrt.cpp260
-rw-r--r--src/vm/clrprivtypecachereflectiononlywinrt.h58
-rw-r--r--src/vm/cominterfacemarshaler.cpp1
-rw-r--r--src/vm/commethodrental.cpp120
-rw-r--r--src/vm/commethodrental.h29
-rw-r--r--src/vm/comsynchronizable.cpp1
-rw-r--r--src/vm/constrainedexecutionregion.cpp2264
-rw-r--r--src/vm/crossdomaincalls.cpp2587
-rw-r--r--src/vm/eeconfigfactory.cpp398
-rw-r--r--src/vm/eeconfigfactory.h149
-rw-r--r--src/vm/gchost.cpp28
-rw-r--r--src/vm/i386/excepx86.cpp1
-rw-r--r--src/vm/i386/remotingx86.cpp225
-rw-r--r--src/vm/mda.cpp4017
-rw-r--r--src/vm/mda.h1
-rw-r--r--src/vm/mdadac.cpp48
-rw-r--r--src/vm/message.cpp1171
-rw-r--r--src/vm/mixedmode.cpp236
-rw-r--r--src/vm/mixedmode.hpp4
-rw-r--r--src/vm/mscorlib.cpp5
-rw-r--r--src/vm/ngenoptout.cpp12
-rw-r--r--src/vm/ngenoptout.h34
-rw-r--r--src/vm/objectclone.cpp3861
-rw-r--r--src/vm/pefile.h2
-rw-r--r--src/vm/remoting.cpp3773
-rw-r--r--src/vm/rwlock.cpp2952
-rw-r--r--src/vm/rwlock.h214
-rw-r--r--src/vm/securitymeta.cpp1
-rw-r--r--src/vm/securitystackwalk.h1
-rw-r--r--src/vm/stackbuildersink.cpp702
-rw-r--r--src/vm/threads.cpp1
-rw-r--r--src/vm/validator.cpp946
46 files changed, 5 insertions, 27868 deletions
diff --git a/src/vm/amd64/remotingamd64.cpp b/src/vm/amd64/remotingamd64.cpp
deleted file mode 100644
index 587afae124..0000000000
--- a/src/vm/amd64/remotingamd64.cpp
+++ /dev/null
@@ -1,672 +0,0 @@
-// 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.
-/*===========================================================================
-**
-** File: RemotingCpu.cpp
-**
-**
-**
-** Purpose: Defines various remoting related functions for the AMD64 architecture
-**
-**
-** See code:EEStartup#TableOfContents for EE overview
-**
-=============================================================================*/
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-
-#include "excep.h"
-#include "comdelegate.h"
-#include "remoting.h"
-#include "field.h"
-#include "siginfo.hpp"
-#include "stackbuildersink.h"
-#include "threads.h"
-#include "method.hpp"
-
-#include "asmconstants.h"
-
-// External variables
-extern DWORD g_dwNonVirtualThunkRemotingLabelOffset;
-extern DWORD g_dwNonVirtualThunkReCheckLabelOffset;
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CheckForContextMatch public
-//
-// Synopsis: This code generates a check to see if the current context and
-// the context of the proxy match.
-//
-//+----------------------------------------------------------------------------
-//
-// returns zero if contexts match
-// returns non-zero if contexts don't match
-//
-extern "C" UINT_PTR __stdcall CRemotingServices__CheckForContextMatch(Object* pStubData)
-{
- // This method cannot have a contract because CreateStubForNonVirtualMethod assumes
- // it won't trash XMM registers. The code generated for contracts by recent compilers
- // is trashing XMM registers.
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
- STATIC_CONTRACT_MODE_COOPERATIVE; // due to the Object parameter
- STATIC_CONTRACT_SO_TOLERANT;
-
- UINT_PTR contextID = *(UINT_PTR*)pStubData->UnBox();
- UINT_PTR contextCur = (UINT_PTR)GetThread()->m_Context;
- return (contextCur != contextID); // chosen to match x86 convention
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CreateThunkForVirtualMethod private
-//
-// Synopsis: Creates the thunk that pushes the supplied slot number and jumps
-// to TP Stub
-//
-//+----------------------------------------------------------------------------
-PCODE CTPMethodTable::CreateThunkForVirtualMethod(DWORD dwSlot, BYTE* pbCode)
-{
- LIMITED_METHOD_CONTRACT;
-
- BYTE *pbCodeStart = pbCode;
-
- // NOTE: if you change the code generated here, update
- // CVirtualThunkMgr::IsThunkByASM, CVirtualThunkMgr::GetMethodDescByASM
-
- //
- // mov r10, <dwSlot>
- // mov rax, TransparentProxyStub
- // jmp rax
- //
- *pbCode++ = 0x49;
- *pbCode++ = 0xc7;
- *pbCode++ = 0xc2;
- *((DWORD*)pbCode) = dwSlot;
- pbCode += sizeof(DWORD);
- *pbCode++ = 0x48;
- *pbCode++ = 0xB8;
- *((UINT64*)pbCode) = (UINT64)(TransparentProxyStub);
- pbCode += sizeof(UINT64);
- *pbCode++ = 0xFF;
- *pbCode++ = 0xE0;
-
- _ASSERTE(pbCode - pbCodeStart == ConstVirtualThunkSize);
- _ASSERTE(CVirtualThunkMgr::IsThunkByASM((PCODE)pbCodeStart));
-
- return (PCODE)pbCodeStart;
-}
-
-
-#ifdef HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::ActivatePrecodeRemotingThunk private
-//
-// Synopsis: Patch the precode remoting thunk to begin interception
-//
-//+----------------------------------------------------------------------------
-void CTPMethodTable::ActivatePrecodeRemotingThunk()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- PORTABILITY_WARNING("CTPMethodTable::ActivatePrecodeRemotingThunk");
-}
-
-#else // HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CreateStubForNonVirtualMethod public
-//
-// Synopsis: Create a stub for a non virtual method
-//
-//+----------------------------------------------------------------------------
-Stub* CTPMethodTable::CreateStubForNonVirtualMethod(MethodDesc* pMD, CPUSTUBLINKER* psl,
- LPVOID pvAddrOfCode, Stub* pInnerStub)
-{
- STANDARD_VM_CONTRACT;
-
- // Sanity check
-
- Stub *pStub = NULL;
-
- // we need a hash table only for virtual methods
- _ASSERTE(!pMD->IsVirtual());
-
- // Ensure the TP MethodTable's fields have been initialized.
- EnsureFieldsInitialized();
-
- /*
- NonVirtualMethodStub<thisReg, pvAddrOfCode, pTPMethodTable, pvTPStub>
- {
- ;; thisReg: this
-
- sub rsp, 0x28
-
- test thisReg, thisReg
- je JmpAddrLabel
-
- mov rax, [thisReg]
- mov r10, <pTPMethodTable>
- cmp rax, r10
- jne JmpAddrLabel
-
- mov [rsp+0x30], rcx ;|
- mov [rsp+0x38], rdx ;|
- mov [rsp+0x40], r8 ;|
- mov [rsp+0x48], r9 ;|
- ;|
- mov rax, [thisReg + TransparentProxyObject___stubData] ;|
- call [thisReg + TransparentProxyObject___stub] ;| EmitCallToStub<pCtxMismatch>
- ;|
- mov rcx, [rsp+0x30] ;|
- mov rdx, [rsp+0x38] ;|
- mov r8, [rsp+0x40] ;|
- mov r9, [rsp+0x48] ;|
- ;|
- test rax, rax ;|
- jnz RemotingLabel ;|
-
- JmpAddrLabel:
- mov rax, <pvAddrOfCode>
- add rsp, 0x28
- jmp rax
-
- RemotingLabel:
- mov r10, <pMD>
- mov rax, <pvTPStub>
- add rsp, 0x20
- jmp rax
- }
- */
-
- X86Reg thisReg = kRCX;
- void* pvTPStub = TransparentProxyStub_CrossContext;
-
- // Generate label where a null reference exception will be thrown
- CodeLabel *pJmpAddrLabel = psl->NewCodeLabel();
- // Generate label where remoting code will execute
- CodeLabel *pRemotingLabel = psl->NewCodeLabel();
-
- // NOTE: if you change any of this code, you must update
- // CNonVirtualThunkMgr::IsThunkByASM.
-
- // Allocate callee scratch area
- // sub rsp, 0x28
- psl->X86EmitSubEsp(0x28);
-
- // test thisReg, thisReg
- psl->X86EmitR2ROp(0x85, thisReg, thisReg);
- // je JmpAddrLabel
- psl->X86EmitCondJump(pJmpAddrLabel, X86CondCode::kJE);
-
- // Emit a label here for the debugger. A breakpoint will
- // be set at the next instruction and the debugger will
- // call CNonVirtualThunkMgr::TraceManager when the
- // breakpoint is hit with the thread's context.
- CodeLabel *pRecheckLabel = psl->NewCodeLabel();
- psl->EmitLabel(pRecheckLabel);
-
- // mov rax, [thisReg]
- psl->X86EmitIndexRegLoad(kRAX, thisReg, 0);
-
- // mov r10, CTPMethodTable::GetMethodTable()
- psl->X86EmitRegLoad(kR10, (UINT_PTR)CTPMethodTable::GetMethodTable());
- // cmp rax, r10
- psl->X86EmitR2ROp(0x3B, kRAX, kR10);
-
- // jne JmpAddrLabel
- psl->X86EmitCondJump(pJmpAddrLabel, X86CondCode::kJNE);
-
- // CONSIDER: write all possible stubs in asm to ensure param registers are not trashed
-
- // mov [rsp+0x30], rcx
- // mov [rsp+0x38], rdx
- // mov [rsp+0x40], r8
- // mov [rsp+0x48], r9
- psl->X86EmitRegSave(kRCX, 0x30);
- psl->X86EmitRegSave(kRDX, 0x38);
- psl->X86EmitRegSave(kR8, 0x40);
- psl->X86EmitRegSave(kR9, 0x48);
-
- // mov rax, [thisReg + TransparentProxyObject___stub]
- psl->X86EmitIndexRegLoad(kRAX, thisReg, TransparentProxyObject___stub);
-
- // mov rcx, [thisReg + TransparentProxyObject___stubData]
- psl->X86EmitIndexRegLoad(kRCX, thisReg, TransparentProxyObject___stubData);
-
- // call rax
- psl->Emit16(0xd0ff);
-
- // mov rcx, [rsp+0x30]
- // mov rdx, [rsp+0x38]
- // mov r8, [rsp+0x40]
- // mov r9, [rsp+0x48]
- psl->X86EmitEspOffset(0x8b, kRCX, 0x30);
- psl->X86EmitEspOffset(0x8b, kRDX, 0x38);
- psl->X86EmitEspOffset(0x8b, kR8, 0x40);
- psl->X86EmitEspOffset(0x8b, kR9, 0x48);
-
- // test rax, rax
- psl->X86EmitR2ROp(0x85, kRAX, kRAX);
- // jnz RemotingLabel
- psl->X86EmitCondJump(pRemotingLabel, X86CondCode::kJNZ);
-
-// pJmpAddrLabel:
- psl->EmitLabel(pJmpAddrLabel);
-
- // Make sure that the actual code does not require MethodDesc in r10
- _ASSERTE(!pMD->RequiresMethodDescCallingConvention());
-
- // mov rax, <pvAddrOfCode>
- // add rsp, 0x28
- // REX.W jmp rax
- psl->X86EmitTailcallWithESPAdjust(psl->NewExternalCodeLabel(pvAddrOfCode), 0x28);
-
-// pRemotingLabel:
- psl->EmitLabel(pRemotingLabel);
-
- // mov r10, <pMD>
- psl->X86EmitRegLoad(kR10, (UINT_PTR)pMD);
-
- // mov rax, <pvTPStub>
- // add rsp, 0x28
- // REX.W jmp rax
- psl->X86EmitTailcallWithESPAdjust(psl->NewExternalCodeLabel(pvTPStub), 0x28);
-
- // Link and produce the stub
- pStub = psl->LinkInterceptor(pMD->GetLoaderAllocator()->GetStubHeap(),
- pInnerStub, pvAddrOfCode);
-
- return pStub;
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Synopsis: Find an existing thunk or create a new one for the given
-// method descriptor. NOTE: This is used for the methods that do
-// not go through the vtable such as constructors, private and
-// final methods.
-//
-//+----------------------------------------------------------------------------
-PCODE CTPMethodTable::CreateNonVirtualThunkForVirtualMethod(MethodDesc* pMD)
-{
- CONTRACTL
- {
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(pMD));
- }
- CONTRACTL_END;
-
- CPUSTUBLINKER sl;
- CPUSTUBLINKER* psl = &sl;
-
- Stub *pStub = NULL;
-
- // The thunk has not been created yet. Go ahead and create it.
- // Compute the address of the slot
- LPVOID pvEntryPoint = (LPVOID)pMD->GetMethodEntryPoint();
-
- X86Reg thisReg = kRCX;
- void* pvStub = CRemotingServices__DispatchInterfaceCall;
-
- // Generate label where a null reference exception will be thrown
- CodeLabel *pExceptionLabel = psl->NewCodeLabel();
-
- // !!! WARNING WARNING WARNING WARNING WARNING !!!
- //
- // DO NOT CHANGE this code without changing the thunk recognition
- // code in CNonVirtualThunkMgr::IsThunkByASM
- // & CNonVirtualThunkMgr::GetMethodDescByASM
- //
- // !!! WARNING WARNING WARNING WARNING WARNING !!!
-
- // NOTE: constant mov's should use an extended register to force a REX
- // prefix and the full 64-bit immediate value, so that
- // g_dwNonVirtualThunkRemotingLabelOffset and
- // g_dwNonVirtualThunkReCheckLabelOffset are the same for all
- // generated code.
-
- // if this == NULL throw NullReferenceException
- // test rcx, rcx
- psl->X86EmitR2ROp(0x85, thisReg, thisReg);
-
- // je ExceptionLabel
- psl->X86EmitCondJump(pExceptionLabel, X86CondCode::kJE);
-
- // Generate label where remoting code will execute
- CodeLabel *pRemotingLabel = psl->NewCodeLabel();
-
- // Emit a label here for the debugger. A breakpoint will
- // be set at the next instruction and the debugger will
- // call CNonVirtualThunkMgr::TraceManager when the
- // breakpoint is hit with the thread's context.
- CodeLabel *pRecheckLabel = psl->NewCodeLabel();
- psl->EmitLabel(pRecheckLabel);
-
- // If this.MethodTable == TPMethodTable then do RemotingCall
- // mov rax, [thisReg]
- psl->X86EmitIndexRegLoad(kRAX, thisReg, 0);
- // mov r10, CTPMethodTable::GetMethodTable()
- psl->X86EmitRegLoad(kR10, (UINT_PTR)CTPMethodTable::GetMethodTable());
- // cmp rax, r10
- psl->X86EmitR2ROp(0x3B, kRAX, kR10);
- // je RemotingLabel
- psl->X86EmitCondJump(pRemotingLabel, X86CondCode::kJE);
-
- // Exception handling and non-remoting share the
- // same codepath
- psl->EmitLabel(pExceptionLabel);
-
- // Non-RemotingCode
- // Jump to the vtable slot of the method
- // mov rax, pvEntryPoint
- // Encoded the mov manually so that it always uses the 64-bit form.
- //psl->X86EmitRegLoad(kRAX, (UINT_PTR)pvEntryPoint);
- psl->Emit8(REX_PREFIX_BASE | REX_OPERAND_SIZE_64BIT);
- psl->Emit8(0xb8);
- psl->EmitBytes((BYTE*)&pvEntryPoint, 8);
- // jmp rax
- psl->Emit8(0xff);
- psl->Emit8(0xe0);
-
- // Remoting code. Note: CNonVirtualThunkMgr::TraceManager
- // relies on this label being right after the jmp pvEntryPoint
- // instruction above. If you move this label, update
- // CNonVirtualThunkMgr::DoTraceStub.
- psl->EmitLabel(pRemotingLabel);
-
- // Save the MethodDesc and goto TPStub
- // push MethodDesc
- psl->X86EmitRegLoad(kR10, (UINT_PTR)pMD);
-
- // jmp TPStub
- psl->X86EmitNearJump(psl->NewExternalCodeLabel(pvStub));
-
- // Link and produce the stub
- // FUTURE: Do we have to provide the loader heap ?
- pStub = psl->Link(SystemDomain::GetGlobalLoaderAllocator()->GetExecutableHeap());
-
- // Grab the offset of the RemotingLabel and RecheckLabel
- // for use in CNonVirtualThunkMgr::DoTraceStub and
- // TraceManager.
- DWORD dwOffset;
-
- dwOffset = psl->GetLabelOffset(pRemotingLabel);
- ASSERT(!g_dwNonVirtualThunkRemotingLabelOffset || g_dwNonVirtualThunkRemotingLabelOffset == dwOffset);
- g_dwNonVirtualThunkRemotingLabelOffset = dwOffset;
-
- dwOffset = psl->GetLabelOffset(pRecheckLabel);
- ASSERT(!g_dwNonVirtualThunkReCheckLabelOffset || g_dwNonVirtualThunkReCheckLabelOffset == dwOffset);
- g_dwNonVirtualThunkReCheckLabelOffset = dwOffset;
-
- return (pStub->GetEntryPoint());
-}
-
-#endif // HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::DoTraceStub public
-//
-// Synopsis: Traces the stub given the starting address
-//
-//+----------------------------------------------------------------------------
-BOOL CVirtualThunkMgr::DoTraceStub(PCODE stubStartAddress, TraceDestination *trace)
-{
- LIMITED_METHOD_CONTRACT;
-
- // <TODO> implement this </TODO>
- return FALSE;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::IsThunkByASM public
-//
-// Synopsis: Check assembly to see if this one of our thunks
-//
-//+----------------------------------------------------------------------------
-BOOL CVirtualThunkMgr::IsThunkByASM(PCODE startaddr)
-{
- LIMITED_METHOD_CONTRACT;
-
- PTR_BYTE pbCode = PTR_BYTE(startaddr);
-
- // NOTE: this depends on the code generated by
- // CTPMethodTable::CreateThunkForVirtualMethod.
-
- // mov r10, <dwSlot>
- return 0x49 == pbCode[0]
- && 0xc7 == pbCode[1]
- && 0xc2 == pbCode[2]
- // mov rax, TransparentProxyStub
- && 0x48 == pbCode[7]
- && 0xb8 == pbCode[8]
- && (TADDR)TransparentProxyStub == *PTR_TADDR(pbCode+9)
- // jmp rax
- && 0xff == pbCode[17]
- && 0xe0 == pbCode[18];
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::GetMethodDescByASM public
-//
-// Synopsis: Parses MethodDesc out of assembly code
-//
-//+----------------------------------------------------------------------------
-MethodDesc *CVirtualThunkMgr::GetMethodDescByASM(PCODE pbThunkCode, MethodTable *pMT)
-{
- LIMITED_METHOD_CONTRACT;
-
- // NOTE: this depends on the code generated by
- // CTPMethodTable::CreateThunkForVirtualMethod.
-
- return pMT->GetMethodDescForSlot(*((DWORD *) (pbThunkCode + 3)));
-}
-
-
-#ifndef HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::TraceManager public
-//
-// Synopsis: Traces the stub given the current context
-//
-//+----------------------------------------------------------------------------
-BOOL CNonVirtualThunkMgr::TraceManager(Thread* thread,
- TraceDestination* trace,
- CONTEXT* pContext,
- BYTE** pRetAddr)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(thread, NULL_OK));
- PRECONDITION(CheckPointer(trace));
- PRECONDITION(CheckPointer(pContext));
- PRECONDITION(CheckPointer(pRetAddr));
- }
- CONTRACTL_END;
-
- BOOL bRet = FALSE;
-
- MethodDesc * pMD = GetMethodDescByASM(GetIP(pContext) - g_dwNonVirtualThunkReCheckLabelOffset);
-
- LPBYTE pThis = (LPBYTE)pContext->Rcx;
-
- if ((pThis != NULL) &&
- (*(LPBYTE*)(SIZE_T)pThis == (LPBYTE)(SIZE_T)CTPMethodTable::GetMethodTable()))
- {
- // <TODO>We know that we've got a proxy
- // in the way. If the proxy is to a remote call, with no
- // managed code in between, then the debugger doesn't care and
- // we should just be able to return FALSE.
- //
- // </TODO>
- bRet = FALSE;
- }
- else
- {
- // No proxy in the way, so figure out where we're really going
- // to and let the stub manager try to pickup the trace from
- // there.
- LPBYTE stubStartAddress = (LPBYTE)GetIP(pContext) -
- g_dwNonVirtualThunkReCheckLabelOffset;
-
- // Extract the address of the destination
- BYTE* pbAddr = (BYTE *)(SIZE_T)(stubStartAddress +
- g_dwNonVirtualThunkRemotingLabelOffset - 2 - sizeof(void *));
-
- SIZE_T destAddress = *(SIZE_T *)pbAddr;
-
- // Ask the stub manager to trace the destination address
- bRet = StubManager::TraceStub((PCODE)(BYTE *)(size_t)destAddress, trace);
- }
-
- // While we may have made it this far, further tracing may reveal
- // that the debugger can't continue on. Therefore, since there is
- // no frame currently pushed, we need to tell the debugger where
- // we're returning to just in case it hits such a situtation. We
- // know that the return address is on the top of the thread's
- // stack.
- (*pRetAddr) = *((BYTE**)(size_t)(GetSP(pContext)));
-
- return bRet;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::DoTraceStub public
-//
-// Synopsis: Traces the stub given the starting address
-//
-//+----------------------------------------------------------------------------
-BOOL CNonVirtualThunkMgr::DoTraceStub(PCODE stubStartAddress,
- TraceDestination* trace)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(stubStartAddress != NULL);
- PRECONDITION(CheckPointer(trace));
- }
- CONTRACTL_END;
-
- BOOL bRet = FALSE;
-
- if (!IsThunkByASM(stubStartAddress))
- return FALSE;
-
- CNonVirtualThunk* pThunk = FindThunk((const BYTE *)stubStartAddress);
-
- if(NULL != pThunk)
- {
- // We can either jump to
- // (1) a slot in the transparent proxy table (UNMANAGED)
- // (2) a slot in the non virtual part of the vtable
- // ... so, we need to return TRACE_MGR_PUSH with the address
- // at which we want to be called back with the thread's context
- // so we can figure out which way we're gonna go.
- if((const BYTE *)stubStartAddress == pThunk->GetThunkCode())
- {
- trace->InitForManagerPush(
- (PCODE) (stubStartAddress + g_dwNonVirtualThunkReCheckLabelOffset),
- this);
- bRet = TRUE;
- }
- }
-
- return bRet;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::IsThunkByASM public
-//
-// Synopsis: Check assembly to see if this one of our thunks
-//
-//+----------------------------------------------------------------------------
-BOOL CNonVirtualThunkMgr::IsThunkByASM(PCODE startaddr)
-{
- LIMITED_METHOD_CONTRACT;
-
- PTR_BYTE pbCode = PTR_BYTE(startaddr);
-
- // test rcx, rcx ; 3 bytes
- return 0x48 == pbCode[0]
- && 0x85 == pbCode[1]
- && 0xc9 == pbCode[2]
- // je ... ; 2 bytes
- && 0x74 == pbCode[3]
- // mov rax, [rcx] ; 3 bytes
- // mov r10, CTPMethodTable::GetMethodTable() ; 2 bytes + MethodTable*
- && (TADDR)CTPMethodTable::GetMethodTable() == *PTR_TADDR(pbCode + 10);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::GetMethodDescByASM public
-//
-// Synopsis: Parses MethodDesc out of assembly code
-//
-//+----------------------------------------------------------------------------
-MethodDesc* CNonVirtualThunkMgr::GetMethodDescByASM(PCODE pbThunkCode)
-{
- LIMITED_METHOD_CONTRACT;
-
- return *((MethodDesc **) (pbThunkCode + g_dwNonVirtualThunkRemotingLabelOffset + 2));
-}
-
-#endif // HAS_REMOTING_PRECODE
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::GenericCheckForContextMatch private
-//
-// Synopsis: Calls the stub in the TP & returns TRUE if the contexts
-// match, FALSE otherwise.
-//
-// Note: 1. Called during FieldSet/Get, used for proxy extensibility
-//
-//+----------------------------------------------------------------------------
-BOOL __stdcall CTPMethodTable__GenericCheckForContextMatch(Object* orTP)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE; // due to the Object parameter
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- Object *StubData = OBJECTREFToObject(((TransparentProxyObject*)orTP)->GetStubData());
- CTPMethodTable::CheckContextCrossingProc *pfnCheckContextCrossing =
- (CTPMethodTable::CheckContextCrossingProc*)(((TransparentProxyObject*)orTP)->GetStub());
- return pfnCheckContextCrossing(StubData) == 0;
-}
-
-#endif // FEATURE_REMOTING
-
-
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index e6d4ed1b4b..e13c7dbe2a 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -37,7 +37,6 @@
#include "comdelegate.h"
#include "siginfo.hpp"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#include "objectclone.h"
#endif
#include "typekey.h"
diff --git a/src/vm/appdomainhelper.cpp b/src/vm/appdomainhelper.cpp
deleted file mode 100644
index 2c0531648f..0000000000
--- a/src/vm/appdomainhelper.cpp
+++ /dev/null
@@ -1,546 +0,0 @@
-// 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.
-
-
-//
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-
-#include "appdomainhelper.h"
-#include "appdomain.inl"
-
-void AppDomainHelper::CopyEncodingToByteArray(IN PBYTE pbData,
- IN DWORD cbData,
- OUT OBJECTREF* pArray)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(cbData==0 || pbData!=NULL);
- PRECONDITION(CheckPointer(pArray));
- }
- CONTRACTL_END;
- PREFIX_ASSUME(pArray != NULL);
-
- U1ARRAYREF pObj;
-
- if(cbData) {
- pObj = (U1ARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_U1,cbData);
- memcpyNoGCRefs(pObj->m_Array, pbData, cbData);
- *pArray = (OBJECTREF) pObj;
- } else
- *pArray = NULL;
-
- VALIDATEOBJECTREF(*pArray);
-}
-
-
-void AppDomainHelper::CopyByteArrayToEncoding(IN U1ARRAYREF* pArray,
- OUT PBYTE* ppbData,
- OUT DWORD* pcbData)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- PRECONDITION(pArray!=NULL);
- PRECONDITION(ppbData!=NULL);
- PRECONDITION(pcbData!=NULL);
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*pArray);
-
- if (*pArray == NULL) {
- *ppbData = NULL;
- *pcbData = 0;
- return;
- }
-
- DWORD size = (*pArray)->GetNumComponents();
- if(size) {
- *ppbData = new BYTE[size];
- *pcbData = size;
-
- CopyMemory(*ppbData, (*pArray)->GetDirectPointerToNonObjectElements(), size);
- }
-}
-
-
-struct MarshalObjectArgs : public CtxTransitionBaseArgs
-{
- OBJECTREF* orObject;
- U1ARRAYREF* porBlob;
-};
-
-void MarshalObjectADCallback(MarshalObjectArgs * args)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
- MethodDescCallSite marshalObject(METHOD__APP_DOMAIN__MARSHAL_OBJECT);
-
- ARG_SLOT argsCall[] = {
- ObjToArgSlot(*(args->orObject))
- };
-
- *(args->porBlob) = (U1ARRAYREF) marshalObject.Call_RetOBJECTREF(argsCall);
-}
-
-
-// Marshal a single object into a serialized blob.
-void AppDomainHelper::MarshalObject(ADID appDomain,
- IN OBJECTREF *orObject, // Object must be GC protected
- OUT U1ARRAYREF *porBlob)
-{
-
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orObject!=NULL);
- PRECONDITION(porBlob!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*orObject);
-
- MarshalObjectArgs args;
- args.orObject = orObject;
- args.porBlob = porBlob;
-
- MakeCallWithPossibleAppDomainTransition(appDomain, (FPAPPDOMAINCALLBACK) MarshalObjectADCallback, &args);
-
- VALIDATEOBJECTREF(*porBlob);
-
-}
-
-void AppDomainHelper::MarshalObject(IN OBJECTREF *orObject, // Object must be GC protected
- OUT U1ARRAYREF *porBlob)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orObject!=NULL);
- PRECONDITION(porBlob!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*orObject);
-
- MethodDescCallSite marshalObject(METHOD__APP_DOMAIN__MARSHAL_OBJECT);
-
- ARG_SLOT argsCall[] = {
- ObjToArgSlot(*orObject)
- };
-
- *porBlob = (U1ARRAYREF) marshalObject.Call_RetOBJECTREF(argsCall);
-
- VALIDATEOBJECTREF(*porBlob);
-}
-
-// Marshal a single object into a serialized blob.
-void AppDomainHelper::MarshalObject(IN AppDomain *pDomain,
- IN OBJECTREF *orObject, // Object must be GC protected
- OUT BYTE **ppbBlob,
- OUT DWORD *pcbBlob)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(orObject!=NULL);
- PRECONDITION(ppbBlob!=NULL);
- PRECONDITION(pcbBlob!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*orObject);
-
- U1ARRAYREF orBlob = NULL;
-
- GCPROTECT_BEGIN(orBlob);
-
- MethodDescCallSite marshalObject(METHOD__APP_DOMAIN__MARSHAL_OBJECT);
-
- ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN)
- {
- ARG_SLOT args[] =
- {
- ObjToArgSlot(*orObject)
- };
-
- orBlob = (U1ARRAYREF) marshalObject.Call_RetOBJECTREF(args);
- }
- END_DOMAIN_TRANSITION;
-
- if (orBlob != NULL)
- CopyByteArrayToEncoding(&orBlob,
- ppbBlob,
- pcbBlob);
- GCPROTECT_END();
-}
-
-// Marshal two objects into serialized blobs.
-void AppDomainHelper::MarshalObjects(IN AppDomain *pDomain,
- IN OBJECTREF *orObject1,
- IN OBJECTREF *orObject2,
- OUT BYTE **ppbBlob1,
- OUT DWORD *pcbBlob1,
- OUT BYTE **ppbBlob2,
- OUT DWORD *pcbBlob2)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(orObject1!=NULL);
- PRECONDITION(ppbBlob1!=NULL);
- PRECONDITION(pcbBlob1!=NULL);
- PRECONDITION(orObject2!=NULL);
- PRECONDITION(ppbBlob2!=NULL);
- PRECONDITION(pcbBlob2!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject1));
- PRECONDITION(IsProtectedByGCFrame(orObject2));
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*orObject1);
- VALIDATEOBJECTREF(*orObject2);
-
- struct _gc {
- U1ARRAYREF orBlob1;
- U1ARRAYREF orBlob2;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
-
- MethodDescCallSite marshalObjects(METHOD__APP_DOMAIN__MARSHAL_OBJECTS);
-
- ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN)
- {
- ARG_SLOT args[] =
- {
- ObjToArgSlot(*orObject1),
- ObjToArgSlot(*orObject2),
- PtrToArgSlot(&gc.orBlob2),
- };
-
- gc.orBlob1 = (U1ARRAYREF) marshalObjects.Call_RetOBJECTREF(args);
- }
- END_DOMAIN_TRANSITION;
-
- if (gc.orBlob1 != NULL)
- {
- CopyByteArrayToEncoding(&gc.orBlob1,
- ppbBlob1,
- pcbBlob1);
- }
-
- if (gc.orBlob2 != NULL)
- {
- CopyByteArrayToEncoding(&gc.orBlob2,
- ppbBlob2,
- pcbBlob2);
- }
-
- GCPROTECT_END();
-}
-
-// Unmarshal a single object from a serialized blob.
-// Callers must GC protect both porBlob and porObject.
-void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain,
- IN U1ARRAYREF *porBlob, // Object must be GC protected
- OUT OBJECTREF *porObject) // Object must be GC protected
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(porBlob!=NULL);
- PRECONDITION(porObject!=NULL);
- PRECONDITION(IsProtectedByGCFrame(porBlob));
- PRECONDITION(IsProtectedByGCFrame(porObject));
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*porBlob);
-
- MethodDescCallSite unmarshalObject(METHOD__APP_DOMAIN__UNMARSHAL_OBJECT);
-
- ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN)
- {
- ARG_SLOT args[] =
- {
- ObjToArgSlot(*porBlob)
- };
-
- *porObject = unmarshalObject.Call_RetOBJECTREF(args);
- }
- END_DOMAIN_TRANSITION;
-
- VALIDATEOBJECTREF(*porObject);
-}
-
-// Unmarshal a single object from a serialized blob.
-void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain,
- IN BYTE *pbBlob,
- IN DWORD cbBlob,
- OUT OBJECTREF *porObject)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(porObject!=NULL);
- PRECONDITION(IsProtectedByGCFrame(porObject));
- }
- CONTRACTL_END;
-
- OBJECTREF orBlob = NULL;
-
- MethodDescCallSite unmarshalObject(METHOD__APP_DOMAIN__UNMARSHAL_OBJECT);
-
- ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN)
- {
- GCPROTECT_BEGIN(orBlob);
-
- AppDomainHelper::CopyEncodingToByteArray(pbBlob,
- cbBlob,
- &orBlob);
-
- ARG_SLOT args[] =
- {
- ObjToArgSlot(orBlob)
- };
-
- *porObject = unmarshalObject.Call_RetOBJECTREF(args);
-
- GCPROTECT_END();
- }
- END_DOMAIN_TRANSITION;
-
- VALIDATEOBJECTREF(*porObject);
-}
-
-// Unmarshal two objects from serialized blobs.
-void AppDomainHelper::UnmarshalObjects(IN AppDomain *pDomain,
- IN BYTE *pbBlob1,
- IN DWORD cbBlob1,
- IN BYTE *pbBlob2,
- IN DWORD cbBlob2,
- OUT OBJECTREF *porObject1,
- OUT OBJECTREF *porObject2)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(porObject1!=NULL);
- PRECONDITION(porObject2!=NULL);
- PRECONDITION(IsProtectedByGCFrame(porObject1));
- PRECONDITION(IsProtectedByGCFrame(porObject2));
- }
- CONTRACTL_END;
-
- MethodDescCallSite unmarshalObjects(METHOD__APP_DOMAIN__UNMARSHAL_OBJECTS);
-
- struct _gc {
- OBJECTREF orBlob1;
- OBJECTREF orBlob2;
- OBJECTREF orObject2;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN)
- {
-
- GCPROTECT_BEGIN(gc);
-
- AppDomainHelper::CopyEncodingToByteArray(pbBlob1,
- cbBlob1,
- &gc.orBlob1);
-
- AppDomainHelper::CopyEncodingToByteArray(pbBlob2,
- cbBlob2,
- &gc.orBlob2);
-
- ARG_SLOT args[] =
- {
- ObjToArgSlot(gc.orBlob1),
- ObjToArgSlot(gc.orBlob2),
- PtrToArgSlot(&gc.orObject2),
- };
-
- *porObject1 = unmarshalObjects.Call_RetOBJECTREF(args);
- *porObject2 = gc.orObject2;
-
- GCPROTECT_END();
- }
- END_DOMAIN_TRANSITION;
-
- VALIDATEOBJECTREF(*porObject1);
- VALIDATEOBJECTREF(*porObject2);
-}
-
-// Copy an object from the given appdomain into the current appdomain.
-OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN ADID dwDomainId,
- IN OBJECTREF *orObject) // Object must be GC protected
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orObject!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- }
- CONTRACTL_END;
-
- struct _gc
- {
- U1ARRAYREF orBlob;
- OBJECTREF pResult;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
- AppDomainHelper::MarshalObject(dwDomainId, orObject, &gc.orBlob);
- AppDomainHelper::UnmarshalObject(GetAppDomain(), &gc.orBlob, &gc.pResult);
- GCPROTECT_END();
- VALIDATEOBJECTREF(gc.pResult);
- return gc.pResult;
-}
-
-// Copy an object from the given appdomain into the current appdomain.
-OBJECTREF AppDomainHelper::CrossContextCopyTo(IN ADID dwDomainId,
- IN OBJECTREF *orObject) // Object must be GC protected
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orObject!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- }
- CONTRACTL_END;
-
-
- struct _gc
- {
- U1ARRAYREF orBlob;
- OBJECTREF pResult;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
- AppDomainHelper::MarshalObject(orObject, &gc.orBlob);
- ENTER_DOMAIN_ID(dwDomainId);
- AppDomainHelper::UnmarshalObject(GetAppDomain(),&gc.orBlob, &gc.pResult);
- END_DOMAIN_TRANSITION;
- GCPROTECT_END();
- VALIDATEOBJECTREF(gc.pResult);
- return gc.pResult;
-
-}
-
-// Copy an object from the given appdomain into the current appdomain.
-OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN AppDomain *pDomain,
- IN OBJECTREF *orObject) // Object must be GC protected
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orObject!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(pDomain != GetAppDomain());
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*orObject);
-
- struct _gc {
- U1ARRAYREF orBlob;
- OBJECTREF result;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
- ENTER_DOMAIN_PTR(pDomain, ADV_RUNNINGIN);
- AppDomainHelper::MarshalObject(orObject, &gc.orBlob);
- END_DOMAIN_TRANSITION;
- AppDomainHelper::UnmarshalObject(GetAppDomain(),&gc.orBlob, &gc.result);
- GCPROTECT_END();
-
- VALIDATEOBJECTREF(gc.result);
-
- return gc.result;
-}
-
-// Copy an object to the given appdomain from the current appdomain.
-OBJECTREF AppDomainHelper::CrossContextCopyTo(IN AppDomain *pDomain,
- IN OBJECTREF *orObject) // Object must be GC protected
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orObject!=NULL);
- PRECONDITION(IsProtectedByGCFrame(orObject));
- PRECONDITION(pDomain!=NULL);
- PRECONDITION(pDomain != GetAppDomain());
- }
- CONTRACTL_END;
-
- VALIDATEOBJECTREF(*orObject);
-
- struct _gc {
- U1ARRAYREF orBlob;
- OBJECTREF result;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
- AppDomainHelper::MarshalObject(orObject, &gc.orBlob);
- AppDomainHelper::UnmarshalObject(pDomain, &gc.orBlob, &gc.result);
- GCPROTECT_END();
-
- VALIDATEOBJECTREF(gc.result);
-
- return gc.result;
-}
-
-#endif // FEATURE_REMOTING
-
diff --git a/src/vm/appdomainhelper.h b/src/vm/appdomainhelper.h
deleted file mode 100644
index e331555292..0000000000
--- a/src/vm/appdomainhelper.h
+++ /dev/null
@@ -1,371 +0,0 @@
-// 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.
-
-
-#ifndef _APPDOMAIN_HELPER_H_
-#define _APPDOMAIN_HELPER_H_
-
-#ifndef FEATURE_REMOTING
-#error FEATURE_REMOTING is not set, please do not include appdomainhelper.h
-#endif
-
-// Marshal a single object into a serialized blob.
-//
-//
-
-class AppDomainHelper {
-
- friend class MarshalCache;
-
- // A pair of helper to move serialization info between managed byte-array and
- // unmanaged blob.
- static void AppDomainHelper::CopyEncodingToByteArray(IN PBYTE pbData,
- IN DWORD cbData,
- OUT OBJECTREF* pArray);
-
- static void AppDomainHelper::CopyByteArrayToEncoding(IN U1ARRAYREF* pArray,
- OUT PBYTE* ppbData,
- OUT DWORD* pcbData);
-
-public:
- // Marshal a single object into a serialized blob.
- static void AppDomainHelper::MarshalObject(IN OBJECTREF *orObject,
- OUT U1ARRAYREF *porBlob);
-
- static void AppDomainHelper::MarshalObject(IN ADID pDomain,
- IN OBJECTREF *orObject,
- OUT U1ARRAYREF *porBlob);
- // Marshal one object into a seraialized blob.
- static void AppDomainHelper::MarshalObject(IN AppDomain *pDomain,
- IN OBJECTREF *orObject,
- OUT BYTE **ppbBlob,
- OUT DWORD *pcbBlob);
-
- // Marshal two objects into serialized blobs.
- static void AppDomainHelper::MarshalObjects(IN AppDomain *pDomain,
- IN OBJECTREF *orObject1,
- IN OBJECTREF *orObject2,
- OUT BYTE **ppbBlob1,
- OUT DWORD *pcbBlob1,
- OUT BYTE **ppbBlob2,
- OUT DWORD *pcbBlob2);
-
- // Unmarshal a single object from a serialized blob.
- static void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain,
- IN U1ARRAYREF *porBlob,
- OUT OBJECTREF *porObject);
-
- // Unmarshal a single object from a serialized blob.
- static void AppDomainHelper::UnmarshalObject(IN AppDomain *pDomain,
- IN BYTE *pbBlob,
- IN DWORD cbBlob,
- OUT OBJECTREF *porObject);
-
- // Unmarshal two objects from serialized blobs.
- static void AppDomainHelper::UnmarshalObjects(IN AppDomain *pDomain,
- IN BYTE *pbBlob1,
- IN DWORD cbBlob1,
- IN BYTE *pbBlob2,
- IN DWORD cbBlob2,
- OUT OBJECTREF *porObject1,
- OUT OBJECTREF *porObject2);
-
- // Copy an object from the given appdomain into the current appdomain.
- static OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN AppDomain *pAppDomain,
- IN OBJECTREF *orObject);
- // Copy an object to the given appdomain from the current appdomain.
- static OBJECTREF AppDomainHelper::CrossContextCopyTo(IN AppDomain *pAppDomain,
- IN OBJECTREF *orObject);
- // Copy an object from the given appdomain into the current appdomain.
- static OBJECTREF AppDomainHelper::CrossContextCopyFrom(IN ADID dwDomainId,
- IN OBJECTREF *orObject);
- // Copy an object to the given appdomain from the current appdomain.
- static OBJECTREF AppDomainHelper::CrossContextCopyTo(IN ADID dwDomainId,
- IN OBJECTREF *orObject);
-
-};
-
-// Cache the bits needed to serialize/deserialize managed objects that will be
-// passed across appdomain boundaries during a stackwalk. The serialization is
-// performed lazily the first time it's needed and remains valid throughout the
-// stackwalk. The last deserialized object is cached and tagged with its
-// appdomain context. It's valid as long as we're walking frames within the same
-// appdomain.
-//
-class MarshalCache
-{
-public:
- MarshalCache()
- {
- LIMITED_METHOD_CONTRACT;
- ZeroMemory(this, sizeof(*this));
- }
-
- ~MarshalCache()
- {
- LIMITED_METHOD_CONTRACT;
- if (m_pbObj1)
- delete [] m_pbObj1;
- if (m_pbObj2)
- delete [] m_pbObj2;
- }
-
- void EnsureSerializationOK()
- {
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
- if ((m_sGC.m_orInput1 != NULL && (m_pbObj1 == NULL || m_cbObj1 == 0)) ||
- (m_sGC.m_orInput2 != NULL && (m_pbObj2 == NULL || m_cbObj2 == 0)))
- {
- // Serialization went bad -> Throw exception indicating so.
- COMPlusThrow(kSecurityException, IDS_UNMARSHALABLE_DEMAND_OBJECT);
- }
- }
-
- void EnsureDeserializationOK()
- {
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
- if ((m_pbObj1 != NULL && m_sGC.m_orOutput1 == NULL ) ||
- (m_pbObj2 != NULL && m_sGC.m_orOutput2 == NULL ) )
- {
- // DeSerialization went bad -> Throw exception indicating so.
- COMPlusThrow(kSecurityException, IDS_UNMARSHALABLE_DEMAND_OBJECT);
- }
- }
-
-#ifndef DACCESS_COMPILE
-
- // Set the original value of the first cached object.
- void SetObject(OBJECTREF orObject)
- {
- LIMITED_METHOD_CONTRACT;
- m_pOriginalDomain = ::GetAppDomain();
- m_sGC.m_orInput1 = orObject;
- }
-
- // Set the original values of both cached objects.
- void SetObjects(OBJECTREF orObject1, OBJECTREF orObject2)
- {
- LIMITED_METHOD_CONTRACT;
- m_pOriginalDomain = ::GetAppDomain();
- m_sGC.m_orInput1 = orObject1;
- m_sGC.m_orInput2 = orObject2;
- }
-
-#endif //!DACCESS_COMPILE
-
- // Get a copy of the first object suitable for use in the given appdomain.
- OBJECTREF GetObject(AppDomain *pDomain)
- {
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
- CheckADValidity(pDomain, ADV_RUNNINGIN);
-
- // No transition -- just return original object.
- if (pDomain == m_pOriginalDomain) {
- if (m_fObjectUpdated)
- UpdateObjectFinish();
- return m_sGC.m_orInput1;
- }
-
- // We've already deserialized the object into the correct context.
- if (pDomain == m_pCachedDomain)
- return m_sGC.m_orOutput1;
-
- // If we've updated the object in a different appdomain from the one we
- // originally started in, the cached object will be more up to date than
- // the original. Resync the objects.
- if (m_fObjectUpdated)
- UpdateObjectFinish();
-
- // Check whether we've serialized the original input object yet.
- if (m_pbObj1 == NULL && m_sGC.m_orInput1 != NULL)
- {
- AppDomainHelper::MarshalObject(m_pOriginalDomain,
- &m_sGC.m_orInput1,
- &m_pbObj1,
- &m_cbObj1);
- EnsureSerializationOK();
- }
-
- // Deserialize into the correct context.
- if (m_pbObj1 != NULL)
- {
- AppDomainHelper::UnmarshalObject(pDomain,
- m_pbObj1,
- m_cbObj1,
- &m_sGC.m_orOutput1);
- EnsureDeserializationOK();
- }
- m_pCachedDomain = pDomain;
-
- return m_sGC.m_orOutput1;
- }
-
- // As above, but retrieve both objects.
- OBJECTREF GetObjects(AppDomain *pDomain, OBJECTREF *porObject2)
- {
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
- CheckADValidity(pDomain, ADV_RUNNINGIN);
- // No transition -- just return original objects.
- if (pDomain == m_pOriginalDomain) {
- if (m_fObjectUpdated)
- UpdateObjectFinish();
- *porObject2 = m_sGC.m_orInput2;
- return m_sGC.m_orInput1;
- }
-
- // We've already deserialized the objects into the correct context.
- if (pDomain == m_pCachedDomain) {
- *porObject2 = m_sGC.m_orOutput2;
- return m_sGC.m_orOutput1;
- }
-
- // If we've updated the object in a different appdomain from the one we
- // originally started in, the cached object will be more up to date than
- // the original. Resync the objects.
- if (m_fObjectUpdated)
- UpdateObjectFinish();
-
- // Check whether we've serialized the original input objects yet.
- if ((m_pbObj1 == NULL && m_sGC.m_orInput1 != NULL) ||
- (m_pbObj2 == NULL && m_sGC.m_orInput2 != NULL))
- {
- AppDomainHelper::MarshalObjects(m_pOriginalDomain,
- &m_sGC.m_orInput1,
- &m_sGC.m_orInput2,
- &m_pbObj1,
- &m_cbObj1,
- &m_pbObj2,
- &m_cbObj2);
- EnsureSerializationOK();
-
- }
- if (m_pbObj1 != NULL || m_pbObj2 != NULL)
- {
- // Deserialize into the correct context.
- AppDomainHelper::UnmarshalObjects(pDomain,
- m_pbObj1,
- m_cbObj1,
- m_pbObj2,
- m_cbObj2,
- &m_sGC.m_orOutput1,
- &m_sGC.m_orOutput2);
- EnsureDeserializationOK();
- }
- m_pCachedDomain = pDomain;
-
- *porObject2 = m_sGC.m_orOutput2;
- return m_sGC.m_orOutput1;
- }
-
- // Change the first object (updating the cacheing information
- // appropriately).
- void UpdateObject(AppDomain *pDomain, OBJECTREF orObject)
- {
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // The cached serialized blob is now useless.
- CheckADValidity(pDomain, ADV_RUNNINGIN);
- if (m_pbObj1)
- delete [] m_pbObj1;
- m_pbObj1 = NULL;
- m_cbObj1 = 0;
-
- // The object we have now is valid in it's own appdomain, so place that
- // in the object cache.
- m_pCachedDomain = pDomain;
- m_sGC.m_orOutput1 = orObject;
-
- // If the object is updated in the original context, just use the new
- // value as is. In this case we have the data to re-marshal the updated
- // object as normal, so we can consider the cache fully updated and exit
- // now.
- if (pDomain == m_pOriginalDomain) {
- m_sGC.m_orInput1 = orObject;
- m_fObjectUpdated = false;
- return;
- }
-
- // We want to avoid re-marshaling the updated value as long as possible
- // (it might be updated again before we need its value in a different
- // context). So set a flag to indicate that the object must be
- // re-marshaled when the value is queried in a new context.
- m_fObjectUpdated = true;
- }
-
- // This structure is public only so that it can be GC protected. Do not
- // access the fields directly, they change in an unpredictable fashion due
- // to the lazy cacheing algorithm.
- struct _gc {
- OBJECTREF m_orInput1;
- OBJECTREF m_orInput2;
- OBJECTREF m_orOutput1;
- OBJECTREF m_orOutput2;
- } m_sGC;
-
-private:
-
- // Called after one or more calls to UpdateObject to marshal the updated
- // object back into its original context (it's assumed we're called in this
- // context).
- void UpdateObjectFinish()
- {
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(m_fObjectUpdated && m_pbObj1 == NULL);
- }
- CONTRACTL_END;
- AppDomainHelper::MarshalObject(m_pCachedDomain,
- &m_sGC.m_orOutput1,
- &m_pbObj1,
- &m_cbObj1);
- AppDomainHelper::UnmarshalObject(m_pOriginalDomain,
- m_pbObj1,
- m_cbObj1,
- &m_sGC.m_orInput1);
- m_fObjectUpdated = false;
- }
-
- BYTE *m_pbObj1;
- DWORD m_cbObj1;
- BYTE *m_pbObj2;
- DWORD m_cbObj2;
- AppDomain *m_pCachedDomain;
- AppDomain *m_pOriginalDomain;
- bool m_fObjectUpdated;
-};
-
-#endif
diff --git a/src/vm/appdomainnative.cpp b/src/vm/appdomainnative.cpp
index 47509d731f..dd46add6ee 100644
--- a/src/vm/appdomainnative.cpp
+++ b/src/vm/appdomainnative.cpp
@@ -9,7 +9,6 @@
#include "appdomainnative.hpp"
#ifdef FEATURE_REMOTING
#include "remoting.h"
-#include "appdomainhelper.h"
#endif
#include "security.h"
#include "vars.hpp"
diff --git a/src/vm/assembly.cpp b/src/vm/assembly.cpp
index 3e1745b23d..fc9ce7189c 100644
--- a/src/vm/assembly.cpp
+++ b/src/vm/assembly.cpp
@@ -46,7 +46,6 @@
#include "appdomainnative.hpp"
#ifdef FEATURE_REMOTING
#include "remoting.h"
-#include "appdomainhelper.h"
#endif
#include "customattribute.h"
#include "winnls.h"
diff --git a/src/vm/assemblynamesconfigfactory.cpp b/src/vm/assemblynamesconfigfactory.cpp
deleted file mode 100644
index ed5da9679b..0000000000
--- a/src/vm/assemblynamesconfigfactory.cpp
+++ /dev/null
@@ -1,264 +0,0 @@
-// 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.
-// AssemblyNamesConfigFactory.cpp
-//
-
-//
-//
-// Parses XML files and adding runtime entries to assembly list
-// Abstract, derived classes need to override AddAssemblyName
-#include "common.h"
-#include "common.h"
-#include <xmlparser.h>
-#include <objbase.h>
-#include "parse.h"
-#include "assemblynamesconfigfactory.h"
-
-
-#define ISWHITE(ch) ((ch) >= 0x09 && (ch) <= 0x0D || (ch) == 0x20)
-
-#define CONST_STRING_AND_LEN(str) str, NumItems(str)-1
-
-extern int EEXMLStringCompare(const WCHAR *pStr1,
- DWORD cchStr1,
- const WCHAR *pStr2,
- DWORD cchStr2);
-extern HRESULT VersionFromString(LPCWSTR wzVersion, WORD *pwVerMajor, WORD *pwVerMinor,
- WORD *pwVerBld, WORD *pwVerRev);
-extern HRESULT MapProcessorArchitectureToPEKIND(LPCWSTR pwzProcArch, PEKIND *pe);
-
-AssemblyNamesConfigFactory::AssemblyNamesConfigFactory()
-{
- LIMITED_METHOD_CONTRACT;
- m_pAssemblyName = NULL;
- m_bCurrentEntryInvalid = TRUE;
- m_dwCurrentElementDepth = 0;
- m_dwProperty = ASM_NAME_MAX_PARAMS;
-}
-
-AssemblyNamesConfigFactory::~AssemblyNamesConfigFactory()
-{
- LIMITED_METHOD_CONTRACT;
-}
-
-
-HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::NotifyEvent(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt)
-{
- LIMITED_METHOD_CONTRACT;
-
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::BeginChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo)
-{
- LIMITED_METHOD_CONTRACT;
- m_dwCurrentElementDepth ++;
-
- return S_OK;
-}
-
-//---------------------------------------------------------------------------
-HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::EndChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmptyNode,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- HRESULT hr = S_OK;
- EX_TRY
- {
- if (m_dwCurrentElementDepth == 1 && m_pAssemblyName != NULL)
- {
- if (!m_bCurrentEntryInvalid)
- {
- // publish
- AddAssemblyName(m_pAssemblyName);
- };
- m_pAssemblyName->Release();
- m_pAssemblyName = NULL;
- }
-
- if (!fEmptyNode)
- m_dwCurrentElementDepth --;
- }
- EX_CATCH_HRESULT(hr);
- return hr;
-}
-
-
-
-HRESULT STDMETHODCALLTYPE AssemblyNamesConfigFactory::CreateNode(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- if(m_dwCurrentElementDepth > 1)
- return S_OK;
-
- HRESULT hr = S_OK;
-
- for(DWORD i = 0; i < cNumRecs; i++) {
- CONTRACT_VIOLATION(ThrowsViolation); // Lots of stuff in here throws!
-
- if(apNodeInfo[i]->dwType == XML_ELEMENT ||
- apNodeInfo[i]->dwType == XML_ATTRIBUTE ||
- apNodeInfo[i]->dwType == XML_PCDATA)
- {
-
- DWORD dwStringSize = apNodeInfo[i]->ulLen;
- LPWSTR pszString = (WCHAR*) apNodeInfo[i]->pwcText;
- // Trim the value
-
- // we should never decrement lgth if it's 0, because it's unsigned
-
- for(;*pszString && ISWHITE(*pszString) && dwStringSize>0; pszString++, dwStringSize--);
- while( dwStringSize > 0 && ISWHITE(pszString[dwStringSize-1]))
- dwStringSize--;
- switch(apNodeInfo[i]->dwType)
- {
- case XML_ELEMENT :
- if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("assemblyIdentity"))) == 0)
- {
- // new entry
- _ASSERTE(m_pAssemblyName == NULL);
- IfFailRet(CreateAssemblyNameObject(&m_pAssemblyName, NULL,0,NULL));
- m_bCurrentEntryInvalid = FALSE;
- }
- else
- {
- m_bCurrentEntryInvalid = TRUE;
- }
-
- break;
-
-
- case XML_ATTRIBUTE :
- if(m_bCurrentEntryInvalid)
- break;
-
- if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("name"))) == 0)
- {
- m_dwProperty = ASM_NAME_NAME;
- }
- else
- if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("version"))) == 0)
- {
- m_dwProperty = ASM_NAME_MAJOR_VERSION;
- }
- else
- if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("publicKeyToken"))) == 0)
- {
- m_dwProperty = ASM_NAME_PUBLIC_KEY_TOKEN;
- }
- else
- if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("processorArchitecture"))) == 0)
- {
- m_dwProperty = ASM_NAME_ARCHITECTURE;
- }
- else
- {
- m_bCurrentEntryInvalid = TRUE;
- }
- break;
-
-
- case XML_PCDATA :
- if(m_bCurrentEntryInvalid)
- break;
-
- _ASSERTE(m_pAssemblyName!= NULL); // can only be null if m_bCurrentEntryInvalid
- switch(m_dwProperty)
- {
- case ASM_NAME_NAME:
- {
- StackSString s(pszString,dwStringSize);
- // takes number of bytes, thus *2
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_NAME, LPCWSTR(s), (dwStringSize+1)*sizeof(WCHAR)));
- }
- break;
- case ASM_NAME_MAJOR_VERSION:
- {
- StackSString s(pszString,dwStringSize);
- WORD wVerMajor = 0;
- WORD wVerMinor = 0;
- WORD wVerBld = 0;
- WORD wVerRev = 0;
- if (SUCCEEDED(VersionFromString(s, &wVerMajor, &wVerMinor, &wVerBld, &wVerRev)))
- {
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_MAJOR_VERSION, &wVerMajor, sizeof(WORD)));
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_MINOR_VERSION, &wVerMinor, sizeof(WORD)));
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_BUILD_NUMBER, &wVerBld, sizeof(WORD)));
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_REVISION_NUMBER, &wVerRev, sizeof(WORD)));
- }
- else
- m_bCurrentEntryInvalid = TRUE;
-
- }
- break;
- case ASM_NAME_ARCHITECTURE:
- {
- StackSString s(pszString,dwStringSize);
- PEKIND PeKind = peNone;
- if(SUCCEEDED(MapProcessorArchitectureToPEKIND(s, &PeKind)))
- {
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_ARCHITECTURE, (LPBYTE) &PeKind, sizeof(PeKind)));
- }
- else
- {
- m_bCurrentEntryInvalid = TRUE;
- }
-
- }
- break;
- case ASM_NAME_PUBLIC_KEY_TOKEN:
- {
- if(EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("null"))) == 0)
- {
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0));
- }
- else
- {
- if (dwStringSize % 2 != 0)
- return FUSION_E_INVALID_NAME;
-
- DWORD cbProp = dwStringSize / 2;
- NewHolder<BYTE> pbProp = new BYTE[cbProp];
- CParseUtils::UnicodeHexToBin(pszString, dwStringSize, pbProp); //????
- IfFailRet(m_pAssemblyName->SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, pbProp, cbProp));
- }
- break;
- }
-
- default:
- _ASSERTE(!"Invalid format");
- m_bCurrentEntryInvalid = TRUE;
- break;
- }
- break;
- }
-
- }
- }
- return S_OK;
-}
diff --git a/src/vm/assemblynamesconfigfactory.h b/src/vm/assemblynamesconfigfactory.h
deleted file mode 100644
index 234adb9208..0000000000
--- a/src/vm/assemblynamesconfigfactory.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.
-// AssemblyNamesConfigFactory.h
-//
-
-//
-//
-// Parses XML files and adding runtime entries to assembly list
-// Abstract, derived classes need to override AddAssemblyName
-
-
-#ifndef ASSEMBLYNAMESCONFIGFACTORY_H
-#define ASSEMBLYNAMESCONFIGFACTORY_H
-
-#include "unknwn.h"
-#include "../xmlparser/_reference.h"
-#include "../xmlparser/_unknown.h"
-
-
-class AssemblyNamesConfigFactory : public _unknown<IXMLNodeFactory, &IID_IXMLNodeFactory>
-{
-
-public:
- AssemblyNamesConfigFactory ();
- ~AssemblyNamesConfigFactory ();
- HRESULT STDMETHODCALLTYPE NotifyEvent(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt);
-
- HRESULT STDMETHODCALLTYPE BeginChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo);
-
- HRESULT STDMETHODCALLTYPE EndChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmptyNode,
- /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo);
-
- HRESULT STDMETHODCALLTYPE Error(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ HRESULT hrErrorCode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo)
- {
- LIMITED_METHOD_CONTRACT;
- /*
- UNUSED(pSource);
- UNUSED(hrErrorCode);
- UNUSED(cNumRecs);
- UNUSED(apNodeInfo);
- */
- return hrErrorCode;
- }
-
- HRESULT STDMETHODCALLTYPE CreateNode(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNodeParent,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo);
-
- virtual void AddAssemblyName(IAssemblyName*) = 0;
-protected:
- IAssemblyName* m_pAssemblyName;
- BOOL m_bCurrentEntryInvalid;
- DWORD m_dwCurrentElementDepth;
- DWORD m_dwProperty;
-
-};
-
-
-#endif
diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp
index 7175b156f0..8daa851c74 100644
--- a/src/vm/assemblynative.cpp
+++ b/src/vm/assemblynative.cpp
@@ -29,7 +29,6 @@
#include "frames.h"
#include "typeparse.h"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#endif
#include "stackprobe.h"
diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp
index 4a03927ee4..f6317f03aa 100644
--- a/src/vm/ceeload.cpp
+++ b/src/vm/ceeload.cpp
@@ -15368,9 +15368,6 @@ void Module::VerifyAllMethods()
};
//Verify all methods in a module eagerly, forcing them to get loaded.
- /* XXX Thu 4/26/2007
- * This code is lifted mostly from Validator.cpp
- */
IMDInternalImport * pMDI = GetMDImport();
HENUMTypeDefInternalHolder hEnum(pMDI);
mdTypeDef td;
diff --git a/src/vm/clrprivbinderfusion.cpp b/src/vm/clrprivbinderfusion.cpp
deleted file mode 100644
index d31774f7b2..0000000000
--- a/src/vm/clrprivbinderfusion.cpp
+++ /dev/null
@@ -1,819 +0,0 @@
-// 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.
-
-
-
-#include "common.h" // precompiled header
-
-#ifndef DACCESS_COMPILE
-
-//=====================================================================================================================
-#include "assemblyspec.hpp"
-#include "corhdr.h"
-#include "domainfile.h"
-#include "fusion.h"
-#include "policy.h"
-#include "sstring.h"
-#include "stackingallocator.h"
-#include "threads.h"
-#include "clrprivbinderfusion.h"
-#include "clrprivbinderutil.h"
-#include "fusionlogging.h"
-
-using namespace CLRPrivBinderUtil;
-
-//=================================================================================================
-#define STDMETHOD_NOTIMPL(...) \
- STDMETHOD(__VA_ARGS__) \
- { \
- WRAPPER_NO_CONTRACT; \
- _ASSERTE_MSG(false, "Method not implemented."); \
- return E_NOTIMPL; \
- }
-
-//=================================================================================================
-static HRESULT PropagateOutStringArgument(
- __in LPCSTR pszValue,
- __out_ecount_opt(*pcchArg) LPWSTR pwzArg,
- __in DWORD cchArg,
- __out DWORD * pcchArg)
-{
- LIMITED_METHOD_CONTRACT;
-
- VALIDATE_PTR_RET(pszValue);
- VALIDATE_CONDITION((pwzArg == nullptr || cchArg > 0), return E_INVALIDARG);
-
- HRESULT hr = S_OK;
-
- if (pwzArg != nullptr)
- {
- DWORD cchWritten = WszMultiByteToWideChar(
- CP_UTF8, 0 /*flags*/, pszValue, -1, pwzArg, cchArg);
-
- if (cchWritten == 0)
- {
- hr = HRESULT_FROM_GetLastError();
- }
- else if (pcchArg != nullptr)
- {
- *pcchArg = cchWritten;
- }
- }
-
- if (pcchArg != nullptr && (pwzArg == nullptr || hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)))
- {
- *pcchArg = WszMultiByteToWideChar(
- CP_UTF8, 0 /*flags*/, pszValue, -1, nullptr, 0);
-
- if (*pcchArg == 0)
- {
- hr = HRESULT_FROM_GetLastError();
- }
- }
-
- return hr;
-}
-
-//=================================================================================================
-// This is needed to allow calls to IsAnyFrameworkAssembly in GC_NOTRIGGER/NO_FAULT regions (i.e.,
-// GC stack walking). CAssemblyName (which implements IAssemblyName in most other uses) allocates
-// during construction and so cannot be used in this scenario.
-
-class AssemblySpecAsIAssemblyName
- : public IAssemblyName
-{
-public:
- AssemblySpecAsIAssemblyName(
- AssemblySpec * pSpec)
- : m_pSpec(pSpec)
- { LIMITED_METHOD_CONTRACT; }
-
- //=============================================================================================
- // IUnknown methods
-
- // Not used by IsAnyFrameworkAssembly
- STDMETHOD_(ULONG, AddRef())
- {
- WRAPPER_NO_CONTRACT;
- _ASSERTE_MSG(false, "Method not implemented.");
- return E_NOTIMPL;
- }
-
- // Not used by IsAnyFrameworkAssembly
- STDMETHOD_(ULONG, Release())
- {
- WRAPPER_NO_CONTRACT;
- _ASSERTE_MSG(false, "Method not implemented.");
- return E_NOTIMPL;
- }
-
- // Not used by IsAnyFrameworkAssembly
- STDMETHOD_NOTIMPL(QueryInterface(
- REFIID riid,
- void **ppvObject));
-
- //=============================================================================================
- // IAssemblyName methods
-
- STDMETHOD_NOTIMPL(SetProperty(
- DWORD PropertyId,
- void const * pvProperty,
- DWORD cbProperty));
-
-#define ASSURE_SUFFICIENT_BUFFER(SRCSIZE) \
- do { \
- if ((pvProperty == nullptr) || (*pcbProperty < SRCSIZE)) { \
- *pcbProperty = SRCSIZE; \
- return HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER); \
- } \
- } while (false)
-
- STDMETHOD(GetProperty)(
- DWORD PropertyId,
- LPVOID pvProperty,
- LPDWORD pcbProperty)
- {
- LIMITED_METHOD_CONTRACT;
-
- VALIDATE_PTR_RET(pcbProperty);
- VALIDATE_CONDITION((pvProperty == nullptr) == (*pcbProperty == 0), return E_INVALIDARG);
-
- HRESULT hr = S_OK;
-
- switch (PropertyId)
- {
- case ASM_NAME_NAME:
- return PropagateOutStringArgument(m_pSpec->GetName(), (LPWSTR) pvProperty,
- *pcbProperty / sizeof(WCHAR), pcbProperty);
-
- case ASM_NAME_MAJOR_VERSION:
- ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT));
- *reinterpret_cast<USHORT*>(pvProperty) = m_pSpec->GetContext()->usMajorVersion;
- *pcbProperty = sizeof(USHORT);
- return S_OK;
-
- case ASM_NAME_MINOR_VERSION:
- ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT));
- *reinterpret_cast<USHORT*>(pvProperty) = m_pSpec->GetContext()->usMinorVersion;
- *pcbProperty = sizeof(USHORT);
- return S_OK;
-
- case ASM_NAME_BUILD_NUMBER:
- ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT));
- *reinterpret_cast<USHORT*>(pvProperty) = m_pSpec->GetContext()->usBuildNumber;
- *pcbProperty = sizeof(USHORT);
- return S_OK;
-
- case ASM_NAME_REVISION_NUMBER:
- ASSURE_SUFFICIENT_BUFFER(sizeof(USHORT));
- *reinterpret_cast<USHORT*>(pvProperty) = m_pSpec->GetContext()->usRevisionNumber;
- *pcbProperty = sizeof(USHORT);
- return S_OK;
-
- case ASM_NAME_CULTURE:
- if (m_pSpec->GetContext()->szLocale == nullptr)
- {
- return FUSION_E_INVALID_NAME;
- }
- return PropagateOutStringArgument(m_pSpec->GetContext()->szLocale, (LPWSTR) pvProperty,
- *pcbProperty / sizeof(WCHAR), pcbProperty);
-
- case ASM_NAME_PUBLIC_KEY_TOKEN:
- {
- if (!m_pSpec->HasPublicKeyToken())
- {
- return FUSION_E_INVALID_NAME;
- }
-
- PBYTE pbSN;
- DWORD cbSN;
- m_pSpec->GetPublicKeyToken(&pbSN, &cbSN);
- ASSURE_SUFFICIENT_BUFFER(cbSN);
- memcpy_s(pvProperty, *pcbProperty, pbSN, cbSN);
- *pcbProperty = cbSN;
- }
- return S_OK;
-
- case ASM_NAME_RETARGET:
- ASSURE_SUFFICIENT_BUFFER(sizeof(BOOL));
- *reinterpret_cast<BOOL*>(pvProperty) = m_pSpec->IsRetargetable();
- *pcbProperty = sizeof(BOOL);
- return S_OK;
-
- default:
- _ASSERTE_MSG(false, "Unexpected property requested.");
- return E_INVALIDARG;
- }
- }
-
-#undef ASSURE_SUFFICIENT_BUFFER
-
- // Not used by IsAnyFrameworkAssembly
- STDMETHOD_NOTIMPL(Finalize());
-
- // Not used by IsAnyFrameworkAssembly
- STDMETHOD_NOTIMPL(GetDisplayName(
- __out_ecount_opt(*pccDisplayName) LPOLESTR szDisplayName,
- __inout LPDWORD pccDisplayName,
- DWORD dwDisplayFlags));
-
- // Not used by IsAnyFrameworkAssembly
- STDMETHOD_NOTIMPL(Reserved(
- REFIID refIID,
- IUnknown *pUnkReserved1,
- IUnknown *pUnkReserved2,
- LPCOLESTR szReserved,
- LONGLONG llReserved,
- LPVOID pvReserved,
- DWORD cbReserved,
- LPVOID *ppReserved));
-
-
- STDMETHOD(GetName)(
- __inout LPDWORD lpcwBuffer,
- __out_ecount_opt(*lpcwBuffer) WCHAR *pwzName)
- {
- LIMITED_METHOD_CONTRACT;
-
- VALIDATE_PTR_RET(lpcwBuffer);
- return PropagateOutStringArgument(
- m_pSpec->GetName(), pwzName, *lpcwBuffer, lpcwBuffer);
- }
-
- STDMETHOD(GetVersion)(
- LPDWORD pdwVersionHi,
- LPDWORD pdwVersionLow)
- {
- LIMITED_METHOD_CONTRACT;
-
- HRESULT hr = S_OK;
-
- VALIDATE_PTR_RET(pdwVersionHi);
- VALIDATE_PTR_RET(pdwVersionLow);
-
- AssemblyMetaDataInternal * pAMDI = m_pSpec->GetContext();
-
- *pdwVersionHi = MAKELONG(pAMDI->usMinorVersion, pAMDI->usMajorVersion);
- *pdwVersionLow = MAKELONG(pAMDI->usRevisionNumber, pAMDI->usBuildNumber);
-
- return S_OK;
- }
-
-
- // Exists exclusively to support fusion's IsSystem helper, which compares against 'mscorlib'.
- STDMETHOD(IsEqual)(
- IAssemblyName *pName,
- DWORD dwCmpFlags)
- {
- LIMITED_METHOD_CONTRACT;
-
- HRESULT hr = S_OK;
-
- VALIDATE_PTR_RET(pName);
-
- // This function is here just to support checks against the name 'mscorlib'.
- if ((dwCmpFlags & ASM_CMPF_NAME) != ASM_CMPF_NAME)
- {
- return E_NOTIMPL;
- }
-
- DWORD cchName1 = 0;
- WCHAR wzName1[_MAX_PATH];
- IfFailRet(pName->GetName(&cchName1, wzName1));
- _ASSERTE(SString::_wcsicmp(wzName1, W("mscorlib")) == 0);
-
- WCHAR wzName2[_MAX_PATH];
- DWORD cchName2 = WszMultiByteToWideChar(
- CP_UTF8, 0 /*flags*/, m_pSpec->GetName(), -1, wzName2, (int) (sizeof(wzName2) / sizeof(wzName2[0])));
-
- if (0 == cchName2)
- {
- _ASSERTE(HRESULT_FROM_GetLastError() != HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER));
- return HRESULT_FROM_GetLastError();
- }
-
- if (cchName1 != cchName2)
- {
- return S_FALSE;
- }
-
- return SString::_wcsnicmp(wzName1, wzName2, cchName1) == 0
- ? S_OK
- : S_FALSE;
- }
-
- STDMETHOD_NOTIMPL(Clone(
- IAssemblyName **pName));
-
-private:
- AssemblySpec * m_pSpec;
-};
-
-//=====================================================================================================================
-HRESULT CLRPrivBinderFusion::FindFusionAssemblyBySpec(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- BindingScope kBindingScope,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly)
-{
- LIMITED_METHOD_CONTRACT;;
- HRESULT hr = S_OK;
-
- AppDomain* pAppDomain = reinterpret_cast<AppDomain*>(pvAppDomain);
- AssemblySpec* pAssemblySpec = reinterpret_cast<AssemblySpec*>(pvAssemblySpec);
- VALIDATE_PTR_RET(pAppDomain);
- VALIDATE_PTR_RET(pAssemblySpec);
- VALIDATE_PTR_RET(pResult);
- VALIDATE_PTR_RET(ppAssembly);
-
- if (pAssemblySpec->IsContentType_WindowsRuntime())
- {
- return CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT;
- }
-
- BOOL fIsSupportedInAppX;
- {
- AssemblySpecAsIAssemblyName asName(pAssemblySpec);
-
- if (Fusion::Util::IsAnyFrameworkAssembly(&asName, &fIsSupportedInAppX) != S_OK)
- { // Not a framework assembly identity.
- IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
- }
- }
-
- if (kBindingScope == kBindingScope_FrameworkSubset)
- { // We should allow only some framework assemblies to load
-
- // DevMode has to allow all FX assemblies, not just a subset - see code:PreBind for more info
- {
- // Disabling for now, as it causes too many violations.
- //CONTRACT_VIOLATION(GCViolation | FaultViolation | ModeViolation);
- //_ASSERTE(!AppX::IsAppXDesignMode());
- }
-
- if (!fIsSupportedInAppX)
- { // Assembly is blocked for AppX, fail the load
- *pResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- *ppAssembly = nullptr;
- return S_OK;
- }
- }
-
- return FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly);
-}
-
-//=====================================================================================================================
-static
-PEAssembly * FindCachedFile(AppDomain * pDomain, AssemblySpec * pSpec)
-{
- // Look for cached bind result. Prefer a cached DomainAssembly, as it takes priority over a
- // cached PEAssembly (which can be different from the one associated with the DomainAssembly).
- DomainAssembly * pDomainAssembly = pDomain->FindCachedAssembly(pSpec, FALSE);
- return (pDomainAssembly != nullptr)
- ? (pDomainAssembly->GetFile())
- : (pDomain->FindCachedFile(pSpec, FALSE));
-}
-
-//=====================================================================================================================
-// There is no need to create a separate binding record, since we can always just look in the AppDomain's
-// AssemblySpecBindingCache for an answer (which is precisely what this function does).
-
-HRESULT CLRPrivBinderFusion::FindAssemblyBySpec(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly)
-{
- LIMITED_METHOD_CONTRACT;;
- HRESULT hr = S_OK;
-
- AppDomain* pAppDomain = reinterpret_cast<AppDomain*>(pvAppDomain);
- AssemblySpec* pAssemblySpec = reinterpret_cast<AssemblySpec*>(pvAssemblySpec);
- VALIDATE_PTR_RET(pAppDomain);
- VALIDATE_PTR_RET(pAssemblySpec);
- VALIDATE_PTR_RET(pResult);
- VALIDATE_PTR_RET(ppAssembly);
-
- // For the Architecture property, canonicalize peMSIL to peNone (which are considered equivalent),
- // to ensure consistent lookups in the AssemblySpecBindingCache for the CLRPrivBinderFusion binder.
- if (pAssemblySpec->GetPEKIND() == peMSIL)
- {
- pAssemblySpec->SetPEKIND(peNone);
- }
-
- PEAssembly * pPEAssembly = FindCachedFile(pAppDomain, pAssemblySpec);
- if (pPEAssembly == nullptr)
- {
- return E_FAIL;
- }
-
- // Could be racing with another thread that has just added the PEAssembly to the binding cache
- // but not yet allocated and assigned a host assembly.
- if (!pPEAssembly->HasHostAssembly())
- {
- return E_FAIL;
- }
-
- *pResult = S_OK;
- *ppAssembly = clr::SafeAddRef(pPEAssembly->GetHostAssembly());
-
- return S_OK;
-}
-
-//=====================================================================================================================
-HRESULT CLRPrivBinderFusion::BindAssemblyByNameWorker(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly)
-{
- STANDARD_VM_CONTRACT;
- PRECONDITION(CheckPointer(pAssemblyName));
- PRECONDITION(CheckPointer(ppAssembly));
-
- HRESULT hr = S_OK;
-
- AppDomain * pCurDomain = AppDomain::GetCurrentDomain();
- if (pCurDomain == nullptr)
- ThrowHR(E_UNEXPECTED);
-
- AssemblySpec prePolicySpec;
- AssemblySpec postPolicySpec;
-
- prePolicySpec.InitializeSpec(pAssemblyName);
-
- // For the Architecture property, canonicalize peMSIL to peNone (which are considered equivalent),
- // to ensure consistent lookups in the AssemblySpecBindingCache for the CLRPrivBinderFusion binder.
- if (prePolicySpec.GetPEKIND() == peMSIL)
- {
- prePolicySpec.SetPEKIND(peNone);
- }
-
- AssemblySpec * pBindSpec = &prePolicySpec;
- PEAssemblyHolder pPEAssembly = clr::SafeAddRef(FindCachedFile(pCurDomain, pBindSpec));
-
- if (pPEAssembly == nullptr)
- {
- // Early on in domain setup there may not be a fusion context, so skip ApplyPolicy then.
- _ASSERTE(pCurDomain->GetFusionContext() != nullptr || prePolicySpec.IsMscorlib());
- if (pCurDomain->GetFusionContext() != nullptr)
- {
- ReleaseHolder<IAssemblyName> pPolicyAssemblyName;
- DWORD dwPolicyApplied = 0;
- ApplyPolicy(pAssemblyName, pCurDomain->GetFusionContext(), nullptr, &pPolicyAssemblyName, nullptr, nullptr, &dwPolicyApplied);
-
- if (dwPolicyApplied != 0)
- {
- postPolicySpec.InitializeSpec(pPolicyAssemblyName);
- pBindSpec = &postPolicySpec;
- pPEAssembly = clr::SafeAddRef(FindCachedFile(pCurDomain, pBindSpec));
- }
- }
-
- if (pPEAssembly == nullptr)
- {
- // Trigger a load.
- pPEAssembly = pCurDomain->BindAssemblySpec(
- pBindSpec, // AssemblySpec
- TRUE, // ThrowOnFileNotFound
- FALSE, // RaisePrebindEvents
- nullptr, // CallerStackMark
- nullptr, // AssemblyLoadSecurity
- FALSE); // fUseHostBinderIfAvailable - to avoid infinite recursion
- _ASSERTE(FindCachedFile(pCurDomain, pBindSpec) == pPEAssembly || pBindSpec->IsMscorlib());
- }
-
- // If a post-policy spec was used, add the pre-policy spec to the binding cache
- // so that it can be found by FindAssemblyBySpec.
- if (&prePolicySpec != pBindSpec)
- {
- // Failure to add simply means someone else beat us to it. In that case
- // the FindCachedFile call below (after catch block) will update result
- // to the cached value.
- INDEBUG(BOOL fRes =) pCurDomain->AddFileToCache(&prePolicySpec, pPEAssembly, TRUE /* fAllowFailure */);
- _ASSERTE(!fRes || prePolicySpec.IsMscorlib() || FindCachedFile(pCurDomain, &prePolicySpec) == pPEAssembly);
- }
-
- // Ensure that the assembly is discoverable through a consistent assembly name (the assembly def name of the assembly)
- AssemblySpec specAssemblyDef;
- specAssemblyDef.InitializeSpec(pPEAssembly);
-
- // It is expected that all assemlbies found here will be unified assemblies, and therefore have a public key.
- _ASSERTE(specAssemblyDef.IsStrongNamed());
-
- // Convert public key into the format that matches the garaunteed cache in the AssemblySpecBindingCache ... see the extended logic
- // in Module::GetAssemblyIfLoaded.
- if (specAssemblyDef.IsStrongNamed() && specAssemblyDef.HasPublicKey())
- {
- specAssemblyDef.ConvertPublicKeyToToken();
- }
- pCurDomain->AddFileToCache(&specAssemblyDef, pPEAssembly, TRUE);
- }
-
- if (!pPEAssembly->HasHostAssembly())
- {
- // This can happen if we just loaded the PEAssembly with BindAssemblySpec above, or if the PEAssembly
- // Was not loaded through this binder. (NGEN Case)
-
- // Note: There can be multiple PEAssembly objects for the same file, however we have to create unique
- // CLRPrivAssemblyFusion object, otherwise code:AppDomain::FindAssembly will not recognize the duplicates which
- // will lead to creation of multiple code:DomainAssembly objects for the same file in the same AppDomain.
-
- InlineSString<128> ssPEAssemblyName;
- FusionBind::GetAssemblyNameDisplayName(pPEAssembly->GetFusionAssemblyName(), ssPEAssemblyName, ASM_DISPLAYF_FULL);
- NewHolder<CLRPrivAssemblyFusion> pAssemblyObj = new CLRPrivAssemblyFusion(ssPEAssemblyName.GetUnicode(), this);
-
- {
- CrstHolder lock(&m_SetHostAssemblyLock);
- if (!pPEAssembly->HasHostAssembly())
- {
- // Add the host assembly to the PEAssembly.
- pPEAssembly->SetHostAssembly(pAssemblyObj.Extract());
- }
- }
- }
-
- // Trigger a load so that a DomainAssembly is associated with the ICLRPrivAssembly created above.
- pPEAssembly = clr::SafeAddRef(pCurDomain->LoadDomainAssembly(pBindSpec, pPEAssembly, FILE_LOADED)->GetFile());
-
- _ASSERTE(pPEAssembly != nullptr);
- _ASSERTE(pPEAssembly->HasHostAssembly());
- _ASSERTE(pCurDomain->FindAssembly(pPEAssembly->GetHostAssembly()) != nullptr);
-
- fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FOUND, pPEAssembly->GetPath().GetUnicode());
-
- *ppAssembly = clr::SafeAddRef(pPEAssembly->GetHostAssembly());
-
- return hr;
-}
-
-//=====================================================================================================================
-void CLRPrivBinderFusion::BindMscorlib(
- PEAssembly * pPEAssembly)
-{
- STANDARD_VM_CONTRACT;
-
-#ifdef _DEBUG
- NewArrayHolder<WCHAR> dbg_wszAssemblySimpleName;
- _ASSERTE(SUCCEEDED(fusion::util::GetProperty(pPEAssembly->GetFusionAssemblyName(), ASM_NAME_NAME, &dbg_wszAssemblySimpleName)));
-
- _ASSERTE(wcscmp(dbg_wszAssemblySimpleName, W("mscorlib")) == 0);
-#endif //_DEBUG
-
- NewHolder<CLRPrivAssemblyFusion> pPrivAssembly = new CLRPrivAssemblyFusion(W("mscorlib"), this);
-
- pPEAssembly->SetHostAssembly(pPrivAssembly.Extract());
-}
-
-//=====================================================================================================================
-HRESULT CLRPrivBinderFusion::BindFusionAssemblyByName(
- IAssemblyName * pAssemblyName,
- BindingScope kBindingScope,
- ICLRPrivAssembly ** ppAssembly)
-{
- STANDARD_VM_CONTRACT;
- HRESULT hr = S_OK;
-
- fusion::logging::StatusScope logStatus(0, ID_FUSLOG_BINDING_STATUS_FRAMEWORK, &hr);
-
- DWORD dwContentType = AssemblyContentType_Default;
- IfFailRet(fusion::util::GetProperty(pAssemblyName, ASM_NAME_CONTENT_TYPE, &dwContentType));
- if ((hr == S_OK) && (dwContentType != AssemblyContentType_Default))
- { // Not a NetFX content type.
- IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
- }
-
- BOOL fIsSupportedInAppX;
- if (Fusion::Util::IsAnyFrameworkAssembly(pAssemblyName, &fIsSupportedInAppX) != S_OK)
- { // Not a framework assembly identity.
- IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
- }
- if (kBindingScope == kBindingScope_FrameworkSubset)
- { // We should allow only some framework assemblies to load
-
- // DevMode has to allow all FX assemblies, not just a subset - see code:PreBind for more info
- _ASSERTE(!AppX::IsAppXDesignMode());
-
- if (!fIsSupportedInAppX)
- { // Assembly is blocked for AppX, fail the load
- fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FX_ASSEMBLY_BLOCKED);
-
- IfFailRet(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
- }
- }
-
- return (hr = BindAssemblyByNameWorker(pAssemblyName, ppAssembly));
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivBinder::BindAssemblyByName
-HRESULT CLRPrivBinderFusion::BindAssemblyByName(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly)
-{
- WRAPPER_NO_CONTRACT;
- return BindAssemblyByNameWorker(
- pAssemblyName,
- ppAssembly);
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivBinder::GetBinderID
-HRESULT CLRPrivBinderFusion::GetBinderID(
- UINT_PTR *pBinderId)
-{
- LIMITED_METHOD_CONTRACT;
-
- *pBinderId = (UINT_PTR)this;
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements code:IBindContext::PreBind
-HRESULT CLRPrivBinderFusion::PreBind(
- IAssemblyName * pIAssemblyName,
- DWORD dwPreBindFlags,
- IBindResult ** ppIBindResult)
-{
- STANDARD_BIND_CONTRACT;
- PRECONDITION(CheckPointer(pIAssemblyName));
- PRECONDITION(CheckPointer(ppIBindResult));
-
- HRESULT hr = S_OK;
-
- BOOL fIsSupportedInAppX;
- if (Fusion::Util::IsAnyFrameworkAssembly(pIAssemblyName, &fIsSupportedInAppX) != S_OK)
- { // Not a framework assembly identity.
- return HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
-
- EX_TRY
- {
- // Create new IL binding scope.
- fusion::logging::BindingScope defaultScope(pIAssemblyName, FUSION_BIND_LOG_CATEGORY_DEFAULT);
-
- // Ideally the caller would give us arg kBindingContext like in code:BindFusionAssemblyByName, so we can give the same answer.
- // That is not easy, so we will make the decision here:
- // - DevMode will allow all FX assemblies (that covers designer binding context scenario for designers that need to
- // load WPF with ngen images for perf reasons).
- // We know that the real bind via code:BindFusionAssemblyByName will succeed for the assemblies (because we are in DevMode).
- // - Normal mode (non-DevMode) we will allow only subset of FX assemblies.
- // It implies that designer binding context (used by debuggers) will not use ngen images for blocked FX assemblies
- // (transitively). That is acceptable performance trade-off.
- if (!AppX::IsAppXDesignMode())
- { // We should allow only some framework assemblies to load
- if (!fIsSupportedInAppX)
- { // Assembly is blocked for AppX, fail the load
- fusion::logging::LogMessage(0, ID_FUSLOG_BINDING_STATUS_FX_ASSEMBLY_BLOCKED);
-
- hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
- }
- }
-
- if (SUCCEEDED(hr))
- {
- AppDomain * pDomain = AppDomain::GetCurrentDomain();
- ReleaseHolder<IBindContext> pIBindContext;
- if (SUCCEEDED(hr = GetBindContextFromApplicationContext(pDomain->CreateFusionContext(), &pIBindContext)))
- {
- hr = pIBindContext->PreBind(pIAssemblyName, dwPreBindFlags, ppIBindResult);
- }
- }
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
-//=====================================================================================================================
-HRESULT CLRPrivBinderFusion::PreBindFusionAssemblyByName(
- IAssemblyName *pIAssemblyName,
- DWORD dwPreBindFlags,
- IBindResult **ppIBindResult)
-{
- STANDARD_VM_CONTRACT;
- HRESULT hr = S_OK;
-
- DWORD dwContentType = AssemblyContentType_Default;
- IfFailRet(fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CONTENT_TYPE, &dwContentType));
- if ((hr == S_OK) && (dwContentType != AssemblyContentType_Default))
- { // Not a NetFX content type.
- IfFailRet(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT);
- }
-
- IfFailRet(PreBind(pIAssemblyName, dwPreBindFlags, ppIBindResult));
- _ASSERTE(*ppIBindResult != nullptr);
-
- if (*ppIBindResult == nullptr)
- IfFailRet(E_UNEXPECTED);
-
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements code:IBindContext::IsDefaultContext
-HRESULT CLRPrivBinderFusion::IsDefaultContext()
-{
- STANDARD_BIND_CONTRACT;
- return S_OK;
-}
-
-//=====================================================================================================================
-CLRPrivBinderFusion::~CLRPrivBinderFusion()
-{
- WRAPPER_NO_CONTRACT;
-}
-
-//=====================================================================================================================
-CLRPrivAssemblyFusion::CLRPrivAssemblyFusion(
- LPCWSTR wszName,
- CLRPrivBinderFusion * pBinder)
- : m_pBinder(clr::SafeAddRef(pBinder)),
- m_wszName(DuplicateStringThrowing(wszName))
-{
- STANDARD_VM_CONTRACT;
-}
-
-//=====================================================================================================================
-LPCWSTR CLRPrivAssemblyFusion::GetName() const
-{
- LIMITED_METHOD_CONTRACT;
-
- return m_wszName;
-}
-
-//=====================================================================================================================
-// Implements code:IUnknown::Release
-ULONG CLRPrivAssemblyFusion::Release()
-{
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_CAN_TAKE_LOCK;
- _ASSERTE(m_cRef > 0);
-
- ULONG cRef = InterlockedDecrement(&m_cRef);
-
- if (cRef == 0)
- {
- delete this;
- }
-
- return cRef;
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivBinder::BindAssemblyByName
-HRESULT CLRPrivAssemblyFusion::BindAssemblyByName(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly)
-{
- WRAPPER_NO_CONTRACT;
- return m_pBinder->BindAssemblyByName(
- pAssemblyName,
- ppAssembly);
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivBinder::GetBinderID
-HRESULT CLRPrivAssemblyFusion::GetBinderID(
- UINT_PTR *pBinderId)
-{
- LIMITED_METHOD_CONTRACT;
-
- *pBinderId = reinterpret_cast<UINT_PTR>(m_pBinder.GetValue());
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivAssembly::IsShareable
-HRESULT CLRPrivAssemblyFusion::IsShareable(
- BOOL * pbIsShareable)
-{
- LIMITED_METHOD_CONTRACT;
- *pbIsShareable = TRUE; // These things are only used in the AppX scenario, where all fusion assemblies are unified, shareable assemblies.
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivAssembly::GetAvailableImageTypes
-HRESULT CLRPrivAssemblyFusion::GetAvailableImageTypes(
- LPDWORD pdwImageTypes)
-{
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(!"CLRPrivAssemblyFusion::GetAvailableImageTypes");
- return E_NOTIMPL;
-}
-
-//=====================================================================================================================
-// Implements code:ICLRPrivAssembly::GetImageResource
-HRESULT CLRPrivAssemblyFusion::GetImageResource(
- DWORD dwImageType,
- DWORD *pdwImageType,
- ICLRPrivResource ** ppIResource)
-{
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(!"CLRPrivAssemblyFusion::GetImageResource");
- return E_NOTIMPL;
-}
-
-#endif // !DACCESS_COMPILE
-
diff --git a/src/vm/clrprivbinderfusion.h b/src/vm/clrprivbinderfusion.h
deleted file mode 100644
index 3cf3694e4f..0000000000
--- a/src/vm/clrprivbinderfusion.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// 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.
-
-
-
-#pragma once
-
-#include "holder.h"
-#include "internalunknownimpl.h"
-#include "shash.h"
-#include "clrprivbinding.h"
-#include "clrprivruntimebinders.h"
-
-//=====================================================================================================================
-// Forward declarations
-class CLRPrivBinderFusion;
-class CLRPrivAssemblyFusion;
-
-class PEAssembly;
-class DomainAssembly;
-struct IMDInternalImport;
-
-//=====================================================================================================================
-class CLRPrivBinderFusion :
- public IUnknownCommon<ICLRPrivBinder, IBindContext>
-{
- friend class CLRPrivAssemblyFusion;
-
-public:
- // Scope for the bind operation
- enum BindingScope
- {
- // Binds only to subset of framework that is not on the black list (non-FX assemblies bindings are rejected)
- kBindingScope_FrameworkSubset,
- // Binds to all framework assemblies (incl. those on the black list) (non-FX assemblies bindings are rejected)
- // Used by designer binding context and in DevMode
- kBindingScope_FrameworkAll
- };
-
-public:
- //=============================================================================================
- // ICLRPrivBinder methods
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::BindAssemblyByName
- STDMETHOD(BindAssemblyByName(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly));
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::VerifyBind
- STDMETHOD(VerifyBind)(
- IAssemblyName *pAssemblyName,
- ICLRPrivAssembly *pAssembly,
- ICLRPrivAssemblyInfo *pAssemblyInfo)
- {
- LIMITED_METHOD_CONTRACT;
- if (pAssemblyName == nullptr || pAssembly == nullptr || pAssemblyInfo == nullptr)
- return E_INVALIDARG;
- return S_OK;
- }
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::GetBinderFlags
- STDMETHOD(GetBinderFlags)(
- DWORD *pBinderFlags)
- {
- LIMITED_METHOD_CONTRACT;
- *pBinderFlags = BINDER_FINDASSEMBLYBYSPEC_REQUIRES_EXACT_MATCH;
- return S_OK;
- }
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::GetBinderID
- STDMETHOD(GetBinderID)(
- UINT_PTR *pBinderId);
-
- STDMETHOD(FindAssemblyBySpec)(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly);
-
- //=============================================================================================
- // IBindContext methods
-
- // Implements code:IBindContext::PreBind
- STDMETHOD(PreBind)(
- IAssemblyName *pIAssemblyName,
- DWORD dwPreBindFlags,
- IBindResult **ppIBindResult);
-
- // Implements code:IBindContext::IsDefaultContext
- STDMETHOD(IsDefaultContext)();
-
- //=============================================================================================
- // Class methods
-
- //---------------------------------------------------------------------------------------------
- CLRPrivBinderFusion()
- : m_SetHostAssemblyLock(CrstLeafLock)
- { STANDARD_VM_CONTRACT; }
-
- //---------------------------------------------------------------------------------------------
- ~CLRPrivBinderFusion();
-
- //---------------------------------------------------------------------------------------------
- HRESULT FindFusionAssemblyBySpec(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- BindingScope kBindingScope,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly);
-
- //---------------------------------------------------------------------------------------------
- HRESULT BindFusionAssemblyByName(
- IAssemblyName * pAssemblyName,
- BindingScope kBindingScope,
- ICLRPrivAssembly ** ppAssembly);
-
- //---------------------------------------------------------------------------------------------
- HRESULT PreBindFusionAssemblyByName(
- IAssemblyName * pIAssemblyName,
- DWORD dwPreBindFlags,
- IBindResult ** ppIBindResult);
-
- //---------------------------------------------------------------------------------------------
- // Binds mscorlib.dll
- void BindMscorlib(
- PEAssembly * pPEAssembly);
-
-private:
- //---------------------------------------------------------------------------------------------
- HRESULT BindAssemblyByNameWorker(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly);
-
-private:
- //---------------------------------------------------------------------------------------------
- // This lock is used to serialize assigning ICLRPrivAssembly instances to PEAssembly objects.
- Crst m_SetHostAssemblyLock;
-
-}; // class CLRPrivBinderFusion
-
-//=====================================================================================================================
-class CLRPrivAssemblyFusion :
- public IUnknownCommon<ICLRPrivAssembly>
-{
-public:
- //---------------------------------------------------------------------------------------------
- CLRPrivAssemblyFusion(
- LPCWSTR wszName,
- CLRPrivBinderFusion * pBinder);
-
- //---------------------------------------------------------------------------------------------
- LPCWSTR GetName() const;
-
- //---------------------------------------------------------------------------------------------
- // Implements code:IUnknown::Release
- STDMETHOD_(ULONG, Release)();
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::BindAssemblyByName
- STDMETHOD(BindAssemblyByName)(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly);
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivAssembly::IsShareable
- STDMETHOD(IsShareable)(
- BOOL * pbIsShareable);
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivAssembly::GetAvailableImageTypes
- STDMETHOD(GetAvailableImageTypes)(
- LPDWORD pdwImageTypes);
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivAssembly::GetImageResource
- STDMETHOD(GetImageResource)(
- DWORD dwImageType,
- DWORD *pdwImageType,
- ICLRPrivResource ** ppIResource);
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::VerifyBind
- STDMETHOD(VerifyBind)(
- IAssemblyName *pAssemblyName,
- ICLRPrivAssembly *pAssembly,
- ICLRPrivAssemblyInfo *pAssemblyInfo)
- {
- WRAPPER_NO_CONTRACT;
- return m_pBinder->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo);
- }
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::GetBinderFlags
- STDMETHOD(GetBinderFlags)(
- DWORD *pBinderFlags)
- {
- LIMITED_METHOD_CONTRACT;
- return m_pBinder->GetBinderFlags(pBinderFlags);
- }
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::GetBinderID
- STDMETHOD(GetBinderID)(
- UINT_PTR *pBinderId);
-
- //---------------------------------------------------------------------------------------------
- // Implements code:ICLRPrivBinder::FindAssemblyBySpec
- STDMETHOD(FindAssemblyBySpec)(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly)
- { STATIC_CONTRACT_WRAPPER; return m_pBinder->FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly); }
-
-protected:
- //---------------------------------------------------------------------------------------------
- // The fusion binder. Need to keep it around as long as this object is around.
- ReleaseHolder<CLRPrivBinderFusion> m_pBinder;
-
- // Full display name of the assembly - used to avoid duplicate CLRPrivAssemblyFusion objects
- NewArrayHolder<WCHAR> m_wszName;
-
-}; // class CLRPrivAssemblyFusion
diff --git a/src/vm/clrprivbinderreflectiononlywinrt.cpp b/src/vm/clrprivbinderreflectiononlywinrt.cpp
deleted file mode 100644
index ad46511e81..0000000000
--- a/src/vm/clrprivbinderreflectiononlywinrt.cpp
+++ /dev/null
@@ -1,497 +0,0 @@
-// 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.
-//
-
-//
-// Contains the types that implement code:ICLRPrivBinder and code:ICLRPrivAssembly for WinRT ReflectionOnly (aka introspection) binding.
-//
-//=====================================================================================================================
-
-#include "common.h" // precompiled header
-
-#ifndef DACCESS_COMPILE
-#ifdef FEATURE_REFLECTION_ONLY_LOAD
-
-//=====================================================================================================================
-#include "sstring.h"
-#include "policy.h"
-#include "clrprivbinderreflectiononlywinrt.h"
-#include "appxutil.h"
-#include "clrprivbinderutil.h"
-#include "imprthelpers.h" // in fusion/inc
-
-#include <winstring.h>
-#include <typeresolution.h>
-
-using namespace CLRPrivBinderUtil;
-
-//=====================================================================================================================
-
-//=====================================================================================================================
-CLRPrivBinderReflectionOnlyWinRT::CLRPrivBinderReflectionOnlyWinRT(
- CLRPrivTypeCacheReflectionOnlyWinRT * pTypeCache)
- : m_MapsLock(CrstLeafLock, CRST_REENTRANCY) // Reentracy is needed for code:CLRPrivAssemblyReflectionOnlyWinRT::Release
-{
- STANDARD_VM_CONTRACT;
-
- // This binder is not supported in AppX scenario.
- _ASSERTE(!AppX::IsAppXProcess());
-
- _ASSERTE(pTypeCache != nullptr);
- m_pTypeCache = clr::SafeAddRef(pTypeCache);
-}
-
-//=====================================================================================================================
-CLRPrivBinderReflectionOnlyWinRT::~CLRPrivBinderReflectionOnlyWinRT()
-{
- WRAPPER_NO_CONTRACT;
-
- if (m_pTypeCache != nullptr)
- {
- m_pTypeCache->Release();
- }
-}
-
-//=====================================================================================================================
-HRESULT
-CLRPrivBinderReflectionOnlyWinRT::BindWinRtType_Internal(
- LPCSTR szTypeNamespace,
- LPCSTR szTypeClassName,
- DomainAssembly * pParentAssembly,
- CLRPrivAssemblyReflectionOnlyWinRT ** ppAssembly)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr = S_OK;
-
- VALIDATE_ARG_RET(ppAssembly != nullptr);
-
- CLRPrivBinderUtil::WStringList * pFileNameList = nullptr;
-
- StackSString ssTypeNamespace(SString::Utf8, szTypeNamespace);
-
- GetFileNameListForNamespace(ssTypeNamespace.GetUnicode(), pParentAssembly, &pFileNameList);
-
- if (pFileNameList == nullptr)
- { // There are no files associated with the namespace
- return CLR_E_BIND_TYPE_NOT_FOUND;
- }
-
- StackSString ssTypeName(ssTypeNamespace);
- ssTypeName.Append(W('.'));
- ssTypeName.AppendUTF8(szTypeClassName);
-
- CLRPrivBinderUtil::WStringListElem * pFileNameElem = pFileNameList->GetHead();
- while (pFileNameElem != nullptr)
- {
- const WCHAR * wszFileName = pFileNameElem->GetValue();
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> pAssembly = FindOrCreateAssemblyByFileName(wszFileName);
- _ASSERTE(pAssembly != NULL);
-
- IfFailRet(hr = m_pTypeCache->ContainsType(pAssembly, ssTypeName.GetUnicode()));
- if (hr == S_OK)
- { // The type we are looking for has been found in this assembly
- *ppAssembly = pAssembly.Extract();
- return S_OK;
- }
- _ASSERTE(hr == S_FALSE);
-
- // Try next file name for this namespace
- pFileNameElem = CLRPrivBinderUtil::WStringList::GetNext(pFileNameElem);
- }
-
- // The type has not been found in any of the files from the type's namespace
- return CLR_E_BIND_TYPE_NOT_FOUND;
-} // CLRPrivBinderReflectionOnlyWinRT::BindWinRtType_Internal
-
-//=====================================================================================================================
-HRESULT
-CLRPrivBinderReflectionOnlyWinRT::BindWinRtType(
- LPCSTR szTypeNamespace,
- LPCSTR szTypeClassName,
- DomainAssembly * pParentAssembly,
- ICLRPrivAssembly ** ppPrivAssembly)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr = S_OK;
-
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> pWinRTAssembly;
- IfFailRet(BindWinRtType_Internal(szTypeNamespace, szTypeClassName, pParentAssembly, &pWinRTAssembly));
- IfFailRet(pWinRTAssembly->QueryInterface(__uuidof(ICLRPrivAssembly), (LPVOID *)ppPrivAssembly));
-
- return hr;
-}
-
-//=====================================================================================================================
-// Implements interface method code:ICLRPrivBinder::BindAssemblyByName.
-//
-HRESULT CLRPrivBinderReflectionOnlyWinRT::BindAssemblyByName(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly)
-{
- LIMITED_METHOD_CONTRACT;
-
- _ASSERTE_MSG(false, "Unexpected call to CLRPrivBinderReflectionOnlyWinRT::BindAssemblyByName");
- return E_UNEXPECTED;
-}
-
-//=====================================================================================================================
-ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT>
-CLRPrivBinderReflectionOnlyWinRT::FindAssemblyByFileName(
- LPCWSTR wszFileName)
-{
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_CAN_TAKE_LOCK;
-
- CrstHolder lock(&m_MapsLock);
- const FileNameToAssemblyMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
- return (pEntry == nullptr) ? nullptr : clr::SafeAddRef(pEntry->m_pAssembly);
-}
-
-//=====================================================================================================================
-// Add FileName -> CLRPrivAssemblyReflectionOnlyWinRT * mapping to the map (multi-thread safe).
-ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT>
-CLRPrivBinderReflectionOnlyWinRT::AddFileNameToAssemblyMapping(
- LPCWSTR wszFileName,
- CLRPrivAssemblyReflectionOnlyWinRT * pAssembly)
-{
- STANDARD_VM_CONTRACT;
-
- _ASSERTE(pAssembly != nullptr);
-
- CrstHolder lock(&m_MapsLock);
-
- const FileNameToAssemblyMapEntry * pEntry = m_FileNameToAssemblyMap.LookupPtr(wszFileName);
- CLRPrivAssemblyReflectionOnlyWinRT * pResultAssembly = nullptr;
- if (pEntry != nullptr)
- {
- pResultAssembly = pEntry->m_pAssembly;
- }
- else
- {
- FileNameToAssemblyMapEntry e;
- e.m_wszFileName = wszFileName;
- e.m_pAssembly = pAssembly;
- m_FileNameToAssemblyMap.Add(e);
-
- pResultAssembly = pAssembly;
- }
- return clr::SafeAddRef(pResultAssembly);
-}
-
-//=====================================================================================================================
-void
-CLRPrivBinderReflectionOnlyWinRT::RemoveFileNameToAssemblyMapping(
- LPCWSTR wszFileName)
-{
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_CAN_TAKE_LOCK;
-
- CrstHolder lock(&m_MapsLock);
- m_FileNameToAssemblyMap.Remove(wszFileName);
-}
-
-//=====================================================================================================================
-ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT>
-CLRPrivBinderReflectionOnlyWinRT::FindOrCreateAssemblyByFileName(
- LPCWSTR wszFileName)
-{
- STANDARD_VM_CONTRACT;
-
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> pAssembly = FindAssemblyByFileName(wszFileName);
-
- if (pAssembly == nullptr)
- {
- NewHolder<CLRPrivResourcePathImpl> pResource(
- new CLRPrivResourcePathImpl(wszFileName));
-
- NewHolder<CLRPrivAssemblyReflectionOnlyWinRT> pNewAssembly(
- new CLRPrivAssemblyReflectionOnlyWinRT(wszFileName, this, pResource));
-
- // pNewAssembly holds reference to this now
- pResource.SuppressRelease();
-
- // Add the assembly into cache (multi-thread aware)
- pAssembly = AddFileNameToAssemblyMapping(pResource->GetPath(), pNewAssembly);
-
- if (pAssembly == pNewAssembly)
- { // We did not find an existing assembly in the cache and are using the newly created pNewAssembly.
- // Stop it from being deleted when we go out of scope.
- pNewAssembly.SuppressRelease();
- }
- }
- return pAssembly.Extract();
-}
-
-//=====================================================================================================================
-// Returns list of file names from code:m_NamespaceToFileNameListMap for the namespace.
-//
-void
-CLRPrivBinderReflectionOnlyWinRT::GetFileNameListForNamespace(
- LPCWSTR wszNamespace,
- DomainAssembly * pParentAssembly,
- CLRPrivBinderUtil::WStringList ** ppFileNameList)
-{
- STANDARD_VM_CONTRACT;
-
- CLRPrivBinderUtil::WStringList * pFileNameList = nullptr;
- {
- CrstHolder lock(&m_MapsLock);
-
- const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszNamespace);
- if (pEntry != nullptr)
- {
- // Entries from the map are never removed, so we do not have to protect the file name list with a lock
- pFileNameList = pEntry->m_pFileNameList;
- }
- }
-
- if (pFileNameList != nullptr)
- {
- *ppFileNameList = pFileNameList;
- }
- else
- {
- CLRPrivBinderUtil::WStringListHolder hFileNameList;
-
- EX_TRY
- {
- m_pTypeCache->RaiseNamespaceResolveEvent(wszNamespace, pParentAssembly, &hFileNameList);
- }
- EX_CATCH
- {
- Exception * ex = GET_EXCEPTION();
- if (!ex->IsTransient())
- { // Exception was caused by user code
- // Cache empty file name list for this namespace
- (void)AddFileNameListForNamespace(wszNamespace, nullptr, ppFileNameList);
- }
- EX_RETHROW;
- }
- EX_END_CATCH_UNREACHABLE
-
- if (AddFileNameListForNamespace(wszNamespace, hFileNameList.GetValue(), ppFileNameList))
- { // The file name list was added to the cache - do not delete it
- _ASSERTE(*ppFileNameList == hFileNameList.GetValue());
- (void)hFileNameList.Extract();
- }
- }
-} // CLRPrivBinderReflectionOnlyWinRT::GetFileNameListForNamespace
-
-//=====================================================================================================================
-// Adds (thread-safe) list of file names to code:m_NamespaceToFileNameListMap for the namespace - returns the cached value.
-// Returns TRUE, if pFileNameList was added to the cache and caller should NOT delete it.
-// Returns FALSE, if pFileNameList was not added to the cache and caller should delete it.
-//
-BOOL
-CLRPrivBinderReflectionOnlyWinRT::AddFileNameListForNamespace(
- LPCWSTR wszNamespace,
- CLRPrivBinderUtil::WStringList * pFileNameList,
- CLRPrivBinderUtil::WStringList ** ppFileNameList)
-{
- STANDARD_VM_CONTRACT;
-
- NewArrayHolder<WCHAR> wszEntryNamespace = DuplicateStringThrowing(wszNamespace);
-
- NamespaceToFileNameListMapEntry entry;
- entry.m_wszNamespace = wszEntryNamespace;
- entry.m_pFileNameList = pFileNameList;
-
- {
- CrstHolder lock(&m_MapsLock);
-
- const NamespaceToFileNameListMapEntry * pEntry = m_NamespaceToFileNameListMap.LookupPtr(wszEntryNamespace);
- if (pEntry == nullptr)
- {
- m_NamespaceToFileNameListMap.Add(entry);
-
- // These values are now owned by the hash table element
- wszEntryNamespace.SuppressRelease();
- *ppFileNameList = pFileNameList;
- return TRUE;
- }
- else
- { // Another thread beat us adding this entry to the hash table
- *ppFileNameList = pEntry->m_pFileNameList;
- return FALSE;
- }
- }
-} // CLRPrivBinderReflectionOnlyWinRT::AddFileNameListForNamespace
-
-//=====================================================================================================================
-HRESULT
-CLRPrivBinderReflectionOnlyWinRT::BindAssemblyExplicit(
- const WCHAR * wszFileName,
- ICLRPrivAssembly ** ppAssembly)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- HRESULT hr;
-
- GCX_PREEMP();
-
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> pAssembly = FindOrCreateAssemblyByFileName(wszFileName);
- _ASSERTE(pAssembly != NULL);
-
- IfFailRet(pAssembly->QueryInterface(__uuidof(ICLRPrivAssembly), (LPVOID *)ppAssembly));
-
- return S_OK;
-}
-
-//=====================================================================================================================
-CLRPrivAssemblyReflectionOnlyWinRT::CLRPrivAssemblyReflectionOnlyWinRT(
- LPCWSTR wzSimpleName,
- CLRPrivBinderReflectionOnlyWinRT * pBinder,
- CLRPrivResourcePathImpl * pResourceIL)
-{
- STANDARD_VM_CONTRACT;
- VALIDATE_ARG_THROW((wzSimpleName != nullptr) && (pBinder != nullptr) && (pResourceIL != nullptr));
-
- m_pBinder = clr::SafeAddRef(pBinder);
- m_pResourceIL = clr::SafeAddRef(pResourceIL);
-}
-
-//=====================================================================================================================
-ULONG CLRPrivAssemblyReflectionOnlyWinRT::Release()
-{
- LIMITED_METHOD_CONTRACT;
- STATIC_CONTRACT_CAN_TAKE_LOCK;
- _ASSERTE(m_cRef > 0);
-
- ULONG cRef;
-
- {
- // To achieve proper lifetime semantics, the name to assembly map elements' CLRPrivAssemblyReflectionOnlyWinRT
- // instances are not ref counted. We cannot allow discovery of the object via m_FileNameToAssemblyMap
- // when the ref count is 0 (to prevent another thread to AddRef and Release it back to 0 in parallel).
- // All uses of the map are guarded by the map lock, so we have to decrease the ref count under that
- // lock (to avoid the chance that 2 threads are running Release to ref count 0 at once).
- CrstHolder lock(&m_pBinder->m_MapsLock);
-
- cRef = InterlockedDecrement(&m_cRef);
- if (cRef == 0)
- {
- m_pBinder->RemoveFileNameToAssemblyMapping(m_pResourceIL->GetPath());
- }
- }
-
- if (cRef == 0)
- {
- delete this;
- }
- return cRef;
-}
-
-//=====================================================================================================================
-// Implements interface method code:ICLRPrivAssembly::IsShareable.
-//
-HRESULT CLRPrivAssemblyReflectionOnlyWinRT::IsShareable(
- BOOL * pbIsShareable)
-{
- LIMITED_METHOD_CONTRACT;
-
- VALIDATE_ARG_RET(pbIsShareable != nullptr);
-
- *pbIsShareable = FALSE;
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements interface method code:ICLRPrivAssembly::GetAvailableImageTypes.
-//
-HRESULT CLRPrivAssemblyReflectionOnlyWinRT::GetAvailableImageTypes(
- LPDWORD pdwImageTypes)
-{
- LIMITED_METHOD_CONTRACT;
-
- VALIDATE_ARG_RET(pdwImageTypes != nullptr);
-
- *pdwImageTypes = 0;
-
- if (m_pResourceIL != nullptr)
- *pdwImageTypes |= ASSEMBLY_IMAGE_TYPE_IL;
-
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements interface method code:ICLRPrivAssembly::GetImageResource.
-//
-HRESULT CLRPrivAssemblyReflectionOnlyWinRT::GetImageResource(
- DWORD dwImageType,
- DWORD * pdwImageType,
- ICLRPrivResource ** ppIResource)
-{
- STANDARD_BIND_CONTRACT;
- HRESULT hr = S_OK;
-
- VALIDATE_ARG_RET(ppIResource != nullptr);
-
- EX_TRY
- {
- DWORD _dwImageType;
- if (pdwImageType == nullptr)
- {
- pdwImageType = &_dwImageType;
- }
-
- if ((dwImageType & ASSEMBLY_IMAGE_TYPE_IL) == ASSEMBLY_IMAGE_TYPE_IL)
- {
- *ppIResource = clr::SafeAddRef(m_pResourceIL);
- *pdwImageType = ASSEMBLY_IMAGE_TYPE_IL;
- }
- else
- { // Native image is not supported by this binder
- hr = CLR_E_BIND_IMAGE_UNAVAILABLE;
- }
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
-//=====================================================================================================================
-// Implements interface method code:ICLRPrivBinder::VerifyBind.
-//
-HRESULT CLRPrivBinderReflectionOnlyWinRT::VerifyBind(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly * pAssembly,
- ICLRPrivAssemblyInfo * pAssemblyInfo)
-{
- STANDARD_BIND_CONTRACT;
- HRESULT hr = S_OK;
-
- UINT_PTR binderID;
- IfFailRet(pAssembly->GetBinderID(&binderID));
- if (binderID != reinterpret_cast<UINT_PTR>(this))
- {
- return pAssembly->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo);
- }
-
- // Since WinRT types are bound by type name and not assembly name, assembly-level version validation
- // does not make sense here. Just return S_OK.
- return S_OK;
-}
-
-//=====================================================================================================================
-// Implements interface method code:ICLRPrivBinder::GetBinderID.
-//
-HRESULT CLRPrivBinderReflectionOnlyWinRT::GetBinderID(
- UINT_PTR * pBinderId)
-{
- LIMITED_METHOD_CONTRACT;
-
- *pBinderId = reinterpret_cast<UINT_PTR>(this);
- return S_OK;
-}
-
-#endif //FEATURE_REFLECTION_ONLY_LOAD
-#endif //!DACCESS_COMPILE
diff --git a/src/vm/clrprivbinderreflectiononlywinrt.h b/src/vm/clrprivbinderreflectiononlywinrt.h
deleted file mode 100644
index 5f8ef46773..0000000000
--- a/src/vm/clrprivbinderreflectiononlywinrt.h
+++ /dev/null
@@ -1,295 +0,0 @@
-// 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.
-//
-
-//
-// Contains the types that implement code:ICLRPrivBinder and code:ICLRPrivAssembly for WinRT ReflectionOnly (aka introspection) binding.
-//
-//=====================================================================================================================
-
-#ifdef FEATURE_REFLECTION_ONLY_LOAD
-
-#pragma once
-
-#include "holder.h"
-#include "internalunknownimpl.h"
-#include "clrprivbinding.h"
-#include "clrprivruntimebinders.h"
-#include "clrprivbinderutil.h"
-#include "clr_std/utility"
-
-//=====================================================================================================================
-// Forward declarations
-class CLRPrivBinderReflectionOnlyWinRT;
-class CLRPrivAssemblyReflectionOnlyWinRT;
-class CLRPrivTypeCacheReflectionOnlyWinRT;
-class DomainAssembly;
-
-//=====================================================================================================================
-//=====================================================================================================================
-//=====================================================================================================================
-class CLRPrivBinderReflectionOnlyWinRT :
- public IUnknownCommon<ICLRPrivBinder>
-{
- friend class CLRPrivAssemblyReflectionOnlyWinRT;
-
-private:
- //=============================================================================================
- // Data structures for Namespace -> FileNameList hash (as returned by RoResolveNamespace API)
-
- // Entry in SHash table that maps namespace to list of files
- struct NamespaceToFileNameListMapEntry
- {
- PWSTR m_wszNamespace;
- CLRPrivBinderUtil::WStringList * m_pFileNameList;
- };
-
- // SHash traits for Namespace -> FileNameList hash
- class NamespaceToFileNameListMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits< NamespaceToFileNameListMapEntry > >
- {
- public:
- typedef PCWSTR key_t;
- static const NamespaceToFileNameListMapEntry Null() { NamespaceToFileNameListMapEntry e; e.m_wszNamespace = nullptr; return e; }
- static bool IsNull(const NamespaceToFileNameListMapEntry & e) { return e.m_wszNamespace == nullptr; }
- static PCWSTR GetKey(const NamespaceToFileNameListMapEntry & e) { return e.m_wszNamespace; }
- static count_t Hash(PCWSTR str) { return HashString(str); }
- static BOOL Equals(PCWSTR lhs, PCWSTR rhs) { LIMITED_METHOD_CONTRACT; return (wcscmp(lhs, rhs) == 0); }
-
- void OnDestructPerEntryCleanupAction(const NamespaceToFileNameListMapEntry & e)
- {
- delete [] e.m_wszNamespace;
- CLRPrivBinderUtil::WStringList_Delete(e.m_pFileNameList);
- }
- static const bool s_DestructPerEntryCleanupAction = true;
- };
-
- typedef SHash<NamespaceToFileNameListMapTraits> NamespaceToFileNameListMap;
-
- //=============================================================================================
- // Data structure for FileName -> CLRPrivAssemblyReflectionOnlyWinRT * map
-
- struct FileNameToAssemblyMapEntry
- {
- PCWSTR m_wszFileName; // File name (owned by m_pAssembly)
- CLRPrivAssemblyReflectionOnlyWinRT * m_pAssembly;
- };
-
- class FileNameToAssemblyMapTraits : public DefaultSHashTraits<FileNameToAssemblyMapEntry>
- {
- public:
- typedef PCWSTR key_t;
- static const FileNameToAssemblyMapEntry Null() { FileNameToAssemblyMapEntry e; e.m_wszFileName = NULL; return e; }
- static bool IsNull(const FileNameToAssemblyMapEntry &e) { return e.m_wszFileName == NULL; }
- static const FileNameToAssemblyMapEntry Deleted() { FileNameToAssemblyMapEntry e; e.m_wszFileName = (PCWSTR)-1; return e; }
- static bool IsDeleted(const FileNameToAssemblyMapEntry & e) { return e.m_wszFileName == (PCWSTR)-1; }
- static PCWSTR GetKey(const FileNameToAssemblyMapEntry & e) { return e.m_wszFileName; }
- static count_t Hash(PCWSTR str) { return HashString(str); }
- static BOOL Equals(PCWSTR lhs, PCWSTR rhs) { LIMITED_METHOD_CONTRACT; return (wcscmp(lhs, rhs) == 0); }
- };
-
- typedef SHash<FileNameToAssemblyMapTraits> FileNameToAssemblyMap;
-
-public:
- //=============================================================================================
- // ICLRPrivBinder interface methods
-
- STDMETHOD(BindAssemblyByName)(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly);
-
- // Implements interface method code:ICLRPrivBinder::VerifyBind.
- STDMETHOD(VerifyBind)(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly * pAssembly,
- ICLRPrivAssemblyInfo * pAssemblyInfo);
-
- // Implements interface method code:ICLRPrivBinder::GetBinderFlags
- STDMETHOD(GetBinderFlags)(
- DWORD *pBinderFlags)
- {
- LIMITED_METHOD_CONTRACT;
- *pBinderFlags = BINDER_NONE;
- return S_OK;
- }
-
- // Implements interface method code:ICLRPrivBinder::GetBinderID.
- STDMETHOD(GetBinderID)(
- UINT_PTR * pBinderId);
-
- // FindAssemblyBySpec is not supported by this binder.
- STDMETHOD(FindAssemblyBySpec)(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly)
- { STATIC_CONTRACT_WRAPPER; return E_FAIL; }
-
- //=============================================================================================
- // Class methods
-
- CLRPrivBinderReflectionOnlyWinRT(
- CLRPrivTypeCacheReflectionOnlyWinRT * pTypeCache);
-
- ~CLRPrivBinderReflectionOnlyWinRT();
-
- HRESULT BindAssemblyExplicit(
- const WCHAR * wszFileName,
- ICLRPrivAssembly ** ppAssembly);
-
- HRESULT BindWinRtType(
- LPCSTR szTypeNamespace,
- LPCSTR szTypeClassName,
- DomainAssembly * pParentAssembly,
- ICLRPrivAssembly ** ppPrivAssembly);
-
-private:
- //=============================================================================================
- // Accessors for FileName -> CLRPrivAssemblyReflectionOnlyWinRT * map
-
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> FindAssemblyByFileName(
- LPCWSTR wzsFileName);
-
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> AddFileNameToAssemblyMapping(
- LPCWSTR wszFileName,
- CLRPrivAssemblyReflectionOnlyWinRT * pAssembly);
-
- void RemoveFileNameToAssemblyMapping(
- LPCWSTR wszFileName);
-
- ReleaseHolder<CLRPrivAssemblyReflectionOnlyWinRT> FindOrCreateAssemblyByFileName(
- LPCWSTR wzsFileName);
-
- //=============================================================================================
- // Internal methods
-
- // Returns list of file names from code:m_NamespaceToFileNameListMap for the namespace.
- void GetFileNameListForNamespace(
- LPCWSTR wszNamespace,
- DomainAssembly * pParentAssembly,
- CLRPrivBinderUtil::WStringList ** ppFileNameList);
-
- // Adds (thread-safe) list of file names to code:m_NamespaceToFileNameListMap for the namespace - returns the cached value.
- BOOL AddFileNameListForNamespace(
- LPCWSTR wszNamespace,
- CLRPrivBinderUtil::WStringList * pFileNameList,
- CLRPrivBinderUtil::WStringList ** ppFileNameList);
-
- HRESULT BindWinRtType_Internal(
- LPCSTR szTypeNamespace,
- LPCSTR szTypeClassName,
- DomainAssembly * pParentAssembly,
- CLRPrivAssemblyReflectionOnlyWinRT ** ppAssembly);
-
-private:
- //=============================================================================================
-
- // Namespace -> FileName list map ... items are never removed
- NamespaceToFileNameListMap m_NamespaceToFileNameListMap;
- // FileName -> CLRPrivAssemblyReflectionOnlyWinRT * map ... items can be removed when CLRPrivAssemblyReflectionOnlyWinRT dies
- FileNameToAssemblyMap m_FileNameToAssemblyMap;
-
- // Lock for the above maps
- Crst m_MapsLock;
-
- //=============================================================================================
- CLRPrivTypeCacheReflectionOnlyWinRT * m_pTypeCache;
-
-}; // class CLRPrivBinderReflectionOnlyWinRT
-
-
-//=====================================================================================================================
-//=====================================================================================================================
-//=====================================================================================================================
-class CLRPrivAssemblyReflectionOnlyWinRT :
- public IUnknownCommon<ICLRPrivAssembly>
-{
- friend class CLRPrivBinderReflectionOnlyWinRT;
-
-public:
- //=============================================================================================
- // Class methods
-
- CLRPrivAssemblyReflectionOnlyWinRT(
- LPCWSTR wzFullTypeName,
- CLRPrivBinderReflectionOnlyWinRT * pBinder,
- CLRPrivBinderUtil::CLRPrivResourcePathImpl * pResourceIL);
-
- //=============================================================================================
- // IUnknown interface methods
-
- // Overridden to implement self-removal from assembly map code:CLRPrivBinderReflectionOnlyWinRT::m_FileNameToAssemblyMap.
- STDMETHOD_(ULONG, Release)();
-
- //=============================================================================================
- // ICLRPrivBinder interface methods
-
- STDMETHOD(BindAssemblyByName)(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly ** ppAssembly)
- {
- STATIC_CONTRACT_WRAPPER;
- return m_pBinder->BindAssemblyByName(pAssemblyName, ppAssembly);
- }
-
- // Implements interface method code:ICLRPrivBinder::VerifyBind.
- STDMETHOD(VerifyBind)(
- IAssemblyName * pAssemblyName,
- ICLRPrivAssembly * pAssembly,
- ICLRPrivAssemblyInfo * pAssemblyInfo)
- {
- STATIC_CONTRACT_WRAPPER;
- return m_pBinder->VerifyBind(pAssemblyName, pAssembly, pAssemblyInfo);
- }
-
- //---------------------------------------------------------------------------------------------
- // Implements interface method code:ICLRPrivBinder::GetBinderFlags
- STDMETHOD(GetBinderFlags)(
- DWORD *pBinderFlags)
- {
- STATIC_CONTRACT_WRAPPER;
- return m_pBinder->GetBinderFlags(pBinderFlags);
- }
-
- // Implements interface method code:ICLRPrivBinder::GetBinderID.
- STDMETHOD(GetBinderID)(
- UINT_PTR * pBinderId)
- {
- STATIC_CONTRACT_WRAPPER;
- return m_pBinder->GetBinderID(pBinderId);
- }
-
- //=============================================================================================
- // ICLRPrivAssembly interface methods
-
- // Implements interface method code:ICLRPrivAssembly::IsShareable.
- STDMETHOD(IsShareable)(
- BOOL * pbIsShareable);
-
- // Implements interface method code:ICLRPrivAssembly::GetAvailableImageTypes.
- STDMETHOD(GetAvailableImageTypes)(
- LPDWORD pdwImageTypes);
-
- // Implements interface method code:ICLRPrivAssembly::GetImageResource.
- STDMETHOD(GetImageResource)(
- DWORD dwImageType,
- DWORD * pdwImageType,
- ICLRPrivResource ** ppIResource);
-
- // Implements code:ICLRPrivBinder::FindAssemblyBySpec
- STDMETHOD(FindAssemblyBySpec)(
- LPVOID pvAppDomain,
- LPVOID pvAssemblySpec,
- HRESULT * pResult,
- ICLRPrivAssembly ** ppAssembly)
- { STATIC_CONTRACT_WRAPPER; return m_pBinder->FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly); }
-
-private:
- //=============================================================================================
-
- ReleaseHolder<CLRPrivBinderReflectionOnlyWinRT> m_pBinder;
- ReleaseHolder<CLRPrivBinderUtil::CLRPrivResourcePathImpl> m_pResourceIL;
-
-}; // class CLRPrivAssemblyReflectionOnlyWinRT
-
-#endif //FEATURE_REFLECTION_ONLY_LOAD
diff --git a/src/vm/clrprivtypecachereflectiononlywinrt.cpp b/src/vm/clrprivtypecachereflectiononlywinrt.cpp
deleted file mode 100644
index 40f90dfe3f..0000000000
--- a/src/vm/clrprivtypecachereflectiononlywinrt.cpp
+++ /dev/null
@@ -1,260 +0,0 @@
-// 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.
-//
-
-//
-// Contains VM implementation of WinRT type cache for code:CLRPrivBinderReflectionOnlyWinRT binder.
-//
-//=====================================================================================================================
-
-#include "common.h" // precompiled header
-
-#ifndef DACCESS_COMPILE
-#ifdef FEATURE_REFLECTION_ONLY_LOAD
-
-#include "clrprivtypecachereflectiononlywinrt.h"
-#include <typeresolution.h>
-
-//=====================================================================================================================
-// S_OK - pAssembly contains type wszTypeName
-// S_FALSE - pAssembly does not contain type wszTypeName
-//
-HRESULT
-CLRPrivTypeCacheReflectionOnlyWinRT::ContainsType(
- ICLRPrivAssembly * pPrivAssembly,
- LPCWSTR wszTypeName)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr = S_OK;
-
- AppDomain * pAppDomain = AppDomain::GetCurrentDomain();
-
- ReleaseHolder<PEAssembly> pPEAssembly;
- IfFailGo(pAppDomain->BindHostedPrivAssembly(nullptr, pPrivAssembly, nullptr, &pPEAssembly, TRUE));
- _ASSERTE(pPEAssembly != nullptr);
-
- {
- // Find DomainAssembly * (can be cached if this is too slow to call always)
- DomainAssembly * pDomainAssembly = pAppDomain->LoadDomainAssembly(
- nullptr, // pIdentity
- pPEAssembly,
- FILE_LOADED,
- nullptr); // pLoadSecurity
-
- // Convert the type name into namespace and type names in UTF8
- StackSString ssTypeNameWCHAR(wszTypeName);
-
- StackSString ssTypeName;
- ssTypeNameWCHAR.ConvertToUTF8(ssTypeName);
- LPUTF8 szTypeName = (LPUTF8)ssTypeName.GetUTF8NoConvert();
-
- LPCUTF8 szNamespace;
- LPCUTF8 szClassName;
- ns::SplitInline(szTypeName, szNamespace, szClassName);
-
- NameHandle typeName(szNamespace, szClassName);
-
- // Find the type in the assembly (use existing hash of all type names defined in the assembly)
- TypeHandle thType;
- mdToken tkType;
- Module * pTypeModule;
- mdToken tkExportedType;
- if (pDomainAssembly->GetAssembly()->GetLoader()->FindClassModuleThrowing(
- &typeName,
- &thType,
- &tkType,
- &pTypeModule,
- &tkExportedType,
- nullptr, // ppClassHashEntry
- nullptr, // pLookInThisModuleOnly
- Loader::DontLoad))
- { // The type is present in the assembly
- hr = S_OK;
- }
- else
- { // The type is not present in the assembly
- hr = S_FALSE;
- }
- }
-
-ErrExit:
- return hr;
-} // CLRPrivTypeCacheReflectionOnlyWinRT::ContainsType
-
-//=====================================================================================================================
-// Raises user event NamespaceResolveEvent to get a list of files for this namespace.
-//
-void
-CLRPrivTypeCacheReflectionOnlyWinRT::RaiseNamespaceResolveEvent(
- LPCWSTR wszNamespace,
- DomainAssembly * pParentAssembly,
- CLRPrivBinderUtil::WStringListHolder * pFileNameList)
-{
- STANDARD_VM_CONTRACT;
-
- _ASSERTE(pFileNameList != nullptr);
-
- AppDomain * pAppDomain = AppDomain::GetCurrentDomain();
-
- GCX_COOP();
-
- struct _gc {
- OBJECTREF AppDomainRef;
- OBJECTREF AssemblyRef;
- STRINGREF str;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
- if ((gc.AppDomainRef = pAppDomain->GetRawExposedObject()) != NULL)
- {
- if (pParentAssembly != nullptr)
- {
- gc.AssemblyRef = pParentAssembly->GetExposedAssemblyObject();
- }
-
- MethodDescCallSite onNamespaceResolve(METHOD__APP_DOMAIN__ON_REFLECTION_ONLY_NAMESPACE_RESOLVE, &gc.AppDomainRef);
- gc.str = StringObject::NewString(wszNamespace);
- ARG_SLOT args[3] =
- {
- ObjToArgSlot(gc.AppDomainRef),
- ObjToArgSlot(gc.AssemblyRef),
- ObjToArgSlot(gc.str)
- };
- PTRARRAYREF ResultingAssemblyArrayRef = (PTRARRAYREF) onNamespaceResolve.Call_RetOBJECTREF(args);
- if (ResultingAssemblyArrayRef != NULL)
- {
- for (DWORD i = 0; i < ResultingAssemblyArrayRef->GetNumComponents(); i++)
- {
- ASSEMBLYREF ResultingAssemblyRef = (ASSEMBLYREF) ResultingAssemblyArrayRef->GetAt(i);
- Assembly * pAssembly = ResultingAssemblyRef->GetAssembly();
-
- if (pAssembly->IsCollectible())
- {
- COMPlusThrow(kNotSupportedException, W("NotSupported_CollectibleAssemblyResolve"));
- }
-
- PEAssembly * pPEAssembly = pAssembly->GetManifestFile();
-
- ICLRPrivAssembly * pPrivAssembly = pPEAssembly->GetHostAssembly();
- if ((pPrivAssembly == NULL) || !IsAfContentType_WindowsRuntime(pPEAssembly->GetFlags()))
- {
- COMPlusThrow(kNotSupportedException, IDS_EE_REFLECTIONONLY_WINRT_INVALIDASSEMBLY);
- }
-
- pFileNameList->InsertTail(pPEAssembly->GetILimage()->GetPath());
- }
- }
- }
- GCPROTECT_END();
-} // CLRPrivTypeCacheReflectionOnlyWinRT::RaiseNamespaceResolveEvent
-
-//=====================================================================================================================
-// Implementation of QCall System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMetadata.nResolveNamespace
-// It's basically a PInvoke wrapper into Win8 API RoResolveNamespace
-//
-void
-QCALLTYPE
-CLRPrivTypeCacheReflectionOnlyWinRT::ResolveNamespace(
- LPCWSTR wszNamespace,
- LPCWSTR wszWindowsSdkPath,
- LPCWSTR * rgPackageGraphPaths,
- INT32 cPackageGraphPaths,
- QCall::ObjectHandleOnStack retFileNames)
-{
- QCALL_CONTRACT;
-
- _ASSERTE(wszNamespace != nullptr);
-
- BEGIN_QCALL;
-
- CoTaskMemHSTRINGArrayHolder hFileNames;
-
- if (!WinRTSupported())
- {
- IfFailThrow(COR_E_PLATFORMNOTSUPPORTED);
- }
-
- {
- CLRPrivBinderUtil::HSTRINGArrayHolder rgPackageGraph;
- rgPackageGraph.Allocate(cPackageGraphPaths);
-
- LPCWSTR wszNamespaceRoResolve = wszNamespace;
-
- for (INT32 i = 0; i < cPackageGraphPaths; i++)
- {
- _ASSERTE(rgPackageGraph.GetRawArray()[i] == nullptr);
- WinRtString hsPackageGraphPath;
- IfFailThrow(hsPackageGraphPath.Initialize(rgPackageGraphPaths[i]));
- hsPackageGraphPath.Detach(&rgPackageGraph.GetRawArray()[i]);
- }
-
- UINT32 cchNamespace, cchWindowsSdkPath;
- IfFailThrow(StringCchLength(wszNamespace, &cchNamespace));
- IfFailThrow(StringCchLength(wszWindowsSdkPath, &cchWindowsSdkPath));
-
- DWORD cFileNames = 0;
- HSTRING * rgFileNames = nullptr;
- HRESULT hr = RoResolveNamespace(
- WinRtStringRef(wszNamespace, cchNamespace),
- WinRtStringRef(wszWindowsSdkPath, cchWindowsSdkPath),
- rgPackageGraph.GetCount(),
- rgPackageGraph.GetRawArray(),
- &cFileNames,
- &rgFileNames,
- nullptr, // pcDirectNamespaceChildren
- nullptr); // rgDirectNamespaceChildren
- hFileNames.Init(rgFileNames, cFileNames);
-
- if (hr == HRESULT_FROM_WIN32(APPMODEL_ERROR_NO_PACKAGE))
- { // User tried to resolve 3rd party namespace without passing package graph - throw InvalidOperationException with custom message
- _ASSERTE(cPackageGraphPaths == 0);
- COMPlusThrow(kInvalidOperationException, IDS_EE_REFLECTIONONLY_WINRT_LOADFAILURE_THIRDPARTY);
- }
- IfFailThrow(hr);
- if (hr != S_OK)
- {
- IfFailThrow(E_UNEXPECTED);
- }
- }
-
- {
- GCX_COOP();
-
- PTRARRAYREF orFileNames = NULL;
- GCPROTECT_BEGIN(orFileNames);
-
- orFileNames = (PTRARRAYREF) AllocateObjectArray(hFileNames.GetCount(), g_pStringClass);
-
- for (DWORD i = 0; i < hFileNames.GetCount(); i++)
- {
- UINT32 cchFileName = 0;
-
- HSTRING hsFileName = hFileNames.GetAt(i);
- LPCWSTR wszFileName;
-
- if (hsFileName != nullptr)
- {
- wszFileName = WindowsGetStringRawBuffer(
- hsFileName,
- &cchFileName);
-
- STRINGREF str = StringObject::NewString(wszFileName);
- orFileNames->SetAt(i, str);
- }
- }
-
- retFileNames.Set(orFileNames);
-
- GCPROTECT_END();
- }
-
- END_QCALL;
-} // CLRPrivTypeCacheReflectionOnlyWinRT::ResolveNamespace
-
-//=====================================================================================================================
-
-#endif //FEATURE_REFLECTION_ONLY_LOAD
-#endif //!DACCESS_COMPILE
diff --git a/src/vm/clrprivtypecachereflectiononlywinrt.h b/src/vm/clrprivtypecachereflectiononlywinrt.h
deleted file mode 100644
index a605c3dc2e..0000000000
--- a/src/vm/clrprivtypecachereflectiononlywinrt.h
+++ /dev/null
@@ -1,58 +0,0 @@
-// 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.
-//
-
-//
-// Contains VM implementation of code:ICLRPrivTypeCacheReflectionOnlyWinRT for code:CLRPrivBinderReflectionOnlyWinRT binder.
-//
-//=====================================================================================================================
-
-#ifdef FEATURE_REFLECTION_ONLY_LOAD
-
-#pragma once
-
-#include "internalunknownimpl.h"
-#include "clrprivbinding.h"
-
-//=====================================================================================================================
-// Forward declarations
-class DomainAssembly;
-
-//=====================================================================================================================
-class CLRPrivTypeCacheReflectionOnlyWinRT :
- public IUnknownCommon<IUnknown>
-{
-public:
- //=============================================================================================
- // Class methods
-
- // S_OK - pAssembly contains type wszTypeName
- // S_FALSE - pAssembly does not contain type wszTypeName
- STDMETHOD(ContainsType)(
- ICLRPrivAssembly * pAssembly,
- LPCWSTR wszTypeName);
-
-#ifndef DACCESS_COMPILE
-
- // Raises user event NamespaceResolveEvent to get a list of files for this namespace.
- void RaiseNamespaceResolveEvent(
- LPCWSTR wszNamespace,
- DomainAssembly * pParentAssembly,
- CLRPrivBinderUtil::WStringListHolder * pFileNameList);
-
-#endif //!DACCESS_COMPILE
-
- // Implementation of QCall System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMetadata.nResolveNamespace
- // It's basically a PInvoke wrapper into Win8 API RoResolveNamespace
- static
- void QCALLTYPE ResolveNamespace(
- LPCWSTR wszNamespace,
- LPCWSTR wszWindowsSdkPath,
- LPCWSTR * rgPackageGraphPaths,
- INT32 cPackageGraphPaths,
- QCall::ObjectHandleOnStack retFileNames);
-
-}; // class CLRPrivTypeCaheReflectionOnlyWinRT
-
-#endif //FEATURE_REFLECTION_ONLY_LOAD
diff --git a/src/vm/cominterfacemarshaler.cpp b/src/vm/cominterfacemarshaler.cpp
index 0bd22a028b..58dd504d6a 100644
--- a/src/vm/cominterfacemarshaler.cpp
+++ b/src/vm/cominterfacemarshaler.cpp
@@ -20,7 +20,6 @@
#include "interopconverter.h"
#ifdef FEATURE_REMOTING
#include "remoting.h"
-#include "appdomainhelper.h"
#include "crossdomaincalls.h"
#endif
#include "notifyexternals.h"
diff --git a/src/vm/commethodrental.cpp b/src/vm/commethodrental.cpp
deleted file mode 100644
index 0a5c011270..0000000000
--- a/src/vm/commethodrental.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-////////////////////////////////////////////////////////////////////////////////
-
-
-
-#include "common.h"
-#include "commethodrental.h"
-#include "corerror.h"
-
-#ifdef FEATURE_METHOD_RENTAL
-// SwapMethodBody
-// This method will take the rgMethod as the new function body for a given method.
-//
-
-void QCALLTYPE COMMethodRental::SwapMethodBody(EnregisteredTypeHandle cls, INT32 tkMethod, LPVOID rgMethod, INT32 iSize, INT32 flags, QCall::StackCrawlMarkHandle stackMark)
-{
- QCALL_CONTRACT;
-
- BEGIN_QCALL;
-
- BYTE *pNewCode = NULL;
- MethodDesc *pMethodDesc;
- ReflectionModule *module;
- ICeeGen* pGen;
- ULONG methodRVA;
- HRESULT hr;
-
- if ( cls == NULL)
- {
- COMPlusThrowArgumentNull(W("cls"));
- }
-
- MethodTable *pMethodTable = TypeHandle::FromPtr(cls).GetMethodTable();
- PREFIX_ASSUME(pMethodTable != NULL);
- module = (ReflectionModule *) pMethodTable->GetModule();
- pGen = module->GetCeeGen();
-
- Assembly* caller = SystemDomain::GetCallersAssembly( stackMark );
-
- _ASSERTE( caller != NULL && "Unable to get calling assembly" );
- _ASSERTE( module->GetCreatingAssembly() != NULL && "ReflectionModule must have a creating assembly to be used with method rental" );
-
- if (module->GetCreatingAssembly() != caller)
- {
- COMPlusThrow(kSecurityException);
- }
-
- // Find the methoddesc given the method token
- pMethodDesc = MemberLoader::FindMethod(pMethodTable, tkMethod);
- if (pMethodDesc == NULL)
- {
- COMPlusThrowArgumentException(W("methodtoken"), NULL);
- }
- if (pMethodDesc->GetMethodTable() != pMethodTable || pMethodDesc->GetNumGenericClassArgs() != 0 || pMethodDesc->GetNumGenericMethodArgs() != 0)
- {
- COMPlusThrowArgumentException(W("methodtoken"), W("Argument_TypeDoesNotContainMethod"));
- }
- hr = pGen->AllocateMethodBuffer(iSize, &pNewCode, &methodRVA);
- if (FAILED(hr))
- COMPlusThrowHR(hr);
-
- if (pNewCode == NULL)
- {
- COMPlusThrowOM();
- }
-
- // <TODO>
- // if method desc is pointing to the post-jitted native code block,
- // we want to recycle this code block
-
- // @todo: SEH handling. Will we need to support a method that can throw exception
- // If not, add an assertion to make sure that there is no SEH contains in the method header.
-
- // @todo: figure out a way not to copy the code block.
-
- // @todo: add link time security check. This function can be executed only if fully trusted.</TODO>
-
- // copy the new function body to the buffer
- memcpy(pNewCode, (void *) rgMethod, iSize);
-
- // add the starting address of the il blob to the il blob hash table
- // we need to find this information from out of process for debugger inspection
- // APIs so we have to store this information where we can get it later
- module->SetDynamicIL(mdToken(tkMethod), TADDR(pNewCode), FALSE);
-
- // Reset the methoddesc back to unjited state
- pMethodDesc->Reset();
-
- if (flags)
- {
- // JITImmediate
-#if _DEBUG
- COR_ILMETHOD* ilHeader = pMethodDesc->GetILHeader(TRUE);
- _ASSERTE(((BYTE *)ilHeader) == pNewCode);
-#endif
- COR_ILMETHOD_DECODER header((COR_ILMETHOD *)pNewCode, pMethodDesc->GetMDImport(), NULL);
-
- // minimum validation on the correctness of method header
- if (header.GetCode() == NULL)
- COMPlusThrowHR(VLDTR_E_MD_BADHEADER);
-
-#ifdef FEATURE_INTERPRETER
- pMethodDesc->MakeJitWorker(&header, CORJIT_FLAGS(CORJIT_FLAGS::CORJIT_FLAG_MAKEFINALCODE));
-#else // !FEATURE_INTERPRETER
- pMethodDesc->MakeJitWorker(&header, CORJIT_FLAGS());
-#endif // !FEATURE_INTERPRETER
- }
-
- // add feature::
- // If SQL is generating class with inheritance hierarchy, we may need to
- // check the whole vtable to find duplicate entries.
-
- END_QCALL;
-
-} // COMMethodRental::SwapMethodBody
-
-
-#endif // FEATURE_METHOD_RENTAL
diff --git a/src/vm/commethodrental.h b/src/vm/commethodrental.h
deleted file mode 100644
index 0523af274e..0000000000
--- a/src/vm/commethodrental.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// 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.
-////////////////////////////////////////////////////////////////////////////////
-
-
-
-#ifndef _COMMETHODRENTAL_H_
-#define _COMMETHODRENTAL_H_
-
-#include "excep.h"
-#include "fcall.h"
-
-#ifdef FEATURE_METHOD_RENTAL
-// COMMethodRental
-// This class implements SwapMethodBody for our MethodRenting story
-class COMMethodRental
-{
-public:
-
- // COMMethodRental.SwapMethodBody -- this function will swap an existing method body with
- // a new method body
- //
- static
- void QCALLTYPE SwapMethodBody(EnregisteredTypeHandle cls, INT32 tkMethod, LPVOID rgMethod, INT32 iSize, INT32 flags, QCall::StackCrawlMarkHandle stackMark);
-};
-#endif // FEATURE_METHOD_RENTAL
-
-#endif //_COMMETHODRENTAL_H_
diff --git a/src/vm/comsynchronizable.cpp b/src/vm/comsynchronizable.cpp
index e042c8effe..3a395235e6 100644
--- a/src/vm/comsynchronizable.cpp
+++ b/src/vm/comsynchronizable.cpp
@@ -29,7 +29,6 @@
#endif
#include "eeconfig.h"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#include "objectclone.h"
#else
#include "callhelpers.h"
diff --git a/src/vm/constrainedexecutionregion.cpp b/src/vm/constrainedexecutionregion.cpp
deleted file mode 100644
index 0745bd5e1b..0000000000
--- a/src/vm/constrainedexecutionregion.cpp
+++ /dev/null
@@ -1,2264 +0,0 @@
-// 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.
-//
-// Methods to support the implementation of Constrained Execution Regions (CERs). This includes logic to walk the IL of methods to
-// determine the statically determinable call graph and prepare each submethod (jit, prepopulate generic dictionaries etc.,
-// everything needed to ensure that the runtime won't generate implicit failure points during the execution of said call graph).
-//
-
-//
-
-
-#include "common.h"
-#include <openum.h>
-#include <mdaassistants.h>
-#include <ecmakey.h>
-#include <typestring.h>
-#include <jitinterface.h>
-
-#ifdef FEATURE_PREJIT
-#include <compile.h>
-#endif
-
-
-// Internal debugging support. Would be nice to use the common logging code but we've run out of unique facility codes and the debug
-// info we spew out is of interest to a limited audience anyhow.
-#ifdef _DEBUG
-
-#define CER_NOISY_PREPARE 0x00000001
-#define CER_NOISY_RESTORE 0x00000002
-#define CER_NOISY_CONTRACTS 0x00000004
-#define CER_NOISY_WARNINGS 0x00000008
-#define CER_NOISY_NGEN_STATS 0x00000010
-
-DWORD g_dwCerLogActions = 0xffffffff;
-DWORD GetCerLoggingOptions()
-{
- WRAPPER_NO_CONTRACT;
- if (g_dwCerLogActions != 0xffffffff)
- return g_dwCerLogActions;
- return g_dwCerLogActions = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CerLogging);
-}
-
-#define CER_LOG(_reason, _msg) do { if (GetCerLoggingOptions() & CER_NOISY_##_reason) printf _msg; } while (false)
-#else
-#define CER_LOG(_reason, _msg)
-#endif
-
-
-// Enumeration used to determine the number of inline data bytes included inside a given IL instruction (except for the case of a
-// SWITCH instruction, where a dynamic calculation is required).
-enum
-{
- ArgBytes_InlineNone = 0, // no inline args
- ArgBytes_InlineVar = 2, // local variable (U2 (U1 if Short on))
- ArgBytes_InlineI = 4, // an signed integer (I4 (I1 if Short on))
- ArgBytes_InlineR = 8, // a real number (R8 (R4 if Short on))
- ArgBytes_InlineBrTarget = 4, // branch target (I4 (I1 if Short on))
- ArgBytes_InlineI8 = 8,
- ArgBytes_InlineMethod = 4, // method token (U4)
- ArgBytes_InlineField = 4, // field token (U4)
- ArgBytes_InlineType = 4, // type token (U4)
- ArgBytes_InlineString = 4, // string TOKEN (U4)
- ArgBytes_InlineSig = 4, // signature tok (U4)
- ArgBytes_InlineRVA = 4, // ldptr token (U4)
- ArgBytes_InlineTok = 4, // a meta-data token of unknown type (U4)
- ArgBytes_InlineSwitch = 4, // count (U4), pcrel1 (U4) .... pcrelN (U4)
- ArgBytes_ShortInlineVar = 1,
- ArgBytes_ShortInlineI = 1,
- ArgBytes_ShortInlineR = 4,
- ArgBytes_ShortInlineBrTarget = 1
-};
-
-// Build an array of argument byte counts as described above by extracting the 'args' field of each entry in opcode.def.
-#define OPDEF(c, s, pop, push, args, type, l, s1, s2, ctrl) ArgBytes_##args,
-const BYTE g_rOpArgs[] = {
-#include <opcode.def>
-};
-#undef OPDEF
-
-
-// Global cache of methods and their reliability contract state.
-PtrHashCache *g_pMethodContractCache = NULL;
-
-
-// Private method forward references.
-bool IsPcrReference(Module *pModule, mdToken tkMethod);
-MethodContext *TokenToMethodDesc(Module *pModule, mdToken tokMethod, SigTypeContext *pTypeContext);
-TypeHandle GetTypeFromMemberDefOrRefOrSpecThrowing(Module *pModule,
- mdToken tokMethod,
- SigTypeContext *pTypeContext);
-
-bool MethodCallGraphPreparer::ShouldGatherExplicitCERCallInfo()
-{
- LIMITED_METHOD_CONTRACT;
-
- // If we're partially processing a method body (at the top of the call graph), we need to fetch exception handling
- // information to determine possible ranges of interesting IL (potentially each finally and catch clause).
- //
- // And if we are probing for stack overflow, we need to know if the explicit CER region contains any calls out, in
- // which case we want to probe in the call to PrepareConstrainedExecutionRegions. This will ensure that we don't
- // take an SO in boundary code and not be able to call the CER. When stack probing is disabled, we rip the process
- // if we take an SO anywhere but managed, or if we take an SO with a CER on the stack. For NGEN images, we need
- // to always probe because stack probing may be enabled in the runtime, but if we haven't probed in the NGEN image
- // then we could take an SO in boundary code and not be able to crawl the stack to know that we've skipped a CER and
- // need to tear the process.
- //
- // Additionally, if the MDA for illegal PrepareConstrainedRegions call positioning is enabled we gather this information for
- // all methods in the graph.
- return !m_fEntireMethod
-#ifdef MDA_SUPPORTED
- || MDA_GET_ASSISTANT(IllegalPrepareConstrainedRegion)
-#endif
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- || m_fNgen
-#endif
- || g_pConfig->ProbeForStackOverflow();
-}
-
-MethodCallGraphPreparer::MethodCallGraphPreparer(MethodDesc *pRootMD, SigTypeContext *pRootTypeContext, bool fEntireMethod, bool fExactTypeContext, bool fIgnoreVirtualCERCallMDA)
-{
- CONTRACTL {
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(pRootMD));
- PRECONDITION(CheckPointer(pRootTypeContext));
- } CONTRACTL_END;
-
- // Canonicalize value type unboxing stubs into their underlying method desc.
- if (pRootMD->IsUnboxingStub())
- pRootMD = pRootMD->GetWrappedMethodDesc();
-
- m_pRootMD = pRootMD;
- m_pRootTypeContext = pRootTypeContext;
- m_fEntireMethod = fEntireMethod;
- m_fExactTypeContext = fExactTypeContext;
- m_fIgnoreVirtualCERCallMDA = fIgnoreVirtualCERCallMDA;
-
- m_pEHClauses = NULL;
- m_cEHClauses = 0;
- m_pCerPrepInfo = NULL;
- m_pMethodDecoder = NULL;
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- m_fNgen = false;
-#endif
-
- m_pThread = GetThread();
- m_fPartialPreparation = false;
- m_fMethodHasCallsWithinExplicitCer = false;
-}
-
-// Walk the call graph of the method given by pRootMD (and type context in pRootTypeContext which provides instantiation information
-// for generic methods/classes).
-//
-// If fEntireMethod is true then the entire body of pRootMD is scanned for callsites, otherwise we assume that one or more CER
-// exception handlers exist in the method and only the finally and catch blocks of such handlers are scanned for graph roots.
-//
-// Each method we come across in the call graph (excluding late bound invocation destinations precipitated by virtual or interface
-// calls) is jitted and has any generic dictionary information we can determine at jit time prepopulated. This includes implicit
-// cctor invocations. If this method is called at ngen time we will attach extra fixup information to the affected method to ensure
-// that fixing up the root method of the graph will cause all methods in the graph to be fixed up at that point also.
-//
-// Some generic dictionary entries may not be prepopulated if unbound type variables exist at the root of the call tree. Such cases
-// will be ignored (as for the virtual/interface dispatch case we assume the caller will use an out-of-band mechanism to pre-prepare
-// these entries explicitly).
-bool MethodCallGraphPreparer::Run()
-{
- STANDARD_VM_CONTRACT;
-
- // Avoid recursion while jitting methods for another preparation.
- if (!m_pThread->GetCerPreparationState()->CanPreparationProceed(m_pRootMD, m_pRootTypeContext))
- return TRUE; // Assume the worst
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- // Determine if we're being called in order to provide an ngen image. This impacts whether we actually prepare methods and the
- // type of tracking data we produce. Ideally we'd call GetAppDomain()->IsCompilationDomain() here, but we have to deal with the
- // problem of ngen'ing mscorlib. Mscorlib code is always shared and some of it is run before the compilation domain is fully
- // created (so we'd end up with some methods being prepared without saving any ngen metadata to that effect). So instead we
- // check to see whether this is an ngen process. This will catch those first few mscorlib methods.
- m_fNgen = IsCompilationProcess() != FALSE;
-
- // We keep a hash table of CERs we've processed on the module object of the root method. See if any work has been done on this
- // CER before. We store different data for ngen and non-ngen cases.
- if (m_fNgen) {
-
- // Pretty simple in ngen case -- if we've stored a context record for this method at all then we've already processed it.
- if (m_pRootMD->GetModule()->IsNgenCerRootMethod(m_pRootMD)) {
- m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD);
-
- // We always store CerPrepInfo if the method has calls, so if we haven't stored
- // anything then we know it doesn't have any calls
- return (m_pCerPrepInfo && m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer);
- }
- } else
-#endif
- {
- // The non-ngen case (normal jit, call to PrepareMethod etc).
- m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD);
- if (m_pCerPrepInfo) {
-
- // Check for the "everything's done" case.
- if (m_pCerPrepInfo->m_fFullyPrepared)
- return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer;
-
- // Check for the "we can't do anything" case (see below for descriptions of that).
- if (m_pCerPrepInfo->m_fRequiresInstantiation && !m_fExactTypeContext)
- return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer;
-
- // Check for the "need to prepare per-instantiation, but we've already done this one" case.
- if (m_pCerPrepInfo->m_fRequiresInstantiation) {
- HashDatum sDatum;
- if (m_pCerPrepInfo->m_sIsInitAtInstHash.GetValue(m_pRootTypeContext, &sDatum))
- return m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer;
- }
- }
- }
-
- // We can't deal with generic methods or methods on generic types that may have some representative type parameters in their
- // instantiation (i.e. some reference types indicated by Object rather than the exact type). The jit will tend to pass us these
- // since it shares code between instantiations over reference types. We can't prepare methods like these completely -- even
- // though we can jit all the method bodies the code might require generic dictionary information at the class or method level
- // that is populated at runtime and can introduce failure points. So we reject such methods immediately (they will need to be
- // prepared at non-jit time by an explicit call to PrepareMethod with a fully instantiated method).
- //
- // In the case where the type context is marked as suspect (m_fExactTypeContext == false) there are a number of possibilites for
- // bad methods the jit will pass us:
- // 1) We're passed a MethodDesc that shared between instantiations (bogus because exact method descs are never shared).
- // 2) We're passed a MethodDesc that's an instantiating stub (bogus because non-shared methods don't need this).
- // 3) We're passed a MethodDesc that has generic variables in its instantiations (I've seen this during ngen).
- //
- // Technically we could do a little better than this -- we could determine whether any of the representative type parameters are
- // actually used within the CER call graph itself. But this would require us to understand the IL at a much deeper level (i.e.
- // parse every instruction that could take a type or member spec and pull apart those specs to see if a type var is used). Plus
- // we couldn't make this determination until we've prepared the entire region and the result is rather brittle from the code
- // author's point of view (i.e. we might prepare a CER automatically one day but stop doing after some relatively subtle changes
- // in the source code).
- m_fPartialPreparation = m_pRootMD->IsSharedByGenericInstantiations() || m_pRootMD->IsInstantiatingStub() || m_pRootMD->ContainsGenericVariables();
- if (!m_fExactTypeContext && m_fPartialPreparation) {
-#ifdef MDA_SUPPORTED
- MDA_TRIGGER_ASSISTANT(OpenGenericCERCall, ReportViolation(m_pRootMD));
-#endif
- CER_LOG(WARNINGS, ("CER: %s has open type parameters and can't be pre-prepared\n", m_pRootMD->m_pszDebugMethodName));
-
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- if (!m_fNgen)
-#endif
- {
- // Set up a prep info structure for this method if it's not there already (the create method takes care of races).
- if (m_pCerPrepInfo == NULL)
- m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD);
-
- // We may be racing to update the structure at this point but that's OK since the flag we're setting is never cleared once
- // it's set and is always guaranteed to be set before we rely on its value (setting it here is just a performance thing,
- // letting us early-out on multiple attempts to prepare this CER from the jit).
- m_pCerPrepInfo->m_fRequiresInstantiation = true;
- }
-
- if (! g_pConfig->ProbeForStackOverflow())
- {
- return FALSE;
- }
- m_pCerPrepInfo = m_pRootMD->GetModule()->GetCerPrepInfo(m_pRootMD);
-
- // We always store CerPrepInfo if the method has calls, so if we haven't stored
- // anything then we know it doesn't have any calls
- return (m_pCerPrepInfo && m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer);
-
- }
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- // If we've been called for a shared generic root method and the exact instantiation (this can happen because ngen lets code
- // execute under some circumstances) we don't currently support saving this information in the ngen image (we don't have a
- // format for the instantiation info). We just ignore the preparation in this case (it will be prepared at runtime).
- if (m_fNgen && m_fPartialPreparation)
- return TRUE;
-#endif
-
- // Prevent inlining of the root method (otherwise it's hard to tell where ThreadAbort exceptions should be delayed). Note that
- // MethodDesc::SetNotInline is thread safe.
- m_pRootMD->SetNotInline(true);
-
- // Remember the checkpoint for all of our allocations. Keep it in a holder so they'll be unwound if we throw an exception past
- // here.
- CheckPointHolder sCheckpoint(m_pThread->m_MarshalAlloc.GetCheckpoint());
-
- // Push the current method as the one and only method to process so far.
- m_sLeftToProcess.Push(MethodContext::PerThreadAllocate(m_pRootMD, m_pRootTypeContext));
-
- MethodContext *pContext = NULL; // The current MethodContext we're processing
-
- // Iterate until we run out of methods to process.
- while ((pContext = m_sLeftToProcess.Pop()) != NULL) {
-
- // Restore the MD if necessary. In particular, if this is an instantiating stub and the wrapped MethodDesc could
- // not be hard bound, then we'll need to restore that pointer before getting it.
- pContext->m_pMethodDesc->CheckRestore();
-
- // Transfer the method to the already seen stack immediately (we don't want to loop infinitely in the case of method
- // recursion).
- m_sAlreadySeen.Push(pContext);
-
- // Check if the enclosing class requires a static class constructor to be run. If so, we need to prepare that method as
- // though it were any other call.
- if (pContext->m_pMethodDesc->GetMethodTable()->HasClassConstructor()) {
-
- // Decode target method into MethodDesc and new SigTypeContext.
- // The type context is easy to derive here : .cctors never have any method type parameters and the class instantiations
- // are those of the method we're currently parsing, so can be simply copied down.
- MethodDesc *pCctor = pContext->m_pMethodDesc->GetCanonicalMethodTable()->GetClassConstructor();
- SigTypeContext sCctorTypeContext(pCctor, pContext->m_sTypeContext.m_classInst, Instantiation());
- MethodContext *pCctorContext = MethodContext::PerThreadAllocate(pCctor, &sCctorTypeContext);
-
- // Only process this cctor the first time we find it in this call graph.
- if (!m_sAlreadySeen.IsInStack(pCctorContext) && !m_sLeftToProcess.IsInStack(pCctorContext))
- m_sLeftToProcess.Push(pCctorContext);
- }
-
- // Skip further processing if this method doesn't have an IL body (note that we assume the method we entered with was IL, so
- // we don't need to bother with partial method processing).
- if (!pContext->m_pMethodDesc->IsIL()) {
- _ASSERTE(m_fEntireMethod);
- continue;
- }
-
- // Locate the IL body of the current method. May have to account for the fact that the current method desc is an
- // instantiating stub and burrow down for the real method desc.
- MethodDesc *pRealMethod = pContext->m_pMethodDesc;
- if (pRealMethod->IsInstantiatingStub()) {
- _ASSERTE(!pRealMethod->ContainsGenericVariables());
- pRealMethod = pRealMethod->GetWrappedMethodDesc();
- }
-
- COR_ILMETHOD* pILHeader = pRealMethod->GetILHeader();
-
- // Skip malformed methods. (We should always have method with IL for well-formed images here.)
- if (pILHeader == NULL) {
- continue;
- }
-
- COR_ILMETHOD_DECODER method(pILHeader);
- m_pMethodDecoder = &method;
-
- // We want to reget the EH clauses for the current method so that we can scan its handlers
- GetEHClauses();
-
- LookForInterestingCallsites(pContext);
-
- // Whatever we've done, we're definitely not processing the top-level method at this point (so we'll be processing full
- // method bodies from now on).
- m_fEntireMethod = true;
- }
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- if (!m_fNgen)
-#endif
- {
- // Set up a prep info structure for this method if it's not there already (the create method takes care of races).
- // This needs to happen before we start JITing the methods as part of preparation. The JIT needs to know
- // about the CER root in CEEInfo::canTailCall.
- if (m_pCerPrepInfo == NULL)
- m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD);
- }
-
- // Prevent infinite recursion by recording on the thread which roots we're currently preparing.
- ThreadPreparingCerHolder sCerHolder(this);
-
- // Once we get here we've run out of methods to process and have recorded each method we visited in the m_sAlreadySeen stack. Now
- // it's time to prepare each of these methods (jit, prepopulate generic dictionaries etc.).
- PrepareMethods();
-
- return RecordResults();
-}
-
-
-// Determine whether a CER preparation for the given root method (with type context for generic instantiation
-// if necessary) can go ahead given any current preparation already being performed on the current thread.
-BOOL MethodCallGraphPreparer::CanPreparationProceed(MethodDesc * pMD, SigTypeContext * pTypeContext)
-{
- WRAPPER_NO_CONTRACT;
- MethodCallGraphPreparer * pCurrPrep = this;
- while (pCurrPrep)
- {
- // Is the prepartion request for the root method of the current preparer?
- if (pMD == pCurrPrep->m_pRootMD && SigTypeContext::Equal(pTypeContext, pCurrPrep->m_pRootTypeContext))
- {
- // We're already preparing this root, return FALSE to turn the request into a no-op and avoid
- // infinite recursion.
- return FALSE;
- }
-
- pCurrPrep = pCurrPrep->m_pNext;
- }
-
- // We found no previous preparation for the same root, so the request can proceed.
- return TRUE;
-}
-
-// Methods that push and pop thread local state used to determine if a re-entrant preparation request should
-// complete immediately as a no-op (because it would lead to an infinite recursion) or should proceed
-// recursively.
-
-//static
-void MethodCallGraphPreparer::BeginPrepareCerForHolder(MethodCallGraphPreparer * pPrepState)
-{
- LIMITED_METHOD_CONTRACT;
-
- Thread * pThread = pPrepState->m_pThread;
- pPrepState->m_pNext = pThread->GetCerPreparationState();
- pThread->SetCerPreparationState(pPrepState);
-}
-
-//static
-void MethodCallGraphPreparer::EndPrepareCerForHolder(MethodCallGraphPreparer * pPrepState)
-{
- LIMITED_METHOD_CONTRACT;
-
- Thread * pThread = pPrepState->m_pThread;
- _ASSERTE(pThread && pThread->GetCerPreparationState() == pPrepState);
- pThread->SetCerPreparationState(pPrepState->m_pNext);
-}
-
-
-void MethodCallGraphPreparer::GetEHClauses()
-{
- STANDARD_VM_CONTRACT;
-
- if (! ShouldGatherExplicitCERCallInfo())
- {
- return;
- }
-
- m_cEHClauses = 0;
- m_pEHClauses = NULL; // we use the StackingAllocator, so don't have to delete the previous storage
-
- COR_ILMETHOD_SECT_EH const * pEH = m_pMethodDecoder->EH;
- if (pEH == NULL ||pEH->EHCount() == 0)
- {
- return;
- }
-
- m_cEHClauses = pEH->EHCount();
- m_pEHClauses = new (&m_pThread->m_MarshalAlloc) EHClauseRange[m_cEHClauses];
-
- for (DWORD i = 0; i < m_cEHClauses; i++)
- {
- COR_ILMETHOD_SECT_EH_CLAUSE_FAT sEHClauseBuffer;
- const COR_ILMETHOD_SECT_EH_CLAUSE_FAT *pEHClause;
-
- pEHClause = (COR_ILMETHOD_SECT_EH_CLAUSE_FAT*)pEH->EHClause(i, &sEHClauseBuffer);
-
- // The algorithm below assumes handlers are located after their associated try blocks. If this turns out to be a
- // false assumption we need to move to a two pass technique (or defer callsite handling in some other fashion until
- // we've scanned the IL for all calls to our preparation marker method).
- if (!(pEHClause->GetTryOffset() < pEHClause->GetHandlerOffset()))
- {
- COMPlusThrowHR(COR_E_NOTSUPPORTED, IDS_EE_NOTSUPPORTED_CATCHBEFORETRY);
- }
-
- m_pEHClauses[i].m_dwTryOffset = pEHClause->GetTryOffset();
- m_pEHClauses[i].m_dwHandlerOffset = pEHClause->GetHandlerOffset();
- m_pEHClauses[i].m_dwHandlerLength = pEHClause->GetHandlerLength();
- m_pEHClauses[i].m_fActive = false;
-
- //printf("Try: %u Handler: %u -> %u\n", pEHClause->GetTryOffset(), pEHClause->GetHandlerOffset(), pEHClause->GetHandlerOffset() + pEHClause->GetHandlerLength() - 1);
- }
-
-}
-
-void MethodCallGraphPreparer::MarkEHClauseActivatedByCERCall(MethodContext *pContext, BYTE *pbIL, DWORD cbIL)
-{
- STANDARD_VM_CONTRACT;
-
- DWORD dwOffset = (DWORD)(SIZE_T)((pbIL + ArgBytes_InlineTok) - (BYTE*)m_pMethodDecoder->Code);
-
- // Additionally we need to cope with the fact that VB and C# (for debug builds) can generate NOP instructions
- // between the PCR call and the beginning of the try block. So we're potentially looking for the
- // intersection of the try with a range of instructions. Count the number of consecutive NOP instructions
- // which follow the call.
- DWORD dwLength = 0;
- BYTE *pbTmpIL = pbIL + ArgBytes_InlineTok;
- while (pbTmpIL < (pbIL + cbIL) && *pbTmpIL++ == CEE_NOP)
- {
- dwLength++;
- }
-
- bool fMatched = false;
- for (DWORD i = 0; i < m_cEHClauses; i++)
- {
- if (m_pEHClauses[i].m_dwTryOffset >= dwOffset &&
- m_pEHClauses[i].m_dwTryOffset <= (dwOffset + dwLength))
- {
- fMatched = true;
- m_pEHClauses[i].m_fActive = true;
- }
- }
- if (!fMatched)
- {
-#if defined(_DEBUG) || defined(MDA_SUPPORTED)
- DWORD dwPCROffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code);
-#endif // defined(_DEBUG) || defined(MDA_SUPPORTED)
-#ifdef MDA_SUPPORTED
- MDA_TRIGGER_ASSISTANT(IllegalPrepareConstrainedRegion, ReportViolation(pContext->m_pMethodDesc, dwPCROffset));
-#endif
- CER_LOG(WARNINGS, ("CER: %s: Invalid call to PrepareConstrainedRegions() at IL +%04X\n",
- pContext->m_pMethodDesc->m_pszDebugMethodName, dwPCROffset));
- }
-}
-
-bool MethodCallGraphPreparer::CheckIfCallsiteWithinCER(DWORD dwOffset)
-{
- STANDARD_VM_CONTRACT;
-
- //printf("Found: %s at %u\n", pCallTarget->m_pMethodDesc->m_pszDebugMethodName, dwOffset);
-
- // Search all the EH regions we know about.
- for (DWORD i = 0; i < m_cEHClauses; i++)
- {
- bool fCallsiteWithinCER = false;
- if (! m_pEHClauses[i].m_fActive)
- {
- // clause not CER-active so skip it
- continue;
- }
- if (dwOffset >= (m_pEHClauses[i].m_dwHandlerOffset + m_pEHClauses[i].m_dwHandlerLength))
- {
- // offset beyond clause, so skip it
- continue;
- }
- if (dwOffset >= m_pEHClauses[i].m_dwTryOffset)
- {
- // For stack probing optimization, we care if either the try or the handler has a call. If neither
- // does, then we can optimize the probe out.
- m_fMethodHasCallsWithinExplicitCer = true;
- if (dwOffset >= m_pEHClauses[i].m_dwHandlerOffset)
- {
- fCallsiteWithinCER = true;
- }
- }
- // Only terminate if we got a positive result (i.e. the calliste is within a hardened clause).
- // We can't terminate early in the negative case because the callsite could be nested
- // in another EH region which may be hardened.
- if (fCallsiteWithinCER == true)
- {
- return true;
- }
- }
-
- return false;
-}
-
-
-// Iterate through the body of the method looking for interesting call sites.
-void MethodCallGraphPreparer::LookForInterestingCallsites(MethodContext *pContext)
-{
- STANDARD_VM_CONTRACT;
-
- BYTE *pbIL = (BYTE*)m_pMethodDecoder->Code;
- DWORD cbIL = m_pMethodDecoder->GetCodeSize();
-
- while (cbIL) {
-
- // Read the IL op.
- DWORD dwOp = *pbIL++; cbIL--;
-
- // Handle prefix codes (only CEE_PREFIX1 is legal so far).
- if (dwOp == CEE_PREFIX1) {
- if (!cbIL)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- dwOp = 256 + *pbIL++; cbIL--;
- } else if (dwOp >= CEE_PREFIX7)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
- // We're interested in NEWOBJ, JMP, CALL and CALLVIRT (can't trace through CALLI). We include CALLVIRT becase C#
- // routinely calls non-virtual instance methods this way in order to get this pointer null checking. We prepare NEWOBJ
- // because that covers the corner case of value types which can be constructed with no failure path.
- if (dwOp == CEE_CALL || dwOp == CEE_CALLVIRT || dwOp == CEE_NEWOBJ || dwOp == CEE_JMP) {
-
- if (cbIL < sizeof(DWORD))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
- // Decode target method into MethodDesc and new SigTypeContext.
- mdToken tkCallTarget = (mdToken)GET_UNALIGNED_VAL32(pbIL);
- MethodContext *pCallTarget = TokenToMethodDesc(pContext->m_pMethodDesc->GetModule(), tkCallTarget, &pContext->m_sTypeContext);
-
- // Check whether we've found a call to our own preparation marker method.
- if (pCallTarget->m_pMethodDesc == g_pPrepareConstrainedRegionsMethod) {
-
- if (ShouldGatherExplicitCERCallInfo()) {
- // If we're preparing a partial method these callsites are significant (we mark which EH clauses are now
- // 'activated' by proximity to this marker method call). Look for EH regions that are 'activated' by the call to
- // PrepareConstrainedRegions by comparing the IL offset of the start of the try to the offset immediately after
- // the callsite (remember to account for the rest of the CALLVIRT instruction we haven't skipped yet).
- MarkEHClauseActivatedByCERCall(pContext, pbIL, cbIL);
- }
-
- // Record the fact that we found a method in the CER which is the root of a sub-CER. This is important since the
- // rude thread abort protection algorithm relies on root CER methods being marked as such.
- pContext->m_fRoot = true;
- }
-
- // Determine if this was really a virtual call (we discard those since we can't reliably determine the call target).
- bool fNonVirtualCall = dwOp == CEE_CALL || !pCallTarget->m_pMethodDesc->IsVirtual() || pCallTarget->m_pMethodDesc->IsFinal();
-
- // When we're only processing qualified catch / finally handlers then we need to compute whether this call site
- // lands in one of them. The callsite is always within a cer if we are processing the full method.
- // If we have stackoverflow probing on, also call to determine if the CER try or finally makes any calls
- bool fCallsiteWithinCerInThisFunction = false;
- if (!m_fEntireMethod || g_pConfig->ProbeForStackOverflow()) {
- DWORD dwOffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code);
- fCallsiteWithinCerInThisFunction = CheckIfCallsiteWithinCER(dwOffset);
- }
- bool fCallsiteWithinCer = m_fEntireMethod || fCallsiteWithinCerInThisFunction;
-
- // Check for the presence of some sort of reliability contract (on the method, class or assembly). This will
- // determine whether we log an error, ignore the method or treat it as part of the prepared call graph.
- ReliabilityContractLevel eLevel = RCL_UNKNOWN;
- if (fNonVirtualCall && // Ignore virtual calls
- fCallsiteWithinCer && // And calls outside CERs
- !m_sAlreadySeen.IsInStack(pCallTarget) && // And methods we've seen before
- !m_sLeftToProcess.IsInStack(pCallTarget) && // And methods we've already queued for processing
- (eLevel = CheckForReliabilityContract(pCallTarget->m_pMethodDesc)) >= RCL_PREPARE_CONTRACT) // And unreliable methods
- m_sLeftToProcess.Push(pCallTarget); // Otherwise add this method to the list to process
- else if (fCallsiteWithinCer) {
-#if defined(_DEBUG) || defined(MDA_SUPPORTED)
- DWORD dwOffset = (DWORD)(SIZE_T)((pbIL - 1) - (BYTE*)m_pMethodDecoder->Code);
-#endif // defined(_DEBUG) || defined(MDA_SUPPORTED)
- if (eLevel == RCL_NO_CONTRACT) {
- // Method was sufficiently unreliable for us to warn interested users that something may be amiss. Do this
- // through MDA logging.
-#ifdef MDA_SUPPORTED
- MDA_TRIGGER_ASSISTANT(InvalidCERCall, ReportViolation(pContext->m_pMethodDesc, pCallTarget->m_pMethodDesc, dwOffset));
-#endif
- CER_LOG(WARNINGS, ("CER: %s +%04X -> %s: weak contract\n", pContext->ToString(), dwOffset, pCallTarget->ToString()));
- } else if (!fNonVirtualCall && !m_fIgnoreVirtualCERCallMDA) {
- // Warn users about virtual calls in CERs (so they can go back and consider which target methods need to be
- // prepared ahead of time).
-#ifdef MDA_SUPPORTED
- MDA_TRIGGER_ASSISTANT(VirtualCERCall, ReportViolation(pContext->m_pMethodDesc, pCallTarget->m_pMethodDesc, dwOffset));
-#endif
- CER_LOG(WARNINGS, ("CER: %s +%04X -> %s: virtual call\n", pContext->ToString(), dwOffset, pCallTarget->ToString()));
- }
- }
- }
-
- // Skip the rest of the current IL instruction. Look up the table built statically at the top of this module for most
- // instructions, but CEE_SWITCH requires special processing (the length of that instruction depends on a count DWORD
- // embedded right after the opcode).
- if (dwOp == CEE_SWITCH) {
- DWORD dwTargets = GET_UNALIGNED_VAL32(pbIL);
- if (dwTargets >= (MAXDWORD / sizeof(DWORD)))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT); // multiplication below would overflow
- DWORD cbSwitch = (1 + dwTargets) * sizeof(DWORD);
- if (cbIL < cbSwitch)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- pbIL += cbSwitch;
- cbIL -= cbSwitch;
- } else {
- if (dwOp >= _countof(g_rOpArgs))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- DWORD cbOp = g_rOpArgs[dwOp];
- if (cbIL < cbOp)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- pbIL += cbOp;
- cbIL -= cbOp;
- }
-
- } // End of IL parsing loop
-}
-
-void MethodCallGraphPreparer::PrepareMethods()
-{
- STANDARD_VM_CONTRACT;
-
-#ifdef _DEBUG
- DWORD dwCount = 0;
- if (GetCerLoggingOptions())
- {
- CER_LOG(PREPARE, ("---------------------------------------------------------------\n"));
- SString ssMethod;
- TypeString::AppendMethodInternal(ssMethod, m_pRootMD, TypeString::FormatNamespace | TypeString::FormatStubInfo);
- CER_LOG(PREPARE, ("Preparing from %S\n", ssMethod.GetUnicode()));
- }
-#endif
-
- MethodContext *pContext; // The current MethodContext we're processing
-
- while ((pContext = m_sAlreadySeen.Pop()) != NULL) {
- MethodDesc *pMD = pContext->m_pMethodDesc;
-
-#ifndef CROSSGEN_COMPILE
- // Jitting. Don't need to do this for the ngen case.
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- if (!m_fNgen)
-#endif
- {
- // Also skip the jit for the root method in the activated from jit case (where this would result in a recursive
- // jit). We'd cope with this just fine, the main reason for this logic is to avoid unbalancing some profiler event
- // counts that upset some of our test cases. This is safe in the face of multiple instantiations of the same method
- // because in the jit activated case (where we're told the root type context is not exact) we early exit if the root
- // method desc isn't 'unique' (i.e. independent of the type context).
- if (m_fExactTypeContext || pMD != m_pRootMD) {
-
- // Jit the method we traced.
- if (pMD->IsPointingToPrestub())
- {
- pMD->EnsureActive();
- pMD->DoPrestub(NULL);
- }
-
- // If we traced an instantiating stub we need to jit the wrapped (real) method as well.
- if (pMD->IsInstantiatingStub()) {
- _ASSERTE(!pMD->ContainsGenericVariables());
- MethodDesc *pRealMD = pMD->GetWrappedMethodDesc();
- if (pRealMD->IsPointingToPrestub())
- {
- pMD->EnsureActive();
- pRealMD->DoPrestub(NULL);
- }
- }
- }
-
- // Remember sub-CER root methods for further processing in RecordResults. We need to build CerPrepInfo structures for
- // these just the same as top-level CERs since we may wander in to them by a route that doesn't include the top-level CER
- // and the thread abort deflection algorithm relies on each CER root method being marked by a CerPrepInfo. Defer this
- // processing to RecordResults since we aren't guaranteed to have prepared all the methods of the sub-graph at this
- // point.
- if (pContext->m_fRoot && pMD != m_pRootMD)
- m_sPersist.Push(pContext);
- }
-#endif // CROSSGEN_COMPILE
-
- // Prepare generic dictionaries (both class and method as needed). We do this even in the ngen scenario, trying to get
- // as many slots filled as possible. By the looks of it, it's possible that not all of these entries will make it across
- // to runtime (the fixup code seems to give up on some of the more complex entries, not sure of the details). But we'll
- // do as best we can here to hopefully minimize any real work on the other side.
-
- // Don't use the direct PrepopulateDictionary method on MethodTable here, it takes binding considerations into account
- // (which we don't care about).
- DictionaryLayout *pClassDictLayout = pMD->GetClass()->GetDictionaryLayout();
- if (pClassDictLayout) {
- // Translate the representative method table we can find from our method desc into an exact instantiation using the
- // type context we have.
- MethodTable *pMT = TypeHandle(pMD->GetMethodTable()).Instantiate(pContext->m_sTypeContext.m_classInst).AsMethodTable();
-
- pMT->GetDictionary()->PrepopulateDictionary(NULL, pMT, false);
-
- // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
- PrepopulateGenericHandleCache(pClassDictLayout, NULL, pMT);
- }
-
- // Don't use the direct PrepopulateDictionary method on MethodDesc here, it appears to use a representative class
- // instantiation (and we have the exact one handy).
- DictionaryLayout *pMethDictLayout = pMD->GetDictionaryLayout();
- if (pMethDictLayout) {
- pMD->GetMethodDictionary()->PrepopulateDictionary(pMD, NULL, false);
-
- // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
- PrepopulateGenericHandleCache(pMethDictLayout, pMD, NULL);
- }
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- // Keep some of the method contexts around for the ngen case (the ones that might still need fixup at runtime). We'll
- // write them into a persisted data structure in the next step.
- // @todo: We use a horrible workaround here to get round the fact that while ngen'ing mscorlib we may prepare some of its
- // methods before we've had a chance to start up the compilation domain (mscorlib code is shared and used by the ngen
- // process itself). So we can't blindly call NeedsRestore() on an mscorlib method since that code asserts we're in the
- // compilation domain. Instead, if we're in the ngen process and we're outside the compilation domain we're going to
- // assume that the method doesn't need restoration. This only affects a handful of methods (six at last count, all to do
- // with security safe handles or some CERs in remoting).
- if (m_fNgen) {
- if (GetAppDomain() == NULL ||
- !GetAppDomain()->IsCompilationDomain() ||
- !(GetAppDomain()->ToCompilationDomain()->canCallNeedsRestore()) ||
- !(GetAppDomain()->ToCompilationDomain()->GetTargetImage()->CanPrerestoreEagerBindToMethodDesc(pMD, NULL))||
- pMD->HasClassOrMethodInstantiation() ||
- pMD->IsNDirect() ||
- pMD->IsComPlusCall() ||
- pMD->IsFCall() ||
- pContext->m_fRoot)
- m_sPersist.Push(pContext);
- }
-#endif
-
-#ifdef _DEBUG
- CER_LOG(PREPARE, (" %s\n", pContext->ToString()));
- dwCount++;
-#endif
- }
-
-#ifdef _DEBUG
- CER_LOG(PREPARE, ("Prepared a total of %u methods\n", dwCount));
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- if (m_fNgen)
- CER_LOG(PREPARE, ("Saved data for %u of them in the ngen image\n", m_sPersist.GetCount()));
-#endif
- CER_LOG(PREPARE, ("---------------------------------------------------------------\n"));
-#endif
-}
-
-// Common code used in creating/looking up a CerPrepInfo and initializing/updating it.
-void InitPrepInfo(MethodDesc *pMD, SigTypeContext *pTypeContext, bool fMethodHasCallsWithinExplicitCer)
-{
- CONTRACTL {
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(pMD));
- } CONTRACTL_END;
-
- // Lookup or allocate the CerPrepInfo.
- CerPrepInfo *pInfo = pMD->GetModule()->CreateCerPrepInfo(pMD);
-
- pInfo->m_fMethodHasCallsWithinExplicitCer = fMethodHasCallsWithinExplicitCer;
-
- // Work out if this was a partial preparation.
- bool fPartialPreparation = pMD->IsSharedByGenericInstantiations() ||
- pMD->IsInstantiatingStub() ||
- pMD->ContainsGenericVariables();
-
- // Simple case first: if this isn't a partial preparation (no pesky unbound type vars to worry about), then the method is
- // now fully prepared.
- if (!fPartialPreparation) {
- pInfo->m_fFullyPrepared = true;
- return;
- }
-
- // Else we know we require per-instantiation initialization. We need to update a hash table to record the preparation we did
- // in this case, and that requires taking a mutex. We could check that nobody beat us to it first, but that will hardly ever
- // happen, so it's not really worth it. So just acquire the mutex right away.
- CrstHolder sHolder(pMD->GetModule()->GetCerCrst());
-
- pInfo->m_fRequiresInstantiation = true;
-
- // Add an entry to a hash that records which instantiations we've prep'd for (again, only if someone hasn't beaten us).
- HashDatum sDatum;
- if (!pInfo->m_sIsInitAtInstHash.GetValue(pTypeContext, &sDatum))
- {
- pInfo->m_sIsInitAtInstHash.InsertKeyAsValue(pTypeContext);
- }
-}
-
-bool MethodCallGraphPreparer::RecordResults()
-{
- STANDARD_VM_CONTRACT;
-
- // Preparation has been successful, record what we've done in a manner consistent with whether we're ngen'ing or running for
- // real.
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
- // If we're ngen'ing an image we save our progess as a list of method contexts that might need restoration at runtime (since
- // even with prejitting there are some things that need to be prepared at runtime). This list goes into a per module table (the
- // module in question being that of the root method in the CER).
- if (m_fNgen) {
-
- // We have the list of MethodContexts ready, but they're in cheap storage that will go away once we exit this method.
- // Not only do we have to copy them to heap memory, but we also know exactly how many there are. So we can allocate a
- // single array with a more compact form of MethodContext for each element. We allocate an extra sentinel value for the end
- // of the list. This means we can store just a pointer to the list without a count (the code that accesses this list cares
- // about keeping the list heads compact and densely packed and doesn't care about counting the elements in the list).
- DWORD cContexts = m_sPersist.GetCount();
- LoaderHeap *pHeap = m_pRootMD->GetAssembly()->GetLowFrequencyHeap();
- MethodContextElement *pContexts = (MethodContextElement*)(void*)pHeap->AllocMem(S_SIZE_T(sizeof(MethodContextElement)) * (S_SIZE_T(cContexts) + S_SIZE_T(1)));
- DWORD i = 0;
-
- MethodContext *pContext; // The current MethodContext we're processing
- while ((pContext = m_sPersist.Pop()) != NULL) {
- pContexts[i].m_pMethodDesc.SetValue(pContext->m_pMethodDesc);
-
- MethodTable * pExactMT = NULL;
- if (!pContext->m_sTypeContext.m_classInst.IsEmpty())
- {
- pExactMT = TypeHandle(pContext->m_pMethodDesc->GetMethodTable()).Instantiate(pContext->m_sTypeContext.m_classInst).AsMethodTable();
- _ASSERTE(pExactMT->HasInstantiation());
- }
- else
- {
- _ASSERTE(!pContext->m_pMethodDesc->GetMethodTable()->HasInstantiation());
- }
- pContexts[i].m_pExactMT.SetValue(pExactMT);
-
- i++;
-
- // Keep the context round for a little longer if the method in question was the root of a sub-CER.
- if (pContext->m_fRoot)
- m_sRootMethods.Push(pContext);
- }
-
- // Write sentinel entry terminating list.
- _ASSERTE(i == cContexts);
-
- // Add list representing this CER to the per-module table (keyed by root method desc).
- m_pRootMD->GetModule()->AddCerListToRootTable(m_pRootMD, pContexts);
-
- // If this did have an call from an explicit PCER range, create a PrepInfo for it so that we can
- // quickly grab that information later when we jit that method. This allows us to optimize the probe
- // away if there are no calls from the PCER range. This is an issue when we've prepared a method
- // as part of a CER call from another method, but haven't ngened that method yet. When we get
- // around to finally ngening that method, we want to be able to optimize the CER probe out if
- // we can, but don't want to reprepare the method.
- if (g_pConfig->ProbeForStackOverflow() && m_fMethodHasCallsWithinExplicitCer)
- {
- if (m_pCerPrepInfo == NULL)
- m_pCerPrepInfo = m_pRootMD->GetModule()->CreateCerPrepInfo(m_pRootMD);
- m_pCerPrepInfo->m_fMethodHasCallsWithinExplicitCer = TRUE;
- }
-
-
- // We need to be careful with sub-CERs in the ngen case. In the jit case they're dealt with automatically (preparing a
- // super-CER always completely prepares a sub-CER). But in the ngen case we potentially need to run further preparation
- // steps at the point that a CER root is executed for the first time. If the sub-root is encountered before the super-root
- // then the sub-CER won't have been prepared correctly.
- // We solve this simply by recursively running this routine over the methods we noted were sub-roots earlier (this list
- // doesn't include the main root). We could potentially do a little better than this given that we've calculated the
- // super-graph, but this is complicated somewhat by the fact that we don't retain the graph structure (i.e. we can't extract
- // sub-graphs easily) and the effort seems wasted just to avoid a little CPU time and stack space just for the ngen creation
- // scenario.
- while ((pContext = m_sRootMethods.Pop()) != NULL)
- {
- MethodCallGraphPreparer mgcp(pContext->m_pMethodDesc, &pContext->m_sTypeContext, false, false);
- mgcp.Run();
- }
-
- return m_fMethodHasCallsWithinExplicitCer;
- }
-#endif // FEATURE_NATIVE_IMAGE_GENERATION
-
- // This is the runtime (non-ngen case). Record our progress in an info structure placed in a hash table hung off the module
- // which owns the root method desc in the CER. The methods which create this info structure handle race conditions (to
- // ensure we don't leak memory or data), but the updates to the info structure itself might not require any serialization
- // (the values are 'latched' -- recomputation should yield the same result). The exception is any update to a more complex
- // data fields (lists and hash tables) that require serialization to prevent corruption of the basic data structure.
-
- // Process sub-CER roots first. We need to build CerPrepInfo structures for these just as same as top-level CERs since we may
- // wander in to them by a route that doesn't include the top-level CER and the thread abort deflection algorithm relies on each
- // CER root method being marked by a CerPrepInfo.
- MethodContext *pContext;
- while ((pContext = m_sPersist.Pop()) != NULL) {
- _ASSERTE(pContext->m_fRoot);
-
- // @todo: need to flow fMethodHasCallsWithinExplicitCer information through method contexts. For now just make a
- // conservative, safe choice.
- InitPrepInfo(pContext->m_pMethodDesc, &pContext->m_sTypeContext, true);
- }
-
- // Now process the top-level CER.
- InitPrepInfo(m_pRootMD, m_pRootTypeContext, m_fMethodHasCallsWithinExplicitCer);
-
- return m_fMethodHasCallsWithinExplicitCer;
-}
-
-// Determines whether the given method contains a CER root that can be pre-prepared (i.e. prepared at jit time).
-bool ContainsPrePreparableCerRoot(MethodDesc *pMD)
-{
- CONTRACTL {
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(pMD));
- } CONTRACTL_END;
-
- // Deal with exotic cases (non-IL methods and the like).
- if (!pMD->IsIL() || pMD->IsAbstract())
- return false;
-
- // And cases where we can't jit prepare (because the code is shared between instantiations).
- if (pMD->IsSharedByGenericInstantiations() || pMD->IsInstantiatingStub() || pMD->ContainsGenericVariables())
- return false;
-
- // Otherwise we have a trickier calculation. We don't want to force the jit of the method at this point (may cause infinite
- // recursion problems when we're called from the jit in the presence of call cycles). Instead we walk the top-level of the
- // method IL using the same algorithm as PrepareMethodCallGraph.
-
- // Locate the IL body of the current method. May have to account for the fact that the current method desc is an
- // instantiating stub and burrow down for the real method desc.
- MethodDesc *pRealMethod = pMD;
- if (pRealMethod->IsInstantiatingStub()) {
- _ASSERTE(!pRealMethod->ContainsGenericVariables());
- pRealMethod = pRealMethod->GetWrappedMethodDesc();
- }
- COR_ILMETHOD_DECODER method(pRealMethod->GetILHeader());
- BYTE *pbIL = (BYTE*)method.Code;
- DWORD cbIL = method.GetCodeSize();
-
- // Look for exception handling information for the method. If there isn't any then we know there can't be a CER rooted here.
- COR_ILMETHOD_SECT_EH const * pEH = method.EH;
- if (pEH == NULL || pEH->EHCount() == 0)
- return false;
-
- // Iterate through the body of the method looking for interesting call sites.
- while (cbIL) {
-
- // Read the IL op.
- DWORD dwOp = *pbIL++; cbIL--;
-
- // Handle prefix codes (only CEE_PREFIX1 is legal so far).
- if (dwOp == CEE_PREFIX1) {
- if (!cbIL)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- dwOp = 256 + *pbIL++; cbIL--;
- if (dwOp >= CEE_ILLEGAL)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- } else if (dwOp >= CEE_PREFIX7)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
- // We'll only ever see CALL instructions targeting PrepareConstrainedRegions (well those are the ones we're interested in
- // anyway).
- if (dwOp == CEE_CALL)
- {
- if (cbIL < sizeof(DWORD))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- if (IsPcrReference(pMD->GetModule(), (mdToken)GET_UNALIGNED_VAL32(pbIL)))
- return true;
- }
-
- // Skip the rest of the current IL instruction. Look up the table built statically at the top of this module for most
- // instructions, but CEE_SWITCH requires special processing (the length of that instruction depends on a count DWORD
- // embedded right after the opcode).
- if (dwOp == CEE_SWITCH) {
- if (cbIL < sizeof(DWORD))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- DWORD dwTargets = GET_UNALIGNED_VAL32(pbIL);
- if (dwTargets >= (MAXDWORD / sizeof(DWORD)))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT); // multiplication below would overflow
- DWORD cbSwitch = (1 + dwTargets) * sizeof(DWORD);
- if (cbIL < cbSwitch)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- pbIL += cbSwitch;
- cbIL -= cbSwitch;
- } else {
- if (dwOp >= _countof(g_rOpArgs))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- DWORD cbOp = g_rOpArgs[dwOp];
- if (cbIL < cbOp)
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
- pbIL += cbOp;
- cbIL -= cbOp;
- }
-
- } // End of IL parsing loop
-
- // If we get here then there was no CER-root.
- return false;
-}
-
-// The name of the PrepareConstrainedRegions method, broken down into its components (the code below scans for these directly in the
-// metadata).
-#define PCR_METHOD "PrepareConstrainedRegions"
-#define PCR_TYPE "RuntimeHelpers"
-#define PCR_NAMESPACE "System.Runtime.CompilerServices"
-
-// Given a token and a module scoping it, determine if that token is a reference to PrepareConstrainedRegions. We want to do this
-// without loading any random types since we're called in a context where type loading is prohibited.
-bool IsPcrReference(Module *pModule, mdToken tkMethod)
-{
- CONTRACTL {
- STANDARD_VM_CHECK;
- PRECONDITION(CheckPointer(pModule));
- } CONTRACTL_END;
-
- IMDInternalImport *pImport = pModule->GetMDImport();
-
- // Validate that the token is one that we can handle.
- if (!pImport->IsValidToken(tkMethod) || (TypeFromToken(tkMethod) != mdtMethodDef &&
- TypeFromToken(tkMethod) != mdtMethodSpec &&
- TypeFromToken(tkMethod) != mdtMemberRef))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
-
- // No reason to see a method spec for a call to something as simple as PrepareConstrainedRegions.
- if (TypeFromToken(tkMethod) == mdtMethodSpec)
- return false;
-
- // If it's a method def then the module had better be mscorlib.
- if (TypeFromToken(tkMethod) == mdtMethodDef) {
- if (pModule->GetAssembly()->GetManifestModule() == SystemDomain::SystemAssembly()->GetManifestModule())
- return tkMethod == g_pPrepareConstrainedRegionsMethod->GetMemberDef();
- else
- return false;
- }
-
- // That leaves the cross module reference case.
- _ASSERTE(TypeFromToken(tkMethod) == mdtMemberRef);
-
- // First get the method name and signature and validate it.
- PCCOR_SIGNATURE pSig;
- DWORD cbSig;
- LPCSTR szMethod;
- IfFailThrow(pImport->GetNameAndSigOfMemberRef(tkMethod, &pSig, &cbSig, &szMethod));
-
- {
- SigParser sig(pSig, cbSig);
- ULONG nCallingConvention;
- ULONG nArgumentsCount;
- BYTE bReturnType;
-
- // Signature is easy: void PCR().
- // Must be a static method signature.
- if (FAILED(sig.GetCallingConvInfo(&nCallingConvention)))
- return false;
- if (nCallingConvention != IMAGE_CEE_CS_CALLCONV_DEFAULT)
- return false;
- // With no arguments.
- if (FAILED(sig.GetData(&nArgumentsCount)))
- return false;
- if (nArgumentsCount != 0)
- return false;
- // And a void return type.
- if (FAILED(sig.GetByte(&bReturnType)))
- return false;
- if (bReturnType != (BYTE)ELEMENT_TYPE_VOID)
- return false;
- }
-
- // Validate the name.
- if (strcmp(szMethod, PCR_METHOD) != 0)
- return false;
-
- // The method looks OK, move up to the type and validate that.
- mdToken tkType;
- IfFailThrow(pImport->GetParentOfMemberRef(tkMethod, &tkType));
-
- if (!pImport->IsValidToken(tkType))
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
-
- // If the parent is not a type ref then this isn't our target (we assume that mscorlib never uses a member ref to target
- // PrepareConstrainedRegions, check that with the assert below, if it ever fails we need to add some additional logic below).
- _ASSERTE(TypeFromToken(tkType) != mdtTypeDef ||
- pModule->GetAssembly()->GetManifestModule() != SystemDomain::SystemAssembly()->GetManifestModule());
- if (TypeFromToken(tkType) != mdtTypeRef)
- return false;
-
- // Get the type name and validate it.
- LPCSTR szNamespace;
- LPCSTR szType;
- IfFailThrow(pImport->GetNameOfTypeRef(tkType, &szNamespace, &szType));
-
- if (strcmp(szType, PCR_TYPE) != 0)
- return false;
- if (strcmp(szNamespace, PCR_NAMESPACE) != 0)
- return false;
-
- // Type is OK as well. Check the assembly reference.
- mdToken tkScope;
- IfFailThrow(pImport->GetResolutionScopeOfTypeRef(tkType, &tkScope));
-
- if (TypeFromToken(tkScope) != mdtAssemblyRef)
- return false;
- if (!pImport->IsValidToken(tkScope))
- {
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
- }
-
- // Fetch the name and public key or public key token.
- BYTE *pbPublicKeyOrToken;
- DWORD cbPublicKeyOrToken;
- LPCSTR szAssembly;
- DWORD dwAssemblyFlags;
- IfFailThrow(pImport->GetAssemblyRefProps(
- tkScope,
- (const void**)&pbPublicKeyOrToken,
- &cbPublicKeyOrToken,
- &szAssembly,
- NULL, // AssemblyMetaDataInternal: we don't care about version, culture etc.
- NULL, // Hash value pointer, obsolete information
- NULL, // Byte count for above
- &dwAssemblyFlags));
-
- // Validate the name.
- if (stricmpUTF8(szAssembly, g_psBaseLibraryName) != 0)
- return false;
-
- // And the public key or token, which ever was burned into the reference by the compiler. For mscorlib this is the ECMA key or
- // token.
- if (IsAfPublicKeyToken(dwAssemblyFlags)) {
- if (cbPublicKeyOrToken != sizeof(g_rbNeutralPublicKeyToken) ||
- memcmp(pbPublicKeyOrToken, g_rbNeutralPublicKeyToken, cbPublicKeyOrToken) != 0)
- return false;
- } else {
- if (cbPublicKeyOrToken != sizeof(g_rbNeutralPublicKey) ||
- memcmp(pbPublicKeyOrToken, g_rbNeutralPublicKey, cbPublicKeyOrToken) != 0)
- return false;
- }
-
- // If we get here we've finally proved the call target was indeed PrepareConstrainedRegions. Whew.
- return true;
-}
-
-// Prepares a method as a CER root. In some scenarios we set
-// fIgnoreVirtualCERCallMDA=TRUE, this happens when we want to ignore firing a
-// VirtualCERCall MDA because we know for sure that the virtual methods are
-// already prepared. A good example of this case is preparing
-// g_pExecuteBackoutCodeHelperMethod method.
-void PrepareMethodDesc(MethodDesc* pMD, Instantiation classInst, Instantiation methodInst, BOOL onlyContractedMethod, BOOL fIgnoreVirtualCERCallMDA)
-{
- CONTRACTL
- {
- THROWS;
- DISABLED(GC_TRIGGERS);
- MODE_ANY;
- }
- CONTRACTL_END;
-
- GCX_PREEMP();
-
-#ifdef FEATURE_PREJIT
- // This method may have some ngen fixup information provided, in which case we just check that it's been restored and can
- // dispense with the preparation altogether.
- Module *pModule = pMD->GetModule();
- if (pModule->IsNgenCerRootMethod(pMD))
- {
- pMD->CheckRestore();
- pModule->RestoreCer(pMD);
- return;
- }
-#endif
-
- // If we are only going to prepare contracted methods and this method does
- // not have a contract then we just return.
- if (onlyContractedMethod && CheckForReliabilityContract(pMD) < RCL_BASIC_CONTRACT)
- {
- return;
- }
-
- SigTypeContext sTypeContext(pMD, classInst, methodInst);
- MethodCallGraphPreparer mcgp(pMD, &sTypeContext, true, true, fIgnoreVirtualCERCallMDA == TRUE);
- mcgp.Run();
-}
-
-// Prepares the critical finalizer call graph for the given object type (which
-// must derive from CriticalFinalizerObject). This involves preparing at least
-// the finalizer method and possibly some others (for SafeHandle and
-// CriticalHandle derivations). If a module pointer is supplied then only the
-// critical methods introduced in that module are prepared (this is used at
-// ngen time to ensure that we're only generating ngen preparation info for the
-// targetted module).
-void PrepareCriticalFinalizerObject(MethodTable *pMT, Module *pModule)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMT));
- } CONTRACTL_END;
-
- // Have we prepared this type before?
- if (pMT->CriticalTypeHasBeenPrepared())
- return;
-
- GCX_PREEMP();
-
- // Restore the method table if necessary.
- pMT->CheckRestore();
-
- // Determine the interesting parent class (either SafeHandle, CriticalHandle or CriticalFinalizerObject).
- MethodTable *pSafeHandleClass = MscorlibBinder::GetClass(CLASS__SAFE_HANDLE);
- MethodTable *pCriticalHandleClass = MscorlibBinder::GetClass(CLASS__CRITICAL_HANDLE);
- MethodTable *pParent = pMT;
- while (pParent) {
- if (pParent == g_pCriticalFinalizerObjectClass ||
- pParent == pSafeHandleClass ||
- pParent == pCriticalHandleClass) {
- break;
- }
- pParent = pParent->GetParentMethodTable();
- }
- _ASSERTE(pParent != NULL);
-
- BinderMethodID rgMethods[5];
- int nMethods;
-
- // Prepare the method or methods based on the parent class.
- if (pParent == pSafeHandleClass) {
- rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE;
- rgMethods[1] = METHOD__SAFE_HANDLE__RELEASE_HANDLE;
- rgMethods[2] = METHOD__SAFE_HANDLE__GET_IS_INVALID;
- rgMethods[3] = METHOD__SAFE_HANDLE__DISPOSE;
- rgMethods[4] = METHOD__SAFE_HANDLE__DISPOSE_BOOL;
- nMethods = 5;
- } else if (pParent == pCriticalHandleClass) {
- rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE;
- rgMethods[1] = METHOD__CRITICAL_HANDLE__RELEASE_HANDLE;
- rgMethods[2] = METHOD__CRITICAL_HANDLE__GET_IS_INVALID;
- rgMethods[3] = METHOD__CRITICAL_HANDLE__DISPOSE;
- rgMethods[4] = METHOD__CRITICAL_HANDLE__DISPOSE_BOOL;
- nMethods = 5;
- } else {
- _ASSERTE(pParent == g_pCriticalFinalizerObjectClass);
- rgMethods[0] = METHOD__CRITICAL_FINALIZER_OBJECT__FINALIZE;
- nMethods = 1;
- }
-
- for (int iMethod = 0; iMethod < nMethods; iMethod++)
- {
- // Prepare a (possibly virtual) method on an instance. The method is identified via a binder ID, so the initial
- // declaration of the method must reside within mscorlib. We might have ngen fixup information for the method and can avoid direct
- // preparation as well.
-
- MethodDesc *pPrepMethod = pMT->GetMethodDescForSlot(MscorlibBinder::GetMethod(rgMethods[iMethod])->GetSlot());
-#ifdef FEATURE_PREJIT
- if (pPrepMethod->GetModule()->IsNgenCerRootMethod(pPrepMethod)) {
- pPrepMethod->GetModule()->RestoreCer(pPrepMethod);
- }
- else
- if (IsCompilationProcess() && pPrepMethod->IsAbstract()) {
- // Skip abstract methods during NGen (we should not ever get abstract methods here at runtime)
- }
- else
-#endif
- {
- if (pModule == NULL || pPrepMethod->GetModule() == pModule) {
- SigTypeContext _sTypeContext(pPrepMethod, TypeHandle(pMT));
- MethodCallGraphPreparer mcgp(pPrepMethod, &_sTypeContext, true, true);
- mcgp.Run();
- }
- }
- }
-
- // Note the fact that we've prepared this type before to prevent repetition of the work above. (Though repetition is harmless in
- // all other respects, so there's no need to worry about the race setting this flag).
- pMT->SetCriticalTypeHasBeenPrepared();
-}
-
-#ifdef _DEBUG
-
-static const char * const g_rszContractNames[] = { "RCL_NO_CONTRACT", "RCL_BASIC_CONTRACT", "RCL_PREPARE_CONTRACT" };
-static DWORD g_dwContractChecks = 0;
-
-#define ReturnContractLevel(_level) do { \
- g_dwContractChecks++; \
- if ((g_dwContractChecks % 100) == 0 && g_pMethodContractCache) \
- g_pMethodContractCache->DbgDumpStats(); \
- ReliabilityContractLevel __level = (_level); \
- CER_LOG(CONTRACTS, ("%s -- %s\n", pMD->m_pszDebugMethodName, g_rszContractNames[__level])); \
- return __level; \
-} while (false)
-#else
-#define ReturnContractLevel(_level) return (_level)
-#endif
-
-// Look for reliability contracts at the method, class and assembly level and parse them to extract the information we're interested
-// in from a runtime preparation viewpoint. This information is abstracted in the form of the ReliabilityContractLevel enumeration.
-ReliabilityContractLevel CheckForReliabilityContract(MethodDesc *pMD)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMD));
- } CONTRACTL_END;
-
- // We are attempting to abstract reliability contracts for the given method into three different buckets: those methods that
- // will cause an error (or a MDA report at least) during preparation (RCL_NO_CONTRACT), those we allow but don't prepare
- // (RCL_BASIC_CONTRACT) and those we allow and prepare (RCL_PREPARE_CONTRACT).
- //
- // We place methods into the first bucket below that matches:
- // RCL_NO_CONTRACT -- Methods with no consistency or whose consistency states they may corrupt the appdomain or process.
- // RCL_BASIC_CONTRACT -- Methods that state CER.None (or don't specify a CER attribute)
- // RCL_PREPARE_CONTRACT -- Methods that state CER.MayFail or CER.Success
- //
- // We look for reliability contracts at three levels: method, class and assembly. Definitions found at the method level override
- // those at the class and assembly level and those at the class level override assembly settings.
- //
- // In the interests of efficiency we cache contract information in a number of ways. Firstly we look at a hash of recently
- // queried MethodDescs. This contains authoritative answers (assembly/class/method information has already been composed so on a
- // hit we don't need to look anywhere else). This cache is allocated lazily, never grows (newer items eventually displace older
- // ones), is global, requires no locks and is never freed. The idea is to limit the amount of working set we ever occupy while
- // keeping the CPU usage as low as possible. Typical usages of this method involve querying a small number of methods in a stack
- // walk, possibly multiple times, so a small hash cache should work reasonably well here.
- //
- // On a miss we're going to have to bite the bullet and look at the assembly, class and method. The assembly and class cache
- // this information at load (ngen) time though, so they're not so expensive (class level data is cached on the EEClass, so it's
- // cold data, but the most performance sensitive scenario in which we're called here, ThreadAbort, isn't all that hot).
-
- // Check the cache first, it contains a raw contract level.
- ReliabilityContractLevel eLevel;
- if (g_pMethodContractCache && g_pMethodContractCache->Lookup(pMD, (DWORD*)&eLevel))
- ReturnContractLevel(eLevel);
-
- // Start at the method level and work up until we've found enough information to make a decision. The contract level is composed
- // in an encoded DWORD form that lets us track both parts of the state (consistency and cer) and whether each has been supplied
- // yet. See the RC_* macros for encoding details.
- DWORD dwMethodContractInfo = GetReliabilityContract(pMD->GetMDImport(), pMD->GetMemberDef());
- if (RC_INCOMPLETE(dwMethodContractInfo)) {
- DWORD dwClassContractInfo = pMD->GetClass()->GetReliabilityContract();
- dwMethodContractInfo = RC_MERGE(dwMethodContractInfo, dwClassContractInfo);
- if (RC_INCOMPLETE(dwMethodContractInfo)) {
- DWORD dwAssemblyContractInfo = pMD->GetModule()->GetReliabilityContract();
- dwMethodContractInfo = RC_MERGE(dwMethodContractInfo, dwAssemblyContractInfo);
- }
- }
-
- // We've got an answer, so attempt to cache it for the next time.
-
- // First check we have a cache (we allocate it lazily).
- if (g_pMethodContractCache == NULL) {
- PtrHashCache *pCache = new (nothrow) PtrHashCache();
- if (pCache)
- if (FastInterlockCompareExchangePointer(&g_pMethodContractCache, pCache, NULL) != NULL)
- delete pCache;
- }
-
- // We still might not have a cache in low memory situations. That's OK.
- if (g_pMethodContractCache)
- g_pMethodContractCache->Add(pMD, RC_ENCODED_TO_LEVEL(dwMethodContractInfo));
-
- ReturnContractLevel(RC_ENCODED_TO_LEVEL(dwMethodContractInfo));
-}
-
-
-// Macro used to handle failures in the routine below.
-#define IfFailRetRcNull(_hr) do { if (FAILED(_hr)) return RC_NULL; } while (false)
-
-// Look for a reliability contract attached to the given metadata token in the given scope. Return the result as an encoded DWORD
-// (see the RC_ENCODE macro).
-DWORD GetReliabilityContract(IMDInternalImport *pImport, mdToken tkParent)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pImport));
- } CONTRACTL_END;
-
- HRESULT hr;
- DWORD dwResult = RC_NULL;
-
- // Sadly we only have two unmanaged APIs available to us for looking at custom attributes. One looks up attributes by name but
- // only returns the byte blob, not the attribute ctor information (which we need to parse the blob) while the other returns
- // everything but requires us to enumerate all attributes on a given token looking for the one we're interested in. To keep the
- // cost down we probe for the existence of the attribute using the first API and then use the enumeration method if we get a
- // hit.
- hr = pImport->GetCustomAttributeByName(tkParent, RELIABILITY_CONTRACT_NAME, NULL, NULL);
- if (hr == S_FALSE)
- return RC_NULL;
-
- IfFailRetRcNull(hr);
-
- // Got at least one contract against this parent. Enumerate them all (filtering by name).
- MDEnumHolder hEnum(pImport);
- hr = pImport->SafeAndSlowEnumCustomAttributeByNameInit(tkParent, RELIABILITY_CONTRACT_NAME, &hEnum);
- _ASSERTE(hr != S_FALSE);
- IfFailRetRcNull(hr);
-
- // Enumerate over all the contracts.
- mdToken tkContract;
- while (S_OK == pImport->SafeAndSlowEnumCustomAttributeByNameNext(tkParent, RELIABILITY_CONTRACT_NAME, &hEnum, &tkContract)) {
-
- // Get the attribute type (token of the ctor used) since we need this information in order to parse the blob we'll find
- // next.
- mdToken tkAttrType;
- IfFailRetRcNull(pImport->GetCustomAttributeProps(tkContract, &tkAttrType));
- if (!pImport->IsValidToken(tkAttrType))
- continue;
-
- // The token should be a member ref or method def.
- // Get the signature of the ctor so we know which version has been called.
- PCCOR_SIGNATURE pSig;
- DWORD cbSig;
- LPCSTR szName_Ignore;
- if (TypeFromToken(tkAttrType) == mdtMemberRef)
- {
- IfFailRetRcNull(pImport->GetNameAndSigOfMemberRef(tkAttrType, &pSig, &cbSig, &szName_Ignore));
- }
- else
- {
- if (TypeFromToken(tkAttrType) != mdtMethodDef)
- continue;
- IfFailRetRcNull(pImport->GetNameAndSigOfMethodDef(tkAttrType, &pSig, &cbSig, &szName_Ignore));
- }
-
- // Only two signatures are supported: the null sig '()' and the full sig '(Consistency, CER)'.
- // Set a boolean based on which one was provided.
- bool fNullCtor;
- ULONG eCallConv;
-
- SigPointer sig(pSig, cbSig);
-
- // Check the calling convention is what we expect (default convention on an instance method).
- IfFailRetRcNull(sig.GetCallingConvInfo(&eCallConv));
- _ASSERTE(eCallConv == (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS));
- if (eCallConv != (IMAGE_CEE_CS_CALLCONV_DEFAULT | IMAGE_CEE_CS_CALLCONV_HASTHIS))
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
- // If so, the next datum is the count of arguments, and this is all we need to determine which ctor has been used.
- ULONG dwArgs;
- IfFailRetRcNull(sig.GetData(&dwArgs));
- _ASSERTE(dwArgs == 0 || dwArgs == 2);
- if (dwArgs != 0 && dwArgs != 2)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
- fNullCtor = dwArgs == 0;
-
- // Now we know how to parse the blob, let's fetch a pointer to it.
- BYTE const *pbData;
- DWORD cbData;
- IfFailRetRcNull(pImport->GetCustomAttributeAsBlob(tkContract, (const void **)&pbData, &cbData));
-
- // Check serialization format (we support version 1 only).
- if (cbData < sizeof(WORD) || GET_UNALIGNED_VAL16(pbData) != 1)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- pbData += sizeof(WORD);
- cbData -= sizeof(WORD);
-
- // Parse ctor arguments if we have any.
- if (!fNullCtor) {
-
- // We assume the enums are based on DWORDS.
- if (cbData < (sizeof(DWORD) * 2))
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
- // Consistency first.
- DWORD dwConsistency = GET_UNALIGNED_VAL32(pbData);
- pbData += sizeof(DWORD);
- cbData -= sizeof(DWORD);
- if (dwConsistency > RC_CONSISTENCY_CORRUPT_NOTHING)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
- // Followed by Cer.
- DWORD dwCer = GET_UNALIGNED_VAL32(pbData);
- pbData += sizeof(DWORD);
- cbData -= sizeof(DWORD);
- if (dwCer > RC_CER_SUCCESS)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
-
- dwResult = RC_MERGE(dwResult, RC_ENCODE(dwConsistency, dwCer));
- }
-
- // Get the count of field/property, value pairs.
- if (cbData < sizeof(WORD))
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- WORD cPairs = GET_UNALIGNED_VAL16(pbData);
- pbData += sizeof(WORD);
- cbData -= sizeof(WORD);
-
- // Iterate over any such pairs, looking for values we haven't picked up yet.
- for (DWORD i = 0 ; i < cPairs; i++) {
-
- // First is a field vs property selector. We expect only properties.
- if (cbData < sizeof(BYTE) || *(BYTE*)pbData != SERIALIZATION_TYPE_PROPERTY)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- pbData += sizeof(BYTE);
- cbData -= sizeof(BYTE);
-
- // Next is the type of the property. It had better be an enum.
- if (cbData < sizeof(BYTE) || *(BYTE*)pbData != SERIALIZATION_TYPE_ENUM)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- pbData += sizeof(BYTE);
- cbData -= sizeof(BYTE);
-
- // Next we have the assembly qualified enum type name. This is preceded by a metadata style packed byte length (the
- // string itself is 8-bit and not null terminated). Ignore it (just skip across) and we'll key off the property name
- // (coming up) instead.
- DWORD cbName;
- BYTE const * pbPostEncodedLength;
- IfFailRetRcNull(CPackedLen::SafeGetData(pbData, cbData, &cbName, &pbPostEncodedLength));
- DWORD cbEncodedLength = static_cast<DWORD>(pbPostEncodedLength - pbData);
- pbData += cbEncodedLength + cbName;
- cbData -= cbEncodedLength + cbName;
-
- // Now we have the name of the property (in a similar format to above).
- IfFailRetRcNull(CPackedLen::SafeGetData(pbData, cbData, &cbName, &pbPostEncodedLength));
- cbEncodedLength = static_cast<DWORD>(pbPostEncodedLength - pbData);
- pbData += cbEncodedLength;
- cbData -= cbEncodedLength;
-
- bool fConsistencyProp = false;
- if (cbName == strlen(RC_CONSISTENCY_PROP_NAME) && strncmp((const char*)pbData, RC_CONSISTENCY_PROP_NAME, cbName) == 0)
- fConsistencyProp = true;
- else if (cbName == strlen(RC_CER_PROP_NAME) && strncmp((const char*)pbData, RC_CER_PROP_NAME, cbName) == 0)
- fConsistencyProp = false;
- else
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- pbData += cbName;
- cbData -= cbName;
-
- // And finally the actual enum value (again, we assume the underlying type is a DWORD).
- if (cbData < sizeof(DWORD))
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- DWORD dwValue = GET_UNALIGNED_VAL32(pbData);
- pbData += sizeof(DWORD);
- cbData -= sizeof(DWORD);
-
- if (fConsistencyProp) {
- if (dwValue > RC_CONSISTENCY_CORRUPT_NOTHING)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- dwResult = RC_MERGE(dwResult, RC_ENCODE(dwValue, RC_CER_UNDEFINED));
- } else {
- if (dwValue > RC_CER_SUCCESS)
- IfFailRetRcNull(COR_E_BADIMAGEFORMAT);
- dwResult = RC_MERGE(dwResult, RC_ENCODE(RC_CONSISTENCY_UNDEFINED, dwValue));
- }
- }
-
- // Shouldn't have any bytes left in the blob at this stage.
- _ASSERTE(cbData == 0);
- }
-
- // Return the result encoded and packed into the 2 low order bits of a DWORD.
- return dwResult;
-}
-
-// Given a metadata token, a scoping module and a type context, look up the appropriate MethodDesc (and recomputed accompanying type
-// context).
-MethodContext *TokenToMethodDesc(Module *pModule, mdToken tokMethod, SigTypeContext *pTypeContext)
-{
- STANDARD_VM_CONTRACT;
-
- // Validate that the token is one that we can handle.
- if (!pModule->GetMDImport()->IsValidToken(tokMethod) || (TypeFromToken(tokMethod) != mdtMethodDef &&
- TypeFromToken(tokMethod) != mdtMethodSpec &&
- TypeFromToken(tokMethod) != mdtMemberRef)) {
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_METHOD_TOKEN);
- }
-
- // Look up the MethodDesc based on the token and type context.
- MethodDesc *pMD = MemberLoader::GetMethodDescFromMemberDefOrRefOrSpec(pModule,
- tokMethod,
- pTypeContext,
- TRUE,
- FALSE);
-
- // The MethodDesc we get might be shared between several types. If so we'll need to do extra work to locate the exact
- // class instantiation instead of the default representative one.
- SigTypeContext sNewTypeContext;
- if (pMD->IsSharedByGenericInstantiations()) {
- TypeHandle th = GetTypeFromMemberDefOrRefOrSpecThrowing(pModule,
- tokMethod,
- pTypeContext);
- SigTypeContext::InitTypeContext(pMD, th,&sNewTypeContext);
- } else
- SigTypeContext::InitTypeContext(pMD, pMD->GetClassInstantiation(), pMD->GetMethodInstantiation(),&sNewTypeContext);
-
- return MethodContext::PerThreadAllocate(pMD, &sNewTypeContext);
-}
-
-// Locate an exact type definition given a method token and the type context in which it can be resolved.
-TypeHandle GetTypeFromMemberDefOrRefOrSpecThrowing(Module *pModule,
- mdToken tokMethod,
- SigTypeContext *pTypeContext)
-{
- STANDARD_VM_CONTRACT;
-
- IMDInternalImport *pImport = pModule->GetMDImport();
-
- // Convert method specs into the underlying member ref.
- if (TypeFromToken(tokMethod) == mdtMethodSpec)
- {
- PCCOR_SIGNATURE pSig;
- ULONG cSig;
- mdMemberRef tkGenericMemberRef;
-
- IfFailThrow(pImport->GetMethodSpecProps(tokMethod, &tkGenericMemberRef, &pSig, &cSig));
-
- if (!pImport->IsValidToken(tkGenericMemberRef) ||
- (TypeFromToken(tkGenericMemberRef) != mdtMethodDef &&
- TypeFromToken(tkGenericMemberRef) != mdtMemberRef))
- {
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN_TYPE);
- }
-
- tokMethod = tkGenericMemberRef;
- }
-
- // Follow the member ref/def back up to the type def/ref/spec or module (for global methods).
- if (TypeFromToken(tokMethod) == mdtMemberRef)
- {
- IfFailThrow(pImport->GetParentOfMemberRef(tokMethod, &tokMethod));
-
- // For varargs, a memberref can point to a methodDef
- if (TypeFromToken(tokMethod) == mdtMethodDef)
- {
- if (!pImport->IsValidToken(tokMethod))
- {
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
- }
- IfFailThrow(pImport->GetParentToken(tokMethod, &tokMethod));
- }
- }
- else if (TypeFromToken(tokMethod) == mdtMethodDef)
- {
- IfFailThrow(pImport->GetParentToken(tokMethod, &tokMethod));
- }
-
- if (!pImport->IsValidToken(tokMethod) || (TypeFromToken(tokMethod) != mdtTypeDef &&
- TypeFromToken(tokMethod) != mdtTypeRef &&
- TypeFromToken(tokMethod) != mdtTypeSpec &&
- TypeFromToken(tokMethod) != mdtModuleRef))
- {
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT, BFA_INVALID_TOKEN);
- }
-
- // Load the type in question, using a type context if necessary to get an exact representation.
- TypeHandle th;
- if (TypeFromToken(tokMethod) == mdtModuleRef) {
- DomainFile *pNewModule = pModule->LoadModule(GetAppDomain(), tokMethod, FALSE);
- if (pNewModule != NULL)
- th = TypeHandle(pNewModule->GetModule()->GetGlobalMethodTable());
- } else {
- th = ClassLoader::LoadTypeDefOrRefOrSpecThrowing(pModule,
- tokMethod,
- pTypeContext);
- }
-
- if (th.IsNull())
- COMPlusThrowHR(COR_E_BADIMAGEFORMAT);
-
- return th;
-}
-
-// Determine whether the method given as a parameter is the root of a CER.
-// @todo: Need an x86 offset as well and logic to determine whether we're actually in a root-CER portion of the method (if the whole
-// thing isn't the root).
-bool IsCerRootMethod(MethodDesc *pMD)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMD));
- SO_TOLERANT;
- } CONTRACTL_END;
-
- // Treat IL stubs as CER roots (marshaling code needs to string together operations without being interruped by thread aborts).
- if (pMD->IsILStub())
- return true;
-
- // There are some well defined root methods defined by the system.
- if (pMD == g_pExecuteBackoutCodeHelperMethod)
- return true;
-
- // For now we just look to see whether there is some prep or fixup info stored for this method.
- Module *pModule = pMD->GetModule();
-
- if (pModule->GetCerPrepInfo(pMD) != NULL)
- return true;
-
-#ifdef FEATURE_PREJIT
- if (pModule->IsNgenCerRootMethod(pMD))
- return true;
-#endif
-
- return false;
-}
-
-// Fill the cache of overflowed generic dictionary entries that the jit maintains with all the overflow slots stored so far in the
-// dictionary layout.
-void PrepopulateGenericHandleCache(DictionaryLayout *pDictionaryLayout,
- MethodDesc *pMD,
- MethodTable *pMT)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- } CONTRACTL_END;
-
- // Dictionary overflow entries are recorded starting in the second bucket of the dictionary layout.
- DictionaryLayout *pOverflows = pDictionaryLayout->GetNextLayout();
-
- while (pOverflows) {
- for (DWORD i = 0; i < pOverflows->GetMaxSlots(); i++) {
- DictionaryEntryLayout *pEntry = pOverflows->GetEntryLayout(i);
-
- // We've finished as soon as we find the first unused slot.
- if (!pEntry->m_signature)
- return;
-
- // We have a valid overflow entry. Determine the handle value given the type context we have and push it into the JIT's
- // cache.
- JIT_GenericHandleWorker(pMD, pMT, pEntry->m_signature);
- }
- pOverflows = pOverflows->GetNextLayout();
- }
-}
-
-#ifdef FEATURE_PREJIT
-
-// Prepare the CER rooted at the given method (it's OK to pass a MethodDesc* that doesn't root a CER, in which case the method
-// is a no-op).
-void CerNgenRootTable::Restore(MethodDesc *pRootMD)
-{
-#ifndef CROSSGEN_COMPILE
- STANDARD_VM_CONTRACT;
-
- // We don't have a restoration bitmap at ngen time. No matter, we just always claim everything is restored.
- if (m_pRestoreBitmap == NULL)
- return;
-
- // Locate the root index from the table. Failure indicates there's no work to do.
- DWORD dwIndex = FindIndex(pRootMD);
- if (dwIndex == NoSuchRoot)
- return;
-
- _ASSERTE(m_pRoots[dwIndex].m_pRootMD == pRootMD);
-
- // Check then mark the fact that we're preparing (to prevent potential recursion).
- SigTypeContext typeContext;
- if (!GetThread()->GetCerPreparationState()->CanPreparationProceed(pRootMD, &typeContext))
- return;
-
- MethodCallGraphPreparer sPrep(pRootMD, &typeContext, true, true);
- MethodCallGraphPreparer::ThreadPreparingCerHolder sCerHolder(&sPrep);
-
-#ifdef _DEBUG
- if (GetCerLoggingOptions())
- {
- CER_LOG(RESTORE, ("---------------------------------------------------------------\n"));
- SString ssRootMethod;
- TypeString::AppendMethodInternal(ssRootMethod, pRootMD, TypeString::FormatNamespace | TypeString::FormatStubInfo);
- CER_LOG(RESTORE, ("Restoring CER graph from %S\n", ssRootMethod.GetUnicode()));
- }
-#endif
-
- g_IBCLogger.LogCerMethodListReadAccess(pRootMD);
-
- // Retrieve the CerRoot structure.
- CerRoot *pRoot = &m_pRoots[dwIndex];
- _ASSERTE(pRoot->m_pRootMD == pRootMD);
-
- // Scan the list of methods in the CER (the last one is a sentinel with a NULL MethodDesc*). Restore each method as we go.
- MethodContextElement *pEntry = pRoot->m_pList;
- while (pEntry->GetMethodDesc())
- {
- // Method desc and type handle pointers may still be tokenized at this point.
- Module::RestoreMethodDescPointer(&pEntry->m_pMethodDesc);
- Module::RestoreMethodTablePointer(&pEntry->m_pExactMT);
-
- g_IBCLogger.LogCerMethodListReadAccess(pEntry->GetMethodDesc());
-
- MethodDesc * pMD = pEntry->GetMethodDesc();
-
- // Check whether there are generic dictionaries that need to be pre-populated.
-
- // Don't use the direct PrepopulateDictionary method here for MethodTable/MethodDesc
- // - MethodTable: Takes binding considerations into account (which we don't care about)
- // - MethodDesc: Appears to use a representative class instantiation (and we have the exact one handy)
- //
- // Additionally, avoid touching EE Class if we don't need to
- MethodTable * pMT = pEntry->GetExactMT();
- if (pMT != NULL)
- {
- // MethodTable
- DictionaryLayout *pClassDictLayout = pMT->GetClass()->GetDictionaryLayout();
- if (pClassDictLayout)
- {
- pMT->GetDictionary()->PrepopulateDictionary(NULL, pMT, false);
-
- // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
- PrepopulateGenericHandleCache(pClassDictLayout, NULL, pMT);
- }
-
- // MethodDesc
- DictionaryLayout *pMethDictLayout = pMD->GetDictionaryLayout();
- if (pMethDictLayout)
- {
- pMD->GetMethodDictionary()->PrepopulateDictionary(pMD, NULL, false);
-
- // The dictionary may have overflowed in which case we need to prepopulate the jit's lookup cache as well.
- PrepopulateGenericHandleCache(pMethDictLayout, pMD, NULL);
- }
- }
-
- // Recreate stubs used by P/Invoke, COM calls, or FCalls by exercising the prestub.
- if (pMD->IsPointingToPrestub() && (pMD->IsNDirect() || pMD->IsComPlusCall() || pMD->IsFCall()))
- {
- pMD->EnsureActive();
- pMD->DoPrestub(NULL);
- }
-
-#ifdef _DEBUG
- if (GetCerLoggingOptions())
- {
- SString ssMethod;
- TypeString::AppendMethodInternal(ssMethod, pMD, TypeString::FormatNamespace | TypeString::FormatStubInfo);
- CER_LOG(RESTORE, (" %S\n", ssMethod.GetUnicode()));
- }
-#endif
-
- // Move to next entry.
- pEntry++;
- }
-
- CER_LOG(RESTORE, ("---------------------------------------------------------------\n"));
-
- // Mark this whole CER region as fixed up by setting a flag in the restore bitmap (kept separate so we can cluster all our page
- // writes).
- // Compute the DWORD offset into the flag array and then the mask for the specific bit in that DWORD.
- DWORD dwOffset = dwIndex / (sizeof(DWORD) * 8);
- DWORD dwMask = 1 << (dwIndex % (sizeof(DWORD) * 8));
- EnsureWritablePages(m_pRestoreBitmap, sizeof(DWORD) * SizeOfRestoreBitmap());
- FastInterlockOr(&m_pRestoreBitmap[dwOffset], dwMask);
-
- // If we fixed up any methods with their own CERs then we will have implicitly fixed up those too. Mark their fixup records as
- // completed as well to avoid further unecessary work.
- pEntry = pRoot->m_pList;
- while (pEntry->GetMethodDesc()) {
- dwIndex = FindIndex(pEntry->GetMethodDesc());
- if (dwIndex != NoSuchRoot) {
- dwOffset = dwIndex / (sizeof(DWORD) * 8);
- dwMask = 1 << (dwIndex % (sizeof(DWORD) * 8));
- FastInterlockOr(&m_pRestoreBitmap[dwOffset], dwMask);
- }
- pEntry++;
- }
-#endif // CROSSGEN_COMPILE
-}
-
-#ifdef FEATURE_NATIVE_IMAGE_GENERATION
-// Add a new root to the table, expanding it as necessary. Note that this method must be called with the CerCrst already held.
-void CerNgenRootTable::AddRoot(MethodDesc *pRootMD, MethodContextElement *pList)
-{
- CONTRACTL {
- STANDARD_VM_CHECK;
- PRECONDITION(IsOwnerOfCrst(pRootMD->GetModule()->GetCerCrst()));
- } CONTRACTL_END;
-
- // Ensure we have enough space first.
- if (m_cRoots == m_cSlots) {
- DWORD cNewSize = m_cSlots + 16;
- CerRoot *pNewArray = new CerRoot[cNewSize];
- memcpyNoGCRefs(pNewArray, m_pRoots, m_cRoots * sizeof(CerRoot));
- MethodContextElement **pNewRootsInCompilationOrder = new MethodContextElement*[cNewSize];
- memcpyNoGCRefs(pNewRootsInCompilationOrder, m_pRootsInCompilationOrder, m_cRoots * sizeof(MethodContextElement*) );
- m_cSlots = cNewSize;
- delete m_pRoots;
- m_pRoots = pNewArray;
- delete m_pRootsInCompilationOrder;
- m_pRootsInCompilationOrder = pNewRootsInCompilationOrder;
- }
-
- // Fill in the new entry in sorted order.
- DWORD i;
- for (i = 0; i < m_cRoots; i++)
- if ((UPTR) m_pRoots[i].m_pRootMD > (UPTR) pRootMD)
- break;
- if (i < m_cRoots)
- memmove(&m_pRoots[i + 1], &m_pRoots[i], (m_cRoots - i) * sizeof(CerRoot));
- m_pRoots[i].m_pRootMD = pRootMD;
- m_pRoots[i].m_pList = pList;
-
- m_pRootsInCompilationOrder[m_cRoots] = pList;
-
- m_cRoots++;
-}
-
-// Ngen callouts to help serialize this structure and its children to storage.
-void CerNgenRootTable::Save(DataImage *image, CorProfileData *profileData)
-{
- STANDARD_VM_CONTRACT;
-
-#ifdef _DEBUG
- DWORD dwMaxEntries = 0;
- DWORD dwTotalEntries = 0;
-#endif
-
- image->StoreStructure(this, sizeof(CerNgenRootTable), DataImage::ITEM_CER_ROOT_TABLE);
- image->StoreStructure(m_pRoots, m_cRoots * sizeof(CerRoot), DataImage::ITEM_CER_ROOT_TABLE);
-
- // Create a bitmap of boolean flags (1 bit per flag) indicating whether the CER at a given index in the array has been restored.
- // This is initially all zero and only filled in at runtime (keep all the flags together this way because they're the only
- // things we have to write at runtime and we want to keep them as dense as possible).
- _ASSERTE((SizeOfRestoreBitmap() % sizeof(DWORD)) == 0);
- m_pRestoreBitmap = new DWORD[SizeOfRestoreBitmap() / sizeof(DWORD)];
- memset(m_pRestoreBitmap, 0xff, SizeOfRestoreBitmap());
-
- image->StoreStructure(m_pRestoreBitmap,
- SizeOfRestoreBitmap(),
- DataImage::ITEM_CER_RESTORE_FLAGS);
-
- // Next save off the list of MethodContextElements associated with each root.
- for (DWORD i = 0; i < m_cRoots; i++) {
- MethodContextElement *pEntry = m_pRootsInCompilationOrder[i];
-
- // Count entries in list.
- DWORD cEntries = 0;
- while (pEntry->GetMethodDesc()) {
- cEntries++;
- pEntry++;
- }
-
- // Plus one for the sentinel value.
- cEntries++;
-
-#ifdef _DEBUG
- dwTotalEntries += cEntries;
- if (cEntries > dwMaxEntries)
- dwMaxEntries = cEntries;
-#endif
-
- // Store this list.
- image->StoreStructure(m_pRootsInCompilationOrder[i],
- cEntries * sizeof(MethodContextElement),
- DataImage::ITEM_CER_METHOD_LIST);
- }
-
-#ifdef _DEBUG
- if (m_cRoots > 0) {
- CER_LOG(NGEN_STATS, ("Saving %u CER roots in ngen image\n", m_cRoots));
- CER_LOG(NGEN_STATS, (" Max methods in CER: %u\n", dwMaxEntries));
- CER_LOG(NGEN_STATS, (" Avg methods in CER: %.1f\n", (float)((float)dwTotalEntries / (float)m_cRoots)));
- } else
- CER_LOG(NGEN_STATS, ("No CER roots in ngen image\n"));
-#endif
-}
-
-void CerNgenRootTable::Fixup(DataImage *image)
-{
- STANDARD_VM_CONTRACT;
-
- DWORD i;
-
- // We still use the point to the root array even though at runtime the two structures will be adjacent.
- image->FixupPointerField(this, offsetof(CerNgenRootTable, m_pRoots));
-
- // Restoration flags are used only at runtime and must start off zeroed.
- image->FixupPointerField(this, offsetof(CerNgenRootTable, m_pRestoreBitmap));
- image->ZeroField(m_pRestoreBitmap, 0, SizeOfRestoreBitmap());
-
- // The root list in compilation order is only used at ngen time, and is not written into native image.
- image->ZeroPointerField(this, offsetof(CerNgenRootTable, m_pRootsInCompilationOrder));
-
- // Fixup all the pointers in the individual CERs.
- for (i = 0; i < m_cRoots; i++) {
-
- // For each MethodContextElement in the list we need to fixup a pointer to a MethodDesc and two array pointers (one for any
- // class instantiation and one for any method instantiation). The actual MethodDescs and TypeHandles themselves are already
- // fixed up as are the instantiation arrays we point to (they're the ones inside the generic dictionaries of the class/method
- // concerned).
- MethodContextElement *pList = m_pRootsInCompilationOrder[i];
- MethodContextElement *pEntry = pList;
- while (pEntry->GetMethodDesc()) {
- image->FixupMethodDescPointer(pList, &pEntry->m_pMethodDesc);
- image->FixupMethodTablePointer(pList, &pEntry->m_pExactMT);
- pEntry++;
- }
- }
-}
-
-void CerNgenRootTable::FixupRVAs(DataImage *image)
-{
- STANDARD_VM_CONTRACT;
-
- DWORD i, j;
-
- // Now we go back through the root table and sort the entries based on the locations of the root method descs in the new image
- // (they may be rearranged due to IBC profiling).
- CerRoot *pNewRoots = (CerRoot*)image->GetImagePointer(m_pRoots);
- PREFIX_ASSUME(pNewRoots != NULL);
-
- // Simple insertion sort. Starting at the second element insert a candidate into its correct location in the sub-list
- // preceding it (which by definition will already be sorted).
- for (i = 1; i < m_cRoots; i++)
- {
- // Look at all of the preceding elements for the first that is larger than the candidate (i.e. should succeed the
- // candidate in sorted order). If we don't find one then the candidate is already in place and we can proceed to the
- // next candidate.
- for (j = 0; j < i; j++)
- if (image->GetRVA(pNewRoots[j].m_pRootMD) > image->GetRVA(pNewRoots[i].m_pRootMD)) {
-
- // Need to move candidate element up. Cache its value because we're about to overwrite it.
- MethodDesc *pTmpRootMD = pNewRoots[i].m_pRootMD;
- MethodContextElement *pTmpList = pNewRoots[i].m_pList;
-
- // Shuffle the sorted list one up to make room for the candidate.
- memmove(&pNewRoots[j + 1], &pNewRoots[j], (i - j) * sizeof(CerRoot));
-
- // Insert the candidate into position.
- pNewRoots[j].m_pRootMD = pTmpRootMD;
- pNewRoots[j].m_pList = pTmpList;
-
- // Sorted the candidate, move onto the next.
- break;
- }
- }
-
- // Fixup all the pointers in the individual CERs.
- for (i = 0; i < m_cRoots; i++) {
- // Fix up the pointer to the root method and the list of methods in the CER.
- image->FixupField(m_pRoots, sizeof(CerRoot) * i + offsetof(CerRoot, m_pRootMD),
- pNewRoots[i].m_pRootMD);
- image->FixupField(m_pRoots, sizeof(CerRoot) * i + offsetof(CerRoot, m_pList),
- pNewRoots[i].m_pList);
- }
-}
-#endif // FEATURE_NATIVE_IMAGE_GENERATION
-
-// Locate the index of a given CerRoot record in the array given the root method. This is used to access the array and to locate the
-// restored flag for the entry in the restored bitmap. NoSuchRoot is returned if the root cannot be found.
-DWORD CerNgenRootTable::FindIndex(MethodDesc *pRootMD)
-{
- CONTRACTL {
- NOTHROW;
- MODE_ANY;
- GC_NOTRIGGER;
- PRECONDITION(CheckPointer(pRootMD));
- SO_TOLERANT;
- } CONTRACTL_END;
-
- // The table is guaranteed to be sorted, so we can lookup our target with a binary search.
- DWORD dwLow = 0;
- DWORD dwHigh = m_cRoots - 1;
- while (true) {
-
- // Take out the simple cases first.
-
- // The range has only one entry.
- if (dwLow == dwHigh) {
- if (m_pRoots[dwLow].m_pRootMD == pRootMD)
- return dwLow;
-#ifdef _DEBUG
- for (DWORD i = 0; i < m_cRoots; i++)
- _ASSERTE(m_pRoots[i].m_pRootMD != pRootMD);
-#endif
- return NoSuchRoot;
- }
-
- // The range has only two entries.
- if (dwLow == dwHigh - 1) {
- if (m_pRoots[dwLow].m_pRootMD == pRootMD)
- return dwLow;
- if (m_pRoots[dwHigh].m_pRootMD == pRootMD)
- return dwHigh;
-#ifdef _DEBUG
- for (DWORD i = 0; i < m_cRoots; i++)
- _ASSERTE(m_pRoots[i].m_pRootMD != pRootMD);
-#endif
- return NoSuchRoot;
- }
-
- // Now we can compute a midpoint that is definitely distinct and in-between the endpoints.
- DWORD dwMid = dwLow + ((dwHigh - dwLow) / 2);
-
- // Did we nail it?
- if (m_pRoots[dwMid].m_pRootMD == pRootMD)
- return dwMid;
-
- // Otherwise adjust our range to be the bit we haven't looked at and iterate.
- if ((UPTR)m_pRoots[dwMid].m_pRootMD < (UPTR)pRootMD)
- dwLow = dwMid + 1;
- else
- dwHigh = dwMid - 1;
- }
-}
-
-// Prepare the class if it is derived from CriticalFinalizerObject. This is used at ngen time since such classes are normally
-// prepared at runtime (at instantiation) and would therefore miss the ngen image.
-void PrepareCriticalType(MethodTable * pMT)
-{
- STANDARD_VM_CONTRACT;
-
- // Prepare any class that satisfies the criteria. Pass a pointer to this module so that we'll only prepare any overrides of
- // the critical methods that were actually introduced here.
- if (pMT->HasCriticalFinalizer())
- PrepareCriticalFinalizerObject(pMT, pMT->GetLoaderModule());
-}
-
-// Prepare a method and its statically determinable call graph if a hint attribute has been applied. This is only called at ngen
-// time to save additional preparation information into the ngen image that wouldn't normally be there (and thus lower runtime
-// overheads).
-void PrePrepareMethodIfNecessary(CORINFO_METHOD_HANDLE hMethod)
-{
- STANDARD_VM_CONTRACT;
-
- EX_TRY {
-
- // Translate jit-style method handle into method desc.
- MethodDesc *pMD = GetMethod(hMethod);
-
- // Check for the existance of the attribute.
- IMDInternalImport *pImport = pMD->GetMDImport();
- mdToken tkMethod = pMD->GetMemberDef();
- HRESULT hr = pImport->GetCustomAttributeByName(tkMethod,
- "System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute",
- NULL, NULL);
-
- // TODO: We should add IBC probes which indicate that methods need to be preprepared
- // which can then be reflected in the IBC data, we can add an additional check
- // here to cover that case, then we can get around this problem with profiling
- // instead of manual programmer effort.
-
- // Only prepare if we definitely saw the attribute.
- if (hr == S_OK) {
- // Prepare the method and its graph. There should never be any open type parameters (we can't do much at ngen time with these),
- // so we can pass a null type context.
- SigTypeContext sTypeContext;
- MethodCallGraphPreparer mcgp(pMD, &sTypeContext, true, true);
- mcgp.Run();
- }
-
- } EX_CATCH {
- } EX_END_CATCH(SwallowAllExceptions);
-}
-
-#endif // FEATURE_PREJIT
-
-PtrHashCache::PtrHashCache()
-{
- LIMITED_METHOD_CONTRACT;
- ZeroMemory(this, sizeof(*this));
-
- // First entry in each bucket is a chain index used to evenly distribute inserts within a bucket.
- _ASSERTE(PHC_CHAIN > 1);
-}
-
-bool PtrHashCache::Lookup(void *pKey, DWORD *pdwValue)
-{
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(((UINT_PTR)pKey & PHC_DATA_MASK) == 0);
-
- DWORD dwBucket = GetHash(pKey);
-
- // Skip first entry in bucket, it's a sequence number used for insertions.
- for (DWORD i = 1; i < PHC_CHAIN; i++) {
- UINT_PTR uipEntry = VolatileLoad<UINT_PTR>(&m_rEntries[(dwBucket * PHC_CHAIN) + i]);
- if ((uipEntry & ~PHC_DATA_MASK) == (UINT_PTR)pKey) {
-#ifdef _DEBUG
- FastInterlockIncrement((LONG*)&m_dwHits);
-#endif
- *pdwValue = uipEntry & PHC_DATA_MASK;
- return true;
- }
- }
-
-#ifdef _DEBUG
- FastInterlockIncrement((LONG*)&m_dwMisses);
-#endif
- return false;
-}
-
-void PtrHashCache::Add(void *pKey, DWORD dwValue)
-{
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(((UINT_PTR)pKey & PHC_DATA_MASK) == 0);
- _ASSERTE((dwValue & ~PHC_DATA_MASK) == 0);
-
- DWORD dwBucket = GetHash(pKey);
-
- // We keep a sequence number in the first entry of the bucket so that we distribute insertions within the bucket evenly. We're
- // racing when we update this value, but it doesn't matter if we lose an update (we're a cache after all). We don't bother being
- // careful to avoid overflowing the value here (we just keep incrementing); we'll do the modulo logic when we insert our value
- // instead.
- DWORD dwIndex = static_cast<DWORD>(m_rEntries[dwBucket * PHC_CHAIN]++);
- dwIndex = (dwIndex % (PHC_CHAIN - 1)) + 1;
- m_rEntries[(dwBucket * PHC_CHAIN) + dwIndex] = ((UINT_PTR)pKey & ~PHC_DATA_MASK) | dwValue;
-}
-
-DWORD PtrHashCache::GetHash(void *pKey)
-{
- LIMITED_METHOD_CONTRACT;
-
- return (DWORD)(((UINT_PTR)pKey >> 4) % PHC_BUCKETS);
-}
-
-#ifdef _DEBUG
-void PtrHashCache::DbgDumpStats()
-{
-#if 0
- if ((m_dwHits + m_dwMisses) == 0)
- return;
-
- printf("Dumping stats for PtrHashCache %08X\n", this);
- printf(" %u hits, %u misses (%u%% hit rate)\n", m_dwHits, m_dwMisses, (m_dwHits * 100) / (m_dwHits + m_dwMisses));
- for (DWORD i = 0; i < PHC_BUCKETS; i++)
- printf(" [%2u] : %u insertions\n", i, m_rEntries[i * PHC_CHAIN]);
- printf("\n");
-#endif
-}
-#endif
diff --git a/src/vm/crossdomaincalls.cpp b/src/vm/crossdomaincalls.cpp
deleted file mode 100644
index b528915a54..0000000000
--- a/src/vm/crossdomaincalls.cpp
+++ /dev/null
@@ -1,2587 +0,0 @@
-// 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.
-//
-// File: CrossDomainCalls.cpp
-//
-
-//
-// The CrossDomainCall class provides a fast path of execution for qualifying
-// cross domain calls. Asynch calls, one way calls, calls on context bound objects
-// etc dont qualify.
-//
-
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-
-#include "crossdomaincalls.h"
-#include "callhelpers.h"
-#include "remoting.h"
-#include "objectclone.h"
-#include "dbginterface.h"
-#include "stackprobe.h"
-#include "virtualcallstub.h"
-#include "typeparse.h"
-#include "typestring.h"
-#include "appdomain.inl"
-#include "callingconvention.h"
-
-// See explanation of flags in crossdomaincalls.h
-RemotableMethodInfo::XADOptimizationType
-RemotableMethodInfo::IsCrossAppDomainOptimizable(MethodDesc *pMeth, DWORD *pNumStackSlotsToCopy)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- // This method table might be representative, but that's OK for the kinds of analysis we're about to do.
- MethodTable *pMT = pMeth->GetMethodTable()->GetCanonicalMethodTable();
-
- _ASSERTE(pMT->HasRemotableMethodInfo());
- _ASSERTE(pMT->GetRemotableMethodInfo());
-
- if (pMT->IsContextful())
- return XAD_NOT_OPTIMIZABLE;
-
- DWORD flags;
-
- // If this method is generic then we can't used cached analysis data stored on the method table and keyed by slot -- the same
- // slot is shared by methods with very different characteristics (such as whether the return type is a GC ref etc.).
- if (pMeth->GetNumGenericMethodArgs() > 0)
- {
- flags = DoStaticAnalysis(pMeth);
- }
- else
- {
- _ASSERTE(pMeth->GetSlot() < pMeth->GetMethodTable()->GetNumVtableSlots());
- RemotableMethodInfo *pRMI = &(pMT->GetRemotableMethodInfo()->GetRemotableMethodInfo()[pMeth->GetSlot()]);
- flags = pRMI->m_OptFlags;
-
- if (!(flags & XAD_FLAGS_INITIALIZED))
- {
- flags = DoStaticAnalysis(pMeth);
- pRMI->m_OptFlags = flags;
- }
- }
-
- *pNumStackSlotsToCopy = flags & XAD_ARG_COUNT_MASK;
-
- return (XADOptimizationType) (flags & XAD_FLAG_MASK);
-}
-
-// This method is not synchronized because the operation is idempotent
-DWORD
-RemotableMethodInfo::DoStaticAnalysis(MethodDesc *pMeth)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- PRECONDITION(CheckPointer(pMeth));
- }
- CONTRACTL_END
-
- BOOL bCallArgsBlittable = TRUE;
- BOOL bRetArgBlittable = TRUE;
- BOOL bOptimizable = TRUE;
- BOOL bMethodIsVirtual = FALSE;
- BOOL bArgsHaveAFloat = FALSE;
-
- DWORD numStackBytes = 0;
- DWORD numStackSlots = 0;
- DWORD returnTypeFlags = 0;
-
- if (pMeth->ContainsGenericVariables())
- {
- bOptimizable = FALSE;
- }
- else
- {
- MetaSig mSig(pMeth);
- ArgIterator argit(&mSig);
-
- SigPointer spRet;
- CorElementType retElem;
-
- IMDInternalImport *pMDImport = pMeth->GetModule()->GetMDImport();
- MDEnumHolder ePm(pMDImport); // For enumerating params.
- mdParamDef tkPm; // A param token.
- DWORD dwFlags; // Param flags.
- USHORT usSeq; // Sequence of a parameter.
-
- if (pMeth->IsOneWay())
- {
- bOptimizable = FALSE;
- goto SetFlags;
- }
-
- if (pMeth->IsVirtual())
- {
- bMethodIsVirtual = TRUE;
- }
-
- numStackBytes = argit.SizeOfFrameArgumentArray();
-
- _ASSERTE(numStackBytes % sizeof(SIZE_T) == 0);
- numStackSlots = numStackBytes / sizeof(SIZE_T);
-
- if (numStackSlots > XAD_ARG_COUNT_MASK)
- {
- bOptimizable = FALSE;
- goto SetFlags;
- }
-
- // Check if there are any [Out] args. If there are, skip the fast path
- IfFailThrow(pMDImport->EnumInit(mdtParamDef, pMeth->GetMemberDef(), &ePm));
-
- // Enumerate through the params and check the flags.
- while (pMDImport->EnumNext(&ePm, &tkPm))
- {
- LPCSTR szParamName_Ignore;
- IfFailThrow(pMDImport->GetParamDefProps(tkPm, &usSeq, &dwFlags, &szParamName_Ignore));
- if (usSeq == 0) // Skip return type flags.
- continue;
- // If the param has Out attribute, do not use fast path for this method
- if (IsPdOut(dwFlags))
- {
- bOptimizable = FALSE;
- goto SetFlags;
- }
- }
-
- // We're getting SigPointer first because this way we can differentiate E_T_STRING and E_T_CLASS
- spRet = mSig.GetReturnProps();
- IfFailThrow(spRet.GetElemType(&retElem));
- if (retElem > ELEMENT_TYPE_PTR &&
- retElem != ELEMENT_TYPE_I &&
- retElem != ELEMENT_TYPE_U &&
- retElem != ELEMENT_TYPE_FNPTR)
- {
- bRetArgBlittable = FALSE;
- }
-
- // Now we can normalize the return type so as to get rid of any generic type variables and the like.
- retElem = mSig.GetReturnType();
-
- if (retElem == ELEMENT_TYPE_VALUETYPE)
- {
- // Make a note that we have a struct in the signature. This way we wont blit the contents
- // and end up in a situation where we have data, but the type isnt loaded yet
- bCallArgsBlittable = FALSE;
-
- // Do some further inspection
- TypeHandle retTypeHandle = mSig.GetRetTypeHandleThrowing();
-
- // Currently we don't handle the special unbox handling for ret values of Nullable<T> in MarshalAndCall
- if (Nullable::IsNullableType(retTypeHandle))
- {
- bOptimizable = FALSE;
- }
-
- retElem = retTypeHandle.GetInternalCorElementType();
- if ((retElem <= ELEMENT_TYPE_PTR || retElem == ELEMENT_TYPE_I || retElem == ELEMENT_TYPE_U) &&
- !retTypeHandle.AsMethodTable()->CannotBeBlittedByObjectCloner())
- bRetArgBlittable = TRUE;
- }
-
- // Check if the return type is a GC ref
- if (gElementTypeInfo[retElem].m_gc == TYPE_GC_REF)
- {
- returnTypeFlags = XAD_RET_GC_REF;
- }
- else
- {
- returnTypeFlags = GetRetTypeFlagsFromFPReturnSize(argit.GetFPReturnSize());
- }
-
- CorElementType currType;
- while ((currType = mSig.NextArg()) != ELEMENT_TYPE_END)
- {
- SigPointer sp = mSig.GetArgProps();
- CorElementType retTy;
- IfFailThrow(sp.GetElemType(&retTy));
- if (retTy > ELEMENT_TYPE_PTR &&
- retTy != ELEMENT_TYPE_VALUETYPE &&
- retTy != ELEMENT_TYPE_I &&
- retTy != ELEMENT_TYPE_U &&
- retTy != ELEMENT_TYPE_FNPTR)
- {
- bCallArgsBlittable = FALSE;
- }
-
- // Currently we don't handle the special unbox handling for Nullable<T> for byrefs in MarshalAndCall
- if (currType == ELEMENT_TYPE_BYREF)
- {
- TypeHandle refType;
- if (mSig.GetByRefType(&refType) == ELEMENT_TYPE_VALUETYPE)
- if (Nullable::IsNullableType(refType))
- {
- bOptimizable = FALSE;
- }
- }
- else if (currType == ELEMENT_TYPE_VALUETYPE)
- {
-#if ENREGISTERED_PARAMTYPE_MAXSIZE
- // Since we also do implict ByRef in some cases, we also have to probit the optimization there too
- TypeHandle argType = mSig.GetLastTypeHandleThrowing();
- if (Nullable::IsNullableType(argType))
- {
- if (ArgIterator::IsArgPassedByRef(argType))
- bOptimizable = FALSE;
- }
-#endif
- bCallArgsBlittable = FALSE;
- }
- else if (currType == ELEMENT_TYPE_R4 || currType == ELEMENT_TYPE_R8)
- {
- bArgsHaveAFloat = TRUE;
- }
- }
- }
-
-SetFlags:
- DWORD optimizationFlags = 0;
- if (!bOptimizable)
- {
- optimizationFlags |= XAD_NOT_OPTIMIZABLE;
- }
- else
- {
- optimizationFlags |= returnTypeFlags;
-
- if (bCallArgsBlittable)
- {
- optimizationFlags |= XAD_BLITTABLE_ARGS;
- }
- if (bRetArgBlittable)
- {
- optimizationFlags |= XAD_BLITTABLE_RET;
- }
- if (bMethodIsVirtual)
- {
- optimizationFlags |= XAD_METHOD_IS_VIRTUAL;
- }
- if (bArgsHaveAFloat)
- {
- optimizationFlags |= XAD_ARGS_HAVE_A_FLOAT;
- }
- }
- optimizationFlags |= numStackSlots;
- optimizationFlags |= XAD_FLAGS_INITIALIZED;
-
- return optimizationFlags;
-}
-
-#ifndef CROSSGEN_COMPILE
-
-BOOL RemotableMethodInfo::TypeIsConduciveToBlitting(MethodTable *pFromMT, MethodTable *pToMT)
-{
- LIMITED_METHOD_CONTRACT;
- // Presence of GC fields or certain atributes, rules out blittability
- if (pFromMT->CannotBeBlittedByObjectCloner() ||
- pToMT->CannotBeBlittedByObjectCloner())
- return FALSE;
-
- // Shared types are okay to blit
- if (pFromMT == pToMT)
- return TRUE;
-
- if (pFromMT->IsEnum() && pToMT->IsEnum()
- && pFromMT->GetBaseSize() == pToMT->GetBaseSize())
- return TRUE;
-
- return FALSE;
-}
-
-PtrHashMap *CrossDomainTypeMap::s_crossDomainMTMap = NULL;
-SimpleRWLock *CrossDomainTypeMap::s_MTMapLock = NULL;
-
-BOOL CrossDomainTypeMap::CompareMTMapEntry (UPTR val1, UPTR val2)
-{
- CONTRACTL {
- MODE_ANY;
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- CrossDomainTypeMap::MTMapEntry *entry1 = (CrossDomainTypeMap::MTMapEntry *)(val1 << 1);
- CrossDomainTypeMap::MTMapEntry *entry2 = (CrossDomainTypeMap::MTMapEntry *)val2;
-
- if (entry1->m_pFromMT == entry2->m_pFromMT &&
- entry1->m_dwFromDomain == entry2->m_dwFromDomain &&
- entry1->m_dwToDomain == entry2->m_dwToDomain)
- return TRUE;
-
- return FALSE;
-}
-
-CrossDomainTypeMap::MTMapEntry::MTMapEntry(AppDomain *pFromDomain, MethodTable *pFromMT, AppDomain *pToDomain, MethodTable *pToMT)
-{
- WRAPPER_NO_CONTRACT;
-
- m_dwFromDomain = pFromDomain->GetId();
- m_dwToDomain = pToDomain->GetId();
- m_pFromMT = pFromMT;
- m_pToMT = pToMT;
-}
-
-static BOOL IsOwnerOfRWLock(LPVOID lock)
-{
- // @TODO - SimpleRWLock does not have knowledge of which thread gets the writer
- // lock, so no way to verify
- return TRUE;
-}
-
-/*static*/
-PtrHashMap *CrossDomainTypeMap::GetTypeMap()
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- if (s_MTMapLock == NULL)
- {
- void *tempLockSpace = SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SimpleRWLock)));
- SimpleRWLock *tempLock = new (tempLockSpace) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT);
-
- if (FastInterlockCompareExchangePointer(&s_MTMapLock,
- tempLock,
- NULL) != NULL)
- {
- // We lost the race
- SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->BackoutMem(tempLockSpace, sizeof(SimpleRWLock));
- }
- }
-
- // Now we have a Crst we can use to synchronize the remainder of the init.
- if (s_crossDomainMTMap == NULL)
- {
- SimpleWriteLockHolder swlh(s_MTMapLock);
-
- if (s_crossDomainMTMap == NULL)
- {
- PtrHashMap *map = new (SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()) PtrHashMap ();
- LockOwner lock = {s_MTMapLock, IsOwnerOfRWLock};
- map->Init (32, CompareMTMapEntry, TRUE, &lock);
- s_crossDomainMTMap = map;
- }
- }
-
- return s_crossDomainMTMap;
-}
-
-MethodTable *
-CrossDomainTypeMap::GetMethodTableForDomain(MethodTable *pMT, AppDomain *pFromDomain, AppDomain *pToDomain)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- PtrHashMap *map = GetTypeMap();
-
- MTMapEntry admt(pFromDomain, pMT, pToDomain, NULL);
-
- SimpleReadLockHolder srlh(s_MTMapLock);
- MTMapEntry *pFound = (MTMapEntry *) map->LookupValue(admt.GetHash(), (LPVOID) &admt);
- if ((MTMapEntry *)INVALIDENTRY == pFound)
- return NULL;
-
- return pFound->m_pToMT;
-}
-
-void
-CrossDomainTypeMap::SetMethodTableForDomain(MethodTable *pFromMT, AppDomain *pFromDomain, MethodTable *pToMT, AppDomain *pToDomain)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- PtrHashMap *map = GetTypeMap();
-
- NewHolder<MTMapEntry> admt(new MTMapEntry(pFromDomain, pFromMT, pToDomain, pToMT));
- PREFIX_ASSUME(admt != NULL);
-
- SimpleWriteLockHolder swlh(s_MTMapLock);
-
- UPTR key = admt->GetHash();
-
- MTMapEntry *pFound = (MTMapEntry *) map->LookupValue(key, (LPVOID) admt);
- if ((MTMapEntry *)INVALIDENTRY == pFound)
- {
- map->InsertValue(key, (LPVOID) admt);
- admt.SuppressRelease();
- }
-}
-
-// Remove any entries in the table that refer to an appdomain that is no longer live.
-void CrossDomainTypeMap::FlushStaleEntries()
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- NOTHROW;
- }
- CONTRACTL_END
-
- if (s_MTMapLock == NULL || s_crossDomainMTMap == NULL)
- return;
-
- SimpleWriteLockHolder swlh(s_MTMapLock);
-
- bool fDeletedEntry = false;
- PtrHashMap::PtrIterator iter = s_crossDomainMTMap->begin();
- while (!iter.end())
- {
- MTMapEntry *pEntry = (MTMapEntry *)iter.GetValue();
- AppDomainFromIDHolder adFrom(pEntry->m_dwFromDomain, TRUE);
- AppDomainFromIDHolder adTo(pEntry->m_dwToDomain, TRUE);
- if (adFrom.IsUnloaded() ||
- adTo.IsUnloaded())
- {
-#ifdef _DEBUG
- LPVOID pDeletedEntry =
-#endif
- s_crossDomainMTMap->DeleteValue(pEntry->GetHash(), pEntry);
- _ASSERTE(pDeletedEntry == pEntry);
- delete pEntry;
- fDeletedEntry = true;
- }
- ++iter;
- }
-
- if (fDeletedEntry)
- s_crossDomainMTMap->Compact();
-}
-
-
-
-// Before a cross appdomain call, we read the principal on the thread and set it aside, so that it can
-// be restored when the call returns.
-// In addition, we let the principal flow thru to the called appdomain, if the principal is serializable
-OBJECTREF CrossDomainChannel::ReadPrincipal()
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- THREADBASEREF ref = (THREADBASEREF) GetThread()->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF )ref->GetExecutionContext();
- if (refExecCtx == NULL)
- return NULL;
-
- LOGICALCALLCONTEXTREF refCallContext = refExecCtx->GetLogicalCallContext();
- if (refCallContext == NULL)
- return NULL;
-
- CCSECURITYDATAREF refSecurityData = refCallContext->GetSecurityData();
- if (refSecurityData == NULL)
- return NULL;
-
- OBJECTREF refPrincipal = refSecurityData->GetPrincipal();
- if (refPrincipal != NULL)
- {
- MethodTable *pPrincipalType = refPrincipal->GetMethodTable();
- if (!pPrincipalType->IsSerializable())
- {
- refSecurityData->SetPrincipal(NULL);
- }
- }
-
- return refPrincipal;
-}
-
-// Principal never flows from called appdomain back to caller domain.
-VOID CrossDomainChannel::ResetPrincipal()
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- THREADBASEREF ref = (THREADBASEREF) GetThread()->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF )ref->GetExecutionContext();
- if (refExecCtx == NULL)
- return;
-
- LOGICALCALLCONTEXTREF refCallContext = refExecCtx->GetLogicalCallContext();
- if (refCallContext == NULL)
- return;
-
- CCSECURITYDATAREF refSecurityData = refCallContext->GetSecurityData();
- if (refSecurityData == NULL)
- return;
-
- refSecurityData->SetPrincipal(NULL);
-
-}
-
-// At the end of a cross-appdomain call, we restore whatever principal was on the thread at the beginning of the call
-VOID CrossDomainChannel::RestorePrincipal(OBJECTREF *prefPrincipal)
-{
- CONTRACTL
- {
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- THREADBASEREF ref = (THREADBASEREF) GetThread()->GetExposedObjectRaw();
- if (ref == NULL)
- return;
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF )ref->GetExecutionContext();
- _ASSERTE(*prefPrincipal == NULL || refExecCtx != NULL);
-
- if (refExecCtx == NULL)
- return;
-
- LOGICALCALLCONTEXTREF refCallContext = refExecCtx->GetLogicalCallContext();
- if (refCallContext == NULL)
- return;
-
- CCSECURITYDATAREF refSecurityData = refCallContext->GetSecurityData();
- _ASSERTE(*prefPrincipal == NULL || refSecurityData != NULL);
-
- if (refSecurityData == NULL)
- return;
-
- refSecurityData->SetPrincipal(*prefPrincipal);
-
-}
-
-// This method mimics the Lease renewal mechanism of the managed CrossDomainChannel
-// The lease object for the server can be accessed via its ServerIdentity.
-VOID CrossDomainChannel::RenewLease()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- // Check if lease needs to be renewed
- OBJECTREF refSrvIdentity = ObjectFromHandle(m_refSrvIdentity);
- if (refSrvIdentity == NULL)
- return;
-
- OBJECTREF refLease = ObjectToOBJECTREF((Object *)refSrvIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfLeaseInIdentity()));
- if (refLease != NULL)
- {
- GCPROTECT_BEGIN(refLease);
- MethodDesc *pLeaseMeth = CRemotingServices::MDofRenewLeaseOnCall();
- PCODE pCode = (PCODE)pLeaseMeth->GetCallTarget(&refLease);
-
- PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCode);
-
- DECLARE_ARGHOLDER_ARRAY(args, 2);
-
- args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(refLease);
- args[ARGNUM_1] = NULL;
-
- CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
- CALL_MANAGED_METHOD_NORET(args);
-
- GCPROTECT_END();
- }
-}
-
-// Given a client side instantiated method desc and a server side generic definition method desc extract the instantiation,
-// translate all the types involved into the server domain and return the fully instantiated server method desc. Note that the
-// client and server method descs might not represent the same type -- the client method might be from an interface, whereas the
-// server method will always be on the real class.
-MethodDesc *InstantiateMethod(MethodDesc *pClientMD, MethodDesc *pServerMD, MethodTable *pServerMT)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- PRECONDITION(CheckPointer(pClientMD));
- PRECONDITION(pClientMD->HasMethodInstantiation());
- PRECONDITION(CheckPointer(pServerMD));
- PRECONDITION(pServerMD->HasMethodInstantiation());
- PRECONDITION(pClientMD->GetNumGenericMethodArgs() == pServerMD->GetNumGenericMethodArgs());
- }
- CONTRACTL_END;
-
- Instantiation clientInst = pClientMD->GetMethodInstantiation();
-
- DWORD dwAllocaSize;
- if (!ClrSafeInt<DWORD>::multiply(clientInst.GetNumArgs(), sizeof(TypeHandle), dwAllocaSize))
- COMPlusThrowHR(COR_E_OVERFLOW);
-
- CQuickBytes qbServerInst;
- TypeHandle *pServerInst = reinterpret_cast<TypeHandle*>(qbServerInst.AllocThrows(dwAllocaSize));
-
- for (DWORD dwArgNum = 0; dwArgNum < clientInst.GetNumArgs(); dwArgNum++)
- {
- SString thName;
- TypeString::AppendType(thName, clientInst[dwArgNum], TypeString::FormatNamespace|TypeString::FormatFullInst|TypeString::FormatAssembly);
-
- pServerInst[dwArgNum] = TypeName::GetTypeFromAsmQualifiedName(thName.GetUnicode(), pClientMD->IsIntrospectionOnly());
-
- _ASSERTE(!pServerInst[dwArgNum].IsNull());
-
- // Check that the type is actually visible on the server side. This prevents a malicious client from luring a trusted server
- // into manipulating types that would be normally invisible to it.
- if (!pServerInst[dwArgNum].IsExternallyVisible())
- COMPlusThrow(kRemotingException, W("Remoting_NonPublicOrStaticCantBeCalledRemotely"));
- }
-
- // Find or create the method will the full instantiation.
- return MethodDesc::FindOrCreateAssociatedMethodDesc(pServerMD,
- pServerMT,
- FALSE,
- Instantiation(pServerInst, clientInst.GetNumArgs()),
- FALSE);
-}
-
-BOOL CrossDomainChannel::GetGenericMethodAddress(MethodTable *pServerType)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END;
-
- m_pSrvMD = InstantiateMethod(m_pCliMD, pServerType->GetMethodDescForSlot(m_pCliMD->GetSlot()), pServerType);
-
- OBJECTREF thisObj = GetServerObject();
- m_pTargetAddress = m_pSrvMD->GetCallTarget(&thisObj);
-
- return TRUE;
-}
-
-// We use this method to find the target address when we are convinced that the most derived type the proxy is cast
-// to on the client side is equivalent to the corresponding type on the server side, in the sense the method table
-// layouts are similar. This fact can be used to look up method addresses faster
-BOOL CrossDomainChannel::GetTargetAddressFast(DWORD optFlags, MethodTable *pSrvMT, BOOL bFindServerMD)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- _ASSERTE(m_pCliMD);
- _ASSERTE(m_pSrvDomain == SystemDomain::GetCurrentDomain()->GetId());
-
- MethodTable *pCliMT = m_pCliMD->GetMethodTable();
- _ASSERTE(!pCliMT->IsInterface());
-
- m_pSrvMD = NULL;
-
- DWORD dwMethodSlot = m_pCliMD->GetSlot();
- if (!RemotableMethodInfo::IsMethodVirtual(m_xret))
- {
- // This is a non-virtual method. Find the matching MT on the
- // server side, dereference the slot and get the method address
-
- MethodTable *pSrvSideMT = pSrvMT;
-
- // We now need to walk the server type hierarchy till we find the type that
- // declared the method we're going to call
-
- // First find how far is the type declaring the called method, from System.Object
- DWORD cliDepth = 0;
- MethodTable *pCurrLevel = pCliMT;
- while (pCurrLevel != NULL)
- {
- _ASSERTE(pCurrLevel);
- pCurrLevel = pCurrLevel->GetParentMethodTable();
- cliDepth++;
- };
-
- // Next find how deep is the server type from System.Object
- DWORD srvDepth = 0;
- pCurrLevel = pSrvMT;
- while (pCurrLevel != NULL)
- {
- _ASSERTE(pCurrLevel);
- pCurrLevel = pCurrLevel->GetParentMethodTable();
- srvDepth++;
- };
-
- _ASSERTE(srvDepth >= cliDepth);
-
- while (srvDepth > cliDepth)
- {
- _ASSERTE(pSrvSideMT);
- _ASSERTE(srvDepth != 0);
- pSrvSideMT = pSrvSideMT->GetParentMethodTable();
- srvDepth--;
- };
-
- if (m_pCliMD->HasMethodInstantiation())
- {
- GetGenericMethodAddress(pSrvSideMT);
- }
- else
- {
- m_pTargetAddress = pSrvSideMT->GetRestoredSlot(dwMethodSlot);
-
-#ifndef _DEBUG
- if (bFindServerMD)
-#endif
- m_pSrvMD = pSrvSideMT->GetMethodDescForSlot(dwMethodSlot);
- }
- }
- else
- {
- if (m_pCliMD->HasMethodInstantiation())
- GetGenericMethodAddress(pSrvMT);
- else
- {
- m_pTargetAddress = pSrvMT->GetRestoredSlot(dwMethodSlot);
-
-#ifndef _DEBUG
- if (bFindServerMD)
-#endif
- m_pSrvMD = pSrvMT->GetMethodDescForSlot(dwMethodSlot);
- }
- }
-
- _ASSERTE(m_pTargetAddress);
-#ifdef _DEBUG
- _ASSERTE(!strcmp(m_pSrvMD->GetName(), m_pCliMD->GetName()));
- DefineFullyQualifiedNameForClass();
- LPCUTF8 szSrvTypeName = GetFullyQualifiedNameForClassNestedAware(pSrvMT);
- LPCUTF8 pszMethodName = m_pCliMD->GetName();
- LOG((LF_REMOTING, LL_INFO100, "GetTargetAddressFast. Address of %s::%s is 0x%x\n", &szSrvTypeName[0], pszMethodName, m_pTargetAddress));
-#endif // _DEBUG
- return TRUE;
-}
-
-BOOL
-CrossDomainChannel::GetInterfaceMethodAddressFast(DWORD optFlags, MethodTable *pSrvMT, BOOL bFindServerMD)
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- _ASSERTE(m_pCliMD);
-
- MethodTable *pCliItfMT = m_pCliMD->GetMethodTable();
- _ASSERTE(pCliItfMT->IsInterface());
-
- // Only use the fast path if the interface is shared. If the interface isnt shared, then we'll have to search the
- // interface map on server type using name as key and then deref the slot # etc. I think shared interfaces will
- // be the common pattern. If not they should be.
- // Note that it's not enough to check that the client interface is shared, it must also be loaded in the server appdomain (since
- // it's now possible to have more than one instance of a shared assembly in a process).
- _ASSERTE(pCliItfMT->IsDomainNeutral());
- AppDomain* ad = SystemDomain::GetAppDomainFromId(m_pSrvDomain,ADV_RUNNINGIN);
- if (ad->FindDomainAssembly(pCliItfMT->GetAssembly()) == NULL)
- return FALSE;
-
- m_pSrvMD = NULL;
-
- OBJECTREF thisObj = GetServerObject();
-
-#ifdef FEATURE_COMINTEROP
- // Check for a COM interop server.
- if (thisObj->GetMethodTable()->IsComObjectType())
- {
-#if 0
- // We don't have all the logic in place to deal with COM interop yet. The following code is taken from the regular remoting
- // invocation path in CStackBuilderSink::PrivateProcessMessage, but I think we still need some work on the actual invocation
- // itself (leastways we didn't end up invoking the method correctly when I tried it).
- // For now we'll just bail back to the regular remoting path for COM interop.
- m_pSrvMD = thisObj->GetMethodTable()->GetMethodDescForComInterfaceMethod(m_pCliMD, false);
- if (m_pSrvMD == NULL)
- return FALSE;
-#endif
- return FALSE;
- }
-#endif // FEATURE_COMINTEROP
-
- GCPROTECT_BEGIN(thisObj);
-
- DispatchSlot impl(pSrvMT->FindDispatchSlotForInterfaceMD(m_pCliMD));
- CONSISTENCY_CHECK(!impl.IsNull());
- m_pSrvMD = impl.GetMethodDesc();
-
- _ASSERTE(m_pSrvMD);
-
- // If the method called has a generic instantiation then the server method desc we've just received doesn't contain that
- // information (generic method slots are filled with generic definition method descs). We need to build the exact method desc by
- // copying the instantiation from the client method (translating each type into the new domain of course).
- if (m_pSrvMD->HasMethodInstantiation())
- m_pSrvMD = InstantiateMethod(m_pCliMD, m_pSrvMD, pSrvMT);
-
- m_pTargetAddress = m_pSrvMD->GetCallTarget(&thisObj);
-
- GCPROTECT_END();
-
- return TRUE;
-}
-
-
-// Here we check whether the remote call is a cross domain call, if so, does it qualify
-BOOL
-CrossDomainChannel::CheckCrossDomainCall(TPMethodFrame *pFrame)
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- m_pFrame = pFrame;
- m_pCliMD = m_pFrame->GetFunction();
-
- MethodTable *pCliMT = m_pCliMD->GetMethodTable();
-
- // Check if this is an async delegate call
- if (pCliMT->IsDelegate())
- return FALSE;
-
- // Only use the fast path if the interface is shared. If the interface isnt shared, then we'll have to search the
- // interface map on server type using name as key and then deref the slot # etc. I think shared interfaces will
- // be the common pattern.
- if (pCliMT->IsInterface() && !pCliMT->IsDomainNeutral())
- return FALSE;
-
- OBJECTREF refTP = pFrame->GetThis();
- REALPROXYREF refRP = CTPMethodTable::GetRP(refTP);
-
- // Check if this is a x-domain call
- DWORD domainID = refRP->GetDomainID();
- if (domainID == 0)
- return FALSE; // Not x-appdomain call, or proxy not initted for optimization
-
- // Check if we are in a context different from default. If so, we may need to run context
- // policies etc. Use regular path.
- if (GetThread()->GetContext() != SystemDomain::GetCurrentDomain()->GetDefaultContext())
- return FALSE;
-
- // Check if method call args can be blitted (or not optimizable at all)
- m_xret = RemotableMethodInfo::IsCrossAppDomainOptimizable(m_pCliMD, &m_numStackSlotsToCopy);
- if (RemotableMethodInfo::IsCallNotOptimizable(m_xret))
- {
-#ifdef _DEBUG
- DefineFullyQualifiedNameForClass();
- LPCUTF8 szSrvTypeName = GetFullyQualifiedNameForClassNestedAware(m_pCliMD->GetMethodTable());
- LOG((LF_REMOTING, LL_INFO100, "CheckCrossDomainCall. Call to %s::%s is not optimizable\n",
- &szSrvTypeName[0], m_pCliMD->GetName()));
-#endif // _DEBUG
- return FALSE;
- }
-
- m_pCliDomain = SystemDomain::GetCurrentDomain();
- m_pSrvDomain = ADID(domainID);
-
- return ExecuteCrossDomainCall();
-}
-
-// Dereference the server identity handle, to reach the server object
-// If the handle is null, someone either called Disconnect on the server
-// or the server's lease ran out
-OBJECTREF CrossDomainChannel::GetServerObject()
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_TRIGGERS;
- }
- CONTRACTL_END
-
- _ASSERTE(m_pSrvDomain == SystemDomain::GetCurrentDomain()->GetId());
-
- OBJECTREF refSrvIdentity = ObjectFromHandle(m_refSrvIdentity);
- if (refSrvIdentity == NULL)
- {
- OBJECTREF refTP = m_pFrame->GetThis();
- REALPROXYREF refRP = CTPMethodTable::GetRP(refTP);
- OBJECTREF refIdentity = ObjectToOBJECTREF((Object *)refRP->GetPtrOffset(CRemotingServices::GetOffsetOfCliIdentityInRP()));
- STRINGREF refURI = (STRINGREF)ObjectToOBJECTREF((Object *)refIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfURIInIdentity()));
- SString sURI;
- refURI->GetSString(sURI);
-
- COMPlusThrow(kRemotingException,
- IDS_REMOTING_SERVER_DISCONNECTED,
- sURI.GetUnicode());
- }
- OBJECTREF srvObject = ObjectToOBJECTREF((Object *)refSrvIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfTPOrObjInIdentity()));
- return srvObject;
-}
-
-// Here the we find the target method address, make a decision whether to
-// execute the call locally, if remote whether to blit the arguments or to marshal them,
-BOOL CrossDomainChannel::ExecuteCrossDomainCall()
-{
- STATIC_CONTRACT_THROWS;
- STATIC_CONTRACT_GC_TRIGGERS;
- STATIC_CONTRACT_MODE_COOPERATIVE;
-
- BOOL bOptimizable = TRUE;
-
- {
- ProfilerRemotingClientCallbackHolder profilerHolder;
-
- // Short circuit calls to Object::GetType and run them locally
- if (m_pCliMD == CRemotingServices::MDofObjectGetType())
- {
- LOG((LF_REMOTING, LL_INFO100, "ExecuteCrossDomainCall. Short circuiting call to Object::GetType and running it locally.\n"));
- OBJECTREF refTP = m_pFrame->GetThis();
- OBJECTREF refType = CRemotingServices::GetClass(refTP);
- LPVOID pReturnValuePtr = m_pFrame->GetReturnValuePtr();
- *(Object **)pReturnValuePtr = OBJECTREFToObject(refType);
- }
- else if (RemotableMethodInfo::AreArgsBlittable(m_xret))
- {
- bOptimizable = BlitAndCall();
- }
- else
- {
- bOptimizable = MarshalAndCall();
- }
- }
-
- if (!bOptimizable)
- return FALSE;
-
- // Check for the need to trip thread
- if (GetThread()->CatchAtSafePointOpportunistic())
- {
- // There is no need to GC protect the return object as
- // TPFrame is GC protecting it
- CommonTripThread();
- }
-
-#ifdef _TARGET_X86_
- // Set the number of bytes to pop for x86
- m_pFrame->SetCbStackPop(m_numStackSlotsToCopy * sizeof(SIZE_T));
-#endif // _TARGET_X86_
-
- return TRUE;
-}
-
-BOOL
-CrossDomainChannel::InitServerInfo()
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_TRIGGERS;
- }
- CONTRACTL_END
-
- _ASSERTE(m_pFrame);
- _ASSERTE(m_pSrvDomain == SystemDomain::GetCurrentDomain()->GetId());
-
- // Get the server object
- OBJECTREF refTP = m_pFrame->GetThis();
- REALPROXYREF refRP = CTPMethodTable::GetRP(refTP);
- m_refSrvIdentity = (OBJECTHANDLE)refRP->GetPtrOffset(CRemotingServices::GetOffsetOfSrvIdentityInRP());
- OBJECTREF srvObject = GetServerObject();
-
- MethodTable *pSrvMT = srvObject->GetMethodTable();
-
- // Find the target address
- DWORD optFlag = refRP->GetOptFlags();
-
- // If we are cloning some arguments to server domain, we want to do a type check
- // on the cloned objects against the expected type. To find the expected type, we need to
- // know the method signature on the server side, which in turn is obtainable if we know
- // the server MethodDesc. Finding MethodDesc from a slot isnt cheap, so we do it only if we need it
- BOOL bFindServerMD = (RemotableMethodInfo::AreArgsBlittable(m_xret)) ? FALSE : TRUE;
- BOOL bResultOfAddressLookup = FALSE;
-
- if (m_pCliMD->GetMethodTable()->IsInterface())
- {
- bResultOfAddressLookup = GetInterfaceMethodAddressFast(optFlag, pSrvMT, bFindServerMD);
- }
- else if ((optFlag & OPTIMIZATION_FLAG_INITTED) && (optFlag & OPTIMIZATION_FLAG_PROXY_EQUIVALENT))
- {
- bResultOfAddressLookup = GetTargetAddressFast(optFlag, pSrvMT, bFindServerMD);
- }
- else
- {
- // If the proxy is not cast to an equivalent type, do not perform any optimizations
- bResultOfAddressLookup = FALSE;
- }
-
-#ifdef _DEBUG
- if (!bResultOfAddressLookup)
- LOG((LF_REMOTING, LL_INFO100, "InitServerInfo. Skipping fast path because failed to find target address.\n"));
-#endif // _DEBUG
-
- _ASSERTE(!bResultOfAddressLookup || !bFindServerMD || m_pSrvMD);
- return bResultOfAddressLookup;
-}
-
-// A macro used to help calculate the exact declaring type of a method (this may not be as simple as calling GetMethodTable on the
-// method desc if the type is generic and not an interface). We get the additional information from the instance (which provides an
-// exact method table, though not necessarily the one the method is actually _declared_ on). We don't compute the instance or the
-// method table from that instance in this macro since the logic varies greatly from client to server (the client has to adjust for
-// the fact that the instance is a TP).
-// We assume a variable called thDeclaringType has already been declared in the current scope.
-#define CDC_DETERMINE_DECLARING_TYPE(_pMD, _thInst) \
- if (!(_pMD)->HasClassInstantiation() || (_pMD)->IsInterface()) \
- { \
- thDeclaringType = TypeHandle((_pMD)->GetMethodTable()); \
- } \
- else \
- { \
- Instantiation inst = (_pMD)->GetExactClassInstantiation(_thInst); \
- MethodTable *pApproxDeclaringMT = (_pMD)->GetMethodTable(); \
- thDeclaringType = ClassLoader::LoadGenericInstantiationThrowing(pApproxDeclaringMT->GetModule(), \
- pApproxDeclaringMT->GetCl(), \
- inst); \
- }
-
-// We have decided the arguments are blittable. We may still need to marshal
-// call context if any.
-BOOL
-CrossDomainChannel::BlitAndCall()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- SIZE_T *pRegArgs = NULL;
- SIZE_T *pStackArgs = NULL;
-#ifdef CALLDESCR_ARGREGS
- ArgumentRegisters RegArgs = {0};
- pRegArgs = (SIZE_T*)&RegArgs;
-#endif
-#ifdef CALLDESCR_FPARGREGS
- FloatArgumentRegisters *pFloatArgumentRegisters = NULL;
-#endif
-
- BOOL bOptimizable = TRUE;
- BOOL bHasObjRefReturnVal = FALSE;
-
- Thread *pCurThread = GetThread();
-
-#ifdef _DEBUG
- LPCUTF8 pszMethodName;
- pszMethodName = m_pCliMD->GetName();
- LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Blitting arguments to method %s\n", pszMethodName));
-#endif // _DEBUG
-
- // Collect all client domain GC references together in a single GC frame.
- // refReturnValue contains the returned object.
- // It can also contain a boxed object when the return is a value type and needs marshalling
- struct _gc {
- OBJECTREF refReturnValue;
- OBJECTREF refException;
- OBJECTREF refExecutionContext;
- OBJECTREF refPrincipal;
- } ClientGC;
- ZeroMemory(&ClientGC, sizeof(ClientGC));
- GCPROTECT_BEGIN(ClientGC);
-
- _ASSERTE(RemotableMethodInfo::IsReturnBlittable(m_xret));
-
- // Check for any logical call context that contains data
- BOOL bMarshalCallContext = FALSE;
- BOOL bMarshalReturnCallContext = FALSE;
- if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext();
- if (refExecCtx != NULL)
- {
- ClientGC.refExecutionContext = refExecCtx;
- ClientGC.refPrincipal = ReadPrincipal();
-
- LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext();
- if (refLogCallCtx != NULL)
- {
- if (refLogCallCtx->ContainsDataForSerialization())
- {
- bMarshalCallContext = TRUE;
- }
- }
- }
- }
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // Assume that exception at server was NotCorrupting
- CorruptionSeverity severity = NotCorrupting;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
- // Push the frame
- ENTER_DOMAIN_ID(m_pSrvDomain);
-
- // Now create a server domain GC frame for all server side GC references.
- struct _gc {
- OBJECTREF refReturnValue;
- OBJECTREF refException;
- OBJECTREF refExecutionContext;
- } ServerGC;
- ZeroMemory(&ServerGC, sizeof(ServerGC));
- GCPROTECT_BEGIN(ServerGC);
-
- // Initialize server side info, such as method address etc
- bOptimizable = InitServerInfo();
-
- if (!bOptimizable)
- goto LeaveDomain;
-
- RenewLease();
-
- if (bMarshalCallContext)
- {
- LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Marshalling call context\n", pszMethodName));
- CrossAppDomainClonerCallback cadcc;
- ObjectClone Marshaller(&cadcc, CrossAppDomain, FALSE);
- ServerGC.refExecutionContext = Marshaller.Clone(ClientGC.refExecutionContext,
- m_pCliDomain,
- GetAppDomain(),
- ClientGC.refExecutionContext);
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- ref->SetExecutionContext(ServerGC.refExecutionContext);
-
- Marshaller.RemoveGCFrames();
- }
- else if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- ref->SetExecutionContext(NULL);
- }
-
-#ifdef PROFILING_SUPPORTED
- // If we're profiling, notify the profiler that we're about to invoke the remoting target
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationStarted();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
- {
- GCX_COOP();
- UINT64 uRegTypeMap = 0;
- pStackArgs = (SIZE_T *)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgs());
-
- // Get the 'this' object
- OBJECTREF srvObject = GetServerObject();
-
-#if defined(_TARGET_X86_)
- pRegArgs[0] = *((SIZE_T*)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()));
- pRegArgs[1] = (SIZE_T) OBJECTREFToObject(srvObject);
-#elif defined(CALLDESCR_ARGREGS)
- // Have to buffer argument registers since we're going to overwrite the this object with the server
- // version and the frame owning the registers is in the wrong domain to report that object.
- pRegArgs[0] = (SIZE_T) OBJECTREFToObject(srvObject);
- memcpy(pRegArgs + 1,
- (SIZE_T*)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters()) + 1,
- sizeof(ArgumentRegisters) - sizeof(SIZE_T));
-
-#ifdef CALLDESCR_FPARGREGS
- // Only provide a pointer to the floating point area of the stack frame if there any any floating
- // point arguments (passing NULL optimizes the CallDescr thunk by omitting the initialization of
- // floating point argument registers).
- if (RemotableMethodInfo::DoArgsContainAFloat(m_xret))
- pFloatArgumentRegisters = (FloatArgumentRegisters*)(m_pFrame->GetTransitionBlock() + TransitionBlock::GetOffsetOfFloatArgumentRegisters());
-#endif // CALLDESCR_FPARGREGS
-
-#else // CALLDESCR_ARGREGS
-
- // It's a pity that we have to allocate a buffer for the arguments on the stack even in BlitAndCall().
- // The problem is we can't use the portion of the stack protected by m_pFrame to store the srvObject,
- // since the srvObject is in the server domain and the TPMethodFrame m_pFrame is in the client domain.
- // I don't think we need to protect the srvOjbect in this case, since it's reachable from the transparent
- // proxy, which is protected by the TPMethodFrame.
- SIZE_T* pTmpStackArgs = (SIZE_T*)_alloca(m_numStackSlotsToCopy * sizeof(SIZE_T));
- memcpy(pTmpStackArgs, pStackArgs, m_numStackSlotsToCopy * sizeof(SIZE_T));
- pStackArgs = pTmpStackArgs;
-
- pStackArgs[0] = (SIZE_T)OBJECTREFToObject(srvObject);
-#endif // CALLDESCR_ARGREGS
-
-#if defined(CALLDESCR_REGTYPEMAP) || defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
- // We have to copy the floating point registers from a different stack location to the portion of
- // the stack used to save the general registers. Since this is expensive, we only do this if
- // we have some floating point arguments.
- if (RemotableMethodInfo::DoArgsContainAFloat(m_xret))
- {
- // When computing the method signature we need to take special care if the call is on a non-interface class with a
- // generic instantiation (since in that case we may have a representative method with a non-concrete signature).
- TypeHandle thDeclaringType;
- CDC_DETERMINE_DECLARING_TYPE(m_pCliMD, TypeHandle(CTPMethodTable::GetMethodTableBeingProxied(m_pFrame->GetThis())));
- MetaSig mSig(m_pCliMD, thDeclaringType);
- ArgIterator argit(&mSig);
-
- int offset;
- while (TransitionBlock::InvalidOffset != (offset = argit.GetNextOffset()))
- {
- int regArgNum = TransitionBlock::GetArgumentIndexFromOffset(offset);
-
- if (regArgNum >= NUM_ARGUMENT_REGISTERS)
- break;
-
- CorElementType argTyp = argit.GetArgType();
-
-#ifdef CALLDESCR_REGTYPEMAP
- FillInRegTypeMap(offset, argTyp, (BYTE*)&uRegTypeMap);
-#endif
-
-#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
- if (argTyp == ELEMENT_TYPE_R4 || argTyp == ELEMENT_TYPE_R8)
- {
- PVOID pSrc = (PVOID)(m_pFrame->GetTransitionBlock() + m_pFrame->GetFPArgOffset(regArgNum));
-
- ARG_SLOT val;
- if (argTyp == ELEMENT_TYPE_R4)
- val = FPSpillToR4(pSrc);
- else
- val = FPSpillToR8(pSrc);
-
- *(ARG_SLOT*)(&pStackArgs[regArgNum]) = val;
- }
-#endif
- }
- }
-#endif // CALLDESCR_REGTYPEMAP || COM_STUBS_SEPARATE_FP_LOCATIONS
-
- CallDescrData callDescrData;
-
- callDescrData.pSrc = pStackArgs;
- callDescrData.numStackSlots = m_numStackSlotsToCopy,
-#ifdef CALLDESCR_ARGREGS
- callDescrData.pArgumentRegisters = (ArgumentRegisters *)pRegArgs;
-#endif
-#ifdef CALLDESCR_FPARGREGS
- callDescrData.pFloatArgumentRegisters = pFloatArgumentRegisters;
-#endif
-#ifdef CALLDESCR_REGTYPEMAP
- callDescrData.dwRegTypeMap = uRegTypeMap;
-#endif
- callDescrData.fpReturnSize = GetFPReturnSize();
- callDescrData.pTarget = m_pTargetAddress;
-
- DispatchCall(
- &callDescrData,
- &ServerGC.refException,
- GET_CTX_TRANSITION_FRAME()
- COMMA_CORRUPTING_EXCEPTIONS_ONLY(&severity)
- );
-
- // If the return value is a GC ref, store it in a protected place
- if (ServerGC.refException != NULL)
- {
- // Return value is invalid if there was exception thrown
- }
- else
- if (RemotableMethodInfo::IsReturnGCRef(m_xret))
- {
- ServerGC.refReturnValue = ObjectToOBJECTREF(*(Object **)(&callDescrData.returnValue));
- bHasObjRefReturnVal = TRUE;
- }
- else
- {
- memcpyNoGCRefs(m_pFrame->GetReturnValuePtr(), &callDescrData.returnValue, sizeof(callDescrData.returnValue));
- }
- }
-
-#ifdef PROFILING_SUPPORTED
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationReturned();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
- // Propagate any logical call context changes except those to the principal
- if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext();
- if (refExecCtx != NULL)
- {
- LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext();
- if (bMarshalCallContext ||
- (refLogCallCtx != NULL && refLogCallCtx->ContainsNonSecurityDataForSerialization()))
- {
- ServerGC.refExecutionContext = ref->GetExecutionContext();
- bMarshalReturnCallContext = TRUE;
- LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Marshalling return call context\n", pszMethodName));
- CrossAppDomainClonerCallback cadcc;
- ObjectClone Marshaller(&cadcc, CrossAppDomain, FALSE);
-
- ResetPrincipal();
-
- EXECUTIONCONTEXTREF ecref = (EXECUTIONCONTEXTREF)Marshaller.Clone(ServerGC.refExecutionContext,
- GetAppDomain(),
- m_pCliDomain,
- ServerGC.refExecutionContext);
- if (ClientGC.refExecutionContext != NULL)
- ((EXECUTIONCONTEXTREF)ClientGC.refExecutionContext)->SetLogicalCallContext(ecref->GetLogicalCallContext());
- else
- ClientGC.refExecutionContext = (OBJECTREF)ecref;
-
- Marshaller.RemoveGCFrames();
- }
- }
- }
-
- if (ServerGC.refException != NULL)
- {
- LOG((LF_REMOTING, LL_INFO100, "BlitAndCall. Exception thrown ! Marshalling exception. \n", pszMethodName));
-
- // Save Watson buckets before the exception object is changed
- if (GetThread() != NULL)
- {
- // Ensure that we have the buckets for the exception in question.
- // For preallocated exceptions, we capture the buckets in the
- // UE WatsonBucket Tracker in AppDomainTransitionExceptionFilter.
- //
- // When the exception is reraised in the returning AppDomain,
- // StackTraceInfo::AppendElement will copy over the buckets
- // to the EHtracker corresponding to the raised exception.
- if (!CLRException::IsPreallocatedExceptionObject(ServerGC.refException))
- {
- // For non-preallocated exception objects, the throwable
- // is expected have the buckets in it, assuming that
- // CLR's personality routine for managed code was notified
- // of the exception before returning from the AD transition.
- //
- // There are scenarios where few managed frames, post AD transition,
- // may get optimized away by the JIT. If a managed exception is
- // thrown from within the VM at a later time, the personality routine
- // for managed will not be invoked if there are no managed frames present
- // between the AD Transition frame and the frame where VM raised the managed
- // exception.
- //
- // When such an exception comes back to the calling AppDomain, we will
- // come here and look for watson buckets and may not find them. In such
- // a case, simply log it.
- if(!((EXCEPTIONREF)ServerGC.refException)->AreWatsonBucketsPresent())
- {
- LOG((LF_EH, LL_INFO100, "CrossDomainChannel::BlitAndCall: Watson buckets not found in regular exception object. Exception likely raised in native code.\n"));
- }
- }
- }
-
- CrossAppDomainClonerCallback cadcc;
- ObjectClone Marshaller(&cadcc, CrossAppDomain, FALSE);
- ClientGC.refException = Marshaller.Clone(ServerGC.refException, GetAppDomain(), m_pCliDomain, ServerGC.refExecutionContext);
-
- Marshaller.RemoveGCFrames();
-
- // We have to be in the right domain before we throw the exception
- goto LeaveDomain;
- }
-
- if (bHasObjRefReturnVal)
- {
- // Must be a domain agile GC ref. We can just copy the reference into the client GC frame.
- ClientGC.refReturnValue = ServerGC.refReturnValue;
- }
-
-LeaveDomain: ;
-
- GCPROTECT_END(); // ServerGC
-
- END_DOMAIN_TRANSITION;
-
- if (ClientGC.refException != NULL)
- {
- RestorePrincipal(&ClientGC.refPrincipal);
- COMPlusThrow(ClientGC.refException
- COMMA_CORRUPTING_EXCEPTIONS_ONLY(severity)
- );
- }
-
- if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- ref->SetExecutionContext(ClientGC.refExecutionContext);
- }
-
- RestorePrincipal(&ClientGC.refPrincipal);
-
- // If the return type is an object, take it out of the protected ref
- if (bHasObjRefReturnVal)
- {
- *(Object **)m_pFrame->GetReturnValuePtr() = OBJECTREFToObject(ClientGC.refReturnValue);
- }
-
- GCPROTECT_END(); // ClientGC
-
- return bOptimizable;
-}
-
-// Argument attributes
-#define ARG_NEEDS_UNBOX 0x80000000
-#define ARG_GOES_IN_EDX 0x40000000
-#define ARG_IS_BYREF 0x20000000
-#define ARG_OFFSET_MASK 0x00FFFFFF
-
-// Structure to hold arguments for MarshalAndCall
-struct MarshalAndCallArgs : public CtxTransitionBaseArgs
-{
- MarshalAndCallArgs() : Marshaller(&cadcc, CrossAppDomain, FALSE)
- {
- STATIC_CONTRACT_SO_INTOLERANT;
- }
-
- CrossDomainChannel * pThis;
-
- struct _gc {
- OBJECTREF refReturnValue;
- OBJECTREF refException;
- OBJECTREF refExecutionContext;
- OBJECTREF refPrincipal;
- } ClientGC;
-
- BOOL bOptimizable;
-
- ObjectClone Marshaller;
- CrossAppDomainClonerCallback cadcc;
-
- MetaSig *mSig;
- ArgIterator *argit;
-
- DWORD dwNumArgs;
-#ifdef CALLDESCR_ARGREGS
- SIZE_T *pRegArgs;
-#endif
-#ifdef CALLDESCR_FPARGREGS
- FloatArgumentRegisters *pFloatArgumentRegisters;
-#endif
- SIZE_T *pStackArgs;
- DWORD *pArgAttribs;
-
- DWORD dwNumObjectsMarshalled;
- BOOL *bMarshalledArgs;
- OBJECTREF *pClientArgArray;
-
- BOOL bHasByRefArgsToMarshal;
- int *pByRefArgAttribs;
- TypeHandle *pThByRefs;
-
- TypeHandle retTh;
- BOOL bHasObjRefReturnVal;
- BOOL bHasRetBuffArg;
- BOOL bHasValueTypeReturnValToMarshal;
-
- BOOL bMarshalCallContext;
- BOOL bMarshalReturnCallContext;
-
-#ifdef CALLDESCR_REGTYPEMAP
- UINT64 uRegTypeMap;
-#endif
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- CorruptionSeverity severity;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-};
-
-// Simple wrapper to go from C to C++.
-void MarshalAndCall_Wrapper2(MarshalAndCallArgs * pArgs)
-{
- WRAPPER_NO_CONTRACT;
-
- pArgs->pThis->MarshalAndCall_Wrapper(pArgs);
-}
-
-void CrossDomainChannel::MarshalAndCall_Wrapper(MarshalAndCallArgs * pArgs)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END;
-
- // Set up a rip-cord that will immediately stop us reporting GC references we're keeping alive in the Marshaller that was passed
- // to us in the event that this appdomain is unloaded underneath our feet. This avoids us keeping any server objects alive after
- // their domain has unloaded.
- ReportClonerRefsHolder sHolder(&pArgs->Marshaller);
-
- Thread* pCurThread = GetThread();
- AppDomain* pCurAppDomain = GetAppDomain();
-
- // Now create a server domain GC frame for all non-arg server side GC references.
- struct _gc {
- OBJECTREF refReturnValue;
- OBJECTREF refException;
- OBJECTREF refExecutionContext;
- } ServerGC;
- ZeroMemory(&ServerGC, sizeof(ServerGC));
- GCPROTECT_BEGIN(ServerGC);
-
- // And a variable sized array and frame of marshaled arg GC references.
- OBJECTREF *pServerArgArray = NULL;
- pServerArgArray = (OBJECTREF *) _alloca(pArgs->dwNumObjectsMarshalled * sizeof(OBJECTREF));
- ZeroMemory(pServerArgArray, sizeof(OBJECTREF) * pArgs->dwNumObjectsMarshalled);
-
- TypeHandle* pServerArgTH = (TypeHandle *) _alloca(pArgs->dwNumObjectsMarshalled * sizeof(TypeHandle));
- GCPROTECT_ARRAY_BEGIN(pServerArgArray[0], pArgs->dwNumObjectsMarshalled);
-
- // Initialize server side info, such as method address etc
- pArgs->bOptimizable = InitServerInfo();
-
- if (!pArgs->bOptimizable)
- goto LeaveDomain;
-
- RenewLease();
-
- // First clone objref arguments into the called domain
- if (!RemotableMethodInfo::AreArgsBlittable(m_xret))
- {
- // When computing the method signature we need to take special care if the call is on a non-interface class with a
- // generic instantiation (since in that case we may have a representative method with a non-concrete signature).
- TypeHandle thDeclaringType;
- CDC_DETERMINE_DECLARING_TYPE(m_pSrvMD, TypeHandle(GetServerObject()->GetTypeHandle()));
- MetaSig mSrvSideSig(m_pSrvMD, thDeclaringType);
- DWORD dwMarshalledArg = 0;
- for (DWORD i = 0; i < pArgs->dwNumArgs; i++)
- {
- CorElementType cType = mSrvSideSig.NextArg();
- if (pArgs->bMarshalledArgs[i] != TRUE)
- {
- // Make sure argument type is loaded
- if (cType == ELEMENT_TYPE_VALUETYPE)
- {
- mSrvSideSig.GetLastTypeHandleThrowing();
- }
- continue;
- }
-
- TypeHandle argTh;
- if (cType == ELEMENT_TYPE_BYREF)
- mSrvSideSig.GetByRefType(&argTh);
- else
- argTh = mSrvSideSig.GetLastTypeHandleThrowing();
-
- pServerArgTH[dwMarshalledArg] = argTh;
- pServerArgArray[dwMarshalledArg] = pArgs->Marshaller.Clone(pArgs->pClientArgArray[dwMarshalledArg],
- argTh,
- m_pCliDomain,
- pCurAppDomain,
- pArgs->ClientGC.refExecutionContext);
- dwMarshalledArg++;
- }
-
- // Make sure return type is loaded
- TypeHandle thReturn = mSrvSideSig.GetRetTypeHandleThrowing();
- _ASSERTE(!thReturn.IsNull());
-
- if (pArgs->bHasValueTypeReturnValToMarshal)
- {
- // The return is a value type which could have GC ref fields. Allocate a boxed value type so that the
- // return value goes into that. During return from call we'll clone it and copy it onto the stack
- ServerGC.refReturnValue = thReturn.AsMethodTable()->Allocate();
- }
- }
-
- // Then clone the call context if any
- if (pArgs->bMarshalCallContext)
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling call context\n"));
-#endif
- ServerGC.refExecutionContext = pArgs->Marshaller.Clone(pArgs->ClientGC.refExecutionContext,
- m_pCliDomain,
- pCurAppDomain,
- pArgs->ClientGC.refExecutionContext);
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- ref->SetExecutionContext(ServerGC.refExecutionContext);
- }
- else if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- ref->SetExecutionContext(NULL);
- }
-
-#ifdef PROFILING_SUPPORTED
- // If we're profiling, notify the profiler that we're about to invoke the remoting target
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationStarted();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
- {
- GCX_COOP();
- if (!RemotableMethodInfo::AreArgsBlittable(m_xret))
- {
- // Next place arguments into the destination array
- // No GC should occur between now and call dispatch
- for (DWORD i = 0 ; i < pArgs->dwNumObjectsMarshalled; i++)
- {
- BOOL bNeedUnbox = pArgs->pArgAttribs[i] & ARG_NEEDS_UNBOX;
- BOOL bGoesInEDX = pArgs->pArgAttribs[i] & ARG_GOES_IN_EDX;
- BOOL bIsByRef = pArgs->pArgAttribs[i] & ARG_IS_BYREF;
- DWORD dwOffset = pArgs->pArgAttribs[i] & ARG_OFFSET_MASK;
-
- SIZE_T *pDest = NULL;
-
-#if defined(_TARGET_X86_)
- if (bGoesInEDX)
- {
- // This has to be EDX for this platform.
- pDest = pArgs->pRegArgs;
- }
- else
- {
- pDest = (SIZE_T *)((BYTE *)(pArgs->pStackArgs) + dwOffset);
- }
-#elif defined(CALLDESCR_ARGREGS)
- // To help deal with the fact that a single argument can span both registers and stack
- // we've ensured that the register and stack buffers are contiguous and encoded all offsets
- // from the beginning of the register buffer.
- pDest = (SIZE_T *)((BYTE *)(pArgs->pRegArgs) + dwOffset);
-#else
- pDest = (SIZE_T *)((BYTE *)(pArgs->pStackArgs) + dwOffset);
-#endif
-
- if (bNeedUnbox && !bIsByRef)
- {
- pServerArgTH[i].GetMethodTable()->UnBoxIntoUnchecked(pDest, pServerArgArray[i]);
- }
- else if (bIsByRef)
- {
- if (bNeedUnbox)
- {
- // We don't use the fast path for byref nullables, so UnBox() can be used
- *pDest = (SIZE_T)pServerArgArray[i]->UnBox();
- }
- else
- {
- // Point to the OBJECTREF
- *pDest = (SIZE_T)&pServerArgArray[i];
- }
- }
- else
- {
- *pDest = (SIZE_T)OBJECTREFToObject(pServerArgArray[i]);
- }
- }
- }
-
- // Get the 'this' object
- OBJECTREF srvObject = GetServerObject();
- LPVOID pvRetBuff = NULL;
-
- FrameWithCookie<ProtectValueClassFrame>* pProtectValueClassFrame = NULL;
- ValueClassInfo* pValueClasses = NULL;
-
- if (pArgs->bHasRetBuffArg)
- {
- // Need some sort of check here that retTH has been initialized?
- MethodTable* pMT = pArgs->retTh.GetMethodTable();
- _ASSERTE_MSG(pMT != NULL, "GetRetType failed?");
- if (pMT->IsStructRequiringStackAllocRetBuf())
- {
- SIZE_T sz = pMT->GetNumInstanceFieldBytes();
- pvRetBuff = _alloca(sz);
- memset(pvRetBuff, 0, sz);
- pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pvRetBuff, pMT, pValueClasses);
- }
- else
- {
- // We don't use the fast path for values that return nullables, so UnBox() can be used
- pvRetBuff = (PVOID)ServerGC.refReturnValue->UnBox();
- }
- }
-#if defined(_TARGET_X86_)
- // Check if EDX should point to a return buffer (either stack- or heap-allocated).
- if (pArgs->bHasValueTypeReturnValToMarshal && pArgs->bHasRetBuffArg)
- {
- *(pArgs->pRegArgs) = (SIZE_T)pvRetBuff;
- }
- (pArgs->pRegArgs)[1] = (SIZE_T)OBJECTREFToObject(srvObject);
-#elif defined(CALLDESCR_ARGREGS)
- // On ARM the this pointer goes in r0 and any return buffer argument pointer in r1.
- pArgs->pRegArgs[0] = (SIZE_T)OBJECTREFToObject(srvObject);
- if (pArgs->bHasRetBuffArg)
- {
- pArgs->pRegArgs[1] = (SIZE_T)pvRetBuff;
- }
-#else // CALLDESCR_ARGREGS
-
- if (pArgs->bHasRetBuffArg)
- {
- (pArgs->pStackArgs)[0] = (SIZE_T)OBJECTREFToObject(srvObject);
- (pArgs->pStackArgs)[1] = (SIZE_T)pvRetBuff;
- }
- else
- {
- (pArgs->pStackArgs)[0] = (SIZE_T)OBJECTREFToObject(srvObject);
- }
-
-#endif // CALLDESCR_ARGREGS
-
- CallDescrData callDescrData;
-
-
- callDescrData.pSrc = pArgs->pStackArgs;
- callDescrData.numStackSlots = m_numStackSlotsToCopy,
-#ifdef CALLDESCR_ARGREGS
- callDescrData.pArgumentRegisters = (ArgumentRegisters *)pArgs->pRegArgs;
-#endif
-#ifdef CALLDESCR_FPARGREGS
- callDescrData.pFloatArgumentRegisters = pArgs->pFloatArgumentRegisters;
-#endif
-#ifdef CALLDESCR_REGTYPEMAP
- callDescrData.dwRegTypeMap = pArgs->uRegTypeMap;
-#endif
- callDescrData.fpReturnSize = GetFPReturnSize();
- callDescrData.pTarget = m_pTargetAddress;
-
- if (pValueClasses != NULL)
- {
- pProtectValueClassFrame = new (_alloca (sizeof (FrameWithCookie<ProtectValueClassFrame>)))
- FrameWithCookie<ProtectValueClassFrame>(pCurThread, pValueClasses);
- }
-
- DispatchCall(&callDescrData,
- &ServerGC.refException,
- pArgs->GetCtxTransitionFrame()
- COMMA_CORRUPTING_EXCEPTIONS_ONLY(&(pArgs->severity))
- );
-
- // If the return value is a GC ref, store it in a protected place
- if (ServerGC.refException != NULL)
- {
- // Return value is invalid if there was exception thrown
- }
- else
- if (RemotableMethodInfo::IsReturnGCRef(m_xret))
- {
- ServerGC.refReturnValue = ObjectToOBJECTREF(*(Object **)(&callDescrData.returnValue));
- pArgs->bHasObjRefReturnVal = TRUE;
- }
- else
- if (pArgs->bHasValueTypeReturnValToMarshal)
- {
- if (!pArgs->bHasRetBuffArg)
- {
- //
- // The value type return value is returned by value in this case.
- // We have to copy it back into our server object.
- //
- // We don't use the fast path for values that return nullables, so UnBox() can be used
- //
- CopyValueClass(ServerGC.refReturnValue->UnBox(), &callDescrData.returnValue, ServerGC.refReturnValue->GetMethodTable(), pCurAppDomain);
- }
- else if (pValueClasses != NULL)
- {
- // We passed a stack allocated ret buff. Copy back into the allocated server object.
- // We don't use the fast path for values that return nullables, so UnBox() can be used
- CopyValueClass(ServerGC.refReturnValue->UnBox(), pvRetBuff, ServerGC.refReturnValue->GetMethodTable(), pCurAppDomain);
- }
- // In all other cases, the return value should be in the server object already.
- }
- else
- {
- memcpyNoGCRefs(m_pFrame->GetReturnValuePtr(), &callDescrData.returnValue, sizeof(callDescrData.returnValue));
- }
-
- if (pProtectValueClassFrame != NULL)
- pProtectValueClassFrame->Pop(pCurThread);
- }
-
-#ifdef PROFILING_SUPPORTED
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationReturned();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
- if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext();
- if (refExecCtx != NULL)
- {
- LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext();
- if (pArgs->bMarshalCallContext ||
- (refLogCallCtx != NULL && refLogCallCtx->ContainsNonSecurityDataForSerialization()))
- {
- ServerGC.refExecutionContext = ref->GetExecutionContext();
- pArgs->bMarshalReturnCallContext = TRUE;
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling return call context\n"));
-#endif
- ResetPrincipal();
- EXECUTIONCONTEXTREF ecref = (EXECUTIONCONTEXTREF)pArgs->Marshaller.Clone(ServerGC.refExecutionContext,
- pCurAppDomain,
- m_pCliDomain,
- ServerGC.refExecutionContext);
- if (pArgs->ClientGC.refExecutionContext != NULL)
- {
- ((EXECUTIONCONTEXTREF)pArgs->ClientGC.refExecutionContext)->SetLogicalCallContext(ecref->GetLogicalCallContext());
- }
- else
- {
- pArgs->ClientGC.refExecutionContext = (OBJECTREF)ecref;
- }
- }
- }
- }
-
-
- if (ServerGC.refException != NULL)
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Exception thrown ! Marshalling exception. \n"));
-#endif
-
- // Save Watson buckets before the exception object is changed
- if (GetThread() != NULL)
- {
- // Ensure that we have the buckets for the exception in question.
- // For preallocated exceptions, we capture the buckets in the
- // UE WatsonBucket Tracker in AppDomainTransitionExceptionFilter.
- //
- // When the exception is reraised in the returning AppDomain,
- // StackTraceInfo::AppendElement will copy over the buckets
- // to the EHtracker corresponding to the raised exception.
- if (!CLRException::IsPreallocatedExceptionObject(ServerGC.refException))
- {
- // For non-preallocated exception objects, the throwable
- // should already have the buckets in it, unless it was raised in VM native code
- // and reached here before CLR's managed code exception handler could see it.
- if(!((EXCEPTIONREF)ServerGC.refException)->AreWatsonBucketsPresent())
- {
- LOG((LF_EH, LL_INFO1000, "MarshalAndCall - Regular exception object received (%p) does not contain watson buckets.\n",
- OBJECTREFToObject(ServerGC.refException)));
- }
- }
- }
-
- pArgs->ClientGC.refException = pArgs->Marshaller.Clone(ServerGC.refException,
- pCurAppDomain,
- m_pCliDomain,
- ServerGC.refExecutionContext);
- goto LeaveDomain;
- }
-
- if (!RemotableMethodInfo::IsReturnBlittable(m_xret))
- {
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling return object\n"));
- // Need to marshal the return object
-
- pArgs->ClientGC.refReturnValue = pArgs->Marshaller.Clone(ServerGC.refReturnValue,
- pArgs->retTh,
- pCurAppDomain,
- m_pCliDomain,
- ServerGC.refExecutionContext);
-
- if (pArgs->bHasValueTypeReturnValToMarshal)
- {
- // Need to copy contents from temp return buffer to the original return buffer
- void *pDest;
- if (!pArgs->bHasRetBuffArg)
- {
- pDest = m_pFrame->GetReturnValuePtr();
- }
- else
- {
- pDest = *(void **)(m_pFrame->GetTransitionBlock() + pArgs->argit->GetRetBuffArgOffset());
- }
- // We don't use the fast path for values that return nullables, so UnBox() can be used
- CopyValueClass(pDest, pArgs->ClientGC.refReturnValue->UnBox(), pArgs->ClientGC.refReturnValue->GetMethodTable(), m_pCliDomain);
- }
- }
- else if (pArgs->bHasObjRefReturnVal)
- {
- // Must be a domain agile GC ref. We can just copy the reference into the client GC frame.
- pArgs->ClientGC.refReturnValue = ServerGC.refReturnValue;
- }
-
- // Marshal any by-ref args into calling domain
- if (pArgs->bHasByRefArgsToMarshal)
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling by-ref args\n"));
-#endif
- int iMarshalledArg = -1;
- // Look for by ref args
- for (DWORD i = 0; i < pArgs->dwNumArgs; i++)
- {
- if (pArgs->bMarshalledArgs[i] != TRUE)
- continue;
-
- iMarshalledArg++;
-
- BOOL bNeedUnbox = pArgs->pArgAttribs[iMarshalledArg] & ARG_NEEDS_UNBOX;
- BOOL bIsByRef = pArgs->pArgAttribs[iMarshalledArg] & ARG_IS_BYREF;
-
- if (!bIsByRef)
- continue;
-
- TypeHandle argTh = pArgs->pThByRefs[iMarshalledArg];
- int offset = pArgs->pByRefArgAttribs[iMarshalledArg];
- OBJECTREF refReturn = pServerArgArray[iMarshalledArg];
- GCPROTECT_BEGIN(refReturn);
-
- refReturn = pArgs->Marshaller.Clone(refReturn,
- argTh,
- pCurAppDomain,
- m_pCliDomain,
- ServerGC.refExecutionContext);
- if (bNeedUnbox)
- {
- // We don't use the fast path for byref nullables, so UnBox() can be used
- BYTE *pTargetAddress = *((BYTE **)(m_pFrame->GetTransitionBlock() + offset));
- CopyValueClass(pTargetAddress, refReturn->UnBox(), refReturn->GetMethodTable(), m_pCliDomain);
- }
- else
- {
- SetObjectReference(*((OBJECTREF **)(m_pFrame->GetTransitionBlock() + offset)), refReturn, m_pCliDomain);
- }
- GCPROTECT_END();
- }
- }
-
- LeaveDomain:;
-
- GCPROTECT_END(); // pServerArgArray
- GCPROTECT_END(); // ServerGC
-}
-
-
-// Arguments need to be marshalled before dispatch. We walk thru each argument,
-// inspect its type, make a list of objects that need to be marshalled, cross over to the new domain,
-// marshal the objects and dispatch the call. Upon return, we marshal the return object if any and
-// by ref objects if any. Call contexts flows either way
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:21000) // Suppress PREFast warning about overly large function
-#endif
-BOOL
-CrossDomainChannel::MarshalAndCall()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- MarshalAndCallArgs args;
-
- args.bHasByRefArgsToMarshal = FALSE;
-
- args.bHasObjRefReturnVal = FALSE;
- args.bHasRetBuffArg = FALSE;
- args.bHasValueTypeReturnValToMarshal = FALSE;
-
- DWORD dwNumArgs = 0;
- DWORD dwNumObjectsMarshalled = 0;
-
- DWORD *pArgAttribs = NULL;
- BOOL *bMarshalledArgs = NULL;
- int *pByRefArgAttribs = NULL;
- TypeHandle *pThByRefs = NULL;
-
- Thread *pCurThread = GetThread();
-
-#ifdef _DEBUG
- LPCUTF8 pszMethodName;
- pszMethodName = m_pCliMD->GetName();
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Marshalling arguments to method %s\n", pszMethodName));
-#endif // _DEBUG
-
- // Collect all client domain GC references together in a single GC frame.
- // refReturnValue contains the returned object when its a value type and needs marshalling
- ZeroMemory(&args.ClientGC, sizeof(args.ClientGC));
- GCPROTECT_BEGIN(args.ClientGC);
-
- // When computing the method signature we need to take special care if the call is on a non-interface class with a
- // generic instantiation (since in that case we may have a representative method with a non-concrete signature).
- TypeHandle thDeclaringType;
- CDC_DETERMINE_DECLARING_TYPE(m_pCliMD, TypeHandle(CTPMethodTable::GetMethodTableBeingProxied(m_pFrame->GetThis())));
- MetaSig mSig(m_pCliMD, thDeclaringType);
- ArgIterator argit(&mSig);
- int ofs;
-
- // NumFixedArgs() doesn't count the "this" object, but SizeOfFrameArgumentArray() does.
- dwNumArgs = mSig.NumFixedArgs();
- m_numStackSlotsToCopy = argit.SizeOfFrameArgumentArray() / sizeof(SIZE_T);
-
- // Ensure none of the following _alloca's are subject to integer overflow problems.
- DWORD dwMaxEntries = dwNumArgs > m_numStackSlotsToCopy ? dwNumArgs : m_numStackSlotsToCopy;
- DWORD dwResult;
- if (!ClrSafeInt<DWORD>::multiply(dwMaxEntries, sizeof(SIZE_T), dwResult))
- COMPlusThrowOM();
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:26000) // "Suppress PREFast warning about integer overflow (we're doing an umbrella check)"
-#endif
-
- args.bHasRetBuffArg = argit.HasRetBuffArg();
-
-#ifdef _TARGET_X86_
- BOOL bArgumentRegisterUsed = FALSE;
- if (args.bHasRetBuffArg)
- {
- bArgumentRegisterUsed = TRUE;
- }
-#endif // _TARGET_X86_
-
- // pArgAttribs tell where the marshalled objects should go, where they need unboxing etc
- pArgAttribs = (DWORD*) _alloca(dwNumArgs * sizeof(DWORD));
- ZeroMemory(pArgAttribs, sizeof(DWORD) * dwNumArgs);
- // pThByRefs has the typehandles of the by-ref args
- pThByRefs = (TypeHandle *)_alloca(dwNumArgs * sizeof(TypeHandle));
- ZeroMemory(pThByRefs, sizeof(TypeHandle) *dwNumArgs);
- // pByRefArgAttribs tell where the by-ref args should go, after the call
- pByRefArgAttribs = (int*) _alloca(dwNumArgs * sizeof(int));
- ZeroMemory(pByRefArgAttribs, sizeof(int) * dwNumArgs);
- // bMarshalledArgs is a bunch of flags that tell which args were marshalled
- bMarshalledArgs = (BOOL*) _alloca(dwNumArgs * sizeof(BOOL));
- ZeroMemory(bMarshalledArgs, sizeof(BOOL) * dwNumArgs);
-
- // pArgArray contains marshalled objects on the client side
- OBJECTREF *pClientArgArray = NULL;
- pClientArgArray = (OBJECTREF *) _alloca(dwNumArgs * sizeof(OBJECTREF));
- ZeroMemory(pClientArgArray, sizeof(OBJECTREF) * dwNumArgs);
- GCPROTECT_ARRAY_BEGIN(pClientArgArray[0], dwNumArgs);
-
- // pStackArgs will finally contain the arguments that'll be fed to Dispatch call. The Marshalled objects
- // are not placed directly into pStackArgs because its not possible to GCPROTECT an array that can contain
- // both GC refs and primitives.
- DWORD cbStackArgs = m_numStackSlotsToCopy * sizeof (SIZE_T);
-#ifdef CALLDESCR_ARGREGS
- // Allocate enough space to put ArgumentRegisters at the front of the buffer so we can ensure
- // register and stack arguments are stored contiguously and simply the case of unboxing a value type that
- // spans registers and the stack.
- cbStackArgs += sizeof(ArgumentRegisters);
-#endif
- SIZE_T *pStackArgs = (SIZE_T*)_alloca(cbStackArgs);
- ZeroMemory(pStackArgs, cbStackArgs);
-#ifdef CALLDESCR_ARGREGS
- SIZE_T *pRegArgs = pStackArgs;
- pStackArgs += sizeof(ArgumentRegisters) / sizeof(SIZE_T);
-#endif
-#ifdef CALLDESCR_FPARGREGS
- FloatArgumentRegisters *pFloatArgumentRegisters = NULL;
-#endif
-
-#if defined(CALLDESCR_REGTYPEMAP)
- UINT64 uRegTypeMap = 0;
- BYTE* pMap = (BYTE*)&uRegTypeMap;
-#endif
-
- TADDR pTransitionBlock = m_pFrame->GetTransitionBlock();
-
- for (int argNum = 0;
- TransitionBlock::InvalidOffset != (ofs = argit.GetNextOffset());
- argNum++
- )
- {
- DWORD dwOffsetOfArg = 0;
-
-#if defined(CALLDESCR_REGTYPEMAP)
- int regArgNum = TransitionBlock::GetArgumentIndexFromOffset(ofs);
-
- FillInRegTypeMap(ofs, argit.GetArgType(), pMap);
-#endif // defined(CALLDESCR_REGTYPEMAP)
-
- SIZE_T *pDestToCopy = NULL;
-
-#if defined(_TARGET_ARM_)
-
- // On ARM there are ranges of offset that can be returned from ArgIterator::GetNextOffset() (where R
- // == TransitionBlock::GetOffsetOfArgumentRegisters() and S == sizeof(TransitionBlock)):
- //
- // * ofs < 0 : arg is in a floating point register
- // * ofs >= R && ofs < S : arg is in a general register
- // * ofs >= S : arg is on the stack at offset (ofs - X)
- //
- // Arguments can be split between general registers and the stack on ARM and as a result both
- // FramedMethodFrame and this method ensure the storage for register and stack locations is
- // contiguous.
- int iInitialRegOffset = TransitionBlock::GetOffsetOfArgumentRegisters();
- int iInitialStackOffset = sizeof(TransitionBlock);
- _ASSERTE(iInitialStackOffset == (iInitialRegOffset + sizeof(ArgumentRegisters)));
- if (ofs < 0)
- {
- // Floating point register case. Since these registers can never hold a GC reference we can just
- // pass through a pointer to the spilled FP reg area in the frame. But we don't do this unless we
- // see at least one FP arg: passing NULL for pFloatArgumentRegisters enables an optimization in
- // the call thunk.
- if (pFloatArgumentRegisters == NULL)
- pFloatArgumentRegisters = (FloatArgumentRegisters*) (pTransitionBlock + TransitionBlock::GetOffsetOfFloatArgumentRegisters());
-
- // No arg to copy in this case.
- continue;
- }
-
- _ASSERTE(ofs >= iInitialRegOffset);
-
- // We've ensured our registers and stack locations are contiguous so treat both types of arguments
- // identically (i.e. compute a destination offset from the base of the register save area and it will
- // work for arguments that span from registers to stack or live entirely on the stack).
- dwOffsetOfArg = ofs - TransitionBlock::GetOffsetOfArgumentRegisters();
- pDestToCopy = (SIZE_T*)((BYTE *)pRegArgs + dwOffsetOfArg);
-
-#else // _TARGET_ARM_
-
- dwOffsetOfArg = ofs - TransitionBlock::GetOffsetOfArgs();
-
-#ifdef _TARGET_X86_
- if (!bArgumentRegisterUsed && gElementTypeInfo[argit.GetArgType()].m_enregister)
- {
- pDestToCopy = pRegArgs;
- bArgumentRegisterUsed = TRUE;
- }
- else
-#endif // _TARGET_X86_
- {
- _ASSERTE(dwOffsetOfArg < (m_numStackSlotsToCopy * sizeof(SIZE_T)));
- pDestToCopy = (SIZE_T*)((BYTE *)pStackArgs + dwOffsetOfArg);
- }
-
-#endif // _TARGET_ARM_
-
- CorElementType origTyp = argit.GetArgType();
-
- // Get the signature type of the argument (For ex. enum will be E_T_VT, not E_T_I4 etc)
- SigPointer sp = mSig.GetArgProps();
- CorElementType typ;
- IfFailThrow(sp.GetElemType(&typ));
-
- if (typ == ELEMENT_TYPE_VAR ||
- typ == ELEMENT_TYPE_MVAR ||
- typ == ELEMENT_TYPE_GENERICINST)
- {
- typ = origTyp;
- }
-
- switch (typ)
- {
- case ELEMENT_TYPE_BOOLEAN:
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_CHAR:
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
-#if !defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
- case ELEMENT_TYPE_R4:
-#endif
-
-#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
- *(pDestToCopy) = *((SIZE_T*) (pTransitionBlock + ofs));
-#elif defined(_WIN64)
- switch (GetSizeForCorElementType((CorElementType)typ))
- {
- case 1:
- *(BYTE*)(pDestToCopy) = *(BYTE*)(pTransitionBlock + ofs);
- break;
-
- case 2:
- *(USHORT*)(pDestToCopy) = *(USHORT*)(pTransitionBlock + ofs);
- break;
-
- case 4:
- *(UINT*)(pDestToCopy) = *(UINT*)(pTransitionBlock + ofs);
- break;
-
- case 8:
- *(SIZE_T*)(pDestToCopy) = *(SIZE_T*)(pTransitionBlock + ofs);
- break;
-
- default:
- _ASSERTE(!"MarshalAndCall() - unexpected size");
- }
-#else // !defined(_WIN64)
- PORTABILITY_ASSERT("MarshalAndCall() - NYI on this platform");
-#endif // !defined(_WIN64)
- break;
-
- case ELEMENT_TYPE_I:
- case ELEMENT_TYPE_U:
- case ELEMENT_TYPE_PTR:
- case ELEMENT_TYPE_FNPTR:
-
- *((SIZE_T*)((BYTE *)pDestToCopy)) = *((SIZE_T*)(pTransitionBlock + ofs));
- break;
-
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
-#if !defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
- case ELEMENT_TYPE_R8:
-#endif
-
- *((INT64*)((BYTE *)pDestToCopy)) = *((INT64 *)(pTransitionBlock + ofs));
- break;
-
-#if defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
- case ELEMENT_TYPE_R4:
-
- if (regArgNum < NUM_ARGUMENT_REGISTERS)
- {
- *(ARG_SLOT*)pDestToCopy = FPSpillToR4( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) );
- }
- else
- {
- *(UINT*)(pDestToCopy) = *(UINT*)(pTransitionBlock + ofs);
- }
- break;
-
- case ELEMENT_TYPE_R8:
-
- if (regArgNum < NUM_ARGUMENT_REGISTERS)
- {
- *(ARG_SLOT*)pDestToCopy = FPSpillToR8( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) );
- }
- else
- {
- *(SIZE_T*)(pDestToCopy) = *(SIZE_T*)(pTransitionBlock + ofs);
- }
- break;
-#endif // defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
-
- case ELEMENT_TYPE_BYREF:
- {
- // Check if this is a by-ref primitive
- OBJECTREF refTmpBox = NULL;
- TypeHandle ty = TypeHandle();
- CorElementType brType = mSig.GetByRefType(&ty);
- if (CorIsPrimitiveType(brType) || ty.IsValueType())
- {
-
- // Needs marshalling
- MethodTable *pMT = NULL;
- if (CorIsPrimitiveType(brType))
- pMT = MscorlibBinder::GetElementType(brType);
- else
- pMT = ty.GetMethodTable();
- refTmpBox = pMT->Box(*((SIZE_T**)(pTransitionBlock + ofs)));
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_NEEDS_UNBOX;
- }
- else
- {
- OBJECTREF *refRefObj = *((OBJECTREF **)(pTransitionBlock + ofs));
- refTmpBox = (refRefObj == NULL ? NULL : *refRefObj);
- }
-
- pByRefArgAttribs[dwNumObjectsMarshalled] = ofs;
- pThByRefs[dwNumObjectsMarshalled] = ty;
-
- // we should have stopped nullables before we got here in DoStaticAnalysis
- _ASSERTE(ty.IsNull() || !Nullable::IsNullableType(ty));
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_IS_BYREF;
-
- args.bHasByRefArgsToMarshal = TRUE;
-
- pClientArgArray[dwNumObjectsMarshalled] = refTmpBox;
- bMarshalledArgs[argNum] = TRUE;
-
-#if defined(_TARGET_X86_)
- if (pDestToCopy == pRegArgs)
- {
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_GOES_IN_EDX; // Indicate that this goes in EDX
- }
- else
-#endif // _TARGET_X86_
- {
- // @TODO - Use QWORD for attribs
- _ASSERTE(dwOffsetOfArg < ARG_OFFSET_MASK);
- pArgAttribs[dwNumObjectsMarshalled] |= dwOffsetOfArg;
- }
- dwNumObjectsMarshalled++;
- }
- break;
-
- case ELEMENT_TYPE_VALUETYPE:
- {
-#if defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
- if (regArgNum < NUM_ARGUMENT_REGISTERS)
- {
-
- // We have to copy the floating point registers from a different stack location to the portion of
- // the stack used to save the general registers.
- if (origTyp == ELEMENT_TYPE_R4)
- {
- LPVOID pDest = (LPVOID)(pTransitionBlock + ofs);
- *(ARG_SLOT*)pDest = FPSpillToR4( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) );
- }
- else if (origTyp == ELEMENT_TYPE_R8)
- {
- LPVOID pDest = (LPVOID)(pTransitionBlock + ofs);
- *(ARG_SLOT*)pDest = FPSpillToR8( (LPVOID)(pTransitionBlock + m_pFrame->GetFPArgOffset(regArgNum)) );
- }
- }
-#endif // defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
-
- TypeHandle th = mSig.GetLastTypeHandleThrowing();
-
-#ifdef _DEBUG
- {
- DefineFullyQualifiedNameForClass()
- LPCUTF8 szTypeName = GetFullyQualifiedNameForClassNestedAware(th.GetMethodTable());
- LOG((LF_REMOTING, LL_INFO100, "MarshalAndCall. Boxing a value type argument of type %s.\n", &szTypeName[0]));
- }
-#endif // _DEBUG
-
- OBJECTREF refTmpBox;
-#if defined(ENREGISTERED_PARAMTYPE_MAXSIZE)
- if (argit.IsArgPassedByRef())
- {
- refTmpBox = th.GetMethodTable()->Box(*(LPVOID*)(pTransitionBlock + ofs));
-
- // we should have stopped nullables before we got here in DoStaticAnalysis
- _ASSERTE(!Nullable::IsNullableType(th));
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_IS_BYREF;
-
- pByRefArgAttribs[dwNumObjectsMarshalled] = ofs;
- pThByRefs[dwNumObjectsMarshalled] = th;
- }
- else
-#endif // defined(ENREGISTERED_PARAMTYPE_MAXSIZE)
- {
- refTmpBox = th.GetMethodTable()->Box((void *)(pTransitionBlock + ofs));
- }
- pClientArgArray[dwNumObjectsMarshalled] = refTmpBox;
- bMarshalledArgs[argNum] = TRUE;
-
-#if defined(_TARGET_X86_)
- if (pDestToCopy == pRegArgs)
- {
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_GOES_IN_EDX; // Indicate that this goes in EDX
- }
- else
-#endif // _TARGET_X86_
- {
- // @TODO - Use QWORD for attribs
- _ASSERTE(dwOffsetOfArg < ARG_OFFSET_MASK);
- pArgAttribs[dwNumObjectsMarshalled] |= dwOffsetOfArg;
- }
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_NEEDS_UNBOX; // Indicate that an unboxing is required
- dwNumObjectsMarshalled++;
- }
- break;
-
- case ELEMENT_TYPE_SZARRAY: // Single Dim
- case ELEMENT_TYPE_ARRAY: // General Array
- case ELEMENT_TYPE_CLASS: // Class
- case ELEMENT_TYPE_OBJECT:
- case ELEMENT_TYPE_STRING: // System.String
- case ELEMENT_TYPE_VAR:
- {
- OBJECTREF *refRefObj = (OBJECTREF *)(pTransitionBlock + ofs);
- // The frame does protect this object, so mark it as such to avoid asserts
- INDEBUG(Thread::ObjectRefNew(refRefObj);)
- INDEBUG(Thread::ObjectRefProtected(refRefObj);)
-
- pClientArgArray[dwNumObjectsMarshalled] = *refRefObj;
- bMarshalledArgs[argNum] = TRUE;
-
-#ifdef _TARGET_X86_
- if (pDestToCopy == pRegArgs)
- {
- pArgAttribs[dwNumObjectsMarshalled] |= ARG_GOES_IN_EDX; // Indicate that this goes in EDX
- }
- else
-#endif // _TARGET_X86_
- {
- // @TODO - Use QWORD for attribs
- _ASSERTE(dwOffsetOfArg < ARG_OFFSET_MASK);
- pArgAttribs[dwNumObjectsMarshalled] |= dwOffsetOfArg;
- }
- dwNumObjectsMarshalled++;
- }
- break;
-
- default:
- _ASSERTE(!"Unknown Element type in MarshalAndCall" );
- }
- }
-
- if (!RemotableMethodInfo::IsReturnBlittable(m_xret))
- {
- CorElementType retType = mSig.GetReturnType();
- if (retType == ELEMENT_TYPE_VALUETYPE)
- {
- args.retTh = mSig.GetRetTypeHandleThrowing();
- args.bHasValueTypeReturnValToMarshal = TRUE;
- }
- else
- {
- args.retTh = mSig.GetRetTypeHandleThrowing();
- }
- }
-
- // Check for any call context
- BOOL bMarshalCallContext = FALSE;
- args.bMarshalReturnCallContext = FALSE;
- if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- EXECUTIONCONTEXTREF refExecCtx = (EXECUTIONCONTEXTREF) ref->GetExecutionContext();
- if (refExecCtx != NULL)
- {
- args.ClientGC.refExecutionContext = refExecCtx;
- args.ClientGC.refPrincipal = ReadPrincipal();
-
- LOGICALCALLCONTEXTREF refLogCallCtx = refExecCtx->GetLogicalCallContext();
- if (refLogCallCtx != NULL)
- {
- if (refLogCallCtx->ContainsDataForSerialization())
- {
- bMarshalCallContext = TRUE;
- }
- }
- }
- }
-
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
- // Make the Cross-AppDomain call
- {
- args.pThis = this;
-
- args.bOptimizable = TRUE;
-
- args.mSig = &mSig;
- args.argit = &argit;
-
- args.dwNumArgs = dwNumArgs;
- args.pStackArgs = pStackArgs;
-#ifdef CALLDESCR_ARGREGS
- args.pRegArgs = pRegArgs;
-#endif
-#ifdef CALLDESCR_FPARGREGS
- args.pFloatArgumentRegisters = pFloatArgumentRegisters;
-#endif
- args.pArgAttribs = pArgAttribs;
-
- args.dwNumObjectsMarshalled = dwNumObjectsMarshalled;
- args.bMarshalledArgs = bMarshalledArgs;
- args.pClientArgArray = pClientArgArray;
-
- args.pByRefArgAttribs = pByRefArgAttribs;
- args.pThByRefs = pThByRefs;
-
- args.bMarshalCallContext = bMarshalCallContext;
-
-#ifdef CALLDESCR_REGTYPEMAP
- args.uRegTypeMap = *(UINT64*)pMap;
-#endif
-
-#ifdef FEATURE_CORRUPTING_EXCEPTIONS
- // By default assume that exception thrown across the cross-AD call is NotCorrupting.
- args.severity = NotCorrupting;
-#endif // FEATURE_CORRUPTING_EXCEPTIONS
-
- MakeCallWithPossibleAppDomainTransition(m_pSrvDomain, (FPAPPDOMAINCALLBACK) MarshalAndCall_Wrapper2, &args);
- }
-
- if (args.ClientGC.refException != NULL)
- {
- RestorePrincipal(&args.ClientGC.refPrincipal);
- COMPlusThrow(args.ClientGC.refException
- COMMA_CORRUPTING_EXCEPTIONS_ONLY(args.severity)
- );
- }
-
- if (pCurThread->IsExposedObjectSet())
- {
- THREADBASEREF ref = (THREADBASEREF) pCurThread->GetExposedObjectRaw();
- _ASSERTE(ref != NULL);
-
- ref->SetExecutionContext(args.ClientGC.refExecutionContext);
- }
-
- RestorePrincipal(&args.ClientGC.refPrincipal);
-
- // If the return type is an object, take it out of the protected ref
- if (args.bHasObjRefReturnVal)
- {
- *(Object **)m_pFrame->GetReturnValuePtr() = OBJECTREFToObject(args.ClientGC.refReturnValue);
- }
-
- GCPROTECT_END(); // pClientArgArray
- GCPROTECT_END(); // args.ClientGC
-
- args.Marshaller.RemoveGCFrames();
-
- return args.bOptimizable;
-}
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
-#endif // CROSSGEN_COMPILE
-
-#endif // FEATURE_REMOTING
diff --git a/src/vm/eeconfigfactory.cpp b/src/vm/eeconfigfactory.cpp
deleted file mode 100644
index a0eb927ce9..0000000000
--- a/src/vm/eeconfigfactory.cpp
+++ /dev/null
@@ -1,398 +0,0 @@
-// 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.
-// EEConfigFactory.cpp
-//
-
-//
-// Factory used to with the XML parser to read configuration files
-//
-
-#include "common.h"
-#include "ngenoptout.h"
-#include "eeconfigfactory.h"
-
-
-#define ISWHITE(ch) ((ch) >= 0x09 && (ch) <= 0x0D || (ch) == 0x20)
-
-#define CONST_STRING_AND_LEN(str) str, NumItems(str)-1
-
-
-int EEXMLStringCompare(const WCHAR *pStr1,
- DWORD cchStr1,
- const WCHAR *pStr2,
- DWORD cchStr2)
-{
- LIMITED_METHOD_CONTRACT;
- if (cchStr1 != cchStr2)
- return -1;
-
- return wcsncmp(pStr1, pStr2, cchStr1);
-}// EEXMLStringCompare
-
-
-int EEXMLStringComparei(const WCHAR *pStr1,
- DWORD cchStr1,
- const WCHAR *pStr2,
- DWORD cchStr2)
-{
- WRAPPER_NO_CONTRACT;
- if (cchStr1 != cchStr2)
- return -1;
-
- return SString::_wcsnicmp(pStr1, pStr2, cchStr1);
-}// EEXMLStringCompare
-
-
-
-EEConfigFactory::EEConfigFactory(
- ConfigStringHashtable* pTable,
- LPCWSTR pString,
- ParseCtl parseCtl)
-{
- LIMITED_METHOD_CONTRACT;
- m_pTable = pTable;
- m_pVersion = pString;
- m_dwDepth = 0;
- m_fUnderRuntimeElement = FALSE;
- m_fDeveloperSettings = FALSE;
- m_fVersionedRuntime= FALSE;
- m_fOnEnabledAttribute = FALSE;
- m_fOnValueAttribute = FALSE;
- m_pCurrentRuntimeElement = m_pBuffer;
- m_dwCurrentRuntimeElement = 0;
- m_dwSize = CONFIG_KEY_SIZE;
- m_parseCtl = parseCtl;
- m_pActiveFactory = NULL;
-}
-
-EEConfigFactory::~EEConfigFactory()
-{
- LIMITED_METHOD_CONTRACT;
- DeleteKey();
-}
-
-HRESULT STDMETHODCALLTYPE EEConfigFactory::NotifyEvent(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt)
-{
- LIMITED_METHOD_CONTRACT;
- if(iEvt == XMLNF_ENDDOCUMENT) {
- // <TODO> add error handling.</TODO>
- }
- if(m_pActiveFactory != NULL)
- return m_pActiveFactory->NotifyEvent(pSource, iEvt);
-
- return S_OK;
-}
-//---------------------------------------------------------------------------
-HRESULT STDMETHODCALLTYPE EEConfigFactory::BeginChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo)
-{
- LIMITED_METHOD_CONTRACT;
-
- m_dwDepth++;
- if(m_pActiveFactory != NULL)
- return m_pActiveFactory->BeginChildren(pSource, pNodeInfo);
- return S_OK;
-
-}
-//---------------------------------------------------------------------------
-HRESULT STDMETHODCALLTYPE EEConfigFactory::EndChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmptyNode,
- /* [in] */ XML_NODE_INFO __RPC_FAR *pNodeInfo)
-{
- LIMITED_METHOD_CONTRACT;
- if ( fEmptyNode ) {
- m_fDeveloperSettings = FALSE;
- }
- else {
- m_dwDepth--;
- }
-
- if (m_pActiveFactory != NULL)
- {
- HRESULT hr = S_OK;
- IfFailRet(m_pActiveFactory->EndChildren(pSource, fEmptyNode, pNodeInfo));
-
-
- if(m_dwDepth == 2) // when generalizing: use the current active factory depth
- {
- m_pActiveFactory = NULL;
- }
-
- }
-
- if (m_fUnderRuntimeElement && wcscmp(pNodeInfo->pwcText, W("runtime")) == 0) {
- m_fUnderRuntimeElement = FALSE;
- m_fVersionedRuntime = FALSE;
- ClearKey();
- // CLR_STARTUP_OPT:
- // Early out if we only need to read <runtime> section.
- //
- if (m_parseCtl == stopAfterRuntimeSection)
- pSource->Abort(NULL/*unused*/);
- }
-
- return S_OK;
-}
-//---------------------------------------------------------------------------
-HRESULT STDMETHODCALLTYPE EEConfigFactory::CreateNode(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- if(m_pActiveFactory != NULL)
- return m_pActiveFactory->CreateNode(pSource, pNode, cNumRecs, apNodeInfo);
-
- if(m_dwDepth > 3)
- {
-
- return S_OK;
- }
-
- HRESULT hr = S_OK;
- DWORD dwStringSize = 0;
- WCHAR* pszString = NULL;
- DWORD i;
- BOOL fRuntimeKey = FALSE;
- BOOL fVersion = FALSE;
-
- for( i = 0; i < cNumRecs; i++) {
- CONTRACT_VIOLATION(ThrowsViolation); // Lots of stuff in here throws!
-
- if(apNodeInfo[i]->dwType == XML_ELEMENT ||
- apNodeInfo[i]->dwType == XML_ATTRIBUTE ||
- apNodeInfo[i]->dwType == XML_PCDATA) {
-
- dwStringSize = apNodeInfo[i]->ulLen;
- pszString = (WCHAR*) apNodeInfo[i]->pwcText;
- // Trim the value
-
- // we should never decrement lgth if it's 0, because it's unsigned
-
- for(;*pszString && ISWHITE(*pszString) && dwStringSize>0; pszString++, dwStringSize--);
- while( dwStringSize > 0 && ISWHITE(pszString[dwStringSize-1]))
- dwStringSize--;
-
- // NOTE: pszString is not guaranteed to be null terminated. Use EEXMLStringCompare to do
- // string comparisions on it
-
- switch(apNodeInfo[i]->dwType) {
- case XML_ELEMENT :
- fRuntimeKey = FALSE;
- ClearKey();
-
- if (m_dwDepth == 1 && EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("runtime"))) == 0) {
- m_fUnderRuntimeElement = TRUE;
- fRuntimeKey = TRUE;
- }
-
- if(m_dwDepth == 2 && m_fUnderRuntimeElement) {
-
- // Developer settings can look like
- // <runtime>
- // <developerSettings installationVersion="v2.0.40223.0" />
- //
- // or
- //
- // <developmentMode developerInstallation="true" />
- //
- // Neither one is your standard config setting.
- if (!EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("developerSettings"))) ||
- !EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("developmentMode"))))
- {
- m_fDeveloperSettings = TRUE;
- }
- else
- // when generalizing: use map of (string, depth) -> class
- if (!EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("disableNativeImageLoad"))))
- {
- m_pActiveFactory = new NativeImageOptOutConfigFactory();
- m_pActiveFactory->AddRef();
- }
- else
- {
- // This is a standard element under the runtime node.... it could look like this
- // <runtime>
- // <pszString enabled="1" />
-
- hr = CopyToKey(pszString, dwStringSize);
- if(FAILED(hr)) return hr;
- }
- }
- // If our depth isn't 2, and we're not under the runtime element....
- else
- ClearKey();
-
- break ;
-
- case XML_ATTRIBUTE :
- if(fRuntimeKey && EEXMLStringCompare(pszString, dwStringSize, CONST_STRING_AND_LEN(W("version"))) == 0) {
- fVersion = TRUE;
- }
- else
- {
- if (m_dwDepth == 2 && m_fUnderRuntimeElement)
- {
- if (!m_fDeveloperSettings)
- {
- _ASSERTE(m_dwCurrentRuntimeElement > 0);
-
- // The standard model for runtime config settings is as follows
- //
- // <runtime>
- // <m_pCurrentRuntimeElement enabled="true|false" />
- // or
- // <m_pCurrentRuntimeElement enabled="1|0" />
- // or
- // <m_pCurrentRuntimeElement value="string" />
-
- m_fOnEnabledAttribute = (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("enabled"))) == 0);
- m_fOnValueAttribute = (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("value"))) == 0);
- }
- else // We're looking at developer settings
- {
- // Developer settings look like
- // <developerSettings installationVersion="v2.0.40223.0" />
- //
- // or
- //
- // <developmentMode developerInstallation="true" />
- //
-
- // The key name will actually be the attribute name
-
- hr = CopyToKey(pszString, dwStringSize);
- if(FAILED(hr)) return hr;
- m_fOnEnabledAttribute = FALSE;
- m_fOnValueAttribute = FALSE;
- }
- }
- }
- break;
- case XML_PCDATA:
- if(fVersion) {
- // if this is not the right version
- // then we are not interested
- if(EEXMLStringCompare(pszString, dwStringSize, m_pVersion, (DWORD)wcslen(m_pVersion))) {
- m_fUnderRuntimeElement = FALSE;
- }
- else {
- // if it is the right version then overwrite
- // all entries that exist in the hash table
- m_fVersionedRuntime = TRUE;
- }
-
- fVersion = FALSE;
- }
- else if(fRuntimeKey) {
- break; // Ignore all other attributes on <runtime>
- }
-
- // m_dwCurrentRuntimeElement is set when we called CopyToKey in the XML_ELEMENT case
- // section above.
- else if(m_dwCurrentRuntimeElement > 0 && (m_fDeveloperSettings || m_fOnEnabledAttribute || m_fOnValueAttribute)) {
-
- // This means that, either we are working on attribute values for the developer settings,
- // or we've got what "enabled" is equal to, or we're reading a string for a value setting.
- //
- // <runtime>
- // <m_pwzCurrentElementUnderRuntimeElement m_pLastKey=pString />
-
- if (m_fOnEnabledAttribute) {
- // For the enabled settings, let's convert all trues to 1s and the falses to 0s
- if (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("false"))) == 0) {
- pszString = W("0");
- dwStringSize = 1;
- }
- else if (EEXMLStringComparei(pszString, dwStringSize, CONST_STRING_AND_LEN(W("true"))) == 0) {
- pszString = W("1");
- dwStringSize = 1;
- }
-
- // <TODO> Right now, if pString isn't 0 or 1, then the XML schema is bad.
- // If we were to ever do schema validation, this would be a place to put it.
- // </TODO>
- }
-
- hr = AddKeyValuePair(pszString, dwStringSize, m_pCurrentRuntimeElement, m_dwCurrentRuntimeElement);
- if(FAILED(hr)) { return hr; }
- }
-
- break ;
- default:
- ;
- } // end of switch
- }
- }
- return hr;
-}
-
-HRESULT STDMETHODCALLTYPE EEConfigFactory::AddKeyValuePair(
- __in_ecount(dwStringSize) WCHAR * pszString,
- /* [in] */ DWORD dwStringSize,
- __in_ecount(m_dwCurrentRuntimeElement) WCHAR * m_pCurrentRuntimeElement,
- /* [in] */ DWORD m_dwCurrentRuntimeElement
- )
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- INJECT_FAULT(return E_OUTOFMEMORY;);
- }
- CONTRACTL_END;
-
- HRESULT hr = S_OK;
-
- // verify we the size fields don't overflow
- if (dwStringSize + 1 < dwStringSize) { return E_FAIL; }
- if (m_dwCurrentRuntimeElement < m_dwCurrentRuntimeElement - 1) { return E_FAIL; }
-
- EX_TRY
- {
- // Allocate memory that can store this setting
- NewArrayHolder<WCHAR> pStringToKeep(new WCHAR[dwStringSize+1]);
- wcsncpy_s(pStringToKeep, dwStringSize + 1, pszString, dwStringSize);
-
- // See if we've already picked up a value for this setting
- ConfigStringKeyValuePair * pair = m_pTable->Lookup(m_pCurrentRuntimeElement);
- if(pair != NULL) {
- // If this is a config section for this runtime version, then it's allowed to overwrite
- // previous settings that we've picked up
- if(m_fVersionedRuntime) {
- delete[] pair->value;
- pair->value = pStringToKeep;
- pStringToKeep.SuppressRelease();
- }
- }
- else {
- // We're adding a new config item
- NewArrayHolder<WCHAR> pKeyToKeep (new WCHAR[m_dwCurrentRuntimeElement]);
- wcsncpy_s(pKeyToKeep, m_dwCurrentRuntimeElement, m_pCurrentRuntimeElement, m_dwCurrentRuntimeElement - 1);
-
- ConfigStringKeyValuePair * newPair = new ConfigStringKeyValuePair();
- newPair->key = pKeyToKeep;
- newPair->value = pStringToKeep;
- m_pTable->Add(newPair);
- pKeyToKeep.SuppressRelease();
- pStringToKeep.SuppressRelease();
- }
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
diff --git a/src/vm/eeconfigfactory.h b/src/vm/eeconfigfactory.h
deleted file mode 100644
index 2554295268..0000000000
--- a/src/vm/eeconfigfactory.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// 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.
-// EEConfigFactory.h
-//
-
-//
-// Parses XML files and adding runtime entries to the EEConfig list
-//
-
-
-#ifndef EECONFIGFACTORY_H
-#define EECONFIGFACTORY_H
-
-#include <xmlparser.h>
-#include <objbase.h>
-#include "unknwn.h"
-#include "../xmlparser/_reference.h"
-#include "../xmlparser/_unknown.h"
-#include "eehash.h"
-#include "eeconfig.h"
-
-#define CONFIG_KEY_SIZE 128
-
-class EEConfigFactory : public _unknown<IXMLNodeFactory, &IID_IXMLNodeFactory>
-{
-
-public:
- EEConfigFactory(
- ConfigStringHashtable* pTable,
- LPCWSTR,
- ParseCtl parseCtl = parseAll);
- ~EEConfigFactory();
- HRESULT STDMETHODCALLTYPE NotifyEvent(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODEFACTORY_EVENT iEvt);
-
- HRESULT STDMETHODCALLTYPE BeginChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo);
-
- HRESULT STDMETHODCALLTYPE EndChildren(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ BOOL fEmptyNode,
- /* [in] */ XML_NODE_INFO* __RPC_FAR pNodeInfo);
-
- HRESULT STDMETHODCALLTYPE Error(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ HRESULT hrErrorCode,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo)
- {
- LIMITED_METHOD_CONTRACT;
- /*
- UNUSED(pSource);
- UNUSED(hrErrorCode);
- UNUSED(cNumRecs);
- UNUSED(apNodeInfo);
- */
- return hrErrorCode;
- }
-
- HRESULT STDMETHODCALLTYPE CreateNode(
- /* [in] */ IXMLNodeSource __RPC_FAR *pSource,
- /* [in] */ PVOID pNodeParent,
- /* [in] */ USHORT cNumRecs,
- /* [in] */ XML_NODE_INFO* __RPC_FAR * __RPC_FAR apNodeInfo);
-
-private:
-
- HRESULT GrowKey(DWORD dwSize)
- {
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- INJECT_FAULT(return E_OUTOFMEMORY);
- }
- CONTRACTL_END;
-
- if(dwSize > m_dwSize) {
- DeleteKey();
- m_pCurrentRuntimeElement = new(nothrow) WCHAR[dwSize];
- if(m_pCurrentRuntimeElement == NULL) return E_OUTOFMEMORY;
- m_dwSize = dwSize;
- }
- return S_OK;
- }
-
- void ClearKey()
- {
- LIMITED_METHOD_CONTRACT;
-
- *m_pCurrentRuntimeElement = 0;
- m_dwCurrentRuntimeElement = 0;
- }
-
- void DeleteKey()
- {
- WRAPPER_NO_CONTRACT;
- if(m_pCurrentRuntimeElement != NULL && m_pCurrentRuntimeElement != m_pBuffer)
- delete [] m_pCurrentRuntimeElement;
- m_dwSize = 0;
- m_dwCurrentRuntimeElement = 0;
- }
-
- HRESULT CopyToKey(__in_z LPCWSTR pString, DWORD dwString)
- {
- WRAPPER_NO_CONTRACT;
- dwString++; // add in the null
- HRESULT hr = GrowKey(dwString);
- if(FAILED(hr)) return hr;
- wcsncpy_s(m_pCurrentRuntimeElement, m_dwSize, pString, dwString-1);
-
- m_dwCurrentRuntimeElement = dwString;
- return S_OK;
- }
-
- HRESULT STDMETHODCALLTYPE AddKeyValuePair(
- __in_ecount(dwStringSize) WCHAR * pszString,
- /* [in] */ DWORD dwStringSize,
- __in_ecount(m_dwCurrentRuntimeElement) WCHAR * m_pCurrentRuntimeElement,
- /* [in] */ DWORD m_dwCurrentRuntimeElement);
-
- HRESULT CopyVersion(LPCWSTR version, DWORD dwVersion);
-
- ConfigStringHashtable* m_pTable;
- BOOL m_fUnderRuntimeElement;
- BOOL m_fOnEnabledAttribute;
- BOOL m_fOnValueAttribute;
- BOOL m_fVersionedRuntime;
- BOOL m_fDeveloperSettings;
-
- LPCWSTR m_pVersion;
- LPWSTR m_pCurrentRuntimeElement;
- DWORD m_dwCurrentRuntimeElement;
-
- WCHAR m_pBuffer[CONFIG_KEY_SIZE];
- DWORD m_dwSize;
-
- DWORD m_dwDepth;
-
- bool m_bSafeMode; // If true, will ignore any settings that may compromise security
- ParseCtl m_parseCtl; // usually parseAll, sometimes stopAfterRuntimeSection
-
- ReleaseHolder<IXMLNodeFactory> m_pActiveFactory; // hold a factory responsible for parsing subnode
-};
-
-#endif
diff --git a/src/vm/gchost.cpp b/src/vm/gchost.cpp
deleted file mode 100644
index af213c27be..0000000000
--- a/src/vm/gchost.cpp
+++ /dev/null
@@ -1,28 +0,0 @@
-// 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.
-//*****************************************************************************
-// gchost.cpp
-//
-// This module contains the implementation for the IGCController interface.
-// This interface is published through the gchost.idl file. It allows a host
-// environment to set config values for the GC.
-//
-
-//
-//*****************************************************************************
-
-//********** Includes *********************************************************
-
-#include "common.h"
-#include "vars.hpp"
-#include "eeconfig.h"
-#include "perfcounters.h"
-#include "gchost.h"
-#include "corhost.h"
-#include "excep.h"
-#include "field.h"
-#include "gcheaputilities.h"
-
-
-
diff --git a/src/vm/i386/excepx86.cpp b/src/vm/i386/excepx86.cpp
index 10f68a9fbf..2997c5784f 100644
--- a/src/vm/i386/excepx86.cpp
+++ b/src/vm/i386/excepx86.cpp
@@ -28,7 +28,6 @@
#include "dllimportcallback.h"
#include "threads.h"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#endif
#include "eeconfig.h"
#include "vars.hpp"
diff --git a/src/vm/i386/remotingx86.cpp b/src/vm/i386/remotingx86.cpp
deleted file mode 100644
index 3a9e891267..0000000000
--- a/src/vm/i386/remotingx86.cpp
+++ /dev/null
@@ -1,225 +0,0 @@
-// 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.
-//
-//
-//
-// File: remotingx86.cpp
-//
-
-//
-//
-// Purpose: Defines various remoting related functions for the x86 architecture
-//
-
-//
-//
-
-//
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-
-#include "excep.h"
-#include "comdelegate.h"
-#include "remoting.h"
-#include "field.h"
-#include "siginfo.hpp"
-#include "stackbuildersink.h"
-#include "threads.h"
-#include "method.hpp"
-#include "asmconstants.h"
-#include "interoputil.h"
-#include "virtualcallstub.h"
-
-#ifdef FEATURE_COMINTEROP
-#include "comcallablewrapper.h"
-#include "comcache.h"
-#endif // FEATURE_COMINTEROP
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CreateThunkForVirtualMethod private
-//
-// Synopsis: Creates the thunk that pushes the supplied slot number and jumps
-// to TP Stub
-//
-//+----------------------------------------------------------------------------
-PCODE CTPMethodTable::CreateThunkForVirtualMethod(DWORD dwSlot, BYTE *startaddr)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(startaddr));
- }
- CONTRACTL_END;
-
- BYTE *pCode = startaddr;
-
- // 0000 B8 67 45 23 01 MOV EAX, dwSlot
- // 0005 E9 ?? ?? ?? ?? JMP TransparentProxyStub
- *pCode++ = 0xB8;
- *((DWORD *) pCode) = dwSlot;
- pCode += sizeof(DWORD);
- *pCode++ = 0xE9;
- // self-relative call, based on the start of the next instruction.
- *((LONG *) pCode) = (LONG)((size_t)GetTPStubEntryPoint() - (size_t) (pCode + sizeof(LONG)));
-
- _ASSERTE(CVirtualThunkMgr::IsThunkByASM((PCODE)startaddr));
-
- return (PCODE)startaddr;
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::ActivatePrecodeRemotingThunk private
-//
-// Synopsis: Patch the precode remoting thunk to begin interception
-//
-//+----------------------------------------------------------------------------
-void CTPMethodTable::ActivatePrecodeRemotingThunk()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // Before activation:
- // 0000 C3 ret
- // 0001 90 nop
-
- // After activation:
- // 0000 85 C9 test ecx,ecx
-
- // 0002 74 XX je RemotingDone
- // 0004 81 39 XX XX XX XX cmp dword ptr [ecx],11111111h
- // 000A 74 XX je RemotingCheck
-
- // Switch offset and size of patch based on the jump opcode used.
- BYTE* pCode = (BYTE*)PrecodeRemotingThunk;
-
- SIZE_T mtOffset = 0x0006;
- SIZE_T size = 0x000A;
-
- // Patch "ret + nop" to "test ecx,ecx"
- *(UINT16 *)pCode = 0xC985;
-
- // Replace placeholder value with the actual address of TP method table
- _ASSERTE(*(PVOID*)(pCode+mtOffset) == (PVOID*)0x11111111);
- *(PVOID*)(pCode+mtOffset) = GetMethodTable();
-
- FlushInstructionCache(GetCurrentProcess(), pCode, size);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::DoTraceStub public
-//
-// Synopsis: Traces the stub given the starting address
-//
-//+----------------------------------------------------------------------------
-BOOL CVirtualThunkMgr::DoTraceStub(PCODE stubStartAddress, TraceDestination *trace)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(stubStartAddress != NULL);
- PRECONDITION(CheckPointer(trace));
- }
- CONTRACTL_END;
-
- BOOL bIsStub = FALSE;
-
- // Find a thunk whose code address matching the starting address
- LPBYTE pThunk = FindThunk((LPBYTE)stubStartAddress);
- if(NULL != pThunk)
- {
- LPBYTE pbAddr = NULL;
- LONG destAddress = 0;
- if((LPBYTE)stubStartAddress == pThunk)
- {
-
- // Extract the long which gives the self relative address
- // of the destination
- pbAddr = pThunk + sizeof(BYTE) + sizeof(DWORD) + sizeof(BYTE);
- destAddress = *(LONG *)pbAddr;
-
- // Calculate the absolute address by adding the offset of the next
- // instruction after the call instruction
- destAddress += (LONG)(size_t)(pbAddr + sizeof(LONG));
-
- }
-
- // We cannot tell where the stub will end up until OnCall is reached.
- // So we tell the debugger to run till OnCall is reached and then
- // come back and ask us again for the actual destination address of
- // the call
-
- Stub *stub = Stub::RecoverStub((TADDR)destAddress);
-
- trace->InitForFramePush(stub->GetPatchAddress());
- bIsStub = TRUE;
- }
-
- return bIsStub;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::IsThunkByASM public
-//
-// Synopsis: Check assembly to see if this one of our thunks
-//
-//+----------------------------------------------------------------------------
-BOOL CVirtualThunkMgr::IsThunkByASM(PCODE startaddr)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(startaddr != NULL);
- }
- CONTRACTL_END;
-
- PTR_BYTE pbCode = PTR_BYTE(startaddr);
-
- return ((pbCode[0] == 0xB8) &&
- (pbCode[5] == 0xe9) &&
- (rel32Decode((TADDR)(pbCode + 6)) == CTPMethodTable::GetTPStubEntryPoint()));
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::GetMethodDescByASM public
-//
-// Synopsis: Parses MethodDesc out of assembly code
-//
-//+----------------------------------------------------------------------------
-MethodDesc *CVirtualThunkMgr::GetMethodDescByASM(PCODE startaddr, MethodTable *pMT)
-{
- CONTRACT (MethodDesc*)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(startaddr != NULL);
- PRECONDITION(CheckPointer(pMT));
- POSTCONDITION(CheckPointer(RETVAL));
- }
- CONTRACT_END;
-
- RETURN (pMT->GetMethodDescForSlot(*((DWORD *) (startaddr + 1))));
-}
-
-#endif// FEATURE_REMOTING
-
diff --git a/src/vm/mda.cpp b/src/vm/mda.cpp
deleted file mode 100644
index 77c26a993e..0000000000
--- a/src/vm/mda.cpp
+++ /dev/null
@@ -1,4017 +0,0 @@
-// 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.
-
-
-#include "common.h"
-#include "eeconfig.h"
-#include "eeconfigfactory.h"
-#include "corhlpr.h"
-#include <xmlparser.h>
-#include <mscorcfg.h>
-#include <holder.h>
-#include <dbginterface.h>
-#include "wrappers.h"
-#include "mda.h"
-#include "mdaassistants.h"
-#include "sstring.h"
-#include "util.hpp"
-#include "debugdebugger.h"
-
-#ifdef MDA_SUPPORTED
-
-//
-// MdaHashtable
-//
-
-BOOL MdaLockOwner(LPVOID) { LIMITED_METHOD_CONTRACT; return TRUE; }
-
-BOOL IsJustMyCode(MethodDesc* pMethodDesc)
-{
- CONTRACT(BOOL)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACT_END;
-
- if (!ManagedDebuggingAssistants::IsManagedDebuggerAttached())
- return TRUE;
-
- BOOL bIsJMC = FALSE;
-
- EX_TRY
- {
- if (g_pDebugInterface && g_pDebugInterface->IsJMCMethod(pMethodDesc->GetModule(), pMethodDesc->GetMemberDef()))
- bIsJMC = TRUE;
- }
- EX_CATCH
- {
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- RETURN bIsJMC;
-}
-
-
-//
-// ManagedDebuggingAssistants
-//
-
-const bool g_mdaAssistantIsSwitch[] =
-{
-#define MDA_ASSISTANT_IS_SWITCH
-#include "mdaschema.inl"
-#undef MDA_ASSISTANT_IS_SWITCH
- false
-};
-
-void ManagedDebuggingAssistants::Initialize()
-{
- CONTRACT_VOID
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACT_END;
-
- EX_TRY
- {
- //
- // Initialize
- //
- m_pSwitchActivationXml = NULL;
- m_pMdaXmlIndustry = new MdaXmlIndustry();
-
- MdaSchema::Initialize();
-
- //
- // Create AssistantSchema
- //
- m_pAssistantSchema = new MdaAssistantSchema();
-
- //
- // Create AssistantMsgSchema
- //
- m_pAssistantMsgSchema = new MdaAssistantMsgSchema();
-
- //
- // Create SchemaSchema
- //
- m_pSchemaSchema = new MdaSchemaSchema();
-
- //
- // InvalidConfigFile
- //
- g_mdaStaticHeap.m_mdaInvalidConfigFile.Enable();
-
-#ifdef _DEBUG
- StackSString sszValidateFramework(CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MDAValidateFramework));
- if (!sszValidateFramework.IsEmpty() && sszValidateFramework.Equals(W("1")))
- DebugInitialize();
-#endif
- }
- EX_CATCH
- {
- // MDA State corrupted, unable to initialize, runtime still OK
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- RETURN;
-}
-
-MdaEnvironment::~MdaEnvironment()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (m_pStringFactory)
- delete m_pStringFactory;
-
- if (m_pGroups)
- delete m_pGroups;
-
- if (m_szMda)
- delete m_szMda;
-}
-
-MdaEnvironment::MdaEnvironment()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_bDisable = TRUE;
- m_szMda = CLRConfig::GetConfigValue(CLRConfig::EXTERNAL_MDA);
- m_pStringFactory = NULL;
- m_pGroups = NULL;
-
- if (ManagedDebuggingAssistants::IsManagedDebuggerAttached())
- {
- if (m_pStringFactory == NULL)
- m_pStringFactory = new MdaFactory<StackSString>();
-
- if (m_pGroups == NULL)
- m_pGroups = new SArray<SString*>();
-
- SString* pStr = m_pStringFactory->Create();
- pStr->Set(W("managedDebugger"));
- m_pGroups->Append(pStr);
- m_bDisable = FALSE;
- }
-
- if (ManagedDebuggingAssistants::IsUnmanagedDebuggerAttached())
- {
- if (m_pStringFactory == NULL)
- m_pStringFactory = new MdaFactory<StackSString>();
-
- if (m_pGroups == NULL)
- m_pGroups = new SArray<SString*>();
-
- SString* pStr = m_pStringFactory->Create();
- pStr->Set(W("unmanagedDebugger"));
- m_pGroups->Append(pStr);
- m_bDisable = FALSE;
- }
-
- if (m_szMda)
- {
- if (m_pStringFactory == NULL)
- m_pStringFactory = new MdaFactory<StackSString>();
-
- if (m_pGroups == NULL)
- m_pGroups = new SArray<SString*>();
-
- StackSString sszMda(m_szMda);
- SString::Iterator s = sszMda.Begin();
- SString::Iterator e = s;
-
- while (true)
- {
- if (!sszMda.Find(e, W(';')))
- e = sszMda.End();
- SString* psszGroup = m_pStringFactory->Create();
- psszGroup->Set(sszMda, s, e);
-
- if (psszGroup->Equals(W("0")))
- {
- m_pGroups->Clear();
- m_bDisable = TRUE;
- }
- else
- {
- m_pGroups->Append(psszGroup);
-
- m_bDisable = FALSE;
- }
-
- if (e == sszMda.End())
- break;
- s = ++e;
- }
- }
-
- if (m_bDisable == FALSE)
- {
- // If we get here, m_pStringFactory should already have been created.
- _ASSERTE(m_pStringFactory != NULL);
-
- WCHAR szExe[_MAX_PATH];
- if (!WszGetModuleFileName(NULL, szExe, _MAX_PATH))
- return;
-
- // Construct file name of the config file
- m_psszConfigFile = m_pStringFactory->Create();
- m_psszConfigFile->Set(szExe);
- m_psszConfigFile->Append(W(".config"));
-
- // Construct file name of mda config file
- m_psszMdaConfigFile = m_pStringFactory->Create();
- m_psszMdaConfigFile->Set(szExe);
- m_psszMdaConfigFile->Append(W(".mda.config"));
- }
-}
-
-void ManagedDebuggingAssistants::EEStartupActivation()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- //
- // Read environment variable, then registry settings
- //
- MdaEnvironment env;
-
- if (env.IsDisabled())
- return;
-
- AllocateManagedDebuggingAssistants();
-
- //
- // ConfigFile Activation
- //
- g_mdaStaticHeap.m_pMda->EnvironmentActivation(&env);
-}
-
-#ifdef _DEBUG
-void ManagedDebuggingAssistants::DebugInitialize()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- SO_INTOLERANT;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- //
- // Validate MDA output on Debug builds
- //
- m_bValidateOutput = TRUE;
-
- //
- // XmlValidationError
- //
- g_mdaStaticHeap.m_mdaXmlValidationError.Enable();
-
- MdaSchema::ValidationResult validationResult;
-
- //
- // Validate SchemaScheam
- //
- MdaXmlElement* pXmlSchemaSchema = m_pSchemaSchema->ToXml(m_pMdaXmlIndustry);
- if (m_pSchemaSchema->Validate(pXmlSchemaSchema, &validationResult)->ValidationFailed())
- {
- MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult));
- UNREACHABLE();
- }
-
- //
- // Validate AssistantSchema
- //
- MdaXmlElement* pXmlAssistantSchema = m_pAssistantSchema->ToXml(m_pMdaXmlIndustry);
- if (m_pSchemaSchema->Validate(pXmlAssistantSchema, &validationResult)->ValidationFailed())
- {
- MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult));
- ASSERT(!W("You're modifications to MdaAssistantSchema for assistant input don't conform to XSD"));
- }
-
- //
- // Validate AssistantMsgSchema
- //
- MdaXmlElement* pXmlAssistantMsgSchema = m_pAssistantMsgSchema->ToXml(m_pMdaXmlIndustry);
- if (m_pSchemaSchema->Validate(pXmlAssistantMsgSchema, &validationResult)->ValidationFailed())
- {
- MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult));
- ASSERT(!W("You're modifications to MdaAssistantSchema for assistant output don't conform to XSD"));
- }
-}
-#endif
-
-void ManagedDebuggingAssistants::ConfigFileActivation(LPCWSTR szConfigFile, MdaXmlIndustry* pXmlIndustry, MdaHashtable<MdaXmlElement*>* pMdaXmlPairs)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // Parse
- MdaSchema::ValidationResult validationResult;
- MdaXmlElement* pMdaConfig = MdaConfigFactory::ParseXmlStream(pXmlIndustry, szConfigFile);
- if (!pMdaConfig)
- return;
-
- // Validate
- if (m_pAssistantSchema->Validate(pMdaConfig, &validationResult)->ValidationFailed())
- {
- MDA_TRIGGER_ASSISTANT(InvalidConfigFile, ReportError(MdaElemDef(MdaConfig)));
- g_mdaStaticHeap.DisableAll();
- return;
- }
-
- // Activate
- InlineSArray<MdaXmlElement*, MdaElemDef(Max)> xmlMdaConfigs;
- MdaXPath::FindElements(pMdaConfig, W("/mdaConfig/assistants/*"), &xmlMdaConfigs);
- for(COUNT_T i = 0; i < xmlMdaConfigs.GetCount(); i ++)
- {
- MdaXmlElement* pXmlMdaConfig = xmlMdaConfigs[i];
- if (pXmlMdaConfig->GetAttribute(MdaAttrDecl(Enable))->GetValueAsBool())
- {
- pMdaXmlPairs->Set(pXmlMdaConfig->GetName(), xmlMdaConfigs[i]);
- }
- else
- {
- if (pMdaXmlPairs->HasKey(pXmlMdaConfig->GetName()))
- pMdaXmlPairs->DeleteValue(pXmlMdaConfig->GetName());
- }
- }
-}
-
-MdaXmlElement* ManagedDebuggingAssistants::GetSwitchActivationXml(MdaElemDeclDef mda)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (g_mdaAssistantIsSwitch[mda])
- {
- MdaXmlElement* pXml = m_pMdaXmlIndustry->CreateElement()->SetDeclDef(mda);
- pXml->AddAttributeBool(MdaAttrDecl(Enable), TRUE);
- return pXml;
- }
- else
- {
- if (!m_pSwitchActivationXml)
- {
- MdaXmlElement* pXmlMdaConfig = m_pMdaXmlIndustry->CreateElement()->SetDeclDef(MdaElemDef(MdaConfig));
- m_pSwitchActivationXml = pXmlMdaConfig->AddChild(MdaElemDecl(Assistants));
-
- for (COUNT_T i = 0; i < MdaElemDef(AssistantMax); i ++)
- m_pSwitchActivationXml->AddChild((MdaElemDeclDef)i);
-
- MdaSchema::ValidationResult validationResult;
-
- // Validating the schema has the side-effect of initializing the default XML attributes
- if (m_pAssistantSchema->Validate(pXmlMdaConfig, &validationResult)->ValidationFailed())
- ASSERT(!W("MDA Assistant must allow <Assistant /> form."));
- }
-
- return m_pSwitchActivationXml->GetChild(mda);
- }
-}
-
-void ManagedDebuggingAssistants::ActivateGroup(LPCWSTR groupName, SArray<MdaElemDeclDef>* pGroupMdaXmlParis, MdaHashtable<MdaXmlElement*>* pActivationMdaXmlPairs)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszGroupName(groupName);
- BOOL bIsManagedDebuggerSet = sszGroupName.EqualsCaseInsensitive(W("managedDebugger"));
-
- SArray<MdaElemDeclDef>& groupMdaXmlParis = *pGroupMdaXmlParis;
-
- for (COUNT_T i = 0; i < groupMdaXmlParis.GetCount(); i++)
- {
- MdaElemDeclDef mda = groupMdaXmlParis[i];
- MdaXmlElement* pSwitchActivationXml = GetSwitchActivationXml(mda);
-
- PREFIX_ASSUME(pSwitchActivationXml != NULL);
-
- pSwitchActivationXml->AddAttributeBool(MdaAttrDecl(SuppressDialog), bIsManagedDebuggerSet);
-
- pActivationMdaXmlPairs->Set(MdaSchema::g_arElementNames[mda], pSwitchActivationXml);
- }
-}
-
-LPCWSTR ToLowerFirstChar(LPCWSTR name, MdaFactory<SString>* pSstringFactory)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- ASSERT(*name >= 'A' && *name <= 'Z');
-
- SString* pOutput = pSstringFactory->Create();
- pOutput->Clear();
- pOutput->Append(*name - W('A') + W('a'));
- pOutput->Append(&name[1]);
- return pOutput->GetUnicode();
-}
-
-void ManagedDebuggingAssistants::EnvironmentActivation(MdaEnvironment* pEnvironment)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (pEnvironment->GetActivationMechanisms().GetCount() == 0)
- return;
-
- MdaFactory<StackSArray<MdaElemDeclDef> > arrayFactory;
- MdaFactory<SString> sstringFactory;
- MdaHashtable<MdaXmlElement*> mdaXmlPairs;
-
- // Activate
- SArray<SString*>& aActivationMechanisms = pEnvironment->GetActivationMechanisms();
- SArray<MdaElemDeclDef>* pGroup = NULL;
- StackSArray<SArray<MdaElemDeclDef>* > aGroups;
-
-#define MDA_DEFINE_GROUPS
-#include "mdaschema.inl"
-#undef MDA_DEFINE_GROUPS
-
- // Match COMPlus_MDA env var to group
- for (COUNT_T i = 0; i < aActivationMechanisms.GetCount(); i++)
- {
- SString& sszActivationMechanism = *aActivationMechanisms[i];
-
- if (sszActivationMechanism.EqualsCaseInsensitive(W("ConfigFile")) || sszActivationMechanism.EqualsCaseInsensitive(W("1")))
- {
- ConfigFileActivation(pEnvironment->GetMdaConfigFile(), m_pMdaXmlIndustry, &mdaXmlPairs);
- }
- else
- {
- COUNT_T cGroup = 0;
-
-#define MDA_ACTIVATE_GROUPS
-#include "mdaschema.inl"
-#undef MDA_ACTIVATE_GROUPS
-
-#define MDA_ACTIVATE_SINGLTON_GROUPS
-#include "mdaschema.inl"
-#undef MDA_ACTIVATE_SINGLTON_GROUPS
-
- }
- }
-
- if (mdaXmlPairs.GetCount() == 0)
- return;
-
- // Create
- MdaXmlElement* pXmlAssistant = NULL;
-
-#define MDA_ASSISTANT_CREATION
-#include "mdaschema.inl"
-#undef MDA_ASSISTANT_CREATION
-}
-
-typedef enum
-{
- MDA_MSGBOX_NONE = 0,
- MDA_MSGBOX_RETRY = 4,
- MDA_MSGBOX_CANCLE = 2,
-} MsgBoxResult;
-
-BOOL ManagedDebuggingAssistants::IsUnmanagedDebuggerAttached()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (IsDebuggerPresent())
- return TRUE;
-
- return FALSE;
-}
-
-BOOL ManagedDebuggingAssistants::IsManagedDebuggerAttached()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-#if DEBUGGING_SUPPORTED
- if (CORDebuggerAttached())
- return TRUE;
-#endif
-
- return FALSE;
-}
-
-BOOL ManagedDebuggingAssistants::IsDebuggerAttached()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return IsUnmanagedDebuggerAttached() || IsManagedDebuggerAttached();
-}
-
-MdaXmlElement* ManagedDebuggingAssistants::GetRootElement(MdaXmlElement* pMdaXmlRoot)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- pMdaXmlRoot->SetDeclDef(MdaElemDef(Msg));
- pMdaXmlRoot->AddAttributeSz(MdaAttrDecl(Xmlns), MDA_TARGET_NAMESPACE)->SetNs(W("mda"));
- return pMdaXmlRoot;
-}
-
-
-
-//
-// MdaXmlMessage
-//
-BOOL IsFormatChar(WCHAR c) { LIMITED_METHOD_CONTRACT; return (c == W('\\') || c == W('!') || c == W('+') || c == W('.') || c == W(':') || c == W('-')); }
-
-// Logic copied from /fx/src/Xml/System/Xml/Core/XmlRawTextWriterGenerator.cxx::WriteAttributeTextBlock
-SString& MdaXmlEscape(SString& sszBuffer, const SString& sszXml, BOOL bEscapeComment = FALSE)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- sszBuffer.Clear();
-
- SString::CIterator itr = sszXml.Begin();
- SString::CIterator end = sszXml.End();
-
- while (itr != end)
- {
- WCHAR c = *itr;
-
- switch(c)
- {
- case W('-'):
- if (*(itr+1) == W('-') && bEscapeComment)
- sszBuffer.Append(W("- "));
- else
- sszBuffer.Append(W("-"));
- break;
- case W('&'):
- sszBuffer.Append(W("&amp;"));
- break;
- case W('<'):
- sszBuffer.Append(W("&lt;"));
- break;
- case W('>'):
- sszBuffer.Append(W("&gt;"));
- break;
- case W('"'):
- sszBuffer.Append(W("&quote;"));
- break;
- default:
- sszBuffer.Append(c);
- }
-
- itr++;
- }
-
- return sszBuffer;
-}
-
-SString* WrapString(SString& buffer, SString& sszString, SCOUNT_T cWidth, SCOUNT_T cIndent = 0, SCOUNT_T cPostIndent = 0)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszEscapedString;
- MdaXmlEscape(sszEscapedString, sszString, TRUE);
-
- StackSString sszIndent;
- for (SCOUNT_T i = 0; i < cIndent; i ++)
- sszIndent.Append(W(" "));
-
- StackSString sszPostIndent;
- for (SCOUNT_T i = 0; i < cPostIndent; i ++)
- sszPostIndent.Append(W(" "));
-
- buffer.Append(sszIndent);
-
- SString::CIterator itr = sszEscapedString.Begin();
- SString::CIterator lineStart = sszEscapedString.Begin();
- SString::CIterator lineEnd = sszEscapedString.Begin();
- SString::CIterator lastFormatChar = sszEscapedString.Begin();
- SString::CIterator end = sszEscapedString.End();
-
- while (itr != end)
- {
- if (*itr == W(' '))
- lineEnd = itr;
-
- // Keep track of reasonable breaks in member and file names...
- if (IsFormatChar(*itr) && itr - lineStart < cWidth)
- lastFormatChar = itr;
-
- if (itr - lineStart >= cWidth || *itr == W('\n'))
- {
- if (*itr == W('\n'))
- lineEnd = itr;
-
- // If we didn't find a space or wrapping at found space wraps less than 3/5 of the line...
- else if (lineEnd == end || itr - lineEnd > cWidth * 3 / 5)
- {
- // ...then if we found a format char, start the wrap there...
- if (lastFormatChar != end)
- lineEnd = lastFormatChar + 1;
- // ...else just do a simple wrap...
- else
- lineEnd = itr;
- }
-
- SString sszLine(sszEscapedString, lineStart, lineEnd);
- buffer.Append(sszLine);
- buffer.Append(sszPostIndent);
- buffer.Append(W("\n"));
- buffer.Append(sszIndent);
-
- lineStart = lineEnd;
-
- // If we wrapped on a space or a return than skip over that character as we already replaced it with a \n.
- if (*lineEnd == W(' ') || *lineEnd == W('\n'))
- lineStart++;
-
- lineEnd = end;
- lastFormatChar = end;
- }
-
- itr++;
- }
-
- SString sszLine(sszEscapedString, lineStart, itr);
- buffer.Append(sszLine);
-
- return &buffer;
-}
-
-LPCWSTR ToUpperFirstChar(SString& buffer, LPCWSTR name)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- ASSERT(*name >= 'a' && *name <= 'z');
-
- buffer.Clear();
- buffer.Append(*name - W('a') + W('A'));
- buffer.Append(&name[1]);
- return buffer.GetUnicode();
-}
-
-MdaXmlMessage::MdaXmlMessage(MdaAssistant* pAssistant, BOOL bBreak, MdaXmlElement** ppMdaXmlRoot)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda));
- }
- CONTRACTL_END;
-
- m_pMdaAssistant = pAssistant;
- m_bBreak = (pAssistant->GetSuppressDialog()) ? FALSE : bBreak;
- m_pMdaXmlRoot = g_mdaStaticHeap.m_pMda->GetRootElement(m_mdaXmlIndustry.CreateElement());
- *ppMdaXmlRoot = m_pAssistantXmlRoot = pAssistant->GetRootElement(m_mdaXmlIndustry.CreateElement(), bBreak);
-}
-
-MdaXmlMessage::MdaXmlMessage(MdaXmlElement** ppMdaXmlRoot) : m_bBreak(FALSE)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda));
- }
- CONTRACTL_END;
-
- *ppMdaXmlRoot = m_pMdaXmlRoot = g_mdaStaticHeap.m_pMda->GetRootElement(m_mdaXmlIndustry.CreateElement());
-}
-
-BOOL MdaXmlMessage::ShouldLogToManagedDebugger()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- BOOL bUnmanagedDebuggerAttached = FALSE;
- BOOL bManagedDebuggerAttached = FALSE;
- BOOL bManagedDebugLoggingEnabled = FALSE;
-
- bUnmanagedDebuggerAttached = IsUnmanagedDebuggerAttached();
-
-#if DEBUGGING_SUPPORTED
- bManagedDebuggerAttached = IsManagedDebuggerAttached();
- bManagedDebugLoggingEnabled = (g_pDebugInterface && g_pDebugInterface->IsLoggingEnabled());
-#endif
-
- return (!bUnmanagedDebuggerAttached && bManagedDebuggerAttached && bManagedDebugLoggingEnabled);
-}
-
-// Send an event for this MDA.
-void MdaXmlMessage::SendEvent()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (IsHostRegisteredForEvent(Event_MDAFired))
- {
- // A host is registered for the MDA fired event so let's start by notifying the
- // debugger is on is attached.
- if (IsManagedDebuggerAttached() || IsUnmanagedDebuggerAttached())
- {
- SendDebugEvent();
- }
-
- // Now that the debugger has been notified and continued, let's notify the host
- // so it can take any action it deems neccessary based on the MDA that fired.
- SendHostEvent();
- }
- else
- {
- // We aren't hosted or no host registered for the MDA fired event so let's simply
- // send the MDA to the debubber. Note that as opposed to the hosted case, we
- // will force a JIT attach if no debugger is present.
- SendDebugEvent();
- }
-}
-
-// Send an event for this MDA.
-void MdaXmlMessage::SendHostEvent()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MDAInfo info;
- SString strStackTrace;
-
- EX_TRY
- {
- // Retrieve the textual representation of the managed stack trace and add it to
- // the MDA information we give the host.
- GetManagedStackTraceString(TRUE, strStackTrace);
- }
- EX_CATCH
- {
- // We failed to get the stack trace string. This isn't fatal, we will simply not be
- // able to provide this information as part of the notification.
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- // Set up the information and invoke the host to process the MDA fired event.
- info.lpMDACaption = m_pMdaAssistant->GetName();
- info.lpStackTrace = strStackTrace;
- info.lpMDAMessage = m_localizedMessage;
- ProcessEventForHost(Event_MDAFired, &info);
-
- // If the host initiated a thread abort, we want to raise it immediatly to
- // prevent any further code inside the VM from running and potentially
- // crashing the process.
- Thread *pThread = GetThread();
- TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE));
-
- if (pThread && pThread->IsAbortInitiated())
- pThread->HandleThreadAbort(TRUE);
-}
-
-// Send a managed debug event for this MDA.
-// This will block until the debugger continues us. This means the debugger could to things like run callstacks
-// and change debuggee state.
-void MdaXmlMessage::SendDebugEvent()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda));
- }
- CONTRACTL_END;
-
- // Simple check to avoid getting XML string if we're not going to actually use it.
- if (!IsManagedDebuggerAttached() && !IsUnmanagedDebuggerAttached() && !m_bBreak)
- {
- return;
- }
-
- EX_TRY
- {
- StackSString sszXml;
- LPCWSTR ns = NULL;
-
- MdaSchema * pSchema = g_mdaStaticHeap.m_pMda->m_pAssistantSchema;
- ns = pSchema->SetRootAttributes(m_pMdaXmlRoot);
- m_pMdaXmlRoot->ToXml(&sszXml, ns);
-
- // For managed + interop cases, send a managed debug event.
- // If m_bBreak is true and no unmanaged debugger is attached trigger a jit-attach.
- if (IsManagedDebuggerAttached() || (m_bBreak && !IsUnmanagedDebuggerAttached()))
- {
- // Get MDA name (this is the type)
- StackSString sszMdaName;
- ToUpperFirstChar(sszMdaName, m_pMdaAssistant->GetName());
- // SendMDANotification needs to be called in preemptive GC mode.
- GCX_PREEMP();
-
- // This will do two things:
- // 1. If a managed debugger is attached, it will send the managed debug event for the MDA.
- // 2. If it's a m_bBreak, we'll try to do a managed jit-attach.
- // This blocks until continued. Since we're not slipping, we don't need the MDA_FLAG_SLIP flag.
- g_pDebugInterface->SendMDANotification(
- GetThread(),
- &sszMdaName,
- &m_localizedMessage,
- &sszXml,
- ((CorDebugMDAFlags) 0 ),
- RunningInteractive() ? m_bBreak : FALSE);
- }
-
- if (IsUnmanagedDebuggerAttached() && !IsManagedDebuggerAttached())
- {
- // For native case, sent native debug event for logging.
- WszOutputDebugString(sszXml.GetUnicode());
-
- if (m_bBreak)
- RetailBreak();
- }
- }
- EX_CATCH
- {
- // No global MDA state modified in TRY
- }
- EX_END_CATCH(SwallowAllExceptions);
-}
-
-void MdaXmlMessage::SendMessagef(int resourceID, ...)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszResourcef;
- sszResourcef.LoadResource(CCompRC::DesktopCLR, resourceID );
- ASSERT(!sszResourcef.IsEmpty());
-
- va_list argItr;
- va_start(argItr, resourceID);
- m_localizedMessage.PVPrintf(sszResourcef, argItr);
- va_end(argItr);
-
- SendMessage();
-}
-
-
-void MdaXmlMessage::SendMessage(int resourceID)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SendMessagef(resourceID);
-}
-
-void MdaXmlMessage::SendMessage(LPCWSTR szMessage)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_localizedMessage.Set(szMessage);
-
- SendMessage();
-}
-
-void MdaXmlMessage::SendMessage()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(g_mdaStaticHeap.m_pMda));
- }
- CONTRACTL_END;
-
-#if _DEBUG
- if (g_mdaStaticHeap.m_pMda->m_bValidateOutput)
- {
- MdaSchema::ValidationResult validationResult;
- if (g_mdaStaticHeap.m_pMda->m_pAssistantMsgSchema->Validate(m_pAssistantXmlRoot, &validationResult)->ValidationFailed())
- {
- MDA_TRIGGER_ASSISTANT(XmlValidationError, ReportError(&validationResult));
- ASSERT(W("Your MDA assistant's output did not match its output schema."));
- }
- }
-#endif
-
- if (!m_localizedMessage.IsEmpty())
- {
- StackSString sszComment(m_localizedMessage);
- StackSString sszWrappedComment(W("\n"));
- WrapString(sszWrappedComment, sszComment, 80, 7);
- sszWrappedComment.Append(W("\n "));
- m_pMdaXmlRoot->AddChildComment(sszWrappedComment.GetUnicode());
- }
-
- m_pMdaXmlRoot->AddChild(m_pAssistantXmlRoot);
-
- // Send applicable debug event (managed, native, interop) for this MDA.
- // If this is a severe probe, it may trigger a jit-attach
- SendEvent();
-}
-
-
-//
-// MdaXPath::FindXXX
-//
-
-void MdaXPath::Find(SArray<MdaXPathVariable>& args, SString* pWildCard, va_list argItr)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for (COUNT_T i = 0; i < GetArgCount(); i ++)
- {
- XPathVarType varType = m_argTypes[i];
-
- if (varType == XPathVarElemDeclDef)
- args[i].m_u.m_elemDeclDef = va_arg(argItr, MdaElemDeclDef);
-
- else if (varType == XPathVarAttrDeclDef)
- args[i].m_u.m_attrDeclDef = va_arg(argItr, MdaAttrDeclDef);
-
- else if (varType == XPathVarAttrBool)
- args[i].m_u.m_bool = va_arg(argItr, BOOL);
-
- else if (varType == XPathVarAttrINT32)
- args[i].m_u.m_int32 = va_arg(argItr, INT32);
-
- else if (varType == XPathVarAttrSString)
- {
- SString* pSString = va_arg(argItr, SString*);
- ASSERT(CheckPointer(pSString, NULL_OK));
- if (!pSString)
- pSString = pWildCard;
- args[i].m_u.m_pSstr = pSString;
- }
-
- else { UNREACHABLE(); }
- }
-}
-
-MdaXmlElement* MdaXPath::FindElement(MdaXmlElement* pRoot, ...)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!pRoot)
- return NULL;
-
- va_list argItr;
- va_start(argItr, pRoot);
-
- SString wildCard;
- InlineSArray<MdaXPathVariable, 20> args;
- Find(args, &wildCard, argItr);
-
- MdaXPathResult result(&args);
- m_pCompiledQuery->Run(pRoot, &result);
-
- va_end(argItr);
- return result.GetXmlElement();
-}
-
-MdaXmlAttribute* MdaXPath::FindAttribute(MdaXmlElement* pRoot, ...)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!pRoot)
- return NULL;
-
- va_list argItr;
- va_start(argItr, pRoot);
-
- SString wildCard;
- InlineSArray<MdaXPathVariable, 20> args;
- Find(args, &wildCard, argItr);
-
- MdaXPathResult result(&args);
- m_pCompiledQuery->Run(pRoot, &result);
-
- va_end(argItr);
- return result.GetXmlAttribute();
-}
-
-SArray<MdaXmlElement*>* MdaXPath::FindElements(MdaXmlElement* pRoot, SArray<MdaXmlElement*>* pResult, ...)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!pRoot)
- return NULL;
-
- va_list argItr;
- va_start(argItr, pResult);
-
- SString wildCard;
- InlineSArray<MdaXPathVariable, 20> args;
- Find(args, &wildCard, argItr);
-
- MdaXPathResult result(pResult, &args);
- m_pCompiledQuery->Run(pRoot, &result);
-
- va_end(argItr);
- return pResult;
-}
-
-SArray<MdaXmlAttribute*>* MdaXPath::FindAttributes(MdaXmlElement* pRoot, SArray<MdaXmlAttribute*>* pResult, ...)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!pRoot)
- return NULL;
-
- va_list argItr;
- va_start(argItr, pResult);
-
- SString wildCard;
- InlineSArray<MdaXPathVariable, 20> args;
- Find(args, &wildCard, argItr);
-
- MdaXPathResult result(pResult, &args);
- m_pCompiledQuery->Run(pRoot, &result);
-
- va_end(argItr);
- return pResult;
-}
-
-
-//
-// MdaXPath::MdaXPathCompiler -- Lexifier
-//
-
-#define ISWHITE(ch) (ch == W(' ') || ch == W('\t') || ch == W('\n'))
-#define ISRESERVED(ch) (wcschr(W("./()[]&|=@*?':"), ch) != NULL)
-#define ISMDAID(ch) (!ISWHITE(ch) && !ISRESERVED(ch))
-
-MdaXPath::MdaXPathCompiler::MdaXPathTokens MdaXPath::MdaXPathCompiler::LexAToken()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (*m_itr == W('\0'))
- return MdaXPathEnd;
-
- if (ISWHITE(*m_itr))
- {
- m_itr++;
- return LexAToken();
- }
-
- if (ISMDAID(*m_itr))
- {
- m_identifier.Clear();
-
- do
- {
- m_identifier.Append(*m_itr);
- m_itr++;
- }
- while(ISMDAID(*m_itr));
-
- m_identifier.Append(W("\0"));
- return MdaXPathIdentifier;
- }
-
- if (*m_itr == W('\''))
- {
- m_identifier.Clear();
-
- m_itr++;
-
- while(*m_itr != W('\''))
- {
- m_identifier.Append(*m_itr);
- m_itr++;
- }
-
- m_identifier.Append(W("\0"));
-
- m_itr++;
- return MdaXPathQuotedString;
- }
-
- WCHAR c = *m_itr;
- m_itr++;
- switch(c)
- {
- case W('.'): return MdaXPathDot;
- case W('/'): return MdaXPathSlash;
- case W('('): return MdaXPathOpenParen;
- case W(')'): return MdaXPathCloseParen;
- case W('['): return MdaXPathOpenSqBracket;
- case W(']'): return MdaXPathCloseSqBracket;
- case W('&'): return MdaXPathLogicalAnd;
- case W('|'): return MdaXPathLogicalOr;
- case W('='): return MdaXPathEquals;
- case W('@'): return MdaXPathAtSign;
- case W('*'): return MdaXPathAstrix;
- case W('?'): return MdaXPathQMark;
- }
-
- UNREACHABLE();
-}
-
-
-//
-// MdaXPath::MdaXPathCompiler -- Parser
-//
-
-// XPATH
-// '/' ELEMENT_EXPR end
-// '/' ELEMENT_EXPR XPATH
-// '/' ATTRIBUTE end
-MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::XPATH()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathXPATH));
-
- MdaXPathElement* pElementExpr = NULL;
-
- NextToken();
- if (TokenIs(MdaXPathELEMENT_EXPR))
- pElementExpr = ELEMENT_EXPR();
-
- else if (TokenIs(MdaXPathATTRIBUTE))
- {
- MdaXPathAttribute* pAttr = ATTRIBUTE();
- pAttr->MarkAsTarget();
- NextToken();
- ASSERT(TokenIs(MdaXPathEnd));
- return pAttr;
- }
-
- else { UNREACHABLE(); }
-
-
- if (TokenIs(MdaXPathEnd))
- return pElementExpr->MarkAsTarget();
-
- else if (TokenIs(MdaXPathXPATH))
- return pElementExpr->SetChild(XPATH());
-
- else { UNREACHABLE(); }
-}
-
-// ATTRIBUTE
-// '@' id
-// '@' '?'
-MdaXPath::MdaXPathAttribute* MdaXPath::MdaXPathCompiler::ATTRIBUTE()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathATTRIBUTE));
-
- MdaXPathAttribute* pAttr = NULL;
-
- NextToken();
- if (TokenIs(MdaXPathQMark))
- {
- pAttr = m_pXPath->m_attrFactory.Create()->SetName(++m_pXPath->m_cArgs);
- *m_pXPath->m_argTypes.Append() = XPathVarAttrDeclDef;
- }
-
- else if (TokenIs(MdaXPathIdentifier))
- {
- pAttr = m_pXPath->m_attrFactory.Create()->SetName(MdaSchema::GetAttributeType(GetIdentifier()));
- }
-
- else { UNREACHABLE(); }
-
- NextToken();
- return pAttr;
-}
-
-// ELEMENT_EXPR
-// ELEMENT '[' FILTER_EXPR ']'
-// ELEMENT
-MdaXPath::MdaXPathElement* MdaXPath::MdaXPathCompiler::ELEMENT_EXPR()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathELEMENT_EXPR));
-
- MdaXPathElement* pElement = ELEMENT();
-
- if (TokenIs(MdaXPathOpenSqBracket))
- {
- NextToken();
- pElement->SetQualifier(FILTER_EXPR());
- ASSERT(TokenIs(MdaXPathCloseSqBracket));
-
- NextToken();
- }
-
- return pElement;
-}
-
-// FILTER_EXPR
-// FILTER
-// '(' FILTER ')'
-// FILTER '&' FILTER
-// FILTER '|' FILTER
-MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::FILTER_EXPR()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathFILTER_EXPR));
-
- // '(' FILTER ')'
- if (TokenIs(MdaXPathOpenParen))
- {
- MdaXPath::MdaXPathBase* pFilter = FILTER();
- ASSERT(TokenIs(MdaXPathCloseParen));
-
- NextToken();
- return pFilter;
- }
-
- if (TokenIs(MdaXPathFILTER))
- {
- MdaXPath::MdaXPathBase* pFilter = FILTER();
-
- // FILTER '&' FILTER
- if (TokenIs(MdaXPathLogicalAnd))
- {
- NextToken();
- return m_pXPath->m_logicalOpFactory.Create()->Initialize(TRUE, pFilter, FILTER());
- }
-
- // FILTER '|' FILTER
- if (TokenIs(MdaXPathLogicalOr))
- {
- NextToken();
- return m_pXPath->m_logicalOpFactory.Create()->Initialize(FALSE, pFilter, FILTER());
- }
-
- // FILTER
- return pFilter;
- }
-
- UNREACHABLE();
-}
-
-// FILTER
-// ELEMENT_EXPR
-// ATTRIBUTE_FILTER
-// ELEMENT_EXPR ATTRIBUTE_FILTER
-MdaXPath::MdaXPathBase* MdaXPath::MdaXPathCompiler::FILTER()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathFILTER));
-
- if (TokenIs(MdaXPathELEMENT_EXPR))
- {
- MdaXPathElement* pElementExpr = ELEMENT_EXPR();
-
- if (TokenIs(MdaXPathATTRIBUTE_FILTER))
- pElementExpr->SetQualifier(ATTRIBUTE_FILTER());
-
- return pElementExpr;
- }
-
- if (TokenIs(MdaXPathATTRIBUTE_FILTER))
- return ATTRIBUTE_FILTER();
-
- UNREACHABLE();
-}
-
-// ELEMENT
-// id
-// '*'
-// '?'
-MdaXPath::MdaXPathElement* MdaXPath::MdaXPathCompiler::ELEMENT()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathELEMENT));
-
- MdaXPathElement* pElement = m_pXPath->m_elementFactory.Create();
-
- if (TokenIs(MdaXPathAstrix))
- pElement->Initialize();
-
- else if (TokenIs(MdaXPathIdentifier))
- pElement->Initialize(MdaSchema::GetElementType(GetIdentifier()));
-
- else if (TokenIs(MdaXPathQMark))
- {
- pElement->Initialize(++m_pXPath->m_cArgs);
- *m_pXPath->m_argTypes.Append() = XPathVarElemDeclDef;
- }
-
- else { UNREACHABLE(); }
-
- NextToken();
- return pElement;
-}
-
-// ATTRIBUTE_FILTER();
-// ATTRIBUTE
-// ATTRIBUTE '=' ''' id '''
-// ATTRIBUTE '=' '?'
-MdaXPath::MdaXPathAttribute* MdaXPath::MdaXPathCompiler::ATTRIBUTE_FILTER()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- PRECONDITION(TokenIs(MdaXPathATTRIBUTE_FILTER));
-
- MdaXPathAttribute* pAttr = ATTRIBUTE();
-
- if (TokenIs(MdaXPathEquals))
- {
- NextToken();
-
- if (TokenIs(MdaXPathQuotedString))
- {
- NextToken();
- pAttr->SetValue(GetIdentifier());
-
- NextToken();
- ASSERT(TokenIs(MdaXPathQuotedString));
- }
- else if (TokenIs(MdaXPathQMark))
- {
- pAttr->SetValue(++m_pXPath->m_cArgs);
- *m_pXPath->m_argTypes.Append() = XPathVarAttrSString;
- }
- else { UNREACHABLE(); }
- }
-
- NextToken();
- return pAttr;
-}
-
-
-//
-// MdaXPath::Elements::Run() -- The search engine
-//
-
-BOOL MdaXPath::MdaXPathElement::Run(MdaXmlElement* pElement, MdaXPathResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- BOOL bAnyPass = FALSE;
- if (pResult->IsRoot())
- {
- bAnyPass |= RunOnChild(pElement, pResult);
- }
- else
- {
- SArray<MdaXmlElement*>& children = pElement->GetChildren();
-
- for (UINT32 i = 0; i < children.GetCount(); i ++)
- {
- bAnyPass |= RunOnChild(children[i], pResult);
- }
- }
-
- return bAnyPass;
-}
-
-BOOL MdaXPath::MdaXPathElement::RunOnChild(MdaXmlElement* pElement, MdaXPathResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaElemDeclDef name = m_nameArg == NOT_VARIABLE ? m_name : pResult->GetArgs()[m_nameArg].m_u.m_elemDeclDef;
-
- if (name != MdaElemUndefined && name != pElement->GetDeclDef())
- return FALSE;
-
- if (m_pQualifier && !m_pQualifier->Run(pElement, pResult))
- return FALSE;
-
- if (m_pChild && !m_pChild->Run(pElement, pResult))
- return FALSE;
-
- if (m_bIsTarget)
- {
- ASSERT(!m_pChild);
- pResult->AddMatch(pElement);
- }
-
- return TRUE;
-}
-
-BOOL MdaXPath::MdaXPathAttribute::Run(MdaXmlElement* pElement, MdaXPathResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaAttrDeclDef name = m_nameArg == NOT_VARIABLE ? m_name : pResult->GetArgs()[m_nameArg].m_u.m_attrDeclDef;
- SString& value = m_valueArg == NOT_VARIABLE ? m_value : *pResult->GetArgs()[m_valueArg].m_u.m_pSstr;
-
- MdaXmlAttribute* pAttr = pElement->GetAttribute(name);
- if (!pAttr)
- return FALSE;
-
- LPCWSTR szAttrValue = pAttr->GetValue();
- if (!value.IsEmpty() && *szAttrValue != W('*') && !value.Equals(szAttrValue))
- return FALSE;
-
- if (m_bIsTarget)
- pResult->AddMatch(pElement);
-
- return TRUE;
-}
-
-BOOL MdaXPath::MdaXPathLogicalOp::Run(MdaXmlElement* pParent, MdaXPathResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (m_andOp)
- return m_pLhs->Run(pParent, pResult) && m_pRhs->Run(pParent, pResult);
-
- return m_pLhs->Run(pParent, pResult) || m_pRhs->Run(pParent, pResult);
-}
-
-
-//
-// MdaSchema
-//
-
-MdaHashtable<MdaElemDeclDef>* MdaSchema::g_pHtElementType;
-MdaHashtable<MdaAttrDeclDef>* MdaSchema::g_pHtAttributeType;
-LPCWSTR MdaSchema::g_arElementNames[MdaElemEnd];
-LPCWSTR MdaSchema::g_arAttributeNames[MdaAttrEnd];
-MdaFactory<SString>* MdaSchema::g_pSstringFactory;
-MdaElemDeclDef MdaSchema::MdaSchemaTypeToElemDef[MdaSchema::MdaSchemaTypeEnd];
-MdaSchema::MdaSchemaMetaType MdaSchema::MdaSchemaTypeToMetaType[MdaSchema::MdaSchemaTypeEnd];
-
-LPCWSTR MdaSchema::ToLowerFirstChar(LPCWSTR name)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return ::ToLowerFirstChar(name, g_pSstringFactory);
-}
-
-void MdaSchema::Initialize()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- g_pHtElementType = new MdaHashtable<MdaElemDeclDef>();
- g_pHtAttributeType = new MdaHashtable<MdaAttrDeclDef>();
- g_pSstringFactory = new MdaFactory<SString>();
-
- COUNT_T i = 0;
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Sequence); // MdaSchemaSequenceType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Choice); // MdaSchemaChoiceType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Group); // MdaSchemaGroupType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Group); // MdaSchemaGroupRefType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Schema); // MdaSchemaRootType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Attribute); // MdaSchemaAttributeType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexType); // MdaSchemaComplexTypeType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexType); // MdaSchemaComplexTypeDefType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementRefTyp
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Extension); // MdaSchemaExtensionType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementRefTypeType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(ComplexContent); // MdaSchemaComplexContentType
- MdaSchemaTypeToElemDef[i++] = MdaElemDef(Element); // MdaSchemaElementAnyType
-
- i = 0;
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypePattern; // MdaSchemaSequenceType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypePattern; // MdaSchemaChoiceType
- MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypePattern | MdaSchemaMataTypeDeclDef); // MdaSchemaGroupType
- MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypePattern | MdaSchemaMataTypeRef); // MdaSchemaGroupRefType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaRootType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaAttributeType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeDeclDef; // MdaSchemaElementType
- MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataNone | MdaSchemaMataMayHaveAttributes); // MdaSchemaComplexTypeType
- MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeDeclDef | MdaSchemaMataMayHaveAttributes); // MdaSchemaComplexTypeDefType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeRef; // MdaSchemaElementRefTyp
- MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeRef | MdaSchemaMataMayHaveAttributes); // MdaSchemaExtensionType
- MdaSchemaTypeToMetaType[i++] = (MdaSchemaMetaType)(MdaSchemaMataTypeDeclDef | MdaSchemaMataTypeRef); // MdaSchemaElementRefTypeType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataNone; // MdaSchemaComplexContentType
- MdaSchemaTypeToMetaType[i++] = MdaSchemaMataTypeDeclDef; // MdaSchemaElementAnyType
-
- i = 0;
-#define MDA_MAP_ASSISTANT_DEFINITION_TO_NAME
-#include "mdaschema.inl"
-#undef MDA_MAP_ASSISTANT_DEFINITION_TO_NAME
- g_arElementNames[i++] = NULL;
-#define MDA_MAP_ELEMENT_DEFINITION_TO_NAME
-#include "mdaschema.inl"
-#undef MDA_MAP_ELEMENT_DEFINITION_TO_NAME
- g_arElementNames[i++] = NULL;
-#define MDA_MAP_ELEMENT_DECLARATION_TO_NAME
-#include "mdaschema.inl"
-#undef MDA_MAP_ELEMENT_DECLARATION_TO_NAME
- g_arElementNames[i++] = NULL; // Max
- g_arElementNames[i++] = W("!--"); // Comment
- g_arElementNames[i++] = NULL; // Undefined
-
- i = 0;
-#define MDA_MAP_ATTRIBUTE_DECLARATION_TO_NAME
-#include "mdaschema.inl"
-#undef MDA_MAP_ATTRIBUTE_DECLARATION_TO_NAME
-
-#define MDA_MAP_ASSISTANT_NAME_TO_DEFINITION
-#include "mdaschema.inl"
-#undef MDA_MAP_ASSISTANT_NAME_TO_DEFINITION
-
-#define MDA_MAP_ELEMENT_NAME_TO_DEFINITION
-#include "mdaschema.inl"
-#undef MDA_MAP_ELEMENT_NAME_TO_DEFINITION
-
-#define MDA_MAP_ELEMENT_NAME_TO_DECLARATION
-#include "mdaschema.inl"
-#undef MDA_MAP_ELEMENT_NAME_TO_DECLARATION
-
-#define MDA_MAP_ATTRIBUTE_NAME_TO_DECLARATION
-#include "mdaschema.inl"
-#undef MDA_MAP_ATTRIBUTE_NAME_TO_DECLARATION
-}
-
-MdaElemDeclDef MdaSchema::GetElementType(LPCWSTR name, BOOL bAssertDefined)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaElemDeclDef type;
-
- if (!g_pHtElementType->Get(name, &type))
- {
- ASSERT(!bAssertDefined);
- return MdaElemUndefined;
- }
-
- return type;
-}
-
-LPCWSTR MdaSchema::GetElementName(MdaElemDeclDef type)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- PRECONDITION(type >= 0 && type < MdaElemUndefined);
- return g_arElementNames[type];
-}
-
-MdaAttrDeclDef MdaSchema::GetAttributeType(LPCWSTR name, BOOL bAssertDefined)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaAttrDeclDef type;
-
- if (!g_pHtAttributeType->Get(name, &type))
- {
- ASSERT(!bAssertDefined);
- return MdaAttrUndefined;
- }
-
- return type;
-}
-
-LPCWSTR MdaSchema::GetAttributeName(MdaAttrDeclDef type)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return g_arAttributeNames[type];
-}
-
-// TODO: Validation error reporting needs work
-MdaSchema::ValidationResult* MdaSchema::Validate(MdaXmlElement* pRoot, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- pResult->Initialize(this, pRoot);
-
- MdaSchemaBase* pXsd = *GetDef(pRoot->GetDeclDef());
- ASSERT((CheckPointer(pXsd) || (pRoot->GetDeclDef() > MdaElemDecl(Max))) && W("You likley did not include a MDA_DEFINE_OUTPUT section in your schema!"));
-
- BOOL bValidationSucceeded = pXsd ? pXsd->Validate(pRoot, pResult) : FALSE;
-
- if (bValidationSucceeded)
- pResult->ResetResult();
- else
- pResult->SetError();
-
- ASSERT(pResult->ValidationFailed() == !bValidationSucceeded);
- return pResult;
-}
-
-MdaSchema::MdaSchema()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < MdaElemEnd; i ++)
- m_definitions[i] = NULL;
-}
-
-
-//
-// MdaAssistantSchema
-//
-
-MdaAssistantSchema::MdaAssistantSchema()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-#define MDA_DEFINE_ASSISTANT_SCHEMA
-#include "mdaschema.inl"
-#undef MDA_DEFINE_ASSISTANT_SCHEMA
-
-#define MDA_DEFINE_MDA_ASSISTANT_CONFIG_GROUP
-#include "mdaschema.inl"
-#undef MDA_DEFINE_MDA_ASSISTANT_CONFIG_GROUP
-}
-
-LPCWSTR MdaAssistantSchema::SetRootAttributes(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- //pXml->AddAttribute(W("xmlns:") MDA_SCHEMA_PREFIX, MDA_TARGET_NAMESPACE);
- //pXml->AddAttribute(W("xmlns:xsi"), W("http://www.w3.org/2001/XMLSchema-instance"));
- return MDA_SCHEMA_PREFIX;
-}
-
-
-//
-// MdaAssistantMsgSchema
-//
-
-MdaAssistantMsgSchema::MdaAssistantMsgSchema()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-#define MDA_DEFINE_ASSISTANT_MSG_SCHEMA
-#include "mdaschema.inl"
-#undef MDA_DEFINE_ASSISTANT_MSG_SCHEMA
-
-#define MDA_DEFINE_MDA_ASSISTANT_MSG_GROUP
-#include "mdaschema.inl"
-#undef MDA_DEFINE_MDA_ASSISTANT_MSG_GROUP
-}
-
-LPCWSTR MdaAssistantMsgSchema::SetRootAttributes(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- //pXml->AddAttribute(W("xmlns:") MDA_SCHEMA_PREFIX, MDA_TARGET_NAMESPACE);
- //pXml->AddAttribute(W("xmlns:xsi"), W("http://www.w3.org/2001/XMLSchema-instance"));
- return MDA_SCHEMA_PREFIX;
-}
-
-
-//
-// MdaSchemaSchema
-//
-
-MdaSchemaSchema::MdaSchemaSchema()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-#define MDA_DEFINE_SCHEMA_SCHEMA
-#include "mdaschema.inl"
-#undef MDA_DEFINE_SCHEMA_SCHEMA
-}
-
-LPCWSTR MdaSchemaSchema::SetRootAttributes(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- pXml->AddAttributeSz(MdaAttrDecl(TargetNamespace), MDA_TARGET_NAMESPACE);
- pXml->AddAttributeSz(MdaAttrDecl(Xmlns), W("http://www.w3.org/2001/XMLSchema"))->SetNs(W("xs"));
- pXml->AddAttributeSz(MdaAttrDecl(Xmlns), MDA_TARGET_NAMESPACE);
- return W("xs");
-}
-
-
-//
-// MdaSchema::MdaSchemaXXX
-//
-MdaXmlElement* MdaSchema::MdaSchemaBase::ToXml(MdaXmlIndustry* pMdaXmlIndustry, MdaSchemaBase* pViolation)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return ToXml(pMdaXmlIndustry->CreateElement(), pViolation);
-}
-
-MdaXmlElement* MdaSchema::MdaSchemaBase::ToXml(MdaXmlElement* pXmlRoot, MdaSchemaBase* pViolation)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- LPCWSTR debugName = GetName();
-
- MdaXmlElement* pXml = pXmlRoot->AddChild(GetSchemaDeclDef());
- SetAttributes(pXml);
-
-// if (this == pViolation)
-// pXml->AddAttributeSz(MdaAttrDecl(Violated), W("---- THIS XSD ELEMENT VIOLATED -----"));
-
- if (m_children.GetCount() == 1 &&
- m_children[0]->GetSchemaDeclDef() == MdaElemDef(ComplexType) &&
- m_children[0]->m_children.GetCount() == 0 &&
- (!MayHaveAttr(m_children[0]) ||
- m_children[0]->GetAttributes().GetCount() == 0))
- {
- // Convert <Element><ComplexType/><Element> to <Element/>
- return pXml;
- }
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i ++)
- {
- debugName = m_children[i]->GetName();
- m_children[i]->ToXml(pXml, pViolation);
- }
-
- if (MayHaveAttr(this))
- {
- SArray<MdaSchemaAttribute*>& attributes = GetAttributes();
- for(COUNT_T j = 0; j < attributes.GetCount(); j ++)
- {
- debugName = attributes[j]->GetName();
- attributes[j]->ToXml(pXml, pViolation);
- }
- }
-
- return pXml;
-}
-
-
-void MdaSchema::MdaSchemaBase::AddChild(MdaSchemaBase* pElement)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (pElement->GetSchemaDeclDef() == MdaElemDef(Attribute))
- *GetAttributes().Append() = (MdaSchemaAttribute*)pElement;
- else
- *m_children.Append() = pElement;
-}
-
-//
-// Validation
-//
-
-#define CpdXsdIfFailGo(EXPR) do { if (!(EXPR)) { goto Fail; } } while (0)
-#define CpdXsdTest(EXPR) do { if (!(EXPR)) { pResult->SetError(this, pElement); goto Fail; } } while (0)
-#define MDA_XSD_VERIFY_OK return TRUE;
-#define MDA_XSD_VERIFY_FAIL Fail: return FALSE;
-
-BOOL MdaSchema::MdaSchemaElement::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString buffer;
- LPCWSTR debug = pElement->DebugToString(&buffer);
-
- CpdXsdTest(pElement->GetDeclDef() == GetDeclDef());
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i++)
- CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaSequence::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString buffer;
- LPCWSTR debug = pElement->DebugToString(&buffer);
-
- COUNT_T cPeriod = m_children.GetCount();
- COUNT_T cChildren = pElement->GetChildren().GetCount();
- COUNT_T cCurrent = *pCount;
- COUNT_T cCount = cCurrent;
- COUNT_T cMatches = 0;
-
- if (cPeriod == 0)
- return TRUE;
-
- while(cCurrent <= cChildren)
- {
- MdaSchemaBase* pXsd = m_children[cMatches % cPeriod];
- if (pXsd->GetSchemaDeclDef() == MdaElemDef(Element))
- {
- if (cCurrent == cChildren)
- break;
-
- if (!pXsd->Validate(pElement->GetChildren()[cCurrent], pResult))
- break;
-
- cCurrent++;
- }
- else
- {
- ASSERT(IsPattern(pXsd));
- if (!pXsd->ValidatePattern(pElement, pResult, &cCurrent))
- break;
- }
-
- cMatches++;
-
- // One period matched
- if (cMatches % cPeriod == 0)
- cCount = cCurrent;
-
- // Maximum periods matcheds
- if (cMatches / cPeriod == m_max)
- break;
- }
-
- // Test if the minumum number periods have been matched
- if (cMatches / cPeriod < m_min)
- return FALSE;
-
- // Update the position past the matched elements
- *pCount = cCount;
-
- return TRUE;
-}
-
-BOOL MdaSchema::MdaSchemaChoice::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString buffer;
- LPCWSTR debug = pElement->DebugToString(&buffer);
-
- BOOL bFound = FALSE;
- COUNT_T cCurrent = *pCount;
- COUNT_T cChildren = pElement->GetChildren().GetCount();
-
- for(COUNT_T cXsd = 0; cXsd < m_children.GetCount(); cXsd++)
- {
- MdaSchemaBase* pXsd = m_children[cXsd];
-
- if (IsPattern(pXsd))
- {
- COUNT_T cOldCurrent = cCurrent;
- if (pXsd->ValidatePattern(pElement, pResult, &cCurrent))
- {
- // "Empty matches" only allowed in choice pattern if there are no children to match
- if (cOldCurrent != cCurrent || cChildren == 0)
- {
- bFound = TRUE;
- break;
- }
- }
- }
- else
- {
- if (cCurrent == cChildren)
- break;
-
- if (pXsd->Validate(pElement->GetChildren()[cCurrent], pResult))
- {
- cCurrent++;
- bFound = TRUE;
- break;
- }
- }
- }
-
- CpdXsdIfFailGo(bFound);
-
- *pCount = cCurrent;
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-#define this pThis
-BOOL MdaSchema::Validate(MdaSchemaAttribute* pThis, MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszValue;
- MdaXmlAttribute* pAttr = (MdaXmlAttribute*)pElement->GetAttribute(pThis->m_declDef);
-
- if (!pAttr && !pThis->m_szDefault.IsEmpty())
- {
- pAttr = pElement->AddDefaultAttribute(pThis->m_declDef, pThis->m_szDefault.GetUnicode());
- }
-
- if (!pAttr)
- {
- CpdXsdTest(!pThis->m_bRequired);
- return TRUE;
- }
-
-#ifdef _DEBUG
- // Only necessary for validation of assistant output
- if (pAttr->m_type != MdaSchemaPrimitiveUnknown)
- {
- CpdXsdTest(pAttr->m_type == pThis->m_type);
- return TRUE;
- }
-#endif
-
- LPCWSTR szValue = pAttr->GetValue();
- sszValue.Set(szValue);
-
- if (pThis->m_type == MdaSchemaPrimitiveSString)
- {
- /* accept all strings? */
- }
- else if (pThis->m_type == MdaSchemaPrimitiveINT32)
- {
- CpdXsdTest(!sszValue.IsEmpty() && sszValue.GetCount() != 0);
-
- for (COUNT_T i = 0; i < sszValue.GetCount(); i ++)
- {
- if (i == 0 && *szValue == W('-') && sszValue.GetCount() > 1)
- continue;
-
- CpdXsdTest(IS_DIGIT(szValue[i]));
- }
-
- pAttr->SetINT32(_wtoi(szValue));
- }
- else if (pThis->m_type == MdaSchemaPrimitiveBOOL)
- {
- CpdXsdTest(!sszValue.IsEmpty() && sszValue.GetCount() != 0);
-
- if (sszValue.Equals(W("true")))
- pAttr->SetBOOL(true);
- else if (sszValue.Equals(W("false")))
- pAttr->SetBOOL(false);
- else
- CpdXsdTest(FALSE);
- }
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-#undef this
-
-BOOL MdaSchema::MdaSchemaBase::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- COUNT_T count = 0;
-
- CpdXsdTest(ValidatePattern(pElement, pResult, &count));
-
- CpdXsdTest(count == pElement->GetChildren().GetCount());
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaRoot::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i++)
- CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaComplexType::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i++)
- CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult));
-
- for(COUNT_T i = 0; i < m_attributes.GetCount(); i++)
- CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaComplexTypeDef::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i++)
- CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult));
-
- for(COUNT_T i = 0; i < m_attributes.GetCount(); i++)
- CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaComplexContent::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i++)
- CpdXsdIfFailGo(m_children[i]->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaGroup::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i++)
- {
- ASSERT(IsPattern(m_children[i]));
- CpdXsdIfFailGo(m_children[i]->ValidatePattern(pElement, pResult, pCount));
- }
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaGroupRef::ValidatePattern(MdaXmlElement* pElement, ValidationResult* pResult, COUNT_T* pCount)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaSchemaBase* pReference = GetRef();
- LPCWSTR debug = GetRefName();
- ASSERT(IsPattern(this));
- return pReference->ValidatePattern(pElement, pResult, pCount);
-}
-
-BOOL MdaSchema::MdaSchemaExtension::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- ASSERT(GetRef()->GetSchemaType() == MdaSchemaComplexTypeDefType);
- MdaSchemaComplexTypeDef* pReference = (MdaSchemaComplexTypeDef*)GetRef();
-
- MdaSchemaSequence sequence;
- sequence.Initialize(1, 1);
-
- MdaSchemaBase* pXsd = pReference;
- while(true)
- {
- if (MayHaveAttr(pXsd))
- {
- for(COUNT_T i = 0; i < pXsd->GetAttributes().GetCount(); i++)
- CpdXsdIfFailGo(pXsd->GetAttributes()[i]->Validate(pElement, pResult));
- }
-
- if (pXsd->GetSchemaType() == MdaSchemaExtensionType)
- {
- pXsd = ((MdaSchemaComplexTypeDef*)pXsd)->GetRef();
- continue;
- }
-
- if (pXsd->m_children.GetCount() == 0)
- break;
-
- pXsd = pXsd->m_children[0];
-
- if (IsPattern(pXsd))
- {
- sequence.AddChild(pXsd);
- break;
- }
- }
-
- if (m_children.GetCount() == 1)
- {
- ASSERT(IsPattern(m_children[0]));
- sequence.AddChild(m_children[0]);
- }
-
- CpdXsdIfFailGo(sequence.Validate(pElement, pResult));
-
- for(COUNT_T i = 0; i < m_attributes.GetCount(); i++)
- CpdXsdIfFailGo(m_attributes[i]->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaElementRefType::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- CpdXsdIfFailGo(GetRef()->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaElementAny::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString buffer;
- LPCWSTR debug = pElement->DebugToString(&buffer);
-
- CpdXsdTest(pElement->GetDeclDef() == GetDeclDef());
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-BOOL MdaSchema::MdaSchemaElementRef::Validate(MdaXmlElement* pElement, ValidationResult* pResult)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- LPCWSTR debug = GetRefName();
- CpdXsdIfFailGo(GetRef()->Validate(pElement, pResult));
-
- MDA_XSD_VERIFY_OK;
- MDA_XSD_VERIFY_FAIL;
-}
-
-
-//
-// MdaSchema::XXX::SetAttributes()
-//
-
-void MdaSchema::MdaSchemaSequence::SetAttributes(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SmallStackSString ssBound;
-
- ssBound.Printf(W("%d"), m_min);
- pXml->AddAttributeSz(MdaAttrDecl(MinOccurs), ssBound.GetUnicode());
-
- if (m_max == -1)
- {
- pXml->AddAttributeSz(MdaAttrDecl(MaxOccurs), W("unbounded"));
- }
- else
- {
- ssBound.Printf(W("%d"), m_max);
- pXml->AddAttributeSz(MdaAttrDecl(MaxOccurs), ssBound.GetUnicode());
- }
-}
-
-void MdaSchema::MdaSchemaAttribute::SetAttributes(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- pXml->AddAttributeSz(MdaAttrDecl(Name), GetAttributeName(m_declDef));
-
- LPCWSTR szType = NULL;
- if (m_type == MdaSchemaPrimitiveBOOL)
- szType = W("xs:boolean");
- else if (m_type == MdaSchemaPrimitiveINT32)
- szType = W("xs:int");
- else if (m_type == MdaSchemaPrimitiveSString)
- szType = W("xs:string");
- else { UNREACHABLE(); }
-
- pXml->AddAttributeSz(MdaAttrDecl(Type), szType);
- pXml->AddAttributeSz(MdaAttrDecl(Use), m_bRequired ? W("required") : W("optional"));
-
- if (!m_szDefault.IsEmpty())
- pXml->AddAttributeSz(MdaAttrDecl(Default), m_szDefault);
-}
-
-void MdaSchema::MdaSchemaDeclDefRef::SetAttributes(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- LPCWSTR szDeclDef = NULL;
- LPCWSTR szRef = NULL;
-
- if (IsDeclDef(this))
- szDeclDef = GetDeclDefName();
-
- if (IsRef(this))
- szRef = GetRefName();
-
- switch (GetSchemaType())
- {
- case MdaSchemaGroupRefType:
- case MdaSchemaElementRefTyp:
- pXml->AddAttributeSz(MdaAttrDecl(Ref), szRef);
- break;
-
- case MdaSchemaExtensionType:
- pXml->AddAttributeSz(MdaAttrDecl(Base), szRef);
- break;
-
- case MdaSchemaElementRefTypeType:
- pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef);
- pXml->AddAttributeSz(MdaAttrDecl(Type), szRef);
- break;
-
- case MdaSchemaElementAnyType:
- pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef);
- pXml->AddAttributeSz(MdaAttrDecl(Type), W("xs:anyType"));
- break;
-
- case MdaSchemaGroupType:
- case MdaSchemaElementType:
- case MdaSchemaComplexTypeDefType:
- pXml->AddAttributeSz(MdaAttrDecl(Name), szDeclDef);
- break;
-
- default:
- UNREACHABLE();
- }
-}
-
-//
-// MdaAssistant
-//
-void MdaAssistant::Initialize(MdaXmlElement* pXmlInput)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (pXmlInput->GetAttribute(MdaAttrDecl(SuppressDialog)))
- m_bSuppressDialog = !!pXmlInput->GetAttributeValueAsBool(MdaAttrDecl(SuppressDialog));
-}
-
-LPCWSTR MdaAssistant::GetName()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return MdaSchema::GetElementName(m_assistantDeclDef);
-}
-
-MdaXmlElement* MdaAssistant::GetRootElement(MdaXmlElement* pRoot, BOOL bBreak)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaXmlElement* pXmlAssistant = pRoot->AddChild(GetAssistantMsgDeclDef());
-
- if (bBreak)
- pXmlAssistant->AddAttributeSz(MdaAttrDecl(Break), W("true"));
-
- return pXmlAssistant;
-}
-
-BOOL MdaAssistant::IsAssistantActive(MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return TRUE;
-}
-
-MdaXmlElement* MdaAssistant::OutputThread(Thread* pThread, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- _ASSERTE(pThread);
- pXml->AddAttributeInt(MdaAttrDecl(OsId), pThread->GetOSThreadId());
- pXml->AddAttributeInt(MdaAttrDecl(ManagedId), pThread->GetThreadId());
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputMethodTable(MethodTable* pMT, MdaXmlElement* pXml)
-{
- CONTRACT (MdaXmlElement*)
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMT));
- PRECONDITION(CheckPointer(pXml));
- POSTCONDITION(CheckPointer(RETVAL));
- }
- CONTRACT_END;
-
- static WCHAR szTemplateMsg[] = {W("Failed to QI for interface %s because it does not have a COM proxy stub registered.")};
-
- DefineFullyQualifiedNameForClassWOnStack();
- pXml->AddAttributeSz(MdaAttrDecl(Name), GetFullyQualifiedNameForClassW(pMT));
-
- RETURN pXml;
-}
-
-void MdaAssistant::ToString(TypeHandle typeHandle, SString* psszFullname, SString* psszNamespace)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString ssz;;
-
- psszFullname->Clear();
-
- LPCSTR szDeclTypeName, szNamespace;
- InlineSArray<mdTypeDef, 32> nesting;
-
- mdTypeDef tkTypeDef = typeHandle.GetCl();
- Module* pModule = typeHandle.GetModule();
- IMDInternalImport* pImport = pModule->GetMDImport();
-
- // Get tkTypeDef tokens for declaring type and its nested classes
- nesting.Append(tkTypeDef);
- while (S_OK == pImport->GetNestedClassProps(tkTypeDef, &tkTypeDef))
- nesting.Append(tkTypeDef);
-
- // Append the namespace
- COUNT_T i = nesting.GetCount() - 1;
- if (FAILED(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace)))
- {
- szNamespace = NULL;
- szDeclTypeName = NULL;
- }
- if (szNamespace && *szNamespace != W('\0'))
- {
- if (psszNamespace)
- psszNamespace->SetUTF8(szNamespace);
-
- psszFullname->SetUTF8(szNamespace);
- psszFullname->Append(W("."));
- }
-
- // Append the nested classes
- for(; i > 0; i --)
- {
- IfFailThrow(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace));
- ssz.SetUTF8(szDeclTypeName);
- psszFullname->Append(ssz);
- psszFullname->Append(W("+"));
- }
-
- // Append the declaring type name
- IfFailThrow(pImport->GetNameOfTypeDef(nesting[i], &szDeclTypeName, &szNamespace));
- ssz.SetUTF8(szDeclTypeName);
- psszFullname->Append(ssz);
-}
-
-SString& MdaAssistant::ToString(SString& sszBuffer, Module* pModule)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- sszBuffer.AppendUTF8(pModule->GetSimpleName());
- return sszBuffer;
-}
-
-SString& MdaAssistant::ToString(SString& sszBuffer, TypeHandle typeHandle)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszScratch;
- ToString(sszBuffer, typeHandle.GetModule()).GetUnicode();
- sszBuffer.Append(W("!"));
- ToString(typeHandle, &sszScratch, NULL);
- sszBuffer.Append(sszScratch);
- return sszBuffer;
-}
-
-SString& MdaAssistant::ToString(SString& sszBuffer, MethodDesc* pMethodDesc)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- ToString(sszBuffer, pMethodDesc->GetMethodTable()).GetUnicode();
- sszBuffer.Append(W("::"));
- StackSString ssz;
- ssz.SetUTF8(pMethodDesc->GetName());
- sszBuffer.Append(ssz);
- return sszBuffer;
-}
-
-SString& MdaAssistant::ToString(SString& sszBuffer, FieldDesc* pFieldDesc)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- ToString(sszBuffer, pFieldDesc->GetEnclosingMethodTable()).GetUnicode();
- sszBuffer.Append(W("::"));
- StackSString ssz;
- ssz.SetUTF8(pFieldDesc->GetName());
- sszBuffer.Append(ssz);
- return sszBuffer;
-}
-
-MdaXmlElement* MdaAssistant::OutputParameter(SString parameterName, USHORT sequence, MethodDesc* pMethodDesc, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- TypeHandle declType(pMethodDesc->GetMethodTable());
- Module* pDeclModule = declType.GetModule();
-
- pXml->AddAttributeSz(MdaAttrDecl(Name), parameterName);
- pXml->AddAttributeInt(MdaAttrDecl(Index), sequence);
-
- OutputMethodDesc(pMethodDesc, pXml->AddChild(MdaElemDecl(DeclaringMethod)));
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputMethodDesc(MethodDesc* pMethodDesc, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- TypeHandle declType(pMethodDesc->GetMethodTable());
- Module* pDeclModule = declType.GetModule();
-
- StackSString sszMethod;
-
- pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszMethod, pMethodDesc).GetUnicode());
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputFieldDesc(FieldDesc* pFieldDesc, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszField;
-
- pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszField, pFieldDesc).GetUnicode());
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputTypeHandle(TypeHandle typeHandle, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszTypeName;
-
- // Set Attribute
- pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszTypeName, typeHandle.GetMethodTable()).GetUnicode());
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputModule(Module* pModule, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- pXml->AddAttributeSz(MdaAttrDecl(Name), pModule->GetSimpleName());
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputCallsite(MethodDesc *pMethodDesc, DWORD dwOffset, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszMethod;
- pXml->AddAttributeSz(MdaAttrDecl(Name), ToString(sszMethod, pMethodDesc).GetUnicode());
-
- StackSString sszOffset;
- sszOffset.Printf(W("0x%04X"), dwOffset);
- pXml->AddAttributeSz(MdaAttrDecl(Offset), sszOffset.GetUnicode());
-
- return pXml;
-}
-
-MdaXmlElement* MdaAssistant::OutputException(OBJECTREF *pExceptionObj, MdaXmlElement* pXml)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- OutputTypeHandle((*pExceptionObj)->GetTypeHandle(), pXml->AddChild(MdaElemDecl(Type)));
-
- StackSString message;
- GetExceptionMessage(*pExceptionObj, message);
-
- pXml->AddAttributeSz(MdaAttrDecl(Message), message);
-
- return pXml;
-}
-
-//
-// MdaQuery::CompiledQueries
-//
-BOOL MdaQuery::CompiledQueries::Test(MethodDesc* pMethodDesc)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for (COUNT_T i = 0; i < m_queries.GetCount(); i ++)
- {
- if (m_queries[i]->Test(pMethodDesc))
- return TRUE;
- }
-
- return FALSE;
-}
-
-BOOL MdaQuery::CompiledQueries::Test(FieldDesc* pFieldDesc)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for (COUNT_T i = 0; i < m_queries.GetCount(); i ++)
- {
- if (m_queries[i]->Test(pFieldDesc))
- return TRUE;
- }
-
- return FALSE;
-}
-
-BOOL MdaQuery::CompiledQueries::Test(MethodTable* pMethodTable)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for (COUNT_T i = 0; i < m_queries.GetCount(); i ++)
- {
- if (m_queries[i]->Test(pMethodTable))
- return TRUE;
- }
-
- return FALSE;
-}
-
-MdaQuery::CompiledQuery* MdaQuery::CompiledQueries::AddQuery()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- CompiledQuery* pQuery = m_factory.Create();
- m_queries.Append(pQuery);
- return pQuery;
-}
-
-
-//
-// MdaQuery::CompiledQuery
-//
-void MdaQuery::Compile(MdaXmlElement* pXmlFilters, CompiledQueries* pCompiledQueries)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SArray<MdaXmlElement*>& children = pXmlFilters->GetChildren();
- BOOL bJmc = pXmlFilters->GetAttribute(MdaAttrDecl(JustMyCode))->GetValueAsBool();
-
- for (COUNT_T i = 0; i < children.GetCount(); i ++)
- {
- MdaXmlElement* pXmlFilter = children[i];
- SString* psszName = pXmlFilter->GetAttribute(MdaAttrDecl(Name))->GetValueAsCSString();
- MdaXmlAttribute* pJmcOptAttr = pXmlFilter->GetAttribute(MdaAttrDecl(JustMyCode));
- if (pJmcOptAttr)
- bJmc = pJmcOptAttr->GetValueAsBool();
- Compiler compiler;
- CompiledQuery* pQuery = pCompiledQueries->AddQuery();
- compiler.Compile(psszName, pQuery);
- if (bJmc)
- pQuery->SetJustMyCode();
- }
-}
-
-MdaQuery::CompiledQuery::CompiledQuery()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_bJustMyCode = FALSE;
- m_bAnyMember = FALSE;
- m_bAnyType = FALSE;
- m_sszFullname.Clear();
- m_sszMember.Clear();
-}
-
-BOOL StartsWith(SString* psszString, SString* psszSubstring)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszString(*psszString);
- if (psszString->GetCount() < psszSubstring->GetCount())
- return FALSE;
- sszString.Truncate(sszString.Begin() + psszSubstring->GetCount());
- return sszString.Equals(*psszSubstring);
-}
-
-BOOL MdaQuery::CompiledQuery::Test(MethodDesc* pMethodDesc)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszName(SString::Utf8, pMethodDesc->GetName());
-
- if (pMethodDesc->IsLCGMethod() || pMethodDesc->IsILStub())
- return FALSE;
-
- if (!Test(&sszName, pMethodDesc->GetMethodTable()))
- return FALSE;
-
- if (!m_bJustMyCode)
- return TRUE;
-
- if (IsJustMyCode(pMethodDesc))
- return TRUE;
-
- return FALSE;
-}
-
-BOOL MdaQuery::CompiledQuery::Test(FieldDesc* pFieldDesc)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- StackSString sszName(SString::Utf8, pFieldDesc->GetName());
- if (!Test(&sszName, pFieldDesc->GetApproxEnclosingMethodTable()))
- return FALSE;
-
- if (!m_bJustMyCode)
- return TRUE;
-
- return TRUE;
-}
-
-BOOL MdaQuery::CompiledQuery::Test(SString* psszName, MethodTable* pMethodTable)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!m_sszMember.IsEmpty())
- {
- if (!m_sszMember.Equals(*psszName))
- return FALSE;
-
- if (m_sszMember.GetCount() == m_sszFullname.GetCount())
- return TRUE;
- }
- else if (!m_bAnyMember)
- return FALSE;
-
- return Test(pMethodTable);
-}
-
-BOOL MdaQuery::CompiledQuery::Test(MethodTable* pMethodTable)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!pMethodTable)
- return FALSE;
-
- if (m_sszFullname.IsEmpty())
- return TRUE;
-
- StackSString sszNamespace, sszFullName;
- MdaAssistant::ToString(pMethodTable, &sszFullName, &sszNamespace);
-
- if (m_bAnyType && StartsWith(&m_sszFullname, &sszNamespace))
- return TRUE;
-
- if (m_bAnyMember && StartsWith(&m_sszFullname, &sszFullName))
- return TRUE;
-
- return m_sszFullname.Equals(sszFullName);
-}
-
-void MdaQuery::CompiledQuery::SetName(LPCWSTR name)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!m_sszFullname.IsEmpty())
- {
- m_sszFullname.Append(W("."));
- m_sszMember.Clear();
- }
- else
- {
- m_sszMember.Set(name);
- }
-
- m_sszFullname.Append(name);
-
-}
-
-void MdaQuery::CompiledQuery::SetNestedTypeName(LPCWSTR name)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_sszMember.Clear();
-
- if (!m_sszFullname.IsEmpty())
- m_sszFullname.Append(W("+"));
-
- m_sszFullname.Append(name);
-}
-
-void MdaQuery::CompiledQuery::SetAnyMember()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_bAnyMember = TRUE;
- m_sszMember.Clear();
-}
-
-void MdaQuery::CompiledQuery::SetAnyType()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_bAnyType = TRUE;
- m_sszMember.Clear();
-
- if (m_sszFullname.IsEmpty())
- m_bAnyMember = TRUE;
-}
-
-
-//
-// MdaQuery::CompiledQuery
-//
-
-MdaQuery::Compiler::Token MdaQuery::Compiler::LexAToken()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (*m_itr == W('\0'))
- return MdaFilterEnd;
-
- if (ISWHITE(*m_itr))
- {
- m_itr++;
- return LexAToken();
- }
-
- if (ISMDAID(*m_itr))
- {
- m_identifier.Clear();
-
- do
- {
- m_identifier.Append(*m_itr);
- m_itr++;
- }
- while(ISMDAID(*m_itr));
-
- m_identifier.Append(W("\0"));
- return MdaFilterIdentifier;
- }
-
- WCHAR c = *m_itr;
- m_itr++;
- switch(c)
- {
- case W('.'): return MdaFilterDot;
- case W(':'): return MdaFilterColon;
- case W('*'): return MdaFilterAstrix;
- case W('+'): return MdaFilterPlus;
- }
-
- return MdaFilterEnd;
-}
-
-//
-// MdaXPath::MdaXPathCompiler -- Parser
-//
-BOOL MdaQuery::Compiler::Compile(SString* sszQuery, CompiledQuery* pAst)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_itr = sszQuery->Begin();
-
- NextToken();
- BOOL bResult = NAME(pAst);
-
- return bResult;
-}
-
-// NAME
-// '*'
-// id
-// id '.' NAME
-// id '+' NESTNAME
-// id ':' ':' NESTNAME
-BOOL MdaQuery::Compiler::NAME(CompiledQuery* pAst)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (TokenIs(MdaFilterIdentifier))
- {
- pAst->SetName(GetIdentifier());
-
- NextToken();
- if (TokenIs(MdaFilterDot))
- {
- NextToken();
- return NAME(pAst);
- }
- else if (TokenIs(MdaFilterPlus))
- {
- NextToken();
- return NESTNAME(pAst);
- }
- else if (TokenIs(MdaFilterColon))
- {
- NextToken();
- if (!TokenIs(MdaFilterColon))
- return FALSE;
-
- NextToken();
- return MEMBERNAME(pAst);
- }
- }
- else if (TokenIs(MdaFilterAstrix))
- {
- pAst->SetAnyType();
- NextToken();
- }
- else return FALSE;
-
- return TRUE;
-}
-
-// NESTNAME
-// id '+' NESTNAME
-// id ':' ':' NESTNAME
-BOOL MdaQuery::Compiler::NESTNAME(CompiledQuery* pAst)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!TokenIs(MdaFilterIdentifier))
- return FALSE;
-
- pAst->SetNestedTypeName(GetIdentifier());
-
- NextToken();
-
- if (TokenIs(MdaFilterPlus))
- {
- NextToken();
- return NESTNAME(pAst);
- }
- else if (TokenIs(MdaFilterColon))
- {
- NextToken();
- if (!TokenIs(MdaFilterColon))
- return FALSE;
-
- NextToken();
- return MEMBERNAME(pAst);
- }
- else return FALSE;
-}
-
-// MEMBERNAME
-// '*'
-// id
-BOOL MdaQuery::Compiler::MEMBERNAME(CompiledQuery* pAst)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (TokenIs(MdaFilterIdentifier))
- pAst->SetMemberName(GetIdentifier());
-
- else if (TokenIs(MdaFilterAstrix))
- pAst->SetAnyMember();
-
- else return FALSE;
-
- NextToken();
- return TRUE;
-}
-
-
-//
-// MdaXmlElement
-//
-MdaXmlElement* MdaXmlElement::GetChild(MdaElemDeclDef declDef)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- for(COUNT_T i = 0; i < m_children.GetCount(); i ++)
- {
- if (m_children[i]->GetDeclDef() == declDef)
- return m_children[i];
- }
-
- return NULL;
-}
-
-SString* MdaXmlElement::ToXml(SString* pXml, LPCWSTR ns, INT32 depth)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(depth < 60); // Trap for recursion
- }
- CONTRACTL_END;
-
- // Indent
- for (INT32 i = 0; i < depth; i ++)
- pXml->Append(W(" "));
-
- pXml->Append(W("<"));
- if (ns && IsDefinition()) { pXml->Append(ns); pXml->Append(W(":")); }
- pXml->Append(GetName());
-
- if (m_attributes.GetCount() != 0)
- {
- for (COUNT_T i = 0; i < m_defaultAttrIndex && i < m_attributes.GetCount(); i ++)
- {
- pXml->Append(W(" "));
- m_attributes[i]->ToXml(pXml);
- }
- }
-
- if (m_children.GetCount() == 0)
- {
- if (GetDeclDef() == MdaElemComment)
- {
- pXml->Append(W(" "));
- pXml->Append(m_szName.GetUnicode());
- pXml->Append(W(" -->\n"));
- }
- else
- pXml->Append(W("/>\n"));
- }
- else
- {
- pXml->Append(W(">"));
-
- SArray<MdaXmlElement*>::Iterator itr = m_children.Begin();
- SArray<MdaXmlElement*>::Iterator end = m_children.End();
-
- pXml->Append(W("\n"));
- while (itr != end)
- {
- (*itr)->ToXml(pXml, ns, depth + 1);
- itr++;
- }
-
- // Indent
- for (INT32 i = 0; i < depth; i ++)
- pXml->Append(W(" "));
-
- pXml->Append(W("</"));
- if (ns && IsDefinition()) { pXml->Append(ns); pXml->Append(W(":")); }
- pXml->Append(GetName());
- pXml->Append(W(">\n"));
- }
-
-
- return pXml;
-}
-
-LPCWSTR MdaXmlElement::DebugToString(SString* pBuffer)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- pBuffer->Append(W("<"));
- pBuffer->Append(GetName());
-
- for(COUNT_T i = 0; i < GetAttributes().GetCount(); i++)
- {
- pBuffer->Append(W(" "));
- GetAttributes()[i]->ToXml(pBuffer);
- }
-
- pBuffer->Append(W("/>"));
- return pBuffer->GetUnicode();
-}
-
-MdaXmlElement* MdaXmlElement::SetName(LPCWSTR name, BOOL bAssertDefined)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SetDeclDef(MdaSchema::GetElementType(name, bAssertDefined));
-
- if (GetDeclDef() == MdaElemUndefined)
- m_szName.Set(name);
-
- return this;
-}
-
-MdaXmlAttribute* MdaXmlElement::AddAttribute(MdaAttrDeclDef declDef)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return AddAttribute(m_pXmlIndustry->CreateAttribute()->SetDeclDef(declDef));
-}
-
-MdaXmlAttribute* MdaXmlElement::AddAttribute(LPCWSTR szName, LPCWSTR szValue)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return AddAttribute(m_pXmlIndustry->CreateAttribute()->Initialize(szName, szValue));
-}
-
-MdaXmlAttribute* MdaXmlElement::AddDefaultAttribute(MdaAttrDeclDef attrDeclDef, LPCWSTR szValue)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (m_defaultAttrIndex == -1)
- m_defaultAttrIndex = m_attributes.GetCount();
- MdaXmlAttribute* pAttr = AddAttribute(attrDeclDef)->SetSString(szValue);
- pAttr->m_type = MdaSchemaPrimitiveUnknown;
- return pAttr;
-}
-
-MdaXmlElement* MdaXmlElement::AddChild(MdaXmlElement* pChild)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- //PRECONDITION(m_elemDeclDef != MdaElemUndefined);
- PRECONDITION(CheckPointer(pChild));
- PRECONDITION(CheckPointer(pChild->m_pXmlIndustry));
-
- *m_children.Append() = pChild;
- return pChild;
-}
-
-MdaXmlElement* MdaXmlElement::AddChild(LPCWSTR name, BOOL bAssertDefined)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return AddChild(m_pXmlIndustry->CreateElement())->SetName(name, bAssertDefined);
-}
-
-MdaXmlElement* MdaXmlElement::AddChild(MdaElemDeclDef type)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return AddChild(m_pXmlIndustry->CreateElement()->SetDeclDef(type));
-}
-
-LPCWSTR MdaXmlElement::GetName()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (GetDeclDef() == MdaElemUndefined)
- return m_szName.GetUnicode();
-
- return MdaSchema::GetElementName(m_elemDeclDef);
-}
-
-MdaXmlAttribute* MdaXmlElement::GetAttribute(MdaAttrDeclDef attrDeclDef)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-
- for(UINT32 i = 0; i < m_attributes.GetCount(); i++)
- {
- if (attrDeclDef == m_attributes[i]->GetDeclDef())
- return m_attributes[i];
- }
-
- return NULL;
-}
-
-BOOL MdaXmlElement::GetAttributeValueAsBool(MdaAttrDeclDef attrDeclDef, BOOL bDefault)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaXmlAttribute* pAttr = GetAttribute(attrDeclDef);
-
- if (!pAttr)
- return bDefault;
-
- return pAttr->GetValueAsBool();
-}
-
-BOOL MdaXmlElement::GetAttributeValueAsBool(MdaAttrDeclDef attrDeclDef)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- MdaXmlAttribute* pAttr = GetAttribute(attrDeclDef);
- PREFIX_ASSUME(pAttr != NULL);
- ASSERT(pAttr);
- return pAttr->GetValueAsBool();
-}
-
-//
-// MdaXmlAttribute
-//
-
-SString* MdaXmlAttribute::ToXml(SString* xml)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- SString sszBuffer;
-
- xml->Append(GetName());
- if (!m_szNs.IsEmpty())
- {
- xml->Append(W(":"));
- xml->Append(m_szNs.GetUnicode());
- }
-
- xml->Append(W("=\""));
- if (m_type == MdaSchemaPrimitiveSString)
- xml->Append(MdaXmlEscape(sszBuffer, m_value));
- else if (m_type == MdaSchemaPrimitiveBOOL)
- xml->Append(m_bool ? W("true") : W("false"));
- else if (m_type == MdaSchemaPrimitiveINT32)
- {
- StackSString sszOutput;
- sszOutput.Printf(W("%d"), m_int);
- xml->Append(sszOutput);
- }
- xml->Append(W("\""));
- return xml;
-}
-
-LPCWSTR MdaXmlAttribute::GetName()
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (m_declDef != MdaAttrUndefined)
- return MdaSchema::GetAttributeName(m_declDef);
-
- return m_szName.GetUnicode();
-}
-
-MdaXmlAttribute* MdaXmlAttribute::Initialize(LPCWSTR szName, LPCWSTR szValue)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_type = MdaSchemaPrimitiveUnknown;
- m_value.Set(szValue);
-
- SetDeclDef(MdaSchema::GetAttributeType(szName, FALSE));
- if (m_declDef == MdaAttrUndefined)
- m_szName.Set(szName);
-
- return this;
-}
-
-
-//
-// MdaConfigFactory
-//
-STDAPI GetXMLObjectEx(IXMLParser **ppv);
-
-MdaXmlElement* MdaConfigFactory::ParseXmlStream(MdaXmlIndustry* pXmlIndustry, LPCWSTR pszFileName)
-{
- CONTRACT(MdaXmlElement*)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACT_END;
-
- HRESULT hr = S_OK;
- MdaXmlElement* pRoot = NULL;
-
- EX_TRY
- {
- {
- if (!pszFileName)
- goto Exit;
-
- NonVMComHolder<IXMLParser> pIXMLParser(NULL);
- NonVMComHolder<IStream> pFile(NULL);
-
- hr = CreateConfigStream(pszFileName, &pFile);
- if(FAILED(hr)) goto Exit;
-
- hr = GetXMLObjectEx(&pIXMLParser);
- if(FAILED(hr)) goto Exit;
-
- hr = pIXMLParser->SetInput(pFile); // filestream's RefCount=2
- if ( ! SUCCEEDED(hr))
- goto Exit;
-
- pRoot = pXmlIndustry->CreateElement()->SetDeclDef(MdaElemDef(Dummy));
- MdaConfigFactory mdaConfigFactory(pRoot);
-
- hr = pIXMLParser->SetFactory(&mdaConfigFactory); // factory's RefCount=2
- if (!SUCCEEDED(hr))
- goto Exit;
-
- hr = pIXMLParser->Run(-1);
-
- if (pRoot->GetChildren().GetCount() == 1)
- pRoot = pRoot->GetChildren()[0];
- else
- pRoot = NULL;
- }
- Exit: ;
- }
- EX_CATCH
- {
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- if (hr == (HRESULT)XML_E_MISSINGROOT)
- hr = S_OK;
- else if (Assembly::FileNotFound(hr))
- hr = S_FALSE;
-
- RETURN pRoot;
-}
-
-HRESULT STDMETHODCALLTYPE MdaConfigFactory::CreateNode(
- IXMLNodeSource* pSource,
- PVOID pNodeParent,
- USHORT cNumRecs,
- XML_NODE_INFO** apNodeInfo)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_pMdaXmlElement = NULL;
-
- for(INT32 i = 0; i < cNumRecs; i++)
- {
- DWORD dwType = apNodeInfo[i]->dwType;
-
- if(dwType == XML_ELEMENT || dwType == XML_ATTRIBUTE)
- {
- StackSString sszName((WCHAR*)apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen);
-
- if (dwType == XML_ELEMENT)
- {
- m_pMdaXmlElement = m_stack.Tos()->AddChild(sszName, FALSE);
- }
- else if (dwType == XML_ATTRIBUTE)
- {
- i++;
- InlineSString<MDA_BUFFER_SIZE> szValue((WCHAR*)apNodeInfo[i]->pwcText, apNodeInfo[i]->ulLen);
-
- if (m_pMdaXmlElement)
- m_pMdaXmlElement->AddAttribute(sszName.GetUnicode(), szValue);
- }
- }
- }
-
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE MdaConfigFactory::BeginChildren(
- IXMLNodeSource* pSource,
- XML_NODE_INFO* pNodeInfo)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- m_stack.Push(m_pMdaXmlElement);
-
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE MdaConfigFactory::EndChildren(
- IXMLNodeSource* pSource,
- BOOL fEmptyNode,
- XML_NODE_INFO* pNodeInfo)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
-
- if (fEmptyNode)
- return S_OK;
-
- m_stack.Pop();
-
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE MdaConfigFactory::NotifyEvent(
- IXMLNodeSource* pSource,
- XML_NODEFACTORY_EVENT iEvt)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return S_OK;
-}
-
-HRESULT STDMETHODCALLTYPE MdaConfigFactory::Error(
- IXMLNodeSource* pSource,
- HRESULT hrErrorCode,
- USHORT cNumRecs,
- XML_NODE_INFO** apNodeInfo)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- return E_FAIL;
-}
-
-#endif
diff --git a/src/vm/mda.h b/src/vm/mda.h
index b52bd00d42..c711e8ae7f 100644
--- a/src/vm/mda.h
+++ b/src/vm/mda.h
@@ -295,7 +295,6 @@ private:
friend class MdaXmlMessage;
friend class MdaXmlIndustry;
friend class MdaConfigFactory;
- friend class EEConfigFactory;
friend class MdaFramework;
friend void EEStartupHelper(COINITIEE fFlags);
diff --git a/src/vm/mdadac.cpp b/src/vm/mdadac.cpp
deleted file mode 100644
index 95be6bff60..0000000000
--- a/src/vm/mdadac.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-// 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.
-
-
-#include "common.h"
-#include "mda.h"
-#include "mdaassistants.h"
-#include "sstring.h"
-#include "daccess.h"
-
-#ifdef MDA_SUPPORTED
-MdaStaticHeap g_mdaStaticHeap =
-{
- { 0 }, // m_assistants[]
- 0, // m_pMda
- { 0 }, // m_mda[]
-
-#define MDA_ASSISTANT_STATIC_INIT
-#include "mdaschema.inl"
-#undef MDA_ASSISTANT_STATIC_INIT
-};
-
-
-//
-// MdaManagedDebuggingAssistants
-//
-void ManagedDebuggingAssistants::AllocateManagedDebuggingAssistants()
-{
- WRAPPER_NO_CONTRACT;
- g_mdaStaticHeap.m_pMda = new (&g_mdaStaticHeap.m_mda) ManagedDebuggingAssistants();
-}
-
-ManagedDebuggingAssistants::ManagedDebuggingAssistants()
-{
- WRAPPER_NO_CONTRACT;
-
-#ifndef DACCESS_COMPILE
- Initialize();
-#endif
-}
-#endif // MDA_SUPPORTED
-
-
-
-
-
-
diff --git a/src/vm/message.cpp b/src/vm/message.cpp
deleted file mode 100644
index 093f9a2629..0000000000
--- a/src/vm/message.cpp
+++ /dev/null
@@ -1,1171 +0,0 @@
-// 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.
-
-/*============================================================
-**
-** File: message.cpp
-**
-** Purpose: Encapsulates a function call frame into a message
-** object with an interface that can enumerate the
-** arguments of the message
-**
-**
-
-===========================================================*/
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-
-#include "comdelegate.h"
-#include "excep.h"
-#include "message.h"
-#include "remoting.h"
-#include "field.h"
-#include "eeconfig.h"
-#include "invokeutil.h"
-#include "callingconvention.h"
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetArgCount public
-//
-// Synopsis: Returns number of arguments in the method call
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(INT32, CMessage::GetArgCount, MessageObject * pMessage)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(CheckPointer(pMessage));
- }
- CONTRACTL_END;
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount IN pMsg:0x%x\n", pMessage));
-
- // Get the frame pointer from the object
- MetaSig *pSig = pMessage->GetResetMetaSig();
-
- // scan the sig for the argument count
- INT32 ret = pSig->NumFixedArgs();
-
- if (pMessage->GetDelegateMD())
- ret -= 2;
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount OUT ret:0x%x\n", ret));
- return ret;
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetArg public
-//
-// Synopsis: Use to enumerate a call's arguments
-//
-//+----------------------------------------------------------------------------
-FCIMPL2(Object*, CMessage::GetArg, MessageObject* pMessageUNSAFE, INT32 argNum)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- struct _gc {
- OBJECTREF refRetVal;
- MESSAGEREF pMessage;
- } gc;
-
- gc.refRetVal = NULL;
- gc.pMessage = (MESSAGEREF) pMessageUNSAFE;
-
- HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount IN\n"));
-
- MetaSig *pSig = gc.pMessage->GetResetMetaSig();
-
- if ((UINT)argNum >= pSig->NumFixedArgs())
- COMPlusThrow(kTargetParameterCountException);
-
- for (INT32 i = 0; i < argNum; i++)
- pSig->NextArg();
-
- BOOL fIsByRef = FALSE;
- CorElementType eType = pSig->NextArg();
- TypeHandle ty = TypeHandle();
- if (eType == ELEMENT_TYPE_BYREF)
- {
- fIsByRef = TRUE;
- TypeHandle tycopy;
- eType = pSig->GetByRefType(&tycopy);
- if (eType == ELEMENT_TYPE_VALUETYPE)
- ty = tycopy;
- }
- else
- {
- if (eType == ELEMENT_TYPE_VALUETYPE)
- {
- ty = pSig->GetLastTypeHandleThrowing();
-
-#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
- if (ArgIterator::IsArgPassedByRef(ty))
- fIsByRef = TRUE;
-#endif
- }
- }
-
- if (eType == ELEMENT_TYPE_PTR)
- COMPlusThrow(kRemotingException, W("Remoting_CantRemotePointerType"));
-
- GetObjectFromStack(&gc.refRetVal,
- GetStackPtr(argNum, gc.pMessage->GetFrame(), gc.pMessage->GetResetMetaSig()),
- eType,
- ty,
- fIsByRef,
- gc.pMessage->GetFrame());
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArg OUT\n"));
-
- HELPER_METHOD_FRAME_END();
- return OBJECTREFToObject(gc.refRetVal);
-}
-FCIMPLEND
-
-FCIMPL1(Object*, CMessage::GetArgs, MessageObject* pMessageUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- struct _gc {
- PTRARRAYREF refRetVal;
- MESSAGEREF pMessage;
- OBJECTREF arg;
- } gc;
-
- gc.refRetVal = NULL;
- gc.pMessage = (MESSAGEREF) pMessageUNSAFE;
- gc.arg = NULL;
-
- HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgCount IN\n"));
-
- MetaSig *pSig = gc.pMessage->GetResetMetaSig();
-
- // scan the sig for the argument count
- INT32 numArgs = pSig->NumFixedArgs();
- if (gc.pMessage->GetDelegateMD())
- numArgs -= 2;
-
- // Allocate an object array
- gc.refRetVal = (PTRARRAYREF) AllocateObjectArray(numArgs, g_pObjectClass);
-
- ArgIterator iter(pSig);
-
- for (int index = 0; index < numArgs; index++)
- {
- BOOL fIsByRef = FALSE;
- CorElementType eType;
- PVOID addr;
- eType = pSig->PeekArg();
- addr = (LPBYTE) gc.pMessage->GetFrame()->GetTransitionBlock() + GetStackOffset(gc.pMessage->GetFrame(), &iter, pSig);
-
- TypeHandle ty = TypeHandle();
- if (eType == ELEMENT_TYPE_BYREF)
- {
- fIsByRef = TRUE;
- TypeHandle tycopy;
- // If this is a by-ref arg, GetObjectFromStack() will dereference "addr" to
- // get the real argument address. Dereferencing now will open a gc hole if "addr"
- // points into the gc heap, and we trigger gc between here and the point where
- // we return the arguments.
- //addr = *((PVOID *) addr);
- eType = pSig->GetByRefType(&tycopy);
- if (eType == ELEMENT_TYPE_VALUETYPE)
- ty = tycopy;
- }
- else
- {
- if (eType == ELEMENT_TYPE_VALUETYPE)
- {
- ty = pSig->GetLastTypeHandleThrowing();
-
-#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
- if (ArgIterator::IsArgPassedByRef(ty))
- fIsByRef = TRUE;
-#endif
- }
- }
-
- if (eType == ELEMENT_TYPE_PTR)
- COMPlusThrow(kRemotingException, W("Remoting_CantRemotePointerType"));
-
- GetObjectFromStack(&gc.arg,
- addr,
- eType,
- ty,
- fIsByRef,
- gc.pMessage->GetFrame());
-
- gc.refRetVal->SetAt(index, gc.arg);
- }
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetArgs OUT\n"));
-
- HELPER_METHOD_FRAME_END();
- return OBJECTREFToObject(gc.refRetVal);
-}
-FCIMPLEND
-
-//static
-void CMessage::GetObjectFromStack(OBJECTREF* ppDest, PVOID val, const CorElementType eType, TypeHandle ty, BOOL fIsByRef, FramedMethodFrame *pFrame)
-{
- CONTRACT_VOID
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(CheckPointer(ppDest));
- PRECONDITION(CheckPointer(val));
- }
- CONTRACT_END;
-
- // Value types like Nullable<T> have special unboxing semantics,
- //
- if (eType == ELEMENT_TYPE_VALUETYPE)
- {
- //
- // box the value class
- //
-
- _ASSERTE(ty.GetMethodTable()->IsValueType() || ty.GetMethodTable()->IsEnum());
-
- _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((BYTE *) ppDest) ||
- !"(pDest) can not point to GC Heap");
- MethodTable* pMT = ty.GetMethodTable();
-
- if (pMT->IsByRefLike())
- COMPlusThrow(kRemotingException, W("Remoting_TypeCantBeRemoted"));
-
- PVOID* pVal;
- if (fIsByRef)
- pVal = (PVOID *)val;
- else {
- val = StackElemEndianessFixup(val, pMT->GetNumInstanceFieldBytes());
- pVal = &val;
- }
-
- *ppDest = pMT->FastBox(pVal);
- RETURN;
- }
-
- switch (CorTypeInfo::GetGCType(eType))
- {
- case TYPE_GC_NONE:
- {
- if(ELEMENT_TYPE_PTR == eType)
- {
- COMPlusThrow(kNotSupportedException);
- }
-
- MethodTable *pMT = MscorlibBinder::GetElementType(eType);
-
- OBJECTREF pObj = pMT->Allocate();
- if (fIsByRef)
- val = *((PVOID *)val);
- else
- val = StackElemEndianessFixup(val, CorTypeInfo::Size(eType));
-
- void *pDest = pObj->UnBox();
-
-#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
- if ( !fIsByRef
- && ( ELEMENT_TYPE_R4 == eType
- || ELEMENT_TYPE_R8 == eType)
- && pFrame
- && !TransitionBlock::IsStackArgumentOffset(static_cast<int>((TADDR) val - pFrame->GetTransitionBlock())))
- {
- if (ELEMENT_TYPE_R4 == eType)
- *(UINT32*)pDest = (UINT32)FPSpillToR4(val);
- else
- *(UINT64*)pDest = (UINT64)FPSpillToR8(val);
- }
- else
-#endif // COM_STUBS_SEPARATE_FP_LOCATIONS
- {
- memcpyNoGCRefs(pDest, val, CorTypeInfo::Size(eType));
- }
-
- *ppDest = pObj;
- }
- break;
- case TYPE_GC_REF:
- if (fIsByRef)
- val = *((PVOID *)val);
- *ppDest = ObjectToOBJECTREF(*(Object **)val);
- break;
- default:
- COMPlusThrow(kRemotingException, W("Remoting_TypeCantBeRemoted"));
- }
-
- RETURN;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::PropagateOutParameters private
-//
-// Synopsis: Copy back data for in/out parameters and the return value
-//
-//+----------------------------------------------------------------------------
-FCIMPL3(void, CMessage::PropagateOutParameters, MessageObject* pMessageUNSAFE, ArrayBase* pOutPrmsUNSAFE, Object* RetValUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- struct _gc
- {
- MESSAGEREF pMessage;
- BASEARRAYREF pOutPrms;
- OBJECTREF RetVal;
- OBJECTREF param;
- } gc;
- gc.pMessage = (MESSAGEREF) pMessageUNSAFE;
- gc.pOutPrms = (BASEARRAYREF) pOutPrmsUNSAFE;
- gc.RetVal = (OBJECTREF) RetValUNSAFE;
- gc.param = NULL;
- HELPER_METHOD_FRAME_BEGIN_PROTECT(gc);
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::PropogateOutParameters IN\n"));
-
- // Retrieve the message's flags.
- INT32 flags = gc.pMessage->GetFlags();
-
- // Construct an ArgIterator from the message's frame and sig.
- MetaSig *pSig = gc.pMessage->GetResetMetaSig();
- FramedMethodFrame *pFrame = gc.pMessage->GetFrame();
- ArgIterator argit(pSig);
-
- // move into object to return to client
-
- // Propagate the return value only if the pMsg is not a Ctor message
- // Check if the return type has a return buffer associated with it
- if ((flags& MSGFLG_CTOR) == 0 && pSig->GetReturnType() != ELEMENT_TYPE_VOID)
- {
- if (argit.HasRetBuffArg())
- {
- // Copy from RetVal into the retBuff.
- INT64 retVal = CopyOBJECTREFToStack(
- *(void**)(pFrame->GetTransitionBlock() + argit.GetRetBuffArgOffset()),
- &gc.RetVal,
- pSig->GetReturnType(),
- TypeHandle(),
- pSig,
- TRUE); // copy class contents
-
- // Copy the return value
- *(ARG_SLOT *)(gc.pMessage->GetFrame()->GetReturnValuePtr()) = retVal;
- }
- else
- {
-#ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
- if (argit.HasNonStandardByvalReturn())
- {
- //
- // in these cases, we put the pointer to the return buffer into the frame's
- // return value slot
- //
- CopyOBJECTREFToStack(gc.pMessage->GetFrame()->GetReturnValuePtr(),
- &gc.RetVal,
- pSig->GetReturnType(),
- TypeHandle(),
- pSig,
- TRUE); // copy class contents
- }
- else
-#endif // ENREGISTERED_RETURNTYPE_MAXSIZE
- {
- // There is no separate return buffer, the retVal should fit in
- // an INT64.
- INT64 retVal = CopyOBJECTREFToStack(
- NULL, //no return buff
- &gc.RetVal,
- pSig->GetReturnType(),
- TypeHandle(),
- pSig,
- FALSE); //don't copy class contents
-
- // Copy the return value
- *(ARG_SLOT *)(gc.pMessage->GetFrame()->GetReturnValuePtr()) = retVal;
- }
- }
- }
-
- // Refetch all the variables as GC could have happened after call to
- // CopyOBJECTREFToStack
- UINT32 cOutParams = (gc.pOutPrms != NULL) ? gc.pOutPrms->GetNumComponents() : 0;
- if (cOutParams > 0)
- {
- PVOID *argAddr;
- UINT32 i = 0;
- MetaSig syncSig(gc.pMessage->GetMethodDesc());
- MetaSig *pSyncSig = NULL;
-
- if (flags & MSGFLG_ENDINVOKE)
- {
- pSyncSig = &syncSig;
- }
-
- for (i=0; i<cOutParams; i++)
- {
- if (pSyncSig)
- {
- CorElementType typ = pSyncSig->NextArg();
- if (typ == ELEMENT_TYPE_END)
- {
- break;
- }
-
- if (typ != ELEMENT_TYPE_BYREF)
- {
- continue;
- }
-
- argAddr = (PVOID *)(pFrame->GetTransitionBlock() + argit.GetNextOffset());
- }
- else
- {
- int ofs = argit.GetNextOffset();
- if (ofs == TransitionBlock::InvalidOffset)
- {
- break;
- }
-
- if (argit.GetArgType() != ELEMENT_TYPE_BYREF)
- {
- continue;
- }
-
- argAddr = (PVOID *)(pFrame->GetTransitionBlock() + ofs);
- }
-
- TypeHandle ty = TypeHandle();
- CorElementType brType = pSig->GetByRefType(&ty);
-
- gc.param = ((OBJECTREF *) gc.pOutPrms->GetDataPtr())[i];
-
- CopyOBJECTREFToStack(
- *argAddr,
- &gc.param,
- brType,
- ty,
- pSig,
- ty.IsNull() ? FALSE : ty.IsValueType());
- }
-
- }
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-INT64 CMessage::CopyOBJECTREFToStack(PVOID pvDest, OBJECTREF *pSrc, CorElementType typ, TypeHandle ty, MetaSig *pSig, BOOL fCopyClassContents)
-{
- INT64 ret = 0;
-
- CONTRACT(INT64)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(CheckPointer(pvDest, NULL_OK));
- PRECONDITION(CheckPointer(pSrc));
- PRECONDITION(typ != ELEMENT_TYPE_VOID);
- PRECONDITION(CheckPointer(pSig));
- }
- CONTRACT_END;
-
- if (fCopyClassContents)
- {
- // We have to copy the contents of a value class to pvDest
-
- // write unboxed version back to memory provided by the client
- if (pvDest)
- {
- if (ty.IsNull())
- ty = pSig->GetRetTypeHandleThrowing();
-
- if (*pSrc == NULL && !Nullable::IsNullableType(ty))
- COMPlusThrow(kRemotingException, W("Remoting_Message_BadRetValOrOutArg"));
-
- ty.GetMethodTable()->UnBoxIntoUnchecked(pvDest, *pSrc);
-
- // return the object so it can be stored in the frame and
- // propagated to the root set
- // pSrc may not be doubleword aligned!
- *(OBJECTREF*)&ret = *pSrc;
- }
- }
- else
- {
- // We have either a real OBJECTREF or something that does not have
- // a return buffer associated
-
- // Check if it is an ObjectRef (from the GC heap)
- if (CorTypeInfo::IsObjRef(typ))
- {
- if ((*pSrc!=NULL) && ((*pSrc)->IsTransparentProxy()))
- {
- if (ty.IsNull())
- ty = pSig->GetRetTypeHandleThrowing();
-
- // CheckCast ensures that the returned object (proxy) gets
- // refined to the level expected by the caller of the method
- if (!CRemotingServices::CheckCast(*pSrc, ty))
- COMPlusThrow(kInvalidCastException, W("Arg_ObjObj"));
- }
- if (pvDest)
- SetObjectReferenceUnchecked((OBJECTREF *)pvDest, *pSrc);
-
- // pSrc may not be double-word aligned!
- *(OBJECTREF*)&ret = *pSrc;
- }
- else
- {
- // Note: this assert includes VALUETYPE because for Enums
- // HasRetBuffArg() returns false since the normalized type is I4
- // so we end up here ... but GetReturnType() returns VALUETYPE
- // Almost all VALUETYPEs will go through the fCopyClassContents
- // codepath instead of here.
- // Also, IsPrimitiveType() does not check for IntPtr, UIntPtr etc
- // there is a note in siginfo.hpp about that ... hence we have
- // ELEMENT_TYPE_I, ELEMENT_TYPE_U.
- _ASSERTE(
- CorTypeInfo::IsPrimitiveType(typ)
- || (typ == ELEMENT_TYPE_VALUETYPE)
- || (typ == ELEMENT_TYPE_I)
- || (typ == ELEMENT_TYPE_U)
- || (typ == ELEMENT_TYPE_FNPTR)
- );
-
- // REVIEW: For a "ref int" arg, if a nasty sink replaces the boxed
- // int with a null OBJECTREF, this is where we check. We need to be
- // uniform in our policy w.r.t. this (throw v/s ignore)
- // The 'if' block above throws, CallFieldAccessor also has this
- // problem.
- if (*pSrc != NULL)
- {
- PVOID pvSrcData = (*pSrc)->GetData();
- int cbsize = gElementTypeInfo[typ].m_cbSize;
- INT64 retBuff;
-
- // ElementTypeInfo.m_cbSize can be less that zero for cases that need
- // special handling (e.g. value types) to be sure of size (see
- // siginfo.cpp). Luckily, the type handle has the actual byte count,
- // so we look there for such cases.
- if (cbsize < 0)
- {
- if (ty.IsNull())
- ty = pSig->GetRetTypeHandleThrowing();
-
- _ASSERTE(!ty.IsNull());
- cbsize = ty.GetSize();
-
- // we are returning this value class in an INT64 so it better be small enough
- _ASSERTE(cbsize <= (int) sizeof(INT64));
- // Unbox it into a local buffer, This coveres the Nullable<T> case
- // then do the endianness morph below
- ty.GetMethodTable()->UnBoxIntoUnchecked(&retBuff, *pSrc);
-
- pvSrcData = &retBuff;
- }
-
- if (pvDest)
- {
- memcpyNoGCRefs(pvDest, pvSrcData, cbsize);
- }
-
- // need to sign-extend signed types
- bool fEndianessFixup = false;
- switch (typ) {
- case ELEMENT_TYPE_I1:
- ret = *(INT8*)pvSrcData;
- fEndianessFixup = true;
- break;
- case ELEMENT_TYPE_I2:
- ret = *(INT16*)pvSrcData;
- fEndianessFixup = true;
- break;
- case ELEMENT_TYPE_I4:
- ret = *(INT32*)pvSrcData;
- fEndianessFixup = true;
- break;
- default:
- memcpyNoGCRefs(StackElemEndianessFixup(&ret, cbsize), pvSrcData, cbsize);
- break;
- }
-
-#if !defined(_WIN64) && BIGENDIAN
- if (fEndianessFixup)
- ret <<= 32;
-#endif
- }
- }
- }
-
- RETURN(ret);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetReturnValue
-//
-// Synopsis: Pull return value off the stack
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(Object*, CMessage::GetReturnValue, MessageObject* pMessageUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- struct _gc {
- OBJECTREF refRetVal;
- MESSAGEREF pMessage;
- } gc;
-
- gc.refRetVal = NULL;
- gc.pMessage = (MESSAGEREF) pMessageUNSAFE;
-
- HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
- MetaSig* pSig = gc.pMessage->GetResetMetaSig();
- FramedMethodFrame* pFrame = gc.pMessage->GetFrame();
-
- ArgIterator argit(pSig);
-
- PVOID pvRet;
- if (argit.HasRetBuffArg())
- {
- pvRet = *(PVOID *)(pFrame->GetTransitionBlock() + argit.GetRetBuffArgOffset());
- }
- else
- {
- pvRet = pFrame->GetReturnValuePtr();
- }
-
- CorElementType eType = pSig->GetReturnType();
- TypeHandle ty;
- if (eType == ELEMENT_TYPE_VALUETYPE)
- {
- ty = pSig->GetRetTypeHandleThrowing();
- }
- else
- {
- ty = TypeHandle();
- }
-
- GetObjectFromStack(&gc.refRetVal,
- pvRet,
- eType,
- ty);
-
- HELPER_METHOD_FRAME_END();
- return OBJECTREFToObject(gc.refRetVal);
-}
-FCIMPLEND
-
-
-
-FCIMPL2(FC_BOOL_RET, CMessage::Dispatch, MessageObject* pMessageUNSAFE, Object* pServerUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- PRECONDITION(pServerUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- BOOL fDispatched = FALSE;
- MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE;
- OBJECTREF pServer = (OBJECTREF) pServerUNSAFE;
- HELPER_METHOD_FRAME_BEGIN_RET_2(pMessage, pServer);
-
- MetaSig *pSig = pMessage->GetResetMetaSig();
-
- if (pMessage->GetFlags() & (MSGFLG_BEGININVOKE | MSGFLG_ENDINVOKE | MSGFLG_ONEWAY))
- {
- fDispatched = FALSE;
- goto lExit;
- }
-
- {
- ArgIterator argit(pSig);
-
- UINT nStackBytes;
- MethodDesc *pMD;
- PCODE pTarget;
-
- nStackBytes = argit.SizeOfFrameArgumentArray();
- pMD = pMessage->GetMethodDesc();
-
- // Get the address of the code
- pTarget = pMD->GetCallTarget(&(pServer));
-
-#ifdef PROFILING_SUPPORTED
- // If we're profiling, notify the profiler that we're about to invoke the remoting target
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationStarted();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
-#ifdef CALLDESCR_FPARGREGS
- // @TODO: This code badly needs refactorization. It's largely shared with MethodDesc::CallDescr in
- // method.cpp and CallDescrWithObjectArray in stackbuildersync.cpp.
-
- FloatArgumentRegisters *pFloatArgumentRegisters = NULL;
-
- // Iterate through all the args looking for floating point values that will be passed in (FP) argument
- // registers.
- int ofs;
- while ((ofs = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
- {
- if (TransitionBlock::HasFloatRegister(ofs, argit.GetArgLocDescForStructInRegs()))
- {
- // Found a floating point argument register. The first time we find this we point
- // pFloatArgumentRegisters to the part of the frame where these values were spilled (we don't do
- // this unconditionally since the call worker can optimize out the copy of the floating point
- // registers if none are involved at all.
- pFloatArgumentRegisters = (FloatArgumentRegisters*)(pMessage->GetFrame()->GetTransitionBlock() +
- TransitionBlock::GetOffsetOfFloatArgumentRegisters());
-
- // That's all we need to do, CallDescrWorkerWithHandler will automatically pick up all the
- // floating point argument values now.
- break;
- }
- }
-#endif // CALLDESCR_FPARGREGS
-
-#if defined(CALLDESCR_REGTYPEMAP) || defined(COM_STUBS_SEPARATE_FP_LOCATIONS)
- DWORD_PTR dwRegTypeMap = 0;
-
- {
- int ofs;
- while ((ofs = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
- {
- int regArgNum = TransitionBlock::GetArgumentIndexFromOffset(ofs);
-
- if (regArgNum >= NUM_ARGUMENT_REGISTERS)
- break;
-
- CorElementType argTyp = argit.GetArgType();
-
-#ifdef CALLDESCR_REGTYPEMAP
- FillInRegTypeMap(ofs, argTyp, (BYTE*)&dwRegTypeMap);
-#endif
-
-#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
- // If this is a floating point argument, it was stored in a
- // separate area of the frame. Copy it into the argument array.
- if (ELEMENT_TYPE_R4 == argTyp || ELEMENT_TYPE_R8 == argTyp)
- {
- TADDR pTransitionBlock = pMessage->GetFrame()->GetTransitionBlock();
-
- PVOID pDest = (PVOID)(pTransitionBlock + ofs);
- PVOID pSrc = (PVOID)(pTransitionBlock + pMessage->GetFrame()->GetFPArgOffset(regArgNum));
-
- ARG_SLOT val;
- if (ELEMENT_TYPE_R4 == argTyp)
- val = FPSpillToR4(pSrc);
- else
- val = FPSpillToR8(pSrc);
-
- *(ARG_SLOT*)pDest = val;
- }
-#endif
- }
- }
-#endif // CALLDESCR_REGTYPEMAP || COM_STUBS_SEPARATE_FP_LOCATIONS
-
- CallDescrData callDescrData;
-
- callDescrData.pSrc = (BYTE*)pMessage->GetFrame()->GetTransitionBlock() + sizeof(TransitionBlock);
- callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE;
-#ifdef CALLDESCR_ARGREGS
- callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pMessage->GetFrame()->GetTransitionBlock() + TransitionBlock::GetOffsetOfArgumentRegisters());
-#endif
-#ifdef CALLDESCR_FPARGREGS
- callDescrData.pFloatArgumentRegisters = pFloatArgumentRegisters;
-#endif
-#ifdef CALLDESCR_REGTYPEMAP
- callDescrData.dwRegTypeMap = dwRegTypeMap;
-#endif
- callDescrData.fpReturnSize = argit.GetFPReturnSize();
- callDescrData.pTarget = pTarget;
-
- CallDescrWorkerWithHandler(&callDescrData);
-
-#ifdef PROFILING_SUPPORTED
- // If we're profiling, notify the profiler that we're about to invoke the remoting target
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationReturned();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
-
- memcpyNoGCRefs(pMessage->GetFrame()->GetReturnValuePtr(), &callDescrData.returnValue, sizeof(callDescrData.returnValue));
-
- fDispatched = TRUE;
- }
-
-lExit: ;
- HELPER_METHOD_FRAME_END();
- FC_RETURN_BOOL(fDispatched);
-}
-FCIMPLEND
-
-void CMessage::AppendAssemblyName(CQuickBytes &out, const CHAR* str)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(CheckPointer(str));
- }
- CONTRACTL_END;
-
- SIZE_T len = strlen(str) * sizeof(CHAR);
- SIZE_T oldSize = out.Size();
- out.ReSizeThrows(oldSize + len + 2);
- CHAR * cur = (CHAR *) ((BYTE *) out.Ptr() + oldSize - 1);
- if (*cur)
- cur++;
-
- *cur = ASSEMBLY_SEPARATOR_CHAR;
- memcpy(cur + 1, str, len);
- cur += (len + 1);
- *cur = '\0';
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetAsyncBeginInfo
-//
-// Synopsis: Pull the AsyncBeginInfo object from an async call
-//
-//+----------------------------------------------------------------------------
-FCIMPL3(void, CMessage::GetAsyncBeginInfo, MessageObject* pMessageUNSAFE, OBJECTREF* ppACBD, OBJECTREF* ppState)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE;
- _ASSERTE(pMessage->GetFlags() & MSGFLG_BEGININVOKE);
-
- HELPER_METHOD_FRAME_BEGIN_1(pMessage);
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetAsyncBeginInfo IN\n"));
-
- if (pMessage == NULL)
- COMPlusThrow(kNullReferenceException, W("NullReference_This"));
-
- MetaSig *pSig = pMessage->GetResetMetaSig();
-
- FramedMethodFrame * pFrame = pMessage->GetFrame();
- ArgIterator argit(pSig);
-
- if ((ppACBD != NULL) || (ppState != NULL))
- {
- int ofs;
- int last = TransitionBlock::InvalidOffset, secondtolast = TransitionBlock::InvalidOffset;
- while ((ofs = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
- {
- secondtolast = last;
- last = ofs;
- }
- _ASSERTE(secondtolast != TransitionBlock::InvalidOffset);
- if (secondtolast != TransitionBlock::InvalidOffset && ppACBD != NULL)
- SetObjectReferenceUnchecked(ppACBD, ObjectToOBJECTREF(*(Object **)(pFrame->GetTransitionBlock() + secondtolast)));
- PREFIX_ASSUME(last != TransitionBlock::InvalidOffset);
- if (ppState != NULL)
- SetObjectReferenceUnchecked(ppState, ObjectToOBJECTREF(*(Object **)(pFrame->GetTransitionBlock() + last)));
- }
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetAsyncResult
-//
-// Synopsis: Pull the AsyncResult from an async call
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(LPVOID, CMessage::GetAsyncResult, MessageObject* pMessageUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- LPVOID retVal = NULL;
- MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE;
- _ASSERTE(pMessage->GetFlags() & MSGFLG_ENDINVOKE);
-
- HELPER_METHOD_FRAME_BEGIN_RET_1(pMessage);
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetAsyncResult IN\n"));
-
- retVal = GetLastArgument(&pMessage);
-
- HELPER_METHOD_FRAME_END();
- return retVal;
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetAsyncObject
-//
-// Synopsis: Pull the AsyncObject from an async call
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(Object*, CMessage::GetAsyncObject, MessageObject* pMessageUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pMessageUNSAFE != NULL);
- }
- CONTRACTL_END;
-
- Object* pobjRetVal = NULL;
- MESSAGEREF pMessage = (MESSAGEREF) pMessageUNSAFE;
- HELPER_METHOD_FRAME_BEGIN_RET_1(pMessage);
-
- LOG((LF_REMOTING, LL_INFO10, "CMessage::GetAsyncObject IN\n"));
-
- FramedMethodFrame *pFrame = pMessage->GetFrame();
- MetaSig *pSig = pMessage->GetResetMetaSig();
- ArgIterator argit(pSig);
-
- pobjRetVal = *(Object**)(pFrame->GetTransitionBlock() + argit.GetThisOffset());
-
- HELPER_METHOD_FRAME_END();
- return pobjRetVal;
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetLastArgument private
-//
-// Synopsis: Pull the last argument of 4 bytes off the stack
-//
-//+----------------------------------------------------------------------------
-LPVOID CMessage::GetLastArgument(MESSAGEREF *pMsg)
-{
- CONTRACT(LPVOID)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pMsg));
- POSTCONDITION(*pMsg != NULL); // CheckPointer doesn't seem to work here.
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- FramedMethodFrame *pFrame = (*pMsg)->GetFrame();
- MetaSig *pSig = (*pMsg)->GetResetMetaSig();
-
- ArgIterator argit(pSig);
- int arg;
- int backadder = TransitionBlock::InvalidOffset;
- while ((arg = argit.GetNextOffset()) != TransitionBlock::InvalidOffset)
- backadder = arg;
-
- _ASSERTE(backadder != TransitionBlock::InvalidOffset);
-
- RETURN *(LPVOID *)(pFrame->GetTransitionBlock() + backadder);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::DebugOut public
-//
-// Synopsis: temp Debug out until the classlibs have one.
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(void, CMessage::DebugOut, StringObject* pOutUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(pOutUNSAFE != NULL);
- }
- CONTRACTL_END;
-
-#ifdef _DEBUG
- STRINGREF pOut = (STRINGREF) pOutUNSAFE;
- HELPER_METHOD_FRAME_BEGIN_1(pOut);
-
- static int fMessageDebugOut = 0;
-
- if (fMessageDebugOut == 0)
- fMessageDebugOut = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_MessageDebugOut) ? 1 : -1;
-
- if (fMessageDebugOut == 1)
- WszOutputDebugString(pOut->GetBuffer());
-
- HELPER_METHOD_FRAME_END();
-#endif
-
- FCUnique(0x76);
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::HasVarArgs public
-//
-// Synopsis: Return TRUE if the method is a VarArgs Method
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(FC_BOOL_RET, CMessage::HasVarArgs, MessageObject * pMessage)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(CheckPointer(pMessage));
- }
- CONTRACTL_END;
-
- BOOL result;
-
- // Need entire path to be SO_TOLERANT or put a Hard SO probe here as
- // no failure path.
- CONTRACT_VIOLATION(SOToleranceViolation);
-
- result = pMessage->GetMethodDesc()->IsVarArg();
-
- FC_RETURN_BOOL(result);
-}
-FCIMPLEND
-
-
-//static
-int CMessage::GetStackOffset (FramedMethodFrame *pFrame, ArgIterator *pArgIter, MetaSig *pSig)
-{
- CONTRACT(int)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(CheckPointer(pFrame));
- PRECONDITION(CheckPointer(pArgIter));
- PRECONDITION(CheckPointer(pSig));
- }
- CONTRACT_END;
-
- LOG((LF_REMOTING, LL_INFO100,
- "CMessage::GetStackOffset pFrame:0x%x, pArgIter:0x%x\n",
- pFrame, pArgIter));
-
- int ret = pArgIter->GetNextOffset();
-
-#ifdef COM_STUBS_SEPARATE_FP_LOCATIONS
- int typ = pArgIter->GetArgType();
- // REVISIT_TODO do we need to handle this?
- if ((ELEMENT_TYPE_R4 == typ || ELEMENT_TYPE_R8 == typ) &&
- TransitionBlock::IsArgumentRegisterOffset(ret))
- {
- int iFPArg = TransitionBlock::GetArgumentIndexFromOffset(ret);
-
- ret = static_cast<int>(pFrame->GetFPArgOffset(iFPArg));
- }
-#endif // COM_STUBS_SEPARATE_FP_LOCATIONS
-
- RETURN ret;
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CMessage::GetStackPtr private
-//
-// Synopsis: Figure out where on the stack a parameter is stored
-//
-// Parameters: ndx - the parameter index (zero-based)
-// pFrame - stack frame pointer (FramedMethodFrame)
-// pSig - method signature, used to determine parameter sizes
-//
-//
-//<REVISIT_TODO>
-// CODEWORK: Currently we assume all parameters to be 32-bit intrinsics
-// or 32-bit pointers. Value classes are not handled correctly.
-//</REVISIT_TODO>
-//+----------------------------------------------------------------------------
-PVOID CMessage::GetStackPtr(INT32 ndx, FramedMethodFrame *pFrame, MetaSig *pSig)
-{
- CONTRACT(PVOID)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(CheckPointer(pFrame));
- PRECONDITION(CheckPointer(pSig));
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- LOG((LF_REMOTING, LL_INFO100,
- "CMessage::GetStackPtr IN ndx:0x%x, pFrame:0x%x, pSig:0x%x\n",
- ndx, pFrame, pSig));
-
- ArgIterator iter(pSig);
- PVOID ret = NULL;
-
- // <REVISIT_TODO>CODEWORK:: detect and optimize for sequential access</REVISIT_TODO>
- _ASSERTE((UINT)ndx < pSig->NumFixedArgs());
- for (int i=0; i<=ndx; i++)
- ret = (BYTE*)pFrame->GetTransitionBlock() + GetStackOffset(pFrame, &iter, pSig);
-
- RETURN ret;
-}
-
-#endif //FEATURE_REMOTING
diff --git a/src/vm/mixedmode.cpp b/src/vm/mixedmode.cpp
deleted file mode 100644
index 32d4368363..0000000000
--- a/src/vm/mixedmode.cpp
+++ /dev/null
@@ -1,236 +0,0 @@
-// 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.
-// ===========================================================================
-// File: MIXEDMODE.CPP
-//
-
-//
-
-// MIXEDMODE deals with mixed-mode binaries support
-// ===========================================================================
-
-
-
-#include "common.h"
-
-#include "mixedmode.hpp"
-
-#include "dllimportcallback.h"
-
-#ifdef FEATURE_MIXEDMODE
-
-
-IJWNOADThunk::IJWNOADThunk(HMODULE pModulebase, DWORD dwIndex, mdToken Token)
-{
- LIMITED_METHOD_CONTRACT;
- m_pModulebase=pModulebase;
- m_dwIndex=dwIndex;
- m_Token=Token;
- m_fAccessingCache = 0;
-
- for (int i=0; i < IJWNOADThunkStubCacheSize; i++)
- {
- m_cache[i].m_AppDomainID = (ADID)-1;
- m_cache[i].m_CodeAddr = 0;
- }
-
-#ifdef _TARGET_X86_
- m_code.Encode((BYTE*)GetEEFuncEntryPoint(IJWNOADThunkJumpTarget), this);
-#else // !_TARGET_X86_
- m_code.Encode((BYTE*)GetEEFuncEntryPoint(MakeCall), this);
-#endif // !_TARGET_X86_
-};
-
-#define E_PROCESS_SHUTDOWN_REENTRY HRESULT_FROM_WIN32(ERROR_PROCESS_ABORTED)
-
-
-#ifdef _TARGET_X86_
-// Slow path lookup...called from stub
-extern "C" LPCVOID __stdcall IJWNOADThunkJumpTargetHelper(IJWNOADThunk* pThunk)
-{
- WRAPPER_NO_CONTRACT;
-
- return pThunk->FindThunkTarget();
-}
-#endif // _TARGET_X86_
-
-LPCVOID IJWNOADThunk::FindThunkTarget()
-{
- CONTRACT(LPCVOID)
- {
- INSTANCE_CHECK;
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- SO_TOLERANT;
- POSTCONDITION(CheckPointer(RETVAL));
- }
- CONTRACT_END;
-
- // We don't plan on fixing this in Whidbey...the IJW scenario has always assumed throwing is "ok" here.
- CONTRACT_VIOLATION(ThrowsViolation);
-
- LPCVOID pvTargetCode = NULL;
-
- AppDomain* pDomain;
-
- Thread* pThread = SetupThread();
-
- // Ensure that we're in preemptive mode.
- // We only need this check for a newly created
- // CLR thread - it defaults to COOP mode from here.
- GCX_PREEMP_NO_DTOR();
-
- pDomain = GetAppDomain();
-
- if (NULL == pDomain)
- {
- _ASSERTE(!"Appdomain should've been set up by SetupThread");
- pDomain = SystemDomain::System()->DefaultDomain();
- }
-
-
- if (NULL != pDomain)
- {
- // Get a local copy so we don't have to deal with a race condition.
- LPCVOID pCacheTarget = NULL;
- GetCachedInfo(pDomain->GetId(), &pvTargetCode);
-
- // Cache miss.
- if (pvTargetCode==NULL)
- {
- INSTALL_UNWIND_AND_CONTINUE_HANDLER;
- BEGIN_SO_INTOLERANT_CODE(pThread);
- {
- Module* pModule;
-
- pModule = pDomain->GetIJWModule(m_pModulebase);
- if (NULL == pModule)
- {
- // New for Whidbey: In V1.1, we just gave up and raised an exception if the target assembly wasn't already loaded
- // into the current appdomain. We now force-inject the assembly.
-
- PEAssemblyHolder pFile(pDomain->BindExplicitAssembly(m_pModulebase, FALSE));
- pDomain->LoadAssembly(NULL, pFile, FILE_ACTIVE);
-
- // Now, try the lookup again. The LoadAssembly() either worked or it didn't. If it didn't, it is probably
- // due to lack of memory and all we can do is raise an exception and hope the IJW caller does something reasonable.
- // Otherwise, we should now succeed in finding the current domain's instantiation of the target module.
- pModule = pDomain->GetIJWModule(m_pModulebase);
- }
-
- if (NULL != pModule)
- {
- pModule->EnsureActive();
-
- UMEntryThunk* pThunkTable;
-
- pThunkTable = pModule->GetADThunkTable();
- pvTargetCode = (LPVOID)GetEEFuncEntryPoint((LPVOID)pThunkTable[m_dwIndex].GetCode());
-
- // Populate the cache with our latest info.
- SetCachedInfo(pDomain->GetId(), pvTargetCode);
- }
- }
- END_SO_INTOLERANT_CODE;
- UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
- }
- }
-
- if(pvTargetCode==NULL)
- pvTargetCode=(LPVOID)GetEEFuncEntryPoint(SafeNoModule);
-
- RETURN (LPCVOID)pvTargetCode;
-}
-
-#ifdef _TARGET_X86_
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning (disable : 4740) // There is inline asm code in this function, which disables
- // global optimizations.
-#endif // _MSC_VER
-
-__declspec(naked) void _cdecl IJWNOADThunk::MakeCall()
-{
- WRAPPER_NO_CONTRACT;
- struct
- {
- LPVOID This;
- LPCVOID RetAddr;
- } Vars;
- #define LocalsSize 8
-
- _asm enter LocalsSize+4,0;
- _asm push ebx;
- _asm push ecx;
- _asm push edx;
- _asm push esi;
- _asm push edi;
-
- _asm mov Vars.This, eax;
-
- //careful above this point
- _ASSERTE(sizeof(Vars)<=LocalsSize);
-
- Vars.RetAddr = ((IJWNOADThunk*)Vars.This)->FindThunkTarget();
-
- _ASSERTE(NULL != Vars.RetAddr);
-
- _asm pop edi;
- _asm pop esi;
- _asm pop edx;
- _asm pop ecx;
- _asm pop ebx;
- _asm mov eax,Vars.RetAddr;
- _asm leave;
- _asm jmp eax;
-};
-
-#if defined(_MSC_VER)
-#pragma warning(pop)
-#endif
-
-#elif defined(_TARGET_AMD64_)
-// Implemented in AMD64\UMThunkStub.asm
-#elif defined(_TARGET_ARM_)
-// Implemented in Arm\asmhelpers.asm
-#else
-void __cdecl IJWNOADThunk::MakeCall()
-{
- LIMITED_METHOD_CONTRACT;
- PORTABILITY_ASSERT("IJWNOADThunk::MakeCall");
-}
-#endif
-
-void IJWNOADThunk::SafeNoModule()
-{
- STATIC_CONTRACT_THROWS;
- STATIC_CONTRACT_GC_TRIGGERS;
-
- if (!CanRunManagedCode())
- {
- Thread* pThread=GetThread();
-
- // DO NOT IMPROVE THIS EXCEPTION! It cannot be a managed exception. It
- // cannot be a real exception object because we cannot execute any managed
- // code here.
- if(pThread)
- pThread->m_fPreemptiveGCDisabled = 0;
- COMPlusThrowBoot(E_PROCESS_SHUTDOWN_REENTRY);
- }
- NoModule();
-}
-
-void IJWNOADThunk::NoModule()
-{
- WRAPPER_NO_CONTRACT;
- INSTALL_UNWIND_AND_CONTINUE_HANDLER;
- //<TODO>This should give the file name as part of the exception message!</TODO>
- COMPlusThrowHR(COR_E_DLLNOTFOUND);
- UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
-}
-
-#endif // FEATURE_MIXEDMODE
-
diff --git a/src/vm/mixedmode.hpp b/src/vm/mixedmode.hpp
index 9d5037af8d..0010410f36 100644
--- a/src/vm/mixedmode.hpp
+++ b/src/vm/mixedmode.hpp
@@ -2,11 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
// ===========================================================================
-// File: mixedmode.H
+// File: mixedmode.hpp
//
//
-// MIXEDMODE.H defines classes to support mixed mode dlls
+// MIXEDMODE.HPP defines classes to support mixed mode dlls
// ===========================================================================
diff --git a/src/vm/mscorlib.cpp b/src/vm/mscorlib.cpp
index 5d8531ec56..53a9ec6fc1 100644
--- a/src/vm/mscorlib.cpp
+++ b/src/vm/mscorlib.cpp
@@ -31,7 +31,8 @@
#include "comdelegate.h"
#include "customattribute.h"
#include "comdynamic.h"
-#include "commethodrental.h"
+#include "excep.h"
+#include "fcall.h"
#include "nlsinfo.h"
#include "calendardata.h"
#include "commodule.h"
@@ -95,7 +96,7 @@
#include "multicorejit.h"
#endif
-#ifdef FEATURE_COMINTEROP
+#if defined(FEATURE_COMINTEROP) && defined(FEATURE_REFLECTION_ONLY_LOAD)
#include "clrprivtypecachereflectiononlywinrt.h"
#endif
diff --git a/src/vm/ngenoptout.cpp b/src/vm/ngenoptout.cpp
deleted file mode 100644
index 50b47782a9..0000000000
--- a/src/vm/ngenoptout.cpp
+++ /dev/null
@@ -1,12 +0,0 @@
-// 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.
-// ngenoptout.cpp
-//
-
-//
-//
-// Contains functionality to reject native images at runtime
-
-
-#include "common.h"
diff --git a/src/vm/ngenoptout.h b/src/vm/ngenoptout.h
deleted file mode 100644
index dbcc9b1f90..0000000000
--- a/src/vm/ngenoptout.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.
-// ngenoptout.h
-//
-
-//
-//
-// Contains functionality to reject native images at runtime
-
-
-#ifndef NGENOPTOUT_H
-#define NGENOPTOUT_H
-
-#include "assemblynamesconfigfactory.h"
-
-// throwing
-BOOL IsNativeImageOptedOut(IAssemblyName* pName);
-void AddNativeImageOptOut(IAssemblyName* pName);
-
-// HRESULT
-HRESULT RuntimeIsNativeImageOptedOut(IAssemblyName* pName);
-
-
-class NativeImageOptOutConfigFactory : public AssemblyNamesConfigFactory
-{
- virtual void AddAssemblyName(IAssemblyName* pName)
- {
- WRAPPER_NO_CONTRACT;
- AddNativeImageOptOut(pName);
- }
-};
-
-#endif // NGENOPTOUT_H
diff --git a/src/vm/objectclone.cpp b/src/vm/objectclone.cpp
deleted file mode 100644
index 93c9d3c30f..0000000000
--- a/src/vm/objectclone.cpp
+++ /dev/null
@@ -1,3861 +0,0 @@
-// 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.
-//
-// File: ObjectClone.cpp
-//
-
-//
-
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-#include "objectclone.h"
-#include "frames.h"
-#include "assembly.hpp"
-#include "field.h"
-#include "security.h"
-#include "virtualcallstub.h"
-#include "crossdomaincalls.h"
-#include "callhelpers.h"
-#include "jitinterface.h"
-#include "typestring.h"
-#include "typeparse.h"
-#include "runtimehandles.h"
-#include "appdomain.inl"
-
-// Define the following to re-enable object cloner strict mode (where we require source fields for non-optional destination fields
-// and don't attempt to load assemblies we can't find via display via partial names instead).
-//#define OBJECT_CLONER_STRICT_MODE
-
-void MakeIDeserializationCallback(OBJECTREF refTarget);
-
-MethodDesc *GetInterfaceMethodImpl(MethodTable *pMT, MethodTable *pItfMT, WORD wSlot)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- } CONTRACTL_END;
-
- MethodDesc *pMeth = NULL;
- DispatchSlot slot(pMT->FindDispatchSlot(pItfMT->GetTypeID(), (UINT32)wSlot));
- CONSISTENCY_CHECK(!slot.IsNull());
- pMeth = slot.GetMethodDesc();
- return pMeth;
-}
-
-// Given a FieldDesc which may be representative and an object which contains said field, return the actual type of the field. This
-// works even when called from a different appdomain from which the type was loaded (though naturally it is the caller's
-// responsbility to ensure such an appdomain cannot be unloaded during the processing of this method).
-TypeHandle LoadExactFieldType(FieldDesc *pFD, OBJECTREF orefParent, AppDomain *pDomain)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- MethodTable *pEnclosingMT = orefParent->GetMethodTable();
-
- // Set up a field signature with the owning type providing a type context for any type variables.
- MetaSig sig(pFD, TypeHandle(pEnclosingMT));
- sig.NextArg();
-
- // If the enclosing type is resident to this domain or domain neutral and loaded in this domain then we can simply go get it.
- // The logic is trickier (and more expensive to calculate) for generic types, so skip the optimization there.
- if (pEnclosingMT->GetDomain() == GetAppDomain() ||
- (pEnclosingMT->IsDomainNeutral() &&
- !pEnclosingMT->HasInstantiation() &&
- pEnclosingMT->GetAssembly()->FindDomainAssembly(GetAppDomain())))
- return sig.GetLastTypeHandleThrowing();
-
- TypeHandle retTH;
-
- // Otherwise we have to do this the expensive way -- switch to the home domain for the type lookup.
- ENTER_DOMAIN_PTR(pDomain, ADV_RUNNINGIN);
- retTH = sig.GetLastTypeHandleThrowing();
- END_DOMAIN_TRANSITION;
-
- return retTH;
-}
-
-extern TypeHandle GetTypeByName( _In_opt_z_ LPUTF8 szFullClassName,
- BOOL bThrowOnError,
- BOOL bIgnoreCase,
- StackCrawlMark *stackMark,
- BOOL *pbAssemblyIsLoading);
-
-#ifndef DACCESS_COMPILE
-#define CUSTOM_GCPROTECT_BEGIN(context) do { \
- FrameWithCookie<GCSafeCollectionFrame> __gcframe(context); \
- /* work around unreachable code warning */ \
- if (true) { DEBUG_ASSURE_NO_RETURN_BEGIN(GCPROTECT)
-
-#define CUSTOM_GCPROTECT_END() \
- DEBUG_ASSURE_NO_RETURN_END(GCPROTECT) } \
- __gcframe.Pop(); } while(0)
-
-#else // #ifndef DACCESS_COMPILE
-
-#define CUSTOM_GCPROTECT_BEGIN(context)
-#define CUSTOM_GCPROTECT_END()
-
-#endif // #ifndef DACCESS_COMPILE
-
-int GCSafeObjectHashTable::HasID(OBJECTREF refObj, OBJECTREF *newObj)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
-
- BOOL seenBefore = FALSE;
- *newObj = NULL;
- int index = FindElement(refObj, seenBefore);
-
- if (seenBefore)
- {
- _ASSERTE(index < (int)m_currArraySize);
- *newObj = m_newObjects[index];
- return m_ids[index];
- }
-
- return -1;
-}
-
-// returns the object id
-int GCSafeObjectHashTable::AddObject(OBJECTREF refObj, OBJECTREF newObj)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
-
- int index = -1;
- GCPROTECT_BEGIN(refObj);
- GCPROTECT_BEGIN(newObj);
-
- if (m_count > m_currArraySize / 2)
- {
- Resize();
- }
-
- BOOL seenBefore = FALSE;
- index = FindElement(refObj, seenBefore);
-
- _ASSERTE(index >= 0 && index < (int)m_currArraySize);
- if (seenBefore)
- {
- _ASSERTE(!"Adding an object thats already present");
- }
- else
- {
- m_objects[index] = refObj;
- m_newObjects[index] = newObj;
- m_ids[index] = ++m_count;
- }
-
- GCPROTECT_END();
- GCPROTECT_END();
-
- return m_ids[index];
-}
-
-// returns the object id
-int GCSafeObjectHashTable::UpdateObject(OBJECTREF refObj, OBJECTREF newObj)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
-
- int index = -1;
- GCPROTECT_BEGIN(refObj);
- GCPROTECT_BEGIN(newObj);
-
- BOOL seenBefore = FALSE;
- index = FindElement(refObj, seenBefore);
-
- _ASSERTE(index >= 0 && index < (int)m_currArraySize);
- if (!seenBefore)
- {
- _ASSERTE(!"An object has to exist in the table, to update it");
- }
- else
- {
- _ASSERTE(m_objects[index] == refObj);
- m_newObjects[index] = newObj;
- }
-
- GCPROTECT_END();
- GCPROTECT_END();
-
- return m_ids[index];
-}
-
-// returns index into array where obj was found or will fit in
-int GCSafeObjectHashTable::FindElement(OBJECTREF refObj, BOOL &seenBefore)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
-
- int currentNumBuckets = m_currArraySize / NUM_SLOTS_PER_BUCKET;
- int hashcode = 0;
- GCPROTECT_BEGIN(refObj);
- hashcode = refObj->GetHashCodeEx();
- GCPROTECT_END();
-
- hashcode &= 0x7FFFFFFF; // ignore sign bit
- int hashIncrement = (1+((hashcode)%(currentNumBuckets-2)));
-#ifdef _DEBUG
- int numLoops = 0;
-#endif
-
- do
- {
- int index = ((unsigned)hashcode % currentNumBuckets) * NUM_SLOTS_PER_BUCKET;
- _ASSERTE(index >= 0 && index < (int)m_currArraySize);
- for (int i = index; i < index + NUM_SLOTS_PER_BUCKET; i++)
- {
- if (m_objects[i] == refObj)
- {
- seenBefore = TRUE;
- return i;
- }
-
- if (m_objects[i] == NULL)
- {
- seenBefore = FALSE;
- return i;
- }
- }
- hashcode += hashIncrement;
-#ifdef _DEBUG
- if (++numLoops > currentNumBuckets)
- _ASSERTE(!"Looped too many times, trying to find object in hashtable. If hitting ignore doesnt seem to help, then contact Ashok");
-#endif
- }while (true);
-
- _ASSERTE(!"Not expected to reach here in GCSafeObjectHashTable::FindElement");
- return -1;
-}
-
-void GCSafeObjectHashTable::Resize()
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
- // Allocate new space
- DWORD newSize = m_currArraySize * 2;
- for (int i = 0; (DWORD) i < sizeof(g_rgPrimes)/sizeof(DWORD); i++)
- {
- if (g_rgPrimes[i] > newSize)
- {
- newSize = g_rgPrimes[i];
- break;
- }
- }
-
- newSize *= NUM_SLOTS_PER_BUCKET;
- NewArrayHolder<OBJECTREF> refTemp (new OBJECTREF[newSize]);
- ZeroMemory((void *)refTemp, sizeof(OBJECTREF) * newSize);
-
- NewArrayHolder<OBJECTREF> refTempNewObj (new OBJECTREF[newSize]);
-#ifdef USE_CHECKED_OBJECTREFS
- ZeroMemory((void *)refTempNewObj, sizeof(OBJECTREF) * newSize);
-#endif
-
- NewArrayHolder<int> bTemp (new int[newSize]);
- ZeroMemory((void *)bTemp, sizeof(int) * newSize);
-
- // Copy over objects and data
- NewArrayHolder<OBJECTREF> refOldObj (m_objects);
- NewArrayHolder<OBJECTREF> refOldNewObj (m_newObjects);
- NewArrayHolder<int> oldIds (m_ids);
- DWORD oldArrSize = m_currArraySize;
-
- if (oldIds == (int *)&m_dataOnStack[0])
- {
- refOldObj.SuppressRelease();
- refOldNewObj.SuppressRelease();
- oldIds.SuppressRelease();
- }
-
- refTemp.SuppressRelease();
- refTempNewObj.SuppressRelease();
- bTemp.SuppressRelease();
-
- m_ids = bTemp;
- m_objects = refTemp;
- m_newObjects = refTempNewObj;
- m_currArraySize = newSize;
-
- for (DWORD i = 0; i < oldArrSize; i++)
- {
- if (refOldObj[i] == NULL)
- continue;
-
- BOOL seenBefore = FALSE;
- int newIndex = FindElement(refOldObj[i], seenBefore);
-
- if (!seenBefore)
- {
- _ASSERTE(newIndex < (int)m_currArraySize);
- m_objects[newIndex] = refOldObj[i];
- m_newObjects[newIndex] = refOldNewObj[i];
- m_ids[newIndex] = oldIds[i];
- }
- else
- _ASSERTE(!"Object seen twice while rehashing");
- }
-
-#ifdef USE_CHECKED_OBJECTREFS
- for(DWORD i = 0; i < m_currArraySize; i++)
- Thread::ObjectRefProtected(&m_objects[i]);
- for(DWORD i = 0; i < m_currArraySize; i++)
- Thread::ObjectRefProtected(&m_newObjects[i]);
-#endif
-
-}
-
-void GCSafeObjectTable::Push(OBJECTREF refObj, OBJECTREF refParent, OBJECTREF refAux, QueuedObjectInfo * pQOI)
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
- _ASSERTE(refObj != NULL);
- _ASSERTE(m_QueueType == LIFO_QUEUE);
- _ASSERTE(m_head == 0 && m_dataHead == 0);
-
- // First find the size of the object info
- DWORD size = pQOI->GetSize();
-
- // Check if resize is needed
- EnsureSize(size);
-
- // Push on the stack, first the objects
- DWORD index = m_count;
- if (m_Objects1)
- m_Objects1[index] = refObj;
-#ifdef _DEBUG
- else
- _ASSERTE(refObj == NULL);
-#endif
- if (m_Objects2)
- m_Objects2[index] = refParent;
-#ifdef _DEBUG
- else
- _ASSERTE(refParent == NULL);
-#endif
- if (m_Objects3)
- m_Objects3[index] = refAux;
-#ifdef _DEBUG
- else
- _ASSERTE(refAux == NULL);
-#endif
-
- // then the info
- if (m_dataIndices)
- m_dataIndices[index] = m_numDataBytes;
- BYTE *pData = &m_data[m_numDataBytes];
- memcpy(pData, (VOID*)pQOI, size);
-
- m_numDataBytes += size;
- m_count++;
-}
-
-OBJECTREF GCSafeObjectTable::Pop(OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo ** pQOI)
-{
- LIMITED_METHOD_CONTRACT;
- _ASSERTE(m_QueueType == LIFO_QUEUE);
- _ASSERTE(m_head == 0 && m_dataHead == 0);
- _ASSERTE(m_dataIndices != NULL);
-
- *pQOI = NULL;
- OBJECTREF refRet = NULL;
- *refParent = NULL;
- *refAux = NULL;
- if (m_count == 0)
- return NULL;
-
- m_count--;
- refRet = m_Objects1[m_count];
- if (m_Objects2)
- *refParent = m_Objects2[m_count];
- if (m_Objects3)
- *refAux = m_Objects3[m_count];
- *pQOI = (QueuedObjectInfo *) &m_data[m_dataIndices[m_count]];
-
- m_numDataBytes -= (*pQOI)->GetSize();
- return refRet;
-}
-
-void GCSafeObjectTable::SetAt(DWORD index, OBJECTREF refObj, OBJECTREF refParent, OBJECTREF refAux, QueuedObjectInfo * pQOI)
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
- _ASSERTE(refObj != NULL);
-#ifdef _DEBUG
- if (m_QueueType == LIFO_QUEUE)
- _ASSERTE(index >= 0 && index < m_count);
- else
- _ASSERTE(index < m_currArraySize);
-#endif
-
- // First find the size of the object info
- DWORD size = pQOI->GetSize();
-
- // Push on the stack, first the objects
- m_Objects1[index] = refObj;
- if (m_Objects2)
- m_Objects2[index] = refParent;
- if (m_Objects3)
- m_Objects3[index] = refAux;
-
- // then the info
- _ASSERTE(m_dataIndices != NULL);
-
- QueuedObjectInfo *pData = (QueuedObjectInfo *)&m_data[m_dataIndices[index]];
- _ASSERTE(pData->GetSize() == size);
-
- memcpy(pData, (VOID*)pQOI, size);
-}
-
-OBJECTREF GCSafeObjectTable::GetAt(DWORD index, OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo ** pQOI)
-{
- LIMITED_METHOD_CONTRACT;
-#ifdef _DEBUG
- if (m_QueueType == LIFO_QUEUE)
- _ASSERTE(index >= 0 && index < m_count);
- else
- _ASSERTE(index < m_currArraySize);
-#endif
-
- OBJECTREF refRet = m_Objects1[index];
- if (m_Objects2)
- *refParent = m_Objects2[index];
- else
- *refParent = NULL;
- if (m_Objects3)
- *refAux = m_Objects3[index];
- else
- *refAux = NULL;
-
- _ASSERTE(m_dataIndices != NULL);
-
- *pQOI = (QueuedObjectInfo *) &m_data[m_dataIndices[index]];
-
- return refRet;
-}
-
-void GCSafeObjectTable::Enqueue(OBJECTREF refObj, OBJECTREF refParent, OBJECTREF refAux, QueuedObjectInfo *pQOI)
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
-
- _ASSERTE(refObj != NULL);
- _ASSERTE(m_QueueType == FIFO_QUEUE);
-
- // First find the size of the object info
- DWORD size = pQOI ? pQOI->GetSize() : 0;
-
- // Check if resize is needed
- EnsureSize(size);
-
- // Append to queue, first the objects
- DWORD index = (m_head + m_count) % m_currArraySize;
- m_Objects1[index] = refObj;
- if (m_Objects2)
- m_Objects2[index] = refParent;
- if (m_Objects3)
- m_Objects3[index] = refAux;
-
- // then the info
- if (pQOI)
- {
- DWORD dataIndex = (m_dataHead + m_numDataBytes) % (m_currArraySize * MAGIC_FACTOR);
- BYTE *pData = &m_data[dataIndex];
- memcpy(pData, (VOID*)pQOI, size);
-
- if (m_dataIndices)
- m_dataIndices[index] = dataIndex;
- m_numDataBytes += size;
- }
-
- m_count++;
-}
-
-OBJECTREF GCSafeObjectTable::Dequeue(OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo ** pQOI)
-{
- LIMITED_METHOD_CONTRACT;
-
- _ASSERTE(m_QueueType == FIFO_QUEUE);
-
- if (pQOI)
- *pQOI = NULL;
- OBJECTREF refRet = NULL;
- *refParent = NULL;
- *refAux = NULL;
- if (m_count == 0)
- return NULL;
-
- refRet = m_Objects1[m_head];
- if (m_Objects2)
- *refParent = m_Objects2[m_head];
- if (m_Objects3)
- *refAux = m_Objects3[m_head];
-
- if (pQOI)
- {
- *pQOI = (QueuedObjectInfo *) &m_data[m_dataHead];
-
- m_dataHead = (m_dataHead + (*pQOI)->GetSize()) % (m_currArraySize * MAGIC_FACTOR);
-
- m_numDataBytes -= (*pQOI)->GetSize();
- }
-
- m_head = (m_head + 1) % m_currArraySize;
- m_count--;
- return refRet;
-}
-
-OBJECTREF GCSafeObjectTable::Peek(OBJECTREF *refParent, OBJECTREF *refAux, QueuedObjectInfo **pQOI)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- *pQOI = NULL;
- *refParent = NULL;
- *refAux = NULL;
- if (m_count == 0)
- return NULL;
-
- DWORD indexToPeek;
- if (m_QueueType == LIFO_QUEUE)
- {
- indexToPeek = m_count;
- return GetAt(indexToPeek, refParent, refAux, pQOI);
- }
- else
- {
- indexToPeek = m_head;
- if (m_Objects2)
- *refParent = m_Objects2[m_head];
- if (m_Objects3)
- *refParent = m_Objects3[m_head];
- *pQOI = (QueuedObjectInfo *) &m_data[m_dataHead];
- return m_Objects1[m_head];
- }
-
-}
-
-void GCSafeObjectTable::EnsureSize(DWORD requiredDataSize)
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
- // Check if the object queue is sized enough
- if (m_count == m_currArraySize)
- {
- Resize();
- return;
- }
-
- // Check if the data array size is enough
- if (m_numDataBytes + requiredDataSize > m_currArraySize * MAGIC_FACTOR)
- {
- Resize();
- return;
- }
-
- if (m_QueueType == FIFO_QUEUE)
- {
- // Will current QueuedObjectInfo go beyond the edge of the array ?
- if (m_dataHead + m_numDataBytes + requiredDataSize > m_currArraySize * MAGIC_FACTOR)
- {
- Resize();
- return;
- }
- }
-}
-
-void GCSafeObjectTable::Resize()
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- }
- CONTRACTL_END
- // Allocate new space
- DWORD newSize = m_currArraySize * 2;
- NewArrayHolder<OBJECTREF> refTemp (NULL);
- NewArrayHolder<OBJECTREF> refParentTemp (NULL);
- NewArrayHolder<OBJECTREF> refAuxTemp (NULL);
-
- refTemp = new OBJECTREF[newSize];
- if (m_Objects2)
- refParentTemp = new OBJECTREF[newSize];
- if (m_Objects3)
- refAuxTemp = new OBJECTREF[newSize];
-
-#ifdef USE_CHECKED_OBJECTREFS
- ZeroMemory((void *)refTemp, sizeof(OBJECTREF) * newSize);
- if (m_Objects2)
- ZeroMemory((void *)refParentTemp, sizeof(OBJECTREF) * newSize);
- if (m_Objects3)
- ZeroMemory((void *)refAuxTemp, sizeof(OBJECTREF) * newSize);
-#endif
-
- NewArrayHolder<BYTE> bTemp (NULL);
- NewArrayHolder<DWORD> dwIndicesTemp (NULL);
-
- bTemp = new BYTE[newSize * MAGIC_FACTOR];
- if (m_dataIndices)
- dwIndicesTemp = new DWORD[newSize];
-
- // Copy over objects and data
- if (m_QueueType == LIFO_QUEUE || (m_QueueType == FIFO_QUEUE && m_head == 0))
- {
- void *pSrc = (void *)&m_Objects1[0];
- void *pDest = (void *)&refTemp[0];
- memcpyUnsafe(pDest, pSrc, m_count * sizeof(OBJECTREF));
-
- if (m_Objects2)
- {
- pSrc = (void *)&m_Objects2[0];
- pDest = (void *)&refParentTemp[0];
- memcpyUnsafe(pDest, pSrc, m_count * sizeof(OBJECTREF));
- }
-
- if (m_Objects3)
- {
- pSrc = (void *)&m_Objects3[0];
- pDest = (void *)&refAuxTemp[0];
- memcpyUnsafe(pDest, pSrc, m_count * sizeof(OBJECTREF));
- }
-
- pSrc = (void *)&m_data[0];
- pDest = (void *)&bTemp[0];
- memcpyNoGCRefs(pDest, pSrc, m_numDataBytes);
-
- if (m_dataIndices)
- {
- pSrc = (void *)&m_dataIndices[0];
- pDest = (void *)&dwIndicesTemp[0];
- memcpyNoGCRefs(pDest, pSrc, m_count * sizeof(DWORD));
- }
-
- }
- else
- {
- _ASSERTE(m_QueueType == FIFO_QUEUE && m_head != 0);
- _ASSERTE(m_currArraySize > m_head);
- DWORD numObjRefsToCopy = (m_count > m_currArraySize - m_head ? m_currArraySize - m_head : m_count);
-
- void *pSrc = (void *)&m_Objects1[m_head];
- void *pDest = (void *)&refTemp[0];
- memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(OBJECTREF));
- pSrc = (void *)&m_Objects1[0];
- pDest = (void *)&refTemp[numObjRefsToCopy];
- memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(OBJECTREF));
-
- if (m_Objects2)
- {
- pSrc = (void *)&m_Objects2[m_head];
- pDest = (void *)&refParentTemp[0];
- memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(OBJECTREF));
- pSrc = (void *)&m_Objects2[0];
- pDest = (void *)&refParentTemp[numObjRefsToCopy];
- memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(OBJECTREF));
- }
-
- if (m_Objects3)
- {
- pSrc = (void *)&m_Objects3[m_head];
- pDest = (void *)&refAuxTemp[0];
- memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(OBJECTREF));
- pSrc = (void *)&m_Objects3[0];
- pDest = (void *)&refAuxTemp[numObjRefsToCopy];
- memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(OBJECTREF));
- }
-
- if (m_dataIndices)
- {
- pSrc = (void *)&m_dataIndices[m_head];
- pDest = (void *)&dwIndicesTemp[0];
- memcpyUnsafe(pDest, pSrc, numObjRefsToCopy * sizeof(DWORD));
- pSrc = (void *)&m_dataIndices[0];
- pDest = (void *)&dwIndicesTemp[numObjRefsToCopy];
- memcpyUnsafe(pDest, pSrc, (m_count - numObjRefsToCopy) * sizeof(DWORD));
- }
-
- DWORD numBytesToCopy = (m_numDataBytes > ((m_currArraySize * MAGIC_FACTOR) - m_dataHead) ? ((m_currArraySize * MAGIC_FACTOR) - m_dataHead) : m_numDataBytes);//(m_currArraySize * MAGIC_FACTOR) - m_dataHead;
- memcpyNoGCRefs((void *)bTemp, (void *) &m_data[m_dataHead], numBytesToCopy);
- memcpyNoGCRefs((void *) &bTemp[numBytesToCopy], (void *)m_data, (m_numDataBytes - numBytesToCopy));
- }
-
- // Delete old allocation
- if (m_usingHeap)
- {
- delete[] m_data;
- delete[] m_Objects1;
- delete[] m_Objects2;
- delete[] m_Objects3;
- delete[] m_dataIndices;
- }
-
- refTemp.SuppressRelease();
- refParentTemp.SuppressRelease();
- refAuxTemp.SuppressRelease();
- dwIndicesTemp.SuppressRelease();
- bTemp.SuppressRelease();
-
- m_currArraySize = newSize;
- m_Objects1 = refTemp;
- m_Objects2 = refParentTemp;
- m_Objects3 = refAuxTemp;
- m_dataIndices = dwIndicesTemp;
- m_data = bTemp;
- m_head = 0;
- m_dataHead = 0;
-
- m_usingHeap = TRUE;
-#ifdef USE_CHECKED_OBJECTREFS
- for(DWORD i = 0; i < m_currArraySize; i++)
- {
- Thread::ObjectRefProtected(&m_Objects1[i]);
- if (m_Objects2)
- Thread::ObjectRefProtected(&m_Objects2[i]);
- if (m_Objects3)
- Thread::ObjectRefProtected(&m_Objects3[i]);
- }
-#endif
-}
-
-
-VOID GCScanRootsInCollection(promote_func *fn, ScanContext* sc, void *context)
-{
- STATIC_CONTRACT_SO_TOLERANT;
- GCSafeCollection *pObjCollection = (GCSafeCollection *)context;
- pObjCollection->ReportGCRefs(fn, sc);
-}
-
-VOID
-BeginCloning(ObjectClone *pOC)
-{
- pOC->Init(FALSE);
-}
-
-VOID
-EndCloning(ObjectClone *pOC)
-{
- pOC->Cleanup(FALSE);
-}
-
-typedef Holder<ObjectClone*, BeginCloning, EndCloning> ObjectCloneHolder;
-
-
-OBJECTREF ObjectClone::Clone(OBJECTREF refObj, TypeHandle expectedType, AppDomain* fromDomain, AppDomain* toDomain, OBJECTREF refExecutionContext)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_TRIGGERS;
- }
- CONTRACTL_END
-
- if (refObj == NULL)
- return NULL;
-
- if (m_context != ObjectFreezer && refObj->GetMethodTable() == g_pStringClass)
- return refObj;
-
- ObjectCloneHolder ocHolder(this);
-
- m_fromDomain = fromDomain;
- m_toDomain = toDomain;
-
- m_currObject = refObj;
- GCPROTECT_BEGIN(m_currObject);
- m_topObject = NULL;
- GCPROTECT_BEGIN(m_topObject);
- m_fromExecutionContext = refExecutionContext;
- GCPROTECT_BEGIN(m_fromExecutionContext);
-
- // Enter the domain we're cloning into, if we're not already there
- ENTER_DOMAIN_PTR(toDomain,ADV_RUNNINGIN);
-
- if (!m_securityChecked)
- {
- Security::SpecialDemand(SSWT_DEMAND_FROM_NATIVE, SECURITY_SERIALIZATION);
- m_securityChecked = TRUE;
- }
-
-#ifdef _DEBUG
- DefineFullyQualifiedNameForClass();
- LOG((LF_REMOTING, LL_INFO100, "Clone. Cloning instance of type %s.\n",
- GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable())));
-#endif
-
- m_newObject = NULL;
- GCPROTECT_BEGIN(m_newObject);
- PTRARRAYREF refValues = NULL;
- GCPROTECT_BEGIN(refValues);
- OBJECTREF refParent = NULL;
- GCPROTECT_BEGIN(refParent);
-
- QueuedObjectInfo *currObjFixupInfo = NULL;
- // For some dynamically sized stack objects
- void *pTempStackSpace = NULL;
- DWORD dwCurrStackSpaceSize = 0;
-
- // Initialize QOM
- QueuedObjectInfo topObj;
- OBJECTREF dummy1, dummy2;
- QOM.Enqueue(m_currObject, NULL, NULL, (QueuedObjectInfo *)&topObj);
-
- while ((m_currObject = QOM.Dequeue(&dummy1, &dummy2, &currObjFixupInfo)) != NULL)
- {
- m_newObject = NULL;
- MethodTable *newMT = NULL;
-
- BOOL repeatObject = FALSE;
- BOOL isISerializable = FALSE, isIObjRef = FALSE, isBoxed = FALSE;
- DWORD ISerializableTSOIndex = (DWORD) -1;
- DWORD IObjRefTSOIndex = (DWORD) -1;
- DWORD BoxedValTSOIndex = (DWORD) -1;
- m_skipFieldScan = FALSE;
-
- // ALLOCATE PHASE
-
- // Was currObject seen before ?
- int currID = TOS.HasID(m_currObject, &m_newObject);
- if (currID != -1)
- {
- // Yes
- repeatObject = TRUE;
- m_skipFieldScan = TRUE;
- newMT = m_newObject->GetMethodTable();
-
- if (m_cbInterface->IsISerializableType(newMT))
- {
- currObjFixupInfo->SetIsISerializableInstance();
- isISerializable = TRUE;
- ISerializableTSOIndex = FindObjectInTSO(currID, ISerializable);
- }
-
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Object of type %s with id %d seen before.\n",
- GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable()), currID));
-#endif
- }
- else
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Object of type %s not seen before.\n",
- GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable())));
-#endif
- // No
- MethodTable *currMT = m_currObject->GetMethodTable();
-
- // Check whether object is serializable
- m_cbInterface->ValidateFromType(currMT);
-
- // Add current object to table of seen objects and get an id
- currID = TOS.AddObject(m_currObject, m_newObject);
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Current object added to Table of Objects Seen. Given id %d.\n", currID));
-
- if ( m_cbInterface->IsRemotedType(currMT, m_fromDomain, m_toDomain))
- {
- refValues = AllocateISerializable(currID, TRUE);
- isISerializable = TRUE;
- ISerializableTSOIndex = TSO.GetCount() - 1;
- currObjFixupInfo->SetIsISerializableInstance();
- if (refValues == NULL)
- {
- // We found a smugglable objref. No field scanning needed
- m_skipFieldScan = TRUE;
- }
- }
- else if( m_cbInterface->IsISerializableType(currMT))
- {
- InvokeVtsCallbacks(m_currObject, RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZING, fromDomain);
- if (HasVtsCallbacks(m_currObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZED))
- VSC.Enqueue(m_currObject, NULL, NULL, NULL);
-
- refValues = AllocateISerializable(currID, FALSE);
- isISerializable = TRUE;
- ISerializableTSOIndex = TSO.GetCount() - 1;
- currObjFixupInfo->SetIsISerializableInstance();
- }
- else if (currMT->IsArray())
- {
- AllocateArray();
- }
- else
- {
- // This is a regular object
- InvokeVtsCallbacks(m_currObject, RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZING, fromDomain);
- if (HasVtsCallbacks(m_currObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZED))
- VSC.Enqueue(m_currObject, NULL, NULL, NULL);
-
- AllocateObject();
-
- if (m_cbInterface->IsISerializableType(m_newObject->GetMethodTable()))
- {
- // We have a situation where the serialized instnce was not ISerializable,
- // but the target instance is. So we make the from object look like a ISerializable
- refValues = MakeObjectLookLikeISerializable(currID);
- isISerializable = TRUE;
- ISerializableTSOIndex = TSO.GetCount() - 1;
- currObjFixupInfo->SetIsISerializableInstance();
- }
- }
-
- _ASSERTE(m_newObject != NULL);
- newMT = m_newObject->GetMethodTable();
-
- // Check whether new object is serializable
- m_cbInterface->ValidateToType(newMT);
-
- // Update the TOS, to include the new object
- int retId;
- retId = TOS.UpdateObject(m_currObject, m_newObject);
- _ASSERTE(retId == currID);
- }
- _ASSERTE(m_newObject != NULL);
-
- // FIXUP PHASE
- // Get parent to be fixed up
- ParentInfo *parentInfo;
- refParent = QOF.Peek(&dummy1, &dummy2, (QueuedObjectInfo **)&parentInfo);
- MethodTable *pParentMT = NULL;
-
- if (refParent == NULL)
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. No parent found. This is the top object.\n"));
- // This is the top object
- _ASSERTE(m_topObject == NULL);
- m_topObject = m_newObject;
- }
- else
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Parent is of type %s.\n",
- GetFullyQualifiedNameForClassNestedAware(m_currObject->GetMethodTable())));
-#endif
- pParentMT = refParent->GetMethodTable();
- }
-
- if (IsDelayedFixup(newMT, currObjFixupInfo))
- {
- // New object is IObjRef or a boxed object
- if (m_cbInterface->IsIObjectReferenceType(newMT))
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. This is an IObjectReference. Delaying fixup.\n"));
- DWORD size = sizeof(IObjRefInstanceInfo) + (currObjFixupInfo ? currObjFixupInfo->GetSize() : 0);
- if (size > dwCurrStackSpaceSize)
- {
- pTempStackSpace = _alloca(size);
- dwCurrStackSpaceSize = size;
- }
- IObjRefInstanceInfo *pIORInfo = new (pTempStackSpace) IObjRefInstanceInfo(currID, 0, 0);
- if (currObjFixupInfo)
- pIORInfo->SetFixupInfo(currObjFixupInfo);
- // Check if this instance is ISerializable also
- if (isISerializable)
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. This is also an ISerializable type at index %d in TSO.\n", ISerializableTSOIndex));
- _ASSERTE(ISerializableTSOIndex != (DWORD) -1);
- pIORInfo->SetISerTSOIndex(ISerializableTSOIndex);
- }
-
- if (repeatObject)
- pIORInfo->SetIsRepeatObject();
-
- // Add to TSO
- TSO.Push(m_newObject, m_currObject, refParent, pIORInfo);
-
- isIObjRef = TRUE;
- IObjRefTSOIndex = TSO.GetCount() - 1;
-
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Added to TSO at index %d.\n", IObjRefTSOIndex));
- // Any special object parent, would wait till the current object is resolved
- if (parentInfo)
- {
- parentInfo->IncrementSpecialMembers();
- TMappings.Add(IObjRefTSOIndex);
- }
-
- }
- if (currObjFixupInfo->NeedsUnboxing())
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. This is a boxed value type. Delaying fixup.\n"));
- DWORD size = sizeof(ValueTypeInfo) + currObjFixupInfo->GetSize();
- if (size > dwCurrStackSpaceSize)
- {
- pTempStackSpace = _alloca(size);
- dwCurrStackSpaceSize = size;
- }
- ValueTypeInfo *valInfo = new (pTempStackSpace) ValueTypeInfo(currID, currObjFixupInfo);
- // If the value type is also ISer or IObj, then it has to wait till those interfaces are addressed
- if (isISerializable)
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. This is also an ISerializable type at index %d in TSO.\n", ISerializableTSOIndex));
- valInfo->SetISerTSOIndex(ISerializableTSOIndex);
- }
- if (isIObjRef)
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. This is also an IObjectReference type at index %d in TSO.\n", IObjRefTSOIndex));
- valInfo->SetIObjRefTSOIndex(IObjRefTSOIndex);
- }
-
- // Add to TSO
- TSO.Push(m_newObject, refParent, NULL, valInfo);
-
- isBoxed = TRUE;
- BoxedValTSOIndex = TSO.GetCount() - 1;
-
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Added to TSO at index %d.\n", BoxedValTSOIndex));
- // An IObjRef parent, or a parent itself boxed, would wait till the current object is resolved
- if (parentInfo && (parentInfo->NeedsUnboxing() || parentInfo->IsIObjRefInstance()))
- {
- parentInfo->IncrementSpecialMembers();
- TMappings.Add(BoxedValTSOIndex);
- }
- }
- }
-
- if (refParent != NULL)
- {
- if (!IsDelayedFixup(newMT, currObjFixupInfo))
- Fixup(m_newObject, refParent, currObjFixupInfo);
-
- // If currObj is ISer, then an IObjRef parent would wait till the current object is resolved
- if (currObjFixupInfo->IsISerializableInstance() &&
- parentInfo->IsIObjRefInstance())
- {
- parentInfo->IncrementSpecialMembers();
- TMappings.Add(ISerializableTSOIndex);
- }
- }
-
- // If we are done with this parent, remove it from QOF
- if (parentInfo && parentInfo->DecrementFixupCount() == 0)
- {
- LOG((LF_REMOTING, LL_INFO1000, "Clone. All children fixed up. Removing parent from QOF.\n", BoxedValTSOIndex));
- LOG((LF_REMOTING, LL_INFO1000, "Clone. Parent has %d special member objects.\n", parentInfo->GetNumSpecialMembers()));
- OBJECTREF refTemp;
- ParentInfo *pFITemp;
- refTemp = QOF.Dequeue(&dummy1, &dummy2, (QueuedObjectInfo **)&pFITemp);
- _ASSERTE(refTemp == refParent);
- _ASSERTE(pFITemp == parentInfo);
-
- // If parent is a special object, then we need to know how many special members it has
- if ((parentInfo->IsIObjRefInstance() ||
- parentInfo->IsISerializableInstance() ||
- parentInfo->NeedsUnboxing())
- && parentInfo->GetNumSpecialMembers() > 0)
- {
- // Make a note in TSO that this parent has non-zero special members
- DWORD index[3];
- index[0] = parentInfo->GetIObjRefIndexIntoTSO();
- index[1] = parentInfo->GetISerIndexIntoTSO();
- index[2] = parentInfo->GetBoxedValIndexIntoTSO();
-
- for (DWORD count = 0; count < 3; count++)
- {
- OBJECTREF refIser, refNames, refValuesTemp;
- SpecialObjectInfo *pISerInfo;
-
- if (index[count] == (DWORD) -1)
- continue;
-
- refIser = TSO.GetAt(index[count], &refNames, &refValuesTemp, (QueuedObjectInfo **)&pISerInfo);
- _ASSERTE(refIser == refParent);
-
- DWORD numSpecialObjects = parentInfo->GetNumSpecialMembers();
- pISerInfo->SetNumSpecialMembers(numSpecialObjects);
-
- _ASSERTE(TMappings.GetCount() >= numSpecialObjects);
- pISerInfo->SetMappingTableIndex(TMappings.GetCount() - numSpecialObjects);
- }
- }
- }
-
- // FIELD SCAN PHASE
- if (!m_skipFieldScan)
- {
- if (m_currObject->GetMethodTable()->IsArray())
- ScanArrayMembers();
- else if (isISerializable)
- ScanISerializableMembers(IObjRefTSOIndex, ISerializableTSOIndex, BoxedValTSOIndex, refValues);
- else
- ScanMemberFields(IObjRefTSOIndex, BoxedValTSOIndex);
- }
-
- } // While there are objects in QOM
-
- // OBJECT COMPLETION PHASE
- CompleteSpecialObjects();
-
- // Deliver VTS OnDeserialized callbacks.
- CompleteVtsOnDeserializedCallbacks();
-
- CompleteIDeserializationCallbacks();
-
- _ASSERTE(m_topObject != NULL);
- // If a type check was requested, see if the returned object is of the expected type
- if (!expectedType.IsNull()
- && !ObjIsInstanceOf(OBJECTREFToObject(m_topObject), expectedType))
- COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
-
- GCPROTECT_END(); // refParent
- GCPROTECT_END(); // refValues
-
- GCPROTECT_END(); // m_newObject
-
- END_DOMAIN_TRANSITION;
-
- // Deliver VTS OnSerialized callbacks.
- CompleteVtsOnSerializedCallbacks();
-
- GCPROTECT_END(); // m_fromExecutionContext
- GCPROTECT_END(); // m_topObject
- GCPROTECT_END(); // m_currObject
-
- return m_topObject;
-}
-
-// IObjRef and value types boxed by us, need to be fixed up towards the end
-BOOL ObjectClone::IsDelayedFixup(MethodTable *newMT, QueuedObjectInfo *pCurrInfo)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- if (m_cbInterface->IsIObjectReferenceType(newMT) ||
- pCurrInfo->NeedsUnboxing())
- return TRUE;
- else
- return FALSE;
-}
-
-void ObjectClone::Fixup(OBJECTREF newObj, OBJECTREF refParent, QueuedObjectInfo *pFixupInfo)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- MethodTable *pParentMT = refParent->GetMethodTable();
-
- if (pFixupInfo->IsISerializableMember())
- {
- HandleISerializableFixup(refParent, pFixupInfo);
- }
- else if (pParentMT->IsArray())
- {
- HandleArrayFixup(refParent, pFixupInfo);
- }
- else
- {
- HandleObjectFixup(refParent, pFixupInfo);
- }
-}
-
-PTRARRAYREF ObjectClone::MakeObjectLookLikeISerializable(int objectId)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- THROWS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END
-
- _ASSERTE(m_context != ObjectFreezer);
-
- LOG((LF_REMOTING, LL_INFO1000, "MakeObjectLookLikeISerializable. Target object is ISerializable, so making from object look ISerializable\n"));
- MethodTable *pCurrMT = m_currObject->GetMethodTable();
- DWORD numFields = pCurrMT->GetNumInstanceFields();
-
- PTRARRAYREF fieldNames = NULL;
- PTRARRAYREF fieldValues = NULL;
-
- GCPROTECT_BEGIN(fieldNames);
- GCPROTECT_BEGIN(fieldValues);
-
- // Go back to from domain
- ENTER_DOMAIN_PTR(m_fromDomain,ADV_RUNNINGIN);
-
- // Reset the execution context to the original state it was in when we first
- // left the from domain (this will automatically be popped once we return
- // from this domain again).
- Thread *pThread = GetThread();
- if (pThread->IsExposedObjectSet())
- {
- THREADBASEREF refThread = (THREADBASEREF)pThread->GetExposedObjectRaw();
- refThread->SetExecutionContext(m_fromExecutionContext);
- }
-
- fieldNames = (PTRARRAYREF)AllocateObjectArray(numFields, g_pStringClass, FALSE);
- fieldValues = (PTRARRAYREF)AllocateObjectArray(numFields, g_pObjectClass, FALSE);
-
- DWORD fieldIndex = 0;
- while (pCurrMT)
- {
-
- DWORD numInstanceFields = pCurrMT->GetNumIntroducedInstanceFields();
-
- FieldDesc *pFields = pCurrMT->GetApproxFieldDescListRaw();
-
- for (DWORD i = 0; i < numInstanceFields; i++)
- {
- if (pFields[i].IsNotSerialized())
- {
- LOG((LF_REMOTING, LL_INFO1000, "MakeObjectLookLikeISerializable. Field %s is marked NonSerialized. Skipping.\n", pFields[i].GetName()));
- continue;
- }
-
- CorElementType typ = pFields[i].GetFieldType();
- DWORD offset = pFields[i].GetOffset();
-
- LPCUTF8 szFieldName = pFields[i].GetName();
- STRINGREF refName = StringObject::NewString(szFieldName);
- _ASSERTE(refName != NULL);
-
- fieldNames->SetAt(fieldIndex, refName);
-
- switch (typ)
- {
- case ELEMENT_TYPE_BOOLEAN:
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_CHAR:
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
- case ELEMENT_TYPE_I:
- case ELEMENT_TYPE_U:
- case ELEMENT_TYPE_R4:
- case ELEMENT_TYPE_R8:
- {
- MethodTable *pFldMT = MscorlibBinder::GetElementType(typ);
- void *pData = m_currObject->GetData() + offset;
- OBJECTREF refBoxed = pFldMT->Box(pData);
-
- fieldValues->SetAt(fieldIndex, refBoxed);
- break;
- }
- case ELEMENT_TYPE_VALUETYPE:
- case ELEMENT_TYPE_PTR:
- case ELEMENT_TYPE_FNPTR:
- {
- TypeHandle th = LoadExactFieldType(&pFields[i], m_currObject, m_fromDomain);
- _ASSERTE(!th.AsMethodTable()->IsByRefLike() && "Field types cannot contain stack pointers.");
-
- OBJECTREF refBoxed = BoxValueTypeInWrongDomain(m_currObject, offset, th.AsMethodTable());
-
- fieldValues->SetAt(fieldIndex, refBoxed);
- break;
- }
- case ELEMENT_TYPE_SZARRAY: // Single Dim
- case ELEMENT_TYPE_ARRAY: // General Array
- case ELEMENT_TYPE_CLASS: // Class
- case ELEMENT_TYPE_OBJECT:
- case ELEMENT_TYPE_STRING: // System.String
- case ELEMENT_TYPE_VAR:
- {
- OBJECTREF refField = *((OBJECTREF *) m_currObject->GetData() + offset);
- fieldValues->SetAt(fieldIndex, refField);
- break;
- }
- default:
- _ASSERTE(!"Unknown element type in MakeObjectLookLikeISerializalbe");
- }
-
- fieldIndex++;
- }
-
- pCurrMT = pCurrMT->GetParentMethodTable();
- }
-
- // Back to original domain
- END_DOMAIN_TRANSITION;
-
- // Add object to TSO
- ISerializableInstanceInfo iserInfo(objectId, 0);
- TSO.Push(m_newObject, fieldNames, NULL, (QueuedObjectInfo *)&iserInfo);
-
- LOG((LF_REMOTING, LL_INFO1000, "MakeObjectLookLikeISerializable. Added to TSO at index %d.\n", TSO.GetCount() - 1));
- GCPROTECT_END();
- GCPROTECT_END();
-
- return fieldValues;
-}
-
-PTRARRAYREF ObjectClone::AllocateISerializable(int objectId, BOOL bIsRemotingObject)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- THROWS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END
-
- _ASSERTE(m_context != ObjectFreezer);
-
- // Go back to from domain
- StackSString ssAssemName;
- StackSString ssTypeName;
-
- struct _gc {
- STRINGREF typeName;
- STRINGREF assemblyName;
- PTRARRAYREF fieldNames;
- PTRARRAYREF fieldValues;
- OBJECTREF refObjRef;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
-
- ENTER_DOMAIN_PTR(m_fromDomain,ADV_RUNNINGIN);
-
- // Reset the execution context to the original state it was in when we first
- // left the from domain (this will automatically be popped once we return
- // from this domain again).
- Thread *pThread = GetThread();
- if (pThread->IsExposedObjectSet())
- {
- THREADBASEREF refThread = (THREADBASEREF)pThread->GetExposedObjectRaw();
- refThread->SetExecutionContext(m_fromExecutionContext);
- }
-
- // Call GetObjectData on the interface
-
- LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. Instance is ISerializable type. Calling GetObjectData.\n"));
-
- PREPARE_NONVIRTUAL_CALLSITE(METHOD__OBJECTCLONEHELPER__GET_OBJECT_DATA);
-
- DECLARE_ARGHOLDER_ARRAY(args, 5);
-
- args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(m_currObject);
- args[ARGNUM_1] = PTR_TO_ARGHOLDER(&gc.typeName);
- args[ARGNUM_2] = PTR_TO_ARGHOLDER(&gc.assemblyName);
- args[ARGNUM_3] = PTR_TO_ARGHOLDER(&gc.fieldNames);
- args[ARGNUM_4] = PTR_TO_ARGHOLDER(&gc.fieldValues);
-
- CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
- CALL_MANAGED_METHOD_RETREF(gc.refObjRef, OBJECTREF, args);
-
- if (!bIsRemotingObject || gc.refObjRef == NULL)
- {
- ssAssemName.Set(gc.assemblyName->GetBuffer());
- ssTypeName.Set(gc.typeName->GetBuffer());
- }
-
- // Back to original domain
- END_DOMAIN_TRANSITION;
-
- // if its a remoting object we are dealing with, we may already have the smugglable objref
- if (bIsRemotingObject && gc.refObjRef != NULL)
- {
- m_newObject = gc.refObjRef;
- // Add object to TSO. We dont need a ISerializable record, because we are smuggling the ObjRef
- // and so, technically the ISerializable ctor can be considered already called. But we still make an entry in
- // TSO and mark it "processed", so repeat references to the same remoting object work correctly
- ISerializableInstanceInfo iserInfo(objectId, 0);
- iserInfo.SetHasBeenProcessed();
- TSO.Push(m_newObject, NULL, NULL, (QueuedObjectInfo *)&iserInfo);
-
- LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. GetObjectData returned smugglable ObjRef. Added dummy record to TSO at index %d.\n", TSO.GetCount() - 1));
- }
- else
- {
- // Find the type (and choke on any exotics such as arrays, function pointers or generic type definitions).
- TypeHandle th = GetType(ssTypeName, ssAssemName);
- if (th.IsTypeDesc() || th.ContainsGenericVariables())
- {
- StackSString ssBeforeTypeName, ssAfterTypeName;
- TypeString::AppendType(ssBeforeTypeName, m_currObject->GetTypeHandle(), TypeString::FormatNamespace | TypeString::FormatFullInst);
- TypeString::AppendType(ssAfterTypeName, th, TypeString::FormatNamespace | TypeString::FormatFullInst);
- COMPlusThrow(kSerializationException, IDS_SERIALIZATION_BAD_ISER_TYPE, ssBeforeTypeName.GetUnicode(), ssAfterTypeName.GetUnicode());
- }
- MethodTable *pSrvMT = th.AsMethodTable();
- _ASSERTE(pSrvMT);
-
-#ifdef _DEBUG
- {
- DefineFullyQualifiedNameForClass();
- LPCUTF8 __szTypeName = GetFullyQualifiedNameForClassNestedAware(pSrvMT);
- LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. Allocating instance of type %s.\n", &__szTypeName[0]));
- }
-#endif
- // Allocate the object
- m_newObject = m_cbInterface->AllocateObject(m_currObject, pSrvMT);
-
- // Add object to TSO
- ISerializableInstanceInfo iserInfo(objectId, 0);
-
- // Check if the target object is ISerializable. If not, we need to treat construction of this object differently
- if (!m_cbInterface->IsISerializableType(pSrvMT))
- {
- iserInfo.SetTargetNotISerializable();
- }
- TSO.Push(m_newObject, gc.fieldNames, NULL, (QueuedObjectInfo *)&iserInfo);
-
- LOG((LF_REMOTING, LL_INFO1000, "AllocateISerializable. Added to TSO at index %d.\n", TSO.GetCount() - 1));
- }
- GCPROTECT_END();
-
- return gc.fieldValues;
-}
-
-void ObjectClone::AllocateArray()
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-
- LOG((LF_REMOTING, LL_INFO1000, "AllocateArray. Instance is an array type.\n"));
- MethodTable *pCurrMT = m_currObject->GetMethodTable();
- _ASSERTE(pCurrMT->IsArray());
-
- BASEARRAYREF refArray = (BASEARRAYREF)m_currObject;
- GCPROTECT_BEGIN(refArray);
-
- TypeHandle elemTh = refArray->GetArrayElementTypeHandle();
- CorElementType elemType = refArray->GetArrayElementType();
- DWORD numComponents = refArray->GetNumComponents();
-
- TypeHandle __elemTh = GetCorrespondingTypeForTargetDomain(elemTh);
- _ASSERTE(!__elemTh.IsNull());
-
- unsigned __rank = pCurrMT->GetRank();
- TypeHandle __arrayTh = ClassLoader::LoadArrayTypeThrowing(__elemTh, __rank == 1 ? ELEMENT_TYPE_SZARRAY : ELEMENT_TYPE_ARRAY, __rank);
-
- DWORD __numArgs = __rank*2;
- INT32* __args = (INT32*) _alloca(sizeof(INT32)*__numArgs);
-
- if (__arrayTh.AsArray()->GetInternalCorElementType() == ELEMENT_TYPE_ARRAY)
- {
- const INT32* bounds = refArray->GetBoundsPtr();
- const INT32* lowerBounds = refArray->GetLowerBoundsPtr();
- for(unsigned int i=0; i < __rank; i++)
- {
- __args[2*i] = lowerBounds[i];
- __args[2*i+1] = bounds[i];
- }
- }
- else
- {
- __numArgs = 1;
- __args[0] = numComponents;
- }
- m_newObject = m_cbInterface->AllocateArray(m_currObject, __arrayTh, __args, __numArgs, FALSE);
-
- // Treat pointer as a primitive type (we shallow copy the bits).
- if (CorTypeInfo::IsPrimitiveType(elemType) || elemType == ELEMENT_TYPE_PTR)
- {
- LOG((LF_REMOTING, LL_INFO1000, "AllocateArray. Instance is an array of primitive type. Copying contents.\n"));
- // Copy contents.
- SIZE_T numBytesToCopy = refArray->GetComponentSize() * numComponents;
- I1ARRAYREF refI1Arr = (I1ARRAYREF)m_newObject;
- BYTE *pDest = (BYTE *)refI1Arr->GetDirectPointerToNonObjectElements();
- I1ARRAYREF refFromArr = (I1ARRAYREF)refArray;
- BYTE *pSrc = (BYTE *)refFromArr->GetDirectPointerToNonObjectElements();
-
- memcpyNoGCRefs(pDest, pSrc, numBytesToCopy);
- m_skipFieldScan = TRUE;
- }
- else if (elemType == ELEMENT_TYPE_VALUETYPE)
- {
- if (!__elemTh.GetMethodTable()->HasFieldsWhichMustBeInited() && RemotableMethodInfo::TypeIsConduciveToBlitting(elemTh.AsMethodTable(), __elemTh.GetMethodTable()))
- {
- LOG((LF_REMOTING, LL_INFO1000, "AllocateArray. Instance is an array of value type with no embedded GC type. Copying contents.\n"));
- // Copy contents.
- SIZE_T numBytesToCopy = refArray->GetComponentSize() * numComponents;
- I1ARRAYREF refI1Arr = (I1ARRAYREF)m_newObject;
- BYTE *pDest = (BYTE *)refI1Arr->GetDirectPointerToNonObjectElements();
- I1ARRAYREF refFromArr = (I1ARRAYREF)refArray;
- BYTE *pSrc = (BYTE *)refFromArr->GetDirectPointerToNonObjectElements();
-
- memcpyNoGCRefs(pDest, pSrc, numBytesToCopy);
- m_skipFieldScan = TRUE;
- }
- }
- GCPROTECT_END();
-}
-
-void ObjectClone::AllocateObject()
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-
- LOG((LF_REMOTING, LL_INFO1000, "AllocateObject. Instance is a regular object.\n"));
- MethodTable *pCurrMT = m_currObject->GetMethodTable();
- _ASSERTE(!pCurrMT->IsArray());
- _ASSERTE(!pCurrMT->IsMarshaledByRef() && !pCurrMT->IsTransparentProxy());
- _ASSERTE(!m_cbInterface->IsISerializableType(pCurrMT));
-
- MethodTable *pCorrespondingMT = GetCorrespondingTypeForTargetDomain(pCurrMT);
- _ASSERTE(pCorrespondingMT);
-
- pCorrespondingMT->EnsureInstanceActive();
-
- m_newObject = m_cbInterface->AllocateObject(m_currObject, pCorrespondingMT);
-
- InvokeVtsCallbacks(m_newObject, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZING, m_toDomain);
-}
-
-// Use this wrapper when the type handle can't be represented as a raw MethodTable (i.e. it's a pointer or array type).
-TypeHandle ObjectClone::GetCorrespondingTypeForTargetDomain(TypeHandle thCli)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-
- TypeHandle thBaseType = thCli;
- TypeHandle thSrvType;
-
- // Strip off any pointer information (and record the depth). We'll put this back later (when we've translated the base type).
- DWORD dwPointerDepth = 0;
- while (thBaseType.IsPointer())
- {
- dwPointerDepth++;
- thBaseType = thBaseType.AsTypeDesc()->GetTypeParam();
- }
-
- // If we hit an array then we'll recursively translate the element type then build an array type out of it.
- if (thBaseType.IsArray())
- {
- ArrayTypeDesc *atd = (ArrayTypeDesc *)thBaseType.AsTypeDesc();
- thSrvType = GetCorrespondingTypeForTargetDomain(atd->GetArrayElementTypeHandle());
-
- thSrvType = ClassLoader::LoadArrayTypeThrowing(thSrvType, atd->GetInternalCorElementType(), atd->GetRank());
- }
- else
- {
- // We should have only unshared types if we get here.
- _ASSERTE(!thBaseType.IsTypeDesc());
- thSrvType = GetCorrespondingTypeForTargetDomain(thBaseType.AsMethodTable());
- }
-
- // Match the level of pointer indirection from the original client type.
- while (dwPointerDepth--)
- {
- thSrvType = thSrvType.MakePointer();
- }
-
- return thSrvType;
-}
-
-MethodTable * ObjectClone::GetCorrespondingTypeForTargetDomain(MethodTable *pCliMT)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-
- MethodTable *pSrvMT = NULL;
- if (m_fromDomain == m_toDomain)
- return pCliMT;
-
- _ASSERTE(m_context != ObjectFreezer);
-#ifdef _DEBUG
- SString __ssTypeName;
- StackScratchBuffer __scratchBuf;
- if (pCliMT->IsArray())
- pCliMT->_GetFullyQualifiedNameForClass(__ssTypeName);
- else
- pCliMT->_GetFullyQualifiedNameForClassNestedAware(__ssTypeName);
-#endif
-
- // Take benefit of shared types. If a type is shared, and its assembly has been loaded
- // in the target domain, go ahead and use the same MT ptr.
- // The logic is trickier (and more expensive to calculate) for generic types, so skip the optimization there.
- if (pCliMT->IsDomainNeutral() && !pCliMT->HasInstantiation())
- {
- if (pCliMT->GetAssembly()->FindDomainAssembly(m_toDomain))
- {
- LOG((LF_REMOTING, LL_INFO1000,
- "GetCorrespondingTypeForTargetDomain. Type %s is shared. Using same MethodTable.\n", __ssTypeName.GetUTF8(__scratchBuf)));
- return pCliMT;
- }
- }
-
- pSrvMT = CrossDomainTypeMap::GetMethodTableForDomain(pCliMT, m_fromDomain, m_toDomain);
- if (pSrvMT)
- {
- LOG((LF_REMOTING, LL_INFO1000,
- "GetCorrespondingTypeForTargetDomain. Found matching type for %s in domain %d from cache.\n", __ssTypeName.GetUTF8(__scratchBuf), m_toDomain));
- return pSrvMT;
- }
-
- // Need to find the name and lookup in target domain
- SString ssCliTypeName;
- if (pCliMT->IsArray())
- {
- pCliMT->_GetFullyQualifiedNameForClass(ssCliTypeName);
- }
- else if (pCliMT->HasInstantiation())
- {
- TypeString::AppendType(ssCliTypeName, TypeHandle(pCliMT), TypeString::FormatNamespace | TypeString::FormatFullInst);
- }
- else
- {
- pCliMT->_GetFullyQualifiedNameForClassNestedAware(ssCliTypeName);
- }
-
-
- SString ssAssemblyName;
- pCliMT->GetAssembly()->GetDisplayName(ssAssemblyName);
-
- // Get the assembly
- TypeHandle th = GetType(ssCliTypeName, ssAssemblyName);
-
- if (!pCliMT->IsArray())
- {
- pSrvMT = th.AsMethodTable();
- }
- else
- {
- _ASSERTE(th.IsArray());
- TypeDesc *td = th.AsTypeDesc();
- pSrvMT = td->GetMethodTable();
- }
- CrossDomainTypeMap::SetMethodTableForDomain(pCliMT, m_fromDomain, pSrvMT, m_toDomain);
- LOG((LF_REMOTING, LL_INFO1000,
- "GetCorrespondingTypeForTargetDomain. Loaded matching type for %s in domain %d. Added to cache.\n", __ssTypeName.GetUTF8(__scratchBuf), m_toDomain));
- return pSrvMT;
-}
-
-TypeHandle ObjectClone::GetType(const SString &ssTypeName, const SString &ssAssemName)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END;
-
- Assembly *pAssembly = NULL;
-
-#ifndef OBJECT_CLONER_STRICT_MODE
- EX_TRY
-#endif
- {
- AssemblySpec spec;
- StackScratchBuffer scratchBuf;
- HRESULT hr = spec.Init(ssAssemName.GetUTF8(scratchBuf));
- if (SUCCEEDED(hr))
- {
- pAssembly = spec.LoadAssembly(FILE_ACTIVE);
- }
- else
- {
- COMPlusThrowHR(hr);
- }
- }
-#ifndef OBJECT_CLONER_STRICT_MODE
- EX_CATCH
- {
- if (GET_EXCEPTION()->IsTransient())
- {
- EX_RETHROW;
- }
-
- DomainAssembly *pDomainAssembly = NULL;
- if (pDomainAssembly == NULL)
- COMPlusThrow(kSerializationException, IDS_SERIALIZATION_UNRESOLVED_TYPE,
- ssTypeName.GetUnicode(), ssAssemName.GetUnicode());
- else
- pAssembly = pDomainAssembly->GetAssembly();
- }
- EX_END_CATCH(SwallowAllExceptions);
-#endif
-
- _ASSERTE(pAssembly);
-
- TypeHandle th = TypeName::GetTypeFromAssembly(ssTypeName.GetUnicode(), pAssembly);
-
- if (th.IsNull())
- {
- COMPlusThrow(kSerializationException, IDS_SERIALIZATION_UNRESOLVED_TYPE,
- ssTypeName.GetUnicode(), ssAssemName.GetUnicode());
- }
-
- LOG((LF_REMOTING, LL_INFO1000, "GetType. Loaded type %S from assembly %S in domain %d. \n",
- ssTypeName.GetUnicode(), ssAssemName.GetUnicode(), m_toDomain->GetId().m_dwId));
-
- return th;
-}
-
-void ObjectClone::HandleISerializableFixup(OBJECTREF refParent, QueuedObjectInfo *currObjFixupInfo)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- _ASSERTE(m_context != ObjectFreezer);
-
- ISerializableMemberInfo *pIsInfo = (ISerializableMemberInfo *)currObjFixupInfo;
- OBJECTREF refNames, refValues;
- ISerializableInstanceInfo *dummy;
- OBJECTREF parent;
- parent = TSO.GetAt(pIsInfo->GetTableIndex(), &refNames, &refValues, (QueuedObjectInfo **)&dummy);
- _ASSERTE(parent == refParent);
- _ASSERTE(dummy->IsISerializableInstance());
-
- PTRARRAYREF refFields = (PTRARRAYREF)refValues;
- _ASSERTE(pIsInfo->GetFieldIndex() < refFields->GetNumComponents());
- refFields->SetAt(pIsInfo->GetFieldIndex(), m_newObject);
-
- LOG((LF_REMOTING, LL_INFO1000, "HandleISerializableFixup. Parent is ISerializable. Added field #%d to TSO record at index %d\n", pIsInfo->GetFieldIndex(), pIsInfo->GetTableIndex()));
-}
-
-void ObjectClone::HandleArrayFixup(OBJECTREF refParent, QueuedObjectInfo *currObjFixupInfo)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- THROWS;
- GC_TRIGGERS;
- }
- CONTRACTL_END
-
- _ASSERTE(refParent->GetMethodTable()->IsArray());
- BASEARRAYREF refParentArray = (BASEARRAYREF) refParent;
- GCPROTECT_BEGIN(refParentArray);
-
- NDimArrayMemberInfo *pArrInfo = (NDimArrayMemberInfo *)currObjFixupInfo;
- DWORD *pIndices = pArrInfo->GetIndices();
-
- TypeHandle arrayElementType = refParentArray->GetArrayElementTypeHandle();
- MethodTable *pArrayMT = refParentArray->GetMethodTable();
-
- DWORD Rank = pArrayMT->GetRank();
- SIZE_T Offset = 0;
- SIZE_T Multiplier = 1;
-
- _ASSERTE(Rank == pArrInfo->GetNumDimensions());
-
- for (int i = Rank-1; i >= 0; i--) {
- INT32 curIndex = pIndices[i];
- const INT32 *pBoundsPtr = refParentArray->GetBoundsPtr();
-
- // Bounds check each index
- // Casting to unsigned allows us to use one compare for [0..limit-1]
- _ASSERTE((UINT32) curIndex < (UINT32) pBoundsPtr[i]);
-
- Offset += curIndex * Multiplier;
- Multiplier *= pBoundsPtr[i];
- }
-
- // The follwing code is loosely based on COMArrayInfo::SetValue
-
- if (!arrayElementType.IsValueType())
- {
- if (!ObjIsInstanceOf(OBJECTREFToObject(m_newObject), arrayElementType))
- COMPlusThrow(kInvalidCastException,W("InvalidCast_StoreArrayElement"));
-
- OBJECTREF* pElem = (OBJECTREF*)(refParentArray->GetDataPtr() + (Offset * pArrayMT->GetComponentSize()));
- SetObjectReference(pElem,m_newObject,GetAppDomain());
- }
- else
- {
- // value class or primitive type
- OBJECTREF* pElem = (OBJECTREF*)(refParentArray->GetDataPtr() + (Offset * pArrayMT->GetComponentSize()));
- if (!arrayElementType.GetMethodTable()->UnBoxInto(pElem, m_newObject))
- COMPlusThrow(kInvalidCastException, W("InvalidCast_StoreArrayElement"));
- }
-
- LOG((LF_REMOTING, LL_INFO1000, "HandleArrayFixup. Parent is an array. Added element at offset %d\n", Offset));
- GCPROTECT_END();
-}
-
-void ObjectClone::HandleObjectFixup(OBJECTREF refParent, QueuedObjectInfo *currObjFixupInfo)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
- ObjectMemberInfo *pObjInfo = (ObjectMemberInfo *)currObjFixupInfo;
- FieldDesc *pTargetField = pObjInfo->GetFieldDesc();
- DWORD offset = pTargetField->GetOffset();
-
-#ifdef _DEBUG
- MethodTable *pTemp = refParent->GetMethodTable();
- _ASSERTE(offset < pTemp->GetBaseSize());
-#endif
-
- GCPROTECT_BEGIN(refParent);
-
- TypeHandle fldType = LoadExactFieldType(pTargetField, refParent, m_toDomain);
-
- if (!ObjIsInstanceOf(OBJECTREFToObject(m_newObject), fldType))
- COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
-
- OBJECTREF *pDest = (OBJECTREF *) (refParent->GetData() + offset);
- _ASSERTE(GetAppDomain()==m_toDomain);
- SetObjectReference(pDest, m_newObject, GetAppDomain());
-
- GCPROTECT_END();
-
- LOG((LF_REMOTING, LL_INFO1000, "HandleObjectFixup. Parent is a regular object. Added field at offset %d\n", offset));
-}
-
-#ifdef OBJECT_CLONER_STRICT_MODE
-static void DECLSPEC_NORETURN ThrowMissingFieldException(FieldDesc *pFD)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END;
-
- StackSString szField(SString::Utf8, pFD->GetName());
-
- StackSString szType;
- TypeString::AppendType(szType, TypeHandle(pFD->GetApproxEnclosingMethodTable()));
-
- COMPlusThrow(kSerializationException,
- IDS_SERIALIZATION_MISSING_FIELD,
- szField.GetUnicode(),
- szType.GetUnicode());
-}
-#endif
-
-void ObjectClone::ScanMemberFields(DWORD IObjRefTSOIndex, DWORD BoxedValTSOIndex)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
- _ASSERTE(m_currObject != NULL);
- _ASSERTE(m_newObject != NULL);
-
- MethodTable *pMT = m_currObject->GetMethodTable();
- _ASSERTE(!pMT->IsMarshaledByRef() && !pMT->IsTransparentProxy());
- _ASSERTE(!pMT->IsArray());
- MethodTable *pTargetMT = m_newObject->GetMethodTable();
-
- DWORD numFixupsNeeded = 0;
-
- if (RemotableMethodInfo::TypeIsConduciveToBlitting(pMT, pTargetMT))
- {
- _ASSERTE(pMT->GetAlignedNumInstanceFieldBytes() == pTargetMT->GetAlignedNumInstanceFieldBytes());
- DWORD numBytes = pMT->GetNumInstanceFieldBytes();
- BYTE *pFrom = m_currObject->GetData();
- BYTE *pTo = m_newObject->GetData();
- memcpyNoGCRefs(pTo, pFrom, numBytes);
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Object has no reference type fields. Blitting contents.\n"));
- }
- else if (AreTypesEmittedIdentically(pMT, pTargetMT))
- {
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Object not blittable but types are layed out for easy cloning .\n"));
- MethodTable *pCurrMT = pMT;
- MethodTable *pCurrTargetMT = pTargetMT;
- while (pCurrMT)
- {
- DWORD numInstanceFields = pCurrMT->GetNumIntroducedInstanceFields();
- _ASSERTE(pCurrTargetMT->GetNumIntroducedInstanceFields() == numInstanceFields);
-
- FieldDesc *pFields = pCurrMT->GetApproxFieldDescListRaw();
- FieldDesc *pTargetFields = pCurrTargetMT->GetApproxFieldDescListRaw();
-
- for (DWORD i = 0; i < numInstanceFields; i++)
- {
- if (pFields[i].IsNotSerialized())
- {
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Field %s is marked NonSerialized. Skipping.\n", pFields[i].GetName()));
- continue;
- }
-
- numFixupsNeeded += CloneField(&pFields[i], &pTargetFields[i]);
- }
-
- pCurrMT = pCurrMT->GetParentMethodTable();
- pCurrTargetMT = pCurrTargetMT->GetParentMethodTable();
- }
- }
- else
- {
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Object type layout is different.\n"));
-
- // The object types between source and destination have significant differences (some fields may be added, removed or
- // re-ordered, the type hierarchy may have had layers added or removed). We can still clone the object if every non-optional
- // field in the destination object can be found and serialized in a type with the same name in the source object. We ignore
- // fields and entire type layers that have been added in the source object and also any fields or layers that have been
- // removed as long as they don't include any fields that are mandatory in the destination object. We allow the fields within
- // a type layer to move around (we key the field by name only, the latter stage of cloning will check type equivalency and
- // as above we will widen primitive types if necessary). Since it requires significant effort to calculate whether the
- // objects can be cloned (and then locate corresponding fields in order to do so) we cache a mapping of source object fields
- // to destination object fields.
-
- // The following call will return such a mapping (it's an array where each entry is a pointer to a source object field desc
- // and the entries are in destination field index order, most derived type first, followed by second most derived type
- // etc.). If a mapping is impossible the method will throw.
- FieldDesc **pFieldMap = CrossDomainFieldMap::LookupOrCreateFieldMapping(pTargetMT, pMT);
- DWORD dwMapIndex = 0;
-
- MethodTable *pDstMT = pTargetMT;
- while (pDstMT)
- {
- FieldDesc *pDstFields = pDstMT->GetApproxFieldDescListRaw();
- DWORD numInstanceFields = pDstMT->GetNumIntroducedInstanceFields();
-
- for (DWORD i = 0; i < numInstanceFields; i++)
- {
- FieldDesc *pSrcField = pFieldMap[dwMapIndex++];
-
- // Non-serialized fields in the destination type (or optional fields where the source type doesn't have an
- // equivalent) don't have a source field desc.
- if (pSrcField == NULL)
- continue;
-
- numFixupsNeeded += CloneField(pSrcField, &pDstFields[i]);
- }
-
- pDstMT = pDstMT->GetParentMethodTable();
- }
-
- _ASSERTE(dwMapIndex == pTargetMT->GetNumInstanceFields());
- }
-
- if (numFixupsNeeded > 0)
- {
- ParentInfo fxInfo(numFixupsNeeded);
- if (IObjRefTSOIndex != (DWORD) -1)
- {
- _ASSERTE(m_cbInterface->IsIObjectReferenceType(pMT));
- fxInfo.SetIsIObjRefInstance();
- fxInfo.SetIObjRefIndexIntoTSO(IObjRefTSOIndex);
- }
- if (BoxedValTSOIndex != (DWORD) -1)
- {
- _ASSERTE(pMT->IsValueType());
- fxInfo.SetNeedsUnboxing();
- fxInfo.SetBoxedValIndexIntoTSO(BoxedValTSOIndex);
- }
- QOF.Enqueue(m_newObject, NULL, NULL, (QueuedObjectInfo *)&fxInfo);
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Current object had total of %d reference type fields. Adding to QOF.\n", numFixupsNeeded));
- // Delay calling any OnDeserialized callbacks until the end of the cloning operation (it's difficult to tell when all the
- // children have been deserialized).
- if (HasVtsCallbacks(m_newObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED))
- VDC.Enqueue(m_newObject, NULL, NULL, NULL);
- if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable()))
- {
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Adding object to Table of IDeserialization Callbacks\n"));
- QueuedObjectInfo noInfo;
- TDC.Enqueue(m_newObject, NULL, NULL, &noInfo);
- }
- }
- else
- {
- // This is effectively a leaf node (no complex children) so if the type has a callback for OnDeserialized we'll deliver it
- // now. This fixes callback ordering for a few more edge cases (e.g. VSW 415611) and is reasonably cheap. We can never do a
- // perfect job (in the presence of object graph cycles) and a near perfect job (intuitively ordered callbacks for acyclic
- // object graphs) is prohibitively expensive; so we're stuck with workarounds like this.
- InvokeVtsCallbacks(m_newObject, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED, m_toDomain);
- if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable()))
- MakeIDeserializationCallback(m_newObject);
- }
-}
-
-DWORD ObjectClone::CloneField(FieldDesc *pSrcField, FieldDesc *pDstField)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END;
-
- BOOL bFixupNeeded = FALSE;
-
- CorElementType srcType = pSrcField->GetFieldType();
- CorElementType dstType = pDstField->GetFieldType();
- DWORD srcOffset = pSrcField->GetOffset();
- DWORD dstOffset = pDstField->GetOffset();
-
- BOOL bUseWidenedValue = FALSE;
- ARG_SLOT fieldData = 0;
- if (srcType != dstType)
- {
- void *pData = m_currObject->GetData() + srcOffset;
-
- MethodTable *pSrcFieldMT = NULL;
- if (CorTypeInfo::IsPrimitiveType(srcType))
- pSrcFieldMT = MscorlibBinder::GetElementType(srcType);
- else
- pSrcFieldMT = LoadExactFieldType(pSrcField, m_currObject, m_fromDomain).AsMethodTable();
-
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Field %s has differing types at source and destination. Will try to convert.\n", pSrcField->GetName()));
- fieldData = HandleFieldTypeMismatch(dstType, srcType, pData, pSrcFieldMT);
- bUseWidenedValue = TRUE;
- }
-
- switch (dstType)
- {
- case ELEMENT_TYPE_I1:
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_BOOLEAN:
- {
- BYTE *pDest = m_newObject->GetData() + dstOffset;
- if (bUseWidenedValue)
- *pDest = (unsigned char) fieldData;
- else
- {
- BYTE *pByte = m_currObject->GetData() + srcOffset;
- *pDest = *pByte;
- }
- }
- break;
- case ELEMENT_TYPE_I2:
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_CHAR:
- {
- WORD *pDest = (WORD*)(m_newObject->GetData() + dstOffset);
- if (bUseWidenedValue)
- *pDest = (short) fieldData;
- else
- {
- WORD *pWord = (WORD*)(m_currObject->GetData() + srcOffset);
- *(pDest) = *pWord;
- }
- }
- break;
- case ELEMENT_TYPE_I4:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_R4:
- IN_WIN32(case ELEMENT_TYPE_FNPTR:)
- IN_WIN32(case ELEMENT_TYPE_I:)
- IN_WIN32(case ELEMENT_TYPE_U:)
- {
- DWORD *pDest = (DWORD*)(m_newObject->GetData() + dstOffset);
- if (bUseWidenedValue)
- *pDest = (int) fieldData;
- else
- {
- DWORD *pDword = (DWORD*)(m_currObject->GetData() + srcOffset);
- *(pDest) = *pDword;
- }
- }
- break;
- case ELEMENT_TYPE_R8:
- case ELEMENT_TYPE_I8:
- case ELEMENT_TYPE_U8:
- IN_WIN64(case ELEMENT_TYPE_FNPTR:)
- IN_WIN64(case ELEMENT_TYPE_I:)
- IN_WIN64(case ELEMENT_TYPE_U:)
- {
- INT64 *pDest = (INT64*)(m_newObject->GetData() + dstOffset);
- if (bUseWidenedValue)
- *pDest = fieldData;
- else
- {
- INT64 *pLong = (INT64*)(m_currObject->GetData() + srcOffset);
- *(pDest) = *pLong;
- }
- }
- break;
- case ELEMENT_TYPE_PTR:
- {
- void **pDest = (void**)(m_newObject->GetData() + dstOffset);
- void **pPtr = (void**)(m_currObject->GetData() + srcOffset);
- *(pDest) = *pPtr;
- }
- break;
- case ELEMENT_TYPE_STRING:
- case ELEMENT_TYPE_CLASS: // objectrefs
- case ELEMENT_TYPE_OBJECT:
- case ELEMENT_TYPE_SZARRAY: // single dim, zero
- case ELEMENT_TYPE_ARRAY: // all other arrays
- {
- OBJECTREF *pSrc = (OBJECTREF *)(m_currObject->GetData() + srcOffset);
- OBJECTREF *pDest = (OBJECTREF *)(m_newObject->GetData() + dstOffset);
-
- if ((*pSrc) == NULL)
- break;
-
- // If no deep copy is required, just copy the reference
- if (!m_cbInterface->RequiresDeepCopy(*pSrc))
- {
- _ASSERTE(GetAppDomain()==m_toDomain);
- SetObjectReference(pDest, *pSrc, GetAppDomain());
- break;
- }
-
- // Special case String
- if ((*pSrc)->GetMethodTable() == g_pStringClass)
- {
- // Better check the destination really expects a string (or maybe an object).
- TypeHandle thDstField = LoadExactFieldType(pDstField, m_newObject, m_toDomain);
- if (thDstField != TypeHandle(g_pStringClass) && thDstField != TypeHandle(g_pObjectClass))
- COMPlusThrow(kArgumentException, W("Arg_ObjObj"));
-
- STRINGREF refStr = (STRINGREF) *pSrc;
- refStr = m_cbInterface->AllocateString(refStr);
- // Get dest addr again, as a GC might have occurred
- pDest = (OBJECTREF *)(m_newObject->GetData() + dstOffset);
- _ASSERTE(GetAppDomain()==m_toDomain);
- SetObjectReference(pDest, refStr, GetAppDomain());
-
- break;
- }
-
- // Add the object to QOM
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Adding object in field %s to Queue of Objects to be Marshalled.\n", pSrcField->GetName()));
- ObjectMemberInfo objInfo(pDstField);
- bFixupNeeded = TRUE;
- QOM.Enqueue(*pSrc, NULL, NULL, (QueuedObjectInfo *)&objInfo);
- }
- break;
-
- case ELEMENT_TYPE_VALUETYPE:
- {
- TypeHandle th = LoadExactFieldType(pSrcField, m_currObject, m_fromDomain);
- _ASSERTE(!th.AsMethodTable()->IsByRefLike() && "Field types cannot contain stack pointers.");
-
- TypeHandle thTarget = LoadExactFieldType(pDstField, m_newObject, m_toDomain);
-
- MethodTable *pValueClassMT = th.AsMethodTable();
- MethodTable *pValueClassTargetMT = thTarget.AsMethodTable();
- if (!RemotableMethodInfo::TypeIsConduciveToBlitting(pValueClassMT, pValueClassTargetMT))
- {
- // Needs marshalling
- // We're allocating an object in the "to" domain
- // using a type from the "from" domain.
- OBJECTREF refTmpBox = BoxValueTypeInWrongDomain(m_currObject, srcOffset, pValueClassMT);
-
- // Nullable<T> might return null here. In that case we don't need to do anything
- // and the null value otherwise confuxes the fixup queue.
- if (refTmpBox != NULL)
- {
- // Add the object to QOM
- ObjectMemberInfo objInfo(pDstField);
- objInfo.SetNeedsUnboxing();
- bFixupNeeded = TRUE;
- QOM.Enqueue(refTmpBox, NULL, NULL, (QueuedObjectInfo *)&objInfo);
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Value type field %s has reference type contents. Boxing and adding to QOM.\n", pSrcField->GetName()));
- }
- }
- else
- {
- DWORD numBytesToCopy = th.AsMethodTable()->GetNumInstanceFieldBytes();
- BYTE *pByte = m_currObject->GetData() + srcOffset;
- BYTE *pDest = m_newObject->GetData() + dstOffset;
- memcpyNoGCRefs(pDest, pByte, numBytesToCopy);
- LOG((LF_REMOTING, LL_INFO1000, "ScanMemberFields. Value type field %s has no reference type contents. Blitting.\n", pSrcField->GetName()));
- }
- }
- break;
- default:
- _ASSERTE(!"Unknown element type seen in ObjectClone::ScanMemberFields");
- break;
- }
-
- return bFixupNeeded ? 1 : 0;
-}
-
-BOOL ObjectClone::AreTypesEmittedIdentically(MethodTable *pMT1, MethodTable *pMT2)
-{
- LIMITED_METHOD_CONTRACT;
-
- // Identical here means that both types have the same hierarchy (depth and names match) and that each level of the hierarchy has
- // the same fields (by name) at the same index.
- // We're going to be called quite frequently (once per call to ScanMemberFields) so until we're convinced that caching this
- // information is worth it we'll just compute the fast cases here and let the rest fall through to the slower technique. The
- // fast check is that the types are shared and identical or that they're loaded from the same file (in which case we have to be
- // a little more paranoid and check up the hierarchy).
- if (pMT1 == pMT2)
- return TRUE;
-
- // While the current level of the type is loaded from the same file...
- // Note that we used to check that the assemblies were the same; now we're more paranoid and check the actual modules scoping
- // the type are identical. This closes a security hole where identically named types in different modules of the same assembly
- // could cause the wrong type to be loaded in the server context allowing violation of the type system.
- while (pMT1->GetModule()->GetFile()->Equals(pMT2->GetModule()->GetFile()))
- {
- // Inspect the parents.
- pMT1 = pMT1->GetParentMethodTable();
- pMT2 = pMT2->GetParentMethodTable();
-
- // If the parents are the same shared type (e.g. Object), then we've found a match.
- if (pMT1 == pMT2)
- return TRUE;
-
- // Else check if one of the hierarchies has run out before the other (and therefore can't be equivalent).
- if (pMT1 == NULL || pMT2 == NULL)
- return FALSE;
- }
-
- return FALSE;
-}
-
-BOOL AreTypesEquivalent(MethodTable *pMT1, MethodTable *pMT2)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END;
-
- // Equivalent here is quite a weak predicate. All it means is that the types have the same (fully assembly qualified) name. The
- // derivation hierarchy is not inspected at all.
- StackSString szType1;
- StackSString szType2;
-
- TypeString::AppendType(szType1, TypeHandle(pMT1), TypeString::FormatNamespace |
- TypeString::FormatFullInst |
- TypeString::FormatAssembly |
- TypeString::FormatNoVersion);
- TypeString::AppendType(szType2, TypeHandle(pMT2), TypeString::FormatNamespace |
- TypeString::FormatFullInst |
- TypeString::FormatAssembly |
- TypeString::FormatNoVersion);
-
- return szType1.Equals(szType2);
-}
-
-PtrHashMap *CrossDomainFieldMap::s_pFieldMap = NULL;
-SimpleRWLock *CrossDomainFieldMap::s_pFieldMapLock = NULL;
-
-BOOL CrossDomainFieldMap::CompareFieldMapEntry(UPTR val1, UPTR val2)
-{
- CONTRACTL {
- MODE_ANY;
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- CrossDomainFieldMap::FieldMapEntry *pEntry1 = (CrossDomainFieldMap::FieldMapEntry *)(val1 << 1);
- CrossDomainFieldMap::FieldMapEntry *pEntry2 = (CrossDomainFieldMap::FieldMapEntry *)val2;
-
- if (pEntry1->m_pSrcMT == pEntry2->m_pSrcMT &&
- pEntry1->m_pDstMT == pEntry2->m_pDstMT)
- return TRUE;
-
- return FALSE;
-}
-
-CrossDomainFieldMap::FieldMapEntry::FieldMapEntry(MethodTable *pSrcMT, MethodTable *pDstMT, FieldDesc **pFieldMap)
-{
- WRAPPER_NO_CONTRACT;
-
- m_pSrcMT = pSrcMT;
- m_pDstMT = pDstMT;
- m_pFieldMap = pFieldMap;
- BaseDomain *pSrcDomain = pSrcMT->GetDomain();
- m_dwSrcDomain = pSrcDomain->IsAppDomain() ? ((AppDomain*)pSrcDomain)->GetId() : ADID(0);
- BaseDomain *pDstDomain = pDstMT->GetDomain();
- m_dwDstDomain = pDstDomain->IsAppDomain() ? ((AppDomain*)pDstDomain)->GetId() : ADID(0);
-}
-
-static BOOL IsOwnerOfRWLock(LPVOID lock)
-{
- // @TODO - SimpleRWLock does not have knowledge of which thread gets the writer
- // lock, so no way to verify
- return TRUE;
-}
-
-// Remove any entries in the table that refer to an appdomain that is no longer live.
-void CrossDomainFieldMap::FlushStaleEntries()
-{
- if (s_pFieldMapLock == NULL || s_pFieldMap == NULL)
- return;
-
- SimpleWriteLockHolder swlh(s_pFieldMapLock);
-
- bool fDeletedEntry = false;
- PtrHashMap::PtrIterator iter = s_pFieldMap->begin();
- while (!iter.end())
- {
- FieldMapEntry *pEntry = (FieldMapEntry *)iter.GetValue();
- AppDomainFromIDHolder adFrom(pEntry->m_dwSrcDomain, TRUE);
- AppDomainFromIDHolder adTo(pEntry->m_dwDstDomain, TRUE);
- if (adFrom.IsUnloaded() ||
- adTo.IsUnloaded()) //we do not use ptr for anything
- {
-#ifdef _DEBUG
- LPVOID pDeletedEntry =
-#endif
- s_pFieldMap->DeleteValue(pEntry->GetHash(), pEntry);
- _ASSERTE(pDeletedEntry == pEntry);
- delete pEntry;
- fDeletedEntry = true;
- }
- ++iter;
- }
-
- if (fDeletedEntry)
- s_pFieldMap->Compact();
-}
-
-FieldDesc **CrossDomainFieldMap::LookupOrCreateFieldMapping(MethodTable *pDstMT, MethodTable *pSrcMT)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END;
-
- // We lazily allocate the reader/writer lock we synchronize access to the hash with.
- if (s_pFieldMapLock == NULL)
- {
- void *pLockSpace = SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->AllocMem(S_SIZE_T(sizeof(SimpleRWLock)));
- SimpleRWLock *pLock = new (pLockSpace) SimpleRWLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT);
-
- if (FastInterlockCompareExchangePointer(&s_pFieldMapLock, pLock, NULL) != NULL)
- // We lost the race, give up our copy.
- SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()->BackoutMem(pLockSpace, sizeof(SimpleRWLock));
- }
-
- // Now we have a lock we can use to synchronize the remainder of the init.
- if (s_pFieldMap == NULL)
- {
- SimpleWriteLockHolder swlh(s_pFieldMapLock);
-
- if (s_pFieldMap == NULL)
- {
- PtrHashMap *pMap = new (SystemDomain::GetGlobalLoaderAllocator()->GetLowFrequencyHeap()) PtrHashMap();
- LockOwner lock = {s_pFieldMapLock, IsOwnerOfRWLock};
- pMap->Init(32, CompareFieldMapEntry, TRUE, &lock);
- s_pFieldMap = pMap;
- }
- }
- else
- {
- // Try getting an existing value first.
-
- FieldMapEntry sEntry(pSrcMT, pDstMT, NULL);
-
- SimpleReadLockHolder srlh(s_pFieldMapLock);
- FieldMapEntry *pFound = (FieldMapEntry *)s_pFieldMap->LookupValue(sEntry.GetHash(), (LPVOID)&sEntry);
- if (pFound != (FieldMapEntry *)INVALIDENTRY)
- return pFound->m_pFieldMap;
- }
-
- // We couldn't find an existing entry in the hash. Now we must go through the painstaking process of matching fields in the
- // destination object to their counterparts in the source object. We build an array of pointers to source field descs ordered by
- // destination type field index (all the fields for the most derived type first, then all the fields for the second most derived
- // type etc.).
- NewArrayHolder<FieldDesc*> pFieldMap(new FieldDesc*[pDstMT->GetNumInstanceFields()]);
- DWORD dwMapIndex = 0;
-
- // We start with the source and destination types for the object (which we know are equivalent at least in type name). For each
- // layer of the type hierarchy for the destination object (from the instance type through to Object) we attempt to locate the
- // corresponding source type in the hierarchy. This is non-trivial since either source or destination type hierarchies may have
- // added or removed layers. We ignore extra type layers in the source hierarchy and just concentrate on destination type layers
- // that introduce instance fields that are not marked NotSerializable. For each such layer we first locate the corresponding
- // source layer (via fully qualified type name) and then map each serialized (and possibly optional) destination field to the
- // corresponding source field (again by name). We don't allow a field to move around the type hierarchy (i.e. a field defined in
- // the base class in one version can't move to a derived type in later versions and be recognized as the original field).
- // Allowing this would introduce all sorts of ambiguity problems (consider the case of private fields all with the same name
- // implemented at every layer of the type hierarchy).
-
- bool fFirstPass = true;
- MethodTable *pCurrDstMT = pDstMT;
- MethodTable *pCurrSrcMT = pSrcMT;
- while (pCurrDstMT)
- {
- DWORD numInstanceFields = pCurrDstMT->GetNumIntroducedInstanceFields();
-
- // Skip destination types with no instance fields to clone.
- if (numInstanceFields == 0)
- {
- pCurrDstMT = pCurrDstMT->GetParentMethodTable();
- // Only safe to skip the source type as well on the first pass (the source version may have eliminated this level of
- // the type hierarchy).
- if (fFirstPass)
- pCurrSrcMT = pCurrSrcMT->GetParentMethodTable();
- fFirstPass = false;
- continue;
- }
-
- // We need to synchronize the source type with the destination type. This means skipping any source types in the
- // hierarchy that the destination doesn't know about.
- MethodTable *pCandidateMT = pCurrSrcMT;
- while (pCandidateMT)
- {
- if (fFirstPass || pCandidateMT == pCurrDstMT || AreTypesEquivalent(pCandidateMT, pCurrDstMT))
- {
- // Skip intermediate source types (the destination type didn't know anything about them, so they're surplus
- // to requirements).
- pCurrSrcMT = pCandidateMT;
- break;
- }
-
- pCandidateMT = pCandidateMT->GetParentMethodTable();
- }
-
-#ifdef OBJECT_CLONER_STRICT_MODE
- // If there's no candidate source type equivalent to the current destination type we need to prove that the destination
- // type has no mandatory instance fields or throw an exception (since there's no place to fetch the field values from).
- if (pCandidateMT == NULL)
- {
- FieldDesc *pFields = pCurrDstMT->GetApproxFieldDescListRaw();
-
- for (DWORD i = 0; i < numInstanceFields; i++)
- {
- if (pFields[i].IsNotSerialized() || pFields[i].IsOptionallySerialized())
- {
- pFieldMap[dwMapIndex++] = NULL;
- continue;
- }
-
- // We've found a field that must be cloned but have no corresponding source-side type to clone it from. Raise an
- // exception.
- ThrowMissingFieldException(&pFields[i]);
- }
-
- // If we get here we know the current destination type level was effectively a no-op. Move onto the next level.
- pCurrDstMT = pCurrDstMT->GetParentMethodTable();
- fFirstPass = false;
- continue;
- }
-#else
- // In lax matching mode we can ignore all fields, even those not marked optional. So the lack of an equivalent type in the
- // source hierarchy doesn't bother us. Mark all fields as having a default value and then move onto the next level in the
- // type hierarchy.
- if (pCandidateMT == NULL)
- {
- for (DWORD i = 0; i < numInstanceFields; i++)
- pFieldMap[dwMapIndex++] = NULL;
-
- pCurrDstMT = pCurrDstMT->GetParentMethodTable();
- fFirstPass = false;
- continue;
- }
-#endif
-
- // If we get here we have equivalent types in pCurrDstMT and pCurrSrcMT. Now we need to locate the source field desc
- // corresponding to every mandatory (and possibly optional) field in the destination type and record it in the field map.
- DWORD numSrcFields = pCurrSrcMT->GetNumIntroducedInstanceFields();
- DWORD numDstFields = pCurrDstMT->GetNumIntroducedInstanceFields();
-
- FieldDesc *pDstFields = pCurrDstMT->GetApproxFieldDescListRaw();
- FieldDesc *pSrcFields = pCurrSrcMT->GetApproxFieldDescListRaw();
-
- for (DWORD i = 0; i < numDstFields; i++)
- {
- // Non-serialized destination fields aren't filled in from source types.
- if (pDstFields[i].IsNotSerialized())
- {
- pFieldMap[dwMapIndex++] = NULL;
- continue;
- }
-
- // Go look for a field in the source type with the same name.
- LPCUTF8 szDstFieldName = pDstFields[i].GetName();
- DWORD j;
- for (j = 0; j < numSrcFields; j++)
- {
- LPCUTF8 szSrcFieldName = pSrcFields[j].GetName();
- if (strcmp(szDstFieldName, szSrcFieldName) == 0)
- {
- // Check that the field isn't marked NotSerialized (if it is then it's invisible to the cloner).
- if (pSrcFields[j].IsNotSerialized())
- j = numSrcFields;
- break;
- }
- }
-
-#ifdef OBJECT_CLONER_STRICT_MODE
- // If we didn't find a corresponding field it might not be fatal; the field could be optionally serializable from the
- // destination type's point of view.
- if (j == numSrcFields)
- {
- if (pDstFields[i].IsOptionallySerialized())
- {
- pFieldMap[dwMapIndex++] = NULL;
- continue;
- }
- // The field was required. Throw an exception.
- ThrowMissingFieldException(&pDstFields[i]);
- }
-#else
- // In lax matching mode we can ignore all fields, even those not marked optional. Simply mark this field as having the
- // default value.
- if (j == numSrcFields)
- {
- pFieldMap[dwMapIndex++] = NULL;
- continue;
- }
-#endif
-
- // Otherwise we found matching fields (in name at least, type processing is done later).
- pFieldMap[dwMapIndex++] = &pSrcFields[j];
- }
-
- pCurrDstMT = pCurrDstMT->GetParentMethodTable();
- pCurrSrcMT = pCurrSrcMT->GetParentMethodTable();
- fFirstPass = false;
- }
-
- _ASSERTE(dwMapIndex == pDstMT->GetNumInstanceFields());
-
- // Now we have a field map we should insert it into the hash.
- NewHolder<FieldMapEntry> pEntry(new FieldMapEntry(pSrcMT, pDstMT, pFieldMap));
- PREFIX_ASSUME(pEntry != NULL);
- pFieldMap.SuppressRelease();
-
- SimpleWriteLockHolder swlh(s_pFieldMapLock);
-
- UPTR key = pEntry->GetHash();
-
- FieldMapEntry *pFound = (FieldMapEntry *)s_pFieldMap->LookupValue(key, (LPVOID)pEntry);
- if (pFound == (FieldMapEntry *)INVALIDENTRY)
- {
- s_pFieldMap->InsertValue(key, (LPVOID)pEntry);
- pEntry.SuppressRelease();
- return pFieldMap;
- }
- else
- return pFound->m_pFieldMap;
-}
-
-ARG_SLOT ObjectClone::HandleFieldTypeMismatch(CorElementType dstType, CorElementType srcType, void *pData, MethodTable *pSrcMT)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
- _ASSERTE(m_context != ObjectFreezer);
- ARG_SLOT data = 0;
- InvokeUtil::CreatePrimitiveValue(dstType, srcType, pData, pSrcMT, &data);
- return data;
-}
-
-void ObjectClone::ScanISerializableMembers(DWORD IObjRefTSOIndex, DWORD ISerTSOIndex, DWORD BoxedValTSOIndex, PTRARRAYREF refValues)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-
- _ASSERTE(m_context != ObjectFreezer);
- // Queue the non-primitive types
- DWORD numFieldsToBeMarshalled = 0;
- PTRARRAYREF refNewValues = NULL;
-
- LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Scanning members of ISerializable type object.\n"));
- GCPROTECT_BEGIN(refValues);
-
- refNewValues = (PTRARRAYREF) AllocateObjectArray(refValues->GetNumComponents(), g_pObjectClass, FALSE);
-
- _ASSERTE(refNewValues != NULL);
-
- for (DWORD index = 0; index < refValues->GetNumComponents(); index++)
- {
- OBJECTREF refField = refValues->GetAt(index);
- if (refField == NULL)
- continue;
-
- if (CorTypeInfo::IsPrimitiveType(refField->GetTypeHandle().GetSignatureCorElementType()) ||
- refField->GetMethodTable() == g_pStringClass)
- {
- refNewValues->SetAt(index, refField);
- continue;
- }
-
- ISerializableMemberInfo isInfo(ISerTSOIndex, index);
- QOM.Enqueue(refField, NULL, NULL, (QueuedObjectInfo *) &isInfo);
- numFieldsToBeMarshalled++;
- refNewValues->SetAt(index, NULL);
- LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Member at index %d is reference type. Adding to QOM.\n", index));
- }
- GCPROTECT_END();
-
- // Update TSO
- OBJECTREF refNames = NULL, refFields = NULL;
- QueuedObjectInfo *pDummy;
- OBJECTREF newObj;
- newObj = TSO.GetAt(ISerTSOIndex, &refNames, &refFields, &pDummy);
- _ASSERTE(newObj == m_newObject);
-
- TSO.SetAt(ISerTSOIndex, m_newObject, refNames, refNewValues, pDummy);
-
- if (numFieldsToBeMarshalled > 0)
- {
- ParentInfo fxInfo(numFieldsToBeMarshalled);
- fxInfo.SetIsISerializableInstance();
- fxInfo.SetIObjRefIndexIntoTSO(IObjRefTSOIndex);
- fxInfo.SetISerIndexIntoTSO(ISerTSOIndex);
- fxInfo.SetBoxedValIndexIntoTSO(BoxedValTSOIndex);
- QOF.Enqueue(m_newObject, NULL, NULL, (QueuedObjectInfo *) &fxInfo);
- LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Current object had total of %d reference type fields. Adding to QOF.\n", numFieldsToBeMarshalled));
- // Delay calling any OnDeserialized callbacks until the end of the cloning operation (it's difficult to tell when all the
- // children have been deserialized).
- if (HasVtsCallbacks(m_newObject->GetMethodTable(), RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED))
- VDC.Enqueue(m_newObject, NULL, NULL, NULL);
- if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable()))
- {
- LOG((LF_REMOTING, LL_INFO1000, "ScanISerializableMembers. Adding object to Table of IDeserialization Callbacks\n"));
- QueuedObjectInfo noInfo;
- TDC.Enqueue(m_newObject, NULL, NULL, &noInfo);
- }
- }
- else
- {
- // This is effectively a leaf node (no complex children) so if the type has a callback for OnDeserialized we'll deliver it
- // now. This fixes callback ordering for a few more edge cases (e.g. VSW 415611) and is reasonably cheap. We can never do a
- // perfect job (in the presence of object graph cycles) and a near perfect job (intuitively ordered callbacks for acyclic
- // object graphs) is prohibitively expensive; so we're stuck with workarounds like this.
- InvokeVtsCallbacks(m_newObject, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED, m_toDomain);
- if (m_cbInterface->RequiresDeserializationCallback(m_newObject->GetMethodTable()))
- MakeIDeserializationCallback(m_newObject);
- }
-}
-
-void ObjectClone::ScanArrayMembers()
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-#ifdef _DEBUG
- MethodTable *pCurrMT = m_currObject->GetMethodTable();
- _ASSERTE(pCurrMT && pCurrMT->IsArray());
- MethodTable *pNewMT = m_newObject->GetMethodTable();
- _ASSERTE(pNewMT && pNewMT->IsArray());
-#endif
-
- LOG((LF_REMOTING, LL_INFO1000, "ScanArrayMembers. Scanning members of array object.\n"));
- BASEARRAYREF refFromArray = (BASEARRAYREF) m_currObject;
- BASEARRAYREF refToArray = (BASEARRAYREF) m_newObject;
-
- GCPROTECT_BEGIN(refFromArray);
- GCPROTECT_BEGIN(refToArray);
-
- TypeHandle toArrayElementType = refToArray->GetArrayElementTypeHandle();
- DWORD numComponents = refFromArray->GetNumComponents();
- MethodTable *pArrayMT = refFromArray->GetMethodTable();
-
- DWORD rank = pArrayMT->GetRank();
- DWORD dwOffset = 0;
-
- DWORD *pIndices = (DWORD*) _alloca(sizeof(DWORD) * rank);
- VOID *pTemp = _alloca(sizeof(NDimArrayMemberInfo) + rank * sizeof(DWORD));
- NDimArrayMemberInfo *pArrInfo = new (pTemp) NDimArrayMemberInfo(rank);
-
- bool boxingObjects = (pArrayMT->GetArrayElementType() == ELEMENT_TYPE_VALUETYPE);
-
- // Must enter the from domain if we are going to be allocating any non-agile boxes
- ENTER_DOMAIN_PTR_PREDICATED(m_fromDomain,ADV_RUNNINGIN,boxingObjects);
-
- if (boxingObjects)
- {
- pArrInfo->SetNeedsUnboxing();
-
- // We may be required to activate value types of array elements, since we
- // are going to box them. Hoist out the required domain transition and
- // activation.
-
- MethodTable *pMT = ((BASEARRAYREF)m_currObject)->GetArrayElementTypeHandle().GetMethodTable();
- pMT->EnsureInstanceActive();
- }
-
- DWORD numFixupsNeeded = 0;
- for (DWORD i = 0; i < numComponents; i++)
- {
- // The array could be huge. To avoid keeping a pending GC waiting (and maybe timing out) we're going to pulse the GC mode
- // every so often. Do this more freqeuntly in debug builds, where each iteration through this loop takes considerably
- // longer.
-#ifdef _DEBUG
-#define COPY_CYCLES 1024
-#else
-#define COPY_CYCLES 8192
-#endif
- if ((i % COPY_CYCLES) == (COPY_CYCLES - 1))
- GetThread()->PulseGCMode();
-
- const INT32 *pBoundsPtr = refFromArray->GetBoundsPtr();
- DWORD findIndices = i;
- for (DWORD rankIndex = rank; rankIndex > 0; rankIndex--)
- {
- DWORD numElementsInDimension = pBoundsPtr[rankIndex - 1];
- DWORD quotient = findIndices / numElementsInDimension;
- DWORD remainder = findIndices % numElementsInDimension;
- pIndices[rankIndex - 1] = remainder;
- findIndices = quotient;
- }
-
- pArrInfo->SetIndices(pIndices);
-
- Object *rv = GetObjectFromArray((BASEARRAYREF *)&m_currObject, dwOffset);
- if (rv != NULL)
- {
- OBJECTREF oRef = ObjectToOBJECTREF(rv);
-
- if (oRef->GetMethodTable() == g_pStringClass && m_context != ObjectFreezer)
- {
- OBJECTREF* pElem = (OBJECTREF*)(refToArray->GetDataPtr() + (dwOffset * pArrayMT->GetComponentSize()));
- SetObjectReference(pElem,oRef,GetAppDomain());
- }
- else
- {
- // Add the object to QOM
- numFixupsNeeded++;
- QOM.Enqueue(oRef, NULL, NULL, pArrInfo);
- LOG((LF_REMOTING, LL_INFO1000, "ScanArrayMembers. Element at offset %d is reference type. Adding to QOM.\n", dwOffset));
- }
- }
- dwOffset ++;
- }
-
- if (numFixupsNeeded > 0)
- {
- ParentInfo fxInfo(numFixupsNeeded);
- QOF.Enqueue(m_newObject, NULL, NULL, (QueuedObjectInfo *)&fxInfo);
- LOG((LF_REMOTING, LL_INFO1000, "ScanArrayMembers. Current object had total of %d reference type fields. Adding to QOF.\n", numFixupsNeeded));
- }
-
- END_DOMAIN_TRANSITION;
-
- GCPROTECT_END();
- GCPROTECT_END();
-}
-
-#ifdef _MSC_VER
-#pragma warning(push)
-#pragma warning(disable:4244)
-#endif // _MSC_VER
-Object *ObjectClone::GetObjectFromArray(BASEARRAYREF* arrObj, DWORD dwOffset)
-{
- CONTRACTL {
- THROWS;
- if ((*arrObj)->GetArrayElementTypeHandle().GetMethodTable()->IsValueType()) GC_TRIGGERS; else GC_NOTRIGGER;
- } CONTRACTL_END;
-
- // Get the type of the element...
- switch ((*arrObj)->GetArrayElementType()) {
-
- case ELEMENT_TYPE_VOID:
- return NULL;
-
- case ELEMENT_TYPE_CLASS: // Class
- case ELEMENT_TYPE_SZARRAY: // Single Dim, Zero
- case ELEMENT_TYPE_ARRAY: // General Array
- case ELEMENT_TYPE_STRING:
- case ELEMENT_TYPE_OBJECT:
- {
- _ASSERTE((*arrObj)->GetComponentSize() == sizeof(OBJECTREF));
- BYTE* pData = ((BYTE*)(*arrObj)->GetDataPtr()) + (dwOffset * sizeof(OBJECTREF));
- return *(Object **)pData;
- }
-
- case ELEMENT_TYPE_VALUETYPE:
- {
- MethodTable *pMT = (*arrObj)->GetArrayElementTypeHandle().GetMethodTable();
- WORD wComponentSize = (*arrObj)->GetComponentSize();
- BYTE* pData = ((BYTE*)(*arrObj)->GetDataPtr()) + (dwOffset * wComponentSize);
- return OBJECTREFToObject(pMT->Box(pData));
- }
- case ELEMENT_TYPE_BOOLEAN: // boolean
- case ELEMENT_TYPE_I1: // sbyte
- case ELEMENT_TYPE_U1:
- case ELEMENT_TYPE_I2: // short
- case ELEMENT_TYPE_U2:
- case ELEMENT_TYPE_CHAR: // char
- case ELEMENT_TYPE_I4: // int
- case ELEMENT_TYPE_I:
- case ELEMENT_TYPE_U:
- case ELEMENT_TYPE_U4:
- case ELEMENT_TYPE_I8: // long
- case ELEMENT_TYPE_U8:
- case ELEMENT_TYPE_R4: // float
- case ELEMENT_TYPE_R8: // double
- case ELEMENT_TYPE_PTR:
- {
- // Note that this is a cloned version of the value class case above for performance
-
- // Watch for GC here. We allocate the object and then
- // grab the void* to the data we are going to copy.
- MethodTable *pMT = (*arrObj)->GetArrayElementTypeHandle().GetMethodTable();
- OBJECTREF obj = ::AllocateObject(pMT);
- WORD wComponentSize = (*arrObj)->GetComponentSize();
- BYTE* pData = ((BYTE*)(*arrObj)->GetDataPtr()) + (dwOffset * wComponentSize);
- CopyValueClassUnchecked(obj->UnBox(), pData, (*arrObj)->GetArrayElementTypeHandle().GetMethodTable());
- return OBJECTREFToObject(obj);
- }
-
- case ELEMENT_TYPE_END:
- default:
- _ASSERTE(!"Unknown array element type");
- }
-
- _ASSERTE(!"Should never get here");
- return NULL;
-}
-#ifdef _MSC_VER
-#pragma warning(pop)
-#endif // _MSC_VER: warning C4244
-
-
-void ObjectClone::CompleteValueTypeFields(OBJECTREF newObj, OBJECTREF refParent, QueuedObjectInfo *objInfo)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_TRIGGERS;
- THROWS;
- }
- CONTRACTL_END
-
-#ifdef _DEBUG
- {
- SString ssTypeName;
- SString ssParentTypeName;
- newObj->GetMethodTable()->_GetFullyQualifiedNameForClassNestedAware(ssTypeName);
- refParent->GetMethodTable()->_GetFullyQualifiedNameForClassNestedAware(ssParentTypeName);
- LOG((LF_REMOTING, LL_INFO1000, "CompleteValueTypeFields. Fixing up value type field of type %S into parent of type %S.\n",
- ssTypeName.GetUnicode(), ssParentTypeName.GetUnicode()));
- }
-#endif
-
- ValueTypeInfo *pValTypeInfo = (ValueTypeInfo *)objInfo;
- QueuedObjectInfo *pFixupInfo = pValTypeInfo->GetFixupInfo();
- PREFIX_ASSUME(pFixupInfo != NULL);
-
- _ASSERTE(pFixupInfo->NeedsUnboxing());
- if (pFixupInfo->IsArray())
- {
- m_newObject = newObj;
- HandleArrayFixup(refParent, pFixupInfo);
- }
- else
- {
- GCPROTECT_BEGIN(refParent);
- GCPROTECT_BEGIN(newObj);
- ObjectMemberInfo *pObjInfo = (ObjectMemberInfo *)pFixupInfo;
- FieldDesc *pTargetField = pObjInfo->GetFieldDesc();
-
- TypeHandle fldType = LoadExactFieldType(pTargetField, refParent, m_toDomain);
- void *pDest = refParent->GetData() + pTargetField->GetOffset();
- _ASSERTE(GetAppDomain()==m_toDomain);
-
- if (!fldType.GetMethodTable()->UnBoxInto(pDest, newObj))
- COMPlusThrow(kArgumentException,W("Arg_ObjObj"));
-
- GCPROTECT_END();
- GCPROTECT_END();
- }
- pValTypeInfo->SetHasBeenProcessed();
-}
-
-void ObjectClone::CompleteSpecialObjects()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- OBJECTREF nextObj = NULL;
- OBJECTREF refNames = NULL;
- OBJECTREF refValues = NULL;
- SpecialObjectInfo *pObjInfo = NULL;
-
- GCPROTECT_BEGIN(refNames);
- GCPROTECT_BEGIN(refValues);
-
- DWORD skippedObjects = 0;
- DWORD numLoops = 0;
-
- if (TSO.GetCount() == 0)
- goto EarlyExit;
-
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Beginning.\n"));
- do
- {
- skippedObjects = 0;
- numLoops++;
- DWORD index = 0;
- TSO.BeginEnumeration(&index);
- while((nextObj = TSO.GetNext(&index, &refNames, &refValues, (QueuedObjectInfo **)&pObjInfo)) != NULL)
- {
- if (pObjInfo->HasBeenProcessed())
- continue;
-
- if (pObjInfo->IsISerializableInstance())
- {
- _ASSERTE(m_context != ObjectFreezer);
-
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. ISerializable instance at index %d.\n", index));
- ISerializableInstanceInfo *iserInfo = (ISerializableInstanceInfo *)pObjInfo;
- if (iserInfo->GetNumSpecialMembers() > 0)
- {
- if (CheckForUnresolvedMembers(iserInfo))
- {
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Skipping ISerializable instance due to unresolved members.\n"));
- skippedObjects++;
- continue;
- }
- }
- CompleteISerializableObject(nextObj, refNames, refValues, iserInfo);
- }
- else if (pObjInfo->IsIObjRefInstance())
- {
- _ASSERTE(m_context != ObjectFreezer);
-
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. IObjectReference instance at index %d.\n", index));
- IObjRefInstanceInfo *iorInfo = (IObjRefInstanceInfo *)pObjInfo;
- if (iorInfo->GetNumSpecialMembers() > 0 ||
- iorInfo->GetISerTSOIndex() != (DWORD) -1)
- {
- if (CheckForUnresolvedMembers(iorInfo))
- {
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Skipping IObjectReference instance due to unresolved members.\n"));
- skippedObjects++;
- continue;
- }
- }
- if (!CompleteIObjRefObject(nextObj, index, iorInfo))
- skippedObjects++;
- }
- else
- {
- _ASSERTE(pObjInfo->IsBoxedObject());
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Boxed valuetype instance at index %d.\n", index));
- ValueTypeInfo *valTypeInfo = (ValueTypeInfo *)pObjInfo;
- if (valTypeInfo->GetNumSpecialMembers() > 0 ||
- valTypeInfo->GetISerTSOIndex() != (DWORD) -1 ||
- valTypeInfo->GetIObjRefTSOIndex() != (DWORD) -1)
- {
- if (CheckForUnresolvedMembers(valTypeInfo))
- {
- LOG((LF_REMOTING, LL_INFO1000, "CompleteSpecialObjects. Skipping boxed value instance due to unresolved members.\n"));
- skippedObjects++;
- continue;
- }
- }
- // If we were waiting on an IObjRef fixup then the target object will have changed.
- if (valTypeInfo->GetIObjRefTSOIndex() != (DWORD) -1)
- {
- OBJECTREF dummy1, dummy2;
- QueuedObjectInfo *dummy3;
- nextObj = TSO.GetAt(valTypeInfo->GetIObjRefTSOIndex(), &dummy1, &dummy2, &dummy3);
- }
- CompleteValueTypeFields(nextObj, refNames, valTypeInfo);
- }
-
- };
- } while (skippedObjects > 0 && numLoops < 100);
-
- if (skippedObjects > 0 && numLoops >= 100)
- {
- COMPlusThrow(kSerializationException, IDS_SERIALIZATION_UNRESOLVED_SPECIAL_OBJECT);
- }
-EarlyExit: ;
- GCPROTECT_END();
- GCPROTECT_END();
-}
-
-BOOL ObjectClone::CheckForUnresolvedMembers(SpecialObjectInfo *splInfo)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- BOOL foundUnresolvedMember = FALSE;
-
- DWORD mappingIndex = splInfo->GetMappingTableIndex();
- for (DWORD count = 0; count < splInfo->GetNumSpecialMembers(); count++)
- {
- DWORD memberIndex = TMappings.GetAt(mappingIndex++);
- SpecialObjectInfo *pMemberInfo;
- OBJECTREF dummy1, dummy2, dummy3;
- dummy1 = TSO.GetAt(memberIndex, &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo);
- // An unresolved IObjRef member is a blocker for any special object parent
- if (pMemberInfo->IsIObjRefInstance() && !pMemberInfo->HasBeenProcessed())
- {
- LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. Found unresolved IObjectReference member at index %d.\n", memberIndex));
- foundUnresolvedMember = TRUE;
- break;
- }
-
- // An unresolved ISer member is a blocker for IObjRef parent
- if (pMemberInfo->IsISerializableInstance() &&
- !pMemberInfo->HasBeenProcessed() &&
- splInfo->IsIObjRefInstance())
- {
- LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. Found unresolved ISerializable member at index %d.\n", memberIndex));
- foundUnresolvedMember = TRUE;
- break;
- }
-
- // An unresolved boxed object is a blocker for a boxed parent or an IObjRef parent
- if (pMemberInfo->IsBoxedObject() &&
- !pMemberInfo->HasBeenProcessed() &&
- (splInfo->IsIObjRefInstance() || splInfo->IsBoxedObject()))
- {
- LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. Found unresolved boxed valuetype member at index %d.\n", memberIndex));
- foundUnresolvedMember = TRUE;
- break;
- }
- }
-
- // Done checking members. Now check if this instance itself needs some processing
- // If an instance is both ISer and IObj, then ISer should be processed before IObjRef
- if (!foundUnresolvedMember && splInfo->IsIObjRefInstance())
- {
- IObjRefInstanceInfo *pObjRefInfo = (IObjRefInstanceInfo *)splInfo;
- if (pObjRefInfo->GetISerTSOIndex() != (DWORD) -1)
- {
- // Check if the ISer requirements have been met
- SpecialObjectInfo *pMemberInfo;
- OBJECTREF dummy1, dummy2, dummy3;
- dummy1 = TSO.GetAt(pObjRefInfo->GetISerTSOIndex(), &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo);
- if (!pMemberInfo->HasBeenProcessed())
- {
- LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. This instance is also ISerializable at index %d. Not resolved yet.\n", pObjRefInfo->GetISerTSOIndex()));
- foundUnresolvedMember = TRUE;
- }
- }
- }
-
- // If an instance is ISer, IObj and a boxed value type, then ISer,IObj should be processed before unboxing
- if (!foundUnresolvedMember && splInfo->IsBoxedObject())
- {
- ValueTypeInfo *pValTypeInfo = (ValueTypeInfo *)splInfo;
- if (pValTypeInfo->GetISerTSOIndex() != (DWORD) -1)
- {
- // Check if the ISer requirements have been met
- SpecialObjectInfo *pMemberInfo;
- OBJECTREF dummy1, dummy2, dummy3;
- dummy1 = TSO.GetAt(pValTypeInfo->GetISerTSOIndex(), &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo);
- if (!pMemberInfo->HasBeenProcessed())
- {
- LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. This instance is also ISerializable at index %d. Not resolved yet.\n", pValTypeInfo->GetISerTSOIndex()));
- foundUnresolvedMember = TRUE;
- }
- }
- if (!foundUnresolvedMember && pValTypeInfo->GetIObjRefTSOIndex() != (DWORD) -1)
- {
- // Check if the ISer requirements have been met
- SpecialObjectInfo *pMemberInfo;
- OBJECTREF dummy1, dummy2, dummy3;
- dummy1 = TSO.GetAt(pValTypeInfo->GetIObjRefTSOIndex(), &dummy2, &dummy3, (QueuedObjectInfo **)&pMemberInfo);
- if (!pMemberInfo->HasBeenProcessed())
- {
- LOG((LF_REMOTING, LL_INFO1000, "CheckForUnresolvedMembers. This instance is also IObjectReference at index %d. Not resolved yet.\n", pValTypeInfo->GetIObjRefTSOIndex()));
- foundUnresolvedMember = TRUE;
- }
- }
- }
- return foundUnresolvedMember;
-}
-
-void ObjectClone::CompleteISerializableObject(OBJECTREF IserObj, OBJECTREF refNames, OBJECTREF refValues, ISerializableInstanceInfo *iserInfo)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- _ASSERTE(m_context != ObjectFreezer);
-
- struct _gc {
- OBJECTREF IserObj;
- OBJECTREF refNames;
- OBJECTREF refValues;
- OBJECTREF refSerInfo;
- } gc;
-
- gc.IserObj = IserObj;
- gc.refNames = refNames;
- gc.refValues = refValues;
- gc.refSerInfo = NULL;
-
- GCPROTECT_BEGIN(gc);
-
-#ifdef _DEBUG
- {
- DefineFullyQualifiedNameForClass();
- LOG((LF_REMOTING, LL_INFO1000, "CompleteISerializableObject. Completing ISerializable object of type %s.\n",
- GetFullyQualifiedNameForClassNestedAware(gc.IserObj->GetMethodTable())));
- }
-#endif
-
- BOOL bIsBoxed = gc.IserObj->GetMethodTable()->IsValueType();
-
- // StreamingContextData is an out parameter of the managed callback, so it's passed by reference on all platforms.
- RuntimeMethodHandle::StreamingContextData context = {0};
-
- PREPARE_NONVIRTUAL_CALLSITE(METHOD__OBJECTCLONEHELPER__PREPARE_DATA);
-
- DECLARE_ARGHOLDER_ARRAY(args, 4);
-
- args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.IserObj);
- args[ARGNUM_1] = OBJECTREF_TO_ARGHOLDER(gc.refNames);
- args[ARGNUM_2] = OBJECTREF_TO_ARGHOLDER(gc.refValues);
- args[ARGNUM_3] = PTR_TO_ARGHOLDER(&context);
-
- CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
- CALL_MANAGED_METHOD_RETREF(gc.refSerInfo, OBJECTREF, args);
-
- if (iserInfo->IsTargetNotISerializable())
- {
- // Prepare data would have constructed the object already
- _ASSERTE(gc.refSerInfo == NULL);
- }
- else
- {
- _ASSERTE(gc.refSerInfo != NULL);
- MethodTable *pMT = gc.IserObj->GetMethodTable();
- _ASSERTE(pMT);
-
- MethodDesc * pCtor;
-
-#ifdef FEATURE_IMPERSONATION
- // Deal with the WindowsIdentity class specially by calling an internal
- // serialization constructor; the public one has a security demand that
- // breaks partial trust scenarios and is too expensive to assert for.
- if (MscorlibBinder::IsClass(pMT, CLASS__WINDOWS_IDENTITY))
- pCtor = MscorlibBinder::GetMethod(METHOD__WINDOWS_IDENTITY__SERIALIZATION_CTOR);
- else
-#endif
- pCtor = MemberLoader::FindConstructor(pMT, &gsig_IM_SerInfo_StrContext_RetVoid);
-
- if (pCtor == NULL)
- {
- DefineFullyQualifiedNameForClassW();
- COMPlusThrow(kSerializationException, IDS_SERIALIZATION_CTOR_NOT_FOUND,
- GetFullyQualifiedNameForClassNestedAwareW(pMT));
- }
-
- MethodDescCallSite ctor(pCtor);
-
- ARG_SLOT argSlots[3];
- // Nullable<T> does not implement ISerializable.
- _ASSERTE(!Nullable::IsNullableType(gc.IserObj->GetMethodTable()));
- argSlots[0] = (bIsBoxed ? (ARG_SLOT)(SIZE_T)(gc.IserObj->UnBox()) : ObjToArgSlot(gc.IserObj));
- argSlots[1] = ObjToArgSlot(gc.refSerInfo);
-#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
- static_assert_no_msg(sizeof(context) == sizeof(ARG_SLOT));
- argSlots[2] = *(ARG_SLOT*)(&context); // StreamingContext is passed by value on x86 and ARM
-#elif defined(_WIN64)
- static_assert_no_msg(sizeof(context) > sizeof(ARG_SLOT));
- argSlots[2] = PtrToArgSlot(&context); // StreamingContext is passed by reference on WIN64
-#else // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_
- PORTABILITY_ASSERT("ObjectClone::CompleteISerializableObject() - NYI on this platform");
-#endif // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_
- ctor.CallWithValueTypes(&argSlots[0]);
- }
- iserInfo->SetHasBeenProcessed();
-
- GCPROTECT_END();
-
-}
-
-// FALSE means the object could not be resolved and need to perform more iterations
-BOOL ObjectClone::CompleteIObjRefObject(OBJECTREF IObjRef, DWORD tsoIndex, IObjRefInstanceInfo *iorInfo)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- BOOL bResult = FALSE;
-
- struct _gc {
- OBJECTREF IObjRef;
- OBJECTREF newObj;
- OBJECTREF refParent;
- OBJECTREF refFromObj;
- OBJECTREF resolvedObject;
- } gc;
-
- gc.IObjRef = IObjRef;
- gc.newObj = NULL;
- gc.refParent = NULL;
- gc.refFromObj = NULL;
- gc.resolvedObject = NULL;
-
- GCPROTECT_BEGIN(gc);
-
- _ASSERTE(m_context != ObjectFreezer);
- // First check if this is a repeat object
- if (iorInfo->IsRepeatObject())
- {
- OBJECTREF dummy;
- dummy = TSO.GetAt(tsoIndex, &gc.refFromObj, &gc.refParent, (QueuedObjectInfo **)&iorInfo);
- PREFIX_ASSUME(gc.refFromObj != NULL);
-
- // Look in the Table of Seen objects whether this IObjRef has been resolved
- int currId;
- currId = TOS.HasID(gc.refFromObj, &gc.resolvedObject);
- _ASSERTE(currId != -1);
-
- MethodTable *pResolvedMT = gc.resolvedObject->GetMethodTable();
- if (!pResolvedMT->IsTransparentProxy() &&
- m_cbInterface->IsIObjectReferenceType(pResolvedMT))
- {
- bResult = FALSE;
- }
- else
- {
-#ifdef _DEBUG
- {
- DefineFullyQualifiedNameForClass();
- LOG((LF_REMOTING, LL_INFO1000, "CompleteIObjRefObject. Found IObjectReference object of type %s already resolved.\n",
- GetFullyQualifiedNameForClassNestedAware(gc.IObjRef->GetMethodTable())));
- }
-#endif
-
- // Yes, its been resolved.
- // Fix the object into its parent (unless it requires unboxing, in which case there's another entry in the TSO ready to
- // do that).
- QueuedObjectInfo *pFixupInfo = (QueuedObjectInfo *)iorInfo->GetFixupInfo();
- PREFIX_ASSUME(pFixupInfo != NULL);
- if (pFixupInfo->NeedsUnboxing())
- {
- TSO.SetAt(tsoIndex, gc.resolvedObject, gc.refFromObj, gc.refParent, iorInfo);
- iorInfo->SetHasBeenProcessed();
- bResult = TRUE;
- }
- else
- {
- if (gc.refParent == NULL)
- m_topObject = gc.resolvedObject;
- else
- {
- m_newObject = gc.resolvedObject;
- if (pFixupInfo->NeedsUnboxing())
- CompleteValueTypeFields(gc.resolvedObject, gc.refParent, pFixupInfo);
- else
- Fixup(gc.resolvedObject, gc.refParent, pFixupInfo);
- }
- iorInfo->SetHasBeenProcessed();
- bResult = TRUE;
- }
- }
- }
- else
- {
- MethodTable *pMT = gc.IObjRef->GetMethodTable();
- _ASSERTE(pMT);
-
- MethodTable *pItf = MscorlibBinder::GetClass(CLASS__IOBJECTREFERENCE);
- MethodDesc *pMeth = GetInterfaceMethodImpl(pMT, pItf, 0);
- MethodDescCallSite method(pMeth, &gc.IObjRef);
-
- // Ensure Streamingcontext type is loaded. Do not delete this line
- MethodTable *pMTStreamingContext;
- pMTStreamingContext = MscorlibBinder::GetClass(CLASS__STREAMING_CONTEXT);
- _ASSERTE(pMTStreamingContext);
-
- ARG_SLOT arg[2];
- arg[0] = ObjToArgSlot(gc.IObjRef);
-
- RuntimeMethodHandle::StreamingContextData context = { NULL, GetStreamingContextState() };
-#ifdef _WIN64
- static_assert_no_msg(sizeof(context) > sizeof(ARG_SLOT));
- arg[1] = PtrToArgSlot(&context);
-#else
- static_assert_no_msg(sizeof(context) <= sizeof(ARG_SLOT));
- arg[1] = *(ARG_SLOT*)(&context);
-#endif
-
- gc.newObj = method.CallWithValueTypes_RetOBJECTREF(&arg[0]);
-
- INDEBUG(DefineFullyQualifiedNameForClass();)
-
- _ASSERTE(gc.newObj != NULL);
- MethodTable *pNewMT = gc.newObj->GetMethodTable();
- if (!pNewMT->IsTransparentProxy() &&
- gc.newObj != gc.IObjRef &&
- m_cbInterface->IsIObjectReferenceType(pNewMT))
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO1000,
- "CompleteIObjRefObject. GetRealObject on object of type %s returned another IObjectReference. Adding back to TSO.\n",
- GetFullyQualifiedNameForClassNestedAware(gc.IObjRef->GetMethodTable())));
-#endif
-
- // Put this back into the table
- OBJECTREF dummy;
- dummy = TSO.GetAt(tsoIndex, &gc.refFromObj, &gc.refParent, (QueuedObjectInfo **)&iorInfo);
- TSO.SetAt(tsoIndex, gc.newObj, gc.refFromObj, gc.refParent, iorInfo);
- bResult = FALSE;
- }
- else
- {
-#ifdef _DEBUG
- LOG((LF_REMOTING, LL_INFO1000,
- "CompleteIObjRefObject. Called GetRealObject on object of type %s. Fixing it up into its parent.\n",
- GetFullyQualifiedNameForClassNestedAware(gc.IObjRef->GetMethodTable())));
-#endif
- // Fix the object into its parent (unless it requires unboxing, in which case there's another entry in the TSO ready to
- // do that).
- QueuedObjectInfo *pFixupInfo = (QueuedObjectInfo *)iorInfo->GetFixupInfo();
- OBJECTREF dummy;
- dummy = TSO.GetAt(tsoIndex, &gc.refFromObj, &gc.refParent, (QueuedObjectInfo **)&iorInfo);
- if (pFixupInfo->NeedsUnboxing())
- {
- TSO.SetAt(tsoIndex, gc.newObj, gc.refFromObj, gc.refParent, iorInfo);
- iorInfo->SetHasBeenProcessed();
- bResult = TRUE;
- }
- else
- {
- if (gc.refParent == NULL)
- m_topObject = gc.newObj;
- else
- {
- m_newObject = gc.newObj;
- Fixup(gc.newObj, gc.refParent, pFixupInfo);
- }
-
- // Update Table of Seen objects, so that any repeat objects can be updated too
- TOS.UpdateObject(gc.refFromObj, gc.newObj);
- iorInfo->SetHasBeenProcessed();
- bResult = TRUE;
- }
- }
- }
-
- GCPROTECT_END();
- return bResult;
-}
-
-void MakeIDeserializationCallback(OBJECTREF refTarget)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END;
-
- struct _gc {
- OBJECTREF refTarget;
- } gc;
- gc.refTarget = refTarget;
-
- GCPROTECT_BEGIN(gc);
-
- MethodTable *pMT = gc.refTarget->GetMethodTable();
- _ASSERTE(pMT);
-
- MethodTable *pItf = MscorlibBinder::GetClass(CLASS__IDESERIALIZATIONCB);
- MethodDesc *pMeth = GetInterfaceMethodImpl(pMT, pItf, 0);
- PCODE pCode = pMeth->GetSingleCallableAddrOfCode();
-
- PREPARE_NONVIRTUAL_CALLSITE_USING_CODE(pCode);
-
- DECLARE_ARGHOLDER_ARRAY(args, 2);
-
- args[ARGNUM_0] = OBJECTREF_TO_ARGHOLDER(gc.refTarget);
- args[ARGNUM_1] = NULL;
-
- CATCH_HANDLER_FOUND_NOTIFICATION_CALLSITE;
- CALL_MANAGED_METHOD_NORET(args);
-
- GCPROTECT_END();
-}
-
-void ObjectClone::CompleteIDeserializationCallbacks()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- OBJECTREF Dummy1 = NULL, Dummy2 = NULL;
- QueuedObjectInfo *pObjInfo = NULL;
-
- if (TDC.GetCount() == 0)
- return;
-
- LOG((LF_REMOTING, LL_INFO1000, "CompleteIDeserializationCallbacks. Beginning.\n"));
-
- OBJECTREF nextObj;
- while ((nextObj = TDC.Dequeue(&Dummy1, &Dummy2, &pObjInfo)) != NULL)
- {
- MakeIDeserializationCallback(nextObj);
- }
-}
-
-void ObjectClone::CompleteVtsOnDeserializedCallbacks()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END;
-
- OBJECTREF nextObj = NULL, Dummy1 = NULL, Dummy2 = NULL;
-
- if (VDC.GetCount() == 0)
- return;
-
- LOG((LF_REMOTING, LL_INFO1000, "CompleteVtsOnDeserializedCallbacks. Beginning.\n"));
-
- GCPROTECT_BEGIN(nextObj);
-
- while ((nextObj = VDC.Dequeue(&Dummy1, &Dummy2, NULL)) != NULL)
- InvokeVtsCallbacks(nextObj, RemotingVtsInfo::VTS_CALLBACK_ON_DESERIALIZED, m_toDomain);
-
- GCPROTECT_END();
-}
-
-void ObjectClone::CompleteVtsOnSerializedCallbacks()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END;
-
- OBJECTREF nextObj = NULL, Dummy1 = NULL, Dummy2 = NULL;
-
- if (VSC.GetCount() == 0)
- return;
-
- LOG((LF_REMOTING, LL_INFO1000, "CompleteVtsOnSerializedCallbacks. Beginning.\n"));
-
- GCPROTECT_BEGIN(nextObj);
-
- while ((nextObj = VSC.Dequeue(&Dummy1, &Dummy2, NULL)) != NULL)
- InvokeVtsCallbacks(nextObj, RemotingVtsInfo::VTS_CALLBACK_ON_SERIALIZED, m_fromDomain);
-
- GCPROTECT_END();
-}
-
-// Does a binary search to find the object with given id, and record of given kind
-DWORD ObjectClone::FindObjectInTSO(int objId, SpecialObjects kind)
-{
- CONTRACTL
- {
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- NOTHROW;
- }
- CONTRACTL_END
-
- DWORD lowIndex = 0;
- DWORD highIndex = TSO.GetCount();
- DWORD midIndex = highIndex / 2;
- DWORD firstMatch;
-
- if (highIndex == 0)
- {
- _ASSERTE(!"Special Object unexpectedly not found for given object id\n");
- return 0; // throw ?
- }
-
- SpecialObjectInfo *splInfo = NULL;
- while (true)
- {
- OBJECTREF refParent, refFromObj;
- OBJECTREF dummy;
- dummy = TSO.GetAt(midIndex, &refFromObj, &refParent, (QueuedObjectInfo **)&splInfo);
-
- if (objId < splInfo->GetObjectId())
- {
- highIndex = midIndex;
- }
- else
- {
- if (objId == splInfo->GetObjectId())
- break;
- lowIndex = midIndex;
- }
-
- DWORD oldIndex = midIndex;
- midIndex = lowIndex + (highIndex - lowIndex)/2;
- if (oldIndex == midIndex)
- {
- // Binary search failed. See comments below
- goto LinearSearch;
- }
- }
-
- // Found match at midIndex
- // Find the first record for this obj id
- firstMatch = midIndex;
- while(midIndex != 0)
- {
- midIndex -= 1;
- SpecialObjectInfo *pTemp;
- OBJECTREF refParent, refFromObj;
- OBJECTREF dummy;
- dummy = TSO.GetAt(midIndex, &refFromObj, &refParent, (QueuedObjectInfo **)&pTemp);
- if (pTemp->GetObjectId() != objId)
- break;
- else
- firstMatch = midIndex;
- };
-
- // Now look for the right kind of record
- do
- {
- OBJECTREF refParent, refFromObj;
- OBJECTREF dummy;
- dummy = TSO.GetAt(firstMatch, &refFromObj, &refParent, (QueuedObjectInfo **)&splInfo);
-
- if (splInfo->GetObjectId() == objId)
- {
- switch(kind)
- {
- case ISerializable:
- if (splInfo->IsISerializableInstance())
- return firstMatch;
- break;
- case IObjectReference:
- if (splInfo->IsIObjRefInstance())
- return firstMatch;
- break;
- case BoxedValueType:
- if (splInfo->IsBoxedObject())
- return firstMatch;
- break;
- default:
- _ASSERTE(!"Unknown enum value in FindObjectInTSO");
- };
- }
-
- firstMatch++;
-
- }while(firstMatch < TSO.GetCount());
-
-LinearSearch:
- // If there are multiple objects that are ISer/IObj, and some of them repeat in a certain fashion,
- // then the entries in TSO are not in sorted order. In such a case binary search will fail. Lets do a linear search
- // in such a case for now. This is probably reasonable since the TSO should usually be short and in-order (and presumably
- // cheaper than trying to keep the list in sorted order at all times).
- DWORD currIndex = 0;
- for (; currIndex < TSO.GetCount(); currIndex++)
- {
- OBJECTREF refParent, refFromObj;
- OBJECTREF dummy;
- dummy = TSO.GetAt(currIndex, &refFromObj, &refParent, (QueuedObjectInfo **)&splInfo);
-
- SpecialObjects foundKind = ISerializable;
- if (splInfo->IsIObjRefInstance())
- foundKind = IObjectReference;
- else if (splInfo->IsBoxedObject())
- foundKind = BoxedValueType;
- else
- _ASSERTE(splInfo->IsISerializableInstance());
-
- if (objId == splInfo->GetObjectId()
- && kind == foundKind)
- return currIndex;
- }
-
-
- _ASSERTE(!"Special Object unexpectedly not found for given object id\n");
- return 0; // throw ?
-}
-
-// This function is effectively a replica of MethodTable::Box. Its replicated to avoid "GCPROTECT_INTERIOR" that Box uses
-// and causes some leak detection asserts to go off. This is a controlled leak situation, where we know we're leaking stuff
-// and dont want the asserts.
-OBJECTREF ObjectClone::BoxValueTypeInWrongDomain(OBJECTREF refParent, DWORD offset, MethodTable *pValueTypeMT)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(pValueTypeMT->IsValueType());
- PRECONDITION(!pValueTypeMT->IsByRefLike());
- }
- CONTRACTL_END;
-
- OBJECTREF ref = NULL;
- void* pSrc = refParent->GetData() + offset;
- GCPROTECT_BEGININTERIOR(pSrc);
-
- // We must enter the target domain if we are boxing a non-agile type. This of course has some overhead
- // so we want to avoid it if possible. GetLoaderModule() == mscorlib && CanBeBlittedByObjectCloner is a
- // conservative first approximation of agile types.
- ENTER_DOMAIN_PTR_PREDICATED(m_fromDomain, ADV_RUNNINGIN,
- !pValueTypeMT->GetLoaderModule()->IsSystem() || pValueTypeMT->GetClass()->CannotBeBlittedByObjectCloner());
-
- ref = pValueTypeMT->FastBox(&pSrc);
-
- END_DOMAIN_TRANSITION;
-
- GCPROTECT_END();
- return ref;
-}
-
-// Returns whether or not a given type requires VTS callbacks of the specified kind.
-BOOL ObjectClone::HasVtsCallbacks(MethodTable *pMT, RemotingVtsInfo::VtsCallbackType eCallbackType)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- while (pMT)
- {
- if (pMT->HasRemotingVtsInfo())
- {
- PTR_RemotingVtsInfo pVtsInfo = pMT->GetRemotingVtsInfo();
- _ASSERTE(pVtsInfo != NULL);
-
- if (!pVtsInfo->m_pCallbacks[eCallbackType].IsNull())
- return TRUE;
- }
- pMT = pMT->GetParentMethodTable();
- }
-
- return FALSE;
-}
-
-// Calls all of the VTS event methods for a given callback type on the object instance provided (starting at the base class).
-void ObjectClone::InvokeVtsCallbacks(OBJECTREF refTarget, RemotingVtsInfo::VtsCallbackType eCallbackType, AppDomain* pDomain)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- GCPROTECT_BEGIN(refTarget);
-
- // Quickly walk the target's type hierarchy and determine the number of methods we'll need to call.
- DWORD cMethods = 0;
- MethodDesc *pLastCallback;
- MethodTable *pMT = refTarget->GetMethodTable();
- while (pMT)
- {
- if (pMT->HasRemotingVtsInfo())
- {
- PTR_RemotingVtsInfo pVtsInfo = pMT->GetRemotingVtsInfo();
- _ASSERTE(pVtsInfo != NULL);
-
- if (!pVtsInfo->m_pCallbacks[eCallbackType].IsNull())
- {
- cMethods++;
-
-#ifdef FEATURE_PREJIT
- // Might have to restore cross module method pointers.
- Module::RestoreMethodDescPointer(&pVtsInfo->m_pCallbacks[eCallbackType]);
-#endif
-
- pLastCallback = pVtsInfo->m_pCallbacks[eCallbackType].GetValue();
- }
- }
- pMT = pMT->GetParentMethodTable();
- }
-
- // Maybe there's no work to do.
- if (cMethods == 0)
- goto Done;
-
- // Allocate an array to hold the methods to invoke (we do this because the invocation order is the opposite way round from the
- // way we can easily scan for the methods). We can easily optimize this for the single callback case though.
- MethodDesc **pCallbacks = cMethods == 1 ? &pLastCallback : (MethodDesc**)_alloca(cMethods * sizeof(MethodDesc*));
-
- if (cMethods > 1)
- {
- // Walk the type hierarchy again, and this time fill in the methods to call in the correct slot of our callback table.
- DWORD dwSlotIndex = cMethods;
- pMT = refTarget->GetMethodTable();
- while (pMT)
- {
- if (pMT->HasRemotingVtsInfo())
- {
- PTR_RemotingVtsInfo pVtsInfo = pMT->GetRemotingVtsInfo();
- _ASSERTE(pVtsInfo != NULL);
-
- if (!pVtsInfo->m_pCallbacks[eCallbackType].IsNull())
- pCallbacks[--dwSlotIndex] = pVtsInfo->m_pCallbacks[eCallbackType].GetValue();
- }
- pMT = pMT->GetParentMethodTable();
- }
- _ASSERTE(dwSlotIndex == 0);
- }
-
- bool fSwitchDomains = pDomain != GetAppDomain();
-
- ENTER_DOMAIN_PTR(pDomain,ADV_RUNNINGIN);
-
- // If we're calling back into the from domain then reset the execution context to its original state (this will automatically be
- // popped once we return from this domain again).
- if (pDomain == m_fromDomain && fSwitchDomains)
- {
- Thread *pThread = GetThread();
- if (pThread->IsExposedObjectSet())
- {
- THREADBASEREF refThread = (THREADBASEREF)pThread->GetExposedObjectRaw();
- refThread->SetExecutionContext(m_fromExecutionContext);
- }
- }
-
- // Remember to adjust this pointer for boxed value types.
- BOOL bIsBoxed = refTarget->GetMethodTable()->IsValueType();
-
- RuntimeMethodHandle::StreamingContextData sContext = { NULL, GetStreamingContextState() };
-
- // Ensure Streamingcontext type is loaded. Do not delete this line
- MethodTable *pMTStreamingContext;
- pMTStreamingContext = MscorlibBinder::GetClass(CLASS__STREAMING_CONTEXT);
- _ASSERTE(pMTStreamingContext);
-
- // Now go and call each method in order.
- for (DWORD i = 0; i < cMethods; i++)
- {
- MethodDescCallSite callback(pCallbacks[i], &refTarget);
-
- ARG_SLOT argSlots[2];
-
- // Nullable<T> does not have any VTS functions
- _ASSERTE(!Nullable::IsNullableType(refTarget->GetMethodTable()));
-
- argSlots[0] = (bIsBoxed ? (ARG_SLOT)(SIZE_T)(refTarget->UnBox()) : ObjToArgSlot(refTarget));
-#if defined(_TARGET_X86_) || defined(_TARGET_ARM_)
- static_assert_no_msg(sizeof(sContext) == sizeof(ARG_SLOT));
- argSlots[1] = *(ARG_SLOT*)(&sContext); // StreamingContext is passed by value on x86 and ARM
-#elif defined(_WIN64)
- static_assert_no_msg(sizeof(sContext) > sizeof(ARG_SLOT));
- argSlots[1] = PtrToArgSlot(&sContext); // StreamingContext is passed by reference on WIN64
-#else // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_
- PORTABILITY_ASSERT("ObjectClone::InvokeVtsCallbacks() - NYI on this platform");
-#endif // !_TARGET_X86_ && !_WIN64 && !_TARGET_ARM_
-
- callback.CallWithValueTypes(&argSlots[0]);
- }
-
- END_DOMAIN_TRANSITION;
-
-Done: ;
- GCPROTECT_END();
-}
-
-#endif // FEATURE_REMOTING
diff --git a/src/vm/pefile.h b/src/vm/pefile.h
index 2f244732e9..697ce03749 100644
--- a/src/vm/pefile.h
+++ b/src/vm/pefile.h
@@ -642,9 +642,7 @@ protected:
protected:
- friend class CLRPrivBinderFusion;
#ifndef DACCESS_COMPILE
- // CLRPrivBinderFusion calls this for Fusion-bound assemblies in AppX processes.
void SetHostAssembly(ICLRPrivAssembly * pHostAssembly)
{ LIMITED_METHOD_CONTRACT; m_pHostAssembly = clr::SafeAddRef(pHostAssembly); }
#endif //DACCESS_COMPILE
diff --git a/src/vm/remoting.cpp b/src/vm/remoting.cpp
deleted file mode 100644
index 1b65323bb6..0000000000
--- a/src/vm/remoting.cpp
+++ /dev/null
@@ -1,3773 +0,0 @@
-// 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.
-//
-// File: remoting.cpp
-//
-
-//
-// Purpose: Defines various remoting related objects such as
-// proxies
-//
-
-//
-
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-#include "virtualcallstub.h"
-#include "excep.h"
-#include "comdelegate.h"
-#include "remoting.h"
-#include "field.h"
-#include "siginfo.hpp"
-#include "stackbuildersink.h"
-#include "eehash.h"
-#include "profilepriv.h"
-#include "message.h"
-#include "eeconfig.h"
-#include "comcallablewrapper.h"
-#include "interopconverter.h"
-#include "asmconstants.h"
-#include "crossdomaincalls.h"
-#include "contractimpl.h"
-#include "typestring.h"
-#include "generics.h"
-#include "appdomain.inl"
-#include "dbginterface.h"
-
-#ifndef DACCESS_COMPILE
-
-// These hold label offsets into non-virtual thunks. They are used by
-// CNonVirtualThunkMgr::DoTraceStub and ::TraceManager to help the
-// debugger figure out where the thunk is going to go.
-DWORD g_dwNonVirtualThunkRemotingLabelOffset = 0;
-DWORD g_dwNonVirtualThunkReCheckLabelOffset = 0;
-
-// Statics
-
-MethodTable *CRemotingServices::s_pMarshalByRefObjectClass;
-MethodTable *CRemotingServices::s_pServerIdentityClass;
-
-MethodDesc *CRemotingServices::s_pRPPrivateInvoke;
-MethodDesc *CRemotingServices::s_pRPInvokeStatic;
-MethodDesc *CRemotingServices::s_pWrapMethodDesc;
-MethodDesc *CRemotingServices::s_pIsCurrentContextOK;
-MethodDesc *CRemotingServices::s_pCheckCast;
-MethodDesc *CRemotingServices::s_pFieldSetterDesc;
-MethodDesc *CRemotingServices::s_pFieldGetterDesc;
-MethodDesc *CRemotingServices::s_pObjectGetTypeDesc;
-MethodDesc *CRemotingServices::s_pGetTypeDesc;
-MethodDesc *CRemotingServices::s_pProxyForDomainDesc;
-MethodDesc *CRemotingServices::s_pServerContextForProxyDesc;
-MethodDesc *CRemotingServices::s_pServerDomainIdForProxyDesc;
-DWORD CRemotingServices::s_dwServerOffsetInRealProxy;
-DWORD CRemotingServices::s_dwSrvIdentityOffsetInRealProxy;
-DWORD CRemotingServices::s_dwIdOffset;
-DWORD CRemotingServices::s_dwTPOrObjOffsetInIdentity;
-DWORD CRemotingServices::s_dwMBRIDOffset;
-DWORD CRemotingServices::s_dwLeaseOffsetInIdentity;
-DWORD CRemotingServices::s_dwURIOffsetInIdentity;
-CrstStatic CRemotingServices::s_RemotingCrst;
-BOOL CRemotingServices::s_fRemotingStarted;
-MethodDesc *CRemotingServices::s_pRenewLeaseOnCallDesc;
-
-
-#ifdef FEATURE_COMINTEROP
-MethodDesc *CRemotingServices::s_pCreateObjectForCom;
-#endif
-
-// CTPMethodTable Statics
-DWORD CTPMethodTable::s_dwCommitedTPSlots;
-DWORD CTPMethodTable::s_dwReservedTPSlots;
-DWORD CTPMethodTable::s_dwReservedTPIndirectionSlotSize;
-DWORD CTPMethodTable::s_dwGCInfoBytes;
-DWORD CTPMethodTable::s_dwMTDataSlots;
-MethodTable *CTPMethodTable::s_pRemotingProxyClass;
-CrstStatic CTPMethodTable::s_TPMethodTableCrst;
-EEThunkHashTable *CTPMethodTable::s_pThunkHashTable;
-BOOL CTPMethodTable::s_fTPTableFieldsInitialized;
-
-#endif // !DACCESS_COMPILE
-
-
-SPTR_IMPL(MethodTable, CTPMethodTable, s_pThunkTable);
-
-#ifndef DACCESS_COMPILE
-
-// CVirtualThunks statics
-CVirtualThunks *CVirtualThunks::s_pVirtualThunks;
-
-// CVirtualThunkMgr statics
-CVirtualThunkMgr *CVirtualThunkMgr::s_pVirtualThunkMgr;
-
-#ifndef HAS_REMOTING_PRECODE
-// CNonVirtualThunk statics
-CNonVirtualThunk *CNonVirtualThunk::s_pNonVirtualThunks;
-SimpleRWLock* CNonVirtualThunk::s_pNonVirtualThunksListLock;
-
-// CNonVirtualThunkMgr statics
-CNonVirtualThunkMgr *CNonVirtualThunkMgr::s_pNonVirtualThunkMgr;
-#endif
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::Initialize public
-//
-// Synopsis: Initialized remoting state
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::Initialize()
-{
- STANDARD_VM_CONTRACT;
-
- // Initialize the remoting services critical section
- s_RemotingCrst.Init(CrstRemoting, CrstFlags(CRST_REENTRANCY|CRST_HOST_BREAKABLE));
-
- CTPMethodTable::Initialize();
-}
-
-INT32 CRemotingServices::IsTransparentProxy(Object* orTP)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- INT32 fIsTPMT = FALSE;
-
- if(orTP != NULL)
- {
- // Check if the supplied object has transparent proxy method table
- MethodTable *pMT = orTP->GetMethodTable();
- fIsTPMT = pMT->IsTransparentProxy() ? TRUE : FALSE;
- }
-
- LOG((LF_REMOTING, LL_EVERYTHING, "!IsTransparentProxyEx(0x%x) returning %s",
- orTP, fIsTPMT ? "TRUE" : "FALSE"));
-
- return(fIsTPMT);
-}
-
-
-Object* CRemotingServices::GetRealProxy(Object* objTP)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- OBJECTREF rv = NULL;
-
- if ((objTP != NULL) && (IsTransparentProxy(objTP)))
- {
- _ASSERTE(s_fRemotingStarted);
- rv = CTPMethodTable::GetRP(OBJECTREF(objTP));
- }
-
- LOG((LF_REMOTING, LL_INFO100, "!GetRealProxy(0x%x) returning 0x%x\n", objTP, OBJECTREFToObject(rv)));
-
- return OBJECTREFToObject(rv);
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::EnsureRemotingStarted
-//
-// Synopsis: Startup the remoting services.
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::EnsureRemotingStarted()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- if (!CRemotingServices::s_fRemotingStarted)
- CRemotingServices::StartRemoting();
-
- if (!CTPMethodTable::s_fTPTableFieldsInitialized)
- CTPMethodTable::EnsureFieldsInitialized();
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::StartRemoting private
-//
-// Synopsis: Initialize the static fields of CRemotingServices class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::StartRemoting()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // Acquire the remoting lock before initializing fields
- GCX_PREEMP();
-
- CrstHolder ch(&s_RemotingCrst);
-
- // Make sure that no other thread has initialized the fields
- if (!s_fRemotingStarted)
- {
- InitActivationServicesClass();
- InitRealProxyClass();
- InitRemotingProxyClass();
- InitIdentityClass();
- InitServerIdentityClass();
- InitMarshalByRefObjectClass();
- InitRemotingServicesClass();
- InitObjectClass();
- InitLeaseClass();
-
- // ********* NOTE ************
- // This must always be the last statement in this block to prevent races
- //
- VolatileStore(&s_fRemotingStarted, TRUE);
- // ********* END NOTE ************
- }
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitActivationServicesClass private
-//
-// Synopsis: Extract the method descriptors and fields of ActivationServices class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitActivationServicesClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pIsCurrentContextOK = MscorlibBinder::GetMethod(METHOD__ACTIVATION_SERVICES__IS_CURRENT_CONTEXT_OK);
-#ifdef FEATURE_COMINTEROP
- s_pCreateObjectForCom = MscorlibBinder::GetMethod(METHOD__ACTIVATION_SERVICES__CREATE_OBJECT_FOR_COM);
-#endif
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitRealProxyClass private
-//
-// Synopsis: Extract the method descriptors and fields of Real Proxy class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitRealProxyClass()
-{
- STANDARD_VM_CONTRACT;
-
- // Now store the methoddesc of the PrivateInvoke method on the RealProxy class
- s_pRPPrivateInvoke = MscorlibBinder::GetMethod(METHOD__REAL_PROXY__PRIVATE_INVOKE);
-
- // Now find the offset to the _identity field inside the
- // RealProxy class
- s_dwIdOffset = RealProxyObject::GetOffsetOfIdentity() - Object::GetOffsetOfFirstField();
-
- s_dwServerOffsetInRealProxy = RealProxyObject::GetOffsetOfServerObject() - Object::GetOffsetOfFirstField();
-
- s_dwSrvIdentityOffsetInRealProxy = RealProxyObject::GetOffsetOfServerIdentity() - Object::GetOffsetOfFirstField();
-
- return;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitRemotingProxyClass private
-//
-// Synopsis: Extract the method descriptors and fields of RemotingProxy class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitRemotingProxyClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pRPInvokeStatic = MscorlibBinder::GetMethod(METHOD__REMOTING_PROXY__INVOKE);
-
- // Note: We cannot do this inside TPMethodTable::InitializeFields ..
- // that causes recursions if in some situation only the latter is called
- // If you do this you will see Asserts when running any process under CorDbg
- // This is because jitting of NV methods on MBR objects calls
- // InitializeFields and when actually doing that we should not need to
- // JIT another NV method on some MBR object.
- CTPMethodTable::s_pRemotingProxyClass = MscorlibBinder::GetClass(CLASS__REMOTING_PROXY);
- _ASSERTE(CTPMethodTable::s_pRemotingProxyClass);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitServerIdentityClass private
-//
-// Synopsis: Extract the method descriptors and fields of ServerIdentity class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitServerIdentityClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pServerIdentityClass = MscorlibBinder::GetClass(CLASS__SERVER_IDENTITY);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitIdentityClass private
-//
-// Synopsis: Extract the method descriptors and fields of Identity class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitIdentityClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_dwTPOrObjOffsetInIdentity = MscorlibBinder::GetFieldOffset(FIELD__IDENTITY__TP_OR_OBJECT);
-
- s_dwLeaseOffsetInIdentity = MscorlibBinder::GetFieldOffset(FIELD__IDENTITY__LEASE);
-
- s_dwURIOffsetInIdentity = MscorlibBinder::GetFieldOffset(FIELD__IDENTITY__OBJURI);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitMarshalByRefObjectClass private
-//
-// Synopsis: Extract the method descriptors and fields of MarshalByRefObject class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitMarshalByRefObjectClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pMarshalByRefObjectClass = MscorlibBinder::GetClass(CLASS__MARSHAL_BY_REF_OBJECT);
- s_dwMBRIDOffset = MarshalByRefObjectBaseObject::GetOffsetOfServerIdentity() - Object::GetOffsetOfFirstField();
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitRemotingServicesClass private
-//
-// Synopsis: Extract the method descriptors and fields of RemotingServices class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitRemotingServicesClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pCheckCast = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__CHECK_CAST);
-
- // Need these to call wrap/unwrap from the VM (message.cpp).
- // Also used by JIT helpers to wrap/unwrap
- s_pWrapMethodDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__WRAP);
- s_pProxyForDomainDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__CREATE_PROXY_FOR_DOMAIN);
- s_pServerContextForProxyDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__GET_SERVER_CONTEXT_FOR_PROXY);
- s_pServerDomainIdForProxyDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__GET_SERVER_DOMAIN_ID_FOR_PROXY);
- s_pGetTypeDesc = MscorlibBinder::GetMethod(METHOD__REMOTING_SERVICES__GET_TYPE);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::InitObjectClass private
-//
-// Synopsis: Extract the method descriptors and fields of Object class
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::InitObjectClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pFieldSetterDesc = MscorlibBinder::GetMethod(METHOD__OBJECT__FIELD_SETTER);
- s_pFieldGetterDesc = MscorlibBinder::GetMethod(METHOD__OBJECT__FIELD_GETTER);
- s_pObjectGetTypeDesc = MscorlibBinder::GetMethod(METHOD__OBJECT__GET_TYPE);
-}
-
-VOID CRemotingServices::InitLeaseClass()
-{
- STANDARD_VM_CONTRACT;
-
- s_pRenewLeaseOnCallDesc = MscorlibBinder::GetMethod(METHOD__LEASE__RENEW_ON_CALL);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::RequiresManagedActivation private
-//
-// Synopsis: Determine if a config file has been parsed or if there
-// are any attributes on the class that would require us
-// to go into the managed activation codepath.
-//
-//
-// Note: Called by CreateProxyOrObject (JIT_NewCrossContext)
-//
-//+----------------------------------------------------------------------------
-ManagedActivationType __stdcall CRemotingServices::RequiresManagedActivation(TypeHandle ty)
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- SO_TOLERANT;
- PRECONDITION(!ty.IsNull());
- }
- CONTRACTL_END;
-
- MethodTable* pMT = ty.GetMethodTable();
-
- PREFIX_ASSUME(pMT != NULL);
- if (!pMT->MayRequireManagedActivation())
- return NoManagedActivation;
-
-#ifdef _DEBUG
-
- ManagedActivationType bManaged = NoManagedActivation;
- if (pMT->IsRemotingConfigChecked())
- {
- // We have done work to figure this out in the past ...
- // use the cached result
- bManaged = pMT->RequiresManagedActivation() ? ManagedActivation : NoManagedActivation;
- }
- else if (pMT->IsContextful() || pMT->GetClass()->HasRemotingProxyAttribute())
- {
- // Contextful and classes that have a remoting proxy attribute
- // (whether they are MarshalByRef or ContextFul) always take the slow
- // path of managed activation
- bManaged = ManagedActivation;
- }
- else
- {
- // If we have parsed a config file that might have configured
- // this Type to be activated remotely
- if (GetAppDomain()->IsRemotingConfigured())
- {
- bManaged = ManagedActivation;
- // We will remember if the activation is actually going
- // remote based on if the managed call to IsContextOK returned us
- // a proxy or not
- }
-
-#ifdef FEATURE_COMINTEROP
- else if (pMT->IsComObjectType())
- {
- bManaged = ComObjectType;
- }
-#endif // FEATURE_COMINTEROP
-
- }
-
-#endif // _DEBUG
-
- if (pMT->RequiresManagedActivation())
- {
- // Contextful and classes that have a remoting proxy attribute
- // (whether they are MarshalByRef or ContextFul) always take the slow
- // path of managed activation
- _ASSERTE(bManaged == ManagedActivation);
- return ManagedActivation;
- }
-
- ManagedActivationType bMng = NoManagedActivation;
- if (!pMT->IsRemotingConfigChecked())
- {
- g_IBCLogger.LogMethodTableAccess(pMT);
-
- // If we have parsed a config file that might have configured
- // this Type to be activated remotely
- if (GetAppDomain()->IsRemotingConfigured())
- {
- bMng = ManagedActivation;
- // We will remember if the activation is actually going
- // remote based on if the managed call to IsContextOK returned us
- // a proxy or not
- }
-
-#ifdef FEATURE_COMINTEROP
- else if (pMT->IsComObjectType())
- {
- bMng = ComObjectType;
- }
-#endif // FEATURE_COMINTEROP
-
- if (bMng == NoManagedActivation)
- {
- pMT->TrySetRemotingConfigChecked();
- }
- }
-
- _ASSERTE(bManaged == bMng);
- return bMng;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CreateProxyOrObject public
-//
-// Synopsis: Determine if the current context is appropriate
-// for activation. If the current context is OK then it creates
-// an object else it creates a proxy.
-//
-//
-// Note: Called by JIT_NewCrossContext
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::CreateProxyOrObject(MethodTable* pMT,
- BOOL fIsCom /*default:FALSE*/, BOOL fIsNewObj /*default:FALSE*/)
- /* fIsCom == Did we come here through CoCreateInstance */
- /* fIsNewObj == Did we come here through Jit_NewCrossContext (newObj) */
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pMT));
- PRECONDITION(!pMT->IsTransparentProxy());
-
- // By the time we reach here, we have already checked that the class may require
- // managed activation. This check is made either through the JIT_NewCrossContext helper
- // or Activator.CreateInstance codepath.
- PRECONDITION(pMT->MayRequireManagedActivation());
- }
- CONTRACTL_END;
-
- // Ensure remoting has been started.
- EnsureRemotingStarted();
-
- // Get the address of IsCurrentContextOK in managed code
- MethodDesc* pTargetMD = NULL;
- Object *pServer = NULL;
-
-#ifdef FEATURE_COMINTEROP
- if(fIsCom)
- {
- pTargetMD = CRemotingServices::MDofCreateObjectForCom();
- }
- else
-#endif // FEATURE_COMINTEROP
- {
- pTargetMD = CRemotingServices::MDofIsCurrentContextOK();
- }
-
- // Arrays are not created by JIT_NewCrossContext
- _ASSERTE(!pMT->IsArray());
-
- // Get the type seen by reflection
- REFLECTCLASSBASEREF reflectType = (REFLECTCLASSBASEREF) pMT->GetManagedClassObject();
- LPVOID pvType = NULL;
- *(REFLECTCLASSBASEREF *)&pvType = reflectType;
-
- // This will return either an uninitialized object or a proxy
- pServer = (Object *)CTPMethodTable::CallTarget(pTargetMD, pvType, NULL, (LPVOID)(size_t)(fIsNewObj?1:0));
-
- if (!pMT->IsContextful() && !pMT->IsComObjectType())
- {
- // Cache the result of the activation attempt ...
- // if a strictly MBR class is not configured for remote
- // activation we will not go
- // through this slow path next time!
- // (see RequiresManagedActivation)
- if (IsTransparentProxy(pServer))
- {
- // Set the flag that this class is remote activate
- // which means activation will go to managed code.
- pMT->SetRequiresManagedActivation();
- }
- else
- {
- // Set only the flag that no managed checks are required
- // for this class next time.
- pMT->SetRemotingConfigChecked();
- }
- }
-
- LOG((LF_REMOTING, LL_INFO1000, "CreateProxyOrObject returning 0x%p\n", pServer));
- if (pMT->IsContextful())
- {
- COUNTER_ONLY(GetPerfCounters().m_Context.cObjAlloc++);
- }
- return ObjectToOBJECTREF(pServer);
-}
-
-
-#ifndef HAS_REMOTING_PRECODE
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetStubForNonVirtualMethod public
-//
-// Synopsis: Get a stub for a non virtual method.
-//
-//
-//+----------------------------------------------------------------------------
-Stub* CRemotingServices::GetStubForNonVirtualMethod(MethodDesc* pMD, LPVOID pvAddrOfCode, Stub* pInnerStub)
-{
- CONTRACT (Stub*)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMD));
- PRECONDITION(CheckPointer(pvAddrOfCode));
- PRECONDITION(CheckPointer(pInnerStub, NULL_OK));
- POSTCONDITION(CheckPointer(RETVAL));
- }
- CONTRACT_END;
-
- CPUSTUBLINKER sl;
- Stub* pStub = CTPMethodTable::CreateStubForNonVirtualMethod(pMD, &sl, pvAddrOfCode, pInnerStub);
-
- RETURN pStub;
-}
-#endif // HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetNonVirtualEntryPointForVirtualMethod public
-//
-// Synopsis: Get a thunk for a non-virtual call to a virtual method.
-// Virtual methods do not normally get thunked in the vtable. This
-// is because virtual calls use the object's vtable, and proxied objects
-// would use the proxy's vtable. Hence local object (which would
-// have the real vtable) can make virtual calls without going through
-// the thunk.
-// However, if the virtual function is called non-virtually, we have
-// a problem (since this would bypass the proxy's vtable). Since this
-// is not a common case, we fix it by using a stub in such cases.
-//
-//
-//+----------------------------------------------------------------------------
-PCODE CRemotingServices::GetNonVirtualEntryPointForVirtualMethod(MethodDesc* pMD)
-{
- CONTRACT (PCODE)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMD));
- PRECONDITION(pMD->IsRemotingInterceptedViaVirtualDispatch());
- POSTCONDITION(RETVAL != NULL);
- }
- CONTRACT_END;
-
-#ifdef HAS_REMOTING_PRECODE
- RETURN pMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pMD, PRECODE_REMOTING);
-#else
- GCX_PREEMP();
- RETURN *CTPMethodTable::GetOrCreateNonVirtualSlotForVirtualMethod(pMD);
-#endif
-}
-
-#ifndef HAS_REMOTING_PRECODE
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::DestroyThunk public
-//
-// Synopsis: Destroy the thunk for the non virtual method.
-//
-//
-//+----------------------------------------------------------------------------
-void CRemotingServices::DestroyThunk(MethodDesc* pMD)
-{
- WRAPPER_NO_CONTRACT;
-
- // Delegate to a helper routine
- CTPMethodTable::DestroyThunk(pMD);
-}
-#endif // HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetDispatchInterfaceHelper public
-//
-// Synopsis: Returns helper for dispatching interface call into the remoting system
-// with exact MethodDesc. Used for remoting of calls on generic interfaces.
-// The returned helper has MethodDesc calling convention
-//+----------------------------------------------------------------------------
-PCODE CRemotingServices::GetDispatchInterfaceHelper(MethodDesc* pMD)
-{
- WRAPPER_NO_CONTRACT;
-
- return GetEEFuncEntryPoint(CRemotingServices__DispatchInterfaceCall);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CheckCast public
-//
-// Synopsis: Checks either
-// (1) If the object type supports the given interface OR
-// (2) If the given type is present in the hierarchy of the
-// object type
-//
-//+----------------------------------------------------------------------------
-BOOL CRemotingServices::CheckCast(OBJECTREF orTP, TypeHandle objTy, TypeHandle ty)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orTP != NULL);
- PRECONDITION(!objTy.IsNull());
- PRECONDITION(!ty.IsNull());
-
- // Object class can never be an interface. We use a separate cached
- // entry for storing interfaces that the proxy supports.
- PRECONDITION(!objTy.IsInterface());
- }
- CONTRACTL_END;
-
- // Early out if someone's trying to cast us to a type desc (such as a byref,
- // array or function pointer).
- if (ty.IsTypeDesc())
- return FALSE;
-
- BOOL fCastOK = FALSE;
-
- // (1) We are trying to cast to an interface
- if (ty.IsInterface())
- {
- // Do a quick check for interface cast by comparing it against the
- // cached entry
- MethodTable *pItfMT = ((TRANSPARENTPROXYREF)orTP)->GetInterfaceMethodTable();
- if (NULL != pItfMT)
- {
- if(pItfMT == ty.GetMethodTable())
- fCastOK = TRUE;
- else
- fCastOK = pItfMT->CanCastToInterface(ty.GetMethodTable());
- }
-
- if(!fCastOK)
- fCastOK = objTy.GetMethodTable()->CanCastToInterface(ty.GetMethodTable());
- }
- // (2) Everything else...
- else
- {
- // Walk up the class hierarchy and find a matching class
- while (ty != objTy)
- {
- if (objTy.IsNull())
- {
- // Oh-oh, the cast did not succeed. Maybe we have to refine
- // the proxy to match the clients view
- break;
- }
-
- // Continue searching
- objTy = objTy.GetParent();
- }
-
- if(objTy == ty)
- fCastOK = TRUE;
- }
-
- return fCastOK;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CheckCast public
-//
-// Synopsis: Refine the type hierarchy that the proxy represents to match
-// the client view. If the client is trying to cast the proxy
-// to a type not supported by the server object then we
-// return NULL
-//
-//
-//+----------------------------------------------------------------------------
-BOOL CRemotingServices::CheckCast(OBJECTREF orTP, TypeHandle ty)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(orTP != NULL);
- PRECONDITION(!ty.IsNull());
- }
- CONTRACTL_END;
-
- BOOL fCastOK = FALSE;
-
- GCPROTECT_BEGIN(orTP);
-
- // Make sure the type being cast to has been restored.
- ty.CheckRestore();
-
- MethodTable *pMT = orTP->GetMethodTable();
-
- // Make sure that we have a transparent proxy
- _ASSERTE(pMT->IsTransparentProxy());
-
- pMT = orTP->GetTrueMethodTable();
-
- // Do a cast check without taking a lock
- fCastOK = CheckCast(orTP, TypeHandle(pMT), ty);
-
- if (!fCastOK && !ty.IsTypeDesc())
- {
- // We reach here only if any of the types in the current type hierarchy
- // represented by the proxy does not match the given type.
- // Call a helper routine in managed RemotingServices to find out
- // whether the server object supports the given type
- MethodDesc* pTargetMD = MDofCheckCast();
- fCastOK = CTPMethodTable::CheckCast(pTargetMD, (TRANSPARENTPROXYREF)orTP, ty);
- }
-
- if (fCastOK)
- {
- // Do the type equivalence tests
- CRealProxy::UpdateOptFlags(orTP);
- }
-
- GCPROTECT_END();
-
- LOG((LF_REMOTING, LL_INFO100, "CheckCast returning %s for object 0x%x and class 0x%x \n", (fCastOK ? "TRUE" : "FALSE")));
-
- return (fCastOK);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::FieldAccessor public
-//
-// Synopsis: Sets/Gets the value of the field given an instance or a proxy
-//
-//+----------------------------------------------------------------------------
-void CRemotingServices::FieldAccessor(FieldDesc* pFD, OBJECTREF o, LPVOID pVal, BOOL fIsGetter)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pFD));
- PRECONDITION(o != NULL);
- PRECONDITION(CheckPointer(pVal, NULL_OK));
- PRECONDITION(o->IsTransparentProxy() || o->GetMethodTable()->IsMarshaledByRef());
- }
- CONTRACTL_END;
-
- MethodTable *pMT = o->GetMethodTable();
- TypeHandle fldClass;
- TypeHandle thRealObjectType;
-
- GCPROTECT_BEGIN(o);
- GCPROTECT_BEGININTERIOR(pVal);
-
- // If the field descriptor type is not exact (i.e. it's a representative
- // descriptor for a generic field) then we need to be more careful
- // determining the properties of the field.
- if (pFD->IsSharedByGenericInstantiations())
- {
- // We need to resolve the field type in the context of the actual object
- // it belongs to. If we've been handed a proxy we have to go grab the
- // proxied type for this to work.
- thRealObjectType = o->GetTrueTypeHandle();
-
- // Evaluate the field signature in the type context of the parent object.
- MetaSig sig(pFD, thRealObjectType);
- sig.NextArg();
- fldClass = sig.GetLastTypeHandleThrowing();
- }
- else
- {
- fldClass = pFD->GetFieldTypeHandleThrowing();
- }
-
- GCPROTECT_END();
- GCPROTECT_END();
-
- CorElementType fieldType = fldClass.GetSignatureCorElementType();
- UINT cbSize = GetSizeForCorElementType(fieldType);
- BOOL fIsGCRef = CorTypeInfo::IsObjRef(fieldType);
- BOOL fIsByValue = fieldType == ELEMENT_TYPE_VALUETYPE;
-
- if(pMT->IsMarshaledByRef())
- {
- GCX_FORBID();
-
- _ASSERTE(!o->IsTransparentProxy());
-
- // This is a reference to a real object. Get/Set the field value
- // and return
- LPVOID pFieldAddress = pFD->GetAddress((LPVOID)OBJECTREFToObject(o));
- LPVOID pDest = (fIsGetter ? pVal : pFieldAddress);
- LPVOID pSrc = (fIsGetter ? pFieldAddress : pVal);
- if(fIsGCRef && !fIsGetter)
- {
- SetObjectReference((OBJECTREF*)pDest, ObjectToOBJECTREF(*(Object **)pSrc), o->GetAppDomain());
- }
- else if(fIsByValue)
- {
- CopyValueClass(pDest, pSrc, fldClass.AsMethodTable(), o->GetAppDomain());
- }
- else
- {
- CopyDestToSrc(pDest, pSrc, cbSize);
- }
- }
- else
- {
- // Call the managed code to start the field access call
- CallFieldAccessor(pFD, o, pVal, fIsGetter, fIsByValue, fIsGCRef, thRealObjectType, fldClass, fieldType, cbSize);
- }
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CopyDestToSrc private
-//
-// Synopsis: Copies the specified number of bytes from the src to dest
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::CopyDestToSrc(LPVOID pDest, LPVOID pSrc, UINT cbSize)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pDest));
- PRECONDITION(CheckPointer(pSrc));
- }
- CONTRACTL_END;
-
- switch (cbSize)
- {
- case 1:
- VolatileStore((INT8*)pDest, *(INT8*)pSrc);
- break;
-
- case 2:
- VolatileStore((INT16*)pDest, *(INT16*)pSrc);
- break;
-
- case 4:
- VolatileStore((INT32*)pDest, *(INT32*)pSrc);
- break;
-
- case 8:
- VolatileStore((INT64*)pDest, *(INT64*)pSrc);
- break;
-
- default:
- UNREACHABLE();
- break;
- }
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CallFieldAccessor private
-//
-// Synopsis: Sets up the arguments and calls RealProxy::FieldAccessor
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::CallFieldAccessor(FieldDesc* pFD,
- OBJECTREF o,
- VOID* pVal,
- BOOL fIsGetter,
- BOOL fIsByValue,
- BOOL fIsGCRef,
- TypeHandle ty,
- TypeHandle fldTy,
- CorElementType fieldType,
- UINT cbSize)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pFD));
- PRECONDITION(o != NULL);
- PRECONDITION(CheckPointer(pVal));
- }
- CONTRACTL_END;
-
- //****************************WARNING******************************
- // GC Protect all non-primitive variables
- //*****************************************************************
-
- FieldArgs fieldArgs;
- fieldArgs.obj = NULL;
- fieldArgs.val = NULL;
- fieldArgs.typeName = NULL;
- fieldArgs.fieldName = NULL;
-
- GCPROTECT_BEGIN(fieldArgs);
- GCPROTECT_BEGININTERIOR(pVal);
-
- fieldArgs.obj = o;
-
- // protect the field value if it is a gc-ref type
- if(fIsGCRef)
- fieldArgs.val = ObjectToOBJECTREF(*(Object **)pVal);
-
-
- // Set up the arguments
-
- // Argument 1: String typeName
- // Argument 2: String fieldName
- // Get the type name and field name strings
- GetTypeAndFieldName(&fieldArgs, pFD, ty);
-
- // Argument 3: Object val
- OBJECTREF val = NULL;
- if(!fIsGetter)
- {
- // If we are setting a field value then we create a variant data
- // structure to hold the field value
- // Extract the field from the gc protected structure if it is an object
- // else use the value passed to the function
- LPVOID pvFieldVal = (fIsGCRef ? (LPVOID)&(fieldArgs.val) : pVal);
- // <REVISIT_TODO>: This can cause a GC. We need some way to protect the variant
- // data</REVISIT_TODO>
- OBJECTREF *lpVal = &val;
- GCPROTECT_BEGININTERIOR (pvFieldVal);
- CMessage::GetObjectFromStack(lpVal, &pvFieldVal, fieldType, fldTy, TRUE);
- GCPROTECT_END ();
- }
-
- // Get the method descriptor of the call
- MethodDesc *pMD = (fIsGetter ? MDofFieldGetter() : MDofFieldSetter());
-
- // Call the field accessor function
- //////////////////////////////// GETTER ///////////////////////////////////
- if(fIsGetter)
- {
- // Set up the return value
- OBJECTREF oRet = NULL;
-
- GCPROTECT_BEGIN (oRet);
- CRemotingServices__CallFieldGetter(pMD,
- (LPVOID)OBJECTREFToObject(fieldArgs.obj),
- (LPVOID)OBJECTREFToObject(fieldArgs.typeName),
- (LPVOID)OBJECTREFToObject(fieldArgs.fieldName),
- (LPVOID)&(oRet));
-
- // If we are getting a field value then extract the field value
- // based on the type of the field
- if(fIsGCRef)
- {
- // Do a check cast to ensure that the field type and the
- // return value are compatible
- OBJECTREF orRet = oRet;
- OBJECTREF orSaved = orRet;
- if(IsTransparentProxy(OBJECTREFToObject(orRet)))
- {
- GCPROTECT_BEGIN(orRet);
-
- if(!CheckCast(orRet, fldTy))
- COMPlusThrow(kInvalidCastException, W("Arg_ObjObj"));
-
- orSaved = orRet;
-
- GCPROTECT_END();
- }
-
- *(OBJECTREF *)pVal = orSaved;
- }
- else if (fIsByValue)
- {
- // Copy from the source to the destination
- if (oRet != NULL)
- {
- fldTy.GetMethodTable()->UnBoxIntoUnchecked(pVal, oRet);
- }
- }
- else
- {
- if (oRet != NULL)
- CopyDestToSrc(pVal, oRet->UnBox(), cbSize);
- }
- GCPROTECT_END ();
- }
- ///////////////////////// SETTER //////////////////////////////////////////
- else
- {
- CRemotingServices__CallFieldSetter(pMD,
- (LPVOID)OBJECTREFToObject(fieldArgs.obj),
- (LPVOID)OBJECTREFToObject(fieldArgs.typeName),
- (LPVOID)OBJECTREFToObject(fieldArgs.fieldName),
- (LPVOID)OBJECTREFToObject(val));
- }
-
- GCPROTECT_END(); // pVal
- GCPROTECT_END(); // fieldArgs
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetTypeAndFieldName private
-//
-// Synopsis: Get the type name and field name of the
-//
-//
-//+----------------------------------------------------------------------------
-VOID CRemotingServices::GetTypeAndFieldName(FieldArgs *pArgs, FieldDesc *pFD, TypeHandle thEnclosingClass)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pArgs));
- PRECONDITION(CheckPointer(pFD));
- }
- CONTRACTL_END;
-
- TypeHandle thDeclaringType = !thEnclosingClass.IsNull() ?
- pFD->GetExactDeclaringType(thEnclosingClass.AsMethodTable()) : pFD->GetEnclosingMethodTable();
- _ASSERTE(!thDeclaringType.IsNull());
-
- // Extract the type name and field name string
- // <REVISIT_TODO>FUTURE: Put this in the reflection data structure cache TarunA 11/26/00</REVISIT_TODO>
- StackSString ss;
- TypeString::AppendType(ss, thDeclaringType, TypeString::FormatNamespace | TypeString::FormatFullInst);
- pArgs->typeName = StringObject::NewString(ss);
-
- pArgs->fieldName = StringObject::NewString(pFD->GetName());
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::MatchField private
-//
-// Synopsis: Find out whether the given field name is the same as the name
-// of the field descriptor field name.
-//
-//
-//+----------------------------------------------------------------------------
-BOOL CRemotingServices::MatchField(FieldDesc* pCurField, LPCUTF8 szFieldName)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pCurField));
- PRECONDITION(CheckPointer(szFieldName));
- }
- CONTRACTL_END;
-
- // Get the name of the field
- LPCUTF8 szCurFieldName;
- if (FAILED(pCurField->GetName_NoThrow(&szCurFieldName)))
- {
- return FALSE;
- }
-
- return strcmp(szCurFieldName, szFieldName) == 0;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::Wrap public
-//
-// Synopsis: Wrap a contextful object to create a proxy
-// Delegates to a helper method to do the actual work
-//
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::Wrap(OBJECTREF obj)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
- // Basic sanity check
- VALIDATEOBJECTREF(obj);
-
- // ******************* WARNING ********************************************
- // Do not throw any exceptions or provoke GC without setting up a frame.
- // At present its the callers responsibility to setup a frame that can
- // handle exceptions.
- // ************************************************************************
- OBJECTREF orProxy = obj;
- if(obj != NULL && (obj->GetMethodTable()->IsContextful()))
- {
- if(!IsTransparentProxy(OBJECTREFToObject(obj)))
- {
- // See if we can extract the proxy from the object
- orProxy = GetProxyFromObject(obj);
- if(orProxy == NULL)
- {
- // ask the remoting services to wrap the object
- orProxy = CRemotingServices::WrapHelper(obj);
- }
- }
- }
-
- return orProxy;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::WrapHelper public
-//
-// Synopsis: Wrap an object to return a proxy. This function assumes that
-// a fcall frame is already setup.
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::WrapHelper(OBJECTREF obj)
-{
- // Basic sanity check
- VALIDATEOBJECTREF(obj);
-
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(obj != NULL);
- PRECONDITION(!IsTransparentProxy(OBJECTREFToObject(obj)));
- PRECONDITION(obj->GetMethodTable()->IsContextful());
- }
- CONTRACTL_END;
-
-
- // Default return value indicates an error
- OBJECTREF newobj = NULL;
- MethodDesc* pTargetMD = NULL;
-
- // Ensure remoting has been started.
- EnsureRemotingStarted();
-
- // Get the address of wrap in managed code
- pTargetMD = CRemotingServices::MDofWrap();
-
- // call the managed method to wrap
- newobj = ObjectToOBJECTREF( (Object *)CTPMethodTable::CallTarget(pTargetMD,
- (LPVOID)OBJECTREFToObject(obj),
- NULL));
-
- return newobj;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetProxyFromObject public
-//
-// Synopsis: Extract the proxy from the field in the
-// ContextBoundObject class
-//
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::GetProxyFromObject(OBJECTREF obj)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- PRECONDITION(obj != NULL);
- }
- CONTRACTL_END;
-
- // Basic sanity check
- VALIDATEOBJECTREF(obj);
-
- // We can derive a proxy for contextful types only.
- _ASSERTE(obj->GetMethodTable()->IsContextful());
-
- OBJECTREF srvID = (OBJECTREF)(Object*)obj->GetPtrOffset(s_dwMBRIDOffset);
- OBJECTREF orProxy = NULL;
-
- if (srvID != NULL)
- orProxy = (OBJECTREF)(Object*)srvID->GetPtrOffset(s_dwTPOrObjOffsetInIdentity);
-
- // This should either be null or a proxy type
- _ASSERTE((orProxy == NULL) || IsTransparentProxy(OBJECTREFToObject(orProxy)));
-
- return orProxy;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::IsProxyToRemoteObject public
-//
-// Synopsis: Check if the proxy is to a remote object
-// (1) TRUE : if object is non local (ie outside this PROCESS) otherwise
-// (2) FALSE
-//
-//+----------------------------------------------------------------------------
-BOOL CRemotingServices::IsProxyToRemoteObject(OBJECTREF obj)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(obj != NULL);
- }
- CONTRACTL_END;
-
- // Basic sanity check
- VALIDATEOBJECTREF(obj);
-
- // If remoting is not started, for now let us just return FALSE
- if(!s_fRemotingStarted)
- return FALSE;
-
- if(!obj->IsTransparentProxy())
- return FALSE;
-
- // so it is a transparent proxy
- AppDomain *pDomain = GetServerDomainForProxy(obj);
- if(pDomain != NULL)
- return TRUE;
-
- return FALSE;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetObjectFromProxy public
-//
-// Synopsis: Extract the object given a proxy.
-//
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::GetObjectFromProxy(OBJECTREF obj)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- PRECONDITION(obj != NULL);
- PRECONDITION(s_fRemotingStarted);
- PRECONDITION(IsTransparentProxy(OBJECTREFToObject(obj)));
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- // Basic sanity check
- VALIDATEOBJECTREF(obj);
-
- OBJECTREF oref = NULL;
- if (CTPMethodTable__GenericCheckForContextMatch(OBJECTREFToObject(obj)))
- {
- OBJECTREF objRef = ObjectToOBJECTREF(GetRealProxy(OBJECTREFToObject(obj)));
- oref = (OBJECTREF)(Object*)objRef->GetPtrOffset(s_dwServerOffsetInRealProxy);
- if (oref != NULL)
- obj = oref;
- }
-
- return obj;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetServerIdentityFromProxy private
-//
-// Synopsis: Gets the server identity (if one exists) from a proxy
-//
-//
-//
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::GetServerIdentityFromProxy(OBJECTREF obj)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(obj != NULL);
- PRECONDITION(IsTransparentProxy(OBJECTREFToObject(obj)));
- }
- CONTRACTL_END;
-
-
- // Extract the real proxy underlying the transparent proxy
- OBJECTREF pObj = ObjectToOBJECTREF(GetRealProxy(OBJECTREFToObject(obj)));
-
- OBJECTREF id = NULL;
-
- // Extract the identity object
- pObj = (OBJECTREF)(Object*)pObj->GetPtrOffset(s_dwIdOffset);
-
- // Extract the _identity from the real proxy only if it is an instance of
- // remoting proxy
- if((pObj != NULL) && IsInstanceOfServerIdentity(pObj->GetMethodTable()))
- id = pObj;
-
- return id;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetServerDomainForProxy public
-//
-// Synopsis: Returns the AppDomain corresponding to the server
-// if the proxy and the server are in the same process.
-//
-//
-//+----------------------------------------------------------------------------
-AppDomain *CRemotingServices::GetServerDomainForProxy(OBJECTREF proxy)
-{
- CONTRACT (AppDomain*)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(proxy != NULL);
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- // call the managed method
- Context *pContext = (Context *)GetServerContextForProxy(proxy);
- if (pContext)
- RETURN pContext->GetDomain();
- else
- RETURN NULL;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetServerDomainIdForProxy public
-//
-// Synopsis: Returns the AppDomain ID corresponding to the server
-// if the proxy and the server are in the same process.
-// Returns 0 if it cannot determine.
-//
-//
-//+----------------------------------------------------------------------------
-int CRemotingServices::GetServerDomainIdForProxy(OBJECTREF proxy)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(proxy != NULL);
- PRECONDITION(IsTransparentProxy(OBJECTREFToObject(proxy)));
- }
- CONTRACTL_END;
-
- // Get the address of GetDomainIdForProxy in managed code
- MethodDesc* pTargetMD = CRemotingServices::MDofGetServerDomainIdForProxy();
-
- // This will just read the appDomain ID from the marshaled data
- // for the proxy. It returns 0 if the proxy is to a server in another
- // process. It may also return 0 if it cannot determine the server
- // domain ID (eg. for Well Known Object proxies).
-
- // call the managed method
- // <REVISIT_TODO>This cast to Int32 actually causes a potential loss
- // of data.</REVISIT_TODO>
- return (int)(INT_PTR)CTPMethodTable::CallTarget(
- pTargetMD,
- (LPVOID)OBJECTREFToObject(proxy),
- NULL);
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetServerContextForProxy public
-//
-// Synopsis: Returns the AppDomain corresponding to the server
-// if the proxy and the server are in the same process.
-//
-//
-//+----------------------------------------------------------------------------
-Context *CRemotingServices::GetServerContextForProxy(OBJECTREF proxy)
-{
- CONTRACT (Context*)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(proxy != NULL);
- PRECONDITION(IsTransparentProxy(OBJECTREFToObject(proxy)));
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- // Get the address of GetAppDomainForProxy in managed code
- MethodDesc* pTargetMD = CRemotingServices::MDofGetServerContextForProxy();
-
- // This will return the correct VM Context object for the server if
- // the proxy is true cross domain proxy to a server in another domain
- // in the same process. The managed method will Assert if called on a proxy
- // which is either half-built or does not have an ObjRef ... which may
- // happen for eg. if the proxy and the server are in the same appdomain.
-
- // we return NULL if the server object for the proxy is in another
- // process or if the appDomain for the server is invalid or if we cannot
- // determine the context (eg. well known object proxies).
-
- // call the managed method
- RETURN (Context *)CTPMethodTable::CallTarget(
- pTargetMD,
- (LPVOID)OBJECTREFToObject(proxy),
- NULL);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::CreateProxyForDomain public
-//
-// Synopsis: Create a proxy for the app domain object by calling marshal
-// inside the newly created domain and unmarshaling in the old
-// domain
-//
-//
-//+----------------------------------------------------------------------------
-OBJECTREF CRemotingServices::CreateProxyForDomain(AppDomain* pDomain)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pDomain));
- }
- CONTRACTL_END;
-
- // Ensure remoting has been started.
- EnsureRemotingStarted();
-
- MethodDesc* pTargetMD = MDOfCreateProxyForDomain();
-
- // Call the managed method which will marshal and unmarshal the
- // appdomain object to create the proxy
-
- // We pass the ContextID of the default context of the new appDomain
- // object. This helps the boot-strapping! (i.e. entering the new domain
- // to marshal itself out).
-
- Object *proxy = (Object *)CTPMethodTable::CallTarget(
- pTargetMD,
- (LPVOID)(DWORD_PTR)pDomain->GetId().m_dwId,
- (LPVOID)pDomain->GetDefaultContext());
- return ObjectToOBJECTREF(proxy);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetClass public
-//
-// Synopsis: Extract the true class of the object whose proxy is given.
-//
-//
-//
-//+----------------------------------------------------------------------------
-REFLECTCLASSBASEREF CRemotingServices::GetClass(OBJECTREF pThis)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(pThis != NULL);
- }
- CONTRACTL_END;
-
- REFLECTCLASSBASEREF refClass = NULL;
- MethodTable *pMT = NULL;
-
- GCPROTECT_BEGIN(pThis);
-
- // For proxies to objects in the same appdomain, we always know the
- // correct type
- if(GetServerIdentityFromProxy(pThis) != NULL)
- {
- pMT = pThis->GetTrueMethodTable();
- }
- else
- {
- // For everything else either we have refined the proxy to its correct type
- // or we have to consult the objref to get the true type
-
- MethodDesc* pTargetMD = CRemotingServices::MDofGetType();
-
- refClass = (REFLECTCLASSBASEREF)(ObjectToOBJECTREF((Object *)CTPMethodTable::CallTarget(pTargetMD,
- (LPVOID)OBJECTREFToObject(pThis), NULL)));
-
- if(refClass == NULL)
- {
- // There was no objref associated with the proxy or it is a proxy
- // that we do not understand.
- // In this case, we return the class that is stored in the proxy
- pMT = pThis->GetTrueMethodTable();
- }
-
- _ASSERTE(refClass != NULL || pMT != NULL);
-
- // Refine the proxy to the class just retrieved
- if(refClass != NULL)
- {
- CTPMethodTable::RefineProxy((TRANSPARENTPROXYREF)pThis, refClass->GetType());
- }
- }
-
- if (refClass == NULL)
- {
- PREFIX_ASSUME(pMT != NULL);
- refClass = (REFLECTCLASSBASEREF)pMT->GetManagedClassObject();
- }
-
- GCPROTECT_END();
-
- _ASSERTE(refClass != NULL);
- return refClass;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRealProxy::SetStubData public
-//
-// Synopsis: Set the stub data in the transparent proxy
-//
-//+----------------------------------------------------------------------------
-FCIMPL2(VOID, CRealProxy::SetStubData, Object* orRPUNSAFE, Object* orStubDataUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- BOOL fThrow = FALSE;
- REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE);
- OBJECTREF orStubData = ObjectToOBJECTREF(orStubDataUNSAFE);
-
- if (orRP != NULL && orStubData != NULL)
- {
- TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy();
- if (orTP != NULL)
- {
- orTP->SetStubData(orStubData);
- }
- else
- {
- fThrow = TRUE;
- }
- }
- else
- {
- fThrow = TRUE;
- }
-
- if(fThrow)
- FCThrowVoid(kArgumentNullException);
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRealProxy::GetStubData public
-//
-// Synopsis: Get the stub data in the transparent proxy
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(Object*, CRealProxy::GetStubData, Object* orRPUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- }
- CONTRACTL_END;
-
- BOOL fThrow = FALSE;
- REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE);
- OBJECTREF orRet = NULL;
-
- if (orRP != NULL)
- {
- TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy();
- if (orTP != NULL)
- orRet = orTP->GetStubData();
- else
- fThrow = TRUE;
- }
- else
- {
- fThrow = TRUE;
- }
-
- if(fThrow)
- FCThrow(kArgumentNullException);
-
- return OBJECTREFToObject(orRet);
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRealProxy::GetDefaultStub public
-//
-// Synopsis: Get the default stub implemented by us which matches contexts
-//
-//+----------------------------------------------------------------------------
-FCIMPL0(LPVOID, CRealProxy::GetDefaultStub)
-{
- FCALL_CONTRACT;
-
- return (LPVOID)CRemotingServices__CheckForContextMatch;
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRealProxy::GetStub public
-//
-// Synopsis: Get the stub pointer in the transparent proxy
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(LPVOID, CRealProxy::GetStub, Object* orRPUNSAFE)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(CheckPointer(orRPUNSAFE));
- }
- CONTRACTL_END;
-
- REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE);
- TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy();
-
- return orTP->GetStub();
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRealProxy::GetProxiedType public
-//
-// Synopsis: Get the type that is represented by the transparent proxy
-//
-//+----------------------------------------------------------------------------
-FCIMPL1(Object*, CRealProxy::GetProxiedType, Object* orRPUNSAFE)
-{
- FCALL_CONTRACT;
-
- REFLECTCLASSBASEREF refClass = NULL;
- REALPROXYREF orRP = (REALPROXYREF)ObjectToOBJECTREF(orRPUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_RET_1(orRP);
-
- TRANSPARENTPROXYREF orTP = orRP->GetTransparentProxy();
-
- refClass = CRemotingServices::GetClass(orTP);
- _ASSERTE(refClass != NULL);
-
- HELPER_METHOD_FRAME_END();
- return OBJECTREFToObject(refClass);
-}
-FCIMPLEND
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::Initialize public
-//
-// Synopsis: Initialized data structures needed for managing tranparent
-// proxies
-//
-//+----------------------------------------------------------------------------
-VOID CTPMethodTable::Initialize()
-{
- STANDARD_VM_CONTRACT;
-
- s_TPMethodTableCrst.Init(CrstTPMethodTable);
-}
-
-//+----------------------------------------------------------------------------
-
-PCODE CTPMethodTable::GetTPStubEntryPoint()
-{
- LIMITED_METHOD_CONTRACT;
- return GetEEFuncEntryPoint(TransparentProxyStub);
-}
-
-PCODE CTPMethodTable::GetDelegateStubEntryPoint()
-{
- LIMITED_METHOD_CONTRACT;
- return GetEEFuncEntryPoint(TransparentProxyStub_CrossContext);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::EnsureFieldsInitialized private
-//
-// Synopsis: Initialize the static fields of CTPMethodTable class
-// and the thunk manager classes
-//
-//
-//+----------------------------------------------------------------------------
-void CTPMethodTable::EnsureFieldsInitialized()
-{
- CONTRACT_VOID
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- POSTCONDITION(s_fTPTableFieldsInitialized);
- }
- CONTRACT_END;
-
- if (!s_fTPTableFieldsInitialized)
- {
- GCX_PREEMP();
-
- // Load Tranparent proxy class (do this before we enter the critical section)
- MethodTable* pTPMT = MscorlibBinder::GetClass(CLASS__TRANSPARENT_PROXY);
- _ASSERTE(pTPMT->IsTransparentProxy());
-
- CrstHolder ch(&s_TPMethodTableCrst);
-
- if(!s_fTPTableFieldsInitialized)
- {
- // Obtain size of GCInfo stored above the method table
- CGCDesc *pGCDesc = CGCDesc::GetCGCDescFromMT(pTPMT);
- BYTE *pGCTop = (BYTE *) pGCDesc->GetLowestSeries();
- s_dwGCInfoBytes = (DWORD)(((BYTE *) pTPMT) - pGCTop);
- _ASSERTE((s_dwGCInfoBytes & 3) == 0);
-
- // Obtain the number of bytes to be copied for creating the TP
- // method tables containing thunks
- _ASSERTE(((s_dwGCInfoBytes + sizeof(MethodTable)) & (sizeof(PCODE)-1)) == 0);
- s_dwMTDataSlots = ((s_dwGCInfoBytes + sizeof(MethodTable)) / sizeof(PCODE));
- _ASSERTE(sizeof(MethodTable) == MethodTable::GetVtableOffset());
-
- // We rely on the number of interfaces implemented by the
- // Transparent proxy being 0, so that InterfaceInvoke hints
- // fail and trap to InnerFailStub which also fails and
- // in turn traps to FailStubWorker. In FailStubWorker, we
- // determine the class being proxied and return correct slot.
- _ASSERTE(pTPMT->GetNumInterfaces() == 0);
-
- CVirtualThunkMgr::InitVirtualThunkManager();
-
- // Create the global thunk table and set the cycle between
- // the transparent proxy class and the global thunk table
- CreateTPMethodTable(pTPMT);
-
-#ifdef HAS_REMOTING_PRECODE
- // Activate the remoting precode helper
- ActivatePrecodeRemotingThunk();
-#endif // HAS_REMOTING_PRECODE
-
- // NOTE: This must always be the last statement in this block
- // to prevent races
- // Load Tranparent proxy class
- s_fTPTableFieldsInitialized = TRUE;
- }
- }
-
- RETURN;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::GetRP public
-//
-// Synopsis: Get the real proxy backing the transparent proxy
-//
-//+----------------------------------------------------------------------------
-REALPROXYREF CTPMethodTable::GetRP(OBJECTREF orTP)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- PRECONDITION(orTP != NULL);
- PRECONDITION(orTP->IsTransparentProxy());
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- return (REALPROXYREF)(((TRANSPARENTPROXYREF)orTP)->GetRealProxy());
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::GetMethodTableBeingProxied public
-//
-// Synopsis: Get the real type backing the transparent proxy
-//
-//+----------------------------------------------------------------------------
-MethodTable * CTPMethodTable::GetMethodTableBeingProxied(OBJECTREF orTP)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_COOPERATIVE;
- SO_TOLERANT;
- PRECONDITION(orTP != NULL);
- PRECONDITION(orTP->IsTransparentProxy());
- }
- CONTRACTL_END;
-
- return ((TRANSPARENTPROXYREF)orTP)->GetMethodTableBeingProxied();
-}
-
-#define PAGE_ROUND_UP(cb) (((cb) + g_SystemInfo.dwAllocationGranularity) & ~(g_SystemInfo.dwAllocationGranularity - 1))
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CreateTPMethodTable private
-//
-// Synopsis: (1) Reserves a transparent proxy method table that is large
-// enough to support the largest vtable
-// (2) Commits memory for the GC info of the global thunk table and
-// sets the cycle between the transparent proxy class and the
-// globale thunk table.
-//
-//+----------------------------------------------------------------------------
-
-void CTPMethodTable::CreateTPMethodTable(MethodTable* pTPMT)
-{
- CONTRACT_VOID {
- THROWS;
- GC_NOTRIGGER;
- MODE_ANY;
- POSTCONDITION(CheckPointer(s_pThunkTable));
- } CONTRACT_END;
-
- // The largest possible vtable size 64K
- DWORD dwMaxSlots = 64*1024;
-
- // Allocate virtual memory that is big enough to hold a method table
- // of the maximum possible size
- DWORD dwReserveSize = 0;
- DWORD dwMethodTableReserveSize = (DWORD)(s_dwMTDataSlots * sizeof(PCODE));
- s_dwReservedTPIndirectionSlotSize = MethodTable::GetNumVtableIndirections(dwMaxSlots) * sizeof(PTR_PCODE);
- dwMethodTableReserveSize += s_dwReservedTPIndirectionSlotSize;
-
- dwMethodTableReserveSize += (DWORD)(dwMaxSlots * sizeof(PCODE));
- dwReserveSize = PAGE_ROUND_UP(dwMethodTableReserveSize);
-
- void *pAlloc = ::ClrVirtualAlloc(0, dwReserveSize, MEM_RESERVE | MEM_TOP_DOWN, PAGE_EXECUTE_READWRITE);
-
- if (pAlloc)
- {
- BOOL bFailed = TRUE;
-
- // Make sure that we have not created the one and only
- // transparent proxy method table before
- _ASSERTE(NULL == s_pThunkTable);
-
- // Commit the required amount of memory
- DWORD dwCommitSize = 0;
-
- // MethodTable memory
- DWORD dwMethodTableCommitSize = (s_dwMTDataSlots) * sizeof(PCODE);
- if (!ClrSafeInt<DWORD>::addition(0, dwMethodTableCommitSize, dwCommitSize))
- {
- COMPlusThrowHR(COR_E_OVERFLOW);
- }
-
- if (::ClrVirtualAlloc(pAlloc, dwCommitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
- {
- // Copy the fixed portion from the true TP Method Table
- memcpy(pAlloc,MTToAlloc(pTPMT, s_dwGCInfoBytes), (dwMethodTableCommitSize));
-
- // Initialize the transparent proxy method table
- InitThunkTable(0, dwMaxSlots, AllocToMT((BYTE *) pAlloc, s_dwGCInfoBytes));
-
- // At this point the transparent proxy class points to the
- // the true TP Method Table and not the transparent
- // proxy method table. We do not use the true method table
- // any more. Instead we use the transparent proxy method table
- // for allocating transparent proxies. So, we have to make the
- // transparent proxy class point to the one and only transparent
- // proxy method table
- pTPMT->GetClass()->SetMethodTableForTransparentProxy(s_pThunkTable);
-
- // Allocate the slots of the Object class method table because
- // we can reflect on the __Transparent proxy class even though
- // we never intend to use remoting.
- _ASSERTE(NULL != g_pObjectClass);
- _ASSERTE(0 == GetCommitedTPSlots());
- if(ExtendCommitedSlots(g_pObjectClass->GetNumMethods()))
- bFailed = FALSE;
- }
- else
- {
- ClrVirtualFree(pAlloc, 0, MEM_RELEASE);
- }
-
- if(bFailed)
- DestroyThunkTable();
- }
- else {
- if (pAlloc != NULL)
- ::ClrVirtualFree(pAlloc, 0, MEM_RELEASE);
- }
-
- // Note that the thunk table is set to null on any failure path
- // via DestroyThunkTable
- if (!s_pThunkTable)
- COMPlusThrowOM();
-
- RETURN;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::ExtendCommitedSlots private
-//
-// Synopsis: Extends the commited slots of transparent proxy method table to
-// the desired number
-//
-//+----------------------------------------------------------------------------
-BOOL CTPMethodTable::ExtendCommitedSlots(_In_range_(1,64*1024) DWORD dwSlots)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- INJECT_FAULT(return FALSE);
- PRECONDITION(s_dwCommitedTPSlots <= dwSlots);
- PRECONDITION(dwSlots <= s_dwReservedTPSlots);
- PRECONDITION((CVirtualThunks::GetVirtualThunks() == NULL) ||
- (s_dwCommitedTPSlots == CVirtualThunks::GetVirtualThunks()->_dwCurrentThunk));
-
- // Either we have initialized everything or we are asked to allocate
- // some slots during initialization
- PRECONDITION(s_fTPTableFieldsInitialized || (0 == s_dwCommitedTPSlots));
- }
- CONTRACTL_END;
-
- // Commit memory for TPMethodTable
- BOOL bAlloc = FALSE;
- void *pAlloc = MTToAlloc(s_pThunkTable, s_dwGCInfoBytes);
- ClrSafeInt<DWORD> dwCommitSize;
- dwCommitSize += s_dwMTDataSlots * sizeof(PCODE);
- dwCommitSize += MethodTable::GetNumVtableIndirections(dwSlots) * sizeof(PTR_PCODE);
-
- DWORD dwLastIndirectionSlot = s_pThunkTable->GetIndexOfVtableIndirection(s_pThunkTable->GetNumVirtuals() - 1);
- DWORD dwSlotsCommitSize = dwSlots * sizeof(PCODE);
- PCODE *pAllocSlots = (PCODE*)(((BYTE*)s_pThunkTable) + s_dwMTDataSlots * sizeof(PCODE) + s_dwReservedTPIndirectionSlotSize);
-
- if (dwCommitSize.IsOverflow())
- {
- return FALSE; // error condition
- }
-
- if (::ClrVirtualAlloc(pAlloc, dwCommitSize.Value(), MEM_COMMIT, PAGE_EXECUTE_READWRITE) &&
- ::ClrVirtualAlloc(pAllocSlots, dwSlotsCommitSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
- {
- _ASSERTE(FitsIn<WORD>(dwSlots));
- s_pThunkTable->SetNumVirtuals((WORD)dwSlots);
-
- MethodTable::VtableIndirectionSlotIterator it = s_pThunkTable->IterateVtableIndirectionSlotsFrom(dwLastIndirectionSlot);
- do
- {
- it.SetIndirectionSlot(&pAllocSlots[it.GetStartSlot()]);
- }
- while (it.Next());
-
- bAlloc = AllocateThunks(dwSlots, dwCommitSize.Value());
- }
-
- return bAlloc;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::AllocateThunks private
-//
-// Synopsis: Allocates the desired number of thunks for virtual methods
-//
-//+----------------------------------------------------------------------------
-BOOL CTPMethodTable::AllocateThunks(DWORD dwSlots, DWORD dwCommitSize)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
- // Check for existing thunks
- DWORD dwCommitThunks = 0;
- DWORD dwAllocThunks = dwSlots;
- MethodTable *pThunkTable = s_pThunkTable;
-
- CVirtualThunks* pThunks = CVirtualThunks::GetVirtualThunks();
- if (pThunks)
- {
- // Compute the sizes of memory to be commited and allocated
- BOOL fCommit;
- if (dwSlots < pThunks->_dwReservedThunks)
- {
- fCommit = TRUE;
- dwCommitThunks = dwSlots;
- dwAllocThunks = 0;
- }
- else
- {
- fCommit = (pThunks->_dwCurrentThunk != pThunks->_dwReservedThunks);
- dwCommitThunks = pThunks->_dwReservedThunks;
- dwAllocThunks = dwSlots - pThunks->_dwReservedThunks;
- }
-
- // Commit memory if needed
- if (fCommit)
- {
- DWORD dwCommitSizeTmp = (sizeof(CVirtualThunks) - ConstVirtualThunkSize) +
- ((dwCommitThunks - pThunks->_dwStartThunk) * ConstVirtualThunkSize);
-
- if (!::ClrVirtualAlloc(pThunks, dwCommitSizeTmp, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
- return(NULL);
-
- // Generate thunks that push slot number and jump to TP stub
- DWORD dwStartSlot = pThunks->_dwStartThunk;
- DWORD dwCurrentSlot = pThunks->_dwCurrentThunk;
- while (dwCurrentSlot < dwCommitThunks)
- {
- PCODE pCode = CreateThunkForVirtualMethod(dwCurrentSlot, (BYTE *)&pThunks->ThunkCode[dwCurrentSlot-dwStartSlot]);
- pThunkTable->SetSlot(dwCurrentSlot, pCode);
- ++dwCurrentSlot;
- }
-
- ClrFlushInstructionCache(&pThunks->ThunkCode[pThunks->_dwCurrentThunk-dwStartSlot],
- (dwCommitThunks-pThunks->_dwCurrentThunk)*ConstVirtualThunkSize);
-
- s_dwCommitedTPSlots = dwCommitThunks;
- pThunks->_dwCurrentThunk = dwCommitThunks;
- }
- }
-
- // <REVISIT_TODO>
- // Check for the avialability of a TP method table that is no longer being
- // reused </REVISIT_TODO>
-
- // Allocate memory if necessary
- if (dwAllocThunks)
- {
- DWORD dwReserveSize = ((sizeof(CVirtualThunks) - ConstVirtualThunkSize) +
- ((dwAllocThunks << 1) * ConstVirtualThunkSize) +
- g_SystemInfo.dwAllocationGranularity) & ~((size_t) g_SystemInfo.dwAllocationGranularity - 1);
-
- void *pAlloc = ::ClrVirtualAlloc(0, dwReserveSize,
- MEM_RESERVE | MEM_TOP_DOWN,
- PAGE_EXECUTE_READWRITE);
- if (pAlloc)
- {
- // Commit the required amount of memory
- DWORD dwCommitSizeTmp = (sizeof(CVirtualThunks) - ConstVirtualThunkSize) +
- (dwAllocThunks * ConstVirtualThunkSize);
-
- if (::ClrVirtualAlloc(pAlloc, dwCommitSizeTmp, MEM_COMMIT, PAGE_EXECUTE_READWRITE))
- {
- ((CVirtualThunks *) pAlloc)->_pNext = pThunks;
- pThunks = CVirtualThunks::SetVirtualThunks((CVirtualThunks *) pAlloc);
- pThunks->_dwReservedThunks = (dwReserveSize -
- (sizeof(CVirtualThunks) - ConstVirtualThunkSize)) /
- ConstVirtualThunkSize;
- pThunks->_dwStartThunk = dwCommitThunks;
- pThunks->_dwCurrentThunk = dwCommitThunks;
-
- // Generate thunks that push slot number and jump to TP stub
- DWORD dwStartSlot = pThunks->_dwStartThunk;
- DWORD dwCurrentSlot = pThunks->_dwCurrentThunk;
- while (dwCurrentSlot < dwSlots)
- {
- PCODE pCode = CreateThunkForVirtualMethod(dwCurrentSlot, (BYTE *)&pThunks->ThunkCode[dwCurrentSlot-dwStartSlot]);
- pThunkTable->SetSlot(dwCurrentSlot, pCode);
- ++dwCurrentSlot;
- }
-
- ClrFlushInstructionCache(&pThunks->ThunkCode[pThunks->_dwCurrentThunk-dwStartSlot],
- (dwSlots-pThunks->_dwCurrentThunk)*ConstVirtualThunkSize);
-
- s_dwCommitedTPSlots = dwSlots;
- pThunks->_dwCurrentThunk = dwSlots;
- }
- else
- {
- ::ClrVirtualFree(pAlloc, 0, MEM_RELEASE);
- return FALSE;
- }
- }
- else
- {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CreateTPOfClassForRP private
-//
-// Synopsis: Creates a transparent proxy that behaves as an object of the
-// supplied class
-//
-//+----------------------------------------------------------------------------
-void CTPMethodTable::CreateTPOfClassForRP(TypeHandle ty, REALPROXYREF *pRP, TRANSPARENTPROXYREF *pTP)
-{
- CONTRACT_VOID
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(!ty.IsNull());
- PRECONDITION(pRP != NULL);
- PRECONDITION(*pRP != NULL);
- PRECONDITION(pTP != NULL);
- POSTCONDITION(*pTP != NULL);
- }
- CONTRACT_END;
-
- // Ensure remoting is started.
- EnsureFieldsInitialized();
-
- MethodTable * pMT = ty.GetMethodTable();
-
- // Get the size of the VTable for the class to proxy
- DWORD dwSlots = pMT->GetNumVirtuals();
-
- if (dwSlots == 0)
- dwSlots = 1;
-
- // The global thunk table must have been initialized
- _ASSERTE(s_pThunkTable != NULL);
-
- // Check for the need to extend existing TP method table
- if (dwSlots > GetCommitedTPSlots())
- {
- CrstHolder ch(&s_TPMethodTableCrst);
-
- if (dwSlots > GetCommitedTPSlots())
- {
- if (!ExtendCommitedSlots(dwSlots))
- COMPlusThrowOM();
- }
- }
-
- // Create a TP Object
- IfNullThrow(*pTP = (TRANSPARENTPROXYREF) AllocateObject(GetMethodTable()));
-
- // Create the cycle between TP and RP
- (*pRP)->SetTransparentProxy(*pTP);
-
- // Make the TP behave as an object of supplied class
- (*pTP)->SetRealProxy(*pRP);
-
- // If we are creating a proxy for an interface then the class
- // is the object class else it is the class supplied
- if (pMT->IsInterface())
- {
- _ASSERTE(NULL != g_pObjectClass);
-
- (*pTP)->SetMethodTableBeingProxied(CRemotingServices::GetMarshalByRefClass());
-
- // Set the cached interface method table to the given interface
- // method table
- (*pTP)->SetInterfaceMethodTable(pMT);
- }
- else
- {
- (*pTP)->SetMethodTableBeingProxied(pMT);
- }
-
- RETURN;
-}
-
-Signature InitMessageData(messageData *msgData,
- FramedMethodFrame *pFrame,
- Module **ppModule,
- SigTypeContext *pTypeContext)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(msgData));
- PRECONDITION(CheckPointer(pFrame));
- PRECONDITION(CheckPointer(ppModule));
- PRECONDITION(CheckPointer(pTypeContext));
- }
- CONTRACTL_END;
-
- msgData->pFrame = pFrame;
- msgData->iFlags = 0;
-
- MethodDesc *pMD = pFrame->GetFunction();
- _ASSERTE(!pMD->ContainsGenericVariables());
- _ASSERTE(pMD->IsRuntimeMethodHandle());
-
- TypeHandle thGoverningType;
- BOOL fIsDelegate = pMD->GetMethodTable()->IsDelegate();
-
- // We want to calculate and store a governing type for the method since
- // sometimes the parent method table might be representative. We get the
- // exact type context from the this reference we're calling on (adjusting
- // for the fact it's a TP).
-
- // But cope with the common cases first for speed:
- // * If the method is not on a generic type and this is not the async
- // delegate case (which requires us to unwrap the delegate and have a
- // look) then we know the method desc's parent method table will be exact.
- // * We require method descs to be exact for the interface case as well (since
- // the target object doesn't help us resolve the interface type at all).
- // * COM interop can use this code path, but that doesn't support generics so
- // we can use the quick logic for that too.
- if ((!pMD->HasClassInstantiation() && !fIsDelegate) ||
- pMD->IsInterface() ||
- pMD->IsComPlusCall())
- {
- thGoverningType = TypeHandle(pMD->GetMethodTable());
- }
- else
- {
- MethodDesc *pTargetMD;
- MethodTable *pTargetMT;
- if (fIsDelegate)
- {
- // Async delegates are also handled differently in that the method and the
- // this are delegate wrappers round the real method and target.
- pTargetMD = COMDelegate::GetMethodDesc(pFrame->GetThis());
-
- // Delegates on static methods don't have a useful target instance.
- // But in that case the target method is guaranteed to have exact
- // type information.
- if (pTargetMD->IsStatic())
- pTargetMT = pTargetMD->GetMethodTable();
- else
- {
- OBJECTREF refDelegateTarget = COMDelegate::GetTargetObject(pFrame->GetThis());
- pTargetMT = refDelegateTarget->GetTrueMethodTable();
- }
- }
- else
- {
- pTargetMD = pMD;
- pTargetMT = CTPMethodTable::GetMethodTableBeingProxied(pFrame->GetThis());
- }
-
- // One last check to see if we can optimize the delegate case now we've
- // unwrapped it.
- if (fIsDelegate && !pTargetMD->HasClassInstantiation() && !pTargetMT->IsDelegate())
- {
- thGoverningType = TypeHandle(pTargetMD->GetMethodTable());
- }
- else
- {
- // Not quite done yet, we need to get the type that declares the method,
- // which may be a superclass of the type we're calling on.
- MethodTable *pDeclaringMT = pTargetMD->GetMethodTable();
- thGoverningType = ClassLoader::LoadGenericInstantiationThrowing(pDeclaringMT->GetModule(),
- pDeclaringMT->GetCl(),
- pTargetMD->GetExactClassInstantiation(TypeHandle(pTargetMT)));
- }
- }
-
- msgData->thGoverningType = thGoverningType;
-
- if (fIsDelegate)
- {
- DelegateEEClass* delegateCls = (DelegateEEClass*) pMD->GetMethodTable()->GetClass();
-
- _ASSERTE(pFrame->GetThis()->GetMethodTable()->IsDelegate());
-
- msgData->pDelegateMD = pMD;
- msgData->pMethodDesc = COMDelegate::GetMethodDesc(pFrame->GetThis());
-
- _ASSERTE(msgData->pMethodDesc != NULL);
- _ASSERTE(!msgData->pMethodDesc->ContainsGenericVariables());
- _ASSERTE(msgData->pMethodDesc->IsRuntimeMethodHandle());
-
- if (pMD == delegateCls->m_pBeginInvokeMethod)
- {
- msgData->iFlags |= MSGFLG_BEGININVOKE;
- }
- else
- {
- _ASSERTE(pMD == delegateCls->m_pEndInvokeMethod);
- msgData->iFlags |= MSGFLG_ENDINVOKE;
- }
- }
- else
- {
- msgData->pDelegateMD = NULL;
- msgData->pMethodDesc = pMD;
- _ASSERTE(msgData->pMethodDesc->IsRuntimeMethodHandle());
- }
-
- if (msgData->pMethodDesc->IsOneWay())
- {
- msgData->iFlags |= MSGFLG_ONEWAY;
- }
-
- if (msgData->pMethodDesc->IsCtor())
- {
- msgData->iFlags |= MSGFLG_CTOR;
- }
-
- Signature signature;
- Module *pModule;
-
- if (msgData->pDelegateMD)
- {
- signature = msgData->pDelegateMD->GetSignature();
- pModule = msgData->pDelegateMD->GetModule();
-
- // If the delegate is generic, pDelegateMD may not represent the exact instantiation so we recover it from 'this'.
- SigTypeContext::InitTypeContext(pFrame->GetThis()->GetMethodTable()->GetInstantiation(), Instantiation(), pTypeContext);
- }
- else if (msgData->pMethodDesc->IsVarArg())
- {
- VASigCookie *pVACookie = pFrame->GetVASigCookie();
- signature = pVACookie->signature;
- pModule = pVACookie->pModule;
- SigTypeContext::InitTypeContext(pTypeContext);
-
- }
- else
- {
- signature = msgData->pMethodDesc->GetSignature();
- pModule = msgData->pMethodDesc->GetModule();
- SigTypeContext::InitTypeContext(msgData->pMethodDesc, thGoverningType, pTypeContext);
- }
-
- *ppModule = pModule;
- return signature;
-}
-
-VOID CRealProxy::UpdateOptFlags(OBJECTREF refTP)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
-
- DWORD hierarchyDepth = 0;
- REALPROXYREF refRP = CTPMethodTable::GetRP(refTP);
-
- OBJECTHANDLE hServerIdentity = (OBJECTHANDLE)refRP->GetPtrOffset(CRemotingServices::GetOffsetOfSrvIdentityInRP());
- if (hServerIdentity == NULL)
- return;
-
- // Check if the proxy has already been marked as not equivalent.
- // In which case, it can never get marked as anything else
- RealProxyObject *rpTemp = (RealProxyObject *)OBJECTREFToObject(refRP);
-
- DWORD domainID = rpTemp->GetDomainID();
- AppDomainFromIDHolder ad((ADID)domainID, TRUE);
- if (domainID == 0 || ad.IsUnloaded()) //we do not use ptr
- return; // The appdomain the server belongs to, has been unloaded
- ad.Release();
- DWORD optFlag = rpTemp->GetOptFlags();
- if ((optFlag & OPTIMIZATION_FLAG_INITTED) &&
- !(optFlag & OPTIMIZATION_FLAG_PROXY_EQUIVALENT))
- return;
-
- OBJECTREF refSrvIdentity = ObjectFromHandle(hServerIdentity);
- // Is this a disconnected proxy ?
- if (refSrvIdentity == NULL)
- return;
-
- OBJECTREF refSrvObject = ObjectToOBJECTREF((Object *)refSrvIdentity->GetPtrOffset(CRemotingServices::GetOffsetOfTPOrObjInIdentity()));
-
- MethodTable *pCliMT = CTPMethodTable::GetMethodTableBeingProxied(refTP);
-
- BOOL bProxyQualifies = FALSE;
- BOOL bCastToSharedType = FALSE;
-
- // Check if modules are physically the same
-
- // Check the inheritance hierarchy of the server object, to find the type
- // that corresponds to the type the proxy is being cast to
- // @TODO - If being cast to an interface, currently the proxy doesnt get marked equivalent
- // @TODO - Need to check equivalency of the interface being cast to, and then reuse interface slot # on other side
- LPCUTF8 szCliTypeName, szCliNameSpace;
- szCliTypeName = pCliMT->GetFullyQualifiedNameInfo(&szCliNameSpace);
- PREFIX_ASSUME(szCliTypeName != NULL);
-
- MethodTable *pSrvHierarchy = refSrvObject->GetMethodTable();
-
- GCPROTECT_BEGIN(refRP);
- while (pSrvHierarchy)
- {
- LPCUTF8 szSrvTypeName, szSrvNameSpace;
- szSrvTypeName = pSrvHierarchy->GetFullyQualifiedNameInfo(&szSrvNameSpace);
- PREFIX_ASSUME(szSrvNameSpace != NULL);
-
- if (!strcmp(szCliTypeName, szSrvTypeName) && !strcmp(szCliNameSpace, szSrvNameSpace))
- {
- // Check if the types are shared. If they are, no further check neccesary
- if (pSrvHierarchy == pCliMT)
- {
- bProxyQualifies = TRUE;
- bCastToSharedType = TRUE;
- }
- else
- {
- bProxyQualifies = CRealProxy::ProxyTypeIdentityCheck(pCliMT, pSrvHierarchy);
- }
- break;
- }
-
- pSrvHierarchy = pSrvHierarchy->GetParentMethodTable();
- hierarchyDepth++;
- }
- GCPROTECT_END();
-
- optFlag = 0;
- if (bProxyQualifies && hierarchyDepth < OPTIMIZATION_FLAG_DEPTH_MASK)
- {
- optFlag = OPTIMIZATION_FLAG_INITTED | OPTIMIZATION_FLAG_PROXY_EQUIVALENT;
- if (bCastToSharedType)
- optFlag |= OPTIMIZATION_FLAG_PROXY_SHARED_TYPE;
- optFlag |= (hierarchyDepth & OPTIMIZATION_FLAG_DEPTH_MASK);
- }
- else
- optFlag = OPTIMIZATION_FLAG_INITTED;
-
- RealProxyObject *rpUNSAFE = (RealProxyObject *)OBJECTREFToObject(refRP);
- rpUNSAFE->SetOptFlags(optFlag);
-}
-
-BOOL CRealProxy::ProxyTypeIdentityCheck(MethodTable *pCliHierarchy, MethodTable *pSrvHierarchy)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- THROWS;
- }
- CONTRACTL_END
- // We have found the server side type that corresponds to the most derived type
- // on client side, that the proxy is cast to
- // Now do identity check on the server type hierarchy to see if there is an exact match
-
- BOOL bProxyQualifies = FALSE;
- do
- {
- LPCUTF8 szCliTypeName, szCliNameSpace;
- LPCUTF8 szSrvTypeName, szSrvNameSpace;
- szCliTypeName = pCliHierarchy->GetFullyQualifiedNameInfo(&szCliNameSpace);
- szSrvTypeName = pSrvHierarchy->GetFullyQualifiedNameInfo(&szSrvNameSpace);
- PREFIX_ASSUME(szCliTypeName != NULL);
- PREFIX_ASSUME(szSrvNameSpace != NULL);
-
- // If type names are different, there is no match
- if (strcmp(szCliTypeName, szSrvTypeName) ||
- strcmp(szCliNameSpace, szSrvNameSpace))
- {
- bProxyQualifies = FALSE;
- return bProxyQualifies;
- }
-
- PEAssembly *pClientPE = pCliHierarchy->GetAssembly()->GetManifestFile();
- PEAssembly *pServerPE = pSrvHierarchy->GetAssembly()->GetManifestFile();
- // If the PE files are different, there is no match
- if (!pClientPE->Equals(pServerPE))
- {
- bProxyQualifies = FALSE;
- return bProxyQualifies;
- }
-
- // If the number of interfaces implemented are different, there is no match
- if (pSrvHierarchy->GetNumInterfaces() != pCliHierarchy->GetNumInterfaces())
- {
- bProxyQualifies = FALSE;
- return bProxyQualifies;
- }
-
- MethodTable::InterfaceMapIterator srvItfIt = pSrvHierarchy->IterateInterfaceMap();
- MethodTable::InterfaceMapIterator cliItfIt = pCliHierarchy->IterateInterfaceMap();
- while (srvItfIt.Next())
- {
- BOOL succeeded;
- succeeded = cliItfIt.Next();
- CONSISTENCY_CHECK(succeeded);
- if (!ProxyTypeIdentityCheck(srvItfIt.GetInterface(), cliItfIt.GetInterface()))
- {
- bProxyQualifies = FALSE;
- return bProxyQualifies;
- }
- }
-
- pSrvHierarchy = pSrvHierarchy->GetParentMethodTable();
- pCliHierarchy = pCliHierarchy->GetParentMethodTable();
- }
- while (pSrvHierarchy && pCliHierarchy);
-
- if (pSrvHierarchy || pCliHierarchy)
- {
- bProxyQualifies = FALSE;
- return bProxyQualifies;
- }
-
- bProxyQualifies = TRUE;
- return bProxyQualifies;
-
-}
-
-ProfilerRemotingClientCallbackHolder::ProfilerRemotingClientCallbackHolder()
-{
-#ifdef PROFILING_SUPPORTED
- // If profiling is active, notify it that remoting stuff is kicking in
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingClientInvocationStarted();
- END_PIN_PROFILER();
-#endif // PROFILING_SUPPORTED
-}
-
-ProfilerRemotingClientCallbackHolder::~ProfilerRemotingClientCallbackHolder()
-{
-#ifdef PROFILING_SUPPORTED
- // If profiling is active, tell profiler we've made the call, received the
- // return value, done any processing necessary, and now remoting is done.
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingClientInvocationFinished();
- END_PIN_PROFILER();
-#endif // PROFILING_SUPPORTED
-}
-
-enum
-{
- CALLTYPE_INVALIDCALL = 0x0, // Important:: sync this with RealProxy.cs
- CALLTYPE_METHODCALL = 0x1, // Important:: sync this with RealProxy.cs
- CALLTYPE_CONSTRUCTORCALL = 0x2 // Important:: sync this with RealProxy.cs
-};
-
-extern "C" void STDCALL TransparentProxyStubPatch();
-
-//+----------------------------------------------------------------------------
-//
-// Method: TransparentProxyStubWorker
-//
-// Synopsis: This function gets control in two situations
-// (1) When a call is made on the transparent proxy it delegates to
-// PrivateInvoke method on the real proxy
-// (2) When a call is made on the constructor it again delegates to the
-// PrivateInvoke method on the real proxy.
-//
-//
-//+----------------------------------------------------------------------------
-extern "C" UINT32 STDCALL TransparentProxyStubWorker(TransitionBlock * pTransitionBlock, TADDR pMethodDescOrSlot)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- ENTRY_POINT;
- PRECONDITION(CheckPointer(pTransitionBlock));
- }
- CONTRACTL_END;
-
- UINT fpRetSize = 0;
-
- FrameWithCookie<TPMethodFrame> frame(pTransitionBlock);
- TPMethodFrame * pFrame = &frame;
-
- //we need to zero out the return value buffer because we will report it during GC
-#ifdef ENREGISTERED_RETURNTYPE_MAXSIZE
- ZeroMemory (pFrame->GetReturnValuePtr(), ENREGISTERED_RETURNTYPE_MAXSIZE);
-#else
- *(ARG_SLOT *)pFrame->GetReturnValuePtr() = 0;
-#endif
-
- // For virtual calls the slot number is pushed but for
- // non virtual calls/interface invoke the method descriptor is already
- // pushed
- MethodDesc * pMD;
- if ((pMethodDescOrSlot >> 16) == 0)
- {
- // The frame is not completly setup at this point.
- // Do not throw exceptions or provoke GC
- MethodTable* pMT = CTPMethodTable::GetMethodTableBeingProxied(pFrame->GetThis());
- _ASSERTE(pMT);
-
- // Replace the slot number with the method descriptor on the stack
- pMD = pMT->GetMethodDescForSlot((WORD)pMethodDescOrSlot);
- }
- else
- {
- pMD = dac_cast<PTR_MethodDesc>(pMethodDescOrSlot);
- }
- pFrame->SetFunction(pMD);
-
- pFrame->Push();
-
- // Give debugger opportunity to stop here now that we know the MethodDesc *
- TransparentProxyStubPatch();
-
- INSTALL_UNWIND_AND_CONTINUE_HANDLER;
-
- if (g_pConfig->UseNewCrossDomainRemoting())
- {
- BOOL bOptSuccess = FALSE;
- CrossDomainChannel cdc;
- bOptSuccess = cdc.CheckCrossDomainCall(pFrame);
- if (bOptSuccess)
- {
- fpRetSize = cdc.GetFPReturnSize();
- goto Done;
- }
- }
-
- {
- messageData msgData;
- Module *pModule = NULL;
- SigTypeContext inst;
- Signature signature = InitMessageData(&msgData, pFrame, &pModule, &inst);
-
- _ASSERTE(!signature.IsEmpty() && pModule);
-
- // Allocate metasig on the stack
- MetaSig mSig(signature, pModule, &inst);
- msgData.pSig = &mSig;
-
- MethodDesc *pMD = pFrame->GetFunction();
- if (pMD->GetMethodTable()->IsDelegate())
- {
- // check that there is only one target
- if (COMDelegate::IsTrueMulticastDelegate(pFrame->GetThis()))
- {
- COMPlusThrow(kArgumentException, W("Remoting_Delegate_TooManyTargets"));
- }
- }
-
- {
- ProfilerRemotingClientCallbackHolder profilerHolder;
-
- OBJECTREF pThisPointer = NULL;
-
- if (pMD->GetMethodTable()->IsDelegate())
- {
- // this is an async call
- _ASSERTE(pFrame->GetThis()->GetMethodTable()->IsDelegate());
-
- pThisPointer = COMDelegate::GetTargetObject(pFrame->GetThis());
- }
- else
- {
- pThisPointer = pFrame->GetThis();
- }
-
- OBJECTREF firstParameter;
- MethodDesc* pTargetMD = NULL;
- size_t callType = CALLTYPE_INVALIDCALL;
-
- // We are invoking either the constructor or a method on the object
- if(pMD->IsCtor())
- {
- // Get the address of PrivateInvoke in managed code
- pTargetMD = CRemotingServices::MDofPrivateInvoke();
- _ASSERTE(pThisPointer->IsTransparentProxy());
-
- firstParameter = CTPMethodTable::GetRP(pThisPointer);
-
- // Set a field to indicate that it is a constructor call
- callType = CALLTYPE_CONSTRUCTORCALL;
- }
- else
- {
- // Set a field to indicate that it is a method call
- callType = CALLTYPE_METHODCALL;
-
- if (pThisPointer->IsTransparentProxy())
- {
- // Extract the real proxy underlying the transparent proxy
- firstParameter = CTPMethodTable::GetRP(pThisPointer);
-
- // Get the address of PrivateInvoke in managed code
- pTargetMD = CRemotingServices::MDofPrivateInvoke();
- _ASSERTE(pTargetMD);
- }
- else
- {
- // must be async if this is not a TP
- _ASSERTE(pMD->GetMethodTable()->IsDelegate());
- firstParameter = NULL;
-
- // Get the address of PrivateInvoke in managed code
- pTargetMD = CRemotingServices::MDofInvokeStatic();
- }
-
- // Go ahead and call PrivateInvoke on Real proxy. There is no need to
- // catch exceptions thrown by it
- // See RealProxy.cs
- }
-
- _ASSERTE(pTargetMD);
-
- // Call the appropriate target
- CTPMethodTable::CallTarget(pTargetMD, (LPVOID)OBJECTREFToObject(firstParameter), (LPVOID)&msgData, (LPVOID)callType);
-
- // Check for the need to trip thread
- if (GetThread()->CatchAtSafePointOpportunistic())
- {
- // There is no need to GC protect the return object as
- // TPFrame is GC protecting it
- CommonTripThread();
- }
- } // ProfilerClientCallbackHolder
-
- {
- mSig.Reset();
-
- ArgIterator argit(&mSig);
-
-#ifdef _TARGET_X86_
- // Set the number of bytes to pop for x86
- pFrame->SetCbStackPop(argit.CbStackPop());
-#endif // _TARGET_X86_
-
- fpRetSize = argit.GetFPReturnSize();
- }
- }
-
-Done: ;
-
- pFrame->Pop();
-
- UNINSTALL_UNWIND_AND_CONTINUE_HANDLER;
-
- return fpRetSize;
-}
-
-
-// Helper due to inability to combine SEH with anything interesting.
-BOOL CTPMethodTable::CheckCastHelper(MethodDesc* pTargetMD, LPVOID pFirst, LPVOID pSecond)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pTargetMD));
- PRECONDITION(CheckPointer(pFirst, NULL_OK));
- PRECONDITION(CheckPointer(pSecond, NULL_OK));
- }
- CONTRACTL_END;
-
- // Actual return type is a managed 'bool', so only look at a CLR_BOOL-sized
- // result. The high bits are undefined on AMD64. (Note that a narrowing
- // cast to CLR_BOOL will not work since it is the same as checking the
- // size_t result != 0.)
- LPVOID ret = CallTarget(pTargetMD, pFirst, pSecond);
- return *(CLR_BOOL*)StackElemEndianessFixup(&ret, sizeof(CLR_BOOL));
-}
-
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CheckCast private
-//
-// Synopsis: Call the managed checkcast method to determine whether the
-// server type can be cast to the given type
-//
-//
-//
-//+----------------------------------------------------------------------------
-BOOL CTPMethodTable::CheckCast(MethodDesc* pTargetMD, TRANSPARENTPROXYREF orTP, TypeHandle ty)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pTargetMD));
- PRECONDITION(orTP != NULL);
- PRECONDITION(!ty.IsNull());
- }
- CONTRACTL_END;
-
- REFLECTCLASSBASEREF reflectType = NULL;
- LPVOID pvType = NULL;
- BOOL fCastOK = FALSE;
-
- typedef struct _GCStruct
- {
- TRANSPARENTPROXYREF orTP;
- REALPROXYREF orRP;
- } GCStruct;
-
- GCStruct gcValues;
- gcValues.orTP = orTP;
- gcValues.orRP = GetRP(orTP);
-
- GCPROTECT_BEGIN (gcValues);
-
- reflectType = (REFLECTCLASSBASEREF) ty.GetMethodTable()->GetManagedClassObject();
- *(REFLECTCLASSBASEREF *)&pvType = reflectType;
-
- fCastOK = CheckCastHelper(pTargetMD,
- (LPVOID)OBJECTREFToObject(gcValues.orRP),
- pvType);
-
- if (fCastOK)
- {
- _ASSERTE(s_fTPTableFieldsInitialized);
-
- // The cast succeeded. Replace the current type in the proxy
- // with the given type.
-
- CrstHolder ch(&s_TPMethodTableCrst);
-
- if (ty.IsInterface())
- {
- // We replace the cached interface method table with the interface
- // method table that we are trying to cast to. This will ensure that
- // casts to this interface, which are likely to happen, will succeed.
- gcValues.orTP->SetInterfaceMethodTable(ty.GetMethodTable());
- }
- else
- {
- MethodTable *pCurrent = gcValues.orTP->GetMethodTableBeingProxied();
-
- BOOL fDerivedClass = FALSE;
- // Check whether this class derives from the current class
- fDerivedClass = CRemotingServices::CheckCast(gcValues.orTP, ty,
- TypeHandle(pCurrent));
- // We replace the current method table only if we cast to a more
- // derived class
- if (fDerivedClass)
- {
- // Set the method table in the proxy to the given method table
- RefineProxy(gcValues.orTP, ty);
- }
- }
- }
-
- GCPROTECT_END();
- return fCastOK;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::RefineProxy public
-//
-// Synopsis: Set the method table in the proxy to the given class' method table.
-// Additionally, expand the TP method table to the required number of slots.
-//
-//
-//+----------------------------------------------------------------------------
-void CTPMethodTable::RefineProxy(TRANSPARENTPROXYREF orTP, TypeHandle ty)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(orTP != NULL);
- PRECONDITION(!ty.IsNull());
- }
- CONTRACTL_END;
-
- // Do the expansion only if necessary
- MethodTable *pMT = ty.GetMethodTable();
-
- if (pMT != orTP->GetMethodTableBeingProxied())
- {
- orTP->SetMethodTableBeingProxied(pMT);
-
- // Extend the vtable if necessary
- DWORD dwSlots = pMT->GetNumVirtuals();
-
- if (dwSlots == 0)
- dwSlots = 1;
-
- if((dwSlots > GetCommitedTPSlots()) && !ExtendCommitedSlots(dwSlots))
- {
- // We failed to extend the committed slots. Out of memory.
- COMPlusThrowOM();
- }
-
- }
-}
-
-#ifndef HAS_REMOTING_PRECODE
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::GetOrCreateNonVirtualSlotForVirtualMethod private
-//
-// Synopsis: Get a slot for a non-virtual call to a virtual method.
-//
-//+----------------------------------------------------------------------------
-PTR_PCODE CTPMethodTable::GetOrCreateNonVirtualSlotForVirtualMethod(MethodDesc* pMD)
-{
- CONTRACT (PTR_PCODE)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMD));
- PRECONDITION(pMD->IsRemotingInterceptedViaVirtualDispatch());
- POSTCONDITION(CheckPointer(RETVAL));
- }
- CONTRACT_END;
-
- // Ensure the TP MethodTable's fields have been initialized.
- EnsureFieldsInitialized();
-
- PTR_PCODE pSlot;
-
- {
- // Create the thunk in a thread safe manner
- CrstHolder ch(&s_TPMethodTableCrst);
-
- // NOTE: CNonVirtualThunk::SetNonVirtualThunks() depends on the lock being initialized
- CNonVirtualThunk::InitializeListLock();
-
- // Create hash table if we do not have one yet
- if (s_pThunkHashTable == NULL)
- {
- NewHolder <EEThunkHashTable> pTempHash(new EEThunkHashTable());
-
- LockOwner lock = {&s_TPMethodTableCrst, IsOwnerOfCrst};
- IfNullThrow(pTempHash->Init(23,&lock));
-
- s_pThunkHashTable = pTempHash.Extract();
- }
-
- if (!s_pThunkHashTable->GetValue(pMD, (HashDatum *)&pSlot))
- {
- PCODE pThunkCode = CreateNonVirtualThunkForVirtualMethod(pMD);
-
- _ASSERTE(CNonVirtualThunkMgr::IsThunkByASM(pThunkCode));
- _ASSERTE(CNonVirtualThunkMgr::GetMethodDescByASM(pThunkCode));
-
- // Set the generated thunk once and for all..
- CNonVirtualThunk *pThunk = CNonVirtualThunk::SetNonVirtualThunks((BYTE*)pThunkCode);
-
- // Remember the thunk address in a hash table
- // so that we dont generate it again
- pSlot = (PTR_PCODE)pThunk->GetAddrOfCode();
- s_pThunkHashTable->InsertValue(pMD, (HashDatum)pSlot);
- }
- }
-
- RETURN pSlot;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::DestroyThunk public
-//
-// Synopsis: Destroy the thunk for the non virtual method.
-//
-//
-//+----------------------------------------------------------------------------
-void CTPMethodTable::DestroyThunk(MethodDesc* pMD)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMD));
- }
- CONTRACTL_END;
-
- if(s_pThunkHashTable)
- {
- CrstHolder ch(&s_TPMethodTableCrst);
-
- LPVOID pvCode = NULL;
- s_pThunkHashTable->GetValue(pMD, (HashDatum *)&pvCode);
- CNonVirtualThunk *pThunk = NULL;
- if(NULL != pvCode)
- {
- pThunk = CNonVirtualThunk::AddrToThunk(pvCode);
- delete pThunk;
- s_pThunkHashTable->DeleteValue(pMD);
- }
- }
-}
-#endif // HAS_REMOTING_PRECODE
-
-static LPVOID CallTargetWorker1(MethodDesc* pTargetMD,
- LPVOID pvFirst,
- LPVOID pvSecond)
-{
- STATIC_CONTRACT_THROWS;
- STATIC_CONTRACT_GC_TRIGGERS;
- STATIC_CONTRACT_MODE_COOPERATIVE;
- STATIC_CONTRACT_SO_INTOLERANT;
-
- LPVOID ret = NULL;
- PCODE pTarget = pTargetMD->GetSingleCallableAddrOfCode();
-
-#if defined(DEBUGGING_SUPPORTED)
- if (CORDebuggerTraceCall())
- {
- g_pDebugInterface->TraceCall((const BYTE*)pTarget);
- }
-#endif // DEBUGGING_SUPPORTED
-
-
- BEGIN_CALL_TO_MANAGED();
-
- ret = CTPMethodTable__CallTargetHelper2((const BYTE*)pTarget, pvFirst, pvSecond);
-
- END_CALL_TO_MANAGED();
-
- return ret;
-}
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CTPMethodTable::CallTarget private
-//
-// Synopsis: Calls the target method on the given object
-//
-//+----------------------------------------------------------------------------
-LPVOID __stdcall CTPMethodTable::CallTarget (MethodDesc* pTargetMD,
- LPVOID pvFirst,
- LPVOID pvSecond)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- SO_INTOLERANT;
- PRECONDITION(CheckPointer(pTargetMD));
- PRECONDITION(CheckPointer(pvFirst, NULL_OK));
- PRECONDITION(CheckPointer(pvSecond, NULL_OK));
- }
- CONTRACTL_END;
-
-#ifdef _DEBUG
-
- Thread* curThread = GetThread();
-
- Object* ObjRefTable[OBJREF_TABSIZE];
-
- if (curThread)
- memcpy(ObjRefTable, curThread->dangerousObjRefs, sizeof(curThread->dangerousObjRefs));
-
-#endif // _DEBUG
-
- LPVOID ret = CallTargetWorker1(pTargetMD, pvFirst, pvSecond);
-
-#ifdef _DEBUG
- // Restore dangerousObjRefs when we return back to EE after call
- if (curThread)
- memcpy(curThread->dangerousObjRefs, ObjRefTable, sizeof(curThread->dangerousObjRefs));
-
- ENABLESTRESSHEAP ();
-#endif // _DEBUG
-
- return ret;
-}
-
-
-static LPVOID CallTargetWorker2(MethodDesc* pTargetMD,
- LPVOID pvFirst,
- LPVOID pvSecond,
- LPVOID pvThird)
-{
- STATIC_CONTRACT_THROWS;
- STATIC_CONTRACT_GC_TRIGGERS;
- STATIC_CONTRACT_MODE_COOPERATIVE;
- STATIC_CONTRACT_SO_INTOLERANT;
-
- LPVOID ret = NULL;
- PCODE pTarget = pTargetMD->GetSingleCallableAddrOfCode();
-
-#if defined(DEBUGGING_SUPPORTED)
- if (CORDebuggerTraceCall())
- {
- g_pDebugInterface->TraceCall((const BYTE*)pTarget);
- }
-#endif // DEBUGGING_SUPPORTED
-
- BEGIN_CALL_TO_MANAGED();
-
- ret = CTPMethodTable__CallTargetHelper3((const BYTE*)pTarget, pvFirst, pvSecond, pvThird);
-
- END_CALL_TO_MANAGED();
- return ret;
-
-}
-
-LPVOID __stdcall CTPMethodTable::CallTarget (MethodDesc* pTargetMD,
- LPVOID pvFirst,
- LPVOID pvSecond,
- LPVOID pvThird)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- SO_INTOLERANT;
- PRECONDITION(CheckPointer(pTargetMD));
- PRECONDITION(CheckPointer(pvFirst, NULL_OK));
- PRECONDITION(CheckPointer(pvSecond, NULL_OK));
- PRECONDITION(CheckPointer(pvThird, NULL_OK));
- }
- CONTRACTL_END;
-
-#ifdef _DEBUG
- Thread* curThread = GetThread();
-
- Object* ObjRefTable[OBJREF_TABSIZE];
- if (curThread)
- memcpy(ObjRefTable, curThread->dangerousObjRefs, sizeof(curThread->dangerousObjRefs));
-
-#endif // _DEBUG
-
- LPVOID ret = CallTargetWorker2(pTargetMD, pvFirst, pvSecond, pvThird);
-
-#ifdef _DEBUG
- // Restore dangerousObjRefs when we return back to EE after call
- if (curThread)
- memcpy(curThread->dangerousObjRefs, ObjRefTable, sizeof(curThread->dangerousObjRefs));
-
- ENABLESTRESSHEAP ();
-#endif // _DEBUG
-
- return ret;
-}
-
-
-#ifndef HAS_REMOTING_PRECODE
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunk::SetNextThunk public
-//
-// Synopsis: Creates a thunk for the given address and adds it to the global
-// list
-//
-//+----------------------------------------------------------------------------
-CNonVirtualThunk* CNonVirtualThunk::SetNonVirtualThunks(const BYTE* pbCode)
-{
- CONTRACT (CNonVirtualThunk*)
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- PRECONDITION(CheckPointer(pbCode));
- POSTCONDITION(CheckPointer(RETVAL));
- }
- CONTRACT_END;
-
- CNonVirtualThunk *pThunk = new CNonVirtualThunk(pbCode);
-
- // Put the generated thunk in a global list
- // Note: this is called when a NV thunk is being created ..
- // The TPMethodTable critsec is held at this point
- pThunk->SetNextThunk();
-
- // Set up the stub manager if necessary
- CNonVirtualThunkMgr::InitNonVirtualThunkManager();
-
- RETURN pThunk;
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunk::~CNonVirtualThunk public
-//
-// Synopsis: Deletes the thunk from the global list of thunks
-//
-//
-//+----------------------------------------------------------------------------
-CNonVirtualThunk::~CNonVirtualThunk()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(s_pNonVirtualThunks));
- }
- CONTRACTL_END;
-
- CNonVirtualThunk* pCurr = s_pNonVirtualThunks;
- CNonVirtualThunk* pPrev = NULL;
- BOOL found = FALSE;
-
- // Note: This is called with the TPMethodTable critsec held
- while(!found && (NULL != pCurr))
- {
- if(pCurr == this)
- {
- found = TRUE;
- SimpleRWLock::SimpleWriteLockHolder swlh(s_pNonVirtualThunksListLock);
-
- // Unlink from the chain
- if(NULL != pPrev)
- {
- pPrev->_pNext = pCurr->_pNext;
- }
- else
- {
- // First entry needs to be deleted
- s_pNonVirtualThunks = pCurr->_pNext;
- }
- }
- pPrev = pCurr;
- pCurr = pCurr->_pNext;
- }
-
- _ASSERTE(found);
-}
-#endif // HAS_REMOTING_PRECODE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::InitVirtualThunkManager public
-//
-// Synopsis: Adds the stub manager to aid debugger in stepping into calls
-//
-//
-//+----------------------------------------------------------------------------
-void CVirtualThunkMgr::InitVirtualThunkManager()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- }
- CONTRACTL_END;
-
- // This is function is already threadsafe since this method is called from within a
- // critical section
- if(NULL == s_pVirtualThunkMgr)
- {
- // Add the stub manager for vtable calls
- s_pVirtualThunkMgr = new CVirtualThunkMgr();
-
- StubManager::AddStubManager(s_pVirtualThunkMgr);
- }
-
-}
-
-#endif // !DACCESS_COMPILE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::CheckIsStub_Internal public
-//
-// Synopsis: Returns TRUE if the given address is the starting address of
-// the transparent proxy stub
-//
-//+----------------------------------------------------------------------------
-BOOL CVirtualThunkMgr::CheckIsStub_Internal(PCODE stubStartAddress)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- SUPPORTS_DAC;
- }
- CONTRACTL_END;
-
- BOOL bIsStub = FALSE;
-
-#ifndef DACCESS_COMPILE
- if (!IsThunkByASM(stubStartAddress))
- return FALSE;
- if(NULL != FindThunk((const BYTE *) stubStartAddress))
- bIsStub = TRUE;
-#endif // !DACCESS_COMPILE
-
- return bIsStub;
-}
-
-#ifndef DACCESS_COMPILE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::Entry2MethodDesc public
-//
-// Synopsis: Convert a starting address to a MethodDesc
-//
-//+----------------------------------------------------------------------------
-MethodDesc *CVirtualThunkMgr::Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT)
-{
- CONTRACT (MethodDesc*)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMT, NULL_OK));
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- if (s_pVirtualThunkMgr == NULL)
- RETURN NULL;
-
- if (!pMT)
- RETURN NULL;
-
- if (!s_pVirtualThunkMgr->CheckIsStub_Internal(StubStartAddress))
- RETURN NULL;
-
- RETURN GetMethodDescByASM(StubStartAddress, pMT);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CVirtualThunkMgr::FindThunk private
-//
-// Synopsis: Finds a thunk that matches the given starting address
-//
-//+----------------------------------------------------------------------------
-LPBYTE CVirtualThunkMgr::FindThunk(const BYTE *stubStartAddress)
-{
- CONTRACT (LPBYTE)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(stubStartAddress, NULL_OK));
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- SO_TOLERANT;
- }
- CONTRACT_END;
-
- CVirtualThunks* pThunks = CVirtualThunks::GetVirtualThunks();
- LPBYTE pThunkAddr = NULL;
-
- while(NULL != pThunks)
- {
- DWORD dwStartSlot = pThunks->_dwStartThunk;
- DWORD dwCurrSlot = pThunks->_dwStartThunk;
- DWORD dwMaxSlot = pThunks->_dwCurrentThunk;
- while (dwCurrSlot < dwMaxSlot)
- {
- LPBYTE pStartAddr = pThunks->ThunkCode[dwCurrSlot-dwStartSlot].pCode;
- if((stubStartAddress >= pStartAddr) &&
- (stubStartAddress < (pStartAddr + ConstVirtualThunkSize)))
- {
- pThunkAddr = pStartAddr;
- break;
- }
- ++dwCurrSlot;
- }
-
- pThunks = pThunks->GetNextThunk();
- }
-
- RETURN pThunkAddr;
-}
-
-#endif // !DACCESS_COMPILE
-
-#ifndef HAS_REMOTING_PRECODE
-
-#ifndef DACCESS_COMPILE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::InitNonVirtualThunkManager public
-//
-// Synopsis: Adds the stub manager to aid debugger in stepping into calls
-//
-//
-//+----------------------------------------------------------------------------
-void CNonVirtualThunkMgr::InitNonVirtualThunkManager()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- }
- CONTRACTL_END;
-
- // This function is already thread safe since this method is called from within a
- // critical section
- if(NULL == s_pNonVirtualThunkMgr)
- {
- // Add the stub manager for non vtable calls
- s_pNonVirtualThunkMgr = new CNonVirtualThunkMgr();
-
- StubManager::AddStubManager(s_pNonVirtualThunkMgr);
- }
-}
-
-#endif // !DACCESS_COMPILE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::CheckIsStub_Internal public
-//
-// Synopsis: Returns TRUE if the given address is the starting address of
-// one of our thunks
-//
-//+----------------------------------------------------------------------------
-BOOL CNonVirtualThunkMgr::CheckIsStub_Internal(PCODE stubStartAddress)
-{
- WRAPPER_NO_CONTRACT;
-
- BOOL bIsStub = FALSE;
-
-#ifndef DACCESS_COMPILE
- if (!IsThunkByASM(stubStartAddress))
- return FALSE;
- if(NULL != FindThunk((const BYTE *) stubStartAddress))
- bIsStub = TRUE;
-#endif // !DACCESS_COMPILE
-
- return bIsStub;
-}
-
-#ifndef DACCESS_COMPILE
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::Entry2MethodDesc public
-//
-// Synopsis: Convert a starting address to a MethodDesc
-//
-//+----------------------------------------------------------------------------
-MethodDesc *CNonVirtualThunkMgr::Entry2MethodDesc(PCODE StubStartAddress, MethodTable *pMT)
-{
- CONTRACT (MethodDesc*)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(pMT, NULL_OK));
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- }
- CONTRACT_END;
-
- if (s_pNonVirtualThunkMgr == NULL)
- RETURN NULL;
-
- if (!s_pNonVirtualThunkMgr->CheckIsStub_Internal(StubStartAddress))
- RETURN NULL;
-
- RETURN GetMethodDescByASM(StubStartAddress);
-}
-
-//+----------------------------------------------------------------------------
-//
-// Method: CNonVirtualThunkMgr::FindThunk private
-//
-// Synopsis: Finds a thunk that matches the given starting address
-//
-//+----------------------------------------------------------------------------
-CNonVirtualThunk* CNonVirtualThunkMgr::FindThunk(const BYTE *stubStartAddress)
-{
- CONTRACT (CNonVirtualThunk*)
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- PRECONDITION(CheckPointer(stubStartAddress, NULL_OK));
- POSTCONDITION(CheckPointer(RETVAL, NULL_OK));
- SO_TOLERANT;
- }
- CONTRACT_END;
-
- SimpleRWLock::SimpleReadLockHolder srlh(CNonVirtualThunk::GetThunksListLock());
- CNonVirtualThunk* pThunk = CNonVirtualThunk::GetNonVirtualThunks();
-
- while(NULL != pThunk)
- {
- if(stubStartAddress == pThunk->GetThunkCode())
- break;
-
- pThunk = pThunk->GetNextThunk();
- }
-
- RETURN pThunk;
-}
-
-#endif // !DACCESS_COMPILE
-
-#endif // HAS_REMOTING_PRECODE
-
-
-#ifndef DACCESS_COMPILE
-
-//+----------------------------------------------------------------------------
-//+- HRESULT MethodDescDispatchHelper(MethodDesc* pMD, ARG_SLOT[] args, ARG_SLOT *pret)
-//+----------------------------------------------------------------------------
-HRESULT MethodDescDispatchHelper(MethodDescCallSite* pMethodCallSite, ARG_SLOT args[], ARG_SLOT *pret)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(CheckPointer(pMethodCallSite));
- PRECONDITION(CheckPointer(args));
- PRECONDITION(CheckPointer(pret));
- }
- CONTRACTL_END;
-
- HRESULT hr = S_OK;
- EX_TRY
- {
- *pret = pMethodCallSite->Call_RetArgSlot(args);
- }
- EX_CATCH_HRESULT(hr);
-
- return hr;
-}
-
-
-#ifdef FEATURE_COMINTEROP
-
-//+----------------------------------------------------------------------------
-//
-// Method: VOID CRemotingServices::CallSetDCOMProxy(OBJECTREF realProxy, IUnknown* pUnk)
-//
-//+----------------------------------------------------------------------------
-
-VOID CRemotingServices::CallSetDCOMProxy(OBJECTREF realProxy, IUnknown* pUnk)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(realProxy != NULL);
- PRECONDITION(CheckPointer(pUnk, NULL_OK));
- }
- CONTRACTL_END;
-
- GCPROTECT_BEGIN(realProxy);
-
- MethodDescCallSite setDCOMProxy(METHOD__REAL_PROXY__SETDCOMPROXY, &realProxy);
-
- ARG_SLOT args[] =
- {
- ObjToArgSlot(realProxy),
- (ARG_SLOT)pUnk
- };
-
- ARG_SLOT ret;
- MethodDescDispatchHelper(&setDCOMProxy, args, &ret);
-
- GCPROTECT_END();
-}
-
-
-BOOL CRemotingServices::CallSupportsInterface(OBJECTREF realProxy, REFIID iid, ARG_SLOT* pret)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- PRECONDITION(realProxy != NULL);
- PRECONDITION(CheckPointer(pret));
- }
- CONTRACTL_END;
-
- BOOL fResult = TRUE;
-
- GCPROTECT_BEGIN(realProxy);
-
- MethodDescCallSite supportsInterface(METHOD__REAL_PROXY__SUPPORTSINTERFACE, &realProxy);
-
- ARG_SLOT args[] =
- {
- ObjToArgSlot(realProxy),
- (ARG_SLOT)&iid
- };
-
- HRESULT hr = MethodDescDispatchHelper(&supportsInterface, args, pret);
-
- // It is allowed for the managed code to return a NULL interface pointer without returning
- // a failure HRESULT. This is done for performance to avoid having to throw an exception.
- // If this occurs, we need to return E_NOINTERFACE.
- if ((*(IUnknown**)pret) == NULL)
- hr = E_NOINTERFACE;
-
- if (FAILED(hr))
- fResult = FALSE;
-
- GCPROTECT_END();
- return fResult;
-}
-#endif // FEATURE_COMINTEROP
-
-//+----------------------------------------------------------------------------
-//
-// Method: CRemotingServices::GetStubForInterfaceMethod
-//
-// Synopsis: Given the exact interface method we wish to invoke on, return
-// the entry point of a stub that will correctly transition into
-// the remoting system passing it this method.
-// The stubs is just another kind of precode. They are cached
-// in per appdomain hash.
-//
-//
-//+----------------------------------------------------------------------------
-PCODE CRemotingServices::GetStubForInterfaceMethod(MethodDesc *pItfMD)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(CheckPointer(pItfMD));
- PRECONDITION(pItfMD->IsInterface() && !pItfMD->IsStatic());
- }
- CONTRACTL_END;
-
- return pItfMD->GetLoaderAllocator()->GetFuncPtrStubs()->GetFuncPtrStub(pItfMD, PRECODE_STUB);
-}
-
-#endif // !DACCESS_COMPILE
-#endif // FEATURE_REMOTING
diff --git a/src/vm/rwlock.cpp b/src/vm/rwlock.cpp
deleted file mode 100644
index 9d8233d140..0000000000
--- a/src/vm/rwlock.cpp
+++ /dev/null
@@ -1,2952 +0,0 @@
-// 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.
-//
-
-//
-//+-------------------------------------------------------------------
-//
-// File: RWLock.cpp
-//
-// Contents: Reader writer lock implementation that supports the
-// following features
-// 1. Cheap enough to be used in large numbers
-// such as per object synchronization.
-// 2. Supports timeout. This is a valuable feature
-// to detect deadlocks
-// 3. Supports caching of events. This allows
-// the events to be moved from least contentious
-// regions to the most contentious regions.
-// In other words, the number of events needed by
-// Reader-Writer lockls is bounded by the number
-// of threads in the process.
-// 4. Supports nested locks by readers and writers
-// 5. Supports spin counts for avoiding context switches
-// on multi processor machines.
-// 6. Supports functionality for upgrading to a writer
-// lock with a return argument that indicates
-// intermediate writes. Downgrading from a writer
-// lock restores the state of the lock.
-// 7. Supports functionality to Release Lock for calling
-// app code. RestoreLock restores the lock state and
-// indicates intermediate writes.
-// 8. Recovers from most common failures such as creation of
-// events. In other words, the lock mainitains consistent
-// internal state and remains usable
-//
-//
-// Classes: CRWLock
-//
-//--------------------------------------------------------------------
-
-
-#include "common.h"
-#include "rwlock.h"
-#include "corhost.h"
-
-#ifdef FEATURE_RWLOCK
-
-// Reader increment
-#define READER 0x00000001
-// Max number of readers
-#define READERS_MASK 0x000003FF
-// Reader being signaled
-#define READER_SIGNALED 0x00000400
-// Writer being signaled
-#define WRITER_SIGNALED 0x00000800
-#define WRITER 0x00001000
-// Waiting reader increment
-#define WAITING_READER 0x00002000
-// Note size of waiting readers must be less
-// than or equal to size of readers
-#define WAITING_READERS_MASK 0x007FE000
-#define WAITING_READERS_SHIFT 13
-// Waiting writer increment
-#define WAITING_WRITER 0x00800000
-// Max number of waiting writers
-#define WAITING_WRITERS_MASK 0xFF800000
-// Events are being cached
-#define CACHING_EVENTS (READER_SIGNALED | WRITER_SIGNALED)
-
-// Cookie flags
-#define UPGRADE_COOKIE 0x02000
-#define RELEASE_COOKIE 0x04000
-#define COOKIE_NONE 0x10000
-#define COOKIE_WRITER 0x20000
-#define COOKIE_READER 0x40000
-#define INVALID_COOKIE (~(UPGRADE_COOKIE | RELEASE_COOKIE | \
- COOKIE_NONE | COOKIE_WRITER | COOKIE_READER))
-#define RWLOCK_MAX_ACQUIRE_COUNT 0xFFFF
-
-// globals
-Volatile<LONGLONG> CRWLock::s_mostRecentLockID = 0;
-CrstStatic CRWLock::s_RWLockCrst;
-
-// Default values
-#ifdef _DEBUG
-DWORD gdwDefaultTimeout = 120000;
-#else //!_DEBUG
-DWORD gdwDefaultTimeout = INFINITE;
-#endif //_DEBUG
-const DWORD gdwReasonableTimeout = 120000;
-DWORD gdwDefaultSpinCount = 0;
-BOOL fBreakOnErrors = FALSE; // Temporarily break on errors
-
-// <REVISIT_TODO> REVISIT_TODO: Bad practise</REVISIT_TODO>
-#define HEAP_SERIALIZE 0
-#define RWLOCK_RECOVERY_FAILURE (0xC0000227L)
-
-// Catch GC holes
-#if _DEBUG
-#define VALIDATE_LOCK(pRWLock) ((Object *) (pRWLock))->Validate();
-#else // !_DEBUG
-#define VALIDATE_LOCK(pRWLock)
-#endif // _DEBUG
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::ProcessInit public
-//
-// Synopsis: Reads default values from registry and intializes
-// process wide data structures
-//
-//+-------------------------------------------------------------------
-void CRWLock::ProcessInit()
-{
- CONTRACTL
- {
- THROWS; // From Crst.Init()
- GC_NOTRIGGER;
- PRECONDITION((g_SystemInfo.dwNumberOfProcessors != 0));
- }
- CONTRACTL_END;
-
- gdwDefaultSpinCount = (g_SystemInfo.dwNumberOfProcessors != 1) ? 500 : 0;
-
- PPEB peb = (PPEB) ClrTeb::GetProcessEnvironmentBlock();
- DWORD dwTimeout = (DWORD)(peb->CriticalSectionTimeout.QuadPart/-10000000);
- if (dwTimeout)
- {
- gdwDefaultTimeout = dwTimeout;
- }
-
- // Initialize the critical section used by the lock
- // Can throw out of memory here.
- s_RWLockCrst.Init(CrstRWLock, CRST_UNSAFE_ANYMODE);
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::CRWLock public
-//
-// Synopsis: Constructor
-//
-//+-------------------------------------------------------------------
-CRWLock::CRWLock()
-: _hWriterEvent(NULL),
- _hReaderEvent(NULL),
- _dwState(0),
- _dwWriterID(0),
- _dwWriterSeqNum(1),
- _wWriterLevel(0)
-#ifdef RWLOCK_STATISTICS
- ,
- _dwReaderEntryCount(0),
- _dwReaderContentionCount(0),
- _dwWriterEntryCount(0),
- _dwWriterContentionCount(0),
- _dwEventsReleasedCount(0)
-#endif
-{
-
- CONTRACT_VOID
- {
- NOTHROW;
- GC_NOTRIGGER;
- POSTCONDITION((_dwLLockID > 0));
- }
- CONTRACT_END;
-
- LONGLONG qwLockID = s_mostRecentLockID;
- while (true)
- {
- LONGLONG qwNextLockID = qwLockID + 1;
- if (static_cast<LONG>(qwNextLockID) == 0)
- {
- // A value of zero for the lower half of the ID is reserved to identify that a thread does not own any RW locks,
- // regardless of the upper half of the ID
- ++qwNextLockID;
- }
-
- LONGLONG qwLockIDBeforeExchange = RWInterlockedCompareExchange64(&s_mostRecentLockID, qwNextLockID, qwLockID);
- if (qwLockIDBeforeExchange == qwLockID)
- {
- qwLockID = qwNextLockID;
- break;
- }
-
- qwLockID = qwLockIDBeforeExchange;
- }
-
- _dwLLockID = static_cast<LONG>(qwLockID);
- _dwULockID = static_cast<LONG>(qwLockID >> 32);
-
- RETURN;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::Cleanup public
-//
-// Synopsis: Cleansup state
-//
-//+-------------------------------------------------------------------
-void CRWLock::Cleanup()
-{
-
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- PRECONDITION((_dwState == 0)); // sanity checks
- PRECONDITION((_dwWriterID == 0));
- PRECONDITION((_wWriterLevel == 0));
- }
- CONTRACTL_END;
-
- if(_hWriterEvent) {
- delete _hWriterEvent;
- _hWriterEvent = NULL;
- }
- if(_hReaderEvent) {
- delete _hReaderEvent;
- _hReaderEvent = NULL;
- }
-
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::ChainEntry private
-//
-// Synopsis: Chains the given lock entry into the chain
-//
-//+-------------------------------------------------------------------
-inline void CRWLock::ChainEntry(Thread *pThread, LockEntry *pLockEntry)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- // This is to synchronize with finalizer thread and deadlock detection.
- CrstHolder rwl(&s_RWLockCrst);
- LockEntry *pHeadEntry = pThread->m_pHead;
- pLockEntry->pNext = pHeadEntry;
- pLockEntry->pPrev = pHeadEntry->pPrev;
- pLockEntry->pPrev->pNext = pLockEntry;
- pHeadEntry->pPrev = pLockEntry;
-
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::GetLockEntry private
-//
-// Synopsis: Gets lock entry from TLS
-//
-//+-------------------------------------------------------------------
-inline LockEntry *CRWLock::GetLockEntry(Thread* pThread)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- if (pThread == NULL) {
- pThread = GetThread();
- }
- LockEntry *pHeadEntry = pThread->m_pHead;
- LockEntry *pLockEntry = pHeadEntry;
- do
- {
- if((pLockEntry->dwLLockID == _dwLLockID) && (pLockEntry->dwULockID == _dwULockID))
- return(pLockEntry);
- pLockEntry = pLockEntry->pNext;
- } while(pLockEntry != pHeadEntry);
-
- return(NULL);
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::FastGetOrCreateLockEntry private
-//
-// Synopsis: The fast path for getting a lock entry from TLS
-//
-//+-------------------------------------------------------------------
-inline LockEntry *CRWLock::FastGetOrCreateLockEntry()
-{
-
- CONTRACTL
- {
- THROWS; // SlowGetOrCreateLockEntry can throw out of memory exception
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- Thread *pThread = GetThread();
- _ASSERTE(pThread);
- LockEntry *pLockEntry = pThread->m_pHead;
- if(pLockEntry->dwLLockID == 0)
- {
- _ASSERTE(pLockEntry->wReaderLevel == 0);
- pLockEntry->dwLLockID = _dwLLockID;
- pLockEntry->dwULockID = _dwULockID;
- return(pLockEntry);
- }
- else if((pLockEntry->dwLLockID == _dwLLockID) && (pLockEntry->dwULockID == _dwULockID))
- {
- // Note, StaticAcquireReaderLock can have reentry via pumping while it's blocking
- // so no assertions about pLockEntry->wReaderLevel's state
- return(pLockEntry);
- }
-
- return(SlowGetOrCreateLockEntry(pThread));
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::SlowGetorCreateLockEntry private
-//
-// Synopsis: The slow path for getting a lock entry from TLS
-//
-//+-------------------------------------------------------------------
-LockEntry *CRWLock::SlowGetOrCreateLockEntry(Thread *pThread)
-{
-
- CONTRACTL
- {
- THROWS; // memory allocation can throw out of memory exception
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- LockEntry *pFreeEntry = NULL;
- LockEntry *pHeadEntry = pThread->m_pHead;
-
- // Search for an empty entry or an entry belonging to this lock
- LockEntry *pLockEntry = pHeadEntry->pNext;
- while(pLockEntry != pHeadEntry)
- {
- if(pLockEntry->dwLLockID &&
- ((pLockEntry->dwLLockID != _dwLLockID) || (pLockEntry->dwULockID != _dwULockID)))
- {
- // Move to the next entry
- pLockEntry = pLockEntry->pNext;
- }
- else
- {
- // Prepare to move it to the head
- pFreeEntry = pLockEntry;
- pLockEntry->pPrev->pNext = pLockEntry->pNext;
- pLockEntry->pNext->pPrev = pLockEntry->pPrev;
-
- break;
- }
- }
-
- if(pFreeEntry == NULL)
- {
- pFreeEntry = new LockEntry;
- pFreeEntry->wReaderLevel = 0;
- }
-
- if(pFreeEntry)
- {
- _ASSERTE((pFreeEntry->dwLLockID != 0) || (pFreeEntry->wReaderLevel == 0));
- _ASSERTE((pFreeEntry->wReaderLevel == 0) ||
- ((pFreeEntry->dwLLockID == _dwLLockID) && (pFreeEntry->dwULockID == _dwULockID)));
-
- // Chain back the entry
- ChainEntry(pThread, pFreeEntry);
-
- // Move this entry to the head
- pThread->m_pHead = pFreeEntry;
-
- // Mark the entry as belonging to this lock
- pFreeEntry->dwLLockID = _dwLLockID;
- pFreeEntry->dwULockID = _dwULockID;
- }
-
- return pFreeEntry;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::FastRecycleLockEntry private
-//
-// Synopsis: Fast path for recycling the lock entry that is used
-// when the thread is the next few instructions is going
-// to call FastGetOrCreateLockEntry again
-//
-//+-------------------------------------------------------------------
-inline void CRWLock::FastRecycleLockEntry(LockEntry *pLockEntry)
-{
-
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
-
- // Sanity checks
- PRECONDITION(pLockEntry->wReaderLevel == 0);
- PRECONDITION((pLockEntry->dwLLockID == _dwLLockID) && (pLockEntry->dwULockID == _dwULockID));
- PRECONDITION(pLockEntry == GetThread()->m_pHead);
- }
- CONTRACTL_END;
-
-
- pLockEntry->dwLLockID = 0;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RecycleLockEntry private
-//
-// Synopsis: Fast path for recycling the lock entry
-//
-//+-------------------------------------------------------------------
-inline void CRWLock::RecycleLockEntry(LockEntry *pLockEntry)
-{
-
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
-
- // Sanity check
- PRECONDITION(pLockEntry->wReaderLevel == 0);
- }
- CONTRACTL_END;
-
- // Move the entry to tail
- Thread *pThread = GetThread();
- LockEntry *pHeadEntry = pThread->m_pHead;
- if(pLockEntry == pHeadEntry)
- {
- pThread->m_pHead = pHeadEntry->pNext;
- }
- else if(pLockEntry->pNext->dwLLockID)
- {
- // Prepare to move the entry to tail
- pLockEntry->pPrev->pNext = pLockEntry->pNext;
- pLockEntry->pNext->pPrev = pLockEntry->pPrev;
-
- // Chain back the entry
- ChainEntry(pThread, pLockEntry);
- }
-
- // The entry does not belong to this lock anymore
- pLockEntry->dwLLockID = 0;
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticIsWriterLockHeld public
-//
-// Synopsis: Return TRUE if writer lock is held
-//
-//+-------------------------------------------------------------------
-FCIMPL1(FC_BOOL_RET, CRWLock::StaticIsWriterLockHeld, CRWLock *pRWLock)
-{
- FCALL_CONTRACT;
-
- if (pRWLock == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
- if(pRWLock->_dwWriterID == GetThread()->GetThreadId())
- FC_RETURN_BOOL(TRUE);
-
- FC_RETURN_BOOL(FALSE);
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticIsReaderLockHeld public
-//
-// Synopsis: Return TRUE if reader lock is held
-//
-//+-------------------------------------------------------------------
-FCIMPL1(FC_BOOL_RET, CRWLock::StaticIsReaderLockHeld, CRWLock *pRWLock)
-{
- FCALL_CONTRACT;
-
- if (pRWLock == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
- LockEntry *pLockEntry = pRWLock->GetLockEntry();
- if(pLockEntry)
- {
- FC_RETURN_BOOL(pLockEntry->wReaderLevel > 0);
- }
-
- FC_RETURN_BOOL(FALSE);
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::AssertWriterLockHeld public
-//
-// Synopsis: Asserts that writer lock is held
-//
-//+-------------------------------------------------------------------
-#ifdef _DEBUG
-BOOL CRWLock::AssertWriterLockHeld()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- if(_dwWriterID == GetThread()->GetThreadId())
- return(TRUE);
-
- _ASSERTE(!"Writer lock not held by the current thread");
- return(FALSE);
-}
-#endif
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::AssertWriterLockNotHeld public
-//
-// Synopsis: Asserts that writer lock is not held
-//
-//+-------------------------------------------------------------------
-#ifdef _DEBUG
-BOOL CRWLock::AssertWriterLockNotHeld()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- if(_dwWriterID != GetThread()->GetThreadId())
- return(TRUE);
-
- _ASSERTE(!"Writer lock held by the current thread");
- return(FALSE);
-}
-#endif
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::AssertReaderLockHeld public
-//
-// Synopsis: Asserts that reader lock is held
-//
-//+-------------------------------------------------------------------
-#ifdef _DEBUG
-BOOL CRWLock::AssertReaderLockHeld()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- LockEntry *pLockEntry = GetLockEntry();
- if(pLockEntry)
- {
- _ASSERTE(pLockEntry->wReaderLevel);
- return(TRUE);
- }
-
- _ASSERTE(!"Reader lock not held by the current thread");
- return(FALSE);
-}
-#endif
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::AssertReaderLockNotHeld public
-//
-// Synopsis: Asserts that writer lock is not held
-//
-//+-------------------------------------------------------------------
-#ifdef _DEBUG
-BOOL CRWLock::AssertReaderLockNotHeld()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- LockEntry *pLockEntry = GetLockEntry();
- if(pLockEntry == NULL)
- return(TRUE);
-
- _ASSERTE(pLockEntry->wReaderLevel);
- _ASSERTE(!"Reader lock held by the current thread");
-
- return(FALSE);
-}
-#endif
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::AssertReaderOrWriterLockHeld public
-//
-// Synopsis: Asserts that writer lock is not held
-//
-//+-------------------------------------------------------------------
-#ifdef _DEBUG
-BOOL CRWLock::AssertReaderOrWriterLockHeld()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- if(_dwWriterID == GetThread()->GetThreadId())
- {
- return(TRUE);
- }
- else
- {
- LockEntry *pLockEntry = GetLockEntry();
- if(pLockEntry)
- {
- _ASSERTE(pLockEntry->wReaderLevel);
- return(TRUE);
- }
- }
-
- _ASSERTE(!"Neither Reader nor Writer lock held");
- return(FALSE);
-}
-#endif
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWSetEvent private
-//
-// Synopsis: Helper function for setting an event
-//
-//+-------------------------------------------------------------------
-inline void CRWLock::RWSetEvent(CLREvent* event)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- if(!event->Set())
- {
- _ASSERTE(!"SetEvent failed");
- if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out.
- DebugBreak();
- COMPlusThrowWin32(E_UNEXPECTED);
- }
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWResetEvent private
-//
-// Synopsis: Helper function for resetting an event
-//
-//+-------------------------------------------------------------------
-inline void CRWLock::RWResetEvent(CLREvent* event)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- if(!event->Reset())
- {
- _ASSERTE(!"ResetEvent failed");
- if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out.
- DebugBreak();
- COMPlusThrowWin32(E_UNEXPECTED);
- }
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWWaitForSingleObject public
-//
-// Synopsis: Helper function for waiting on an event
-//
-//+-------------------------------------------------------------------
-inline DWORD CRWLock::RWWaitForSingleObject(CLREvent* event, DWORD dwTimeout)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- DWORD status = WAIT_FAILED;
- EX_TRY
- {
- status = event->Wait(dwTimeout,TRUE);
- }
- EX_CATCH
- {
- status = GET_EXCEPTION()->GetHR();
- if (status == S_OK)
- {
- status = WAIT_FAILED;
- }
- }
- EX_END_CATCH(SwallowAllExceptions); // The caller will rethrow the exception
-
- return status;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWSleep public
-//
-// Synopsis: Helper function for calling Sleep
-//
-//+-------------------------------------------------------------------
-inline void CRWLock::RWSleep(DWORD dwTime)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- ClrSleepEx(dwTime, TRUE);
-}
-
-
-#undef volatile
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWInterlockedCompareExchange public
-//
-// Synopsis: Helper function for calling intelockedCompareExchange
-//
-//+-------------------------------------------------------------------
-inline LONG CRWLock::RWInterlockedCompareExchange(LONG volatile *pvDestination,
- LONG dwExchange,
- LONG dwComparand)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return FastInterlockCompareExchange(pvDestination,
- dwExchange,
- dwComparand);
-}
-
-inline LONGLONG CRWLock::RWInterlockedCompareExchange64(LONGLONG volatile *pvDestination,
- LONGLONG qwExchange,
- LONGLONG qwComparand)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return FastInterlockCompareExchangeLong(pvDestination, qwExchange, qwComparand);
-}
-
-inline void* CRWLock::RWInterlockedCompareExchangePointer(PVOID volatile *pvDestination,
- void* pExchange,
- void* pComparand)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return FastInterlockCompareExchangePointer(pvDestination,
- pExchange,
- pComparand);
-}
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWInterlockedExchangeAdd public
-//
-// Synopsis: Helper function for adding state
-//
-//+-------------------------------------------------------------------
-inline LONG CRWLock::RWInterlockedExchangeAdd(LONG volatile *pvDestination,
- LONG dwAddToState)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return FastInterlockExchangeAdd(pvDestination, dwAddToState);
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::RWInterlockedIncrement public
-//
-// Synopsis: Helper function for incrementing a pointer
-//
-//+-------------------------------------------------------------------
-inline LONG CRWLock::RWInterlockedIncrement(LONG volatile *pdwState)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return FastInterlockIncrement(pdwState);
-}
-
-#define volatile DoNotUserVolatileKeyword
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::ReleaseEvents public
-//
-// Synopsis: Helper function for caching events
-//
-//+-------------------------------------------------------------------
-void CRWLock::ReleaseEvents()
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- PRECONDITION(((_dwState & CACHING_EVENTS) == CACHING_EVENTS)); // Ensure that reader and writers have been stalled
-
- }
- CONTRACTL_END;
-
- // Save writer event
- CLREvent *hWriterEvent = _hWriterEvent;
- _hWriterEvent = NULL;
-
- // Save reader event
- CLREvent *hReaderEvent = _hReaderEvent;
- _hReaderEvent = NULL;
-
- // Allow readers and writers to continue
- RWInterlockedExchangeAdd(&_dwState, -(CACHING_EVENTS));
-
- // Cache events
- // <REVISIT_TODO>:
- // I am closing events for now. What is needed
- // is an event cache to which the events are
- // released using InterlockedCompareExchange64</REVISIT_TODO>
- if(hWriterEvent)
- {
- LOG((LF_SYNC, LL_INFO10, "Releasing writer event\n"));
- delete hWriterEvent;
- }
- if(hReaderEvent)
- {
- LOG((LF_SYNC, LL_INFO10, "Releasing reader event\n"));
- delete hReaderEvent;
- }
-#ifdef RWLOCK_STATISTICS
- RWInterlockedIncrement(&_dwEventsReleasedCount);
-#endif
-
- return;
-}
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::GetWriterEvent public
-//
-// Synopsis: Helper function for obtaining a auto reset event used
-// for serializing writers. It utilizes event cache
-//
-//+-------------------------------------------------------------------
-CLREvent* CRWLock::GetWriterEvent(HRESULT *pHR)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- *pHR = S_OK;
- //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved
- //during GC. So we need to cache the field before GC could happen
- CLREvent * result = _hWriterEvent;
-
- if(_hWriterEvent == NULL)
- {
- EX_TRY
- {
- CLREvent *pEvent = new CLREvent();
- NewHolder<CLREvent> hWriterEvent (pEvent);
- hWriterEvent->CreateRWLockWriterEvent(FALSE,this);
- if(hWriterEvent)
- {
- if(RWInterlockedCompareExchangePointer((PVOID*) &_hWriterEvent,
- hWriterEvent.GetValue(),
- NULL) == NULL)
- {
- hWriterEvent.SuppressRelease();
- }
- //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved
- //during GC. So we need to cache the field before GC could happen.
- result = _hWriterEvent;
- }
- }
- EX_CATCH
- {
- *pHR = GET_EXCEPTION()->GetHR();
- }
- EX_END_CATCH(SwallowAllExceptions);
- }
-
- return(result);
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::GetReaderEvent public
-//
-// Synopsis: Helper function for obtaining a manula reset event used
-// by readers to wait when a writer holds the lock.
-// It utilizes event cache
-//
-//+-------------------------------------------------------------------
-CLREvent* CRWLock::GetReaderEvent(HRESULT *pHR)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- *pHR = S_OK;
- //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved
- //during GC. So we need to cache the field before GC could happen
- CLREvent * result = _hReaderEvent;
-
- if(_hReaderEvent == NULL)
- {
- EX_TRY
- {
- CLREvent *pEvent = new CLREvent();
- NewHolder<CLREvent> hReaderEvent (pEvent);
- hReaderEvent->CreateRWLockReaderEvent(FALSE, this);
- if(hReaderEvent)
- {
- if(RWInterlockedCompareExchangePointer((PVOID*) &_hReaderEvent,
- hReaderEvent.GetValue(),
- NULL) == NULL)
- {
- hReaderEvent.SuppressRelease();
- }
- //GC could happen in ~CLREvent or EH. "this" is a GC object so it could be moved
- //during GC. So we need to cache the field before GC could happen
- result = _hReaderEvent;
- }
- }
- EX_CATCH
- {
- *pHR = GET_EXCEPTION()->GetHR();
- }
- EX_END_CATCH(SwallowAllExceptions);
- }
-
- return(result);
-}
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticRecoverLock public
-//
-// Synopsis: Helper function to restore the lock to
-// the original state
-//
-
-//
-//+-------------------------------------------------------------------
-void CRWLock::StaticRecoverLock(
- CRWLock **ppRWLock,
- LockCookie *pLockCookie,
- DWORD dwFlags)
-{
- CONTRACTL
- {
- THROWS; // StaticAcquireWriterLock can throw exception
- GC_TRIGGERS;
- CAN_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- DWORD dwTimeout = (gdwDefaultTimeout > gdwReasonableTimeout)
- ? gdwDefaultTimeout
- : gdwReasonableTimeout;
-
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
-
- EX_TRY
- {
- // Check if the thread was a writer
- if(dwFlags & COOKIE_WRITER)
- {
- // Acquire writer lock
- StaticAcquireWriterLock(ppRWLock, dwTimeout);
- _ASSERTE (pThread->m_dwLockCount >= (*ppRWLock)->_wWriterLevel);
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= (*ppRWLock)->_wWriterLevel);
- pThread->m_dwLockCount -= (*ppRWLock)->_wWriterLevel;
- USER_LOCK_RELEASED_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock));
- (*ppRWLock)->_wWriterLevel = pLockCookie->wWriterLevel;
- pThread->m_dwLockCount += (*ppRWLock)->_wWriterLevel;
- USER_LOCK_TAKEN_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock));
- }
- // Check if the thread was a reader
- else if(dwFlags & COOKIE_READER)
- {
- StaticAcquireReaderLock(ppRWLock, dwTimeout);
- LockEntry *pLockEntry = (*ppRWLock)->GetLockEntry();
- _ASSERTE(pLockEntry);
- _ASSERTE (pThread->m_dwLockCount >= pLockEntry->wReaderLevel);
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= pLockEntry->wReaderLevel);
- pThread->m_dwLockCount -= pLockEntry->wReaderLevel;
- USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock));
- pLockEntry->wReaderLevel = pLockCookie->wReaderLevel;
- pThread->m_dwLockCount += pLockEntry->wReaderLevel;
- USER_LOCK_TAKEN_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock));
- }
- }
- EX_CATCH
- {
- // Removed an assert here. This error is expected in case of
- // ThreadAbort.
- COMPlusThrowWin32(RWLOCK_RECOVERY_FAILURE);
- }
- EX_END_CATCH_UNREACHABLE
-}
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticAcquireReaderLockPublic public
-//
-// Synopsis: Public access to StaticAcquireReaderLock
-//
-//+-------------------------------------------------------------------
-FCIMPL2(void, CRWLock::StaticAcquireReaderLockPublic, CRWLock *pRWLockUNSAFE, DWORD dwDesiredTimeout)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(pRWLock);
-
- StaticAcquireReaderLock((CRWLock**)&pRWLock, dwDesiredTimeout);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticAcquireReaderLock private
-//
-// Synopsis: Makes the thread a reader. Supports nested reader locks.
-//
-//+-------------------------------------------------------------------
-
-void CRWLock::StaticAcquireReaderLock(
- CRWLock **ppRWLock,
- DWORD dwDesiredTimeout)
-{
-
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS; // CLREvent::Wait is GC_TRIGGERS
- CAN_TAKE_LOCK;
- PRECONDITION(CheckPointer(ppRWLock));
- PRECONDITION(CheckPointer(*ppRWLock));
- }
- CONTRACTL_END;
-
- TESTHOOKCALL(AppDomainCanBeUnloaded(GetThread()->GetDomain()->GetId().m_dwId,FALSE));
-
- if (GetThread()->IsAbortRequested()) {
- GetThread()->HandleThreadAbort();
- }
-
- LockEntry *pLockEntry = (*ppRWLock)->FastGetOrCreateLockEntry();
- if (pLockEntry == NULL)
- {
- COMPlusThrowWin32(STATUS_NO_MEMORY);
- }
-
- DWORD dwStatus = WAIT_OBJECT_0;
- // Check for the fast path
- if(RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, READER, 0) == 0)
- {
- _ASSERTE(pLockEntry->wReaderLevel == 0);
- }
- // Check for nested reader
- else if(pLockEntry->wReaderLevel != 0)
- {
- _ASSERTE((*ppRWLock)->_dwState & READERS_MASK);
-
- if (pLockEntry->wReaderLevel == RWLOCK_MAX_ACQUIRE_COUNT) {
- COMPlusThrow(kOverflowException, W("Overflow_UInt16"));
- }
- ++pLockEntry->wReaderLevel;
- INCTHREADLOCKCOUNT();
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
- return;
- }
- // Check if the thread already has writer lock
- else if((*ppRWLock)->_dwWriterID == GetThread()->GetThreadId())
- {
- StaticAcquireWriterLock(ppRWLock, dwDesiredTimeout);
- (*ppRWLock)->FastRecycleLockEntry(pLockEntry);
- return;
- }
- else
- {
- DWORD dwSpinCount;
- DWORD dwCurrentState, dwKnownState;
-
- // Initialize
- dwSpinCount = 0;
- dwCurrentState = (*ppRWLock)->_dwState;
- do
- {
- dwKnownState = dwCurrentState;
-
- // Reader need not wait if there are only readers and no writer
- if((dwKnownState < READERS_MASK) ||
- (((dwKnownState & READER_SIGNALED) && ((dwKnownState & WRITER) == 0)) &&
- (((dwKnownState & READERS_MASK) +
- ((dwKnownState & WAITING_READERS_MASK) >> WAITING_READERS_SHIFT)) <=
- (READERS_MASK - 2))))
- {
- // Add to readers
- dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + READER),
- dwKnownState);
- if(dwCurrentState == dwKnownState)
- {
- // One more reader
- break;
- }
- }
- // Check for too many Readers or waiting readers or signaling in progress
- else if(((dwKnownState & READERS_MASK) == READERS_MASK) ||
- ((dwKnownState & WAITING_READERS_MASK) == WAITING_READERS_MASK) ||
- ((dwKnownState & CACHING_EVENTS) == READER_SIGNALED))
- {
- // Sleep
- GetThread()->UserSleep(1000);
-
- // Update to latest state
- dwSpinCount = 0;
- dwCurrentState = (*ppRWLock)->_dwState;
- }
- // Check if events are being cached
- else if((dwKnownState & CACHING_EVENTS) == CACHING_EVENTS)
- {
- if(++dwSpinCount > gdwDefaultSpinCount)
- {
- RWSleep(1);
- dwSpinCount = 0;
- }
- dwCurrentState = (*ppRWLock)->_dwState;
- }
- // Check spin count
- else if(++dwSpinCount <= gdwDefaultSpinCount)
- {
- dwCurrentState = (*ppRWLock)->_dwState;
- }
- else
- {
- // Add to waiting readers
- dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + WAITING_READER),
- dwKnownState);
- if(dwCurrentState == dwKnownState)
- {
- CLREvent* hReaderEvent;
- DWORD dwModifyState;
-
- // One more waiting reader
-#ifdef RWLOCK_STATISTICS
- RWInterlockedIncrement(&(*ppRWLock)->_dwReaderContentionCount);
-#endif
- HRESULT hr;
- hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr);
- if(hReaderEvent)
- {
- dwStatus = RWWaitForSingleObject(hReaderEvent, dwDesiredTimeout);
- VALIDATE_LOCK(*ppRWLock);
-
- // StaticAcquireReaderLock can have reentry via pumping while waiting for
- // hReaderEvent, which may change pLockEntry's state from underneath us.
- if ((pLockEntry->dwLLockID != (*ppRWLock)->_dwLLockID) ||
- (pLockEntry->dwULockID != (*ppRWLock)->_dwULockID))
- {
- pLockEntry = (*ppRWLock)->FastGetOrCreateLockEntry();
- if (pLockEntry == NULL)
- {
- COMPlusThrowWin32(STATUS_NO_MEMORY);
- }
- }
- }
- else
- {
- LOG((LF_SYNC, LL_WARNING,
- "AcquireReaderLock failed to create reader "
- "event for RWLock 0x%x\n", *ppRWLock));
- dwStatus = E_FAIL;
- }
-
- if(dwStatus == WAIT_OBJECT_0)
- {
- _ASSERTE((*ppRWLock)->_dwState & READER_SIGNALED);
- _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) < READERS_MASK);
- dwModifyState = READER - WAITING_READER;
- }
- else
- {
- dwModifyState = (DWORD) -WAITING_READER;
- if(dwStatus == WAIT_TIMEOUT)
- {
- LOG((LF_SYNC, LL_WARNING,
- "Timed out trying to acquire reader lock "
- "for RWLock 0x%x\n", *ppRWLock));
- hr = HRESULT_FROM_WIN32(ERROR_TIMEOUT);
- }
- else if(dwStatus == WAIT_IO_COMPLETION)
- {
- LOG((LF_SYNC, LL_WARNING,
- "Thread interrupted while trying to acquire reader lock "
- "for RWLock 0x%x\n", *ppRWLock));
- hr = COR_E_THREADINTERRUPTED;
- }
- else if (dwStatus == WAIT_FAILED)
- {
- if (SUCCEEDED(hr))
- {
- dwStatus = GetLastError();
- if (dwStatus == WAIT_OBJECT_0)
- {
- dwStatus = WAIT_FAILED;
- }
- hr = HRESULT_FROM_WIN32(dwStatus);
- LOG((LF_SYNC, LL_WARNING,
- "WaitForSingleObject on Event 0x%x failed for "
- "RWLock 0x%x with status code 0x%x\n",
- hReaderEvent, *ppRWLock, dwStatus));
- }
- }
- }
-
- // One less waiting reader and he may have become a reader
- dwKnownState = RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, dwModifyState);
-
- // Check for last signaled waiting reader
- if(dwStatus == WAIT_OBJECT_0)
- {
- _ASSERTE(dwKnownState & READER_SIGNALED);
- _ASSERTE((dwKnownState & READERS_MASK) < READERS_MASK);
- if((dwKnownState & WAITING_READERS_MASK) == WAITING_READER)
- {
- // Reset the event and lower reader signaled flag
- RWResetEvent(hReaderEvent);
- RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, -READER_SIGNALED);
- }
- }
- else
- {
- if(((dwKnownState & WAITING_READERS_MASK) == WAITING_READER) &&
- (dwKnownState & READER_SIGNALED))
- {
- HRESULT hr1;
- if(hReaderEvent == NULL)
- hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr1);
- _ASSERTE(hReaderEvent);
-
- // Ensure the event is signalled before resetting it.
- DWORD dwTemp;
- dwTemp = hReaderEvent->Wait(INFINITE, FALSE);
- _ASSERTE(dwTemp == WAIT_OBJECT_0);
- _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) < READERS_MASK);
-
- // Reset the event and lower reader signaled flag
- RWResetEvent(hReaderEvent);
- RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, (READER - READER_SIGNALED));
-
- // Honor the orginal status
- ++pLockEntry->wReaderLevel;
- INCTHREADLOCKCOUNT();
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
- StaticReleaseReaderLock(ppRWLock);
- }
- else
- {
- (*ppRWLock)->FastRecycleLockEntry(pLockEntry);
- }
-
- _ASSERTE((pLockEntry == NULL) ||
- ((pLockEntry->dwLLockID == 0) &&
- (pLockEntry->wReaderLevel == 0)));
- if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out.
- {
- _ASSERTE(!"Failed to acquire reader lock");
- DebugBreak();
- }
-
- // Prepare the frame for throwing an exception
- if ((DWORD)HOST_E_DEADLOCK == dwStatus)
- {
- // So that the error message is in the exception.
- RaiseDeadLockException();
- } else if ((DWORD)COR_E_THREADINTERRUPTED == dwStatus) {
- COMPlusThrow(kThreadInterruptedException);
- }
- else
- {
- COMPlusThrowWin32 (hr);
- }
- }
-
- // Sanity check
- _ASSERTE(dwStatus == WAIT_OBJECT_0);
- break;
- }
- }
- YieldProcessor(); // Indicate to the processor that we are spining
- } while(TRUE);
- }
-
- // Success
- _ASSERTE(dwStatus == WAIT_OBJECT_0);
- _ASSERTE(((*ppRWLock)->_dwState & WRITER) == 0);
- _ASSERTE((*ppRWLock)->_dwState & READERS_MASK);
- ++pLockEntry->wReaderLevel;
- INCTHREADLOCKCOUNT();
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
-#ifdef RWLOCK_STATISTICS
- RWInterlockedIncrement(&(*ppRWLock)->_dwReaderEntryCount);
-#endif
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticAcquireWriterLockPublic public
-//
-// Synopsis: Public access to StaticAcquireWriterLock
-//
-//+-------------------------------------------------------------------
-FCIMPL2(void, CRWLock::StaticAcquireWriterLockPublic, CRWLock *pRWLockUNSAFE, DWORD dwDesiredTimeout)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(pRWLock);
-
- StaticAcquireWriterLock((CRWLock**)&pRWLock, dwDesiredTimeout);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticAcquireWriterLock private
-//
-// Synopsis: Makes the thread a writer. Supports nested writer
-// locks
-//
-//+-------------------------------------------------------------------
-
-void CRWLock::StaticAcquireWriterLock(
- CRWLock **ppRWLock,
- DWORD dwDesiredTimeout)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS; // CLREvent::Wait can trigger GC
- CAN_TAKE_LOCK;
- PRECONDITION((CheckPointer(ppRWLock)));
- PRECONDITION((CheckPointer(*ppRWLock)));
- }
- CONTRACTL_END;
-
- TESTHOOKCALL(AppDomainCanBeUnloaded(GetThread()->GetDomain()->GetId().m_dwId,FALSE));
- if (GetThread()->IsAbortRequested()) {
- GetThread()->HandleThreadAbort();
- }
-
- // Declare locals needed for setting up frame
- DWORD dwThreadID = GetThread()->GetThreadId();
- DWORD dwStatus;
-
- // Check for the fast path
- if(RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, WRITER, 0) == 0)
- {
- _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) == 0);
- }
- // Check if the thread already has writer lock
- else if((*ppRWLock)->_dwWriterID == dwThreadID)
- {
- if ((*ppRWLock)->_wWriterLevel == RWLOCK_MAX_ACQUIRE_COUNT) {
- COMPlusThrow(kOverflowException, W("Overflow_UInt16"));
- }
- ++(*ppRWLock)->_wWriterLevel;
- INCTHREADLOCKCOUNT();
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
- return;
- }
- else
- {
- DWORD dwCurrentState, dwKnownState;
- DWORD dwSpinCount;
-
- // Initialize
- dwSpinCount = 0;
- dwCurrentState = (*ppRWLock)->_dwState;
- do
- {
- dwKnownState = dwCurrentState;
-
- // Writer need not wait if there are no readers and writer
- if((dwKnownState == 0) || (dwKnownState == CACHING_EVENTS))
- {
- // Can be a writer
- dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + WRITER),
- dwKnownState);
- if(dwCurrentState == dwKnownState)
- {
- // Only writer
- break;
- }
- }
- // Check for too many waiting writers
- else if(((dwKnownState & WAITING_WRITERS_MASK) == WAITING_WRITERS_MASK))
- {
- // Sleep
- GetThread()->UserSleep(1000);
-
- // Update to latest state
- dwSpinCount = 0;
- dwCurrentState = (*ppRWLock)->_dwState;
- }
- // Check if events are being cached
- else if((dwKnownState & CACHING_EVENTS) == CACHING_EVENTS)
- {
- if(++dwSpinCount > gdwDefaultSpinCount)
- {
- RWSleep(1);
- dwSpinCount = 0;
- }
- dwCurrentState = (*ppRWLock)->_dwState;
- }
- // Check spin count
- else if(++dwSpinCount <= gdwDefaultSpinCount)
- {
- dwCurrentState = (*ppRWLock)->_dwState;
- }
- else
- {
- // Add to waiting writers
- dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + WAITING_WRITER),
- dwKnownState);
- if(dwCurrentState == dwKnownState)
- {
- CLREvent* hWriterEvent;
- DWORD dwModifyState;
-
- // One more waiting writer
-#ifdef RWLOCK_STATISTICS
- RWInterlockedIncrement(&(*ppRWLock)->_dwWriterContentionCount);
-#endif
- HRESULT hr;
- hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr);
- if(hWriterEvent)
- {
- dwStatus = RWWaitForSingleObject(hWriterEvent, dwDesiredTimeout);
- VALIDATE_LOCK(*ppRWLock);
- }
- else
- {
- LOG((LF_SYNC, LL_WARNING,
- "AcquireWriterLock failed to create writer "
- "event for RWLock 0x%x\n", *ppRWLock));
- dwStatus = WAIT_FAILED;
- }
-
- if(dwStatus == WAIT_OBJECT_0)
- {
- _ASSERTE((*ppRWLock)->_dwState & WRITER_SIGNALED);
- dwModifyState = WRITER - WAITING_WRITER - WRITER_SIGNALED;
- }
- else
- {
- dwModifyState = (DWORD) -WAITING_WRITER;
- if(dwStatus == WAIT_TIMEOUT)
- {
- LOG((LF_SYNC, LL_WARNING,
- "Timed out trying to acquire writer "
- "lock for RWLock 0x%x\n", *ppRWLock));
- hr = HRESULT_FROM_WIN32 (ERROR_TIMEOUT);
- }
- else if(dwStatus == WAIT_IO_COMPLETION)
- {
- LOG((LF_SYNC, LL_WARNING,
- "Thread interrupted while trying to acquire writer lock "
- "for RWLock 0x%x\n", *ppRWLock));
- hr = COR_E_THREADINTERRUPTED;
- }
- else if (dwStatus == WAIT_FAILED)
- {
- if (SUCCEEDED(hr))
- {
- dwStatus = GetLastError();
- if (dwStatus == WAIT_OBJECT_0)
- {
- dwStatus = WAIT_FAILED;
- }
- hr = HRESULT_FROM_WIN32(dwStatus);
- LOG((LF_SYNC, LL_WARNING,
- "WaitForSingleObject on Event 0x%x failed for "
- "RWLock 0x%x with status code 0x%x",
- hWriterEvent, *ppRWLock, dwStatus));
- }
- }
- }
-
- // One less waiting writer and he may have become a writer
- dwKnownState = RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, dwModifyState);
-
- // Check for last timing out signaled waiting writer
- if(dwStatus == WAIT_OBJECT_0)
- {
- // Common case
- }
- else
- {
- if((dwKnownState & WRITER_SIGNALED) &&
- ((dwKnownState & WAITING_WRITERS_MASK) == WAITING_WRITER))
- {
- HRESULT hr1;
- if(hWriterEvent == NULL)
- hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr1);
- _ASSERTE(hWriterEvent);
- do
- {
- dwKnownState = (*ppRWLock)->_dwState;
- if((dwKnownState & WRITER_SIGNALED) &&
- ((dwKnownState & WAITING_WRITERS_MASK) == 0))
- {
- DWORD dwTemp = hWriterEvent->Wait(10, FALSE);
- if(dwTemp == WAIT_OBJECT_0)
- {
- dwKnownState = RWInterlockedExchangeAdd(&(*ppRWLock)->_dwState, (WRITER - WRITER_SIGNALED));
- _ASSERTE(dwKnownState & WRITER_SIGNALED);
- _ASSERTE((dwKnownState & WRITER) == 0);
-
- // Honor the orginal status
- (*ppRWLock)->_dwWriterID = dwThreadID;
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE ((*ppRWLock)->_wWriterLevel == 0);
- pThread->m_dwLockCount ++;
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
- (*ppRWLock)->_wWriterLevel = 1;
- StaticReleaseWriterLock(ppRWLock);
- break;
- }
- // else continue;
- }
- else
- break;
- }while(TRUE);
- }
-
- if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out.
- {
- _ASSERTE(!"Failed to acquire writer lock");
- DebugBreak();
- }
-
- // Prepare the frame for throwing an exception
- if ((DWORD)HOST_E_DEADLOCK == dwStatus)
- {
- // So that the error message is in the exception.
- RaiseDeadLockException();
- } else if ((DWORD)COR_E_THREADINTERRUPTED == dwStatus) {
- COMPlusThrow(kThreadInterruptedException);
- }
- else
- {
- COMPlusThrowWin32(hr);
- }
- }
-
- // Sanity check
- _ASSERTE(dwStatus == WAIT_OBJECT_0);
- break;
- }
- }
- YieldProcessor(); // indicate to the processor that we are spinning
- } while(TRUE);
- }
-
- // Success
- _ASSERTE((*ppRWLock)->_dwState & WRITER);
- _ASSERTE(((*ppRWLock)->_dwState & READERS_MASK) == 0);
- _ASSERTE((*ppRWLock)->_dwWriterID == 0);
-
- // Save threadid of the writer
- (*ppRWLock)->_dwWriterID = dwThreadID;
- (*ppRWLock)->_wWriterLevel = 1;
- INCTHREADLOCKCOUNT();
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
- ++(*ppRWLock)->_dwWriterSeqNum;
-#ifdef RWLOCK_STATISTICS
- ++(*ppRWLock)->_dwWriterEntryCount;
-#endif
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticReleaseWriterLockPublic public
-//
-// Synopsis: Public access to StaticReleaseWriterLock
-//
-//+-------------------------------------------------------------------
-FCIMPL1(void, CRWLock::StaticReleaseWriterLockPublic, CRWLock *pRWLockUNSAFE)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
-
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock);
-
- // We don't want to block thread abort when we need to construct exception in
- // unwind-continue handler.
- // note that we cannot use this holder in FCALLs outside our HMF since it breaks the epilog walker on x86!
- ThreadPreventAbortHolder preventAbortIn;
-
- StaticReleaseWriterLock((CRWLock**)&pRWLock);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticReleaseWriterLock private
-//
-// Synopsis: Removes the thread as a writer if not a nested
-// call to release the lock
-//
-//+-------------------------------------------------------------------
-void CRWLock::StaticReleaseWriterLock(
- CRWLock **ppRWLock)
-{
-
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- PRECONDITION((CheckPointer(ppRWLock)));
- PRECONDITION((CheckPointer(*ppRWLock)));
- }
- CONTRACTL_END;
-
- DWORD dwThreadID = GetThread()->GetThreadId();
-
- // Check validity of caller
- if((*ppRWLock)->_dwWriterID == dwThreadID)
- {
- DECTHREADLOCKCOUNT();
- USER_LOCK_RELEASED(GetPtrForLockContract(ppRWLock));
- // Check for nested release
- if(--(*ppRWLock)->_wWriterLevel == 0)
- {
- DWORD dwCurrentState, dwKnownState, dwModifyState;
- BOOL fCacheEvents;
- CLREvent* hReaderEvent = NULL, *hWriterEvent = NULL;
-
- // Not a writer any more
- (*ppRWLock)->_dwWriterID = 0;
- dwCurrentState = (*ppRWLock)->_dwState;
- do
- {
- dwKnownState = dwCurrentState;
- dwModifyState = (DWORD) -WRITER;
- fCacheEvents = FALSE;
- if(dwKnownState & WAITING_READERS_MASK)
- {
- HRESULT hr;
- hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr);
- if(hReaderEvent == NULL)
- {
- LOG((LF_SYNC, LL_WARNING,
- "ReleaseWriterLock failed to create "
- "reader event for RWLock 0x%x\n", *ppRWLock));
- RWSleep(100);
- dwCurrentState = (*ppRWLock)->_dwState;
- dwKnownState = 0;
- _ASSERTE(dwCurrentState != dwKnownState);
- continue;
- }
- dwModifyState += READER_SIGNALED;
- }
- else if(dwKnownState & WAITING_WRITERS_MASK)
- {
- HRESULT hr;
- hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr);
- if(hWriterEvent == NULL)
- {
- LOG((LF_SYNC, LL_WARNING,
- "ReleaseWriterLock failed to create "
- "writer event for RWLock 0x%x\n", *ppRWLock));
- RWSleep(100);
- dwCurrentState = (*ppRWLock)->_dwState;
- dwKnownState = 0;
- _ASSERTE(dwCurrentState != dwKnownState);
- continue;
- }
- dwModifyState += WRITER_SIGNALED;
- }
- else if(((*ppRWLock)->_hReaderEvent || (*ppRWLock)->_hWriterEvent) &&
- (dwKnownState == WRITER))
- {
- fCacheEvents = TRUE;
- dwModifyState += CACHING_EVENTS;
- }
-
- // Sanity checks
- _ASSERTE((dwKnownState & READERS_MASK) == 0);
-
- dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + dwModifyState),
- dwKnownState);
- } while(dwCurrentState != dwKnownState);
-
- // Check for waiting readers
- if(dwKnownState & WAITING_READERS_MASK)
- {
- _ASSERTE((*ppRWLock)->_dwState & READER_SIGNALED);
- _ASSERTE(hReaderEvent);
- RWSetEvent(hReaderEvent);
- }
- // Check for waiting writers
- else if(dwKnownState & WAITING_WRITERS_MASK)
- {
- _ASSERTE((*ppRWLock)->_dwState & WRITER_SIGNALED);
- _ASSERTE(hWriterEvent);
- RWSetEvent(hWriterEvent);
- }
- // Check for the need to release events
- else if(fCacheEvents)
- {
- (*ppRWLock)->ReleaseEvents();
- }
-
- Thread *pThread = GetThread();
- TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE));
- if (pThread->IsAbortRequested()) {
- pThread->HandleThreadAbort();
- }
-
- }
- }
- else
- {
- if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out.
- {
- _ASSERTE(!"Attempt to release writer lock on a wrong thread");
- DebugBreak();
- }
- COMPlusThrowWin32(ERROR_NOT_OWNER);
- }
-
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticReleaseReaderLockPublic public
-//
-// Synopsis: Public access to StaticReleaseReaderLock
-//
-//+-------------------------------------------------------------------
-FCIMPL1(void, CRWLock::StaticReleaseReaderLockPublic, CRWLock *pRWLockUNSAFE)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
-
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock);
-
- // note that we cannot use this holder in FCALLs outside our HMF since it breaks the epilog walker on x86!
- ThreadPreventAbortHolder preventAbortIn;
-
- StaticReleaseReaderLock((CRWLock**)&pRWLock);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticReleaseReaderLock private
-//
-// Synopsis: Removes the thread as a reader
-//
-//+-------------------------------------------------------------------
-
-void CRWLock::StaticReleaseReaderLock(
- CRWLock **ppRWLock)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- PRECONDITION((CheckPointer(ppRWLock)));
- PRECONDITION((CheckPointer(*ppRWLock)));
- }
- CONTRACTL_END;
-
- // Check if the thread has writer lock
- if((*ppRWLock)->_dwWriterID == GetThread()->GetThreadId())
- {
- StaticReleaseWriterLock(ppRWLock);
- }
- else
- {
- LockEntry *pLockEntry = (*ppRWLock)->GetLockEntry();
- if(pLockEntry)
- {
- --pLockEntry->wReaderLevel;
- DECTHREADLOCKCOUNT();
- USER_LOCK_RELEASED(GetPtrForLockContract(ppRWLock));
- if(pLockEntry->wReaderLevel == 0)
- {
- DWORD dwCurrentState, dwKnownState, dwModifyState;
- BOOL fLastReader, fCacheEvents = FALSE;
- CLREvent* hReaderEvent = NULL, *hWriterEvent = NULL;
-
- // Sanity checks
- _ASSERTE(((*ppRWLock)->_dwState & WRITER) == 0);
- _ASSERTE((*ppRWLock)->_dwState & READERS_MASK);
-
- // Not a reader any more
- dwCurrentState = (*ppRWLock)->_dwState;
- do
- {
- dwKnownState = dwCurrentState;
- dwModifyState = (DWORD) -READER;
- if((dwKnownState & (READERS_MASK | READER_SIGNALED)) == READER)
- {
- fLastReader = TRUE;
- fCacheEvents = FALSE;
- if(dwKnownState & WAITING_WRITERS_MASK)
- {
- HRESULT hr;
- hWriterEvent = (*ppRWLock)->GetWriterEvent(&hr);
- if(hWriterEvent == NULL)
- {
- LOG((LF_SYNC, LL_WARNING,
- "ReleaseReaderLock failed to create "
- "writer event for RWLock 0x%x\n", *ppRWLock));
- RWSleep(100);
- dwCurrentState = (*ppRWLock)->_dwState;
- dwKnownState = 0;
- _ASSERTE(dwCurrentState != dwKnownState);
- continue;
- }
- dwModifyState += WRITER_SIGNALED;
- }
- else if(dwKnownState & WAITING_READERS_MASK)
- {
- HRESULT hr;
- hReaderEvent = (*ppRWLock)->GetReaderEvent(&hr);
- if(hReaderEvent == NULL)
- {
- LOG((LF_SYNC, LL_WARNING,
- "ReleaseReaderLock failed to create "
- "reader event\n", *ppRWLock));
- RWSleep(100);
- dwCurrentState = (*ppRWLock)->_dwState;
- dwKnownState = 0;
- _ASSERTE(dwCurrentState != dwKnownState);
- continue;
- }
- dwModifyState += READER_SIGNALED;
- }
- else if(((*ppRWLock)->_hReaderEvent || (*ppRWLock)->_hWriterEvent) &&
- (dwKnownState == READER))
- {
- fCacheEvents = TRUE;
- dwModifyState += CACHING_EVENTS;
- }
- }
- else
- {
- fLastReader = FALSE;
- }
-
- // Sanity checks
- _ASSERTE((dwKnownState & WRITER) == 0);
- _ASSERTE(dwKnownState & READERS_MASK);
-
- dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + dwModifyState),
- dwKnownState);
- } while(dwCurrentState != dwKnownState);
-
- // Check for last reader
- if(fLastReader)
- {
- // Check for waiting writers
- if(dwKnownState & WAITING_WRITERS_MASK)
- {
- _ASSERTE((*ppRWLock)->_dwState & WRITER_SIGNALED);
- _ASSERTE(hWriterEvent);
- RWSetEvent(hWriterEvent);
- }
- // Check for waiting readers
- else if(dwKnownState & WAITING_READERS_MASK)
- {
- _ASSERTE((*ppRWLock)->_dwState & READER_SIGNALED);
- _ASSERTE(hReaderEvent);
- RWSetEvent(hReaderEvent);
- }
- // Check for the need to release events
- else if(fCacheEvents)
- {
- (*ppRWLock)->ReleaseEvents();
- }
- }
-
- // Recycle lock entry
- RecycleLockEntry(pLockEntry);
-
- Thread *pThread = GetThread();
- TESTHOOKCALL(AppDomainCanBeUnloaded(pThread->GetDomain()->GetId().m_dwId,FALSE));
-
- if (pThread->IsAbortRequested()) {
- pThread->HandleThreadAbort();
- }
- }
- }
- else
- {
- if(fBreakOnErrors) // fBreakOnErrors == FALSE so will be optimized out.
- {
- _ASSERTE(!"Attempt to release reader lock on a wrong thread");
- DebugBreak();
- }
- COMPlusThrowWin32(ERROR_NOT_OWNER);
- }
- }
-
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticDoUpgradeToWriterLockPublic private
-//
-// Synopsis: Public Access to StaticUpgradeToWriterLockPublic
-//
-//
-//+-------------------------------------------------------------------
-FCIMPL3(void, CRWLock::StaticDoUpgradeToWriterLockPublic, CRWLock *pRWLockUNSAFE, LockCookie * pLockCookie, DWORD dwDesiredTimeout)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(pRWLock);
- GCPROTECT_BEGININTERIOR (pLockCookie)
-
- StaticUpgradeToWriterLock((CRWLock**)&pRWLock, pLockCookie, dwDesiredTimeout);
-
- GCPROTECT_END ();
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticUpgradeToWriterLock Private
-//
-// Synopsis: Upgrades to a writer lock. It returns a BOOL that
-// indicates intervening writes.
-//
-
-//
-//+-------------------------------------------------------------------
-
-void CRWLock::StaticUpgradeToWriterLock(
- CRWLock **ppRWLock,
- LockCookie *pLockCookie,
- DWORD dwDesiredTimeout)
-
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- CAN_TAKE_LOCK;
- }
- CONTRACTL_END;
-
- DWORD dwThreadID = GetThread()->GetThreadId();
-
- // Check if the thread is already a writer
- if((*ppRWLock)->_dwWriterID == dwThreadID)
- {
- // Update cookie state
- pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_WRITER;
- pLockCookie->wWriterLevel = (*ppRWLock)->_wWriterLevel;
-
- // Acquire the writer lock again
- StaticAcquireWriterLock(ppRWLock, dwDesiredTimeout);
- }
- else
- {
- BOOL fAcquireWriterLock;
- LockEntry *pLockEntry = (*ppRWLock)->GetLockEntry();
- if(pLockEntry == NULL)
- {
- fAcquireWriterLock = TRUE;
- pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_NONE;
- }
- else
- {
- // Sanity check
- _ASSERTE((*ppRWLock)->_dwState & READERS_MASK);
- _ASSERTE(pLockEntry->wReaderLevel);
-
- // Save lock state in the cookie
- pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_READER;
- pLockCookie->wReaderLevel = pLockEntry->wReaderLevel;
- pLockCookie->dwWriterSeqNum = (*ppRWLock)->_dwWriterSeqNum;
-
- // If there is only one reader, try to convert reader to a writer
- DWORD dwKnownState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- WRITER,
- READER);
- if(dwKnownState == READER)
- {
- // Thread is no longer a reader
- Thread* pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE (pThread->m_dwLockCount >= pLockEntry->wReaderLevel);
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >= pLockEntry->wReaderLevel);
- pThread->m_dwLockCount -= pLockEntry->wReaderLevel;
- USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock));
- pLockEntry->wReaderLevel = 0;
- RecycleLockEntry(pLockEntry);
-
- // Thread is a writer
- (*ppRWLock)->_dwWriterID = dwThreadID;
- (*ppRWLock)->_wWriterLevel = 1;
- INCTHREADLOCKCOUNT();
- USER_LOCK_TAKEN(GetPtrForLockContract(ppRWLock));
- ++(*ppRWLock)->_dwWriterSeqNum;
- fAcquireWriterLock = FALSE;
-
- // No intevening writes
-#if RWLOCK_STATISTICS
- ++(*ppRWLock)->_dwWriterEntryCount;
-#endif
- }
- else
- {
- // Release the reader lock
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE (pThread->m_dwLockCount >= (DWORD)(pLockEntry->wReaderLevel - 1));
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >=
- (DWORD)(pLockEntry->wReaderLevel - 1));
- pThread->m_dwLockCount -= (pLockEntry->wReaderLevel - 1);
- USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel - 1, GetPtrForLockContract(ppRWLock));
- pLockEntry->wReaderLevel = 1;
- StaticReleaseReaderLock(ppRWLock);
- fAcquireWriterLock = TRUE;
- }
- }
-
- // Check for the need to acquire the writer lock
- if(fAcquireWriterLock)
- {
-
- // Declare and Setup the frame as we are aware of the contention
- // on the lock and the thread will most probably block
- // to acquire writer lock
-
- EX_TRY
- {
- StaticAcquireWriterLock(ppRWLock, dwDesiredTimeout);
- }
- EX_CATCH
- {
- // Invalidate cookie
- DWORD dwFlags = pLockCookie->dwFlags;
- pLockCookie->dwFlags = INVALID_COOKIE;
-
- StaticRecoverLock(ppRWLock, pLockCookie, dwFlags & COOKIE_READER);
-
- EX_RETHROW;
- }
- EX_END_CATCH_UNREACHABLE
- }
- }
-
-
- // Update the validation fields of the cookie
- pLockCookie->dwThreadID = dwThreadID;
-
- return;
-}
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticDowngradeFromWriterLock public
-//
-// Synopsis: Downgrades from a writer lock.
-//
-//+-------------------------------------------------------------------
-
-inline CRWLock* GetLock(OBJECTREF orLock)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return (CRWLock*)OBJECTREFToObject(orLock);
-}
-
-FCIMPL2(void, CRWLock::StaticDowngradeFromWriterLock, CRWLock *pRWLockUNSAFE, LockCookie* pLockCookie)
-{
- FCALL_CONTRACT;
- STATIC_CONTRACT_CAN_TAKE_LOCK;
-
- DWORD dwThreadID = GetThread()->GetThreadId();
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- if( NULL == pLockCookie) {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(pRWLock);
-
- if (GetLock(pRWLock)->_dwWriterID != dwThreadID)
- {
- COMPlusThrowWin32(ERROR_NOT_OWNER);
- }
-
- // Validate cookie
- DWORD dwStatus;
- if(((pLockCookie->dwFlags & INVALID_COOKIE) == 0) &&
- (pLockCookie->dwThreadID == dwThreadID))
- {
- DWORD dwFlags = pLockCookie->dwFlags;
- pLockCookie->dwFlags = INVALID_COOKIE;
-
- // Check if the thread was a reader
- if(dwFlags & COOKIE_READER)
- {
- // Sanity checks
- _ASSERTE(GetLock(pRWLock)->_wWriterLevel == 1);
-
- LockEntry *pLockEntry = GetLock(pRWLock)->FastGetOrCreateLockEntry();
- if(pLockEntry)
- {
- DWORD dwCurrentState, dwKnownState, dwModifyState;
- CLREvent* hReaderEvent = NULL;
-
- // Downgrade to a reader
- GetLock(pRWLock)->_dwWriterID = 0;
- GetLock(pRWLock)->_wWriterLevel = 0;
- DECTHREADLOCKCOUNT ();
- USER_LOCK_RELEASED(GetPtrForLockContract((CRWLock**)&pRWLock));
- dwCurrentState = GetLock(pRWLock)->_dwState;
- do
- {
- dwKnownState = dwCurrentState;
- dwModifyState = READER - WRITER;
- if(dwKnownState & WAITING_READERS_MASK)
- {
- HRESULT hr;
- hReaderEvent = GetLock(pRWLock)->GetReaderEvent(&hr);
- if(hReaderEvent == NULL)
- {
- LOG((LF_SYNC, LL_WARNING,
- "DowngradeFromWriterLock failed to create "
- "reader event for RWLock 0x%x\n", GetLock(pRWLock)));
- RWSleep(100);
- dwCurrentState = GetLock(pRWLock)->_dwState;
- dwKnownState = 0;
- _ASSERTE(dwCurrentState != dwKnownState);
- continue;
- }
- dwModifyState += READER_SIGNALED;
- }
-
- // Sanity checks
- _ASSERTE((dwKnownState & READERS_MASK) == 0);
-
- dwCurrentState = RWInterlockedCompareExchange(&GetLock(pRWLock)->_dwState,
- (dwKnownState + dwModifyState),
- dwKnownState);
- } while(dwCurrentState != dwKnownState);
-
- // Check for waiting readers
- if(dwKnownState & WAITING_READERS_MASK)
- {
- _ASSERTE(GetLock(pRWLock)->_dwState & READER_SIGNALED);
- _ASSERTE(hReaderEvent);
- RWSetEvent(hReaderEvent);
- }
-
- // Restore reader nesting level
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE (pThread->m_dwLockCount >= pLockEntry->wReaderLevel);
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >=
- pLockEntry->wReaderLevel);
- pThread->m_dwLockCount -= pLockEntry->wReaderLevel;
- USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract((CRWLock**)&pRWLock));
- pLockEntry->wReaderLevel = pLockCookie->wReaderLevel;
- pThread->m_dwLockCount += pLockEntry->wReaderLevel;
- USER_LOCK_TAKEN_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract((CRWLock**)&pRWLock));
- #ifdef RWLOCK_STATISTICS
- RWInterlockedIncrement(&GetLock(pRWLock)->_dwReaderEntryCount);
- #endif
- }
- else
- {
- // Removed assert, as thread abort can occur normally
- dwStatus = RWLOCK_RECOVERY_FAILURE;
- goto ThrowException;
- }
- }
- else if(dwFlags & (COOKIE_WRITER | COOKIE_NONE))
- {
- // Release the writer lock
- StaticReleaseWriterLock((CRWLock**)&pRWLock);
- _ASSERTE((GetLock(pRWLock)->_dwWriterID != GetThread()->GetThreadId()) ||
- (dwFlags & COOKIE_WRITER));
- }
- }
- else
- {
- dwStatus = E_INVALIDARG;
-ThrowException:
- COMPlusThrowWin32(dwStatus);
- }
-
- HELPER_METHOD_FRAME_END();
-
- // Update the validation fields of the cookie
- pLockCookie->dwThreadID = dwThreadID;
-
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticDoReleaseLock private
-//
-// Synopsis: Releases the lock held by the current thread
-//
-//+-------------------------------------------------------------------
-
-FCIMPL2(void, CRWLock::StaticDoReleaseLock, CRWLock *pRWLockUNSAFE, LockCookie * pLockCookie)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL)
- {
- FCThrowVoid(kNullReferenceException);
- }
-
- DWORD dwThreadID = GetThread()->GetThreadId();
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
-
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock);
-
- // note that we cannot use this holder in FCALLs outside our HMF since it breaks the epilog walker on x86!
- ThreadPreventAbortHolder preventAbortIn;
-
- GCPROTECT_BEGININTERIOR (pLockCookie)
-
- // Check if the thread is a writer
- if(GetLock(pRWLock)->_dwWriterID == dwThreadID)
- {
- // Save lock state in the cookie
- pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_WRITER;
- pLockCookie->dwWriterSeqNum = GetLock(pRWLock)->_dwWriterSeqNum;
- pLockCookie->wWriterLevel = GetLock(pRWLock)->_wWriterLevel;
-
- // Release the writer lock
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE (pThread->m_dwLockCount >= (DWORD)(GetLock(pRWLock)->_wWriterLevel - 1));
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >=
- (DWORD)(GetLock(pRWLock)->_wWriterLevel - 1));
- pThread->m_dwLockCount -= (GetLock(pRWLock)->_wWriterLevel - 1);
- USER_LOCK_RELEASED_MULTIPLE(GetLock(pRWLock)->_wWriterLevel - 1, GetPtrForLockContract((CRWLock**)&pRWLock));
- GetLock(pRWLock)->_wWriterLevel = 1;
- StaticReleaseWriterLock((CRWLock**)&pRWLock);
- }
- else
- {
- LockEntry *pLockEntry = GetLock(pRWLock)->GetLockEntry();
- if(pLockEntry)
- {
- // Sanity check
- _ASSERTE(GetLock(pRWLock)->_dwState & READERS_MASK);
- _ASSERTE(pLockEntry->wReaderLevel);
-
- // Save lock state in the cookie
- pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_READER;
- pLockCookie->wReaderLevel = pLockEntry->wReaderLevel;
- pLockCookie->dwWriterSeqNum = GetLock(pRWLock)->_dwWriterSeqNum;
-
- // Release the reader lock
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE (pThread->m_dwLockCount >= (DWORD)(pLockEntry->wReaderLevel - 1));
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >=
- (DWORD)(pLockEntry->wReaderLevel - 1));
- pThread->m_dwLockCount -= (pLockEntry->wReaderLevel - 1);
- USER_LOCK_RELEASED_MULTIPLE(pLockEntry->wReaderLevel - 1, GetPtrForLockContract((CRWLock**)&pRWLock));
- pLockEntry->wReaderLevel = 1;
- StaticReleaseReaderLock((CRWLock**)&pRWLock);
- }
- else
- {
- pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_NONE;
- }
- }
-
- GCPROTECT_END ();
-
- HELPER_METHOD_FRAME_END();
-
- // Update the validation fields of the cookie
- pLockCookie->dwThreadID = dwThreadID;
-}
-FCIMPLEND
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticRestoreLockPublic public
-//
-// Synopsis: Public Access to StaticRestoreLock
-//
-//
-//+-------------------------------------------------------------------
-
-FCIMPL2(void, CRWLock::StaticRestoreLockPublic, CRWLock *pRWLockUNSAFE, LockCookie* pLockCookie)
-{
- FCALL_CONTRACT;
-
- if (pRWLockUNSAFE == NULL) {
- FCThrowVoid(kNullReferenceException);
- }
-
- if( NULL == pLockCookie) {
- FCThrowVoid(kNullReferenceException);
- }
-
- OBJECTREF pRWLock = ObjectToOBJECTREF((Object*)pRWLockUNSAFE);
- HELPER_METHOD_FRAME_BEGIN_1(pRWLock);
-
- StaticRestoreLock((CRWLock**)&pRWLock, pLockCookie);
-
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-//+-------------------------------------------------------------------
-//
-// Method: CRWLock::StaticRestoreLock Private
-//
-// Synopsis: Restore the lock held by the current thread
-//
-
-//
-//+-------------------------------------------------------------------
-
-void CRWLock::StaticRestoreLock(
- CRWLock **ppRWLock,
- LockCookie *pLockCookie)
-{
- CONTRACTL
- {
- THROWS;
- CAN_TAKE_LOCK;
- GC_TRIGGERS; // CRWLock::StaticAquireWriterLock can trigger GC
- }
- CONTRACTL_END;
-
- // Validate cookie
- DWORD dwThreadID = GetThread()->GetThreadId();
- DWORD dwFlags = pLockCookie->dwFlags;
- if(pLockCookie->dwThreadID == dwThreadID)
- {
- if (((*ppRWLock)->_dwWriterID == dwThreadID) || ((*ppRWLock)->GetLockEntry() != NULL))
- {
- COMPlusThrow(kSynchronizationLockException, W("Arg_RWLockRestoreException"));
- }
-
- // Check for the no contention case
- pLockCookie->dwFlags = INVALID_COOKIE;
- if(dwFlags & COOKIE_WRITER)
- {
- if(RWInterlockedCompareExchange(&(*ppRWLock)->_dwState, WRITER, 0) == 0)
- {
- // Restore writer nesting level
- (*ppRWLock)->_dwWriterID = dwThreadID;
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- _ASSERTE (pThread->m_dwLockCount >= (*ppRWLock)->_wWriterLevel);
- ASSERT_UNLESS_NO_DEBUG_STATE(__pClrDebugState->GetLockCount(kDbgStateLockType_User) >=
- (*ppRWLock)->_wWriterLevel);
- pThread->m_dwLockCount -= (*ppRWLock)->_wWriterLevel;
- USER_LOCK_RELEASED_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock));
- (*ppRWLock)->_wWriterLevel = pLockCookie->wWriterLevel;
- pThread->m_dwLockCount += (*ppRWLock)->_wWriterLevel;
- USER_LOCK_TAKEN_MULTIPLE((*ppRWLock)->_wWriterLevel, GetPtrForLockContract(ppRWLock));
- ++(*ppRWLock)->_dwWriterSeqNum;
-#ifdef RWLOCK_STATISTICS
- ++(*ppRWLock)->_dwWriterEntryCount;
-#endif
- goto LNormalReturn;
- }
- }
- else if(dwFlags & COOKIE_READER)
- {
- LockEntry *pLockEntry = (*ppRWLock)->FastGetOrCreateLockEntry();
- if(pLockEntry)
- {
- // This thread should not already be a reader
- // else bad things can happen
- _ASSERTE(pLockEntry->wReaderLevel == 0);
- DWORD dwKnownState = (*ppRWLock)->_dwState;
- if(dwKnownState < READERS_MASK)
- {
- DWORD dwCurrentState = RWInterlockedCompareExchange(&(*ppRWLock)->_dwState,
- (dwKnownState + READER),
- dwKnownState);
- if(dwCurrentState == dwKnownState)
- {
- // Restore reader nesting level
- Thread *pThread = GetThread();
- _ASSERTE (pThread);
- pLockEntry->wReaderLevel = pLockCookie->wReaderLevel;
- pThread->m_dwLockCount += pLockEntry->wReaderLevel;
- USER_LOCK_TAKEN_MULTIPLE(pLockEntry->wReaderLevel, GetPtrForLockContract(ppRWLock));
-#ifdef RWLOCK_STATISTICS
- RWInterlockedIncrement(&(*ppRWLock)->_dwReaderEntryCount);
-#endif
- goto LNormalReturn;
- }
- }
-
- // Recycle the lock entry for the slow case
- (*ppRWLock)->FastRecycleLockEntry(pLockEntry);
- }
- else
- {
- // Ignore the error and try again below. May be thread will luck
- // out the second time
- }
- }
- else if(dwFlags & COOKIE_NONE)
- {
- goto LNormalReturn;
- }
-
- // Declare and Setup the frame as we are aware of the contention
- // on the lock and the thread will most probably block
- // to acquire lock below
-ThrowException:
- if((dwFlags & INVALID_COOKIE) == 0)
- {
- StaticRecoverLock(ppRWLock, pLockCookie, dwFlags);
- }
- else
- {
- COMPlusThrowWin32(E_INVALIDARG);
- }
-
- goto LNormalReturn;
- }
- else
- {
- dwFlags = INVALID_COOKIE;
- goto ThrowException;
- }
-
-LNormalReturn:
- return;
-}
-
-
-//+-------------------------------------------------------------------
-//
-// Class: CRWLock::StaticPrivateInitialize
-//
-// Synopsis: Initialize lock
-//
-//+-------------------------------------------------------------------
-FCIMPL1(void, CRWLock::StaticPrivateInitialize, CRWLock *pRWLock)
-{
- FCALL_CONTRACT;
-
- HELPER_METHOD_FRAME_BEGIN_1(pRWLock);
-
- // Run the constructor on the GC allocated space
- // CRWLock's constructor can throw exception
-#ifndef _PREFAST_
- // Prefast falsely complains of memory leak.
- CRWLock *pTemp;
- pTemp = new (pRWLock) CRWLock();
- _ASSERTE(pTemp == pRWLock);
-#endif
-
- // Catch GC holes
- VALIDATE_LOCK(pRWLock);
-
- HELPER_METHOD_FRAME_END();
- return;
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Class: CRWLock::StaticPrivateDestruct
-//
-// Synopsis: Destruct lock
-//+-------------------------------------------------------------------
-FCIMPL1(void, CRWLock::StaticPrivateDestruct, CRWLock *pRWLock)
-{
- FCALL_CONTRACT;
-
- HELPER_METHOD_FRAME_BEGIN_ATTRIB_1(Frame::FRAME_ATTR_NO_THREAD_ABORT, pRWLock);
-
- // Fixing one handle recycling security hole by
- // ensuring we don't delete the events more than once.
- // After deletion (for now, assuming ONE FINALIZER THREAD)
- // make the object essentially unusable by setting handle to
- // INVALID_HANDLE_VALUE (unusable) versus NULL (uninitialized)
-
- if ((pRWLock->_hWriterEvent != INVALID_HANDLE_VALUE) && (pRWLock->_hReaderEvent != INVALID_HANDLE_VALUE))
- {
- // Note, this still allows concurrent event consumers (such as StaticAcquireReaderLock)
- // to Set and/or Wait on non-events. There still exists a security hole here.
- if(pRWLock->_hWriterEvent)
- {
- CLREvent *h = (CLREvent *) FastInterlockExchangePointer((PVOID *)&(pRWLock->_hWriterEvent), INVALID_HANDLE_VALUE);
- delete h;
- }
- if(pRWLock->_hReaderEvent)
- {
- CLREvent *h = (CLREvent *) FastInterlockExchangePointer((PVOID *)&(pRWLock->_hReaderEvent), INVALID_HANDLE_VALUE);
- delete h;
- }
-
- // There is no LockEntry for this lock.
- if (pRWLock->_dwState != 0)
- {
- // Recycle LockEntry on threads
- ThreadStoreLockHolder tsl;
-
- // Take ThreadStore lock and walk over every thread in the process
- Thread *thread = NULL;
- while ((thread = ThreadStore::s_pThreadStore->GetAllThreadList(thread,
- Thread::TS_Unstarted|Thread::TS_Dead|Thread::TS_Detached, 0))
- != NULL)
- {
- LockEntry *pLockEntry;
- {
- CrstHolder rwl(&s_RWLockCrst);
- pLockEntry = pRWLock->GetLockEntry(thread);
- }
- if (pLockEntry)
- {
- // The entry does not belong to this lock anymore
- pLockEntry->dwLLockID = 0;
- pLockEntry->wReaderLevel = 0;
- }
- }
- }
- }
- HELPER_METHOD_FRAME_END();
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Class: CRWLock::StaticGetWriterSeqNum
-//
-// Synopsis: Returns the current sequence number
-//
-//+-------------------------------------------------------------------
-FCIMPL1(INT32, CRWLock::StaticGetWriterSeqNum, CRWLock *pRWLock)
-{
- FCALL_CONTRACT;
-
- if (pRWLock == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
- return(pRWLock->_dwWriterSeqNum);
-}
-FCIMPLEND
-
-
-//+-------------------------------------------------------------------
-//
-// Class: CRWLock::StaticAnyWritersSince
-//
-// Synopsis: Returns TRUE if there were writers since the given
-// sequence number
-//
-//+-------------------------------------------------------------------
-FCIMPL2(FC_BOOL_RET, CRWLock::StaticAnyWritersSince, CRWLock *pRWLock, DWORD dwSeqNum)
-{
- FCALL_CONTRACT;
-
- if (pRWLock == NULL)
- {
- FCThrow(kNullReferenceException);
- }
-
-
- if(pRWLock->_dwWriterID == GetThread()->GetThreadId())
- ++dwSeqNum;
-
- FC_RETURN_BOOL(pRWLock->_dwWriterSeqNum > dwSeqNum);
-}
-FCIMPLEND
-
-struct RWLockIterator
-{
- IHostTask **m_Owner;
- DWORD m_Capacity;
- DWORD m_index;
-};
-
-OBJECTHANDLE CRWLock::GetObjectHandle()
-{
- CONTRACTL
- {
- THROWS;
- MODE_COOPERATIVE;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- if (_hObjectHandle == NULL)
- {
- OBJECTREF obj = ObjectToOBJECTREF((Object*)this);
- OBJECTHANDLE handle = GetAppDomain()->CreateLongWeakHandle(obj);
- if (RWInterlockedCompareExchangePointer((PVOID*)&_hObjectHandle, handle, NULL) != NULL)
- {
- DestroyLongWeakHandle(handle);
- }
- }
- return _hObjectHandle;
-}
-
-// CRWLock::CreateOwnerIterator can return E_OUTOFMEMORY
-//
-HRESULT CRWLock::CreateOwnerIterator(SIZE_T *pIterator)
-{
- CONTRACTL
- {
- NOTHROW;
- MODE_PREEMPTIVE;
- GC_NOTRIGGER;
- SO_INTOLERANT;
- }
- CONTRACTL_END;
-
- *pIterator = 0;
- if (_dwState == 0) {
- return S_OK;
- }
- NewHolder<RWLockIterator> IteratorHolder(new (nothrow) RWLockIterator);
- RWLockIterator *pRWLockIterator = IteratorHolder;
- if (pRWLockIterator == NULL) {
- return E_OUTOFMEMORY;
- }
- // Writer can be handled fast
- if (_dwState & WRITER) {
- DWORD writerID = _dwWriterID;
- if (writerID != 0)
- {
- pRWLockIterator->m_Capacity = 1;
- pRWLockIterator->m_index = 0;
- pRWLockIterator->m_Owner = new (nothrow) IHostTask*[1];
- if (pRWLockIterator->m_Owner == NULL) {
- return E_OUTOFMEMORY;
- }
- Thread *pThread = g_pThinLockThreadIdDispenser->IdToThreadWithValidation(writerID);
- if (pThread == NULL)
- {
- return S_OK;
- }
- IteratorHolder.SuppressRelease();
- pRWLockIterator->m_Owner[0] = pThread->GetHostTaskWithAddRef();
- *pIterator = (SIZE_T)pRWLockIterator;
- return S_OK;
- }
- }
- if (_dwState == 0) {
- return S_OK;
- }
- pRWLockIterator->m_Capacity = 4;
- pRWLockIterator->m_index = 0;
- pRWLockIterator->m_Owner = new (nothrow) IHostTask*[pRWLockIterator->m_Capacity];
- if (pRWLockIterator->m_Owner == NULL) {
- return E_OUTOFMEMORY;
- }
-
- HRESULT hr = S_OK;
-
- NewArrayHolder<IHostTask*> OwnerHolder(pRWLockIterator->m_Owner);
-
- // Take ThreadStore lock and walk over every thread in the process
- Thread *thread = NULL;
- while ((thread = ThreadStore::s_pThreadStore->GetAllThreadList(thread,
- Thread::TS_Unstarted|Thread::TS_Dead|Thread::TS_Detached, 0))
- != NULL)
- {
- LockEntry *pLockEntry;
- {
- CrstHolder rwl(&s_RWLockCrst);
- pLockEntry = GetLockEntry(thread);
- }
- if (pLockEntry && pLockEntry->wReaderLevel >= 1) {
- if (pRWLockIterator->m_index == pRWLockIterator->m_Capacity) {
- IHostTask** newArray = new (nothrow) IHostTask*[2*pRWLockIterator->m_Capacity];
- if (newArray == NULL) {
- hr = E_OUTOFMEMORY;
- break;
- }
- memcpy (newArray,pRWLockIterator->m_Owner,pRWLockIterator->m_Capacity*sizeof(IHostTask*));
- pRWLockIterator->m_Owner = newArray;
- pRWLockIterator->m_Capacity *= 2;
- OwnerHolder = pRWLockIterator->m_Owner;
- }
- IHostTask *pHostTask = thread->GetHostTaskWithAddRef();
- if (pHostTask)
- {
- pRWLockIterator->m_Owner[pRWLockIterator->m_index++] = pHostTask;
- }
- }
- }
- if (FAILED(hr))
- {
- for (DWORD i = 0; i < pRWLockIterator->m_index; i ++)
- {
- if (pRWLockIterator->m_Owner[i])
- {
- pRWLockIterator->m_Owner[i]->Release();
- }
- }
- }
- if (SUCCEEDED(hr)) {
- IteratorHolder.SuppressRelease();
- OwnerHolder.SuppressRelease();
- pRWLockIterator->m_Capacity = pRWLockIterator->m_index;
- pRWLockIterator->m_index = 0;
- *pIterator = (SIZE_T)pRWLockIterator;
- }
-
- return hr;
-}
-
-void CRWLock::GetNextOwner(SIZE_T Iterator, IHostTask **ppOwnerHostTask)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- *ppOwnerHostTask = NULL;
- if (Iterator) {
- RWLockIterator* tmp = (RWLockIterator*)Iterator;
- if (tmp->m_index < tmp->m_Capacity) {
- *ppOwnerHostTask = tmp->m_Owner[tmp->m_index];
- tmp->m_index ++;
- }
- }
-}
-
-void CRWLock::DeleteOwnerIterator(SIZE_T Iterator)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
-
- if (Iterator) {
- RWLockIterator* pIterator = (RWLockIterator*)Iterator;
- while (pIterator->m_index < pIterator->m_Capacity) {
- IHostTask *pHostTask = pIterator->m_Owner[pIterator->m_index];
- if (pHostTask)
- {
- pHostTask->Release();
- }
- pIterator->m_index ++;
- }
- delete[] pIterator->m_Owner;
- delete pIterator;
- }
-}
-#endif // FEATURE_RWLOCK
diff --git a/src/vm/rwlock.h b/src/vm/rwlock.h
index dc8e67e6fb..908e007169 100644
--- a/src/vm/rwlock.h
+++ b/src/vm/rwlock.h
@@ -67,220 +67,6 @@ typedef struct {
DWORD dwThreadID;
} LockCookie;
-//+-------------------------------------------------------------------
-//
-// Class: CRWLock
-//
-// Synopsis: Class the implements the reader writer locks.
-//
-//+-------------------------------------------------------------------
-class CRWLock : public Object
-{
- friend class MscorlibBinder;
-
-public:
- // Constuctor
- CRWLock();
-
- // Cleanup
- void Cleanup();
-
- OBJECTHANDLE GetObjectHandle();
- HRESULT CreateOwnerIterator(SIZE_T *pIterator);
- static void GetNextOwner(SIZE_T Iterator, IHostTask **ppOwnerHostTask);
- static void DeleteOwnerIterator(SIZE_T Iterator);
-
- // Statics that do the core work
- static FCDECL1 (void, StaticPrivateInitialize, CRWLock *pRWLock);
- static FCDECL1 (void, StaticPrivateDestruct, CRWLock *pRWLock);
- static FCDECL2 (void, StaticAcquireReaderLockPublic, CRWLock *pRWLock, DWORD dwDesiredTimeout);
- static FCDECL2 (void, StaticAcquireWriterLockPublic, CRWLock *pRWLock, DWORD dwDesiredTimeout);
- static FCDECL1 (void, StaticReleaseReaderLockPublic, CRWLock *pRWLock);
- static FCDECL1 (void, StaticReleaseWriterLockPublic, CRWLock *pRWLock);
- static FCDECL3 (void, StaticDoUpgradeToWriterLockPublic, CRWLock *pRWLock, LockCookie * pLockCookie, DWORD dwDesiredTimeout);
- static FCDECL2 (void, StaticDowngradeFromWriterLock, CRWLock *pRWLock, LockCookie* pLockCookie);
- static FCDECL2 (void, StaticDoReleaseLock, CRWLock *pRWLock, LockCookie * pLockCookie);
- static FCDECL2 (void, StaticRestoreLockPublic, CRWLock *pRWLock, LockCookie* pLockCookie);
- static FCDECL1 (FC_BOOL_RET, StaticIsReaderLockHeld, CRWLock *pRWLock);
- static FCDECL1 (FC_BOOL_RET, StaticIsWriterLockHeld, CRWLock *pRWLock);
- static FCDECL1 (INT32, StaticGetWriterSeqNum, CRWLock *pRWLock);
- static FCDECL2 (FC_BOOL_RET, StaticAnyWritersSince, CRWLock *pRWLock, DWORD dwSeqNum);
-private:
- static void StaticAcquireReaderLock(CRWLock **ppRWLock, DWORD dwDesiredTimeout);
- static void StaticAcquireWriterLock(CRWLock **ppRWLock, DWORD dwDesiredTimeout);
- static void StaticReleaseReaderLock(CRWLock **ppRWLock);
- static void StaticReleaseWriterLock(CRWLock **ppRWLock);
- static void StaticRecoverLock(CRWLock **ppRWLock, LockCookie *pLockCookie, DWORD dwFlags);
- static void StaticRestoreLock(CRWLock **ppRWLock, LockCookie *pLockCookie);
- static void StaticUpgradeToWriterLock(CRWLock **ppRWLock, LockCookie *pLockCookie, DWORD dwDesiredTimeout);
-public:
- // Assert functions
-#ifdef _DEBUG
- BOOL AssertWriterLockHeld();
- BOOL AssertWriterLockNotHeld();
- BOOL AssertReaderLockHeld();
- BOOL AssertReaderLockNotHeld();
- BOOL AssertReaderOrWriterLockHeld();
- void AssertHeld()
- {
- WRAPPER_NO_CONTRACT;
- AssertWriterLockHeld();
- }
- void AssertNotHeld()
- {
- WRAPPER_NO_CONTRACT;
- AssertWriterLockNotHeld();
- AssertReaderLockNotHeld();
- }
-#else
- void AssertWriterLockHeld() { LIMITED_METHOD_CONTRACT; }
- void AssertWriterLockNotHeld() { LIMITED_METHOD_CONTRACT; }
- void AssertReaderLockHeld() { LIMITED_METHOD_CONTRACT; }
- void AssertReaderLockNotHeld() { LIMITED_METHOD_CONTRACT; }
- void AssertReaderOrWriterLockHeld() { LIMITED_METHOD_CONTRACT; }
- void AssertHeld() { LIMITED_METHOD_CONTRACT; }
- void AssertNotHeld() { LIMITED_METHOD_CONTRACT; }
-#endif
-
- // Helper functions
-#ifdef RWLOCK_STATISTICS
- DWORD GetReaderEntryCount()
- {
- LIMITED_METHOD_CONTRACT;
- return(_dwReaderEntryCount);
- }
- DWORD GetReaderContentionCount() { LIMITED_METHOD_CONTRACT; return(_dwReaderContentionCount); }
- DWORD GetWriterEntryCount() { LIMITED_METHOD_CONTRACT; return(_dwWriterEntryCount); }
- DWORD GetWriterContentionCount() { LIMITED_METHOD_CONTRACT; return(_dwWriterContentionCount); }
-#endif
- // Static functions
- static void *operator new(size_t size)
- {
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- return ::operator new(size);
- }
- static void ProcessInit();
-
- static void SetTimeout(DWORD dwTimeout)
- {
- LIMITED_METHOD_CONTRACT;
-
- gdwDefaultTimeout = dwTimeout;
- }
- static DWORD GetTimeout()
- {
- LIMITED_METHOD_CONTRACT;
- return(gdwDefaultTimeout);
- }
- static void SetSpinCount(DWORD dwSpinCount)
- {
- LIMITED_METHOD_CONTRACT;
-
- gdwDefaultSpinCount = g_SystemInfo.dwNumberOfProcessors > 1
- ? dwSpinCount
- : 0;
- }
- static DWORD GetSpinCount() { LIMITED_METHOD_CONTRACT; return(gdwDefaultSpinCount); }
-
-private:
- // Private helpers
- static void ChainEntry(Thread *pThread, LockEntry *pLockEntry);
- LockEntry *GetLockEntry(Thread *pThread = NULL);
- LockEntry *FastGetOrCreateLockEntry();
- LockEntry *SlowGetOrCreateLockEntry(Thread *pThread);
- void FastRecycleLockEntry(LockEntry *pLockEntry);
- static void RecycleLockEntry(LockEntry *pLockEntry);
-
- CLREvent* GetReaderEvent(HRESULT *pHR);
- CLREvent* GetWriterEvent(HRESULT *pHR);
- void ReleaseEvents();
-
- static LONG RWInterlockedCompareExchange(LONG RAW_KEYWORD(volatile) *pvDestination,
- LONG dwExchange,
- LONG dwComperand);
- static LONGLONG RWInterlockedCompareExchange64(LONGLONG RAW_KEYWORD(volatile) *pvDestination,
- LONGLONG qwExchange,
- LONGLONG qwComparand);
- static void* RWInterlockedCompareExchangePointer(PVOID RAW_KEYWORD(volatile) *pvDestination,
- PVOID pExchange,
- PVOID pComparand);
- static LONG RWInterlockedExchangeAdd(LONG RAW_KEYWORD(volatile) *pvDestination, LONG dwAddState);
- static LONG RWInterlockedIncrement(LONG RAW_KEYWORD(volatile) *pdwState);
-
- static DWORD RWWaitForSingleObject(CLREvent* event, DWORD dwTimeout);
- static void RWSetEvent(CLREvent* event);
- static void RWResetEvent(CLREvent* event);
- static void RWSleep(DWORD dwTime);
-
-#if defined(ENABLE_CONTRACTS_IMPL)
- // The LOCK_TAKEN/RELEASED macros need a "pointer" to the lock object to do
- // comparisons between takes & releases (and to provide debugging info to the
- // developer). We can't use "this" (*ppRWLock), because CRWLock is an Object and thus
- // can move. So we use _dwLLockID instead. It's not exactly unique, but it's
- // good enough--worst that can happen is if a thread takes RWLock A and erroneously
- // releases RWLock B (instead of A), we'll fail to catch that if their _dwLLockID's
- // are the same. On 64 bits, we can use both _dwULockID & _dwLLockID and be unique
- static void * GetPtrForLockContract(CRWLock ** ppRWLock)
- {
-#if defined(_WIN64)
- return (void *)
- (
- (
- ((__int64) ((*ppRWLock)->_dwULockID)) << 32
- )
- |
- (
- (__int64) ((*ppRWLock)->_dwLLockID)
- )
- );
-#else //defined(_WIN64)
- return LongToPtr((*ppRWLock)->_dwLLockID);
-#endif //defined(_WIN64)
- }
-#endif //defined(ENABLE_CONTRACTS_IMPL)
-
- // private new
- static void *operator new(size_t size, void *pv) { LIMITED_METHOD_CONTRACT; return(pv); }
-
- // Private data
- CLREvent *_hWriterEvent;
- CLREvent *_hReaderEvent;
- OBJECTHANDLE _hObjectHandle;
- Volatile<LONG> _dwState;
- LONG _dwULockID;
- LONG _dwLLockID;
- DWORD _dwWriterID;
- DWORD _dwWriterSeqNum;
- WORD _wWriterLevel;
-#ifdef RWLOCK_STATISTICS
- // WARNING: You must explicitly #define RWLOCK_STATISTICS when you build
- // in both the VM and BCL directories, as the managed class must also
- // contain these fields!
- Volatile<LONG> _dwReaderEntryCount;
- Volatile<LONG> _dwReaderContentionCount;
- Volatile<LONG> _dwWriterEntryCount;
- Volatile<LONG> _dwWriterContentionCount;
- Volatile<LONG> _dwEventsReleasedCount;
-#endif
-
- // Static data
- static Volatile<LONGLONG> s_mostRecentLockID;
- static CrstStatic s_RWLockCrst;
-};
-
-#ifdef USE_CHECKED_OBJECTREFS
-typedef REF<CRWLock> RWLOCKREF;
-
-#else
-typedef CRWLock* RWLOCKREF;
-#endif
-
#endif // _RWLOCK_H_
#endif // FEATURE_RWLOCK
diff --git a/src/vm/securitymeta.cpp b/src/vm/securitymeta.cpp
index 7027c47c83..7cc8b65426 100644
--- a/src/vm/securitymeta.cpp
+++ b/src/vm/securitymeta.cpp
@@ -29,7 +29,6 @@
#include "threads.h"
#include "eventtrace.h"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#include "objectclone.h"
#endif //FEATURE_REMOTING
#include "typestring.h"
diff --git a/src/vm/securitystackwalk.h b/src/vm/securitystackwalk.h
index 3aaf9b5084..f59c958145 100644
--- a/src/vm/securitystackwalk.h
+++ b/src/vm/securitystackwalk.h
@@ -19,7 +19,6 @@
#include "security.h"
#include "holder.h"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#endif
class ApplicationSecurityDescriptor;
diff --git a/src/vm/stackbuildersink.cpp b/src/vm/stackbuildersink.cpp
deleted file mode 100644
index 2e363f2802..0000000000
--- a/src/vm/stackbuildersink.cpp
+++ /dev/null
@@ -1,702 +0,0 @@
-// 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.
-//
-// File: StackBuilderSink.cpp
-//
-
-//
-// Purpose: Native implementation for System.Runtime.Remoting.Messaging.StackBuilderSink
-//
-
-
-#include "common.h"
-
-#ifdef FEATURE_REMOTING
-
-#include "excep.h"
-#include "message.h"
-#include "stackbuildersink.h"
-#include "dbginterface.h"
-#include "remoting.h"
-#include "profilepriv.h"
-#include "class.h"
-
-struct ArgInfo
-{
- PBYTE dataLocation;
- INT32 dataSize;
- TypeHandle dataTypeHandle;
- BYTE dataType;
- BYTE byref;
-};
-
-
-//+----------------------------------------------------------------------------
-//
-// Method: CStackBuilderSink::PrivateProcessMessage, public
-//
-// Synopsis: Builds the stack and calls an object
-//
-//
-//+----------------------------------------------------------------------------
-FCIMPL5(Object*, CStackBuilderSink::PrivateProcessMessage,
- Object* pSBSinkUNSAFE,
- MethodDesc* pMD,
- PTRArray* pArgsUNSAFE,
- Object* pServerUNSAFE,
- PTRARRAYREF* ppVarOutParams)
-{
- CONTRACTL
- {
- FCALL_CHECK;
- PRECONDITION(CheckPointer(pMD));
- PRECONDITION(!pMD->IsGenericMethodDefinition());
- PRECONDITION(pMD->IsRuntimeMethodHandle());
- }
- CONTRACTL_END;
-
- struct _gc
- {
- PTRARRAYREF pArgs;
- OBJECTREF pServer;
- OBJECTREF pSBSink;
- OBJECTREF ret;
- } gc;
- gc.pArgs = (PTRARRAYREF) pArgsUNSAFE;
- gc.pServer = (OBJECTREF) pServerUNSAFE;
- gc.pSBSink = (OBJECTREF) pSBSinkUNSAFE;
- gc.ret = NULL;
-
- HELPER_METHOD_FRAME_BEGIN_RET_PROTECT(gc);
-
- // pMD->IsStatic() is SO_INTOLERANT.
- // Either pServer is non-null or the method is static (but not both)
- _ASSERTE( (pServerUNSAFE!=NULL) == !(pMD->IsStatic()) );
-
- LOG((LF_REMOTING, LL_INFO10, "CStackBuilderSink::PrivateProcessMessage\n"));
-
- MethodDesc *pResolvedMD = pMD;
- // Check if this is an interface invoke, if yes, then we have to find the
- // real method descriptor on the class of the server object.
- if(pMD->GetMethodTable()->IsInterface())
- {
- _ASSERTE(gc.pServer != NULL);
-
- // NOTE: This method can trigger GC
- // The last parameter (true) causes the method to take into account that
- // the object passed in is a TP and try to resolve the interface MD into
- // a server MD anyway (normally the call short circuits thunking objects
- // and just returns the interface MD unchanged).
- MethodTable *pRealMT = gc.pServer->GetTrueMethodTable();
-
-#ifdef FEATURE_COMINTEROP
- if (pRealMT->IsComObjectType())
- pResolvedMD = pRealMT->GetMethodDescForComInterfaceMethod(pMD, true);
- else
-#endif // FEATURE_COMINTEROP
- {
- if (pRealMT->ImplementsInterface(pMD->GetMethodTable()))
- {
- pResolvedMD = pRealMT->GetMethodDescForInterfaceMethod(TypeHandle(pMD->GetMethodTable()), pMD);
-
- // If the method is generic then we have more work to do --
- // we'll get back the generic method descriptor and we'll have
- // to load the version with the right instantiation (get the
- // instantiation from the interface method).
- if (pResolvedMD->HasMethodInstantiation())
- {
- _ASSERTE(pResolvedMD->IsGenericMethodDefinition());
- _ASSERTE(pMD->GetNumGenericMethodArgs() == pResolvedMD->GetNumGenericMethodArgs());
-
- pResolvedMD = MethodDesc::FindOrCreateAssociatedMethodDesc(pResolvedMD,
- pRealMT,
- FALSE,
- pMD->GetMethodInstantiation(),
- FALSE);
-
- _ASSERTE(!pResolvedMD->ContainsGenericVariables());
- }
- }
- else
- pResolvedMD = NULL;
- }
-
- if(!pResolvedMD)
- {
- MAKE_WIDEPTR_FROMUTF8(wName, pMD->GetName());
- COMPlusThrow(kMissingMethodException, IDS_EE_MISSING_METHOD, wName);
- }
- }
-
- // <TODO>This looks a little dodgy for generics: pResolvedMD has been interface-resolved but not
- // virtual-resolved. So we seem to be taking the signature of a
- // half-resolved-virtual-call. But the MetaSig
- // is only used for GC purposes, and thus is probably OK: although the
- // metadata for the signature of a call may be different
- // as we move to base classes, the instantiated version
- // of the signature will still be the same
- // at both the callsite and the target). </TODO>
- MetaSig mSig(pResolvedMD);
-
- // get the target depending on whether the method is virtual or non-virtual
- // like a constructor, private or final method
- PCODE pTarget = pResolvedMD->GetCallTarget(&(gc.pServer));
-
- VASigCookie *pCookie = NULL;
- _ASSERTE(NULL != pTarget);
-
- // this function does the work
- ::CallDescrWithObjectArray(
- gc.pServer,
- pResolvedMD,
- //pRM,
- pTarget,
- &mSig,
- pCookie,
- gc.pArgs,
- &gc.ret,
- ppVarOutParams);
-
- LOG((LF_REMOTING, LL_INFO10, "CStackBuilderSink::PrivateProcessMessage OUT\n"));
-
- HELPER_METHOD_FRAME_END();
-
- return OBJECTREFToObject(gc.ret);
-}
-FCIMPLEND
-
-class ProfilerServerCallbackHolder
-{
-public:
- ProfilerServerCallbackHolder(Thread* pThread) : m_pThread(pThread)
- {
-#ifdef PROFILING_SUPPORTED
- // If we're profiling, notify the profiler that we're about to invoke the remoting target
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationStarted();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
- }
-
- ~ProfilerServerCallbackHolder()
- {
-#ifdef PROFILING_SUPPORTED
- // If profiling is active, tell profiler we've made the call, received the
- // return value, done any processing necessary, and now remoting is done.
- {
- BEGIN_PIN_PROFILER(CORProfilerTrackRemoting());
- GCX_PREEMP();
- g_profControlBlock.pProfInterface->RemotingServerInvocationReturned();
- END_PIN_PROFILER();
- }
-#endif // PROFILING_SUPPORTED
- }
-
-private:
- Thread* m_pThread;
-};
-
-//+----------------------------------------------------------------------------
-//
-// Function: CallDescrWithObjectArray, private
-//
-// Synopsis: Builds the stack from a object array and call the object
-//
-//
-// Note this function triggers GC and assumes that pServer, pArguments, pVarRet, and ppVarOutParams are
-// all already protected!!
-//+----------------------------------------------------------------------------
-void CallDescrWithObjectArray(OBJECTREF& pServer,
- //ReflectMethod *pRM,
- MethodDesc *pMeth,
- PCODE pTarget,
- MetaSig* sig,
- VASigCookie *pCookie,
- PTRARRAYREF& pArgArray,
- OBJECTREF *pVarRet,
- PTRARRAYREF *ppVarOutParams)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- INJECT_FAULT(COMPlusThrowOM());
- }
- CONTRACTL_END;
-
- LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray IN\n"));
-
-#ifdef _PREFAST_
-#pragma warning(push)
-#pragma warning(disable:6263) // "Suppress PREFast warning about _alloca in a loop"
- // _alloca is called within a loop in a number of places within this method
- // (as an ultra fast means of acquiring temporary storage). This can be a
- // problem in some scenarios (swiftly drive us to stack overflow). But in
- // this case the allocations are tightly bounded (by the number of arguments
- // in the target method) and the allocations themselves are small (no worse
- // really than calling the method an extra time).
-#endif
-
- ByRefInfo *pByRefs = NULL;
- FrameWithCookie<ProtectValueClassFrame> *pProtectValueClassFrame = NULL;
- FrameWithCookie<ProtectByRefsFrame> *pProtectionFrame = NULL;
- UINT nStackBytes = 0;
- LPBYTE pAlloc = 0;
- LPBYTE pTransitionBlock = 0;
- UINT32 numByRef = 0;
- //DWORD attr = pRM->dwFlags;
-#ifdef _DEBUG
- //MethodDesc *pMD = pRM->pMethod;
-#endif
- ValueClassInfo *pValueClasses = NULL;
-
- // check the calling convention
-
- BYTE callingconvention = sig->GetCallingConvention();
- if (!isCallConv(callingconvention, IMAGE_CEE_CS_CALLCONV_DEFAULT))
- {
- _ASSERTE(!"This calling convention is not supported.");
- COMPlusThrow(kInvalidProgramException);
- }
-
- // Make sure we are properly loaded
- CONSISTENCY_CHECK(GetAppDomain()->CheckCanExecuteManagedCode(pMeth));
-
- // Note this is redundant with the above but we do it anyway for safety
- pMeth->EnsureActive();
-
-#ifdef DEBUGGING_SUPPORTED
- // debugger goo What does this do? can someone put a comment here?
- if (CORDebuggerTraceCall())
- {
- g_pDebugInterface->TraceCall((const BYTE *)pTarget);
- }
-#endif // DEBUGGING_SUPPORTED
-
- Thread * pThread = GetThread();
-
- {
- ProfilerServerCallbackHolder profilerHolder(pThread);
-
- ArgIterator argit(sig);
-
- // Create a fake FramedMethodFrame on the stack.
- nStackBytes = argit.SizeOfFrameArgumentArray();
-
- UINT32 cbAlloc = 0;
- if (!ClrSafeInt<UINT32>::addition(TransitionBlock::GetNegSpaceSize(), sizeof(TransitionBlock), cbAlloc))
- COMPlusThrow(kArgumentException);
- if (!ClrSafeInt<UINT32>::addition(cbAlloc, nStackBytes, cbAlloc))
- COMPlusThrow(kArgumentException);
-
- pAlloc = (LPBYTE)_alloca(cbAlloc);
- pTransitionBlock = pAlloc + TransitionBlock::GetNegSpaceSize();
-
- // cycle through the parameters and see if there are byrefs
- BOOL fHasByRefs = FALSE;
-
- //if (attr & RM_ATTR_BYREF_FLAG_SET)
- // fHasByRefs = attr & RM_ATTR_HAS_BYREF_ARG;
- //else
- {
- sig->Reset();
- CorElementType typ;
- while ((typ = sig->NextArg()) != ELEMENT_TYPE_END)
- {
- if (typ == ELEMENT_TYPE_BYREF)
- {
- fHasByRefs = TRUE;
- //attr |= RM_ATTR_HAS_BYREF_ARG;
- break;
- }
- }
- //attr |= RM_ATTR_BYREF_FLAG_SET;
- //pRM->dwFlags = attr;
- sig->Reset();
- }
-
- UINT32 nFixedArgs = sig->NumFixedArgs();
- // To avoid any security problems with integer overflow/underflow we're
- // going to validate the number of args here (we're about to _alloca an
- // array of ArgInfo structures and maybe a managed object array as well
- // based on this count).
- _ASSERTE(sizeof(Object*) <= sizeof(ArgInfo));
- UINT32 nMaxArgs = UINT32_MAX / sizeof(ArgInfo);
- if (nFixedArgs > nMaxArgs)
- COMPlusThrow(kArgumentException);
-
- // if there are byrefs allocate and array for the out parameters
- if (fHasByRefs)
- {
- *ppVarOutParams = PTRARRAYREF(AllocateObjectArray(sig->NumFixedArgs(), g_pObjectClass));
-
- // Null out the array
- memset(&(*ppVarOutParams)->m_Array, 0, sizeof(OBJECTREF) * sig->NumFixedArgs());
- }
-
- OBJECTREF *ppThis = NULL;
-
- if (sig->HasThis())
- {
- ppThis = (OBJECTREF*)(pTransitionBlock + argit.GetThisOffset());
-
- // *ppThis is not GC protected. It will be set to the right value
- // after all object allocations are made.
- *ppThis = NULL;
- }
-
- // if we have the Value Class return, we need to allocate that class and place a pointer to it on the stack.
-
- *pVarRet = NULL;
- TypeHandle retType = sig->GetRetTypeHandleThrowing();
- // Note that we want the unnormalized (signature) type because GetStackObject
- // boxes as the element type, which if we normalized it would loose information.
- CorElementType retElemType = sig->GetReturnType();
-
- // The MethodTable pointer of the return type, if that's a struct
- MethodTable* pStructRetTypeMT = NULL;
-
- // Allocate a boxed struct instance to hold the return value in any case.
- if (retElemType == ELEMENT_TYPE_VALUETYPE)
- {
- pStructRetTypeMT = retType.GetMethodTable();
- *pVarRet = pStructRetTypeMT->Allocate();
- }
- else {
- _ASSERTE(!argit.HasRetBuffArg());
- }
-
-#ifdef CALLDESCR_REGTYPEMAP
- UINT64 dwRegTypeMap = 0;
- BYTE* pMap = (BYTE*)&dwRegTypeMap;
-#endif // CALLDESCR_REGTYPEMAP
-
-#ifdef CALLDESCR_FPARGREGS
- FloatArgumentRegisters *pFloatArgumentRegisters = NULL;
-#endif // CALLDESCR_FPARGREGS
-
- // gather data about the parameters by iterating over the sig:
- UINT32 arg = 0;
- int ofs = 0;
-
- // REVIEW: need to use actual arg count if VarArgs are supported
- ArgInfo* pArgInfoStart = (ArgInfo*) _alloca(nFixedArgs*sizeof(ArgInfo));
-
-#ifdef _DEBUG
- // We expect to write useful data over every part of this so need
- // not do this in retail!
- memset((void *)pArgInfoStart, 0, sizeof(ArgInfo)*nFixedArgs);
-#endif
-
- for (; TransitionBlock::InvalidOffset != (ofs = argit.GetNextOffset()); arg++)
- {
- CONSISTENCY_CHECK(arg < nFixedArgs);
- ArgInfo* pArgInfo = pArgInfoStart + arg;
-
-#ifdef CALLDESCR_REGTYPEMAP
- FillInRegTypeMap(ofs, argit.GetArgType(), pMap);
-#endif
-
-#ifdef CALLDESCR_FPARGREGS
- // Under CALLDESCR_FPARGREGS we can have arguments in floating point registers. If we have at
- // least one such argument we point the call worker at the floating point area of the frame (we leave
- // it null otherwise since the worker can perform a useful optimization if it knows no floating point
- // registers need to be set up).
- if (TransitionBlock::HasFloatRegister(ofs, argit.GetArgLocDescForStructInRegs()) &&
- (pFloatArgumentRegisters == NULL))
- {
- pFloatArgumentRegisters = (FloatArgumentRegisters*)(pTransitionBlock +
- TransitionBlock::GetOffsetOfFloatArgumentRegisters());
- }
-#endif
-
- if (argit.GetArgType() == ELEMENT_TYPE_BYREF)
- {
- TypeHandle ty = TypeHandle();
- CorElementType brType = sig->GetByRefType(&ty);
- if (CorIsPrimitiveType(brType))
- {
- pArgInfo->dataSize = gElementTypeInfo[brType].m_cbSize;
- }
- else if (ty.IsValueType())
- {
- pArgInfo->dataSize = ty.GetMethodTable()->GetNumInstanceFieldBytes();
- numByRef ++;
- }
- else
- {
- pArgInfo->dataSize = sizeof(Object *);
- numByRef ++;
- }
-
- ByRefInfo *brInfo = (ByRefInfo *) _alloca(offsetof(ByRefInfo,data) + pArgInfo->dataSize);
- brInfo->argIndex = arg;
- brInfo->typ = brType;
- brInfo->typeHandle = ty;
- brInfo->pNext = pByRefs;
- pByRefs = brInfo;
- pArgInfo->dataLocation = (BYTE*)brInfo->data;
- *((void**)(pTransitionBlock + ofs)) = (void*)pArgInfo->dataLocation;
- pArgInfo->dataTypeHandle = ty;
- pArgInfo->dataType = static_cast<BYTE>(brType);
- pArgInfo->byref = TRUE;
- }
- else
- {
- pArgInfo->dataLocation = pTransitionBlock + ofs;
- pArgInfo->dataSize = argit.GetArgSize();
- pArgInfo->dataTypeHandle = sig->GetLastTypeHandleThrowing(); // this may cause GC!
- pArgInfo->dataType = (BYTE)argit.GetArgType();
- pArgInfo->byref = FALSE;
- }
- }
-
-
- if (ppThis)
- {
- // If this isn't a value class, verify the objectref
-#ifdef _DEBUG
- //if (pMD->GetMethodTable()->IsValueType() == FALSE)
- //{
- // VALIDATEOBJECTREF(pServer);
- //}
-#endif //_DEBUG
- *ppThis = pServer;
- }
-
- PVOID pRetBufStackData = NULL;
-
- if (argit.HasRetBuffArg())
- {
- // If the return buffer *must* be a stack-allocated object, allocate it.
- PVOID pRetBufData = NULL;
- if (pStructRetTypeMT->IsStructRequiringStackAllocRetBuf())
- {
- SIZE_T sz = pStructRetTypeMT->GetNumInstanceFieldBytes();
- pRetBufData = pRetBufStackData = _alloca(sz);
- memset(pRetBufData, 0, sz);
- pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pRetBufStackData, pStructRetTypeMT, pValueClasses);
- }
- else
- {
- pRetBufData = (*pVarRet)->GetData();
- }
- *((LPVOID*) (pTransitionBlock + argit.GetRetBuffArgOffset())) = pRetBufData;
- }
-
- // There should be no GC when we fill up the stack with parameters, as we don't protect them
- // Assignment of "*ppThis" above triggers the point where we become unprotected.
- {
- GCX_FORBID();
-
- PBYTE dataLocation;
- INT32 dataSize;
- TypeHandle dataTypeHandle;
- BYTE dataType;
-
- OBJECTREF* pArguments = pArgArray->m_Array;
- UINT32 i;
- for (i=0; i<nFixedArgs; i++)
- {
- ArgInfo* pArgInfo = pArgInfoStart + i;
-
- dataSize = pArgInfo->dataSize;
- dataLocation = pArgInfo->dataLocation;
- dataTypeHandle = pArgInfo->dataTypeHandle;
- dataType = pArgInfo->dataType;
-
- // Nullable<T> needs special treatment, even if it is 1, 2, 4, or 8 bytes
- if (dataType == ELEMENT_TYPE_VALUETYPE)
- goto DEFAULT_CASE;
-
- switch (dataSize)
- {
- case 1:
- // This "if" statement is necessary to make the assignement big-endian aware
- if (pArgInfo->byref)
- *((INT8*)dataLocation) = *((INT8*)pArguments[i]->GetData());
- else
- *(StackElemType*)dataLocation = (StackElemType)*((INT8*)pArguments[i]->GetData());
- break;
- case 2:
- // This "if" statement is necessary to make the assignement big-endian aware
- if (pArgInfo->byref)
- *((INT16*)dataLocation) = *((INT16*)pArguments[i]->GetData());
- else
- *(StackElemType*)dataLocation = (StackElemType)*((INT16*)pArguments[i]->GetData());
- break;
- case 4:
-#ifndef _WIN64
- if ((dataType == ELEMENT_TYPE_STRING) ||
- (dataType == ELEMENT_TYPE_OBJECT) ||
- (dataType == ELEMENT_TYPE_CLASS) ||
- (dataType == ELEMENT_TYPE_SZARRAY) ||
- (dataType == ELEMENT_TYPE_ARRAY))
- {
- *(OBJECTREF *)dataLocation = pArguments[i];
- }
- else
- {
- *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData());
- }
-#else // !_WIN64
- // This "if" statement is necessary to make the assignement big-endian aware
- if (pArgInfo->byref)
- *(INT32*)dataLocation = *((INT32*)pArguments[i]->GetData());
- else
- *(StackElemType*)dataLocation = (StackElemType)*((INT32*)pArguments[i]->GetData());
-#endif // !_WIN64
- break;
-
- case 8:
-#ifdef _WIN64
- if ((dataType == ELEMENT_TYPE_STRING) ||
- (dataType == ELEMENT_TYPE_OBJECT) ||
- (dataType == ELEMENT_TYPE_CLASS) ||
- (dataType == ELEMENT_TYPE_SZARRAY) ||
- (dataType == ELEMENT_TYPE_ARRAY))
- {
- *(OBJECTREF *)dataLocation = pArguments[i];
- }
- else
- {
- *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData());
- }
-#else // _WIN64
- *((INT64*)dataLocation) = *((INT64*)pArguments[i]->GetData());
-#endif // _WIN64
- break;
-
- default:
- {
- DEFAULT_CASE:
- MethodTable * pMT = dataTypeHandle.GetMethodTable();
-
-#ifdef ENREGISTERED_PARAMTYPE_MAXSIZE
- // We do not need to allocate a buffer if the argument is already passed by reference.
- if (!pArgInfo->byref && ArgIterator::IsArgPassedByRef(dataTypeHandle))
- {
- PVOID pvArg = _alloca(dataSize);
- pMT->UnBoxIntoUnchecked(pvArg, pArguments[i]);
- *(PVOID*)dataLocation = pvArg;
-
- pValueClasses = new (_alloca(sizeof(ValueClassInfo))) ValueClassInfo(pvArg, pMT, pValueClasses);
- }
- else
-#endif
- {
- pMT->UnBoxIntoUnchecked(dataLocation, pArguments[i]);
- }
- }
- }
- }
-
-#ifdef _DEBUG
- // Should not be using this any more
- memset((void *)pArgInfoStart, 0, sizeof(ArgInfo)*nFixedArgs);
-#endif
-
- // if there were byrefs, push a protection frame
- if (pByRefs && numByRef > 0)
- {
- char *pBuffer = (char*)_alloca (sizeof (FrameWithCookie<ProtectByRefsFrame>));
- pProtectionFrame = new (pBuffer) FrameWithCookie<ProtectByRefsFrame>(pThread, pByRefs);
- }
-
- // If there were any value classes that must be protected by the
- // caller, push a ProtectValueClassFrame.
- if (pValueClasses)
- {
- char *pBuffer = (char*)_alloca (sizeof (FrameWithCookie<ProtectValueClassFrame>));
- pProtectValueClassFrame = new (pBuffer) FrameWithCookie<ProtectValueClassFrame>(pThread, pValueClasses);
- }
-
- } // GCX_FORBID
-
- UINT fpReturnSize = argit.GetFPReturnSize();
-
- CallDescrData callDescrData;
-
- callDescrData.pSrc = pTransitionBlock + sizeof(TransitionBlock);
- callDescrData.numStackSlots = nStackBytes / STACK_ELEM_SIZE;
-#ifdef CALLDESCR_ARGREGS
- callDescrData.pArgumentRegisters = (ArgumentRegisters*)(pTransitionBlock + TransitionBlock::GetOffsetOfArgumentRegisters());
-#endif
-#ifdef CALLDESCR_FPARGREGS
- callDescrData.pFloatArgumentRegisters = pFloatArgumentRegisters;
-#endif
-#ifdef CALLDESCR_REGTYPEMAP
- callDescrData.dwRegTypeMap = dwRegTypeMap;
-#endif
- callDescrData.fpReturnSize = fpReturnSize;
- callDescrData.pTarget = pTarget;
-
- CallDescrWorkerWithHandler(&callDescrData);
-
- // It is still illegal to do a GC here. The return type might have/contain GC pointers.
- if (retElemType == ELEMENT_TYPE_VALUETYPE)
- {
- _ASSERTE(*pVarRet != NULL); // we have already allocated a return object
- PVOID pVarRetData = (*pVarRet)->GetData();
-
- // If the return result was passed back in registers, then copy it into the return object
- if (!argit.HasRetBuffArg())
- {
- CopyValueClass(pVarRetData, &callDescrData.returnValue, (*pVarRet)->GetMethodTable(), (*pVarRet)->GetAppDomain());
- }
- else if (pRetBufStackData != NULL)
- {
- // Copy the stack-allocated ret buff to the heap-allocated one.
- CopyValueClass(pVarRetData, pRetBufStackData, (*pVarRet)->GetMethodTable(), (*pVarRet)->GetAppDomain());
- }
-
- // If the return is a Nullable<T>, box it using Nullable<T> conventions.
- // TODO: this double allocates on constructions which is wasteful
- if (!retType.IsNull())
- *pVarRet = Nullable::NormalizeBox(*pVarRet);
- }
- else
- CMessage::GetObjectFromStack(pVarRet, &callDescrData.returnValue, retElemType, retType);
-
- // You can now do GCs if you want to
-
- if (pProtectValueClassFrame)
- pProtectValueClassFrame->Pop(pThread);
-
- // extract the out args from the byrefs
- if (pByRefs)
- {
- do
- {
- // Always extract the data ptr every time we enter this loop because
- // calls to GetObjectFromStack below can cause a GC.
- // Even this is not enough, because that we are passing a pointer to GC heap
- // to GetObjectFromStack . If GC happens, nobody is protecting the passed in pointer.
-
- OBJECTREF pTmp = NULL;
- void* dataLocation = pByRefs->data;
- CMessage::GetObjectFromStack(&pTmp, &dataLocation, pByRefs->typ, pByRefs->typeHandle, TRUE);
- (*ppVarOutParams)->SetAt(pByRefs->argIndex, pTmp);
- pByRefs = pByRefs->pNext;
- }
- while (pByRefs);
-
- if (pProtectionFrame)
- pProtectionFrame->Pop(pThread);
- }
-
- } // ProfilerServerCallbackHolder
-
-#ifdef _PREFAST_
-#pragma warning(pop)
-#endif
-
- LOG((LF_REMOTING, LL_INFO10, "CallDescrWithObjectArray OUT\n"));
-}
-
-#endif // FEATURE_REMOTING
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index 791a09fc42..81bf023568 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -31,7 +31,6 @@
#include "appdomainstack.inl"
#include "eventtrace.h"
#ifdef FEATURE_REMOTING
-#include "appdomainhelper.h"
#endif
#include "comutilnative.h"
#include "finalizerthread.h"
diff --git a/src/vm/validator.cpp b/src/vm/validator.cpp
deleted file mode 100644
index 54f6ecdb2b..0000000000
--- a/src/vm/validator.cpp
+++ /dev/null
@@ -1,946 +0,0 @@
-// 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.
-
-
-/*
- *
- * Purpose: Provide IValidate implementation.
- * IValidate is used to validate PE stub, Metadata and IL.
- *
- */
-
-#include "common.h"
-
-#include "corerror.h"
-#include "vererror.h"
-#include "ivalidator.h"
-#include "securityattributes.h"
-#include "corhost.h"
-#include "verifier.hpp"
-#include "pedecoder.h"
-#include "comcallablewrapper.h"
-#include "../dlls/mscorrc/resource.h"
-#include "posterror.h"
-#include "comcallablewrapper.h"
-#include "eeconfig.h"
-#include "corhost.h"
-#include "security.h"
-#include "appdomain.inl"
-
-typedef void (*VerifyErrorHandler)(void* pThis, HRESULT hrError, struct VerErrorStruct* pError);
-
-// Declare global variables
-#define DECLARE_DATA
-#include "veropcodes.hpp"
-#undef DECLARE_DATA
-
-class CValidator
-{
-public:
- CValidator(IVEHandler *veh) : m_veh(veh)
- {
- LIMITED_METHOD_CONTRACT;
- }
- HRESULT VerifyAllMethodsForClass(Module *pModule, mdTypeDef cl, ValidateWorkerArgs* pArgs);
- HRESULT VerifyAllGlobalFunctions(Module *pModule, ValidateWorkerArgs* pArgs);
- HRESULT VerifyAssembly(Assembly *pAssembly, ValidateWorkerArgs* pArgs);
- HRESULT VerifyModule(Module* pModule, ValidateWorkerArgs* pArgs);
- HRESULT ReportError(HRESULT hr, ValidateWorkerArgs* pArgs, mdToken tok=0);
- HRESULT VerifyMethod(COR_ILMETHOD_DECODER* pILHeader, IVEHandler* pVEHandler, WORD wFlags, ValidateWorkerArgs* pArgs);
- HRESULT VerifyExportedType(
- Module * pModule,
- mdToken tkExportedType,
- ValidateWorkerArgs * pArgs);
- void HandleError(HRESULT hrError, struct VerErrorStruct* pError);
-
-private:
- IVEHandler *m_veh;
- ValidateWorkerArgs* m_pArgs;
-}; // class CValidator
-
-HRESULT CValidator::ReportError(HRESULT hr, ValidateWorkerArgs* pArgs, mdToken tok /* = 0 */)
-{
- CONTRACTL {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- } CONTRACTL_END;
-
- if (m_veh == NULL)
- return hr;
-
- HRESULT hr2 = E_FAIL;
- BEGIN_SO_INTOLERANT_CODE_NOTHROW(GetThread(), return COR_E_STACKOVERFLOW);
- VEContext vec;
-
- memset(&vec, 0, sizeof(VEContext));
-
- if (tok != 0)
- {
- vec.flags = VER_ERR_TOKEN;
- vec.Token = tok;
- }
-
- hr2 = Verifier::ReportError(m_veh, hr, &vec, pArgs);
- END_SO_INTOLERANT_CODE;
- return hr2;
-} // CValidator::ReportError
-
-// Separate method since EX_TRY uses _alloca and is in a loop below.
-COR_ILMETHOD* GetILHeader(MethodDesc *pMD)
-{
- STANDARD_VM_CONTRACT;
-
- COR_ILMETHOD *pILHeader = NULL;
-
- EX_TRY
- {
- pILHeader = pMD->GetILHeader();
- }
- EX_CATCH
- {
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- return pILHeader;
-}
-
-HRESULT CValidator::VerifyAllMethodsForClass(Module *pModule, mdTypeDef cl, ValidateWorkerArgs* pArgs)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr = S_OK;
- MethodTable *pMT = NULL;
-
- // In the case of COR_GLOBAL_PARENT_TOKEN (i.e. global functions), it is guaranteed
- // that the module has a method table or our caller will have skipped this step.
- TypeHandle th;
- {
- // <REVISIT>
- // Although there's no assert to disable here, we need to improve OOM reliability here. We are ignoring the HRESULT from the loader here.
- // That could cause an OOM failure to be disguised as something else. OOM's
- // need to be handled or propagated up to the caller.
- // </REVISIT>
- CONTRACT_VIOLATION(0);
-
- EX_TRY {
- th = ClassLoader::LoadTypeDefOrRefThrowing(pModule, cl,
- ClassLoader::ReturnNullIfNotFound,
- ClassLoader::PermitUninstDefOrRef);
- }
- EX_CATCH_HRESULT(hr);
-
- if (FAILED(hr)) {
- if ((hr==COR_E_TYPELOAD) || (hr==VER_E_TYPELOAD)) {
- hr = ReportError(hr, pArgs,cl);
- } else {
- hr = ReportError(hr, pArgs);
- }
- goto Exit;
- }
- }
-
- pMT = th.GetMethodTable();
- if (pMT == NULL)
- {
- hr = ReportError(VER_E_TYPELOAD, pArgs, cl);
- goto Exit;
- }
-
- g_fVerifierOff = false;
-
- {
- // Verify all methods in class - excluding inherited methods
- MethodTable::MethodIterator it(pMT);
- for (; it.IsValid(); it.Next())
- {
- pArgs->pMethodDesc = it.GetMethodDesc();
-
- bool fVerifyTransparentMethod = true;
- if (pArgs->fTransparentMethodsOnly)
- {
- MethodSecurityDescriptor msd(pArgs->pMethodDesc);
- fVerifyTransparentMethod = !msd.IsCritical();
- }
-
- if (pArgs->pMethodDesc &&
- pArgs->pMethodDesc->GetMethodTable() == pMT &&
- pArgs->pMethodDesc->IsIL() &&
- !pArgs->pMethodDesc->IsAbstract() &&
- !pArgs->pMethodDesc->IsUnboxingStub() &&
- fVerifyTransparentMethod)
- {
- COR_ILMETHOD* pILHeader = GetILHeader(pArgs->pMethodDesc);
-
- if (pILHeader != NULL)
- {
- COR_ILMETHOD_DECODER::DecoderStatus status;
- COR_ILMETHOD_DECODER ILHeader(pILHeader,
- pArgs->pMethodDesc->GetMDImport(), &status);
-
- if (status == COR_ILMETHOD_DECODER::SUCCESS)
- {
- hr = VerifyMethod(&ILHeader, m_veh, VER_FORCE_VERIFY, pArgs);
- if (hr == VER_E_INTERNAL) // this probably means peverify.dll was missing
- {
- goto Exit;
- }
- }
- else if (status == COR_ILMETHOD_DECODER::VERIFICATION_ERROR)
- {
- hr = COR_E_VERIFICATION;
- }
- else if (status == COR_ILMETHOD_DECODER::FORMAT_ERROR)
- {
- hr = COR_E_BADIMAGEFORMAT;
- }
- else
- {
- _ASSERTE(!"Unhandled status from COR_ILMETHOD_DECODER");
- }
- }
- else
- {
- hr = COR_E_BADIMAGEFORMAT;
- }
-
- if (FAILED(hr))
- hr = ReportError(hr, pArgs);
-
- if (FAILED(hr))
- goto Exit;
- }
- // We should ideally have an API to yield to the host,
- // but this is not critical for Whidbey.
- if (CLRTaskHosted())
- ClrSleepEx(0, FALSE);
- }
- }
-
-Exit:
- pArgs->pMethodDesc = NULL;
- return hr;
-} // CValidator::VerifyAllMethodsForClass
-
-//---------------------------------------------------------------------------------------
-//
-void
-MethodDescAndCorILMethodDecoderToCorInfoMethodInfo(
- MethodDesc * ftn,
- COR_ILMETHOD_DECODER * ILHeader,
- CORINFO_METHOD_INFO * pMethodInfo)
-{
- STANDARD_VM_CONTRACT;
-
- pMethodInfo->ftn = CORINFO_METHOD_HANDLE(ftn);
- pMethodInfo->scope = CORINFO_MODULE_HANDLE(ftn->GetModule());
- pMethodInfo->ILCode = const_cast<BYTE*>(ILHeader->Code);
- pMethodInfo->ILCodeSize = ILHeader->GetCodeSize();
- pMethodInfo->maxStack = ILHeader->GetMaxStack();
- pMethodInfo->EHcount = ILHeader->EHCount();
- pMethodInfo->options =
- (CorInfoOptions)
- (((ILHeader->GetFlags() & CorILMethod_InitLocals) ? CORINFO_OPT_INIT_LOCALS : 0) |
- (ftn->AcquiresInstMethodTableFromThis() ? CORINFO_GENERICS_CTXT_FROM_THIS : 0) |
- (ftn->RequiresInstMethodTableArg() ? CORINFO_GENERICS_CTXT_FROM_METHODTABLE : 0) |
- (ftn->RequiresInstMethodDescArg() ? CORINFO_GENERICS_CTXT_FROM_METHODDESC : 0));
-
- PCCOR_SIGNATURE pSigToConvert;
- DWORD cbSigToConvert;
- ftn->GetSig(&pSigToConvert, &cbSigToConvert);
- CONSISTENCY_CHECK(NULL != pSigToConvert);
- // fetch the method signature
- CEEInfo::ConvToJitSig(
- pSigToConvert,
- cbSigToConvert,
- pMethodInfo->scope,
- mdTokenNil,
- &pMethodInfo->args,
- ftn,
- false);
-
- //@GENERICS:
- // Shared generic methods and shared methods on generic structs take an extra argument representing their instantiation
- if (ftn->RequiresInstArg())
- pMethodInfo->args.callConv = (CorInfoCallConv) (pMethodInfo->args.callConv | CORINFO_CALLCONV_PARAMTYPE);
-
- // method attributes and signature are consistant
- _ASSERTE(!!ftn->IsStatic() == ((pMethodInfo->args.callConv & CORINFO_CALLCONV_HASTHIS) == 0));
-
- // And its local variables
- CEEInfo::ConvToJitSig(
- ILHeader->LocalVarSig,
- ILHeader->cbLocalVarSig,
- pMethodInfo->scope,
- mdTokenNil,
- &pMethodInfo->locals,
- ftn,
- true);
-} // MethodDescAndCorILMethodDecoderToCorInfoMethodInfo
-
-//---------------------------------------------------------------------------------------
-//
-void PEVerifyErrorHandler(void* pThis, HRESULT hrError, struct VerErrorStruct* pError)
-{
- WRAPPER_NO_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
- ((CValidator*)pThis)->HandleError(hrError, pError);
-}
-
-void CValidator::HandleError(HRESULT hrError, struct VerErrorStruct* pError)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- SO_TOLERANT;
- }
- CONTRACTL_END;
-
- BEGIN_SO_INTOLERANT_CODE(GetThread());
- _ASSERTE(sizeof(VEContext) == sizeof(struct VerErrorStruct));
- Verifier::ReportError(m_veh, hrError, (VEContext*)pError, m_pArgs);
- END_SO_INTOLERANT_CODE;
-}
-typedef void (__stdcall* VerifyFunc)(ICorJitInfo* pJitInfo, CORINFO_METHOD_INFO* pMethodInfo, VerifyErrorHandler pErrorHandler, void* pThis);
-static void VerifyMethodHelper(VerifyFunc pVerFunc, CEEJitInfo* pJI, CORINFO_METHOD_INFO* pMethodInfo, void* pThis)
-{
- // Helper method to allow us to use SO_TOLERANT_CODE macro
- STATIC_CONTRACT_SO_INTOLERANT;
- WRAPPER_NO_CONTRACT;
-
- BEGIN_SO_TOLERANT_CODE(GetThread());
- // Verify the method
- pVerFunc(pJI, pMethodInfo, PEVerifyErrorHandler, pThis);
- END_SO_TOLERANT_CODE;
-
-}
-
-static Volatile<VerifyFunc> g_pVerFunc = NULL;
-
-HRESULT CValidator::VerifyMethod(COR_ILMETHOD_DECODER* pILHeader, IVEHandler* pVEHandler, WORD wFlags, ValidateWorkerArgs* pArgs)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr = S_OK;
- EX_TRY
- {
- // Find the DLL entrypoint
- m_pArgs = pArgs;
- if (g_pVerFunc.Load() == NULL)
- {
- HINSTANCE hJit64 = NULL;
- if (SUCCEEDED(g_pCLRRuntime->LoadLibrary(W("peverify.dll"), &hJit64)))
- {
- typedef void (__stdcall* psxsPeVerifyStartup) (CoreClrCallbacks);
- psxsPeVerifyStartup sxsPeVerifyStartup = (psxsPeVerifyStartup) GetProcAddress(hJit64, "sxsPeVerifyStartup");
-
- if(sxsPeVerifyStartup)
- {
- CoreClrCallbacks cccallbacks = GetClrCallbacks();
- (*sxsPeVerifyStartup) (cccallbacks);
- g_pVerFunc = (VerifyFunc)GetProcAddress(hJit64, "VerifyMethod");
- }
- }
- }
-
- if(!g_pVerFunc)
- {
- _ASSERTE(!"Failed to load peverify.dll or find VerifyMethod proc address");
- hr = VER_E_INTERNAL;
- }
- else
- {
- Thread *pThread = GetThread();
- if (pThread->IsAbortRequested())
- {
- pThread->HandleThreadAbort();
- }
- // Prepare the args
- MethodDesc* ftn = pArgs->pMethodDesc;
- CEEJitInfo ji(pArgs->pMethodDesc, pILHeader, NULL, true /* verify only */);
- CORINFO_METHOD_INFO methodInfo;
- MethodDescAndCorILMethodDecoderToCorInfoMethodInfo(ftn, pILHeader, &methodInfo);
-
- // Verify the method
- VerifyMethodHelper(g_pVerFunc, &ji, &methodInfo, this);
- }
- }
- EX_CATCH
- {
- // Catch and report any errors that peverify.dll lets fall through (ideally that should never happen)
- hr = GET_EXCEPTION()->GetHR();
- hr = ReportError(hr, pArgs);
- }
- EX_END_CATCH(RethrowTerminalExceptions)
-
- return hr;
-} // CValidator::VerifyMethod
-
-// Helper function to verify the global functions
-HRESULT CValidator::VerifyAllGlobalFunctions(Module *pModule, ValidateWorkerArgs* pArgs)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr = S_OK;
- // Is there anything worth verifying?
- if (pModule->GetGlobalMethodTable())
- hr = VerifyAllMethodsForClass(pModule, COR_GLOBAL_PARENT_TOKEN, pArgs);
- return hr;
-} // CValidator::VerifyAllGlobalFunctions
-
-HRESULT CValidator::VerifyModule(Module* pModule, ValidateWorkerArgs* pArgs)
-{
- STANDARD_VM_CONTRACT;
-
- // Get a count of all the classdefs and enumerate them.
- HRESULT hr = S_OK;
- IMDInternalImport * pMDI = NULL;
-
- if (pModule == NULL)
- {
- IfFailGo(VER_E_BAD_MD);
- }
-
- pMDI = pModule->GetMDImport();
- if (pMDI == NULL)
- {
- IfFailGo(VER_E_BAD_MD);
- }
-
- // First verify all global functions - if there are any
- IfFailGoto(
- VerifyAllGlobalFunctions(pModule, pArgs),
- ErrExit_SkipReportError);
-
- {
- HENUMTypeDefInternalHolder hTypeDefEnum(pMDI);
-
- IfFailGo(hTypeDefEnum.EnumTypeDefInitNoThrow());
-
- // Verify all TypeDefs
- mdTypeDef tkTypeDef;
- while (pMDI->EnumTypeDefNext(&hTypeDefEnum, &tkTypeDef))
- {
- IfFailGoto(
- VerifyAllMethodsForClass(pModule, tkTypeDef, pArgs),
- ErrExit_SkipReportError);
- }
- }
-
- {
- HENUMInternalHolder hExportedTypeEnum(pMDI);
-
- IfFailGo(hExportedTypeEnum.EnumInitNoThrow(
- mdtExportedType,
- mdTokenNil));
-
- // Verify all ExportedTypes
- mdToken tkExportedType;
- while (pMDI->EnumNext(&hExportedTypeEnum, &tkExportedType))
- {
- IfFailGoto(
- VerifyExportedType(pModule, tkExportedType, pArgs),
- ErrExit_SkipReportError);
- }
- }
-
-ErrExit:
- if (FAILED(hr))
- {
- hr = ReportError(hr, pArgs);
- }
-
-ErrExit_SkipReportError:
- return hr;
-} // CValidator::VerifyModule
-
-HRESULT CValidator::VerifyAssembly(Assembly *pAssembly, ValidateWorkerArgs* pArgs)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr;
-
- _ASSERTE(pAssembly->GetManifestImport());
-
- // Verify the module containing the manifest. There is no
- // FileRefence so will no show up in the list.
- hr = VerifyModule(pAssembly->GetManifestModule(), pArgs);
- if (FAILED(hr))
- goto Exit;
-
- {
- IMDInternalImport* pManifestImport = pAssembly->GetManifestImport();
-
- HENUMInternalHolder hEnum(pManifestImport);
-
- mdToken mdFile;
- hr = hEnum.EnumInitNoThrow(mdtFile, mdTokenNil);
- if (FAILED(hr))
- {
- hr = ReportError(hr, pArgs);
- goto Exit;
- }
-
- while(pManifestImport->EnumNext(&hEnum, &mdFile))
- {
- DomainFile* pModule = pAssembly->GetManifestModule()->LoadModule(GetAppDomain(), mdFile, FALSE);
-
- if (pModule != NULL)
- {
- hr = VerifyModule(pModule->GetModule(), pArgs);
- if (FAILED(hr))
- goto Exit;
- }
- }
- }
-
-Exit:
- return hr;
-} // CValidator::VerifyAssembly
-
-HRESULT
-CValidator::VerifyExportedType(
- Module * pModule,
- mdToken tkExportedType,
- ValidateWorkerArgs * pArgs)
-{
- STANDARD_VM_CONTRACT;
-
- HRESULT hr;
- TypeHandle th;
- NameHandle nameHandle(pModule, tkExportedType);
-
- LPCSTR szNamespace;
- LPCSTR szName;
- IfFailGo(pModule->GetMDImport()->GetExportedTypeProps(
- tkExportedType,
- &szNamespace,
- &szName,
- NULL, // tkImplementation
- NULL, // tkTypeDefId
- NULL)); // dwExportedTypeFlags
-
- nameHandle.SetName(szNamespace, szName);
-
- EX_TRY
- {
- th = pModule->GetClassLoader()->LoadTypeHandleThrowing(
- &nameHandle,
- CLASS_LOADED,
- pModule);
- hr = S_OK;
- }
- EX_CATCH
- {
- hr = GET_EXCEPTION()->GetHR();
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- IfFailGo(hr);
- if (th.GetMethodTable() == NULL)
- {
- IfFailGo(VER_E_TYPELOAD);
- }
-
-ErrExit:
- if (FAILED(hr))
- {
- hr = ReportError(hr, pArgs, tkExportedType);
- }
-
- return hr;
-} // CValidator::VerifyExportedType
-
-static void ValidateWorker(LPVOID /* ValidateWorker_Args */ ptr)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- } CONTRACTL_END;
-
- ValidateWorkerArgs *args = (ValidateWorkerArgs *) ptr;
- AppDomain *pDomain = GetThread()->GetDomain();
-
- StackSString ssFile(args->wszFileName);
- StackSString ssFileDir;
- StackSString ssDirectory;
-
- // Fill ssDirectory with just drive of the file (e.g. 'C:')
- SplitPath(ssFile, &ssDirectory, &ssFileDir, NULL, NULL);
- // Now apped directory from the file name (incl. leading and trailing '/' or '\')
- ssDirectory.Append(ssFileDir);
-
- {
- // Set up the domain to resolve all dependency assemblies for introspection
- struct _gc {
- OBJECTREF orAppDomain;
- STRINGREF refDirectory;
- } gc;
- ZeroMemory(&gc, sizeof(gc));
-
- GCPROTECT_BEGIN(gc);
-
- gc.orAppDomain = pDomain->GetExposedObject();
- if (!ssDirectory.IsEmpty())
- {
- gc.refDirectory = StringObject::NewString(ssDirectory);
- }
-
- MethodDescCallSite meth(METHOD__APP_DOMAIN__ENABLE_RESOLVE_ASSEMBLIES_FOR_INTROSPECTION, &gc.orAppDomain);
- ARG_SLOT args[2] =
- {
- ObjToArgSlot(gc.orAppDomain),
- ObjToArgSlot(gc.refDirectory)
- };
- meth.Call(args);
-
- GCPROTECT_END();
- }
-
- GCX_PREEMP();
-
- Assembly *pAssembly;
- if (args->wszFileName)
- {
- // Load the primary assembly for introspection
- AssemblySpec spec;
- spec.SetCodeBase(args->wszFileName);
- spec.SetIntrospectionOnly(TRUE);
- pAssembly = spec.LoadAssembly(FILE_LOADED);
- }
- else
- {
- // TODO: This is a workaround to get SQLCLR running.
- // Our loader requires that a parent assembly is specified in order to load an
- // assembly from byte array. But here we do not know the parent.
- PEAssemblyHolder pFile(PEAssembly::OpenMemory(SystemDomain::System()->SystemFile(),
- args->pe, args->size, TRUE));
- pAssembly = pDomain->LoadAssembly(NULL, pFile, FILE_LOADED);
- }
-
- // Verify the assembly
- args->hr = args->val->VerifyAssembly(pAssembly, args);
-}
-
-
-static HRESULT ValidateHelper(
- IVEHandler *veh,
- IUnknown *pAppDomain,
- DWORD ulAppDomainId,
- BOOL UseId,
- unsigned long ulFlags,
- unsigned long ulMaxError,
- unsigned long token,
- __in_z LPWSTR fileName,
- BYTE *pe,
- unsigned long ulSize)
-{
- CONTRACTL {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- SO_TOLERANT;
- } CONTRACTL_END;
-
- Thread *pThread = GetThread();
-
- if (pe == NULL)
- return E_POINTER;
-
- HRESULT hr = S_OK;
- BEGIN_SO_INTOLERANT_CODE_NOTHROW(pThread, return COR_E_STACKOVERFLOW);
- ADID pDomain;
- ValidateWorkerArgs args;
- CValidator val(veh);
- AppDomainFromIDHolder ad;
-
- BOOL Chk = FALSE;
- BOOL UnloadDomain = FALSE;
-
- GCX_COOP();
-
- EX_TRY {
- PEDecoder pev(pe, (COUNT_T)ulSize);
-
- args.wszFileName = fileName;
- args.fVerbose = (ulFlags & VALIDATOR_EXTRA_VERBOSE) ? true : false;
- args.fShowSourceLines = (ulFlags & VALIDATOR_SHOW_SOURCE_LINES) ? true : false;
- args.fTransparentMethodsOnly = (ulFlags & VALIDATOR_TRANSPARENT_ONLY) ? true : false;
- args.val = &val;
- args.pe = pe;
- args.size = ulSize;
-
- if((ulFlags & VALIDATOR_NOCHECK_PEFORMAT) == 0)
- {
- // Verify the PE header / native stubs first
- // <REVISIT> This validation is not performed on non-manifest modules. </REVISIT>
- Chk = ((ulFlags & VALIDATOR_CHECK_ILONLY) != 0) ? (BOOL) pev.CheckILOnlyFormat() :
- (BOOL) pev.CheckILFormat();
- if (!Chk)
- {
- hr = val.ReportError(VER_E_BAD_PE, &args);
-
- if (FAILED(hr))
- goto End;
- }
- }
- if((ulFlags & VALIDATOR_CHECK_PEFORMAT_ONLY) != 0)
- goto End;
-
- if (fileName)
- {
- AppDomain* pAD = AppDomain::CreateDomainContext(fileName);
- UnloadDomain = TRUE;
- pAD->SetPassiveDomain();
- pDomain=pAD->GetId();
- }
- else if (UseId)
- {
- pDomain = (ADID)ulAppDomainId;
- }
- else
- {
- SystemDomain::LockHolder lh;
- ComCallWrapper* pWrap = GetCCWFromIUnknown(pAppDomain, FALSE);
- if (pWrap == NULL)
- {
- hr = COR_E_APPDOMAINUNLOADED;
- goto End;
- }
- pDomain = pWrap->GetDomainID();
- }
-
- if (FAILED(hr))
- {
- hr = val.ReportError(hr, &args);
- goto End;
- }
-
- ad.Assign(pDomain, TRUE);
- if (ad.IsUnloaded())
- COMPlusThrow(kAppDomainUnloadedException);
- if (ad->IsIllegalVerificationDomain())
- COMPlusThrow(kFileLoadException, IDS_LOADINTROSPECTION_DISALLOWED);
- ad->SetVerificationDomain();
- ad.Release();
-
- args.val = &val;
-
- // We need a file path here. This is to do a fusion bind, and also
- // to make sure we can find any modules in the assembly. We assume
- // that the path points to the same place the bytes came from, which is true
- // with PEVerify, but perhaps not with other clients.
-
- if (pDomain != pThread->GetDomain()->GetId())
- {
- pThread->DoADCallBack(
- pDomain, ValidateWorker, &args);
- }
- else
- {
- ValidateWorker(&args);
- }
-
- if (FAILED(args.hr))
- hr = val.ReportError(args.hr, &args);
-
- // Only Unload the domain if we created it.
- if (UnloadDomain)
- AppDomain::UnloadById(pDomain,TRUE);
-End:;
-
- }
- EX_CATCH
- {
- hr = GET_EXCEPTION()->GetHR();
- hr = val.ReportError(hr, &args);
- }
- EX_END_CATCH(RethrowSOExceptions)
-
- END_SO_INTOLERANT_CODE;
- return hr;
-}
-
-void GetFormattingErrorMsg(__out_ecount(ulMaxLength) __out_z LPWSTR msg, unsigned int ulMaxLength)
-{
- CONTRACTL {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(ulMaxLength >= 30);
- } CONTRACTL_END;
-
- EX_TRY
- {
- SString s;
- s.LoadResource(CCompRC::Debugging, IDS_VER_E_FORMATTING);
- wcsncpy_s(msg, ulMaxLength, s.GetUnicode(), _TRUNCATE);
- }
- EX_CATCH
- {
- wcscpy_s(msg, ulMaxLength, W("Error loading resource string"));
- }
- EX_END_CATCH(SwallowAllExceptions)
-}
-
-static HRESULT FormatEventInfoHelper(
- HRESULT hVECode,
- VEContext Context,
- __out_ecount(ulMaxLength) __out_z LPWSTR msg,
- unsigned int ulMaxLength,
- SAFEARRAY *psa)
-{
- CONTRACTL {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- PRECONDITION(ulMaxLength >= 30);
- SO_TOLERANT;
- } CONTRACTL_END;
-
- BEGIN_SO_INTOLERANT_CODE(GetThread());
-
- VerError err;
- memcpy(&err, &Context, sizeof(VerError));
-
- ValidateWorkerArgs argsDefault;
- ValidateWorkerArgs* pArgs = &argsDefault;
-
- // We passed a pointer to the ValidateWorkerArgs object through
- // the SAFEARRAY casted as a UINT because there was no room left in the
- // interface to pass information through it.
- {
- UINT dim;
- LONG l;
-#ifdef _WIN64
- VARTYPE vt;
-#endif // _WIN64
- VARIANT var;
-
- if(!psa) {
- goto lDone;
- }
-
- dim = SafeArrayGetDim(psa);
- if (dim != 1) {
- _ASSERTE(!"There should be one element in the SafeArray");
- goto lDone;
- }
-
- if (FAILED(SafeArrayGetLBound(psa, 1, &l))) {
- _ASSERTE(false);
- goto lDone;
- }
- if (l != 0) {
- _ASSERTE(!"expected the lower bound to be zero");
- goto lDone;
- }
-
- if (FAILED(SafeArrayGetUBound(psa, 1, &l))) {
- _ASSERTE(false);
- goto lDone;
- }
- if (l != 0) {
- _ASSERTE(!"expected the upper bound to be zero");
- goto lDone;
- }
-#ifdef _WIN64
- // This check fails on Win2K when it should pass
- SafeArrayGetVartype(psa, &vt);
- if(vt != VT_VARIANT) {
- _ASSERTE(!"expected the ElementType to be a VT_VARIANT");
- goto lDone;
- }
-#endif // _WIN64
- l = 0;
- SafeArrayGetElement(psa, &l, &var);
-
-#ifdef _WIN64
- if (V_VT(&var) != VT_UI8) { // We expect the VarType to be a VT_UI8 (VT_UI8 is not supported on Windows 2000)
- _ASSERTE(false);
- goto lDone;
- }
-
- pArgs = (ValidateWorkerArgs*)(size_t)V_UI8(&var);
-#else
- // We don't check that the type is V_UINT here because that check fails on Win2K when it should pass
- pArgs = (ValidateWorkerArgs*)(size_t)V_UINT(&var);
-#endif
-
- }
-lDone: ;
-
- EX_TRY
- {
- Verifier::GetErrorMsg(hVECode, err, msg, ulMaxLength, pArgs);
- }
- EX_CATCH
- {
- GetFormattingErrorMsg(msg, ulMaxLength);
- }
- EX_END_CATCH(SwallowAllExceptions)
-
- END_SO_INTOLERANT_CODE;
- return S_OK;
-}
-
-HRESULT CorValidator::Validate(
- IVEHandler *veh,
- IUnknown *pAppDomain,
- unsigned long ulFlags,
- unsigned long ulMaxError,
- unsigned long token,
- __in_z LPWSTR fileName,
- BYTE *pe,
- unsigned long ulSize)
-{
- WRAPPER_NO_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
- return ValidateHelper(veh, pAppDomain, 0, FALSE, ulFlags, ulMaxError,
- token, fileName, pe, ulSize);
-}
-
-HRESULT CLRValidator::Validate(
- IVEHandler *veh,
- unsigned long ulAppDomainId,
- unsigned long ulFlags,
- unsigned long ulMaxError,
- unsigned long token,
- __in_z LPWSTR fileName,
- BYTE *pe,
- unsigned long ulSize)
-{
- WRAPPER_NO_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
- return ValidateHelper(veh, NULL, ulAppDomainId, TRUE, ulFlags, ulMaxError,
- token, fileName, pe, ulSize);
-}
-
-HRESULT CorValidator::FormatEventInfo(
- HRESULT hVECode,
- VEContext Context,
- __out_ecount(ulMaxLength) LPWSTR msg,
- unsigned long ulMaxLength,
- SAFEARRAY *psa)
-{
- WRAPPER_NO_CONTRACT;
- return FormatEventInfoHelper(hVECode, Context, msg, ulMaxLength, psa);
-}
-
-HRESULT CLRValidator::FormatEventInfo(
- HRESULT hVECode,
- VEContext Context,
- __out_ecount(ulMaxLength) LPWSTR msg,
- unsigned long ulMaxLength,
- SAFEARRAY *psa)
-{
- WRAPPER_NO_CONTRACT;
- STATIC_CONTRACT_SO_TOLERANT;
- return FormatEventInfoHelper(hVECode, Context, msg, ulMaxLength, psa);
-}
-
-