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
6#include "common.h"
7#include "objectlist.h"
8
9#ifndef DACCESS_COMPILE
10
11ObjectList::ObjectList( void )
12: freeIndexHead_( INVALID_COMPRESSEDSTACK_INDEX ),
13 listLock_( CrstObjectList, CrstFlags(CRST_UNSAFE_SAMELEVEL | CRST_UNSAFE_ANYMODE) )
14{
15 CONTRACTL {
16 THROWS;
17 GC_NOTRIGGER;
18 MODE_ANY;
19 } CONTRACTL_END;
20}
21
22#endif
23
24#define MAX_LOOP 2
25
26DWORD
27ObjectList::AddToList( PVOID ptr )
28{
29 CONTRACTL {
30 THROWS;
31 GC_NOTRIGGER;
32 MODE_ANY;
33 PRECONDITION(CheckPointer(ptr));
34 } CONTRACTL_END;
35
36
37 // sanity check that the pointer low bit is not set
38 _ASSERTE( (((DWORD)(size_t)ptr & 0x1) == 0) && "Invalid pointer" );
39
40 DWORD retval = INVALID_COMPRESSEDSTACK_INDEX;
41
42 CrstHolder ch( &listLock_ );
43
44 // If there is an entry in the free list, simply use it.
45
46 if (this->freeIndexHead_ != INVALID_COMPRESSEDSTACK_INDEX)
47 {
48 _ASSERTE( this->listLock_.OwnedByCurrentThread() );
49
50 // grab the head of the list
51 retval = (this->freeIndexHead_ >> 1);
52
53 DWORD nextFreeIndex = (DWORD)(size_t)this->allEntries_.Get( retval );
54
55 // index in use, pointer values have low bit as 0
56 _ASSERTE( ((nextFreeIndex & 0x01) == 1) && "The free list points to an index that is in use" );
57 // update the head of the list with the next free index stored in the array list
58 this->freeIndexHead_ = nextFreeIndex;
59
60 // store the pointer
61 this->allEntries_.Set( retval, ptr);
62 }
63 // Otherwise we place this new entry at that end of the list.
64 else
65 {
66 _ASSERTE( this->listLock_.OwnedByCurrentThread() );
67 retval = this->allEntries_.GetCount();
68 IfFailThrow(this->allEntries_.Append(ptr));
69 }
70
71 _ASSERTE( retval != INVALID_COMPRESSEDSTACK_INDEX );
72
73 return retval;
74}
75
76void
77ObjectList::RemoveFromList( PVOID ptr )
78{
79 CONTRACTL {
80 THROWS;
81 GC_TRIGGERS;
82 MODE_ANY;
83 PRECONDITION(CheckPointer(ptr));
84 } CONTRACTL_END;
85
86 // sanity check that the pointer low bit is not set
87 _ASSERTE( (((DWORD)(size_t)ptr & 0x1) == 0) && "Invalid pointer" );
88
89 DWORD index = INVALID_COMPRESSEDSTACK_INDEX;
90
91 CrstHolder ch( &listLock_ );
92
93 ObjectList::Iterator iter = Iterate();
94
95 while (iter.Next())
96 {
97 if (iter.GetElement() == ptr)
98 {
99 index = iter.GetIndex();
100 break;
101 }
102 }
103
104 if (index == INVALID_COMPRESSEDSTACK_INDEX)
105 {
106 _ASSERTE( FALSE && "Unable to find object" );
107 }
108 else
109 {
110 // add the index to the free list ( shift the freeIndex left and set the low bit)
111 this->allEntries_.Set( index, (PVOID)(size_t)(this->freeIndexHead_));
112 this-> freeIndexHead_ = ((index<<1) | 0x1);
113 }
114}
115
116
117
118void
119ObjectList::RemoveFromList( DWORD index, PVOID ptr )
120{
121 CONTRACTL {
122 NOTHROW;
123 GC_NOTRIGGER;
124 MODE_ANY;
125 PRECONDITION(CheckPointer(ptr));
126 } CONTRACTL_END;
127
128 CrstHolder ch( &listLock_ );
129
130 // sanity check that the pointer low bit is not set
131 _ASSERTE( (((DWORD)(size_t)ptr & 0x1) == 0) && "Invalid pointer" );
132
133 _ASSERTE( index < this->allEntries_.GetCount() );
134 _ASSERTE( this->allEntries_.Get( index ) == ptr && "Index tracking failed for this object" );
135
136 // add the index to the free list ( shift the freeIndex left and set the low bit)
137 this->allEntries_.Set( index, (PVOID)(size_t)(this->freeIndexHead_));
138 this-> freeIndexHead_ = ((index<<1) | 0x1);
139
140}
141
142PVOID
143ObjectList::Get( DWORD index )
144{
145 LIMITED_METHOD_CONTRACT;
146 return this->allEntries_.Get( index );
147}
148
149
150UnsynchronizedBlockAllocator::UnsynchronizedBlockAllocator( size_t blockSize )
151: blockSize_( blockSize ),
152 offset_( blockSize ),
153 index_( INVALID_COMPRESSEDSTACK_INDEX )
154{
155 LIMITED_METHOD_CONTRACT;
156 // We start off the offset at the block size to force the first
157 // allocation to create a new (first) block
158}
159
160UnsynchronizedBlockAllocator::~UnsynchronizedBlockAllocator( void )
161{
162 LIMITED_METHOD_CONTRACT;
163 ArrayList::Iterator iter = this->blockList_.Iterate();
164
165 while (iter.Next())
166 {
167 delete [] (BYTE *) iter.GetElement();
168 }
169}
170
171
172PVOID
173UnsynchronizedBlockAllocator::Allocate( size_t size )
174{
175 CONTRACTL {
176 THROWS;
177 GC_NOTRIGGER;
178 MODE_ANY;
179 } CONTRACTL_END;
180
181 _ASSERTE( size <= this->blockSize_ );
182
183 NewHolder<BYTE> buffer;
184
185 S_SIZE_T sizecheck = S_SIZE_T(this->offset_) + S_SIZE_T(size) ;
186 if( sizecheck.IsOverflow() )
187 {
188 ThrowOutOfMemory();
189 }
190
191 if (sizecheck.Value() > this->blockSize_)
192 {
193 buffer.Assign( new BYTE[this->blockSize_] );
194 IfFailThrow(this->blockList_.Append( buffer ));
195 buffer.SuppressRelease();
196 ++this->index_;
197 this->offset_ = 0;
198 }
199 else
200 {
201 buffer.Assign( (BYTE*)this->blockList_.Get( index_ ) );
202 buffer.SuppressRelease();
203 }
204
205 void* retval = buffer.GetValue() + this->offset_;
206 this->offset_ += size;
207
208 return retval;
209}
210