/** * Load the key and ordinal from an iterator instance and place them in the appropriate fields. */ public void LoadIteratorData(LoadableValue iterator, FieldValue key, FieldValue ordinal) { Builder.Emit(OpCodes.Ldarg_0); iterator.Load(Builder); Builder.Emit(OpCodes.Callvirt, typeof(MergeIterator).GetMethod("get_Current")); Builder.Emit(OpCodes.Stfld, key.Field); Builder.Emit(OpCodes.Ldarg_0); iterator.Load(Builder); Builder.Emit(OpCodes.Callvirt, typeof(MergeIterator).GetMethod("get_Position")); Builder.Emit(OpCodes.Stfld, ordinal.Field); }
protected LoadableValue GenerateLookupField(Generator generator, LoadableValue source_reference, LoadableValue context) { var lookup_result = generator.MakeField("lookup_" + Name, typeof(object)); generator.LoadTaskMaster(); generator.Builder.Emit(OpCodes.Dup); source_reference.Load(generator); var name_parts = Name.Split('.'); generator.Builder.Emit(OpCodes.Ldc_I4, name_parts.Length); generator.Builder.Emit(OpCodes.Newarr, typeof(string)); for (var it = 0; it < name_parts.Length; it++) { generator.Builder.Emit(OpCodes.Dup); generator.Builder.Emit(OpCodes.Ldc_I4, it); generator.Builder.Emit(OpCodes.Ldstr, name_parts[it]); generator.Builder.Emit(OpCodes.Stelem, typeof(string)); } context.Load(generator); generator.Builder.Emit(OpCodes.Newobj, typeof(Lookup).GetConstructors()[0]); generator.Builder.Emit(OpCodes.Dup); generator.GenerateConsumeResult(lookup_result, true); generator.Builder.Emit(OpCodes.Call, typeof(Lookup).GetMethod("Notify", new[] { typeof(ConsumeResult) })); generator.Builder.Emit(OpCodes.Call, typeof(TaskMaster).GetMethod("Slot", new[] { typeof(Computation) })); return(lookup_result); }
private void ToStringishHelperStringish(bool boxed, LoadableValue source) { source.Load(Builder); if (boxed) { Builder.Emit(OpCodes.Unbox_Any, typeof(Stringish)); } }
private void ToStringishHelper <T>(bool boxed, LoadableValue source) { source.Load(Builder); if (boxed) { Builder.Emit(OpCodes.Unbox_Any, typeof(T)); } Builder.Emit(OpCodes.Call, typeof(T).GetMethod("ToString", new System.Type[] { typeof(T) })); }
private void ToStringishHelperBool(bool boxed, LoadableValue source) { Builder.Emit(OpCodes.Ldsfld, typeof(Stringish).GetField("BOOLEANS")); source.Load(Builder); if (boxed) { Builder.Emit(OpCodes.Unbox_Any, typeof(bool)); } Builder.Emit(OpCodes.Ldelem); }
/** * Generate a successful return. */ public void Return(LoadableValue result) { if (result.BackingType == typeof(Frame) || result.BackingType == typeof(object)) { var end = Builder.DefineLabel(); if (result.BackingType == typeof(object)) { result.Load(Builder); Builder.Emit(OpCodes.Isinst, typeof(Frame)); result.Load(Builder); Builder.Emit(OpCodes.Castclass, typeof(Frame)); } else { result.Load(Builder); } LoadTaskMaster(); Builder.Emit(OpCodes.Callvirt, typeof(Frame).GetMethod("Slot")); Builder.MarkLabel(end); } CopyField(result, typeof(Computation).GetField("result")); Builder.Emit(OpCodes.Ldc_I4_1); Builder.Emit(System.Reflection.Emit.OpCodes.Ret); }
/** * Create a new source reference based on an existing one, updated to reflect * entry into a new AST node. */ public FieldValue AmendSourceReference(AstNode node, string message, LoadableValue source_reference) { var field = MakeField("source_reference", typeof(SourceReference)); Builder.Emit(OpCodes.Ldarg_0); Builder.Emit(OpCodes.Ldstr, message); Builder.Emit(OpCodes.Ldc_I4, node.StartRow); Builder.Emit(OpCodes.Ldc_I4, node.StartColumn); Builder.Emit(OpCodes.Ldc_I4, node.EndRow); Builder.Emit(OpCodes.Ldc_I4, node.EndColumn); source_reference.Load(Builder); Builder.Emit(OpCodes.Newobj, typeof(SourceReference).GetConstructors()[0]); Builder.Emit(OpCodes.Stfld, field.Field); return(field); }
void CopyField(LoadableValue source, FieldInfo target) { Builder.Emit(OpCodes.Ldarg_0); source.Load(Builder); if (source.BackingType != target.FieldType) { if (target.FieldType == typeof(object)) { Builder.Emit(OpCodes.Box); } else { Builder.Emit(OpCodes.Unbox_Any, target.FieldType); } } Builder.Emit(OpCodes.Stfld, target); }
/** * Generate a runtime dispatch that checks each of the provided types. */ void DynamicTypeDispatch(LoadableValue original, LoadableValue source_reference, System.Type[] types, ParameterisedBlock block) { var labels = new Label[types.Length]; for (var it = 0; it < types.Length; it++) { labels[it] = Builder.DefineLabel(); original.Load(Builder); Builder.Emit(OpCodes.Isinst, types[it]); Builder.Emit(OpCodes.Brtrue, labels[it]); } EmitTypeError(source_reference, String.Format("Unexpected type {0} instead of {1}.", "{0}", string.Join(", ", (object[])types)), original); for (var it = 0; it < types.Length; it++) { Builder.MarkLabel(labels[it]); var converted_field = MakeField("converted", types[it]); CopyField(original, converted_field); block(converted_field); } }
public void ToStringish(LoadableValue source, LoadableValue source_reference) { var boxed = source.BackingType == typeof(object); var converters = new Dictionary <System.Type, Action>() { { typeof(bool), () => ToStringishHelper <double>(boxed, source) }, { typeof(bool), () => ToStringishHelper <long>(boxed, source) }, { typeof(bool), () => ToStringishHelperBool(boxed, source) }, { typeof(Stringish), () => ToStringishHelperStringish(boxed, source) } }; if (boxed) { var end = Builder.DefineLabel(); var labels = new Dictionary <System.Type, Label>(); foreach (var type in converters.Keys) { var label = Builder.DefineLabel(); labels[type] = label; source.Load(Builder); Builder.Emit(OpCodes.Isinst, type); Builder.Emit(OpCodes.Brtrue, label); } EmitTypeError(source_reference, "Cannot convert type {0} to string.", source); foreach (var entry in converters) { Builder.MarkLabel(labels[entry.Key]); entry.Value(); Builder.Emit(OpCodes.Br, end); } Builder.MarkLabel(end); } else { converters[source.BackingType](); } }
public void EmitTypeError(LoadableValue source_reference, string message, params LoadableValue[] data) { LoadTaskMaster(); source_reference.Load(Builder); Builder.Emit(OpCodes.Ldstr, message); foreach (var item in data) { item.Load(Builder); Builder.Emit(OpCodes.Call, typeof(object).GetMethod("GetType")); } var signature = new System.Type[data.Length + 1]; signature[0] = typeof(string); for (var it = 0; it < data.Length; it++) { signature[it + 1] = typeof(object); } Builder.Emit(OpCodes.Call, typeof(String).GetMethod("Format", signature)); Builder.Emit(OpCodes.Callvirt, typeof(TaskMaster).GetMethod("ReportOtherError")); Builder.Emit(OpCodes.Ldc_I4_0); Builder.Emit(OpCodes.Ret); }
internal void IntrinsicDispatch(Generator generator, AstNode node, LoadableValue original, LoadableValue source_reference, Generator.ParameterisedBlock <LoadableValue> block) { var intrinsic = Intrinsics[node]; if (!intrinsic.Item2) { block(original); return; } var types = AstTypeableNode.ClrTypeFromType(intrinsic.Item1); foreach (var type in types) { var next_label = generator.Builder.DefineLabel(); original.Load(generator); generator.Builder.Emit(OpCodes.Isinst, type); generator.Builder.Emit(OpCodes.Brfalse, next_label); var builder = generator.Builder; block(new AutoUnboxValue(original, type)); generator.Builder = builder; generator.Builder.MarkLabel(next_label); } generator.EmitTypeError(source_reference, String.Format("Expected type {0} for {1}, but got {2}.", String.Join(" or ", from t in types select Stringish.NameForType(t)), node.PrettyName, "{0}"), original); }
internal void GenerateLookupCache(Generator generator, IEnumerable <Tuple <RestrictableType, Generator.ParameterisedBlock <Generator.ParameterisedBlock <LoadableValue> > > > specials, LookupCache current, LoadableValue source_reference, LoadableValue context, LoadableValue self_frame, Block block) { generator.DebugPosition(this); var lookup_results = new List <LoadableCache>(); if (specials != null) { var child_context = generator.MakeField("anon_ctxt", typeof(Context)); var child_frame = generator.MakeField("anon_frame", typeof(MutableFrame)); generator.Builder.Emit(OpCodes.Ldarg_0); generator.LoadTaskMaster(); source_reference.Load(generator); context.Load(generator); self_frame.Load(generator); generator.Builder.Emit(OpCodes.Newobj, typeof(MutableFrame).GetConstructors()[0]); generator.Builder.Emit(OpCodes.Stfld, child_frame.Field); generator.Builder.Emit(OpCodes.Ldarg_0); child_frame.Load(generator.Builder); context.Load(generator.Builder); generator.Builder.Emit(OpCodes.Call, typeof(Context).GetMethod("Prepend", new[] { typeof(Frame), typeof(Context) })); generator.Builder.Emit(OpCodes.Stfld, child_context.Field); // Promote the context with the specials to proper status context = child_context; foreach (var entry in specials) { var next = generator.DefineState(); var field = generator.MakeField("special$" + entry.Item1.Name, typeof(object)); // The types that we might allow are a superset of the ones we // might actually see. So, build a set of the ones we see. Type known_types = 0; entry.Item2(result => { child_frame.Load(generator.Builder); generator.Builder.Emit(OpCodes.Ldstr, entry.Item1.Name); generator.LoadReboxed(result, typeof(object)); generator.Builder.Emit(OpCodes.Call, typeof(MutableFrame).GetMethod("Set", new[] { typeof(string), typeof(object) })); generator.CopyField(result, field); generator.JumpToState(next); known_types |= AstTypeableNode.TypeFromClrType(result.BackingType); }); generator.MarkState(next); lookup_results.Add(new LoadableCache(field, entry.Item1.RestrictedType & known_types, entry.Item1, entry.Item1.MustUnbox)); } } var base_lookup_cache = new LookupCache(current); var all_children = new List <NameInfo>(); foreach (var info in Children.Values) { if (info == null) { continue; } info.AddAll(all_children); } if (current != null) { string narrow_error = null; foreach (var info in all_children) { var current_narrow_error = info.CheckValidNarrowing(base_lookup_cache, current); if (narrow_error != null && current_narrow_error != null) { narrow_error = String.Format("{0}\n{1}", narrow_error, current_narrow_error); } else { narrow_error = narrow_error ?? current_narrow_error; } } if (narrow_error != null) { generator.LoadTaskMaster(); source_reference.Load(generator); generator.Builder.Emit(OpCodes.Ldstr, narrow_error); generator.Builder.Emit(OpCodes.Callvirt, typeof(TaskMaster).GetMethod("ReportOtherError", new[] { typeof(SourceReference), typeof(string) })); generator.Builder.Emit(OpCodes.Ldc_I4_0); generator.Builder.Emit(OpCodes.Ret); return; } } var load_count = all_children.Sum(info => info.NeedsLoad(current) ? 1 : 0); if (load_count > 0) { generator.StartInterlock(load_count); lookup_results.AddRange(from info in all_children where info.NeedsLoad(current) select info.Load(generator, source_reference, context)); var state = generator.DefineState(); generator.SetState(state); generator.DecrementInterlock(generator.Builder); var end_label = generator.Builder.DefineLabel(); generator.Builder.Emit(OpCodes.Brfalse, end_label); generator.Builder.Emit(OpCodes.Ldc_I4_0); generator.Builder.Emit(OpCodes.Ret); generator.Builder.MarkLabel(end_label); generator.JumpToState(state); generator.MarkState(state); } foreach (var lookup_result in lookup_results.Where(x => x.DirectCopy)) { base_lookup_cache[lookup_result.NameInfo] = lookup_result.Value; } foreach (var lookup_result in lookup_results.Where(x => x.SinglyTyped && !x.DirectCopy)) { base_lookup_cache[lookup_result.NameInfo] = new AutoUnboxValue(lookup_result.Value, lookup_result.Types[0]); var label = generator.Builder.DefineLabel(); lookup_result.Value.Load(generator); generator.Builder.Emit(OpCodes.Isinst, lookup_result.Types[0]); generator.Builder.Emit(OpCodes.Brtrue, label); generator.EmitTypeError(source_reference, String.Format("Expected type {0} for “{1}”, but got {2}.", Stringish.NameForType(lookup_result.Types[0]), lookup_result.NameInfo.Name, "{0}"), lookup_result.Value); generator.Builder.MarkLabel(label); } var permutable_caches = lookup_results.Where(x => !x.SinglyTyped && !x.DirectCopy).ToArray(); var old_paths = generator.Paths; generator.Paths = permutable_caches.Aggregate(old_paths, (acc, c) => acc * c.Types.Length); if (generator.Paths > 200 && !combinatorial_explosion) { Console.Error.WriteLine("{0}:{1}:{2}-{3}:{4}: There are {5} type-derived flows in the generated code. This will be slow to compile.", FileName, StartRow, StartColumn, EndRow, EndColumn, generator.Paths); combinatorial_explosion = true; } GenerateLookupPermutation(generator, context, base_lookup_cache, 0, permutable_caches, source_reference, block); generator.Paths = old_paths; }
/** * Slot a computation for execution by the task master. */ public void Slot(LoadableValue target) { LoadTaskMaster(); target.Load(Builder); Builder.Emit(OpCodes.Callvirt, typeof(TaskMaster).GetMethod("Slot")); }