Skip to content

Commit 481a870

Browse files
committed
feat: explicit cast
1 parent 5284826 commit 481a870

File tree

10 files changed

+174
-9
lines changed

10 files changed

+174
-9
lines changed

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>35.9.2</Version>
3+
<Version>35.9.3</Version>
44
<TargetFramework>net10.0</TargetFramework>
55
<RepositoryUrl>https://github.com/dead-cells-core-modding/core</RepositoryUrl>
66
<RepositoryType>git</RepositoryType>

sources/HashlinkNET.Compiler/Data/ObjClassData.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using HashlinkNET.Bytecode;
22
using HashlinkNET.Compiler.Data.Interfaces;
33
using Mono.Cecil;
4+
using System.Collections.Concurrent;
45
using IObjComparable = HashlinkNET.Compiler.Data.Interfaces.IObjComparable;
56

67
namespace HashlinkNET.Compiler.Data
@@ -28,7 +29,10 @@ public required TypeDefinition TypeDef
2829
{
2930
get; set;
3031
}
31-
32+
public ConcurrentDictionary<TypeReference, bool> CastExplicitTypes
33+
{
34+
get; set;
35+
} = [];
3236
public List<PropertyDefinition> Fields
3337
{
3438
get;

sources/HashlinkNET.Compiler/Data/RuntimeImports.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ internal class RuntimeImports
5050
public MethodReference hGetNullableProxy;
5151
public MethodReference hGetCallInfoById;
5252
public MethodReference hCreateEnumInstance;
53+
public MethodReference hToVirtual;
54+
public MethodReference hToObject;
5355

5456
public MethodReference hAddHook;
5557
public MethodReference hRemoveHook;
@@ -83,5 +85,6 @@ internal class RuntimeImports
8385
public MethodReference phWriteMem;
8486
public MethodReference hGetTypeIndexFromType;
8587
public MethodReference attrInitialValue;
88+
8689
}
8790
}

sources/HashlinkNET.Compiler/HashlinkCompiler.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ protected override void InstallSteps()
8888
AddStep<GenerateClassGlobalPropStep>();
8989
AddStep<GenerateClassMethodDefStep>();
9090
AddStep<GenerateClassCtorStep>();
91+
92+
AddStep<FindCastExplicitTypesStep>();
93+
AddStep<GenerateClassExplicitCastStep>();
9194
#endregion
9295

