StationObscurum/Assets/FishNet/CodeGenerating/cecil-0.11.4/rocks/Mono.Cecil.Rocks/ILParser.cs

229 lines
6.5 KiB
C#

//
// Author:
// Jb Evain (jbevain@gmail.com)
//
// Copyright (c) 2008 - 2015 Jb Evain
// Copyright (c) 2008 - 2011 Novell, Inc.
//
// Licensed under the MIT/X11 license.
//
using MonoFN.Cecil.Cil;
using MonoFN.Collections.Generic;
using System;
namespace MonoFN.Cecil.Rocks {
#if UNITY_EDITOR
public
#endif
interface IILVisitor {
void OnInlineNone (OpCode opcode);
void OnInlineSByte (OpCode opcode, sbyte value);
void OnInlineByte (OpCode opcode, byte value);
void OnInlineInt32 (OpCode opcode, int value);
void OnInlineInt64 (OpCode opcode, long value);
void OnInlineSingle (OpCode opcode, float value);
void OnInlineDouble (OpCode opcode, double value);
void OnInlineString (OpCode opcode, string value);
void OnInlineBranch (OpCode opcode, int offset);
void OnInlineSwitch (OpCode opcode, int [] offsets);
void OnInlineVariable (OpCode opcode, VariableDefinition variable);
void OnInlineArgument (OpCode opcode, ParameterDefinition parameter);
void OnInlineSignature (OpCode opcode, CallSite callSite);
void OnInlineType (OpCode opcode, TypeReference type);
void OnInlineField (OpCode opcode, FieldReference field);
void OnInlineMethod (OpCode opcode, MethodReference method);
}
#if UNITY_EDITOR
public
#endif
static class ILParser {
class ParseContext {
public CodeReader Code { get; set; }
public int Position { get; set; }
public MetadataReader Metadata { get; set; }
public Collection<VariableDefinition> Variables { get; set; }
public IILVisitor Visitor { get; set; }
}
public static void Parse (MethodDefinition method, IILVisitor visitor)
{
if (method == null)
throw new ArgumentNullException ("method");
if (visitor == null)
throw new ArgumentNullException ("visitor");
if (!method.HasBody || !method.HasImage)
throw new ArgumentException ();
method.Module.Read (method, (m, _) => {
ParseMethod (m, visitor);
return true;
});
}
static void ParseMethod (MethodDefinition method, IILVisitor visitor)
{
var context = CreateContext (method, visitor);
var code = context.Code;
var flags = code.ReadByte ();
switch (flags & 0x3) {
case 0x2: // tiny
int code_size = flags >> 2;
ParseCode (code_size, context);
break;
case 0x3: // fat
code.Advance (-1);
ParseFatMethod (context);
break;
default:
throw new NotSupportedException ();
}
code.MoveBackTo (context.Position);
}
static ParseContext CreateContext (MethodDefinition method, IILVisitor visitor)
{
var code = method.Module.Read (method, (_, reader) => reader.code);
var position = code.MoveTo (method);
return new ParseContext {
Code = code,
Position = position,
Metadata = code.reader,
Visitor = visitor,
};
}
static void ParseFatMethod (ParseContext context)
{
var code = context.Code;
code.Advance (4);
var code_size = code.ReadInt32 ();
var local_var_token = code.ReadToken ();
if (local_var_token != MetadataToken.Zero)
context.Variables = code.ReadVariables (local_var_token);
ParseCode (code_size, context);
}
static void ParseCode (int code_size, ParseContext context)
{
var code = context.Code;
var metadata = context.Metadata;
var visitor = context.Visitor;
var start = code.Position;
var end = start + code_size;
while (code.Position < end) {
var il_opcode = code.ReadByte ();
var opcode = il_opcode != 0xfe
? OpCodes.OneByteOpCode [il_opcode]
: OpCodes.TwoBytesOpCode [code.ReadByte ()];
switch (opcode.OperandType) {
case OperandType.InlineNone:
visitor.OnInlineNone (opcode);
break;
case OperandType.InlineSwitch:
var length = code.ReadInt32 ();
var branches = new int [length];
for (int i = 0; i < length; i++)
branches [i] = code.ReadInt32 ();
visitor.OnInlineSwitch (opcode, branches);
break;
case OperandType.ShortInlineBrTarget:
visitor.OnInlineBranch (opcode, code.ReadSByte ());
break;
case OperandType.InlineBrTarget:
visitor.OnInlineBranch (opcode, code.ReadInt32 ());
break;
case OperandType.ShortInlineI:
if (opcode == OpCodes.Ldc_I4_S)
visitor.OnInlineSByte (opcode, code.ReadSByte ());
else
visitor.OnInlineByte (opcode, code.ReadByte ());
break;
case OperandType.InlineI:
visitor.OnInlineInt32 (opcode, code.ReadInt32 ());
break;
case OperandType.InlineI8:
visitor.OnInlineInt64 (opcode, code.ReadInt64 ());
break;
case OperandType.ShortInlineR:
visitor.OnInlineSingle (opcode, code.ReadSingle ());
break;
case OperandType.InlineR:
visitor.OnInlineDouble (opcode, code.ReadDouble ());
break;
case OperandType.InlineSig:
visitor.OnInlineSignature (opcode, code.GetCallSite (code.ReadToken ()));
break;
case OperandType.InlineString:
visitor.OnInlineString (opcode, code.GetString (code.ReadToken ()));
break;
case OperandType.ShortInlineArg:
visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadByte ()));
break;
case OperandType.InlineArg:
visitor.OnInlineArgument (opcode, code.GetParameter (code.ReadInt16 ()));
break;
case OperandType.ShortInlineVar:
visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadByte ()));
break;
case OperandType.InlineVar:
visitor.OnInlineVariable (opcode, GetVariable (context, code.ReadInt16 ()));
break;
case OperandType.InlineTok:
case OperandType.InlineField:
case OperandType.InlineMethod:
case OperandType.InlineType:
var member = metadata.LookupToken (code.ReadToken ());
switch (member.MetadataToken.TokenType) {
case TokenType.TypeDef:
case TokenType.TypeRef:
case TokenType.TypeSpec:
visitor.OnInlineType (opcode, (TypeReference)member);
break;
case TokenType.Method:
case TokenType.MethodSpec:
visitor.OnInlineMethod (opcode, (MethodReference)member);
break;
case TokenType.Field:
visitor.OnInlineField (opcode, (FieldReference)member);
break;
case TokenType.MemberRef:
var field_ref = member as FieldReference;
if (field_ref != null) {
visitor.OnInlineField (opcode, field_ref);
break;
}
var method_ref = member as MethodReference;
if (method_ref != null) {
visitor.OnInlineMethod (opcode, method_ref);
break;
}
throw new InvalidOperationException ();
}
break;
}
}
}
static VariableDefinition GetVariable (ParseContext context, int index)
{
return context.Variables [index];
}
}
}