/lib/CodeGen.cs
C# | 4727 lines | 4240 code | 385 blank | 102 comment | 885 complexity | 2cb1760051616a05e216acc2c6e32958 MD5 | raw file
Possible License(s): AGPL-3.0
Large files files are truncated, but you can click here to view the full file
- // This is the new CLR backend. The old one generated C# from Perl, which
- // was slow and gave us the limitations of C#; this one aims to be faster.
- // Also, by making the Perl code emit a portable format, it makes future
- // portability work easier.
- using System;
- using System.Reflection;
- using System.Reflection.Emit;
- using System.Collections.Generic;
- using System.Collections;
- using System.Text;
- using System.IO;
- using Niecza;
- using Mono.Terminal;
- namespace Niecza.CLRBackend {
- // The portable format is a subset of JSON, and is currently read
- // into a matching internal form.
- static class JScalar {
- public static string[] SA(int cut, object x) {
- object[] arr = (object[]) x;
- string[] r = new string[ arr.Length - cut ];
- for (int i = 0; i < r.Length; i++)
- r[i] = S(arr[i+cut]);
- return r;
- }
- public static int[] IA(int cut, object x) {
- object[] arr = (object[]) x;
- int[] r = new int[ arr.Length - cut ];
- for (int i = 0; i < r.Length; i++)
- r[i] = I(arr[i+cut]);
- return r;
- }
- public static T[] A<T>(int cut, object x, Func<object, T> rdr) {
- object[] arr = (object[]) x;
- T[] r = new T[ arr.Length - cut ];
- for (int i = 0; i < r.Length; i++)
- r[i] = rdr(arr[i+cut]);
- return r;
- }
- public static bool B(object x) {
- string s = S(x);
- if (s == "1") return true;
- if (s == "0" || s == "") return false;
- throw new ArgumentException(s);
- }
- public static int I(object x) { return (int)N(x); }
- public static double N(object x) { return Utils.S2N((string)x); }
- public static int IN(object x) { return x == null ? -1 : (int)N(x); }
- public static string S(object x) { return x == null ? null : ((string)x); }
- }
- class Reader {
- static char GetHexQuad(char[] s, int ix) {
- int acc = 0;
- for (int i = 0; i < 4; i++) {
- acc <<= 4;
- int ch = (int)s[ix+i];
- acc += (ch>=(int)'a'&&ch<=(int)'f') ? (ch + 10 - (int)'a') :
- (ch>=(int)'A'&&ch<=(int)'F') ? (ch + 10 - (int)'A') :
- (ch - (int)'0');
- }
- return (char)acc;
- }
- public static object Read(string inputx, object[] refs) {
- char[] input = inputx.ToCharArray();
- int ilen = input.Length;
- int start, write;
- int ix = 0;
- List<List<object>> containers = new List<List<object>>();
- char i;
- while (true) {
- i = input[ix];
- if (i == '\t' || i == ' ' || i == '\r' || i == '\n' ||
- i == ',' || i == ':') {
- ix++;
- continue;
- }
- if (i == '[' || i == '{') {
- containers.Add(new List<object>());
- ix++;
- continue;
- }
- if (i == ']' || i == '}') {
- object[] r = containers[containers.Count - 1].ToArray();
- containers.RemoveAt(containers.Count - 1);
- if (containers.Count == 0) return r;
- containers[containers.Count - 1].Add(r);
- ix++;
- continue;
- }
- if (i == 'n' && ilen >= ix + 4 &&
- input[ix+1] == 'u' && input[ix+2] == 'l' &&
- input[ix+3] == 'l') {
- containers[containers.Count - 1].Add(null);
- ix += 4;
- continue;
- }
- if (i == '"') {
- ix++;
- start = ix;
- write = ix;
- while (true) {
- i = input[ix];
- if (i == '\\') {
- switch (input[ix+1]) {
- case '/': i = '/'; break;
- case '\\': i = '\\'; break;
- case '"': i = '"'; break;
- case 't': i = '\t'; break;
- case 'r': i = '\r'; break;
- case 'n': i = '\n'; break;
- case 'f': i = '\f'; break;
- case 'b': i = '\b'; break;
- case 'u': i = GetHexQuad(input, ix+2); ix += 4; break;
- }
- ix += 2;
- input[write++] = i;
- } else if (i == '"') {
- break;
- } else {
- input[write++] = i;
- ix++;
- }
- }
- ix++;
- containers[containers.Count - 1].Add(new string(input, start, write - start));
- continue;
- }
- start = ix;
- while (true) {
- i = input[ix];
- if (i == ',' || i == '\r' || i == '\t' || i == '\n' ||
- i == ' ' || i == ']' || i == '}')
- break;
- ix++;
- }
- if (input[start] == '!') {
- string str = new string(input, start+1, ix - start - 1);
- containers[containers.Count - 1].Add(refs[int.Parse(str)]);
- } else {
- containers[containers.Count - 1].Add(new string(input, start, ix - start));
- }
- }
- }
- }
- // Extra info needed beyond what ILGenerator alone provides. Note
- // that switch generation is done in another pass.
- class CgContext {
- public ILGenerator il;
- public TypeBuilder tb;
- public int next_case;
- public Label[] cases;
- public int num_cases;
- public Dictionary<string,int> named_cases
- = new Dictionary<string,int>();
- public Dictionary<string,Label> named_labels
- = new Dictionary<string,Label>();
- public string[] let_names = new string[0];
- public Type[] let_types = new Type[0];
- public LocalBuilder ospill, sspill, pspill, nspill;
- public List<int> lineStack = new List<int>();
- public List<int> lineBuffer = new List<int>();
- public List<int> ehspanBuffer = new List<int>();
- public List<string> ehlabelBuffer = new List<string>();
- public List<LocalBuilder> scratches = new List<LocalBuilder>();
- public void make_ospill() {
- if (ospill == null)
- ospill = il.DeclareLocal(Tokens.Variable);
- }
- public void make_sspill() {
- if (sspill == null)
- sspill = il.DeclareLocal(Tokens.Variable);
- }
- public void save_line() {
- lineBuffer.Add(lineStack.Count == 0 ? 0 : lineStack[lineStack.Count - 1]);
- }
- public void EmitDataArray(Type ty, int ct, byte[] vec) {
- EmitInt(ct);
- // the mono JIT checks for this exact sequence
- il.Emit(OpCodes.Newarr, ty);
- if (vec.Length != 0) {
- FieldBuilder fb = tb.DefineInitializedData(
- "A" + (EmitUnit.Current.nextid++), vec, 0);
- il.Emit(OpCodes.Dup);
- il.Emit(OpCodes.Ldtoken, fb);
- il.Emit(OpCodes.Call, typeof(System.Runtime.CompilerServices.RuntimeHelpers).GetMethod("InitializeArray"));
- }
- }
- // logic stolen from mcs
- public void EmitInt(int i) {
- switch (i) {
- case -1: il.Emit(OpCodes.Ldc_I4_M1); break;
- case 0: il.Emit(OpCodes.Ldc_I4_0); break;
- case 1: il.Emit(OpCodes.Ldc_I4_1); break;
- case 2: il.Emit(OpCodes.Ldc_I4_2); break;
- case 3: il.Emit(OpCodes.Ldc_I4_3); break;
- case 4: il.Emit(OpCodes.Ldc_I4_4); break;
- case 5: il.Emit(OpCodes.Ldc_I4_5); break;
- case 6: il.Emit(OpCodes.Ldc_I4_6); break;
- case 7: il.Emit(OpCodes.Ldc_I4_7); break;
- case 8: il.Emit(OpCodes.Ldc_I4_8); break;
- default:
- if (i >= -128 && i < 127) {
- il.Emit(OpCodes.Ldc_I4_S, (sbyte) i);
- } else {
- il.Emit(OpCodes.Ldc_I4, i);
- }
- break;
- }
- }
- /* this too */
- public void EmitLong(long l) {
- if (l >= int.MinValue && l <= int.MaxValue) {
- EmitInt((int)l);
- il.Emit(OpCodes.Conv_I8);
- } else if (l >= 0 && l <= uint.MaxValue) {
- EmitInt((int)l);
- il.Emit(OpCodes.Conv_U8);
- } else {
- il.Emit(OpCodes.Ldc_I8, l);
- }
- }
- public void EmitPreSetlex(int ix) {
- if (ix >= (Tokens.NumInt32 + Tokens.NumInline)) {
- il.Emit(OpCodes.Ldfld, Tokens.Frame_lexn);
- EmitInt(ix - (Tokens.NumInt32 + Tokens.NumInline));
- }
- }
- public void EmitSetlex(int ix, Type t) {
- if (ix >= Tokens.NumInt32 && t.IsValueType)
- il.Emit(OpCodes.Box, t);
- if (ix >= (Tokens.NumInt32 + Tokens.NumInline)) {
- il.Emit(OpCodes.Stelem_Ref);
- } else if (ix >= Tokens.NumInt32) {
- il.Emit(OpCodes.Stfld,
- Tokens.Frame_lexobj[ix - Tokens.NumInt32]);
- } else {
- il.Emit(OpCodes.Stfld, Tokens.Frame_lexi32[ix]);
- }
- }
- public void EmitGetlex(int ix, Type t) {
- if (ix >= (Tokens.NumInt32 + Tokens.NumInline)) {
- il.Emit(OpCodes.Ldfld, Tokens.Frame_lexn);
- EmitInt(ix - (Tokens.NumInt32 + Tokens.NumInline));
- il.Emit(OpCodes.Ldelem_Ref);
- } else if (ix >= Tokens.NumInt32) {
- il.Emit(OpCodes.Ldfld,
- Tokens.Frame_lexobj[ix - Tokens.NumInt32]);
- } else {
- il.Emit(OpCodes.Ldfld, Tokens.Frame_lexi32[ix]);
- }
- if (ix >= Tokens.NumInt32 &&
- (Config.CGVerifiable || t.IsValueType)) {
- il.Emit(OpCodes.Unbox_Any, t);
- }
- }
- }
- sealed class Tokens {
- public static readonly Type Void = typeof(void);
- public static readonly Type String = typeof(string);
- public static readonly Type Boolean = typeof(bool);
- public static readonly Type Int16 = typeof(short);
- public static readonly Type Int32 = typeof(int);
- public static readonly Type Int64 = typeof(long);
- public static readonly Type UInt32 = typeof(uint);
- public static readonly Type UInt64 = typeof(ulong);
- public static readonly Type IntPtr = typeof(IntPtr);
- public static readonly Type Double = typeof(double);
- public static readonly Type Frame = typeof(Frame);
- public static readonly Type Kernel = typeof(Kernel);
- public static readonly Type Builtins = typeof(Builtins);
- public static readonly Type SubInfo = typeof(SubInfo);
- public static readonly Type P6any = typeof(P6any);
- public static readonly Type Variable = typeof(Variable);
- public static readonly Type P6opaque = typeof(P6opaque);
- public static readonly Type DynBlockDelegate = typeof(DynBlockDelegate);
- public static readonly Type STable = typeof(STable);
- public static readonly Type VarHash = typeof(VarHash);
- public static readonly Type VVarList = typeof(VarDeque);
- public static readonly Type FVarList = typeof(Variable[]);
- public static readonly Type Cursor = typeof(Cursor);
- public static readonly Type RxFrame = typeof(RxFrame);
- public static readonly Type CC = typeof(CC);
- public static readonly Type LAD = typeof(LAD);
- public static readonly Type RuntimeUnit = typeof(RuntimeUnit);
- public static readonly Type StashCursor = typeof(StashCursor);
- public static readonly ConstructorInfo SubInfo_ctor =
- SubInfo.GetConstructor(new Type[] {
- String, typeof(int[]), typeof(DynBlockDelegate),
- SubInfo, LAD, typeof(int[]), typeof(string[]),
- Int32, typeof(string[]), typeof(int[]) });
- public static readonly ConstructorInfo DynBlockDelegate_ctor =
- typeof(DynBlockDelegate).GetConstructor(new Type[] {
- typeof(object), typeof(IntPtr) });
- public static readonly ConstructorInfo P6opaque_ctor =
- typeof(P6opaque).GetConstructor(new Type[] {
- STable });
- public static readonly ConstructorInfo DMO_ctor =
- STable.GetConstructor(new Type[] { String });
- public static readonly ConstructorInfo RxFrame_ctor =
- RxFrame.GetConstructor(new Type[] { String, Cursor, Boolean });
- public static readonly ConstructorInfo SV_ctor =
- typeof(RWVariable).GetConstructor(new Type[] {
- STable, typeof(ViviHook), P6any });
- public static readonly ConstructorInfo SubViviHook_ctor =
- typeof(SubViviHook).GetConstructor(new Type[] { P6any });
- public static readonly ConstructorInfo Rat_ctor =
- typeof(Rat).GetConstructor(new Type[] { typeof(BigInteger), typeof(ulong) });
- public static readonly ConstructorInfo BigInteger_ctor =
- typeof(BigInteger).GetConstructor(new Type[] { typeof(short), typeof(uint[]) });
- public static readonly ConstructorInfo CC_ctor =
- CC.GetConstructor(new Type[] { typeof(int[]) });
- public static readonly ConstructorInfo SC_ctor =
- StashCursor.GetConstructor(new Type[] { typeof(Frame), typeof(int) });
- public static readonly MethodInfo P6any_InvokeMethod =
- P6any.GetMethod("InvokeMethod");
- public static readonly MethodInfo P6any_Invoke =
- P6any.GetMethod("Invoke");
- public static readonly MethodInfo P6any_SetSlot =
- P6any.GetMethod("SetSlot", new Type[] { STable, String, typeof(object) });
- public static readonly MethodInfo P6any_GetSlot =
- P6any.GetMethod("GetSlot", new Type[] { STable, String });
- public static readonly MethodInfo SubInfo_AddHint =
- SubInfo.GetMethod("AddHint");
- public static readonly MethodInfo Variable_Fetch =
- Variable.GetMethod("Fetch");
- public static readonly MethodInfo VVarList_Item =
- VVarList.GetMethod("get_Item");
- public static readonly MethodInfo VarHash_Remove =
- VarHash.GetMethod("Remove");
- public static readonly MethodInfo VarHash_get_Item =
- VarHash.GetMethod("get_Item");
- public static readonly MethodInfo VarHash_set_Item =
- VarHash.GetMethod("set_Item");
- public static readonly MethodInfo Kernel_MakeSub =
- typeof(Kernel).GetMethod("MakeSub");
- public static readonly MethodInfo Kernel_CheckUnsafe =
- typeof(Kernel).GetMethod("CheckUnsafe");
- public static readonly MethodInfo Kernel_NewLabelVar =
- typeof(Kernel).GetMethod("NewLabelVar");
- public static readonly MethodInfo Kernel_MakeDispatcher =
- typeof(Kernel).GetMethod("MakeDispatcherF");
- public static readonly MethodInfo Kernel_Die =
- typeof(Kernel).GetMethod("Die");
- public static readonly MethodInfo Kernel_SFH =
- typeof(Kernel).GetMethod("SearchForHandler");
- public static readonly MethodInfo Kernel_BootModule =
- typeof(Kernel).GetMethod("BootModule");
- public static readonly MethodInfo Kernel_GetGlobal =
- typeof(Kernel).GetMethod("GetGlobal");
- public static readonly MethodInfo Kernel_BindGlobal =
- typeof(Kernel).GetMethod("BindGlobal");
- public static readonly MethodInfo Kernel_NewRWListVar =
- typeof(Kernel).GetMethod("NewRWListVar");
- public static readonly MethodInfo Kernel_NewRWScalar =
- typeof(Kernel).GetMethod("NewRWScalar");
- public static readonly MethodInfo Kernel_NewTypedScalar =
- typeof(Kernel).GetMethod("NewTypedScalar");
- public static readonly MethodInfo Kernel_NewMuAnyScalar =
- typeof(Kernel).GetMethod("NewMuAnyScalar");
- public static readonly MethodInfo Kernel_Assign =
- typeof(Kernel).GetMethod("Assign");
- public static readonly MethodInfo Kernel_CreateArray =
- typeof(Kernel).GetMethod("CreateArray");
- public static readonly MethodInfo Kernel_CreateHash =
- typeof(Kernel).GetMethod("CreateHash");
- public static readonly MethodInfo Kernel_GetVar =
- typeof(Kernel).GetMethod("GetVar");
- public static readonly MethodInfo Kernel_Decontainerize =
- typeof(Kernel).GetMethod("Decontainerize");
- public static readonly MethodInfo Kernel_NewBoundVar =
- typeof(Kernel).GetMethod("NewBoundVar");
- public static readonly MethodInfo Kernel_IterHasFlat =
- typeof(Kernel).GetMethod("IterHasFlat");
- public static readonly MethodInfo Kernel_ContextHelper =
- typeof(Kernel).GetMethod("ContextHelper");
- public static readonly MethodInfo Kernel_StatusHelper =
- typeof(Kernel).GetMethod("StatusHelper");
- public static readonly MethodInfo Kernel_SetStatus =
- typeof(Kernel).GetMethod("SetStatus");
- public static readonly MethodInfo Kernel_SortHelper =
- typeof(Kernel).GetMethod("SortHelper");
- public static readonly MethodInfo Kernel_AddPhaser =
- typeof(Kernel).GetMethod("AddPhaser");
- public static readonly MethodInfo Kernel_FirePhasers =
- typeof(Kernel).GetMethod("FirePhasers");
- public static readonly MethodInfo Kernel_BoxAnyMO_Int32 =
- typeof(Kernel).GetMethod("BoxAnyMO").MakeGenericMethod(typeof(int));
- public static readonly MethodInfo Kernel_BoxAnyMO_Double =
- typeof(Kernel).GetMethod("BoxAnyMO").MakeGenericMethod(typeof(double));
- public static readonly MethodInfo Kernel_BoxAnyMO_Rat =
- typeof(Kernel).GetMethod("BoxAnyMO").MakeGenericMethod(typeof(Rat));
- public static readonly MethodInfo Kernel_BoxAnyMO_BigInteger =
- typeof(Kernel).GetMethod("BoxAnyMO").MakeGenericMethod(typeof(BigInteger));
- public static readonly MethodInfo Builtins_Make =
- typeof(Builtins).GetMethod("Make");
- public static readonly MethodInfo Builtins_MEMap =
- typeof(Builtins).GetMethod("MEMap");
- public static readonly MethodInfo Builtins_MEGrep =
- typeof(Builtins).GetMethod("MEGrep");
- public static readonly MethodInfo DMO_AddMethod =
- typeof(STable).GetMethod("AddMethod");
- public static readonly MethodInfo DMO_AddAttribute =
- typeof(STable).GetMethod("AddAttribute");
- public static readonly MethodInfo DMO_Invalidate =
- typeof(STable).GetMethod("Invalidate");
- public static readonly MethodInfo DMO_FillParametricRole =
- typeof(STable).GetMethod("FillParametricRole");
- public static readonly MethodInfo DMO_FillRole =
- typeof(STable).GetMethod("FillRole");
- public static readonly MethodInfo RxFrame_PushBacktrack =
- typeof(RxFrame).GetMethod("PushBacktrack");
- public static readonly MethodInfo RxFrame_PushCapture =
- typeof(RxFrame).GetMethod("PushCapture");
- public static readonly MethodInfo Console_WriteLine =
- typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) });
- public static readonly MethodInfo Console_Write =
- typeof(Console).GetMethod("Write", new Type[] { typeof(string) });
- public static readonly MethodInfo Environment_Exit =
- typeof(Environment).GetMethod("Exit");
- public static readonly MethodInfo StringBuilder_Append_String =
- typeof(StringBuilder).GetMethod("Append", new Type[] { String });
- public static readonly MethodInfo TW_WriteLine =
- typeof(TextWriter).GetMethod("WriteLine", new Type[] { String });
- public static readonly MethodInfo Console_get_Error =
- typeof(Console).GetMethod("get_Error");
- public static readonly MethodInfo Object_ToString =
- typeof(object).GetMethod("ToString", new Type[0]);
- public static readonly MethodInfo RU_LoadStrArray =
- RuntimeUnit.GetMethod("LoadStrArray");
- public static readonly MethodInfo RU_LoadPackage =
- RuntimeUnit.GetMethod("LoadPackage");
- public static readonly MethodInfo RU_LoadClassMembers =
- RuntimeUnit.GetMethod("LoadClassMembers");
- public static readonly MethodInfo RU_LoadSubInfo =
- RuntimeUnit.GetMethod("LoadSubInfo");
- public static readonly MethodInfo RU_LoadSignature =
- RuntimeUnit.GetMethod("LoadSignature");
- public static readonly MethodInfo RU_LoadLAD =
- RuntimeUnit.GetMethod("LoadLAD");
- public static readonly MethodInfo RU_LoadLADArr =
- RuntimeUnit.GetMethod("LoadLADArr");
- public static readonly MethodInfo Frame_Return =
- Frame.GetMethod("Return");
- public static readonly MethodInfo Frame_Binder =
- Frame.GetMethod("Binder");
- public static readonly FieldInfo P6any_mo =
- P6any.GetField("mo");
- public static readonly FieldInfo StashEnt_v =
- typeof(StashEnt).GetField("v");
- public static readonly FieldInfo SubInfo_protosub =
- SubInfo.GetField("protosub");
- public static readonly FieldInfo SubInfo_protopad =
- SubInfo.GetField("protopad");
- public static readonly FieldInfo SubInfo_mo =
- SubInfo.GetField("mo");
- public static readonly FieldInfo P6opaque_slots =
- P6opaque.GetField("slots");
- public static readonly FieldInfo DMO_typeObj =
- STable.GetField("typeObj");
- public static readonly FieldInfo DMO_initObj =
- STable.GetField("initObj");
- public static readonly FieldInfo DMO_how =
- STable.GetField("how");
- public static readonly FieldInfo Frame_rx =
- typeof(Frame).GetField("rx");
- public static readonly FieldInfo Frame_ip =
- typeof(Frame).GetField("ip");
- public static readonly FieldInfo Frame_caller =
- typeof(Frame).GetField("caller");
- public static readonly FieldInfo Frame_outer =
- typeof(Frame).GetField("outer");
- public static readonly FieldInfo Frame_resultSlot =
- typeof(Frame).GetField("resultSlot");
- public static readonly FieldInfo Frame_lexn =
- typeof(Frame).GetField("lexn");
- [Immutable]
- public static readonly FieldInfo[] Frame_lexi32 = new FieldInfo[] {
- typeof(Frame).GetField("lexi0"),
- typeof(Frame).GetField("lexi1")
- };
- [Immutable]
- public static readonly FieldInfo[] Frame_lexobj = new FieldInfo[] {
- typeof(Frame).GetField("lex0"),
- typeof(Frame).GetField("lex1"),
- typeof(Frame).GetField("lex2"),
- typeof(Frame).GetField("lex3"),
- typeof(Frame).GetField("lex4"),
- typeof(Frame).GetField("lex5"),
- typeof(Frame).GetField("lex6"),
- typeof(Frame).GetField("lex7"),
- typeof(Frame).GetField("lex8"),
- typeof(Frame).GetField("lex9")
- };
- public static readonly FieldInfo RU_xref = RuntimeUnit.GetField("xref");
- public const int NumInt32 = 2;
- public const int NumInline = 10;
- // other random stuff
- public static readonly ClrOp[] EmptyClrOp = new ClrOp[0];
- }
- // This are expressional CLR operators. This is lower level than the
- // CPS stuff; if HasCases is true, Returns must be void. Thus,
- // there is no need to handle argument spills.
- abstract class ClrOp {
- public bool HasCases;
- public bool Constant; // if this returns a value, can it be reordered?
- public Type Returns;
- public abstract void CodeGen(CgContext cx);
- public virtual void ListCases(CgContext cx) { }
- public virtual ClrOp Sink() {
- throw (Returns == Tokens.Void)
- ? (Exception)new ArgumentException()
- : new NotImplementedException();
- }
- protected static void TypeCheck(Type sub, Type super) {
- if (!super.IsAssignableFrom(sub))
- throw new Exception(sub + " not subtype of " + super);
- }
- protected static void TypeCheck(Type sub, Type super, object c) {
- if (!super.IsAssignableFrom(sub))
- throw new Exception(sub + " not subtype of " + super + ": " + c);
- }
- }
- // NOT FOR GENERAL USE: only in implementing Sink for Clr*** with
- // irreducable operations
- class ClrSink : ClrOp {
- public readonly ClrOp zyg;
- public override void ListCases(CgContext cx) {
- zyg.ListCases(cx);
- }
- public override void CodeGen(CgContext cx) {
- zyg.CodeGen(cx);
- cx.il.Emit(OpCodes.Pop);
- }
- public ClrSink(ClrOp zyg) {
- if (zyg.Returns == Tokens.Void)
- throw new ArgumentException();
- this.zyg = zyg;
- Returns = Tokens.Void;
- }
- }
- class ClrMethodCall : ClrOp {
- public readonly MethodInfo Method;
- public readonly ClrOp[] Zyg;
- public override ClrOp Sink() {
- return new ClrSink(this);
- }
- public override void CodeGen(CgContext cx) {
- if (HasCases) {
- cx.il.Emit(OpCodes.Ldarg_1);
- cx.EmitInt(cx.next_case);
- cx.il.Emit(OpCodes.Stfld, Tokens.Frame_ip);
- }
- int scratch_ix = -1;
- LocalBuilder scratch_lb = null;
- int i = 0;
- if (!Method.IsStatic) {
- ClrOp o = Zyg[i++];
- o.CodeGen(cx);
- if (o.Returns.IsValueType) {
- if (Method.DeclaringType == o.Returns) {
- scratch_ix = 0;
- while (scratch_ix < cx.scratches.Count &&
- cx.scratches[scratch_ix].LocalType != o.Returns)
- scratch_ix++;
- if (scratch_ix == cx.scratches.Count)
- cx.scratches.Add(cx.il.DeclareLocal(o.Returns));
- scratch_lb = cx.scratches[scratch_ix];
- cx.scratches[scratch_ix] = null;
- cx.il.Emit(OpCodes.Stloc, scratch_lb);
- cx.il.Emit(OpCodes.Ldloca, scratch_lb);
- }
- else
- cx.il.Emit(OpCodes.Box, o.Returns);
- }
- }
- // this needs to come AFTER the invocant
- if (HasCases)
- cx.il.Emit(OpCodes.Ldarg_1);
- for (; i < Zyg.Length; i++) {
- Zyg[i].CodeGen(cx);
- }
- cx.il.Emit(((Method.IsStatic || !Method.IsVirtual) ?
- OpCodes.Call : OpCodes.Callvirt), Method);
- if (HasCases) {
- cx.il.Emit(OpCodes.Ret);
- cx.il.MarkLabel(cx.cases[cx.next_case++]);
- cx.save_line();
- }
- if (scratch_ix >= 0)
- cx.scratches[scratch_ix] = scratch_lb;
- }
- public override void ListCases(CgContext cx) {
- // it is not legal for any of out children to have cases to list
- if (HasCases)
- cx.num_cases++;
- }
- public ClrMethodCall(bool cps, MethodInfo mi, params ClrOp[] zyg) {
- Method = mi;
- Zyg = zyg;
- Returns = cps ? Tokens.Void : mi.ReturnType;
- HasCases = cps;
- List<Type> ts = new List<Type>();
- if (!mi.IsStatic)
- ts.Add(mi.DeclaringType);
- if (cps && mi.GetParameters()[0].ParameterType != Tokens.Frame)
- throw new ArgumentException("CPS method not taking a frame");
- if (cps && mi.ReturnType != Tokens.Frame)
- throw new ArgumentException("CPS method not returning a frame");
- bool skip = cps;
- foreach (ParameterInfo pi in mi.GetParameters()) {
- if (skip) { skip = false; continue; }
- ts.Add(pi.ParameterType);
- }
- if (zyg.Length != ts.Count)
- throw new Exception("argument list length mismatch for " + mi +
- " got " + zyg.Length + " need " + ts.Count);
- for (int i = 0; i < ts.Count; i++) {
- TypeCheck(zyg[i].Returns, ts[i], mi);
- }
- }
- }
- class ClrConstructorCall : ClrOp {
- public readonly ConstructorInfo Method;
- public readonly ClrOp[] Zyg;
- public override ClrOp Sink() {
- return new ClrSink(this);
- }
- public override void CodeGen(CgContext cx) {
- foreach (ClrOp o in Zyg) {
- o.CodeGen(cx);
- }
- cx.il.Emit(OpCodes.Newobj, Method);
- }
- public ClrConstructorCall(ConstructorInfo mi, ClrOp[] zyg) {
- Method = mi;
- Zyg = zyg;
- Returns = mi.DeclaringType;
- List<Type> ts = new List<Type>();
- foreach (ParameterInfo pi in mi.GetParameters()) {
- ts.Add(pi.ParameterType);
- }
- if (zyg.Length != ts.Count)
- throw new Exception("argument list length mismatch");
- for (int i = 0; i < ts.Count; i++) {
- TypeCheck(zyg[i].Returns, ts[i], mi);
- }
- }
- }
- class ClrContexty : ClrOp {
- public readonly ClrOp[] zyg;
- public readonly MethodInfo inv;
- public readonly FieldInfo thing;
- // This could be avoided in some cases, but probably +$customobj;
- // shouldn't be optimized out
- public override ClrOp Sink() {
- return new ClrSink(this);
- }
- public override void CodeGen(CgContext cx) {
- zyg[0].CodeGen(cx);
- cx.make_ospill();
- cx.il.Emit(OpCodes.Dup);
- cx.il.Emit(OpCodes.Stloc, cx.ospill);
- cx.il.Emit(OpCodes.Callvirt, Tokens.Variable_Fetch);
- cx.il.Emit(OpCodes.Ldfld, Tokens.P6any_mo);
- cx.il.Emit(OpCodes.Ldfld, thing);
- cx.il.Emit(OpCodes.Ldloc, cx.ospill);
- for (int i = 1; i < zyg.Length; i++)
- zyg[i].CodeGen(cx);
- cx.il.Emit(OpCodes.Callvirt, inv);
- }
- public ClrContexty(FieldInfo thing, MethodInfo inv, ClrOp[] zyg) {
- this.thing = thing;
- this.inv = inv;
- this.zyg = zyg;
- Returns = inv.ReturnType;
- }
- }
- class ClrOperator : ClrOp {
- public readonly OpCode op;
- public readonly ClrOp[] zyg;
- public override ClrOp Sink() {
- ClrOp[] szyg = new ClrOp[zyg.Length];
- for (int i = 0; i < szyg.Length; i++)
- szyg[i] = zyg[i].Sink();
- return new ClrSeq(szyg);
- }
- public override void CodeGen(CgContext cx) {
- foreach (ClrOp c in zyg)
- c.CodeGen(cx);
- cx.il.Emit(op);
- }
- public ClrOperator(Type ret, OpCode op, ClrOp[] zyg) {
- Returns = ret;
- this.op = op;
- this.zyg = zyg;
- }
- }
- class ClrCompare : ClrOp {
- public readonly string op;
- public readonly ClrOp[] zyg;
- public override ClrOp Sink() {
- ClrOp[] szyg = new ClrOp[zyg.Length];
- for (int i = 0; i < szyg.Length; i++)
- szyg[i] = zyg[i].Sink();
- return new ClrSeq(szyg);
- }
- public override void CodeGen(CgContext cx) {
- foreach (ClrOp c in zyg)
- c.CodeGen(cx);
- bool flt = zyg[0].Returns == Tokens.Double;
- OpCode ilop;
- bool not = false;
- if (op == "<") { ilop = OpCodes.Clt; }
- else if (op == ">") { ilop = OpCodes.Cgt; }
- else if (op == ">=") {
- ilop = flt ? OpCodes.Clt_Un : OpCodes.Clt;
- not = true;
- }
- else if (op == "<=") {
- ilop = flt ? OpCodes.Cgt_Un : OpCodes.Cgt;
- not = true;
- }
- else if (op == "==") { ilop = OpCodes.Ceq; }
- else if (op == "!=") { ilop = OpCodes.Ceq; not = true; }
- else throw new ArgumentException(op + " as polyop");
- cx.il.Emit(ilop);
- if (not) {
- cx.il.Emit(OpCodes.Ldc_I4_0);
- cx.il.Emit(OpCodes.Ceq);
- }
- }
- public ClrCompare(string op, ClrOp[] zyg) {
- Returns = Tokens.Boolean;
- this.op = op;
- this.zyg = zyg;
- }
- }
- class ClrGetField : ClrOp {
- public readonly FieldInfo f;
- public readonly ClrOp zyg;
- // Not strictly right, but Perl 6 code never sees CLR nulls, and
- // this is a major win for some cases
- public override ClrOp Sink() {
- return zyg.Sink();
- }
- public override void CodeGen(CgContext cx) {
- zyg.CodeGen(cx);
- cx.il.Emit(OpCodes.Ldfld, f);
- }
- public ClrGetField(FieldInfo f, ClrOp zyg) {
- TypeCheck(zyg.Returns, f.DeclaringType);
- Returns = f.FieldType;
- this.f = f;
- this.zyg = zyg;
- }
- }
- class ClrSetField : ClrOp {
- public readonly FieldInfo f;
- public readonly ClrOp zyg1;
- public readonly ClrOp zyg2;
- public override void CodeGen(CgContext cx) {
- zyg1.CodeGen(cx);
- zyg2.CodeGen(cx);
- cx.il.Emit(OpCodes.Stfld, f);
- }
- public ClrSetField(FieldInfo f, ClrOp zyg1, ClrOp zyg2) {
- TypeCheck(zyg1.Returns, f.DeclaringType);
- TypeCheck(zyg2.Returns, f.FieldType);
- Returns = Tokens.Void;
- this.f = f;
- this.zyg1 = zyg1;
- this.zyg2 = zyg2;
- }
- }
- class ClrGetConst : ClrOp {
- public readonly FieldInfo f;
- public override ClrOp Sink() { return ClrNoop.Instance; }
- public override void CodeGen(CgContext cx) {
- cx.il.Emit(OpCodes.Ldarg_0);
- cx.il.Emit(OpCodes.Ldfld, f);
- }
- public ClrGetConst(FieldInfo f) {
- Returns = f.FieldType;
- this.f = f;
- }
- }
- class ClrPadGet : ClrOp {
- public readonly int up;
- public readonly int index;
- public override ClrOp Sink() { return ClrNoop.Instance; }
- public override void CodeGen(CgContext cx) {
- cx.il.Emit(OpCodes.Ldarg_1);
- for (int i = 0; i < up; i++)
- cx.il.Emit(OpCodes.Ldfld, Tokens.Frame_outer);
- cx.EmitGetlex(index + Tokens.NumInt32, Tokens.Variable);
- }
- public ClrPadGet(int up, int index) {
- Returns = Tokens.Variable;
- this.up = up;
- this.index = index;
- }
- }
- class ClrPadSet : ClrOp {
- public readonly int up;
- public readonly int index;
- public readonly ClrOp zyg;
- public override void CodeGen(CgContext cx) {
- cx.il.Emit(OpCodes.Ldarg_1);
- for (int i = 0; i < up; i++)
- cx.il.Emit(OpCodes.Ldfld, Tokens.Frame_outer);
- cx.EmitPreSetlex(index + Tokens.NumInt32);
- zyg.CodeGen(cx);
- cx.EmitSetlex(index + Tokens.NumInt32, Tokens.Variable);
- }
- public ClrPadSet(int up, int index, ClrOp zyg) {
- Returns = Tokens.Void;
- this.zyg = zyg;
- this.up = up;
- this.index = index;
- }
- }
- class ClrProtoSet : ClrOp {
- public readonly int ix;
- public readonly ClrOp zyg1;
- public readonly ClrOp zyg2;
- public override void CodeGen(CgContext cx) {
- zyg1.CodeGen(cx);
- cx.EmitPreSetlex(ix + Tokens.NumInt32);
- zyg2.CodeGen(cx);
- cx.EmitSetlex(ix + Tokens.NumInt32, Tokens.Variable);
- }
- public ClrProtoSet(int ix, ClrOp zyg1, ClrOp zyg2) {
- TypeCheck(zyg1.Returns, Tokens.Frame);
- Returns = Tokens.Void;
- this.ix = ix;
- this.zyg1 = zyg1;
- this.zyg2 = zyg2;
- }
- }
- class ClrProtoGet : ClrOp {
- public readonly int ix;
- public readonly ClrOp zyg;
- public override ClrOp Sink() { return ClrNoop.Instance; }
- public override void CodeGen(CgContext cx) {
- zyg.CodeGen(cx);
- cx.EmitGetlex(ix + Tokens.NumInt32, Tokens.Variable);
- }
- public ClrProtoGet(int ix, ClrOp zyg) {
- TypeCheck(zyg.Returns, Tokens.Frame);
- Returns = Tokens.Variable;
- this.ix = ix;
- this.zyg = zyg;
- }
- }
- class ClrMarkConstant : ClrOp {
- readonly ClrOp real;
- public ClrMarkConstant(ClrOp real) {
- this.real = real;
- Returns = real.Returns;
- HasCases = false;
- Constant = true;
- }
- // no side effects, huh?
- public override ClrOp Sink() {
- return ClrNoop.Instance;
- }
- public override void CodeGen(CgContext cx) {
- real.CodeGen(cx);
- }
- }
- class ClrNoop : ClrOp {
- private ClrNoop() {
- Returns = Tokens.Void;
- HasCases = false;
- }
- public override void CodeGen(CgContext cx) { }
- [Immutable] public static ClrNoop Instance = new ClrNoop();
- }
- class ClrEhSpan : ClrOp {
- public readonly int kls;
- public readonly string tag;
- public readonly string ls;
- public readonly string le;
- public readonly int ng;
- public readonly string lg;
- public ClrEhSpan(int kls, string tag, string ls, string le, string lg) {
- Returns = Tokens.Void;
- HasCases = false;
- this.kls = kls; this.tag = tag; this.ls = ls; this.le = le;
- this.lg = lg;
- }
- public ClrEhSpan(int kls, string tag, string ls, string le, int ng) {
- Returns = Tokens.Void;
- HasCases = false;
- this.kls = kls; this.tag = tag; this.ls = ls; this.le = le;
- this.ng = ng;
- }
- public override void CodeGen(CgContext cx) {
- int lidn = -1;
- if (tag != "") {
- for (lidn = 0; lidn < cx.ehlabelBuffer.Count &&
- cx.ehlabelBuffer[lidn] != tag; lidn++);
- if (lidn == cx.ehlabelBuffer.Count)
- cx.ehlabelBuffer.Add(tag);
- }
- cx.ehspanBuffer.Add(cx.named_cases[ls]);
- cx.ehspanBuffer.Add(cx.named_cases[le]);
- cx.ehspanBuffer.Add(kls);
- if (lg == null) {
- cx.ehspanBuffer.Add(ng);
- } else if (kls == SubInfo.ON_VARLOOKUP) {
- int ix = cx.let_names.Length - 1;
- while (ix >= 0 && cx.let_names[ix] != lg)
- ix--;
- if (ix < Tokens.NumInt32)
- throw new Exception("variable in index area??");
- cx.ehspanBuffer.Add(ix - Tokens.NumInt32);
- } else {
- cx.ehspanBuffer.Add(cx.named_cases[lg]);
- }
- cx.ehspanBuffer.Add(lidn);
- }
- }
- class ClrPushLine : ClrOp {
- public readonly int line;
- public ClrPushLine(int line) {
- this.line = line;
- Returns = Tokens.Void;
- HasCases = false;
- }
- public override void CodeGen(CgContext cx) {
- cx.lineStack.Add(line);
- }
- }
- class ClrPopLine : ClrOp {
- public ClrPopLine() {
- Returns = Tokens.Void;
- HasCases = false;
- }
- public override void CodeGen(CgContext cx) {
- cx.lineStack.RemoveAt(cx.lineStack.Count - 1);
- }
- }
- class ClrSync : ClrOp {
- private ClrSync() {
- Returns = Tokens.Void;
- HasCases = true;
- }
- public override void ListCases(CgContext cx) { cx.num_cases++; }
- public override void CodeGen(CgContext cx) {
- cx.il.Emit(OpCodes.Ldarg_1);
- cx.EmitInt(cx.next_case);
- cx.il.Emit(OpCodes.Stfld, Tokens.Frame_ip);
- cx.il.MarkLabel(cx.cases[cx.next_case++]);
- cx.save_line();
- }
- [Immutable] public static ClrSync Instance = new ClrSync();
- }
- // only used in ClrOperator.Sink, and assumes it in the HasCases=false
- class ClrSeq : ClrOp {
- readonly ClrOp[] zyg;
- public ClrSeq(ClrOp[] zyg) {
- Returns = Tokens.Void;
- HasCases = false;
- this.zyg = zyg;
- }
- public override void CodeGen(CgContext cx) {
- foreach(ClrOp z in zyg)
- z.CodeGen(cx);
- }
- }
- class ClrSubyCall : ClrOp {
- public readonly bool ismethod;
- public readonly string sig;
- public readonly ClrOp[] zyg;
- // generates the argument list, from the elements of zyg
- void GenArgList(int min, CgContext cx) {
- bool general = false;
- for (int i = min; i < zyg.Length; i++)
- if (sig[i - min] != '\0')
- general = true;
- if (!general) {
- cx.EmitInt(zyg.Length - min + (ismethod ? 1 : 0));
- cx.il.Emit(OpCodes.Newarr, Tokens.Variable);
- if (ismethod) {
- cx.il.Emit(OpCodes.Dup);
- cx.EmitInt(0);
- cx.il.Emit(OpCodes.Ldloc, cx.sspill);
- cx.il.Emit(OpCodes.Stelem_Ref);
- }
- for (int i = min; i < zyg.Length; i++) {
- cx.il.Emit(OpCodes.Dup);
- cx.EmitInt(i - min + (ismethod ? 1 : 0));
- zyg[i].CodeGen(cx);
- cx.il.Emit(OpCodes.Stelem_Ref);
- }
- cx.il.Emit(OpCodes.Ldnull);
- } else {
- if (cx.pspill == null) cx.pspill = cx.il.DeclareLocal(typeof(List<Variable>));
- if (cx.nspill == null) cx.nspill = cx.il.DeclareLocal(Tokens.VarHash);
- cx.il.Emit(OpCodes.Newobj, typeof(List<Variable>).GetConstructor(new Type[0]));
- cx.il.Emit(OpCodes.Stloc, cx.pspill);
- cx.il.Emit(OpCodes.Newobj, Tokens.VarHash.GetConstructor(new Type[0]));
- cx.il.Emit(OpCodes.Stloc, cx.nspill);
- if (ismethod) {
- cx.il.Emit(OpCodes.Ldloc, cx.pspill);
- cx.il.Emit(OpCodes.Ldloc, cx.sspill);
- cx.il.Emit(OpCodes.Call, typeof(List<Variable>).GetMethod("Add"));
- }
- int csr = 0;
- int ix = min;
- while (csr != sig.Length) {
- int len = (int)sig[csr];
- string tok = sig.Substring(csr+1, len);
- csr += (len + 1);
- if (tok == "") {
- cx.il.Emit(OpCodes.Ldloc, cx.pspill);
- zyg[ix++].CodeGen(cx);
- cx.il.Emit(OpCodes.Call, typeof(List<Variable>).GetMethod("Add"));
- } else if (tok == "flatcap") {
- cx.il.Emit(OpCodes.Ldloc, cx.pspill);
- cx.il.Emit(OpCodes.Ldloc, cx.nspill);
- zyg[ix++].CodeGen(cx);
- cx.il.Emit(OpCodes.Call, Tokens.Kernel.GetMethod("AddCap"));
- } else if (tok[0] == ':') {
- cx.il.Emit(OpCodes.Ldloc, cx.nspill);
- cx.il.Emit(OpCodes.Ldstr, tok.Substring(1));
- zyg[ix++].CodeGen(cx);
- cx.il.Emit(OpCodes.Call, Tokens.VarHash_set_Item);
- } else {
- throw new ArgumentException(tok);
- }
- }
- cx.il.Emit(OpCodes.Ldloc, cx.pspill);
- cx.il.Emit(OpCodes.Call, typeof(List<Variable>).GetMethod("ToArray"));
- cx.il.Emit(OpCodes.Ldloc, cx.nspill);
- }
- }
- public override void CodeGen(CgContext cx) {
- cx.il.Emit(OpCodes.Ldarg_1);
- cx.EmitInt(cx.next_case);
- cx.il.Emit(OpCodes.Stfld, Tokens.Frame_ip);
- zyg[ismethod ? 1 : 0].CodeGen(cx);
- if (ismethod) {
- cx.make_sspill();
- cx.il.Emit(OpCodes.Dup);
- cx.il.Emit(OpCodes.Stloc, cx.sspill);
- cx.il.Emit(OpCodes.Callvirt, Tokens.Variable_Fetch);
- }
- cx.il.Emit(OpCodes.Ldarg_1);
- if (ismethod)
- zyg[0].CodeGen(cx);
- GenArgList(ismethod ? 2 : 1, cx);
- cx.il.Emit(OpCodes.Callvirt, ismethod ?
- Tokens.P6any_InvokeMethod : Tokens.P6any_Invoke);
- cx.il.Emit(OpCodes.Ret);
- cx.il.MarkLabel(cx.cases[cx.next_case++]);
- cx.save_line();
- }
- public override void ListCases(CgContext cx) {
- cx.num_cases++;
- }
- public ClrSubyCall(bool ismethod, string sig, ClrOp[] zyg) {
- int i = 0;
- if (ismethod) TypeCheck(zyg[i++].Returns, Tokens.String, "methodname");
- TypeCheck(zyg[i++].Returns, ismethod ? Tokens.Variable : Tokens.P6any, "sub");
- int j = 0;
- while (j < sig.Length) {
- string s = sig.Substring(j+1, sig[j]);
- j += (1 + s.Length);
- TypeCheck(zyg[i++].Returns, (s == "flatcap") ? Tokens.P6any : Tokens.Variable, j);
- }
- this.ismethod = ismethod;
- this.sig = sig;
- this.zyg = zyg;
- this.Returns = Tokens.Void;
- this.HasCases = true;
- }
- }
- class ClrPushLet : ClrOp {
- string Name;
- // Initial must not have a net let-stack effect (how to enforce?)
- ClrOp Initial;
- public ClrPushLet(string name, ClrOp initial) {
- Initial = initial;
- Name = name;
- Returns = Tokens.Void;
- }
- public override void CodeGen(CgContext cx) {
- // indexes 0-1 can only be used by ints
- int ix = (Initial.Returns == typeof(int)) ? 0 : Tokens.NumInt32;
- while (ix < cx.let_types.Length && cx.let_types[ix] != null)
- ix++;
- cx.il.Emit(OpCodes.Ldarg_1);
- cx.EmitPreSetlex(ix);
- // Initial must not have a net effect on cx.let_types
- Initial.CodeGen(cx);
- // let_types.Length tracks the highest index used.
- if (ix >= cx.let_types.Length) {
- Array.Resize(ref cx.let_types, ix+1);
- Array.Resize(ref cx.let_names, ix+1);
- }
- cx.let_types[ix] = Initial.Returns;
- cx.let_names[ix] = Name;
- cx.EmitSetlex(ix, Initial.Returns);
- }
- }
- class ClrPokeLet : ClrOp {
- string Name;
- ClrOp Value;
- public ClrPokeLet(string name, ClrOp value) {
- Value = value;
- Name = name;
- Returns = Tokens.Void;
- }
- public override void CodeGen(CgContext cx) {
- int ix = cx.let_names.Length - 1;
- while (ix >= 0 && cx.let_names[ix] != Name)
- ix--;
- if (ix == cx.let_names.Length)
- throw new Exception("let " + Name + " not found");
- cx.il.Emit(OpCodes.Ldarg_1);
- cx.EmitPreSetlex(ix);
- // Initial must not have a net effect on cx.let_types
- Value.CodeGen(cx);
- cx.EmitSetlex(ix, Value.Returns);
- }
- }
- class ClrPeekLet : ClrOp {
- string Name;
- public override ClrOp Sink() { return ClrNoop.Instance; }
- public ClrPeekLet(string name, Type letType) {
- Name = name;
- Returns = letType;
- }
- public override void CodeGen(CgContext cx) {
- int ix = cx.let_names.Length - 1;
- while (ix >= 0 && cx.let_names[ix] != Name)
- ix--;
- if (ix == cx.let_names.Length)
- throw new Exception("let " + Name + " not found");
- cx.il.Emit(OpCodes.Ldarg_1);
- cx.EmitGetlex(ix, Returns);
- }
- }
- class ClrSetResult : ClrOp {
- ClrOp zyg;
- public ClrSetResult(ClrOp zyg) {
- Returns = Tokens.Void;
- this.zyg = zyg;
- }
- public override void CodeGen(CgContext cx) {
- cx.il.Emit(OpCodes.Ldarg_1);
- zyg.CodeGen(cx);
- if (zyg.Returns.IsValueType)
- cx.il.Emit(OpCodes.Box, zyg.Returns);
- cx.il.Emit(OpCodes.Stfld, Tokens.Frame_resultSlot);
- }
- }
- class ClrResult : ClrOp {
- public ClrRe…
Large files files are truncated, but you can click here to view the full file