ILRuntime学习笔记(六)——提升使用值类型的性能

提升使用值类型的性能

1.由于在热更里面值类型会有装箱操作,调用时性能较低。
2.Vector3等Unity常用值类型如果不做任何处理,在ILRuntime中使用会产生较多额外的CPU开销和GC Alloc。
3.我们通过值类型绑定可以解决这个问题,只有Unity主工程的值类型才需要此处理,热更DLL内定义的值类型不需要任何处理。
4.请注释或者解注InitializeILRuntime里的代码来对比进行值类型绑定前后的性能差别。

先看看运行效果
未绑定前:
在这里插入图片描述
未绑定后:
在这里插入图片描述
GC Alloc降低了好几倍

注册方法:

    void InitializeILRuntime()
    {
    
    
#if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE)
        //由于Unity的Profiler接口只允许在主线程使用,为了避免出异常,需要告诉ILRuntime主线程的线程ID才能正确将函数运行耗时报告给Profiler
        appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
#endif
        //这里做一些ILRuntime的注册,这里我们注册值类型Binder,注释和解注下面的代码来对比性能差别
        appdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
        appdomain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder());
        appdomain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder());
    }

主工程:

QuaternionBinder.cs如下:

using UnityEngine;
using System.Collections.Generic;
using ILRuntime.Other;
using System;
using System.Reflection;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.Runtime.Stack;

public unsafe class QuaternionBinder : ValueTypeBinder<Quaternion>
{
    
    
    Vector3Binder vector3Binder;
    bool vector3BinderGot;

    Vector3Binder Vector3Binder
    {
    
    
        get
        {
    
    
            if (!vector3BinderGot)
            {
    
    
                vector3BinderGot = true;
                var vector3Type = CLRType.AppDomain.GetType(typeof(Vector3)) as CLRType;
                vector3Binder = vector3Type.ValueTypeBinder as Vector3Binder;
            }

            return vector3Binder;
        }
    }

    public override unsafe void AssignFromStack(ref Quaternion ins, StackObject* ptr, IList<object> mStack)
    {
    
    
        var v = ILIntepreter.Minus(ptr, 1);
        ins.x = *(float*)&v->Value;
        v = ILIntepreter.Minus(ptr, 2);
        ins.y = *(float*)&v->Value;
        v = ILIntepreter.Minus(ptr, 3);
        ins.z = *(float*)&v->Value;
        v = ILIntepreter.Minus(ptr, 4);
        ins.w = *(float*)&v->Value;
    }

