diff --git a/src/dobjtype.h b/src/dobjtype.h index 7edf8ca6ab..d0ccee7465 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -18,6 +18,7 @@ typedef std::pair FTypeAndOffset; #define VARF_Method (1<<1) // func has an implied self parameter #define VARF_Action (1<<2) // func has implied owner and state parameters #define VARF_Native (1<<3) // func is native code/don't auto serialize field +#define VARF_ReadOnly (1<<4) // field is read only, do not write to it // Symbol information ------------------------------------------------------- diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp index 3b114fbeef..8fceca8ee4 100644 --- a/src/thingdef/thingdef_data.cpp +++ b/src/thingdef/thingdef_data.cpp @@ -631,38 +631,38 @@ void InitThingdef() // Define some member variables we feel like exposing to the user PSymbolTable &symt = RUNTIME_CLASS(AActor)->Symbols; PType *array5 = NewArray(TypeSInt32, 5); - symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor,Alpha))); - symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Yaw))); - symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor,args))); - symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native, myoffsetof(AActor,ceilingz))); - symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native, myoffsetof(AActor,floorz))); - symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native, myoffsetof(AActor,health))); - symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor,Mass))); - symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Pitch))); - symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor,Angles.Roll))); - symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor,special))); - symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native, myoffsetof(AActor,tid))); - symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native, myoffsetof(AActor,TIDtoHate))); - symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native, myoffsetof(AActor,waterlevel))); - symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.X))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Y))); // must remain read-only! - symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native, myoffsetof(AActor,__Pos.Z))); // must remain read-only! - symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native, myoffsetof(AActor,Vel.X))); - symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.X))); - symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Y))); - symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native, myoffsetof(AActor, Vel.Z))); - symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); - symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); - symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor,Score))); - symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor,accuracy))); - symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor,stamina))); - symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native, myoffsetof(AActor,Height))); - symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native, myoffsetof(AActor,radius))); - symt.AddSymbol(new PField(NAME_ReactionTime,TypeSInt32, VARF_Native, myoffsetof(AActor,reactiontime))); - symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor,meleerange))); - symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor,Speed))); - symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native, myoffsetof(AActor,threshold))); - symt.AddSymbol(new PField(NAME_DefThreshold,TypeSInt32, VARF_Native, myoffsetof(AActor,DefThreshold))); + symt.AddSymbol(new PField(NAME_Alpha, TypeFloat64, VARF_Native, myoffsetof(AActor, Alpha))); + symt.AddSymbol(new PField(NAME_Angle, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Yaw))); + symt.AddSymbol(new PField(NAME_Args, array5, VARF_Native, myoffsetof(AActor, args))); + symt.AddSymbol(new PField(NAME_CeilingZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, ceilingz))); + symt.AddSymbol(new PField(NAME_FloorZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, floorz))); + symt.AddSymbol(new PField(NAME_Health, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, health))); + symt.AddSymbol(new PField(NAME_Mass, TypeSInt32, VARF_Native, myoffsetof(AActor, Mass))); + symt.AddSymbol(new PField(NAME_Pitch, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Pitch))); + symt.AddSymbol(new PField(NAME_Roll, TypeFloat64, VARF_Native, myoffsetof(AActor, Angles.Roll))); + symt.AddSymbol(new PField(NAME_Special, TypeSInt32, VARF_Native, myoffsetof(AActor, special))); + symt.AddSymbol(new PField(NAME_TID, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, tid))); + symt.AddSymbol(new PField(NAME_TIDtoHate, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, TIDtoHate))); + symt.AddSymbol(new PField(NAME_WaterLevel, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, waterlevel))); + symt.AddSymbol(new PField(NAME_X, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.X))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Y, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Y))); // must remain read-only! + symt.AddSymbol(new PField(NAME_Z, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, __Pos.Z))); // must remain read-only! + symt.AddSymbol(new PField(NAME_VelX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_VelY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_VelZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_MomX, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.X))); + symt.AddSymbol(new PField(NAME_MomY, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Y))); + symt.AddSymbol(new PField(NAME_MomZ, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Vel.Z))); + symt.AddSymbol(new PField(NAME_ScaleX, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.X))); + symt.AddSymbol(new PField(NAME_ScaleY, TypeFloat64, VARF_Native, myoffsetof(AActor, Scale.Y))); + symt.AddSymbol(new PField(NAME_Score, TypeSInt32, VARF_Native, myoffsetof(AActor, Score))); + symt.AddSymbol(new PField(NAME_Accuracy, TypeSInt32, VARF_Native, myoffsetof(AActor, accuracy))); + symt.AddSymbol(new PField(NAME_Stamina, TypeSInt32, VARF_Native, myoffsetof(AActor, stamina))); + symt.AddSymbol(new PField(NAME_Height, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, Height))); + symt.AddSymbol(new PField(NAME_Radius, TypeFloat64, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, radius))); + symt.AddSymbol(new PField(NAME_ReactionTime, TypeSInt32, VARF_Native, myoffsetof(AActor, reactiontime))); + symt.AddSymbol(new PField(NAME_MeleeRange, TypeFloat64, VARF_Native, myoffsetof(AActor, meleerange))); + symt.AddSymbol(new PField(NAME_Speed, TypeFloat64, VARF_Native, myoffsetof(AActor, Speed))); + symt.AddSymbol(new PField(NAME_Threshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, threshold))); + symt.AddSymbol(new PField(NAME_DefThreshold, TypeSInt32, VARF_Native|VARF_ReadOnly, myoffsetof(AActor, DefThreshold))); } diff --git a/src/thingdef/thingdef_exp.cpp b/src/thingdef/thingdef_exp.cpp index 2659171754..12dd5957ef 100644 --- a/src/thingdef/thingdef_exp.cpp +++ b/src/thingdef/thingdef_exp.cpp @@ -63,6 +63,7 @@ static FxExpression *ParseClamp(FScanner &sc, PClassActor *cls); // // ParseExpression // [GRB] Parses an expression and stores it into Expression array +// It's worth mentioning that this is using C++ operator precedence // static FxExpression *ParseExpressionM (FScanner &sc, PClassActor *cls); @@ -257,6 +258,10 @@ static FxExpression *ParseExpressionB (FScanner &sc, PClassActor *cls) case '+': return new FxPlusSign(ParseExpressionA (sc, cls)); + case TK_Incr: + case TK_Decr: + return new FxPreIncrDecr(ParseExpressionA(sc, cls), sc.TokenType); + default: sc.UnGet(); return ParseExpressionA (sc, cls); @@ -312,6 +317,14 @@ static FxExpression *ParseExpressionA (FScanner &sc, PClassActor *cls) sc.MustGetToken(']'); base_expr = new FxArrayElement(base_expr, index); } + else if (sc.CheckToken(TK_Incr)) + { + return new FxPostIncrDecr(base_expr, TK_Incr); + } + else if (sc.CheckToken(TK_Decr)) + { + return new FxPostIncrDecr(base_expr, TK_Decr); + } else break; } @@ -478,7 +491,7 @@ static FxExpression *ParseExpression0 (FScanner &sc, PClassActor *cls) } break; } - } + } else { return new FxIdentifier(identifier, sc); diff --git a/src/thingdef/thingdef_exp.h b/src/thingdef/thingdef_exp.h index c1e8863e86..25c4b3afb1 100644 --- a/src/thingdef/thingdef_exp.h +++ b/src/thingdef/thingdef_exp.h @@ -201,7 +201,7 @@ public: virtual FxExpression *Resolve(FCompileContext &ctx); virtual bool isConstant() const; - virtual void RequestAddress(); + virtual bool RequestAddress(); virtual VMFunction *GetDirectFunction(); bool IsNumeric() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); } bool IsPointer() const { return ValueType->GetRegType() == REGT_POINTER; } @@ -469,6 +469,45 @@ public: ExpEmit Emit(VMFunctionBuilder *build); }; +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +class FxPreIncrDecr : public FxExpression +{ + int Token; + FxExpression *Base; + bool AddressRequested; + bool AddressWritable; + +public: + FxPreIncrDecr(FxExpression *base, int token); + ~FxPreIncrDecr(); + FxExpression *Resolve(FCompileContext&); + bool RequestAddress(); + ExpEmit Emit(VMFunctionBuilder *build); +}; + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +class FxPostIncrDecr : public FxExpression +{ + int Token; + FxExpression *Base; + +public: + FxPostIncrDecr(FxExpression *base, int token); + ~FxPostIncrDecr(); + FxExpression *Resolve(FCompileContext&); + ExpEmit Emit(VMFunctionBuilder *build); +}; + //========================================================================== // // FxBinary @@ -753,7 +792,7 @@ public: FxClassMember(FxExpression*, PField*, const FScriptPosition&); ~FxClassMember(); FxExpression *Resolve(FCompileContext&); - void RequestAddress(); + bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); }; @@ -796,12 +835,13 @@ class FxArrayElement : public FxExpression public: FxExpression *Array; FxExpression *index; - //bool AddressRequested; + bool AddressRequested; + bool AddressWritable; FxArrayElement(FxExpression*, FxExpression*); ~FxArrayElement(); FxExpression *Resolve(FCompileContext&); - //void RequestAddress(); + bool RequestAddress(); ExpEmit Emit(VMFunctionBuilder *build); }; diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index d40b7605c1..63b6be9ca9 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -218,13 +218,14 @@ FxExpression *FxExpression::Resolve(FCompileContext &ctx) //========================================================================== // -// +// Returns true if we can write to the address. // //========================================================================== -void FxExpression::RequestAddress() +bool FxExpression::RequestAddress() { ScriptPosition.Message(MSG_ERROR, "invalid dereference\n"); + return false; } //========================================================================== @@ -887,6 +888,166 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) return from; } +//========================================================================== +// +// FxPreIncrDecr +// +//========================================================================== + +FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token) +: FxExpression(base->ScriptPosition), Base(base), Token(token) +{ + AddressRequested = false; + AddressWritable = false; +} + +FxPreIncrDecr::~FxPreIncrDecr() +{ + SAFE_DELETE(Base); +} + +bool FxPreIncrDecr::RequestAddress() +{ + AddressRequested = true; + return AddressWritable; +} + +FxExpression *FxPreIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!(AddressWritable = Base->RequestAddress())) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + ExpEmit value(build, regtype); + build->Emit(ValueType->GetLoadOp(), value.RegNum, pointer.RegNum, zero); + + if (regtype == REGT_INT) + { + build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, value.RegNum, value.RegNum, build->GetConstantInt(1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, value.RegNum, value.RegNum, build->GetConstantFloat(1.)); + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, value.RegNum, zero); + + if (AddressRequested) + { + value.Free(build); + return pointer; + } + + pointer.Free(build); + return value; +} + +//========================================================================== +// +// FxPostIncrDecr +// +//========================================================================== + +FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token) +: FxExpression(base->ScriptPosition), Base(base), Token(token) +{ +} + +FxPostIncrDecr::~FxPostIncrDecr() +{ + SAFE_DELETE(Base); +} + +FxExpression *FxPostIncrDecr::Resolve(FCompileContext &ctx) +{ + CHECKRESOLVED(); + SAFE_RESOLVE(Base, ctx); + + ValueType = Base->ValueType; + + if (!Base->IsNumeric()) + { + ScriptPosition.Message(MSG_ERROR, "Numeric type expected"); + delete this; + return nullptr; + } + else if (Base->ValueType == TypeBool) + { + ScriptPosition.Message(MSG_ERROR, "%s is not allowed on type bool", FScanner::TokenName(Token).GetChars()); + delete this; + return nullptr; + } + if (!Base->RequestAddress()) + { + ScriptPosition.Message(MSG_ERROR, "Expression must be a modifiable value"); + delete this; + return nullptr; + } + + return this; +} + +ExpEmit FxPostIncrDecr::Emit(VMFunctionBuilder *build) +{ + assert(Token == TK_Incr || Token == TK_Decr); + assert(ValueType == Base->ValueType && IsNumeric()); + + int zero = build->GetConstantInt(0); + int regtype = ValueType->GetRegType(); + ExpEmit pointer = Base->Emit(build); + + ExpEmit out(build, regtype); + build->Emit(ValueType->GetLoadOp(), out.RegNum, pointer.RegNum, zero); + + ExpEmit assign(build, regtype); + if (regtype == REGT_INT) + { + build->Emit((Token == TK_Incr) ? OP_ADD_RK : OP_SUB_RK, assign.RegNum, out.RegNum, build->GetConstantInt(1)); + } + else + { + build->Emit((Token == TK_Incr) ? OP_ADDF_RK : OP_SUBF_RK, assign.RegNum, out.RegNum, build->GetConstantFloat(1.)); + } + + build->Emit(ValueType->GetStoreOp(), pointer.RegNum, assign.RegNum, zero); + + pointer.Free(build); + assign.Free(build); + return out; +} + //========================================================================== // // @@ -2995,9 +3156,10 @@ FxClassMember::~FxClassMember() // //========================================================================== -void FxClassMember::RequestAddress() +bool FxClassMember::RequestAddress() { AddressRequested = true; + return !!(~membervar->Flags & VARF_ReadOnly); } //========================================================================== @@ -3027,6 +3189,17 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) ExpEmit obj = classx->Emit(build); assert(obj.RegType == REGT_POINTER); + if (obj.Konst) + { + // If the situation where we are dereferencing a constant + // pointer is common, then it would probably be worthwhile + // to add new opcodes for those. But as of right now, I + // don't expect it to be a particularly common case. + ExpEmit newobj(build, REGT_POINTER); + build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); + obj = newobj; + } + if (AddressRequested) { if (membervar->Offset == 0) @@ -3040,20 +3213,8 @@ ExpEmit FxClassMember::Emit(VMFunctionBuilder *build) } int offsetreg = build->GetConstantInt((int)membervar->Offset); - ExpEmit loc, tmp; + ExpEmit loc(build, membervar->Type->GetRegType()); - if (obj.Konst) - { - // If the situation where we are dereferencing a constant - // pointer is common, then it would probably be worthwhile - // to add new opcodes for those. But as of right now, I - // don't expect it to be a particularly common case. - ExpEmit newobj(build, REGT_POINTER); - build->Emit(OP_LKP, newobj.RegNum, obj.RegNum); - obj = newobj; - } - - loc = ExpEmit(build, membervar->Type->GetRegType()); build->Emit(membervar->Type->GetLoadOp(), loc.RegNum, obj.RegNum, offsetreg); obj.Free(build); return loc; @@ -3071,7 +3232,8 @@ FxArrayElement::FxArrayElement(FxExpression *base, FxExpression *_index) { Array=base; index = _index; - //AddressRequested = false; + AddressRequested = false; + AddressWritable = false; } //========================================================================== @@ -3092,12 +3254,11 @@ FxArrayElement::~FxArrayElement() // //========================================================================== -/* -void FxArrayElement::RequestAddress() +bool FxArrayElement::RequestAddress() { AddressRequested = true; + return AddressWritable; } -*/ //========================================================================== // @@ -3145,7 +3306,7 @@ FxExpression *FxArrayElement::Resolve(FCompileContext &ctx) delete this; return NULL; } - Array->RequestAddress(); + AddressWritable = Array->RequestAddress(); return this; } @@ -3159,13 +3320,13 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { ExpEmit start = Array->Emit(build); PArray *const arraytype = static_cast(Array->ValueType); - PType *const elementtype = arraytype->ElementType; - ExpEmit dest(build, elementtype->GetRegType()); + ExpEmit dest(build, arraytype->ElementType->GetRegType()); if (start.Konst) { ExpEmit tmpstart(build, REGT_POINTER); build->Emit(OP_LKP, tmpstart.RegNum, start.RegNum); + start.Free(build); start = tmpstart; } if (index->isConstant()) @@ -3176,8 +3337,19 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) I_Error("Array index out of bounds"); } indexval *= arraytype->ElementSize; - build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, - start.RegNum, build->GetConstantInt(indexval)); + + if (AddressRequested) + { + if (indexval != 0) + { + build->Emit(OP_ADDA_RK, start.RegNum, start.RegNum, build->GetConstantInt(indexval)); + } + } + else + { + build->Emit(arraytype->ElementType->GetLoadOp(), dest.RegNum, + start.RegNum, build->GetConstantInt(indexval)); + } } else { @@ -3193,10 +3365,24 @@ ExpEmit FxArrayElement::Emit(VMFunctionBuilder *build) { build->Emit(OP_SLL_RI, indexv.RegNum, indexv.RegNum, shiftbits); } - build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that - dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + + if (AddressRequested) + { + build->Emit(OP_ADDA_RR, start.RegNum, start.RegNum, indexv.RegNum); + } + else + { + build->Emit(arraytype->ElementType->GetLoadOp() + 1, // added 1 to use the *_R version that + dest.RegNum, start.RegNum, indexv.RegNum); // takes the offset from a register + } indexv.Free(build); } + if (AddressRequested) + { + dest.Free(build); + return start; + } + start.Free(build); return dest; }