Use SpanToRef in IterActionGenerator

wip/source-generators
copygirl 1 year ago
parent 3d533fcee9
commit 6eb1ef0de9
  1. 69
      src/gaemstone/Utility/IL/IterActionGenerator.cs

@ -14,24 +14,24 @@ public unsafe class IterActionGenerator
{
private static readonly ConstructorInfo _entityRefCtor = typeof(EntityRef).GetConstructors().Single();
private static readonly PropertyInfo _iteratorWorldProp = typeof(Iterator).GetProperty(nameof(Iterator.World))!;
private static readonly PropertyInfo _iteratorDeltaTimeProp = typeof(Iterator).GetProperty(nameof(Iterator.DeltaTime))!;
private static readonly PropertyInfo _iteratorCountProp = typeof(Iterator).GetProperty(nameof(Iterator.Count))!;
private static readonly MethodInfo _iteratorEntityMethod = typeof(Iterator).GetMethod(nameof(Iterator.Entity))!;
private static readonly MethodInfo _iteratorFieldMethod = typeof(Iterator).GetMethod(nameof(Iterator.Field))!;
private static readonly MethodInfo _iteratorFieldOrEmptyMethod = typeof(Iterator).GetMethod(nameof(Iterator.FieldOrEmpty))!;
private static readonly PropertyInfo _handleTargetProp = typeof(ReferenceHandle).GetProperty(nameof(ReferenceHandle.Target))!;
private static readonly PropertyInfo _iterWorldProp = typeof(Iterator).GetProperty(nameof(Iterator.World))!;
private static readonly PropertyInfo _iterDeltaTimeProp = typeof(Iterator).GetProperty(nameof(Iterator.DeltaTime))!;
private static readonly PropertyInfo _iterCountProp = typeof(Iterator).GetProperty(nameof(Iterator.Count))!;
private static readonly MethodInfo _iterEntityMethod = typeof(Iterator).GetMethod(nameof(Iterator.Entity))!;
private static readonly MethodInfo _iterFieldMethod = typeof(Iterator).GetMethod(nameof(Iterator.Field ), 1, new[] { typeof(int) })!;
private static readonly MethodInfo _iterFieldOrEmptyMethod = typeof(Iterator).GetMethod(nameof(Iterator.FieldOrEmpty), 1, new[] { typeof(int) })!;
private static readonly MethodInfo _iterFieldRefMethod = typeof(Iterator).GetMethod(nameof(Iterator.Field ), 1, new[] { typeof(int), Type.MakeGenericMethodParameter(0) })!;
private static readonly MethodInfo _iterFieldOrEmptyRefMethod = typeof(Iterator).GetMethod(nameof(Iterator.FieldOrEmpty), 1, new[] { typeof(int), Type.MakeGenericMethodParameter(0) })!;
private static readonly ConditionalWeakTable<MethodInfo, IterActionGenerator> _cache = new();
private static readonly Dictionary<Type, Action<ILGeneratorWrapper, IArgument<Iterator>>> _globalUniqueParameters = new() {
[typeof(World)] = (IL, iter) => { IL.Load(iter, _iteratorWorldProp); },
[typeof(Universe)] = (IL, iter) => { IL.Load(iter, _iteratorWorldProp); IL.Cast(typeof(Universe)); },
[typeof(TimeSpan)] = (IL, iter) => { IL.Load(iter, _iteratorDeltaTimeProp); },
[typeof(World)] = (IL, iter) => { IL.Load(iter, _iterWorldProp); },
[typeof(Universe)] = (IL, iter) => { IL.Load(iter, _iterWorldProp); IL.Cast(typeof(Universe)); },
[typeof(TimeSpan)] = (IL, iter) => { IL.Load(iter, _iterDeltaTimeProp); },
};
private static readonly Dictionary<Type, Action<ILGeneratorWrapper, IArgument<Iterator>, ILocal<int>>> _uniqueParameters = new() {
[typeof(Iterator)] = (IL, iter, i) => { IL.Load(iter); },
[typeof(EntityRef)] = (IL, iter, i) => { IL.Load(iter); IL.Load(i); IL.Call(_iteratorEntityMethod); },
[typeof(EntityRef)] = (IL, iter, i) => { IL.Load(iter); IL.Load(i); IL.Call(_iterEntityMethod); },
};
public World World { get; }
@ -110,7 +110,7 @@ public unsafe class IterActionGenerator
fieldLocal = IL.Local(spanType, $"{p.Info.Name}Field");
IL.Load(iteratorArg);
IL.LoadConst(fieldIndex);
IL.Call(_iteratorFieldOrEmptyMethod.MakeGenericMethod(p.FieldType));
IL.Call(_iterFieldOrEmptyMethod.MakeGenericMethod(p.FieldType));
IL.Store(fieldLocal);
if (p.UnderlyingType.IsValueType) {
@ -126,7 +126,7 @@ public unsafe class IterActionGenerator
fieldLocal = IL.Local(spanType, $"{p.Info.Name}Field");
IL.Load(iteratorArg);
IL.LoadConst(fieldIndex);
IL.Call(_iteratorFieldMethod.MakeGenericMethod(p.FieldType));
IL.Call(_iterFieldMethod.MakeGenericMethod(p.FieldType));
IL.Store(fieldLocal);
break;
}
@ -134,17 +134,11 @@ public unsafe class IterActionGenerator
paramData.Add((p, term, fieldLocal, tempLocal));
}
// If there's any reference type parameters, we need to define a ReferenceHandle local.
var hasReferenceType = paramData
.Where(p => p.Info.Kind > ParamKind.Unique)
.Any(p => !p.Info.UnderlyingType.IsValueType);
var handleLocal = hasReferenceType ? IL.Local<ReferenceHandle>() : null;
var indexLocal = IL.Local<int>("iter_index");
var countLocal = IL.Local<int>("iter_count");
IL.Set(indexLocal, 0);
IL.Load(iteratorArg, _iteratorCountProp);
IL.Load(iteratorArg, _iterCountProp);
IL.Store(countLocal);
// If all parameters are fixed, iterator count will be 0, but since
@ -186,9 +180,10 @@ public unsafe class IterActionGenerator
break;
default:
var spanType = typeof(Span<>).MakeGenericType(info.FieldType);
var spanItemMethod = spanType.GetProperty("Item")!.GetMethod!;
var spanLengthMethod = spanType.GetProperty("Length")!.GetMethod!;
var spanType = isValueType ? typeof(Span<>) : typeof(Iterator.SpanToRef<>);
var concreteSpanType = spanType.MakeGenericType(info.UnderlyingType);
var spanItemMethod = concreteSpanType.GetProperty("Item")!.GetMethod!;
var spanLengthMethod = concreteSpanType.GetProperty("Length")!.GetMethod!;
IL.Comment($"Parameter {paramName}");
if (info.IsByRef) {
@ -201,15 +196,7 @@ public unsafe class IterActionGenerator
if (info.IsFixed) IL.LoadConst(0);
else IL.Load(indexLocal!);
IL.Call(spanItemMethod);
IL.LoadObj(info.FieldType);
if (!isValueType) {
IL.Comment($"Convert ReferenceHandle to {paramName}");
IL.Store(handleLocal!);
IL.LoadAddr(handleLocal!);
IL.Call(_handleTargetProp.GetMethod!);
IL.Cast(info.UnderlyingType);
}
if (isValueType) IL.LoadObj(info.FieldType);
} else {
var elseLabel = IL.DefineLabel();
var doneLabel = IL.DefineLabel();
@ -220,18 +207,14 @@ public unsafe class IterActionGenerator
if (info.IsFixed) IL.LoadConst(0);
else IL.Load(indexLocal!);
IL.Call(spanItemMethod);
IL.LoadObj(info.FieldType);
if (!isValueType) {
IL.Comment($"Convert ReferenceHandle to {paramName}");
IL.Store(handleLocal!);
IL.LoadAddr(handleLocal!);
IL.Call(_handleTargetProp.GetMethod!);
IL.Cast(info.UnderlyingType);
} else IL.New(info.ParameterType);
if (isValueType) {
IL.LoadObj(info.FieldType);
IL.New(info.ParameterType);
}
IL.Goto(doneLabel);
IL.MarkLabel(elseLabel);
if (!isValueType) IL.LoadNull();
else IL.LoadObj(tempLocal!);
if (isValueType) IL.LoadObj(tempLocal!);
else IL.LoadNull();
IL.MarkLabel(doneLabel);
}
break;

Loading…
Cancel
Save