- scriptified parts of a_bossbrain.cpp. Some things cannot be done yet, the script code is there but commented out.

- exported thinker iterator and drop item chain to scripting. Unlike its native counterpart the script-side iterator is wrapped into a DObject to allow proper handling for memory management.
- fixed: The VMFunctionBuilder only distinguished between member and action functions but failed on static ones.
- fixed: FxAssign did not add all needed type casts. Except for purely numeric types it will now wrap the expression in an FxTypeCast. Numeric handling remains unchanged for both performance reasons and not altering semantics for DECORATE.
- exported all internal flags as variables to scripting. They still cannot be used in an actor definition.
- make ATAG_STATE the same as ATAG_GENERIC. Since state pointers exist as actual variables they can take both values which on occasion can trigger some asserts.
- gave PClass a bExported flag, so that scripts cannot see purely internal classes. Especially the types like PInt can cause problems.

Todo: we need readonly references to safely expose the actor defaults. Right now some badly behaving code could overwrite them.
This commit is contained in:
Christoph Oelckers 2016-10-31 17:02:47 +01:00
parent 6ff973a06b
commit e620c9bd7d
17 changed files with 668 additions and 161 deletions

View file

@ -2078,6 +2078,8 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
return nullptr;
}
// keep the redundant handling for numeric types here to avoid problems with DECORATE.
// for non-numerics FxTypeCast can be used without issues.
if (Base->IsNumeric() && Right->IsNumeric())
{
if (Right->ValueType != ValueType)
@ -2113,32 +2115,13 @@ FxExpression *FxAssign::Resolve(FCompileContext &ctx)
}
// Both types are the same so this is ok.
}
else if ((Base->ValueType == TypeState || Base->ValueType->IsKindOf(RUNTIME_CLASS(PPointer))) && Right->ValueType == TypeNullPtr)
{
// null pointers can be assigned to any other pointer
}
else if (Base->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
// class pointers may be assignable so add a cast which performs a check.
Right = new FxClassTypeCast(static_cast<PClassPointer *>(ValueType), Right);
SAFE_RESOLVE(Right, ctx);
}
else if (Base->ValueType == TypeString && (Right->ValueType == TypeName || Right->ValueType == TypeSound))
{
Right = new FxStringCast(Right);
SAFE_RESOLVE(Right, ctx);
}
else if (Base->ValueType == TypeName && Right->ValueType == TypeString)
{
Right = new FxNameCast(Right);
SAFE_RESOLVE(Right, ctx);
}
else
{
ScriptPosition.Message(MSG_ERROR, "Assignment between incompatible types.");
delete this;
return nullptr;
// pass it to FxTypeCast for complete handling.
Right = new FxTypeCast(Right, Base->ValueType, false);
SAFE_RESOLVE(Right, ctx);
}
if (!Base->RequestAddress(&AddressWritable) || !AddressWritable)
{
ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value");
@ -3100,6 +3083,69 @@ FxExpression *FxCompareEq::Resolve(FCompileContext& ctx)
delete this;
return e;
}
else
{
// also simplify comparisons against zero. For these a bool cast on the other value will do just as well and create better code.
if (left->isConstant())
{
bool leftisnull;
switch (left->ValueType->GetRegType())
{
case REGT_INT:
leftisnull = static_cast<FxConstant *>(left)->GetValue().GetInt() == 0;
break;
case REGT_FLOAT:
assert(left->ValueType->GetRegCount() == 1); // vectors should not be able to get here.
leftisnull = static_cast<FxConstant *>(left)->GetValue().GetFloat() == 0;
break;
case REGT_POINTER:
leftisnull = static_cast<FxConstant *>(left)->GetValue().GetPointer() == nullptr;
break;
default:
leftisnull = false;
}
if (leftisnull)
{
FxExpression *x = new FxBoolCast(right);
right = nullptr;
delete this;
return x->Resolve(ctx);
}
}
if (right->isConstant())
{
bool rightisnull;
switch (right->ValueType->GetRegType())
{
case REGT_INT:
rightisnull = static_cast<FxConstant *>(right)->GetValue().GetInt() == 0;
break;
case REGT_FLOAT:
assert(right->ValueType->GetRegCount() == 1); // vectors should not be able to get here.
rightisnull = static_cast<FxConstant *>(right)->GetValue().GetFloat() == 0;
break;
case REGT_POINTER:
rightisnull = static_cast<FxConstant *>(right)->GetValue().GetPointer() == nullptr;
break;
default:
rightisnull = false;
}
if (rightisnull)
{
FxExpression *x = new FxBoolCast(left);
left = nullptr;
delete this;
return x->Resolve(ctx);
}
}
}
Promote(ctx);
ValueType = TypeBool;
return this;
@ -3720,7 +3766,7 @@ int BuiltinTypeCheck(VMFrameStack *stack, VMValue *param, TArray<VMValue> &defau
assert(numparam == 2);
PARAM_POINTER_AT(0, obj, DObject);
PARAM_CLASS_AT(1, cls, DObject);
ACTION_RETURN_BOOL(obj->IsKindOf(cls));
ACTION_RETURN_BOOL(obj && obj->IsKindOf(cls));
}
//==========================================================================
@ -3762,6 +3808,72 @@ ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build)
//
//==========================================================================
FxDynamicCast::FxDynamicCast(PClass * cls, FxExpression *r)
: FxExpression(EFX_DynamicCast, r->ScriptPosition)
{
expr = new FxTypeCast(r, NewPointer(RUNTIME_CLASS(DObject)), true, true);
ValueType = NewPointer(cls);
CastType = cls;
}
//==========================================================================
//
//
//
//==========================================================================
FxDynamicCast::~FxDynamicCast()
{
SAFE_DELETE(expr);
}
//==========================================================================
//
//
//
//==========================================================================
FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx)
{
CHECKRESOLVED();
SAFE_RESOLVE(expr, ctx);
return this;
}
//==========================================================================
//
//
//
//==========================================================================
ExpEmit FxDynamicCast::Emit(VMFunctionBuilder *build)
{
ExpEmit out = expr->Emit(build);
ExpEmit check(build, REGT_INT);
assert(out.RegType == REGT_POINTER);
build->Emit(OP_PARAM, 0, REGT_POINTER, out.RegNum);
build->Emit(OP_PARAM, 0, REGT_POINTER | REGT_KONST, build->GetConstantAddress(CastType, ATAG_OBJECT));
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck);
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
auto callfunc = ((PSymbolVMFunction *)sym)->Function;
build->Emit(OP_CALL_K, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
build->Emit(OP_RESULT, 0, REGT_INT, check.RegNum);
auto patch = build->Emit(OP_EQ_K, 0, check.RegNum, build->GetConstantInt(0));
build->Emit(OP_LKP, out.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT));
build->BackpatchToHere(patch);
return out;
}
//==========================================================================
//
//
//
//==========================================================================
FxConditional::FxConditional(FxExpression *c, FxExpression *t, FxExpression *f)
: FxExpression(EFX_Conditional, c->ScriptPosition)
{
@ -5655,6 +5767,24 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
return x->Resolve(ctx);
}
PClass *cls = PClass::FindClass(MethodName);
if (cls != nullptr && cls->bExported)
{
if (CheckArgSize(MethodName, ArgList, 1, 1, ScriptPosition))
{
FxExpression *x = new FxDynamicCast(cls, (*ArgList)[0]);
(*ArgList)[0] = nullptr;
delete this;
return x->Resolve(ctx);
}
else
{
delete this;
return nullptr;
}
}
// Last but not least: Check builtins and type casts. The random functions can take a named RNG if specified.
// Note that for all builtins the used arguments have to be nulled in the ArgList so that they won't get deleted before they get used.
FxExpression *func = nullptr;
@ -5681,7 +5811,12 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
break;
case NAME_Random:
if (CheckArgSize(NAME_Random, ArgList, 2, 2, ScriptPosition))
// allow calling Random without arguments to default to (0, 255)
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;
@ -5754,7 +5889,7 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
break;
default:
// todo: Check for class type casts
ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars());
break;
}
if (func != nullptr)
@ -5762,7 +5897,6 @@ FxExpression *FxFunctionCall::Resolve(FCompileContext& ctx)
delete this;
return func->Resolve(ctx);
}
ScriptPosition.Message(MSG_ERROR, "Call to unknown function '%s'", MethodName.GetChars());
delete this;
return nullptr;
}
@ -5803,10 +5937,22 @@ FxMemberFunctionCall::~FxMemberFunctionCall()
FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
{
ABORT(ctx.Class);
SAFE_RESOLVE(Self, ctx);
PClass *cls;
bool staticonly = false;
if (Self->ExprType == EFX_Identifier)
{
// If the left side is a class name for a static member function call it needs to be resolved manually
// because the resulting value type would cause problems in nearly every other place where identifiers are being used.
cls = PClass::FindClass(static_cast<FxIdentifier *>(Self)->Identifier);
if (cls != nullptr && cls->bExported)
{
staticonly = true;
goto isresolved;
}
}
SAFE_RESOLVE(Self, ctx);
if (Self->IsVector())
{
// handle builtins: Vectors got 2: Length and Unit.
@ -5819,12 +5965,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
}
}
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PClassPointer)))
{
cls = static_cast<PClassPointer *>(Self->ValueType)->ClassRestriction;
staticonly = true;
}
else if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
if (Self->ValueType->IsKindOf(RUNTIME_CLASS(PPointer)))
{
auto ptype = static_cast<PPointer *>(Self->ValueType)->PointedType;
if (ptype->IsKindOf(RUNTIME_CLASS(PClass)))
@ -5845,6 +5986,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
return nullptr;
}
isresolved:
bool error = false;
PFunction *afd = FindClassMemberFunction(cls, cls, MethodName, ScriptPosition, &error);
if (error)
@ -5859,7 +6001,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
delete this;
return nullptr;
}
if (staticonly && !(afd->Variants[0].Flags & VARF_Static))
if (staticonly && (afd->Variants[0].Flags & VARF_Method))
{
if (!ctx.Class->IsDescendantOf(cls))
{
@ -5867,11 +6009,17 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
delete this;
return nullptr;
}
// If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.)
else
{
// Todo: If this is a qualified call to a parent class function, let it through (but this needs to disable virtual calls later.)
ScriptPosition.Message(MSG_ERROR, "Qualified member call to parent class not yet implemented\n", cls->TypeName.GetChars(), MethodName.GetChars());
delete this;
return nullptr;
}
}
// do not pass the self pointer to static functions.
auto self = !(afd->Variants[0].Flags & VARF_Static) ? Self : nullptr;
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;
@ -6128,7 +6276,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
int implicit = Function->GetImplicitArgs();
// This should never happen.
if (Self == nullptr && !(Function->Variants[0].Flags & VARF_Static))
if (Self == nullptr && (Function->Variants[0].Flags & VARF_Method))
{
ScriptPosition.Message(MSG_ERROR, "Call to non-static function without a self pointer");
delete this;
@ -6200,8 +6348,7 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx)
ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
{
assert((build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= NAP) ||
(!build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 1));
assert(build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits);
int count = 0; (ArgList ? ArgList->Size() : 0);
if (count == 1)
@ -6225,7 +6372,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
if (Function->Variants[0].Flags & VARF_Action)
{
static_assert(NAP == 3, "This code needs to be updated if NAP changes");
if (build->IsActionFunc && selfemit.RegNum == 0) // only pass this function's stateowner and stateinfo if the subfunction is run in self's context.
if (build->NumImplicits == NAP && selfemit.RegNum == 0) // only pass this function's stateowner and stateinfo if the subfunction is run in self's context.
{
build->Emit(OP_PARAM, 0, REGT_POINTER, 1);
build->Emit(OP_PARAM, 0, REGT_POINTER, 2);
@ -6238,6 +6385,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
}
count += 2;
}
selfemit.Free(build);
}
// Emit code to pass explicit parameters
if (ArgList != nullptr)
@ -7654,7 +7802,9 @@ static int BuiltinHandleRuntimeState(VMFrameStack *stack, VMValue *param, TArray
ExpEmit FxRuntimeStateIndex::Emit(VMFunctionBuilder *build)
{
assert(build->IsActionFunc && build->Registers[REGT_POINTER].GetMostUsed() >= 3 &&
// This code can only be called from DECORATE, not ZSCRIPT so any function going through here
// is an anoynmous one which are always marked as 'action'.
assert(build->NumImplicits >= NAP && build->Registers[REGT_POINTER].GetMostUsed() >= build->NumImplicits &&
"FxRuntimeStateIndex is only valid inside action functions");
ExpEmit out(build, REGT_POINTER);
@ -7741,7 +7891,7 @@ FxExpression *FxMultiNameState::Resolve(FCompileContext &ctx)
delete this;
return nullptr;
}
else if (!scope->IsAncestorOf(ctx.Class))
else if (!scope->IsAncestorOf(ctx.Class) && ctx.Class != RUNTIME_CLASS(AActor)) // AActor needs access to subclasses in a few places. TBD: Relax this for non-action functions?
{
ScriptPosition.Message(MSG_ERROR, "'%s' is not an ancestor of '%s'", names[0].GetChars(), ctx.Class->TypeName.GetChars());
delete this;
@ -7827,7 +7977,7 @@ int BuiltinFindSingleNameState(VMFrameStack *stack, VMValue *param, TArray<VMVal
ExpEmit FxMultiNameState::Emit(VMFunctionBuilder *build)
{
ExpEmit dest(build, REGT_POINTER);
if (build->IsActionFunc)
if (build->NumImplicits == NAP)
{
build->Emit(OP_PARAM, 0, REGT_POINTER, 1); // pass stateowner
}

View file

@ -268,6 +268,7 @@ enum EFxType
EFX_VectorValue,
EFX_VectorBuiltin,
EFX_TypeCheck,
EFX_DynamicCast,
EFX_COUNT
};
@ -320,10 +321,9 @@ public:
class FxIdentifier : public FxExpression
{
protected:
public:
FName Identifier;
public:
FxIdentifier(FName i, const FScriptPosition &p);
FxExpression *Resolve(FCompileContext&);
};
@ -940,7 +940,7 @@ public:
//==========================================================================
//
// FxBinaryLogical
//
//
//==========================================================================
@ -959,6 +959,25 @@ public:
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
//
//
//==========================================================================
class FxDynamicCast : public FxExpression
{
PClass *CastType;
public:
FxExpression *expr;
FxDynamicCast(PClass*, FxExpression*);
~FxDynamicCast();
FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build);
};
//==========================================================================
//
// FxConditional

View file

@ -61,6 +61,39 @@ static TArray<AFuncDesc> AFTable;
#define DEFINE_DEPRECATED_FLAG(name) { DEPF_##name, #name, -1, 0, true }
#define DEFINE_DUMMY_FLAG(name, deprec) { DEPF_UNUSED, #name, -1, 0, deprec? VARF_Deprecated:0 }
// internal flags. These do not get exposed to actor definitions but scripts need to be able to access them as variables.
static FFlagDef InternalActorFlagDefs[]=
{
DEFINE_FLAG(MF, INCHASE, AActor, flags),
DEFINE_FLAG(MF, UNMORPHED, AActor, flags),
DEFINE_FLAG(MF2, FLY, AActor, flags2),
DEFINE_FLAG(MF2, ONMOBJ, AActor, flags2),
DEFINE_FLAG(MF2, DONTTRANSLATE, AActor, flags2),
DEFINE_FLAG(MF2, ARGSDEFINED, AActor, flags2),
DEFINE_FLAG(MF3, NOSIGHTCHECK, AActor, flags3),
DEFINE_FLAG(MF3, CRASHED, AActor, flags3),
DEFINE_FLAG(MF3, WARNBOT, AActor, flags3),
DEFINE_FLAG(MF3, HUNTPLAYERS, AActor, flags3),
DEFINE_FLAG(MF4, NOHATEPLAYERS, AActor, flags4),
DEFINE_FLAG(MF4, NOSKIN, AActor, flags4),
DEFINE_FLAG(MF4, SCROLLMOVE, AActor, flags4),
DEFINE_FLAG(MF4, VFRICTION, AActor, flags4),
DEFINE_FLAG(MF4, BOSSSPAWNED, AActor, flags4),
DEFINE_FLAG(MF5, AVOIDINGDROPOFF, AActor, flags5),
DEFINE_FLAG(MF5, CHASEGOAL, AActor, flags5),
DEFINE_FLAG(MF5, INCONVERSATION, AActor, flags5),
DEFINE_FLAG(MF6, ARMED, AActor, flags6),
DEFINE_FLAG(MF6, FALLING, AActor, flags6),
DEFINE_FLAG(MF6, LINEDONE, AActor, flags6),
DEFINE_FLAG(MF6, SHATTERING, AActor, flags6),
DEFINE_FLAG(MF6, KILLED, AActor, flags6),
DEFINE_FLAG(MF6, BOSSCUBE, AActor, flags6),
DEFINE_FLAG(MF6, INTRYMOVE, AActor, flags6),
DEFINE_FLAG(MF7, HANDLENODELAY, AActor, flags7),
DEFINE_FLAG(MF7, FLYCHEAT, AActor, flags7),
};
static FFlagDef ActorFlagDefs[]=
{
DEFINE_FLAG(MF, PICKUP, APlayerPawn, flags),
@ -687,6 +720,7 @@ void InitThingdef()
symt.AddSymbol(new PField("Gravity", TypeFloat64, VARF_Native, myoffsetof(AActor, Gravity)));
symt.AddSymbol(new PField("DamageType", TypeName, VARF_Native, myoffsetof(AActor, DamageType)));
symt.AddSymbol(new PField("FloatBobPhase", TypeUInt8, VARF_Native, myoffsetof(AActor, FloatBobPhase)));
symt.AddSymbol(new PField("tics", TypeSInt32, VARF_Native, myoffsetof(AActor, tics)));
symt.AddSymbol(new PField("RipperLevel", TypeSInt32, VARF_Native, myoffsetof(AActor, RipperLevel)));
symt.AddSymbol(new PField("RipLevelMin", TypeSInt32, VARF_Native, myoffsetof(AActor, RipLevelMin)));
symt.AddSymbol(new PField("RipLevelMax", TypeSInt32, VARF_Native, myoffsetof(AActor, RipLevelMax)));
@ -695,6 +729,7 @@ void InitThingdef()
symt.AddSymbol(new PField(NAME_VisibleEndAngle, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndAngle)));
symt.AddSymbol(new PField(NAME_VisibleEndPitch, TypeFloat64, VARF_Native, myoffsetof(AActor, VisibleEndPitch)));
symt.AddSymbol(new PField("AttackSound", TypeSound, VARF_Native, myoffsetof(AActor, AttackSound)));
symt.AddSymbol(new PField("DeathSound", TypeSound, VARF_Native, myoffsetof(AActor, DeathSound)));
symt.AddSymbol(new PField("Pos", TypeVector3, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos)));
symt.AddSymbol(new PField("Vel", TypeVector3, VARF_Native, myoffsetof(AActor, Vel)));
symt.AddSymbol(new PField("Scale", TypeVector2, VARF_Native, myoffsetof(AActor, Scale)));
@ -706,7 +741,7 @@ void InitThingdef()
symt.AddSymbol(new PField("LastHeard", TypeActor, VARF_Native, myoffsetof(AActor, LastHeard)));
symt.AddSymbol(new PField("LastEnemy", TypeActor, VARF_Native, myoffsetof(AActor, lastenemy)));
// synthesize a symbol for each flag. The bounce flags are excluded on purpose.
// synthesize a symbol for each flag.
for (size_t i = 0; i < countof(ActorFlagDefs); i++)
{
int bit = 0;
@ -714,5 +749,19 @@ void InitThingdef()
while ((val >>= 1)) bit++;
symt.AddSymbol(new PField(FStringf("b%s", ActorFlagDefs[i].name), (ActorFlagDefs[i].fieldsize == 4? TypeSInt32 : TypeSInt16), ActorFlagDefs[i].varflags, ActorFlagDefs[i].structoffset, bit));
}
for (size_t i = 0; i < countof(InternalActorFlagDefs); i++)
{
int bit = 0;
unsigned val = InternalActorFlagDefs[i].flagbit;
while ((val >>= 1)) bit++;
symt.AddSymbol(new PField(FStringf("b%s", InternalActorFlagDefs[i].name), (InternalActorFlagDefs[i].fieldsize == 4 ? TypeSInt32 : TypeSInt16), InternalActorFlagDefs[i].varflags, InternalActorFlagDefs[i].structoffset, bit));
}
PSymbolTable &symt2 = RUNTIME_CLASS(DDropItem)->Symbols;
PType *TypeDropItem = NewPointer(RUNTIME_CLASS(DDropItem));
symt2.AddSymbol(new PField("Next", TypeDropItem, VARF_Native | VARF_ReadOnly, myoffsetof(DDropItem, Next)));
symt2.AddSymbol(new PField("ItemName", TypeName, VARF_Native | VARF_ReadOnly, myoffsetof(DDropItem, Name)));
symt2.AddSymbol(new PField("Probability", TypeSInt32, VARF_Native | VARF_ReadOnly, myoffsetof(DDropItem, Probability)));
symt2.AddSymbol(new PField("Amount", TypeSInt32, VARF_Native | VARF_ReadOnly, myoffsetof(DDropItem, Amount)));
}

View file

@ -161,8 +161,8 @@ enum
ATAG_SREGISTER, // pointer to a string register
ATAG_AREGISTER, // pointer to an address register
ATAG_STATE, // pointer to FState
ATAG_RNG, // pointer to FRandom
ATAG_STATE = ATAG_GENERIC, // pointer to FState (cannot have its own type because there's no means to track inside the VM.)
};
enum EVMAbortException

