use a memory arena for allocating code generation nodes.

- Since the number of small allocations here is extremely high this will help a lot to prevent fragmentation and since most nodes are collected up front and this is done when no large resources are being loaded it won't cause heap spikes.

let Emit methods delete FxExpression arrays when they are done.
- For some reason the deletion process does not work 100%, there are always some nodes left behind and so far I haven't found them. This ensures that these arrays do not live any longer than needed.
This commit is contained in:
Christoph Oelckers 2016-11-10 15:13:31 +01:00
parent e0bd6a2c0a
commit a60bdc2bfb
9 changed files with 209 additions and 204 deletions

View file

@ -43,8 +43,6 @@
#include "c_dispatch.h"
#include "zstring.h"
#define BLOCK_SIZE (10*1024)
struct FMemArena::Block
{
Block *NextBlock;
@ -74,10 +72,11 @@ static inline void *RoundPointer(void *ptr)
//
//==========================================================================
FMemArena::FMemArena()
FMemArena::FMemArena(int bs)
{
TopBlock = NULL;
FreeBlocks = NULL;
BlockSize = bs;
}
//==========================================================================
@ -191,14 +190,14 @@ FMemArena::Block *FMemArena::AddBlock(size_t size)
if (mem == NULL)
{
// Allocate a new block
if (size < BLOCK_SIZE)
if (size < BlockSize)
{
size = BLOCK_SIZE;
size = BlockSize;
}
else
{ // Stick some free space at the end so we can use this block for
// other things.
size += BLOCK_SIZE/2;
size += BlockSize/2;
}
mem = (Block *)M_Malloc(size);
mem->Limit = (BYTE *)mem + size;

View file

@ -40,7 +40,7 @@
class FMemArena
{
public:
FMemArena();
FMemArena(int blocksize = 10*1024);
~FMemArena();
void *Alloc(size_t size);
@ -55,6 +55,7 @@ protected:
Block *TopBlock;
Block *FreeBlocks;
int BlockSize;
};
// An arena specializing in storage of FStrings. It knows how to free them,

View file

@ -57,6 +57,7 @@
#include "math/cmath.h"
extern FRandom pr_exrandom;
FMemArena FxAlloc(65536);
struct FLOP
{
@ -483,7 +484,9 @@ FxVectorValue::FxVectorValue(FxExpression *x, FxExpression *y, FxExpression *z,
FxVectorValue::~FxVectorValue()
{
for (auto &a : xyz)
{
SAFE_DELETE(a);
}
}
FxExpression *FxVectorValue::Resolve(FCompileContext&ctx)
@ -3721,6 +3724,8 @@ ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build)
build->Emit(OP_JMP, 1);
auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1);
for (auto addr : patchspots) build->Backpatch(addr, ctarget);
list.Clear();
list.ShrinkToFit();
return to;
}
@ -4362,6 +4367,7 @@ FxMinMax::FxMinMax(TArray<FxExpression*> &expr, FName type, const FScriptPositio
for (unsigned i = 0; i < expr.Size(); ++i)
{
choices[i] = expr[i];
expr[i] = nullptr;
}
}
@ -4713,10 +4719,12 @@ FxRandomPick::FxRandomPick(FRandom *r, TArray<FxExpression*> &expr, bool floaty,
if (floaty)
{
choices[index] = new FxFloatCast(expr[index]);
expr[index] = nullptr;
}
else
{
choices[index] = new FxIntCast(expr[index], nowarn);
expr[index] = nullptr;
}
}
@ -5218,6 +5226,11 @@ FxMemberIdentifier::FxMemberIdentifier(FxExpression *left, FName name, const FSc
ExprType = EFX_MemberIdentifier;
}
FxMemberIdentifier::~FxMemberIdentifier()
{
SAFE_DELETE(Object);
}
//==========================================================================
//
//
@ -5277,6 +5290,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
return nullptr;
}
auto x = isclass? new FxClassMember(Object, vsym, ScriptPosition) : new FxStructMember(Object, vsym, ScriptPosition);
Object = nullptr;
delete this;
return x->Resolve(ctx);
}
@ -5313,6 +5327,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
ScriptPosition.Message(MSG_WARNING, "Accessing deprecated member variable %s", vsym->SymbolName.GetChars());
}
auto x = new FxStructMember(Object, vsym, ScriptPosition);
Object = nullptr;
delete this;
return x->Resolve(ctx);
}
@ -5942,12 +5957,12 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList *args, const FScriptPosition &pos)
FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos)
: FxExpression(EFX_FunctionCall, pos)
{
MethodName = methodname;
RNG = &pr_exrandom;
ArgList = args;
ArgList = std::move(args);
if (rngname != NAME_None)
{
switch (MethodName)
@ -5976,7 +5991,6 @@ FxFunctionCall::FxFunctionCall(FName methodname, FName rngname, FArgumentList *a
FxFunctionCall::~FxFunctionCall()
{
SAFE_DELETE(ArgList);
}
//==========================================================================
@ -5985,9 +5999,9 @@ FxFunctionCall::~FxFunctionCall()
//
//==========================================================================
static bool CheckArgSize(FName fname, FArgumentList *args, int min, int max, FScriptPosition &sc)
static bool CheckArgSize(FName fname, FArgumentList &args, int min, int max, FScriptPosition &sc)
{
int s = args ? args->Size() : 0;
int s = args.Size();
if (s < min)
{
sc.Message(MSG_ERROR, "Insufficient arguments in call to %s, expected %d, got %d", fname.GetChars(), min, s);
@ -6030,7 +6044,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
}
auto self = !(afd->Variants[0].Flags & VARF_Static)? new FxSelf(ScriptPosition) : nullptr;
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, false);
ArgList = nullptr;
delete this;
return x->Resolve(ctx);
}
@ -6040,7 +6053,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
if (MethodName == FxFlops[i].Name)
{
FxExpression *x = new FxFlopFunctionCall(i, ArgList, ScriptPosition);
ArgList = nullptr;
delete this;
return x->Resolve(ctx);
}
@ -6059,7 +6071,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
}
if (special != 0 && min >= 0)
{
int paramcount = ArgList? ArgList->Size() : 0;
int paramcount = ArgList.Size();
if (paramcount < min)
{
ScriptPosition.Message(MSG_ERROR, "Not enough parameters for '%s' (expected %d, got %d)",
@ -6076,7 +6088,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
}
FxExpression *self = (ctx.Function && ctx.Function->Variants[0].Flags & VARF_Method) ? new FxSelf(ScriptPosition) : nullptr;
FxExpression *x = new FxActionSpecialCall(self, special, ArgList, ScriptPosition);
ArgList = nullptr;
delete this;
return x->Resolve(ctx);
}
@ -6086,8 +6097,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
{
if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition))
{
FxExpression *x = new FxDynamicCast(cls, (*ArgList)[0]);
(*ArgList)[0] = nullptr;
FxExpression *x = new FxDynamicCast(cls, ArgList[0]);
ArgList[0] = nullptr;
delete this;
return x->Resolve(ctx);
}
@ -6126,29 +6137,29 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
MethodName == NAME_Color ? TypeColor :
MethodName == NAME_State? TypeState :(PType*)TypeSound;
func = new FxTypeCast((*ArgList)[0], type, true, true);
(*ArgList)[0] = nullptr;
func = new FxTypeCast(ArgList[0], type, true, true);
ArgList[0] = nullptr;
}
break;
case NAME_Random:
// allow calling Random without arguments to default to (0, 255)
if (ArgList->Size() == 0)
if (ArgList.Size() == 0)
{
func = new FxRandom(RNG, new FxConstant(0, ScriptPosition), new FxConstant(255, ScriptPosition), ScriptPosition, ctx.FromDecorate);
}
else if (CheckArgSize(NAME_Random, ArgList, 2, 2, ScriptPosition))
{
func = new FxRandom(RNG, (*ArgList)[0], (*ArgList)[1], ScriptPosition, ctx.FromDecorate);
(*ArgList)[0] = (*ArgList)[1] = nullptr;
func = new FxRandom(RNG, ArgList[0], ArgList[1], ScriptPosition, ctx.FromDecorate);
ArgList[0] = ArgList[1] = nullptr;
}
break;
case NAME_FRandom:
if (CheckArgSize(NAME_FRandom, ArgList, 2, 2, ScriptPosition))
{
func = new FxFRandom(RNG, (*ArgList)[0], (*ArgList)[1], ScriptPosition);
(*ArgList)[0] = (*ArgList)[1] = nullptr;
func = new FxFRandom(RNG, ArgList[0], ArgList[1], ScriptPosition);
ArgList[0] = ArgList[1] = nullptr;
}
break;
@ -6156,16 +6167,15 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
case NAME_FRandomPick:
if (CheckArgSize(MethodName, ArgList, 1, -1, ScriptPosition))
{
func = new FxRandomPick(RNG, *ArgList, MethodName == NAME_FRandomPick, ScriptPosition, ctx.FromDecorate);
for (auto &i : *ArgList) i = nullptr;
func = new FxRandomPick(RNG, ArgList, MethodName == NAME_FRandomPick, ScriptPosition, ctx.FromDecorate);
}
break;
case NAME_Random2:
if (CheckArgSize(NAME_Random2, ArgList, 0, 1, ScriptPosition))
{
func = new FxRandom2(RNG, ArgList->Size() == 0? nullptr : (*ArgList)[0], ScriptPosition, ctx.FromDecorate);
if (ArgList->Size() > 0) (*ArgList)[0] = nullptr;
func = new FxRandom2(RNG, ArgList.Size() == 0? nullptr : ArgList[0], ScriptPosition, ctx.FromDecorate);
if (ArgList.Size() > 0) ArgList[0] = nullptr;
}
break;
@ -6173,8 +6183,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
case NAME_Max:
if (CheckArgSize(MethodName, ArgList, 2, -1, ScriptPosition))
{
func = new FxMinMax(*ArgList, MethodName, ScriptPosition);
for (auto &i : *ArgList) i = nullptr;
func = new FxMinMax(ArgList, MethodName, ScriptPosition);
}
break;
@ -6183,20 +6192,20 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
{
TArray<FxExpression *> pass;
pass.Resize(2);
pass[0] = (*ArgList)[0];
pass[1] = (*ArgList)[1];
pass[0] = ArgList[0];
pass[1] = ArgList[1];
pass[0] = new FxMinMax(pass, NAME_Max, ScriptPosition);
pass[1] = (*ArgList)[2];
pass[1] = ArgList[2];
func = new FxMinMax(pass, NAME_Min, ScriptPosition);
(*ArgList)[0] = (*ArgList)[1] = (*ArgList)[2] = nullptr;
ArgList[0] = ArgList[1] = ArgList[2] = nullptr;
}
break;
case NAME_Abs:
if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition))
{
func = new FxAbs((*ArgList)[0]);
(*ArgList)[0] = nullptr;
func = new FxAbs(ArgList[0]);
ArgList[0] = nullptr;
}
break;
@ -6204,8 +6213,8 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
case NAME_VectorAngle:
if (CheckArgSize(MethodName, ArgList, 2, 2, ScriptPosition))
{
func = MethodName == NAME_ATan2 ? new FxATan2((*ArgList)[0], (*ArgList)[1], ScriptPosition) : new FxATan2((*ArgList)[1], (*ArgList)[0], ScriptPosition);
(*ArgList)[0] = (*ArgList)[1] = nullptr;
func = MethodName == NAME_ATan2 ? new FxATan2(ArgList[0], ArgList[1], ScriptPosition) : new FxATan2(ArgList[1], ArgList[0], ScriptPosition);
ArgList[0] = ArgList[1] = nullptr;
}
break;
@ -6229,12 +6238,12 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
//
//==========================================================================
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos)
FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos)
: FxExpression(EFX_MemberFunctionCall, pos)
{
Self = self;
MethodName = methodname;
ArgList = args;
ArgList = std::move(args);
}
//==========================================================================
@ -6246,7 +6255,6 @@ FxMemberFunctionCall::FxMemberFunctionCall(FxExpression *self, FName methodname,
FxMemberFunctionCall::~FxMemberFunctionCall()
{
SAFE_DELETE(Self);
SAFE_DELETE(ArgList);
}
//==========================================================================
@ -6342,7 +6350,6 @@ isresolved:
// do not pass the self pointer to static functions.
auto self = (afd->Variants[0].Flags & VARF_Method) ? Self : nullptr;
auto x = new FxVMFunctionCall(self, afd, ArgList, ScriptPosition, staticonly);
ArgList = nullptr;
if (Self == self) Self = nullptr;
delete this;
return x->Resolve(ctx);
@ -6358,12 +6365,12 @@ isresolved:
//
//==========================================================================
FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos)
FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos)
: FxExpression(EFX_ActionSpecialCall, pos)
{
Self = self;
Special = special;
ArgList = args;
ArgList = std::move(args);
EmitTail = false;
}
@ -6376,7 +6383,6 @@ FxActionSpecialCall::FxActionSpecialCall(FxExpression *self, int special, FArgum
FxActionSpecialCall::~FxActionSpecialCall()
{
SAFE_DELETE(Self);
SAFE_DELETE(ArgList);
}
//==========================================================================
@ -6403,51 +6409,48 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
bool failed = false;
SAFE_RESOLVE_OPT(Self, ctx);
if (ArgList != nullptr)
for (unsigned i = 0; i < ArgList.Size(); i++)
{
for (unsigned i = 0; i < ArgList->Size(); i++)
ArgList[i] = ArgList[i]->Resolve(ctx);
if (ArgList[i] == nullptr)
{
(*ArgList)[i] = (*ArgList)[i]->Resolve(ctx);
if ((*ArgList)[i] == nullptr)
failed = true;
}
else if (Special < 0 && i == 0)
{
if (ArgList[i]->ValueType == TypeString)
{
ArgList[i] = new FxNameCast(ArgList[i]);
ArgList[i] = ArgList[i]->Resolve(ctx);
if (ArgList[i] == nullptr)
{
failed = true;
}
}
else if (ArgList[i]->ValueType != TypeName)
{
ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i);
failed = true;
}
else if (Special < 0 && i == 0)
{
if ((*ArgList)[i]->ValueType == TypeString)
{
(*ArgList)[i] = new FxNameCast((*ArgList)[i]);
(*ArgList)[i] = (*ArgList)[i]->Resolve(ctx);
if ((*ArgList)[i] == nullptr)
{
failed = true;
}
}
else if ((*ArgList)[i]->ValueType != TypeName)
{
ScriptPosition.Message(MSG_ERROR, "Name expected for parameter %d", i);
failed = true;
}
}
else if (!(*ArgList)[i]->IsInteger())
{
if ((*ArgList)[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
(*ArgList)[i] = new FxIntCast((*ArgList)[i], ctx.FromDecorate);
}
else
{
ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i);
failed = true;
}
}
}
if (failed)
else if (!ArgList[i]->IsInteger())
{
delete this;
return nullptr;
if (ArgList[i]->ValueType->GetRegType() == REGT_FLOAT /* lax */)
{
ArgList[i] = new FxIntCast(ArgList[i], ctx.FromDecorate);
}
else
{
ScriptPosition.Message(MSG_ERROR, "Integer expected for parameter %d", i);
failed = true;
}
}
}
if (failed)
{
delete this;
return nullptr;
}
ValueType = TypeSInt32;
return this;
}
@ -6481,30 +6484,27 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
// fixme: This really should use the Self pointer that got passed to this class instead of just using the first argument from the function.
// Once static functions are possible, or specials can be called through a member access operator this won't work anymore.
build->Emit(OP_PARAM, 0, REGT_POINTER, 0); // pass self
if (ArgList != nullptr)
for (; i < ArgList.Size(); ++i)
{
for (; i < ArgList->Size(); ++i)
FxExpression *argex = ArgList[i];
if (Special < 0 && i == 0)
{
FxExpression *argex = (*ArgList)[i];
if (Special < 0 && i == 0)
assert(argex->ValueType == TypeName);
assert(argex->isConstant());
build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName());
}
else
{
assert(argex->ValueType->GetRegType() == REGT_INT);
if (argex->isConstant())
{
assert(argex->ValueType == TypeName);
assert(argex->isConstant());
build->EmitParamInt(-static_cast<FxConstant *>(argex)->GetValue().GetName());
build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt());
}
else
{
assert(argex->ValueType->GetRegType() == REGT_INT);
if (argex->isConstant())
{
build->EmitParamInt(static_cast<FxConstant *>(argex)->GetValue().GetInt());
}
else
{
ExpEmit arg(argex->Emit(build));
build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum);
arg.Free(build);
}
ExpEmit arg(argex->Emit(build));
build->Emit(OP_PARAM, 0, arg.RegType, arg.RegNum);
arg.Free(build);
}
}
}
@ -6515,6 +6515,8 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
callfunc = ((PSymbolVMFunction *)sym)->Function;
ArgList.Clear();
ArgList.ShrinkToFit();
if (EmitTail)
{
@ -6536,12 +6538,12 @@ ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList *args, const FScriptPosition &pos, bool novirtual)
FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual)
: FxExpression(EFX_VMFunctionCall, pos)
{
Self = self;
Function = func;
ArgList = args;
ArgList = std::move(args);
EmitTail = false;
NoVirtual = novirtual;
}
@ -6554,7 +6556,6 @@ FxVMFunctionCall::FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumen
FxVMFunctionCall::~FxVMFunctionCall()
{
SAFE_DELETE(ArgList);
}
//==========================================================================
@ -6581,7 +6582,7 @@ VMFunction *FxVMFunctionCall::GetDirectFunction()
// then it can be a "direct" function. That is, the DECORATE
// definition can call that function directly without wrapping
// it inside VM code.
if ((ArgList ? ArgList->Size() : 0) == 0 && !(Function->Variants[0].Flags & VARF_Virtual))
if (ArgList.Size() == 0 && !(Function->Variants[0].Flags & VARF_Virtual))
{
return Function->Variants[0].Implementation;
}
@ -6613,18 +6614,18 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
return nullptr;
}
if (ArgList != nullptr)
if (ArgList.Size() > 0)
{
bool foundvarargs = false;
PType * type = nullptr;
if (argtypes.Last() != nullptr && ArgList->Size() + implicit > argtypes.Size())
if (argtypes.Last() != nullptr && ArgList.Size() + implicit > argtypes.Size())
{
ScriptPosition.Message(MSG_ERROR, "Too many arguments in call to %s", Function->SymbolName.GetChars());
delete this;
return nullptr;
}
for (unsigned i = 0; i < ArgList->Size(); i++)
for (unsigned i = 0; i < ArgList.Size(); i++)
{
// Varargs must all have the same type as the last typed argument. A_Jump is the only function using it.
if (!foundvarargs)
@ -6634,12 +6635,12 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
}
assert(type != nullptr);
FxExpression *x = new FxTypeCast((*ArgList)[i], type, false);
FxExpression *x = new FxTypeCast(ArgList[i], type, false);
x = x->Resolve(ctx);
failed |= (x == nullptr);
(*ArgList)[i] = x;
ArgList[i] = x;
}
int numargs = ArgList->Size() + implicit;
int numargs = ArgList.Size() + implicit;
if ((unsigned)numargs < argtypes.Size() && argtypes[numargs] != nullptr)
{
auto flags = Function->Variants[0].ArgFlags[numargs];
@ -6679,13 +6680,15 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
int count = 0; (ArgList ? ArgList->Size() : 0);
int count = 0;
if (count == 1)
{
ExpEmit reg;
if (CheckEmitCast(build, EmitTail, reg))
{
ArgList.Clear();
ArgList.ShrinkToFit();
return reg;
}
}
@ -6718,13 +6721,13 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
selfemit.Free(build);
}
// Emit code to pass explicit parameters
if (ArgList != nullptr)
for (unsigned i = 0; i < ArgList.Size(); ++i)
{
for (unsigned i = 0; i < ArgList->Size(); ++i)
{
count += EmitParameter(build, (*ArgList)[i], ScriptPosition);
}
count += EmitParameter(build, ArgList[i], ScriptPosition);
}
ArgList.Clear();
ArgList.ShrinkToFit();
// Get a constant register for this function
VMFunction *vmfunc = Function->Variants[0].Implementation;
int funcaddr = build->GetConstantAddress(vmfunc, ATAG_OBJECT);
@ -6766,7 +6769,7 @@ bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, Ex
funcname == NAME___decorate_internal_state__ ||
funcname == NAME___decorate_internal_float__)
{
FxExpression *arg = (*ArgList)[0];
FxExpression *arg = ArgList[0];
if (returnit)
{
if (arg->isConstant() &&
@ -6799,12 +6802,12 @@ bool FxVMFunctionCall::CheckEmitCast(VMFunctionBuilder *build, bool returnit, Ex
//
//==========================================================================
FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList *args, const FScriptPosition &pos)
FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList &args, const FScriptPosition &pos)
: FxExpression(EFX_FlopFunctionCall, pos)
{
assert(index < countof(FxFlops) && "FLOP index out of range");
Index = (int)index;
ArgList = args;
ArgList = std::move(args);
}
//==========================================================================
@ -6815,44 +6818,43 @@ FxFlopFunctionCall::FxFlopFunctionCall(size_t index, FArgumentList *args, const
FxFlopFunctionCall::~FxFlopFunctionCall()
{
SAFE_DELETE(ArgList);
}
FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
if (ArgList == nullptr || ArgList->Size() != 1)
if (ArgList.Size() != 1)
{
ScriptPosition.Message(MSG_ERROR, "%s only has one parameter", FName(FxFlops[Index].Name).GetChars());
delete this;
return nullptr;
}
(*ArgList)[0] = (*ArgList)[0]->Resolve(ctx);
if ((*ArgList)[0] == nullptr)
ArgList[0] = ArgList[0]->Resolve(ctx);
if (ArgList[0] == nullptr)
{
delete this;
return nullptr;
}
if (!(*ArgList)[0]->IsNumeric())
if (!ArgList[0]->IsNumeric())
{
ScriptPosition.Message(MSG_ERROR, "numeric value expected for parameter");
delete this;
return nullptr;
}
if ((*ArgList)[0]->isConstant())
if (ArgList[0]->isConstant())
{
double v = static_cast<FxConstant *>((*ArgList)[0])->GetValue().GetFloat();
double v = static_cast<FxConstant *>(ArgList[0])->GetValue().GetFloat();
v = FxFlops[Index].Evaluate(v);
FxExpression *x = new FxConstant(v, ScriptPosition);
delete this;
return x;
}
if ((*ArgList)[0]->ValueType->GetRegType() == REGT_INT)
if (ArgList[0]->ValueType->GetRegType() == REGT_INT)
{
(*ArgList)[0] = new FxFloatCast((*ArgList)[0]);
ArgList[0] = new FxFloatCast(ArgList[0]);
}
ValueType = TypeFloat64;
return this;
@ -6865,10 +6867,12 @@ FxExpression *FxFlopFunctionCall::Resolve(FCompileContext& ctx)
ExpEmit FxFlopFunctionCall::Emit(VMFunctionBuilder *build)
{
ExpEmit v = (*ArgList)[0]->Emit(build);
ExpEmit v = ArgList[0]->Emit(build);
assert(!v.Konst && v.RegType == REGT_FLOAT);
build->Emit(OP_FLOP, v.RegNum, v.RegNum, FxFlops[Index].Flop);
ArgList.Clear();
ArgList.ShrinkToFit();
return v;
}
@ -7081,17 +7085,16 @@ bool FxCompoundStatement::CheckLocalVariable(FName name)
//
//==========================================================================
FxSwitchStatement::FxSwitchStatement(FxExpression *cond, FArgumentList *content, const FScriptPosition &pos)
FxSwitchStatement::FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos)
: FxExpression(EFX_SwitchStatement, pos)
{
Condition = new FxIntCast(cond, false);
Content = content;
Content = std::move(content);
}
FxSwitchStatement::~FxSwitchStatement()
{
SAFE_DELETE(Condition);
SAFE_DELETE(Content);
}
FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
@ -7099,7 +7102,7 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
CHECKRESOLVED();
SAFE_RESOLVE(Condition, ctx);
if (Content == nullptr || Content->Size() == 0)
if (Content.Size() == 0)
{
ScriptPosition.Message(MSG_WARNING, "Empty switch statement");
if (Condition->isConstant())
@ -7117,7 +7120,7 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
}
}
for (auto &line : *Content)
for (auto &line : Content)
{
// Do not resolve breaks, they need special treatment inside switch blocks.
if (line->ExprType != EFX_JumpStatement || static_cast<FxJumpStatement *>(line)->Token != TK_Break)
@ -7130,7 +7133,7 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
if (Condition->isConstant())
{
ScriptPosition.Message(MSG_WARNING, "Case expression is constant");
auto &content = *Content;
auto &content = Content;
int defaultindex = -1;
int defaultbreak = -1;
int caseindex = -1;
@ -7182,7 +7185,7 @@ FxExpression *FxSwitchStatement::Resolve(FCompileContext &ctx)
int mincase = INT_MAX;
int maxcase = INT_MIN;
for (auto line : *Content)
for (auto line : Content)
{
if (line->ExprType == EFX_CaseStatement)
{
@ -7227,7 +7230,7 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
size_t DefaultAddress = build->Emit(OP_JMP, 0);
TArray<size_t> BreakAddresses;
for (auto line : *Content)
for (auto line : Content)
{
switch (line->ExprType)
{
@ -7266,6 +7269,8 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
{
build->BackpatchToHere(addr);
}
Content.Clear();
Content.ShrinkToFit();
return ExpEmit();
}
@ -7278,14 +7283,14 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
bool FxSwitchStatement::CheckReturn()
{
//A switch statement returns when it contains no breaks and ends with a return
for (auto line : *Content)
for (auto line : Content)
{
if (line->ExprType == EFX_JumpStatement)
{
return false; // Break means that the end of the statement will be reached, Continue cannot happen in the last statement of the last block.
}
}
return Content->Size() > 0 && Content->Last()->CheckReturn();
return Content.Size() > 0 && Content.Last()->CheckReturn();
}
//==========================================================================
@ -8414,6 +8419,8 @@ ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), names.Size() + 1, 1);
build->Emit(OP_RESULT, 0, REGT_POINTER, dest.RegNum);
names.Clear();
names.ShrinkToFit();
return dest;
}
@ -8433,6 +8440,11 @@ FxLocalVariableDeclaration::FxLocalVariableDeclaration(PType *type, FName name,
Init = initval == nullptr? nullptr : new FxTypeCast(initval, type, false);
}
FxLocalVariableDeclaration::~FxLocalVariableDeclaration()
{
SAFE_DELETE(Init);
}
FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
{
CHECKRESOLVED();

View file

@ -56,6 +56,8 @@
class VMFunctionBuilder;
class FxJumpStatement;
extern FMemArena FxAlloc;
//==========================================================================
//
//
@ -317,6 +319,14 @@ public:
bool isresolved = false;
bool NeedResult = true; // should be set to false if not needed and properly handled by all nodes for their subnodes to eliminate redundant code
EFxType ExprType;
void *operator new(size_t size)
{
return FxAlloc.Alloc(size);
}
void operator delete(void *block) {}
void operator delete[](void *block) {}
};
//==========================================================================
@ -347,6 +357,7 @@ class FxMemberIdentifier : public FxIdentifier
public:
FxMemberIdentifier(FxExpression *obj, FName i, const FScriptPosition &p);
~FxMemberIdentifier();
FxExpression *Resolve(FCompileContext&);
};
@ -1264,11 +1275,11 @@ class FxFunctionCall : public FxExpression
{
FName MethodName;
FRandom *RNG;
FArgumentList *ArgList;
FArgumentList ArgList;
public:
FxFunctionCall(FName methodname, FName rngname, FArgumentList *args, const FScriptPosition &pos);
FxFunctionCall(FName methodname, FName rngname, FArgumentList &args, const FScriptPosition &pos);
~FxFunctionCall();
FxExpression *Resolve(FCompileContext&);
};
@ -1284,11 +1295,11 @@ class FxMemberFunctionCall : public FxExpression
{
FxExpression *Self;
FName MethodName;
FArgumentList *ArgList;
FArgumentList ArgList;
public:
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList *args, const FScriptPosition &pos);
FxMemberFunctionCall(FxExpression *self, FName methodname, FArgumentList &args, const FScriptPosition &pos);
~FxMemberFunctionCall();
FxExpression *Resolve(FCompileContext&);
};
@ -1305,11 +1316,11 @@ class FxActionSpecialCall : public FxExpression
int Special;
bool EmitTail;
FxExpression *Self;
FArgumentList *ArgList;
FArgumentList ArgList;
public:
FxActionSpecialCall(FxExpression *self, int special, FArgumentList *args, const FScriptPosition &pos);
FxActionSpecialCall(FxExpression *self, int special, FArgumentList &args, const FScriptPosition &pos);
~FxActionSpecialCall();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
@ -1325,11 +1336,11 @@ public:
class FxFlopFunctionCall : public FxExpression
{
int Index;
FArgumentList *ArgList;
FArgumentList ArgList;
public:
FxFlopFunctionCall(size_t index, FArgumentList *args, const FScriptPosition &pos);
FxFlopFunctionCall(size_t index, FArgumentList &args, const FScriptPosition &pos);
~FxFlopFunctionCall();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
@ -1366,10 +1377,10 @@ class FxVMFunctionCall : public FxExpression
bool NoVirtual;
FxExpression *Self;
PFunction *Function;
FArgumentList *ArgList;
FArgumentList ArgList;
public:
FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList *args, const FScriptPosition &pos, bool novirtual);
FxVMFunctionCall(FxExpression *self, PFunction *func, FArgumentList &args, const FScriptPosition &pos, bool novirtual);
~FxVMFunctionCall();
FxExpression *Resolve(FCompileContext&);
PPrototype *ReturnProto();
@ -1429,7 +1440,7 @@ public:
class FxSwitchStatement : public FxExpression
{
FxExpression *Condition;
FArgumentList *Content;
FArgumentList Content;
struct CaseAddr
{
@ -1440,7 +1451,7 @@ class FxSwitchStatement : public FxExpression
TArray<CaseAddr> CaseAddresses;
public:
FxSwitchStatement(FxExpression *cond, FArgumentList *content, const FScriptPosition &pos);
FxSwitchStatement(FxExpression *cond, FArgumentList &content, const FScriptPosition &pos);
~FxSwitchStatement();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
@ -1714,6 +1725,7 @@ public:
int RegNum = -1;
FxLocalVariableDeclaration(PType *type, FName name, FxExpression *initval, int varflags, const FScriptPosition &p);
~FxLocalVariableDeclaration();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
void Release(VMFunctionBuilder *build);

View file

@ -482,7 +482,6 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
else if (sc.CheckToken(TK_Identifier))
{
FName identifier = FName(sc.String);
FArgumentList *args;
PFunction *func;
switch (identifier)
@ -503,18 +502,12 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
// There is an action function ACS_NamedExecuteWithResult which must be ignored here for this to work.
if (func != nullptr && identifier != NAME_ACS_NamedExecuteWithResult)
{
args = new FArgumentList;
FArgumentList args;
if (sc.CheckToken('('))
{
sc.UnGet();
ParseFunctionParameters(sc, cls, *args, func, "", nullptr);
ParseFunctionParameters(sc, cls, args, func, "", nullptr);
}
if (args->Size() == 0)
{
delete args;
args = nullptr;
}
return new FxVMFunctionCall(new FxSelf(sc), func, args, sc, false);
}
}
@ -536,26 +529,17 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls)
case NAME_VectorAngle:
return ParseAtan2(sc, identifier, cls);
default:
args = new FArgumentList;
try
FArgumentList args;
if (!sc.CheckToken(')'))
{
if (!sc.CheckToken(')'))
do
{
do
{
args->Push(ParseExpressionM (sc, cls));
}
while (sc.CheckToken(','));
sc.MustGetToken(')');
args.Push(ParseExpressionM (sc, cls));
}
return new FxFunctionCall(identifier, NAME_None, args, sc);
while (sc.CheckToken(','));
sc.MustGetToken(')');
}
catch (...)
{
delete args;
throw;
}
break;
return new FxFunctionCall(identifier, NAME_None, args, sc);
}
}
else

