cgiobuff.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 817 行 · 第 1/2 页

C
817
字号
/****************************************************************************
*
*                            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:  WHEN YOU FIGURE OUT WHAT THIS FILE DOES, PLEASE
*               DESCRIBE IT HERE!
*
****************************************************************************/


#include "plusplus.h"

#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>

#include "memmgr.h"
#include "errdefns.h"
#include "cgiobuff.h"
#include "ring.h"
#include "iosupp.h"
#include "fname.h"
#include "toggle.h"
#include "dbg.h"
#include "icodes.h"
#include "stats.h"
#include "cgdata.h"
#include "icopmask.h"
#include "stringl.h"
#include "conpool.h"
#include "pcheader.h"

#define CGIOBUFF_CHECK  (-(sizeof(CGIOBUFF)|1))

// This must be free at bottom of a block for that block to be re-used
// for another virtual file
#define MAX_REUSE       ( sizeof( CGINTER ) * 8 + sizeof( BUFF_XFER ) )

// maximum capacity of a buffer before an IC_NEXT instruction is req'd
#define MAX_WRITE_AMT   ( TMPBLOCK_BSIZE - sizeof( BUFF_XFER ) - sizeof( CGINTER ) )

#ifndef NDEBUG
#define DICT_SIZE       4
#include "pragdefn.h"
#else
#define DICT_SIZE       128
#endif

typedef struct buff_dict BUFFDICT;
struct buff_dict {
    BUFFDICT    *next;
    CGIOBUFF    *dict[DICT_SIZE];
};

static BUFFDICT *directoryOfBufs;
static unsigned maxDictIndex;
static CGIOBUFF *allBufs;
static CGIOBUFF *reusableBufs;
static CGIOBUFF *beingWritten;          // NULL or the one being written

static icop_mask icMaskTable[] = {
    #include "ic_mask.gh"
};

// defines ic_op_type ICOpTypes[]
#include "itypvec.h"

#define doReadOpNUL     NULL
#define doReadOpBIN     NULL
#define doReadOpCON     ConstantPoolMapIndex
#define doReadOpSYM     SymbolMapIndex
#define doReadOpSTR     StringMapIndex
#define doReadOpTYP     TypeMapIndex
#define doReadOpSCP     ScopeMapIndex
#define doReadOpSRC     SrcFileMapIndex

static CGIRELOCFN *relocReadOperand[] = {
#define ITYPE( typ )    ((CGIRELOCFN*) doReadOp##typ)
#include "itypes.h"
};

ExtraRptCtr( ctr_buffers );     // counts buffers
ExtraRptCtr( ctr_usage );       // counts bytes used in buffers


typedef struct {                // disk transfer code
    CGINTER     leap_ins;       // - IC_NEXT (value.uvalue has disk block)
    DISK_OFFSET offset;         // - disk offset
} BUFF_XFER;

#define pointXferOffset( ctl, off )     ( (void*)( (ctl)->data + (off)) )
#define pointXfer( ctl )                ( (void*)( (ctl)->data + (ctl)->free_offset) )

static BUFFDICT *newDict( void )
{
    BUFFDICT *dict;

    dict = CPermAlloc( sizeof( *dict ) );
    memset( dict, 0, sizeof( *dict ) );
    dict->next = directoryOfBufs;
    directoryOfBufs = dict;
    ++maxDictIndex;
    return( dict );
}

static void addDirectoryEntry( CGIOBUFF *e )
{
    unsigned dict_index;
    unsigned dict_offset;
    BUFFDICT *dict;

    dict_index = e->disk_addr / DICT_SIZE;
    dict_offset = e->disk_addr % DICT_SIZE;
    DbgAssert( dict_index <= (maxDictIndex + 1) );
    dict = directoryOfBufs;
    if( dict_index != maxDictIndex ) {
        dict = newDict();
    }
    dict->dict[ dict_offset ] = e;
}

static CGIOBUFF **findDirectoryEntry( DISK_ADDR disk_addr )
{
    unsigned dict_index;
    unsigned dict_offset;
    unsigned i;
    BUFFDICT *dict;

    dict_index = disk_addr / DICT_SIZE;
    dict_offset = disk_addr % DICT_SIZE;
    DbgAssert( dict_index <= maxDictIndex );
    dict = directoryOfBufs;
    i = maxDictIndex;
    for(;;) {
        if( i == dict_index ) break;
        DbgAssert( i != 0 );
        --i;
        dict = dict->next;
        DbgAssert( dict != NULL );
    }
    return( &(dict->dict[ dict_offset ]) );
}