View file

@ -43,7 +43,7 @@
//
//==========================================================================
VMFunctionBuilder::VMFunctionBuilder(bool selfcheck)
VMFunctionBuilder::VMFunctionBuilder(int numimplicits)
{
NumIntConstants = 0;
NumFloatConstants = 0;
@ -51,7 +51,7 @@ VMFunctionBuilder::VMFunctionBuilder(bool selfcheck)
NumStringConstants = 0;
MaxParam = 0;
ActiveParam = 0;
IsActionFunc = selfcheck;
NumImplicits = numimplicits;
}
//==========================================================================

View file

@ -23,7 +23,7 @@ public:
friend class VMFunctionBuilder;
};
VMFunctionBuilder(bool checkself = false);
VMFunctionBuilder(int numimplicits);
~VMFunctionBuilder();
void MakeFunction(VMScriptFunction *func);
@ -60,8 +60,8 @@ public:
// Track available registers.
RegAvailability Registers[4];
// For use by DECORATE's self/stateowner sanitizer.
bool IsActionFunc;
// amount of implicit parameters so that proper code can be emitted for method calls
int NumImplicits;
private:
struct AddrKonst

View file

@ -175,7 +175,7 @@ begin:
OP(LO):
ASSERTA(a); ASSERTA(B); ASSERTKD(C);
GETADDR(PB,KC,X_READ_NIL);
reg.a[a] = GC::ReadBarrier(*(DObject **)ptr);
reg.a[a] = *(DObject **)ptr;
reg.atag[a] = ATAG_OBJECT;
NEXTOP;
OP(LO_R):

View file

@ -508,6 +508,7 @@ void ZCCCompiler::CreateClassTypes()
// We will never get here if the name is a duplicate, so we can just do the assignment.
c->cls->Type = parent->FindClassTentative(c->NodeName());
}
c->Type()->bExported = true; // this class is accessible to script side type casts. (The reason for this flag is that types like PInt need to be skipped.)
c->cls->Symbol = new PSymbolType(c->NodeName(), c->Type());
GlobalSymbols.AddSymbol(c->cls->Symbol);
c->Type()->Symbols.SetName(c->NodeName());