2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
15 #include "selectors.h"
17 #include "stackframe.h"
22 /* Global arena block */
25 DWORD base
; /* Base address (0 if discarded) */
26 DWORD size
; /* Size in bytes (0 indicates a free block) */
27 HGLOBAL handle
; /* Handle for this block */
28 HGLOBAL hOwner
; /* Owner of this block */
29 BYTE lockCount
; /* Count of GlobalFix() calls */
30 BYTE pageLockCount
; /* Count of GlobalPageLock() calls */
31 BYTE flags
; /* Allocation flags */
32 BYTE selCount
; /* Number of selectors allocated for this block */
38 /* Flags definitions */
39 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
40 #define GA_DGROUP 0x04
41 #define GA_DISCARDABLE 0x08
42 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
45 static GLOBALARENA
*pGlobalArena
= NULL
;
46 static int globalArenaSize
= 0;
48 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
50 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
52 /***********************************************************************
55 * Return the arena for a given selector, growing the arena array if needed.
57 static GLOBALARENA
*GLOBAL_GetArena( WORD sel
, WORD selcount
)
59 if (((sel
>> __AHSHIFT
) + selcount
) > globalArenaSize
)
61 int newsize
= ((sel
>> __AHSHIFT
) + selcount
+ 0xff) & ~0xff;
62 GLOBALARENA
*pNewArena
= realloc( pGlobalArena
,
63 newsize
* sizeof(GLOBALARENA
) );
64 if (!pNewArena
) return 0;
65 pGlobalArena
= pNewArena
;
66 memset( pGlobalArena
+ globalArenaSize
, 0,
67 (newsize
- globalArenaSize
) * sizeof(GLOBALARENA
) );
68 globalArenaSize
= newsize
;
70 return pGlobalArena
+ (sel
>> __AHSHIFT
);
78 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
79 if (pGlobalArena
[i
].size
!=0 && (pGlobalArena
[i
].handle
& 0x8000)){
81 printf("0x%08x, ",pGlobalArena
[i
].handle
);
89 /***********************************************************************
92 * Create a global heap block for a fixed range of linear memory.
94 HGLOBAL
GLOBAL_CreateBlock( WORD flags
, const void *ptr
, DWORD size
,
95 HGLOBAL hOwner
, BOOL isCode
,
96 BOOL is32Bit
, BOOL isReadOnly
,
102 /* Allocate the selector(s) */
104 sel
= SELECTOR_AllocBlock( ptr
, size
,
105 isCode
? SEGMENT_CODE
: SEGMENT_DATA
,
106 is32Bit
, isReadOnly
);
109 selcount
= (size
+ 0xffff) / 0x10000;
111 if (!(pArena
= GLOBAL_GetArena( sel
, selcount
)))
117 /* Fill the arena block */
119 pArena
->base
= (DWORD
)ptr
;
120 pArena
->size
= GET_SEL_LIMIT(sel
) + 1;
123 if ((flags
& GMEM_DDESHARE
) && Options
.ipc
)
125 pArena
->handle
= shmdata
->handle
;
126 pArena
->shmid
= shmdata
->shmid
;
131 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
135 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
137 pArena
->hOwner
= hOwner
;
138 pArena
->lockCount
= 0;
139 pArena
->pageLockCount
= 0;
140 pArena
->flags
= flags
& GA_MOVEABLE
;
141 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
142 if (flags
& GMEM_DDESHARE
) pArena
->flags
|= GA_IPCSHARE
;
143 if (!isCode
) pArena
->flags
|= GA_DGROUP
;
144 pArena
->selCount
= selcount
;
145 if (selcount
> 1) /* clear the next arena blocks */
146 memset( pArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
148 return pArena
->handle
;
152 /***********************************************************************
155 * Free a block allocated by GLOBAL_CreateBlock, without touching
156 * the associated linear memory range.
158 BOOL
GLOBAL_FreeBlock( HGLOBAL handle
)
162 if (!handle
) return TRUE
;
163 sel
= GlobalHandleToSel( handle
);
164 if (FreeSelector( sel
)) return FALSE
; /* failed */
165 memset( GET_ARENA_PTR(sel
), 0, sizeof(GLOBALARENA
) );
170 /***********************************************************************
173 * Implementation of GlobalAlloc()
175 HGLOBAL
GLOBAL_Alloc( WORD flags
, DWORD size
, HGLOBAL hOwner
,
176 BOOL isCode
, BOOL is32Bit
, BOOL isReadOnly
)
182 dprintf_global( stddeb
, "GlobalAlloc: %ld flags=%04x\n", size
, flags
);
184 /* If size is 0, create a discarded block */
186 if (size
== 0) return GLOBAL_CreateBlock( flags
, NULL
, 1, hOwner
, isCode
,
187 is32Bit
, isReadOnly
, NULL
);
191 if (size
>= GLOBAL_MAX_ALLOC_SIZE
- 0x1f) return 0;
192 size
= (size
+ 0x1f) & ~0x1f;
194 /* Allocate the linear memory */
197 if ((flags
& GMEM_DDESHARE
) && Options
.ipc
)
198 ptr
= DDE_malloc(flags
, size
, &shmdata
);
200 #endif /* CONFIG_IPC */
201 ptr
= malloc( size
);
204 /* Allocate the selector(s) */
206 handle
= GLOBAL_CreateBlock( flags
, ptr
, size
, hOwner
,
207 isCode
, is32Bit
, isReadOnly
, &shmdata
);
214 if (flags
& GMEM_ZEROINIT
) memset( ptr
, 0, size
);
220 /***********************************************************************
223 * Find the arena for a given handle
224 * (when handle is not serial - e.g. DDE)
226 static GLOBALARENA
*GLOBAL_FindArena( HGLOBAL handle
)
229 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
230 if (pGlobalArena
[i
].size
!=0 && pGlobalArena
[i
].handle
== handle
)
231 return ( &pGlobalArena
[i
] );
237 /***********************************************************************
238 * DDE_GlobalHandleToSel
241 WORD
DDE_GlobalHandleToSel( HGLOBAL handle
)
246 pArena
= GLOBAL_FindArena(handle
);
248 int ArenaIdx
= pArena
- pGlobalArena
;
250 /* See if synchronized to the shared memory */
251 return DDE_SyncHandle(handle
, ( ArenaIdx
<< __AHSHIFT
) | 7);
254 /* attach the block */
255 DDE_AttachHandle(handle
, &segptr
);
257 return SELECTOROF( segptr
);
259 #endif /* CONFIG_IPC */
262 /***********************************************************************
263 * GlobalAlloc (KERNEL.15)
265 HGLOBAL
GlobalAlloc( WORD flags
, DWORD size
)
267 HANDLE owner
= GetCurrentPDB();
269 if (flags
& GMEM_DDESHARE
)
270 owner
= GetExePtr(owner
); /* Make it a module handle */
271 return GLOBAL_Alloc( flags
, size
, owner
, FALSE
, FALSE
, FALSE
);
275 /***********************************************************************
276 * GlobalReAlloc (KERNEL.16)
278 HGLOBAL
GlobalReAlloc( HGLOBAL handle
, DWORD size
, WORD flags
)
283 GLOBALARENA
*pArena
, *pNewArena
;
284 WORD sel
= GlobalHandleToSel( handle
);
286 dprintf_global( stddeb
, "GlobalReAlloc: %04x %ld flags=%04x\n",
287 handle
, size
, flags
);
288 if (!handle
) return 0;
291 if (Options
.ipc
&& (flags
& GMEM_DDESHARE
|| is_dde_handle(handle
))) {
293 "GlobalReAlloc: shared memory reallocating unimplemented\n");
296 #endif /* CONFIG_IPC */
298 pArena
= GET_ARENA_PTR( handle
);
300 /* Discard the block if requested */
302 if ((size
== 0) && (flags
& GMEM_MOVEABLE
) && !(flags
& GMEM_MODIFY
))
304 if (!(pArena
->flags
& GA_MOVEABLE
) ||
305 !(pArena
->flags
& GA_DISCARDABLE
) ||
306 (pArena
->lockCount
> 0) || (pArena
->pageLockCount
> 0)) return 0;
307 free( (void *)pArena
->base
);
309 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
310 /* change the selector if we are shrinking the block */
311 SELECTOR_ReallocBlock( sel
, 0, 1, SEGMENT_DATA
, 0, 0 );
317 if (size
> GLOBAL_MAX_ALLOC_SIZE
- 0x20) return 0;
318 if (size
== 0) size
= 0x20;
319 else size
= (size
+ 0x1f) & ~0x1f;
321 /* Change the flags */
323 if (flags
& GMEM_MODIFY
)
325 /* Change the flags, leaving GA_DGROUP alone */
326 pArena
->flags
= (pArena
->flags
& GA_DGROUP
) | (flags
& GA_MOVEABLE
);
327 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
331 /* Reallocate the linear memory */
333 ptr
= (void *)pArena
->base
;
334 oldsize
= pArena
->size
;
335 dprintf_global(stddeb
,"oldsize %08lx\n",oldsize
);
336 if (ptr
&& (size
== oldsize
)) return handle
; /* Nothing to do */
338 ptr
= realloc( ptr
, size
);
342 memset( pArena
, 0, sizeof(GLOBALARENA
) );
346 /* Reallocate the selector(s) */
348 sel
= SELECTOR_ReallocBlock( sel
, ptr
, size
, SEGMENT_DATA
, 0, 0 );
352 memset( pArena
, 0, sizeof(GLOBALARENA
) );
355 selcount
= (size
+ 0xffff) / 0x10000;
357 if (!(pNewArena
= GLOBAL_GetArena( sel
, selcount
)))
364 /* Fill the new arena block */
366 if (pNewArena
!= pArena
) memcpy( pNewArena
, pArena
, sizeof(GLOBALARENA
) );
367 pNewArena
->base
= (DWORD
)ptr
;
368 pNewArena
->size
= GET_SEL_LIMIT(sel
) + 1;
369 pNewArena
->selCount
= selcount
;
370 pNewArena
->handle
= (pNewArena
->flags
& GA_MOVEABLE
) ? sel
- 1 : sel
;
372 if (selcount
> 1) /* clear the next arena blocks */
373 memset( pNewArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
375 if ((oldsize
< size
) && (flags
& GMEM_ZEROINIT
))
376 memset( (char *)ptr
+ oldsize
, 0, size
- oldsize
);
377 return pNewArena
->handle
;
381 /***********************************************************************
382 * GlobalFree (KERNEL.17)
384 HGLOBAL
GlobalFree( HGLOBAL handle
)
386 void *ptr
= GlobalLock( handle
);
388 dprintf_global( stddeb
, "GlobalFree: %04x\n", handle
);
389 if (!GLOBAL_FreeBlock( handle
)) return handle
; /* failed */
391 if (is_dde_handle(handle
)) return DDE_GlobalFree(handle
);
392 #endif /* CONFIG_IPC */
393 if (ptr
) free( ptr
);
398 /***********************************************************************
399 * WIN16_GlobalLock (KERNEL.18)
401 * This is the GlobalLock() function used by 16-bit code.
403 SEGPTR
WIN16_GlobalLock( HGLOBAL handle
)
405 dprintf_global( stddeb
, "WIN16_GlobalLock(%04x) -> %08lx\n",
406 handle
, MAKELONG( 0, GlobalHandleToSel(handle
)) );
407 if (!handle
) return 0;
410 if (is_dde_handle(handle
))
411 return (SEGPTR
)MAKELONG( 0, DDE_GlobalHandleToSel(handle
) );
412 #endif /* CONFIG_IPC */
414 if (!GET_ARENA_PTR(handle
)->base
) return (SEGPTR
)0;
415 return (SEGPTR
)MAKELONG( 0, GlobalHandleToSel(handle
) );
419 /***********************************************************************
420 * GlobalLock (KERNEL.18)
422 * This is the GlobalLock() function used by 32-bit code.
424 LPVOID
GlobalLock( HGLOBAL handle
)
426 if (!handle
) return 0;
428 if (is_dde_handle(handle
)) return DDE_AttachHandle(handle
, NULL
);
430 return (LPSTR
)GET_ARENA_PTR(handle
)->base
;
434 /***********************************************************************
435 * GlobalUnlock (KERNEL.19)
437 BOOL
GlobalUnlock( HGLOBAL handle
)
439 dprintf_global( stddeb
, "GlobalUnlock: %04x\n", handle
);
444 /***********************************************************************
445 * GlobalSize (KERNEL.20)
447 DWORD
GlobalSize( HGLOBAL handle
)
449 dprintf_global( stddeb
, "GlobalSize: %04x\n", handle
);
450 if (!handle
) return 0;
451 return GET_ARENA_PTR(handle
)->size
;
455 /***********************************************************************
456 * GlobalHandle (KERNEL.21)
458 DWORD
GlobalHandle( WORD sel
)
460 dprintf_global( stddeb
, "GlobalHandle: %04x\n", sel
);
461 return MAKELONG( GET_ARENA_PTR(sel
)->handle
, GlobalHandleToSel(sel
) );
465 /***********************************************************************
466 * GlobalFlags (KERNEL.22)
468 WORD
GlobalFlags( HGLOBAL handle
)
472 dprintf_global( stddeb
, "GlobalFlags: %04x\n", handle
);
473 pArena
= GET_ARENA_PTR(handle
);
474 return pArena
->lockCount
|
475 ((pArena
->flags
& GA_DISCARDABLE
) ? GMEM_DISCARDABLE
: 0) |
476 ((pArena
->base
== 0) ? GMEM_DISCARDED
: 0);
480 /***********************************************************************
481 * LockSegment (KERNEL.23)
483 HGLOBAL
LockSegment( HGLOBAL handle
)
485 dprintf_global( stddeb
, "LockSegment: %04x\n", handle
);
486 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
487 GET_ARENA_PTR(handle
)->lockCount
++;
492 /***********************************************************************
493 * UnlockSegment (KERNEL.24)
495 void UnlockSegment( HGLOBAL handle
)
497 dprintf_global( stddeb
, "UnlockSegment: %04x\n", handle
);
498 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
499 GET_ARENA_PTR(handle
)->lockCount
--;
500 /* FIXME: this ought to return the lock count in CX (go figure...) */
504 /***********************************************************************
505 * GlobalCompact (KERNEL.25)
507 DWORD
GlobalCompact( DWORD desired
)
509 return GLOBAL_MAX_ALLOC_SIZE
;
513 /***********************************************************************
514 * GlobalFreeAll (KERNEL.26)
516 void GlobalFreeAll( HANDLE owner
)
521 pArena
= pGlobalArena
;
522 for (i
= 0; i
< globalArenaSize
; i
++, pArena
++)
524 if ((pArena
->size
!= 0) && (pArena
->hOwner
== owner
))
525 GlobalFree( pArena
->handle
);
530 /***********************************************************************
531 * GlobalWire (KERNEL.111)
533 SEGPTR
GlobalWire( HGLOBAL handle
)
535 return WIN16_GlobalLock( handle
);
539 /***********************************************************************
540 * GlobalUnWire (KERNEL.112)
542 BOOL
GlobalUnWire( HGLOBAL handle
)
544 return GlobalUnlock( handle
);
548 /***********************************************************************
549 * GlobalDOSAlloc (KERNEL.184)
551 DWORD
GlobalDOSAlloc( DWORD size
)
553 WORD sel
= GlobalAlloc( GMEM_FIXED
, size
);
555 return MAKELONG( sel
, sel
/* this one ought to be a real-mode segment */ );
559 /***********************************************************************
560 * GlobalDOSFree (KERNEL.185)
562 WORD
GlobalDOSFree( WORD sel
)
564 return GlobalFree( GlobalHandle(sel
) ) ? sel
: 0;
568 /***********************************************************************
569 * SetSwapAreaSize (KERNEL.106)
571 LONG
SetSwapAreaSize( WORD size
)
573 dprintf_global(stdnimp
, "STUB: SetSwapAreaSize(%d)\n", size
);
574 return MAKELONG( size
, 0xffff );
578 /***********************************************************************
579 * GlobalLRUOldest (KERNEL.163)
581 HGLOBAL
GlobalLRUOldest( HGLOBAL handle
)
583 dprintf_global( stddeb
, "GlobalLRUOldest: %04x\n", handle
);
584 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
589 /***********************************************************************
590 * GlobalLRUNewest (KERNEL.164)
592 HGLOBAL
GlobalLRUNewest( HGLOBAL handle
)
594 dprintf_global( stddeb
, "GlobalLRUNewest: %04x\n", handle
);
595 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
600 /***********************************************************************
601 * GetFreeSpace (KERNEL.169)
603 DWORD
GetFreeSpace( UINT wFlags
)
605 return GLOBAL_MAX_ALLOC_SIZE
;
609 /***********************************************************************
610 * GlobalPageLock (KERNEL.191)
612 WORD
GlobalPageLock( HGLOBAL handle
)
614 dprintf_global( stddeb
, "GlobalPageLock: %04x\n", handle
);
615 return ++(GET_ARENA_PTR(handle
)->pageLockCount
);
619 /***********************************************************************
620 * GlobalPageUnlock (KERNEL.192)
622 WORD
GlobalPageUnlock( HGLOBAL handle
)
624 dprintf_global( stddeb
, "GlobalPageUnlock: %04x\n", handle
);
625 return --(GET_ARENA_PTR(handle
)->pageLockCount
);
629 /***********************************************************************
630 * GlobalFix (KERNEL.197)
632 void GlobalFix( HGLOBAL handle
)
634 dprintf_global( stddeb
, "GlobalFix: %04x\n", handle
);
635 GET_ARENA_PTR(handle
)->lockCount
++;
639 /***********************************************************************
640 * GlobalUnfix (KERNEL.198)
642 void GlobalUnfix( HGLOBAL handle
)
644 dprintf_global( stddeb
, "GlobalUnfix: %04x\n", handle
);
645 GET_ARENA_PTR(handle
)->lockCount
--;
649 /***********************************************************************
650 * FarSetOwner (KERNEL.403)
652 void FarSetOwner( HANDLE handle
, WORD hOwner
)
654 GET_ARENA_PTR(handle
)->hOwner
= hOwner
;
658 /***********************************************************************
659 * FarGetOwner (KERNEL.404)
661 WORD
FarGetOwner( HANDLE handle
)
663 return GET_ARENA_PTR(handle
)->hOwner
;
667 /***********************************************************************
668 * GlobalHandleToSel (TOOLHELP.50)
670 WORD
GlobalHandleToSel( HGLOBAL handle
)
672 dprintf_toolhelp( stddeb
, "GlobalHandleToSel: %04x\n", handle
);
673 if (!handle
) return 0;
675 if (is_dde_handle(handle
)) return DDE_GlobalHandleToSel(handle
);
679 fprintf( stderr
, "Program attempted invalid selector conversion\n" );
686 /***********************************************************************
687 * GlobalFirst (TOOLHELP.51)
689 BOOL
GlobalFirst( GLOBALENTRY
*pGlobal
, WORD wFlags
)
691 if (wFlags
== GLOBAL_LRU
) return FALSE
;
693 return GlobalNext( pGlobal
, wFlags
);
697 /***********************************************************************
698 * GlobalNext (TOOLHELP.52)
700 BOOL
GlobalNext( GLOBALENTRY
*pGlobal
, WORD wFlags
)
704 if (pGlobal
->dwNext
>= globalArenaSize
) return FALSE
;
705 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
706 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
709 for (i
= pGlobal
->dwNext
; i
< globalArenaSize
; i
++, pArena
++)
710 if (pArena
->size
== 0) break; /* block is free */
711 if (i
>= globalArenaSize
) return FALSE
;
715 pGlobal
->dwAddress
= pArena
->base
;
716 pGlobal
->dwBlockSize
= pArena
->size
;
717 pGlobal
->hBlock
= pArena
->handle
;
718 pGlobal
->wcLock
= pArena
->lockCount
;
719 pGlobal
->wcPageLock
= pArena
->pageLockCount
;
720 pGlobal
->wFlags
= (GetCurrentPDB() == pArena
->hOwner
);
721 pGlobal
->wHeapPresent
= FALSE
;
722 pGlobal
->hOwner
= pArena
->hOwner
;
723 pGlobal
->wType
= GT_UNKNOWN
;
730 /***********************************************************************
731 * GlobalInfo (TOOLHELP.53)
733 BOOL
GlobalInfo( GLOBALINFO
*pInfo
)
738 pInfo
->wcItems
= globalArenaSize
;
739 pInfo
->wcItemsFree
= 0;
740 pInfo
->wcItemsLRU
= 0;
741 for (i
= 0, pArena
= pGlobalArena
; i
< globalArenaSize
; i
++, pArena
++)
742 if (pArena
->size
== 0) pInfo
->wcItemsFree
++;
747 /***********************************************************************
748 * GlobalEntryHandle (TOOLHELP.54)
750 BOOL
GlobalEntryHandle( GLOBALENTRY
*pGlobal
, HGLOBAL hItem
)
756 /***********************************************************************
757 * GlobalEntryModule (TOOLHELP.55)
759 BOOL
GlobalEntryModule( GLOBALENTRY
*pGlobal
, HMODULE hModule
, WORD wSeg
)
765 /***********************************************************************
766 * MemManInfo (TOOLHELP.72)
768 BOOL
MemManInfo( MEMMANINFO
*pInfo
)
771 /* FIXME: does not take into account the dwSize member
772 * could be corrupting memory therefore
774 /* shamefully stolen from free */
782 if ((meminfo
= fopen("/proc/meminfo", "r")) < 0) {
783 perror("wine: open");
787 fgets(buf
, 80, meminfo
); /* read first line */
788 while ( fgets(buf
, 80, meminfo
) ) {
789 n
= sscanf( buf
, "%*s %d %d %d %d %d", &col
[0], &col
[1], &col
[2], &col
[3], &col
[4]);
790 if ( n
< 1 ) continue; /* escape the loop at the top */
792 availmem
+= col
[2] + col
[4];
795 fprintf(stderr
,"MemManInfo called with dwSize = %ld\n",pInfo
->dwSize
);
797 pInfo
->wPageSize
= getpagesize();
798 pInfo
->dwLargestFreeBlock
= availmem
;
799 pInfo
->dwTotalLinearSpace
= totalmem
/ pInfo
->wPageSize
;
800 pInfo
->dwMaxPagesAvailable
= pInfo
->dwLargestFreeBlock
/ pInfo
->wPageSize
;
801 pInfo
->dwMaxPagesLockable
= pInfo
->dwMaxPagesLockable
;
802 /* FIXME: the next three are not quite correct */
803 pInfo
->dwTotalUnlockedPages
= pInfo
->dwMaxPagesAvailable
;
804 pInfo
->dwFreePages
= pInfo
->dwMaxPagesAvailable
;
805 pInfo
->dwTotalPages
= pInfo
->dwMaxPagesAvailable
;
806 /* FIXME: the three above are not quite correct */
807 pInfo
->dwFreeLinearSpace
= pInfo
->dwMaxPagesAvailable
;
808 pInfo
->dwSwapFilePages
= 0L;
816 /***********************************************************************
818 * implements GlobalAlloc (KERNEL32.316)
819 * LocalAlloc (KERNEL32.372)
821 void *GlobalAlloc32(int flags
,int size
)
823 dprintf_global(stddeb
,"GlobalAlloc32(%x,%x)\n",flags
,size
);