static void setDirectoryEntry( DISK_ADDR disk_addr, CGIOBUFF *e )
{
    CGIOBUFF **dict;

    dict = findDirectoryEntry( disk_addr );
    *dict = e;
}


static void addToReuseList(     // ADD BUFFER TO REUSE LIST (IF IT CAN BE REUSED)
    CGIOBUFF *ctl )             // - buffer control
{
    CGIOBUFF *head;
    CGIOBUFF *head_next;

    if( ctl->reuse_next != NULL ) {
        return;
    }
    if( ctl->writing ) {
        return;
    }
    if( ctl->free_offset > ( TMPBLOCK_BSIZE - MAX_REUSE ) ) {
        return;
    }
    if( reusableBufs != NULL ) {
        head = reusableBufs;
        head_next = head->reuse_next;
        // insert between 'head' and 'head_next'
        ctl->reuse_prev = head;
        ctl->reuse_next = head_next;
        head_next->reuse_prev = ctl;
        head->reuse_next = ctl;
    } else {
        ctl->reuse_prev = ctl;
        ctl->reuse_next = ctl;
        reusableBufs = ctl;
    }
}


static void removeFromReuseList(// DETACH BUFFER FROM REUSE LIST
    CGIOBUFF *ctl )             // - buffer control
{
    CGIOBUFF *prev;
    CGIOBUFF *next;

    DbgAssert( ctl->reuse_next != NULL );
    DbgAssert( ctl->reuse_prev != NULL );
    prev = ctl->reuse_prev;
    next = ctl->reuse_next;
    prev->reuse_next = next;
    next->reuse_prev = prev;
    if( reusableBufs == ctl ) {
        if( prev == next ) {
            reusableBufs = NULL;
        } else {
            reusableBufs = prev;
        }
    }
    // must be here in case 'prev' == 'next'
    ctl->reuse_prev = NULL;
    ctl->reuse_next = NULL;
}


static CGIOBUFF *allocateBuffer(// ALLOCATE A NEW BUFFER
    DISK_ADDR block )           // - block number
{
    CGIOBUFF *ctl;              // - new buffer

    ctl = CMemAlloc( sizeof( *ctl ) );
    ctl->next = NULL;
    ctl->reuse_prev = NULL;
    ctl->reuse_next = NULL;
    ctl->disk_addr = block;
    ctl->free_offset = 0;
    ctl->reading = 0;
    ctl->written = FALSE;
    ctl->writing = FALSE;
    ctl->active = FALSE;
    DbgStmt( ctl->check = CGIOBUFF_CHECK );
    RingAppend( &allBufs, ctl );
    ExtraRptIncrementCtr( ctr_buffers );
    return ctl;
}


static CGIOBUFF *findWrBuffer(  // FIND A BUFFER FOR WRITING
    void )
{
    CGIOBUFF *ctl;              // - buffer control
    DISK_ADDR block;            // - block number

    ctl = reusableBufs;
    if( ctl != NULL ) {
        removeFromReuseList( ctl );
    } else {
        block = IoSuppTempNextBlock( 1 );
        ctl = allocateBuffer( block );
        addDirectoryEntry( ctl );
    }
    ctl->active = TRUE;
    ctl->writing = TRUE;
    ctl->written = FALSE;
    DbgAssert( ctl->check == CGIOBUFF_CHECK );
    return( ctl );
}


static CGIOBUFF *findRdBuffer(  // FIND A BUFFER FOR READING
    DISK_ADDR block  )          // - disk block
{
    CGIOBUFF *ctl;
    CGIOBUFF **dict;

    dict = findDirectoryEntry( block );
    ctl = *dict;
    if( ctl == NULL ) {
        ctl = allocateBuffer( block );
        setDirectoryEntry( block, ctl );
        IoSuppTempRead( block, TMPBLOCK_BSIZE, ctl->data );
        ctl->written = TRUE;
        ctl->free_offset = TMPBLOCK_BSIZE;
    }
    ctl->active = TRUE;
    ++ctl->reading;
    DbgAssert( ctl->check == CGIOBUFF_CHECK );
    return ctl;
}


