summaryrefslogtreecommitdiff
path: root/src/vm/extensibleclassfactory.cpp
diff options
context:
space:
mode:
authordotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
committerdotnet-bot <dotnet-bot@microsoft.com>2015-01-30 14:14:42 -0800
commitef1e2ab328087c61a6878c1e84f4fc5d710aebce (patch)
treedee1bbb89e9d722e16b0d1485e3cdd1b6c8e2cfa /src/vm/extensibleclassfactory.cpp
downloadcoreclr-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.cpp131
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