diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f65ff87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +/Source/UnityProj/Assets/IFix/Binding.meta +/Source/UnityProj/Assets/IFix/Binding +/Source/UnityProj/Library +/Source/UnityProj/AndroidBuild +/Source/UnityProj/obj +/Source/UnityProj/Logs +/Source/UnityProj/.idea +/Source/UnityProj/.vs +/Source/UnityProj/Assembly-CSharp-firstpass.csproj +/Source/UnityProj/Assembly-CSharp-firstpass.patch.bytes +/Source/UnityProj/UnityProj.sln +/Source/UnityProj/UnityProj.sln.DotSettings.user +/Source/UnityProj/Assembly-CSharp.csproj +/Source/UnityProj/Assembly-CSharp.dll +/Source/UnityProj/Assembly-CSharp.patch.bytes +/Source/UnityProj/Assembly-CSharp-Editor.csproj +/Source/UnityProj/ProjectSettings +/Source/UnityProj/buildexe +/Source/UnityProj/buildvs +/Source/UnityProj/buildvs2 +/Source/VSProj/vs2013/.idea +/Source/VSProj/vs2013/obj +/Source/VSProj/vs2013/IFix.sln.DotSettings.user +/Source/UnityProj/Temp +/Source/VSProj/Lib +/Source/VSProj/Bin +/Source/VSProj/Data +/Source/UnityProj/UserSettings +/Source/UnityProj/Assets/Plugins/IFix.Core.pdb.meta +/Source/UnityProj/Assets/Plugins/IFix.Core.dll +/Source/UnityProj/Assets/Plugins/IFix.Core.pdb +/Source/UnityProj/IFixToolKit/IFix.exe.mdb +/Source/UnityProj/IFixToolKit/IFix.exe +/Source/UnityProj/Packages +/Source/UnityProj/Assets/Resources.meta +/Source/UnityProj/Assets/Resources +/Source/VSProj/Instruction.cs +/Source/VSProj/ShuffleInstruction.exe diff --git a/Source/UnityProj/Assets/Helloworld/Calc.cs b/Source/UnityProj/Assets/Helloworld/Calc.cs index 4d6bb5e..f4460ed 100644 --- a/Source/UnityProj/Assets/Helloworld/Calc.cs +++ b/Source/UnityProj/Assets/Helloworld/Calc.cs @@ -1,35 +1,116 @@ /* * Tencent is pleased to support the open source community by making InjectFix available. * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. + * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ -namespace IFix.Test + +//HelloworldCfg.cs里配置了这个类型 + +using System; +using IFix; +using UnityEngine; + +public enum TestEnumValue +{ + t1 = 1, + t2 = 2, +} + +public struct AllValueStruct +{ + public int x; +} + +public struct ChildClassStruct +{ + public ClassStruct cs; +} + +public struct ClassStruct { - //HelloworldCfg.cs里配置了这个类型 - public class Calculator + public GameObject go; +} + +public class Calculator +{ + private TestEnumValue thisEnum = TestEnumValue.t2; + private Vector3 v = Vector3.right; + private Vector3? nullableV1 = null; + private Vector3? nullableV2 = Vector3.left; + + private static Vector3? nullableV3 = Vector3.left; + + private AllValueStruct astruct = new AllValueStruct{x=1}; + + //修改成正确的逻辑后,打开如下注释,生成的补丁将修正该函数 + public int Add(int a, int b) { - //修改成正确的逻辑后,打开如下注释,生成的补丁将修正该函数 - //[Patch] - public int Add(int a, int b) - { - return a * b; - } + return + TestAllValueStruct(default(AllValueStruct)) + TestAllValueStruct(default(AllValueStruct)) + + TestAllValueStruct(astruct) + + TestVector3(default(Vector3)) + TestVector3(default(Vector3)) + TestVector3(v) + TestVector3(Vector3.one) + + TestEnum(TestEnumValue.t2) + TestEnum(default(TestEnumValue)) + TestEnum(thisEnum) + TestEnum(TestEnumValue.t1) + + TestRefInt(ref a) + a + + TestNullable(null) + TestNullable(Vector3.left) + TestNullable(nullableV1) + TestNullable(nullableV2) + + TestNullable(nullableV3); + //return DoAdd(a, b); + } - public int Sub(int a, int b) + public int TestNullable(ref Vector3? v) + { + if (v == null) { - return a / b; + return 9 * 1000000; } - public int Mult(int a, int b) + return (int)(v.Value.x + v.Value.y + v.Value.z) * 1000000; + } + + public int TestNullable(Vector3? v) + { + if (v == null) { - return a * b; + return 9 * 1000000; } - public int Div(int a, int b) - { - return a / b; - } + return (int)(v.Value.x + v.Value.y + v.Value.z) * 1000000; } -} + + public int TestRefInt(ref int v) + { + v = 100000; + return v; + } + + public int TestEnum(TestEnumValue v) + { + return (int)v * 1000; + } + + public int TestAllValueStruct(AllValueStruct v) + { + return v.x * 10000; + } + + public int TestVector3(Vector3 v) + { + return 10 * (int)(v.x + v.y + v.z); + } + + public int Sub(int a, int b) + { + return a / b; + } + + public int Mult(int a, int b) + { + return a * b; + } + + public int Div(int a, int b) + { + return a / b; + } +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs index 8651e8b..f2e4fbb 100644 --- a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs +++ b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs @@ -22,9 +22,9 @@ static IEnumerable hotfix return new List() { typeof(Helloworld), - typeof(IFix.Test.Calculator), - //AnotherClass在Pro Standard Assets下,会编译到Assembly-CSharp-firstpass.dll下,用来演示多dll的修复 - typeof(AnotherClass), + typeof(Calculator), + // //AnotherClass在Pro Standard Assets下,会编译到Assembly-CSharp-firstpass.dll下,用来演示多dll的修复 + // typeof(AnotherClass), }; } } diff --git a/Source/UnityProj/Assets/Helloworld/Helloworld.cs b/Source/UnityProj/Assets/Helloworld/Helloworld.cs index 9fc99ad..27e825b 100644 --- a/Source/UnityProj/Assets/Helloworld/Helloworld.cs +++ b/Source/UnityProj/Assets/Helloworld/Helloworld.cs @@ -1,68 +1,238 @@ /* * Tencent is pleased to support the open source community by making InjectFix available. * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. + * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ +using System; +using System.Collections.Generic; using UnityEngine; using IFix.Core; using System.IO; using System.Diagnostics; +using System.Net.Http.Headers; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading.Tasks; +using IFix; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Profiling; +using UnityEngine.Assertions.Must; +using UnityEngine.Profiling; +using Unsafe.As; +using Debug = UnityEngine.Debug; +using Object = UnityEngine.Object; +using Random = UnityEngine.Random; + +public class TestStruct +{ + public int v; + + public void TestCall() + { + Debug.Log("TestCall " + v); + } +} // 跑不同仔细看文档Doc/example.md -public class Helloworld : MonoBehaviour { +public unsafe class Helloworld : MonoBehaviour +{ + public static readonly ProfilerMarker marker = new ProfilerMarker("marker"); + private Dictionary dict = new Dictionary(); + + static FieldInfo methodCodeField = typeof(Delegate).GetField("method_code",BindingFlags.Instance | BindingFlags.NonPublic); + static int methodCodeOffset = UnsafeUtility.GetFieldOffset(methodCodeField); + static FieldInfo targetField = typeof(Delegate).GetField("m_target",BindingFlags.Instance | BindingFlags.NonPublic); + static int targetOffset = UnsafeUtility.GetFieldOffset(targetField); + + public Transform parent; + public int xxx; + + private GameObject prefab; // check and load patchs - void Start () { - VirtualMachine.Info = (s) => UnityEngine.Debug.Log(s); - //try to load patch for Assembly-CSharp.dll + void Start() + { + TestStruct ts = new TestStruct(); + ts.v = 1; + var method = typeof(TestStruct).GetMethod("TestCall"); + var action = (Action)Delegate.CreateDelegate(typeof(Action), ts, method); + action(); + + ts = new TestStruct(); + ts.v = 114514; + void* p = UnsafeAsUtility.AsPoint(ref ts); + byte* ap = (byte*)UnsafeAsUtility.AsPoint(ref action); + + int v = 1; + ref int vv = ref v; + ref int vvv = ref vv; + + *(void**)(ap + targetOffset) = p; + *(void**)(ap + methodCodeOffset) = p; + + //field.SetValue(action, (IntPtr)); + action(); + IFixBindingCaller.Init(); + //test(); + if(calc == null) calc = new Calculator(); + UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + + prefab = Resources.Load("Button"); + } + + + Vector3 pos = new Vector3(1, 2, 3); + + Calculator calc; + + private void Update() + { + for(int i = 0;i<10;i++) + calc.Add(10, 9); + } + + static Vector3[] vecs = new Vector3[] { Vector3.zero, Vector3.one, 100 *Vector3.forward, 200 *Vector3.forward, 300 *Vector3.forward, 400 *Vector3.forward,}; + public void TestAsyncInstance() + { + Profiler.BeginSample("TestAsyncInstance"); + InstantiateAsync(prefab, 6, parent, vecs); + Profiler.EndSample(); + } + + public void TestSyncInstance() + { + Profiler.BeginSample("TestSyncInstance"); + for(int i =0;i<6;i++) + Instantiate(prefab, Vector3.zero, Quaternion.identity, parent); + Profiler.EndSample(); + } + + public void LoadPatch() + { var patch = Resources.Load("Assembly-CSharp.patch"); if (patch != null) - { + { UnityEngine.Debug.Log("loading Assembly-CSharp.patch ..."); - var sw = Stopwatch.StartNew(); - PatchManager.Load(new MemoryStream(patch.bytes)); + var sw = Stopwatch.StartNew(); + var vm = PatchManager.Load(new MemoryStream(patch.bytes), false, + (MethodBase mb, out ExternInvoker ei) => + { + bool ret = false; + if (mb is ConstructorInfo) + { + ei = null; + return false; + } + + var fb = new IFixBindingCaller(mb, out ret); + ei = fb.Invoke; + return ret; + }); + UnityEngine.Debug.Log("patch Assembly-CSharp.patch, using " + sw.ElapsedMilliseconds + " ms"); } - //try to load patch for Assembly-CSharp-firstpass.dll - patch = Resources.Load("Assembly-CSharp-firstpass.patch"); - if (patch != null) + + test(); + } + + + private void OnDestroy() + { + try { - UnityEngine.Debug.Log("loading Assembly-CSharp-firstpass ..."); - var sw = Stopwatch.StartNew(); - PatchManager.Load(new MemoryStream(patch.bytes)); - UnityEngine.Debug.Log("patch Assembly-CSharp-firstpass, using " + sw.ElapsedMilliseconds + " ms"); + if (!enabled) + { + using (marker.Auto()) + { + IFixBindingCaller.UnInit(); + } + } + else + { + var m = new ProfilerMarker("marker2"); + using (m.Auto()) + { + IFixBindingCaller.UnInit(); + } + } + + // using (new ProfilerMarker(enabled? "marker" : range + "marker " + range + Random.Range(0, 1)).Auto()) + // { + // IFixBindingCaller.UnInit(); + // Vector3 v = default; + // using (new ProfilerMarker($"marker{range}").Auto()) + // { + // IFixBindingCaller.UnInit(); + // } + // } + } + finally + { + IFixBindingCaller.UnInit(); } + } - test(); + public void TestRand() + { + var sw = Stopwatch.StartNew(); + // for (int i = 0; i < 10000000; i++) + // { + // DoTestRand(); + // } + + DoTestRand(); + // for(int i = 0;i<1000;i++) + // calc.Add(10, 9); + + UnityEngine.Debug.Log("Test call 1000 Struct, using " + (float)sw.ElapsedTicks / 10000 + " ms"); + } + + private static int range = 10; + [Patch] + public void DoTestRand() + { + int i = 0; + for (i = 0; i < 10000000; ++i) + { + Random.Range(-500, 500); + } + + print(i); } - [IFix.Patch] + //[IFix.Patch] void test() { - var calc = new IFix.Test.Calculator(); - //test calc.Add - UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); - //test calc.Sub - UnityEngine.Debug.Log("10 - 2 = " + calc.Sub(10, 2)); - - var anotherClass = new AnotherClass(1); - //AnotherClass in Assembly-CSharp-firstpass.dll - var ret = anotherClass.Call(i => i + 1); - UnityEngine.Debug.Log("anotherClass.Call, ret = " + ret); - - //test for InjectFix/Fix(Android) InjectFix/Fix(IOS) Menu for unity 2018.3 or newer + if (calc == null) calc = new Calculator(); + //test calc.Add + + // 测试多线程fix会不会出问题 + Parallel.For(0, 10, (v) => + { + UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + }); + // UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + // UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + // UnityEngine.Debug.Log("10 + 9 = " + calc.Add(10, 9)); + + #if UNITY_2018_3_OR_NEWER #if UNITY_IOS UnityEngine.Debug.Log("UNITY_IOS"); -#endif +#endif #if UNITY_EDITOR - UnityEngine.Debug.Log("UNITY_EDITOR"); -#endif + UnityEngine.Debug.Log("UNITY_EDITOR"); +#endif #if UNITY_ANDROID UnityEngine.Debug.Log("UNITY_ANDROID"); #endif #endif } -} +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/Helloworld/Helloworld.unity b/Source/UnityProj/Assets/Helloworld/Helloworld.unity index dae1980..2281a2c 100644 Binary files a/Source/UnityProj/Assets/Helloworld/Helloworld.unity and b/Source/UnityProj/Assets/Helloworld/Helloworld.unity differ diff --git a/Source/UnityProj/Assets/Helloworld/InvokeTest.cs b/Source/UnityProj/Assets/Helloworld/InvokeTest.cs new file mode 100644 index 0000000..029d97c --- /dev/null +++ b/Source/UnityProj/Assets/Helloworld/InvokeTest.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +//using IFix.Binding; +using IFix.Core; +using IFix.Test; +using UnityEngine; + + +public class TestClass +{ + public TestClass() + { + } + + public TestClass(string data) + { + Data = data; + } + + private string data; + + private string Data + { + get { return data; } + set { data = value; } + } + + public static int GetValue(int v) + { + return v; + } +} + +public class IFixTestClassWrapper +{ + public unsafe static int Invoke(int v) + { + return TestClass.GetValue(v); + } + + public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isInstantiate) + { + TestClass @class = (TestClass)call.GetObject(); + int v = call.GetInt32(sizeof(Value)); + int ret = TestClass.GetValue(v); + call.PushObjectAsResult(ret, typeof(int)); + } +} + +public class InvokeTest : MonoBehaviour +{ + private TestClass testClass; + private IFixTestClassWrapper ifix; + private Type @class; + + private PropertyInfo cachedPropertyInfo; + private MethodInfo cachedMethodInfo; + + private Func getDelegate; + + private Func getValue; + + // Start is called before the first frame update + void Start() + { + //Test(); + AtomAdd(); + } + + public void AtomAdd() + { + int result = 0; + Stopwatch st = new Stopwatch(); + + st.Start(); + for (int i = 0; i < 1000000; i++) + { + result++; + } + + st.Stop(); + UnityEngine.Debug.LogError($"normal:{st.ElapsedMilliseconds}ms, result:{result}"); + + st.Restart(); + result = 0; + Parallel.For(0, 10, (index) => + { + for (int i = 0; i < 100000; i++) + { + lock (this) + { + result++; + } + } + }); + st.Stop(); + UnityEngine.Debug.LogError($"lock in:{st.ElapsedMilliseconds}ms, result:{result}"); + + st.Restart(); + result = 0; + Parallel.For(0, 10, (index) => + { + lock (this) + { + for (int i = 0; i < 100000; i++) + { + result++; + } + } + }); + st.Stop(); + UnityEngine.Debug.LogError($"lock out:{st.ElapsedMilliseconds}ms, result:{result}"); + + result = 0; + st.Restart(); + Parallel.For(0, 10, (index) => + { + for (int i = 0; i < 100000; i++) + { + Interlocked.Increment(ref result); + } + }); + st.Stop(); + UnityEngine.Debug.LogError($"Interlocked.Increment:{st.ElapsedMilliseconds}ms, result:{result}"); + + result = 0; + st.Restart(); + Parallel.For(0, 10, (index) => + { + int originalValue; + int newValue; + for (int i = 0; i < 100000; i++) + { + do + { + originalValue = result; + newValue = originalValue + 1; + } while (Interlocked.CompareExchange(ref result, newValue, originalValue) != originalValue); + } + }); + st.Stop(); + UnityEngine.Debug.LogError($"Interlocked.CompareExchange:{st.ElapsedMilliseconds}ms, result:{result}"); + } + + + [ContextMenu("Test")] + public void Test() + { + //PerfTest.CallOrigin(); + //PerfTest.SafeCallExtern(); + //MethodInfo mi = typeof(List).GetMethod("get_Item"); + //var invoker = new System_Collections_Generic_List_1_int_System_Int32get_Item(mi); + AssetBundle ab = + AssetBundle.LoadFromFile("D:/work/InjectFix/Source/UnityProj/buildexe/e6b45fcfc63ff8a19a769f547e3c.ab"); + } + + public string GetViaReflection() + { + BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public; + PropertyInfo property = @class.GetProperty("Data", bindingFlags); + return (string)property.GetValue(testClass, null); + } + + public string GetViaCacheReflection() + { + return (string)cachedPropertyInfo.GetValue(testClass, null); + } + + public string GetViaDelegate() + { + return getDelegate(testClass); + } + + // Update is called once per frame + void Update() + { + } +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/Helloworld/InvokeTest.cs.meta b/Source/UnityProj/Assets/Helloworld/InvokeTest.cs.meta new file mode 100644 index 0000000..f486fee --- /dev/null +++ b/Source/UnityProj/Assets/Helloworld/InvokeTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 6c8e426081d922d499eb7adce900c5c9 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/Helloworld/PerfTest.cs b/Source/UnityProj/Assets/Helloworld/PerfTest.cs new file mode 100644 index 0000000..2099a1d --- /dev/null +++ b/Source/UnityProj/Assets/Helloworld/PerfTest.cs @@ -0,0 +1,156 @@ +/* + * Tencent is pleased to support the open source community by making InjectFix available. + * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. + * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. + * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. + */ + +using IFix.Core; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Runtime.InteropServices; + +namespace IFix.Test +{ + public class PerfTest + { + //基准测试,空方法调用 + static void Base() + { + int LOOPS = 10000000; + var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); + Call call = default; + for (int i = 0; i < 3; i++) + { + var sw = Stopwatch.StartNew(); + Call.BeginRef(ref call); + virtualMachine.Execute(1, ref call, 0); + Call.End(ref call); + sw.Stop(); + Console.WriteLine("Base " + i + " : " + (LOOPS / (int)sw.Elapsed.TotalMilliseconds * 1000) + "\r\n"); + } + } + + //通过Call对象调用add方法,该方法逻辑如下,SimpleVirtualMachineBuilder通过硬编码指令获得 + //int add(int a, int b) + //{ + // return a + b; + //} + //原生方法通过这种方式调用虚拟机方法 + static unsafe void SafeCall() + { + IntPtr nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(Value) + * VirtualMachine.MAX_EVALUATION_STACK_SIZE); + Value* evaluationStackPointer = (Value*)nativePointer.ToPointer(); + object[] managedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; + + int LOOPS = 10000000; + var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); + + var sw = Stopwatch.StartNew(); + Call call = default; + int ret = 0; + for (int i = 0; i < LOOPS; i++) + { + Call.BeginRef(ref call); + call.PushInt32(4); + call.PushInt32(6); + virtualMachine.Execute(0, ref call, 2); + ret = call.GetInt32(); + } + Console.WriteLine($"SafeCall {ret}" + " : " + ((int)sw.Elapsed.TotalMilliseconds) + "ms\r\n"); + } + + + public struct Vector3 + { + + } + + public int __Gen_Wrap_1(object P0, Vector3 P1) + { + Call call = Call.Begin(); + call.PushObject(P0); + call.PushValueUnmanaged(P1); + return call.GetInt32(0); + } + + static unsafe void CallOrigin() + { + int LOOPS = 1000000; + + var sw = Stopwatch.StartNew(); + int ret = 0; + SimpleVirtualMachineBuilder sb = new SimpleVirtualMachineBuilder(); + // for (int i = 0; i < LOOPS; i++) + // { + // ret = sb.GetValue(10, 20); + // } + Console.WriteLine($"CallOrigin {ret}" + " : " + ((int)sw.Elapsed.TotalMilliseconds) + "ms\r\n"); + } + + static unsafe void SafeCallExtern() + { + int LOOPS = 1;//1000000; + SimpleVirtualMachineBuilder sb = new SimpleVirtualMachineBuilder(); + var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); + + var sw = Stopwatch.StartNew(); + int ret = 0; + Call call = default; + List list = new List { 12 }; + for (int i = 0; i < LOOPS; i++) + { + Call.BeginRef(ref call); + call.PushObject(sb); + call.PushObject(list); + virtualMachine.Execute(2, ref call, 3); + ret = call.GetInt32(); + } + sw.Stop(); + Console.WriteLine($"SafeCallExtern ret:{ret} " + " : " + (sw.Elapsed.TotalMilliseconds) + "ms\r\n"); + } + + //直接通过指针操作栈,调用add方法 + //虚拟机内部方法间调用是通过这种方式 + unsafe static void UnsafeCall() + { + IntPtr nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(Value) + * VirtualMachine.MAX_EVALUATION_STACK_SIZE); + Value* evaluationStackPointer = (Value*)nativePointer.ToPointer(); + object[] managedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; + byte* stackValueHandler = (byte*)Marshal.AllocHGlobal(32 * VirtualMachine.MAX_EVALUATION_STACK_SIZE).ToPointer(); + + int LOOPS = 10000000; + var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); + var sw = Stopwatch.StartNew(); + + int ret = 0; + for (int i = 0; i < LOOPS; i++) + { + evaluationStackPointer->Value1 = 10; + evaluationStackPointer->Type = IFix.Core.ValueType.Integer; + + (evaluationStackPointer + 1)->Value1 = 20; + (evaluationStackPointer + 1)->Type = IFix.Core.ValueType.Integer; + + virtualMachine.Execute(0, evaluationStackPointer, managedStack, evaluationStackPointer, 2); + ret = evaluationStackPointer->Value1; + } + Console.WriteLine($"UnsafeCall {ret}" + " : " + ((int)sw.Elapsed.TotalMilliseconds) + "ms\r\n"); + + System.Runtime.InteropServices.Marshal.FreeHGlobal(nativePointer); + } + + public static void Main(string[] args) + { + CallOrigin(); + SafeCallExtern(); + //Base(); + SafeCall(); + UnsafeCall(); + Console.Read(); + } + } +} diff --git a/Source/UnityProj/Assets/Helloworld/PerfTest.cs.meta b/Source/UnityProj/Assets/Helloworld/PerfTest.cs.meta new file mode 100644 index 0000000..91f5181 --- /dev/null +++ b/Source/UnityProj/Assets/Helloworld/PerfTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 7f053a4b31d5d7644981ceeab0fff448 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/IFix/Editor.meta b/Source/UnityProj/Assets/IFix/Editor.meta index 3a5016d..fdfeb92 100644 --- a/Source/UnityProj/Assets/IFix/Editor.meta +++ b/Source/UnityProj/Assets/IFix/Editor.meta @@ -1,9 +1,8 @@ fileFormatVersion: 2 guid: 89d3afd1ac6383a4bb803e86127d5ed3 folderAsset: yes -timeCreated: 1514965388 -licenseType: Pro DefaultImporter: + externalObjects: {} userData: assetBundleName: assetBundleVariant: diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixCodeGen.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixCodeGen.cs new file mode 100644 index 0000000..5fef51a --- /dev/null +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixCodeGen.cs @@ -0,0 +1,1071 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; +using IFix.Core; +using Unity.Collections.LowLevel.Unsafe; +using ValueType = System.ValueType; +using System.Reflection.Emit; +using UnityEditor; +using Debug = System.Diagnostics.Debug; + +public static class OpCodeLookup +{ + // 单字节操作码集合 + public static readonly OpCode[] SingleByteOpCodes; + + // 多字节操作码集合 + public static readonly OpCode[] MultiByteOpCodes; + + // 静态构造函数,用于初始化操作码集合 + static OpCodeLookup() + { + // 获取所有操作码 + var opcodes = typeof(OpCodes).GetFields(BindingFlags.Public | BindingFlags.Static); + + // 初始化单字节操作码集合 + SingleByteOpCodes = new OpCode[256]; + foreach (var opcode in opcodes) + { + var code = (OpCode)opcode.GetValue(null); + if (code.Size == 1) + { + SingleByteOpCodes[code.Value] = code; + } + } + + // 初始化多字节操作码集合 + MultiByteOpCodes = new OpCode[256]; + foreach (var opcode in opcodes) + { + var code = (OpCode)opcode.GetValue(null); + if (code.Size == 2) + { + MultiByteOpCodes[code.Value & 0xff] = code; + } + } + } +} + +namespace IFix.Editor +{ + public class ILFixCodeGen + { + #region menu + + [MenuItem("InjectFix/GenBinding", false, 2)] + public static void GenBinding() + { + ILFixCodeGen gen = new ILFixCodeGen(); + gen.path = "Assets/IFix/Binding/"; + gen.methodCount = 0; + gen.ClearMethod(); + gen.DeleteAll(); + // custom type + //gen.Generate(typeof(List)); + //gen.Generate(typeof(string)); + + // search by dll caller + List mbList = new List(); + var asses = AppDomain.CurrentDomain.GetAssemblies(); + foreach (var assembly in IFixEditor.injectAssemblys) + { + foreach (var ass in asses) + { + if (!(ass.ManifestModule is System.Reflection.Emit.ModuleBuilder) + && (ass.GetName().Name == assembly)) + { + UnityEngine.Debug.Log( string.Format("Scan {0} assembly", ass.GetName().Name)); + mbList.AddRange(FindAllMethod(ass)); + } + } + } + + gen.GenAll(mbList); + } + + public static List FindAllMethod(Assembly assembly) + { + HashSet result = new HashSet(); + Module[] modules = assembly.GetModules(); + Module mainModule = modules[0]; + // 遍历程序集中的所有类型 + foreach (var type in assembly.GetTypes()) + { + if (type.FullName == "IFix.ILFixDynamicMethodWrapper") + { + throw new Exception("You can't gen binding when dll is injected"); + } + + if (type.IsSubclassOf(typeof(Delegate))) + continue; + // 遍历类型中的所有方法 + var methods = type.GetMethods(BindingFlags.Public + | BindingFlags.DeclaredOnly | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static); + + var constructors = type.GetConstructors(BindingFlags.Public + | BindingFlags.DeclaredOnly | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static); + + List mbList = new List(); + mbList.AddRange(methods); + mbList.AddRange(constructors); + + foreach (var methodInfo in mbList) + { + if (methodInfo == null) continue; + if(methodInfo.ReflectedType == null) continue; + if (!string.IsNullOrEmpty(methodInfo.ReflectedType.Namespace)) + { + if(methodInfo.ReflectedType.Namespace == "IFix.Core") continue; + if(methodInfo.ReflectedType.Namespace == "IFix.Binding") continue; + if(methodInfo.ReflectedType.Namespace.Contains("UnityEditor")) continue; + } + // 输出方法的名称 + + + // 获取方法体 + var methodBody = methodInfo.GetMethodBody(); + + // 检查方法是否有方法体 + if (methodBody != null) + { + // 获取方法体中的 IL 字节码 + var ilBytes = methodBody.GetILAsByteArray(); + + // 创建一个指向 IL 字节码的索引 + int ilIndex = 0; + + // 遍历 IL 字节码 + while (ilIndex < ilBytes.Length) + { + // 从 IL 字节码中读取操作码 + var opcodeValue = ilBytes[ilIndex++]; + var opcode = OpCodes.Nop; // 默认为 Nop,以防止未知操作码 + if (opcodeValue != 0xFE) // 如果操作码的值不在 0xFE 开头的范围内 + { + opcode = OpCodeLookup.SingleByteOpCodes[opcodeValue]; // 使用单字节操作码查找表 + } + else // 如果操作码的值在 0xFE 开头的范围内 + { + opcodeValue = ilBytes[ilIndex++]; + opcode = OpCodeLookup.MultiByteOpCodes[opcodeValue]; // 使用多字节操作码查找表 + } + + // 检查是否是方法调用指令 + if (opcode == OpCodes.Call || opcode == OpCodes.Callvirt || opcode == OpCodes.Newobj) + { + // 读取调用的方法的元数据标记 + int metadataToken = BitConverter.ToInt32(ilBytes, ilIndex); + //ilIndex += 4; + + // 解析元数据标记获取调用的方法信息 + try + { + var calledMethod = mainModule.ResolveMethod(metadataToken); + if (!result.Contains(calledMethod)) + { + if (calledMethod is ConstructorInfo) + { + // 构造函数暂时不处理 + // if (!calledMethod.ReflectedType.IsValueType) + // { + // //UnityEngine.Debug.Log($"class ctor:{calledMethod.ReflectedType}, {calledMethod.Name}"); + // } + // else if(calledMethod.IsPublic) + // { + // result.Add(calledMethod); + // } + + } + else + { + // IFix.Core空间下不导出 + if (calledMethod.ReflectedType.FullName.Contains("IFix.Core")) + { + } + else + { + result.Add(calledMethod); + } + } + + // 输出调用的方法信息 + //UnityEngine.Debug.Log($" 调用方法: {ILFixCodeGen.GetUniqueStringForMethod(calledMethod)}"); + } + } + catch //(Exception e) + { + //UnityEngine.Debug.LogError(e); + } + + } + + // 检查是否有操作数,并根据操作码的操作数类型移动索引 + switch (opcode.OperandType) + { + case OperandType.InlineBrTarget: + case OperandType.InlineField: + case OperandType.InlineI: + case OperandType.InlineI8: + case OperandType.InlineMethod: + case OperandType.InlineR: + case OperandType.InlineSig: + case OperandType.InlineString: + case OperandType.InlineSwitch: + case OperandType.InlineTok: + case OperandType.InlineType: + case OperandType.InlineVar: + ilIndex += 4; + break; + case OperandType.ShortInlineBrTarget: + case OperandType.ShortInlineI: + case OperandType.ShortInlineR: + case OperandType.ShortInlineVar: + ilIndex += 1; + break; + } + } + } + } + } + + return result.ToList(); + } + + #endregion + + #region static + + public Dictionary> delegateDict = new Dictionary>(); + public Dictionary ctorCache = new Dictionary(); + public Dictionary publicInstanceStructCache = new Dictionary(); + + public void ClearMethod() + { + delegateDict.Clear(); + ctorCache.Clear(); + publicInstanceStructCache.Clear(); + } + + public bool TryGetDelegateStr(MethodInfo mi, out string ret) + { + bool result = true; + var key = TypeNameUtils.GetMethodDelegateKey(mi); + + if (string.IsNullOrEmpty(key)) + { + ret = ""; + return true; + } + + if (key.Contains("!")) + { + ret = ""; + return true; + } + + if (key.Contains(">d__")) + { + ret = ""; + return true; + } + + if (key.Contains("<>")) + { + ret = ""; + return true; + } + + if (!delegateDict.ContainsKey(key)) + { + result = false; + ret = MethodInfoToDelegate(mi); + delegateDict.Add(key, new Tuple(methodCount, ret)); + } + else + { + ret = delegateDict[key].Item2; + } + + return result; + } + + #endregion + + #region cal name + + public string MethodInfoToDelegate(MethodInfo method) + { + List args = new List(); + var parameters = method.GetParameters(); + + for (int i = 0, imax = parameters.Length; i < imax; i++) + { + var p = parameters[i]; + if (p.ParameterType.IsByRef && p.IsOut) + args.Add("out " + TypeNameUtils.SimpleType(p.ParameterType) + string.Format(" arg{0}", i + 1)); + else if (p.ParameterType.IsByRef) + args.Add("ref " + TypeNameUtils.SimpleType(p.ParameterType) + string.Format(" arg{0}", i + 1)); + else + args.Add(TypeNameUtils.SimpleType(p.ParameterType) + string.Format(" arg{0}", i + 1)); + } + + var parameterTypeNames = string.Join(",", args); + + Type retType = method.ReturnType; + + return string.Format("public delegate {0} IFixCallDel{2}({1});", TypeNameUtils.SimpleType(retType), + parameterTypeNames, methodCount); + } + + #endregion + + #region type + + static MethodInfo tryFixGenericMethod(MethodInfo method) + { + if (!method.ContainsGenericParameters) + return method; + + try + { + Type[] genericTypes = method.GetGenericArguments(); + for (int j = 0; j < genericTypes.Length; j++) + { + Type[] contraints = genericTypes[j].GetGenericParameterConstraints(); + if (contraints != null && contraints.Length == 1 && contraints[0] != typeof(ValueType)) + genericTypes[j] = contraints[0]; + else + return method; + } + + // only fixed here + return method.MakeGenericMethod(genericTypes); + } + catch (Exception e) + { + //Debug.LogError(e); + } + + return method; + } + + ConstructorInfo[] GetValidConstructor(Type t) + { + List ret = new List(); + if (t.GetConstructor(Type.EmptyTypes) == null && t.IsAbstract && t.IsSealed) + return ret.ToArray(); + if (t.IsAbstract) + return ret.ToArray(); + if (t.BaseType != null && t.BaseType.Name == "MonoBehaviour") + return ret.ToArray(); + + ConstructorInfo[] cons = t.GetConstructors( + BindingFlags.Instance | BindingFlags.Public + ); + foreach (ConstructorInfo ci in cons) + { + ret.Add(ci); + } + + return ret.ToArray(); + } + + MethodInfo[] GetValidMethodInfo(Type t) + { + List methods = new List(); + + BindingFlags bf = BindingFlags.Public + | BindingFlags.DeclaredOnly | BindingFlags.NonPublic + | BindingFlags.Instance | BindingFlags.Static; + + MethodInfo[] members = t.GetMethods(bf); + foreach (MethodInfo mi in members) + { + if (mi.ReturnType.IsNotPublic) continue; + bool hasPrivateType = false; + foreach (var item in mi.GetParameters()) + { + if (item.ParameterType.IsNotPublic) + { + hasPrivateType = true; + break; + } + } + + if (hasPrivateType) continue; + methods.Add(tryFixGenericMethod(mi)); + } + + return methods.ToArray(); + } + + bool IsBaseType(Type t) + { + return t.IsPrimitive; + } + + bool IsValueType(Type t) + { + if (t.IsByRef) t = t.GetElementType(); + return t.BaseType == typeof(ValueType) && !IsBaseType(t); + } + + bool IsOutArg(ParameterInfo p) + { + return (p.IsOut || p.IsDefined(typeof(System.Runtime.InteropServices.OutAttribute), false)) && + !p.ParameterType.IsArray; + } + + string FuncCall(MethodBase m, int parOffset = 0) + { + string str = ""; + ParameterInfo[] pars = m.GetParameters(); + + for (int n = 0; n < pars.Length; n++) + { + ParameterInfo p = pars[n]; + int idx = n + 1; + if (p.ParameterType.IsByRef && p.IsOut) + str += string.Format("out arg{0}", idx); + else if (p.ParameterType.IsByRef) + str += string.Format("ref arg{0}", idx); + else + str += string.Format("arg{0}", idx); + if (n < pars.Length - 1) + str += ","; + } + + return str; + } + + string FuncGetArg(ParameterInfo p) + { + Type t = p.ParameterType; + return string.Format("({0})", TypeNameUtils.SimpleType(t)); + } + + string FuncPushResult(Type t) + { + if (t.IsPrimitive) + { + if (t == typeof(int)) + { + return "call.PushInt32AsResult(result);"; + } + else if (t == typeof(uint)) + { + return "call.PushUInt32AsResult(result);"; + } + else if (t == typeof(float)) + { + return "call.PushSingleAsResult(result);"; + } + else if (t == typeof(bool)) + { + return "call.PushBooleanAsResult(result);"; + } + else if (t == typeof(double)) + { + return "call.PushDoubleAsResult(result);"; + } + else if (t == typeof(long)) + { + return "call.PushInt64AsResult(result);"; + } + else if (t == typeof(byte)) + { + return "call.PushByteAsResult(result);"; + } + else if (t == typeof(ushort)) + { + return "call.PushUInt16AsResult(result);"; + } + else if (t == typeof(short)) + { + return "call.PushInt16AsResult(result);"; + } + else if (t == typeof(char)) + { + return "call.PushCharAsResult(result);"; + } + else if (t == typeof(ulong)) + { + return "call.PushUInt64AsResult(result);"; + } + else if (t == typeof(sbyte)) + { + return "call.PushSByteAsResult(result);"; + } + else if (t == typeof(IntPtr)) + { + return "call.PushIntPtr64AsResult(result);"; + } + else if (t == typeof(UIntPtr)) + { + return "call.PushUIntPtr64AsResult(result);"; + } + } + else if (t.IsPointer) + { + return "call.PushIntPtr64AsResult((IntPtr)result);"; + } + else if (t.IsEnum) + { + var underlyingType = Enum.GetUnderlyingType(t); + if (underlyingType == typeof(long) || underlyingType == typeof(ulong)) + { + return "call.PushInt64AsResult((long)result);"; + } + else + { + return "call.PushInt32AsResult((int)result);"; + } + } + else if (t.IsValueType) + { + return "call.PushValueUnmanagedAsResult(result);"; + } + + return $"call.PushObjectAsResult(result, typeof({TypeNameUtils.SimpleType(t)}));"; + } + + string GetArg(Type t, int n) + { + if (t.IsPrimitive) + { + if (t == typeof(int)) + { + return $"var arg{n} = (curArgument++)->Value1;"; + } + else if (t == typeof(uint)) + { + return $"var arg{n} = (uint)(curArgument++)->Value1;"; + } + else if (t == typeof(float)) + { + return $"var arg{n} = (float)(curArgument++)->Value1;"; + } + else if (t == typeof(ushort)) + { + return $"var arg{n} = (ushort)(curArgument++)->Value1;"; + } + else if (t == typeof(short)) + { + return $"var arg{n} = (short)(curArgument++)->Value1;"; + } + else if (t == typeof(char)) + { + return $"var arg{n} = (char)(curArgument++)->Value1;"; + } + else if (t == typeof(bool)) + { + return $"var arg{n} = (curArgument++)->Value1 == 0;"; + } + else if (t == typeof(byte)) + { + return $"var arg{n} = (byte)(curArgument++)->Value1;"; + } + else if (t == typeof(sbyte)) + { + return $"var arg{n} = (sbyte)(curArgument++)->Value1;"; + } + else if (t == typeof(double)) + { + return $"var arg{n} = *(double*)&(curArgument++)->Value1;"; + } + else if (t == typeof(long)) + { + return $"var arg{n} = *(long*)&(curArgument++)->Value1;"; + } + else if (t == typeof(ulong)) + { + return $"var arg{n} = *(ulong*)&(curArgument++)->Value1;"; + } + else if (t == typeof(IntPtr)) + { + return $"var arg{n} = (IntPtr)(*(long*)&(curArgument++)->Value1);"; + } + else if (t == typeof(UIntPtr)) + { + return $"var arg{n} = (UIntPtr)(*(long*)&(curArgument++)->Value1);"; + } + } + else if (t.IsPointer) + { + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})((IntPtr)(*(long*)&(curArgument++)->Value1)).ToPointer();"; + } + else if (t.IsEnum) + { + var underlyingType = Enum.GetUnderlyingType(t); + if (underlyingType == typeof(long) || underlyingType == typeof(ulong)) + { + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})(*(long*)&(curArgument++)->Value1);"; + } + else + { + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})(curArgument++)->Value1;"; + } + } + // else if (t.IsValueType) + // { + // + // } + + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})managedStack[(curArgument++)->Value1];"; + } + + + string ToArgRef(int n) + { + return $"Value* arg{n}Ref = EvaluationStackOperation.ToBaseRef(curArgument++);"; + } + + string UpdateArgRef(Type t, int n, StreamWriter file) + { + string ret = ""; + if (t.IsPrimitive) + { + if (t == typeof(int)) + { + return $"arg{n}Ref->Value1 = arg{n};"; + } + else if (t == typeof(uint)) + { + return $"arg{n}Ref->Value1 = (int)arg{n};"; + } + else if (t == typeof(float)) + { + return $"*(float*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(ushort)) + { + return $"*(ushort*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(short)) + { + return $"*(short*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(char)) + { + return $"*(char*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(bool)) + { + return $"arg{n}Ref->Value1 = arg{n} ? 1 : 0;"; + } + else if (t == typeof(byte)) + { + return $"*(byte*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(sbyte)) + { + return $"*(sbyte*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(double)) + { + return $"*(double*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(long)) + { + return $"*(long*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(ulong)) + { + return $"*(ulong*)(&arg{n}Ref->Value1) = arg{n};"; + } + else if (t == typeof(IntPtr)) + { + return $"*(long*)(&arg{n}Ref->Value1) = arg{n}.ToInt64();"; + } + else if (t == typeof(UIntPtr)) + { + return $"*(ulong*)(&arg{n}Ref->Value1) = arg{n}.ToUInt64();"; + } + } + else if (t.IsPointer) + { + return $"*(long*)(&arg{n}Ref->Value1) = (long)arg{n};"; + } + else if (t.IsEnum) + { + var underlyingType = Enum.GetUnderlyingType(t); + if (underlyingType == typeof(long) || underlyingType == typeof(ulong)) + { + return $"*(long*)(&arg{n}Ref->Value1) = (long)arg{n};"; + } + else + { + return $"arg{n}Ref->Value1 = (int)arg{n};"; + } + } + else + { + if (t.IsValueType) + { + Write(file, $"BoxUtils.RecycleObject(managedStack[arg{n}Ref->Value1]);"); + } + + ret = $"managedStack[arg{n}Ref->Value1] = BoxUtils.BoxObject(arg{n});"; + } + + return ret; + } + + string GetRefArg(Type t, int n) + { + if (t.IsPrimitive) + { + if (t == typeof(int)) + { + return $"var arg{n} = arg{n}Ref->Value1;"; + } + else if (t == typeof(uint)) + { + return $"var arg{n} = (uint)arg{n}Ref->Value1;"; + } + else if (t == typeof(float)) + { + return $"var arg{n} = (float)arg{n}Ref->Value1;"; + } + else if (t == typeof(ushort)) + { + return $"var arg{n} = (ushort)arg{n}Ref->Value1;"; + } + else if (t == typeof(short)) + { + return $"var arg{n} = (short)arg{n}Ref->Value1;"; + } + else if (t == typeof(char)) + { + return $"var arg{n} = (char)arg{n}Ref->Value1;"; + } + else if (t == typeof(bool)) + { + return $"var arg{n} = arg{n}Ref->Value1 == 0;"; + } + else if (t == typeof(byte)) + { + return $"var arg{n} = (byte)arg{n}Ref->Value1;"; + } + else if (t == typeof(sbyte)) + { + return $"var arg{n} = (sbyte)arg{n}Ref->Value1;"; + } + else if (t == typeof(double)) + { + return $"var arg{n} = *(double*)&arg{n}Ref->Value1;"; + } + else if (t == typeof(long)) + { + return $"var arg{n} = *(long*)&arg{n}Ref->Value1;"; + } + else if (t == typeof(ulong)) + { + return $"var arg{n} = *(ulong*)&arg{n}Ref->Value1;"; + } + else if (t == typeof(IntPtr)) + { + return $"var arg{n} = (IntPtr)(*(long*)&arg{n}Ref->Value1);"; + } + else if (t == typeof(UIntPtr)) + { + return $"var arg{n} = (UIntPtr)(*(long*)&arg{n}Ref->Value1);"; + } + } + else if (t.IsPointer) + { + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})((IntPtr)(*(long*)&arg{n}Ref->Value1)).ToPointer();"; + } + else if (t.IsEnum) + { + var underlyingType = Enum.GetUnderlyingType(t); + if (underlyingType == typeof(long) || underlyingType == typeof(ulong)) + { + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})(*(long*)&arg{n}Ref->Value1);"; + } + else + { + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})arg{n}Ref->Value1;"; + } + } + + return $"var arg{n} = ({TypeNameUtils.SimpleType(t)})managedStack[arg{n}Ref->Value1];"; + } + + + #endregion + + #region write + + void Write(StreamWriter file, string fmt, params object[] args) + { + fmt = Regex.Replace(fmt, @"\r\n?|\n|\r", NewLine); + + if (fmt.StartsWith("}")) indent--; + + for (int n = 0; n < indent; n++) + file.Write("\t"); + + + if (args.Length == 0) + file.WriteLine(fmt); + else + { + string line = string.Format(fmt, args); + file.WriteLine(line); + } + + if (fmt.EndsWith("{")) indent++; + } + + private void WriteHead(StreamWriter file) + { + Write(file, "using System;"); + Write(file, "using IFix.Core;"); + Write(file, "using System.Collections.Generic;"); + Write(file, "using System.Reflection;"); + Write(file, "#if UNITY_5_5_OR_NEWER"); + Write(file, "using UnityEngine.Profiling;"); + Write(file, "#else"); + Write(file, "using UnityEngine;"); + Write(file, "#endif"); + + Write(file, "namespace IFix.Core"); + Write(file, "{"); + Write(file, "public unsafe partial class IFixBindingCaller"); + Write(file, "{"); + Write(file, ""); + } + + private void End(StreamWriter file) + { + Write(file, "}"); + Write(file, "}"); + file.Flush(); + file.Close(); + + GenFileDictionary(); + } + + private void GenFileDictionary() + { + string bindingDelDictPath = path + "/Resources/BindingDelDict.bytes"; + FileDictionary file = + new FileDictionary(bindingDelDictPath, 1024, true); + + foreach (var item in delegateDict) + { + file.Add(item.Key, item.Value.Item1); + } + + file.Close(); + } + + void WriteTry(StreamWriter file) + { + Write(file, "try"); + Write(file, "{"); + Write(file, "#if DEBUG"); + Write(file, "Profiler.BeginSample(methodName);"); + Write(file, "#endif"); + } + + void WriteFinaly(StreamWriter file, int paramStart, int paramCount) + { + Write(file, "}"); + Write(file, "finally"); + Write(file, "{"); + Write(file, "#if DEBUG"); + Write(file, "Profiler.EndSample();"); + Write(file, "#endif"); + Write(file, $"PopEvaluationStack(ref call, pushResult, {paramStart}, {paramCount});"); + Write(file, "}"); + } + + private bool WriteMethodCaller(MethodBase mb, StreamWriter file) + { + var key = TypeNameUtils.GetMethodDelegateKey(mb); + if (string.IsNullOrEmpty(key)) + { + return false; + } + + if (key.Contains("!")) + { + return false; + } + + if (key.Contains(">d__")) + { + return false; + } + + if (key.Contains("<>")) + { + return false; + } + + // class method + if (mb is MethodInfo) + { + string delegateStr; + if (TryGetDelegateStr((MethodInfo)mb, out delegateStr)) + { + return false; + } + + Write(file, delegateStr); + } + else + { + return false; + } + + Write(file, ""); + Write(file, "public void Invoke{0}(VirtualMachine vm, ref Call call, bool instantiate) {{", methodCount); + Write(file, "var curArgument = hasThis ? call.argumentBase + 1 : call.argumentBase;"); + Write(file, "var managedStack = call.managedStack;"); + ParameterInfo[] pars = mb.GetParameters(); + var mi = mb as MethodInfo; + + for (int n = 0; n < pars.Length; n++) + { + var p = pars[n]; + int idx = n + 1; + if (!p.IsOut && !p.ParameterType.IsByRef) + { + Write(file, GetArg(p.ParameterType, idx)); + } + else + { + Write(file, ToArgRef(idx)); + Write(file, GetRefArg(p.ParameterType.GetElementType(), idx)); + } + } + + if (mi.ReturnType != typeof(void)) + { + Write(file, "var result = ((IFixCallDel{1})caller)({0});", FuncCall(mi), methodCount); + Write(file, FuncPushResult(mi.ReturnType)); + } + else + { + Write(file, "((IFixCallDel{1})caller)({0});", FuncCall(mi), methodCount); + } + + + for (int n = 0; n < pars.Length; n++) + { + var p = pars[n]; + var idx = n + 1; + if (p.ParameterType.IsByRef) + { + string updateStr = UpdateArgRef(p.ParameterType.GetElementType(), idx, file); + Write(file, updateStr); + } + } + + Write(file, "}"); + Write(file, ""); + return true; + } + + #endregion + + #region public + + public void DeleteAll() + { + if (Directory.Exists(path)) + { + foreach (var file in Directory.EnumerateFiles(path, "*.*", SearchOption.AllDirectories)) + { + File.Delete(file); + } + } + } + + public void GenAll(List mbList) + { + var file = Begin(); + WriteHead(file); + + for (int i = 0, imax = mbList.Count; i < imax; i++) + { + if (WriteMethodCaller(mbList[i], file)) + methodCount++; + } + + End(file); + } + + #endregion + + StreamWriter Begin() + { + if (!Directory.Exists(path)) + { + Directory.CreateDirectory(path); + } + + if (!Directory.Exists(path + "/Resources")) + { + Directory.CreateDirectory(path + "/Resources"); + } + + string bindingFile = path + "IFixBindingCaller.cs"; + + StreamWriter file = new StreamWriter(bindingFile, false, Encoding.UTF8); + file.NewLine = NewLine; + return file; + } + + #region property + + public EOL eol = EOL.CRLF; + + public enum EOL + { + Native, + CRLF, + CR, + LF, + } + + string NewLine + { + get + { + switch (eol) + { + case EOL.Native: + return System.Environment.NewLine; + case EOL.CRLF: + return "\r\n"; + case EOL.CR: + return "\r"; + case EOL.LF: + return "\n"; + default: + return ""; + } + } + } + + #endregion + + #region member + + public string path; + public int methodCount = 0; + int indent = 0; + + #endregion + } +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixCodeGen.cs.meta b/Source/UnityProj/Assets/IFix/Editor/ILFixCodeGen.cs.meta new file mode 100644 index 0000000..e280786 --- /dev/null +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixCodeGen.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f7f4398db3d54a5a90b2cd75845ef132 +timeCreated: 1711696371 \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 402c054..02ba056 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -1,4 +1,4 @@ -/* +/* * Tencent is pleased to support the open source community by making InjectFix available. * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. @@ -15,6 +15,9 @@ using System.Text.RegularExpressions; using System.Text; using System.Reflection; +using System.Reflection.Emit; +using IFix.Core; +using Debug = System.Diagnostics.Debug; #if UNITY_2018_3_OR_NEWER using UnityEditor.Build.Player; #endif @@ -25,7 +28,7 @@ namespace IFix.Editor public class VersionSelector : EditorWindow { public string buttonText = "Patch"; - public string[] options = new string[] {}; + public string[] options = new string[] { }; public int index = 0; public Action callback = null; @@ -51,6 +54,7 @@ void doPatch() { callback(index); } + Close(); } } @@ -59,6 +63,7 @@ public class IFixEditor { //备份目录 const string BACKUP_PATH = "./IFixDllBackup"; + //备份文件的时间戳生成格式 const string TIMESTAMP_FORMAT = "yyyyMMddHHmmss"; @@ -84,6 +89,7 @@ public static void CallIFix(List args) { UnityEngine.Debug.LogError("can not find mono!"); } + var inject_tool_path = "./IFixToolKit/IFix.exe"; //"--runtime = v4.0.30319" if (!File.Exists(inject_tool_path)) @@ -99,7 +105,7 @@ public static void CallIFix(List args) #else hotfix_injection.StartInfo.Arguments = "--debug \"" + inject_tool_path + "\" \"" #endif - + string.Join("\" \"", args.ToArray()) + "\""; + + string.Join("\" \"", args.ToArray()) + "\""; hotfix_injection.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; hotfix_injection.StartInfo.RedirectStandardOutput = true; hotfix_injection.StartInfo.UseShellExecute = false; @@ -110,7 +116,7 @@ public static void CallIFix(List args) //UnityEngine.Debug.Log(hotfix_injection.StartInfo.Arguments); StringBuilder exceptionInfo = null; - while(!hotfix_injection.StandardOutput.EndOfStream) + while (!hotfix_injection.StandardOutput.EndOfStream) { string line = hotfix_injection.StandardOutput.ReadLine(); if (exceptionInfo != null) @@ -137,6 +143,7 @@ public static void CallIFix(List args) } } } + hotfix_injection.WaitForExit(); if (exceptionInfo != null) { @@ -152,15 +159,17 @@ public static void InjectAssemblys() UnityEngine.Debug.LogError("compiling or playing"); return; } + EditorUtility.DisplayProgressBar("Inject", "injecting...", 0); try { InjectAllAssemblys(); } - catch(Exception e) + catch (Exception e) { UnityEngine.Debug.LogError(e); } + EditorUtility.ClearProgressBar(); #if UNITY_2019_3_OR_NEWER EditorUtility.RequestScriptReload(); @@ -198,7 +207,7 @@ public static void GetBackupInfo(out string[] backups, out string[] timestamps) backups = allBackup.Select(path => r.Match(path).Groups[1].Captures[0].Value).ToArray(); timestamps = allBackup.Select(path => DateTime.ParseExact(r.Match(path).Groups[1].Captures[0].Value, - TIMESTAMP_FORMAT, System.Globalization.CultureInfo.InvariantCulture) + TIMESTAMP_FORMAT, System.Globalization.CultureInfo.InvariantCulture) .ToString("yyyy-MM-dd hh:mm:ss tt")).ToArray(); } @@ -209,10 +218,7 @@ public static void SelectBackup(string buttonText, Action cb) string[] timestamps; GetBackupInfo(out backups, out timestamps); - VersionSelector.Show(timestamps.ToArray(), index => - { - cb(backups[index]); - }, buttonText); + VersionSelector.Show(timestamps.ToArray(), index => { cb(backups[index]); }, buttonText); } /// @@ -221,7 +227,8 @@ public static void SelectBackup(string buttonText, Action cb) /// 程序集路径 public static void InjectAssembly(string assembly) { - var configure = Configure.GetConfigureByTags(new List() { + var configure = Configure.GetConfigureByTags(new List() + { "IFix.IFixAttribute", "IFix.InterpretAttribute", "IFix.ReverseWrapperAttribute", @@ -237,7 +244,7 @@ public static void InjectAssembly(string assembly) var blackList = new List(); using (BinaryWriter writer = new BinaryWriter(new FileStream(processCfgPath, FileMode.Create, - FileAccess.Write))) + FileAccess.Write))) { writer.Write(configure.Count); @@ -262,16 +269,17 @@ public static void InjectAssembly(string assembly) writer.Write(cfgItem.Value); if (filters.Count > 0 && kv.Key == "IFix.IFixAttribute") { - foreach(var method in cfgItem.Key.GetMethods(BindingFlags.Instance - | BindingFlags.Static | BindingFlags.Public - | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) + foreach (var method in cfgItem.Key.GetMethods(BindingFlags.Instance + | BindingFlags.Static | BindingFlags.Public + | BindingFlags.NonPublic | + BindingFlags.DeclaredOnly)) { - foreach(var filter in filters) + foreach (var filter in filters) { if ((bool)filter.Invoke(null, new object[] - { - method - })) + { + method + })) { blackList.Add(method); } @@ -286,23 +294,27 @@ public static void InjectAssembly(string assembly) if (hasSomethingToDo) { - var core_path = "./Assets/Plugins/IFix.Core.dll"; var assembly_path = string.Format("./Library/{0}/{1}.dll", targetAssembliesFolder, assembly); var patch_path = string.Format("./{0}.ill.bytes", assembly); - List args = new List() { "-inject", core_path, assembly_path, - processCfgPath, patch_path, assembly_path }; + List args = new List() + { + "-inject", core_path, assembly_path, + processCfgPath, patch_path, assembly_path + }; foreach (var path in - (from asm in AppDomain.CurrentDomain.GetAssemblies() - select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct()) + (from asm in AppDomain.CurrentDomain.GetAssemblies() + select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct()) { try { //UnityEngine.Debug.Log("searchPath:" + path); args.Add(path); } - catch { } + catch + { + } } CallIFix(args); @@ -327,7 +339,7 @@ public static void InjectAllAssemblys() { InjectAssembly(assembly); } - + //doBackup(DateTime.Now.ToString(TIMESTAMP_FORMAT)); AssetDatabase.Refresh(); @@ -340,12 +352,13 @@ private static string GetScriptAssembliesFolder() { assembliesFolder = "ScriptAssemblies"; } + return assembliesFolder; } //默认的注入及备份程序集 //另外可以直接调用InjectAssembly对其它程序集进行注入。 - static string[] injectAssemblys = new string[] + public static string[] injectAssemblys = new string[] { "Assembly-CSharp", "Assembly-CSharp-firstpass" @@ -371,6 +384,7 @@ static void doBackup(string ts) { continue; } + File.Copy(dllFile, string.Format("{0}/{1}-{2}.dll", BACKUP_PATH, assembly, ts), true); var mdbFile = string.Format("{0}{1}.dll.mdb", scriptAssembliesDir, assembly); @@ -402,6 +416,7 @@ static void doRestore(string ts) { continue; } + File.Copy(dllFile, string.Format("{0}{1}.dll", scriptAssembliesDir, assembly), true); UnityEngine.Debug.Log("Revert to: " + dllFile); @@ -437,8 +452,8 @@ static string GetCecilTypeName(Type type) else { return Regex.Replace(type.ToString().Replace('+', '/'), @"(`\d).+", "$1") - + "<" + string.Join(",", type.GetGenericArguments().Select(t => GetCecilTypeName(t)) - .ToArray()) + ">"; + + "<" + string.Join(",", type.GetGenericArguments().Select(t => GetCecilTypeName(t)) + .ToArray()) + ">"; } } else @@ -462,13 +477,13 @@ public enum Platform private static string parseCompileTemplate(string path) { return string.Join("\n", File.ReadAllLines(path).Where(line => !line.StartsWith("Assets/") - && !line.StartsWith("\"Assets/") - && !line.StartsWith("'Assets/") - && !line.StartsWith("-r:Assets/") - && !line.StartsWith("-r:\"Assets/") - && !line.StartsWith("-r:'Assets/") - && !line.StartsWith("-out") - ).ToArray()); + && !line.StartsWith("\"Assets/") + && !line.StartsWith("'Assets/") + && !line.StartsWith("-r:Assets/") + && !line.StartsWith("-r:\"Assets/") + && !line.StartsWith("-r:'Assets/") + && !line.StartsWith("-out") + ).ToArray()); } //对路径预处理,然后添加到StringBuilder @@ -494,10 +509,11 @@ private static void appendDirectory(StringBuilder src, string dir) foreach (var file in Directory.GetFiles(dir)) { //排除调Editor下的东西 - if (file.IndexOf(Path.DirectorySeparatorChar + "Editor" + Path.DirectorySeparatorChar) > 0 ) + if (file.IndexOf(Path.DirectorySeparatorChar + "Editor" + Path.DirectorySeparatorChar) > 0) { continue; } + //排除Assembly-CSharp-firstpass if (file.Substring(file.Length - 3).ToLower() == ".cs") { @@ -507,11 +523,12 @@ private static void appendDirectory(StringBuilder src, string dir) { continue; } + appendFile(src, file); } } - foreach(var subDir in Directory.GetDirectories(dir)) + foreach (var subDir in Directory.GetDirectories(dir)) { appendDirectory(src, subDir); } @@ -540,9 +557,11 @@ private static string getCompileArguments(Platform platform, string output) + " in IFixToolKit directory!"); } } + compileTemplate = parseCompileTemplate(path); compileTemplates.Add(platform, compileTemplate); } + StringBuilder cmd = new StringBuilder(); StringBuilder src = new StringBuilder(); StringBuilder dll = new StringBuilder(); @@ -567,7 +586,10 @@ private static string getCompileArguments(Platform platform, string output) #if (UNITY_EDITOR || XLUA_GENERAL) && !NET_STANDARD_2_0 } #endif - } catch { } + } + catch + { + } } cmd.AppendLine(compileTemplate); @@ -632,7 +654,7 @@ public static void Compile(string compileArgFile) { UnityEngine.Debug.Log(compileProcess.StandardOutput.ReadLine()); } - + compileProcess.WaitForExit(); } @@ -650,7 +672,7 @@ public static void GenPlatformPatch(Platform platform, string patchOutputDir, scriptCompilationSettings.group = BuildTargetGroup.Android; scriptCompilationSettings.target = BuildTarget.Android; } - else if(platform == Platform.ios) + else if (platform == Platform.ios) { scriptCompilationSettings.group = BuildTargetGroup.iOS; scriptCompilationSettings.target = BuildTarget.iOS; @@ -661,7 +683,8 @@ public static void GenPlatformPatch(Platform platform, string patchOutputDir, scriptCompilationSettings.target = BuildTarget.StandaloneWindows; } - ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, outputDir); + ScriptCompilationResult scriptCompilationResult = + PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, outputDir); foreach (var assembly in injectAssemblys) { @@ -755,6 +778,7 @@ static bool hasGenericParameter(Type type) { return hasGenericParameter(type.GetElementType()); } + if (type.IsGenericType) { foreach (var typeArg in type.GetGenericArguments()) @@ -764,8 +788,10 @@ static bool hasGenericParameter(Type type) return true; } } + return false; } + return type.IsGenericParameter; } @@ -781,8 +807,8 @@ static bool hasGenericParameter(MethodBase method) return true; } } - return false; + return false; } /// @@ -793,7 +819,7 @@ static bool hasGenericParameter(MethodBase method) /// IFix.Core.dll所在路径 /// 生成的patch的保存路径 public static void GenPatch(string assembly, string assemblyCSharpPath - = "./Library/ScriptAssemblies/Assembly-CSharp.dll", + = "./Library/ScriptAssemblies/Assembly-CSharp.dll", string corePath = "./Assets/Plugins/IFix.Core.dll", string patchPath = "Assembly-CSharp.patch.bytes") { var patchMethods = Configure.GetTagMethods(typeof(PatchAttribute), assembly).ToList(); @@ -821,7 +847,7 @@ public static void GenPatch(string assembly, string assemblyCSharpPath var processCfgPath = "./process_cfg"; using (BinaryWriter writer = new BinaryWriter(new FileStream(processCfgPath, FileMode.Create, - FileAccess.Write))) + FileAccess.Write))) { writeMethods(writer, patchMethods); writeMethods(writer, newMethods); @@ -830,19 +856,24 @@ public static void GenPatch(string assembly, string assemblyCSharpPath writeClasses(writer, newClasses); } - List args = new List() { "-patch", corePath, assemblyCSharpPath, "null", - processCfgPath, patchPath }; + List args = new List() + { + "-patch", corePath, assemblyCSharpPath, "null", + processCfgPath, patchPath + }; foreach (var path in - (from asm in AppDomain.CurrentDomain.GetAssemblies() - select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct()) + (from asm in AppDomain.CurrentDomain.GetAssemblies() + select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct()) { try { //UnityEngine.Debug.Log("searchPath:" + path); args.Add(path); } - catch { } + catch + { + } } CallIFix(args); @@ -869,9 +900,11 @@ public static void Patch() { UnityEngine.Debug.LogError(e); } + EditorUtility.ClearProgressBar(); } + #if UNITY_2018_3_OR_NEWER [MenuItem("InjectFix/Fix(Android)", false, 3)] public static void CompileToAndroid() @@ -881,10 +914,11 @@ public static void CompileToAndroid() { GenPlatformPatch(Platform.android, ""); } - catch(Exception e) + catch (Exception e) { UnityEngine.Debug.LogError(e); } + EditorUtility.ClearProgressBar(); } @@ -896,12 +930,13 @@ public static void CompileToIOS() { GenPlatformPatch(Platform.ios, ""); } - catch(Exception e) + catch (Exception e) { UnityEngine.Debug.LogError(e); } + EditorUtility.ClearProgressBar(); } #endif } -} +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs.meta b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs.meta index 37eb3ba..a670837 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs.meta +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs.meta @@ -1,12 +1,3 @@ -fileFormatVersion: 2 -guid: ea1d006806821c945ad3dfda116f04f7 -timeCreated: 1514863799 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: +fileFormatVersion: 2 +guid: a28e2c8f14b84f79a08c48fb75479f32 +timeCreated: 1711696371 \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/FileDicionary.meta b/Source/UnityProj/Assets/IFix/FileDicionary.meta new file mode 100644 index 0000000..0cefb59 --- /dev/null +++ b/Source/UnityProj/Assets/IFix/FileDicionary.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 28fa2fcdffd479845adfbec5308ad6bb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionary.cs b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionary.cs new file mode 100644 index 0000000..2414dbf --- /dev/null +++ b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionary.cs @@ -0,0 +1,627 @@ +using System.IO; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace IFix.Core +{ + public unsafe class FileDictionary : IDictionary,IDisposable + where TKey : IEquatable + { + #region member + + private IFileDictionaryDelegate funs; + + const int SIZE_COUNT = 2; + const int MAX_CONFLIGCT_TIME = 8; + private Stream _stream; + private string _fileName; + private int _capacity = 0; + private int _dataOffset = 0; + private int _size = 0; + + #endregion + + ~FileDictionary() + { + Dispose(true); + } + + #region cache + + private const int CACHE_COUNT = 256; + private Dictionary>> _cache = new Dictionary>>(CACHE_COUNT); + private LinkedList> _lruQueue = new LinkedList>(); + private ICollection _keys; + private ICollection _values; + + private bool TryGetCache(TKey key, out TValue value) + { + LinkedListNode> ln; + bool ret = _cache.TryGetValue(key, out ln); + + if (ret) + { + value = ln.Value.Value; + _lruQueue.Remove(ln); + _lruQueue.AddLast(ln); + } + else + { + value = default(TValue); + } + + return ret; + } + + private void AddToCache(TKey key, TValue value) + { + if (_lruQueue.Count >= CACHE_COUNT) + { + var first = _lruQueue.First; + _lruQueue.RemoveFirst(); + + first.Value = new KeyValuePair(key, value); + _cache.Add(key, first); + _lruQueue.AddLast(first); + } + else + { + LinkedListNode> lruNode = new LinkedListNode>(new KeyValuePair(key, value)); + _cache.Add(key, lruNode); + _lruQueue.AddLast(lruNode); + } + } + + #endregion + + #region private + + public static int FindNextPowerOfTwo(int number) + { + if (number <= 0) + { + return 1; // 最小的2幂是2^0 = 1 + } + + int result = 1; + while (result < number) + { + result <<= 1; // 左移一位,相当于乘以2 + } + + return result; + } + + private void Resize(int capacity) + { + _stream.Seek(0, SeekOrigin.Begin); + // 写入capacity + WriteInt(capacity); + WriteInt(_size); + + int* p; + fixed (byte* bp = FileDictionaryUtils.intBuff) + { + p = (int*)bp; + } + + *p = -1; + + if (_dataOffset != 0) // 不是第一次resize + { + // 移动数据区的数据 + int endIndex = (int)_stream.Length; + int delta = (capacity - _capacity) * 4; + int index = endIndex; + + while (index > _dataOffset) + { + int newIndex = index - FileDictionaryUtils.MOVE_BUFF_SIZE; + if (_dataOffset > newIndex) + { + newIndex = _dataOffset; + } + + int size = index - newIndex; + + _stream.Seek(newIndex, SeekOrigin.Begin); + _stream.Read(FileDictionaryUtils.moveTempBuff, 0, size); + + _stream.Seek(newIndex + delta, SeekOrigin.Begin); + _stream.Write(FileDictionaryUtils.moveTempBuff, 0, size); + + index = newIndex; + } + + // 把索引区的数据都读取到内存中 + byte[] oldData = new byte[4 * (_capacity + MAX_CONFLIGCT_TIME)]; + int* oldDataPoint = null; + + _stream.Seek(4 * SIZE_COUNT, SeekOrigin.Begin); + _stream.Read(oldData, 0, 4 * (_capacity + MAX_CONFLIGCT_TIME)); + + // 开辟空间,并把索引区数据全部改成-1 + _stream.Seek(4 * SIZE_COUNT, SeekOrigin.Begin); + for (int i = 0; i < capacity + MAX_CONFLIGCT_TIME; i++) + { + _stream.Write(FileDictionaryUtils.intBuff, 0, 4); + } + + _dataOffset = (capacity + SIZE_COUNT + MAX_CONFLIGCT_TIME) * 4; + int oldCapacity = _capacity; + _capacity = capacity; + // 重新插入 索引区数据 + fixed (byte* b = oldData) + { + oldDataPoint = (int*)b; + } + + for (int i = 0; i < oldCapacity + MAX_CONFLIGCT_TIME; i++) + { + int offset = *(oldDataPoint + i); + ResetVal(offset); + } + } + else + { + // 开辟空间默认值为-1 + for (int i = 0; i < capacity + MAX_CONFLIGCT_TIME; i++) + { + _stream.Write(FileDictionaryUtils.intBuff, 0, 4); + } + + _dataOffset = (capacity + SIZE_COUNT + MAX_CONFLIGCT_TIME) * 4; + _capacity = capacity; + _size = 0; + } + + _stream.Flush(); + } + + private int ReadInt() + { + _stream.Read(FileDictionaryUtils.intBuff, 0, 4); + + int* p; + fixed (byte* bp = FileDictionaryUtils.intBuff) + { + p = (int*)bp; + } + + return *p; + } + + private void WriteInt(int val) + { + int* p; + fixed (byte* bp = FileDictionaryUtils.intBuff) + { + p = (int*)bp; + } + + *p = val; + + _stream.Write(FileDictionaryUtils.intBuff, 0, 4); + } + + private void ResetVal(int offset) + { + if (offset < 0) + { + return; + } + + // 拿到原来的string值 + int len; + TKey key = GetKey(offset, out len); + + DoSetVal(key, offset); + } + + private void DoSetVal(TKey key, int offset, int resizeTime = 0) + { + // 计算CRC32 并计算出来一个索引 + int index = (int)(funs.GetHashCode(key) & (_capacity - 1)); + + bool isReset = false; + for (int i = 0; i < MAX_CONFLIGCT_TIME; i++) + { + int ii = index + i; + if (SetVal(ii, offset)) + { + isReset = true; + break; + } + } + + if (!isReset) + { + if (resizeTime > 4) + { + StringBuilder sb = new StringBuilder(); + sb.Append("hash code conflict is too high,you can change hashcode,values:"); + for (int i = 0; i < MAX_CONFLIGCT_TIME; i++) + { + int ii = index + i; + _stream.Seek((ii + SIZE_COUNT) * 4, SeekOrigin.Begin); + int addr = ReadInt(); + int keyLen = 0; + var k = GetKey(addr, out keyLen); + sb.Append(k); + sb.Append(","); + } + sb.Append(key); + throw new Exception(sb.ToString()); + } + else + { + Resize(_capacity * 2); + resizeTime++; + } + + + DoSetVal(key, offset, resizeTime); + } + } + + private bool SetVal(int index, int offset) + { + _stream.Seek((index + SIZE_COUNT) * 4, SeekOrigin.Begin); + int v = ReadInt(); + if (v < 0) + { + _stream.Seek(-4, SeekOrigin.Current); + WriteInt(offset); + return true; + } + + return false; + } + + private TKey GetKey(int offset, out int len) + { + _stream.Seek(offset + _dataOffset, SeekOrigin.Begin); + len = ReadInt(); + return funs.DeserializeKey(_stream, len); + } + + private bool TryGetValue(TKey key, out TValue value, out int ofs, out int index, out int oldValueLen, out int keyLen) + { + value = default(TValue); + ofs = 0; + // 计算CRC32 并计算出来一个索引 + index = (int)(funs.GetHashCode(key) & (_capacity - 1)); + oldValueLen = 0; + keyLen = 0; + + bool isFind = false; + TKey k; + int offset; + for (int i = 0; i < MAX_CONFLIGCT_TIME; i++) + { + int ii = index + i; + _stream.Seek((ii + SIZE_COUNT) * 4, SeekOrigin.Begin); + offset = ReadInt(); + // 没有值 + if (offset < 0) + { + return false; + } + + k = GetKey(offset, out keyLen); + if (k.Equals(key)) + { + ofs = offset; + oldValueLen = ReadInt(); + value = funs.DeserializeValue(_stream, oldValueLen); + AddToCache(key, value); + return true; + } + } + + return isFind; + } + + #endregion + + #region public + + // 文件存在就从文件里面读取 capacity,文件不存在就用capacity new 一个 文件hash表出来 + public FileDictionary(string fileName, int capacity = 1024, bool isClear = false, bool readOnly = false) + { + bool fileExit = File.Exists(fileName); + if (isClear && fileExit) + { + File.Delete(fileName); + fileExit = false; + } + + if (readOnly) + { + _stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Read); + } + else + { + _stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); + } + + _fileName = fileName; + funs = FileDictionaryDelegateFactory.GetFileDictionaryDelegate(); + if (funs == null) + { + throw new Exception(string.Format("Implement IFileDictionaryDelegate<{0}, {1}>", typeof(TKey).Name, typeof(TValue).Name) ); + } + + // 文件不存在就先写入点东西 + if (!fileExit) + { + //capacity = Math.Max(1024, capacity); + capacity = FindNextPowerOfTwo(capacity); + Resize(capacity); + } + else + { + _capacity = ReadInt(); + _size = ReadInt(); + _dataOffset = (_capacity + SIZE_COUNT + MAX_CONFLIGCT_TIME) * 4; + } + } + + public void Flush() + { + _stream.Flush(); + } + + public void Close() + { + _stream.Flush(); + _stream.Close(); + _stream = null; + } + + #endregion + + #region interface + + public bool Contains(object key) + { + throw new NotImplementedException(); + } + + public IEnumerator> GetEnumerator() + { + _stream.Seek(_dataOffset, SeekOrigin.Begin); + + for (int i = 0; i < _size; i++) + { + int len = ReadInt(); + var key = funs.DeserializeKey(_stream, len); + len = ReadInt(); + var value = funs.DeserializeValue(_stream, len); + + yield return new KeyValuePair(key, value); + } + } + + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void AddNewValue(TKey key, TValue value) + { + int offset; + ++_size; + _stream.Seek(4, SeekOrigin.Begin); + WriteInt(_size); + offset = (int)_stream.Length - _dataOffset; + + _stream.Seek(offset + _dataOffset, SeekOrigin.Begin); + funs.SerializeKey(_stream, key); + funs.SerializeValue(_stream, value); + + DoSetVal(key, offset); + } + + public void Add(TKey key, TValue value) + { + TValue oldValue; + int offset, index, oldValueLen, keyLen; + bool hasValue = TryGetValue(key, out oldValue, out offset, out index, out oldValueLen, out keyLen); + if (hasValue) + { + if (oldValue.Equals(value)) return; + } + int newValueLen = funs.GetValueLen(value); + if (hasValue && oldValueLen >= newValueLen) + { + _stream.Seek(offset + _dataOffset + 4 + keyLen, SeekOrigin.Begin); + funs.SerializeValue(_stream, value); + } + else if (hasValue) + { + offset = (int)_stream.Length - _dataOffset; + + _stream.Seek((index + SIZE_COUNT) * 4, SeekOrigin.Begin); + WriteInt(offset); + + _stream.Seek(offset + _dataOffset, SeekOrigin.Begin); + funs.SerializeKey(_stream, key); + funs.SerializeValue(_stream, value); + } + else + { + ++_size; + _stream.Seek(4, SeekOrigin.Begin); + WriteInt(_size); + offset = (int)_stream.Length - _dataOffset; + + _stream.Seek(offset + _dataOffset, SeekOrigin.Begin); + funs.SerializeKey(_stream, key); + funs.SerializeValue(_stream, value); + + DoSetVal(key, offset); + } + } + + public void Add(KeyValuePair item) + { + Add(item.Key, item.Value); + } + + public void Add(IDictionary dict) + { + foreach (var item in dict) + { + Add(item.Key, item.Value); + } + } + + public void Clear() + { + _stream.Close(); + File.Delete(_fileName); + _dataOffset = 0; + _size = 0; + + _stream = new FileStream(_fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite); + var capacity = _capacity; + _capacity = 0; + Resize(capacity); + } + + public bool Contains(KeyValuePair item) + { + return ContainsKey(item.Key); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + public void CopyTo(Array array, int index) + { + throw new NotImplementedException(); + } + + public int Count + { + get { return _size; } + } + + public bool IsSynchronized { get; } + public object SyncRoot { get; } + + public bool IsReadOnly + { + get { return false; } + } + + public object this[object key] + { + get => throw new NotImplementedException(); + set => throw new NotImplementedException(); + } + + public bool ContainsKey(TKey key) + { + TValue value; + bool find = TryGetValue(key, out value); + return find; + } + + public bool Remove(TKey key) + { + TValue oldValue; + int offset, index, oldLen, keyLen; + bool hasValue = TryGetValue(key, out oldValue, out offset, out index, out oldLen, out keyLen); + if (hasValue) + { + _stream.Seek((index + SIZE_COUNT) * 4, SeekOrigin.Begin); + WriteInt(-1); + _size--; + _stream.Seek(4, SeekOrigin.Begin); + WriteInt(_size); + } + + return hasValue; + } + + public bool TryGetValue(TKey key, out TValue value) + { + // LRU cahce + bool ret = TryGetCache(key, out value); + if (ret) return ret; + + int ofs, index, oldLen, keyLen; + return TryGetValue(key, out value, out ofs, out index, out oldLen, out keyLen); + } + + public TValue this[TKey key] + { + get + { + TValue value; + bool find = TryGetValue(key, out value); + if (!find) + { + value = default(TValue); + } + + return value; + } + set { Add(key, value); } + } + + public Dictionary ToDictionary() + { + Dictionary result = new Dictionary(Count); + _stream.Seek(_dataOffset, SeekOrigin.Begin); + + for (int i = 0; i < _size; i++) + { + int len = ReadInt(); + var key = funs.DeserializeKey(_stream, len); + len = ReadInt(); + var value = funs.DeserializeValue(_stream, len); + + result.Add(key, value); + } + + return result; + } + + public ICollection Keys + { + get { throw new NotImplementedException(); } + } + + public ICollection Values + { + get { throw new NotImplementedException(); } + } + + #endregion + + private void Dispose(bool disposing) + { + _stream?.Dispose(); + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + } +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionary.cs.meta b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionary.cs.meta new file mode 100644 index 0000000..4cad978 --- /dev/null +++ b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionary.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: a0c80ab3dcf2cac4381a3aadb4278acc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionaryDelegate.cs b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionaryDelegate.cs new file mode 100644 index 0000000..516ba7f --- /dev/null +++ b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionaryDelegate.cs @@ -0,0 +1,672 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using UnityEngine.Experimental.XR; + +namespace IFix.Core +{ + public static class CRC32 + { + private static readonly uint[] table; + + static CRC32() + { + uint polynomial = 0xEDB88320; + table = new uint[256]; + for (uint i = 0; i < 256; i++) + { + uint crc = i; + for (int j = 0; j < 8; j++) + { + if ((crc & 1) == 1) + { + crc = (crc >> 1) ^ polynomial; + } + else + { + crc >>= 1; + } + } + + table[i] = crc; + } + } + + public static uint Compute(byte[] bytes) + { + uint crc = 0xFFFFFFFF; + foreach (byte b in bytes) + { + crc = (crc >> 8) ^ table[(crc ^ b) & 0xFF]; + } + + return ~crc; + } + } + + public unsafe static class FileDictionaryUtils + { + public static byte[] intBuff = new byte[4]; + + public const int MOVE_BUFF_SIZE = 4 * 4096; + + public static byte[] moveTempBuff = new byte[MOVE_BUFF_SIZE]; + + public const int SERIALIZE_BUFF_SIZE = 4096 * 4; + + public static byte[] SerializeTempBuff = new byte[SERIALIZE_BUFF_SIZE]; + + public static void WriteInt(Stream stream, int val) + { + int* p; + fixed (byte* bp = intBuff) + { + p = (int*)bp; + } + + *p = val; + + stream.Write(intBuff, 0, 4); + } + + public static int ReadInt(Stream stream) + { + stream.Read(intBuff, 0, 4); + + int* p; + fixed (byte* bp = intBuff) + { + p = (int*)bp; + } + + return *p; + } + + #region int + + public static int DeserializeInt(Stream stream, int len) + { + byte[] intBuff = FileDictionaryUtils.intBuff; + stream.Read(intBuff, 0, len); + + int* intb; + fixed (byte* b = intBuff) + { + intb = (int*)(b); + } + + return *intb; + } + + public static void SerializeInt(Stream stream, int value) + { + WriteInt(stream, 4); + + byte[] intBuff = FileDictionaryUtils.intBuff; + int* intb; + fixed (byte* b = intBuff) + { + intb = (int*)(b); + *intb = value; + } + stream.Write(intBuff, 0, 4); + } + #endregion + + #region bool + + public static bool DeserializeBool(Stream stream, int len) + { + byte[] intBuff = FileDictionaryUtils.intBuff; + stream.Read(intBuff, 0, len); + + fixed (byte* b = intBuff) + { + return *b > (byte)0; + } + } + + public static void SerializeBool(Stream stream, bool value) + { + WriteInt(stream, 1); + + byte[] intBuff = FileDictionaryUtils.intBuff; + fixed (byte* b = intBuff) + { + *b = value ? (byte)1: (byte)0; + } + stream.Write(intBuff, 0, 1); + } + #endregion + + #region byte[] + public static byte[] DeserializeBytes(Stream stream, int len) + { + byte[] result = new byte[len]; + stream.Read(result, 0, len); + + return result; + } + + public static void SerializeBytes(Stream stream, byte[] value) + { + WriteInt(stream, value.Length); + stream.Write(value, 0, value.Length); + } + #endregion + + #region string + + public static string DeserializeString(Stream stream, int len) + { + var buff = SerializeTempBuff; + if (len > SerializeTempBuff.Length) + { + buff = new byte[len]; + } + + stream.Read(buff, 0, len); + return System.Text.Encoding.UTF8.GetString(buff, 0, len); + } + + public static void SerializeString(Stream stream, string value) + { + int len = System.Text.Encoding.UTF8.GetByteCount(value); + var buff = SerializeTempBuff; + if (len <= SerializeTempBuff.Length) + { + System.Text.Encoding.UTF8.GetBytes(value, 0, value.Length, buff, 0); + WriteInt(stream, len); + stream.Write(buff, 0, len); + } + else + { + byte[] data = System.Text.Encoding.UTF8.GetBytes(value); + WriteInt(stream, data.Length); + stream.Write(data, 0, data.Length); + } + } + + #endregion + + #region string[] + + public static string[] DeserializeStringArray(Stream stream, int len) + { + byte[] data = SerializeTempBuff; + + if (len > data.Length) + { + data = new byte[len]; + } + + stream.Read(data, 0, len); + string[] result = null; + fixed (byte* bp = data) + { + byte* p = bp; + int count = (*(int*)p); + p = p + 4; + + result = new string[count]; + + for (int i = 0; i < count; i++) + { + int strLen = (*(int*)p); + p = p + 4; + result[i] = System.Text.Encoding.UTF8.GetString(data, (int)(p - bp), strLen); + p = p + strLen; + } + } + + return result; + } + + public static int GetValueLen(string[] value) + { + // string len + int len = 4; + for (int i = 0, imax = value.Length; i < imax; i++) + { + len += 4 + UTF8Encoding.UTF8.GetByteCount(value[i]); + } + return len; + } + + public static void SerializeStringArray(Stream stream, string[] value) + { + WriteInt(stream, GetValueLen(value)); + WriteInt(stream, value.Length); + + for (int i = 0, imax = value.Length; i < imax; i++) + { + var data = System.Text.Encoding.UTF8.GetBytes(value[i]); + WriteInt(stream, data.Length); + stream.Write(data, 0, data.Length); + } + } + #endregion + } + + public interface IFileDictionaryDelegate + { + uint GetHashCode(TKey key); + + TValue DeserializeValue(Stream stream, int len); + + int GetValueLen(TValue value); + + void SerializeValue(Stream stream, TValue value); + + TKey DeserializeKey(Stream stream, int len); + void SerializeKey(Stream stream, TKey value); + } + + public class IntBytesFileDictionaryDelegate : IFileDictionaryDelegate + { + public static IntBytesFileDictionaryDelegate Default = new IntBytesFileDictionaryDelegate(); + public uint GetHashCode(int key) + { + return (uint)key * 2654435761U; + } + + public int GetValueLen(byte[] value) + { + return value.Length; + } + + public byte[] DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeBytes(stream, len); + } + + public void SerializeValue(Stream stream, byte[] value) + { + FileDictionaryUtils.SerializeBytes(stream, value); + } + + public int DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public void SerializeKey(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + } + + public class IntBoolFileDictionaryDelegate : IFileDictionaryDelegate + { + public static IntBoolFileDictionaryDelegate Default = new IntBoolFileDictionaryDelegate(); + public uint GetHashCode(int key) + { + return (uint)key * 2654435761U; + } + + public bool DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeBool(stream, len); + } + + public int GetValueLen(bool value) + { + return 1; + } + + public void SerializeValue(Stream stream, bool value) + { + FileDictionaryUtils.SerializeBool(stream, value); + } + + public int DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public void SerializeKey(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + + } + + public class IntStringFileDictionaryDelegate : IFileDictionaryDelegate + { + public static IntStringFileDictionaryDelegate Default = new IntStringFileDictionaryDelegate(); + + public uint GetHashCode(int key) + { + return (uint)key * 2654435761U; + } + + public int GetValueLen(string value) + { + return System.Text.Encoding.UTF8.GetByteCount(value); + } + + public string DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeValue(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + + public int DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public void SerializeKey(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + } + + public class IntIntFileDictionaryDelegate : IFileDictionaryDelegate + { + public static IntIntFileDictionaryDelegate Default = new IntIntFileDictionaryDelegate(); + public uint GetHashCode(int key) + { + return (uint)key * 2654435761U; + } + + public int DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public int GetValueLen(int value) + { + return 4; + } + + public void SerializeValue(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + + public int DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public void SerializeKey(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + + } + + public class IntStringArrayFileDictionaryDelegate : IFileDictionaryDelegate + { + public static IntStringArrayFileDictionaryDelegate Default = new IntStringArrayFileDictionaryDelegate(); + public uint GetHashCode(int key) + { + return (uint)key * 2654435761U; + } + + public string[] DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeStringArray(stream, len); + } + + public int GetValueLen(string[] value) + { + // string len + int len = 4; + for (int i = 0, imax = value.Length; i < imax; i++) + { + len += 4 + UTF8Encoding.UTF8.GetByteCount(value[i]); + } + return len; + } + + public void SerializeValue(Stream stream, string[] value) + { + FileDictionaryUtils.SerializeStringArray(stream, value); + } + + public int DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public void SerializeKey(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + + } + + public class StringBytesFileDictionaryDelegate : IFileDictionaryDelegate + { + public static StringBytesFileDictionaryDelegate Default = new StringBytesFileDictionaryDelegate(); + + public uint GetHashCode(string key) + { + var data = System.Text.Encoding.UTF8.GetBytes(key); + return CRC32.Compute(data); + } + + public int GetValueLen(byte[] value) + { + return value.Length; + } + + public byte[] DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeBytes(stream, len); + } + + public void SerializeValue(Stream stream, byte[] value) + { + FileDictionaryUtils.SerializeBytes(stream, value); + } + + public string DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeKey(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + + } + + public class StringIntFileDictionaryDelegate : IFileDictionaryDelegate + { + public static StringIntFileDictionaryDelegate Default = new StringIntFileDictionaryDelegate(); + + public uint GetHashCode(string key) + { + var data = System.Text.Encoding.UTF8.GetBytes(key); + return CRC32.Compute(data); + } + + public int GetValueLen(int value) + { + return 4; + } + + public int DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeInt(stream, len); + } + + public void SerializeValue(Stream stream, int value) + { + FileDictionaryUtils.SerializeInt(stream, value); + } + + public string DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeKey(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + + } + + public class StringBoolFileDictionaryDelegate : IFileDictionaryDelegate + { + public static StringBoolFileDictionaryDelegate Default = new StringBoolFileDictionaryDelegate(); + + public uint GetHashCode(string key) + { + var data = System.Text.Encoding.UTF8.GetBytes(key); + return CRC32.Compute(data); + } + + public int GetValueLen(bool value) + { + return 1; + } + + public bool DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeBool(stream, len); + } + + public void SerializeValue(Stream stream, bool value) + { + FileDictionaryUtils.SerializeBool(stream, value); + } + + public string DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeKey(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + + } + + public class StringStringFileDictionaryDelegate : IFileDictionaryDelegate + { + public static StringStringFileDictionaryDelegate Default = new StringStringFileDictionaryDelegate(); + + public uint GetHashCode(string key) + { + var data = System.Text.Encoding.UTF8.GetBytes(key); + return CRC32.Compute(data); + } + + public int GetValueLen(string value) + { + return System.Text.Encoding.UTF8.GetByteCount(value); + } + + public string DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeValue(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + + public string DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeKey(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + } + + public class StringStringArrayFileDictionaryDelegate : IFileDictionaryDelegate + { + public static StringStringArrayFileDictionaryDelegate Default = new StringStringArrayFileDictionaryDelegate(); + public uint GetHashCode(string key) + { + var data = System.Text.Encoding.UTF8.GetBytes(key); + return CRC32.Compute(data); + } + + public string[] DeserializeValue(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeStringArray(stream, len); + } + + public int GetValueLen(string[] value) + { + // string len + int len = 4; + for (int i = 0, imax = value.Length; i < imax; i++) + { + len += 4 + UTF8Encoding.UTF8.GetByteCount(value[i]); + } + return len; + } + + public void SerializeValue(Stream stream, string[] value) + { + FileDictionaryUtils.SerializeStringArray(stream, value); + } + + public string DeserializeKey(Stream stream, int len) + { + return FileDictionaryUtils.DeserializeString(stream, len); + } + + public void SerializeKey(Stream stream, string value) + { + FileDictionaryUtils.SerializeString(stream, value); + } + } + + public static class FileDictionaryDelegateFactory + { + public static IFileDictionaryDelegate GetFileDictionaryDelegate() + { + if (typeof(TKey) == typeof(string) && typeof(TValue) == typeof(byte[])) + return (IFileDictionaryDelegate)StringBytesFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(string) && typeof(TValue) == typeof(string)) + return (IFileDictionaryDelegate)StringStringFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(string) && typeof(TValue) == typeof(string[])) + return (IFileDictionaryDelegate)StringStringArrayFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(string) && typeof(TValue) == typeof(int)) + return (IFileDictionaryDelegate)StringIntFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(string) && typeof(TValue) == typeof(bool)) + return (IFileDictionaryDelegate)StringBoolFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(int) && typeof(TValue) == typeof(byte[])) + return (IFileDictionaryDelegate)IntBytesFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(int) && typeof(TValue) == typeof(string)) + return (IFileDictionaryDelegate)IntStringFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(int) && typeof(TValue) == typeof(string[])) + return (IFileDictionaryDelegate)IntStringArrayFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(int) && typeof(TValue) == typeof(int)) + return (IFileDictionaryDelegate)IntIntFileDictionaryDelegate.Default; + + if (typeof(TKey) == typeof(int) && typeof(TValue) == typeof(bool)) + return (IFileDictionaryDelegate)IntBoolFileDictionaryDelegate.Default; + + return null; + } + } + +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionaryDelegate.cs.meta b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionaryDelegate.cs.meta new file mode 100644 index 0000000..6d4f55a --- /dev/null +++ b/Source/UnityProj/Assets/IFix/FileDicionary/FileDictionaryDelegate.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 9403db99121540a1b45e5a336a9a776b +timeCreated: 1696938542 \ No newline at end of file diff --git a/Source/UnityProj/Assets/IFix/IFixBindingCaller.New.cs b/Source/UnityProj/Assets/IFix/IFixBindingCaller.New.cs new file mode 100644 index 0000000..30e29ff --- /dev/null +++ b/Source/UnityProj/Assets/IFix/IFixBindingCaller.New.cs @@ -0,0 +1,135 @@ + +using System.Collections.Generic; +using Unity.Collections.LowLevel.Unsafe; +using Unsafe.As; + +namespace IFix.Core +{ + using System; + using System.Reflection; + using IFix.Core; + using UnityEngine; + using System.IO; +#if UNITY_5_5_OR_NEWER + using UnityEngine.Profiling; +#endif + using UnityEngine; + public unsafe partial class IFixBindingCaller + { + + static FieldInfo methodCodeField = typeof(Delegate).GetField("method_code",BindingFlags.Instance | BindingFlags.NonPublic); + static int methodCodeOffset = UnsafeUtility.GetFieldOffset(methodCodeField); + static FieldInfo targetField = typeof(Delegate).GetField("m_target",BindingFlags.Instance | BindingFlags.NonPublic); + static int targetOffset = UnsafeUtility.GetFieldOffset(targetField); + + private static FileDictionary delDict; + + public static void Init() + { + string dictPath = Application.persistentDataPath + "/BindingDelDict.bytes"; + var datas = Resources.Load("BindingDelDict").bytes; + File.WriteAllBytes(dictPath, datas); + delDict = new FileDictionary(dictPath, 1024, false, true); + } + + public static void UnInit() + { + if (delDict != null) + { + delDict.Dispose(); + } + } + + public ExternInvoker InvokeCall = null; + private MethodInfo method; + Delegate caller = null; + byte* callerPtr = null; + bool hasThis; + bool pushResult; + int paramStart = 0; + int paramCount = 0; + + public IFixBindingCaller(MethodBase method, out bool isSuccess) + { + this.method = (MethodInfo)method; + isSuccess = false; + string methodUniqueStr = TypeNameUtils.GetMethodDelegateKey(method); + + if (methodUniqueStr == "") + { + isSuccess = false; + return; + } + + if (delDict == null) + { + Init(); + } + + if (delDict.TryGetValue(methodUniqueStr, out int info)) + { + InitParams(); + var invokeMethod = typeof(IFixBindingCaller).GetMethod($"Invoke{info}"); + InvokeCall = (ExternInvoker)Delegate.CreateDelegate(typeof(ExternInvoker), this, invokeMethod); + + var delType = Type.GetType($"IFix.Core.IFixBindingCaller+IFixCallDel{info}"); + if (hasThis) + { + //object obj = Activator.CreateInstance(method.ReflectedType); + caller = Delegate.CreateDelegate(delType, null, (MethodInfo)method); + } + else + caller = Delegate.CreateDelegate(delType, (MethodInfo)method); + + callerPtr = (byte*)UnsafeAsUtility.AsPoint(ref caller); + + isSuccess = true; + } + + } + + private void InitParams() + { + hasThis = !method.IsStatic; + paramStart = method.IsStatic ? 0 : 1; + pushResult = method.ReturnType != typeof(void); + paramCount = method.GetParameters().Length; + } + + public void Invoke(VirtualMachine virtualMachine, ref Call call, bool isInstantiate) + { + if (hasThis) + { + object instance = call.managedStack[call.argumentBase->Value1]; + //targetField.SetValue(caller, instance); + void* p = UnsafeAsUtility.AsPoint(ref instance); + +#if ENABLE_IL2CPP + *(void**)(callerPtr + methodCodeOffset) = p; +#else + *(void**)(callerPtr + targetOffset) = p; +#endif + } + + // 这里走delegate创建 + InvokeCall(virtualMachine, ref call, isInstantiate); + + // finally + // { + // Value* pArg = call.argumentBase; + // if (pushResult) + // { + // pArg++; + // } + // + // for (int i = (pushResult ? 1 : 0); i < paramCount + (hasThis ? 1 : 0); i++) + // { + // BoxUtils.RecycleObject(call.managedStack[pArg - call.evaluationStackBase]); + // call.managedStack[pArg - call.evaluationStackBase] = null; + // pArg++; + // } + // } + } + + } +} diff --git a/Source/UnityProj/Assets/IFix/IFixBindingCaller.New.cs.meta b/Source/UnityProj/Assets/IFix/IFixBindingCaller.New.cs.meta new file mode 100644 index 0000000..f008a76 --- /dev/null +++ b/Source/UnityProj/Assets/IFix/IFixBindingCaller.New.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3618f2a002a142d46aff20648fa8e4d8 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/IFix/TypeNameUtils.cs b/Source/UnityProj/Assets/IFix/TypeNameUtils.cs new file mode 100644 index 0000000..a94cbd3 --- /dev/null +++ b/Source/UnityProj/Assets/IFix/TypeNameUtils.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text.RegularExpressions; +using UnityEngine; + +namespace IFix.Core +{ + public static class TypeNameUtils + { + static string[] prefix = new string[] { "System.Collections.Generic" }; + + static string RemoveRef(string s, bool removearray = true) + { + if (s.EndsWith("&")) s = s.Substring(0, s.Length - 1); + if (s.EndsWith("[]") && removearray) s = s.Substring(0, s.Length - 2); + if (s.StartsWith(prefix[0])) s = s.Substring(prefix[0].Length + 1, s.Length - prefix[0].Length - 1); + + s = s.Replace("+", "."); + if (s.Contains("`")) + { + string regstr = @"`\d"; + Regex r = new Regex(regstr, RegexOptions.None); + s = r.Replace(s, ""); + s = s.Replace("[", "<"); + s = s.Replace("]", ">"); + } + + return s; + } + + public static string FullName(Type t) + { + if (t.FullName == null) + { + Debug.Log(t.Name); + return t.Name; + } + + return FullName(t.FullName); + } + + public static string FullName(string str) + { + if (str == null) + { + throw new NullReferenceException(); + } + + return RemoveRef(str.Replace("+", ".")); + } + + public static string SimpleType(Type t) + { + string tn = t.Name; + switch (tn) + { + case "Single": + return "float"; + case "String": + return "string"; + case "String[]": + return "string[]"; + case "Double": + return "double"; + case "Boolean": + return "bool"; + case "Int32": + return "int"; + case "Int32[]": + return "int[]"; + case "UInt32": + return "uint"; + case "UInt32[]": + return "uint[]"; + case "Int16": + return "short"; + case "Int16[]": + return "short[]"; + case "UInt16": + return "ushort"; + case "UInt16[]": + return "ushort[]"; + case "Object": + return FullName(t); + case "Void*": + return "void*"; + default: + tn = TypeDecl(t); + tn = tn.Replace("System.Collections.Generic.", ""); + tn = tn.Replace("System.Object", "object"); + return tn; + } + } + + public static string _Name(string n) + { + n = n.Replace("*", "__X"); + string ret = ""; + for (int i = 0; i < n.Length; i++) + { + if (char.IsLetterOrDigit(n[i])) + ret += n[i]; + else + ret += "_"; + } + + return ret; + } + + public static string GenericBaseName(Type t) + { + string n = t.FullName; + if (string.IsNullOrEmpty(n)) return ""; + if (n.IndexOf('[') > 0) + { + n = n.Substring(0, n.IndexOf('[')); + } + + return n.Replace("+", "."); + } + + public static bool MethodIsStructPublic(MethodBase mb) + { + return mb is MethodInfo && + (!mb.IsStatic && mb.ReflectedType.IsValueType && mb.IsPublic); + } + + public static string GetMethodDelegateKey(MethodBase method) + { + if(TypeNameUtils.SimpleType(method.ReflectedType) == "!") + { + return ""; + } + Type retType = (method is MethodInfo) + ? (method as MethodInfo).ReturnType + : (method as ConstructorInfo).ReflectedType; + + if (!retType.IsVisible) + { + return ""; + } + + if (string.IsNullOrEmpty(retType.FullName)) return ""; + string funName = ""; + List args = new List(); + var parameters = method.GetParameters(); + if (!method.ReflectedType.IsVisible) + { + return ""; + } + if (method is ConstructorInfo) + { + funName = "ctor"; + } + + for (int i = 0, imax = parameters.Length; i + + + + + + + + + + + + diff --git a/Source/UnityProj/Assets/Plugins/Android/AndroidManifest.xml.meta b/Source/UnityProj/Assets/Plugins/Android/AndroidManifest.xml.meta new file mode 100644 index 0000000..6f1a985 --- /dev/null +++ b/Source/UnityProj/Assets/Plugins/Android/AndroidManifest.xml.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 1c2b5d1d59f046043bf9daf86a883405 +TextScriptImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/Plugins/Unsafe.As.dll b/Source/UnityProj/Assets/Plugins/Unsafe.As.dll new file mode 100644 index 0000000..cbae1e5 Binary files /dev/null and b/Source/UnityProj/Assets/Plugins/Unsafe.As.dll differ diff --git a/Source/UnityProj/Assets/Plugins/Unsafe.As.dll.meta b/Source/UnityProj/Assets/Plugins/Unsafe.As.dll.meta new file mode 100644 index 0000000..cf0829d --- /dev/null +++ b/Source/UnityProj/Assets/Plugins/Unsafe.As.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 13d7325f00ddc9b419952b771134dcc8 +PluginImporter: + externalObjects: {} + serializedVersion: 2 + iconMap: {} + executionOrder: {} + defineConstraints: [] + isPreloaded: 0 + isOverridable: 0 + isExplicitlyReferenced: 0 + validateReferences: 1 + platformData: + - first: + Any: + second: + enabled: 1 + settings: {} + - first: + Editor: Editor + second: + enabled: 0 + settings: + DefaultValueInitialized: true + - first: + Windows Store Apps: WindowsStoreApps + second: + enabled: 0 + settings: + CPU: AnyCPU + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/StreamingAssets.meta b/Source/UnityProj/Assets/StreamingAssets.meta new file mode 100644 index 0000000..d4c108e --- /dev/null +++ b/Source/UnityProj/Assets/StreamingAssets.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a6780cd738c6be94198101a994b79f4c +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index 400c853..4f8b02e 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -5,6 +5,8 @@ * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ +using Unity.Collections.LowLevel.Unsafe; + namespace IFix.Core { using System.Collections.Generic; @@ -270,7 +272,7 @@ static int[] readSlotInfo(BinaryReader reader, Dictionary itfMe } // #lizard forgives - unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) + unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true, VirtualMachine.ExternInvokersHandle externInvokersHandle = null) { List nativePointers = new List(); @@ -488,6 +490,7 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) } }) { + externInvokersHandle = externInvokersHandle, ExternTypes = externTypes, ExternMethods = externMethods, ExceptionHandlers = exceptionHandlers.ToArray(), @@ -496,7 +499,7 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) NewFieldInfos = newFieldInfo, AnonymousStoreyInfos = anonymousStoreyInfos, StaticFieldTypes = staticFieldTypes, - Cctors = cctors + Cctors = cctors, }; var wrappersManagerImplName = reader.ReadString(); @@ -570,6 +573,9 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) } } Array arr = wrapperManager.InitWrapperArray(maxPos + 1) as Array; + Type wmType = wrapperManager.GetType(); + object boxTrue = true; + for (int i = 0; i < fixCount; i++) { var wrapper = wrapperManager.CreateWrapper(methodIdArray[i]); @@ -578,6 +584,7 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) throw new Exception("create wrapper fail"); } arr.SetValue(wrapper, posArray[i]); + wmType.GetField($"isPatched_{posArray[i]}").SetValue(null, boxTrue); } removers[assembly] = () => { diff --git a/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs index 6641591..f4115eb 100644 --- a/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs @@ -5,6 +5,8 @@ * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ +using System.Reflection; + namespace IFix.Core { using System.Collections.Generic; @@ -13,6 +15,40 @@ namespace IFix.Core public class SimpleVirtualMachineBuilder { + public unsafe int GetValue(long* a, long* b) + { + long ret = 0; + for (int i = 0; i < 1000; i++) + { + ret = *a + *b; + } + + return (int)ret; + } + + public unsafe int CallTest(List v) + { + var l = new List(); + l.Add(1); + l[0] = 1; + var c = l.Count; + + return v.Count; + } + + public unsafe int CallGetValue(long a, long b) + { + KeyValuePair v = default(KeyValuePair); + return (int)v.Value; + } + + public static string GetUniqueStringForMethod(MethodBase method) + { + var parameters = method.GetParameters(); + var parameterTypeNames = string.Join(",", Array.ConvertAll(parameters, p => p.ParameterType.FullName)); + return $"{method.DeclaringType.FullName}.{method.Name}({parameterTypeNames})"; + } + unsafe static public VirtualMachine CreateVirtualMachine(int loopCount) { Instruction[][] methods = new Instruction[][] @@ -48,6 +84,16 @@ unsafe static public VirtualMachine CreateVirtualMachine(int loopCount) new Instruction {Code = Code.Blt, Operand = -10 }, //14 new Instruction {Code = Code.Ret, Operand = 0 } + }, + new Instruction[] // call extern fun + { + new Instruction {Code = Code.StackSpace, Operand = (1 << 16) | 1 }, + new Instruction {Code = Code.Ldarg, Operand = 1 }, + + new Instruction {Code = Code.CallExtern, Operand = (1 << 16) | 2}, + // new Instruction {Code = Code.Stloc, Operand = 0 }, + // new Instruction {Code = Code.Ldloc, Operand = 0 }, + new Instruction {Code = Code.Ret, Operand = 1 } } }; @@ -69,14 +115,23 @@ unsafe static public VirtualMachine CreateVirtualMachine(int loopCount) } nativePointers.Add(nativePointer); } - - return new VirtualMachine(unmanagedCodes, () => + var newM = typeof(List).GetMethod("get_Count", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); + var externMethods = new MethodBase[3]; + externMethods[0] = typeof(SimpleVirtualMachineBuilder).GetMethod("GetValue"); + externMethods[2] = newM; + + var ret = new VirtualMachine(unmanagedCodes, () => { for (int i = 0; i < nativePointers.Count; i++) { System.Runtime.InteropServices.Marshal.FreeHGlobal(nativePointers[i]); } - }); + }) + { + ExternMethods = externMethods, + }; + + return ret; } } } diff --git a/Source/VSProj/Src/Core/BoxUtils.cs b/Source/VSProj/Src/Core/BoxUtils.cs new file mode 100644 index 0000000..0c87e04 --- /dev/null +++ b/Source/VSProj/Src/Core/BoxUtils.cs @@ -0,0 +1,495 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.IL2CPP.CompilerServices; +using UnityEngine; +using Unsafe.As; +using Object = System.Object; + +namespace IFix.Core +{ + [Il2CppSetOption(Option.NullChecks, false)] + [Il2CppSetOption(Option.ArrayBoundsChecks, false)] + public static unsafe class BoxUtils + { + [ThreadStatic] + private static Stack[] objectPool = null; + + public static readonly int OBJ_OFFSET = 2 * IntPtr.Size; + public static readonly int ONE_OFFSET = IntPtr.Size; + + [ThreadStatic] + private static bool isDummpyInit = false; + + public static void InitD() + { + //var stack = Thread.GetData(localSlot) as ThreadStackInfo; + if (!isDummpyInit) + { + objectPool = new Stack[256]; + isDummpyInit = true; + } + } + + // 第二个位置 用来上锁的。但是一般不会上锁 type,所以拿来存储自定义数据 + // 这个设计的就是不能lock type + public static void CacheTypeInfo(Type t, object obj = null) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + if (*monitorOffset != null) + { + return; + } + + void** info = (void**)UnsafeUtility.Malloc(32, 16, Allocator.Persistent); + UnsafeUtility.MemClear((void*)info, 32); + + /* + * typeHead(8) + * isEnum(1) + * isPrimitive(1) + * isValueType(1) + * isNullable(1) + * size (4) + * nullable UnderlyingType ptr(8) + * nullableOffset (4) + */ + // 把object的typeinfo 保存下来 + bool isNullable = t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>); + if (t.IsValueType && !isNullable) + { + if (obj == null) obj = Activator.CreateInstance(t); + void** typeHead = (void**)UnsafeAsUtility.AsPoint(ref obj); + *info = *typeHead; + *((int*)((byte*)info + 12)) = UnsafeUtility.SizeOf(t); + } + else + { + *info = null; + } + + bool* bptr = (bool*)info; + *(bptr + 8) = t.IsEnum; + *(bptr + 9) = t.IsPrimitive; + *(bptr + 10) = t.IsValueType; + *(bptr + 11) = isNullable; + + if (isNullable) + { + Type ut = Nullable.GetUnderlyingType(t); + *((void**)(bptr + 16)) = UnsafeAsUtility.AsPoint(ref ut); + + var f = t.GetField("hasValue", BindingFlags.Instance| BindingFlags.NonPublic); + if (f == null) f = t.GetField("has_value", BindingFlags.Instance| BindingFlags.NonPublic); + + *(int*)(bptr + 24) = UnsafeUtility.GetFieldOffset(f); + } + + *monitorOffset = info; + } + + + /* + * typeHead(8) + * isEnum(1) + * isPrimitive(1) + * isValueType(1) + * isNullable(1) + * size (4) + * nullable UnderlyingType ptr(8) + * nullableOffset (4) + */ + public static void* GetTypeHead(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return **(void***)monitorOffset; + } + + public static bool GetTypeIsEnum(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return *(*(bool**)monitorOffset + 8); + } + + public static bool GetTypeIsPrimitive(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return *(*(bool**)monitorOffset + 9); + } + + public static bool GetTypeIsValueType(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return *(*(bool**)monitorOffset + 10); + } + + public static bool GetTypeIsNullable(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return *(*(bool**)monitorOffset + 11); + } + + public static int GetTypeSize(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return *(*(int**)monitorOffset + 3); + } + + public static Type GetNullableUnderlying(Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + void* ptr = *(void**)((byte*)*monitorOffset + 16); + return UnsafeAsUtility.RefAs(&ptr); + } + + public static int GetFieldOffset(FieldInfo fi) + { + long* monitorOffset = (long*)UnsafeAsUtility.AsPoint(ref fi) + 1; + if (*monitorOffset == 0) + { + int offset = UnsafeUtility.GetFieldOffset(fi); + if (fi.ReflectedType.IsValueType) + { + *((int*)monitorOffset) = offset + 2 * OBJ_OFFSET; + } + else + { + *((int*)monitorOffset) = offset + OBJ_OFFSET; + } + } + + return *((int*)monitorOffset) - OBJ_OFFSET; + } + + public static object CreateDefaultBoxValue(Type t) + { + void* p = null; + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + byte* typeInfo = (byte*)*monitorOffset; + bool isNullable = *(bool*)(typeInfo + 11); + if (isNullable) return null; + // bool isValueType = *(bool*)(typeInfo + 10); + // if(isValueType) + + return CreateBoxValue(monitorOffset, ref p, true, true); + } + + public static object CreateBoxValue(Type t, bool jumpNulable = false) + { + void* p = null; + return CreateBoxValue(t, ref p, jumpNulable); + } + + public static object CreateBoxValue(Type t, ref void* objPtr, bool jumpNulable = false, bool clearObj = false) + { + //if (t == typeof(void)) return null; + //if (t == null) return null; + // class type + //if (!t.IsValueType) return null; + + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + + return CreateBoxValue(monitorOffset, ref objPtr, jumpNulable, clearObj); + } + + public static object CreateBoxValue(void** monitorOffset, ref void* objPtr, bool jumpNulable = false, bool clearObj = false) + { + byte* typeInfo = (byte*)*monitorOffset; + bool isValueType = *(bool*)(typeInfo + 10); + if (!isValueType) return null; + + if (!jumpNulable) + { + bool isNullable = *(bool*)(typeInfo + 11); + if (isNullable) + { + var ut = UnsafeAsUtility.RefAs((void**)(typeInfo + 16)); + + monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref ut) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(ut); + } + typeInfo = (byte*)*monitorOffset; + } + } + + int size = *(int*)(typeInfo + 12); + int idx = (size + 15) / 16 - 1; + + var pool = objectPool[idx]; + if (pool == null) + { + pool = new Stack(); + objectPool[idx] = pool; + } + + object obj = null; + void* p; + if (pool.Count > 0) + { + //lock (pool) + { + obj = pool.Pop(); + p = UnsafeAsUtility.AsPoint(ref obj); + } + } + else + { + p = UnsafeUtility.Malloc(size + OBJ_OFFSET, OBJ_OFFSET, Allocator.Persistent); + // 把type头设置到 自定义申请的内存中,这样就可以伪造一个 C#的object + *((void**)p) = *(void**)typeInfo; + obj = UnsafeAsUtility.RefAs(&p); + } + + // 第二个字段是 lock的hash,一半我们不会用box对象lock + // 所以这里直接拿来当是否被cache + *(int*)((byte*)p + ONE_OFFSET) = size; + // 把type头设置到 自定义申请的内存中,这样就可以伪造一个 C#的object + *(void**)p = *(void**)typeInfo; + objPtr = p; + + if(clearObj) + UnsafeUtility.MemClear((byte*)p + OBJ_OFFSET, size); + + return obj; + } + + public static object CreateReturnValue(Type returnType) + { + if (!GetTypeIsValueType(returnType)) return null; + + void* p = null; + return CreateBoxValue(returnType, ref p); + } + + public static object CloneObject(object value) + { + if (value == null) return null; + Type t = value.GetType(); + + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + byte* typeInfo = (byte*)*monitorOffset; + bool isValueType = *(bool*)(typeInfo + 10); + if (!isValueType) return value; + + void* p = null; + int len = *(int*)(typeInfo + 12); + object result = CreateBoxValue(monitorOffset, ref p); + byte* source = (byte*)UnsafeAsUtility.AsPoint(ref value) + OBJ_OFFSET; + UnsafeUtility.MemCpy((byte*)p + OBJ_OFFSET, source, len); + + return result; + } + + public static object GetStaticFieldValue(FieldInfo fi, Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + byte* typeInfo = (byte*)*monitorOffset; + bool isValueType = *(bool*)(typeInfo + 10); + if (!isValueType) return fi.GetValue(null); + + bool isNullable = *(bool*)(typeInfo + 11); + void* p = null; + object ret = CreateBoxValue(monitorOffset, ref p,!isNullable, false); + UnsafeUtility.GetStaticFieldValue(fi, ret); + + return ret; + } + + public static object GetFieldValue(object thisArg, FieldInfo fi, Type t) + { + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + byte* typeInfo = (byte*)*monitorOffset; + bool isValueType = *(bool*)(typeInfo + 10); + if (!isValueType) return fi.GetValue(thisArg); + + bool isNullable = *(bool*)(typeInfo + 11); + byte* source = (byte*)UnsafeAsUtility.AsPoint(ref thisArg); + int filedOffset = GetFieldOffset(fi); + int len = *(int*)(typeInfo + 12); + + if (isNullable) + { + var ut = UnsafeAsUtility.RefAs((void**)(typeInfo + 16)); + int nullableOffset = *(int*)(typeInfo + 24); + if (*(bool*)(source + filedOffset+ nullableOffset) == false) return null; + + t = ut; + monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + typeInfo = (byte*)*monitorOffset; + len = *(int*)(typeInfo + 12); + } + + void* b = null; + object result = CreateBoxValue(monitorOffset, ref b, true); + source = source + filedOffset; + + UnsafeUtility.MemCpy((byte*)b + OBJ_OFFSET, source, len); + + return result; + } + + public static object BoxEnumObject(Type t, int value) + { + void* p = null; + object obj = CreateBoxValue(t, ref p, true); + *((int*)((byte*)p + OBJ_OFFSET)) = value; + + return obj; + } + + public static object BoxEnumObject(Type t, long value) + { + void* p = null; + object obj = CreateBoxValue(t, ref p, true); + *((long*)((byte*)p + OBJ_OFFSET)) = value; + + return obj; + } + + public static object BoxObject(T value, bool jumpTypeCheck = false) + { + Type t = typeof(T); + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + // 没cache + if (*monitorOffset == null) + { + CacheTypeInfo(t); + } + byte* typeInfo = (byte*)*monitorOffset; + + if (!jumpTypeCheck) + { + bool isValueType = *(bool*)(typeInfo + 10); + if (!isValueType) return value; + } + + //var dummpy = new Dummpy(value); + void* addr = UnsafeAsUtility.AsPoint(ref value);// UnsafeUtility.AddressOf(ref dummpy); + + bool isNullable = *(bool*)(typeInfo + 11); + // nullable特殊处理,用offset 判断出来是否为空 + if (isNullable) + { + t = UnsafeAsUtility.RefAs((void**)(typeInfo + 16)); + int offset = *(int*)(typeInfo + 24); + if (*((bool*)addr + offset) == false) return null; + monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref t) + 1; + typeInfo = (byte*)*monitorOffset; + + int len = *(int*)(typeInfo + 12); + void* p = null; + object obj = CreateBoxValue(monitorOffset, ref p, true); + UnsafeUtility.MemCpy((byte*)p + OBJ_OFFSET, addr, len); + + return obj; + } + else + { + void* p = null; + int len = *(int*)(typeInfo + 12); + object obj = CreateBoxValue(monitorOffset, ref p, true); + UnsafeAsUtility.CopyStructureToPtr(ref value, (byte*)p + OBJ_OFFSET); + + return obj; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RecycleObject(object obj) + { + if (obj == null) return; + byte* p = (byte*)UnsafeAsUtility.AsPoint(ref obj); + // 第二个字段是 lock的hash,一般我们不会用box对象lock + // 所以这里直接拿来当是否 isInPool + int* sizePtr = (int*)(p + ONE_OFFSET); + int size = *sizePtr; + // monitor的lock 会超过4096的,但是一般value type的长度不会 + if (size == 0 || size > 4096) return; + + objectPool[(size + 15) / 16 - 1].Push(obj); + + //UnsafeUtility.MemClear(p + OBJ_OFFSET, size); + *sizePtr = 0; + } + } +} \ No newline at end of file diff --git a/Source/VSProj/Src/Core/DataDefine.cs b/Source/VSProj/Src/Core/DataDefine.cs index 140117b..920d692 100644 --- a/Source/VSProj/Src/Core/DataDefine.cs +++ b/Source/VSProj/Src/Core/DataDefine.cs @@ -7,7 +7,7 @@ namespace IFix.Core { - public enum ValueType + public enum ValueType : int { Integer, Long, @@ -25,8 +25,8 @@ public enum ValueType [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] public struct Value { - public ValueType Type; public int Value1; public int Value2; + public ValueType Type; } } \ No newline at end of file diff --git a/Source/VSProj/Src/Core/GenericDelegate.cs b/Source/VSProj/Src/Core/GenericDelegate.cs index f41d382..128a243 100644 --- a/Source/VSProj/Src/Core/GenericDelegate.cs +++ b/Source/VSProj/Src/Core/GenericDelegate.cs @@ -68,9 +68,9 @@ internal static Delegate Create(Type delegateType, VirtualMachine virtualMachine MethodInfo delegateMethod = delegateType.GetMethod("Invoke"); var parameters = delegateMethod.GetParameters(); - if ((delegateMethod.ReturnType.IsValueType && delegateMethod.ReturnType != typeof(void)) - || parameters.Length > 4 - || parameters.Any(p => p.ParameterType.IsValueType || p.ParameterType.IsByRef) + if ((BoxUtils.GetTypeIsValueType(delegateMethod.ReturnType) && delegateMethod.ReturnType != typeof(void)) + || parameters.Length > 4 + || parameters.Any(p => BoxUtils.GetTypeIsValueType(p.ParameterType) || p.ParameterType.IsByRef) ) { //如果不在支持的范围,则生成一个永远返回空的构造器 diff --git a/Source/VSProj/Src/Core/Instruction.cs b/Source/VSProj/Src/Core/Instruction.cs index cfe8843..c2d57a1 100644 --- a/Source/VSProj/Src/Core/Instruction.cs +++ b/Source/VSProj/Src/Core/Instruction.cs @@ -7,192 +7,196 @@ namespace IFix.Core { - public enum Code + public enum Code : int { - Nop, - Break, - Ldarg, - Ldloc, - Stloc, - Ldarga, - Starg, - Ldloca, - Ldnull, - Ldc_I4, - Ldc_I8, - Ldc_R4, - Ldc_R8, - Dup, - Pop, - Jmp, - Call, - CallExtern, - //Calli, - Ret, - Br, - Brfalse, - Brtrue, - Beq, - Bge, - Bgt, - Ble, - Blt, - Bne_Un, - Bge_Un, - Bgt_Un, - Ble_Un, - Blt_Un, - Switch, - Ldind_I1, - Ldind_U1, - Ldind_I2, - Ldind_U2, - Ldind_I4, - Ldind_U4, - Ldind_I8, - Ldind_I, - Ldind_R4, - Ldind_R8, - Ldind_Ref, - Stind_Ref, - Stind_I1, - Stind_I2, - Stind_I4, - Stind_I8, - Stind_R4, - Stind_R8, - Add, - Sub, - Mul, - Div, - Div_Un, - Rem, - Rem_Un, - And, - Or, - Xor, - Shl, - Shr, - Shr_Un, - Neg, - Not, - Conv_I1, - Conv_I2, - Conv_I4, - Conv_I8, - Conv_R4, - Conv_R8, - Conv_U4, - Conv_U8, - Callvirt, - Callvirtvirt, - Ldvirtftn2, - Cpobj, - Ldobj, - Ldstr, - Newobj, - Castclass, - Isinst, - Conv_R_Un, - Unbox, - Throw, - Ldfld, - Ldflda, - Stfld, - Ldsfld, - Ldsflda, - Stsfld, - Stobj, - Conv_Ovf_I1_Un, - Conv_Ovf_I2_Un, - Conv_Ovf_I4_Un, - Conv_Ovf_I8_Un, - Conv_Ovf_U1_Un, - Conv_Ovf_U2_Un, - Conv_Ovf_U4_Un, - Conv_Ovf_U8_Un, - Conv_Ovf_I_Un, - Conv_Ovf_U_Un, - Box, - Newarr, - Ldlen, - Ldelema, - Ldelem_I1, - Ldelem_U1, - Ldelem_I2, - Ldelem_U2, - Ldelem_I4, - Ldelem_U4, - Ldelem_I8, - Ldelem_I, - Ldelem_R4, - Ldelem_R8, - Ldelem_Ref, - Stelem_I, - Stelem_I1, - Stelem_I2, - Stelem_I4, - Stelem_I8, - Stelem_R4, - Stelem_R8, - Stelem_Ref, - Ldelem_Any, - Stelem_Any, - Unbox_Any, - Conv_Ovf_I1, - Conv_Ovf_U1, - Conv_Ovf_I2, - Conv_Ovf_U2, - Conv_Ovf_I4, - Conv_Ovf_U4, - Conv_Ovf_I8, - Conv_Ovf_U8, - Refanyval, - Ckfinite, - Mkrefany, - Ldtoken, - Ldtype, // custom - Conv_U2, - Conv_U1, - Conv_I, - Conv_Ovf_I, - Conv_Ovf_U, - Add_Ovf, - Add_Ovf_Un, - Mul_Ovf, - Mul_Ovf_Un, - Sub_Ovf, - Sub_Ovf_Un, - Endfinally, - Leave, - Stind_I, - Conv_U, - Arglist, - Ceq, - Cgt, - Cgt_Un, - Clt, - Clt_Un, - Ldftn, - Newanon, - Ldvirtftn, - Localloc, - Endfilter, - Unaligned, - Volatile, - Tail, - Initobj, - Constrained, - Cpblk, - Initblk, - No, - Rethrow, - Sizeof, - Refanytype, - Readonly, + Cgt, + Stelem_R8, + Volatile, + Conv_Ovf_I4, + Add_Ovf, + Conv_Ovf_U4_Un, + Conv_Ovf_U1_Un, + Unaligned, + Ldc_R4, + Conv_Ovf_I_Un, + And, + Neg, + Ldind_I8, + Ldelem_Ref, + Conv_Ovf_I2_Un, + Add_Ovf_Un, + Cpblk, + Conv_Ovf_I, + Shr_Un, + Conv_Ovf_U4, + Ret, + Xor, + Clt, + Conv_I, + Ldind_I4, + Dup, + Ldelem_R4, + Clt_Un, + Ldarga, + Sizeof, + Mul, + Localloc, + Ckfinite, + Conv_U8, + Stelem_I, + Or, + Blt, + Ble, + Ble_Un, + Blt_Un, + Bgt, + Bge, + Bge_Un, + Bgt_Un, + Bne_Un, + Ldelema, + Ldftn, + No, + Ldfld, + Conv_Ovf_I4_Un, + Tail, + Initblk, + Readonly, + Stelem_I1, + Sub_Ovf_Un, + Ldtoken, + Ldelem_I1, + Refanyval, + Stind_I1, + Div_Un, + Ldarg, + Newanon, + Ldvirtftn2, + Conv_Ovf_U2, + Conv_Ovf_I1_Un, + Br, + Mkrefany, + Ldstr, + Newarr, + Ldtype, + Conv_Ovf_I1, + Conv_R4, + Ldc_I4, + Stelem_I4, + Not, + Conv_U2, + Rem_Un, + Ldelem_U2, + Conv_I4, + Stobj, + Brtrue, + Conv_U4, + Call, + Rem, + Castclass, + Conv_Ovf_I8, + Conv_I8, + Add, + Ldloc, + Conv_Ovf_U8_Un, + CallExtern, + Conv_U1, + Conv_Ovf_U1, + StackSpace, + Stsfld, + Shl, + Ldelem_R8, + Ldelem_I8, + Ldind_U4, + Break, + Sub_Ovf, + Conv_R8, + Mul_Ovf, + Brfalse, + Conv_Ovf_I2, + Jmp, + Conv_U, + Ldelem_U1, + Div, + Ldsfld, + Initobj, + Stelem_I8, + Newobj, + Stelem_Any, + Conv_I2, + Pop, + Unbox_Any, + Cpobj, + Stind_R8, + Ldind_I, + Conv_I1, + Cgt_Un, + Stelem_Ref, + Stind_I2, + Mul_Ovf_Un, + Ldind_R4, + Conv_Ovf_U, + Ldelem_I, + Stind_I4, + Nop, + Throw, + Ldobj, + Endfinally, + Ldvirtftn, + Ldsflda, + Callvirtvirt, + Stind_Ref, + Ldnull, + Stind_I8, + Ldelem_U4, + Conv_Ovf_U8, + Ldc_I8, + Stind_I, + Unbox, + Beq, + Switch, + Callvirt, + Constrained, + Refanytype, + Ldind_U1, + Starg, + Sub, + Ldflda, + Ldind_I1, + Rethrow, + Ldind_U2, + Ldind_R8, + Ldelem_Any, + Leave, + Endfilter, + Conv_Ovf_U_Un, + Conv_Ovf_I8_Un, + Stelem_R4, + Stloc, + Stfld, + Ceq, + Box, + Ldind_I2, + Shr, + Arglist, + Conv_R_Un, + Stelem_I2, - //Pseudo instruction - StackSpace, + Ldind_Ref, + Ldc_R8, + Ldelem_I4, + Conv_Ovf_U2_Un, + Stind_R4, + Ldlen, + Ldloca, + Ldelem_I2, + + //Pseudo instruction + Isinst, + + CallStaticR_I4_I4_I4_Extern, + Add1_Loc, + Add_I4, } [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)] @@ -201,7 +205,7 @@ public struct Instruction /// /// 指令MAGIC /// - public const ulong INSTRUCTION_FORMAT_MAGIC = 317431043901; + public const ulong INSTRUCTION_FORMAT_MAGIC = 1719456845587952638UL; /// /// 当前指令 @@ -214,6 +218,8 @@ public struct Instruction public int Operand; } + public delegate int CallR_I4_I4_I4(int arg1, int arg2); + public enum ExceptionHandlerType { Catch = 0, diff --git a/Source/VSProj/Src/Core/ObjectClone.cs b/Source/VSProj/Src/Core/ObjectClone.cs index 76d193b..86431ab 100644 --- a/Source/VSProj/Src/Core/ObjectClone.cs +++ b/Source/VSProj/Src/Core/ObjectClone.cs @@ -11,13 +11,13 @@ namespace IFix.Core using System; using System.Linq.Expressions; - public class ObjectClone + public static class ObjectClone { - MethodInfo memberwiseClone; + static MethodInfo memberwiseClone; //Func ptrToMemberwiseClone; //FieldInfo target; - //Func cloneFunc; - public ObjectClone() + static Func cloneFunc; + static ObjectClone() { memberwiseClone = typeof(object).GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic); @@ -28,16 +28,16 @@ public ObjectClone() // | BindingFlags.NonPublic); //var p = Expression.Parameter(typeof(object), "obj"); //var mce = Expression.Call(p, methodInfo); - //cloneFunc = Expression.Lambda>(mce, p).Compile();//TODO: 需要用到jit么? + cloneFunc = (Func)Delegate.CreateDelegate(typeof(Func), memberwiseClone); //Expression.Lambda>(mce, p).Compile();//TODO: 需要用到jit么? } - public object Clone(object obj) + public static object Clone(object obj) { - return memberwiseClone.Invoke(obj, null);//1.79s + //return memberwiseClone.Invoke(obj, null);//1.79s //target.SetValue(ptrToMemberwiseClone, obj); //return ptrToMemberwiseClone();//1.17s //return ((Func)Delegate.CreateDelegate(typeof(Func), obj, memberwiseClone))();//3.05s - //return cloneFunc(obj);//0.06s + return cloneFunc(obj);//0.06s } } } \ No newline at end of file diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index 2de7441..1ae7712 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -7,14 +7,16 @@ using System.Reflection; using System; +using System.Collections.Generic; +using Unity.Collections.LowLevel.Unsafe; namespace IFix.Core { internal class ReflectionMethodInvoker { int paramCount; - bool hasThis; + bool valueInstance; bool hasReturn; @@ -22,18 +24,71 @@ internal class ReflectionMethodInvoker bool[] outFlags; + bool[] isValueFlags; + Type[] rawTypes; - //object[] args; + [ThreadStatic] + static Stack[] argsPool = null; MethodBase method; ConstructorInfo ctor = null; Type returnType = null; + bool returnTypeIsValueType; + Type declaringType = null; + Type cacheReturnType = null; bool isNullableHasValue = false; bool isNullableValue = false; + bool isNullableGetValueOrDefault = false; + bool IsConstructor = false; + bool declaringTypeIsValueType = false; + + private static object[] GetArgs(int paramCount) + { + if (argsPool == null) + { + argsPool = new Stack[256]; + for (int i = 0; i < 256; i++) + { + argsPool[i] = new Stack(); + } + } + + Stack pool = argsPool[paramCount]; + if (pool.Count > 0) + { + return pool.Pop(); + } + return new object[paramCount]; + } + + private static void RecycleArgsToPool(object[] args) + { + int paramCount = args.Length; + Stack pool = argsPool[paramCount]; + // if(pool == null) + // { + // pool = new Stack(); + // argsPool[paramCount] = pool; + // } + pool.Push(args); + } + + private void RecycleArgs(object[] args) + { + for (int i = 0; i < paramCount; i++) + { + if(isValueFlags[i]) + BoxUtils.RecycleObject(args[i]); + + args[i] = null; + } + + RecycleArgsToPool(args); + } public ReflectionMethodInvoker(MethodBase method) { @@ -41,8 +96,8 @@ public ReflectionMethodInvoker(MethodBase method) paramCount = paramerInfos.Length; refFlags = new bool[paramCount]; outFlags = new bool[paramCount]; + isValueFlags = new bool[paramCount]; rawTypes = new Type[paramCount]; - //args = new object[paramCount]; for (int i = 0; i < paramerInfos.Length; i++) { @@ -57,24 +112,44 @@ public ReflectionMethodInvoker(MethodBase method) refFlags[i] = false; rawTypes[i] = paramerInfos[i].ParameterType; } + + isValueFlags[i] = paramerInfos[i].ParameterType.IsValueType; } this.method = method; + returnTypeIsValueType = false; if (method.IsConstructor) { ctor = method as ConstructorInfo; returnType = method.DeclaringType; + returnTypeIsValueType = returnType.IsValueType; + cacheReturnType = Nullable.GetUnderlyingType(returnType); + if (cacheReturnType == null) cacheReturnType = returnType; + hasReturn = true; } else { returnType = (method as MethodInfo).ReturnType; hasReturn = returnType != typeof(void); + if (hasReturn) + { + returnTypeIsValueType = returnType.IsValueType; + cacheReturnType = Nullable.GetUnderlyingType(returnType); + if (cacheReturnType == null) cacheReturnType = returnType; + } } hasThis = !method.IsStatic; + valueInstance = hasThis && method.DeclaringType.IsValueType; + bool isNullableMethod = method.DeclaringType.IsGenericType && method.DeclaringType.GetGenericTypeDefinition() == typeof(Nullable<>); isNullableHasValue = isNullableMethod && method.Name == "get_HasValue"; isNullableValue = isNullableMethod && method.Name == "get_Value"; + isNullableGetValueOrDefault = isNullableMethod && method.Name == "GetValueOrDefault"; + + IsConstructor = method.IsConstructor; + declaringTypeIsValueType = method.DeclaringType.IsValueType; + declaringType = method.DeclaringType; } // #lizard forgives @@ -82,7 +157,10 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI { var managedStack = call.managedStack; var pushResult = false; - var args = new object[paramCount]; + object ret = null; + var args = GetArgs(paramCount); + // invoke中会自己调用自己 + try { //virtualMachine._Info("method: " + method); @@ -101,40 +179,24 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI if (!outFlags[i]) { args[i] = EvaluationStackOperation.ToObject(call.evaluationStackBase, pArg, managedStack, - rawTypes[i], virtualMachine); + rawTypes[i], virtualMachine, false); } - //if (pArg->Type >= ValueType.Object) - //{ - // managedStack[pArg->Value1] = null; - //} - //if (method.Name == "Invoke" && method.DeclaringType.Name == "MethodBase") - //{ - // VirtualMachine._Info(i + " pArg->Type:" + pArg->Type); - // VirtualMachine._Info(i + " args[i]:" + args[i]); - // if (args[i] != null) - // { - // VirtualMachine._Info(i + " args[i]:" + args[i].GetHashCode()); - // } - // VirtualMachine._Info(i + " args[i].GetType:" + (args[i] == null ? - // "null" : args[i].GetType().ToString())); - // if (i == 1 && args[i] is object[]) - // { - // var objs = args[i] as object[]; - // for (int j = 0; j < objs.Length;j++) - // { - // VirtualMachine._Info("obj " + j + ": " + (objs[j] == null ? - // "null" : objs[j].GetType().ToString())); - // } - // } - //} pArg++; } - object ret; - - if (isInstantiate || (method.IsConstructor && method.DeclaringType.IsValueType)) + if (isInstantiate || (IsConstructor && declaringTypeIsValueType)) { - ret = ctor.Invoke(args);//TODO: Delegate创建用Delegate.CreateDelegate + if (returnTypeIsValueType) + { + ret = BoxUtils.CreateBoxValue(cacheReturnType, true); + } + else + { + ret = null; + } + + ret = UnsafeUtility.CallMethod(ctor, args, ret); + //ret = ctor.Invoke(args);//TODO: Delegate创建用Delegate.CreateDelegate } else { @@ -142,7 +204,7 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI if (hasThis) { instance = EvaluationStackOperation.ToObject(call.evaluationStackBase, call.argumentBase, - managedStack, method.DeclaringType, virtualMachine, false); + managedStack, declaringType, virtualMachine, false); } //Nullable仍然是值类型,只是新增了是否为null的标志位,仍然通过传地址的方式进行方法调用, //但这在反射调用行不通,参数是object类型,boxing到object就是null,所以会触发 @@ -156,19 +218,51 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI { ret = instance; } + else if (isNullableGetValueOrDefault) + { + if(instance == null) + { + if (paramCount == 0) + ret = BoxUtils.CreateDefaultBoxValue(returnType); + else + ret = args[0]; + } + else + { + ret = instance; + } + } else { - if (method.IsStatic == false && instance == null) + if (hasThis && instance == null) { throw new TargetException(string.Format("can not invoke method [{0}.{1}], Non-static method require instance but got null.", method.DeclaringType, method.Name)); } else { - ret = method.Invoke(instance, args); + if (returnTypeIsValueType) + { + ret = BoxUtils.CreateBoxValue(cacheReturnType, true); + } + else + { + ret = null; + } + + ret = UnsafeUtility.CallMethod(method, instance, args, ret); + //ret = method.Invoke(instance, args); } } + + if (valueInstance) + { + BoxUtils.RecycleObject(instance); + } + } + + for (int i = 0; i < paramCount; i++) { if (refFlags[i]) @@ -179,9 +273,9 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI if (hasReturn || isInstantiate) { - if (method.IsConstructor && method.DeclaringType.IsValueType && !isInstantiate) + if (IsConstructor && BoxUtils.GetTypeIsValueType(declaringType) && !isInstantiate) { - call.UpdateReference(0, ret, virtualMachine, method.DeclaringType); + call.UpdateReference(0, ret, virtualMachine, declaringType); } else { @@ -194,49 +288,22 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI { throw e.InnerException; } - //catch (TargetException e) - //{ - // //VirtualMachine._Info("exception method: " + method + ", in " + method.DeclaringType + ", msg:" - // + e.InnerException); - // //for (int i = 0; i < paramCount; i++) - // //{ - // // VirtualMachine._Info("arg " + i + " type: " + (args[i] == null ? "null" : args[i].GetType() - // // .ToString()) + " value: " + args[i]); - // //} - // if (e.InnerException is System.ArgumentException && args.Length == 2 && args[1] is object[]) - // { - // //VirtualMachine._Info("exception method: " + method + ", in " + method.DeclaringType - // // + ", msg:" + e.InnerException); - // if (instance is MethodBase) - // { - // MethodBase mb = instance as MethodBase; - // VirtualMachine._Info("exception method: " + mb + ", in " + mb.DeclaringType); - // } - // args = args[1] as object[]; - // for (int i = 0; i < args.Length; i++) - // { - // VirtualMachine._Info("arg " + i + " type: " + (args[i] == null ? - // "null" : args[i].GetType().ToString()) + " value: " + args[i]); - // } - // } - // throw e; - //} finally { - //for (int i = 0; i < paramCount; i++) - //{ - // args[i] = null; - //} - Value* pArg = call.argumentBase; - if (pushResult) - { - pArg++; - } - for (int i = (pushResult ? 1 : 0); i < paramCount + ((hasThis && !isInstantiate) ? 1 : 0); i++) - { - managedStack[pArg - call.evaluationStackBase] = null; - pArg++; - } + RecycleArgs(args); + + // Value* pArg = call.argumentBase; + // if (pushResult) + // { + // pArg++; + // } + // + // for (int i = (pushResult ? 1 : 0),imax=paramCount + ((hasThis && !isInstantiate) ? 1 : 0); i < imax; i++) + // { + // BoxUtils.RecycleObject(managedStack[pArg - call.evaluationStackBase]); + // managedStack[pArg - call.evaluationStackBase] = null; + // pArg++; + // } } } } diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index 541d55c..68d833b 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -5,6 +5,11 @@ * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ +using System.Text; +using Unity.Collections.LowLevel.Unsafe; +using UnityEngine; +using Unsafe.As; + namespace IFix.Core { using System; @@ -14,13 +19,13 @@ namespace IFix.Core using System.Collections.Generic; [StructLayout(LayoutKind.Sequential)] - unsafe struct UnmanagedStack + public unsafe struct UnmanagedStack { public Value* Base; public Value* Top; } - unsafe class ThreadStackInfo + public unsafe class ThreadStackInfo { public UnmanagedStack* UnmanagedStack; public object[] ManagedStack; @@ -64,35 +69,38 @@ public ThreadStackInfo() //This is a known limitation of the liveness check, as the we don't handle thread static or //context static variables as roots when performing the collection. //The crash will happen in mono_unity_liveness_calculation_from_statics - //[ThreadStatic] - //internal static ThreadStackInfo Stack = null; + [ThreadStatic] + private static ThreadStackInfo stack = null; - static LocalDataStoreSlot localSlot = Thread.AllocateDataSlot(); + //static LocalDataStoreSlot localSlot = Thread.AllocateDataSlot(); internal static ThreadStackInfo Stack { get { - var stack = Thread.GetData(localSlot) as ThreadStackInfo; + //var stack = Thread.GetData(localSlot) as ThreadStackInfo; if (stack == null) { - VirtualMachine._Info("create thread stack"); + //VirtualMachine._Info("create thread stack"); stack = new ThreadStackInfo(); - Thread.SetData(localSlot, stack); + BoxUtils.InitD(); + //Thread.SetData(localSlot, stack); } + return stack; } } } - unsafe internal static class EvaluationStackOperation + unsafe public static class EvaluationStackOperation { internal static void UnboxPrimitive(Value* evaluationStackPointer, object obj, Type type) { - if (obj.GetType().IsEnum) - { - obj = Convert.ChangeType(obj, type); - } + // if (BoxUtils.GetTypeIsEnum(obj.GetType())) + // { + // obj = Convert.ChangeType(obj, type); + // } + if (obj is int) { evaluationStackPointer->Type = ValueType.Integer; @@ -167,7 +175,8 @@ internal static void UnboxPrimitive(Value* evaluationStackPointer, object obj, T throw new NotImplementedException("Unbox a " + obj.GetType() + " to " + type); } - internal static object mGet(bool isArray, object root, int layer, int[] fieldIdList, FieldInfo[] fieldInfos, Dictionary newFieldInfos) + internal static object mGet(bool isArray, object root, int layer, int[] fieldIdList, FieldInfo[] fieldInfos, + Dictionary newFieldInfos) { //Console.WriteLine("mGet " + root); var fieldId = fieldIdList[layer]; @@ -180,8 +189,8 @@ internal static object mGet(bool isArray, object root, int layer, int[] fieldIdL else { var fieldInfo = fieldInfos[fieldId]; - - if(fieldInfo == null) + + if (fieldInfo == null) { return newFieldInfos[fieldId].GetValue(root); } @@ -193,13 +202,14 @@ internal static object mGet(bool isArray, object root, int layer, int[] fieldIdL { var fieldInfo = fieldInfos[fieldId]; - if(fieldInfo == null) + if (fieldInfo == null) { - return newFieldInfos[fieldId].GetValue(mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos)); + return newFieldInfos[fieldId] + .GetValue(mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos)); } - + //VirtualMachine._Info("before --- " + fieldInfo); - var ret = fieldInfo.GetValue(mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos)); + var ret = fieldInfo.GetValue(mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos)); //VirtualMachine._Info("after --- " + fieldInfo); return ret; } @@ -219,7 +229,7 @@ internal static void mSet(bool isArray, object root, object val, int layer, int[ { var fieldInfo = fieldInfos[fieldId]; - if(fieldInfo == null) + if (fieldInfo == null) { newFieldInfos[fieldId].SetValue(root, val); } @@ -228,6 +238,7 @@ internal static void mSet(bool isArray, object root, object val, int layer, int[ //VirtualMachine._Info("set1 " + val.GetType() + " to " + fieldInfo + " of " + root.GetType() // + ", root.hc = " + root.GetHashCode()); fieldInfo.SetValue(root, val); + BoxUtils.RecycleObject(val); } } } @@ -238,22 +249,62 @@ internal static void mSet(bool isArray, object root, object val, int layer, int[ var parent = mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos); //VirtualMachine._Info("after get " + fieldInfo); //VirtualMachine._Info("before set " + fieldInfo); - if(fieldInfo == null) + if (fieldInfo == null) { newFieldInfos[fieldId].SetValue(parent, val); } else { fieldInfo.SetValue(parent, val); + BoxUtils.RecycleObject(val); } + //VirtualMachine._Info("set2 " + val.GetType() + " to " + fieldInfo + " of " + parent.GetType()); //VirtualMachine._Info("after set " + fieldInfo); mSet(isArray, root, parent, layer - 1, fieldIdList, fieldInfos, newFieldInfos); } } + private static Dictionary readonlyStaticFieldCache = new Dictionary(); + private static HashSet readonlyStaticObjectCache = new HashSet(); + public static object GetStaticValueFromeCache(FieldInfo fi) + { + if (BoxUtils.GetTypeIsValueType(fi.FieldType) && (fi.IsInitOnly || fi.IsLiteral)) + { + object result = null; + lock (readonlyStaticFieldCache) + { + if (!readonlyStaticFieldCache.TryGetValue(fi, out result)) + { + result = fi.GetValue(null); + readonlyStaticFieldCache.Add(fi, result); + readonlyStaticObjectCache.Add(result); + } + } + + return result; + } + + return fi.GetValue(null); + } + + private static Type intType = typeof(int); + private static Type boolType = typeof(bool); + private static Type sbyteType = typeof(sbyte); + private static Type byteType = typeof(byte); + private static Type charType = typeof(char); + private static Type shortType = typeof(short); + private static Type ushortType = typeof(ushort); + private static Type uintType = typeof(uint); + private static Type longType = typeof(long); + private static Type ulongType = typeof(ulong); + private static Type IntPtrType = typeof(IntPtr); + private static Type UIntPtrType = typeof(UIntPtr); + private static Type floatType = typeof(float); + private static Type doubleType = typeof(double); + // #lizard forgives - internal static unsafe object ToObject(Value* evaluationStackBase, Value* evaluationStackPointer, + public static unsafe object ToObject(Value* evaluationStackBase, Value* evaluationStackPointer, object[] managedStack, Type type, VirtualMachine virtualMachine, bool valueTypeClone = true) { //未初始化的local引用可能作为out参数反射调用 @@ -261,192 +312,346 @@ internal static unsafe object ToObject(Value* evaluationStackBase, Value* evalua switch (evaluationStackPointer->Type) { case ValueType.Integer: + { + int i = evaluationStackPointer->Value1; + if (type == intType) { - int i = evaluationStackPointer->Value1; - if (type == typeof(int)) - return i; - else if (type == typeof(bool)) - return i == 1; - else if (type == typeof(sbyte)) - return (sbyte)i; - else if (type == typeof(byte)) - return (byte)i; - else if (type == typeof(char)) - return (char)i; - else if (type == typeof(short)) - return (short)i; - else if (type == typeof(ushort)) - return (ushort)i; - else if (type == typeof(uint)) - return (uint)i; - else if (type.IsEnum) - { - return Enum.ToObject(type, i); - } - else - return null; + var ret = BoxUtils.BoxObject(i, true); + return ret; + } + else if (type == boolType) + { + var ret = BoxUtils.BoxObject(i == 1, true); + return ret; + } + else if (type == byteType) + { + var ret = BoxUtils.BoxObject((byte)i, true); + return ret; + } + else if (BoxUtils.GetTypeIsEnum(type)) + { + return BoxUtils.BoxEnumObject(type, i); + } + else if (type == charType) + { + var ret = BoxUtils.BoxObject((char)i, true); + return ret; + } + else if (type == uintType) + { + var ret = BoxUtils.BoxObject((uint)i, true); + return ret; + } + else if (type == shortType) + { + var ret = BoxUtils.BoxObject((short)i, true); + return ret; + } + else if (type == ushortType) + { + var ret = BoxUtils.BoxObject((ushort)i, true); + return ret; + } + else if (type == sbyteType) + { + var ret = BoxUtils.BoxObject((sbyte)i, true); + return ret; } + else + return null; + } case ValueType.Long: + { + long l = *(long*)&evaluationStackPointer->Value1; + if (type == longType) { - long l = *(long*)&evaluationStackPointer->Value1; - if (type == typeof(long)) - { - return l; - } - else if (type == typeof(ulong)) - { - return (ulong)l; - } - else if (type == typeof(IntPtr)) - { - return new IntPtr(l); - } - else if (type == typeof(UIntPtr)) - { - return new UIntPtr((ulong)l); - } - else if (type.IsEnum) - { - return Enum.ToObject(type, l); - } - else - { - return null; - } + var ret = BoxUtils.BoxObject((long)l, true); + return ret; + } + else if (type == ulongType) + { + var ret = BoxUtils.BoxObject((ulong)l, true); + return ret; } + else if (type == IntPtrType) + { + var ret = BoxUtils.BoxObject((IntPtr)l, true); + return ret; + } + else if (type == UIntPtrType) + { + var ret = BoxUtils.BoxObject(new UIntPtr((ulong)l), true); + return ret; + } + else if (BoxUtils.GetTypeIsEnum(type)) + { + return BoxUtils.BoxEnumObject(type, l); + } + else + { + return null; + } + } case ValueType.Float: + { + if (type == floatType) { - if (type == typeof(float)) - { - return *(float*)&evaluationStackPointer->Value1; - } - else - { - return null; - } + var ret = BoxUtils.BoxObject(*(float*)&evaluationStackPointer->Value1, true); + return ret; + } + else + { + return null; } + } case ValueType.Double: + { + if (type == doubleType) { - if (type == typeof(double)) - { - return *(double*)&evaluationStackPointer->Value1; - } - else - { - return null; - } + var ret = BoxUtils.BoxObject(*(double*)&evaluationStackPointer->Value1, true); + return ret; + } + else + { + return null; } + } case ValueType.Object: return managedStack[evaluationStackPointer->Value1]; case ValueType.ValueType: if (valueTypeClone && managedStack[evaluationStackPointer->Value1] != null) { - return virtualMachine.objectClone.Clone(managedStack[evaluationStackPointer->Value1]); + return BoxUtils.CloneObject(managedStack[evaluationStackPointer->Value1]); } else { return managedStack[evaluationStackPointer->Value1]; } case ValueType.StackReference: - { - return ToObject(evaluationStackBase, (*(Value**)&evaluationStackPointer->Value1), - managedStack, type, virtualMachine, valueTypeClone); - } + { + return ToObject(evaluationStackBase, (*(Value**)&evaluationStackPointer->Value1), + managedStack, type, virtualMachine, valueTypeClone); + } case ValueType.FieldReference: case ValueType.ChainFieldReference: + { + //VirtualMachine._Info("ToObject FieldReference:" + evaluationStackPointer->Value2 + // + "," + evaluationStackPointer->Value1); + if (evaluationStackPointer->Type == ValueType.ChainFieldReference) + { + var fieldAddr = managedStack[evaluationStackPointer - evaluationStackBase] as FieldAddr; + var fieldIdList = fieldAddr.FieldIdList; + return mGet(evaluationStackPointer->Value2 != -1, + fieldAddr.Object, fieldIdList.Length - 1, + fieldIdList, virtualMachine.fieldInfos, virtualMachine.newFieldInfos); + } + else { - //VirtualMachine._Info("ToObject FieldReference:" + evaluationStackPointer->Value2 - // + "," + evaluationStackPointer->Value1); - if (evaluationStackPointer->Type == ValueType.ChainFieldReference) + if (evaluationStackPointer->Value2 >= 0) { - var fieldAddr = managedStack[evaluationStackPointer - evaluationStackBase] as FieldAddr; - var fieldIdList = fieldAddr.FieldIdList; - return mGet(evaluationStackPointer->Value2 != -1, - fieldAddr.Object, fieldIdList.Length - 1, - fieldIdList, virtualMachine.fieldInfos, virtualMachine.newFieldInfos); + var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value2]; + var obj = managedStack[evaluationStackPointer->Value1]; + if (fieldInfo == null) + { + virtualMachine.newFieldInfos[evaluationStackPointer->Value2] + .CheckInit(virtualMachine, obj); + return virtualMachine.newFieldInfos[evaluationStackPointer->Value2].GetValue(obj); + } + + return fieldInfo.GetValue(obj); } else { - if (evaluationStackPointer->Value2 >= 0) - { - var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value2]; - var obj = managedStack[evaluationStackPointer->Value1]; - if(fieldInfo == null) - { - virtualMachine.newFieldInfos[evaluationStackPointer->Value2].CheckInit(virtualMachine, obj); - return virtualMachine.newFieldInfos[evaluationStackPointer->Value2].GetValue(obj); - } - return fieldInfo.GetValue(obj); - } - else - { - var obj = managedStack[evaluationStackPointer->Value1] as AnonymousStorey; - return obj.Get(-(evaluationStackPointer->Value2 + 1), type, - virtualMachine, valueTypeClone); - } + var obj = managedStack[evaluationStackPointer->Value1] as AnonymousStorey; + return obj.Get(-(evaluationStackPointer->Value2 + 1), type, + virtualMachine, valueTypeClone); } } + } case ValueType.ArrayReference: var arr = managedStack[evaluationStackPointer->Value1] as Array; return arr.GetValue(evaluationStackPointer->Value2); case ValueType.StaticFieldReference: + { + var fieldIndex = evaluationStackPointer->Value1; + if (fieldIndex >= 0) { - var fieldIndex = evaluationStackPointer->Value1; - if (fieldIndex >= 0) + var fieldInfo = virtualMachine.fieldInfos[fieldIndex]; + if (fieldInfo == null) { - var fieldInfo = virtualMachine.fieldInfos[fieldIndex]; - if(fieldInfo == null) - { - virtualMachine.newFieldInfos[fieldIndex].CheckInit(virtualMachine, null); - - return virtualMachine.newFieldInfos[fieldIndex].GetValue(null); - } - return fieldInfo.GetValue(null); - } - else - { - fieldIndex = -(fieldIndex + 1); - return virtualMachine.staticFields[fieldIndex]; + virtualMachine.newFieldInfos[fieldIndex].CheckInit(virtualMachine, null); + + return virtualMachine.newFieldInfos[fieldIndex].GetValue(null); } + + return GetStaticValueFromeCache(fieldInfo); + } + else + { + fieldIndex = -(fieldIndex + 1); + return virtualMachine.staticFields[fieldIndex]; } + } default: throw new NotImplementedException("get obj of " + evaluationStackPointer->Type); } } + + public static Value* ToBaseRef(Value* sp) + { + if (sp->Type != ValueType.StackReference) + { + return sp; + } + else + { + return ToBaseRef(*(Value**)&sp->Value1); + } + } + + public static void PushValue(Value* evaluationStackBase, Value* evaluationStackPointer, + object[] managedStack, T v) + { + var o = BoxUtils.BoxObject(v, true); + PushObject(evaluationStackBase, evaluationStackPointer, managedStack, o, typeof(T)); + } + + public static void PushField(Value* evaluationStackBase, Value* evaluationStackPointer, + object[] managedStack, object obj, FieldInfo fieldInfo, Type fieldType) + { + object ret = BoxUtils.GetFieldValue(obj, fieldInfo, fieldType); + PushObject(evaluationStackBase, evaluationStackPointer, managedStack, ret, fieldType); + } + public static void PushObject(Value* evaluationStackBase, Value* evaluationStackPointer, object[] managedStack, object obj, Type type) { + bool isValueType = false; if (obj != null) { - if (type.IsPrimitive) + void** monitorOffset = (void**)UnsafeAsUtility.AsPoint(ref type) + 1; + if (*monitorOffset == null) + { + BoxUtils.CacheTypeInfo(type); + } + byte* typeInfo = (byte*)*monitorOffset; + bool isPrimitive = *(bool*)(typeInfo + 9); + bool isEnum = *(bool*)(typeInfo + 8); + isValueType = *(bool*)(typeInfo + 10); + + if (isPrimitive) { UnboxPrimitive(evaluationStackPointer, obj, type); + BoxUtils.RecycleObject(obj); return; } - else if (type.IsEnum) + else if (isEnum) { - var underlyingType = Enum.GetUnderlyingType(type); - if (underlyingType == typeof(long) || underlyingType == typeof(ulong)) + int size = *(int*)(typeInfo + 12); + byte* b = (byte*)UnsafeAsUtility.AsPoint(ref obj)+ BoxUtils.OBJ_OFFSET; + + if (size == 8) { evaluationStackPointer->Type = ValueType.Long; - *(long*)(&evaluationStackPointer->Value1) = underlyingType == typeof(long) ? - Convert.ToInt64(obj) : (long)Convert.ToUInt64(obj) ; + *(long*)(&evaluationStackPointer->Value1) = *(long*)b; } else { evaluationStackPointer->Type = ValueType.Integer; - evaluationStackPointer->Value1 = Convert.ToInt32(obj); + evaluationStackPointer->Value1 = *(int*)b; } + + BoxUtils.RecycleObject(obj); return; } } + int pos = (int)(evaluationStackPointer - evaluationStackBase); evaluationStackPointer->Value1 = pos; + BoxUtils.RecycleObject(managedStack[pos]); managedStack[pos] = obj; - evaluationStackPointer->Type = (obj != null && type.IsValueType) ? - ValueType.ValueType : ValueType.Object; + evaluationStackPointer->Type = (obj != null && isValueType) + ? ValueType.ValueType : ValueType.Object; + } + + + public static void PushDouble(Value* evaluationStackPointer, double d) + { + evaluationStackPointer->Type = ValueType.Double; + *(double*)(&evaluationStackPointer->Value1) = d; + } + + public static void PushInt64(Value* evaluationStackPointer, Int64 obj) + { + evaluationStackPointer->Type = ValueType.Long; + *(long*)(&evaluationStackPointer->Value1) = obj; + } + + public static void PushUInt64(Value* evaluationStackPointer, UInt64 obj) + { + evaluationStackPointer->Type = ValueType.Long; + *(UInt64*)(&evaluationStackPointer->Value1) = obj; + } + + public static void PushSingle(Value* evaluationStackPointer, float f) + { + evaluationStackPointer->Type = ValueType.Float; + *(float*)(&evaluationStackPointer->Value1) = f; + } + + public static void PushInt32(Value* evaluationStackPointer, Int32 obj) + { + evaluationStackPointer->Type = ValueType.Integer; + evaluationStackPointer->Value1 = (int)obj; + } + + public static void PushIntPtr(Value* evaluationStackPointer, IntPtr i) + { + PushInt64(evaluationStackPointer, i.ToInt64()); + } + + public static void PushUIntPtr(Value* evaluationStackPointer, UIntPtr i) + { + PushUInt64(evaluationStackPointer, i.ToUInt64()); + } + + public static void PushUInt32(Value* evaluationStackPointer, UInt32 obj) + { + evaluationStackPointer->Type = ValueType.Integer; + evaluationStackPointer->Value1 = (int)obj; + } + + public static void PushInt16(Value* evaluationStackPointer, short us) + { + PushInt32(evaluationStackPointer, us); + } + + public static void PushUInt16(Value* evaluationStackPointer, ushort us) + { + PushInt32(evaluationStackPointer, us); + } + + public static void PushChar(Value* evaluationStackPointer, char c) + { + PushInt32(evaluationStackPointer, c); + } + + public static void PushSByte(Value* evaluationStackPointer, sbyte sb) + { + PushInt32(evaluationStackPointer, sb); + } + + public static void PushByte(Value* evaluationStackPointer, byte b) + { + PushInt32(evaluationStackPointer, b); + } + + public static void PushBoolean(Value* evaluationStackPointer, bool b) + { + PushInt32(evaluationStackPointer, b ? 1 : 0); } public static void UpdateReference(Value* evaluationStackBase, Value* evaluationStackPointer, @@ -466,87 +671,97 @@ public static void UpdateReference(Value* evaluationStackBase, Value* evaluation break; case ValueType.FieldReference: case ValueType.ChainFieldReference: + { + if (evaluationStackPointer->Type == ValueType.ChainFieldReference) { - if (evaluationStackPointer->Type == ValueType.ChainFieldReference) - { - var fieldAddr = managedStack[evaluationStackPointer - evaluationStackBase] as FieldAddr; - var fieldIdList = fieldAddr.FieldIdList; - //for(int i = 0; i < fieldIdList.Length; i++) - //{ - // VirtualMachine._Info("fid " + i + ": " + fieldIdList[i] + ", " - // + virtualMachine.fieldInfos[fieldIdList[i]]); - //} - mSet(evaluationStackPointer->Value2 != -1, - fieldAddr.Object, obj, fieldIdList.Length - 1, - fieldIdList, virtualMachine.fieldInfos, virtualMachine.newFieldInfos); - } - else + var fieldAddr = managedStack[evaluationStackPointer - evaluationStackBase] as FieldAddr; + var fieldIdList = fieldAddr.FieldIdList; + //for(int i = 0; i < fieldIdList.Length; i++) + //{ + // VirtualMachine._Info("fid " + i + ": " + fieldIdList[i] + ", " + // + virtualMachine.fieldInfos[fieldIdList[i]]); + //} + mSet(evaluationStackPointer->Value2 != -1, + fieldAddr.Object, obj, fieldIdList.Length - 1, + fieldIdList, virtualMachine.fieldInfos, virtualMachine.newFieldInfos); + } + else + { + if (evaluationStackPointer->Value2 >= 0) { - if (evaluationStackPointer->Value2 >= 0) + var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value2]; + if (fieldInfo == null) { - - - var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value2]; - if(fieldInfo == null) - { - virtualMachine.newFieldInfos[evaluationStackPointer->Value2].SetValue(managedStack[evaluationStackPointer->Value1], obj);; - } - else - { - //VirtualMachine._Info("update field: " + fieldInfo); - //VirtualMachine._Info("update field of: " + fieldInfo.DeclaringType); - //VirtualMachine._Info("update ref obj: " - // + managedStack[evaluationStackPointer->Value1]); - //VirtualMachine._Info("update ref obj idx: " + evaluationStackPointer->Value1); - fieldInfo.SetValue(managedStack[evaluationStackPointer->Value1], obj); - } + virtualMachine.newFieldInfos[evaluationStackPointer->Value2] + .SetValue(managedStack[evaluationStackPointer->Value1], obj); + ; } else { - var anonymousStorey = managedStack[evaluationStackPointer->Value1] - as AnonymousStorey; - anonymousStorey.Set(-(evaluationStackPointer->Value2 + 1), obj, type, virtualMachine); + //VirtualMachine._Info("update field: " + fieldInfo); + //VirtualMachine._Info("update field of: " + fieldInfo.DeclaringType); + //VirtualMachine._Info("update ref obj: " + // + managedStack[evaluationStackPointer->Value1]); + //VirtualMachine._Info("update ref obj idx: " + evaluationStackPointer->Value1); + fieldInfo.SetValue(managedStack[evaluationStackPointer->Value1], obj); + BoxUtils.RecycleObject(obj); } } - break; + else + { + var anonymousStorey = managedStack[evaluationStackPointer->Value1] + as AnonymousStorey; + anonymousStorey.Set(-(evaluationStackPointer->Value2 + 1), obj, type, virtualMachine); + } } - case ValueType.StaticFieldReference://更新完毕,直接return + + break; + } + case ValueType.StaticFieldReference: //更新完毕,直接return + { + var fieldIndex = evaluationStackPointer->Value1; + if (fieldIndex >= 0) { - var fieldIndex = evaluationStackPointer->Value1; - if (fieldIndex >= 0) + var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value1]; + if (fieldInfo == null) { - var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value1]; - if(fieldInfo == null) - { - virtualMachine.newFieldInfos[evaluationStackPointer->Value1].SetValue(null, obj);; - } - else - { - fieldInfo.SetValue(null, obj); - } + virtualMachine.newFieldInfos[evaluationStackPointer->Value1].SetValue(null, obj); + ; } else { - fieldIndex = -(fieldIndex + 1); - virtualMachine.staticFields[fieldIndex] = obj; + fieldInfo.SetValue(null, obj); + BoxUtils.RecycleObject(obj); } - break; } + else + { + fieldIndex = -(fieldIndex + 1); + virtualMachine.staticFields[fieldIndex] = obj; + } + + break; + } } } } unsafe public struct Call { - internal Value* argumentBase; + public Value* argumentBase; - internal Value* evaluationStackBase; + public Value* evaluationStackBase; - internal object[] managedStack; + public object[] managedStack; - internal Value* currentTop;//用于push状态 + public Value* currentTop; //用于push状态 - internal Value** topWriteBack; + public Value** topWriteBack; + + public static Call NewCall() + { + return new Call(); + } public static Call Begin() { @@ -557,20 +772,27 @@ public static Call Begin() currentTop = stack.UnmanagedStack->Top, argumentBase = stack.UnmanagedStack->Top, evaluationStackBase = stack.UnmanagedStack->Base, - topWriteBack = &(stack.UnmanagedStack->Top) + topWriteBack = &(stack.UnmanagedStack->Top), }; } - internal static Call BeginForStack(ThreadStackInfo stack) + public static void BeginRef(ref Call ret) { - return new Call() - { - managedStack = stack.ManagedStack, - currentTop = stack.UnmanagedStack->Top, - argumentBase = stack.UnmanagedStack->Top, - evaluationStackBase = stack.UnmanagedStack->Base, - topWriteBack = &(stack.UnmanagedStack->Top) - }; + var stack = ThreadStackInfo.Stack; + ret.managedStack = stack.ManagedStack; + ret.currentTop = stack.UnmanagedStack->Top; + ret.argumentBase = stack.UnmanagedStack->Top; + ret.evaluationStackBase = stack.UnmanagedStack->Base; + ret.topWriteBack = &(stack.UnmanagedStack->Top); + } + + public static void BeginForStack(ThreadStackInfo stack, ref Call ret) + { + ret.managedStack = stack.ManagedStack; + ret.currentTop = stack.UnmanagedStack->Top; + ret.argumentBase = stack.UnmanagedStack->Top; + ret.evaluationStackBase = stack.UnmanagedStack->Base; + ret.topWriteBack = &(stack.UnmanagedStack->Top); } public void PushBoolean(bool b) @@ -713,6 +935,22 @@ public IntPtr GetIntPtr(int offset = 0) return new IntPtr(GetInt64(offset)); } + public int* GetInt32Point(int offset = 0) + { + IntPtr p = new IntPtr(GetInt64(offset)); + int* v = (int*)((byte*)p.ToPointer() + 4); + + return v; + } + + public long* GetInt64Point(int offset = 0) + { + IntPtr p = new IntPtr(GetInt64(offset)); + long* v = (long*)((byte*)p.ToPointer() + 4); + + return v; + } + public void PushUIntPtr(UIntPtr i) { PushUInt64(i.ToUInt64()); @@ -728,24 +966,48 @@ public void PushObject(object o) int pos = (int)(currentTop - evaluationStackBase); currentTop->Type = ValueType.Object; currentTop->Value1 = pos; + BoxUtils.RecycleObject(managedStack[pos]); managedStack[pos] = o; currentTop++; } + public void PushValueUnmanaged(T v) + { + var o = BoxUtils.BoxObject(v, true); + PushObject(o); + } + public void PushValueType(object o) { int pos = (int)(currentTop - evaluationStackBase); currentTop->Type = ValueType.ValueType; currentTop->Value1 = pos; + BoxUtils.RecycleObject(managedStack[pos]); managedStack[pos] = o; currentTop++; } + public object GetEveryObject(VirtualMachine vm, Type rawType, int offset = 0) + { + object obj = EvaluationStackOperation.ToObject(evaluationStackBase, evaluationStackBase + offset, managedStack, + rawType, vm); + return obj; + } + public object GetObject(int offset = 0) { var ptr = argumentBase + offset; object ret = managedStack[ptr->Value1]; + + // 因为拿出去之后就被unbox掉了所以这里可以回收 + if (ptr->Type == ValueType.ValueType) + { + BoxUtils.RecycleObject(ret); + } + + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); managedStack[ptr - evaluationStackBase] = null; + return ret; } @@ -781,6 +1043,104 @@ public void PushObjectAsResult(object obj, Type type) //反射专用 currentTop = argumentBase + 1; } + public void PushValueUnmanagedAsResult(T v)//反射专用 + { + var o = BoxUtils.BoxObject(v, true); + + int pos = (int)(argumentBase - evaluationStackBase); + argumentBase->Value1 = pos; + argumentBase->Type = ValueType.ValueType; + BoxUtils.RecycleObject(managedStack[pos]); + + managedStack[pos] = o; + + currentTop = argumentBase + 1; + } + + public void PushInt32AsResult(int value) + { + EvaluationStackOperation.PushInt32(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushUInt32AsResult(uint value) + { + EvaluationStackOperation.PushUInt32(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushUIntPtr64AsResult(UIntPtr value) + { + EvaluationStackOperation.PushUIntPtr(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushIntPtr64AsResult(IntPtr value) + { + EvaluationStackOperation.PushIntPtr(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushUInt64AsResult(ulong value) + { + EvaluationStackOperation.PushUInt64(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushInt64AsResult(long value) + { + EvaluationStackOperation.PushInt64(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushDoubleAsResult(double value) + { + EvaluationStackOperation.PushDouble(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushSingleAsResult(float value) + { + EvaluationStackOperation.PushSingle(argumentBase, value); + currentTop = argumentBase + 1; + } + + public void PushInt16AsResult(short s) + { + EvaluationStackOperation.PushInt32(argumentBase, s); + currentTop = argumentBase + 1; + } + + public void PushUInt16AsResult(ushort us) + { + EvaluationStackOperation.PushInt32(argumentBase, us); + currentTop = argumentBase + 1; + } + + public void PushCharAsResult(char c) + { + EvaluationStackOperation.PushInt32(argumentBase, c); + currentTop = argumentBase + 1; + } + + public void PushSByteAsResult(sbyte sb) + { + EvaluationStackOperation.PushInt32(argumentBase, sb); + currentTop = argumentBase + 1; + } + + public void PushByteAsResult(byte b) + { + EvaluationStackOperation.PushInt32(argumentBase, b); + currentTop = argumentBase + 1; + } + + public void PushBooleanAsResult(bool b) + { + EvaluationStackOperation.PushBoolean(argumentBase, b); + currentTop = argumentBase + 1; + } + public void PushRef(int offset) { //Console.WriteLine("PushRef:" + offset + " address:" + new IntPtr(argumentBase + offset)); @@ -801,5 +1161,4 @@ public static void End(ref Call call) //ThreadStackInfo.Stack.UnmanagedStack->Top = call.argumentBase; } } - } \ No newline at end of file diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 128099a..e643334 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -1,10 +1,12 @@ /* * Tencent is pleased to support the open source community by making InjectFix available. * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved. - * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. + * InjectFix is licensed under the MIT License, except for the third-party components listed in the file 'LICENSE' which may be subject to their corresponding license terms. * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ +using System.Runtime.InteropServices; + namespace IFix.Core { using System; @@ -16,7 +18,7 @@ namespace IFix.Core class RuntimeException : Exception { - public Exception Real { get;set;} + public Exception Real { get; set; } } public delegate void ExternInvoker(VirtualMachine vm, ref Call call, bool isInstantiate); @@ -33,10 +35,10 @@ public class Cleanner public static void Start() { - if(!start) + if (!start) { start = true; - new Cleanner(); + new Cleanner(); } } @@ -47,14 +49,14 @@ public static void Stop() ~Cleanner() { - if(start) + if (start) { NewFieldInfo.Sweep(); Start(); } } } - + public class NewFieldInfo { public string Name; @@ -66,17 +68,18 @@ public class NewFieldInfo static readonly ThreadStackInfo stack = new ThreadStackInfo(); - static readonly Dictionary> newFieldValues = new Dictionary>(); + static readonly Dictionary> newFieldValues = + new Dictionary>(); static readonly Dictionary objList = new Dictionary(); private object SetDefaultValue(object obj) { - if(FieldType.IsValueType) + if (BoxUtils.GetTypeIsValueType(FieldType)) { var ret = Activator.CreateInstance(FieldType); SetValue(obj, ret); - return ret; + return ret; } else { @@ -89,7 +92,7 @@ public static void Sweep() { foreach (var item in objList.ToList()) { - if(!item.Value.IsAlive) + if (!item.Value.IsAlive) { newFieldValues.Remove(item.Key); objList.Remove(item.Key); @@ -99,9 +102,10 @@ public static void Sweep() public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) { - if( MethodId >= 0 && !HasInitialize(obj) ) + if (MethodId >= 0 && !HasInitialize(obj)) { - Call call = Call.BeginForStack(stack); + Call call = default(Call); + Call.BeginForStack(stack, ref call); virtualMachine.Execute(MethodId, ref call, 0, 0); SetValue(obj, call.GetObject()); } @@ -109,7 +113,7 @@ public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) public int ObjectToIndex(object obj) { - if(obj == null) + if (obj == null) { return staticObjectKey; } @@ -121,14 +125,14 @@ public bool HasInitialize(object obj) { var index = ObjectToIndex(obj); - if(!newFieldValues.ContainsKey(index)) + if (!newFieldValues.ContainsKey(index)) { return false; } Dictionary fieldValues = null; newFieldValues.TryGetValue(index, out fieldValues); - if(!fieldValues.ContainsKey(Name)) + if (!fieldValues.ContainsKey(Name)) { return false; } @@ -142,14 +146,14 @@ public object GetValue(object obj) Dictionary fieldValues = null; newFieldValues.TryGetValue(index, out fieldValues); - if(fieldValues != null) + if (fieldValues != null) { object val = null; - if(!fieldValues.TryGetValue(Name, out val)) + if (!fieldValues.TryGetValue(Name, out val)) { return SetDefaultValue(obj); } - + return val; } else @@ -162,22 +166,22 @@ public void SetValue(object obj, object value) { var index = ObjectToIndex(obj); - if(!newFieldValues.ContainsKey(index)) + if (!newFieldValues.ContainsKey(index)) { newFieldValues.Add(index, new Dictionary()); - if(obj != null) + if (obj != null) { objList.Add(index, new WeakReference(obj)); } } - + newFieldValues[index][Name] = value; // if(obj.GetType() != DeclaringType || (value != null && value.GetType() != FieldType)) // { // } - } + } } unsafe public class VirtualMachine @@ -186,23 +190,24 @@ unsafe public class VirtualMachine public const int MAX_EVALUATION_STACK_SIZE = 1024 * 10; - internal ObjectClone objectClone = new ObjectClone(); - Instruction** unmanagedCodes; ExceptionHandler[][] exceptionHandlers; Action onDispose; - ExternInvoker[] externInvokers; + Delegate[] externInvokers; MethodBase[] externMethods; + bool?[] externIsNewDelegate; Type[] externTypes; string[] internStrings; internal FieldInfo[] fieldInfos; + private Type[] fieldTypes; + private Type[] fieldDeclareType; internal Dictionary newFieldInfos; @@ -221,95 +226,60 @@ Dictionary> overrideCache public ExceptionHandler[][] ExceptionHandlers { - get - { - return exceptionHandlers; - } - set - { - exceptionHandlers = value; - } + get { return exceptionHandlers; } + set { exceptionHandlers = value; } } public Type[] ExternTypes { - get - { - return externTypes; - } - set - { - externTypes = value; - } + get { return externTypes; } + set { externTypes = value; } } public MethodBase[] ExternMethods { - get - { - return externMethods; - } + get { return externMethods; } set { externMethods = value; - externInvokers = new ExternInvoker[externMethods.Length]; + externInvokers = new Delegate[externMethods.Length]; + + externIsNewDelegate = new bool?[externMethods.Length]; } } public string[] InternStrings { - get - { - return internStrings; - } - set - { - internStrings = value; - } + get { return internStrings; } + set { internStrings = value; } } public FieldInfo[] FieldInfos { - get - { - return fieldInfos; - } + get { return fieldInfos; } set { fieldInfos = value; + fieldTypes = new Type[value.Length]; + fieldDeclareType = new Type[value.Length]; } } public Dictionary NewFieldInfos { - get - { - return newFieldInfos; - } - set - { - newFieldInfos = value; - } + get { return newFieldInfos; } + set { newFieldInfos = value; } } public AnonymousStoreyInfo[] AnonymousStoreyInfos { - get - { - return anonymousStoreyInfos; - } - set - { - anonymousStoreyInfos = value; - } + get { return anonymousStoreyInfos; } + set { anonymousStoreyInfos = value; } } public Type[] StaticFieldTypes { - get - { - return staticFieldTypes; - } + get { return staticFieldTypes; } set { staticFields = value != null ? new object[value.Length] : null; @@ -319,28 +289,21 @@ public Type[] StaticFieldTypes public int[] Cctors { - get - { - return cctors; - } - set - { - cctors = value; - } + get { return cctors; } + set { cctors = value; } } public WrappersManager WrappersManager { - get - { - return wrappersManager; - } - set - { - wrappersManager = value; - } + get { return wrappersManager; } + set { wrappersManager = value; } } + public delegate bool ExternInvokersHandle(MethodBase mb, out ExternInvoker ei); + + public ExternInvokersHandle externInvokersHandle; + + internal VirtualMachine(Instruction** unmanaged_codes, Action on_dispose) { unmanagedCodes = unmanaged_codes; @@ -363,7 +326,7 @@ void checkCctorExecute(int fieldId, Value* argumentBase, object[] managedStack, //_Info("check " + fieldId + ", cctorId = " + cctorId); if (cctorId >= 0) { - for(int i = 0; i < cctors.Length; i++) + for (int i = 0; i < cctors.Length; i++) { if (cctors[i] == cctorId) { @@ -371,6 +334,7 @@ void checkCctorExecute(int fieldId, Value* argumentBase, object[] managedStack, cctors[i] = -1; } } + Execute(cctorId, argumentBase, managedStack, evaluationStackBase, 0); } } @@ -381,17 +345,32 @@ void checkCctorExecute(int fieldId, Value* argumentBase, object[] managedStack, void store(Value* stackBase, Value* dst, Value* src, object[] managedStack) { *dst = *src; - if (dst->Type >= ValueType.Object) + switch (dst->Type) { - var obj = (dst->Type == ValueType.ValueType && managedStack[src->Value1] != null) //Nullable box后可能为空 - ? objectClone.Clone(managedStack[src->Value1]) - : managedStack[src->Value1]; - var dstPos = dst->Value1 = (int)(dst - stackBase); - managedStack[dstPos] = obj; - } - else if (dst->Type == ValueType.ChainFieldReference) - { - managedStack[dst - stackBase] = managedStack[src - stackBase]; + case ValueType.ChainFieldReference: + { + BoxUtils.RecycleObject(managedStack[dst - stackBase]); //field addr + managedStack[dst - stackBase] = managedStack[src - stackBase]; + + int srcIndex = (int)(src - stackBase); + BoxUtils.RecycleObject(managedStack[srcIndex]); + managedStack[srcIndex] = null; + } + break; + case ValueType.Object: + case ValueType.ValueType: + case ValueType.ArrayReference: + { + var obj = managedStack[src->Value1]; + var dstPos = dst->Value1 = (int)(dst - stackBase); + BoxUtils.RecycleObject(managedStack[dstPos]); + managedStack[dstPos] = obj; + + int srcIndex = (int)(src - stackBase); + BoxUtils.RecycleObject(managedStack[srcIndex]); + managedStack[srcIndex] = null; + } + break; } } @@ -401,17 +380,25 @@ void store(Value* stackBase, Value* dst, Value* src, object[] managedStack) void copy(Value* stackBase, Value* dst, Value* src, object[] managedStack) { *dst = *src; - if (dst->Type == ValueType.ValueType) - { - object obj = null; - if (managedStack[src->Value1] != null) //Nullable box后可能为空 - obj = objectClone.Clone(managedStack[src->Value1]); - var dstPos = dst->Value1 = (int)(dst - stackBase); - managedStack[dstPos] = obj; - } - else if (dst->Type == ValueType.ChainFieldReference) + switch (dst->Type) { - managedStack[dst - stackBase] = managedStack[src - stackBase]; + case ValueType.ValueType: + { + object obj = null; + if (managedStack[src->Value1] != null) //Nullable box后可能为空 + obj = BoxUtils.CloneObject(managedStack[src->Value1]); + + var dstPos = dst->Value1 = (int)(dst - stackBase); + BoxUtils.RecycleObject(managedStack[dstPos]); + managedStack[dstPos] = obj; + } + break; + case ValueType.ChainFieldReference: + { + BoxUtils.RecycleObject(managedStack[dst - stackBase]); + managedStack[dst - stackBase] = managedStack[src - stackBase]; + } + break; } } @@ -471,17 +458,18 @@ ExceptionHandler getExceptionHandler(int methodIndex, Type exceptionType, int pc //1 catch只能从先catch子类,再catch父类 //2 排列顺序按Handle block来,外层处理的handle block肯定在内层的后面 if ( - ( - exceptionHandler.HandlerType == ExceptionHandlerType.Finally - || (exceptionHandler.HandlerType == ExceptionHandlerType.Catch + ( + exceptionHandler.HandlerType == ExceptionHandlerType.Finally + || (exceptionHandler.HandlerType == ExceptionHandlerType.Catch && exceptionHandler.CatchType.IsAssignableFrom(exceptionType)) - ) //type match - && pc >= exceptionHandler.TryStart && pc < exceptionHandler.TryEnd - ) + ) //type match + && pc >= exceptionHandler.TryStart && pc < exceptionHandler.TryEnd + ) { return exceptionHandler; } } + return null; } @@ -496,6 +484,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = intArr[idx]; return; } + float[] floatArr = obj as float[]; if (floatArr != null) { @@ -503,6 +492,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva *(float*)&val->Value1 = floatArr[idx]; return; } + double[] doubleArr = obj as double[]; if (doubleArr != null) { @@ -510,6 +500,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva *(double*)&val->Value1 = doubleArr[idx]; return; } + byte[] byteArr = obj as byte[]; if (byteArr != null) { @@ -517,6 +508,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = byteArr[idx]; return; } + bool[] boolArr = obj as bool[]; if (boolArr != null) { @@ -524,6 +516,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = boolArr[idx] ? 1 : 0; return; } + long[] longArr = obj as long[]; if (longArr != null) { @@ -531,6 +524,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva *(long*)&val->Value1 = longArr[idx]; return; } + ulong[] ulongArr = obj as ulong[]; if (ulongArr != null) { @@ -538,6 +532,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva *(ulong*)&val->Value1 = ulongArr[idx]; return; } + sbyte[] sbyteArr = obj as sbyte[]; if (sbyteArr != null) { @@ -545,6 +540,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = sbyteArr[idx]; return; } + short[] shortArr = obj as short[]; if (shortArr != null) { @@ -552,6 +548,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = shortArr[idx]; return; } + ushort[] ushortArr = obj as ushort[]; if (ushortArr != null) { @@ -559,6 +556,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = ushortArr[idx]; return; } + char[] charArr = obj as char[]; if (charArr != null) { @@ -566,6 +564,7 @@ void arrayGet(object obj, int idx, Value* val, object[] managedStack, Value* eva val->Value1 = charArr[idx]; return; } + uint[] uintArr = obj as uint[]; if (uintArr != null) { @@ -586,66 +585,77 @@ void arraySet(object obj, int idx, Value* val, object[] managedStack, Value* eva intArr[idx] = val->Value1; return; } + float[] floatArr = obj as float[]; if (floatArr != null) { floatArr[idx] = *(float*)&val->Value1; return; } + double[] doubleArr = obj as double[]; if (doubleArr != null) { doubleArr[idx] = *(double*)&val->Value1; return; } + byte[] byteArr = obj as byte[]; if (byteArr != null) { byteArr[idx] = (byte)val->Value1; return; } + bool[] boolArr = obj as bool[]; if (boolArr != null) { boolArr[idx] = val->Value1 != 0; return; } + long[] longArr = obj as long[]; if (longArr != null) { longArr[idx] = *(long*)&val->Value1; return; } + ulong[] ulongArr = obj as ulong[]; if (ulongArr != null) { ulongArr[idx] = *(ulong*)&val->Value1; return; } + sbyte[] sbyteArr = obj as sbyte[]; if (sbyteArr != null) { sbyteArr[idx] = (sbyte)val->Value1; return; } + short[] shortArr = obj as short[]; if (shortArr != null) { shortArr[idx] = (short)val->Value1; return; } + ushort[] ushortArr = obj as ushort[]; if (ushortArr != null) { ushortArr[idx] = (ushort)val->Value1; return; } + char[] charArr = obj as char[]; if (charArr != null) { charArr[idx] = (char)val->Value1; return; } + uint[] uintArr = obj as uint[]; if (uintArr != null) { @@ -692,6 +702,7 @@ public static void _Info(string a) throwRuntimeException(new StackOverflowException(), topWriteBack == null); } + var stack = ThreadStackInfo.Stack; Value* localBase = argumentBase + argsCount; Value* evaluationStackPointer = localBase + localsCount; //Debug.Log("loc:" + ((int)(code[0].TokenLong >> 32))); @@ -710,212 +721,223 @@ public static void _Info(string a) try { var code = pc->Code; - //if (methodIndex == 527 || methodIndex == 528) - //{ - // _Info("** Method Id = " + methodIndex + ", Start Code = " + code + ", Oprand = " - // + pc->Operand + ", ESP = " + (evaluationStackPointer - localBase - localsCount) - // + ", ABS = " + (evaluationStackPointer - evaluationStackBase)); - //if (methodIndex == 84 && code == Code.Ldfld) throw new Exception("stop"); - //} - //if (traceValue != null) - //{ - // _Info("before:" + traceValue->Type + "," + traceValue->Value1 + (traceValue->Type - // == ValueType.Object ? ("," + managedStack[traceValue->Value1]) : "")); - //} switch (code) { //Ldarg_0: 10.728% Ldarg_1: 4.4% Ldarg_2: 1.87% Ldarg_S:0.954% Ldarg_3:0.93% case Code.Ldarg: + { + var src = argumentBase + pc->Operand; + *evaluationStackPointer = *src; + switch (evaluationStackPointer->Type) { - //if (methodIndex == 197) - //{ - // var a = argumentBase + pc->Operand; - // if (a->Type == ValueType.FieldReference) - // { - // var fieldInfo = fieldInfos[a->Value2]; - // _Info("field: " + fieldInfo.DeclaringType + "." + fieldInfo.Name); - // _Info("a->Value1:" + a->Value1); - // var obj = managedStack[a->Value1]; - // _Info("a.obj = " + (obj == null ? "null" : obj.ToString())); - // } - //} - copy(evaluationStackBase, evaluationStackPointer, argumentBase + pc->Operand, - managedStack); - //if (methodIndex == 197) - //{ - // var a = evaluationStackPointer; - // if (a->Type == ValueType.FieldReference) - // { - // var fieldInfo = fieldInfos[a->Value2]; - // _Info("ep field: " + fieldInfo.DeclaringType + "." + fieldInfo.Name); - // _Info("ep a->Value1:" + a->Value1); - // var obj = managedStack[a->Value1]; - // _Info("ep a.obj = " + (obj == null ? "null" : obj.ToString())); - // } - //} - evaluationStackPointer++; - } - break; - case Code.Call:// Call: 8.1233% - { - int narg = pc->Operand >> 16; - //Console.WriteLine("narg:" + narg); - //Console.WriteLine("before call ESP = " + (evaluationStackPointer - localBase - // - localsCount) + ", ESPV=" + (long)evaluationStackPointer); - //printStack("a 1", evaluationStackPointer - 1 - 1); - //printStack("a 2", evaluationStackPointer - 1); - int methodIndexToCall = pc->Operand & 0xFFFF; - //if (methodIndex == 196 || methodIndex == 197 || methodIndex == 13) - //{ - // _Info("methodIndexToCall:" + methodIndexToCall); - //} - evaluationStackPointer = Execute(unmanagedCodes[methodIndexToCall], - evaluationStackPointer - narg, managedStack, evaluationStackBase, narg, - methodIndexToCall); - //Console.WriteLine("after call ESP = " + (evaluationStackPointer - localBase - // - localsCount)); - //printStack("ret", evaluationStackPointer - 1); - } - break; - case Code.Callvirt: //Callvirt: 5.156 - { - int narg = pc->Operand >> 16; - var arg0 = evaluationStackPointer - narg; - if (arg0->Type != ValueType.Object) + case ValueType.ValueType: { - throwRuntimeException(new InvalidProgramException(arg0->Type.ToString() - + " for Callvirt"), true); + object obj = null; + if (managedStack[src->Value1] != null) //Nullable box后可能为空 + obj = BoxUtils.CloneObject(managedStack[src->Value1]); + + var dstPos = evaluationStackPointer->Value1 = (int)(evaluationStackPointer - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[dstPos]); + managedStack[dstPos] = obj; } - if (managedStack[arg0->Value1] == null) + break; + case ValueType.ChainFieldReference: { - throw new NullReferenceException("this is null"); + BoxUtils.RecycleObject(managedStack[evaluationStackPointer - evaluationStackBase]); + managedStack[evaluationStackPointer - evaluationStackBase] = managedStack[src - evaluationStackBase]; } - //Console.WriteLine("narg:" + narg); - //Console.WriteLine("before call ESP = " + (evaluationStackPointer - localBase - // - localsCount) + ", ESPV=" + (long)evaluationStackPointer); - //printStack("a 1", evaluationStackPointer - 1 - 1); - //printStack("a 2", evaluationStackPointer - 1); - int methodIndexToCall = pc->Operand & 0xFFFF; - //if (methodIndex == 203) - //{ - // _Info("methodIndexToCall:" + methodIndexToCall); - //} - evaluationStackPointer = Execute(unmanagedCodes[methodIndexToCall], - evaluationStackPointer - narg, managedStack, evaluationStackBase, - narg, methodIndexToCall); - //Console.WriteLine("after call ESP = " + (evaluationStackPointer - localBase - // - localsCount)); - //printStack("ret", evaluationStackPointer - 1); + break; } + + evaluationStackPointer++; + } + break; + case Code.Call: // Call: 8.1233% + { + int narg = pc->Operand >> 16; + //Console.WriteLine("narg:" + narg); + //Console.WriteLine("before call ESP = " + (evaluationStackPointer - localBase + // - localsCount) + ", ESPV=" + (long)evaluationStackPointer); + //printStack("a 1", evaluationStackPointer - 1 - 1); + //printStack("a 2", evaluationStackPointer - 1); + int methodIndexToCall = pc->Operand & 0xFFFF; + //if (methodIndex == 196 || methodIndex == 197 || methodIndex == 13) + //{ + // _Info("methodIndexToCall:" + methodIndexToCall); + //} + evaluationStackPointer = Execute(unmanagedCodes[methodIndexToCall], + evaluationStackPointer - narg, managedStack, evaluationStackBase, narg, + methodIndexToCall); + //Console.WriteLine("after call ESP = " + (evaluationStackPointer - localBase + // - localsCount)); + //printStack("ret", evaluationStackPointer - 1); + } + break; + case Code.Callvirt: //Callvirt: 5.156 + { + int narg = pc->Operand >> 16; + //var arg0 = evaluationStackPointer - narg; + // if (arg0->Type != ValueType.Object) + // { + // throwRuntimeException(new InvalidProgramException(arg0->Type.ToString() + // + " for Callvirt"), true); + // } + // if (managedStack[arg0->Value1] == null) + // { + // throw new NullReferenceException("this is null"); + // } + //Console.WriteLine("narg:" + narg); + //Console.WriteLine("before call ESP = " + (evaluationStackPointer - localBase + // - localsCount) + ", ESPV=" + (long)evaluationStackPointer); + //printStack("a 1", evaluationStackPointer - 1 - 1); + //printStack("a 2", evaluationStackPointer - 1); + int methodIndexToCall = pc->Operand & 0xFFFF; + //if (methodIndex == 203) + //{ + // _Info("methodIndexToCall:" + methodIndexToCall); + //} + evaluationStackPointer = Execute(unmanagedCodes[methodIndexToCall], + evaluationStackPointer - narg, managedStack, evaluationStackBase, + narg, methodIndexToCall); + //Console.WriteLine("after call ESP = " + (evaluationStackPointer - localBase + // - localsCount)); + //printStack("ret", evaluationStackPointer - 1); + } break; case Code.Callvirtvirt: + { + int narg = pc->Operand >> 16; + var arg0 = evaluationStackPointer - narg; + if (arg0->Type != ValueType.Object) { - int narg = pc->Operand >> 16; - var arg0 = evaluationStackPointer - narg; - if (arg0->Type != ValueType.Object) - { - throwRuntimeException(new InvalidProgramException(arg0->Type.ToString() - + " for Callvirtvirt"), true); - } - if (managedStack[arg0->Value1] == null) - { - throw new NullReferenceException("this is null"); - } - var anonObj = managedStack[arg0->Value1] as AnonymousStorey; - int[] vTable = anonymousStoreyInfos[anonObj.typeId].VTable; - int methodIndexToCall = vTable[pc->Operand & 0xFFFF]; - evaluationStackPointer = Execute(unmanagedCodes[methodIndexToCall], - evaluationStackPointer - narg, managedStack, evaluationStackBase, - narg, methodIndexToCall); + throwRuntimeException(new InvalidProgramException(arg0->Type.ToString() + + " for Callvirtvirt"), true); } + + if (managedStack[arg0->Value1] == null) + { + throw new NullReferenceException("this is null"); + } + + var anonObj = managedStack[arg0->Value1] as AnonymousStorey; + int[] vTable = anonymousStoreyInfos[anonObj.typeId].VTable; + int methodIndexToCall = vTable[pc->Operand & 0xFFFF]; + evaluationStackPointer = Execute(unmanagedCodes[methodIndexToCall], + evaluationStackPointer - narg, managedStack, evaluationStackBase, + narg, methodIndexToCall); + } break; case Code.Ldvirtftn2: + { + int slot = pc->Operand & 0xFFFF; + var pm = evaluationStackPointer - 1; + var po = pm - 1; + var anonObj = managedStack[po->Value1] as AnonymousStorey; + pm->Value1 = anonymousStoreyInfos[anonObj.typeId].VTable[slot]; + pm->Type = ValueType.Integer; + } + break; + case Code.CallStaticR_I4_I4_I4_Extern: + { + var externInvokeFunc = externInvokers[pc->Operand]; + if (externInvokeFunc == null) { - int slot = pc->Operand & 0xFFFF; - var pm = evaluationStackPointer - 1; - var po = pm - 1; - var anonObj = managedStack[po->Value1] as AnonymousStorey; - pm->Value1 = anonymousStoreyInfos[anonObj.typeId].VTable[slot]; - pm->Type = ValueType.Integer; + externInvokeFunc = + (CallR_I4_I4_I4)Delegate.CreateDelegate(typeof(CallR_I4_I4_I4), null, (MethodInfo)externMethods[pc->Operand]); + externInvokers[pc->Operand] = externInvokeFunc; } + evaluationStackPointer--; + (evaluationStackPointer - 1)->Value1 = ((CallR_I4_I4_I4)externInvokeFunc)((evaluationStackPointer - 1)->Value1, evaluationStackPointer->Value1); + } break; + case Code.CallExtern: //部分来自Call部分来自Callvirt + { + int methodId = pc->Operand & 0xFFFF; + int paramCount = pc->Operand >> 16; + var externInvokeFunc = (ExternInvoker)externInvokers[methodId]; + if (externInvokeFunc == null) + { + externInvokers[methodId] = externInvokeFunc + = (new ReflectionMethodInvoker(externMethods[methodId])).Invoke; + } + + var top = evaluationStackPointer - paramCount; + Call call = new Call() + { + argumentBase = top, + currentTop = top, + managedStack = managedStack, + evaluationStackBase = evaluationStackBase + }; - case Code.CallExtern://部分来自Call部分来自Callvirt + //调用外部前,需要保存当前top,以免外部从新进入内部时覆盖栈 + stack.UnmanagedStack->Top = evaluationStackPointer; + externInvokeFunc(this, ref call, false); + evaluationStackPointer = call.currentTop; + } + break; case Code.Newobj: // 2.334642% + { int methodId = pc->Operand & 0xFFFF; - if (code == Code.Newobj) + var method = externMethods[methodId]; + bool? isDelegate = externIsNewDelegate[methodId]; + if (isDelegate == null) + { + isDelegate = method.DeclaringType.BaseType == typeof(MulticastDelegate); + externIsNewDelegate[methodId] = isDelegate; + } + + if (isDelegate == true) // create delegate { - var method = externMethods[methodId]; - if (method.DeclaringType.BaseType == typeof(MulticastDelegate)) // create delegate + var pm = evaluationStackPointer - 1; + var po = pm - 1; + var o = managedStack[po->Value1]; + BoxUtils.RecycleObject(managedStack[po - evaluationStackBase]); + managedStack[po - evaluationStackBase] = null; + Delegate del = null; + if (pm->Type == ValueType.Integer) { - var pm = evaluationStackPointer - 1; - var po = pm - 1; - var o = managedStack[po->Value1]; - managedStack[po - evaluationStackBase] = null; - Delegate del = null; - if (pm->Type == ValueType.Integer) + //_Info("new closure!"); + del = wrappersManager.CreateDelegate(method.DeclaringType, pm->Value1, o); + if (del == null) { - //_Info("new closure!"); - del = wrappersManager.CreateDelegate(method.DeclaringType, pm->Value1, o); - if (del == null) - { - del = GenericDelegateFactory.Create(method.DeclaringType, this, - pm->Value1, o); - } - if (del == null) - { - throwRuntimeException( - new InvalidProgramException("no closure wrapper for " - + method.DeclaringType), true); - } + del = GenericDelegateFactory.Create(method.DeclaringType, this, + pm->Value1, o); } - //else if (pm->Type == ValueType.Float) // - //{ - // del = GetGlobalWrappersManager().CreateDelegate(method.DeclaringType, - // pm->Value1, null); - // if (del == null) - // { - // throwRuntimeException(new InvalidProgramException( - // "no closure wrapper for " + method.DeclaringType), true); - // } - //} - else + + if (del == null) { - var mi = managedStack[pm->Value1] as MethodInfo; - managedStack[pm - evaluationStackBase] = null; - del = Delegate.CreateDelegate(method.DeclaringType, o, mi); + throwRuntimeException( + new InvalidProgramException("no closure wrapper for " + + method.DeclaringType), true); } - po->Value1 = (int)(po - evaluationStackBase); - managedStack[po->Value1] = del; - evaluationStackPointer = pm; - break; } + else + { + var mi = managedStack[pm->Value1] as MethodInfo; + BoxUtils.RecycleObject(managedStack[pm - evaluationStackBase]); + managedStack[pm - evaluationStackBase] = null; + del = Delegate.CreateDelegate(method.DeclaringType, o, mi); + } + + po->Value1 = (int)(po - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[po->Value1]); + managedStack[po->Value1] = del; + evaluationStackPointer = pm; + break; } + int paramCount = pc->Operand >> 16; - var externInvokeFunc = externInvokers[methodId]; + var externInvokeFunc = (ExternInvoker)externInvokers[methodId]; if (externInvokeFunc == null) { externInvokers[methodId] = externInvokeFunc = (new ReflectionMethodInvoker(externMethods[methodId])).Invoke; } - //Info("call extern: " + externMethods[methodId]); + var top = evaluationStackPointer - paramCount; - //for(int kk = 0; kk < paramCount; kk++) - //{ - // string info = "arg " + kk + " " + (top + kk)->Type.ToString() + ": "; - // if ((top + kk)->Type >= ValueType.Object) - // { - // var o = managedStack[(top + kk)->Value1]; - // info += "obj(" + (o == null ? "null" : o.GetHashCode().ToString()) + ")"; - // } - // else - // { - // info += (top + kk)->Value1; - // } - // Info(info); - //} Call call = new Call() { argumentBase = top, @@ -924,2967 +946,3200 @@ public static void _Info(string a) evaluationStackBase = evaluationStackBase }; //调用外部前,需要保存当前top,以免外部从新进入内部时覆盖栈 - ThreadStackInfo.Stack.UnmanagedStack->Top = evaluationStackPointer; - externInvokeFunc(this, ref call, code == Code.Newobj); + stack.UnmanagedStack->Top = evaluationStackPointer; + externInvokeFunc(this, ref call, true); evaluationStackPointer = call.currentTop; + } break; //Ldloc_0:3.35279% Ldloc_S:2.624982% Ldloc_1:1.958552% Ldloc_2:1.278956% Ldloc_3:0.829925% case Code.Ldloc: + { + var src = localBase + pc->Operand; + *evaluationStackPointer = *src; + if (evaluationStackPointer->Type == ValueType.ChainFieldReference) { - //print("+++ldloc", locs + ins.Operand); - //if (methodIndex == 326) - //{ - // var a = localBase + pc->Operand; - // _Info("l->Type:" + a->Type + ", l->Value1:" + a->Value1); - // if (a->Type == ValueType.Object) - // { - // var obj = managedStack[a->Value1]; - // _Info("l.obj = " + (obj == null ? "null" : obj.GetType() + "(" - // + obj.GetHashCode() + ")")); - // } - //} - copy(evaluationStackBase, evaluationStackPointer, localBase + pc->Operand, - managedStack); - //if (methodIndex == 326) - //{ - // var a = evaluationStackPointer; - // _Info("e->Type:" + a->Type + ", e->Value1:" + a->Value1); - // if (a->Type == ValueType.Object) - // { - // var obj = managedStack[a->Value1]; - // _Info("e.obj = " + (obj == null ? "null" : obj.GetType() + "(" - // + obj.GetHashCode() + ")")); - // } - //} - evaluationStackPointer++; + BoxUtils.RecycleObject(managedStack[evaluationStackPointer - evaluationStackBase]); + managedStack[evaluationStackPointer - evaluationStackBase] = managedStack[src - evaluationStackBase]; } + evaluationStackPointer++; + } break; // Ldc_I4_0:3% Ldc_I4_1:2.254763% Ldc_I4_S:1.16403% Ldc_I4:0.8208519% Ldc_I4_2:0.58922% // Ldc_I4_4:0.3086645% Ldc_I4_M1:0.2323434% Ldc_I4_8:0.1894684% Ldc_I4_3:0.1850208% // Ldc_I4_5:0.1158159% Ldc_I4_7:0.08076869% Ldc_I4_6:0.07045022% case Code.Ldc_I4: + { + //*((long*)(&evaluationStackPointer->Value1)) = pc->Operand; + evaluationStackPointer->Value1 = pc->Operand; //高位不清除 + evaluationStackPointer->Type = ValueType.Integer; + evaluationStackPointer++; + } + break; + case Code.Ret: // 5.5% TODO: 分为带返回值和不带返回值 + { + //TODO: 可优化? 检查到没都是基本类型后改指令 + + if (topWriteBack != null) { - //*((long*)(&evaluationStackPointer->Value1)) = pc->Operand; - evaluationStackPointer->Value1 = pc->Operand; //高位不清除 - evaluationStackPointer->Type = ValueType.Integer; - evaluationStackPointer++; + *topWriteBack = argumentBase - refCount; } - break; - case Code.Ret:// 5.5% TODO: 分为带返回值和不带返回值 + + throwExcepton = null; + if (pc->Operand != 0) { - //TODO: 可优化? 检查到没都是基本类型后改指令 - - if (topWriteBack != null) - { - *topWriteBack = argumentBase - refCount; - } - throwExcepton = null; - if (pc->Operand != 0) + *argumentBase = *(evaluationStackPointer - 1); + if (argumentBase->Type == ValueType.Object + || argumentBase->Type == ValueType.ValueType) { - *argumentBase = *(evaluationStackPointer - 1); - if (argumentBase->Type == ValueType.Object - || argumentBase->Type == ValueType.ValueType) - { - int resultPos = argumentBase->Value1; - if (resultPos != argumentPos) - { - managedStack[argumentPos] = managedStack[resultPos]; - //managedStack[resultPos] = null; - } - argumentBase->Value1 = argumentPos; - } - for (int i = 0; i < evaluationStackPointer - evaluationStackBase - 1; i++) + int resultPos = argumentBase->Value1; + if (resultPos != argumentPos) { - managedStack[i + argumentPos + 1] = null; + BoxUtils.RecycleObject(managedStack[argumentPos]); + managedStack[argumentPos] = managedStack[resultPos]; + //managedStack[resultPos] = null; } - return argumentBase + 1; + argumentBase->Value1 = argumentPos; } - else + + for (int i = 0; i < evaluationStackPointer - evaluationStackBase - 1; i++) { - for (int i = 0; i < evaluationStackPointer - evaluationStackBase; i++) - { - managedStack[i + argumentPos] = null; - } - return argumentBase; + BoxUtils.RecycleObject(managedStack[i + argumentPos + 1]); + managedStack[i + argumentPos + 1] = null; + } + + return argumentBase + 1; + } + else + { + for (int i = 0; i < evaluationStackPointer - evaluationStackBase; i++) + { + BoxUtils.RecycleObject(managedStack[i + argumentPos]); + managedStack[i + argumentPos] = null; } + + return argumentBase; } + } //Stloc_0:1.717491% Stloc_S:1.316672% Stloc_1:1.020105% Stloc_2:0.6683876% Stloc_3:0.4547242% case Code.Stloc: + { + evaluationStackPointer--; + + // store(evaluationStackBase, localBase + pc->Operand, evaluationStackPointer, + // managedStack); + + var dst = localBase + pc->Operand; + *dst = *evaluationStackPointer; + switch (dst->Type) { - evaluationStackPointer--; - //print("+++before stloc", locs + ins.Operand); - store(evaluationStackBase, localBase + pc->Operand, evaluationStackPointer, - managedStack); - //print("+++after stloc", locs + ins.Operand); - managedStack[evaluationStackPointer - evaluationStackBase] = null; + case ValueType.ChainFieldReference: + { + BoxUtils.RecycleObject(managedStack[dst - evaluationStackBase]); //field addr + managedStack[dst - evaluationStackBase] = managedStack[evaluationStackPointer - evaluationStackBase]; + } + break; + case ValueType.Object: + case ValueType.ValueType: + case ValueType.ArrayReference: + { + var obj = managedStack[evaluationStackPointer->Value1]; + var dstPos = dst->Value1 = (int)(dst - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[dstPos]); + managedStack[dstPos] = obj; + } + break; } + + // BoxUtils.RecycleObject(managedStack[evaluationStackPointer - evaluationStackBase]); + // managedStack[evaluationStackPointer - evaluationStackBase] = null; + } break; case Code.Ldfld: //5.017799% + { + var ptr = evaluationStackPointer - 1; + var fieldIndex = pc->Operand; + //_Info("Ldfld fieldIndex:" + fieldIndex); + if (fieldIndex >= 0) { - var ptr = evaluationStackPointer - 1; - var fieldIndex = pc->Operand; - //_Info("Ldfld fieldIndex:" + fieldIndex); - if (fieldIndex >= 0) - { - var fieldInfo = fieldInfos[fieldIndex]; - //_Info("Ldfld fieldInfo:" + fieldInfo); + var fieldInfo = fieldInfos[fieldIndex]; + //_Info("Ldfld fieldInfo:" + fieldInfo); - Type declaringType = null; - Type fieldType = null; - string fieldName = null; - - if(fieldInfo == null) - { - fieldName = newFieldInfos[fieldIndex].Name; - fieldType = newFieldInfos[fieldIndex].FieldType; - declaringType = newFieldInfos[fieldIndex].DeclaringType; - } - else - { - fieldName = fieldInfo.Name; - fieldType = fieldInfo.FieldType; - declaringType = fieldInfo.DeclaringType; - } - - object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, declaringType, this, false); - - if (obj == null) - { - throw new NullReferenceException(declaringType + "." + fieldName); - } - //_Info("Ldfld:" + fieldInfo + ",obj=" + obj.GetType()); - - object fieldValue = null; - - if(fieldInfo == null) + Type declaringType = null; + Type fieldType = null; + //string fieldName = null; + + if (fieldInfo == null) + { + //fieldName = newFieldInfos[fieldIndex].Name; + fieldType = newFieldInfos[fieldIndex].FieldType; + declaringType = newFieldInfos[fieldIndex].DeclaringType; + } + else + { + //fieldName = fieldInfo.Name; + if (fieldTypes[fieldIndex] == null) { - newFieldInfos[fieldIndex].CheckInit(this, obj); - - fieldValue = newFieldInfos[fieldIndex].GetValue(obj); + fieldTypes[fieldIndex] = fieldInfo.FieldType; } - else + + if (fieldDeclareType[fieldIndex] == null) { - fieldValue = fieldInfo.GetValue(obj); + fieldDeclareType[fieldIndex] = fieldInfo.DeclaringType; } - //_Info("fieldValue:" + fieldValue); - //throw new Exception("fieldValue=" + fieldValue); + fieldType = fieldTypes[fieldIndex]; + declaringType = fieldDeclareType[fieldIndex]; + } + + object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, + managedStack, declaringType, this, false); + + if (obj == null) + { + throw new NullReferenceException(declaringType + "." + fieldInfo != null + ? fieldInfo.Name + : newFieldInfos[fieldIndex].Name); + } + //_Info("Ldfld:" + fieldInfo + ",obj=" + obj.GetType()); + + object fieldValue = null; + if (fieldInfo == null) + { + newFieldInfos[fieldIndex].CheckInit(this, obj); + fieldValue = newFieldInfos[fieldIndex].GetValue(obj); EvaluationStackOperation.PushObject(evaluationStackBase, ptr, managedStack, fieldValue, fieldType); } else { - fieldIndex = -(fieldIndex + 1); - AnonymousStorey anonyObj = managedStack[ptr->Value1] as AnonymousStorey; - anonyObj.Ldfld(fieldIndex, evaluationStackBase, ptr, managedStack); + EvaluationStackOperation.PushField(evaluationStackBase, ptr, managedStack, obj, + fieldInfo, fieldType); + //fieldValue = fieldInfo.GetValue(obj); } + + //_Info("fieldValue:" + fieldValue); + //throw new Exception("fieldValue=" + fieldValue); + // EvaluationStackOperation.PushObject(evaluationStackBase, ptr, managedStack, fieldValue, fieldType); } - break; - case Code.Ldstr://2.656827% + else { - EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, - managedStack, internStrings[pc->Operand], typeof(string)); - evaluationStackPointer++; + fieldIndex = -(fieldIndex + 1); + AnonymousStorey anonyObj = managedStack[ptr->Value1] as AnonymousStorey; + anonyObj.Ldfld(fieldIndex, evaluationStackBase, ptr, managedStack); } + } + break; + case Code.Ldstr: //2.656827% + { + EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, + managedStack, internStrings[pc->Operand], typeof(string)); + evaluationStackPointer++; + } break; - case Code.Brfalse://Brfalse_S:2.418613% Brfalse:0.106387% + case Code.Brfalse: //Brfalse_S:2.418613% Brfalse:0.106387% + { + evaluationStackPointer--; + bool transfer = evaluationStackPointer->Value1 == 0; + + if (transfer) { - bool transfer = false; - evaluationStackPointer--; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = evaluationStackPointer->Value1 == 0; - break; - case ValueType.Long: - transfer = *(long*)&evaluationStackPointer->Value1 == 0; - break; - case ValueType.Object: - case ValueType.ValueType: - transfer = managedStack[evaluationStackPointer->Value1] == null; - break; - } - managedStack[evaluationStackPointer - evaluationStackBase] = null; - if (transfer) - { - pc += pc->Operand; - continue; - } + pc += pc->Operand; + continue; } + } break; - case Code.Stfld://2.13361% + case Code.Stfld: //2.13361% + { + var ptr = evaluationStackPointer - 1 - 1; + var fieldIndex = pc->Operand; + if (fieldIndex >= 0) { - var ptr = evaluationStackPointer - 1 - 1; - var fieldIndex = pc->Operand; - if (fieldIndex >= 0) - { - var fieldInfo = fieldInfos[pc->Operand]; - - Type declaringType = null; - Type fieldType = null; - string fieldName = null; - - if(fieldInfo == null) - { - fieldName = newFieldInfos[fieldIndex].Name; - fieldType = newFieldInfos[fieldIndex].FieldType; - declaringType = newFieldInfos[fieldIndex].DeclaringType; - } - else - { - fieldName = fieldInfo.Name; - fieldType = fieldInfo.FieldType; - declaringType = fieldInfo.DeclaringType; - } + var fieldInfo = fieldInfos[pc->Operand]; - object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, declaringType, this, false); + Type declaringType = null; + Type fieldType = null; + string fieldName = null; - if (obj == null) - { - throw new NullReferenceException(declaringType + "." + fieldName); - } + if (fieldInfo == null) + { + fieldName = newFieldInfos[fieldIndex].Name; + fieldType = newFieldInfos[fieldIndex].FieldType; + declaringType = newFieldInfos[fieldIndex].DeclaringType; + } + else + { + fieldName = fieldInfo.Name; + fieldType = fieldInfo.FieldType; + declaringType = fieldInfo.DeclaringType; + } - if(fieldInfo != null) - { - fieldInfo.SetValue(obj, EvaluationStackOperation.ToObject(evaluationStackBase, - evaluationStackPointer - 1, managedStack, fieldType, this)); - } - else - { - newFieldInfos[fieldIndex].SetValue(obj, EvaluationStackOperation.ToObject(evaluationStackBase, - evaluationStackPointer - 1, managedStack, fieldType, this)); - } + object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, + managedStack, declaringType, this, false); - //如果field,array元素是值类型,需要重新update回去 - if ((ptr->Type == ValueType.FieldReference - || ptr->Type == ValueType.ChainFieldReference - || ptr->Type == ValueType.StaticFieldReference - || ptr->Type == ValueType.ArrayReference) - && declaringType.IsValueType) - { - EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, - managedStack, obj, this, declaringType); - } - managedStack[ptr - evaluationStackBase] = null; - managedStack[evaluationStackPointer - 1 - evaluationStackBase] = null; - evaluationStackPointer = ptr; + if (obj == null) + { + throw new NullReferenceException(declaringType + "." + fieldName); } - else + + if (fieldInfo != null) { - fieldIndex = -(fieldIndex + 1); - object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, ptr->Type.GetType(), this, false); - AnonymousStorey anonyObj = obj as AnonymousStorey; - anonyObj.Stfld(fieldIndex, evaluationStackBase, evaluationStackPointer - 1, - managedStack); - evaluationStackPointer = ptr; + object value = EvaluationStackOperation.ToObject(evaluationStackBase, + evaluationStackPointer - 1, managedStack, fieldType, this); + fieldInfo.SetValue(obj, value); + BoxUtils.RecycleObject(value); } - } - break; - case Code.Brtrue://Brtrue_S:1.944675% Brtrue:0.07400832% - { - bool transfer = false; - evaluationStackPointer--; - switch (evaluationStackPointer->Type) + else { - case ValueType.Integer: - transfer = evaluationStackPointer->Value1 != 0; - break; - case ValueType.Long: - transfer = *(long*)&evaluationStackPointer->Value1 != 0; - break; - case ValueType.Object: - case ValueType.ValueType: - transfer = managedStack[evaluationStackPointer->Value1] != null; - break; + object value = EvaluationStackOperation.ToObject(evaluationStackBase, + evaluationStackPointer - 1, managedStack, fieldType, this); + newFieldInfos[fieldIndex].SetValue(obj, value); } - managedStack[evaluationStackPointer - evaluationStackBase] = null; - if (transfer) + + //如果field,array元素是值类型,需要重新update回去 + if ((ptr->Type == ValueType.FieldReference + || ptr->Type == ValueType.ChainFieldReference + || ptr->Type == ValueType.StaticFieldReference + || ptr->Type == ValueType.ArrayReference) + && BoxUtils.GetTypeIsValueType(declaringType)) { - pc += pc->Operand; - continue; + EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, + managedStack, obj, this, declaringType); } + + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + BoxUtils.RecycleObject(managedStack[evaluationStackPointer - 1 - evaluationStackBase]); + managedStack[evaluationStackPointer - 1 - evaluationStackBase] = null; + evaluationStackPointer = ptr; } - break; - case Code.Add://1.356345% + else { - Value* b = evaluationStackPointer - 1; - //大于1的立即数和指针运算在il2cpp(unity 5.4)有bug,都会按1算 - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type)//TODO: 通过修改指令优化掉 - { - case ValueType.Long: - *((long*)&evaluationStackPointer->Value1) - = *((long*)&a->Value1) + *((long*)&b->Value1); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 = a->Value1 + b->Value1; - break; - case ValueType.Float: - *((float*)&evaluationStackPointer->Value1) - = *((float*)&a->Value1) + *((float*)&b->Value1); - break; - case ValueType.Double: - *((double*)&evaluationStackPointer->Value1) - = *((double*)&a->Value1) + *((double*)&b->Value1); - break; - default: - throwRuntimeException(new NotImplementedException(), true); - break; - } - evaluationStackPointer++; + fieldIndex = -(fieldIndex + 1); + object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, + managedStack, ptr->Type.GetType(), this, false); + AnonymousStorey anonyObj = obj as AnonymousStorey; + anonyObj.Stfld(fieldIndex, evaluationStackBase, evaluationStackPointer - 1, + managedStack); + evaluationStackPointer = ptr; } + } break; - case Code.Br://Br_S:1.162784% Br:0.2334108% + case Code.Brtrue: //Brtrue_S:1.944675% Brtrue:0.07400832% + { + evaluationStackPointer--; + bool transfer = evaluationStackPointer->Value1 != 0; + + if (transfer) { pc += pc->Operand; + continue; } - continue; - case Code.Ldnull://1.203347% + } + break; + case Code.Add1_Loc: + (localBase + pc->Operand)->Value1 += 1; + break; + case Code.Add_I4: + { + // evaluationStackPointer->Value1 = pc->Operand; //高位不清除 + // evaluationStackPointer->Type = ValueType.Integer; + // evaluationStackPointer++; + (evaluationStackPointer - 1)->Value1 += pc->Operand; + } + break; + case Code.Add: //1.356345% + { + Value* b = evaluationStackPointer - 1; + //大于1的立即数和指针运算在il2cpp(unity 5.4)有bug,都会按1算 + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) //TODO: 通过修改指令优化掉 { - var pos = (int)(evaluationStackPointer - evaluationStackBase); - managedStack[pos] = null; - evaluationStackPointer->Value1 = pos; - evaluationStackPointer->Type = ValueType.Object; - evaluationStackPointer++; + case ValueType.Integer: + evaluationStackPointer->Value1 = a->Value1 + b->Value1; + break; + case ValueType.Long: + *((long*)&evaluationStackPointer->Value1) + = *((long*)&a->Value1) + *((long*)&b->Value1); + break; + case ValueType.Float: + *((float*)&evaluationStackPointer->Value1) + = *((float*)&a->Value1) + *((float*)&b->Value1); + break; + case ValueType.Double: + *((double*)&evaluationStackPointer->Value1) + = *((double*)&a->Value1) + *((double*)&b->Value1); + break; + default: + throwRuntimeException(new NotImplementedException(), true); + break; } + + evaluationStackPointer++; + } + break; + case Code.Br: //Br_S:1.162784% Br:0.2334108% + { + pc += pc->Operand; + } + continue; + case Code.Ldnull: //1.203347% + { + var pos = (int)(evaluationStackPointer - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = null; + evaluationStackPointer->Value1 = pos; + evaluationStackPointer->Type = ValueType.Object; + evaluationStackPointer++; + } break; case Code.Ldloca: //Ldloca_S:1.023663% - { - *(Value**)&evaluationStackPointer->Value1 = localBase + pc->Operand; - evaluationStackPointer->Type = ValueType.StackReference; - evaluationStackPointer++; - } + { + *(Value**)&evaluationStackPointer->Value1 = localBase + pc->Operand; + evaluationStackPointer->Type = ValueType.StackReference; + evaluationStackPointer++; + } break; - case Code.Dup://0.9831008% + case Code.Dup: //0.9831008% copy(evaluationStackBase, evaluationStackPointer, evaluationStackPointer - 1, managedStack); evaluationStackPointer++; break; case Code.Ldsfld: //0.7173114% + { + var fieldIndex = pc->Operand; + if (fieldIndex >= 0) { - var fieldIndex = pc->Operand; - if (fieldIndex >= 0) - { - var fieldInfo = fieldInfos[fieldIndex]; - Type fieldType = null; + var fieldInfo = fieldInfos[fieldIndex]; + Type fieldType = null; - object fieldValue = null; + object fieldValue = null; - if (fieldInfo == null) - { - newFieldInfos[fieldIndex].CheckInit(this, null); + if (fieldInfo == null) + { + newFieldInfos[fieldIndex].CheckInit(this, null); - fieldType = newFieldInfos[fieldIndex].FieldType; - fieldValue = newFieldInfos[fieldIndex].GetValue(null); - } - else - { - fieldType = fieldInfo.FieldType; - fieldValue = fieldInfo.GetValue(null); - } - - EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, - managedStack, fieldValue, fieldType); + fieldType = newFieldInfos[fieldIndex].FieldType; + fieldValue = newFieldInfos[fieldIndex].GetValue(null); } else { - fieldIndex = -(fieldIndex + 1); - checkCctorExecute(fieldIndex, evaluationStackPointer, managedStack, - evaluationStackBase); - //_Info("load static field " + fieldIndex + " : " + staticFields[fieldIndex]); - EvaluationStackOperation.PushObject(evaluationStackBase, - evaluationStackPointer, managedStack, - staticFields[fieldIndex], staticFieldTypes[fieldIndex]); + fieldType = fieldInfo.FieldType; + fieldValue = BoxUtils.GetStaticFieldValue(fieldInfo, fieldType); } - evaluationStackPointer++; + + EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, + managedStack, fieldValue, fieldType); + } + else + { + fieldIndex = -(fieldIndex + 1); + checkCctorExecute(fieldIndex, evaluationStackPointer, managedStack, + evaluationStackBase); + //_Info("load static field " + fieldIndex + " : " + staticFields[fieldIndex]); + EvaluationStackOperation.PushObject(evaluationStackBase, + evaluationStackPointer, managedStack, + staticFields[fieldIndex], staticFieldTypes[fieldIndex]); } + + evaluationStackPointer++; + } break; case Code.Conv_I4: //0.5349591% + { + var ptr = evaluationStackPointer - 1; + int val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = (int)*(long*)&ptr->Value1; - break; - case ValueType.Float: - val = (int)*(float*)&ptr->Value1; - break; - case ValueType.Double: - val = (int)*(double*)&ptr->Value1; - break; - case ValueType.Integer: - val = ptr->Value1; - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + val = (int)*(long*)&ptr->Value1; + break; + case ValueType.Float: + val = (int)*(float*)&ptr->Value1; + break; + case ValueType.Double: + val = (int)*(double*)&ptr->Value1; + break; + case ValueType.Integer: + val = ptr->Value1; + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Sub: //0.5299778% + { + Value* b = evaluationStackPointer - 1; + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - *((long*)&evaluationStackPointer->Value1) - = *((long*)&a->Value1) - *((long*)&b->Value1); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 = a->Value1 - b->Value1; - break; - case ValueType.Float: - *((float*)&evaluationStackPointer->Value1) - = *((float*)&a->Value1) - *((float*)&b->Value1); - break; - case ValueType.Double: - *((double*)&evaluationStackPointer->Value1) - = *((double*)&a->Value1) - *((double*)&b->Value1); - break; - default: - throwRuntimeException(new NotImplementedException(), true); - break; - } - evaluationStackPointer++; + case ValueType.Long: + *((long*)&evaluationStackPointer->Value1) + = *((long*)&a->Value1) - *((long*)&b->Value1); + break; + case ValueType.Integer: + evaluationStackPointer->Value1 = a->Value1 - b->Value1; + break; + case ValueType.Float: + *((float*)&evaluationStackPointer->Value1) + = *((float*)&a->Value1) - *((float*)&b->Value1); + break; + case ValueType.Double: + *((double*)&evaluationStackPointer->Value1) + = *((double*)&a->Value1) - *((double*)&b->Value1); + break; + default: + throwRuntimeException(new NotImplementedException(), true); + break; } + + evaluationStackPointer++; + } break; case Code.Ldlen: //0.5175245% - { - var ptr = evaluationStackPointer - 1; - Array arr = managedStack[ptr->Value1] as Array; - managedStack[ptr - evaluationStackBase] = null; - ptr->Type = ValueType.Integer; - ptr->Value1 = arr.Length; - } + { + var ptr = evaluationStackPointer - 1; + Array arr = managedStack[ptr->Value1] as Array; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + ptr->Type = ValueType.Integer; + ptr->Value1 = arr.Length; + } break; //TODO: 指令是否可以精简?比如if (a > b) 可以等同于if (b < a) case Code.Blt: //Blt_S:0.4835447% Blt:0.04465406% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = a->Value1 < b->Value1; - break; - case ValueType.Long: - transfer = *(long*)&a->Value1 < *(long*)&b->Value1; - break; - case ValueType.Float: - transfer = *(float*)&a->Value1 < *(float*)&b->Value1; - break; - case ValueType.Double: - transfer = *(double*)&a->Value1 < *(double*)&b->Value1; - break; - } + case ValueType.Integer: + transfer = a->Value1 < b->Value1; + break; + case ValueType.Long: + transfer = *(long*)&a->Value1 < *(long*)&b->Value1; + break; + case ValueType.Float: + transfer = *(float*)&a->Value1 < *(float*)&b->Value1; + break; + case ValueType.Double: + transfer = *(double*)&a->Value1 < *(double*)&b->Value1; + break; + } - if (transfer) - { - pc += pc->Operand; - continue; - } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Stelem_Ref: //0.4734042% + { + var arrPtr = evaluationStackPointer - 1 - 1 - 1; + int idx = (evaluationStackPointer - 1 - 1)->Value1; + var valPtr = evaluationStackPointer - 1; + var arr = managedStack[arrPtr->Value1] as object[]; + if (valPtr->Type != ValueType.Object) { - var arrPtr = evaluationStackPointer - 1 - 1 - 1; - int idx = (evaluationStackPointer - 1 - 1)->Value1; - var valPtr = evaluationStackPointer - 1; - var arr = managedStack[arrPtr->Value1] as object[]; - if (valPtr->Type != ValueType.Object) - { - throw new ArrayTypeMismatchException(); - } - arr[idx] = managedStack[valPtr->Value1]; - managedStack[arrPtr - evaluationStackBase] = null; //清理,如果有的话 - managedStack[valPtr - evaluationStackBase] = null; - evaluationStackPointer = arrPtr; + throw new ArrayTypeMismatchException(); } + + arr[idx] = managedStack[valPtr->Value1]; + // BoxUtils.RecycleObject(managedStack[arrPtr - evaluationStackBase]); + // managedStack[arrPtr - evaluationStackBase] = null; //清理,如果有的话 + // BoxUtils.RecycleObject(managedStack[valPtr - evaluationStackBase]); + // managedStack[valPtr - evaluationStackBase] = null; + evaluationStackPointer = arrPtr; + } break; - case Code.Pop://0.4614846% - { - evaluationStackPointer--; - managedStack[evaluationStackPointer - evaluationStackBase] = null; ; - } + case Code.Pop: //0.4614846% + { + evaluationStackPointer--; + //BoxUtils.RecycleObject(managedStack[evaluationStackPointer - evaluationStackBase]); + //managedStack[evaluationStackPointer - evaluationStackBase] = null; + } break; - case Code.Bne_Un://Bne_Un_S:0.4565032% Bne_Un:0.02793102% + case Code.Bne_Un: //Bne_Un_S:0.4565032% Bne_Un:0.02793102% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + if (a->Type != b->Type + || ((a->Type == ValueType.Object || a->Type == ValueType.ValueType) + ? (managedStack[a->Value1] != managedStack[b->Value1]) + : ((a->Value1 != b->Value1) || (a->Type != ValueType.Integer + && a->Type != ValueType.Float && + a->Value2 != b->Value2)))) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - if (a->Type != b->Type - || ((a->Type == ValueType.Object || a->Type == ValueType.ValueType) ? - (managedStack[a->Value1] != managedStack[b->Value1]) : - ((a->Value1 != b->Value1) || (a->Type != ValueType.Integer - && a->Type != ValueType.Float && a->Value2 != b->Value2)))) - { - pc += pc->Operand; - continue; - } + pc += pc->Operand; + continue; } + } break; - case Code.Leave://Leave_S:0.4552579% Leave:0.03220074% - { - leavePoint = pc->Operand; - } + case Code.Leave: //Leave_S:0.4552579% Leave:0.03220074% + { + leavePoint = pc->Operand; + } break; case Code.Newarr: //0.4408476% - { - var type = externTypes[pc->Operand]; - var ptr = evaluationStackPointer - 1; - int pos = (int)(ptr - evaluationStackBase); - managedStack[pos] = Array.CreateInstance(type, ptr->Value1); - ptr->Type = ValueType.Object; - ptr->Value1 = pos; - } + { + var type = externTypes[pc->Operand]; + var ptr = evaluationStackPointer - 1; + int pos = (int)(ptr - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = Array.CreateInstance(type, ptr->Value1); + ptr->Type = ValueType.Object; + ptr->Value1 = pos; + } break; case Code.And: //0.3967273% + { + var rhs = evaluationStackPointer - 1; + var lhs = evaluationStackPointer - 1 - 1; + switch (lhs->Type) { - var rhs = evaluationStackPointer - 1; - var lhs = evaluationStackPointer - 1 - 1; - switch (lhs->Type) - { - case ValueType.Long: - *((long*)&lhs->Value1) = *((long*)&lhs->Value1) & *((long*)&rhs->Value1); - break; - case ValueType.Integer: - lhs->Value1 = lhs->Value1 & rhs->Value1; - break; - default: - throw new InvalidProgramException("& for " + lhs->Type); - } - evaluationStackPointer = rhs; + case ValueType.Long: + *((long*)&lhs->Value1) = *((long*)&lhs->Value1) & *((long*)&rhs->Value1); + break; + case ValueType.Integer: + lhs->Value1 = lhs->Value1 & rhs->Value1; + break; + default: + throw new InvalidProgramException("& for " + lhs->Type); } + + evaluationStackPointer = rhs; + } break; case Code.Volatile: //0.3912123% break; case Code.Castclass: //0.358122% + { + var ptr = evaluationStackPointer - 1; + var type = pc->Operand >= 0 ? externTypes[pc->Operand] : typeof(AnonymousStorey); + var obj = managedStack[ptr->Value1]; + if (obj != null) { - var ptr = evaluationStackPointer - 1; - var type = pc->Operand >= 0 ? externTypes[pc->Operand] : typeof(AnonymousStorey); - var obj = managedStack[ptr->Value1]; - if (obj != null) + bool canAssign = type.IsAssignableFrom(obj.GetType()); + if (!canAssign) { - bool canAssign = type.IsAssignableFrom(obj.GetType()); - if(!canAssign) - { - throw new InvalidCastException(type + " is not assignable from " - + obj.GetType()); - } + throw new InvalidCastException(type + " is not assignable from " + + obj.GetType()); + } - if(canAssign && pc->Operand < 0 && (obj is AnonymousStorey) && (obj as AnonymousStorey).typeId != -(pc->Operand+1) ) + if (canAssign && pc->Operand < 0 && (obj is AnonymousStorey) && + (obj as AnonymousStorey).typeId != -(pc->Operand + 1)) + { + var fromInfo = anonymousStoreyInfos[(obj as AnonymousStorey).typeId]; + var targetInfo = anonymousStoreyInfos[-(pc->Operand + 1)]; + + if (fromInfo.Slots != null && targetInfo.Slots != null && + fromInfo.Slots.Length == targetInfo.Slots.Length) { - var fromInfo = anonymousStoreyInfos[(obj as AnonymousStorey).typeId]; - var targetInfo = anonymousStoreyInfos[-(pc->Operand+1)]; - - if(fromInfo.Slots != null && targetInfo.Slots != null && fromInfo.Slots.Length == targetInfo.Slots.Length) + for (int i = 0; i < fromInfo.Slots.Length; ++i) { - for(int i = 0; i < fromInfo.Slots.Length; ++i) + if (fromInfo.Slots[i] != targetInfo.Slots[i]) { - if(fromInfo.Slots[i] != targetInfo.Slots[i]) - { - canAssign = false; - break; - } + canAssign = false; + break; } } - else - { - canAssign = false; - } - - if(!canAssign) - { - throw new InvalidCastException("AnonymousStorey typeid different, " + (obj as AnonymousStorey).typeId + " <-> " + -(pc->Operand+1)); - } + } + else + { + canAssign = false; + } + + if (!canAssign) + { + throw new InvalidCastException("AnonymousStorey typeid different, " + + (obj as AnonymousStorey).typeId + " <-> " + + -(pc->Operand + 1)); } } } + } break; - case Code.Beq://Beq_S:0.3517174% Beq: 0.03700416% + case Code.Beq: //Beq_S:0.3517174% Beq: 0.03700416% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + if (a->Type == b->Type && ((a->Type == ValueType.Object + || a->Type == ValueType.ValueType) + ? (managedStack[a->Value1] == managedStack[b->Value1]) + : ((a->Value1 == b->Value1) && (a->Type == ValueType.Integer + || a->Type == ValueType.Float || + a->Value2 == b->Value2)))) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - if (a->Type == b->Type && ((a->Type == ValueType.Object - || a->Type == ValueType.ValueType) ? - (managedStack[a->Value1] == managedStack[b->Value1]) : - ((a->Value1 == b->Value1) && (a->Type == ValueType.Integer - || a->Type == ValueType.Float || a->Value2 == b->Value2)))) - { - pc += pc->Operand; - continue; - } + pc += pc->Operand; + continue; } + } break; case Code.Ldelem_Ref: //0.3449571% - { - var arrPtr = evaluationStackPointer - 1 - 1; - int idx = (evaluationStackPointer - 1)->Value1; - var arrPos = arrPtr - evaluationStackBase; - var arr = managedStack[arrPtr->Value1] as object[]; - managedStack[arrPos] = arr[idx]; - arrPtr->Value1 = (int)arrPos; - evaluationStackPointer = evaluationStackPointer - 1; - } + { + var arrPtr = evaluationStackPointer - 1 - 1; + int idx = (evaluationStackPointer - 1)->Value1; + var arrPos = arrPtr - evaluationStackBase; + var arr = managedStack[arrPtr->Value1] as object[]; + BoxUtils.RecycleObject(managedStack[arrPos]); + managedStack[arrPos] = arr[idx]; + arrPtr->Value1 = (int)arrPos; + evaluationStackPointer = evaluationStackPointer - 1; + } break; - case Code.Ldtype:// Ldtoken:0.3325037% + case Code.Ldtype: // Ldtoken:0.3325037% EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, managedStack, externTypes[pc->Operand], typeof(Type)); evaluationStackPointer++; break; - case Code.Box://0.3100877% - { - var ptr = evaluationStackPointer - 1; - if(pc->Operand >= 0) - { - var type = externTypes[pc->Operand]; - var pos = (int)(ptr - evaluationStackBase); - switch (ptr->Type) - { - case ValueType.ValueType: - case ValueType.Object: - break; - case ValueType.Integer: - if (type.IsEnum) - { - managedStack[pos] = Enum.ToObject(type, ptr->Value1); - } - else if (type == typeof(int)) - { - managedStack[pos] = ptr->Value1; - } - else if (type == typeof(uint)) - { - managedStack[pos] = (uint)ptr->Value1; - } - else - { - managedStack[pos] = Convert.ChangeType(ptr->Value1, type); - } - ptr->Value1 = pos; - break; - case ValueType.Long: - if (type == typeof(long)) - { - managedStack[pos] = *(long*)&ptr->Value1; - } - else if (type == typeof(ulong)) - { - managedStack[pos] = *(ulong*)&ptr->Value1; - } - else if (type.IsEnum) - { - managedStack[pos] = Enum.ToObject(type, *(long*)&ptr->Value1); - } - else if (type == typeof(IntPtr)) - { - managedStack[pos] = new IntPtr(*(long*)&ptr->Value1); - } - else if (type == typeof(UIntPtr)) - { - managedStack[pos] = new UIntPtr(*(ulong*)&ptr->Value1); - } - else - { - managedStack[pos] = Convert.ChangeType(*(long*)&ptr->Value1, type); - } - ptr->Value1 = pos; - break; - case ValueType.Float: - managedStack[pos] = *(float*)&ptr->Value1; - ptr->Value1 = pos; - break; - case ValueType.Double: - managedStack[pos] = *(double*)&ptr->Value1; - ptr->Value1 = pos; - break; - default: - throwRuntimeException(new InvalidProgramException("to box a " + ptr->Type), - true); - break; - } - } - ptr->Type = ValueType.Object; - } - break; - case Code.Isinst://0.3074192% + case Code.Box: //0.3100877% + { + var ptr = evaluationStackPointer - 1; + if (pc->Operand >= 0) { - var ptr = evaluationStackPointer - 1; - var type = pc->Operand >= 0 ? externTypes[pc->Operand] : typeof(AnonymousStorey); + var type = externTypes[pc->Operand]; var pos = (int)(ptr - evaluationStackBase); - var obj = managedStack[ptr->Value1]; - ptr->Type = ValueType.Object; - ptr->Value1 = pos; - if (obj == null) - { - managedStack[pos] = null; - } - else - { - bool canAssign = type.IsAssignableFrom(obj.GetType()); - managedStack[pos] = canAssign - ? obj : null; - if (pc->Operand < 0 && canAssign) - { - if ((obj is AnonymousStorey) && (obj as AnonymousStorey).typeId != -(pc->Operand + 1)) - { - var fromInfo = anonymousStoreyInfos[(obj as AnonymousStorey).typeId]; - var targetInfo = anonymousStoreyInfos[-(pc->Operand + 1)]; - - if (fromInfo.Slots != null && targetInfo.Slots != null && fromInfo.Slots.Length == targetInfo.Slots.Length) - { - for (int i = 0; i < fromInfo.Slots.Length; ++i) - { - if (fromInfo.Slots[i] != targetInfo.Slots[i]) - { - canAssign = false; - break; - } - } - } - else - { - canAssign = false; - } - - if (!canAssign) - { - managedStack[pos] = null; - } - } - } - } - } - break; - case Code.Bge: //Bge_S:0.2954996% Bge:0.005870852% - { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) + + switch (ptr->Type) { + case ValueType.ValueType: + case ValueType.Object: + break; case ValueType.Integer: - transfer = a->Value1 >= b->Value1; + if (BoxUtils.GetTypeIsEnum(type)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = Enum.ToObject(type, ptr->Value1); + } + else if (type == typeof(int)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = ptr->Value1; + } + else if (type == typeof(uint)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = (uint)ptr->Value1; + } + else + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = Convert.ChangeType(ptr->Value1, type); + } + + ptr->Value1 = pos; break; case ValueType.Long: - transfer = *(long*)&a->Value1 >= *(long*)&b->Value1; + if (type == typeof(long)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = *(long*)&ptr->Value1; + } + else if (type == typeof(ulong)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = *(ulong*)&ptr->Value1; + } + else if (BoxUtils.GetTypeIsEnum(type)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = Enum.ToObject(type, *(long*)&ptr->Value1); + } + else if (type == typeof(IntPtr)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = new IntPtr(*(long*)&ptr->Value1); + } + else if (type == typeof(UIntPtr)) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = new UIntPtr(*(ulong*)&ptr->Value1); + } + else + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = Convert.ChangeType(*(long*)&ptr->Value1, type); + } + + ptr->Value1 = pos; break; case ValueType.Float: - transfer = *(float*)&a->Value1 >= *(float*)&b->Value1; + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = *(float*)&ptr->Value1; + ptr->Value1 = pos; break; case ValueType.Double: - transfer = *(double*)&a->Value1 >= *(double*)&b->Value1; + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = *(double*)&ptr->Value1; + ptr->Value1 = pos; + break; + default: + throwRuntimeException(new InvalidProgramException("to box a " + ptr->Type), + true); break; } + } - if (transfer) + ptr->Type = ValueType.Object; + } + break; + case Code.Isinst: //0.3074192% + { + var ptr = evaluationStackPointer - 1; + var type = pc->Operand >= 0 ? externTypes[pc->Operand] : typeof(AnonymousStorey); + var pos = (int)(ptr - evaluationStackBase); + var obj = managedStack[ptr->Value1]; + ptr->Type = ValueType.Object; + ptr->Value1 = pos; + if (obj == null) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = null; + } + else + { + bool canAssign = type.IsAssignableFrom(obj.GetType()); + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = canAssign + ? obj + : null; + if (pc->Operand < 0 && canAssign) { - pc += pc->Operand; - continue; + if ((obj is AnonymousStorey) && + (obj as AnonymousStorey).typeId != -(pc->Operand + 1)) + { + var fromInfo = anonymousStoreyInfos[(obj as AnonymousStorey).typeId]; + var targetInfo = anonymousStoreyInfos[-(pc->Operand + 1)]; + + if (fromInfo.Slots != null && targetInfo.Slots != null && + fromInfo.Slots.Length == targetInfo.Slots.Length) + { + for (int i = 0; i < fromInfo.Slots.Length; ++i) + { + if (fromInfo.Slots[i] != targetInfo.Slots[i]) + { + canAssign = false; + break; + } + } + } + else + { + canAssign = false; + } + + if (!canAssign) + { + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = null; + } + } } + } + } + break; + case Code.Bge: //Bge_S:0.2954996% Bge:0.005870852% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) + { + case ValueType.Integer: + transfer = a->Value1 >= b->Value1; + break; + case ValueType.Long: + transfer = *(long*)&a->Value1 >= *(long*)&b->Value1; + break; + case ValueType.Float: + transfer = *(float*)&a->Value1 >= *(float*)&b->Value1; + break; + case ValueType.Double: + transfer = *(double*)&a->Value1 >= *(double*)&b->Value1; + break; + } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Conv_I8: //0.2652557% + { + var obj = evaluationStackPointer - 1; + long val; + switch (obj->Type) { - var obj = evaluationStackPointer - 1; - long val; - switch (obj->Type) - { - case ValueType.Integer: - val = obj->Value1; - break; - case ValueType.Long: - pc++; - continue; - case ValueType.Float: - val = (long)*(float*)&obj->Value1; - break; - case ValueType.Double: - val = (long)*(double*)&obj->Value1; - break; - default: - val = 0; - throwRuntimeException(new NotImplementedException(), true); - break; - } - obj->Type = ValueType.Long; - *(long*)(&obj->Value1) = val; + case ValueType.Integer: + val = obj->Value1; + break; + case ValueType.Long: + pc++; + continue; + case ValueType.Float: + val = (long)*(float*)&obj->Value1; + break; + case ValueType.Double: + val = (long)*(double*)&obj->Value1; + break; + default: + val = 0; + throwRuntimeException(new NotImplementedException(), true); + break; } + + obj->Type = ValueType.Long; + *(long*)(&obj->Value1) = val; + } break; - case Code.Ble://Ble_S:0.2581396% Ble:0.0152998% + case Code.Ble: //Ble_S:0.2581396% Ble:0.0152998% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = a->Value1 <= b->Value1; - break; - case ValueType.Long: - transfer = *(long*)&a->Value1 <= *(long*)&b->Value1; - break; - case ValueType.Float: - transfer = *(float*)&a->Value1 <= *(float*)&b->Value1; - break; - case ValueType.Double: - transfer = *(double*)&a->Value1 <= *(double*)&b->Value1; - break; - default: - throwRuntimeException(new NotImplementedException("Blt for " - + evaluationStackPointer->Type), true); - break; - } + case ValueType.Integer: + transfer = a->Value1 <= b->Value1; + break; + case ValueType.Long: + transfer = *(long*)&a->Value1 <= *(long*)&b->Value1; + break; + case ValueType.Float: + transfer = *(float*)&a->Value1 <= *(float*)&b->Value1; + break; + case ValueType.Double: + transfer = *(double*)&a->Value1 <= *(double*)&b->Value1; + break; + default: + throwRuntimeException(new NotImplementedException("Blt for " + + evaluationStackPointer->Type), true); + break; + } - if (transfer) - { - pc += pc->Operand; - continue; - } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Endfinally: //0.2513792% + { + if (leavePoint == 0) //有异常 + { + int exceptionPos = (int)(evaluationStackPointer - evaluationStackBase - 1); + var exception = managedStack[(evaluationStackPointer - 1)->Value1] + as Exception; + // BoxUtils.RecycleObject(managedStack[exceptionPos]); 不是 value类型 + managedStack[exceptionPos] = null; + evaluationStackPointer--; + throw exception; + } + else { - if (leavePoint == 0)//有异常 + if (pc->Operand == -1) //最外层 { - int exceptionPos = (int)(evaluationStackPointer - evaluationStackBase - 1); - var exception = managedStack[(evaluationStackPointer - 1)->Value1] - as Exception; - managedStack[exceptionPos] = null; - evaluationStackPointer--; - throw exception; + pc = pcb + leavePoint; + leavePoint = 0; + continue; } - else + else //不是最外层 { - if (pc->Operand == -1) //最外层 + var nextFinally = exceptionHandlers[methodIndex][pc->Operand]; + if (leavePoint >= nextFinally.TryStart && leavePoint < nextFinally.TryEnd) { pc = pcb + leavePoint; leavePoint = 0; continue; } - else //不是最外层 + else { - var nextFinally = exceptionHandlers[methodIndex][pc->Operand]; - if (leavePoint >= nextFinally.TryStart && leavePoint < nextFinally.TryEnd) - { - pc = pcb + leavePoint; - leavePoint = 0; - continue; - } - else - { - pc = pcb + nextFinally.HandlerStart; - continue; - } + pc = pcb + nextFinally.HandlerStart; + continue; } } } + } case Code.Or: //0.2490664% + { + var rhs = evaluationStackPointer - 1; + var lhs = evaluationStackPointer - 1 - 1; + switch (lhs->Type) { - var rhs = evaluationStackPointer - 1; - var lhs = evaluationStackPointer - 1 - 1; - switch (lhs->Type) - { - case ValueType.Long: - *((long*)&lhs->Value1) = *((long*)&lhs->Value1) | *((long*)&rhs->Value1); - break; - case ValueType.Integer: - lhs->Value1 = lhs->Value1 | rhs->Value1; - break; - default: - throw new InvalidProgramException("| for " + lhs->Type); - } - evaluationStackPointer = rhs; + case ValueType.Long: + *((long*)&lhs->Value1) = *((long*)&lhs->Value1) | *((long*)&rhs->Value1); + break; + case ValueType.Integer: + lhs->Value1 = lhs->Value1 | rhs->Value1; + break; + default: + throw new InvalidProgramException("| for " + lhs->Type); } + + evaluationStackPointer = rhs; + } break; case Code.Stsfld: //0.2488885% + { + var fieldIndex = pc->Operand; + if (fieldIndex >= 0) { - var fieldIndex = pc->Operand; - if (fieldIndex >= 0) + var fieldInfo = fieldInfos[fieldIndex]; + Type filedType = null; + + if (fieldInfo == null) { - var fieldInfo = fieldInfos[fieldIndex]; - Type filedType = null; - - if (fieldInfo == null) - { - filedType = newFieldInfos[fieldIndex].FieldType; - } - else - { - filedType = fieldInfo.FieldType; - } + filedType = newFieldInfos[fieldIndex].FieldType; + } + else + { + filedType = fieldInfo.FieldType; + } - var value = EvaluationStackOperation.ToObject(evaluationStackBase, - evaluationStackPointer - 1, managedStack, filedType, this); - - if (fieldInfo == null) - { - newFieldInfos[fieldIndex].SetValue(null, value); - } - else - { - fieldInfo.SetValue(null, value); - } + var value = EvaluationStackOperation.ToObject(evaluationStackBase, + evaluationStackPointer - 1, managedStack, filedType, this); + + if (fieldInfo == null) + { + newFieldInfos[fieldIndex].SetValue(null, value); } else { - fieldIndex = -(fieldIndex + 1); - checkCctorExecute(fieldIndex, evaluationStackPointer, managedStack, - evaluationStackBase); - staticFields[fieldIndex] - = EvaluationStackOperation.ToObject(evaluationStackBase, - evaluationStackPointer - 1, managedStack, staticFieldTypes[fieldIndex], this); - //_Info("store static field " + fieldIndex + " : " + staticFields[fieldIndex]); + fieldInfo.SetValue(null, value); + BoxUtils.RecycleObject(value); } - managedStack[evaluationStackPointer - 1 - evaluationStackBase] = null; - evaluationStackPointer--; } + else + { + fieldIndex = -(fieldIndex + 1); + checkCctorExecute(fieldIndex, evaluationStackPointer, managedStack, + evaluationStackBase); + staticFields[fieldIndex] + = EvaluationStackOperation.ToObject(evaluationStackBase, + evaluationStackPointer - 1, managedStack, staticFieldTypes[fieldIndex], this); + //_Info("store static field " + fieldIndex + " : " + staticFields[fieldIndex]); + } + + BoxUtils.RecycleObject(managedStack[evaluationStackPointer - 1 - evaluationStackBase]); + managedStack[evaluationStackPointer - 1 - evaluationStackBase] = null; + evaluationStackPointer--; + } break; case Code.Ldflda: //0.240527% - { - var fieldInfo = pc->Operand >= 0 ? fieldInfos[pc->Operand] : null; + { + var fieldInfo = pc->Operand >= 0 ? fieldInfos[pc->Operand] : null; - Type declaringType = null; - Type fieldType = null; - var ptr = evaluationStackPointer - 1; + Type declaringType = null; + Type fieldType = null; + var ptr = evaluationStackPointer - 1; - if(pc->Operand >= 0) + if (pc->Operand >= 0) + { + if (fieldInfo == null) { - if(fieldInfo == null) - { - fieldType = newFieldInfos[pc->Operand].FieldType; - declaringType = newFieldInfos[pc->Operand].DeclaringType; - } - else + fieldType = newFieldInfos[pc->Operand].FieldType; + declaringType = newFieldInfos[pc->Operand].DeclaringType; + } + else + { + fieldType = fieldInfo.FieldType; + declaringType = fieldInfo.DeclaringType; + } + } + + //栈顶也是字段引用,而且该字段是值类型,需要update上层对象 + if ((ptr->Type == ValueType.FieldReference + || ptr->Type == ValueType.ChainFieldReference + || ptr->Type == ValueType.ArrayReference) && pc->Operand >= 0 + && BoxUtils.GetTypeIsValueType(fieldType)) + { + // if (pc->Operand < 0) + // { + // throwRuntimeException(new NotSupportedException( + // "chain ref for compiler generated object!"), true); + // } + //_Info("mult ref"); + //ptr->Value1:指向实际对象 + //ptr->Value2:-1表示第一个是FieldReference, -2表示是ArrayReference + //managedStack[offset]:int[],表示 + + //多层引用managedStack[ptr - evaluationStackBase] == fieldIdList + //多层引用,append + if (ptr->Type == ValueType.ChainFieldReference) + { + var offset = ptr - evaluationStackBase; + var fieldAddr = managedStack[offset] as FieldAddr; + var fieldIdList = fieldAddr.FieldIdList; + var newFieldIdList = new int[fieldIdList.Length + 1]; + Array.Copy(fieldIdList, newFieldIdList, fieldIdList.Length); + newFieldIdList[fieldIdList.Length] = pc->Operand; + BoxUtils.RecycleObject(managedStack[offset]); + managedStack[offset] = new FieldAddr() { - fieldType = fieldInfo.FieldType; - declaringType = fieldInfo.DeclaringType; - } + Object = fieldAddr.Object, + FieldIdList = newFieldIdList + }; } - - //栈顶也是字段引用,而且该字段是值类型,需要update上层对象 - if ((ptr->Type == ValueType.FieldReference - || ptr->Type == ValueType.ChainFieldReference - || ptr->Type == ValueType.ArrayReference) && pc->Operand >= 0 - && fieldType.IsValueType) + else { - // if (pc->Operand < 0) - // { - // throwRuntimeException(new NotSupportedException( - // "chain ref for compiler generated object!"), true); - // } - //_Info("mult ref"); - //ptr->Value1:指向实际对象 - //ptr->Value2:-1表示第一个是FieldReference, -2表示是ArrayReference - //managedStack[offset]:int[],表示 + if (ptr->Value2 < 0) + { + throwRuntimeException(new NotSupportedException( + "ref of compiler generated object field ref!"), true); + } - //多层引用managedStack[ptr - evaluationStackBase] == fieldIdList - //多层引用,append - if (ptr->Type == ValueType.ChainFieldReference) + var offset = ptr - evaluationStackBase; + var fieldAddr = new FieldAddr() { - var offset = ptr - evaluationStackBase; - var fieldAddr = managedStack[offset] as FieldAddr; - var fieldIdList = fieldAddr.FieldIdList; - var newFieldIdList = new int[fieldIdList.Length + 1]; - Array.Copy(fieldIdList, newFieldIdList, fieldIdList.Length); - newFieldIdList[fieldIdList.Length] = pc->Operand; - managedStack[offset] = new FieldAddr() - { - Object = fieldAddr.Object, - FieldIdList = newFieldIdList - }; - } - else - { - if (ptr->Value2 < 0) - { - throwRuntimeException(new NotSupportedException( - "ref of compiler generated object field ref!"), true); - } - var offset = ptr - evaluationStackBase; - var fieldAddr = new FieldAddr() - { - Object = managedStack[ptr->Value1], - FieldIdList = new int[] { ptr->Value2, pc->Operand } - }; - managedStack[offset] = fieldAddr; - ptr->Value2 = ptr->Type == ValueType.FieldReference ? -1 : -2; - } - ptr->Type = ValueType.ChainFieldReference; + Object = managedStack[ptr->Value1], + FieldIdList = new int[] { ptr->Value2, pc->Operand } + }; + BoxUtils.RecycleObject(managedStack[offset]); + managedStack[offset] = fieldAddr; + ptr->Value2 = ptr->Type == ValueType.FieldReference ? -1 : -2; } - else - { - object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, pc->Operand < 0 ? typeof(AnonymousStorey) + + ptr->Type = ValueType.ChainFieldReference; + } + else + { + object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, + managedStack, pc->Operand < 0 + ? typeof(AnonymousStorey) : declaringType, this, false); - ptr->Type = ValueType.FieldReference; - ptr->Value1 = (int)(ptr - evaluationStackBase); - managedStack[ptr->Value1] = obj; - ptr->Value2 = pc->Operand; - //_Info("sigle ref type = " + obj.GetType() + ",hc=" + obj.GetHashCode() - // + ",v1=" + ptr->Value1 + ",v2=" + ptr->Value2); - } - //_Info("Ldflda fieldInfo:" + fieldInfo + ", dt:" + fieldInfo.DeclaringType - // + ", ptr->Value1:" + ptr->Value1 + ", obj info:" + (obj == null ? "null" - // : obj.GetHashCode().ToString() + "/" + managedStack[ptr->Value1] - // .GetHashCode().ToString()) - // + ", ref eq? " + ReferenceEquals(obj, managedStack[ptr->Value1])); + ptr->Type = ValueType.FieldReference; + ptr->Value1 = (int)(ptr - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[ptr->Value1]); + managedStack[ptr->Value1] = obj; + ptr->Value2 = pc->Operand; + //_Info("sigle ref type = " + obj.GetType() + ",hc=" + obj.GetHashCode() + // + ",v1=" + ptr->Value1 + ",v2=" + ptr->Value2); } + //_Info("Ldflda fieldInfo:" + fieldInfo + ", dt:" + fieldInfo.DeclaringType + // + ", ptr->Value1:" + ptr->Value1 + ", obj info:" + (obj == null ? "null" + // : obj.GetHashCode().ToString() + "/" + managedStack[ptr->Value1] + // .GetHashCode().ToString()) + // + ", ref eq? " + ReferenceEquals(obj, managedStack[ptr->Value1])); + } break; - case Code.Mul://0.2389259% + case Code.Mul: //0.2389259% + { + Value* b = evaluationStackPointer - 1; + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - *((long*)&evaluationStackPointer->Value1) - = (*((long*)&a->Value1)) * (*((long*)&b->Value1)); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 = a->Value1 * b->Value1; - break; - case ValueType.Float: - *((float*)&evaluationStackPointer->Value1) - = (*((float*)&a->Value1)) * (*((float*)&b->Value1)); - break; - case ValueType.Double: - *((double*)&evaluationStackPointer->Value1) - = (*((double*)&a->Value1)) * (*((double*)&b->Value1)); - break; - } - evaluationStackPointer++; + case ValueType.Long: + *((long*)&evaluationStackPointer->Value1) + = (*((long*)&a->Value1)) * (*((long*)&b->Value1)); + break; + case ValueType.Integer: + evaluationStackPointer->Value1 = a->Value1 * b->Value1; + break; + case ValueType.Float: + *((float*)&evaluationStackPointer->Value1) + = (*((float*)&a->Value1)) * (*((float*)&b->Value1)); + break; + case ValueType.Double: + *((double*)&evaluationStackPointer->Value1) + = (*((double*)&a->Value1)) * (*((double*)&b->Value1)); + break; } + + evaluationStackPointer++; + } break; //case Code.Conv_I: //0.2136634% Convert to native int, pushing native int on stack. case Code.Ldarga: // Ldarga_S:0.2035229% - { - *(Value**)&evaluationStackPointer->Value1 = argumentBase + pc->Operand; - evaluationStackPointer->Type = ValueType.StackReference; - evaluationStackPointer++; - } + { + *(Value**)&evaluationStackPointer->Value1 = argumentBase + pc->Operand; + evaluationStackPointer->Type = ValueType.StackReference; + evaluationStackPointer++; + } break; case Code.Conv_U: //0.1764814% Convert to unsigned native int, pushing native int on stack. + { + var ptr = evaluationStackPointer - 1; + void* val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - void* val; - switch (ptr->Type) - { - case ValueType.Long: - val = (void *)*(ulong*)&ptr->Value1; - break; - case ValueType.Integer: - val = (void*)(uint)ptr->Value1; - break; - default: - val = null; - throwRuntimeException(new NotImplementedException("Conv_U for" + ptr->Type), true); - break; - } - ptr->Type = ValueType.Long; - *(void **)&ptr->Value1 = val; + case ValueType.Long: + val = (void*)*(ulong*)&ptr->Value1; + break; + case ValueType.Integer: + val = (void*)(uint)ptr->Value1; + break; + case ValueType.StackReference: + val = (*(IntPtr*)(&ptr->Value1)).ToPointer(); + break; + default: + val = null; + throwRuntimeException(new NotImplementedException("Conv_U for" + ptr->Type), true); + break; } + + ptr->Type = ValueType.Long; + *(void**)&ptr->Value1 = val; + } break; - case Code.Starg://Starg_S:0.1551328 % - { - evaluationStackPointer--; - store(evaluationStackBase, argumentBase + pc->Operand, evaluationStackPointer, - managedStack); - managedStack[evaluationStackPointer - evaluationStackBase] = null; ; - } + case Code.Starg: //Starg_S:0.1551328 % + { + evaluationStackPointer--; + store(evaluationStackBase, argumentBase + pc->Operand, evaluationStackPointer, + managedStack); + // BoxUtils.RecycleObject(managedStack[evaluationStackPointer - evaluationStackBase]); + // managedStack[evaluationStackPointer - evaluationStackBase] = null; + } break; case Code.Ceq: //0.1549549% - { - var rhs = evaluationStackPointer - 1; - var lhs = rhs - 1; - bool eq = false; + { + var rhs = evaluationStackPointer - 1; + var lhs = rhs - 1; + bool eq = false; - if (lhs->Type == rhs->Type) + if (lhs->Type == rhs->Type) + { + if (lhs->Type == ValueType.Object || lhs->Type == ValueType.ValueType) { - if (lhs->Type == ValueType.Object || lhs->Type == ValueType.ValueType) - { - var lpos = (int)(lhs - evaluationStackBase); - var rpos = (int)(rhs - evaluationStackBase); - eq = ReferenceEquals(managedStack[lhs->Value1], managedStack[rhs->Value1]); - managedStack[lpos] = null; - managedStack[rpos] = null; - } - else - { - eq = lhs->Value1 == rhs->Value1; - if (lhs->Type != ValueType.Integer && lhs->Type != ValueType.Float) - { - eq = eq && (lhs->Value2 == rhs->Value2); - } - } + var lpos = (int)(lhs - evaluationStackBase); + var rpos = (int)(rhs - evaluationStackBase); + eq = ReferenceEquals(managedStack[lhs->Value1], managedStack[rhs->Value1]); + BoxUtils.RecycleObject(managedStack[lpos]); + managedStack[lpos] = null; + BoxUtils.RecycleObject(managedStack[rpos]); + managedStack[rpos] = null; } else { - throwRuntimeException(new InvalidProgramException("Ceq for diff type"), true); + eq = lhs->Value1 == rhs->Value1; + if (lhs->Type != ValueType.Integer && lhs->Type != ValueType.Float) + { + eq = eq && (lhs->Value2 == rhs->Value2); + } } - lhs->Type = ValueType.Integer; - lhs->Value1 = eq ? 1 : 0; - evaluationStackPointer = rhs; } + else + { + throwRuntimeException(new InvalidProgramException("Ceq for diff type"), true); + } + + lhs->Type = ValueType.Integer; + lhs->Value1 = eq ? 1 : 0; + evaluationStackPointer = rhs; + } break; case Code.Shl: //0.1362749% + { + var ptr = evaluationStackPointer - 1 - 1; + int bits = (evaluationStackPointer - 1)->Value1; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1 - 1; - int bits = (evaluationStackPointer - 1)->Value1; - switch(ptr->Type) - { - case ValueType.Integer: - ptr->Value1 = ptr->Value1 << bits; - break; - case ValueType.Long: - *((long*)&ptr->Value1) = (*((long*)&ptr->Value1)) << bits; - break; - default: - throw new InvalidProgramException("<< for " + ptr->Type); - } - evaluationStackPointer--; + case ValueType.Integer: + ptr->Value1 = ptr->Value1 << bits; + break; + case ValueType.Long: + *((long*)&ptr->Value1) = (*((long*)&ptr->Value1)) << bits; + break; + default: + throw new InvalidProgramException("<< for " + ptr->Type); } + + evaluationStackPointer--; + } break; case Code.Conv_U1: //0.1239995% + { + var ptr = evaluationStackPointer - 1; + int val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val; - switch (ptr->Type) - { - case ValueType.Long: - case ValueType.Integer: - val = (byte)ptr->Value1; - break; - case ValueType.Float: - val = (byte)*(float*)&ptr->Value1; - break; - case ValueType.Double: - val = (byte)*(double*)&ptr->Value1; - break; - default: - throw new NotImplementedException(); - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + case ValueType.Integer: + val = (byte)ptr->Value1; + break; + case ValueType.Float: + val = (byte)*(float*)&ptr->Value1; + break; + case ValueType.Double: + val = (byte)*(double*)&ptr->Value1; + break; + default: + throw new NotImplementedException(); } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Ldelema: //0.1124357% - { - var ptr = evaluationStackPointer - 1 - 1; - ptr->Type = ValueType.ArrayReference; - ptr->Value2 = (evaluationStackPointer - 1)->Value1; - evaluationStackPointer--; - } + { + var ptr = evaluationStackPointer - 1 - 1; + ptr->Type = ValueType.ArrayReference; + ptr->Value2 = (evaluationStackPointer - 1)->Value1; + evaluationStackPointer--; + } break; - case Code.Stind_Ref://0.09482315% - case Code.Stind_I1://0.06333404% - case Code.Stind_I2://0.02793102% - case Code.Stind_I4://0.1106567% - case Code.Stind_I8://0.01352075% + case Code.Stind_Ref: //0.09482315% + case Code.Stind_I1: //0.06333404% + case Code.Stind_I2: //0.02793102% + case Code.Stind_I4: //0.1106567% + case Code.Stind_I8: //0.01352075% case Code.Stind_R4: //0.001956951% case Code.Stind_R8: //0.002668569% - case Code.Stind_I://0.01031847% + case Code.Stind_I: //0.01031847% case Code.Stobj: // 0.02846474% + { + var ptr = evaluationStackPointer - 1 - 1; + var src = evaluationStackPointer - 1; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1 - 1; - var src = evaluationStackPointer - 1; - switch (ptr->Type) + case ValueType.FieldReference: + case ValueType.ChainFieldReference: { - case ValueType.FieldReference: - case ValueType.ChainFieldReference: + Type fieldType = null; + if (ptr->Type == ValueType.ChainFieldReference) + { + var fieldAddr = managedStack[ptr - evaluationStackBase] as FieldAddr; + var fieldIdList = fieldAddr.FieldIdList; + + if (fieldInfos[fieldIdList[fieldIdList.Length - 1]] == null) { - Type fieldType = null; - if (ptr->Type == ValueType.ChainFieldReference) - { - var fieldAddr = managedStack[ptr - evaluationStackBase] as FieldAddr; - var fieldIdList = fieldAddr.FieldIdList; + fieldType + = newFieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + } + else + { + fieldType + = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + } + } + else + { + if (fieldInfos[ptr->Value2] == null) + { + fieldType = newFieldInfos[ptr->Value2].FieldType; + } + else + { + fieldType = fieldInfos[ptr->Value2].FieldType; + } + } - if(fieldInfos[fieldIdList[fieldIdList.Length - 1]] == null) - { - fieldType - = newFieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; - } - else - { - fieldType - = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; - } + EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, + managedStack, EvaluationStackOperation.ToObject(evaluationStackBase, + src, managedStack, fieldType, this), this, fieldType); + //managedStack[ptr->Value1] = null; + if (src->Type >= ValueType.Object) + { + BoxUtils.RecycleObject(managedStack[src - evaluationStackBase]); + managedStack[src - evaluationStackBase] = null; + } - } - else - { - if(fieldInfos[ptr->Value2] == null) - { - fieldType = newFieldInfos[ptr->Value2].FieldType; - } - else - { - fieldType = fieldInfos[ptr->Value2].FieldType; - } - } - EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, - managedStack, EvaluationStackOperation.ToObject(evaluationStackBase, - src, managedStack, fieldType, this), this, fieldType); - //managedStack[ptr->Value1] = null; - if (src->Type >= ValueType.Object) - { - managedStack[src - evaluationStackBase] = null; - } - evaluationStackPointer = ptr; - } - break; - case ValueType.ArrayReference: + evaluationStackPointer = ptr; + } + break; + case ValueType.ArrayReference: + { + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + int idx = ptr->Value2; + arraySet(obj, idx, src, managedStack, evaluationStackBase); + if (src->Type >= ValueType.Object) + { + BoxUtils.RecycleObject(managedStack[src - evaluationStackBase]); + managedStack[src - evaluationStackBase] = null; + } + + evaluationStackPointer = ptr; + } + break; + case ValueType.StaticFieldReference: + { + var fieldIndex = ptr->Value1; + if (fieldIndex >= 0) + { + var fieldInfo = fieldInfos[fieldIndex]; + Type fieldType = null; + + if (fieldInfo == null) { - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - int idx = ptr->Value2; - arraySet(obj, idx, src, managedStack, evaluationStackBase); - if (src->Type >= ValueType.Object) - { - managedStack[src - evaluationStackBase] = null; - } - evaluationStackPointer = ptr; + fieldType = newFieldInfos[fieldIndex].FieldType; } - break; - case ValueType.StaticFieldReference: + else { - var fieldIndex = ptr->Value1; - if (fieldIndex >= 0) - { - var fieldInfo = fieldInfos[fieldIndex]; - Type fieldType = null; + fieldType = fieldInfo.FieldType; + } - if(fieldInfo == null) - { - fieldType = newFieldInfos[fieldIndex].FieldType; - } - else - { - fieldType = fieldInfo.FieldType; - } - - var val = EvaluationStackOperation.ToObject(evaluationStackBase, src, - managedStack, fieldType, this); - - if(fieldInfo == null) - { - newFieldInfos[fieldIndex].SetValue(null, val); - } - else - { - fieldInfo.SetValue(null, val); - } - } - else - { - fieldIndex = -(fieldIndex + 1); - staticFields[fieldIndex] - = EvaluationStackOperation.ToObject(evaluationStackBase, src, - managedStack, staticFieldTypes[fieldIndex], this); - } - if (src->Type >= ValueType.Object) - { - managedStack[src - evaluationStackBase] = null; - } - evaluationStackPointer = ptr; + var val = EvaluationStackOperation.ToObject(evaluationStackBase, src, + managedStack, fieldType, this); + + if (fieldInfo == null) + { + newFieldInfos[fieldIndex].SetValue(null, val); } - break; - case ValueType.StackReference: + else { - Value* des = *(Value**)&ptr->Value1; - *des = *src; - if (src->Type == ValueType.Object) - { - int offset = (int)(des - evaluationStackBase); - des->Value1 = offset; - managedStack[offset] = managedStack[src->Value1]; - managedStack[src - evaluationStackBase] = null; - } - else if (src->Type == ValueType.ValueType) - { - int offset = (int)(des - evaluationStackBase); - des->Value1 = offset; - managedStack[offset] = objectClone.Clone(managedStack[src->Value1]); - managedStack[src - evaluationStackBase] = null; - } - //Console.WriteLine("store to stack address:" + new IntPtr(des) - // + ",val type:" + src->Type + ",val1:" + src->Value1); - evaluationStackPointer = ptr; + fieldInfo.SetValue(null, val); + BoxUtils.RecycleObject(val); } - break; - default: - throwRuntimeException(new InvalidProgramException(code - + " expect ref, but got " + ptr->Type + " value1:" + ptr->Value1 + " value2:" + ptr->Value2), true); - break; + } + else + { + fieldIndex = -(fieldIndex + 1); + staticFields[fieldIndex] + = EvaluationStackOperation.ToObject(evaluationStackBase, src, + managedStack, staticFieldTypes[fieldIndex], this); + } + + if (src->Type >= ValueType.Object) + { + BoxUtils.RecycleObject(managedStack[src - evaluationStackBase]); + managedStack[src - evaluationStackBase] = null; + } + + evaluationStackPointer = ptr; + } + break; + case ValueType.StackReference: + { + Value* des = *(Value**)&ptr->Value1; + *des = *src; + if (src->Type == ValueType.Object) + { + int offset = (int)(des - evaluationStackBase); + des->Value1 = offset; + BoxUtils.RecycleObject(managedStack[offset]); + managedStack[offset] = managedStack[src->Value1]; + BoxUtils.RecycleObject(managedStack[src - evaluationStackBase]); + managedStack[src - evaluationStackBase] = null; + } + else if (src->Type == ValueType.ValueType) + { + int offset = (int)(des - evaluationStackBase); + des->Value1 = offset; + BoxUtils.RecycleObject(managedStack[offset]); + managedStack[offset] = BoxUtils.CloneObject(managedStack[src->Value1]); + BoxUtils.RecycleObject(managedStack[src - evaluationStackBase]); + managedStack[src - evaluationStackBase] = null; + } + + //Console.WriteLine("store to stack address:" + new IntPtr(des) + // + ",val type:" + src->Type + ",val1:" + src->Value1); + evaluationStackPointer = ptr; } + break; + default: + throwRuntimeException(new InvalidProgramException(code + + " expect ref, but got " + ptr->Type + " value1:" + ptr->Value1 + " value2:" + + ptr->Value2), true); + break; } + } break; case Code.Ldind_I1: //0.006226661% case Code.Ldind_U1: //0.05870852% case Code.Ldind_I2: //0.008717326% case Code.Ldind_U2: //0.04536567% - case Code.Ldind_I4: //0.106387% - case Code.Ldind_U4: //0.04981329% - case Code.Ldind_I8: //0.03042169% + case Code.Ldind_I4: //0.106387% + case Code.Ldind_U4: //0.04981329% + case Code.Ldind_I8: //0.03042169% case Code.Ldind_I: //0.02081484% case Code.Ldind_R4: //0.007294089% - case Code.Ldind_R8: //wrapper调用应先push值,然后参数取该值的地址 + case Code.Ldind_R8: //wrapper调用应先push值,然后参数取该值的地址 case Code.Ldind_Ref: //0.1070986% 操作符可以作为类型依据,不用走反射 case Code.Ldobj: //0.02348341% + { + Value* ptr = evaluationStackPointer - 1; + switch (ptr->Type) { - Value* ptr = evaluationStackPointer - 1; - switch (ptr->Type) + case ValueType.FieldReference: { - case ValueType.FieldReference: + var fieldIndex = ptr->Value2; + if (fieldIndex >= 0) + { + Type fieldType = null; + if (fieldInfos[fieldIndex] == null) { - var fieldIndex = ptr->Value2; - if (fieldIndex >= 0) - { - Type fieldType = null; - if(fieldInfos[fieldIndex] == null) - { - fieldType = newFieldInfos[fieldIndex].FieldType; - } - else - { - fieldType = fieldInfos[fieldIndex].FieldType; - } - - //var fieldInfo = fieldInfos[ptr->Value2]; - var val = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, fieldType, this, false); - //_Info("val = " + val); - EvaluationStackOperation.PushObject(evaluationStackBase, ptr, - managedStack, val, fieldType); - } - else - { - fieldIndex = -(fieldIndex + 1); - AnonymousStorey anonyObj - = managedStack[ptr->Value1] as AnonymousStorey; - anonyObj.Ldfld(fieldIndex, evaluationStackBase, ptr, managedStack); - } + fieldType = newFieldInfos[fieldIndex].FieldType; } - break; - case ValueType.ChainFieldReference: + else { - Type fieldType = null; + fieldType = fieldInfos[fieldIndex].FieldType; + } - var fieldAddr = managedStack[ptr - evaluationStackBase] as FieldAddr; - var fieldIdList = fieldAddr.FieldIdList; - if(fieldInfos[fieldIdList[fieldIdList.Length - 1]] == null) - { - fieldType = newFieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; - } - else - { - fieldType = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; - } + //var fieldInfo = fieldInfos[ptr->Value2]; + var val = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, + managedStack, fieldType, this, false); + //_Info("val = " + val); + EvaluationStackOperation.PushObject(evaluationStackBase, ptr, + managedStack, val, fieldType); + } + else + { + fieldIndex = -(fieldIndex + 1); + AnonymousStorey anonyObj + = managedStack[ptr->Value1] as AnonymousStorey; + anonyObj.Ldfld(fieldIndex, evaluationStackBase, ptr, managedStack); + } + } + break; + case ValueType.ChainFieldReference: + { + Type fieldType = null; - //var fieldInfo = fieldInfos[ptr->Value2]; - var val = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, fieldType, this, false); - EvaluationStackOperation.PushObject(evaluationStackBase, ptr, - managedStack, val, fieldType); - } - break; - case ValueType.ArrayReference: - { - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - int idx = ptr->Value2; - arrayGet(obj, idx, ptr, managedStack, evaluationStackBase); - } - break; - case ValueType.StaticFieldReference: - { - var fieldIndex = ptr->Value1; - if (fieldIndex >= 0) - { - var fieldInfo = fieldInfos[ptr->Value1]; - object value = null; - Type fieldType = null; - if(fieldInfo == null) - { - newFieldInfos[fieldIndex].CheckInit(this, null); - - fieldType = newFieldInfos[fieldIndex].FieldType; - value = newFieldInfos[fieldIndex].GetValue(null); - } - else - { - fieldType = fieldInfo.FieldType; - value = fieldInfo.GetValue(null); - } - - EvaluationStackOperation.PushObject(evaluationStackBase, ptr, - managedStack, value, fieldType); - } - else - { - fieldIndex = -(fieldIndex + 1); - EvaluationStackOperation.PushObject(evaluationStackBase, ptr, - managedStack, staticFields[fieldIndex], - staticFieldTypes[fieldIndex]); - } + var fieldAddr = managedStack[ptr - evaluationStackBase] as FieldAddr; + var fieldIdList = fieldAddr.FieldIdList; + if (fieldInfos[fieldIdList[fieldIdList.Length - 1]] == null) + { + fieldType = newFieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + } + else + { + fieldType = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + } + + //var fieldInfo = fieldInfos[ptr->Value2]; + var val = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, + managedStack, fieldType, this, false); + EvaluationStackOperation.PushObject(evaluationStackBase, ptr, + managedStack, val, fieldType); + } + break; + case ValueType.ArrayReference: + { + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + int idx = ptr->Value2; + arrayGet(obj, idx, ptr, managedStack, evaluationStackBase); + } + break; + case ValueType.StaticFieldReference: + { + var fieldIndex = ptr->Value1; + if (fieldIndex >= 0) + { + var fieldInfo = fieldInfos[ptr->Value1]; + object value = null; + Type fieldType = null; + if (fieldInfo == null) + { + newFieldInfos[fieldIndex].CheckInit(this, null); + + fieldType = newFieldInfos[fieldIndex].FieldType; + value = newFieldInfos[fieldIndex].GetValue(null); } - break; - case ValueType.StackReference: + else { - Value* src = *(Value**)&ptr->Value1; - *ptr = *src; - if (src->Type == ValueType.Object) - { - managedStack[ptr - evaluationStackBase] = managedStack[src->Value1]; - ptr->Value1 = (int)(ptr - evaluationStackBase); - } - else if (src->Type == ValueType.ValueType) - { - managedStack[ptr - evaluationStackBase] - = objectClone.Clone(managedStack[src->Value1]); - ptr->Value1 = (int)(ptr - evaluationStackBase); - } + fieldType = fieldInfo.FieldType; + value = EvaluationStackOperation.GetStaticValueFromeCache(fieldInfo); } - break; - default: - throwRuntimeException(new InvalidProgramException(code - + " expect ref, but got " + ptr->Type + " value1:" + ptr->Value1 + " value2:" + ptr->Value2), true); - break; + + EvaluationStackOperation.PushObject(evaluationStackBase, ptr, + managedStack, value, fieldType); + } + else + { + fieldIndex = -(fieldIndex + 1); + EvaluationStackOperation.PushObject(evaluationStackBase, ptr, + managedStack, staticFields[fieldIndex], + staticFieldTypes[fieldIndex]); + } + } + break; + case ValueType.StackReference: + { + Value* src = *(Value**)&ptr->Value1; + *ptr = *src; + if (src->Type == ValueType.Object || src->Type == ValueType.ValueType) + { + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = managedStack[src->Value1]; + ptr->Value1 = (int)(ptr - evaluationStackBase); + } + // else if (src->Type == ValueType.ValueType) + // { + // BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + // managedStack[ptr - evaluationStackBase] + // = BoxUtils.CloneObject(managedStack[src->Value1]); + // ptr->Value1 = (int)(ptr - evaluationStackBase); + // } } + break; + default: + throwRuntimeException(new InvalidProgramException(code + + " expect ref, but got " + ptr->Type + " value1:" + ptr->Value1 + " value2:" + + ptr->Value2), true); + break; } + } break; case Code.Bgt: //Bgt_S:0.1104788% Bgt:0.01103009% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = a->Value1 > b->Value1; - break; - case ValueType.Long: - transfer = *(long*)&a->Value1 > *(long*)&b->Value1; - break; - case ValueType.Float: - transfer = *(float*)&a->Value1 > *(float*)&b->Value1; - break; - case ValueType.Double: - transfer = *(double*)&a->Value1 > *(double*)&b->Value1; - break; - default: - throw new InvalidProgramException("Bgt for " + evaluationStackPointer->Type); - } + case ValueType.Integer: + transfer = a->Value1 > b->Value1; + break; + case ValueType.Long: + transfer = *(long*)&a->Value1 > *(long*)&b->Value1; + break; + case ValueType.Float: + transfer = *(float*)&a->Value1 > *(float*)&b->Value1; + break; + case ValueType.Double: + transfer = *(double*)&a->Value1 > *(double*)&b->Value1; + break; + default: + throw new InvalidProgramException("Bgt for " + evaluationStackPointer->Type); + } - if (transfer) - { - pc += pc->Operand; - continue; - } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Initobj: //0.1085218% + { + var ptr = evaluationStackPointer - 1; + var type = externTypes[pc->Operand]; + EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, managedStack, + BoxUtils.CreateDefaultBoxValue(type), this, type); + if (ptr->Type >= ValueType.Object) { - var ptr = evaluationStackPointer - 1; - var type = externTypes[pc->Operand]; - EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, managedStack, - Activator.CreateInstance(type), this, type); - if (ptr->Type >= ValueType.Object) - { - managedStack[ptr - evaluationStackBase] = null; - } - evaluationStackPointer = ptr; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; } + + evaluationStackPointer = ptr; + } break; case Code.Shr_Un: //0.09589058% + { + var ptr = evaluationStackPointer - 1 - 1; + int bits = (evaluationStackPointer - 1)->Value1; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1 - 1; - int bits = (evaluationStackPointer - 1)->Value1; - switch (ptr->Type) - { - case ValueType.Integer: - ptr->Value1 = (int)(((uint)ptr->Value1) >> bits); - break; - case ValueType.Long: - *((ulong*)&ptr->Value1) = (*((ulong*)&ptr->Value1)) >> bits; - break; - default: - throw new InvalidProgramException(">> for " + ptr->Type); - } - evaluationStackPointer--; + case ValueType.Integer: + ptr->Value1 = (int)(((uint)ptr->Value1) >> bits); + break; + case ValueType.Long: + *((ulong*)&ptr->Value1) = (*((ulong*)&ptr->Value1)) >> bits; + break; + default: + throw new InvalidProgramException(">> for " + ptr->Type); } + + evaluationStackPointer--; + } break; case Code.Stelem_I1: //0.09019764% + { + var val = (evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + byte[] byteArr = obj as byte[]; + if (byteArr != null) { - var val = (evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - byte[] byteArr = obj as byte[]; - if (byteArr != null) - { - byteArr[idx] = (byte)val; - break; - } - bool[] boolArr = obj as bool[]; - if (boolArr != null) - { - boolArr[idx] = val != 0; - break; - } - sbyte[] sbyteArr = obj as sbyte[]; - if (sbyteArr != null) - { - sbyteArr[idx] = (sbyte)val; - } + byteArr[idx] = (byte)val; + break; + } + + bool[] boolArr = obj as bool[]; + if (boolArr != null) + { + boolArr[idx] = val != 0; + break; + } + + sbyte[] sbyteArr = obj as sbyte[]; + if (sbyteArr != null) + { + sbyteArr[idx] = (sbyte)val; } + } break; //为什么有Ldelem_U1而没有Stelem_U1?因为load后push到es后,会扩展到int32,同样是0xff, //作为有符号或无符号扩展是不一样的,一句话,高位扩展要考虑符号位,截取低位不需要 case Code.Ldelem_U1: //0.08557212% + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Integer; + byte[] byteArr = obj as byte[]; + if (byteArr != null) { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Integer; - byte[] byteArr = obj as byte[]; - if (byteArr != null) - { - ptr->Value1 = byteArr[idx]; - break; - } - bool[] boolArr = obj as bool[]; - if (boolArr != null) - { - ptr->Value1 = boolArr[idx] ? 1 : 0; - } + ptr->Value1 = byteArr[idx]; + break; + } + + bool[] boolArr = obj as bool[]; + if (boolArr != null) + { + ptr->Value1 = boolArr[idx] ? 1 : 0; } + } break; //hacker: mscorlib,Unbox指令只有6条,均是这样形式的语句产生的:((SomeValueType)obj).field, //所以Unbox按Unbox_Any处理,只要ldfld能处理即可 case Code.Unbox: - case Code.Unbox_Any://0.0848605% + case Code.Unbox_Any: //0.0848605% + { + var ptr = evaluationStackPointer - 1; + if (pc->Operand >= 0) { - var ptr = evaluationStackPointer - 1; - if(pc->Operand >= 0) + var type = externTypes[pc->Operand]; + //var pos = (int)(ptr - evaluationStackBase); + var obj = managedStack[ptr->Value1]; + if (ptr->Type == ValueType.Object) { - var type = externTypes[pc->Operand]; - //var pos = (int)(ptr - evaluationStackBase); - var obj = managedStack[ptr->Value1]; - if (ptr->Type == ValueType.Object) + if (BoxUtils.GetTypeIsValueType(type)) { - if (type.IsValueType) + if (obj == null) { - if (obj == null) - { - throw new NullReferenceException(); - } - else if(type.IsPrimitive) - { - EvaluationStackOperation.UnboxPrimitive(ptr, obj, type); - } - else if(type.IsEnum) - { - EvaluationStackOperation.UnboxPrimitive(ptr, obj, Enum.GetUnderlyingType(type)); - } - else - { - ptr->Type = ValueType.ValueType; - } + throw new NullReferenceException(); + } + else if (BoxUtils.GetTypeIsValueType(type)) + { + EvaluationStackOperation.UnboxPrimitive(ptr, obj, type); + } + else if (BoxUtils.GetTypeIsEnum(type)) + { + EvaluationStackOperation.UnboxPrimitive(ptr, obj, + Enum.GetUnderlyingType(type)); } - //泛型函数是有可能Unbox_Any一个非值类型的 - else if (obj != null && !type.IsAssignableFrom(obj.GetType())) + else { - throw new InvalidCastException(); + ptr->Type = ValueType.ValueType; } } + //泛型函数是有可能Unbox_Any一个非值类型的 + else if (obj != null && !type.IsAssignableFrom(obj.GetType())) + { + throw new InvalidCastException(); + } } } + } break; case Code.Div: //0.0693828% + { + Value* b = evaluationStackPointer - 1; + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - *((long*)&evaluationStackPointer->Value1) - = (*((long*)&a->Value1)) / (*((long*)&b->Value1)); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 = a->Value1 / b->Value1; - break; - case ValueType.Float: - *((float*)&evaluationStackPointer->Value1) - = (*((float*)&a->Value1)) / (*((float*)&b->Value1)); - break; - case ValueType.Double: - *((double*)&evaluationStackPointer->Value1) - = (*((double*)&a->Value1)) / (*((double*)&b->Value1)); - break; - } - evaluationStackPointer++; + case ValueType.Long: + *((long*)&evaluationStackPointer->Value1) + = (*((long*)&a->Value1)) / (*((long*)&b->Value1)); + break; + case ValueType.Integer: + evaluationStackPointer->Value1 = a->Value1 / b->Value1; + break; + case ValueType.Float: + *((float*)&evaluationStackPointer->Value1) + = (*((float*)&a->Value1)) / (*((float*)&b->Value1)); + break; + case ValueType.Double: + *((double*)&evaluationStackPointer->Value1) + = (*((double*)&a->Value1)) / (*((double*)&b->Value1)); + break; } + + evaluationStackPointer++; + } break; case Code.Cgt_Un: //0.06724794% - { - Value* rhs = evaluationStackPointer - 1; - Value* lhs = rhs - 1; + { + Value* rhs = evaluationStackPointer - 1; + Value* lhs = rhs - 1; - bool res = false; - switch (lhs->Type) - { - case ValueType.Integer: - res = (uint)lhs->Value1 > (uint)rhs->Value1; - break; - case ValueType.Long: - res = *(ulong*)&lhs->Value1 > *(ulong*)&rhs->Value1; - break; - case ValueType.Float: - res = !(*(float*)&lhs->Value1 <= *(float*)&rhs->Value1); - break; - case ValueType.Double: - res = !(*(double*)&lhs->Value1 <= *(double*)&rhs->Value1); - break; - case ValueType.Object: - case ValueType.ValueType: - res = managedStack[lhs->Value1] != null && managedStack[rhs->Value1] == null; - break; - } - lhs->Type = ValueType.Integer; - lhs->Value1 = res ? 1 : 0; - evaluationStackPointer = rhs; + bool res = false; + switch (lhs->Type) + { + case ValueType.Integer: + res = (uint)lhs->Value1 > (uint)rhs->Value1; + break; + case ValueType.Long: + res = *(ulong*)&lhs->Value1 > *(ulong*)&rhs->Value1; + break; + case ValueType.Float: + res = !(*(float*)&lhs->Value1 <= *(float*)&rhs->Value1); + break; + case ValueType.Double: + res = !(*(double*)&lhs->Value1 <= *(double*)&rhs->Value1); + break; + case ValueType.Object: + case ValueType.ValueType: + res = managedStack[lhs->Value1] != null && managedStack[rhs->Value1] == null; + break; } + + lhs->Type = ValueType.Integer; + lhs->Value1 = res ? 1 : 0; + evaluationStackPointer = rhs; + } break; case Code.Ldelem_I4: //0.05853061% - { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var arr = managedStack[ptr->Value1] as int[]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Integer; - ptr->Value1 = arr[idx]; - } + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var arr = managedStack[ptr->Value1] as int[]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Integer; + ptr->Value1 = arr[idx]; + } break; case Code.Ldelem_Any: //0.05657366% - { - var arrPtr = evaluationStackPointer - 1 - 1; - int idx = (evaluationStackPointer - 1)->Value1; - var arr = managedStack[arrPtr->Value1] as Array; - EvaluationStackOperation.PushObject(evaluationStackBase, arrPtr, managedStack, - arr.GetValue(idx), arr.GetType().GetElementType()); - evaluationStackPointer = evaluationStackPointer - 1; - } + { + var arrPtr = evaluationStackPointer - 1 - 1; + int idx = (evaluationStackPointer - 1)->Value1; + var arr = managedStack[arrPtr->Value1] as Array; + EvaluationStackOperation.PushObject(evaluationStackBase, arrPtr, managedStack, + arr.GetValue(idx), arr.GetType().GetElementType()); + evaluationStackPointer = evaluationStackPointer - 1; + } break; case Code.Ldc_R8: //0.05088072% - { - *(double*)&evaluationStackPointer->Value1 = *(double*)(pc + 1); - evaluationStackPointer->Type = ValueType.Double; - evaluationStackPointer++; - pc++; - } + { + *(double*)&evaluationStackPointer->Value1 = *(double*)(pc + 1); + evaluationStackPointer->Type = ValueType.Double; + evaluationStackPointer++; + pc++; + } break; case Code.Stelem_I4: //0.05052491% + { + var val = (evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + int[] intArr = obj as int[]; + if (intArr != null) { - var val = (evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - int[] intArr = obj as int[]; - if (intArr != null) - { - intArr[idx] = val; - break; - } - uint[] uintArr = obj as uint[]; - if (uintArr != null) - { - uintArr[idx] = (uint)val; - } + intArr[idx] = val; + break; + } + + uint[] uintArr = obj as uint[]; + if (uintArr != null) + { + uintArr[idx] = (uint)val; } + } break; case Code.Conv_U8: //0.04839005% + { + var obj = evaluationStackPointer - 1; + ulong val; + switch (obj->Type) { - var obj = evaluationStackPointer - 1; - ulong val; - switch (obj->Type) - { - case ValueType.Integer: - val = *(uint*)&obj->Value1;//Conv_U8的操作数肯定是uint - break; - case ValueType.Long: - pc++; - continue; - case ValueType.Float: - val = (ulong)*(float*)&obj->Value1; - break; - case ValueType.Double: - val = (ulong)*(double*)&obj->Value1; - break; - default: - val = 0; - throwRuntimeException(new NotImplementedException(), true); - break; - } - obj->Type = ValueType.Long; - *(ulong*)(&obj->Value1) = val; + case ValueType.Integer: + val = *(uint*)&obj->Value1; //Conv_U8的操作数肯定是uint + break; + case ValueType.Long: + pc++; + continue; + case ValueType.Float: + val = (ulong)*(float*)&obj->Value1; + break; + case ValueType.Double: + val = (ulong)*(double*)&obj->Value1; + break; + default: + val = 0; + throwRuntimeException(new NotImplementedException(), true); + break; } + + obj->Type = ValueType.Long; + *(ulong*)(&obj->Value1) = val; + } break; case Code.Rem: //0.04714472% - { - Value* rhs = evaluationStackPointer - 1; - Value* lhs = rhs - 1; - - switch (lhs->Type) - { - case ValueType.Integer: - lhs->Value1 = lhs->Value1 % rhs->Value1; - break; - case ValueType.Long: - *(long*)&lhs->Value1 = *(long*)&lhs->Value1 % *(long*)&rhs->Value1; - break; - case ValueType.Float: - *(float*)&lhs->Value1 = *(float*)&lhs->Value1 % *(float*)&rhs->Value1; - break; - case ValueType.Double: - *(double*)&lhs->Value1 = *(double*)&lhs->Value1 % *(double*)&rhs->Value1; - break; - } + { + Value* rhs = evaluationStackPointer - 1; + Value* lhs = rhs - 1; - evaluationStackPointer = rhs; - } - break; - case Code.Constrained://0.04714472% + switch (lhs->Type) { - var lastInstruction = pc - 1; - var type = externTypes[pc->Operand]; - var ptr = evaluationStackPointer - 1 - lastInstruction->Operand; - var obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, managedStack, type, this); - var pos = (int)(ptr - evaluationStackBase); - managedStack[pos] = obj; - ptr->Value1 = pos; - ptr->Type = ValueType.Object; + case ValueType.Integer: + lhs->Value1 = lhs->Value1 % rhs->Value1; + break; + case ValueType.Long: + *(long*)&lhs->Value1 = *(long*)&lhs->Value1 % *(long*)&rhs->Value1; + break; + case ValueType.Float: + *(float*)&lhs->Value1 = *(float*)&lhs->Value1 % *(float*)&rhs->Value1; + break; + case ValueType.Double: + *(double*)&lhs->Value1 = *(double*)&lhs->Value1 % *(double*)&rhs->Value1; + break; } - break; - case Code.Switch://0.04518777% + + evaluationStackPointer = rhs; + } + break; + case Code.Constrained: //0.04714472% + { + var lastInstruction = pc - 1; + var type = externTypes[pc->Operand]; + var ptr = evaluationStackPointer - 1 - lastInstruction->Operand; + var obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, managedStack, type, + this); + var pos = (int)(ptr - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[pos]); + managedStack[pos] = obj; + ptr->Value1 = pos; + ptr->Type = ValueType.Object; + } + break; + case Code.Switch: //0.04518777% + { + int val = (evaluationStackPointer - 1)->Value1; + if (val >= 0 && val < pc->Operand) { - int val = (evaluationStackPointer - 1)->Value1; - if (val >= 0 && val < pc->Operand) - { - int* jmpTable = (int*)(pc + 1); - //Console.WriteLine("val:" + val + ", jmp to:" + jmpTable[val]); - pc += jmpTable[val]; - } - else - { - pc += ((pc->Operand + 1) >> 1) + 1; - } - continue; + int* jmpTable = (int*)(pc + 1); + //Console.WriteLine("val:" + val + ", jmp to:" + jmpTable[val]); + pc += jmpTable[val]; } - case Code.Ldc_I8: //0.04429825% + else { - *(long*)&evaluationStackPointer->Value1 = *(long*)(pc + 1); - evaluationStackPointer->Type = ValueType.Long; - evaluationStackPointer++; - pc++; + pc += ((pc->Operand + 1) >> 1) + 1; } + + continue; + } + case Code.Ldc_I8: //0.04429825% + { + *(long*)&evaluationStackPointer->Value1 = *(long*)(pc + 1); + evaluationStackPointer->Type = ValueType.Long; + evaluationStackPointer++; + pc++; + } break; //case Code.Sizeof: //0.04412034% 用于指针,不支持 case Code.Xor: //0.03842739% + { + var rhs = evaluationStackPointer - 1; + var lhs = rhs - 1; + switch (lhs->Type) { - var rhs = evaluationStackPointer - 1; - var lhs = rhs - 1; - switch (lhs->Type) - { - case ValueType.Long: - *((long*)&lhs->Value1) = *((long*)&lhs->Value1) ^ *((long*)&rhs->Value1); - break; - case ValueType.Integer: - lhs->Value1 = lhs->Value1 ^ rhs->Value1; - break; - } - evaluationStackPointer = rhs; + case ValueType.Long: + *((long*)&lhs->Value1) = *((long*)&lhs->Value1) ^ *((long*)&rhs->Value1); + break; + case ValueType.Integer: + lhs->Value1 = lhs->Value1 ^ rhs->Value1; + break; } + + evaluationStackPointer = rhs; + } break; case Code.Ldftn: //0.03682625% - { - evaluationStackPointer->Type = ValueType.Object; - evaluationStackPointer->Value1 = (int)(evaluationStackPointer - evaluationStackBase); - managedStack[evaluationStackPointer->Value1] = externMethods[pc->Operand]; - evaluationStackPointer++; - } + { + evaluationStackPointer->Type = ValueType.Object; + evaluationStackPointer->Value1 = (int)(evaluationStackPointer - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[evaluationStackPointer->Value1]); + managedStack[evaluationStackPointer->Value1] = externMethods[pc->Operand]; + evaluationStackPointer++; + } break; case Code.Newanon: - { - - var anonymousStoreyInfo = anonymousStoreyInfos[pc->Operand]; - //_Info(anonymousStoreyInfo.Slots == null ? "raw" : "object with interfaces"); - var pn = anonymousStoreyInfo.CtorParamNum; - //_Info("param count:" + pn + ", ctor id:" + anonymousStoreyInfo.CtorId); - AnonymousStorey anonymousStorey = (anonymousStoreyInfo.Slots == null) - ? new AnonymousStorey(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, pc->Operand, anonymousStoreyInfo.VTable, this) - : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, pc->Operand, anonymousStoreyInfo.VTable, + { + var anonymousStoreyInfo = anonymousStoreyInfos[pc->Operand]; + //_Info(anonymousStoreyInfo.Slots == null ? "raw" : "object with interfaces"); + var pn = anonymousStoreyInfo.CtorParamNum; + //_Info("param count:" + pn + ", ctor id:" + anonymousStoreyInfo.CtorId); + AnonymousStorey anonymousStorey = (anonymousStoreyInfo.Slots == null) + ? new AnonymousStorey(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, + pc->Operand, anonymousStoreyInfo.VTable, this) + : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, + anonymousStoreyInfo.FieldTypes, pc->Operand, anonymousStoreyInfo.VTable, anonymousStoreyInfo.Slots, this); - var pos = evaluationStackPointer; - for (int p = 0; p < pn; p++) + var pos = evaluationStackPointer; + for (int p = 0; p < pn; p++) + { + //var src = pos - 1; + //_Info("src t:" + src->Type + ",v:" + src->Value1); + copy(evaluationStackBase, pos, pos - 1, managedStack); + if (pos->Type >= ValueType.Object && pos->Type != ValueType.ValueType) { - //var src = pos - 1; - //_Info("src t:" + src->Type + ",v:" + src->Value1); - copy(evaluationStackBase, pos, pos - 1, managedStack); - if (pos->Type >= ValueType.Object && pos->Type != ValueType.ValueType) - { - var src = pos - 1; - pos->Value1 = (int)(pos - evaluationStackBase); - managedStack[pos->Value1] = managedStack[src->Value1]; - } - //_Info("des t:" + pos->Type + ",v:" + pos->Value1); - pos = pos - 1; + var src = pos - 1; + pos->Value1 = (int)(pos - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[pos->Value1]); + managedStack[pos->Value1] = managedStack[src->Value1]; } - pos->Type = ValueType.Object; - pos->Value1 = (int)(pos - evaluationStackBase); - //for (int p = 0; p < pn + 1; p++) - //{ - // var dsp = pos + p; - //_Info("p " + p + ":" + dsp->Type + ",v:" + dsp->Value1); - //} - managedStack[pos->Value1] = anonymousStorey; - Execute(unmanagedCodes[anonymousStoreyInfo.CtorId], pos, managedStack, - evaluationStackBase, pn + 1, anonymousStoreyInfo.CtorId); - pos->Type = ValueType.Object; - pos->Value1 = (int)(pos - evaluationStackBase); - managedStack[pos->Value1] = anonymousStorey; - evaluationStackPointer = pos + 1; + + //_Info("des t:" + pos->Type + ",v:" + pos->Value1); + pos = pos - 1; } + + pos->Type = ValueType.Object; + pos->Value1 = (int)(pos - evaluationStackBase); + //for (int p = 0; p < pn + 1; p++) + //{ + // var dsp = pos + p; + //_Info("p " + p + ":" + dsp->Type + ",v:" + dsp->Value1); + //} + BoxUtils.RecycleObject(managedStack[pos->Value1]); + managedStack[pos->Value1] = anonymousStorey; + Execute(unmanagedCodes[anonymousStoreyInfo.CtorId], pos, managedStack, + evaluationStackBase, pn + 1, anonymousStoreyInfo.CtorId); + pos->Type = ValueType.Object; + pos->Value1 = (int)(pos - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[pos->Value1]); + managedStack[pos->Value1] = anonymousStorey; + evaluationStackPointer = pos + 1; + } break; case Code.Stelem_Any: //0.03166702% - { - var arrPtr = evaluationStackPointer - 1 - 1 - 1; - int idx = (evaluationStackPointer - 1 - 1)->Value1; - var valPtr = evaluationStackPointer - 1; - var arr = managedStack[arrPtr->Value1] as Array; - var val = EvaluationStackOperation.ToObject(evaluationStackBase, valPtr, - managedStack, arr.GetType().GetElementType(), this, false); - arr.SetValue(val, idx); - managedStack[arrPtr - evaluationStackBase] = null; //清理,如果有的话 - managedStack[valPtr - evaluationStackBase] = null; - evaluationStackPointer = arrPtr; - } + { + var arrPtr = evaluationStackPointer - 1 - 1 - 1; + int idx = (evaluationStackPointer - 1 - 1)->Value1; + var valPtr = evaluationStackPointer - 1; + var arr = managedStack[arrPtr->Value1] as Array; + var val = EvaluationStackOperation.ToObject(evaluationStackBase, valPtr, + managedStack, arr.GetType().GetElementType(), this, false); + arr.SetValue(val, idx); + BoxUtils.RecycleObject(managedStack[arrPtr - evaluationStackBase]); + managedStack[arrPtr - evaluationStackBase] = null; //清理,如果有的话 + BoxUtils.RecycleObject(managedStack[valPtr - evaluationStackBase]); + managedStack[valPtr - evaluationStackBase] = null; + evaluationStackPointer = arrPtr; + } break; case Code.Conv_U2: //0.02917635% + { + var obj = evaluationStackPointer - 1; + ushort val = 0; + switch (obj->Type) { - var obj = evaluationStackPointer - 1; - ushort val = 0; - switch (obj->Type) - { - case ValueType.Long: - case ValueType.Integer: - val = (ushort)obj->Value1; - break; - case ValueType.Float: - val = (ushort)*(float*)&obj->Value1; - break; - case ValueType.Double: - val = (ushort)*(double*)&obj->Value1; - break; - } - obj->Type = ValueType.Integer; - obj->Value1 = val; + case ValueType.Long: + case ValueType.Integer: + val = (ushort)obj->Value1; + break; + case ValueType.Float: + val = (ushort)*(float*)&obj->Value1; + break; + case ValueType.Double: + val = (ushort)*(double*)&obj->Value1; + break; } + + obj->Type = ValueType.Integer; + obj->Value1 = val; + } break; case Code.Ldsflda: //0.02632988% + { + if (pc->Operand < 0) { - if (pc->Operand < 0) - { - var fieldIndex = -(pc->Operand + 1); - checkCctorExecute(fieldIndex, evaluationStackPointer, managedStack, - evaluationStackBase); - } - evaluationStackPointer->Type = ValueType.StaticFieldReference; - evaluationStackPointer->Value1 = pc->Operand; - evaluationStackPointer++; + var fieldIndex = -(pc->Operand + 1); + checkCctorExecute(fieldIndex, evaluationStackPointer, managedStack, + evaluationStackBase); } + + evaluationStackPointer->Type = ValueType.StaticFieldReference; + evaluationStackPointer->Value1 = pc->Operand; + evaluationStackPointer++; + } break; case Code.Stelem_I2: //0.02117065% + { + var val = (evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + short[] shortArr = obj as short[]; + if (shortArr != null) { - var val = (evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - short[] shortArr = obj as short[]; - if (shortArr != null) - { - shortArr[idx] = (short)val; - break; - } - ushort[] ushortArr = obj as ushort[]; - if (ushortArr != null) - { - ushortArr[idx] = (ushort)val; - break; - } - char[] charArr = obj as char[]; - if (charArr != null) - { - charArr[idx] = (char)val; - } + shortArr[idx] = (short)val; + break; } + + ushort[] ushortArr = obj as ushort[]; + if (ushortArr != null) + { + ushortArr[idx] = (ushort)val; + break; + } + + char[] charArr = obj as char[]; + if (charArr != null) + { + charArr[idx] = (char)val; + } + } break; case Code.Blt_Un: //0.02010322% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = (uint)a->Value1 < (uint)b->Value1; - break; - case ValueType.Long: - transfer = *(ulong*)&a->Value1 < *(ulong*)&b->Value1; - break; - case ValueType.Float: - transfer = !(*(float*)&a->Value1 >= *(float*)&b->Value1); - break; - case ValueType.Double: - transfer = !(*(double*)&a->Value1 >= *(double*)&b->Value1); - break; - } + case ValueType.Integer: + transfer = (uint)a->Value1 < (uint)b->Value1; + break; + case ValueType.Long: + transfer = *(ulong*)&a->Value1 < *(ulong*)&b->Value1; + break; + case ValueType.Float: + transfer = !(*(float*)&a->Value1 >= *(float*)&b->Value1); + break; + case ValueType.Double: + transfer = !(*(double*)&a->Value1 >= *(double*)&b->Value1); + break; + } - if (transfer) - { - pc += pc->Operand; - continue; - } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Ble_Un: //Ble_Un_S:0.01725675% Ble_Un:0.0003558092% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = (uint)a->Value1 <= (uint)b->Value1; - break; - case ValueType.Long: - transfer = *(ulong*)&a->Value1 <= *(ulong*)&b->Value1; - break; - case ValueType.Float: - transfer = !(*(float*)&a->Value1 > *(float*)&b->Value1); - break; - case ValueType.Double: - transfer = !(*(double*)&a->Value1 > *(double*)&b->Value1); - break; - } + case ValueType.Integer: + transfer = (uint)a->Value1 <= (uint)b->Value1; + break; + case ValueType.Long: + transfer = *(ulong*)&a->Value1 <= *(ulong*)&b->Value1; + break; + case ValueType.Float: + transfer = !(*(float*)&a->Value1 > *(float*)&b->Value1); + break; + case ValueType.Double: + transfer = !(*(double*)&a->Value1 > *(double*)&b->Value1); + break; + } - if (transfer) - { - pc += pc->Operand; - continue; - } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Ldelem_U2: //0.01690094% + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Integer; + ushort[] ushortArr = obj as ushort[]; + if (ushortArr != null) { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Integer; - ushort[] ushortArr = obj as ushort[]; - if (ushortArr != null) - { - ptr->Value1 = ushortArr[idx]; - break; - } - char[] charArr = obj as char[]; - if (charArr != null) - { - ptr->Value1 = charArr[idx]; - } + ptr->Value1 = ushortArr[idx]; + break; } + + char[] charArr = obj as char[]; + if (charArr != null) + { + ptr->Value1 = charArr[idx]; + } + } break; case Code.Conv_R8: //0.01654513% + { + var ptr = evaluationStackPointer - 1; + double val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - double val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = *(long*)&ptr->Value1; - break; - case ValueType.Float: - val = *(float*)&ptr->Value1; - break; - case ValueType.Integer: - val = ptr->Value1; - break; - case ValueType.Double: - pc++; - continue; - } - ptr->Type = ValueType.Double; - *(double*)&ptr->Value1 = val; + case ValueType.Long: + val = *(long*)&ptr->Value1; + break; + case ValueType.Float: + val = *(float*)&ptr->Value1; + break; + case ValueType.Integer: + val = ptr->Value1; + break; + case ValueType.Double: + pc++; + continue; } + + ptr->Type = ValueType.Double; + *(double*)&ptr->Value1 = val; + } break; case Code.Conv_I2: //0.0154777% + { + var ptr = evaluationStackPointer - 1; + int val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = (short)*(long*)&ptr->Value1; - break; - case ValueType.Float: - val = (short)*(float*)&ptr->Value1; - break; - case ValueType.Double: - val = (short)*(double*)&ptr->Value1; - break; - case ValueType.Integer: - val = (short)ptr->Value1; - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + val = (short)*(long*)&ptr->Value1; + break; + case ValueType.Float: + val = (short)*(float*)&ptr->Value1; + break; + case ValueType.Double: + val = (short)*(double*)&ptr->Value1; + break; + case ValueType.Integer: + val = (short)ptr->Value1; + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Bgt_Un: //0.01476608% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = (uint)a->Value1 > (uint)b->Value1; - break; - case ValueType.Long: - transfer = *(ulong*)&a->Value1 > *(ulong*)&b->Value1; - break; - case ValueType.Float: - transfer = !(*(float*)&a->Value1 <= *(float*)&b->Value1); - break; - case ValueType.Double: - transfer = !(*(double*)&a->Value1 <= *(double*)&b->Value1); - break; - } + case ValueType.Integer: + transfer = (uint)a->Value1 > (uint)b->Value1; + break; + case ValueType.Long: + transfer = *(ulong*)&a->Value1 > *(ulong*)&b->Value1; + break; + case ValueType.Float: + transfer = !(*(float*)&a->Value1 <= *(float*)&b->Value1); + break; + case ValueType.Double: + transfer = !(*(double*)&a->Value1 <= *(double*)&b->Value1); + break; + } - if (transfer) - { - pc += pc->Operand; - continue; - } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Mul_Ovf_Un: //0.01458818% + { + Value* b = evaluationStackPointer - 1; + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - *((ulong*)&evaluationStackPointer->Value1) - = checked((*((ulong*)&a->Value1)) * (*((ulong*)&b->Value1))); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 - = (int)checked((uint)a->Value1 * (uint)b->Value1); - break; - } - evaluationStackPointer++; + case ValueType.Long: + *((ulong*)&evaluationStackPointer->Value1) + = checked((*((ulong*)&a->Value1)) * (*((ulong*)&b->Value1))); + break; + case ValueType.Integer: + evaluationStackPointer->Value1 + = (int)checked((uint)a->Value1 * (uint)b->Value1); + break; } + + evaluationStackPointer++; + } break; //Localloc 0.01441027% no support case Code.Bge_Un: //0.01405446% + { + var b = evaluationStackPointer - 1; + var a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + bool transfer = false; + switch (evaluationStackPointer->Type) { - var b = evaluationStackPointer - 1; - var a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - bool transfer = false; - switch (evaluationStackPointer->Type) - { - case ValueType.Integer: - transfer = (uint)a->Value1 >= (uint)b->Value1; - break; - case ValueType.Long: - transfer = *(ulong*)&a->Value1 >= *(ulong*)&b->Value1; - break; - case ValueType.Float: - transfer = !(*(float*)&a->Value1 < *(float*)&b->Value1); - break; - case ValueType.Double: - transfer = !(*(double*)&a->Value1 < *(double*)&b->Value1); - break; - } - - if (transfer) - { - pc += pc->Operand; - continue; - } + case ValueType.Integer: + transfer = (uint)a->Value1 >= (uint)b->Value1; + break; + case ValueType.Long: + transfer = *(ulong*)&a->Value1 >= *(ulong*)&b->Value1; + break; + case ValueType.Float: + transfer = !(*(float*)&a->Value1 < *(float*)&b->Value1); + break; + case ValueType.Double: + transfer = !(*(double*)&a->Value1 < *(double*)&b->Value1); + break; + } + if (transfer) + { + pc += pc->Operand; + continue; } + } break; case Code.Clt: //0.01405446% + { + Value* rhs = evaluationStackPointer - 1; + Value* lhs = rhs - 1; + + bool res = false; + switch (lhs->Type) { - Value* rhs = evaluationStackPointer - 1; - Value* lhs = rhs - 1; - - bool res = false; - switch (lhs->Type) - { - case ValueType.Integer: - res = lhs->Value1 < rhs->Value1; - break; - case ValueType.Long: - res = *(long*)&lhs->Value1 < *(long*)&rhs->Value1; - break; - case ValueType.Float: - res = *(float*)&lhs->Value1 < *(float*)&rhs->Value1; - break; - case ValueType.Double: - res = *(double*)&lhs->Value1 < *(double*)&rhs->Value1; - break; - } - lhs->Type = ValueType.Integer; - lhs->Value1 = res ? 1 : 0; - evaluationStackPointer = rhs; + case ValueType.Integer: + res = lhs->Value1 < rhs->Value1; + break; + case ValueType.Long: + res = *(long*)&lhs->Value1 < *(long*)&rhs->Value1; + break; + case ValueType.Float: + res = *(float*)&lhs->Value1 < *(float*)&rhs->Value1; + break; + case ValueType.Double: + res = *(double*)&lhs->Value1 < *(double*)&rhs->Value1; + break; } + + lhs->Type = ValueType.Integer; + lhs->Value1 = res ? 1 : 0; + evaluationStackPointer = rhs; + } break; case Code.Cgt: //0.01387656% - { - Value* rhs = evaluationStackPointer - 1; - Value* lhs = rhs - 1; + { + Value* rhs = evaluationStackPointer - 1; + Value* lhs = rhs - 1; - bool res = false; - switch (lhs->Type) - { - case ValueType.Integer: - res = lhs->Value1 > rhs->Value1; - break; - case ValueType.Long: - res = *(long*)&lhs->Value1 > *(long*)&rhs->Value1; - break; - case ValueType.Float: - res = *(float*)&lhs->Value1 > *(float*)&rhs->Value1; - break; - case ValueType.Double: - res = *(double*)&lhs->Value1 > *(double*)&rhs->Value1; - break; - } - lhs->Type = ValueType.Integer; - lhs->Value1 = res ? 1 : 0; - evaluationStackPointer = rhs; + bool res = false; + switch (lhs->Type) + { + case ValueType.Integer: + res = lhs->Value1 > rhs->Value1; + break; + case ValueType.Long: + res = *(long*)&lhs->Value1 > *(long*)&rhs->Value1; + break; + case ValueType.Float: + res = *(float*)&lhs->Value1 > *(float*)&rhs->Value1; + break; + case ValueType.Double: + res = *(double*)&lhs->Value1 > *(double*)&rhs->Value1; + break; } + + lhs->Type = ValueType.Integer; + lhs->Value1 = res ? 1 : 0; + evaluationStackPointer = rhs; + } break; case Code.Neg: //0.009606848% + { + var ptr = evaluationStackPointer - 1; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - switch (ptr->Type) - { - case ValueType.Long: - *((long*)&ptr->Value1) = -*((long*)&ptr->Value1); - break; - case ValueType.Integer: - ptr->Value1 = -ptr->Value1; - break; - case ValueType.Float: - *((float*)&ptr->Value1) = -*((float*)&ptr->Value1); - break; - case ValueType.Double: - *((double*)&ptr->Value1) = -*((double*)&ptr->Value1); - break; - } + case ValueType.Long: + *((long*)&ptr->Value1) = -*((long*)&ptr->Value1); + break; + case ValueType.Integer: + ptr->Value1 = -ptr->Value1; + break; + case ValueType.Float: + *((float*)&ptr->Value1) = -*((float*)&ptr->Value1); + break; + case ValueType.Double: + *((double*)&ptr->Value1) = -*((double*)&ptr->Value1); + break; } + } break; case Code.Not: //0.008717326% + { + var ptr = evaluationStackPointer - 1; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - switch (ptr->Type) - { - case ValueType.Long: - *((long*)&ptr->Value1) = ~*((long*)&ptr->Value1); - break; - case ValueType.Integer: - ptr->Value1 = ~ptr->Value1; - break; - } + case ValueType.Long: + *((long*)&ptr->Value1) = ~*((long*)&ptr->Value1); + break; + case ValueType.Integer: + ptr->Value1 = ~ptr->Value1; + break; } + } break; case Code.Ldelem_I8: //0.008005707% + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Long; + long[] longArr = obj as long[]; + if (longArr != null) { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Long; - long[] longArr = obj as long[]; - if (longArr != null) - { - *(long*)&ptr->Value1 = longArr[idx]; - break; - } - ulong[] ulongArr = obj as ulong[]; - if (ulongArr != null) - { - *(ulong*)&ptr->Value1 = ulongArr[idx]; - } + *(long*)&ptr->Value1 = longArr[idx]; + break; + } + + ulong[] ulongArr = obj as ulong[]; + if (ulongArr != null) + { + *(ulong*)&ptr->Value1 = ulongArr[idx]; } + } break; case Code.Ldc_R4: //0.006404566% - { - //*((long*)(&evaluationStackPointer->Value1)) = pc->Operand; - *(float*)&evaluationStackPointer->Value1 = *(float*)&pc->Operand; //高位不清除 - evaluationStackPointer->Type = ValueType.Float; - evaluationStackPointer++; - } + { + //*((long*)(&evaluationStackPointer->Value1)) = pc->Operand; + *(float*)&evaluationStackPointer->Value1 = *(float*)&pc->Operand; //高位不清除 + evaluationStackPointer->Type = ValueType.Float; + evaluationStackPointer++; + } break; case Code.Add_Ovf: //0.006404566% case Code.Add_Ovf_Un: + { + Value* b = evaluationStackPointer - 1; + //大于1的立即数和指针运算在il2cpp(unity 5.4)有bug,都会按1算 + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - //大于1的立即数和指针运算在il2cpp(unity 5.4)有bug,都会按1算 - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - if (code == Code.Add_Ovf) - { - *((long*)&evaluationStackPointer->Value1) - = checked(*((long*)&a->Value1) + *((long*)&b->Value1)); - } - else - { - *((ulong*)&evaluationStackPointer->Value1) - = checked(*((ulong*)&a->Value1) + *((ulong*)&b->Value1)); - } - break; - case ValueType.Integer: - if (code == Code.Add_Ovf) - { - evaluationStackPointer->Value1 = checked(a->Value1 + b->Value1); - } - else - { - evaluationStackPointer->Value1 - = (int)checked((uint)a->Value1 + (uint)b->Value1); - } - break; - case ValueType.Float: - *((float*)&evaluationStackPointer->Value1) - = checked(*((float*)&a->Value1) + *((float*)&b->Value1)); - break; - case ValueType.Double: - *((double*)&evaluationStackPointer->Value1) - = checked(*((double*)&a->Value1) + *((double*)&b->Value1)); - break; - } - evaluationStackPointer++; + case ValueType.Long: + if (code == Code.Add_Ovf) + { + *((long*)&evaluationStackPointer->Value1) + = checked(*((long*)&a->Value1) + *((long*)&b->Value1)); + } + else + { + *((ulong*)&evaluationStackPointer->Value1) + = checked(*((ulong*)&a->Value1) + *((ulong*)&b->Value1)); + } + + break; + case ValueType.Integer: + if (code == Code.Add_Ovf) + { + evaluationStackPointer->Value1 = checked(a->Value1 + b->Value1); + } + else + { + evaluationStackPointer->Value1 + = (int)checked((uint)a->Value1 + (uint)b->Value1); + } + + break; + case ValueType.Float: + *((float*)&evaluationStackPointer->Value1) + = checked(*((float*)&a->Value1) + *((float*)&b->Value1)); + break; + case ValueType.Double: + *((double*)&evaluationStackPointer->Value1) + = checked(*((double*)&a->Value1) + *((double*)&b->Value1)); + break; } + + evaluationStackPointer++; + } break; case Code.Ldelem_U4: //0.006226661% - { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var arr = managedStack[ptr->Value1] as uint[]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Integer; - ptr->Value1 = (int)arr[idx]; - } + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var arr = managedStack[ptr->Value1] as uint[]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Integer; + ptr->Value1 = (int)arr[idx]; + } break; case Code.Conv_U4: //0.006048756% + { + var ptr = evaluationStackPointer - 1; + uint val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - uint val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = (uint)*(long*)&ptr->Value1; - break; - case ValueType.Float: - val = (uint)*(float*)&ptr->Value1; - break; - case ValueType.Double: - val = (uint)*(double*)&ptr->Value1; - break; - case ValueType.Integer: - val = (uint)ptr->Value1; - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = (int)val; + case ValueType.Long: + val = (uint)*(long*)&ptr->Value1; + break; + case ValueType.Float: + val = (uint)*(float*)&ptr->Value1; + break; + case ValueType.Double: + val = (uint)*(double*)&ptr->Value1; + break; + case ValueType.Integer: + val = (uint)ptr->Value1; + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = (int)val; + } break; case Code.Stelem_I8: //0.004269711% + { + var val = *(long*)&(evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + long[] longArr = obj as long[]; + if (longArr != null) { - var val = *(long*)&(evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - long[] longArr = obj as long[]; - if (longArr != null) - { - longArr[idx] = val; - break; - } - ulong[] ulongArr = obj as ulong[]; - if (ulongArr != null) - { - ulongArr[idx] = (ulong)val; - } + longArr[idx] = val; + break; } + + ulong[] ulongArr = obj as ulong[]; + if (ulongArr != null) + { + ulongArr[idx] = (ulong)val; + } + } break; case Code.Ldelem_I2: //0.004269711% + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Integer; + short[] shortArr = obj as short[]; + if (shortArr != null) { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Integer; - short[] shortArr = obj as short[]; - if (shortArr != null) - { - ptr->Value1 = shortArr[idx]; - break; - } - char[] charArr = obj as char[]; - if (charArr != null) - { - ptr->Value1 = charArr[idx]; - } + ptr->Value1 = shortArr[idx]; + break; + } + + char[] charArr = obj as char[]; + if (charArr != null) + { + ptr->Value1 = charArr[idx]; } + } break; case Code.Conv_I1: //0.003913901% + { + var ptr = evaluationStackPointer - 1; + int val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val = 0; - switch (ptr->Type) - { - case ValueType.Long: - case ValueType.Integer: - val = (sbyte)ptr->Value1; - break; - case ValueType.Float: - val = (sbyte)*(float*)&ptr->Value1; - break; - case ValueType.Double: - val = (sbyte)*(double*)&ptr->Value1; - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + case ValueType.Integer: + val = (sbyte)ptr->Value1; + break; + case ValueType.Float: + val = (sbyte)*(float*)&ptr->Value1; + break; + case ValueType.Double: + val = (sbyte)*(double*)&ptr->Value1; + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Conv_R4: //0.003380188% + { + var ptr = evaluationStackPointer - 1; + float val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - float val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = *(long*)&ptr->Value1; - break; - case ValueType.Float: - pc++; - continue; - case ValueType.Integer: - val = ptr->Value1; - break; - case ValueType.Double: - val = (float)*(double*)&ptr->Value1; - break; - } - ptr->Type = ValueType.Float; - *(float*)&ptr->Value1 = val; + case ValueType.Long: + val = *(long*)&ptr->Value1; + break; + case ValueType.Float: + pc++; + continue; + case ValueType.Integer: + val = ptr->Value1; + break; + case ValueType.Double: + val = (float)*(double*)&ptr->Value1; + break; } + + ptr->Type = ValueType.Float; + *(float*)&ptr->Value1 = val; + } break; case Code.Rem_Un: //0.003202283% - { - Value* rhs = evaluationStackPointer - 1; - Value* lhs = rhs - 1; - - switch (lhs->Type) - { - case ValueType.Integer: - lhs->Value1 = (int)(((uint)lhs->Value1) % ((uint)rhs->Value1)); - break; - case ValueType.Long: - *(ulong*)&lhs->Value1 = *(ulong*)&lhs->Value1 % *(ulong*)&rhs->Value1; - break; - } + { + Value* rhs = evaluationStackPointer - 1; + Value* lhs = rhs - 1; - evaluationStackPointer = rhs; + switch (lhs->Type) + { + case ValueType.Integer: + lhs->Value1 = (int)(((uint)lhs->Value1) % ((uint)rhs->Value1)); + break; + case ValueType.Long: + *(ulong*)&lhs->Value1 = *(ulong*)&lhs->Value1 % *(ulong*)&rhs->Value1; + break; } + + evaluationStackPointer = rhs; + } break; case Code.Ldvirtftn: //0.003202283% + { + var ptr = evaluationStackPointer - 1; + var obj = managedStack[ptr->Value1]; + var method = externMethods[pc->Operand]; + if (obj.GetType() == method.DeclaringType) { - var ptr = evaluationStackPointer - 1; - var obj = managedStack[ptr->Value1]; - var method = externMethods[pc->Operand]; - if (obj.GetType() == method.DeclaringType) + ptr->Type = ValueType.Object; + ptr->Value1 = (int)(ptr - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[ptr->Value1]); + managedStack[ptr->Value1] = externMethods[pc->Operand]; + } + else + { + //子类,.net实现Delegate.CreateDelegate会找到具体的override方法, + //mono(至少unity5.2配套的mono)创建的delegate会指向父类方法 + var type = obj.GetType(); + var baseMethod = (method as MethodInfo).GetBaseDefinition(); + Dictionary overrideMap; + MethodInfo foundMethod = null; + if (!overrideCache.TryGetValue(type, out overrideMap)) { - ptr->Type = ValueType.Object; - ptr->Value1 = (int)(ptr - evaluationStackBase); - managedStack[ptr->Value1] = externMethods[pc->Operand]; + overrideMap = new Dictionary(); + overrideCache[type] = overrideMap; } - else + + if (!overrideMap.TryGetValue(baseMethod, out foundMethod)) { - //子类,.net实现Delegate.CreateDelegate会找到具体的override方法, - //mono(至少unity5.2配套的mono)创建的delegate会指向父类方法 - var type = obj.GetType(); - var baseMethod = (method as MethodInfo).GetBaseDefinition(); - Dictionary overrideMap; - MethodInfo foundMethod = null; - if (!overrideCache.TryGetValue(type, out overrideMap)) + while (type != null) { - overrideMap = new Dictionary(); - overrideCache[type] = overrideMap; - } - if (!overrideMap.TryGetValue(baseMethod, out foundMethod)) - { - while (type != null) + var members = type.GetMember(baseMethod.Name, MemberTypes.Method, + BindingFlags.Instance | BindingFlags.Public + | BindingFlags.NonPublic); + for (int i = 0; i < members.Length; i++) { - var members = type.GetMember(baseMethod.Name, MemberTypes.Method, - BindingFlags.Instance | BindingFlags.Public - | BindingFlags.NonPublic); - for (int i = 0; i < members.Length; i++) + var methodToCheck = members[i] as MethodInfo; + if (methodToCheck.GetBaseDefinition() == baseMethod) { - var methodToCheck = members[i] as MethodInfo; - if (methodToCheck.GetBaseDefinition() == baseMethod) - { - foundMethod = methodToCheck; - break; - } + foundMethod = methodToCheck; + break; } - if (foundMethod != null) break; - type = type.BaseType; } - overrideMap[baseMethod] = foundMethod; + + if (foundMethod != null) break; + type = type.BaseType; } - ptr->Type = ValueType.Object; - ptr->Value1 = (int)(ptr - evaluationStackBase); - managedStack[ptr->Value1] = foundMethod; + overrideMap[baseMethod] = foundMethod; } + + ptr->Type = ValueType.Object; + ptr->Value1 = (int)(ptr - evaluationStackBase); + BoxUtils.RecycleObject(managedStack[ptr->Value1]); + managedStack[ptr->Value1] = foundMethod; } + } break; case Code.Div_Un: //0.00231276% + { + Value* b = evaluationStackPointer - 1; + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - *((ulong*)&evaluationStackPointer->Value1) - = (*((ulong*)&a->Value1)) / (*((ulong*)&b->Value1)); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 = (int)((uint)a->Value1 / (uint)b->Value1); - break; - } - evaluationStackPointer++; + case ValueType.Long: + *((ulong*)&evaluationStackPointer->Value1) + = (*((ulong*)&a->Value1)) / (*((ulong*)&b->Value1)); + break; + case ValueType.Integer: + evaluationStackPointer->Value1 = (int)((uint)a->Value1 / (uint)b->Value1); + break; } + + evaluationStackPointer++; + } break; case Code.Mul_Ovf: //0.002134855% + { + Value* b = evaluationStackPointer - 1; + Value* a = evaluationStackPointer - 1 - 1; + evaluationStackPointer = a; + switch (a->Type) { - Value* b = evaluationStackPointer - 1; - Value* a = evaluationStackPointer - 1 - 1; - evaluationStackPointer = a; - switch (a->Type) - { - case ValueType.Long: - *((long*)&evaluationStackPointer->Value1) - = checked((*((long*)&a->Value1)) * (*((long*)&b->Value1))); - break; - case ValueType.Integer: - evaluationStackPointer->Value1 = checked(a->Value1 * b->Value1); - break; - case ValueType.Float: - *((float*)&evaluationStackPointer->Value1) - = checked((*((float*)&a->Value1)) * (*((float*)&b->Value1))); - break; - case ValueType.Double: - *((double*)&evaluationStackPointer->Value1) - = checked((*((double*)&a->Value1)) * (*((double*)&b->Value1))); - break; - } - evaluationStackPointer++; + case ValueType.Long: + *((long*)&evaluationStackPointer->Value1) + = checked((*((long*)&a->Value1)) * (*((long*)&b->Value1))); + break; + case ValueType.Integer: + evaluationStackPointer->Value1 = checked(a->Value1 * b->Value1); + break; + case ValueType.Float: + *((float*)&evaluationStackPointer->Value1) + = checked((*((float*)&a->Value1)) * (*((float*)&b->Value1))); + break; + case ValueType.Double: + *((double*)&evaluationStackPointer->Value1) + = checked((*((double*)&a->Value1)) * (*((double*)&b->Value1))); + break; } + + evaluationStackPointer++; + } break; case Code.Clt_Un: //0.001956951% - { - Value* rhs = evaluationStackPointer - 1; - Value* lhs = rhs - 1; + { + Value* rhs = evaluationStackPointer - 1; + Value* lhs = rhs - 1; - bool res = false; - switch (lhs->Type) - { - case ValueType.Integer: - res = (uint)lhs->Value1 < (uint)rhs->Value1; - break; - case ValueType.Long: - res = *(ulong*)&lhs->Value1 < *(ulong*)&rhs->Value1; - break; - case ValueType.Float: - res = !(*(float*)&lhs->Value1 >= *(float*)&rhs->Value1); - break; - case ValueType.Double: - res = !(*(double*)&lhs->Value1 >= *(double*)&rhs->Value1); - break; - } - lhs->Type = ValueType.Integer; - lhs->Value1 = res ? 1 : 0; - evaluationStackPointer = rhs; + bool res = false; + switch (lhs->Type) + { + case ValueType.Integer: + res = (uint)lhs->Value1 < (uint)rhs->Value1; + break; + case ValueType.Long: + res = *(ulong*)&lhs->Value1 < *(ulong*)&rhs->Value1; + break; + case ValueType.Float: + res = !(*(float*)&lhs->Value1 >= *(float*)&rhs->Value1); + break; + case ValueType.Double: + res = !(*(double*)&lhs->Value1 >= *(double*)&rhs->Value1); + break; } + + lhs->Type = ValueType.Integer; + lhs->Value1 = res ? 1 : 0; + evaluationStackPointer = rhs; + } break; case Code.Conv_R_Un: //0.001423237% + { + var ptr = evaluationStackPointer - 1; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - switch (ptr->Type) - { - case ValueType.Long: - *(double*)&ptr->Value1 = *(ulong*)&ptr->Value1; - break; - case ValueType.Integer: - *(double*)&ptr->Value1 = (uint)ptr->Value1; - break; - } - ptr->Type = ValueType.Double; + case ValueType.Long: + *(double*)&ptr->Value1 = *(ulong*)&ptr->Value1; + break; + case ValueType.Integer: + *(double*)&ptr->Value1 = (uint)ptr->Value1; + break; } + + ptr->Type = ValueType.Double; + } break; case Code.Stelem_I: //0.001245332% + { + var val = *(long*)&(evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var obj = managedStack[ptr->Value1]; + //BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + IntPtr[] intPtrArr = obj as IntPtr[]; + if (intPtrArr != null) { - var val = *(long*)&(evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - IntPtr[] intPtrArr = obj as IntPtr[]; - if (intPtrArr != null) - { - intPtrArr[idx] = new IntPtr(val); - break; - } - UIntPtr[] uintPtrArr = obj as UIntPtr[]; - if (uintPtrArr != null) - { - uintPtrArr[idx] = new UIntPtr((ulong)val); - } + intPtrArr[idx] = new IntPtr(val); + break; + } + + UIntPtr[] uintPtrArr = obj as UIntPtr[]; + if (uintPtrArr != null) + { + uintPtrArr[idx] = new UIntPtr((ulong)val); } + } break; //case Code.Mkrefany: //0.001067428% __makeref关键字,先不支持 case Code.Stelem_R8: //0.000889523% - { - var val = *(double*)&(evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var arr = managedStack[ptr->Value1] as double[]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - arr[idx] = val; - } + { + var val = *(double*)&(evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var arr = managedStack[ptr->Value1] as double[]; + //BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + arr[idx] = val; + } break; case Code.Ldelem_I: //0.000889523% 指针相关 - { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Long; - IntPtr[] intPtrArr = obj as IntPtr[]; - if (intPtrArr != null) - { - *(long*)(&ptr->Value1) = intPtrArr[idx].ToInt64(); - break; - } - UIntPtr[] uintPtrArr = obj as UIntPtr[]; - if (uintPtrArr != null) - { - *(ulong*)(&ptr->Value1) = uintPtrArr[idx].ToUInt64(); - } + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var obj = managedStack[ptr->Value1]; + //BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Long; + IntPtr[] intPtrArr = obj as IntPtr[]; + if (intPtrArr != null) + { + *(long*)(&ptr->Value1) = intPtrArr[idx].ToInt64(); + break; + } + + UIntPtr[] uintPtrArr = obj as UIntPtr[]; + if (uintPtrArr != null) + { + *(ulong*)(&ptr->Value1) = uintPtrArr[idx].ToUInt64(); } + } break; case Code.Conv_Ovf_U8: //4 case Code.Conv_Ovf_U8_Un: + { + var ptr = evaluationStackPointer - 1; + ulong val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - ulong val; - switch (ptr->Type) - { - case ValueType.Long: - val = pc->Code == Code.Conv_Ovf_U8 ? checked((ulong)*(long*)&ptr->Value1) : - checked(*(ulong*)&ptr->Value1); - break; - case ValueType.Integer: - val = pc->Code == Code.Conv_Ovf_U8 ? checked((ulong)ptr->Value1) : - checked((uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((ulong)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((ulong)*(double*)&ptr->Value1); - break; - default: - throw new InvalidProgramException("Conv_Ovf_U8 for " + ptr->Type); - } - ptr->Type = ValueType.Long; - *(long*)&ptr->Value1 = (long)val; + case ValueType.Long: + val = pc->Code == Code.Conv_Ovf_U8 + ? checked((ulong)*(long*)&ptr->Value1) + : checked(*(ulong*)&ptr->Value1); + break; + case ValueType.Integer: + val = pc->Code == Code.Conv_Ovf_U8 + ? checked((ulong)ptr->Value1) + : checked((uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((ulong)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((ulong)*(double*)&ptr->Value1); + break; + default: + throw new InvalidProgramException("Conv_Ovf_U8 for " + ptr->Type); } + + ptr->Type = ValueType.Long; + *(long*)&ptr->Value1 = (long)val; + } break; case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: + { + var ptr = evaluationStackPointer - 1; + long val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - long val; - switch (ptr->Type) - { - case ValueType.Long: - val = pc->Code == Code.Conv_Ovf_I8 ? checked(*(long*)&ptr->Value1) : - checked((long)*(ulong*)&ptr->Value1); - break; - case ValueType.Integer: - val = pc->Code == Code.Conv_Ovf_I8 ? checked((long)ptr->Value1) : - checked((uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((long)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((long)*(double*)&ptr->Value1); - break; - default: - throw new InvalidProgramException("Conv_Ovf_I8 for " + ptr->Type); - } - ptr->Type = ValueType.Long; - *(long*)&ptr->Value1 = val; + case ValueType.Long: + val = pc->Code == Code.Conv_Ovf_I8 + ? checked(*(long*)&ptr->Value1) + : checked((long)*(ulong*)&ptr->Value1); + break; + case ValueType.Integer: + val = pc->Code == Code.Conv_Ovf_I8 + ? checked((long)ptr->Value1) + : checked((uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((long)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((long)*(double*)&ptr->Value1); + break; + default: + throw new InvalidProgramException("Conv_Ovf_I8 for " + ptr->Type); } + + ptr->Type = ValueType.Long; + *(long*)&ptr->Value1 = val; + } break; case Code.Conv_Ovf_I1: //3 case Code.Conv_Ovf_I1_Un: + { + var ptr = evaluationStackPointer - 1; + int val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val = 0; - switch (ptr->Type) - { - case ValueType.Long: - case ValueType.Integer: - val = pc->Code == Code.Conv_Ovf_I1 ? checked((sbyte)ptr->Value1) : - checked((sbyte)(uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((sbyte)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((sbyte)*(double*)&ptr->Value1); - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + case ValueType.Integer: + val = pc->Code == Code.Conv_Ovf_I1 + ? checked((sbyte)ptr->Value1) + : checked((sbyte)(uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((sbyte)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((sbyte)*(double*)&ptr->Value1); + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; // case Code.Refanytype: //关键字__reftype(this),暂时不支持 case Code.Ldelem_R8: - { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var arr = managedStack[ptr->Value1] as double[]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Double; - *(double*)&ptr->Value1 = arr[idx]; - } + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var arr = managedStack[ptr->Value1] as double[]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Double; + *(double*)&ptr->Value1 = arr[idx]; + } break; case Code.Ldelem_R4: - { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var arr = managedStack[ptr->Value1] as float[]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Float; - *(float*)&ptr->Value1 = arr[idx]; - } + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var arr = managedStack[ptr->Value1] as float[]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Float; + *(float*)&ptr->Value1 = arr[idx]; + } break; case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I: // TODO: Conv_Ovf_I + { + var ptr = evaluationStackPointer - 1; + int val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val; - switch (ptr->Type) - { - case ValueType.Long: - val = checked((int)*(long*)&ptr->Value1); - break; - case ValueType.Float: - val = checked((int)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((int)*(double*)&ptr->Value1); - break; - case ValueType.Integer: - val = ptr->Value1; - break; - default: - val = 0; - throwRuntimeException(new NotImplementedException(), true); - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + val = checked((int)*(long*)&ptr->Value1); + break; + case ValueType.Float: + val = checked((int)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((int)*(double*)&ptr->Value1); + break; + case ValueType.Integer: + val = ptr->Value1; + break; + default: + val = 0; + throwRuntimeException(new NotImplementedException(), true); + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Conv_Ovf_U2: case Code.Conv_Ovf_U2_Un: + { + var ptr = evaluationStackPointer - 1; + int val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = pc->Code == Code.Conv_Ovf_U2 ? checked((ushort)*(long*)&ptr->Value1) : - checked((ushort)*(ulong*)&ptr->Value1); - break; - case ValueType.Integer: - val = pc->Code == Code.Conv_Ovf_U2 ? checked((ushort)ptr->Value1) : - checked((ushort)(uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((ushort)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((ushort)*(double*)&ptr->Value1); - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + val = pc->Code == Code.Conv_Ovf_U2 + ? checked((ushort)*(long*)&ptr->Value1) + : checked((ushort)*(ulong*)&ptr->Value1); + break; + case ValueType.Integer: + val = pc->Code == Code.Conv_Ovf_U2 + ? checked((ushort)ptr->Value1) + : checked((ushort)(uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((ushort)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((ushort)*(double*)&ptr->Value1); + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: + { + var ptr = evaluationStackPointer - 1; + int val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val; - switch (ptr->Type) - { - case ValueType.Long: - val = pc->Code == Code.Conv_Ovf_U1 ? checked((byte)*(long*)&ptr->Value1) : - checked((byte)*(ulong*)&ptr->Value1); - break; - case ValueType.Integer: - val = pc->Code == Code.Conv_Ovf_U1 ? checked((byte)ptr->Value1) : - checked((byte)(uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((byte)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((byte)*(double*)&ptr->Value1); - break; - default: - throw new InvalidProgramException("Conv_Ovf_U1 for " + ptr->Type); - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + val = pc->Code == Code.Conv_Ovf_U1 + ? checked((byte)*(long*)&ptr->Value1) + : checked((byte)*(ulong*)&ptr->Value1); + break; + case ValueType.Integer: + val = pc->Code == Code.Conv_Ovf_U1 + ? checked((byte)ptr->Value1) + : checked((byte)(uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((byte)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((byte)*(double*)&ptr->Value1); + break; + default: + throw new InvalidProgramException("Conv_Ovf_U1 for " + ptr->Type); } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: + { + var ptr = evaluationStackPointer - 1; + uint val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - uint val = 0; - switch (ptr->Type) - { - case ValueType.Long: - val = pc->Code == Code.Conv_Ovf_U4 ? checked((uint)*(long*)&ptr->Value1) : - checked((uint)*(ulong*)&ptr->Value1); - break; - case ValueType.Integer: - val = checked((uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((uint)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((uint)*(double*)&ptr->Value1); - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = (int)val; + case ValueType.Long: + val = pc->Code == Code.Conv_Ovf_U4 + ? checked((uint)*(long*)&ptr->Value1) + : checked((uint)*(ulong*)&ptr->Value1); + break; + case ValueType.Integer: + val = checked((uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((uint)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((uint)*(double*)&ptr->Value1); + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = (int)val; + } break; case Code.Ldelem_I1: + { + var idx = (evaluationStackPointer - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1; + var obj = managedStack[ptr->Value1]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer--; + ptr->Type = ValueType.Integer; + sbyte[] sbyteArr = obj as sbyte[]; + if (sbyteArr != null) { - var idx = (evaluationStackPointer - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1; - var obj = managedStack[ptr->Value1]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer--; - ptr->Type = ValueType.Integer; - sbyte[] sbyteArr = obj as sbyte[]; - if (sbyteArr != null) - { - ptr->Value1 = sbyteArr[idx]; - break; - } - bool[] boolArr = obj as bool[]; - if (boolArr != null) - { - ptr->Value1 = boolArr[idx] ? 1 : 0; - } + ptr->Value1 = sbyteArr[idx]; + break; + } + + bool[] boolArr = obj as bool[]; + if (boolArr != null) + { + ptr->Value1 = boolArr[idx] ? 1 : 0; } + } break; case Code.Conv_Ovf_I_Un: // TODO: case Code.Conv_Ovf_I4_Un: + { + var ptr = evaluationStackPointer - 1; + int val; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val; - switch (ptr->Type) - { - case ValueType.Long: - val = checked((int)*(ulong*)&ptr->Value1); - break; - case ValueType.Float: - val = checked((int)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((int)*(double*)&ptr->Value1); - break; - case ValueType.Integer: - val = checked((int)*(uint*)&ptr->Value1); - break; - default: - val = 0; - throwRuntimeException(new NotImplementedException(), true); - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + val = checked((int)*(ulong*)&ptr->Value1); + break; + case ValueType.Float: + val = checked((int)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((int)*(double*)&ptr->Value1); + break; + case ValueType.Integer: + val = checked((int)*(uint*)&ptr->Value1); + break; + default: + val = 0; + throwRuntimeException(new NotImplementedException(), true); + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; case Code.Stelem_R4: - { - var val = *(float*)&(evaluationStackPointer - 1)->Value1; - var idx = (evaluationStackPointer - 1 - 1)->Value1; - var ptr = evaluationStackPointer - 1 - 1 - 1; - var arr = managedStack[ptr->Value1] as float[]; - managedStack[ptr - evaluationStackBase] = null; - evaluationStackPointer = ptr; - arr[idx] = val; - } + { + var val = *(float*)&(evaluationStackPointer - 1)->Value1; + var idx = (evaluationStackPointer - 1 - 1)->Value1; + var ptr = evaluationStackPointer - 1 - 1 - 1; + var arr = managedStack[ptr->Value1] as float[]; + BoxUtils.RecycleObject(managedStack[ptr - evaluationStackBase]); + managedStack[ptr - evaluationStackBase] = null; + evaluationStackPointer = ptr; + arr[idx] = val; + } break; case Code.Conv_Ovf_I2: case Code.Conv_Ovf_I2_Un: + { + var ptr = evaluationStackPointer - 1; + int val = 0; + switch (ptr->Type) { - var ptr = evaluationStackPointer - 1; - int val = 0; - switch (ptr->Type) - { - case ValueType.Long: - case ValueType.Integer: - val = pc->Code == Code.Conv_Ovf_I2 ? checked((short)ptr->Value1) : - checked((short)(uint)ptr->Value1); - break; - case ValueType.Float: - val = checked((short)*(float*)&ptr->Value1); - break; - case ValueType.Double: - val = checked((short)*(double*)&ptr->Value1); - break; - } - ptr->Type = ValueType.Integer; - ptr->Value1 = val; + case ValueType.Long: + case ValueType.Integer: + val = pc->Code == Code.Conv_Ovf_I2 + ? checked((short)ptr->Value1) + : checked((short)(uint)ptr->Value1); + break; + case ValueType.Float: + val = checked((short)*(float*)&ptr->Value1); + break; + case ValueType.Double: + val = checked((short)*(double*)&ptr->Value1); + break; } + + ptr->Type = ValueType.Integer; + ptr->Value1 = val; + } break; //case Code.Conv_Ovf_U: //ptr->m_Size = (this.scratch - checked((UIntPtr)ptr->m_Ptr)) / 1; case Code.Throw: //1.404557%,虽然静态占比大,但运行时执行的次数应该比较少 + { + var exceptionPos = (evaluationStackPointer - evaluationStackBase - 1); + var exception = managedStack[(evaluationStackPointer - 1)->Value1] as Exception; + BoxUtils.RecycleObject(managedStack[exceptionPos]); + managedStack[exceptionPos] = null; + evaluationStackPointer--; + throw exception; + } + case Code.Shr: + { + var ptr = evaluationStackPointer - 1 - 1; + int bits = (evaluationStackPointer - 1)->Value1; + switch (ptr->Type) { - var exceptionPos = (evaluationStackPointer - evaluationStackBase - 1); - var exception = managedStack[(evaluationStackPointer - 1)->Value1] as Exception; - managedStack[exceptionPos] = null; - evaluationStackPointer--; - throw exception; - } - case Code.Shr: - { - var ptr = evaluationStackPointer - 1 - 1; - int bits = (evaluationStackPointer - 1)->Value1; - switch (ptr->Type) - { - case ValueType.Integer: - ptr->Value1 = ptr->Value1 >> bits; - break; - case ValueType.Long: - *((long*)&ptr->Value1) = (*((long*)&ptr->Value1)) >> bits; - break; - default: - throw new InvalidProgramException(">> for " + ptr->Type); - } - evaluationStackPointer--; + case ValueType.Integer: + ptr->Value1 = ptr->Value1 >> bits; + break; + case ValueType.Long: + *((long*)&ptr->Value1) = (*((long*)&ptr->Value1)) >> bits; + break; + default: + throw new InvalidProgramException(">> for " + ptr->Type); } + + evaluationStackPointer--; + } break; case Code.Ldtoken: //大多数都被ldtype替代了 - { - var type = externTypes[pc->Operand]; - EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, - managedStack, type.TypeHandle, typeof(RuntimeTypeHandle)); - evaluationStackPointer++; - } + { + var type = externTypes[pc->Operand]; + EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, + managedStack, type.TypeHandle, typeof(RuntimeTypeHandle)); + evaluationStackPointer++; + } break; case Code.Rethrow: throw throwExcepton; - case Code.Nop://0.0270415% but被过滤了 + case Code.Nop: //0.0270415% but被过滤了 + break; + case Code.Unaligned: + break; + case Code.Cpblk: + break; + case Code.Conv_I: + break; + case Code.Sizeof: + break; + case Code.Localloc: + break; + case Code.Ckfinite: + break; + case Code.No: + break; + case Code.Tail: + break; + case Code.Initblk: + break; + case Code.Readonly: + break; + case Code.Sub_Ovf_Un: + break; + case Code.Refanyval: + break; + case Code.Break: + break; + case Code.Sub_Ovf: + break; + case Code.Jmp: + break; + case Code.Cpobj: + break; + case Code.Conv_Ovf_U: + break; + case Code.Refanytype: + break; + case Code.Endfilter: + break; + case Code.Conv_Ovf_U_Un: + break; + case Code.Arglist: break; default: throwRuntimeException(new NotImplementedException(code.ToString() + " " + pc->Operand), true); break; - } //if (methodIndex == 527 || methodIndex == 528) @@ -3899,7 +4154,7 @@ AnonymousStorey anonyObj //} pc++; } - catch(RuntimeException e) + catch (RuntimeException e) { if (topWriteBack != null) { @@ -3911,7 +4166,7 @@ AnonymousStorey anonyObj throw e; } } - catch(Exception e) + catch (Exception e) { int ipc = (int)(pc - pcb); ExceptionHandler eh = getExceptionHandler(methodIndex, e.GetType(), ipc); @@ -3923,12 +4178,14 @@ AnonymousStorey anonyObj int newPos = (int)(newEvaluationStackPointer - evaluationStackBase); for (int i = newPos; i < topPos; i++) { + BoxUtils.RecycleObject(managedStack[i]); managedStack[i] = null; } evaluationStackPointer = newEvaluationStackPointer; evaluationStackPointer->Type = ValueType.Object; evaluationStackPointer->Value1 = newPos; + BoxUtils.RecycleObject(managedStack[newPos]); managedStack[newPos] = e; evaluationStackPointer++; @@ -3942,6 +4199,7 @@ AnonymousStorey anonyObj int newPos = (int)(argumentBase - evaluationStackBase) - refCount; for (int i = newPos; i < topPos; i++) { + BoxUtils.RecycleObject(managedStack[i]); managedStack[i] = null; } @@ -3951,7 +4209,7 @@ AnonymousStorey anonyObj } throwExcepton = null; - throw e; + throw new Exception(e.Message + e.StackTrace); } } } @@ -3972,7 +4230,8 @@ public string Statistics() sb.AppendFormat("externTypes: {0}\n", externTypes == null ? 0 : externTypes.Length); sb.AppendFormat("internStrings: {0}\n", internStrings == null ? 0 : internStrings.Length); sb.AppendFormat("fieldInfos: {0}\n", fieldInfos == null ? 0 : fieldInfos.Length); - sb.AppendFormat("anonymousStoreyInfos: {0}\n", anonymousStoreyInfos == null ? 0 + sb.AppendFormat("anonymousStoreyInfos: {0}\n", anonymousStoreyInfos == null + ? 0 : anonymousStoreyInfos.Length); sb.AppendFormat("overrideCache: {0}\n", overrideCache == null ? 0 : overrideCache.Count); sb.AppendFormat("staticFieldTypes: {0}\n", staticFieldTypes == null ? 0 : staticFieldTypes.Length); @@ -4012,4 +4271,4 @@ public static VirtualMachine GetGlobal() throw new NotSupportedException(); } } -} +} \ No newline at end of file diff --git a/Source/VSProj/Src/PerfTest/PerfTest.cs b/Source/VSProj/Src/PerfTest/PerfTest.cs index c54524f..2099a1d 100644 --- a/Source/VSProj/Src/PerfTest/PerfTest.cs +++ b/Source/VSProj/Src/PerfTest/PerfTest.cs @@ -9,6 +9,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Runtime.InteropServices; namespace IFix.Test { @@ -19,11 +20,11 @@ static void Base() { int LOOPS = 10000000; var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); - + Call call = default; for (int i = 0; i < 3; i++) { var sw = Stopwatch.StartNew(); - Call call = Call.Begin(); + Call.BeginRef(ref call); virtualMachine.Execute(1, ref call, 0); Call.End(ref call); sw.Stop(); @@ -37,22 +38,78 @@ static void Base() // return a + b; //} //原生方法通过这种方式调用虚拟机方法 - static void SafeCall() + static unsafe void SafeCall() { + IntPtr nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(Value) + * VirtualMachine.MAX_EVALUATION_STACK_SIZE); + Value* evaluationStackPointer = (Value*)nativePointer.ToPointer(); + object[] managedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; + int LOOPS = 10000000; var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); var sw = Stopwatch.StartNew(); + Call call = default; + int ret = 0; for (int i = 0; i < LOOPS; i++) { - Call call = Call.Begin(); + Call.BeginRef(ref call); call.PushInt32(4); call.PushInt32(6); virtualMachine.Execute(0, ref call, 2); - Call.End(ref call); - call.GetInt32(); + ret = call.GetInt32(); + } + Console.WriteLine($"SafeCall {ret}" + " : " + ((int)sw.Elapsed.TotalMilliseconds) + "ms\r\n"); + } + + + public struct Vector3 + { + + } + + public int __Gen_Wrap_1(object P0, Vector3 P1) + { + Call call = Call.Begin(); + call.PushObject(P0); + call.PushValueUnmanaged(P1); + return call.GetInt32(0); + } + + static unsafe void CallOrigin() + { + int LOOPS = 1000000; + + var sw = Stopwatch.StartNew(); + int ret = 0; + SimpleVirtualMachineBuilder sb = new SimpleVirtualMachineBuilder(); + // for (int i = 0; i < LOOPS; i++) + // { + // ret = sb.GetValue(10, 20); + // } + Console.WriteLine($"CallOrigin {ret}" + " : " + ((int)sw.Elapsed.TotalMilliseconds) + "ms\r\n"); + } + + static unsafe void SafeCallExtern() + { + int LOOPS = 1;//1000000; + SimpleVirtualMachineBuilder sb = new SimpleVirtualMachineBuilder(); + var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); + + var sw = Stopwatch.StartNew(); + int ret = 0; + Call call = default; + List list = new List { 12 }; + for (int i = 0; i < LOOPS; i++) + { + Call.BeginRef(ref call); + call.PushObject(sb); + call.PushObject(list); + virtualMachine.Execute(2, ref call, 3); + ret = call.GetInt32(); } - Console.WriteLine("SafeCall " + " : " + (LOOPS / (int)sw.Elapsed.TotalMilliseconds * 1000) + "\r\n"); + sw.Stop(); + Console.WriteLine($"SafeCallExtern ret:{ret} " + " : " + (sw.Elapsed.TotalMilliseconds) + "ms\r\n"); } //直接通过指针操作栈,调用add方法 @@ -63,10 +120,13 @@ unsafe static void UnsafeCall() * VirtualMachine.MAX_EVALUATION_STACK_SIZE); Value* evaluationStackPointer = (Value*)nativePointer.ToPointer(); object[] managedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; - + byte* stackValueHandler = (byte*)Marshal.AllocHGlobal(32 * VirtualMachine.MAX_EVALUATION_STACK_SIZE).ToPointer(); + int LOOPS = 10000000; var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(LOOPS); var sw = Stopwatch.StartNew(); + + int ret = 0; for (int i = 0; i < LOOPS; i++) { evaluationStackPointer->Value1 = 10; @@ -74,17 +134,20 @@ unsafe static void UnsafeCall() (evaluationStackPointer + 1)->Value1 = 20; (evaluationStackPointer + 1)->Type = IFix.Core.ValueType.Integer; - + virtualMachine.Execute(0, evaluationStackPointer, managedStack, evaluationStackPointer, 2); + ret = evaluationStackPointer->Value1; } - Console.WriteLine("UnsafeCall " + " : " + (LOOPS / (int)sw.Elapsed.TotalMilliseconds * 1000) + "\r\n"); + Console.WriteLine($"UnsafeCall {ret}" + " : " + ((int)sw.Elapsed.TotalMilliseconds) + "ms\r\n"); System.Runtime.InteropServices.Marshal.FreeHGlobal(nativePointer); } public static void Main(string[] args) { - Base(); + CallOrigin(); + SafeCallExtern(); + //Base(); SafeCall(); UnsafeCall(); Console.Read(); diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 104bc51..35ded78 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -348,6 +348,7 @@ int addExternMethod(MethodReference callee, MethodDefinition caller) } externMethodToId[callee] = methodId; externMethods.Add(callee); + return methodId; } @@ -414,6 +415,7 @@ bool checkILAndGetOffset(MethodDefinition method, Mono.Collections.Generic.Collection instructions, Dictionary ilOffset, out int stopPos) { + var localVars = method.Body.Variables; int offset = 0; stopPos = 0; for (int i = 0; i < instructions.Count; i++) @@ -441,6 +443,43 @@ bool checkILAndGetOffset(MethodDefinition method, return false; } } + case Code.Ldloc_0: + case Code.Ldloc_1: + case Code.Ldloc_2: + case Code.Ldloc_3: + { + string strCode = instructions[i].OpCode.Code.ToString(); + int op = int.Parse(strCode.Substring(strCode.Length - 1)); + if (i + 3 < instructions.Count + && instructions[i+1].OpCode.Code == Code.Ldc_I4_1 + && instructions[i+2].OpCode.Code == Code.Add + && instructions[i+3].OpCode.Code == (Code)Enum.Parse(typeof(Code), strCode.Replace("Ld", "St")) + && localVars[op].VariableType == intType + ) + { + i += 3; + } + offset += 1; + } + break; + case Code.Ldloc: + case Code.Ldloc_S: + { + string strCode = instructions[i].OpCode.Code.ToString(); + int op = (instructions[i].Operand as VariableDefinition).Index; + if (i + 3 < instructions.Count + && instructions[i+1].OpCode.Code == Code.Ldc_I4_1 + && instructions[i+2].OpCode.Code == Code.Add + && instructions[i+3].OpCode.Code == (Code)Enum.Parse(typeof(Code), strCode.Replace("Ld", "St")) + && (instructions[i+3].Operand as VariableDefinition).Index == op + && (instructions[i+3].Operand as VariableDefinition).VariableType == intType + ) + { + i += 3; + } + offset += 1; + } + break; case Code.Ldc_I8: case Code.Ldc_R8: case Code.Leave: @@ -979,10 +1018,11 @@ void fieldAccessInject(InjectType injectType, MethodDefinition method, int metho void idAccessInject(InjectType injectType, MethodDefinition method, int methodId) { addRedirectIdInfo(method, methodId); + //RemoveProfilerUsingBlock(method); var body = method.Body; var msIls = body.Instructions; var ilProcessor = body.GetILProcessor(); - + var redirectTo = getWrapperMethod(wrapperType, anonObjOfWrapper, method, false, false); Instruction insertPoint; if (injectType == InjectType.Redirect) @@ -998,8 +1038,21 @@ void idAccessInject(InjectType injectType, MethodDefinition method, int methodId { ilProcessor.InsertBefore(msIls[0], Instruction.Create(OpCodes.Ret)); insertPoint = msIls[0]; - ilProcessor.InsertBefore(insertPoint, createLdcI4(methodId)); - ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Call, isPatched)); + FieldDefinition fd; + if (!isMethodPatchDict.TryGetValue(methodId, out fd)) + { + fd = new FieldDefinition( + $"isPatched_{methodId}", + FieldAttributes.Static | FieldAttributes.Public, + boolType + ); + wrapperMgrImpl.Fields.Add(fd); + isMethodPatchDict.Add(methodId, fd); + } + + ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Ldsfld, fd)); + //ilProcessor.InsertBefore(insertPoint, createLdcI4(methodId)); + //ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Call, isPatched)); ilProcessor.InsertBefore(insertPoint, ilProcessor.Create(OpCodes.Brfalse, insertPoint.Next)); } @@ -1023,7 +1076,377 @@ void idAccessInject(InjectType injectType, MethodDefinition method, int methodId ilProcessor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Box, ptype)); } } - ilProcessor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Callvirt, redirectTo)); + ilProcessor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Call, redirectTo)); + } + + Instruction GetProfilerStart(Instruction markerInstr, MethodDefinition method) + { + Instruction result = markerInstr.Previous; + switch (result.OpCode.Code) + { + case Code.Ldloca_S: + { + method.Body.Variables.Remove((VariableDefinition)result.Operand); + return GetProfilerStart(result, method); + } + case Code.Stloc_0: + case Code.Stloc_1: + case Code.Stloc_2: + case Code.Stloc_3: + case Code.Stloc_S: + if (markerInstr.OpCode.Code == Code.Ldloca_S) + { + return GetProfilerStart(result, method); + } + break; + case Code.Ldsfld: + case Code.Ldfld: + case Code.Ldflda: + case Code.Ldsflda: + return result; + case Code.Newobj: + if (((MethodReference)result.Operand).DeclaringType.FullName == "Unity.Profiling.ProfilerMarker") + { + return result.Previous; + } + break; + case Code.Call: + if (((MethodReference)result.Operand).DeclaringType.FullName == "Unity.Profiling.ProfilerMarker") + { + return result.Previous.Previous; + } + break; + default: + throw new Exception($"don't know how to deal with Instruction:{result}"); + } + throw new Exception($"don't know how to deal with Instruction:{result}"); + } + + void RemoveProfilerUsingBlock(MethodDefinition method) + { + var ilProcessor = method.Body.GetILProcessor(); + var instructions = method.Body.Instructions; + + // Find and remove instructions related to ProfilerMarker.Auto() + var markersToRemove = instructions + .Where(instr => instr.OpCode == OpCodes.Call && + ((MethodReference)instr.Operand).Name == "Auto" && + ((MethodReference)instr.Operand).DeclaringType.FullName == "Unity.Profiling.ProfilerMarker") + .ToList(); + + if (markersToRemove.Count > 0) + { + Console.WriteLine($"method:{method.FullName} find instructions {markersToRemove.Count}"); + } + + foreach (var markerInstr in markersToRemove) + { + // Assuming the pattern of: ldsfld, stloc, ldloca.s, call Auto, stloc + + var start = GetProfilerStart(markerInstr, method); + var end = markerInstr.Next; + + // Collect all instructions that reference the target instructions + var references = instructions + .Where(instr => instr.Operand is Instruction target && + (target == start || target == markerInstr.Previous || target == markerInstr || + target == end)) + .ToList(); + + // Find the next valid instruction to replace the removed ones + var nextValidInstruction = end.Next;//FindNextValidInstruction(end, instructions); + + // Update all references to point to the next valid instruction + foreach (var reference in references) + { + reference.Operand = nextValidInstruction; + } + + // Remove instructions from start to end + var curInstr = start; + while (curInstr != nextValidInstruction) + { + var next = curInstr.Next; + ilProcessor.Remove(curInstr); + curInstr = next; + } + + // Adjust the instructions to ensure the correct control flow + // If there's a finally handler, adjust accordingly + var exceptionHandlers = method.Body.ExceptionHandlers; + ExceptionHandler finallyHandler = null; + foreach (var eh in exceptionHandlers) + { + if (eh.HandlerType == ExceptionHandlerType.Finally) + { + if (eh.TryStart == nextValidInstruction) + { + finallyHandler = eh; + break; + } + } + } + + // remove finnalyhandler + if (finallyHandler != null) + { + // Ensure the control flow is correct + // Remove the instructions in the try block and finally block + + var current = finallyHandler.HandlerStart.Previous; + while (current != finallyHandler.HandlerEnd) + { + var next = current.Next; + ilProcessor.Remove(current); + current = next; + } + ilProcessor.Remove(finallyHandler.HandlerEnd); + + method.Body.ExceptionHandlers.Remove(finallyHandler); + } + + } + + if (markersToRemove.Count > 0) + { + // remove nop + RemoveNop(method); + } + } + + void ShowStackBehaviour(MethodDefinition method) + { + var instructions = method.Body.Instructions; + int stackCount = 0; + var start = instructions[0]; + + var inst = start; + int pushCount; + int popCount; + + while (inst.Next != null) + { + int instCount = GetInstructionStackBehaviour(inst, method, out pushCount, out popCount); + stackCount += instCount; + Console.WriteLine($"{inst}: instCount:{instCount},stackCount:{stackCount} StackBehaviourPop:{inst.OpCode.StackBehaviourPop}, StackBehaviourPush:{inst.OpCode.StackBehaviourPush}"); + + if (inst.OpCode.Code == Code.Br_S || inst.OpCode.Code == Code.Br) + { + inst = (Instruction)inst.Operand; + } + else + { + inst = inst.Next; + } + } + } + + // void DeleteInstruction(Instruction inst, MethodDefinition method) + // { + // int pushCount; + // int popCount; + // + // GetInstructionStackBehaviour(inst, method, out pushCount, out popCount); + // + // if (pushCount > 0) + // { + // var needPopCount = pushCount; + // var nextInst = inst.Next; + // while (needPopCount > 0 && nextInst != null) + // { + // GetInstructionStackBehaviour(nextInst, method, out pushCount, out popCount); + // needPopCount -= popCount; + // nextInst = nextInst.Next; + // } + // } + // + // } + + + int GetInstructionStackBehaviour(Instruction inst, MethodDefinition method, out int pushCount, out int popCount) + { + pushCount = 0; + popCount = 0; + // TODO call 函数 + if ( + inst.OpCode.Code == Code.Call || + inst.OpCode.Code == Code.Calli || + inst.OpCode.Code == Code.Callvirt) + { + var methodReference = (MethodReference)inst.Operand; + // Parameters are pushed onto the stack + popCount += methodReference.Parameters.Count; + if (methodReference.HasThis) + { + popCount += 1; + } + + pushCount += methodReference.ReturnType != voidType ? 1 : 0; + } + else if (inst.OpCode.Code == Code.Newobj) + { + pushCount = 1; + var methodReference = (MethodReference)inst.Operand; + popCount += methodReference.Parameters.Count; + } + else if (inst.OpCode.Code == Code.Ret) + { + popCount = method.ReturnType == voidType ? 0 : 1; + } + else + { + StackBehaviour pushBehaviour = inst.OpCode.StackBehaviourPush; + StackBehaviour popBehaviour = inst.OpCode.StackBehaviourPop; + switch (pushBehaviour) + { + case StackBehaviour.Push0: + break; + case StackBehaviour.Push1: + pushCount = 1; + break; + case StackBehaviour.Push1_push1: + pushCount = 2; + break; + case StackBehaviour.Pushi: + pushCount = 1; + break; + case StackBehaviour.Pushi8: + pushCount = 1; + break; + case StackBehaviour.Pushr4: + pushCount = 1; + break; + case StackBehaviour.Pushr8: + pushCount = 1; + break; + case StackBehaviour.Pushref: + pushCount = 1; + break; + case StackBehaviour.Varpop: + case StackBehaviour.Varpush: + default: + throw new ArgumentOutOfRangeException($"Instruction:{inst}"); + } + + switch (popBehaviour) + { + case StackBehaviour.Pop0: + break; + case StackBehaviour.Pop1_pop1: + popCount = 2; + break; + case StackBehaviour.Pop1: + popCount = 1; + break; + case StackBehaviour.Popi: + popCount = 1; + break; + case StackBehaviour.Popi_pop1: + popCount = 2; + break; + case StackBehaviour.Popi_popi: + popCount = 2; + break; + case StackBehaviour.Popi_popi8: + popCount = 2; + break; + case StackBehaviour.Popi_popi_popi: + popCount = 3; + break; + case StackBehaviour.Popi_popr4: + popCount = 2; + break; + case StackBehaviour.Popi_popr8: + popCount = 2; + break; + case StackBehaviour.Popref: + popCount = 1; + break; + case StackBehaviour.Popref_pop1: + popCount = 2; + break; + case StackBehaviour.Popref_popi: + popCount = 2; + break; + case StackBehaviour.Popref_popi_popi: + popCount = 3; + break; + case StackBehaviour.Popref_popi_popi8: + popCount = 3; + break; + case StackBehaviour.Popref_popi_popr4: + popCount = 3; + break; + case StackBehaviour.Popref_popi_popr8: + popCount = 3; + break; + case StackBehaviour.Popref_popi_popref: + popCount = 3; + break; + case StackBehaviour.PopAll: + popCount = 0; + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return pushCount - popCount; + } + + void RemoveNop(MethodDefinition method) + { + var ilProcessor = method.Body.GetILProcessor(); + var instructions = method.Body.Instructions; + + // Find Nop + var markersToRemove = instructions + .Where(instr => instr.OpCode == OpCodes.Nop) + .ToList(); + + var exceptionHandlers = method.Body.ExceptionHandlers; + foreach (var markerInstr in markersToRemove) + { + + // Collect all instructions that reference the target instructions + var references = instructions + .Where(instr => instr.Operand is Instruction target && target == markerInstr) + .ToList(); + + var nextValidInstruction = markerInstr.Next; + + foreach (var reference in references) + { + reference.Operand = nextValidInstruction; + } + + foreach (var eh in exceptionHandlers) + { + if (eh.TryStart == markerInstr) + { + eh.TryStart = nextValidInstruction; + } + if (eh.TryEnd == markerInstr) + { + eh.TryEnd = nextValidInstruction; + } + if (eh.HandlerStart == markerInstr) + { + eh.HandlerStart = nextValidInstruction; + } + if (eh.HandlerEnd == markerInstr) + { + eh.HandlerEnd = nextValidInstruction; + } + + if (eh.FilterStart == markerInstr) + { + eh.FilterStart = nextValidInstruction; + } + } + + ilProcessor.Remove(markerInstr); + } } void injectMethod(MethodDefinition method, int methodId) @@ -1052,6 +1475,13 @@ int allocMethodId(MethodDefinition method) methodToId.Add(method, methodId); + FieldDefinition f = new FieldDefinition( + $"isPatched_{methodId}", + FieldAttributes.Static | FieldAttributes.Public, + boolType + ); + wrapperMgrImpl.Fields.Add(f); + isMethodPatchDict.Add(methodId, f); if (mode == ProcessMode.Patch && methodId > ushort.MaxValue) { throw new OverflowException("too many internal methods"); @@ -1156,6 +1586,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, tryAddBaseProxy(method.DeclaringType, method); var body = method.Body; var msIls = body.Instructions; + var localVars = body.Variables; var ilOffset = new Dictionary(); //Console.WriteLine("process method id:" + codes.Count); @@ -1426,6 +1857,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, Code = (Core.Code)Enum.Parse(typeof(Core.Code), strCode), Operand = ilOffset[msIl.Operand as Instruction] - ilOffset[msIl] }); + //Console.WriteLine($"jump offset {ilOffset[msIl.Operand as Instruction] - ilOffset[msIl]}"); //if (msIl.OpCode.Code == Code.Br_S || msIl.OpCode.Code == Code.Br) //{ // Console.WriteLine("il:" + msIl + ",jump to:" + msIl.Operand); @@ -1471,10 +1903,38 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, }); } break; - case Code.Stloc: - case Code.Stloc_S: case Code.Ldloc: case Code.Ldloc_S: + { + int op = (msIl.Operand as VariableDefinition).Index; + if (i + 3 < msIls.Count + && msIls[i+1].OpCode.Code == Code.Ldc_I4_1 + && msIls[i+2].OpCode.Code == Code.Add + && msIls[i+3].OpCode.Code == (Code)Enum.Parse(typeof(Code), strCode.Replace("Ld", "St")) + && (msIls[i+3].Operand as VariableDefinition).Index == op + && (msIls[i+3].Operand as VariableDefinition).VariableType == intType + ) + { + Console.WriteLine($"convert to add1_loc"); + code.Add(new Core.Instruction + { + Code = Core.Code.Add1_Loc, + Operand = op, + }); + i += 3; + } + else + { + code.Add(new Core.Instruction + { + Code = (Core.Code)Enum.Parse(typeof(Core.Code), strCode), + Operand = op + }); + } + } + break; + case Code.Stloc: + case Code.Stloc_S: case Code.Ldloca: case Code.Ldloca_S: code.Add(new Core.Instruction @@ -1509,11 +1969,32 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: - code.Add(new Core.Instruction + { + int op = int.Parse(strCode.Substring(strCode.Length - 1)); + if (i + 3 < msIls.Count + && msIls[i+1].OpCode.Code == Code.Ldc_I4_1 + && msIls[i+2].OpCode.Code == Code.Add + && msIls[i+3].OpCode.Code == (Code)Enum.Parse(typeof(Code), strCode.Replace("Ld", "St")) + && localVars[op].VariableType == intType + ) { - Code = Core.Code.Ldloc, - Operand = int.Parse(strCode.Substring(strCode.Length - 1)), - }); + Console.WriteLine($"convert to add1_loc"); + code.Add(new Core.Instruction + { + Code = Core.Code.Add1_Loc, + Operand = op, + }); + i += 3; + } + else + { + code.Add(new Core.Instruction + { + Code = Core.Code.Ldloc, + Operand = op, + }); + } + } break; case Code.Stloc_0: case Code.Stloc_1: @@ -1534,11 +2015,27 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, case Code.Ldc_I4_6: case Code.Ldc_I4_7: case Code.Ldc_I4_8: - code.Add(new Core.Instruction + { + // if next is add,jump + if(msIls[i+1] != null && msIls[i+1].OpCode.Code == Code.Add) { - Code = Core.Code.Ldc_I4, - Operand = int.Parse(strCode.Substring(strCode.Length - 1)), - }); + Console.WriteLine($"{msIl.OpCode} to add_i4"); + code.Add(new Core.Instruction + { + Code = Core.Code.Add_I4, + Operand = int.Parse(strCode.Substring(strCode.Length - 1)), + }); + i++; // jump add + } + else + { + code.Add(new Core.Instruction + { + Code = Core.Code.Ldc_I4, + Operand = int.Parse(strCode.Substring(strCode.Length - 1)), + }); + } + } break; case Code.Ldc_I4_M1: code.Add(new Core.Instruction @@ -1654,12 +2151,28 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } else if (methodIdInfo.Type == CallType.Extern) { - code.Add(new Core.Instruction + if (!methodToCall.HasThis && methodToCall.Parameters.Count == 2 + && methodToCall.Parameters[0].ParameterType == intType + && methodToCall.Parameters[1].ParameterType == intType + && methodToCall.ReturnType == intType) { - Code = msIl.OpCode.Code == Code.Newobj ? Core.Code.Newobj : - Core.Code.CallExtern, - Operand = (paramCount << 16) | methodIdInfo.Id - }); + Console.WriteLine($"call i4 i4 method {methodToCall.FullName}"); + code.Add(new Core.Instruction + { + Code = Core.Code.CallStaticR_I4_I4_I4_Extern, + Operand = methodIdInfo.Id + }); + } + else + { + code.Add(new Core.Instruction + { + Code = msIl.OpCode.Code == Code.Newobj ? Core.Code.Newobj : + Core.Code.CallExtern, + Operand = (paramCount << 16) | methodIdInfo.Id + }); + } + } else if (methodIdInfo.Type == CallType.InteralVirtual) { @@ -1989,6 +2502,8 @@ public enum ProcessResult AssemblyDefinition assembly; + private TypeReference intType; + private TypeReference boolType; private TypeReference objType; private TypeReference voidType; private TypeDefinition wrapperType; @@ -2018,6 +2533,7 @@ public enum ProcessResult private TypeReference VirtualMachineType; private TypeReference WrappersManagerType; private TypeDefinition wrapperMgrImpl; + private Dictionary isMethodPatchDict = new Dictionary(); private MethodDefinition ctorOfWrapperMgrImpl; private MethodReference VirtualMachine_Execute_Ref; @@ -2037,6 +2553,7 @@ public enum ProcessResult new Dictionary(); private MethodReference Call_PushValueType_Ref; + private MethodReference Call_PushValueUnmanaged; TypeReference wrapperParamerterType(TypeReference type) { if (type.IsByReference) @@ -2508,7 +3025,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, { throw new NotImplementedException("no push for " + paramRawType + " at " + method); } - instructions.Add(Instruction.Create(OpCodes.Callvirt, push)); + instructions.Add(Instruction.Create(OpCodes.Call, push)); } else { @@ -2518,17 +3035,21 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, MethodReference push; if (pushMap.TryGetValue(tryGetUnderlyingType(paramRawType), out push)) { - instructions.Add(Instruction.Create(OpCodes.Callvirt, push)); + instructions.Add(Instruction.Create(OpCodes.Call, push)); } else { if (paramRawType.IsValueType) { - instructions.Add(Instruction.Create(OpCodes.Callvirt, Call_PushValueType_Ref)); + var rawType = parameterTypes[i]; + instructions.Add(Instruction.Create(OpCodes.Call, + makeGenericMethod(Call_PushValueUnmanaged, rawType)) + ); + //instructions.Add(Instruction.Create(OpCodes.Callvirt, Call_PushValueType_Ref)); } else { - instructions.Add(Instruction.Create(OpCodes.Callvirt, + instructions.Add(Instruction.Create(OpCodes.Call, pushMap[assembly.MainModule.TypeSystem.Object])); } } @@ -2541,7 +3062,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, { instructions.Add(Instruction.Create(OpCodes.Ldloca_S, call)); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(Instruction.Create(OpCodes.Callvirt, pushMap[assembly.MainModule.TypeSystem.Object])); + instructions.Add(Instruction.Create(OpCodes.Call, pushMap[assembly.MainModule.TypeSystem.Object])); } else { @@ -2554,7 +3075,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, instructions.Add(Instruction.Create(OpCodes.Ldloca_S, call)); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldfld, anonObj)); - instructions.Add(Instruction.Create(OpCodes.Callvirt, pushMap[assembly.MainModule.TypeSystem.Object])); + instructions.Add(Instruction.Create(OpCodes.Call, pushMap[assembly.MainModule.TypeSystem.Object])); instructions.Add(nop); } @@ -2565,7 +3086,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, if (parameterTypes[i].IsByReference) { emitLdcI4(instructions, refPos[i]); - instructions.Add(Instruction.Create(OpCodes.Callvirt, Call_PushRef_Ref)); + instructions.Add(Instruction.Create(OpCodes.Call, Call_PushRef_Ref)); } else { @@ -2574,21 +3095,26 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, MethodReference push; if (pushMap.TryGetValue(tryGetUnderlyingType(paramRawType), out push)) { - instructions.Add(Instruction.Create(OpCodes.Callvirt, push)); + instructions.Add(Instruction.Create(OpCodes.Call, push)); } else { if (paramRawType.IsValueType) { - instructions.Add(Instruction.Create(OpCodes.Box, paramRawType)); + var rawType = tryGetUnderlyingType(getRawType(parameterTypes[i])); + instructions.Add(Instruction.Create(OpCodes.Call, + makeGenericMethod(Call_PushValueUnmanaged, rawType)) + ); + + //instructions.Add(Instruction.Create(OpCodes.Box, paramRawType)); //Console.WriteLine("Call_PushValueType_Ref for " + method.Name + ", pidx:" + i // + ", ptype:" + parameterTypes[i] + ", paramRawType:" + paramRawType + ",wrap:" // + wrapperMethod.Name); - instructions.Add(Instruction.Create(OpCodes.Callvirt, Call_PushValueType_Ref)); + //instructions.Add(Instruction.Create(OpCodes.Callvirt, Call_PushValueType_Ref)); } else { - instructions.Add(Instruction.Create(OpCodes.Callvirt, + instructions.Add(Instruction.Create(OpCodes.Call, pushMap[assembly.MainModule.TypeSystem.Object])); } } @@ -2819,6 +3345,8 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) virtualMethodToIndex.Add(ObjectVirtualMethodDefinitionList[methodIdx], methodIdx); } voidType = assembly.MainModule.TypeSystem.Void; + boolType = assembly.MainModule.TypeSystem.Boolean; + intType = assembly.MainModule.TypeSystem.Int32; wrapperType = new TypeDefinition("IFix", DYNAMICWRAPPER, Mono.Cecil.TypeAttributes.Class | Mono.Cecil.TypeAttributes.Public, objType); @@ -2907,7 +3435,10 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) Call_Ref = assembly.MainModule.ImportReference(Call); Call_Begin_Ref = importMethodReference(Call, "Begin"); Call_PushRef_Ref = importMethodReference(Call, "PushRef"); + Call_PushValueType_Ref = importMethodReference(Call, "PushValueType"); + Call_PushValueUnmanaged = importMethodReference(Call, "PushValueUnmanaged"); + Call_GetAsType_Ref = importMethodReference(Call, "GetAsType"); VirtualMachine_Execute_Ref = assembly.MainModule.ImportReference( @@ -3132,22 +3663,6 @@ void emitWrapperManager() instructions.Add(Instruction.Create(OpCodes.Ret)); assembly.MainModule.Types.Add(wrapperMgrImpl); - - var initWrapperArray = new MethodDefinition("InitWrapperArray", MethodAttributes.Public - | MethodAttributes.HideBySig - | MethodAttributes.NewSlot - | MethodAttributes.Virtual - | MethodAttributes.Final, assembly.MainModule.TypeSystem.Object); - wrapperMgrImpl.Methods.Add(initWrapperArray); - initWrapperArray.Parameters.Add(new ParameterDefinition("len", ParameterAttributes.None, - assembly.MainModule.TypeSystem.Int32)); - instructions = initWrapperArray.Body.Instructions; - instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); - instructions.Add(Instruction.Create(OpCodes.Newarr, wrapperType)); - instructions.Add(Instruction.Create(OpCodes.Stsfld, wrapperArray)); - instructions.Add(Instruction.Create(OpCodes.Ldsfld, wrapperArray)); - instructions.Add(Instruction.Create(OpCodes.Ret)); - } //void makeCloneFast(AssemblyDefinition ilfixAassembly) @@ -3442,7 +3957,7 @@ from type in allTypes { processMethod(kv.Key); } - + genCodeForCustomBridge(); emitCCtor(); @@ -3458,11 +3973,37 @@ from type in allTypes } EmitAsyncBuilderStartMethod(allTypes); - } + } + emitInitWrapperArray(); + return ProcessResult.OK; } + void emitInitWrapperArray() + { + var initWrapperArray = new MethodDefinition("InitWrapperArray", MethodAttributes.Public + | MethodAttributes.HideBySig + | MethodAttributes.NewSlot + | MethodAttributes.Virtual + | MethodAttributes.Final, assembly.MainModule.TypeSystem.Object); + wrapperMgrImpl.Methods.Add(initWrapperArray); + initWrapperArray.Parameters.Add(new ParameterDefinition("len", ParameterAttributes.None, + assembly.MainModule.TypeSystem.Int32)); + + var instructions = initWrapperArray.Body.Instructions; + foreach (var item in isMethodPatchDict) + { + instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0)); + instructions.Add(Instruction.Create(OpCodes.Stsfld, item.Value)); + } + instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); + instructions.Add(Instruction.Create(OpCodes.Newarr, wrapperType)); + instructions.Add(Instruction.Create(OpCodes.Stsfld, wrapperArray)); + instructions.Add(Instruction.Create(OpCodes.Ldsfld, wrapperArray)); + instructions.Add(Instruction.Create(OpCodes.Ret)); + } + void emitFieldCtor(FieldDefinition field, Mono.Collections.Generic.Collection insertInstructions) { var staticConstructorAttributes = diff --git a/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs b/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs index 4f44926..ce568da 100644 --- a/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs +++ b/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs @@ -44,7 +44,7 @@ public static void Init() public void SimpleTest() { var virtualMachine = SimpleVirtualMachineBuilder.CreateVirtualMachine(1); - Call call = Call.Begin(); + Call call = Call.BeginRef(); call.PushInt32(4); call.PushInt32(6); virtualMachine.Execute(0, ref call, 2); diff --git a/Source/VSProj/ThirdParty/UnityEngine.CoreModule.dll b/Source/VSProj/ThirdParty/UnityEngine.CoreModule.dll new file mode 100644 index 0000000..1b1ade0 Binary files /dev/null and b/Source/VSProj/ThirdParty/UnityEngine.CoreModule.dll differ diff --git a/Source/VSProj/ThirdParty/Unsafe.As.dll b/Source/VSProj/ThirdParty/Unsafe.As.dll new file mode 100644 index 0000000..4e5a759 Binary files /dev/null and b/Source/VSProj/ThirdParty/Unsafe.As.dll differ diff --git a/Source/VSProj/build_for_unity.bat b/Source/VSProj/build_for_unity.bat index d0ee967..82bc988 100644 --- a/Source/VSProj/build_for_unity.bat +++ b/Source/VSProj/build_for_unity.bat @@ -1,27 +1,24 @@ -@set UNITY_HOME=D:\Program Files\Unity523f1 -if exist "%UNITY_HOME%\Editor\Data\Mono\bin\gmcs" ( - @set GMCS="%UNITY_HOME%\Editor\Data\Mono\bin\gmcs" -) else ( - @set GMCS="%UNITY_HOME%\Editor\Data\MonoBleedingEdge\bin\mcs.bat" -) -@set MONO="%UNITY_HOME%\Editor\Data\MonoBleedingEdge\bin\mono" +@set UNITY_HOME=E:\work\unitysource2019_x3\build\WindowsEditor +@set UNITY_HOME_LIB=E:/work/unitysource2019_x3/build/WindowsEditor/Data/MonoBleedingEdge/lib + +@set GMCS="%UNITY_HOME%\Data\MonoBleedingEdge\bin\mcs.bat" +@set CSC="%UNITY_HOME%\Data\Tools\Roslyn\csc" + +@set MONO="%UNITY_HOME%\Data\MonoBleedingEdge\bin\mono" @set DLL_OUTPUT=..\UnityProj\Assets\Plugins\IFix.Core.dll @set TOOL_KIT_PATH=..\UnityProj\IFixToolKit call %GMCS% ShuffleInstruction.cs -out:.\ShuffleInstruction.exe %MONO% ShuffleInstruction.exe Src\Core\Instruction.cs Instruction.cs -call %GMCS% -define:UNITY_IPHONE -unsafe -target:library -out:%DLL_OUTPUT% Src\Builder\*.cs Src\Version.cs Instruction.cs ^ -Src\Core\AnonymousStorey.cs ^ -Src\Core\DataDefine.cs ^ -Src\Core\GenericDelegate.cs ^ -Src\Core\Il2CppSetOptionAttribute.cs ^ -Src\Core\ObjectClone.cs ^ -Src\Core\ReflectionMethodInvoker.cs ^ -Src\Core\StackOperation.cs ^ -Src\Core\SwitchFlags.cs ^ -Src\Core\Utils.cs ^ -Src\Core\VirtualMachine.cs ^ -Src\Core\WrappersManager.cs + +call %CSC% /noconfig ^ +/reference:%UNITY_HOME_LIB%/mono/4.7.1-api/mscorlib.dll ^ +/reference:%UNITY_HOME_LIB%/mono/4.7.1-api/System.dll ^ +/reference:%UNITY_HOME_LIB%/mono/4.7.1-api/System.Core.dll ^ +/reference:ThirdParty/Unsafe.As.dll ^ +/reference:%UNITY_HOME%/Data/Managed/UnityEngine/UnityEngine.CoreModule.dll ^ +/reference:%UNITY_HOME%/Data/Managed/UnityEngine/UnityEngine.PhysicsModule.dll @build_response + md %TOOL_KIT_PATH% copy /Y ThirdParty\Mono.Cecil* %TOOL_KIT_PATH% -call %GMCS% -define:UNITY_IPHONE -unsafe -reference:ThirdParty\Mono.Cecil.dll,ThirdParty\Mono.Cecil.Mdb.dll,ThirdParty\Mono.Cecil.Pdb.dll -out:%TOOL_KIT_PATH%\IFix.exe -debug Instruction.cs Src\Tools\*.cs Src\Version.cs -pause +call %GMCS% -define:UNITY_IPHONE -unsafe -reference:ThirdParty\Mono.Cecil.dll,ThirdParty\Mono.Cecil.Mdb.dll,ThirdParty\Mono.Cecil.Pdb.dll -out:%TOOL_KIT_PATH%\IFix.exe -debug Src\Core\Instruction.cs Src\Tools\*.cs Src\Version.cs +pause \ No newline at end of file diff --git a/Source/VSProj/build_response b/Source/VSProj/build_response new file mode 100644 index 0000000..3f071da --- /dev/null +++ b/Source/VSProj/build_response @@ -0,0 +1,26 @@ +/target:library +/nowarn:0169 +/nowarn:0649 +/optimize+ +/debug:portable +/out:../UnityProj/Assets/Plugins/IFix.Core.dll +/unsafe +/preferreduilang:en-US +/langversion:latest +/define:UNITY_IPHONE +/define:ENABLE_PROFILER +Src\Builder\*.cs +Src\Version.cs +Src\Core\Instruction.cs +Src\Core\AnonymousStorey.cs +Src\Core\BoxUtils.cs +Src\Core\DataDefine.cs +Src\Core\GenericDelegate.cs +Src\Core\Il2CppSetOptionAttribute.cs +Src\Core\ObjectClone.cs +Src\Core\ReflectionMethodInvoker.cs +Src\Core\StackOperation.cs +Src\Core\SwitchFlags.cs +Src\Core\Utils.cs +Src\Core\VirtualMachine.cs +Src\Core\WrappersManager.cs \ No newline at end of file diff --git a/Source/VSProj/vs2013/IFix.Core.csproj b/Source/VSProj/vs2013/IFix.Core.csproj index 261a7ab..963d1ae 100644 --- a/Source/VSProj/vs2013/IFix.Core.csproj +++ b/Source/VSProj/vs2013/IFix.Core.csproj @@ -9,7 +9,7 @@ Properties IFix.Core IFix.Core - v3.5 + v4.8 512 @@ -40,6 +40,12 @@ + + ..\ThirdParty\UnityEngine.CoreModule.dll + + + ..\ThirdParty\Unsafe.As.dll + @@ -51,6 +57,9 @@ Src\Core\AnonymousStorey.cs + + Src\Core\BoxUtils.cs + Src\Core\DataDefine.cs diff --git a/Source/VSProj/vs2013/IFix.PerfTest.csproj b/Source/VSProj/vs2013/IFix.PerfTest.csproj index aae3043..0943d0d 100644 --- a/Source/VSProj/vs2013/IFix.PerfTest.csproj +++ b/Source/VSProj/vs2013/IFix.PerfTest.csproj @@ -9,7 +9,7 @@ Properties IFix.PerfTest IFix.PerfTest - v3.5 + v4.5 512 diff --git a/Source/VSProj/vs2013/IFix.csproj b/Source/VSProj/vs2013/IFix.csproj index 090cabe..5fc83d3 100644 --- a/Source/VSProj/vs2013/IFix.csproj +++ b/Source/VSProj/vs2013/IFix.csproj @@ -9,7 +9,7 @@ Properties IFix IFix - v3.5 + v4.5 512