mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-25 13:31:37 +00:00
Finish implementing function pointers
Allow using function literals with function pointers, allow narrowing classes parameter types, and widening classes in return types, allow pointers to non-static, non-virtual functions, add null checking to function calls
This commit is contained in:
parent
23c21b23c3
commit
e61bd10bbf
8 changed files with 244 additions and 20 deletions
|
@ -268,6 +268,8 @@ PFunction *FindBuiltinFunction(FName funcname)
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
static bool AreCompatibleFnPtrTypes(PPrototype *to, PPrototype *from);
|
||||||
|
|
||||||
bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
|
bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
|
||||||
{
|
{
|
||||||
if (dest->isPointer() && source->isPointer())
|
if (dest->isPointer() && source->isPointer())
|
||||||
|
@ -301,8 +303,9 @@ bool AreCompatiblePointerTypes(PType *dest, PType *source, bool forcompare)
|
||||||
{
|
{
|
||||||
auto from = static_cast<PFunctionPointer*>(source);
|
auto from = static_cast<PFunctionPointer*>(source);
|
||||||
auto to = static_cast<PFunctionPointer*>(dest);
|
auto to = static_cast<PFunctionPointer*>(dest);
|
||||||
return to->PointedType == TypeVoid || (from->PointedType == to->PointedType && from->ArgFlags == to->ArgFlags && FScopeBarrier::CheckSidesForFunctionPointer(from->Scope, to->Scope));
|
if(from->PointedType == TypeVoid) return false;
|
||||||
// TODO allow narrowing argument types and widening return types via cast, ex.: Function<Actor(Object or Class<Object>)> to Function<Object(Actor or Class<Actor>)>
|
|
||||||
|
return to->PointedType == TypeVoid || (AreCompatibleFnPtrTypes((PPrototype *)to->PointedType, (PPrototype *)from->PointedType) && from->ArgFlags == to->ArgFlags && FScopeBarrier::CheckSidesForFunctionPointer(from->Scope, to->Scope));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -1615,6 +1618,35 @@ FxTypeCast::~FxTypeCast()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
FxConstant * FxTypeCast::convertRawFunctionToFunctionPointer(FxExpression * in, FScriptPosition &ScriptPosition)
|
||||||
|
{
|
||||||
|
assert(in->isConstant() && in->ValueType == TypeRawFunction);
|
||||||
|
FxConstant *val = static_cast<FxConstant*>(in);
|
||||||
|
PFunction * fn = static_cast<PFunction*>(val->value.pointer);
|
||||||
|
if(fn && (fn->Variants[0].Flags & (VARF_Virtual | VARF_Action | VARF_Method)) == 0)
|
||||||
|
{
|
||||||
|
val->ValueType = val->value.Type = NewFunctionPointer(fn->Variants[0].Proto, TArray<uint32_t>(fn->Variants[0].ArgFlags), FScopeBarrier::SideFromFlags(fn->Variants[0].Flags));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else if(fn && (fn->Variants[0].Flags & (VARF_Virtual | VARF_Action | VARF_Method)) == VARF_Method)
|
||||||
|
{
|
||||||
|
TArray<uint32_t> flags(fn->Variants[0].ArgFlags);
|
||||||
|
flags[0] = 0;
|
||||||
|
val->ValueType = val->value.Type = NewFunctionPointer(fn->Variants[0].Proto, std::move(flags), FScopeBarrier::SideFromFlags(fn->Variants[0].Flags));
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else if(!fn)
|
||||||
|
{
|
||||||
|
val->ValueType = val->value.Type = NewFunctionPointer(nullptr, {}, -1); // Function<void>
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptPosition.Message(MSG_ERROR, "virtual/action function pointers are not allowed");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
|
@ -1626,6 +1658,22 @@ FxExpression *FxTypeCast::Resolve(FCompileContext &ctx)
|
||||||
if (result != this) return result;
|
if (result != this) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (basex->isConstant() && basex->ValueType == TypeRawFunction && ValueType->isFunctionPointer())
|
||||||
|
{
|
||||||
|
FxConstant *val = convertRawFunctionToFunctionPointer(basex, ScriptPosition);
|
||||||
|
if(!val)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (basex->isConstant() && basex->ValueType == TypeRawFunction && ValueType == TypeVMFunction)
|
||||||
|
{
|
||||||
|
FxConstant *val = static_cast<FxConstant*>(basex);
|
||||||
|
val->ValueType = val->value.Type = TypeVMFunction;
|
||||||
|
val->value.pointer = static_cast<PFunction*>(val->value.pointer)->Variants[0].Implementation;
|
||||||
|
}
|
||||||
|
|
||||||
// first deal with the simple types
|
// first deal with the simple types
|
||||||
if (ValueType == TypeError || basex->ValueType == TypeError || basex->ValueType == nullptr)
|
if (ValueType == TypeError || basex->ValueType == TypeError || basex->ValueType == nullptr)
|
||||||
{
|
{
|
||||||
|
@ -6370,9 +6418,8 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
if (ctx.Version >= MakeVersion(4, 11, 100))
|
if (ctx.Version >= MakeVersion(4, 11, 100))
|
||||||
{
|
{
|
||||||
// VMFunction is only supported since 4.12 and Raze 1.8.
|
// VMFunction is only supported since 4.12 and Raze 1.8.
|
||||||
newex = new FxConstant(static_cast<PFunction*>(sym)->Variants[0].Implementation, ScriptPosition);
|
newex = new FxConstant(static_cast<PFunction*>(sym), ScriptPosition);
|
||||||
goto foundit;
|
goto foundit;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6391,7 +6438,7 @@ FxExpression *FxIdentifier::Resolve(FCompileContext& ctx)
|
||||||
if (ctx.Version >= MakeVersion(4, 11, 100))
|
if (ctx.Version >= MakeVersion(4, 11, 100))
|
||||||
{
|
{
|
||||||
// VMFunction is only supported since 4.12 and Raze 1.8.
|
// VMFunction is only supported since 4.12 and Raze 1.8.
|
||||||
newex = new FxConstant(static_cast<PFunction*>(sym)->Variants[0].Implementation, ScriptPosition);
|
newex = new FxConstant(static_cast<PFunction*>(sym), ScriptPosition);
|
||||||
goto foundit;
|
goto foundit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6539,7 +6586,6 @@ FxExpression *FxIdentifier::ResolveMember(FCompileContext &ctx, PContainerType *
|
||||||
if (result != this) return result;
|
if (result != this) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (objtype != nullptr && (sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
|
if (objtype != nullptr && (sym = objtype->Symbols.FindSymbolInTable(Identifier, symtbl)) != nullptr)
|
||||||
{
|
{
|
||||||
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
if (sym->IsKindOf(RUNTIME_CLASS(PSymbolConst)))
|
||||||
|
@ -6755,7 +6801,7 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
|
|
||||||
SAFE_RESOLVE(Object, ctx);
|
SAFE_RESOLVE(Object, ctx);
|
||||||
|
|
||||||
// check for class or struct constants if the left side is a type name.
|
// check for class or struct constants/functions if the left side is a type name.
|
||||||
if (Object->ValueType == TypeError)
|
if (Object->ValueType == TypeError)
|
||||||
{
|
{
|
||||||
if (ccls != nullptr)
|
if (ccls != nullptr)
|
||||||
|
@ -6769,6 +6815,16 @@ FxExpression *FxMemberIdentifier::Resolve(FCompileContext& ctx)
|
||||||
delete this;
|
delete this;
|
||||||
return FxConstant::MakeConstant(sym, ScriptPosition);
|
return FxConstant::MakeConstant(sym, ScriptPosition);
|
||||||
}
|
}
|
||||||
|
else if(sym->IsKindOf(RUNTIME_CLASS(PFunction)))
|
||||||
|
{
|
||||||
|
if (ctx.Version >= MakeVersion(4, 11, 100))
|
||||||
|
{
|
||||||
|
// VMFunction is only supported since 4.12 and Raze 1.8.
|
||||||
|
auto x = new FxConstant(static_cast<PFunction*>(sym), ScriptPosition);
|
||||||
|
delete this;
|
||||||
|
return x->Resolve(ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto f = dyn_cast<PField>(sym);
|
auto f = dyn_cast<PField>(sym);
|
||||||
|
@ -9604,6 +9660,7 @@ ExpEmit FxVMFunctionCall::Emit(VMFunctionBuilder *build)
|
||||||
assert(Self != nullptr);
|
assert(Self != nullptr);
|
||||||
selfemit = Self->Emit(build);
|
selfemit = Self->Emit(build);
|
||||||
assert(selfemit.RegType == REGT_POINTER);
|
assert(selfemit.RegType == REGT_POINTER);
|
||||||
|
build->Emit(OP_NULLCHECK, selfemit.RegNum, 0, 0);
|
||||||
staticcall = false;
|
staticcall = false;
|
||||||
}
|
}
|
||||||
else staticcall = true;
|
else staticcall = true;
|
||||||
|
@ -11704,11 +11761,118 @@ FxFunctionPtrCast::~FxFunctionPtrCast()
|
||||||
//
|
//
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
||||||
|
static bool AreCompatibleFnPtrs(PFunctionPointer * to, PFunctionPointer * from);
|
||||||
|
|
||||||
|
bool CanNarrowTo(PClass * from, PClass * to)
|
||||||
|
{
|
||||||
|
return from->IsAncestorOf(to);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CanWidenTo(PClass * from, PClass * to)
|
||||||
|
{
|
||||||
|
return to->IsAncestorOf(from);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AreCompatibleFnPtrTypes(PPrototype *to, PPrototype *from)
|
||||||
|
{
|
||||||
|
if(to->ArgumentTypes.Size() != from->ArgumentTypes.Size()
|
||||||
|
|| to->ReturnTypes.Size() != from->ReturnTypes.Size()) return false;
|
||||||
|
int n = to->ArgumentTypes.Size();
|
||||||
|
|
||||||
|
//allow narrowing of arguments
|
||||||
|
for(int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
PType * fromType = from->ArgumentTypes[i];
|
||||||
|
PType * toType = to->ArgumentTypes[i];
|
||||||
|
if(fromType->isFunctionPointer() && toType->isFunctionPointer())
|
||||||
|
{
|
||||||
|
if(!AreCompatibleFnPtrs(static_cast<PFunctionPointer *>(toType), static_cast<PFunctionPointer *>(fromType))) return false;
|
||||||
|
}
|
||||||
|
else if(fromType->isClassPointer() && toType->isClassPointer())
|
||||||
|
{
|
||||||
|
PClassPointer * fromClass = static_cast<PClassPointer *>(fromType);
|
||||||
|
PClassPointer * toClass = static_cast<PClassPointer *>(toType);
|
||||||
|
//allow narrowing parameters
|
||||||
|
if(!CanNarrowTo(fromClass->ClassRestriction, toClass->ClassRestriction)) return false;
|
||||||
|
}
|
||||||
|
else if(fromType->isObjectPointer() && toType->isObjectPointer())
|
||||||
|
{
|
||||||
|
PObjectPointer * fromObj = static_cast<PObjectPointer *>(fromType);
|
||||||
|
PObjectPointer * toObj = static_cast<PObjectPointer *>(toType);
|
||||||
|
//allow narrowing parameters
|
||||||
|
if(!CanNarrowTo(fromObj->PointedClass(), toObj->PointedClass())) return false;
|
||||||
|
}
|
||||||
|
else if(fromType != toType)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
n = to->ReturnTypes.Size();
|
||||||
|
|
||||||
|
for(int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
PType * fromType = from->ReturnTypes[i];
|
||||||
|
PType * toType = to->ReturnTypes[i];
|
||||||
|
if(fromType->isFunctionPointer() && toType->isFunctionPointer())
|
||||||
|
{
|
||||||
|
if(!AreCompatibleFnPtrs(static_cast<PFunctionPointer *>(toType), static_cast<PFunctionPointer *>(fromType))) return false;
|
||||||
|
}
|
||||||
|
else if(fromType->isClassPointer() && toType->isClassPointer())
|
||||||
|
{
|
||||||
|
PClassPointer * fromClass = static_cast<PClassPointer *>(fromType);
|
||||||
|
PClassPointer * toClass = static_cast<PClassPointer *>(toType);
|
||||||
|
//allow widening returns
|
||||||
|
if(!CanWidenTo(fromClass->ClassRestriction, toClass->ClassRestriction)) return false;
|
||||||
|
}
|
||||||
|
else if(fromType->isObjectPointer() && toType->isObjectPointer())
|
||||||
|
{
|
||||||
|
PObjectPointer * fromObj = static_cast<PObjectPointer *>(fromType);
|
||||||
|
PObjectPointer * toObj = static_cast<PObjectPointer *>(toType);
|
||||||
|
//allow widening returns
|
||||||
|
if(!CanWidenTo(fromObj->PointedClass(), toObj->PointedClass())) return false;
|
||||||
|
}
|
||||||
|
else if(fromType != toType)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool AreCompatibleFnPtrs(PFunctionPointer * to, PFunctionPointer * from)
|
||||||
|
{
|
||||||
|
if(to->PointedType == TypeVoid) return true;
|
||||||
|
else if(from->PointedType == TypeVoid) return false;
|
||||||
|
|
||||||
|
PPrototype * toProto = (PPrototype *)to->PointedType;
|
||||||
|
PPrototype * fromProto = (PPrototype *)from->PointedType;
|
||||||
|
return
|
||||||
|
( FScopeBarrier::CheckSidesForFunctionPointer(from->Scope, to->Scope)
|
||||||
|
/*
|
||||||
|
&& toProto->ArgumentTypes == fromProto->ArgumentTypes
|
||||||
|
&& toProto->ReturnTypes == fromProto->ReturnTypes
|
||||||
|
*/
|
||||||
|
&& AreCompatibleFnPtrTypes(toProto, fromProto)
|
||||||
|
&& to->ArgFlags == from->ArgFlags
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
FxExpression *FxFunctionPtrCast::Resolve(FCompileContext &ctx)
|
FxExpression *FxFunctionPtrCast::Resolve(FCompileContext &ctx)
|
||||||
{
|
{
|
||||||
CHECKRESOLVED();
|
CHECKRESOLVED();
|
||||||
SAFE_RESOLVE(basex, ctx);
|
SAFE_RESOLVE(basex, ctx);
|
||||||
|
|
||||||
|
if (basex->isConstant() && basex->ValueType == TypeRawFunction)
|
||||||
|
{
|
||||||
|
FxConstant *val = FxTypeCast::convertRawFunctionToFunctionPointer(basex, ScriptPosition);
|
||||||
|
if(!val)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!(basex->ValueType && basex->ValueType->isFunctionPointer()))
|
if (!(basex->ValueType && basex->ValueType->isFunctionPointer()))
|
||||||
{
|
{
|
||||||
delete this;
|
delete this;
|
||||||
|
@ -11717,21 +11881,20 @@ FxExpression *FxFunctionPtrCast::Resolve(FCompileContext &ctx)
|
||||||
auto to = static_cast<PFunctionPointer *>(ValueType);
|
auto to = static_cast<PFunctionPointer *>(ValueType);
|
||||||
auto from = static_cast<PFunctionPointer *>(basex->ValueType);
|
auto from = static_cast<PFunctionPointer *>(basex->ValueType);
|
||||||
|
|
||||||
if(to->PointedType == TypeVoid)
|
if(from->PointedType == TypeVoid)
|
||||||
{ // no need to do anything for (Function<void)(...) casts
|
{ // nothing to check at compile-time for casts from Function<void>
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
else if(AreCompatibleFnPtrs(to, from))
|
||||||
|
{ // no need to do anything for (Function<void>)(...) or compatible casts
|
||||||
basex->ValueType = ValueType;
|
basex->ValueType = ValueType;
|
||||||
auto x = basex;
|
auto x = basex;
|
||||||
basex = nullptr;
|
basex = nullptr;
|
||||||
delete this;
|
delete this;
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
else if(from->PointedType == TypeVoid)
|
|
||||||
{ // nothing to check at compile-time for casts from Function<void>
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// TODO allow narrowing argument types and widening return types via cast, ex.: Function<Actor(Object or Class<Object>)> to Function<Object(Actor or Class<Actor>)>
|
|
||||||
ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName());
|
ScriptPosition.Message(MSG_ERROR, "Cannot cast %s to %s. The types are incompatible.", basex->ValueType->DescriptiveName(), to->DescriptiveName());
|
||||||
delete this;
|
delete this;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -11746,12 +11909,27 @@ FxExpression *FxFunctionPtrCast::Resolve(FCompileContext &ctx)
|
||||||
|
|
||||||
PFunction *NativeFunctionPointerCast(PFunction *from, const PFunctionPointer *to)
|
PFunction *NativeFunctionPointerCast(PFunction *from, const PFunctionPointer *to)
|
||||||
{
|
{
|
||||||
// TODO allow narrowing argument types and widening return types via cast, ex.: Function<Actor(Object or Class<Object>)> to Function<Object(Actor or Class<Actor>)>
|
if(to->PointedType == TypeVoid)
|
||||||
return (to->PointedType == TypeVoid || (from &&
|
{
|
||||||
( from->Variants[0].Proto == static_cast<PPrototype*>(to->PointedType)
|
return from;
|
||||||
&& from->Variants[0].ArgFlags == to->ArgFlags
|
}
|
||||||
&& FScopeBarrier::CheckSidesForFunctionPointer(FScopeBarrier::SideFromFlags(from->Variants[0].Flags), to->Scope)
|
else if(from && ((from->Variants[0].Flags & (VARF_Virtual | VARF_Action)) == 0) && FScopeBarrier::CheckSidesForFunctionPointer(FScopeBarrier::SideFromFlags(from->Variants[0].Flags), to->Scope))
|
||||||
))) ? from : nullptr;
|
{
|
||||||
|
if(to->ArgFlags.Size() != from->Variants[0].ArgFlags.Size()) return nullptr;
|
||||||
|
int n = to->ArgFlags.Size();
|
||||||
|
for(int i = from->GetImplicitArgs(); i < n; i++) // skip checking flags for implicit self
|
||||||
|
{
|
||||||
|
if(from->Variants[0].ArgFlags[i] != to->ArgFlags[i])
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return AreCompatibleFnPtrTypes(static_cast<PPrototype*>(to->PointedType), from->Variants[0].Proto) ? from : nullptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ // cannot cast virtual/action functions to anything
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinFunctionPtrCast, NativeFunctionPointerCast)
|
DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinFunctionPtrCast, NativeFunctionPointerCast)
|
||||||
|
@ -11841,6 +12019,17 @@ FxExpression *FxLocalVariableDeclaration::Resolve(FCompileContext &ctx)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
SAFE_RESOLVE(Init, ctx);
|
SAFE_RESOLVE(Init, ctx);
|
||||||
|
|
||||||
|
if(Init->isConstant() && Init->ValueType == TypeRawFunction)
|
||||||
|
{
|
||||||
|
FxConstant *val = FxTypeCast::convertRawFunctionToFunctionPointer(Init, ScriptPosition);
|
||||||
|
if(!val)
|
||||||
|
{
|
||||||
|
delete this;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ValueType = Init->ValueType;
|
ValueType = Init->ValueType;
|
||||||
if (ValueType->RegType == REGT_NIL)
|
if (ValueType->RegType == REGT_NIL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -513,6 +513,13 @@ public:
|
||||||
ValueType = value.Type = TypeVMFunction;
|
ValueType = value.Type = TypeVMFunction;
|
||||||
isresolved = true;
|
isresolved = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FxConstant(PFunction* rawptr, const FScriptPosition& pos) : FxExpression(EFX_Constant, pos)
|
||||||
|
{
|
||||||
|
value.pointer = rawptr;
|
||||||
|
ValueType = value.Type = TypeRawFunction;
|
||||||
|
isresolved = true;
|
||||||
|
}
|
||||||
|
|
||||||
FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
|
FxConstant(const FScriptPosition &pos) : FxExpression(EFX_Constant, pos)
|
||||||
{
|
{
|
||||||
|
@ -558,6 +565,8 @@ public:
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
|
||||||
|
friend class FxTypeCast;
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -736,6 +745,8 @@ public:
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
|
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
|
||||||
|
static FxConstant * convertRawFunctionToFunctionPointer(FxExpression * in, FScriptPosition &ScriptPosition);
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -75,6 +75,7 @@ PStruct *TypeStringStruct;
|
||||||
PStruct* TypeQuaternionStruct;
|
PStruct* TypeQuaternionStruct;
|
||||||
PPointer *TypeNullPtr;
|
PPointer *TypeNullPtr;
|
||||||
PPointer *TypeVoidPtr;
|
PPointer *TypeVoidPtr;
|
||||||
|
PPointer *TypeRawFunction;
|
||||||
PPointer* TypeVMFunction;
|
PPointer* TypeVMFunction;
|
||||||
|
|
||||||
|
|
||||||
|
@ -323,6 +324,8 @@ void PType::StaticInit()
|
||||||
TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID);
|
TypeTable.AddType(TypeTextureID = new PTextureID, NAME_TextureID);
|
||||||
|
|
||||||
TypeVoidPtr = NewPointer(TypeVoid, false);
|
TypeVoidPtr = NewPointer(TypeVoid, false);
|
||||||
|
TypeRawFunction = new PPointer;
|
||||||
|
TypeRawFunction->mDescriptiveName = "Raw Function Pointer";
|
||||||
TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true));
|
TypeVMFunction = NewPointer(NewStruct("VMFunction", nullptr, true));
|
||||||
TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value.
|
TypeColorStruct = NewStruct("@ColorStruct", nullptr); //This name is intentionally obfuscated so that it cannot be used explicitly. The point of this type is to gain access to the single channels of a color value.
|
||||||
TypeStringStruct = NewStruct("Stringstruct", nullptr, true);
|
TypeStringStruct = NewStruct("Stringstruct", nullptr, true);
|
||||||
|
|
|
@ -727,6 +727,7 @@ extern PPointer *TypeFont;
|
||||||
extern PStateLabel *TypeStateLabel;
|
extern PStateLabel *TypeStateLabel;
|
||||||
extern PPointer *TypeNullPtr;
|
extern PPointer *TypeNullPtr;
|
||||||
extern PPointer *TypeVoidPtr;
|
extern PPointer *TypeVoidPtr;
|
||||||
|
extern PPointer* TypeRawFunction;
|
||||||
extern PPointer* TypeVMFunction;
|
extern PPointer* TypeVMFunction;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,9 @@
|
||||||
#define LKP MODE_AP | MODE_BCJOINT | MODE_BCKP
|
#define LKP MODE_AP | MODE_BCJOINT | MODE_BCKP
|
||||||
#define LFP MODE_AP | MODE_BUNUSED | MODE_CUNUSED
|
#define LFP MODE_AP | MODE_BUNUSED | MODE_CUNUSED
|
||||||
|
|
||||||
|
|
||||||
|
#define RP MODE_AP | MODE_BUNUSED | MODE_CUNUSED
|
||||||
|
|
||||||
#define RIRPKI MODE_AI | MODE_BP | MODE_CKI
|
#define RIRPKI MODE_AI | MODE_BP | MODE_CKI
|
||||||
#define RIRPRI MODE_AI | MODE_BP | MODE_CI
|
#define RIRPRI MODE_AI | MODE_BP | MODE_CI
|
||||||
#define RFRPKI MODE_AF | MODE_BP | MODE_CKI
|
#define RFRPKI MODE_AF | MODE_BP | MODE_CKI
|
||||||
|
|
|
@ -719,3 +719,8 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature()
|
||||||
signature.init(CallConv::kIdHost, rettype, cachedArgs->Data(), cachedArgs->Size());
|
signature.init(CallConv::kIdHost, rettype, cachedArgs->Data(), cachedArgs->Size());
|
||||||
return signature;
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void JitCompiler::EmitNULLCHECK()
|
||||||
|
{
|
||||||
|
EmitNullPointerThrow(A, X_READ_NIL);
|
||||||
|
}
|
|
@ -1937,6 +1937,15 @@ static int ExecScriptFunc(VMFrameStack *stack, VMReturn *ret, int numret)
|
||||||
CMPJMP(reg.a[B] == konsta[C].v);
|
CMPJMP(reg.a[B] == konsta[C].v);
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
|
|
||||||
|
OP(NULLCHECK):
|
||||||
|
ASSERTA(a);
|
||||||
|
if (PA == nullptr)
|
||||||
|
{
|
||||||
|
ThrowAbortException(X_WRITE_NIL, nullptr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
NEXTOP;
|
||||||
|
|
||||||
OP(NOP):
|
OP(NOP):
|
||||||
NEXTOP;
|
NEXTOP;
|
||||||
}
|
}
|
||||||
|
|
|
@ -289,4 +289,7 @@ xx(SUBA, sub, RIRPRP, NOP, 0, 0) // dA = pB - pC
|
||||||
xx(EQA_R, beq, CPRR, NOP, 0, 0) // if ((pB == pkC) != A) then pc++
|
xx(EQA_R, beq, CPRR, NOP, 0, 0) // if ((pB == pkC) != A) then pc++
|
||||||
xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER)
|
xx(EQA_K, beq, CPRK, EQA_R, 4, REGT_POINTER)
|
||||||
|
|
||||||
|
// Null check
|
||||||
|
xx(NULLCHECK, nullcheck, RP, NOP, 0, 0) // EmitNullPointerThrow(pA)
|
||||||
|
|
||||||
#undef xx
|
#undef xx
|
||||||
|
|
Loading…
Reference in a new issue