- make dynamic object casts a dedicated VM instruction instead of a builtin function.
This can see some heavy use in iterators where saving several hundreds of function calls can be achieved. In these cases, using a function to do the job will become a significant time waster.
This commit is contained in:
parent
f722967abe
commit
092461ed34
6 changed files with 44 additions and 72 deletions
|
|
@ -4324,58 +4324,32 @@ FxExpression *FxTypeCheck::Resolve(FCompileContext& ctx)
|
|||
//
|
||||
//==========================================================================
|
||||
|
||||
PPrototype *FxTypeCheck::ReturnProto()
|
||||
ExpEmit FxTypeCheck::EmitCommon(VMFunctionBuilder *build)
|
||||
{
|
||||
EmitTail = true;
|
||||
return FxExpression::ReturnProto();
|
||||
ExpEmit castee = left->Emit(build);
|
||||
ExpEmit casttype = right->Emit(build);
|
||||
castee.Free(build);
|
||||
casttype.Free(build);
|
||||
ExpEmit ares(build, REGT_POINTER);
|
||||
build->Emit(casttype.Konst ? OP_DYNCAST_K : OP_DYNCAST_R, ares.RegNum, castee.RegNum, casttype.RegNum);
|
||||
return ares;
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
int BuiltinTypeCheck(VMValue *param, TArray<VMValue> &defaultparam, int numparam, VMReturn *ret, int numret)
|
||||
{
|
||||
assert(numparam == 2);
|
||||
PARAM_POINTER_AT(0, obj, DObject);
|
||||
PARAM_CLASS_AT(1, cls, DObject);
|
||||
ACTION_RETURN_BOOL(obj && obj->IsKindOf(cls));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
//
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
ExpEmit FxTypeCheck::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
EmitParameter(build, left, ScriptPosition);
|
||||
EmitParameter(build, right, ScriptPosition);
|
||||
ExpEmit ares = EmitCommon(build);
|
||||
ares.Free(build);
|
||||
ExpEmit bres(build, REGT_INT);
|
||||
build->Emit(OP_CASTB, bres.RegNum, ares.RegNum, CASTB_A);
|
||||
return bres;
|
||||
}
|
||||
|
||||
|
||||
PSymbol *sym = FindBuiltinFunction(NAME_BuiltinTypeCheck, BuiltinTypeCheck);
|
||||
|
||||
assert(sym->IsKindOf(RUNTIME_CLASS(PSymbolVMFunction)));
|
||||
assert(((PSymbolVMFunction *)sym)->Function != nullptr);
|
||||
auto callfunc = ((PSymbolVMFunction *)sym)->Function;
|
||||
|
||||
int opcode = (EmitTail ? OP_TAIL_K : OP_CALL_K);
|
||||
build->Emit(opcode, build->GetConstantAddress(callfunc, ATAG_OBJECT), 2, 1);
|
||||
|
||||
if (EmitTail)
|
||||
{
|
||||
ExpEmit call;
|
||||
call.Final = true;
|
||||
return call;
|
||||
}
|
||||
|
||||
ExpEmit out(build, REGT_INT);
|
||||
build->Emit(OP_RESULT, 0, REGT_INT, out.RegNum);
|
||||
return out;
|
||||
void FxTypeCheck::EmitCompare(VMFunctionBuilder *build, bool invert, TArray<size_t> &patchspots_yes, TArray<size_t> &patchspots_no)
|
||||
{
|
||||
ExpEmit ares = EmitCommon(build);
|
||||
ares.Free(build);
|
||||
build->Emit(OP_EQA_K, !invert, ares.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT));
|
||||
patchspots_no.Push(build->Emit(OP_JMP, 0));
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -4443,27 +4417,11 @@ FxExpression *FxDynamicCast::Resolve(FCompileContext& ctx)
|
|||
|
||||
ExpEmit FxDynamicCast::Emit(VMFunctionBuilder *build)
|
||||
{
|
||||
ExpEmit in = expr->Emit(build);
|
||||
ExpEmit out = in.Fixed ? ExpEmit(build, in.RegType) : in;
|
||||
ExpEmit check(build, REGT_INT);
|
||||
assert(out.RegType == REGT_POINTER);
|
||||
|
||||
if (in.Fixed) build->Emit(OP_MOVEA, out.RegNum, in.RegNum);
|
||||
build->Emit(OP_PARAM, 0, REGT_POINTER, in.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);
|
||||
build->Emit(OP_EQ_K, 0, check.RegNum, build->GetConstantInt(0));
|
||||
auto patch = build->Emit(OP_JMP, 0);
|
||||
build->Emit(OP_LKP, out.RegNum, build->GetConstantAddress(nullptr, ATAG_OBJECT));
|
||||
build->BackpatchToHere(patch);
|
||||
return out;
|
||||
ExpEmit castee = expr->Emit(build);
|
||||
castee.Free(build);
|
||||
ExpEmit ares(build, REGT_POINTER);
|
||||
build->Emit(OP_DYNCAST_K, ares.RegNum, castee.RegNum, build->GetConstantAddress(CastType, ATAG_OBJECT));
|
||||
return ares;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
|
|
@ -9586,8 +9544,7 @@ int BuiltinNameToClass(VMValue *param, TArray<VMValue> &defaultparam, int numpar
|
|||
|
||||
if (!cls->IsDescendantOf(desttype))
|
||||
{
|
||||
// Let the caller check this. The message can be enabled for diagnostic purposes.
|
||||
DPrintf(DMSG_SPAMMY, "class '%s' is not compatible with '%s'\n", clsname.GetChars(), desttype->TypeName.GetChars());
|
||||
// Let the caller check this. Making this an error with a message is only taking away options from the user.
|
||||
cls = nullptr;
|
||||
}
|
||||
ret->SetPointer(const_cast<PClass *>(cls), ATAG_OBJECT);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue