/// <summary> /// <para>如果栈顶部是值对象,那么该方法可以将顶部的对象拆箱成<paramref name="type"/>对应的值类型</para> /// <para>如果栈顶部是引用对象,那么该方法可以顶部的对象转换成<paramref name="type"/>对应的引用类型</para> /// <para>转换后的值会被存储在堆栈上</para> /// </summary> public MethodGenerator UnboxAny(Type type) { if (type == null) { throw new ArgumentNullException("type"); } var item = _evalStack.Pop(); StackAssert.IsAssignable(item, new StackItem(typeof(object), LoadOptions.BoxValues), false); _writer.Emit(OpCodes.Unbox_Any, type); _evalStack.Push(type); return(this); }
/// <summary> /// 封装了返回指令 /// </summary> public void Return() { if (_header.ReturnType != typeof(void)) { StackAssert.IsAssignable(_evalStack.Pop(), new StackItem(_header.ReturnType, LoadOptions.Default), true); } if (_evalStack.Count > 0) { throw new InvalidOperationException("在返回代码执行之前,计算堆栈上的所有数据应该已被移除."); } _writer.Emit(OpCodes.Ret); }
public override void Open() { var item = Owner._evalStack.Peek(); StackAssert.AreEqual(item, new StackItem(item.Type, LoadOptions.Default)); _targetDisposeMethod = UsingTarget.Type.GetBestCallableOverride(_disposeMethod); UsingTarget = Owner.Declare(item.Type); Owner.Store(UsingTarget); base.Open(); Owner._writer.BeginTry(); }
/// <summary> /// 三元运算 /// </summary> /// <param name="type"></param> /// <param name="options"></param> /// <param name="condition"></param> /// <param name="trueValue"></param> /// <param name="falseValue"></param> public void Ternary(Type type, LoadOptions options, Func <LogicOperator> condition, Action trueValue, Action falseValue) { if (condition == null) { throw new ArgumentNullException("condition"); } if (trueValue == null) { throw new ArgumentNullException("trueValue"); } if (falseValue == null) { throw new ArgumentNullException("falseValue"); } var trueLabel = _writer.DefineLabel(); var doneLabel = _writer.DefineLabel(); var c = condition(); GoToIf(c, trueLabel); int count = _evalStack.Count; falseValue(); if (_evalStack.Count != count + 1) { throw new StackValidationException("The ternary operator expects exactly one more item on the evaluation stack after falseValue completes"); } var falseResult = _evalStack.Pop(); StackAssert.IsAssignable(falseResult, new StackItem(type, options), true); _writer.Emit(OpCodes.Br, doneLabel); trueLabel.Mark(); count = _evalStack.Count(); trueValue(); if (_evalStack.Count != count + 1) { throw new StackValidationException("The ternary operator expects exactly one more item on the evaluation stack after trueValue completes"); } var trueResult = _evalStack.Pop(); StackAssert.IsAssignable(trueResult, new StackItem(type, options), true); doneLabel.Mark(); _evalStack.Push(type, options); }
/// <summary> /// 检查参数合法性,并从模拟计算堆栈中弹出参数 /// </summary> /// <param name="method"></param> private void PopAndValidateParams(MethodBase method) { var parameters = method.GetParameters(); for (int i = parameters.Length - 1; i >= 0; --i) { // 验证参数是否合法 StackAssert.IsAssignable(_evalStack.Pop(), new StackItem(parameters[i].ParameterType, LoadOptions.Default), true); } if (!method.IsStatic && !method.IsConstructor) { //如果不是静态方法或者构造方法,那么当前栈顶的数据,应该是this //即:方法所声明的类型 StackAssert.IsAssignable(_evalStack.Pop(), new StackItem(method.DeclaringType, LoadOptions.ValueAsAddress), false); } }
public void Convert(Type toType, bool withOverflowCheck) { var item = _evalStack.Pop(); StackAssert.IsPrimitive(item); OpCode conversionCode; if (_conversions.TryGetValue(new ConversionKey(toType, withOverflowCheck), out conversionCode)) { _writer.Emit(conversionCode); _evalStack.Push(toType); return; } throw new ArgumentException("不能转换类型 " + toType.Name, "toType"); }
/// <summary> /// <para>开始加载数组元素</para> /// <para>请在执行该方法之后,加载索引:</para> /// <code> /// g.BeginLoadElement(); /// { /// g.Load(i); /// } /// g.EndLoadElement(); /// </code> /// </summary> private void BeginLoadElement() { _delayedInstructions.Push(() => { //需要加载的成员的索引值 var item = _evalStack.Pop(); StackAssert.IsAssignable(item, new StackItem(typeof(int)), false);//检查索引值是否为int型 //目标数组 //此处是模拟弹出,用于效验 item = _evalStack.Pop(); StackAssert.IsAssignable(item, new StackItem(typeof(Array)), false);//检查弹出的项是否为array //var elementType = item.Type.GetElementType(); var elementType = item.Type.ResolveElementType(); _writer.EmitLdelem(elementType);//将指定数组索引中的元素加载到计算堆栈的顶部。 _evalStack.Push(elementType); }); }
/// <summary> /// <para>开始创建新的数组</para> /// <para>请在此方法时候,调用加载数组长度的方法,例如:</para> /// <code> /// g.BeginNewArray(_elementType); /// { /// g.Load(count); /// } /// g.EndNewArray(); /// </code> /// </summary> /// <param name="elementType">数组的成员类型</param> /// <param name="rank">维数</param> private void BeginNewArray(Type elementType, int rank) { if (elementType == null) { throw new ArgumentNullException("elementType"); } if (rank < 1) { throw new ArgumentOutOfRangeException("rank", "数组维度不能小于1"); } var arrayType = rank == 1 ? elementType.MakeArrayType() : elementType.MakeArrayType(rank); _delayedInstructions.Push(() => { for (int i = 0; i < rank; ++i) { StackAssert.AreEqual(_evalStack.Pop(), typeof(int)); } if (rank == 1) { //创建一维数组 //将对新的从零开始的一维数组(其元素属于特定类型)的对象引用推送到计算堆栈上 _writer.Emit(OpCodes.Newarr, elementType); } else { var paramTypes = new Type[rank]; for (int i = 0; i < paramTypes.Length; ++i) { paramTypes[i] = typeof(int); } //创建多维数组 //利用多维数组的构造函数,创建多维数组对象 _writer.Emit(OpCodes.Newobj, arrayType.GetConstructor(paramTypes)); } _evalStack.Push(arrayType); }); }
/// <summary> /// <para>开始将值存入数组指定的索引处</para> /// <para>示例代码:</para> /// <code> /// g.Load(context.Member); /// g.BeginStoreElement(); /// { /// g.Load(i); /// g.Load(element); /// } /// g.EndStoreElement(); /// </code> /// </summary> /// <remarks> /// 注意:由于BeginStoreElement前后,分为三步: /// 1.将对数组 array 的对象引用推送到堆栈上。 /// 2.将 array 中元素的索引值 index 推送到堆栈上。 /// 3.将指令中指定类型的值推送到堆栈上。 /// 因此,以下代码,要反向验证,即:堆栈顶部的数据为: /// 1.需要存储的值 /// 2.索引值 index /// 3.数组 array 的对象引用 /// </remarks> private void BeginStoreElement() { _delayedInstructions.Push(() => { //需要存储的值 var valueItem = _evalStack.Pop(); //验证索引值为int型 StackAssert.IsAssignable(_evalStack.Pop(), typeof(int), false); //将对数组 array 的对象引用推送到堆栈上。 var arrayItem = _evalStack.Pop(); //检查是否为array类型 StackAssert.IsAssignable(arrayItem, typeof(Array), false); Debug.Assert(arrayItem.Type.IsArray, "项必须存储在数组类型上"); var elementType = arrayItem.Type.GetElementType(); StackAssert.IsAssignable(valueItem, new StackItem(elementType, LoadOptions.Default), true); _writer.EmitStelem(elementType); }); }