提升使用值类型的性能
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);
}
}
}