source: Include/system/gc.sbp@ 299

Last change on this file since 299 was 299, checked in by dai, 17 years ago

【32bitコンパイラ】
静的リンクライブラリを実装
ジェネリクスを実装
※64bitコンパイラは未実装

File size: 14.1 KB
RevLine 
[109]1/*
2 このファイルでは、ABのガベージコレクションの実装を行います。
3*/
[1]4
[109]5
[1]6/*
7※これらの変数はコンパイラが自動的に定義します。
8Dim _System_gc_StackRoot_StartPtr As VoidPtr
9*/
10
11Function _System_GetSp() As LONG_PTR 'dummy
12End Function
13
14
15Const _System_GC_FLAG_ATOMIC = 1
16Const _System_GC_FLAG_NEEDFREE = 2
17Const _System_GC_FLAG_INITZERO = 4
[144]18Const _System_GC_FLAG_OBJECT = 8
[1]19
[214]20Type _System_GlobalRoot
21 ptr As *LONG_PTR
22 count As Long
23End Type
24
[1]25Class _System_CGarbageCollection
[266]26
[144]27 ppPtr As *VoidPtr
[1]28 pSize As *SIZE_T
[144]29 pdwFlags As *DWord
[1]30 n As Long
31
32 iAllSize As SIZE_T
33
[144]34 isSweeping As Boolean
35
[1]36 CriticalSection As CRITICAL_SECTION
37
[214]38 ' メモリの上限値(この値を超えるとGCが発動します)
39 limitMemorySize As LONG_PTR ' バイト単位
40 limitMemoryObjectNum As Long ' メモリオブジェクトの個数単位
[109]41
[144]42 isFinish As Boolean
43
44
[214]45 ' Global Root
46 pGlobalRoots As *_System_GlobalRoot
47 globalRootNum As Long
48 Sub AddGlobalRootPtr( ptr As *LONG_PTR, count As Long )
49 pGlobalRoots = _System_realloc( pGlobalRoots, (globalRootNum + 1) * SizeOf(_System_GlobalRoot) )
50 pGlobalRoots[globalRootNum].ptr = ptr
51 pGlobalRoots[globalRootNum].count = count
52 globalRootNum++
53 End Sub
54
55 Sub RegisterGlobalRoots()
56 ' このメソッドの実装はコンパイラが自動生成する
57
58 ' AddGlobalRootPtr(...)
59 ' ...
60 End Sub
61
[144]62 ' 特殊クラスのため、コンストラクタ・デストラクタは呼ばれません
[1]63 Sub _System_CGarbageCollection()
[144]64 End Sub
65 Sub ~_System_CGarbageCollection()
66 End Sub
67
[214]68Public
69
[266]70 Static Sub Initialize()
71 Dim temporary[255] As Char
72 If GetEnvironmentVariable( "ActiveBasicGarbageCollection", temporary, 255 ) Then
73 ' 既にGCがプロセスに存在するとき
74 sscanf( temporary, "%08x", VarPtr( _System_pGC ) )
75 MessageBox(0,temporary,"GetEnvironmentVariable",0)
76 Else
77 _System_pGC = _System_calloc( SizeOf( _System_CGarbageCollection ) )
78 _System_pGC->Begin()
79
80 ' GCをプロセスに登録する
81 sprintf( temporary, "%08x", _System_pGC )
82 SetEnvironmentVariable( "ActiveBasicGarbageCollection", temporary )
83 End If
84 End Sub
85
[144]86 Sub Begin()
[1]87 If ppPtr Then Exit Sub
88
[144]89 isFinish = False
90
91 'メモリの上限値(この値を超えるとGCが発動します)
[214]92 limitMemorySize = 1024*1024 As LONG_PTR ' バイト単位
93 limitMemoryObjectNum = 2000 ' メモリオブジェクトの個数単位
[144]94
95 ppPtr=_System_calloc( 1 )
96 pSize=_System_calloc( 1 )
97 pdwFlags=_System_calloc( 1 )
[1]98 n=0
99
[214]100 ' Global Root
101 pGlobalRoots = _System_calloc( 1 )
102 globalRootNum = 0
103 RegisterGlobalRoots()
104
[1]105 iAllSize=0
106
[144]107 ' スウィープ中かどうか
108 isSweeping = False
[1]109
110 'クリティカルセッションを生成
111 InitializeCriticalSection(CriticalSection)
112
[18]113
114 '---------------------------
115 ' 開始時のスレッドを通知
116 '---------------------------
[1]117 Dim hTargetThread As HANDLE
118 DuplicateHandle(GetCurrentProcess(),
119 GetCurrentThread(),
120 GetCurrentProcess(),
121 hTargetThread, 0, FALSE, DUPLICATE_SAME_ACCESS) 'カレントスレッドのハンドルを複製
[18]122
[144]123 ' スレッド管理用オブジェクトを生成
124 _System_pobj_AllThreads = New _System_CThreadCollection()
[18]125
[144]126 ' 自身のThreadオブジェクトを生成
127 Dim thread As Thread(hTargetThread,GetCurrentThreadId(),0)
[18]128
[232]129 _System_pobj_AllThreads->BeginThread(ObjPtr( thread ),_System_gc_StackRoot_StartPtr As *LONG_PTR)
[144]130
[1]131 End Sub
[144]132 Sub Finish()
[1]133 If ppPtr=0 Then Exit Sub
134
[144]135 isFinish = True
[79]136
[144]137 ' スレッド管理用オブジェクトを破棄
138 Delete _System_pobj_AllThreads
[1]139
[144]140 ' 自分以外のスレッドを一時停止
141 '_System_pobj_AllThreads->SuspendAnotherThread()
142
[259]143 _System_DebugOnly_OutputDebugString( Ex"garbage colletion sweeping all memory objects!\r\n" )
[144]144 DeleteAllGarbageMemories()
145
146 ' 未解放のメモリオブジェクトをトレース
147 DumpMemoryLeaks()
148
149 ' 自分以外のスレッドを再開
150 '_System_pobj_AllThreads->ResumeAnotherThread()
151
[214]152 _System_free( ppPtr )
153 ppPtr = NULL
[1]154
[214]155 _System_free( pSize )
156 pSize = NULL
157 _System_free( pdwFlags )
158 pdwFlags = NULL
[1]159
[214]160 _System_free( pGlobalRoots )
161 pGlobalRoots = NULL
162
[1]163 'クリティカルセッションを破棄
164 DeleteCriticalSection(CriticalSection)
[144]165
[79]166 End Sub
[1]167
[170]168 Sub add(new_ptr As VoidPtr, size As SIZE_T, flags As DWord)
[1]169 iAllSize+=size
170
[144]171 EnterCriticalSection(CriticalSection)
172 ppPtr=HeapReAlloc(_System_hProcessHeap,0,ppPtr,(n+1)*SizeOf(VoidPtr))
173 ppPtr[n]=new_ptr
[1]174
[144]175 pSize=HeapReAlloc(_System_hProcessHeap,0,pSize,(n+1)*SizeOf(SIZE_T))
176 pSize[n]=size
[1]177
[144]178 pdwFlags=HeapReAlloc(_System_hProcessHeap,0,pdwFlags,(n+1)*SizeOf(DWord))
179 pdwFlags[n]=flags
180 LeaveCriticalSection(CriticalSection)
[1]181
182 n++
183 End Sub
184
185
186 Function __malloc(size As SIZE_T,flags As Byte) As VoidPtr
[203]187' EnterCriticalSection(CriticalSection)
[1]188 Dim dwFlags As DWord
189 If flags and _System_GC_FLAG_INITZERO Then
190 dwFlags=HEAP_ZERO_MEMORY
191 Else
192 dwFlags=0
193 End If
194
[144]195 Dim ptr = HeapAlloc(_System_hProcessHeap,dwFlags,size)
196 add( ptr, size, flags )
[203]197' LeaveCriticalSection(CriticalSection)
[1]198
[144]199 Return ptr
[1]200 End Function
201
202 Function __realloc(lpMem As VoidPtr, size As SIZE_T) As VoidPtr
[18]203 EnterCriticalSection(CriticalSection)
204 Dim i As Long
205 For i=0 To ELM(n)
206 If ppPtr[i]=lpMem Then
207 iAllSize+=size-pSize[i]
[1]208
[18]209 pSize[i]=size
210 ppPtr[i]=HeapReAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,lpMem,size)
211
212 LeaveCriticalSection(CriticalSection)
213 Return ppPtr[i]
214 End If
215 Next
216 LeaveCriticalSection(CriticalSection)
[1]217 Return 0
218 End Function
219
[144]220 Sub __free_ex(lpMem As VoidPtr, isSweeping As Boolean)
[18]221 EnterCriticalSection(CriticalSection)
222 Dim i As Long
223 For i=0 To ELM(n)
224 If ppPtr[i]=lpMem Then
[144]225 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 or isSweeping Then
[18]226 iAllSize-=pSize[i]
[1]227
[18]228 HeapFree(_System_hProcessHeap,0,ppPtr[i])
229 ppPtr[i]=0
230 pSize[i]=0
231 Else
[144]232 If isFinish = False Then
[259]233 _System_DebugOnly_OutputDebugString( Ex"heap free missing!\r\n" )
[144]234 End If
[18]235 End If
[1]236 End If
[18]237 Next
238 LeaveCriticalSection(CriticalSection)
[1]239 End Sub
240
[144]241 Sub __free(lpMem As VoidPtr)
242 __free_ex( lpMem, False )
243 End Sub
244
[1]245 Sub sweep()
[214]246 If isSweeping <> False or (iAllSize<limitMemorySize and n<limitMemoryObjectNum) Then
[171]247 'メモリ使用量が上限値を超えていないとき
248 Exit Sub
249 End If
[144]250
[171]251 Dim hThread As HANDLE
252 Dim ThreadId As DWord
253 hThread=_beginthreadex(NULL,0,AddressOf(SweepOnOtherThread),VarPtr(This),0,ThreadId)
254 WaitForSingleObject(hThread,INFINITE)
255 CloseHandle(hThread)
[202]256 isSweeping = False
[1]257 End Sub
258
[144]259Private
[1]260
[214]261 Static Function IsNull( object As Object ) As Boolean
[237]262 Return Object.ReferenceEquals(object, Nothing)
[214]263 End Function
264
[144]265 ' 生存検知
266 Function HitTest(pSample As VoidPtr) As Long
267 Dim i As Long
268 For i=0 To ELM(n)
269 If (ppPtr[i] As LONG_PTR)<=(pSample As LONG_PTR) and (pSample As LONG_PTR)<((ppPtr[i] As LONG_PTR)+pSize[i]) Then
270 Return i
271 End If
272 Next
273 Return -1
274 End Function
[1]275
[214]276 ' オブジェクトのスキャン
277 Function ScanObject(pObject As *Object, pbMark As *Byte) As Boolean
[275]278 Dim classTypeInfo = Nothing As ActiveBasic.Core._System_TypeForClass
279 classTypeInfo = pObject->GetType() As ActiveBasic.Core._System_TypeForClass
[214]280
281 If IsNull( classTypeInfo ) Then
282 Return False
283 End If
284
285 Dim i As Long
286 For i = 0 To ELM(classTypeInfo.numOfReference)
287 Scan( (pObject + classTypeInfo.referenceOffsets[i]) As *LONG_PTR, 1, pbMark )
288 Next
289
290 Return True
291 End Function
292
[144]293 ' 指定領域のスキャン
[214]294 Sub Scan(pStartPtr As *LONG_PTR, maxNum As Long, pbMark As *Byte)
295 Dim i As Long, index As Long
296
297 For i=0 To ELM(maxNum)
[144]298 index=HitTest(pStartPtr[i] As VoidPtr)
299 If index<>-1 Then
300 If pbMark[index]=0 Then
301 pbMark[index]=1
[170]302
[214]303 If pdwFlags[index] and _System_GC_FLAG_OBJECT Then
304 ' オブジェクトの場合
[249]305 If ScanObject( (ppPtr[index] + 4*SizeOf(LONG_PTR)) As *Object, pbMark) = False Then
[214]306 Dim maxNum = (pSize[index]\SizeOf(LONG_PTR)) As Long
307 Scan(ppPtr[index] As *LONG_PTR, maxNum, pbMark)
308 End If
309
310 ElseIf (pdwFlags[index] and _System_GC_FLAG_ATOMIC)=0 Then
311 ' ヒープ領域がポインタ値を含む可能性があるとき
[144]312 If ppPtr[index] = 0 Then
313 'エラー
[170]314
[144]315 End If
[214]316
317 Dim maxNum = (pSize[index]\SizeOf(LONG_PTR)) As Long
318 Scan(ppPtr[index] As *LONG_PTR, maxNum, pbMark)
[144]319 End If
320 End If
321 End If
322 Next
323 End Sub
[1]324
[144]325 ' ローカル領域をルートに指定してスキャン
326 Sub LocalScan( pbMark As *Byte )
[18]327 Dim Context As CONTEXT
[1]328 Dim NowSp As *LONG_PTR
329 Dim size As LONG_PTR
[18]330 Dim i As Long
331 For i=0 To ELM(_System_pobj_AllThreads->ThreadNum)
332 If _System_pobj_AllThreads->ppobj_Thread[i] Then
[1]333 FillMemory(VarPtr(Context),SizeOf(CONTEXT),0)
334 Context.ContextFlags=CONTEXT_CONTROL
[18]335 If _System_pobj_AllThreads->ppobj_Thread[i]->__GetContext(Context)=0 Then
[259]336 _System_DebugOnly_OutputDebugString(Ex"レジスタ情報の取得に失敗しました。\r\n")
[1]337 End If
338
339#ifdef _WIN64
340 NowSp=Context.Rsp As *LONG_PTR
341#else
342 NowSp=Context.Esp As *LONG_PTR
343#endif
344
[214]345 Dim size=(_System_pobj_AllThreads->pStackBase[i] As LONG_PTR)-(NowSp As LONG_PTR)
346 Dim maxNum = (size\SizeOf(LONG_PTR)) As Long
[1]347
[144]348 If NowSp = 0 Then
349 debug
350 Exit Sub
351 End If
352
[214]353 Scan( NowSp, maxNum, pbMark )
[1]354 End If
355 Next
[144]356 End Sub
[1]357
[144]358 Sub DeleteGarbageMemories( pbMark As *Byte )
[1]359
[144]360 Dim isAllDelete = False
361 If pbMark = NULL Then
362 ' すべてを破棄するとき
363 isAllDelete = True
364 pbMark = _System_calloc( n )
365 End If
[1]366
[144]367 Dim i As Long
[1]368 For i=0 To ELM(n)
[144]369 If pbMark[i]=0 and ppPtr[i]<>0 and (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)=0 Then
370 If ppPtr[i] = 0 Then
371 If isAllDelete Then
372 Continue
373 Else
374 debug
375 End If
376 End If
[1]377
[144]378 Dim ptr = ppPtr[i]
379 Dim size = pSize[i]
380
[1]381 ppPtr[i]=0
382 pSize[i]=0
[144]383
384 If (pdwFlags[i] and _System_GC_FLAG_OBJECT) <> 0 Then
385 /* ・オブジェクトの個数
386 ・オブジェクトのサイズ
387 ・デストラクタの関数ポインタ
[249]388 ・リザーブ領域
[144]389 を考慮 */
[249]390 _System_SweepingDelete (ptr + SizeOf( LONG_PTR ) * 4 )
[144]391 Else
392 HeapFree(_System_hProcessHeap,0,ptr)
393 End If
[214]394
395 iAllSize-=size
[1]396 End If
397 Next
398
[144]399 If isAllDelete Then
400 _System_free( pbMark )
401 End If
402
403 End Sub
404
405 Sub DeleteAllGarbageMemories()
406 DeleteGarbageMemories( NULL )
407 End Sub
408
409 Sub Compaction()
410 Dim i As Long, i2 = 0 As Long
411 For i=0 To ELM(n)
412 ppPtr[i2] = ppPtr[i]
413 pSize[i2] = pSize[i]
414 pdwFlags[i2] = pdwFlags[i]
415
416 If ppPtr[i] Then
417 i2++
418 End If
419 Next
420 n = i2
421 End Sub
422
423 ' スウィープ(新規スレッドで呼び出し)
[284]424 Function SweepOnOtherThread() As Long
[171]425 EnterCriticalSection(CriticalSection)
[144]426
[214]427
428 Dim startTime = GetTickCount()
429
[259]430 _System_DebugOnly_OutputDebugString( Ex"garbage colletion sweep start!\r\n" )
[214]431
432
433 If isSweeping <> False or (iAllSize<limitMemorySize and n<limitMemoryObjectNum) Then
[202]434 ExitThread(0)
435 End If
[203]436 isSweeping = True
[202]437
[144]438 ' すべてのスレッドを一時停止
439 _System_pobj_AllThreads->SuspendAllThread()
440
441 ' マークリストを生成
442 Dim pbMark = HeapAlloc(_System_hProcessHeap,HEAP_ZERO_MEMORY,n*SizeOf(Byte)) As *Byte
443
444 ' グローバル領域をルートに指定してスキャン
[214]445 Dim i As Long
446 For i = 0 To ELM( globalRootNum )
447 Scan( pGlobalRoots[i].ptr, pGlobalRoots[i].count, pbMark )
448 Next
[144]449
450 ' ローカル領域をルートに指定してスキャン
451 LocalScan( pbMark )
452
453 ' スウィープ前のメモリサイズを退避
454 Dim iBackAllSize = iAllSize
455
456 ' スウィープ前のメモリオブジェクトの数
457 Dim iBeforeN = n
458
459 '使われていないメモリを解放する
460 DeleteGarbageMemories(pbMark)
461
462 'コンパクション
463 Compaction()
464
[1]465 'マークリストを解放
466 HeapFree(_System_hProcessHeap,0,pbMark)
467
[299]468 If iBackAllSize <= iAllSize * 2 Then
[144]469 If iAllSize > limitMemorySize Then
470 limitMemorySize = iAllSize
471 End If
472
[1]473 '許容量を拡張する
[144]474 limitMemorySize *= 2
[214]475 limitMemoryObjectNum *= 2
[144]476
[259]477 _System_DebugOnly_OutputDebugString( Ex"memory size is extended for gc!\r\n" )
[1]478 End If
479
[144]480 Dim temp[100] As Char
[214]481 wsprintf(temp,Ex"object items ... %d -> %d ( %d MB -> %d MB )\r\n",iBeforeN,n, iBackAllSize\1024\1024, iAllSize\1024\1024)
[259]482 _System_DebugOnly_OutputDebugString( temp )
[144]483 wsprintf(temp,Ex"limit size of memory ... %d\r\n",limitMemorySize)
[259]484 _System_DebugOnly_OutputDebugString( temp )
[214]485 wsprintf(temp,Ex"garbage colletion sweep finish! (%d ms)\r\n\r\n", GetTickCount()-startTime)
[259]486 _System_DebugOnly_OutputDebugString( temp )
[1]487
[144]488
[1]489 '-------------------------------------
490 ' すべてのスレッドを再開
491 '-------------------------------------
[18]492 _System_pobj_AllThreads->ResumeAllThread()
[171]493
494 LeaveCriticalSection(CriticalSection)
[1]495 End Function
496
[144]497 ' 未解放のメモリオブジェクトをトレース
498 Sub DumpMemoryLeaks()
499 Dim isLeak = False
[1]500 Dim i As Long
501 For i=0 To ELM(n)
[144]502 If ppPtr[i] Then
503 If (pdwFlags[i] and _System_GC_FLAG_NEEDFREE)<>0 Then
504 If isLeak = False Then
[259]505 _System_DebugOnly_OutputDebugString( Ex"Detected memory leaks!\r\n" )
[144]506 isLeak = True
507 End If
[1]508
[144]509 Dim temp[100] As Char
[259]510 _System_DebugOnly_OutputDebugString( Ex"heap free missing!\r\n" )
[144]511 wsprintf(temp,Ex"{%d} normal block at &H%08X, %d bytes long.\r\n", i, ppPtr[i], pSize[i])
[259]512 _System_DebugOnly_OutputDebugString( temp )
[1]513 End If
514 End If
515 Next
[144]516
517 If isLeak Then
[259]518 _System_DebugOnly_OutputDebugString( Ex"Object dump complete.\r\n" )
[144]519 End If
[170]520
[1]521 End Sub
[144]522
[1]523End Class
524
525'GC管理用の特殊なシステムオブジェクト(デストラクタは最終のタイミングで呼び出されます)
[144]526Dim _System_pGC As *_System_CGarbageCollection
[1]527
528
529
530Function GC_malloc(size As Long) As VoidPtr
531 ' sweep
[144]532 _System_pGC->sweep()
[1]533
534 'allocate
[144]535 Return _System_pGC->__malloc(size,0)
[1]536End Function
537
538Function GC_malloc_atomic(size As Long) As VoidPtr
539 ' sweep
[144]540 _System_pGC->sweep()
[1]541
542 'allocate
[144]543 Return _System_pGC->__malloc(size,_System_GC_FLAG_ATOMIC)
[1]544End Function
[144]545
546Function _System_GC_malloc_ForObject(size As Long) As VoidPtr
547 ' sweep
548 _System_pGC->sweep()
549
550 'allocate
551 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO)
552End Function
553
554Function _System_GC_malloc_ForObjectPtr(size As Long) As VoidPtr
555 ' sweep
556 _System_pGC->sweep()
557
558 'allocate
559 Return _System_pGC->__malloc(size,_System_GC_FLAG_OBJECT or _System_GC_FLAG_INITZERO or _System_GC_FLAG_NEEDFREE)
560End Function
561
562Function _System_GC_free_for_SweepingDelete( ptr As *Object )
563 ' free
564 _System_pGC->__free_ex( ptr, True )
565End Function
Note: See TracBrowser for help on using the repository browser.