    public override unsafe void CopyValueTypeToStack(ref Quaternion ins, StackObject* ptr, IList<object> mStack)
    {
    
    
        var v = ILIntepreter.Minus(ptr, 1);
        *(float*)&v->Value = ins.x;
        v = ILIntepreter.Minus(ptr, 2);
        *(float*)&v->Value = ins.y;
        v = ILIntepreter.Minus(ptr, 3);
        *(float*)&v->Value = ins.z;
        v = ILIntepreter.Minus(ptr, 4);
        *(float*)&v->Value = ins.w;
    }
    public override void RegisterCLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
    {
    
    
        BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
        MethodBase method;
        Type[] args;
        Type type = typeof(Quaternion);
        args = new Type[] {
    
     typeof(float), typeof(float), typeof(float), typeof(float) };
        method = type.GetConstructor(flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, NewQuaternion);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Quaternion) };
        method = type.GetMethod("op_Multiply", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Multiply);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Vector3) };
        method = type.GetMethod("op_Multiply", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Multiply2);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Quaternion) };
        method = type.GetMethod("op_Equality", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Equality);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Quaternion) };
        method = type.GetMethod("op_Inequality", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Inequality);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Quaternion) };
        method = type.GetMethod("Dot", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Dot);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Quaternion) };
        method = type.GetMethod("Angle", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Angle);

        args = new Type[] {
    
     typeof(Quaternion), typeof(Quaternion), typeof(float) };
        method = type.GetMethod("Slerp", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Slerp);

        args = new Type[] {
    
     typeof(Vector3) };
        method = type.GetMethod("Euler", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Euler);

        args = new Type[] {
    
     typeof(float), typeof(float), typeof(float) };
        method = type.GetMethod("Euler", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Quaternion_Euler2);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_eulerAngles", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_EulerAngle);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_identity", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Identity);
    }

    StackObject* Quaternion_Multiply(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        Quaternion left, right;

        var ptr = ILIntepreter.Minus(esp, 1);
        ParseQuaternion(out right, intp, ptr, mStack);
        
        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out left, intp, ptr, mStack);

        var res = left * right;
        PushQuaternion(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Quaternion_Multiply2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        Vector3 vec;
        Quaternion left;

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3Binder.ParseVector3(out vec, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out left, intp, ptr, mStack);

        vec = left * vec;
        PushVector3(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Quaternion_Equality(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Quaternion left, right;
        ParseQuaternion(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out left, intp, ptr, mStack);

        var res = left == right;

        ret->ObjectType = ObjectTypes.Integer;
        ret->Value = res ? 1 : 0;
        return ret + 1;
    }

    StackObject* Quaternion_Inequality(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Quaternion left, right;
        ParseQuaternion(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out left, intp, ptr, mStack);

        var res = left != right;

        ret->ObjectType = ObjectTypes.Integer;
        ret->Value = res ? 1 : 0;
        return ret + 1;
    }

    StackObject* Quaternion_Dot(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Quaternion left, right;
        ParseQuaternion(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out left, intp, ptr, mStack);

        var res = Quaternion.Dot(left, right);

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Quaternion_Angle(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Quaternion left, right;
        ParseQuaternion(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out left, intp, ptr, mStack);

        var res = Quaternion.Angle(left, right);

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Quaternion_Euler(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 vec;
        Vector3Binder.ParseVector3(out vec, intp, ptr, mStack);

        var res = Quaternion.Euler(vec);

        PushQuaternion(ref res, intp, ptr, mStack);
        return ret + 1;
    }

    StackObject* Quaternion_Euler2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 3);
        float x, y, z;

        var ptr = ILIntepreter.GetObjectAndResolveReference(ILIntepreter.Minus(esp, 1));
        z = *(float*)&ptr->Value;

        ptr = ILIntepreter.GetObjectAndResolveReference(ILIntepreter.Minus(esp, 2));
        y = *(float*)&ptr->Value;

        ptr = ILIntepreter.GetObjectAndResolveReference(ILIntepreter.Minus(esp, 3));
        x = *(float*)&ptr->Value;

        var res = Quaternion.Euler(x, y, z);

        PushQuaternion(ref res, intp, ptr, mStack);
        return ret + 1;
    }

    StackObject* Quaternion_Slerp(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 3);
        Quaternion left, right;

        var ptr = ILIntepreter.Minus(esp, 1);
        float t = *(float*)&ptr->Value;

        ptr = ILIntepreter.Minus(esp, 2);
        ParseQuaternion(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 3);
        ParseQuaternion(out left, intp, ptr, mStack);

        var res = Quaternion.Slerp(left, right, t);
        PushQuaternion(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* NewQuaternion(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        StackObject* ret;
        if (isNewObj)
        {
    
    
            ret = ILIntepreter.Minus(esp, 3);
            Quaternion vec;
            var ptr = ILIntepreter.Minus(esp, 1);
            vec.w = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 2);
            vec.z = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 3);
            vec.y = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 4);
            vec.x = *(float*)&ptr->Value;

            PushQuaternion(ref vec, intp, ptr, mStack);
        }
        else
        {
    
    
            ret = ILIntepreter.Minus(esp, 5);
            var instance = ILIntepreter.GetObjectAndResolveReference(ret);
            var dst = *(StackObject**)&instance->Value;
            var f = ILIntepreter.Minus(dst, 1);
            var v = ILIntepreter.Minus(esp, 4);
            *f = *v;

            f = ILIntepreter.Minus(dst, 2);
            v = ILIntepreter.Minus(esp, 3);
            *f = *v;

            f = ILIntepreter.Minus(dst, 3);
            v = ILIntepreter.Minus(esp, 2);
            *f = *v;

            f = ILIntepreter.Minus(dst, 4);
            v = ILIntepreter.Minus(esp, 1);
            *f = *v;
        }
        return ret;
    }

    StackObject* Get_EulerAngle(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Quaternion vec;
        ParseQuaternion(out vec, intp, ptr, mStack);

        var res = vec.eulerAngles;

        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Identity(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;

        var res = Quaternion.identity;
        PushQuaternion(ref res, intp, ret, mStack);
        return ret + 1;
    }

    static void ParseQuaternion(out Quaternion vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        var a = ILIntepreter.GetObjectAndResolveReference(ptr);
        if (a->ObjectType == ObjectTypes.ValueTypeObjectReference)
        {
    
    
            var src = *(StackObject**)&a->Value;
            vec.x = *(float*)&ILIntepreter.Minus(src, 1)->Value;
            vec.y = *(float*)&ILIntepreter.Minus(src, 2)->Value;
            vec.z = *(float*)&ILIntepreter.Minus(src, 3)->Value;
            vec.w = *(float*)&ILIntepreter.Minus(src, 4)->Value;
            intp.FreeStackValueType(ptr);
        }
        else
        {
    
    
            vec = (Quaternion)StackObject.ToObject(a, intp.AppDomain, mStack);
            intp.Free(ptr);
        }
    }

    void PushQuaternion(ref Quaternion vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        intp.AllocValueType(ptr, CLRType);
        var dst = *((StackObject**)&ptr->Value);
        CopyValueTypeToStack(ref vec, dst, mStack);
    }

    void PushVector3(ref Vector3 vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        var binder = Vector3Binder;
        if (binder != null)
            binder.PushVector3(ref vec, intp, ptr, mStack);
        else
            ILIntepreter.PushObject(ptr, mStack, vec, true);
    }
}

