From 632708bccb1fe88cfb0e8f54f74bb68b2b48e277 Mon Sep 17 00:00:00 2001 From: Chronos Ouroboros Date: Wed, 23 Oct 2019 18:38:41 -0300 Subject: [PATCH] Fixed dynamic arrays as function arguments. --- src/scripting/backend/codegen.cpp | 118 +++++++++++++++++++++++++++++- src/scripting/backend/codegen.h | 24 ++++++ 2 files changed, 140 insertions(+), 2 deletions(-) diff --git a/src/scripting/backend/codegen.cpp b/src/scripting/backend/codegen.cpp index 56cb07ae5..8f41895ff 100644 --- a/src/scripting/backend/codegen.cpp +++ b/src/scripting/backend/codegen.cpp @@ -7301,6 +7301,16 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) SAFE_RESOLVE(Array,ctx); SAFE_RESOLVE(index,ctx); + if (Array->ValueType->isRealPointer()) + { + auto pointedType = Array->ValueType->toPointer()->PointedType; + if (pointedType && pointedType->isDynArray()) + { + Array = new FxOutVarDereference(Array, Array->ScriptPosition); + SAFE_RESOLVE(Array, ctx); + } + } + if (index->ValueType->GetRegType() == REGT_FLOAT /* lax */) { // DECORATE allows floats here so cast them to int. @@ -7358,7 +7368,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) auto parentfield = static_cast(Array)->membervar; SizeAddr = parentfield->Offset + sizeof(void*); } - else if (Array->ExprType == EFX_ArrayElement) + else if (Array->ExprType == EFX_ArrayElement || Array->ExprType == EFX_OutVarDereference) { SizeAddr = ~0u; } @@ -7462,7 +7472,7 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) arrayvar.Free(build); } - else if (Array->ExprType == EFX_ArrayElement && Array->isStaticArray()) + else if ((Array->ExprType == EFX_ArrayElement || Array->ExprType == EFX_OutVarDereference) && Array->isStaticArray()) { bound = ExpEmit(build, REGT_INT); build->Emit(OP_LW, bound.RegNum, arrayvar.RegNum, build->GetConstantInt(myoffsetof(FArray, Count))); @@ -8152,6 +8162,16 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) } } + if (Self->ValueType->isRealPointer()) + { + auto pointedType = Self->ValueType->toPointer()->PointedType; + if (pointedType && pointedType->isDynArray()) + { + Self = new FxOutVarDereference(Self, Self->ScriptPosition); + SAFE_RESOLVE(Self, ctx); + } + } + if (Self->ExprType == EFX_Super) { if (ctx.Function == nullptr) @@ -8276,6 +8296,17 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx) delete this; return nullptr; } + + if (a->ValueType->isRealPointer()) + { + auto pointedType = a->ValueType->toPointer()->PointedType; + if (pointedType && pointedType->isDynArray()) + { + a = new FxOutVarDereference(a, a->ScriptPosition); + SAFE_RESOLVE(a, ctx); + } + } + if (isDynArrayObj && ((MethodName == NAME_Push && idx == 0) || (MethodName == NAME_Insert && idx == 1))) { // Null pointers are always valid. @@ -9042,6 +9073,17 @@ FxExpression *FxVMFunctionCall::Resolve(FCompileContext& ctx) { bool writable; ArgList[i] = ArgList[i]->Resolve(ctx); // must be resolved before the address is requested. + + if (ArgList[i]->ValueType->isRealPointer()) + { + auto pointedType = ArgList[i]->ValueType->toPointer()->PointedType; + if (pointedType && pointedType->isDynArray()) + { + ArgList[i] = new FxOutVarDereference(ArgList[i], ArgList[i]->ScriptPosition); + SAFE_RESOLVE(ArgList[i], ctx); + } + } + if (ArgList[i] != nullptr && ArgList[i]->ValueType != TypeNullPtr) { if (type == ArgList[i]->ValueType && type->isRealPointer() && type->toPointer()->PointedType->isStruct()) @@ -11789,3 +11831,75 @@ ExpEmit FxLocalArrayDeclaration::Emit(VMFunctionBuilder *build) return ExpEmit(); } + +//========================================================================== +// +// +// +//========================================================================== + +FxOutVarDereference::~FxOutVarDereference() +{ + SAFE_DELETE(Self); +} + +bool FxOutVarDereference::RequestAddress(FCompileContext &ctx, bool *writable) +{ + if (writable != nullptr) *writable = AddressWritable; + return true; +} + +FxExpression *FxOutVarDereference::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + + SAFE_RESOLVE(Self, ctx); + + assert(Self->ValueType->isPointer()); // 'Self' must be a pointer. + + Self->RequestAddress(ctx, &AddressWritable); + SelfType = Self->ValueType->toPointer()->PointedType; + ValueType = SelfType; + + if (SelfType->GetRegType() == REGT_NIL && !SelfType->isRealPointer() && !SelfType->isDynArray()) + { + ScriptPosition.Message(MSG_ERROR, "Cannot dereference pointer"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxOutVarDereference::Emit(VMFunctionBuilder *build) +{ + ExpEmit selfEmit = Self->Emit(build); + assert(selfEmit.RegType == REGT_POINTER); + assert(SelfType->GetRegCount() == 1 && selfEmit.RegCount == 1); + + int regType = 0; + int loadOp = 0; + + if (SelfType->GetRegType() != REGT_NIL) + { + regType = SelfType->GetRegType(); + loadOp = SelfType->GetLoadOp (); + } + else if (SelfType->isRealPointer()) + { + regType = REGT_POINTER; + loadOp = OP_LP; + } + else if (SelfType->isDynArray()) + { + regType = REGT_POINTER; + loadOp = OP_MOVEA; + } + + ExpEmit out = ExpEmit(build, regType); + + build->Emit(loadOp, out.RegNum, selfEmit.RegNum, 0); + selfEmit.Free(build); + + return out; +} \ No newline at end of file diff --git a/src/scripting/backend/codegen.h b/src/scripting/backend/codegen.h index fdd44cfc0..4588f2447 100644 --- a/src/scripting/backend/codegen.h +++ b/src/scripting/backend/codegen.h @@ -302,6 +302,7 @@ enum EFxType EFX_GetDefaultByType, EFX_FontCast, EFX_LocalArrayDeclaration, + EFX_OutVarDereference, EFX_COUNT }; @@ -2209,4 +2210,27 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// +// +//========================================================================== + +class FxOutVarDereference : public FxExpression +{ + FxExpression *Self; + PType *SelfType; + bool AddressWritable; + +public: + FxOutVarDereference(FxExpression *self, const FScriptPosition &p) + : FxExpression(EFX_OutVarDereference, p), Self (self) + { + } + ~FxOutVarDereference(); + FxExpression *Resolve(FCompileContext &); + bool RequestAddress(FCompileContext &ctx, bool *writable); + ExpEmit Emit(VMFunctionBuilder *build); +}; + #endif