2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
# include "platform/platform.h"
# include "console/console.h"
2023-04-23 08:39:54 +00:00
# include "compiler.h"
2012-09-19 15:15:01 +00:00
# include "console/simBase.h"
2021-09-21 01:00:33 +00:00
extern FuncVars gEvalFuncVars ;
2021-11-17 04:56:52 +00:00
extern FuncVars gGlobalScopeFuncVars ;
extern FuncVars * gFuncVars ;
namespace Con
{
extern bool scriptWarningsAsAsserts ;
} ;
2021-09-21 01:00:33 +00:00
2012-09-19 15:15:01 +00:00
namespace Compiler
{
F64 consoleStringToNumber ( const char * str , StringTableEntry file , U32 line )
{
F64 val = dAtof ( str ) ;
2017-11-06 04:33:32 +00:00
if ( val ! = 0 )
2012-09-19 15:15:01 +00:00
return val ;
2017-11-06 04:33:32 +00:00
else if ( ! dStricmp ( str , " true " ) )
2012-09-19 15:15:01 +00:00
return 1 ;
2017-11-06 04:33:32 +00:00
else if ( ! dStricmp ( str , " false " ) )
2012-09-19 15:15:01 +00:00
return 0 ;
2017-11-06 04:33:32 +00:00
else if ( file )
2012-09-19 15:15:01 +00:00
{
Con : : warnf ( ConsoleLogEntry : : General , " %s (%d): string always evaluates to 0. " , file , line ) ;
return 0 ;
}
return 0 ;
}
//------------------------------------------------------------
CompilerStringTable * gCurrentStringTable , gGlobalStringTable , gFunctionStringTable ;
2017-11-06 04:33:32 +00:00
CompilerFloatTable * gCurrentFloatTable , gGlobalFloatTable , gFunctionFloatTable ;
2012-09-19 15:15:01 +00:00
DataChunker gConsoleAllocator ;
CompilerIdentTable gIdentTable ;
2021-08-14 05:37:01 +00:00
CompilerLocalVariableToRegisterMappingTable gFunctionVariableMappingTable ;
2012-09-19 15:15:01 +00:00
//------------------------------------------------------------
2014-09-07 16:38:35 +00:00
void evalSTEtoCode ( StringTableEntry ste , U32 ip , U32 * ptr )
2012-09-19 15:15:01 +00:00
{
2021-05-09 02:18:45 +00:00
# if defined(TORQUE_CPU_X64) || defined(TORQUE_CPU_ARM64)
2014-09-25 22:10:14 +00:00
* ( U64 * ) ( ptr ) = ( U64 ) ste ;
2014-09-07 16:38:35 +00:00
# else
* ptr = ( U32 ) ste ;
# endif
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
void compileSTEtoCode ( StringTableEntry ste , U32 ip , U32 * ptr )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( ste )
2012-09-19 15:15:01 +00:00
getIdentTable ( ) . add ( ste , ip ) ;
2014-09-07 16:38:35 +00:00
* ptr = 0 ;
2017-11-06 04:33:32 +00:00
* ( ptr + 1 ) = 0 ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
void ( * STEtoCode ) ( StringTableEntry ste , U32 ip , U32 * ptr ) = evalSTEtoCode ;
2012-09-19 15:15:01 +00:00
//------------------------------------------------------------
bool gSyntaxError = false ;
2021-09-21 01:00:33 +00:00
bool gIsEvalCompile = false ;
2012-09-19 15:15:01 +00:00
//------------------------------------------------------------
2017-11-06 04:33:32 +00:00
CompilerStringTable * getCurrentStringTable ( ) { return gCurrentStringTable ; }
CompilerStringTable & getGlobalStringTable ( ) { return gGlobalStringTable ; }
2012-09-19 15:15:01 +00:00
CompilerStringTable & getFunctionStringTable ( ) { return gFunctionStringTable ; }
2021-08-14 05:37:01 +00:00
CompilerLocalVariableToRegisterMappingTable & getFunctionVariableMappingTable ( ) { return gFunctionVariableMappingTable ; }
2017-11-06 04:33:32 +00:00
void setCurrentStringTable ( CompilerStringTable * cst ) { gCurrentStringTable = cst ; }
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
CompilerFloatTable * getCurrentFloatTable ( ) { return gCurrentFloatTable ; }
CompilerFloatTable & getGlobalFloatTable ( ) { return gGlobalFloatTable ; }
CompilerFloatTable & getFunctionFloatTable ( ) { return gFunctionFloatTable ; }
2012-09-19 15:15:01 +00:00
2017-11-06 04:33:32 +00:00
void setCurrentFloatTable ( CompilerFloatTable * cst ) { gCurrentFloatTable = cst ; }
2012-09-19 15:15:01 +00:00
CompilerIdentTable & getIdentTable ( ) { return gIdentTable ; }
void precompileIdent ( StringTableEntry ident )
{
2017-11-06 04:33:32 +00:00
if ( ident )
2012-09-19 15:15:01 +00:00
gGlobalStringTable . add ( ident ) ;
}
void resetTables ( )
{
setCurrentStringTable ( & gGlobalStringTable ) ;
setCurrentFloatTable ( & gGlobalFloatTable ) ;
getGlobalFloatTable ( ) . reset ( ) ;
getGlobalStringTable ( ) . reset ( ) ;
getFunctionFloatTable ( ) . reset ( ) ;
getFunctionStringTable ( ) . reset ( ) ;
getIdentTable ( ) . reset ( ) ;
2021-08-14 05:37:01 +00:00
getFunctionVariableMappingTable ( ) . reset ( ) ;
2021-11-17 04:56:52 +00:00
gGlobalScopeFuncVars . clear ( ) ;
gFuncVars = gIsEvalCompile ? & gEvalFuncVars : & gGlobalScopeFuncVars ;
2012-09-19 15:15:01 +00:00
}
2017-11-06 04:33:32 +00:00
void * consoleAlloc ( U32 size ) { return gConsoleAllocator . alloc ( size ) ; }
void consoleAllocReset ( ) { gConsoleAllocator . freeBlocks ( ) ; }
2012-09-19 15:15:01 +00:00
2021-11-17 04:56:52 +00:00
void scriptErrorHandler ( const char * str )
{
if ( Con : : scriptWarningsAsAsserts )
{
AssertISV ( false , str ) ;
}
else
{
Con : : warnf ( ConsoleLogEntry : : Type : : Script , " %s " , str ) ;
}
}
2012-09-19 15:15:01 +00:00
}
//-------------------------------------------------------------------------
using namespace Compiler ;
2021-09-21 01:00:33 +00:00
S32 FuncVars : : assign ( StringTableEntry var , TypeReq currentType , S32 lineNumber , bool isConstant )
{
std : : unordered_map < StringTableEntry , Var > : : iterator found = vars . find ( var ) ;
if ( found ! = vars . end ( ) )
{
2023-09-13 02:07:28 +00:00
// if we are calling assign more than once AND it changes type, we don't know what the variable type is as this is a
// dynamically typed language. So we will assign to None and bail. None will be taken care of by the code to always
// load what the default type is (What Globals and arrays use, type None).
if ( currentType ! = found - > second . currentType & & found - > second . currentType ! = TypeReqNone )
found - > second . currentType = TypeReqNone ;
2021-11-17 04:56:52 +00:00
if ( found - > second . isConstant )
{
const char * str = avar ( " Script Warning: Reassigning variable %s when it is a constant. File: %s Line : %d " , var , CodeBlock : : smCurrentParser - > getCurrentFile ( ) , lineNumber ) ;
scriptErrorHandler ( str ) ;
}
2021-09-21 01:00:33 +00:00
return found - > second . reg ;
}
S32 id = counter + + ;
vars [ var ] = { id , currentType , var , isConstant } ;
variableNameMap [ id ] = var ;
return id ;
}
S32 FuncVars : : lookup ( StringTableEntry var , S32 lineNumber )
{
std : : unordered_map < StringTableEntry , Var > : : iterator found = vars . find ( var ) ;
2023-04-23 08:39:54 +00:00
2021-11-17 04:56:52 +00:00
if ( found = = vars . end ( ) )
{
const char * str = avar ( " Script Warning: Variable %s referenced before used when compiling script. File: %s Line: %d " , var , CodeBlock : : smCurrentParser - > getCurrentFile ( ) , lineNumber ) ;
scriptErrorHandler ( str ) ;
2023-04-23 08:39:54 +00:00
2021-11-17 04:56:52 +00:00
return assign ( var , TypeReqString , lineNumber , false ) ;
}
2023-04-23 08:39:54 +00:00
2021-09-21 01:00:33 +00:00
return found - > second . reg ;
}
TypeReq FuncVars : : lookupType ( StringTableEntry var , S32 lineNumber )
{
std : : unordered_map < StringTableEntry , Var > : : iterator found = vars . find ( var ) ;
2021-11-17 04:56:52 +00:00
if ( found = = vars . end ( ) )
{
const char * str = avar ( " Script Warning: Variable %s referenced before used when compiling script. File: %s Line: %d " , var , CodeBlock : : smCurrentParser - > getCurrentFile ( ) , lineNumber ) ;
scriptErrorHandler ( str ) ;
2023-04-23 08:39:54 +00:00
2021-11-17 04:56:52 +00:00
assign ( var , TypeReqString , lineNumber , false ) ;
return vars . find ( var ) - > second . currentType ;
}
2023-04-23 08:39:54 +00:00
2021-09-21 01:00:33 +00:00
return found - > second . currentType ;
}
void FuncVars : : clear ( )
{
vars . clear ( ) ;
variableNameMap . clear ( ) ;
counter = 0 ;
}
2012-09-19 15:15:01 +00:00
//-------------------------------------------------------------------------
U32 CompilerStringTable : : add ( const char * str , bool caseSens , bool tag )
{
// Is it already in?
Entry * * walk ;
2017-11-06 04:33:32 +00:00
for ( walk = & list ; * walk ; walk = & ( ( * walk ) - > next ) )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( ( * walk ) - > tag ! = tag )
2012-09-19 15:15:01 +00:00
continue ;
2017-11-06 04:33:32 +00:00
if ( caseSens )
2012-09-19 15:15:01 +00:00
{
2020-10-03 12:37:55 +00:00
if ( ! String : : compare ( ( * walk ) - > string , str ) )
2012-09-19 15:15:01 +00:00
return ( * walk ) - > start ;
}
else
{
2017-11-06 04:33:32 +00:00
if ( ! dStricmp ( ( * walk ) - > string , str ) )
2012-09-19 15:15:01 +00:00
return ( * walk ) - > start ;
}
}
// Write it out.
2017-11-06 04:33:32 +00:00
Entry * newStr = ( Entry * ) consoleAlloc ( sizeof ( Entry ) ) ;
2012-09-19 15:15:01 +00:00
* walk = newStr ;
newStr - > next = NULL ;
newStr - > start = totalLen ;
U32 len = dStrlen ( str ) + 1 ;
2017-11-06 04:33:32 +00:00
if ( tag & & len < 7 ) // alloc space for the numeric tag 1 for tag, 5 for # and 1 for nul
2012-09-19 15:15:01 +00:00
len = 7 ;
totalLen + = len ;
2017-11-06 04:33:32 +00:00
newStr - > string = ( char * ) consoleAlloc ( len ) ;
2012-09-19 15:15:01 +00:00
newStr - > len = len ;
newStr - > tag = tag ;
2018-03-06 06:59:05 +00:00
dStrcpy ( newStr - > string , str , len ) ;
2017-11-06 04:33:32 +00:00
// Put into the hash table.
hashTable [ str ] = newStr ;
2012-09-19 15:15:01 +00:00
return newStr - > start ;
}
U32 CompilerStringTable : : addIntString ( U32 value )
{
dSprintf ( buf , sizeof ( buf ) , " %d " , value ) ;
return add ( buf ) ;
}
U32 CompilerStringTable : : addFloatString ( F64 value )
{
dSprintf ( buf , sizeof ( buf ) , " %g " , value ) ;
return add ( buf ) ;
}
void CompilerStringTable : : reset ( )
{
list = NULL ;
totalLen = 0 ;
}
char * CompilerStringTable : : build ( )
{
char * ret = new char [ totalLen ] ;
2017-11-06 04:33:32 +00:00
dMemset ( ret , 0 , totalLen ) ;
for ( Entry * walk = list ; walk ; walk = walk - > next )
2018-03-06 06:59:05 +00:00
dStrcpy ( ret + walk - > start , walk - > string , totalLen - walk - > start ) ;
2012-09-19 15:15:01 +00:00
return ret ;
}
void CompilerStringTable : : write ( Stream & st )
{
st . write ( totalLen ) ;
2017-11-06 04:33:32 +00:00
for ( Entry * walk = list ; walk ; walk = walk - > next )
2012-09-19 15:15:01 +00:00
st . write ( walk - > len , walk - > string ) ;
}
//------------------------------------------------------------
2021-09-02 02:15:37 +00:00
void CompilerLocalVariableToRegisterMappingTable : : add ( StringTableEntry functionName , StringTableEntry namespaceName , StringTableEntry varName )
2021-08-14 05:37:01 +00:00
{
2021-08-20 02:05:43 +00:00
StringTableEntry funcLookupTableName = StringTable - > insert ( avar ( " %s::%s " , namespaceName , functionName ) ) ;
2021-09-02 02:15:37 +00:00
localVarToRegister [ funcLookupTableName ] . varList . push_back ( varName ) ; ;
2021-08-14 05:37:01 +00:00
}
2021-08-20 02:05:43 +00:00
S32 CompilerLocalVariableToRegisterMappingTable : : lookup ( StringTableEntry namespaceName , StringTableEntry functionName , StringTableEntry varName )
2021-08-14 05:37:01 +00:00
{
2021-08-20 02:05:43 +00:00
StringTableEntry funcLookupTableName = StringTable - > insert ( avar ( " %s::%s " , namespaceName , functionName ) ) ;
auto functionPosition = localVarToRegister . find ( funcLookupTableName ) ;
2021-08-14 05:37:01 +00:00
if ( functionPosition ! = localVarToRegister . end ( ) )
{
2021-09-02 02:15:37 +00:00
const auto & table = localVarToRegister [ funcLookupTableName ] . varList ;
auto varPosition = std : : find ( table . begin ( ) , table . end ( ) , varName ) ;
2021-08-14 05:37:01 +00:00
if ( varPosition ! = table . end ( ) )
{
2021-09-02 02:15:37 +00:00
return std : : distance ( table . begin ( ) , varPosition ) ;
2021-08-14 05:37:01 +00:00
}
}
2021-08-20 02:05:43 +00:00
Con : : errorf ( " Unable to find local variable %s in function name %s " , varName , funcLookupTableName ) ;
2021-08-14 05:37:01 +00:00
return - 1 ;
}
CompilerLocalVariableToRegisterMappingTable CompilerLocalVariableToRegisterMappingTable : : copy ( )
{
// Trivilly copyable as its all plain old data and using STL containers... (We want a deep copy though!)
CompilerLocalVariableToRegisterMappingTable table ;
table . localVarToRegister = localVarToRegister ;
2021-09-02 02:15:37 +00:00
return table ;
2021-08-14 05:37:01 +00:00
}
void CompilerLocalVariableToRegisterMappingTable : : reset ( )
{
localVarToRegister . clear ( ) ;
}
2021-09-02 02:15:37 +00:00
void CompilerLocalVariableToRegisterMappingTable : : write ( Stream & stream )
{
2021-09-04 20:37:59 +00:00
stream . write ( ( U32 ) localVarToRegister . size ( ) ) ;
2021-09-02 02:15:37 +00:00
for ( const auto & pair : localVarToRegister )
{
StringTableEntry functionName = pair . first ;
stream . writeString ( functionName ) ;
const auto & localVariableTableForFunction = localVarToRegister [ functionName ] . varList ;
2021-09-04 20:37:59 +00:00
stream . write ( ( U32 ) localVariableTableForFunction . size ( ) ) ;
2021-09-02 02:15:37 +00:00
for ( const StringTableEntry & varName : localVariableTableForFunction )
2021-09-04 20:37:59 +00:00
{
2021-09-02 02:15:37 +00:00
stream . writeString ( varName ) ;
2021-09-04 20:37:59 +00:00
}
2021-09-02 02:15:37 +00:00
}
}
2021-08-14 05:37:01 +00:00
//------------------------------------------------------------
2012-09-19 15:15:01 +00:00
U32 CompilerFloatTable : : add ( F64 value )
{
Entry * * walk ;
U32 i = 0 ;
2017-11-06 04:33:32 +00:00
for ( walk = & list ; * walk ; walk = & ( ( * walk ) - > next ) , i + + )
if ( value = = ( * walk ) - > val )
2012-09-19 15:15:01 +00:00
return i ;
2017-11-06 04:33:32 +00:00
Entry * newFloat = ( Entry * ) consoleAlloc ( sizeof ( Entry ) ) ;
2012-09-19 15:15:01 +00:00
newFloat - > val = value ;
newFloat - > next = NULL ;
count + + ;
* walk = newFloat ;
2017-11-06 04:33:32 +00:00
return count - 1 ;
2012-09-19 15:15:01 +00:00
}
void CompilerFloatTable : : reset ( )
{
list = NULL ;
count = 0 ;
}
F64 * CompilerFloatTable : : build ( )
{
F64 * ret = new F64 [ count ] ;
U32 i = 0 ;
2017-11-06 04:33:32 +00:00
for ( Entry * walk = list ; walk ; walk = walk - > next , i + + )
2012-09-19 15:15:01 +00:00
ret [ i ] = walk - > val ;
return ret ;
}
void CompilerFloatTable : : write ( Stream & st )
{
st . write ( count ) ;
2017-11-06 04:33:32 +00:00
for ( Entry * walk = list ; walk ; walk = walk - > next )
2012-09-19 15:15:01 +00:00
st . write ( walk - > val ) ;
}
//------------------------------------------------------------
void CompilerIdentTable : : reset ( )
{
list = NULL ;
}
void CompilerIdentTable : : add ( StringTableEntry ste , U32 ip )
{
U32 index = gGlobalStringTable . add ( ste , false ) ;
2017-11-06 04:33:32 +00:00
Entry * newEntry = ( Entry * ) consoleAlloc ( sizeof ( Entry ) ) ;
2012-09-19 15:15:01 +00:00
newEntry - > offset = index ;
newEntry - > ip = ip ;
2017-11-06 04:33:32 +00:00
for ( Entry * walk = list ; walk ; walk = walk - > next )
2012-09-19 15:15:01 +00:00
{
2017-11-06 04:33:32 +00:00
if ( walk - > offset = = index )
2012-09-19 15:15:01 +00:00
{
newEntry - > nextIdent = walk - > nextIdent ;
walk - > nextIdent = newEntry ;
return ;
}
}
newEntry - > next = list ;
list = newEntry ;
newEntry - > nextIdent = NULL ;
}
void CompilerIdentTable : : write ( Stream & st )
{
U32 count = 0 ;
Entry * walk ;
2017-11-06 04:33:32 +00:00
for ( walk = list ; walk ; walk = walk - > next )
2012-09-19 15:15:01 +00:00
count + + ;
st . write ( count ) ;
2017-11-06 04:33:32 +00:00
for ( walk = list ; walk ; walk = walk - > next )
2012-09-19 15:15:01 +00:00
{
U32 ec = 0 ;
Entry * el ;
2017-11-06 04:33:32 +00:00
for ( el = walk ; el ; el = el - > nextIdent )
2012-09-19 15:15:01 +00:00
ec + + ;
st . write ( walk - > offset ) ;
st . write ( ec ) ;
2017-11-06 04:33:32 +00:00
for ( el = walk ; el ; el = el - > nextIdent )
2012-09-19 15:15:01 +00:00
st . write ( el - > ip ) ;
}
}
2014-09-07 16:38:35 +00:00
//-------------------------------------------------------------------------
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
U8 * CodeStream : : allocCode ( U32 sz )
{
U8 * ptr = NULL ;
if ( mCodeHead )
{
const U32 bytesLeft = BlockSize - mCodeHead - > size ;
if ( bytesLeft > sz )
{
ptr = mCodeHead - > data + mCodeHead - > size ;
mCodeHead - > size + = sz ;
return ptr ;
}
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
CodeData * data = new CodeData ;
data - > data = ( U8 * ) dMalloc ( BlockSize ) ;
data - > size = sz ;
data - > next = NULL ;
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
if ( mCodeHead )
mCodeHead - > next = data ;
mCodeHead = data ;
if ( mCode = = NULL )
mCode = data ;
return data - > data ;
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
//-------------------------------------------------------------------------
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
void CodeStream : : fixLoop ( U32 loopBlockStart , U32 breakPoint , U32 continuePoint )
{
AssertFatal ( mFixStack . size ( ) > 0 , " Fix stack mismatch " ) ;
2017-11-06 04:33:32 +00:00
U32 fixStart = mFixStack [ mFixStack . size ( ) - 1 ] ;
for ( U32 i = fixStart ; i < mFixList . size ( ) ; i + = 2 )
2014-09-07 16:38:35 +00:00
{
2017-11-06 04:33:32 +00:00
FixType type = ( FixType ) mFixList [ i + 1 ] ;
2014-09-07 16:38:35 +00:00
U32 fixedIp = 0 ;
bool valid = true ;
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
switch ( type )
{
case FIXTYPE_LOOPBLOCKSTART :
fixedIp = loopBlockStart ;
break ;
case FIXTYPE_BREAK :
fixedIp = breakPoint ;
break ;
case FIXTYPE_CONTINUE :
fixedIp = continuePoint ;
break ;
default :
//Con::warnf("Address %u fixed as %u", mFixList[i], mFixList[i+1]);
valid = false ;
break ;
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
if ( valid )
{
patch ( mFixList [ i ] , fixedIp ) ;
}
}
}
//-------------------------------------------------------------------------
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
void CodeStream : : emitCodeStream ( U32 * size , U32 * * stream , U32 * * lineBreaks )
{
// Alloc stream
U32 numLineBreaks = getNumLineBreaks ( ) ;
* stream = new U32 [ mCodePos + ( numLineBreaks * 2 ) ] ;
dMemset ( * stream , ' \0 ' , mCodePos + ( numLineBreaks * 2 ) ) ;
* size = mCodePos ;
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
// Dump chunks & line breaks
U32 outBytes = mCodePos * sizeof ( U32 ) ;
U8 * outPtr = * ( ( U8 * * ) stream ) ;
for ( CodeData * itr = mCode ; itr ! = NULL ; itr = itr - > next )
{
U32 bytesToCopy = itr - > size > outBytes ? outBytes : itr - > size ;
dMemcpy ( outPtr , itr - > data , bytesToCopy ) ;
outPtr + = bytesToCopy ;
outBytes - = bytesToCopy ;
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
* lineBreaks = * stream + mCodePos ;
dMemcpy ( * lineBreaks , mBreakLines . address ( ) , sizeof ( U32 ) * mBreakLines . size ( ) ) ;
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
// Apply patches on top
2017-11-06 04:33:32 +00:00
for ( U32 i = 0 ; i < mPatchList . size ( ) ; i + + )
2014-09-07 16:38:35 +00:00
{
PatchEntry & e = mPatchList [ i ] ;
( * stream ) [ e . addr ] = e . value ;
}
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
//-------------------------------------------------------------------------
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
void CodeStream : : reset ( )
{
mCodePos = 0 ;
mFixStack . clear ( ) ;
mFixLoopStack . clear ( ) ;
mFixList . clear ( ) ;
mBreakLines . clear ( ) ;
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
// Pop down to one code block
CodeData * itr = mCode ? mCode - > next : NULL ;
while ( itr ! = NULL )
{
CodeData * next = itr - > next ;
dFree ( itr - > data ) ;
2014-11-21 02:34:19 +00:00
delete ( itr ) ;
2014-09-07 16:38:35 +00:00
itr = next ;
}
2017-11-06 04:33:32 +00:00
2014-09-07 16:38:35 +00:00
if ( mCode )
{
mCode - > size = 0 ;
mCode - > next = NULL ;
mCodeHead = mCode ;
}
}