memmgr.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 614 行 · 第 1/2 页
C
614 行
/****************************************************************************
*
* Open Watcom Project
*
* Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
* ========================================================================
*
* This file contains Original Code and/or Modifications of Original
* Code as defined in and that are subject to the Sybase Open Watcom
* Public License version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. BY USING THIS FILE YOU AGREE TO
* ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
* provided with the Original Code and Modifications, and is also
* available at www.sybase.com/developer/opensource.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
* ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
* NON-INFRINGEMENT. Please see the License for the specific language
* governing rights and limitations under the License.
*
* ========================================================================
*
* Description: Fast memory manager used by the code generator.
*
****************************************************************************/
/****************************************************************************
This is a free list based memory manager optimized for codegen performance.
It will allocate fixed size blocks of several classes (sizes), any freed
memory blocks will be kept in a singly linked free list. If an attempt is
made to allocate memory and a free block of appropriate size exists, it will
be found extremely quickly. The memory manager allocates memory from the
system via malloc() and free(), but it could use OS functions that allocate
memory pages directly.
Memory classes/sizes are powers of two, but they might be arbitrary sizes
designed to fit typical allocation sizes. Allocations greater than certain
maximum size will go directly to the OS.
Expected usage is great number of mostly small allocs and frees. The
allocator is designed to reuse memory well, and do it fast.
Disadvantages: May waste memory in certain scenarios. No attempts are made
to coalesce free memory blocks. Since the codegen extremely rarely allocates
more than even 256KB memory, some wastage is considered acceptable.
Advantages: Speed. Memory allocation is extremely fast, with no searches if
appropriately sized block is available. Memory frees are instantaneous, with
no searching whatsoever. Did I mention speed? Memory blocks will be reused
immediately, which should produce helpful memory access patterns. There is
essentially no worst case performance scenario.
****************************************************************************/
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "standard.h"
#include "ptrint.h"
#include "hostsys.h"
#include "cg.h"
#if defined( M_I86 ) || defined( M_I386 )
#include <i86.h>
#endif
#include <unistd.h>
#if defined( __NT__ )
#include <windows.h>
#elif defined( __OSI__ )
#define __CALL21__
#include "tinyio.h"
#elif defined( __QNX__ )
#include <sys/osinfo.h>
#include <sys/seginfo.h>
#endif
#ifdef __DOS__
#include "tinyio.h"
#include "dosmem.h"
typedef struct {
unsigned long largest_free;
unsigned long max_unlocked_page_alloc;
unsigned long max_locked_page_alloc;
unsigned long linear_addr_space_in_pages;
unsigned long total_unlocked_pages;
unsigned long free_pages;
unsigned long physical_pages;
unsigned long free_linear_addr_space_in_pages;
unsigned long size_of_page_file_in_pages;
unsigned long fill[4];
} dpmi_mem;
extern long _TinyDPMIGetFreeMemoryInformation( dpmi_mem * );
#pragma aux _TinyDPMIGetFreeMemoryInformation = \
"push es" \
"push ds" \
"pop es" \
"mov ah,05h" \
"mov al,00h" \
"int 31h" \
"pop es" \
"sbb ax,ax" \
parm[edi] value[eax];
#include "extender.h"
extern char int2f( short );
#pragma aux int2f parm [ ax ] value [ al ] = "int 2fh";
#pragma aux __psp "*";
extern short __psp;
#endif
typedef unsigned_32 tag;
extern bool GetEnvVar( char*, char*, int );
extern char *CopyStr( char *src, char *dst );
extern uint Length( char* );
extern void FatalError( char* );
#define _1K 1024L
#define _4K (4*_1K)
#define _64K (64*_1K)
#define _1M (_1K*_1K)
#define _4M (4*_1M)
#define _16M (16*_1M)
static char *MemFromSys( tag );
static pointer_int AllocSize = { 0 };
static pointer_int MemorySize;
static int Initialized = 0;
#ifdef MEMORY_STATS
static pointer_int PeakAlloc = 0;
#endif
#define ALLOCATED 1
#define MAX_SIZE 14 /* 16384 */
#define MIN_SIZE 4 /* 16 */
#define WORD_SIZE 4
#define MAX_CLASS (MAX_SIZE-MIN_SIZE)
/* Free list structure - length holds the size of memory block, which
* is necessary for freeing memory. Note that the length field is set
* when the block is first allocated and never changes afterwards.
* The link member holds the address of the next free block of the
* same size, or NULL if it's the last free block.
*/
typedef struct frl {
tag length;
struct frl *link;
} frl;
#if (1 << MIN_SIZE) < (2 * WORD_SIZE)
#error "Free list will not fit into freed chunk"
#endif
/* Memory block structure - memory is allocated from the OS in large
* chunks (perhaps 64K, perhaps more or less than that). If there is
* no memory in a free list, it will be allocated from a block, and
* will end up on a free list when (if) it's freed.
*/
typedef struct mem_blk {
struct mem_blk *next;
tag free;
tag size; /* This must be the last member! */
} mem_blk;
typedef struct blk_hdr {
struct mem_blk *block;
tag size; /* This must be the last member! */
} blk_hdr;
#define TAG_SIZE sizeof( tag )
#define MIN_ALLOC ((sizeof(frl)+(WORD_SIZE-1))&~(WORD_SIZE-1))
#define MAX_ALLOC (1 << MAX_SIZE)
#define _WALKTAG( free ) ((frl *)((char *)(free) + (free)->length ))
static mem_blk *_Blks;
static frl *_FreeList[ MAX_CLASS + 1 ];
static tag _ClassSizes[ MAX_CLASS + 1 ];
#if defined( __DOS__ ) || defined( __QNX__ )
static void NotEnoughMem( void )
/**********************************/
{
FatalError( "Not enough memory to satisfy WCGMEMORY" );
}
#endif
static int myatoi( char *p )
/**************************/
{
int i;
i = 0;
while( *p != '\0' ) {
i *= 10;
i += *p - '0';
++p;
}
return( i );
}
static void myitoa( int i, char *p )
/**********************************/
{
char buff[20];
char *q;
q = buff + 20;
*--q = '\0';
while( i != 0 ) {
*--q = ( i % 10 ) + '0';
i /= 10;
}
CopyStr( q, p );
}
static void CalcMemSize( void )
/*********************************/
{
bool max_size_queried;
bool size_queried;
unsigned_32 size_requested;
unsigned_32 memory_available;
char buff[80];
Initialized = 2;
size_requested = 0;
size_queried = FALSE;
max_size_queried = FALSE;
if( GetEnvVar( "WCGMEMORY", buff, 9 ) ) {
if( buff[0] == '?' && buff[1] == '\0' ) {
max_size_queried = TRUE;
} else if( buff[0] == '#' && buff[1] == '\0' ) {
size_queried = TRUE;
} else {
size_requested = myatoi( buff ) * _1K;
}
}
#if defined( __DOS__ )
{
char *memstart;
MemorySize = 0;
if( _IsRational() ) {
dpmi_mem mem_info;
_TinyDPMIGetFreeMemoryInformation( &mem_info );
memory_available = mem_info.largest_free - _1K;
} else { // PharLap or win386
memstart = sbrk( 0 );
if( int2f( 0x1686 ) == 0 ) { // DPMI HOST
dpmi_mem mem_info;
_TinyDPMIGetFreeMemoryInformation( &mem_info );
if( max_size_queried ) {
memory_available = mem_info.largest_free;
} else {
memory_available = ( mem_info.physical_pages / 2 ) * _4K;
if( memory_available > _16M ) { // OS/2 reports 4G
memory_available = mem_info.largest_free;
if( memory_available > _16M ) {
memory_available = _16M;
}
}
}
} else {
#ifdef __DOS__
memory_available = *(char * far *)MK_FP( __psp, 0x60 ) - memstart;
#endif
}
if( memory_available < _1M ) memory_available = _1M;
}
if( size_requested != 0 ) {
if( memory_available < size_requested ) {
NotEnoughMem();
}
MemorySize = size_requested;
} else {
MemorySize = memory_available;
}
}
#elif defined( __NT__ )
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?