예제 #1
0
        private static String TypeSpecFromSpec(OpCodeKb kb)
        {
            var type = kb.Meta.GetOrDefault("Type", "i4");

            if (kb.Tags.Contains("s"))
            {
                var bytes = int.Parse(type.Substring(1));
                type = type.Substring(0, 1) + (bytes / 4);
            }

            return(type);
        }
예제 #2
0
 private static Type TypeFromSpec(OpCodeKb kb)
 {
     return TypeFromTypeSpec(TypeSpecFromSpec(kb));
 }
예제 #3
0
        private static String TypeSpecFromSpec(OpCodeKb kb)
        {
            var type = kb.Meta.GetOrDefault("Type", "i4");
            if (kb.Tags.Contains("s"))
            {
                var bytes = int.Parse(type.Substring(1));
                type = type.Substring(0, 1) + (bytes / 4);
            }

            return type;
        }
예제 #4
0
        private static void InferFromTag(OpCodeKb kb, String tag)
        {
            if (tag == "ovf")
            {
                var p = kb.EnsureProperty("FailsOnOverflow", typeof(bool));
                p.Getter = "true";
            }
            else if (tag == "un")
            {
                var p = kb.EnsureProperty("ExpectsUn", typeof(bool));
                p.Getter = "true";
            }
            else if (tag == "s")
            {
                // just ignore this
            }
            else if (tag == "virt")
            {
                var p = kb.EnsureProperty("IsVirtual", typeof(bool));
                p.Getter = "true";
            }
            else if (tag.StartsWith("expects.") || tag.StartsWith("yields."))
            {
                var p = kb.EnsureProperty(CapitalizeAfterPeriods(tag), typeof(bool));
                p.Getter = "true";
            }
            else if (tag.StartsWith("predicate."))
            {
                var p = kb.EnsureProperty("PredicateType", typeof(PredicateType?));
                var predicate = PredicateFromPredicateSpec(tag);
                p.Getter = typeof(PredicateType).GetCSharpRef(ToCSharpOptions.ForCodegen) + "." + predicate;
            }
            else if (tag.StartsWith("operator."))
            {
                var p = kb.EnsureProperty("OperatorType", typeof(OperatorType));
                var @operator = OperatorFromOperatorSpec(tag);
                p.Getter = typeof(OperatorType).GetCSharpRef(ToCSharpOptions.ForCodegen) + "." + @operator;
            }
            else if (tag.StartsWith("instantiates."))
            {
                var f_ctor = kb.Fields["_ctorToken"];
                var f_type = kb.Fields["_typeToken"];

                var what = tag.Substring("instantiates.".Length);
                if (what == "obj")
                {
                    f_ctor.Initializer = "ReadMetadataToken(reader)";
                }
                else if (what == "arr")
                {
                    f_type.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    AssertionHelper.Fail();
                }
            }
            else if (tag == "br" || tag == "leave")
            {
                // this will be processed elsewhere
            }
            else if (tag == String.Empty)
            {
                // empty string after dot in prefix ops
                kb.Tags.Remove(String.Empty);
                kb.Tags.Add(".");
            }
            else
            {
                // all this hassle is solely for Ldstr/Ldtoken instructions
                // since they need both type and const semantics

                var type = TypeFromTypeSpec(tag);
                var @const = ValueFromConstSpec(tag);

                if (type != null)
                {
                    kb.Meta["Type"] = tag;

                    kb.Props.ContainsKey("Type").AssertFalse();
                    var p = kb.EnsureProperty("Type", typeof(Type));
                    if (tag != "token") p.Getter = "typeof(" + type.GetCSharpRef(ToCSharpOptions.ForCodegen) + ")";
                    else p.Getter = "_constValue.GetType()";
                }

                if (@const != null)
                {
                    var f_constValue = kb.Fields["_constValue"];
                    var f_useConstValue = kb.Fields["_useConstValue"];

                    f_constValue.Initializer = @const.ToInvariantString();
                    f_useConstValue.Initializer = "true";
                }

                if (@type == null && @const == null)
                {
                    // so that we never miss an instruction with an unknown part
                    AssertionHelper.Fail();
                }
            }
        }