static void finishWrBuffer(     // COMPLETE WRITE-USE OF A BUFFER
    CGIOBUFF *ctl )             // - buffer control
{
    DbgAssert( ctl->check == CGIOBUFF_CHECK );
    ctl->writing = FALSE;
    if( ctl->reading == 0 ) {
        ctl->active = FALSE;
    }
    addToReuseList( ctl );
}


static void finishRdBuffer(     // COMPLETE READ-USE OF A BUFFER
    CGIOBUFF *ctl )             // - buffer control
{
    DbgAssert( ctl->check == CGIOBUFF_CHECK );
    -- ctl->reading;
    if( ctl->reading == 0 && ! ctl->writing ) {
        ctl->active = FALSE;
        addToReuseList( ctl );
    }
}


CGIOBUFF *CgioBuffWrOpen(       // GET BUFFER FOR WRITING
    void )
{
    return findWrBuffer();
}

static CGIOBUFF *switchToNextBuffer( CGIOBUFF *ctl )
{
    CGIOBUFF *next;             // - next buffer control
    BUFF_XFER *xfer;            // - transfer record

    next = findWrBuffer();
    xfer = pointXfer( ctl );
    xfer->leap_ins.opcode = IC_NEXT;
    xfer->leap_ins.value.uvalue = next->disk_addr;
    xfer->offset = next->free_offset;
    ctl->free_offset += sizeof( BUFF_XFER );
    finishWrBuffer( ctl );
    return( next );
}

CGINTER *CgioBuffPCHRead(       // READ FROM PCH AND WRITE INTO BUFFER
    CGINTER *buff,              // - alternate buffer for PCHReadLoc
    CGIOBUFF **pctl )           // - addr( buffer control )
{
    CGIRELOCFN *relocate;       // - relocator function
    CGINTER *p_instr;           // - IC to process
    CGINTER *s_instr;           // - past last IC to process
    CGIOBUFF *ctl;              // - buffer control
    CGINTER *start;             // - first destination for IC
    CGINTER *dest;              // - destination for IC
    CGINTER *stop;              // - last destination for IC
    unsigned opcode;            // - IC opcode

    #define CBP_LIMIT ( MAX_WRITE_AMT - CGINTER_BLOCKING * sizeof(CGINTER) )
    ctl = *pctl;
    start = pointXfer( ctl );
    dest = start;
    stop = pointXferOffset( ctl, CBP_LIMIT );
    for(;;) {
        if( dest >= stop ) {
            ctl->free_offset += ((char*)dest) - (char*)start;
            ctl = switchToNextBuffer( ctl );
            start = pointXfer( ctl );
            dest = start;
            stop = pointXferOffset( ctl, CBP_LIMIT );
        }
        PCHReadLocSize( p_instr, buff, CGINTER_BLOCKING * sizeof( *p_instr ) );
        s_instr = &p_instr[ CGINTER_BLOCKING ];
        do {
            opcode = p_instr->opcode;
            if( icMaskTable[ opcode ] & ICOPM_PCHREAD ) {
                ctl->free_offset += ((char*)dest) - (char*)start;
                *pctl = ctl;
                // rest of block can be ignored
#ifndef NDEBUG
                {
                    CGINTER *c = p_instr + 1;
                    DbgAssert( c <= s_instr );
                    DbgAssert(( s_instr - c ) < CGINTER_BLOCKING );
                    while( c < s_instr ) {
                        DbgAssert( c->opcode == IC_PCH_PAD );
                        ++c;
                    }
                }
#endif
                return( p_instr );
            }
            relocate = relocReadOperand[ ICOpTypes[ opcode ] ];
            if( relocate != NULL ) {
                dest->value.pvalue = (*relocate)( p_instr->value.pvalue );
            } else {
                dest->value = p_instr->value;
            }
            dest->opcode = opcode;
            ++dest;
            ++p_instr;
        } while( p_instr < s_instr );
    }
    #undef CBP_LIMIT
}


CGVALUE CgioMapIndex( unsigned opcode, CGVALUE value )
/****************************************************/
{
    ic_op_type op_class;
    CGIRELOCFN *reloc;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?