View file

@ -75,8 +75,8 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
if (special > 0 && min_args >= 0)
{
FArgumentList *args = new FArgumentList;
args->Push(new FxConstant(special, sc));
FArgumentList args;
args.Push(new FxConstant(special, sc));
i = 0;
// Make this consistent with all other parameter parsing
@ -84,7 +84,7 @@ FxVMFunctionCall *DoActionSpecials(FScanner &sc, FState & state, Baggage &bag)
{
while (i < 5)
{
args->Push(new FxIntCast(ParseExpression(sc, bag.Info), true));
args.Push(new FxIntCast(ParseExpression(sc, bag.Info), true));
i++;
if (!sc.CheckToken (',')) break;
}
@ -571,13 +571,9 @@ FxVMFunctionCall *ParseAction(FScanner &sc, FState state, FString statestring, B
PFunction *afd = dyn_cast<PFunction>(bag.Info->Symbols.FindSymbol(symname, true));
if (afd != NULL)
{
FArgumentList *args = new FArgumentList;
ParseFunctionParameters(sc, bag.Info, *args, afd, statestring, &bag.statedef);
call = new FxVMFunctionCall(new FxSelf(sc), afd, args->Size() > 0 ? args : NULL, sc, false);
if (args->Size() == 0)
{
delete args;
}
FArgumentList args;
ParseFunctionParameters(sc, bag.Info, args, afd, statestring, &bag.statedef);
call = new FxVMFunctionCall(new FxSelf(sc), afd, args, sc, false);
return call;
}
sc.ScriptError("Invalid parameter '%s'\n", sc.String);

View file

@ -776,4 +776,5 @@ void FFunctionBuildList::Build()
}
FScriptPosition::StrictErrors = false;
mItems.Clear();
FxAlloc.FreeAllBlocks();
}

View file

@ -2239,7 +2239,7 @@ FxExpression *ZCCCompiler::SetupActionFunction(PClass *cls, ZCC_TreeNode *af)
if (fc->Parameters == nullptr && !(afd->Variants[0].Flags & VARF_Virtual))
{
// We can use this function directly without wrapping it in a caller.
return new FxVMFunctionCall(new FxSelf(*af), afd, nullptr, *af, false);
return new FxVMFunctionCall(new FxSelf(*af), afd, FArgumentList(), *af, false);
}
}
else
@ -2563,16 +2563,17 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
// - class members
// - array syntax for random() calls.
// Everything else coming here is a syntax error.
FArgumentList args;
switch (fcall->Function->NodeType)
{
case AST_ExprID:
// The function name is a simple identifier.
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, ConvertNodeList(fcall->Parameters), *ast);
return new FxFunctionCall(static_cast<ZCC_ExprID *>(fcall->Function)->Identifier, NAME_None, ConvertNodeList(args, fcall->Parameters), *ast);
case AST_ExprMemberAccess:
{
auto ema = static_cast<ZCC_ExprMemberAccess *>(fcall->Function);
return new FxMemberFunctionCall(ConvertNode(ema->Left), ema->Right, ConvertNodeList(fcall->Parameters), *ast);
return new FxMemberFunctionCall(ConvertNode(ema->Left), ema->Right, ConvertNodeList(args, fcall->Parameters), *ast);
}
case AST_ExprBinary:
@ -2582,7 +2583,7 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
auto binary = static_cast<ZCC_ExprBinary *>(fcall->Function);
if (binary->Left->NodeType == AST_ExprID && binary->Right->NodeType == AST_ExprID)
{
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, ConvertNodeList(fcall->Parameters), *ast);
return new FxFunctionCall(static_cast<ZCC_ExprID *>(binary->Left)->Identifier, static_cast<ZCC_ExprID *>(binary->Right)->Identifier, ConvertNodeList(args, fcall->Parameters), *ast);
}
}
// fall through if this isn't an array access node.
@ -2832,21 +2833,20 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
case AST_ReturnStmt:
{
auto ret = static_cast<ZCC_ReturnStmt *>(ast);
FArgumentList *args = ConvertNodeList(ret->Values);
if (args->Size() == 0)
FArgumentList args;
ConvertNodeList(args, ret->Values);
if (args.Size() == 0)
{
return new FxReturnStatement(nullptr, *ast);
}
else if (args->Size() == 1)
else if (args.Size() == 1)
{
auto arg = (*args)[0];
(*args)[0] = nullptr;
delete args;
return new FxReturnStatement((*args)[0], *ast);
auto arg = args[0];
args[0] = nullptr;
return new FxReturnStatement(arg, *ast);
}
else
{
delete args;
Error(ast, "Return with multiple values not implemented yet.");
return new FxReturnStatement(nullptr, *ast);
}
@ -2893,7 +2893,8 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
{
// The switch content is wrapped into a compound statement which needs to be unraveled here.
auto cmpnd = static_cast<ZCC_CompoundStmt *>(swtch->Content);
return new FxSwitchStatement(ConvertNode(swtch->Condition), ConvertNodeList(cmpnd->Content), *ast);
FArgumentList args;
return new FxSwitchStatement(ConvertNode(swtch->Condition), ConvertNodeList(args, cmpnd->Content), *ast);
}
}
@ -2922,17 +2923,16 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast)
}
FArgumentList *ZCCCompiler::ConvertNodeList(ZCC_TreeNode *head)
FArgumentList &ZCCCompiler::ConvertNodeList(FArgumentList &args, ZCC_TreeNode *head)
{
FArgumentList *list = new FArgumentList;
if (head != nullptr)
{
auto node = head;
do
{
list->Push(ConvertNode(node));
args.Push(ConvertNode(node));
node = node->SiblingNext;
} while (node != head);
}
return list;
return args;
}

View file

@ -144,7 +144,7 @@ private:
FxExpression *ConvertAST(PClass *cclass, ZCC_TreeNode *ast);
FxExpression *ConvertNode(ZCC_TreeNode *node);
FArgumentList *ConvertNodeList(ZCC_TreeNode *head);
FArgumentList &ConvertNodeList(FArgumentList &, ZCC_TreeNode *head);
DObject *Outer;
PClass *ConvertClass; // class type to be used when resoving symbold while converting an AST