Vector2Binder.cs如下:

using UnityEngine;
using System.Collections.Generic;
using ILRuntime.Other;
using System;
using System.Reflection;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.CLR.Method;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.Runtime.Stack;

public unsafe class Vector2Binder : ValueTypeBinder<Vector2>
{
    
    
    Vector3Binder vector3Binder;
    bool vector3BinderGot;

    Vector3Binder Vector3Binder
    {
    
    
        get
        {
    
    
            if (!vector3BinderGot)
            {
    
    
                vector3BinderGot = true;
                var vector3Type = CLRType.AppDomain.GetType(typeof(Vector3)) as CLRType;
                vector3Binder = vector3Type.ValueTypeBinder as Vector3Binder;
            }

            return vector3Binder;
        }
    }

    public override unsafe void AssignFromStack(ref Vector2 ins, StackObject* ptr, IList<object> mStack)
    {
    
    
        var v = ILIntepreter.Minus(ptr, 1);
        ins.x = *(float*)&v->Value;
        v = ILIntepreter.Minus(ptr, 2);
        ins.y = *(float*)&v->Value;
    }

    public override unsafe void CopyValueTypeToStack(ref Vector2 ins, StackObject* ptr, IList<object> mStack)
    {
    
    
        var v = ILIntepreter.Minus(ptr, 1);
        *(float*)&v->Value = ins.x;
        v = ILIntepreter.Minus(ptr, 2);
        *(float*)&v->Value = ins.y;
    }
    public override void RegisterCLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
    {
    
    
        BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
        MethodBase method;
        Type[] args;
        Type type = typeof(Vector2);
        args = new Type[] {
    
     typeof(float), typeof(float) };
        method = type.GetConstructor(flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, NewVector2);

        args = new Type[] {
    
     typeof(Vector2), typeof(Vector2) };
        method = type.GetMethod("op_Addition", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Add);

        args = new Type[] {
    
     typeof(Vector2), typeof(Vector2) };
        method = type.GetMethod("op_Subtraction", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Subtraction);

        args = new Type[] {
    
     typeof(Vector2), typeof(float) };
        method = type.GetMethod("op_Multiply", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Multiply);

        args = new Type[] {
    
     typeof(float), typeof(Vector2) };
        method = type.GetMethod("op_Multiply", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Multiply2);

        args = new Type[] {
    
     typeof(Vector2), typeof(float) };
        method = type.GetMethod("op_Division", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Division);

        args = new Type[] {
    
     typeof(Vector2) };
        method = type.GetMethod("op_UnaryNegation", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Negate);

        args = new Type[] {
    
     typeof(Vector2), typeof(Vector2) };
        method = type.GetMethod("op_Equality", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Equality);

        args = new Type[] {
    
     typeof(Vector2), typeof(Vector2) };
        method = type.GetMethod("op_Inequality", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Inequality);

        args = new Type[] {
    
     typeof(Vector2) };
        method = type.GetMethod("op_Implicit", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Implicit);

        args = new Type[] {
    
     typeof(Vector3) };
        method = type.GetMethod("op_Implicit", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Implicit2);

        args = new Type[] {
    
     typeof(Vector2), typeof(Vector2) };
        method = type.GetMethod("Dot", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Dot);

        args = new Type[] {
    
     typeof(Vector2), typeof(Vector2) };
        method = type.GetMethod("Distance", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector2_Distance);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_magnitude", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Magnitude);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_sqrMagnitude", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_SqrMagnitude);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_normalized", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Normalized);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_one", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_One);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_zero", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Zero);
    }

    StackObject* Vector2_Add(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector2 left, right;
        ParseVector2(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out left, intp, ptr, mStack);

        var res = left + right;
        PushVector2(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Subtraction(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector2 left, right;
        ParseVector2(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out left, intp, ptr, mStack);

        var res = left - right;
        PushVector2(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Multiply(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);

        var ptr = ILIntepreter.Minus(esp, 1);
        var b = ILIntepreter.GetObjectAndResolveReference(ptr);

        float val = *(float*)&b->Value;

        Vector2 vec;

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out vec, intp, ptr, mStack);

        vec = vec * val;
        PushVector2(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Multiply2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        Vector2 vec;

        var ptr = ILIntepreter.Minus(esp, 1);
        ParseVector2(out vec, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        var b = ILIntepreter.GetObjectAndResolveReference(ptr);

        float val = *(float*)&b->Value;

        vec = val * vec;
        PushVector2(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Division(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);

        var ptr = ILIntepreter.Minus(esp, 1);
        var b = ILIntepreter.GetObjectAndResolveReference(ptr);

        float val = *(float*)&b->Value;

        Vector2 vec;

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out vec, intp, ptr, mStack);

        vec = vec / val;
        PushVector2(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Negate(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector2 vec;

        ptr = ILIntepreter.Minus(esp, 1);
        ParseVector2(out vec, intp, ptr, mStack);

        vec = -vec;
        PushVector2(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Implicit(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector2 vec;

        ptr = ILIntepreter.Minus(esp, 1);
        ParseVector2(out vec, intp, ptr, mStack);

        Vector3 res = vec;
        PushVector3(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Implicit2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3 vec;

        ptr = ILIntepreter.Minus(esp, 1);
        Vector3Binder.ParseVector3(out vec, intp, ptr, mStack);

        Vector2 res = vec;
        PushVector2(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector2_Equality(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector2 left, right;
        ParseVector2(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out left, intp, ptr, mStack);

        var res = left == right;

        ret->ObjectType = ObjectTypes.Integer;
        ret->Value = res ? 1 : 0;
        return ret + 1;
    }

    StackObject* Vector2_Inequality(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector2 left, right;
        ParseVector2(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out left, intp, ptr, mStack);

        var res = left != right;

        ret->ObjectType = ObjectTypes.Integer;
        ret->Value = res ? 1 : 0;
        return ret + 1;
    }

    StackObject* Vector2_Dot(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector2 left, right;
        ParseVector2(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out left, intp, ptr, mStack);

        var res = Vector3.Dot(left, right);

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Vector2_Distance(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector2 left, right;
        ParseVector2(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector2(out left, intp, ptr, mStack);

        var res = Vector3.Distance(left, right);

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }        

    StackObject* NewVector2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        StackObject* ret;
        if (isNewObj)
        {
    
    
            ret = ILIntepreter.Minus(esp, 1);
            Vector2 vec;
            var ptr = ILIntepreter.Minus(esp, 1);
            vec.y = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 2);
            vec.x = *(float*)&ptr->Value;

            PushVector2(ref vec, intp, ptr, mStack);
        }
        else
        {
    
    
            ret = ILIntepreter.Minus(esp, 3);
            var instance = ILIntepreter.GetObjectAndResolveReference(ret);
            var dst = *(StackObject**)&instance->Value;
            var f = ILIntepreter.Minus(dst, 1);
            var v = ILIntepreter.Minus(esp, 2);
            *f = *v;

            f = ILIntepreter.Minus(dst, 2);
            v = ILIntepreter.Minus(esp, 1);
            *f = *v;
        }
        return ret;
    }

    StackObject* Get_Magnitude(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector2 vec;
        ParseVector2(out vec, intp, ptr, mStack);

        float res = vec.magnitude;

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Get_SqrMagnitude(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector2 vec;
        ParseVector2(out vec, intp, ptr, mStack);

        float res = vec.sqrMagnitude;

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Get_Normalized(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);
        var ptr = ILIntepreter.Minus(esp, 1);
        Vector2 vec;
        ParseVector2(out vec, intp, ptr, mStack);

        var res = vec.normalized;

        PushVector2(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_One(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector2.one;
        PushVector2(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Zero(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector2.zero;
        PushVector2(ref res, intp, ret, mStack);
        return ret + 1;
    }

    public static void ParseVector2(out Vector2 vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        var a = ILIntepreter.GetObjectAndResolveReference(ptr);
        if (a->ObjectType == ObjectTypes.ValueTypeObjectReference)
        {
    
    
            var src = *(StackObject**)&a->Value;
            vec.x = *(float*)&ILIntepreter.Minus(src, 1)->Value;
            vec.y = *(float*)&ILIntepreter.Minus(src, 2)->Value;
            intp.FreeStackValueType(ptr);
        }
        else
        {
    
    
            vec = (Vector2)StackObject.ToObject(a, intp.AppDomain, mStack);
            intp.Free(ptr);
        }
    }

    public void PushVector2(ref Vector2 vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        intp.AllocValueType(ptr, CLRType);
        var dst = *((StackObject**)&ptr->Value);
        CopyValueTypeToStack(ref vec, dst, mStack);
    }

    void PushVector3(ref Vector3 vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        var binder = Vector3Binder;
        if (binder != null)
            binder.PushVector3(ref vec, intp, ptr, mStack);
        else
            ILIntepreter.PushObject(ptr, mStack, vec, true);
    }
}

Vector3Binder.cs如下:

using UnityEngine;
using System.Collections.Generic;
using ILRuntime.Other;
using System;
using System.Reflection;
using ILRuntime.Runtime.Enviorment;
using ILRuntime.Runtime.Intepreter;
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Stack;

public unsafe class Vector3Binder : ValueTypeBinder<Vector3>
{
    
    
    public override unsafe void AssignFromStack(ref Vector3 ins, StackObject* ptr, IList<object> mStack)
    {
    
    
        var v = ILIntepreter.Minus(ptr, 1);
        ins.x = *(float*)&v->Value;
        v = ILIntepreter.Minus(ptr, 2);
        ins.y = *(float*)&v->Value;
        v = ILIntepreter.Minus(ptr, 3);
        ins.z = *(float*)&v->Value;
    }

    public override unsafe void CopyValueTypeToStack(ref Vector3 ins, StackObject* ptr, IList<object> mStack)
    {
    
    
        var v = ILIntepreter.Minus(ptr, 1);
        *(float*)&v->Value = ins.x;
        v = ILIntepreter.Minus(ptr, 2);
        *(float*)&v->Value = ins.y;
        v = ILIntepreter.Minus(ptr, 3);
        *(float*)&v->Value = ins.z;
    }
    public override void RegisterCLRRedirection(ILRuntime.Runtime.Enviorment.AppDomain appdomain)
    {
    
    
        BindingFlags flag = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.DeclaredOnly;
        MethodBase method;
        Type[] args;
        Type type = typeof(Vector3);
        args = new Type[] {
    
     typeof(float), typeof(float), typeof(float) };
        method = type.GetConstructor(flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, NewVector3);

        args = new Type[] {
    
     typeof(float), typeof(float) };
        method = type.GetConstructor(flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, NewVector3_2);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("op_Addition", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Add);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("op_Subtraction", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Subtraction);

        args = new Type[] {
    
     typeof(Vector3), typeof(float) };
        method = type.GetMethod("op_Multiply", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Multiply);

        args = new Type[] {
    
     typeof(float), typeof(Vector3) };
        method = type.GetMethod("op_Multiply", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Multiply2);

        args = new Type[] {
    
     typeof(Vector3), typeof(float) };
        method = type.GetMethod("op_Division", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Division);

        args = new Type[] {
    
     typeof(Vector3) };
        method = type.GetMethod("op_UnaryNegation", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Negate);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("op_Equality", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Equality);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("op_Inequality", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Inequality);

        args = new Type[] {
    
     typeof(Vector3) };
        method = type.GetMethod("Normalize", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Normalize);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("Dot", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Dot);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("Cross", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Cross);

        args = new Type[] {
    
     typeof(Vector3), typeof(Vector3) };
        method = type.GetMethod("Distance", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Vector3_Distance);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_magnitude", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Magnitude);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_sqrMagnitude", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_SqrMagnitude);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_normalized", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Normalized);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_one", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_One);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_zero", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Zero);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_up", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Up);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_down", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Down);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_left", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Left);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_right", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Right);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_forward", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Forward);

        args = new Type[] {
    
     };
        method = type.GetMethod("get_back", flag, null, args, null);
        appdomain.RegisterCLRMethodRedirection(method, Get_Back);
    }

    StackObject* Vector3_Add(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = left + right;
        PushVector3(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Subtraction(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = left - right;
        PushVector3(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Multiply(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);

        var ptr = ILIntepreter.Minus(esp, 1);
        var b = ILIntepreter.GetObjectAndResolveReference(ptr);

        float val = *(float*)&b->Value;

        Vector3 vec;

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out vec, intp, ptr, mStack);

        vec = vec * val;
        PushVector3(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Multiply2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        Vector3 vec;

        var ptr = ILIntepreter.Minus(esp, 1);
        ParseVector3(out vec, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        var b = ILIntepreter.GetObjectAndResolveReference(ptr);

        float val = *(float*)&b->Value;

        vec = val * vec;
        PushVector3(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Division(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);

        var ptr = ILIntepreter.Minus(esp, 1);
        var b = ILIntepreter.GetObjectAndResolveReference(ptr);

        float val = *(float*)&b->Value;

        Vector3 vec;

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out vec, intp, ptr, mStack);

        vec = vec / val;
        PushVector3(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Negate(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3 vec;

        ptr = ILIntepreter.Minus(esp, 1);
        ParseVector3(out vec, intp, ptr, mStack);

        vec = -vec;
        PushVector3(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Normalize(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3 vec;

        ptr = ILIntepreter.Minus(esp, 1);
        ParseVector3(out vec, intp, ptr, mStack);

        vec = Vector3.Normalize(vec);
        PushVector3(ref vec, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* Vector3_Equality(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = left == right;

        ret->ObjectType = ObjectTypes.Integer;
        ret->Value = res ? 1 : 0;
        return ret + 1;
    }

    StackObject* Vector3_Inequality(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = left != right;

        ret->ObjectType = ObjectTypes.Integer;
        ret->Value = res ? 1 : 0;
        return ret + 1;
    }

    StackObject* Vector3_Dot(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = Vector3.Dot(left, right);

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Vector3_Distance(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = Vector3.Distance(left, right);

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Vector3_Cross(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 2);
        var ptr = ILIntepreter.Minus(esp, 1);

        Vector3 left, right;
        ParseVector3(out right, intp, ptr, mStack);

        ptr = ILIntepreter.Minus(esp, 2);
        ParseVector3(out left, intp, ptr, mStack);

        var res = Vector3.Cross(left, right);
        PushVector3(ref res, intp, ret, mStack);

        return ret + 1;
    }

    StackObject* NewVector3(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        StackObject* ret;
        if (isNewObj)
        {
    
    
            ret = ILIntepreter.Minus(esp, 2);
            Vector3 vec;
            var ptr = ILIntepreter.Minus(esp, 1);
            vec.z = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 2);
            vec.y = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 3);
            vec.x = *(float*)&ptr->Value;

            PushVector3(ref vec, intp, ptr, mStack);
        }
        else
        {
    
    
            ret = ILIntepreter.Minus(esp, 4);
            var instance = ILIntepreter.GetObjectAndResolveReference(ret);
            var dst = *(StackObject**)&instance->Value;
            var f = ILIntepreter.Minus(dst, 1);
            var v = ILIntepreter.Minus(esp, 3);
            *f = *v;

            f = ILIntepreter.Minus(dst, 2);
            v = ILIntepreter.Minus(esp, 2);
            *f = *v;

            f = ILIntepreter.Minus(dst, 3);
            v = ILIntepreter.Minus(esp, 1);
            *f = *v;
        }
        return ret;
    }
    StackObject* NewVector3_2(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        StackObject* ret;
        if (isNewObj)
        {
    
    
            ret = ILIntepreter.Minus(esp, 1);
            Vector3 vec;
            var ptr = ILIntepreter.Minus(esp, 1);
            vec.y = *(float*)&ptr->Value;
            ptr = ILIntepreter.Minus(esp, 2);
            vec.x = *(float*)&ptr->Value;
            vec.z = 0;

            PushVector3(ref vec, intp, ptr, mStack);
        }
        else
        {
    
    
            ret = ILIntepreter.Minus(esp, 3);
            var instance = ILIntepreter.GetObjectAndResolveReference(ret);
            var dst = *(StackObject**)&instance->Value;
            var f = ILIntepreter.Minus(dst, 1);
            var v = ILIntepreter.Minus(esp, 2);
            *f = *v;

            f = ILIntepreter.Minus(dst, 2);
            v = ILIntepreter.Minus(esp, 1);
            *f = *v;

            f = ILIntepreter.Minus(dst, 3);
            *(float*)&f->Value = 0f;
        }
        return ret;
    }

    StackObject* Get_Magnitude(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3 vec;
        ParseVector3(out vec, intp, ptr, mStack);

        float res = vec.magnitude;

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Get_SqrMagnitude(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);

        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3 vec;
        ParseVector3(out vec, intp, ptr, mStack);

        float res = vec.sqrMagnitude;

        ret->ObjectType = ObjectTypes.Float;
        *(float*)&ret->Value = res;
        return ret + 1;
    }

    StackObject* Get_Normalized(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = ILIntepreter.Minus(esp, 1);
        var ptr = ILIntepreter.Minus(esp, 1);
        Vector3 vec;
        ParseVector3(out vec, intp, ptr, mStack);

        var res = vec.normalized;

        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_One(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.one;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Zero(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.zero;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Up(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.up;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Down(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.down;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Left(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.left;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Right(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.right;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Forward(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.forward;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }

    StackObject* Get_Back(ILIntepreter intp, StackObject* esp, IList<object> mStack, CLRMethod method, bool isNewObj)
    {
    
    
        var ret = esp;
        var res = Vector3.back;
        PushVector3(ref res, intp, ret, mStack);
        return ret + 1;
    }


    public static void ParseVector3(out Vector3 vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        var a = ILIntepreter.GetObjectAndResolveReference(ptr);
        if (a->ObjectType == ObjectTypes.ValueTypeObjectReference)
        {
    
    
            var src = *(StackObject**)&a->Value;
            vec.x = *(float*)&ILIntepreter.Minus(src, 1)->Value;
            vec.y = *(float*)&ILIntepreter.Minus(src, 2)->Value;
            vec.z = *(float*)&ILIntepreter.Minus(src, 3)->Value;
            intp.FreeStackValueType(ptr);
        }
        else
        {
    
    
            vec = (Vector3)StackObject.ToObject(a, intp.AppDomain, mStack);
            intp.Free(ptr);
        }
    }

    public void PushVector3(ref Vector3 vec, ILIntepreter intp, StackObject* ptr, IList<object> mStack)
    {
    
    
        intp.AllocValueType(ptr, CLRType);
        var dst = *((StackObject**)&ptr->Value);
        CopyValueTypeToStack(ref vec, dst, mStack);
    }
}

ValueTypeBindingDemo.cs如下:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using ILRuntime.CLR.TypeSystem;
using ILRuntime.CLR.Method;
using ILRuntime.Runtime.Enviorment;
//下面这行为了取消使用WWW的警告,Unity2018以后推荐使用UnityWebRequest,处于兼容性考虑Demo依然使用WWW
#pragma warning disable CS0618

public class ValueTypeBindingDemo : MonoBehaviour
{
    
    
    //AppDomain是ILRuntime的入口,最好是在一个单例类中保存,整个游戏全局就一个,这里为了示例方便,每个例子里面都单独做了一个
    //大家在正式项目中请全局只创建一个AppDomain
    AppDomain appdomain;
    System.IO.MemoryStream fs;
    System.IO.MemoryStream p;

    void Start()
    {
    
    
        StartCoroutine(LoadHotFixAssembly());
    }

    IEnumerator LoadHotFixAssembly()
    {
    
    
        //首先实例化ILRuntime的AppDomain,AppDomain是一个应用程序域,每个AppDomain都是一个独立的沙盒
        appdomain = new ILRuntime.Runtime.Enviorment.AppDomain();
        //正常项目中应该是自行从其他地方下载dll,或者打包在AssetBundle中读取,平时开发以及为了演示方便直接从StreammingAssets中读取,
        //正式发布的时候需要大家自行从其他地方读取dll

        //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        //这个DLL文件是直接编译HotFix_Project.sln生成的,已经在项目中设置好输出目录为StreamingAssets,在VS里直接编译即可生成到对应目录,无需手动拷贝
#if UNITY_ANDROID
        WWW www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.dll");
#else
        WWW www = new WWW("file:///" + Application.streamingAssetsPath + "/HotFix_Project.dll");
#endif
        while (!www.isDone)
            yield return null;
        if (!string.IsNullOrEmpty(www.error))
            UnityEngine.Debug.LogError(www.error);
        byte[] dll = www.bytes;
        www.Dispose();

        //PDB文件是调试数据库,如需要在日志中显示报错的行号,则必须提供PDB文件,不过由于会额外耗用内存,正式发布时请将PDB去掉,下面LoadAssembly的时候pdb传null即可
#if UNITY_ANDROID
        www = new WWW(Application.streamingAssetsPath + "/HotFix_Project.pdb");
#else
        www = new WWW("file:///" + Application.streamingAssetsPath + "/HotFix_Project.pdb");
#endif
        while (!www.isDone)
            yield return null;
        if (!string.IsNullOrEmpty(www.error))
            UnityEngine.Debug.LogError(www.error);
        byte[] pdb = www.bytes;
        fs = new MemoryStream(dll);
        p = new MemoryStream(pdb);
        try
        {
    
    
            appdomain.LoadAssembly(fs, p, new ILRuntime.Mono.Cecil.Pdb.PdbReaderProvider());
        }
        catch
        {
    
    
            Debug.LogError("加载热更DLL失败,请确保已经通过VS打开Assets/Samples/ILRuntime/1.6/Demo/HotFix_Project/HotFix_Project.sln编译过热更DLL");
        }

        InitializeILRuntime();
        yield return new WaitForSeconds(0.5f);
        RunTest();
        yield return new WaitForSeconds(0.5f);
        RunTest2();
        yield return new WaitForSeconds(0.5f);
        RunTest3();
    }

    void InitializeILRuntime()
    {
    
    
#if DEBUG && (UNITY_EDITOR || UNITY_ANDROID || UNITY_IPHONE)
        //由于Unity的Profiler接口只允许在主线程使用,为了避免出异常,需要告诉ILRuntime主线程的线程ID才能正确将函数运行耗时报告给Profiler
        appdomain.UnityMainThreadID = System.Threading.Thread.CurrentThread.ManagedThreadId;
#endif
        //这里做一些ILRuntime的注册,这里我们注册值类型Binder,注释和解注下面的代码来对比性能差别
        appdomain.RegisterValueTypeBinder(typeof(Vector3), new Vector3Binder());
        appdomain.RegisterValueTypeBinder(typeof(Quaternion), new QuaternionBinder());
        appdomain.RegisterValueTypeBinder(typeof(Vector2), new Vector2Binder());
    }

    void RunTest()
    {
    
    
        Debug.Log("Vector3等Unity常用值类型如果不做任何处理,在ILRuntime中使用会产生较多额外的CPU开销和GC Alloc");
        Debug.Log("我们通过值类型绑定可以解决这个问题,只有Unity主工程的值类型才需要此处理,热更DLL内定义的值类型不需要任何处理");        
        Debug.Log("请注释或者解注InitializeILRuntime里的代码来对比进行值类型绑定前后的性能差别");
        //调用无参数静态方法,appdomain.Invoke("类名", "方法名", 对象引用, 参数列表);
        appdomain.Invoke("HotFix_Project.TestValueType", "RunTest", null, null);
    }

    void RunTest2()
    {
    
    
        Debug.Log("=======================================");
        Debug.Log("Quaternion测试");
        //调用无参数静态方法,appdomain.Invoke("类名", "方法名", 对象引用, 参数列表);
        appdomain.Invoke("HotFix_Project.TestValueType", "RunTest2", null, null);
    }

    void RunTest3()
    {
    
    
        Debug.Log("=======================================");
        Debug.Log("Vector2测试");
        //调用无参数静态方法,appdomain.Invoke("类名", "方法名", 对象引用, 参数列表);
        appdomain.Invoke("HotFix_Project.TestValueType", "RunTest3", null, null);
    }

    private void OnDestroy()
    {
    
    
        if (fs != null)
            fs.Close();
        if (p != null)
            p.Close();
        fs = null;
        p = null;
    }
}

热更工程:

using System;
using System.Collections.Generic;
using UnityEngine;

namespace HotFix_Project
{
    
    
    class TestValueType
    {
    
    
        public static void RunTest()
        {
    
    
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            //Debug.Log("测试Vector3的各种运算");
            Vector3 a = new Vector3(1, 2, 3);
            Vector3 b = Vector3.one;

            Debug.Log("a + b = " + (a + b));
            Debug.Log("a - b = " + (a - b));
            Debug.Log("a * 2 = " + (a * 2));
            Debug.Log("2 * a = " + (2 * a));
            Debug.Log("a / 2 = " + (a / 2));
            Debug.Log("-a = " + (-a));
            Debug.Log("a == b = " + (a == b));
            Debug.Log("a != b = " + (a != b));
            Debug.Log("a dot b = " + Vector3.Dot(a, b));
            Debug.Log("a cross b = " + Vector3.Cross(a, b));
            Debug.Log("a distance b = " + Vector3.Distance(a, b));
            Debug.Log("a.magnitude = " + a.magnitude);
            Debug.Log("a.normalized = " + a.normalized);
            Debug.Log("a.sqrMagnitude = " + a.sqrMagnitude);

            sw.Start();
            float dot = 0;
            for(int i = 0; i < 100000; i++)
            {
    
    
                a += Vector3.one;
                dot += Vector3.Dot(a, Vector3.zero);
            }
            sw.Stop();

            Debug.LogFormat("Value: a={0},dot={1}, time = {2}ms", a, dot, sw.ElapsedMilliseconds);
        }

        public static void RunTest2()
        {
    
    
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            //Debug.Log("测试Vector3的各种运算");
            Quaternion a = new Quaternion(1, 2, 3, 4);
            Quaternion b = Quaternion.identity;
            Vector3 c = new Vector3(2, 3, 4);

            Debug.Log("a * b = " + (a * b));
            Debug.Log("a * c = " + (a * c));
            Debug.Log("a == b = " + (a == b));
            Debug.Log("a != b = " + (a != b));
            Debug.Log("a dot b = " + Quaternion.Dot(a, b));
            Debug.Log("a angle b = " + Quaternion.Angle(a, b));
            Debug.Log("a.eulerAngles = " + a.eulerAngles);
            Debug.Log("Quaternion.Euler(c) = " + Quaternion.Euler(c));
            Debug.Log("Quaternion.Euler(2,3,4) = " + Quaternion.Euler(2, 3, 4));

            sw.Start();
            var rot = Quaternion.Euler(c);
            float dot = 0;
            for (int i = 0; i < 100000; i++)
            {
    
    
                a *= rot;
                dot += Quaternion.Dot(a, b);
            }
            sw.Stop();

            Debug.LogFormat("Value: a={0},dot={1}, time = {2}ms", a, dot, sw.ElapsedMilliseconds);
        }

        public static void RunTest3()
        {
    
    
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
            //Debug.Log("测试Vector2的各种运算");
            Vector2 a = new Vector2(1, 2);
            Vector2 b = Vector2.one;

            Debug.Log("a + b = " + (a + b));
            Debug.Log("a - b = " + (a - b));
            Debug.Log("a * 2 = " + (a * 2));
            Debug.Log("2 * a = " + (2 * a));
            Debug.Log("a / 2 = " + (a / 2));
            Debug.Log("-a = " + (-a));
            Debug.Log("a == b = " + (a == b));
            Debug.Log("a != b = " + (a != b));
            Debug.Log("(Vector3)a = " + ((Vector3)a));
            Debug.Log("(Vector2)Vector3.one = " + ((Vector2)Vector3.one));
            Debug.Log("a dot b = " + Vector2.Dot(a, b));
            Debug.Log("a distance b = " + Vector2.Distance(a, b));
            Debug.Log("a.magnitude = " + a.magnitude);
            Debug.Log("a.normalized = " + a.normalized);
            Debug.Log("a.sqrMagnitude = " + a.sqrMagnitude);

            sw.Start();
            float dot = 0;
            for (int i = 0; i < 100000; i++)
            {
    
    
                a += Vector2.one;
                dot += Vector2.Dot(a, Vector2.zero);
            }
            sw.Stop();

            Debug.LogFormat("Value: a={0},dot={1}, time = {2}ms", a, dot, sw.ElapsedMilliseconds);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_45724919/article/details/129640785