1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3// See the LICENSE file in the project root for more information.
4//
5// OBJECT.CPP
6//
7// Definitions of a Com+ Object
8//
9
10
11
12#include "common.h"
13
14#include "vars.hpp"
15#include "class.h"
16#include "object.h"
17#include "threads.h"
18#include "excep.h"
19#include "eeconfig.h"
20#include "gcheaputilities.h"
21#include "field.h"
22#include "argdestination.h"
23
24
25SVAL_IMPL(INT32, ArrayBase, s_arrayBoundsZero);
26
27// follow the necessary rules to get a new valid hashcode for an object
28DWORD Object::ComputeHashCode()
29{
30 DWORD hashCode;
31
32 // note that this algorithm now uses at most HASHCODE_BITS so that it will
33 // fit into the objheader if the hashcode has to be moved back into the objheader
34 // such as for an object that is being frozen
35 do
36 {
37 // we use the high order bits in this case because they're more random
38 hashCode = GetThread()->GetNewHashCode() >> (32-HASHCODE_BITS);
39 }
40 while (hashCode == 0); // need to enforce hashCode != 0
41
42 // verify that it really fits into HASHCODE_BITS
43 _ASSERTE((hashCode & ((1<<HASHCODE_BITS)-1)) == hashCode);
44
45 return hashCode;
46}
47
48#ifndef DACCESS_COMPILE
49INT32 Object::GetHashCodeEx()
50{
51 CONTRACTL
52 {
53 MODE_COOPERATIVE;
54 THROWS;
55 GC_NOTRIGGER;
56 SO_TOLERANT;
57 }
58 CONTRACTL_END
59
60 // This loop exists because we're inspecting the header dword of the object
61 // and it may change under us because of races with other threads.
62 // On top of that, it may have the spin lock bit set, in which case we're
63 // not supposed to change it.
64 // In all of these case, we need to retry the operation.
65 DWORD iter = 0;
66 DWORD dwSwitchCount = 0;
67 while (true)
68 {
69 DWORD bits = GetHeader()->GetBits();
70
71 if (bits & BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX)
72 {
73 if (bits & BIT_SBLK_IS_HASHCODE)
74 {
75 // Common case: the object already has a hash code
76 return bits & MASK_HASHCODE;
77 }
78 else
79 {
80 // We have a sync block index. This means if we already have a hash code,
81 // it is in the sync block, otherwise we generate a new one and store it there
82 SyncBlock *psb = GetSyncBlock();
83 DWORD hashCode = psb->GetHashCode();
84 if (hashCode != 0)
85 return hashCode;
86
87 hashCode = ComputeHashCode();
88
89 return psb->SetHashCode(hashCode);
90 }
91 }
92 else
93 {
94 // If a thread is holding the thin lock or an appdomain index is set, we need a syncblock
95 if ((bits & (SBLK_MASK_LOCK_THREADID | (SBLK_MASK_APPDOMAININDEX << SBLK_APPDOMAIN_SHIFT))) != 0)
96 {
97 GetSyncBlock();
98 // No need to replicate the above code dealing with sync blocks
99 // here - in the next iteration of the loop, we'll realize
100 // we have a syncblock, and we'll do the right thing.
101 }
102 else
103 {
104 // We want to change the header in this case, so we have to check the BIT_SBLK_SPIN_LOCK bit first
105 if (bits & BIT_SBLK_SPIN_LOCK)
106 {
107 iter++;
108 if ((iter % 1024) != 0 && g_SystemInfo.dwNumberOfProcessors > 1)
109 {
110 YieldProcessor(); // indicate to the processor that we are spining
111 }
112 else
113 {
114 __SwitchToThread(0, ++dwSwitchCount);
115 }
116 continue;
117 }
118
119 DWORD hashCode = ComputeHashCode();
120
121 DWORD newBits = bits | BIT_SBLK_IS_HASH_OR_SYNCBLKINDEX | BIT_SBLK_IS_HASHCODE | hashCode;
122
123 if (GetHeader()->SetBits(newBits, bits) == bits)
124 return hashCode;
125 // Header changed under us - let's restart this whole thing.
126 }
127 }
128 }
129}
130#endif // #ifndef DACCESS_COMPILE
131
132BOOL Object::ValidateObjectWithPossibleAV()
133{
134 CANNOT_HAVE_CONTRACT;
135 SUPPORTS_DAC;
136
137 return GetGCSafeMethodTable()->ValidateWithPossibleAV();
138}
139
140
141#ifndef DACCESS_COMPILE
142
143TypeHandle Object::GetTrueTypeHandle()
144{
145 CONTRACTL
146 {
147 NOTHROW;
148 GC_NOTRIGGER;
149 SO_TOLERANT;
150 MODE_COOPERATIVE;
151 }
152 CONTRACTL_END;
153
154 if (m_pMethTab->IsArray())
155 return ((ArrayBase*) this)->GetTypeHandle();
156 else
157 return TypeHandle(GetMethodTable());
158}
159
160// There are cases where it is not possible to get a type handle during a GC.
161// If we can get the type handle, this method will return it.
162// Otherwise, the method will return NULL.
163TypeHandle Object::GetGCSafeTypeHandleIfPossible() const
164{
165 CONTRACTL
166 {
167 NOTHROW;
168 GC_NOTRIGGER;
169 if(!IsGCThread()) { MODE_COOPERATIVE; }
170 }
171 CONTRACTL_END;
172
173 // Although getting the type handle is unsafe and could cause recursive type lookups
174 // in some cases, it's always safe and straightforward to get to the MethodTable.
175 MethodTable * pMT = GetGCSafeMethodTable();
176 _ASSERTE(pMT != NULL);
177
178 // Don't look at types that belong to an unloading AppDomain, or else
179 // pObj->GetGCSafeTypeHandle() can AV. For example, we encountered this AV when pObj
180 // was an array like this:
181 //
182 // MyValueType1<MyValueType2>[] myArray
183 //
184 // where MyValueType1<T> & MyValueType2 are defined in different assemblies. In such
185 // a case, looking up the type handle for myArray requires looking in
186 // MyValueType1<T>'s module's m_AssemblyRefByNameTable, which is garbage if its
187 // AppDomain is unloading.
188 //
189 // Another AV was encountered in a similar case,
190 //
191 // MyRefType1<MyRefType2>[] myArray
192 //
193 // where MyRefType2's module was unloaded by the time the GC occurred. In at least
194 // one case, the GC was caused by the AD unload itself (AppDomain::Unload ->
195 // AppDomain::Exit -> GCInterface::AddMemoryPressure -> WKS::GCHeapUtilities::GarbageCollect).
196 //
197 // To protect against all scenarios, verify that
198 //
199 // * The MT of the object is not getting unloaded, OR
200 // * In the case of arrays (potentially of arrays of arrays of arrays ...), the
201 // MT of the innermost element is not getting unloaded. This then ensures the
202 // MT of the original object (i.e., array) itself must not be getting
203 // unloaded either, since the MTs of arrays and of their elements are
204 // allocated on the same loader heap, except the case where the array is
205 // Object[], in which case its MT is in mscorlib and thus doesn't unload.
206
207 MethodTable * pMTToCheck = pMT;
208 if (pMTToCheck->IsArray())
209 {
210 TypeHandle thElem = static_cast<const ArrayBase * const>(this)->GetArrayElementTypeHandle();
211
212 // Ideally, we would just call thElem.GetLoaderModule() here. Unfortunately, the
213 // current TypeDesc::GetLoaderModule() implementation depends on data structures
214 // that might have been unloaded already. So we just simulate
215 // TypeDesc::GetLoaderModule() for the limited array case that we care about. In
216 // case we're dealing with an array of arrays of arrays etc. traverse until we
217 // find the deepest element, and that's the type we'll check
218 while (thElem.HasTypeParam())
219 {
220 thElem = thElem.GetTypeParam();
221 }
222
223 pMTToCheck = thElem.GetMethodTable();
224 }
225
226 Module * pLoaderModule = pMTToCheck->GetLoaderModule();
227
228 BaseDomain * pBaseDomain = pLoaderModule->GetDomain();
229
230 // Don't look up types that are unloading due to Collectible Assemblies. Haven't been
231 // able to find a case where we actually encounter objects like this that can cause
232 // problems; however, it seems prudent to add this protection just in case.
233 LoaderAllocator * pLoaderAllocator = pLoaderModule->GetLoaderAllocator();
234 _ASSERTE(pLoaderAllocator != NULL);
235 if ((pLoaderAllocator->IsCollectible()) &&
236 (ObjectHandleIsNull(pLoaderAllocator->GetLoaderAllocatorObjectHandle())))
237 {
238 return NULL;
239 }
240
241 // Ok, it should now be safe to get the type handle
242 return GetGCSafeTypeHandle();
243}
244
245/* static */ BOOL Object::SupportsInterface(OBJECTREF pObj, MethodTable* pInterfaceMT)
246{
247 CONTRACTL
248 {
249 THROWS;
250 GC_TRIGGERS;
251 INJECT_FAULT(COMPlusThrowOM());
252 PRECONDITION(CheckPointer(pInterfaceMT));
253 PRECONDITION(pObj->GetMethodTable()->IsRestored_NoLogging());
254 PRECONDITION(pInterfaceMT->IsInterface());
255 }
256 CONTRACTL_END
257
258 BOOL bSupportsItf = FALSE;
259
260 GCPROTECT_BEGIN(pObj)
261 {
262 // Make sure the interface method table has been restored.
263 pInterfaceMT->CheckRestore();
264
265 // Check to see if the static class definition indicates we implement the interface.
266 MethodTable * pMT = pObj->GetMethodTable();
267 if (pMT->CanCastToInterface(pInterfaceMT))
268 {
269 bSupportsItf = TRUE;
270 }
271#ifdef FEATURE_COMINTEROP
272 else
273 if (pMT->IsComObjectType())
274 {
275 // If this is a COM object, the static class definition might not be complete so we need
276 // to check if the COM object implements the interface.
277 bSupportsItf = ComObject::SupportsInterface(pObj, pInterfaceMT);
278 }
279#endif // FEATURE_COMINTEROP
280 }
281 GCPROTECT_END();
282
283 return bSupportsItf;
284}
285
286Assembly *AssemblyBaseObject::GetAssembly()
287{
288 WRAPPER_NO_CONTRACT;
289 return m_pAssembly->GetAssembly();
290}
291
292#ifdef _DEBUG
293// Object::DEBUG_SetAppDomain specified DEBUG_ONLY in the contract to disable SO-tolerance
294// checking for paths that are DEBUG-only.
295//
296// NOTE: currently this is only used by WIN64 allocation helpers, but they really should
297// be calling the JIT helper SetObjectAppDomain (which currently only exists for
298// x86).
299void Object::DEBUG_SetAppDomain(AppDomain *pDomain)
300{
301 CONTRACTL
302 {
303 THROWS;
304 GC_NOTRIGGER;
305 DEBUG_ONLY;
306 INJECT_FAULT(COMPlusThrowOM(););
307 PRECONDITION(CheckPointer(pDomain));
308 }
309 CONTRACTL_END;
310
311 /*_ASSERTE(GetThread()->IsSOTolerant());*/
312 SetAppDomain(pDomain);
313}
314#endif
315
316void Object::SetAppDomain(AppDomain *pDomain)
317{
318 CONTRACTL
319 {
320 THROWS;
321 GC_NOTRIGGER;
322 SO_INTOLERANT;
323 INJECT_FAULT(COMPlusThrowOM(););
324 PRECONDITION(CheckPointer(pDomain));
325 }
326 CONTRACTL_END;
327
328#ifndef _DEBUG
329 //
330 // If we have a per-app-domain method table, we can
331 // infer the app domain from the method table, so
332 // there is no reason to mark the object.
333 //
334 // But we don't do this in a debug build, because
335 // we want to be able to detect the case when the
336 // domain was unloaded from underneath an object (and
337 // the MethodTable will be toast in that case.)
338 //
339 _ASSERTE(pDomain == GetMethodTable()->GetDomain());
340#else
341 ADIndex index = pDomain->GetIndex();
342 GetHeader()->SetAppDomainIndex(index);
343#endif
344
345 _ASSERTE(GetHeader()->GetAppDomainIndex().m_dwIndex != 0);
346}
347
348BOOL Object::SetAppDomainNoThrow()
349{
350 CONTRACTL
351 {
352 NOTHROW;
353 GC_NOTRIGGER;
354 SO_INTOLERANT;
355 }
356 CONTRACTL_END;
357
358 BOOL success = FALSE;
359
360 EX_TRY
361 {
362 SetAppDomain();
363 success = TRUE;
364 }
365 EX_CATCH
366 {
367 _ASSERTE (!"Exception happened during Object::SetAppDomain");
368 }
369 EX_END_CATCH(RethrowTerminalExceptions)
370
371 return success;
372}
373
374AppDomain *Object::GetAppDomain()
375{
376 CONTRACTL
377 {
378 NOTHROW;
379 GC_NOTRIGGER;
380 SO_TOLERANT;
381 MODE_COOPERATIVE;
382 }
383 CONTRACTL_END;
384#ifndef _DEBUG
385 return (AppDomain*) GetMethodTable()->GetDomain();
386#endif
387
388 ADIndex index = GetHeader()->GetAppDomainIndex();
389
390 if (index.m_dwIndex == 0)
391 return NULL;
392
393 AppDomain *pDomain = SystemDomain::TestGetAppDomainAtIndex(index);
394 return pDomain;
395}
396
397STRINGREF AllocateString(SString sstr)
398{
399 CONTRACTL {
400 THROWS;
401 GC_TRIGGERS;
402 } CONTRACTL_END;
403
404 COUNT_T length = sstr.GetCount(); // count of WCHARs excluding terminating NULL
405 STRINGREF strObj = AllocateString(length);
406 memcpyNoGCRefs(strObj->GetBuffer(), sstr.GetUnicode(), length*sizeof(WCHAR));
407
408 return strObj;
409}
410
411CHARARRAYREF AllocateCharArray(DWORD dwArrayLength)
412{
413 CONTRACTL
414 {
415 THROWS;
416 GC_TRIGGERS;
417 MODE_COOPERATIVE;
418 }
419 CONTRACTL_END;
420 return (CHARARRAYREF)AllocatePrimitiveArray(ELEMENT_TYPE_CHAR, dwArrayLength);
421}
422
423void Object::ValidatePromote(ScanContext *sc, DWORD flags)
424{
425 STATIC_CONTRACT_NOTHROW;
426 STATIC_CONTRACT_GC_NOTRIGGER;
427 STATIC_CONTRACT_FORBID_FAULT;
428
429
430#if defined (VERIFY_HEAP)
431 Validate();
432#endif
433}
434
435void Object::ValidateHeap(Object *from, BOOL bDeep)
436{
437 STATIC_CONTRACT_NOTHROW;
438 STATIC_CONTRACT_GC_NOTRIGGER;
439 STATIC_CONTRACT_FORBID_FAULT;
440
441#if defined (VERIFY_HEAP)
442 //no need to verify next object's header in this case
443 //since this is called in verify_heap, which will verfiy every object anyway
444 Validate(bDeep, FALSE);
445#endif
446}
447
448void Object::SetOffsetObjectRef(DWORD dwOffset, size_t dwValue)
449{
450 STATIC_CONTRACT_NOTHROW;
451 STATIC_CONTRACT_GC_NOTRIGGER;
452 STATIC_CONTRACT_FORBID_FAULT;
453 STATIC_CONTRACT_MODE_COOPERATIVE;
454 STATIC_CONTRACT_SO_TOLERANT;
455
456 OBJECTREF* location;
457 OBJECTREF o;
458
459 location = (OBJECTREF *) &GetData()[dwOffset];
460 o = ObjectToOBJECTREF(*(Object **) &dwValue);
461
462 SetObjectReference( location, o, GetAppDomain() );
463}
464
465void SetObjectReferenceUnchecked(OBJECTREF *dst,OBJECTREF ref)
466{
467 STATIC_CONTRACT_NOTHROW;
468 STATIC_CONTRACT_GC_NOTRIGGER;
469 STATIC_CONTRACT_FORBID_FAULT;
470 STATIC_CONTRACT_MODE_COOPERATIVE;
471 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
472
473 // Assign value. We use casting to avoid going thru the overloaded
474 // OBJECTREF= operator which in this case would trigger a false
475 // write-barrier violation assert.
476 VolatileStore((Object**)dst, OBJECTREFToObject(ref));
477#ifdef _DEBUG
478 Thread::ObjectRefAssign(dst);
479#endif
480 ErectWriteBarrier(dst, ref);
481}
482
483void STDCALL CopyValueClassUnchecked(void* dest, void* src, MethodTable *pMT)
484{
485
486 STATIC_CONTRACT_NOTHROW;
487 STATIC_CONTRACT_GC_NOTRIGGER;
488 STATIC_CONTRACT_FORBID_FAULT;
489 STATIC_CONTRACT_MODE_COOPERATIVE;
490
491 _ASSERTE(!pMT->IsArray()); // bunch of assumptions about arrays wrong.
492
493 // <TODO> @todo Only call MemoryBarrier() if needed.
494 // Reflection is a known use case where this is required.
495 // Unboxing is a use case where this should not be required.
496 // </TODO>
497 MemoryBarrier();
498
499 // Copy the bulk of the data, and any non-GC refs.
500 switch (pMT->GetNumInstanceFieldBytes())
501 {
502 case 1:
503 *(UINT8*)dest = *(UINT8*)src;
504 break;
505#ifndef ALIGN_ACCESS
506 // we can hit an alignment fault if the value type has multiple
507 // smaller fields. Example: if there are two I4 fields, the
508 // value class can be aligned to 4-byte boundaries, yet the
509 // NumInstanceFieldBytes is 8
510 case 2:
511 *(UINT16*)dest = *(UINT16*)src;
512 break;
513 case 4:
514 *(UINT32*)dest = *(UINT32*)src;
515 break;
516 case 8:
517 *(UINT64*)dest = *(UINT64*)src;
518 break;
519#endif // !ALIGN_ACCESS
520 default:
521 memcpyNoGCRefs(dest, src, pMT->GetNumInstanceFieldBytes());
522 break;
523 }
524
525 // Tell the GC about any copies.
526 if (pMT->ContainsPointers())
527 {
528 CGCDesc* map = CGCDesc::GetCGCDescFromMT(pMT);
529 CGCDescSeries* cur = map->GetHighestSeries();
530 CGCDescSeries* last = map->GetLowestSeries();
531 DWORD size = pMT->GetBaseSize();
532 _ASSERTE(cur >= last);
533 do
534 {
535 // offset to embedded references in this series must be
536 // adjusted by the VTable pointer, when in the unboxed state.
537 size_t offset = cur->GetSeriesOffset() - sizeof(void*);
538 OBJECTREF* srcPtr = (OBJECTREF*)(((BYTE*) src) + offset);
539 OBJECTREF* destPtr = (OBJECTREF*)(((BYTE*) dest) + offset);
540 OBJECTREF* srcPtrStop = (OBJECTREF*)((BYTE*) srcPtr + cur->GetSeriesSize() + size);
541 while (srcPtr < srcPtrStop)
542 {
543 SetObjectReferenceUnchecked(destPtr, ObjectToOBJECTREF(*(Object**)srcPtr));
544 srcPtr++;
545 destPtr++;
546 }
547 cur--;
548 } while (cur >= last);
549 }
550}
551
552// Copy value class into the argument specified by the argDest.
553// The destOffset is nonzero when copying values into Nullable<T>, it is the offset
554// of the T value inside of the Nullable<T>
555void STDCALL CopyValueClassArgUnchecked(ArgDestination *argDest, void* src, MethodTable *pMT, int destOffset)
556{
557 STATIC_CONTRACT_NOTHROW;
558 STATIC_CONTRACT_GC_NOTRIGGER;
559 STATIC_CONTRACT_FORBID_FAULT;
560 STATIC_CONTRACT_MODE_COOPERATIVE;
561
562#if defined(UNIX_AMD64_ABI)
563
564 if (argDest->IsStructPassedInRegs())
565 {
566 argDest->CopyStructToRegisters(src, pMT->GetNumInstanceFieldBytes(), destOffset);
567 return;
568 }
569
570#elif defined(_TARGET_ARM64_)
571
572 if (argDest->IsHFA())
573 {
574 argDest->CopyHFAStructToRegister(src, pMT->GetAlignedNumInstanceFieldBytes());
575 return;
576 }
577
578#endif // UNIX_AMD64_ABI
579 // destOffset is only valid for Nullable<T> passed in registers
580 _ASSERTE(destOffset == 0);
581
582 CopyValueClassUnchecked(argDest->GetDestinationAddress(), src, pMT);
583}
584
585// Initialize the value class argument to zeros
586void InitValueClassArg(ArgDestination *argDest, MethodTable *pMT)
587{
588 STATIC_CONTRACT_NOTHROW;
589 STATIC_CONTRACT_GC_NOTRIGGER;
590 STATIC_CONTRACT_FORBID_FAULT;
591 STATIC_CONTRACT_MODE_COOPERATIVE;
592
593#if defined(UNIX_AMD64_ABI)
594
595 if (argDest->IsStructPassedInRegs())
596 {
597 argDest->ZeroStructInRegisters(pMT->GetNumInstanceFieldBytes());
598 return;
599 }
600
601#endif
602 InitValueClass(argDest->GetDestinationAddress(), pMT);
603}
604
605#if defined (VERIFY_HEAP)
606
607#include "dbginterface.h"
608
609 // make the checking code goes as fast as possible!
610#if defined(_MSC_VER)
611#pragma optimize("tgy", on)
612#endif
613
614#define CREATE_CHECK_STRING(x) #x
615#define CHECK_AND_TEAR_DOWN(x) \
616 do{ \
617 if (!(x)) \
618 { \
619 _ASSERTE(!CREATE_CHECK_STRING(x)); \
620 EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); \
621 } \
622 } while (0)
623
624VOID Object::Validate(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncBlock)
625{
626 STATIC_CONTRACT_NOTHROW;
627 STATIC_CONTRACT_GC_NOTRIGGER;
628 STATIC_CONTRACT_FORBID_FAULT;
629 STATIC_CONTRACT_MODE_COOPERATIVE;
630 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
631
632 if (this == NULL)
633 {
634 return; // NULL is ok
635 }
636
637 if (g_IBCLogger.InstrEnabled() && !GCStress<cfg_any>::IsEnabled())
638 {
639 // If we are instrumenting for IBC (and GCStress is not enabled)
640 // then skip these Object::Validate() as they slow down the
641 // instrument phase by an order of magnitude
642 return;
643 }
644
645 if (g_fEEShutDown & ShutDown_Phase2)
646 {
647 // During second phase of shutdown the code below is not guaranteed to work.
648 return;
649 }
650
651#ifdef _DEBUG
652 {
653 BEGIN_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
654 Thread *pThread = GetThread();
655
656 if (pThread != NULL && !(pThread->PreemptiveGCDisabled()))
657 {
658 // Debugger helper threads are special in that they take over for
659 // what would normally be a nonEE thread (the RCThread). If an
660 // EE thread is doing RCThread duty, then it should be treated
661 // as such.
662 //
663 // There are some GC threads in the same kind of category. Note that
664 // GetThread() sometimes returns them, if DLL_THREAD_ATTACH notifications
665 // have run some managed code.
666 if (!dbgOnly_IsSpecialEEThread() && !IsGCSpecialThread())
667 _ASSERTE(!"OBJECTREF being accessed while thread is in preemptive GC mode.");
668 }
669 END_GETTHREAD_ALLOWED_IN_NO_THROW_REGION;
670 }
671#endif
672
673
674 { // ValidateInner can throw or fault on failure which violates contract.
675 CONTRACT_VIOLATION(ThrowsViolation | FaultViolation);
676
677 // using inner helper because of TRY and stack objects with destructors.
678 ValidateInner(bDeep, bVerifyNextHeader, bVerifySyncBlock);
679 }
680}
681
682VOID Object::ValidateInner(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncBlock)
683{
684 STATIC_CONTRACT_THROWS; // See CONTRACT_VIOLATION above
685 STATIC_CONTRACT_GC_NOTRIGGER;
686 STATIC_CONTRACT_FAULT; // See CONTRACT_VIOLATION above
687 STATIC_CONTRACT_MODE_COOPERATIVE;
688 STATIC_CONTRACT_CANNOT_TAKE_LOCK;
689
690 int lastTest = 0;
691
692 EX_TRY
693 {
694 // in order to avoid contract violations in the EH code we'll allow AVs here,
695 // they'll be handled in the catch block
696 AVInRuntimeImplOkayHolder avOk;
697
698 MethodTable *pMT = GetGCSafeMethodTable();
699
700 lastTest = 1;
701
702 CHECK_AND_TEAR_DOWN(pMT && pMT->Validate());
703 lastTest = 2;
704
705 bool noRangeChecks =
706 (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_NO_RANGE_CHECKS) == EEConfig::HEAPVERIFY_NO_RANGE_CHECKS;
707
708 // noRangeChecks depends on initial values being FALSE
709 BOOL bSmallObjectHeapPtr = FALSE, bLargeObjectHeapPtr = FALSE;
710 if (!noRangeChecks)
711 {
712 bSmallObjectHeapPtr = GCHeapUtilities::GetGCHeap()->IsHeapPointer(this, true);
713 if (!bSmallObjectHeapPtr)
714 bLargeObjectHeapPtr = GCHeapUtilities::GetGCHeap()->IsHeapPointer(this);
715
716 CHECK_AND_TEAR_DOWN(bSmallObjectHeapPtr || bLargeObjectHeapPtr);
717 }
718
719 lastTest = 3;
720
721 if (bDeep)
722 {
723 CHECK_AND_TEAR_DOWN(GetHeader()->Validate(bVerifySyncBlock));
724 }
725
726 lastTest = 4;
727
728 if (bDeep && (g_pConfig->GetHeapVerifyLevel() & EEConfig::HEAPVERIFY_GC)) {
729 GCHeapUtilities::GetGCHeap()->ValidateObjectMember(this);
730 }
731
732 lastTest = 5;
733
734 // since bSmallObjectHeapPtr is initialized to FALSE
735 // we skip checking noRangeChecks since if skipping
736 // is enabled bSmallObjectHeapPtr will always be false.
737 if (bSmallObjectHeapPtr) {
738 CHECK_AND_TEAR_DOWN(!GCHeapUtilities::GetGCHeap()->IsObjectInFixedHeap(this));
739 }
740
741 lastTest = 6;
742
743 lastTest = 7;
744
745 _ASSERTE(GCHeapUtilities::IsGCHeapInitialized());
746 // try to validate next object's header
747 if (bDeep
748 && bVerifyNextHeader
749 && GCHeapUtilities::GetGCHeap()->RuntimeStructuresValid()
750 //NextObj could be very slow if concurrent GC is going on
751 && !GCHeapUtilities::GetGCHeap ()->IsConcurrentGCInProgress ())
752 {
753 Object * nextObj = GCHeapUtilities::GetGCHeap ()->NextObj (this);
754 if ((nextObj != NULL) &&
755 (nextObj->GetGCSafeMethodTable() != g_pFreeObjectMethodTable))
756 {
757 CHECK_AND_TEAR_DOWN(nextObj->GetHeader()->Validate(FALSE));
758 }
759 }
760
761 lastTest = 8;
762
763#ifdef FEATURE_64BIT_ALIGNMENT
764 if (pMT->RequiresAlign8())
765 {
766 CHECK_AND_TEAR_DOWN((((size_t)this) & 0x7) == (pMT->IsValueType()? 4:0));
767 }
768 lastTest = 9;
769#endif // FEATURE_64BIT_ALIGNMENT
770
771 }
772 EX_CATCH
773 {
774 STRESS_LOG3(LF_ASSERT, LL_ALWAYS, "Detected use of corrupted OBJECTREF: %p [MT=%p] (lastTest=%d)", this, lastTest > 0 ? (*(size_t*)this) : 0, lastTest);
775 CHECK_AND_TEAR_DOWN(!"Detected use of a corrupted OBJECTREF. Possible GC hole.");
776 }
777 EX_END_CATCH(SwallowAllExceptions);
778}
779
780
781#endif // VERIFY_HEAP
782
783#ifndef DACCESS_COMPILE
784#ifdef _DEBUG
785void ArrayBase::AssertArrayTypeDescLoaded()
786{
787 _ASSERTE (m_pMethTab->IsArray());
788
789 // The type should already be loaded
790 // See also: MethodTable::DoFullyLoad
791 TypeHandle th = ClassLoader::LoadArrayTypeThrowing(m_pMethTab->GetApproxArrayElementTypeHandle(),
792 m_pMethTab->GetInternalCorElementType(),
793 m_pMethTab->GetRank(),
794 ClassLoader::DontLoadTypes);
795
796 _ASSERTE(!th.IsNull());
797}
798#endif // DEBUG
799#endif // !DACCESS_COMPILE
800
801/*==================================NewString===================================
802**Action: Creates a System.String object.
803**Returns:
804**Arguments:
805**Exceptions:
806==============================================================================*/
807STRINGREF StringObject::NewString(INT32 length) {
808 CONTRACTL {
809 GC_TRIGGERS;
810 MODE_COOPERATIVE;
811 PRECONDITION(length>=0);
812 } CONTRACTL_END;
813
814 STRINGREF pString;
815
816 if (length<0) {
817 return NULL;
818 } else if (length == 0) {
819 return GetEmptyString();
820 } else {
821 pString = AllocateString(length);
822 _ASSERTE(pString->GetBuffer()[length] == 0);
823
824 return pString;
825 }
826}
827
828
829/*==================================NewString===================================
830**Action: Many years ago, VB didn't have the concept of a byte array, so enterprising
831** users created one by allocating a BSTR with an odd length and using it to
832** store bytes. A generation later, we're still stuck supporting this behavior.
833** The way that we do this is to take advantage of the difference between the
834** array length and the string length. The string length will always be the
835** number of characters between the start of the string and the terminating 0.
836** If we need an odd number of bytes, we'll take one wchar after the terminating 0.
837** (e.g. at position StringLength+1). The high-order byte of this wchar is
838** reserved for flags and the low-order byte is our odd byte. This function is
839** used to allocate a string of that shape, but we don't actually mark the
840** trailing byte as being in use yet.
841**Returns: A newly allocated string. Null if length is less than 0.
842**Arguments: length -- the length of the string to allocate
843** bHasTrailByte -- whether the string also has a trailing byte.
844**Exceptions: OutOfMemoryException if AllocateString fails.
845==============================================================================*/
846STRINGREF StringObject::NewString(INT32 length, BOOL bHasTrailByte) {
847 CONTRACTL {
848 GC_TRIGGERS;
849 MODE_COOPERATIVE;
850 PRECONDITION(length>=0 && length != INT32_MAX);
851 } CONTRACTL_END;
852
853 STRINGREF pString;
854 if (length<0 || length == INT32_MAX) {
855 return NULL;
856 } else if (length == 0) {
857 return GetEmptyString();
858 } else {
859 pString = AllocateString(length);
860 _ASSERTE(pString->GetBuffer()[length]==0);
861 if (bHasTrailByte) {
862 _ASSERTE(pString->GetBuffer()[length+1]==0);
863 }
864 }
865
866 return pString;
867}
868
869//========================================================================
870// Creates a System.String object and initializes from
871// the supplied null-terminated C string.
872//
873// Maps NULL to null. This function does *not* return null to indicate
874// error situations: it throws an exception instead.
875//========================================================================
876STRINGREF StringObject::NewString(const WCHAR *pwsz)
877{
878 CONTRACTL {
879 GC_TRIGGERS;
880 MODE_COOPERATIVE;
881 } CONTRACTL_END;
882
883 if (!pwsz)
884 {
885 return NULL;
886 }
887 else
888 {
889
890 DWORD nch = (DWORD)wcslen(pwsz);
891 if (nch==0) {
892 return GetEmptyString();
893 }
894
895#if 0
896 //
897 // This assert is disabled because it is valid for us to get a
898 // pointer from the gc heap here as long as it is pinned. This
899 // can happen when a string is marshalled to unmanaged by
900 // pinning and then later put into a struct and that struct is
901 // then marshalled to managed.
902 //
903 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((BYTE *) pwsz) ||
904 !"pwsz can not point to GC Heap");
905#endif // 0
906
907 STRINGREF pString = AllocateString( nch );
908
909 memcpyNoGCRefs(pString->GetBuffer(), pwsz, nch*sizeof(WCHAR));
910 _ASSERTE(pString->GetBuffer()[nch] == 0);
911 return pString;
912 }
913}
914
915#if defined(_MSC_VER) && defined(_TARGET_X86_)
916#pragma optimize("y", on) // Small critical routines, don't put in EBP frame
917#endif
918
919STRINGREF StringObject::NewString(const WCHAR *pwsz, int length) {
920 CONTRACTL {
921 THROWS;
922 GC_TRIGGERS;
923 MODE_COOPERATIVE;
924 PRECONDITION(length>=0);
925 } CONTRACTL_END;
926
927 if (!pwsz)
928 {
929 return NULL;
930 }
931 else if (length <= 0) {
932 return GetEmptyString();
933 } else {
934#if 0
935 //
936 // This assert is disabled because it is valid for us to get a
937 // pointer from the gc heap here as long as it is pinned. This
938 // can happen when a string is marshalled to unmanaged by
939 // pinning and then later put into a struct and that struct is
940 // then marshalled to managed.
941 //
942 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((BYTE *) pwsz) ||
943 !"pwsz can not point to GC Heap");
944#endif // 0
945 STRINGREF pString = AllocateString(length);
946
947 memcpyNoGCRefs(pString->GetBuffer(), pwsz, length*sizeof(WCHAR));
948 _ASSERTE(pString->GetBuffer()[length] == 0);
949 return pString;
950 }
951}
952
953#if defined(_MSC_VER) && defined(_TARGET_X86_)
954#pragma optimize("", on) // Go back to command line default optimizations
955#endif
956
957STRINGREF StringObject::NewString(LPCUTF8 psz)
958{
959 CONTRACTL {
960 GC_TRIGGERS;
961 MODE_COOPERATIVE;
962 THROWS;
963 PRECONDITION(CheckPointer(psz));
964 } CONTRACTL_END;
965
966 int length = (int)strlen(psz);
967 if (length == 0) {
968 return GetEmptyString();
969 }
970 CQuickBytes qb;
971 WCHAR* pwsz = (WCHAR*) qb.AllocThrows((length) * sizeof(WCHAR));
972 length = WszMultiByteToWideChar(CP_UTF8, 0, psz, length, pwsz, length);
973 if (length == 0) {
974 COMPlusThrow(kArgumentException, W("Arg_InvalidUTF8String"));
975 }
976 return NewString(pwsz, length);
977}
978
979STRINGREF StringObject::NewString(LPCUTF8 psz, int cBytes)
980{
981 CONTRACTL {
982 GC_TRIGGERS;
983 MODE_COOPERATIVE;
984 THROWS;
985 PRECONDITION(CheckPointer(psz, NULL_OK));
986 } CONTRACTL_END;
987
988 if (!psz)
989 return NULL;
990
991 _ASSERTE(psz);
992 _ASSERTE(cBytes >= 0);
993 if (cBytes == 0) {
994 return GetEmptyString();
995 }
996 int cWszBytes = 0;
997 if (!ClrSafeInt<int>::multiply(cBytes, sizeof(WCHAR), cWszBytes))
998 COMPlusThrowOM();
999 CQuickBytes qb;
1000 WCHAR* pwsz = (WCHAR*) qb.AllocThrows(cWszBytes);
1001 int length = WszMultiByteToWideChar(CP_UTF8, 0, psz, cBytes, pwsz, cBytes);
1002 if (length == 0) {
1003 COMPlusThrow(kArgumentException, W("Arg_InvalidUTF8String"));
1004 }
1005 return NewString(pwsz, length);
1006}
1007
1008//
1009//
1010// STATIC MEMBER VARIABLES
1011//
1012//
1013STRINGREF* StringObject::EmptyStringRefPtr=NULL;
1014
1015//The special string helpers are used as flag bits for weird strings that have bytes
1016//after the terminating 0. The only case where we use this right now is the VB BSTR as
1017//byte array which is described in MakeStringAsByteArrayFromBytes.
1018#define SPECIAL_STRING_VB_BYTE_ARRAY 0x100
1019
1020FORCEINLINE BOOL MARKS_VB_BYTE_ARRAY(WCHAR x)
1021{
1022 return static_cast<BOOL>(x & SPECIAL_STRING_VB_BYTE_ARRAY);
1023}
1024
1025FORCEINLINE WCHAR MAKE_VB_TRAIL_BYTE(BYTE x)
1026{
1027 return static_cast<WCHAR>(x) | SPECIAL_STRING_VB_BYTE_ARRAY;
1028}
1029
1030FORCEINLINE BYTE GET_VB_TRAIL_BYTE(WCHAR x)
1031{
1032 return static_cast<BYTE>(x & 0xFF);
1033}
1034
1035
1036/*==============================InitEmptyStringRefPtr============================
1037**Action: Gets an empty string refptr, cache the result.
1038**Returns: The retrieved STRINGREF.
1039==============================================================================*/
1040STRINGREF* StringObject::InitEmptyStringRefPtr() {
1041 CONTRACTL {
1042 THROWS;
1043 MODE_ANY;
1044 GC_TRIGGERS;
1045 } CONTRACTL_END;
1046
1047 GCX_COOP();
1048
1049 EEStringData data(0, W(""), TRUE);
1050 EmptyStringRefPtr = SystemDomain::System()->DefaultDomain()->GetLoaderAllocator()->GetStringObjRefPtrFromUnicodeString(&data);
1051 return EmptyStringRefPtr;
1052}
1053
1054// strAChars must be null-terminated, with an appropriate aLength
1055// strBChars must be null-terminated, with an appropriate bLength OR bLength == -1
1056// If bLength == -1, we stop on the first null character in strBChars
1057BOOL StringObject::CaseInsensitiveCompHelper(__in_ecount(aLength) WCHAR *strAChars, __in_z INT8 *strBChars, INT32 aLength, INT32 bLength, INT32 *result) {
1058 CONTRACTL {
1059 NOTHROW;
1060 GC_NOTRIGGER;
1061 MODE_ANY;
1062 PRECONDITION(CheckPointer(strAChars));
1063 PRECONDITION(CheckPointer(strBChars));
1064 PRECONDITION(CheckPointer(result));
1065 SO_TOLERANT;
1066 } CONTRACTL_END;
1067
1068 WCHAR *strAStart = strAChars;
1069 INT8 *strBStart = strBChars;
1070 unsigned charA;
1071 unsigned charB;
1072
1073 for(;;) {
1074 charA = *strAChars;
1075 charB = (unsigned) *strBChars;
1076
1077 //Case-insensitive comparison on chars greater than 0x7F
1078 //requires a locale-aware casing operation and we're not going there.
1079 if ((charA|charB)>0x7F) {
1080 *result = 0;
1081 return FALSE;
1082 }
1083
1084 // uppercase both chars.
1085 if (charA>='a' && charA<='z') {
1086 charA ^= 0x20;
1087 }
1088 if (charB>='a' && charB<='z') {
1089 charB ^= 0x20;
1090 }
1091
1092 //Return the (case-insensitive) difference between them.
1093 if (charA!=charB) {
1094 *result = (int)(charA-charB);
1095 return TRUE;
1096 }
1097
1098
1099 if (charA==0) // both strings have null character
1100 {
1101 if (bLength == -1)
1102 {
1103 *result = aLength - static_cast<INT32>(strAChars - strAStart);
1104 return TRUE;
1105 }
1106 if (strAChars==strAStart + aLength || strBChars==strBStart + bLength)
1107 {
1108 *result = aLength - bLength;
1109 return TRUE;
1110 }
1111 // else both embedded zeros
1112 }
1113
1114 // Next char
1115 strAChars++; strBChars++;
1116 }
1117
1118}
1119
1120/*=============================InternalHasHighChars=============================
1121**Action: Checks if the string can be sorted quickly. The requirements are that
1122** the string contain no character greater than 0x80 and that the string not
1123** contain an apostrophe or a hypen. Apostrophe and hyphen are excluded so that
1124** words like co-op and coop sort together.
1125**Returns: Void. The side effect is to set a bit on the string indicating whether or not
1126** the string contains high chars.
1127**Arguments: The String to be checked.
1128**Exceptions: None
1129==============================================================================*/
1130DWORD StringObject::InternalCheckHighChars() {
1131 WRAPPER_NO_CONTRACT;
1132
1133 WCHAR *chars;
1134 WCHAR c;
1135 INT32 length;
1136
1137 RefInterpretGetStringValuesDangerousForGC((WCHAR **) &chars, &length);
1138
1139 DWORD stringState = STRING_STATE_FAST_OPS;
1140
1141 for (int i=0; i<length; i++) {
1142 c = chars[i];
1143 if (c>=0x80) {
1144 SetHighCharState(STRING_STATE_HIGH_CHARS);
1145 return STRING_STATE_HIGH_CHARS;
1146 } else if (HighCharHelper::IsHighChar((int)c)) {
1147 //This means that we have a character which forces special sorting,
1148 //but doesn't necessarily force slower casing and indexing. We'll
1149 //set a value to remember this, but we need to check the rest of
1150 //the string because we may still find a charcter greater than 0x7f.
1151 stringState = STRING_STATE_SPECIAL_SORT;
1152 }
1153 }
1154
1155 SetHighCharState(stringState);
1156 return stringState;
1157}
1158
1159#ifdef VERIFY_HEAP
1160/*=============================ValidateHighChars=============================
1161**Action: Validate if the HighChars bits is set correctly, no side effect
1162**Returns: BOOL for result of validation
1163**Arguments: The String to be checked.
1164**Exceptions: None
1165==============================================================================*/
1166BOOL StringObject::ValidateHighChars()
1167{
1168 WRAPPER_NO_CONTRACT;
1169 DWORD curStringState = GetHighCharState ();
1170 // state could always be undetermined
1171 if (curStringState == STRING_STATE_UNDETERMINED)
1172 {
1173 return TRUE;
1174 }
1175
1176 WCHAR *chars;
1177 INT32 length;
1178 RefInterpretGetStringValuesDangerousForGC((WCHAR **) &chars, &length);
1179
1180 DWORD stringState = STRING_STATE_FAST_OPS;
1181 for (int i=0; i<length; i++) {
1182 WCHAR c = chars[i];
1183 if (c>=0x80)
1184 {
1185 // if there is a high char in the string, the state has to be STRING_STATE_HIGH_CHARS
1186 return curStringState == STRING_STATE_HIGH_CHARS;
1187 }
1188 else if (HighCharHelper::IsHighChar((int)c)) {
1189 //This means that we have a character which forces special sorting,
1190 //but doesn't necessarily force slower casing and indexing. We'll
1191 //set a value to remember this, but we need to check the rest of
1192 //the string because we may still find a charcter greater than 0x7f.
1193 stringState = STRING_STATE_SPECIAL_SORT;
1194 }
1195 }
1196
1197 return stringState == curStringState;
1198}
1199
1200#endif //VERIFY_HEAP
1201
1202/*============================InternalTrailByteCheck============================
1203**Action: Many years ago, VB didn't have the concept of a byte array, so enterprising
1204** users created one by allocating a BSTR with an odd length and using it to
1205** store bytes. A generation later, we're still stuck supporting this behavior.
1206** The way that we do this is stick the trail byte in the sync block
1207** whenever we encounter such a situation. Since we expect this to be a very corner case
1208** accessing the sync block seems like a good enough solution
1209**
1210**Returns: True if <CODE>str</CODE> contains a VB trail byte, false otherwise.
1211**Arguments: str -- The string to be examined.
1212**Exceptions: None
1213==============================================================================*/
1214BOOL StringObject::HasTrailByte() {
1215 WRAPPER_NO_CONTRACT;
1216 STATIC_CONTRACT_SO_TOLERANT;
1217
1218 SyncBlock * pSyncBlock = PassiveGetSyncBlock();
1219 if(pSyncBlock != NULL)
1220 {
1221 return pSyncBlock->HasCOMBstrTrailByte();
1222 }
1223
1224 return FALSE;
1225}
1226
1227/*=================================GetTrailByte=================================
1228**Action: If <CODE>str</CODE> contains a vb trail byte, returns a copy of it.
1229**Returns: True if <CODE>str</CODE> contains a trail byte. *bTrailByte is set to
1230** the byte in question if <CODE>str</CODE> does have a trail byte, otherwise
1231** it's set to 0.
1232**Arguments: str -- The string being examined.
1233** bTrailByte -- An out param to hold the value of the trail byte.
1234**Exceptions: None.
1235==============================================================================*/
1236BOOL StringObject::GetTrailByte(BYTE *bTrailByte) {
1237 CONTRACTL
1238 {
1239 NOTHROW;
1240 GC_NOTRIGGER;
1241 SO_TOLERANT;
1242 MODE_ANY;
1243 }
1244 CONTRACTL_END;
1245 _ASSERTE(bTrailByte);
1246 *bTrailByte=0;
1247
1248 BOOL retValue = HasTrailByte();
1249
1250 if(retValue)
1251 {
1252 *bTrailByte = GET_VB_TRAIL_BYTE(GetHeader()->PassiveGetSyncBlock()->GetCOMBstrTrailByte());
1253 }
1254
1255 return retValue;
1256}
1257
1258/*=================================SetTrailByte=================================
1259**Action: Sets the trail byte in the sync block
1260**Returns: True.
1261**Arguments: str -- The string into which to set the trail byte.
1262** bTrailByte -- The trail byte to be added to the string.
1263**Exceptions: None.
1264==============================================================================*/
1265BOOL StringObject::SetTrailByte(BYTE bTrailByte) {
1266 WRAPPER_NO_CONTRACT;
1267
1268 GetHeader()->GetSyncBlock()->SetCOMBstrTrailByte(MAKE_VB_TRAIL_BYTE(bTrailByte));
1269 return TRUE;
1270}
1271
1272#ifdef USE_CHECKED_OBJECTREFS
1273
1274//-------------------------------------------------------------
1275// Default constructor, for non-initializing declarations:
1276//
1277// OBJECTREF or;
1278//-------------------------------------------------------------
1279OBJECTREF::OBJECTREF()
1280{
1281 STATIC_CONTRACT_NOTHROW;
1282 STATIC_CONTRACT_GC_NOTRIGGER;
1283 STATIC_CONTRACT_FORBID_FAULT;
1284
1285 STATIC_CONTRACT_VIOLATION(SOToleranceViolation);
1286
1287 m_asObj = (Object*)POISONC;
1288 Thread::ObjectRefNew(this);
1289}
1290
1291//-------------------------------------------------------------
1292// Copy constructor, for passing OBJECTREF's as function arguments.
1293//-------------------------------------------------------------
1294OBJECTREF::OBJECTREF(const OBJECTREF & objref)
1295{
1296 STATIC_CONTRACT_NOTHROW;
1297 STATIC_CONTRACT_GC_NOTRIGGER;
1298 STATIC_CONTRACT_MODE_COOPERATIVE;
1299 STATIC_CONTRACT_FORBID_FAULT;
1300
1301 STATIC_CONTRACT_VIOLATION(SOToleranceViolation);
1302
1303 VALIDATEOBJECT(objref.m_asObj);
1304
1305 // !!! If this assert is fired, there are two possibilities:
1306 // !!! 1. You are doing a type cast, e.g. *(OBJECTREF*)pObj
1307 // !!! Instead, you should use ObjectToOBJECTREF(*(Object**)pObj),
1308 // !!! or ObjectToSTRINGREF(*(StringObject**)pObj)
1309 // !!! 2. There is a real GC hole here.
1310 // !!! Either way you need to fix the code.
1311 _ASSERTE(Thread::IsObjRefValid(&objref));
1312 if ((objref.m_asObj != 0) &&
1313 ((IGCHeap*)GCHeapUtilities::GetGCHeap())->IsHeapPointer( (BYTE*)this ))
1314 {
1315 _ASSERTE(!"Write Barrier violation. Must use SetObjectReference() to assign OBJECTREF's into the GC heap!");
1316 }
1317 m_asObj = objref.m_asObj;
1318
1319 if (m_asObj != 0) {
1320 ENABLESTRESSHEAP();
1321 }
1322
1323 Thread::ObjectRefNew(this);
1324}
1325
1326
1327//-------------------------------------------------------------
1328// To allow NULL to be used as an OBJECTREF.
1329//-------------------------------------------------------------
1330OBJECTREF::OBJECTREF(TADDR nul)
1331{
1332 STATIC_CONTRACT_NOTHROW;
1333 STATIC_CONTRACT_GC_NOTRIGGER;
1334 STATIC_CONTRACT_FORBID_FAULT;
1335
1336 STATIC_CONTRACT_VIOLATION(SOToleranceViolation);
1337
1338 //_ASSERTE(nul == 0);
1339 m_asObj = (Object*)nul;
1340 if( m_asObj != NULL)
1341 {
1342 // REVISIT_TODO: fix this, why is this constructor being used for non-null object refs?
1343 STATIC_CONTRACT_VIOLATION(ModeViolation);
1344
1345 VALIDATEOBJECT(m_asObj);
1346 ENABLESTRESSHEAP();
1347 }
1348 Thread::ObjectRefNew(this);
1349}
1350
1351//-------------------------------------------------------------
1352// This is for the GC's use only. Non-GC code should never
1353// use the "Object" class directly. The unused "int" argument
1354// prevents C++ from using this to implicitly convert Object*'s
1355// to OBJECTREF.
1356//-------------------------------------------------------------
1357OBJECTREF::OBJECTREF(Object *pObject)
1358{
1359 STATIC_CONTRACT_NOTHROW;
1360 STATIC_CONTRACT_GC_NOTRIGGER;
1361 STATIC_CONTRACT_MODE_COOPERATIVE;
1362 STATIC_CONTRACT_FORBID_FAULT;
1363
1364 DEBUG_ONLY_FUNCTION;
1365
1366 if ((pObject != 0) &&
1367 ((IGCHeap*)GCHeapUtilities::GetGCHeap())->IsHeapPointer( (BYTE*)this ))
1368 {
1369 _ASSERTE(!"Write Barrier violation. Must use SetObjectReference() to assign OBJECTREF's into the GC heap!");
1370 }
1371 m_asObj = pObject;
1372 VALIDATEOBJECT(m_asObj);
1373 if (m_asObj != 0) {
1374 ENABLESTRESSHEAP();
1375 }
1376 Thread::ObjectRefNew(this);
1377}
1378
1379void OBJECTREF::Validate(BOOL bDeep, BOOL bVerifyNextHeader, BOOL bVerifySyncBlock)
1380{
1381 LIMITED_METHOD_CONTRACT;
1382 m_asObj->Validate(bDeep, bVerifyNextHeader, bVerifySyncBlock);
1383}
1384
1385//-------------------------------------------------------------
1386// Test against NULL.
1387//-------------------------------------------------------------
1388int OBJECTREF::operator!() const
1389{
1390 STATIC_CONTRACT_NOTHROW;
1391 STATIC_CONTRACT_GC_NOTRIGGER;
1392 STATIC_CONTRACT_FORBID_FAULT;
1393
1394 // We don't do any validation here, as we want to allow zero comparison in preemptive mode
1395 return !m_asObj;
1396}
1397
1398//-------------------------------------------------------------
1399// Compare two OBJECTREF's.
1400//-------------------------------------------------------------
1401int OBJECTREF::operator==(const OBJECTREF &objref) const
1402{
1403 STATIC_CONTRACT_NOTHROW;
1404 STATIC_CONTRACT_GC_NOTRIGGER;
1405 STATIC_CONTRACT_FORBID_FAULT;
1406
1407 if (objref.m_asObj != NULL) // Allow comparison to zero in preemptive mode
1408 {
1409 // REVISIT_TODO: Weakening the contract system a little bit here. We should really
1410 // add a special NULLOBJECTREF which can be used for these situations and have
1411 // a seperate code path for that with the correct contract protections.
1412 STATIC_CONTRACT_VIOLATION(ModeViolation);
1413
1414 VALIDATEOBJECT(objref.m_asObj);
1415
1416 // !!! If this assert is fired, there are two possibilities:
1417 // !!! 1. You are doing a type cast, e.g. *(OBJECTREF*)pObj
1418 // !!! Instead, you should use ObjectToOBJECTREF(*(Object**)pObj),
1419 // !!! or ObjectToSTRINGREF(*(StringObject**)pObj)
1420 // !!! 2. There is a real GC hole here.
1421 // !!! Either way you need to fix the code.
1422 _ASSERTE(Thread::IsObjRefValid(&objref));
1423 VALIDATEOBJECT(m_asObj);
1424 // If this assert fires, you probably did not protect
1425 // your OBJECTREF and a GC might have occurred. To
1426 // where the possible GC was, set a breakpoint in Thread::TriggersGC
1427 _ASSERTE(Thread::IsObjRefValid(this));
1428
1429 if (m_asObj != 0 || objref.m_asObj != 0) {
1430 ENABLESTRESSHEAP();
1431 }
1432 }
1433 return m_asObj == objref.m_asObj;
1434}
1435
1436//-------------------------------------------------------------
1437// Compare two OBJECTREF's.
1438//-------------------------------------------------------------
1439int OBJECTREF::operator!=(const OBJECTREF &objref) const
1440{
1441 STATIC_CONTRACT_NOTHROW;
1442 STATIC_CONTRACT_GC_NOTRIGGER;
1443 STATIC_CONTRACT_FORBID_FAULT;
1444
1445 if (objref.m_asObj != NULL) // Allow comparison to zero in preemptive mode
1446 {
1447 // REVISIT_TODO: Weakening the contract system a little bit here. We should really
1448 // add a special NULLOBJECTREF which can be used for these situations and have
1449 // a seperate code path for that with the correct contract protections.
1450 STATIC_CONTRACT_VIOLATION(ModeViolation);
1451
1452 VALIDATEOBJECT(objref.m_asObj);
1453
1454 // !!! If this assert is fired, there are two possibilities:
1455 // !!! 1. You are doing a type cast, e.g. *(OBJECTREF*)pObj
1456 // !!! Instead, you should use ObjectToOBJECTREF(*(Object**)pObj),
1457 // !!! or ObjectToSTRINGREF(*(StringObject**)pObj)
1458 // !!! 2. There is a real GC hole here.
1459 // !!! Either way you need to fix the code.
1460 _ASSERTE(Thread::IsObjRefValid(&objref));
1461 VALIDATEOBJECT(m_asObj);
1462 // If this assert fires, you probably did not protect
1463 // your OBJECTREF and a GC might have occurred. To
1464 // where the possible GC was, set a breakpoint in Thread::TriggersGC
1465 _ASSERTE(Thread::IsObjRefValid(this));
1466
1467 if (m_asObj != 0 || objref.m_asObj != 0) {
1468 ENABLESTRESSHEAP();
1469 }
1470 }
1471
1472 return m_asObj != objref.m_asObj;
1473}
1474
1475
1476//-------------------------------------------------------------
1477// Forward method calls.
1478//-------------------------------------------------------------
1479Object* OBJECTREF::operator->()
1480{
1481 STATIC_CONTRACT_NOTHROW;
1482 STATIC_CONTRACT_GC_NOTRIGGER;
1483 STATIC_CONTRACT_FORBID_FAULT;
1484
1485 VALIDATEOBJECT(m_asObj);
1486 // If this assert fires, you probably did not protect
1487 // your OBJECTREF and a GC might have occurred. To
1488 // where the possible GC was, set a breakpoint in Thread::TriggersGC
1489 _ASSERTE(Thread::IsObjRefValid(this));
1490
1491 if (m_asObj != 0) {
1492 ENABLESTRESSHEAP();
1493 }
1494
1495 // if you are using OBJECTREF directly,
1496 // you probably want an Object *
1497 return (Object *)m_asObj;
1498}
1499
1500
1501//-------------------------------------------------------------
1502// Forward method calls.
1503//-------------------------------------------------------------
1504const Object* OBJECTREF::operator->() const
1505{
1506 STATIC_CONTRACT_NOTHROW;
1507 STATIC_CONTRACT_GC_NOTRIGGER;
1508 STATIC_CONTRACT_FORBID_FAULT;
1509
1510 VALIDATEOBJECT(m_asObj);
1511 // If this assert fires, you probably did not protect
1512 // your OBJECTREF and a GC might have occurred. To
1513 // where the possible GC was, set a breakpoint in Thread::TriggersGC
1514 _ASSERTE(Thread::IsObjRefValid(this));
1515
1516 if (m_asObj != 0) {
1517 ENABLESTRESSHEAP();
1518 }
1519
1520 // if you are using OBJECTREF directly,
1521 // you probably want an Object *
1522 return (Object *)m_asObj;
1523}
1524
1525
1526//-------------------------------------------------------------
1527// Assignment. We don't validate the destination so as not
1528// to break the sequence:
1529//
1530// OBJECTREF or;
1531// or = ...;
1532//-------------------------------------------------------------
1533OBJECTREF& OBJECTREF::operator=(const OBJECTREF &objref)
1534{
1535 STATIC_CONTRACT_NOTHROW;
1536 STATIC_CONTRACT_GC_NOTRIGGER;
1537 STATIC_CONTRACT_FORBID_FAULT;
1538
1539 VALIDATEOBJECT(objref.m_asObj);
1540
1541 // !!! If this assert is fired, there are two possibilities:
1542 // !!! 1. You are doing a type cast, e.g. *(OBJECTREF*)pObj
1543 // !!! Instead, you should use ObjectToOBJECTREF(*(Object**)pObj),
1544 // !!! or ObjectToSTRINGREF(*(StringObject**)pObj)
1545 // !!! 2. There is a real GC hole here.
1546 // !!! Either way you need to fix the code.
1547 _ASSERTE(Thread::IsObjRefValid(&objref));
1548
1549 if ((objref.m_asObj != 0) &&
1550 ((IGCHeap*)GCHeapUtilities::GetGCHeap())->IsHeapPointer( (BYTE*)this ))
1551 {
1552 _ASSERTE(!"Write Barrier violation. Must use SetObjectReference() to assign OBJECTREF's into the GC heap!");
1553 }
1554 Thread::ObjectRefAssign(this);
1555
1556 m_asObj = objref.m_asObj;
1557 if (m_asObj != 0) {
1558 ENABLESTRESSHEAP();
1559 }
1560 return *this;
1561}
1562
1563//-------------------------------------------------------------
1564// Allows for the assignment of NULL to a OBJECTREF
1565//-------------------------------------------------------------
1566
1567OBJECTREF& OBJECTREF::operator=(TADDR nul)
1568{
1569 STATIC_CONTRACT_NOTHROW;
1570 STATIC_CONTRACT_GC_NOTRIGGER;
1571 STATIC_CONTRACT_FORBID_FAULT;
1572
1573 _ASSERTE(nul == 0);
1574 Thread::ObjectRefAssign(this);
1575 m_asObj = (Object*)nul;
1576 if (m_asObj != 0) {
1577 ENABLESTRESSHEAP();
1578 }
1579 return *this;
1580}
1581#endif // DEBUG
1582
1583#ifdef _DEBUG
1584
1585void* __cdecl GCSafeMemCpy(void * dest, const void * src, size_t len)
1586{
1587 STATIC_CONTRACT_NOTHROW;
1588 STATIC_CONTRACT_GC_NOTRIGGER;
1589 STATIC_CONTRACT_FORBID_FAULT;
1590 STATIC_CONTRACT_SO_TOLERANT;
1591
1592 if (!(((*(BYTE**)&dest) < g_lowest_address ) ||
1593 ((*(BYTE**)&dest) >= g_highest_address)))
1594 {
1595 Thread* pThread = GetThread();
1596
1597 // GCHeapUtilities::IsHeapPointer has race when called in preemptive mode. It walks the list of segments
1598 // that can be modified by GC. Do the check below only if it is safe to do so.
1599 if (pThread != NULL && pThread->PreemptiveGCDisabled())
1600 {
1601 // Note there is memcpyNoGCRefs which will allow you to do a memcpy into the GC
1602 // heap if you really know you don't need to call the write barrier
1603
1604 _ASSERTE(!GCHeapUtilities::GetGCHeap()->IsHeapPointer((BYTE *) dest) ||
1605 !"using memcpy to copy into the GC heap, use CopyValueClass");
1606 }
1607 }
1608 return memcpyNoGCRefs(dest, src, len);
1609}
1610
1611#endif // _DEBUG
1612
1613// This function clears a piece of memory in a GC safe way. It makes the guarantee
1614// that it will clear memory in at least pointer sized chunks whenever possible.
1615// Unaligned memory at the beginning and remaining bytes at the end are written bytewise.
1616// We must make this guarantee whenever we clear memory in the GC heap that could contain
1617// object references. The GC or other user threads can read object references at any time,
1618// clearing them bytewise can result in a read on another thread getting incorrect data.
1619void __fastcall ZeroMemoryInGCHeap(void* mem, size_t size)
1620{
1621 WRAPPER_NO_CONTRACT;
1622 BYTE* memBytes = (BYTE*) mem;
1623 BYTE* endBytes = &memBytes[size];
1624
1625 // handle unaligned bytes at the beginning
1626 while (!IS_ALIGNED(memBytes, sizeof(PTR_PTR_VOID)) && memBytes < endBytes)
1627 *memBytes++ = 0;
1628
1629 // now write pointer sized pieces
1630 // volatile ensures that this doesn't get optimized back into a memset call
1631 size_t nPtrs = (endBytes - memBytes) / sizeof(PTR_PTR_VOID);
1632 PTR_VOID volatile * memPtr = (PTR_PTR_VOID) memBytes;
1633 for (size_t i = 0; i < nPtrs; i++)
1634 *memPtr++ = 0;
1635
1636 // handle remaining bytes at the end
1637 memBytes = (BYTE*) memPtr;
1638 while (memBytes < endBytes)
1639 *memBytes++ = 0;
1640}
1641
1642void StackTraceArray::Append(StackTraceElement const * begin, StackTraceElement const * end)
1643{
1644 CONTRACTL
1645 {
1646 THROWS;
1647 GC_TRIGGERS;
1648 MODE_COOPERATIVE;
1649 PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
1650 }
1651 CONTRACTL_END;
1652
1653 // ensure that only one thread can write to the array
1654 EnsureThreadAffinity();
1655
1656 size_t newsize = Size() + (end - begin);
1657 Grow(newsize);
1658 memcpyNoGCRefs(GetData() + Size(), begin, (end - begin) * sizeof(StackTraceElement));
1659 MemoryBarrier(); // prevent the newsize from being reordered with the array copy
1660 SetSize(newsize);
1661
1662#if defined(_DEBUG)
1663 CheckState();
1664#endif
1665}
1666
1667void StackTraceArray::CheckState() const
1668{
1669 CONTRACTL
1670 {
1671 NOTHROW;
1672 GC_NOTRIGGER;
1673 MODE_COOPERATIVE;
1674 }
1675 CONTRACTL_END;
1676
1677 if (!m_array)
1678 return;
1679
1680 assert(GetObjectThread() == GetThread());
1681
1682 size_t size = Size();
1683 StackTraceElement const * p;
1684 p = GetData();
1685 for (size_t i = 0; i < size; ++i)
1686 assert(p[i].pFunc != NULL);
1687}
1688
1689void StackTraceArray::Grow(size_t grow_size)
1690{
1691 CONTRACTL
1692 {
1693 THROWS;
1694 GC_TRIGGERS;
1695 MODE_COOPERATIVE;
1696 INJECT_FAULT(ThrowOutOfMemory(););
1697 PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
1698 }
1699 CONTRACTL_END;
1700
1701 size_t raw_size = grow_size * sizeof(StackTraceElement) + sizeof(ArrayHeader);
1702
1703 if (!m_array)
1704 {
1705 SetArray(I1ARRAYREF(AllocatePrimitiveArray(ELEMENT_TYPE_I1, static_cast<DWORD>(raw_size))));
1706 SetSize(0);
1707 SetObjectThread();
1708 }
1709 else
1710 {
1711 if (Capacity() >= raw_size)
1712 return;
1713
1714 // allocate a new array, copy the data
1715 size_t new_capacity = Max(Capacity() * 2, raw_size);
1716
1717 _ASSERTE(new_capacity >= grow_size * sizeof(StackTraceElement) + sizeof(ArrayHeader));
1718
1719 I1ARRAYREF newarr = (I1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I1, static_cast<DWORD>(new_capacity));
1720 memcpyNoGCRefs(newarr->GetDirectPointerToNonObjectElements(),
1721 GetRaw(),
1722 Size() * sizeof(StackTraceElement) + sizeof(ArrayHeader));
1723
1724 SetArray(newarr);
1725 }
1726}
1727
1728void StackTraceArray::EnsureThreadAffinity()
1729{
1730 WRAPPER_NO_CONTRACT;
1731
1732 if (!m_array)
1733 return;
1734
1735 if (GetObjectThread() != GetThread())
1736 {
1737 // object is being changed by a thread different from the one which created it
1738 // make a copy of the array to prevent a race condition when two different threads try to change it
1739 StackTraceArray copy;
1740 GCPROTECT_BEGIN(copy);
1741 copy.CopyFrom(*this);
1742 this->Swap(copy);
1743 GCPROTECT_END();
1744 }
1745}
1746
1747#ifdef _MSC_VER
1748#pragma warning(disable: 4267)
1749#endif
1750
1751// Deep copies the stack trace array
1752void StackTraceArray::CopyFrom(StackTraceArray const & src)
1753{
1754 CONTRACTL
1755 {
1756 THROWS;
1757 GC_TRIGGERS;
1758 MODE_COOPERATIVE;
1759 INJECT_FAULT(ThrowOutOfMemory(););
1760 PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)this));
1761 PRECONDITION(IsProtectedByGCFrame((OBJECTREF*)&src));
1762 }
1763 CONTRACTL_END;
1764
1765 m_array = (I1ARRAYREF) AllocatePrimitiveArray(ELEMENT_TYPE_I1, static_cast<DWORD>(src.Capacity()));
1766
1767 Volatile<size_t> size = src.Size();
1768 memcpyNoGCRefs(GetRaw(), src.GetRaw(), size * sizeof(StackTraceElement) + sizeof(ArrayHeader));
1769
1770 SetSize(size); // set size to the exact value which was used when we copied the data
1771 // another thread might have changed it at the time of copying
1772 SetObjectThread(); // affinitize the newly created array with the current thread
1773}
1774
1775#ifdef _MSC_VER
1776#pragma warning(default: 4267)
1777#endif
1778
1779
1780#ifdef _DEBUG
1781//===============================================================================
1782// Code that insures that our unmanaged version of Nullable is consistant with
1783// the managed version Nullable<T> for all T.
1784
1785void Nullable::CheckFieldOffsets(TypeHandle nullableType)
1786{
1787 LIMITED_METHOD_CONTRACT;
1788
1789/***
1790 // The non-instantiated method tables like List<T> that are used
1791 // by reflection and verification do not have correct field offsets
1792 // but we never make instances of these anyway.
1793 if (nullableMT->ContainsGenericVariables())
1794 return;
1795***/
1796
1797 MethodTable* nullableMT = nullableType.GetMethodTable();
1798
1799 // insure that the managed version of the table is the same as the
1800 // unmanaged. Note that we can't do this in mscorlib.h because this
1801 // class is generic and field layout depends on the instantiation.
1802
1803 _ASSERTE(nullableMT->GetNumInstanceFields() == 2);
1804 FieldDesc* field = nullableMT->GetApproxFieldDescListRaw();
1805
1806 _ASSERTE(strcmp(field->GetDebugName(), "hasValue") == 0);
1807// _ASSERTE(field->GetOffset() == offsetof(Nullable, hasValue));
1808 field++;
1809
1810 _ASSERTE(strcmp(field->GetDebugName(), "value") == 0);
1811// _ASSERTE(field->GetOffset() == offsetof(Nullable, value));
1812}
1813#endif
1814
1815//===============================================================================
1816// Returns true if nullableMT is Nullable<T> for T is equivalent to paramMT
1817
1818BOOL Nullable::IsNullableForTypeHelper(MethodTable* nullableMT, MethodTable* paramMT)
1819{
1820 CONTRACTL
1821 {
1822 THROWS;
1823 GC_TRIGGERS;
1824 SO_TOLERANT;
1825 MODE_ANY;
1826 }
1827 CONTRACTL_END;
1828 if (!nullableMT->IsNullable())
1829 return FALSE;
1830
1831 // we require the parameter types to be equivalent
1832 return TypeHandle(paramMT).IsEquivalentTo(nullableMT->GetInstantiation()[0]);
1833}
1834
1835//===============================================================================
1836// Returns true if nullableMT is Nullable<T> for T == paramMT
1837
1838BOOL Nullable::IsNullableForTypeHelperNoGC(MethodTable* nullableMT, MethodTable* paramMT)
1839{
1840 LIMITED_METHOD_CONTRACT;
1841 if (!nullableMT->IsNullable())
1842 return FALSE;
1843
1844 // we require an exact match of the parameter types
1845 return TypeHandle(paramMT) == nullableMT->GetInstantiation()[0];
1846}
1847
1848//===============================================================================
1849CLR_BOOL* Nullable::HasValueAddr(MethodTable* nullableMT) {
1850
1851 LIMITED_METHOD_CONTRACT;
1852
1853 _ASSERTE(strcmp(nullableMT->GetApproxFieldDescListRaw()[0].GetDebugName(), "hasValue") == 0);
1854 _ASSERTE(nullableMT->GetApproxFieldDescListRaw()[0].GetOffset() == 0);
1855 return (CLR_BOOL*) this;
1856}
1857
1858//===============================================================================
1859void* Nullable::ValueAddr(MethodTable* nullableMT) {
1860
1861 LIMITED_METHOD_CONTRACT;
1862
1863 _ASSERTE(strcmp(nullableMT->GetApproxFieldDescListRaw()[1].GetDebugName(), "value") == 0);
1864 return (((BYTE*) this) + nullableMT->GetApproxFieldDescListRaw()[1].GetOffset());
1865}
1866
1867//===============================================================================
1868// Special Logic to box a nullable<T> as a boxed<T>
1869
1870OBJECTREF Nullable::Box(void* srcPtr, MethodTable* nullableMT)
1871{
1872 CONTRACTL
1873 {
1874 THROWS;
1875 GC_TRIGGERS;
1876 MODE_COOPERATIVE;
1877 }
1878 CONTRACTL_END;
1879
1880 FAULT_NOT_FATAL(); // FIX_NOW: why do we need this?
1881
1882 Nullable* src = (Nullable*) srcPtr;
1883
1884 _ASSERTE(IsNullableType(nullableMT));
1885 // We better have a concrete instantiation, or our field offset asserts are not useful
1886 _ASSERTE(!nullableMT->ContainsGenericVariables());
1887
1888 if (!*src->HasValueAddr(nullableMT))
1889 return NULL;
1890
1891 OBJECTREF obj = 0;
1892 GCPROTECT_BEGININTERIOR (src);
1893 MethodTable* argMT = nullableMT->GetInstantiation()[0].GetMethodTable();
1894 obj = argMT->Allocate();
1895 CopyValueClass(obj->UnBox(), src->ValueAddr(nullableMT), argMT, obj->GetAppDomain());
1896 GCPROTECT_END ();
1897
1898 return obj;
1899}
1900
1901//===============================================================================
1902// Special Logic to unbox a boxed T as a nullable<T>
1903
1904BOOL Nullable::UnBox(void* destPtr, OBJECTREF boxedVal, MethodTable* destMT)
1905{
1906 CONTRACTL
1907 {
1908 THROWS;
1909 GC_TRIGGERS;
1910 MODE_COOPERATIVE;
1911 SO_TOLERANT;
1912 }
1913 CONTRACTL_END;
1914 Nullable* dest = (Nullable*) destPtr;
1915 BOOL fRet = TRUE;
1916
1917 // We should only get here if we are unboxing a T as a Nullable<T>
1918 _ASSERTE(IsNullableType(destMT));
1919
1920 // We better have a concrete instantiation, or our field offset asserts are not useful
1921 _ASSERTE(!destMT->ContainsGenericVariables());
1922
1923 if (boxedVal == NULL)
1924 {
1925 // Logically we are doing *dest->HasValueAddr(destMT) = false;
1926 // We zero out the whole structure becasue it may contain GC references
1927 // and these need to be initialized to zero. (could optimize in the non-GC case)
1928 InitValueClass(destPtr, destMT);
1929 fRet = TRUE;
1930 }
1931 else
1932 {
1933 GCPROTECT_BEGIN(boxedVal);
1934 if (!IsNullableForType(destMT, boxedVal->GetMethodTable()))
1935 {
1936 // For safety's sake, also allow true nullables to be unboxed normally.
1937 // This should not happen normally, but we want to be robust
1938 if (destMT->IsEquivalentTo(boxedVal->GetMethodTable()))
1939 {
1940 CopyValueClass(dest, boxedVal->GetData(), destMT, boxedVal->GetAppDomain());
1941 fRet = TRUE;
1942 }
1943 else
1944 {
1945 fRet = FALSE;
1946 }
1947 }
1948 else
1949 {
1950 *dest->HasValueAddr(destMT) = true;
1951 CopyValueClass(dest->ValueAddr(destMT), boxedVal->UnBox(), boxedVal->GetMethodTable(), boxedVal->GetAppDomain());
1952 fRet = TRUE;
1953 }
1954 GCPROTECT_END();
1955 }
1956 return fRet;
1957}
1958
1959//===============================================================================
1960// Special Logic to unbox a boxed T as a nullable<T>
1961// Does not handle type equivalence (may conservatively return FALSE)
1962BOOL Nullable::UnBoxNoGC(void* destPtr, OBJECTREF boxedVal, MethodTable* destMT)
1963{
1964 CONTRACTL
1965 {
1966 NOTHROW;
1967 GC_NOTRIGGER;
1968 MODE_COOPERATIVE;
1969 SO_TOLERANT;
1970 }
1971 CONTRACTL_END;
1972 Nullable* dest = (Nullable*) destPtr;
1973
1974 // We should only get here if we are unboxing a T as a Nullable<T>
1975 _ASSERTE(IsNullableType(destMT));
1976
1977 // We better have a concrete instantiation, or our field offset asserts are not useful
1978 _ASSERTE(!destMT->ContainsGenericVariables());
1979
1980 if (boxedVal == NULL)
1981 {
1982 // Logically we are doing *dest->HasValueAddr(destMT) = false;
1983 // We zero out the whole structure becasue it may contain GC references
1984 // and these need to be initialized to zero. (could optimize in the non-GC case)
1985 InitValueClass(destPtr, destMT);
1986 }
1987 else
1988 {
1989 if (!IsNullableForTypeNoGC(destMT, boxedVal->GetMethodTable()))
1990 {
1991 // For safety's sake, also allow true nullables to be unboxed normally.
1992 // This should not happen normally, but we want to be robust
1993 if (destMT == boxedVal->GetMethodTable())
1994 {
1995 CopyValueClass(dest, boxedVal->GetData(), destMT, boxedVal->GetAppDomain());
1996 return TRUE;
1997 }
1998 return FALSE;
1999 }
2000
2001 *dest->HasValueAddr(destMT) = true;
2002 CopyValueClass(dest->ValueAddr(destMT), boxedVal->UnBox(), boxedVal->GetMethodTable(), boxedVal->GetAppDomain());
2003 }
2004 return TRUE;
2005}
2006
2007//===============================================================================
2008// Special Logic to unbox a boxed T as a nullable<T> into an argument
2009// specified by the argDest.
2010// Does not handle type equivalence (may conservatively return FALSE)
2011BOOL Nullable::UnBoxIntoArgNoGC(ArgDestination *argDest, OBJECTREF boxedVal, MethodTable* destMT)
2012{
2013 CONTRACTL
2014 {
2015 NOTHROW;
2016 GC_NOTRIGGER;
2017 MODE_COOPERATIVE;
2018 SO_TOLERANT;
2019 }
2020 CONTRACTL_END;
2021
2022#if defined(UNIX_AMD64_ABI)
2023 if (argDest->IsStructPassedInRegs())
2024 {
2025 // We should only get here if we are unboxing a T as a Nullable<T>
2026 _ASSERTE(IsNullableType(destMT));
2027
2028 // We better have a concrete instantiation, or our field offset asserts are not useful
2029 _ASSERTE(!destMT->ContainsGenericVariables());
2030
2031 if (boxedVal == NULL)
2032 {
2033 // Logically we are doing *dest->HasValueAddr(destMT) = false;
2034 // We zero out the whole structure becasue it may contain GC references
2035 // and these need to be initialized to zero. (could optimize in the non-GC case)
2036 InitValueClassArg(argDest, destMT);
2037 }
2038 else
2039 {
2040 if (!IsNullableForTypeNoGC(destMT, boxedVal->GetMethodTable()))
2041 {
2042 // For safety's sake, also allow true nullables to be unboxed normally.
2043 // This should not happen normally, but we want to be robust
2044 if (destMT == boxedVal->GetMethodTable())
2045 {
2046 CopyValueClassArg(argDest, boxedVal->GetData(), destMT, boxedVal->GetAppDomain(), 0);
2047 return TRUE;
2048 }
2049 return FALSE;
2050 }
2051
2052 Nullable* dest = (Nullable*)argDest->GetStructGenRegDestinationAddress();
2053 *dest->HasValueAddr(destMT) = true;
2054 int destOffset = (BYTE*)dest->ValueAddr(destMT) - (BYTE*)dest;
2055 CopyValueClassArg(argDest, boxedVal->UnBox(), boxedVal->GetMethodTable(), boxedVal->GetAppDomain(), destOffset);
2056 }
2057 return TRUE;
2058 }
2059
2060#endif // UNIX_AMD64_ABI
2061
2062 return UnBoxNoGC(argDest->GetDestinationAddress(), boxedVal, destMT);
2063}
2064
2065//===============================================================================
2066// Special Logic to unbox a boxed T as a nullable<T>
2067// Does not do any type checks.
2068void Nullable::UnBoxNoCheck(void* destPtr, OBJECTREF boxedVal, MethodTable* destMT)
2069{
2070 CONTRACTL
2071 {
2072 NOTHROW;
2073 GC_NOTRIGGER;
2074 MODE_COOPERATIVE;
2075 SO_TOLERANT;
2076 }
2077 CONTRACTL_END;
2078 Nullable* dest = (Nullable*) destPtr;
2079
2080 // We should only get here if we are unboxing a T as a Nullable<T>
2081 _ASSERTE(IsNullableType(destMT));
2082
2083 // We better have a concrete instantiation, or our field offset asserts are not useful
2084 _ASSERTE(!destMT->ContainsGenericVariables());
2085
2086 if (boxedVal == NULL)
2087 {
2088 // Logically we are doing *dest->HasValueAddr(destMT) = false;
2089 // We zero out the whole structure becasue it may contain GC references
2090 // and these need to be initialized to zero. (could optimize in the non-GC case)
2091 InitValueClass(destPtr, destMT);
2092 }
2093 else
2094 {
2095 if (IsNullableType(boxedVal->GetMethodTable()))
2096 {
2097 // For safety's sake, also allow true nullables to be unboxed normally.
2098 // This should not happen normally, but we want to be robust
2099 CopyValueClass(dest, boxedVal->GetData(), destMT, boxedVal->GetAppDomain());
2100 }
2101
2102 *dest->HasValueAddr(destMT) = true;
2103 CopyValueClass(dest->ValueAddr(destMT), boxedVal->UnBox(), boxedVal->GetMethodTable(), boxedVal->GetAppDomain());
2104 }
2105}
2106
2107//===============================================================================
2108// a boxed Nullable<T> should either be null or a boxed T, but sometimes it is
2109// useful to have a 'true' boxed Nullable<T> (that is it has two fields). This
2110// function returns a 'normalized' version of this pointer.
2111
2112OBJECTREF Nullable::NormalizeBox(OBJECTREF obj) {
2113 CONTRACTL
2114 {
2115 THROWS;
2116 GC_TRIGGERS;
2117 MODE_COOPERATIVE;
2118 }
2119 CONTRACTL_END;
2120
2121 if (obj != NULL) {
2122 MethodTable* retMT = obj->GetMethodTable();
2123 if (Nullable::IsNullableType(retMT))
2124 obj = Nullable::Box(obj->GetData(), retMT);
2125 }
2126 return obj;
2127}
2128
2129
2130void ThreadBaseObject::SetInternal(Thread *it)
2131{
2132 WRAPPER_NO_CONTRACT;
2133
2134 // only allow a transition from NULL to non-NULL
2135 _ASSERTE((m_InternalThread == NULL) && (it != NULL));
2136 m_InternalThread = it;
2137
2138 // Now the native Thread will only be destroyed after the managed Thread is collected.
2139 // Tell the GC that the managed Thread actually represents much more memory.
2140 GCInterface::NewAddMemoryPressure(sizeof(Thread));
2141}
2142
2143void ThreadBaseObject::ClearInternal()
2144{
2145 WRAPPER_NO_CONTRACT;
2146
2147 _ASSERTE(m_InternalThread != NULL);
2148 m_InternalThread = NULL;
2149 GCInterface::NewRemoveMemoryPressure(sizeof(Thread));
2150}
2151
2152#endif // #ifndef DACCESS_COMPILE
2153
2154
2155StackTraceElement const & StackTraceArray::operator[](size_t index) const
2156{
2157 WRAPPER_NO_CONTRACT;
2158 return GetData()[index];
2159}
2160
2161StackTraceElement & StackTraceArray::operator[](size_t index)
2162{
2163 WRAPPER_NO_CONTRACT;
2164 return GetData()[index];
2165}
2166
2167#if !defined(DACCESS_COMPILE)
2168// Define the lock used to access stacktrace from an exception object
2169SpinLock g_StackTraceArrayLock;
2170
2171void ExceptionObject::SetStackTrace(StackTraceArray const & stackTrace, PTRARRAYREF dynamicMethodArray)
2172{
2173 CONTRACTL
2174 {
2175 GC_NOTRIGGER;
2176 NOTHROW;
2177 MODE_COOPERATIVE;
2178 SO_TOLERANT;
2179 }
2180 CONTRACTL_END;
2181
2182 Thread *m_pThread = GetThread();
2183 SpinLock::AcquireLock(&g_StackTraceArrayLock, SPINLOCK_THREAD_PARAM_ONLY_IN_SOME_BUILDS);
2184
2185 SetObjectReference((OBJECTREF*)&_stackTrace, (OBJECTREF)stackTrace.Get(), GetAppDomain());
2186 SetObjectReference((OBJECTREF*)&_dynamicMethods, (OBJECTREF)dynamicMethodArray, GetAppDomain());
2187
2188 SpinLock::ReleaseLock(&g_StackTraceArrayLock, SPINLOCK_THREAD_PARAM_ONLY_IN_SOME_BUILDS);
2189
2190}
2191
2192void ExceptionObject::SetNullStackTrace()
2193{
2194 CONTRACTL
2195 {
2196 GC_NOTRIGGER;
2197 NOTHROW;
2198 MODE_COOPERATIVE;
2199 SO_TOLERANT;
2200 }
2201 CONTRACTL_END;
2202
2203 Thread *m_pThread = GetThread();
2204 SpinLock::AcquireLock(&g_StackTraceArrayLock, SPINLOCK_THREAD_PARAM_ONLY_IN_SOME_BUILDS);
2205
2206 I1ARRAYREF stackTraceArray = NULL;
2207 PTRARRAYREF dynamicMethodArray = NULL;
2208
2209 SetObjectReference((OBJECTREF*)&_stackTrace, (OBJECTREF)stackTraceArray, GetAppDomain());
2210 SetObjectReference((OBJECTREF*)&_dynamicMethods, (OBJECTREF)dynamicMethodArray, GetAppDomain());
2211
2212 SpinLock::ReleaseLock(&g_StackTraceArrayLock, SPINLOCK_THREAD_PARAM_ONLY_IN_SOME_BUILDS);
2213}
2214
2215#endif // !defined(DACCESS_COMPILE)
2216
2217void ExceptionObject::GetStackTrace(StackTraceArray & stackTrace, PTRARRAYREF * outDynamicMethodArray /*= NULL*/) const
2218{
2219 CONTRACTL
2220 {
2221 GC_NOTRIGGER;
2222 NOTHROW;
2223 MODE_COOPERATIVE;
2224 SO_TOLERANT;
2225 }
2226 CONTRACTL_END;
2227
2228#if !defined(DACCESS_COMPILE)
2229 Thread *m_pThread = GetThread();
2230 SpinLock::AcquireLock(&g_StackTraceArrayLock, SPINLOCK_THREAD_PARAM_ONLY_IN_SOME_BUILDS);
2231#endif // !defined(DACCESS_COMPILE)
2232
2233 StackTraceArray temp(_stackTrace);
2234 stackTrace.Swap(temp);
2235
2236 if (outDynamicMethodArray != NULL)
2237 {
2238 *outDynamicMethodArray = _dynamicMethods;
2239 }
2240
2241#if !defined(DACCESS_COMPILE)
2242 SpinLock::ReleaseLock(&g_StackTraceArrayLock, SPINLOCK_THREAD_PARAM_ONLY_IN_SOME_BUILDS);
2243#endif // !defined(DACCESS_COMPILE)
2244
2245}
2246