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

Loading…
Cancel
Save