9396
#region Arrow Function
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using HashlinkNET.Bytecode;
2+
using HashlinkNET.Compiler.Data;
3+
using HashlinkNET.Compiler.Utils;
4+
using Mono.Cecil;
5+
using Mono.Cecil.Cil;
6+
using System;
7+
using System.Collections.Generic;
8+
using System.Text;
9+
10+
namespace HashlinkNET.Compiler.Steps.Class
11+
{
12+
internal class GenerateClassExplicitCastStep : ForeachHlTypeCompileStep
13+
{
14+
public override bool Filter( HlType type )
15+
{
16+
return type.Kind == HlTypeKind.Obj;
17+
}
18+
public override void Execute( IDataContainer container, HlCode code, GlobalData gdata, RuntimeImports rdata, HlType type )
19+
{
20+
var info = container.GetData<ObjClassData>(type);
21+
var td = info.TypeDef;
22+
foreach (var v in info.CastExplicitTypes)
23+
{
24+
if (!v.Value)
25+
{
26+
continue;
27+
}
28+
{
29+
var to = new MethodDefinition(
30+
$"op_Explicit",
31+
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
32+
rdata.objectType
33+
)
34+
{
35+
Parameters =
36+
{
37+
new("value", ParameterAttributes.None, td)
38+
},
39+
ReturnType = v.Key
40+
};
41+
var il = to.Body.GetILProcessor();
42+
43+
il.Emit(OpCodes.Ldarg_0);
44+
45+
if (v.Value) //Is Virtual
46+
{
47+
il.Emit(OpCodes.Call, rdata.hToVirtual.MakeInstance(v.Key));
48+
}
49+
else
50+
{
51+
il.Emit(OpCodes.Call, rdata.hToObject.MakeInstance(v.Key));
52+
}
53+
54+
il.Emit(OpCodes.Ret);
55+
56+
57+
td.Methods.Add(to);
58+
}
59+
{
60+
var from = new MethodDefinition(
61+
$"op_Explicit",
62+
MethodAttributes.Public | MethodAttributes.Static | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
63+
rdata.objectType
64+
)
65+
{
66+
Parameters =
67+
{
68+
new("value", ParameterAttributes.None, v.Key)
69+
},
70+
ReturnType = td
71+
};
72+
73+
var il = from.Body.GetILProcessor();
74+
75+
il.Emit(OpCodes.Ldarg_0);
76+
il.Emit(OpCodes.Call, rdata.hToObject.MakeInstance(td));
77+
il.Emit(OpCodes.Ret);
78+
79+
td.Methods.Add(from);
80+
}
81+
}
82+
}
83+
}
84+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using HashlinkNET.Bytecode;
2+
using HashlinkNET.Compiler.Data;
3+
using HashlinkNET.Compiler.Data.Interfaces;
4+
using HashlinkNET.Compiler.Utils;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
9+
namespace HashlinkNET.Compiler.Steps.Func
10+
{
11+
internal class FindCastExplicitTypesStep : ParallelCompileStep<HlFunction>
12+
{
13+
protected override IReadOnlyList<HlFunction> GetItems( IDataContainer container )
14+
{
15+
return container.GetGlobalData<GlobalData>().Code.Functions;
16+
}
17+
18+
protected override void Execute( IDataContainer container, HlFunction item, int index )
19+
{
20+
foreach (var v in item.Opcodes)
21+
{
22+
if (v.Kind != HlOpcodeKind.SafeCast &
23+
v.Kind != HlOpcodeKind.ToVirtual)
24+
{
25+
continue;
26+
}
27+
28+
var t1 = item.GetLocalRegType(v.Data[1]);
29+
var t2 = item.GetLocalRegType(v.Data[2]);
30+
31+
void Process(HlType a, HlType b)
32+
{
33+
if (a.Kind != HlTypeKind.Obj)
34+
{
35+
return;
36+
}
37+
if (b.Kind != HlTypeKind.Obj && b.Kind != HlTypeKind.Virtual)
38+
{
39+
return;
40+
}
41+
var info = container.GetData<ObjClassData>(a);
42+
var another = container.GetData<ITypeReferenceValue>(b).TypeRef;
43+
info.CastExplicitTypes.TryAdd(another, b.Kind == HlTypeKind.Virtual);
44+
}
45+
Process(t1, t2);
46+
Process(t2, t1);
47+
}
48+
}
49+
}
50+
}

sources/HashlinkNET.Compiler/Steps/Preprocessor/Imports/ImportRuntimeTypesStep.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ public override void Execute( IDataContainer container )
9494
rdata.hCreateEnumInstance = ImportHelperMethod(nameof(HaxeProxyHelper.CreateEnumInstance));
9595
rdata.hGetEnumIndex = ImportMethod(typeof(HaxeEnum), "get_RawIndex");
9696
rdata.hGetTypeIndexFromType = ImportHelperMethod(nameof(HaxeProxyHelper.GetTypeIndexFromType));
97+
rdata.hToVirtual = ImportHelperMethod(nameof(HaxeProxyHelper.ToVirtual));
98+
rdata.hToObject = ImportHelperMethod(nameof(HaxeProxyHelper.ToObject));
9799

98100
rdata.hAddHook = ImportHelperMethod(nameof(HaxeProxyHelper.AddHook));
99101
rdata.hRemoveHook = ImportHelperMethod(nameof(HaxeProxyHelper.RemoveHook));

sources/HashlinkNET.Compiler/Utils/GeneralUtils.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ public static void AddDynamicAttribute( this ICustomAttributeProvider provider,
287287
provider.CustomAttributes.Add(new(runtimeImports.attrDynamic));
288288
}
289289

290+
public static HlType GetLocalRegType( this HlFunction func, int idx )
291+
{
292+
return func.LocalVariables[idx].Value;
293+
}
294+
290295
private static bool IsObjectType( TypeReference type )
291296
{
292297
return type.Namespace == "System" && type.Name == "Object";
@@ -302,10 +307,12 @@ public static void CheckDynamic( this ICustomAttributeProvider provider, Runtime
302307

303308
if (type is GenericInstanceType)
304309
{
305-
static void CheckDynamic2(List<bool> values, TypeReference tr)
310+
bool anyDynamic = false;
311+
void CheckDynamic2(List<bool> values, TypeReference tr)
306312
{
307313
if (IsObjectType(tr))
308314
{
315+
anyDynamic = true;
309316
values.Add(true);
310317
return;
311318
}
@@ -321,13 +328,16 @@ static void CheckDynamic2(List<bool> values, TypeReference tr)
321328
dynamicFlagsList.Clear();
322329
CheckDynamic2(dynamicFlagsList, type);
323330

324-
provider.CustomAttributes.Add(new(runtimeImports.attrDynamic2)
331+
if (anyDynamic)
325332
{
326-
ConstructorArguments = {
333+
334+
provider.CustomAttributes.Add(new(runtimeImports.attrDynamic2)
335+
{
336+
ConstructorArguments = {
327337
new(runtimeImports.typeSystem.Boolean.MakeArrayType(), dynamicFlagsList.ToArray())
328338
}
329-
});
330-
339+
});
340+
}
331341
}
332342
else if (IsObjectType(type))
333343
{

sources/HaxeProxy/Runtime/HaxeProxyBase.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public override bool TryConvert( ConvertBinder binder, out object? result )
6060
}
6161
return base.TryConvert(binder, out result);
6262
}
63-
public T ToVirtual<T>() where T : HaxeVirtual
63+
public virtual T ToVirtual<T>() where T : HaxeVirtual
6464
{
6565
var tid = HaxeProxyManager.type2typeId[typeof(T)];
6666
var vt = HashlinkMarshal.Module.Types[tid];
@@ -69,7 +69,7 @@ public T ToVirtual<T>() where T : HaxeVirtual
6969
)!;
7070
return result.AsHaxe<T>();
7171
}
72-
public T AsObject<T>() where T : HaxeObject
72+
public virtual T AsObject<T>() where T : HaxeObject
7373
{
7474
if (this is T result)
7575
{

sources/HaxeProxy/Runtime/Internals/HaxeProxyHelper.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ public static void SetValueFieldById<T>( HaxeProxyBase self, T value, string nam
124124
global
125125
);
126126
}
127+
public static T ToObject<T>( HaxeProxyBase val ) where T : HaxeObject
128+
{
129+
return val.AsObject<T>();
130+
}
131+
[MethodImpl(MethodImplOptions.AggressiveInlining)]
132+
public static T ToVirtual<T>( HaxeProxyBase val ) where T : HaxeVirtual
133+
{
134+
return val.ToVirtual<T>();
135+
}
127136
[return: NotNullIfNotNull(nameof(val))]
128137
[MethodImpl(MethodImplOptions.AggressiveInlining)]
129138
public static object? GetProxy<T>( object? val )

0 commit comments

Comments
 (0)