예제 #5
0
        private static void InferFromOpcode(OpCodeKb kb)
        {
            if (kb.OpCode.FlowControl == FlowControl.Meta)
            {
                kb.Tags.Add("Prefix");

                if (kb.Family == "unaligned")
                {
                    (kb.OpCode.OperandType == OperandType.ShortInlineI).AssertTrue();

                    var p = kb.EnsureProperty("Alignment", typeof(Byte));
                    kb.Meta["ValueProp"] = p.Name;
                    p.Getter = "_alignment";

                    var f = kb.EnsureField("_alignment", typeof(Byte));
                    f.Initializer = "ReadU1(reader)";
                }
                else if (kb.Family == "constrained")
                {
                    (kb.OpCode.OperandType == OperandType.InlineType).AssertTrue();

                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    (kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();
                }
            }
            else if (kb.Family == "endfinally" || kb.Family == "endfilter")
            {
                (kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

//                kb.Tags.Add("Ignore");
                // todo. uncomment the line above and perform all necessary fixups
            }
            else if (kb.Family == "switch")
            {
                var f = kb.EnsureField("_targetOffsets", typeof(ReadOnlyCollection<Tuple<Int32, Int32>>));
                var buffer1 = new StringBuilder();
                buffer1.AppendLine(String.Format("(({0})(() => ",
                    typeof(Func<ReadOnlyCollection<Tuple<Int32, Int32>>>).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buffer1.AppendLine("{");
                buffer1.AppendLine("var n = ReadI4(reader);".Indent());
                buffer1.AppendLine(String.Format("var pivot = ({0})reader.BaseStream.Position + sizeof({0}) * n;",
                    typeof(Int32).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent());
                buffer1.AppendLine();
                buffer1.Append(String.Format("return {0}.ToReadOnly(",
                    typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent());
                buffer1.AppendLine(String.Format("{0}.Select(",
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buffer1.AppendLine(String.Format("{0}.Range(1, n), _ => ",
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent().Indent());
                buffer1.AppendLine("{".Indent().Indent());
                buffer1.AppendLine("var relative = ReadI4(reader);".Indent().Indent().Indent());
                buffer1.AppendLine("var absolute = pivot + relative;".Indent().Indent().Indent());
                buffer1.AppendLine(String.Format("return {0}.Create(relative, absolute);",
                    typeof(Tuple).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent().Indent().Indent());
                buffer1.AppendLine("}));".Indent().Indent());
                buffer1.Append("}))()");
                f.Initializer = buffer1.ToString();

                var p_RelativeTargetOffsets = kb.EnsureProperty("RelativeTargetOffsets", typeof(ReadOnlyCollection<Int32>));
                p_RelativeTargetOffsets.Getter = String.Format(
                    "{0}.ToReadOnly({1}.Select(_targetOffsets, t => t.Item2))",
                    typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen),
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen));

                var p_AbsoluteTargetOffsets = kb.EnsureProperty("AbsoluteTargetOffsets", typeof(ReadOnlyCollection<Int32>));
                p_AbsoluteTargetOffsets.Getter = String.Format(
                    "{0}.ToReadOnly({1}.Select(_targetOffsets, t => t.Item2))",
                    typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen),
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen));

                var p_Targets = kb.EnsureProperty("Targets", typeof(ReadOnlyCollection<ILOp>));
                var buffer2 = new StringBuilder();
                buffer2.Append(String.Format("var resolved = {0}.Select(",
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buffer2.AppendLine("AbsoluteTargetOffsets, offset => ResolveReference(offset));");
                buffer2.Append(String.Format("return {0}.ToReadOnly(resolved);",
                    typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                p_Targets.Getter = buffer2.ToString();
            }
            else if (kb.OpCode.FlowControl == FlowControl.Branch ||
                kb.OpCode.FlowControl == FlowControl.Cond_Branch)
            {
                (kb.OpCode.OperandType == OperandType.InlineBrTarget ||
                kb.OpCode.OperandType == OperandType.ShortInlineBrTarget).AssertTrue();

                var p_target = kb.EnsureProperty("Target", typeof(IILOp));
                p_target.Getter = "ResolveReference(_absoluteTargetOffset)";

                var p_rto = kb.EnsureProperty("RelativeTargetOffset", typeof(Int32));
                p_rto.Getter = "_relativeTargetOffset";

                var p_ato = kb.EnsureProperty("AbsoluteTargetOffset", typeof(Int32));
                p_ato.Getter = "_absoluteTargetOffset";

                // relative offset === operand of the opcode
                var f_rto = kb.EnsureField("_relativeTargetOffset", typeof(Int32));
                f_rto.SetLazyInitializer(_ => String.Format(
                    "Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)",
                    typeof(Int32).GetCSharpRef(ToCSharpOptions.ForCodegen)));

                // absolute offset === exact offset that can be resolved into target
                var f_ato = kb.EnsureField("_absoluteTargetOffset", typeof(Int32));
                f_ato.SetLazyInitializer(_ => String.Format(
                    "({0})origPos + sizeof({1}) + _relativeTargetOffset",
                    typeof(Int32).GetCSharpRef(ToCSharpOptions.ForCodegen),
                    TypeFromSpec(kb).AssertNotNull().GetCSharpRef(ToCSharpOptions.ForCodegen)));
            }
            else if (kb.Family == "ldarg" || kb.Family == "ldarga" || kb.Family == "starg")
            {
                (kb.OpCode.OperandType == OperandType.InlineVar ||
                kb.OpCode.OperandType == OperandType.ShortInlineVar ||
                kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                var p_Index = kb.EnsureProperty("Index", typeof(int));
                p_Index.Getter = "_value";

                var p_Arg = kb.EnsureProperty("Arg", typeof(ParameterInfo));
                p_Arg.Getter = 
                    "if (Source.Method == null || Source.Args == null)" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    return null;" + Environment.NewLine +
                    "}" + Environment.NewLine +
                    "else" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    if (Source.Method.IsStatic)" + Environment.NewLine +
                    "    {" + Environment.NewLine +
                    "        return Source.Args[_value];" + Environment.NewLine +
                    "    }" + Environment.NewLine +
                    "    else" + Environment.NewLine +
                    "    {" + Environment.NewLine +
                    "        return _value == 0 ? null : Source.Args[_value - 1];" + Environment.NewLine +
                    "    }" + Environment.NewLine +
                    "}";

                var f_value = kb.EnsureField("_value", typeof(Int32));
                var f_useConstValue = kb.EnsureField("_useConstValue", typeof(bool));
                var f_constValue = kb.EnsureField("_constValue", typeof(Int32?));
                f_value.SetLazyInitializer(_ => f_useConstValue.Name + " ? " +
                    f_constValue.Name + ".Value : Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)");
            }
            else if (kb.Family == "ldloc" || kb.Family == "ldloca" || kb.Family == "stloc")
            {
                (kb.OpCode.OperandType == OperandType.InlineVar ||
                kb.OpCode.OperandType == OperandType.ShortInlineVar ||
                kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                var p_Index = kb.EnsureProperty("Index", typeof(int));
                p_Index.Getter = "_value";

                var p_Loc = kb.EnsureProperty("Loc", typeof(ILocalVar));
                p_Loc.Getter =
                    "if (Source.Method == null || Source.Locals == null)" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    return null;" + Environment.NewLine +
                    "}" + Environment.NewLine +
                    "else" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    return Source.Locals[_value];" + Environment.NewLine +
                    "}";

                var f_value = kb.EnsureField("_value", typeof(Int32));
                var f_useConstValue = kb.EnsureField("_useConstValue", typeof(bool));
                var f_constValue = kb.EnsureField("_constValue", typeof(Int32?));
                f_value.SetLazyInitializer(_ => f_useConstValue.Name + " ? " +
                    f_constValue.Name + ".Value : Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)");
            }
            else if (kb.Family == "ldc")
            {
                (kb.OpCode.OperandType == OperandType.InlineI ||
                kb.OpCode.OperandType == OperandType.InlineI8 ||
                kb.OpCode.OperandType == OperandType.InlineR ||
                kb.OpCode.OperandType == OperandType.ShortInlineI ||
                kb.OpCode.OperandType == OperandType.ShortInlineR ||
                kb.OpCode.OperandType == OperandType.InlineString ||
                kb.OpCode.OperandType == OperandType.InlineTok ||
                kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                var p = kb.EnsureProperty("Value", typeof(Object));
                p.Getter = "_value";

                var f_value = kb.EnsureField("_value", typeof(Object));
                var f_useConstValue = kb.EnsureField("_useConstValue", typeof(bool));
                var f_constValue = kb.EnsureField("_constValue", typeof(Object));
                var cast = kb.OpCode.Name == "ldc.i4.s" ? String.Format("({0})",
                    typeof(int).GetCSharpRef(ToCSharpOptions.Informative)) : String.Empty;
                f_value.SetLazyInitializer(_ => f_useConstValue.Name + " ? " +
                    f_constValue.Name + " : " + cast + "Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)");
            }
            else if (kb.Family == "isinst" || kb.Family == "sizeof" ||
                kb.Family == "initobj" || kb.Family == "stobj" || kb.Family == "ldobj" || kb.Family == "cpobj" || 
                kb.Family == "mkrefany" || kb.Family == "refanyval")
            {
                (kb.OpCode.OperandType == OperandType.InlineType).AssertTrue();

                var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                p_Token.Getter = "_typeToken;";

                var p_Type = kb.EnsureProperty("Type", typeof(Type));
                p_Type.Getter = "TypeFromToken(_typeToken);";

                var f = kb.EnsureField("_typeToken", typeof(Int32));
                f.Initializer = "ReadMetadataToken(reader)";
            }
            else if (kb.Family == "ldelem" || kb.Family == "ldelema" || kb.Family == "stelem")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                if (kb.OpCode.OperandType == OperandType.InlineType)
                {
                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    // InferFromTag will take care of XXXelemYYY.TYPE (see below)
                }
            }
            else if (kb.Family == "ldind" || kb.Family == "stind")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                if (kb.OpCode.OperandType == OperandType.InlineType)
                {
                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    // InferFromTag will take care of XXXind.TYPE (see below)
                }

                kb.EnsurePrefix("IsVolatile", typeof(bool), "volatile");
                kb.EnsurePrefix("IsUnaligned", typeof(bool), "unaligned");
                var p_IsAligned = kb.EnsureProperty("IsAligned", typeof(bool));
                p_IsAligned.Getter = "!IsUnaligned";
                var p_Alignment = kb.EnsureProperty("Alignment", typeof(byte));
                var buf = new StringBuilder();
                buf.AppendLine(String.Format(
                    "var unaligned = {0}.SingleOrDefault({0}.OfType<{1}>(Prefixes));",
                    typeof(Enumerable), "Unaligned"));
                buf.AppendLine(String.Format(
                    "var defaultAlignment = (({0})(() => {{ throw new {1}(); }}))();",
                     typeof(Func<byte>).GetCSharpRef(ToCSharpOptions.ForCodegen),
                     typeof(NotImplementedException).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buf.Append("return unaligned != null ? unaligned.Alignment : defaultAlignment");
                p_Alignment.Getter = buf.ToString();
            }
            else if (kb.Family == "cast")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                if (kb.OpCode.OperandType == OperandType.InlineType)
                {
                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = kb.OpCode.Name == "box" ?
                        String.Format("typeof({0})", typeof(Object).GetCSharpRef(ToCSharpOptions.ForCodegen)) :
                        "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
            }
            else if (kb.Family == "new")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                kb.OpCode.OperandType == OperandType.InlineMethod).AssertTrue();

                var f_ctorToken = kb.EnsureField("_ctorToken", typeof(Int32?));
                var p_ctorToken = kb.EnsureProperty("CtorToken", typeof(Int32?));
                p_ctorToken.Getter = "_ctorToken;";

                var f_typeToken = kb.EnsureField("_typeToken", typeof(Int32?));
                var p_typeToken = kb.EnsureProperty("TypeToken", typeof(Int32?));
                p_typeToken.Getter = "_typeToken;";

                var p_ctor = kb.EnsureProperty("Ctor", typeof(ConstructorInfo));
                if (kb.OpCode == OpCodes.Newobj) p_ctor.Getter = String.Format("CtorFromToken({0}.AssertValue({1}))", typeof(AssertionHelper).GetCSharpRef(ToCSharpOptions.ForCodegen), f_ctorToken.Name);
                else if (kb.OpCode == OpCodes.Newarr) p_ctor.Getter = String.Format("Type != null ? {0}.AssertSingle(Type.GetConstructors()) : null", typeof(AssertionHelper).GetCSharpRef(ToCSharpOptions.ForCodegen));
                else throw AssertionHelper.Fail();

                var p_type = kb.EnsureProperty("Type", typeof(Type));
                if (kb.OpCode == OpCodes.Newobj) p_type.Getter = "Ctor != null ? Ctor.DeclaringType : null";
                else if (kb.OpCode == OpCodes.Newarr) p_type.Getter = 
                    String.Format("var elementType = TypeFromToken({0}.AssertValue({1}));", typeof(AssertionHelper).GetCSharpRef(ToCSharpOptions.ForCodegen), f_typeToken.Name) + Environment.NewLine +
                    "return elementType != null ? elementType.MakeArrayType() : null;";
                else throw AssertionHelper.Fail();
            }
            else if (kb.Family == "ldftn" || kb.Family == "jmp")
            {
                (kb.OpCode.OperandType == OperandType.InlineMethod).AssertTrue();

                var p_Token = kb.EnsureProperty("MethodToken", typeof(Int32));
                p_Token.Getter = "_methodToken;";

                var p_Method = kb.EnsureProperty("Method", typeof(MethodBase));
                p_Method.Getter = "MethodBaseFromToken(_methodToken);";

                var f = kb.EnsureField("_methodToken", typeof(Int32));
                f.Initializer = "ReadMetadataToken(reader)";
            }
            else if (kb.Family == "call")
            {
                (kb.OpCode.OperandType == OperandType.InlineMethod ||
                 kb.OpCode.OperandType == OperandType.InlineSig).AssertTrue();

                var p_Method = kb.EnsureProperty("Method", typeof(MethodBase));
                if (kb.OpCode.OperandType == OperandType.InlineMethod) p_Method.Getter = "MethodBaseFromToken(_methodToken);";
                else if (kb.OpCode.OperandType == OperandType.InlineSig) p_Method.Getter = "MethodBaseFromSignature(SignatureFromToken(_signatureToken));";
                else throw AssertionHelper.Fail();

                var p_MethodToken = kb.EnsureProperty("MethodToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod) p_MethodToken.Getter = "_methodToken;";
                else if (kb.OpCode.OperandType == OperandType.InlineSig) p_MethodToken.Getter = null;
                else throw AssertionHelper.Fail();

                var f_MethodToken = kb.EnsureField("_methodToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod) f_MethodToken.Initializer = "ReadMetadataToken(reader)";
                else if (kb.OpCode.OperandType == OperandType.InlineSig) f_MethodToken.Initializer = null;
                else throw AssertionHelper.Fail();

                var p_Signature = kb.EnsureProperty("Signature", typeof(byte[]));
                if (kb.OpCode.OperandType == OperandType.InlineMethod) p_Signature.Getter = null;
                else if (kb.OpCode.OperandType == OperandType.InlineSig) p_Signature.Getter = "SignatureFromToken(_signatureToken);";
                else throw AssertionHelper.Fail();

                var p_SignatureToken = kb.EnsureProperty("SignatureToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod) p_SignatureToken.Getter = null;
                else if (kb.OpCode.OperandType == OperandType.InlineSig) p_SignatureToken.Getter = "_signatureToken;";
                else throw AssertionHelper.Fail();

                var f_SignatureToken = kb.EnsureField("_signatureToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod) f_SignatureToken.Initializer = null;
                else if (kb.OpCode.OperandType == OperandType.InlineSig) f_SignatureToken.Initializer = "ReadMetadataToken(reader)";
                else throw AssertionHelper.Fail();

                var pfx_constrained = kb.EnsurePrefix("Constraint", typeof(Type), "constrained");
                pfx_constrained.Getter = "Type";
                kb.EnsurePrefix("IsTail", typeof(bool), "tail");
            }
            else if (kb.Family == "ldfld" || kb.Family == "ldflda" || kb.Family == "stfld")
            {
                (kb.OpCode.OperandType == OperandType.InlineField).AssertTrue();

                var p_Token = kb.EnsureProperty("FieldToken", typeof(Int32));
                p_Token.Getter = "_fieldToken;";

                var p_Fld = kb.EnsureProperty("Field", typeof(FieldInfo));
                p_Fld.Getter = "FieldFromToken(_fieldToken);";

                var f = kb.EnsureField("_fieldToken", typeof(Int32));
                f.Initializer = "ReadMetadataToken(reader)";

                kb.EnsurePrefix("IsVolatile", typeof(bool), "volatile");
                var pfx_Unaligned = kb.EnsurePrefix("IsUnaligned", typeof(bool), "unaligned");
                if (kb.Family == "ldfld") pfx_Unaligned.Filter = "OpSpec.OpCode.Value != 0x7e /* ldsfld */";
                if (kb.Family == "stfld") pfx_Unaligned.Filter = "OpSpec.OpCode.Value != 0x80 /* stsfld */";

                var p_IsAligned = kb.EnsureProperty("IsAligned", typeof(bool));
                p_IsAligned.Getter = "!IsUnaligned";
                var p_Alignment = kb.EnsureProperty("Alignment", typeof(byte));
                var buf = new StringBuilder();
                buf.AppendLine(String.Format(
                    "var unaligned = {0}.SingleOrDefault({0}.OfType<{1}>(Prefixes));",
                    typeof(Enumerable), "Unaligned"));
                buf.AppendLine(String.Format(
                    "var defaultAlignment = (({0})(() => {{ throw new {1}(); }}))();",
                     typeof(Func<byte>).GetCSharpRef(ToCSharpOptions.ForCodegen),
                     typeof(NotImplementedException).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buf.Append("return unaligned != null ? unaligned.Alignment : defaultAlignment");
                p_Alignment.Getter = buf.ToString();
            }
            else if (kb.Family == "initblk" || kb.Family == "cpblk")
            {
                kb.EnsurePrefix("IsVolatile", typeof(bool), "volatile");
                kb.EnsurePrefix("IsUnaligned", typeof(bool), "unaligned");
                var p_IsAligned = kb.EnsureProperty("IsAligned", typeof(bool));
                p_IsAligned.Getter = "!IsUnaligned";
                var p_Alignment = kb.EnsureProperty("Alignment", typeof(byte));
                var buf = new StringBuilder();
                buf.AppendLine(String.Format(
                    "var unaligned = {0}.SingleOrDefault({0}.OfType<{1}>(Prefixes));",
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen), 
                    "Unaligned"));
                buf.AppendLine(String.Format(
                    "var defaultAlignment = ({0}){1}.SizeOf(typeof({2}));",
                    typeof(byte).GetCSharpRef(ToCSharpOptions.ForCodegen),
                    typeof(Marshal).GetCSharpRef(ToCSharpOptions.ForCodegen),
                     typeof(IntPtr).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buf.Append("return unaligned != null ? unaligned.Alignment : defaultAlignment");
                p_Alignment.Getter = buf.ToString();
                p_Alignment.IsUnsafe = true;
            }
            else
            {
                // so that we never miss any other instructions with arguments
                (kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();
            }
        }
예제 #6
0
 private static Type TypeFromSpec(OpCodeKb kb)
 {
     return(TypeFromTypeSpec(TypeSpecFromSpec(kb)));
 }
예제 #7
0
        private static void InferFromTag(OpCodeKb kb, String tag)
        {
            if (tag == "ovf")
            {
                var p = kb.EnsureProperty("FailsOnOverflow", typeof(bool));
                p.Getter = "true";
            }
            else if (tag == "un")
            {
                var p = kb.EnsureProperty("ExpectsUn", typeof(bool));
                p.Getter = "true";
            }
            else if (tag == "s")
            {
                // just ignore this
            }
            else if (tag == "virt")
            {
                var p = kb.EnsureProperty("IsVirtual", typeof(bool));
                p.Getter = "true";
            }
            else if (tag.StartsWith("expects.") || tag.StartsWith("yields."))
            {
                var p = kb.EnsureProperty(CapitalizeAfterPeriods(tag), typeof(bool));
                p.Getter = "true";
            }
            else if (tag.StartsWith("predicate."))
            {
                var p         = kb.EnsureProperty("PredicateType", typeof(PredicateType?));
                var predicate = PredicateFromPredicateSpec(tag);
                p.Getter = typeof(PredicateType).GetCSharpRef(ToCSharpOptions.ForCodegen) + "." + predicate;
            }
            else if (tag.StartsWith("operator."))
            {
                var p         = kb.EnsureProperty("OperatorType", typeof(OperatorType));
                var @operator = OperatorFromOperatorSpec(tag);
                p.Getter = typeof(OperatorType).GetCSharpRef(ToCSharpOptions.ForCodegen) + "." + @operator;
            }
            else if (tag.StartsWith("instantiates."))
            {
                var f_ctor = kb.Fields["_ctorToken"];
                var f_type = kb.Fields["_typeToken"];

                var what = tag.Substring("instantiates.".Length);
                if (what == "obj")
                {
                    f_ctor.Initializer = "ReadMetadataToken(reader)";
                }
                else if (what == "arr")
                {
                    f_type.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    AssertionHelper.Fail();
                }
            }
            else if (tag == "br" || tag == "leave")
            {
                // this will be processed elsewhere
            }
            else if (tag == String.Empty)
            {
                // empty string after dot in prefix ops
                kb.Tags.Remove(String.Empty);
                kb.Tags.Add(".");
            }
            else
            {
                // all this hassle is solely for Ldstr/Ldtoken instructions
                // since they need both type and const semantics

                var type   = TypeFromTypeSpec(tag);
                var @const = ValueFromConstSpec(tag);

                if (type != null)
                {
                    kb.Meta["Type"] = tag;

                    kb.Props.ContainsKey("Type").AssertFalse();
                    var p = kb.EnsureProperty("Type", typeof(Type));
                    if (tag != "token")
                    {
                        p.Getter = "typeof(" + type.GetCSharpRef(ToCSharpOptions.ForCodegen) + ")";
                    }
                    else
                    {
                        p.Getter = "_constValue.GetType()";
                    }
                }

                if (@const != null)
                {
                    var f_constValue    = kb.Fields["_constValue"];
                    var f_useConstValue = kb.Fields["_useConstValue"];

                    f_constValue.Initializer    = @const.ToInvariantString();
                    f_useConstValue.Initializer = "true";
                }

                if (@type == null && @const == null)
                {
                    // so that we never miss an instruction with an unknown part
                    AssertionHelper.Fail();
                }
            }
        }
예제 #8
0
        private static void InferFromOpcode(OpCodeKb kb)
        {
            if (kb.OpCode.FlowControl == FlowControl.Meta)
            {
                kb.Tags.Add("Prefix");

                if (kb.Family == "unaligned")
                {
                    (kb.OpCode.OperandType == OperandType.ShortInlineI).AssertTrue();

                    var p = kb.EnsureProperty("Alignment", typeof(Byte));
                    kb.Meta["ValueProp"] = p.Name;
                    p.Getter             = "_alignment";

                    var f = kb.EnsureField("_alignment", typeof(Byte));
                    f.Initializer = "ReadU1(reader)";
                }
                else if (kb.Family == "constrained")
                {
                    (kb.OpCode.OperandType == OperandType.InlineType).AssertTrue();

                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    (kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();
                }
            }
            else if (kb.Family == "endfinally" || kb.Family == "endfilter")
            {
                (kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

//                kb.Tags.Add("Ignore");
                // todo. uncomment the line above and perform all necessary fixups
            }
            else if (kb.Family == "switch")
            {
                var f       = kb.EnsureField("_targetOffsets", typeof(ReadOnlyCollection <Tuple <Int32, Int32> >));
                var buffer1 = new StringBuilder();
                buffer1.AppendLine(String.Format("(({0})(() => ",
                                                 typeof(Func <ReadOnlyCollection <Tuple <Int32, Int32> > >).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buffer1.AppendLine("{");
                buffer1.AppendLine("var n = ReadI4(reader);".Indent());
                buffer1.AppendLine(String.Format("var pivot = ({0})reader.BaseStream.Position + sizeof({0}) * n;",
                                                 typeof(Int32).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent());
                buffer1.AppendLine();
                buffer1.Append(String.Format("return {0}.ToReadOnly(",
                                             typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent());
                buffer1.AppendLine(String.Format("{0}.Select(",
                                                 typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buffer1.AppendLine(String.Format("{0}.Range(1, n), _ => ",
                                                 typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent().Indent());
                buffer1.AppendLine("{".Indent().Indent());
                buffer1.AppendLine("var relative = ReadI4(reader);".Indent().Indent().Indent());
                buffer1.AppendLine("var absolute = pivot + relative;".Indent().Indent().Indent());
                buffer1.AppendLine(String.Format("return {0}.Create(relative, absolute);",
                                                 typeof(Tuple).GetCSharpRef(ToCSharpOptions.ForCodegen)).Indent().Indent().Indent());
                buffer1.AppendLine("}));".Indent().Indent());
                buffer1.Append("}))()");
                f.Initializer = buffer1.ToString();

                var p_RelativeTargetOffsets = kb.EnsureProperty("RelativeTargetOffsets", typeof(ReadOnlyCollection <Int32>));
                p_RelativeTargetOffsets.Getter = String.Format(
                    "{0}.ToReadOnly({1}.Select(_targetOffsets, t => t.Item2))",
                    typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen),
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen));

                var p_AbsoluteTargetOffsets = kb.EnsureProperty("AbsoluteTargetOffsets", typeof(ReadOnlyCollection <Int32>));
                p_AbsoluteTargetOffsets.Getter = String.Format(
                    "{0}.ToReadOnly({1}.Select(_targetOffsets, t => t.Item2))",
                    typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen),
                    typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen));

                var p_Targets = kb.EnsureProperty("Targets", typeof(ReadOnlyCollection <ILOp>));
                var buffer2   = new StringBuilder();
                buffer2.Append(String.Format("var resolved = {0}.Select(",
                                             typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buffer2.AppendLine("AbsoluteTargetOffsets, offset => ResolveReference(offset));");
                buffer2.Append(String.Format("return {0}.ToReadOnly(resolved);",
                                             typeof(EnumerableExtensions).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                p_Targets.Getter = buffer2.ToString();
            }
            else if (kb.OpCode.FlowControl == FlowControl.Branch ||
                     kb.OpCode.FlowControl == FlowControl.Cond_Branch)
            {
                (kb.OpCode.OperandType == OperandType.InlineBrTarget ||
                 kb.OpCode.OperandType == OperandType.ShortInlineBrTarget).AssertTrue();

                var p_target = kb.EnsureProperty("Target", typeof(IILOp));
                p_target.Getter = "ResolveReference(_absoluteTargetOffset)";

                var p_rto = kb.EnsureProperty("RelativeTargetOffset", typeof(Int32));
                p_rto.Getter = "_relativeTargetOffset";

                var p_ato = kb.EnsureProperty("AbsoluteTargetOffset", typeof(Int32));
                p_ato.Getter = "_absoluteTargetOffset";

                // relative offset === operand of the opcode
                var f_rto = kb.EnsureField("_relativeTargetOffset", typeof(Int32));
                f_rto.SetLazyInitializer(_ => String.Format(
                                             "Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)",
                                             typeof(Int32).GetCSharpRef(ToCSharpOptions.ForCodegen)));

                // absolute offset === exact offset that can be resolved into target
                var f_ato = kb.EnsureField("_absoluteTargetOffset", typeof(Int32));
                f_ato.SetLazyInitializer(_ => String.Format(
                                             "({0})origPos + sizeof({1}) + _relativeTargetOffset",
                                             typeof(Int32).GetCSharpRef(ToCSharpOptions.ForCodegen),
                                             TypeFromSpec(kb).AssertNotNull().GetCSharpRef(ToCSharpOptions.ForCodegen)));
            }
            else if (kb.Family == "ldarg" || kb.Family == "ldarga" || kb.Family == "starg")
            {
                (kb.OpCode.OperandType == OperandType.InlineVar ||
                 kb.OpCode.OperandType == OperandType.ShortInlineVar ||
                 kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                var p_Index = kb.EnsureProperty("Index", typeof(int));
                p_Index.Getter = "_value";

                var p_Arg = kb.EnsureProperty("Arg", typeof(ParameterInfo));
                p_Arg.Getter =
                    "if (Source.Method == null || Source.Args == null)" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    return null;" + Environment.NewLine +
                    "}" + Environment.NewLine +
                    "else" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    if (Source.Method.IsStatic)" + Environment.NewLine +
                    "    {" + Environment.NewLine +
                    "        return Source.Args[_value];" + Environment.NewLine +
                    "    }" + Environment.NewLine +
                    "    else" + Environment.NewLine +
                    "    {" + Environment.NewLine +
                    "        return _value == 0 ? null : Source.Args[_value - 1];" + Environment.NewLine +
                    "    }" + Environment.NewLine +
                    "}";

                var f_value         = kb.EnsureField("_value", typeof(Int32));
                var f_useConstValue = kb.EnsureField("_useConstValue", typeof(bool));
                var f_constValue    = kb.EnsureField("_constValue", typeof(Int32?));
                f_value.SetLazyInitializer(_ => f_useConstValue.Name + " ? " +
                                           f_constValue.Name + ".Value : Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)");
            }
            else if (kb.Family == "ldloc" || kb.Family == "ldloca" || kb.Family == "stloc")
            {
                (kb.OpCode.OperandType == OperandType.InlineVar ||
                 kb.OpCode.OperandType == OperandType.ShortInlineVar ||
                 kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                var p_Index = kb.EnsureProperty("Index", typeof(int));
                p_Index.Getter = "_value";

                var p_Loc = kb.EnsureProperty("Loc", typeof(ILocalVar));
                p_Loc.Getter =
                    "if (Source.Method == null || Source.Locals == null)" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    return null;" + Environment.NewLine +
                    "}" + Environment.NewLine +
                    "else" + Environment.NewLine +
                    "{" + Environment.NewLine +
                    "    return Source.Locals[_value];" + Environment.NewLine +
                    "}";

                var f_value         = kb.EnsureField("_value", typeof(Int32));
                var f_useConstValue = kb.EnsureField("_useConstValue", typeof(bool));
                var f_constValue    = kb.EnsureField("_constValue", typeof(Int32?));
                f_value.SetLazyInitializer(_ => f_useConstValue.Name + " ? " +
                                           f_constValue.Name + ".Value : Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)");
            }
            else if (kb.Family == "ldc")
            {
                (kb.OpCode.OperandType == OperandType.InlineI ||
                 kb.OpCode.OperandType == OperandType.InlineI8 ||
                 kb.OpCode.OperandType == OperandType.InlineR ||
                 kb.OpCode.OperandType == OperandType.ShortInlineI ||
                 kb.OpCode.OperandType == OperandType.ShortInlineR ||
                 kb.OpCode.OperandType == OperandType.InlineString ||
                 kb.OpCode.OperandType == OperandType.InlineTok ||
                 kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                var p = kb.EnsureProperty("Value", typeof(Object));
                p.Getter = "_value";

                var f_value         = kb.EnsureField("_value", typeof(Object));
                var f_useConstValue = kb.EnsureField("_useConstValue", typeof(bool));
                var f_constValue    = kb.EnsureField("_constValue", typeof(Object));
                var cast            = kb.OpCode.Name == "ldc.i4.s" ? String.Format("({0})",
                                                                                   typeof(int).GetCSharpRef(ToCSharpOptions.Informative)) : String.Empty;
                f_value.SetLazyInitializer(_ => f_useConstValue.Name + " ? " +
                                           f_constValue.Name + " : " + cast + "Read" + TypeSpecFromSpec(kb).Capitalize() + "(reader)");
            }
            else if (kb.Family == "isinst" || kb.Family == "sizeof" ||
                     kb.Family == "initobj" || kb.Family == "stobj" || kb.Family == "ldobj" || kb.Family == "cpobj" ||
                     kb.Family == "mkrefany" || kb.Family == "refanyval")
            {
                (kb.OpCode.OperandType == OperandType.InlineType).AssertTrue();

                var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                p_Token.Getter = "_typeToken;";

                var p_Type = kb.EnsureProperty("Type", typeof(Type));
                p_Type.Getter = "TypeFromToken(_typeToken);";

                var f = kb.EnsureField("_typeToken", typeof(Int32));
                f.Initializer = "ReadMetadataToken(reader)";
            }
            else if (kb.Family == "ldelem" || kb.Family == "ldelema" || kb.Family == "stelem")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                 kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                if (kb.OpCode.OperandType == OperandType.InlineType)
                {
                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    // InferFromTag will take care of XXXelemYYY.TYPE (see below)
                }
            }
            else if (kb.Family == "ldind" || kb.Family == "stind")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                 kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                if (kb.OpCode.OperandType == OperandType.InlineType)
                {
                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    // InferFromTag will take care of XXXind.TYPE (see below)
                }

                kb.EnsurePrefix("IsVolatile", typeof(bool), "volatile");
                kb.EnsurePrefix("IsUnaligned", typeof(bool), "unaligned");
                var p_IsAligned = kb.EnsureProperty("IsAligned", typeof(bool));
                p_IsAligned.Getter = "!IsUnaligned";
                var p_Alignment = kb.EnsureProperty("Alignment", typeof(byte));
                var buf         = new StringBuilder();
                buf.AppendLine(String.Format(
                                   "var unaligned = {0}.SingleOrDefault({0}.OfType<{1}>(Prefixes));",
                                   typeof(Enumerable), "Unaligned"));
                buf.AppendLine(String.Format(
                                   "var defaultAlignment = (({0})(() => {{ throw new {1}(); }}))();",
                                   typeof(Func <byte>).GetCSharpRef(ToCSharpOptions.ForCodegen),
                                   typeof(NotImplementedException).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buf.Append("return unaligned != null ? unaligned.Alignment : defaultAlignment");
                p_Alignment.Getter = buf.ToString();
            }
            else if (kb.Family == "cast")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                 kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();

                if (kb.OpCode.OperandType == OperandType.InlineType)
                {
                    var p_Token = kb.EnsureProperty("TypeToken", typeof(Int32));
                    p_Token.Getter = "_typeToken;";

                    var p_Type = kb.EnsureProperty("Type", typeof(Type));
                    p_Type.Getter = kb.OpCode.Name == "box" ?
                                    String.Format("typeof({0})", typeof(Object).GetCSharpRef(ToCSharpOptions.ForCodegen)) :
                                    "TypeFromToken(_typeToken);";

                    var f = kb.EnsureField("_typeToken", typeof(Int32));
                    f.Initializer = "ReadMetadataToken(reader)";
                }
            }
            else if (kb.Family == "new")
            {
                (kb.OpCode.OperandType == OperandType.InlineType ||
                 kb.OpCode.OperandType == OperandType.InlineMethod).AssertTrue();

                var f_ctorToken = kb.EnsureField("_ctorToken", typeof(Int32?));
                var p_ctorToken = kb.EnsureProperty("CtorToken", typeof(Int32?));
                p_ctorToken.Getter = "_ctorToken;";

                var f_typeToken = kb.EnsureField("_typeToken", typeof(Int32?));
                var p_typeToken = kb.EnsureProperty("TypeToken", typeof(Int32?));
                p_typeToken.Getter = "_typeToken;";

                var p_ctor = kb.EnsureProperty("Ctor", typeof(ConstructorInfo));
                if (kb.OpCode == OpCodes.Newobj)
                {
                    p_ctor.Getter = String.Format("CtorFromToken({0}.AssertValue({1}))", typeof(AssertionHelper).GetCSharpRef(ToCSharpOptions.ForCodegen), f_ctorToken.Name);
                }
                else if (kb.OpCode == OpCodes.Newarr)
                {
                    p_ctor.Getter = String.Format("Type != null ? {0}.AssertSingle(Type.GetConstructors()) : null", typeof(AssertionHelper).GetCSharpRef(ToCSharpOptions.ForCodegen));
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var p_type = kb.EnsureProperty("Type", typeof(Type));
                if (kb.OpCode == OpCodes.Newobj)
                {
                    p_type.Getter = "Ctor != null ? Ctor.DeclaringType : null";
                }
                else if (kb.OpCode == OpCodes.Newarr)
                {
                    p_type.Getter =
                        String.Format("var elementType = TypeFromToken({0}.AssertValue({1}));", typeof(AssertionHelper).GetCSharpRef(ToCSharpOptions.ForCodegen), f_typeToken.Name) + Environment.NewLine +
                        "return elementType != null ? elementType.MakeArrayType() : null;";
                }
                else
                {
                    throw AssertionHelper.Fail();
                }
            }
            else if (kb.Family == "ldftn" || kb.Family == "jmp")
            {
                (kb.OpCode.OperandType == OperandType.InlineMethod).AssertTrue();

                var p_Token = kb.EnsureProperty("MethodToken", typeof(Int32));
                p_Token.Getter = "_methodToken;";

                var p_Method = kb.EnsureProperty("Method", typeof(MethodBase));
                p_Method.Getter = "MethodBaseFromToken(_methodToken);";

                var f = kb.EnsureField("_methodToken", typeof(Int32));
                f.Initializer = "ReadMetadataToken(reader)";
            }
            else if (kb.Family == "call")
            {
                (kb.OpCode.OperandType == OperandType.InlineMethod ||
                 kb.OpCode.OperandType == OperandType.InlineSig).AssertTrue();

                var p_Method = kb.EnsureProperty("Method", typeof(MethodBase));
                if (kb.OpCode.OperandType == OperandType.InlineMethod)
                {
                    p_Method.Getter = "MethodBaseFromToken(_methodToken);";
                }
                else if (kb.OpCode.OperandType == OperandType.InlineSig)
                {
                    p_Method.Getter = "MethodBaseFromSignature(SignatureFromToken(_signatureToken));";
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var p_MethodToken = kb.EnsureProperty("MethodToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod)
                {
                    p_MethodToken.Getter = "_methodToken;";
                }
                else if (kb.OpCode.OperandType == OperandType.InlineSig)
                {
                    p_MethodToken.Getter = null;
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var f_MethodToken = kb.EnsureField("_methodToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod)
                {
                    f_MethodToken.Initializer = "ReadMetadataToken(reader)";
                }
                else if (kb.OpCode.OperandType == OperandType.InlineSig)
                {
                    f_MethodToken.Initializer = null;
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var p_Signature = kb.EnsureProperty("Signature", typeof(byte[]));
                if (kb.OpCode.OperandType == OperandType.InlineMethod)
                {
                    p_Signature.Getter = null;
                }
                else if (kb.OpCode.OperandType == OperandType.InlineSig)
                {
                    p_Signature.Getter = "SignatureFromToken(_signatureToken);";
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var p_SignatureToken = kb.EnsureProperty("SignatureToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod)
                {
                    p_SignatureToken.Getter = null;
                }
                else if (kb.OpCode.OperandType == OperandType.InlineSig)
                {
                    p_SignatureToken.Getter = "_signatureToken;";
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var f_SignatureToken = kb.EnsureField("_signatureToken", typeof(Int32));
                if (kb.OpCode.OperandType == OperandType.InlineMethod)
                {
                    f_SignatureToken.Initializer = null;
                }
                else if (kb.OpCode.OperandType == OperandType.InlineSig)
                {
                    f_SignatureToken.Initializer = "ReadMetadataToken(reader)";
                }
                else
                {
                    throw AssertionHelper.Fail();
                }

                var pfx_constrained = kb.EnsurePrefix("Constraint", typeof(Type), "constrained");
                pfx_constrained.Getter = "Type";
                kb.EnsurePrefix("IsTail", typeof(bool), "tail");
            }
            else if (kb.Family == "ldfld" || kb.Family == "ldflda" || kb.Family == "stfld")
            {
                (kb.OpCode.OperandType == OperandType.InlineField).AssertTrue();

                var p_Token = kb.EnsureProperty("FieldToken", typeof(Int32));
                p_Token.Getter = "_fieldToken;";

                var p_Fld = kb.EnsureProperty("Field", typeof(FieldInfo));
                p_Fld.Getter = "FieldFromToken(_fieldToken);";

                var f = kb.EnsureField("_fieldToken", typeof(Int32));
                f.Initializer = "ReadMetadataToken(reader)";

                kb.EnsurePrefix("IsVolatile", typeof(bool), "volatile");
                var pfx_Unaligned = kb.EnsurePrefix("IsUnaligned", typeof(bool), "unaligned");
                if (kb.Family == "ldfld")
                {
                    pfx_Unaligned.Filter = "OpSpec.OpCode.Value != 0x7e /* ldsfld */";
                }
                if (kb.Family == "stfld")
                {
                    pfx_Unaligned.Filter = "OpSpec.OpCode.Value != 0x80 /* stsfld */";
                }

                var p_IsAligned = kb.EnsureProperty("IsAligned", typeof(bool));
                p_IsAligned.Getter = "!IsUnaligned";
                var p_Alignment = kb.EnsureProperty("Alignment", typeof(byte));
                var buf         = new StringBuilder();
                buf.AppendLine(String.Format(
                                   "var unaligned = {0}.SingleOrDefault({0}.OfType<{1}>(Prefixes));",
                                   typeof(Enumerable), "Unaligned"));
                buf.AppendLine(String.Format(
                                   "var defaultAlignment = (({0})(() => {{ throw new {1}(); }}))();",
                                   typeof(Func <byte>).GetCSharpRef(ToCSharpOptions.ForCodegen),
                                   typeof(NotImplementedException).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buf.Append("return unaligned != null ? unaligned.Alignment : defaultAlignment");
                p_Alignment.Getter = buf.ToString();
            }
            else if (kb.Family == "initblk" || kb.Family == "cpblk")
            {
                kb.EnsurePrefix("IsVolatile", typeof(bool), "volatile");
                kb.EnsurePrefix("IsUnaligned", typeof(bool), "unaligned");
                var p_IsAligned = kb.EnsureProperty("IsAligned", typeof(bool));
                p_IsAligned.Getter = "!IsUnaligned";
                var p_Alignment = kb.EnsureProperty("Alignment", typeof(byte));
                var buf         = new StringBuilder();
                buf.AppendLine(String.Format(
                                   "var unaligned = {0}.SingleOrDefault({0}.OfType<{1}>(Prefixes));",
                                   typeof(Enumerable).GetCSharpRef(ToCSharpOptions.ForCodegen),
                                   "Unaligned"));
                buf.AppendLine(String.Format(
                                   "var defaultAlignment = ({0}){1}.SizeOf(typeof({2}));",
                                   typeof(byte).GetCSharpRef(ToCSharpOptions.ForCodegen),
                                   typeof(Marshal).GetCSharpRef(ToCSharpOptions.ForCodegen),
                                   typeof(IntPtr).GetCSharpRef(ToCSharpOptions.ForCodegen)));
                buf.Append("return unaligned != null ? unaligned.Alignment : defaultAlignment");
                p_Alignment.Getter   = buf.ToString();
                p_Alignment.IsUnsafe = true;
            }
            else
            {
                // so that we never miss any other instructions with arguments
                (kb.OpCode.OperandType == OperandType.InlineNone).AssertTrue();
            }
        }