diff options
author | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
---|---|---|
committer | dotnet-bot <dotnet-bot@microsoft.com> | 2015-01-30 14:14:42 -0800 |
commit | ef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch) | |
tree | dee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/vm/extensibleclassfactory.cpp | |
download | coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.gz coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.tar.bz2 coreclr-ef1e2ab328087c61a6878c1e84f4fc5d710aebce.zip |
Initial commit to populate CoreCLR repo
[tfs-changeset: 1407945]
Diffstat (limited to 'src/vm/extensibleclassfactory.cpp')
-rw-r--r-- | src/vm/extensibleclassfactory.cpp | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/src/vm/extensibleclassfactory.cpp b/src/vm/extensibleclassfactory.cpp new file mode 100644 index 0000000000..3107f555e7 --- /dev/null +++ b/src/vm/extensibleclassfactory.cpp @@ -0,0 +1,131 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +/*============================================================ +** +** Header: ExtensibleClassFactory.cpp +** +** +** Purpose: Native methods on System.Runtime.InteropServices.ExtensibleClassFactory +** + +** +===========================================================*/ + +#include "common.h" + +#include "excep.h" +#include "stackwalk.h" +#include "extensibleclassfactory.h" + + +// Helper function used to walk stack frames looking for a class initializer. +static StackWalkAction FrameCallback(CrawlFrame *pCF, void *pData) +{ + _ASSERTE(NULL != pCF); + MethodDesc *pMD = pCF->GetFunction(); + + CONTRACTL + { + THROWS; + GC_TRIGGERS; + MODE_ANY; + SO_TOLERANT; + PRECONDITION(CheckPointer(pMD)); + PRECONDITION(CheckPointer(pData, NULL_OK)); + PRECONDITION(pMD->GetMethodTable() != NULL); + } + CONTRACTL_END; + + + // We use the pData context argument to track the class as we move down the + // stack and to return the class whose initializer is being called. If + // *ppMT is NULL we are looking at the caller's initial frame and just + // record the class that the method belongs to. From that point on the class + // must remain the same until we hit a class initializer or else we must + // fail (to prevent other classes called from a class initializer from + // setting the current classes callback). The very first class we will see + // belongs to RegisterObjectCreationCallback itself, so skip it (we set + // *ppMT to an initial value of -1 to detect this). + MethodTable **ppMT = (MethodTable **)pData; + + if (*ppMT == (MethodTable *)-1) + *ppMT = NULL; + + else if (*ppMT == NULL) + *ppMT = pMD->GetMethodTable(); + + else if (pMD->GetMethodTable() != *ppMT) + { + *ppMT = NULL; + return SWA_ABORT; + } + + if (pMD->IsClassConstructor()) + return SWA_ABORT; + + return SWA_CONTINUE; +} + + +// Register a delegate that will be called whenever an instance of a +// managed type that extends from an unmanaged type needs to allocate +// the aggregated unmanaged object. This delegate is expected to +// allocate and aggregate the unmanaged object and is called in place +// of a CoCreateInstance. This routine must be called in the context +// of the static initializer for the class for which the callbacks +// will be made. +// It is not legal to register this callback from a class that has any +// parents that have already registered a callback. +FCIMPL1(void, RegisterObjectCreationCallback, Object* pDelegateUNSAFE) +{ + FCALL_CONTRACT; + + OBJECTREF orDelegate = (OBJECTREF) pDelegateUNSAFE; + HELPER_METHOD_FRAME_BEGIN_1(orDelegate); + + // Validate the delegate argument. + if (orDelegate == 0) + COMPlusThrowArgumentNull(W("callback")); + + // We should have been called in the context of a class static initializer. + // Walk back up the stack to verify this and to determine just what class + // we're registering a callback for. + MethodTable *pMT = (MethodTable *)-1; + if (GetThread()->StackWalkFrames(FrameCallback, &pMT, FUNCTIONSONLY, NULL) == SWA_FAILED) + COMPlusThrow(kInvalidOperationException, IDS_EE_CALLBACK_NOT_CALLED_FROM_CCTOR); + + // If we didn't find a class initializer, we can't continue. + if (pMT == NULL) + { + COMPlusThrow(kInvalidOperationException, IDS_EE_CALLBACK_NOT_CALLED_FROM_CCTOR); + } + + // The object type must derive at some stage from a COM imported object. + // Also we must fail the call if some parent class has already registered a + // callback. + MethodTable *pParent = pMT; + do + { + pParent = pParent->GetParentMethodTable(); + if (pParent && !pParent->IsComImport() && (pParent->GetObjCreateDelegate() != NULL)) + { + COMPlusThrow(kInvalidOperationException, IDS_EE_CALLBACK_ALREADY_REGISTERED); + } + } + while (pParent && !pParent->IsComImport()); + + // If the class does not have a COM imported base class then fail the call. + if (pParent == NULL || pParent->IsProjectedFromWinRT()) + { + COMPlusThrow(kInvalidOperationException, IDS_EE_CALLBACK_NOT_CALLED_FROM_CCTOR); + } + + // Save the delegate in the MethodTable for the class. + pMT->SetObjCreateDelegate(orDelegate); + + HELPER_METHOD_FRAME_END(); +} +FCIMPLEND |