From 7b81646872da7ceee7fd04c5eb25da4e9b64dfa1 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 9 Oct 2019 11:36:56 +0800 Subject: [PATCH 001/103] fix https://github.com/Tencent/InjectFix/issues/22 --- Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 02abd2c..271639b 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -373,7 +373,11 @@ static void doRestore(string ts) //cecil里的类名表示和.net标准并不一样,这里做些转换 static string GetCecilTypeName(Type type) { - if (type.IsGenericType) + if (type.IsByRef && type.GetElementType().IsGenericType) + { + return GetCecilTypeName(type.GetElementType()) + "&"; + } + else if (type.IsGenericType) { if (type.IsGenericTypeDefinition) { @@ -600,10 +604,10 @@ public static void GenPlatformPatch(Platform platform, string patchOutputDir, scriptCompilationSettings.group = BuildTargetGroup.iOS; scriptCompilationSettings.target = BuildTarget.iOS; } - else - { - scriptCompilationSettings.group = BuildTargetGroup.Standalone; - scriptCompilationSettings.target = BuildTarget.StandaloneWindows; + else + { + scriptCompilationSettings.group = BuildTargetGroup.Standalone; + scriptCompilationSettings.target = BuildTarget.StandaloneWindows; } ScriptCompilationResult scriptCompilationResult = PlayerBuildInterface.CompilePlayerScripts(scriptCompilationSettings, outputDir); From b0382aac4c731273bef7686d0b1821e30cf06693 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 9 Oct 2019 14:31:50 +0800 Subject: [PATCH 002/103] =?UTF-8?q?patch=E4=B8=80=E4=B8=AA=E5=B8=A6?= =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E5=8F=82=E6=95=B0=E7=9A=84=E5=87=BD=E6=95=B0?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E5=8F=8B=E5=A5=BD=E7=9A=84=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E4=B8=8D=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/IFix/Editor/ILFixEditor.cs | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 271639b..d7bfef9 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -657,6 +657,42 @@ static void writeMethods(BinaryWriter writer, List methods) } } + static bool hasGenericParameter(Type type) + { + if (type.IsByRef || type.IsArray) + { + return hasGenericParameter(type.GetElementType()); + } + if (type.IsGenericType) + { + foreach (var typeArg in type.GetGenericArguments()) + { + if (hasGenericParameter(typeArg)) + { + return true; + } + } + return false; + } + return type.IsGenericParameter; + } + + static bool hasGenericParameter(MethodBase method) + { + if (method.IsGenericMethodDefinition || method.IsGenericMethod) return true; + if (!method.IsConstructor && hasGenericParameter((method as MethodInfo).ReturnType)) return true; + + foreach (var param in method.GetParameters()) + { + if (hasGenericParameter(param.ParameterType)) + { + return true; + } + } + return false; + + } + /// /// 生成patch /// @@ -669,7 +705,7 @@ public static void GenPatch(string assembly, string assemblyCSharpPath string corePath = "./Assets/Plugins/IFix.Core.dll", string patchPath = "Assembly-CSharp.patch.bytes") { var patchMethods = Configure.GetTagMethods(typeof(PatchAttribute), assembly).ToList(); - var genericMethod = patchMethods.FirstOrDefault(m => m.IsGenericMethodDefinition || m.IsGenericMethod); + var genericMethod = patchMethods.FirstOrDefault(m => hasGenericParameter(m)); if (genericMethod != null) { throw new InvalidDataException("not support generic method: " + genericMethod); @@ -681,7 +717,7 @@ public static void GenPatch(string assembly, string assemblyCSharpPath } var newMethods = Configure.GetTagMethods(typeof(InterpretAttribute), assembly).ToList(); - genericMethod = newMethods.FirstOrDefault(m => m.IsGenericMethodDefinition || m.IsGenericMethod); + genericMethod = newMethods.FirstOrDefault(m => hasGenericParameter(m)); if (genericMethod != null) { throw new InvalidDataException("not support generic method: " + genericMethod); From 11851f61f23b47d2fc82e5bed308240cdf72bab3 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 10 Oct 2019 10:05:57 +0800 Subject: [PATCH 003/103] =?UTF-8?q?=E6=B3=A8=E5=85=A5=E9=98=B6=E6=AE=B5?= =?UTF-8?q?=EF=BC=8C=E5=A6=82=E6=9E=9C=E5=A4=84=E7=90=86=E6=8C=87=E4=BB=A4?= =?UTF-8?q?=E6=97=B6=E5=BC=82=E5=B8=B8=EF=BC=8C=E5=8F=AA=E6=89=93=E5=8D=B0?= =?UTF-8?q?warning=EF=BC=8C=E5=9B=A0=E4=B8=BA=E5=8F=AF=E4=BB=A5=E5=9C=A8?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E9=98=B6=E6=AE=B5=E8=A7=84=E9=81=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index bb31614..d3d5805 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1044,6 +1044,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } //if (!methodToInjectType.TryGetValue(method, out injectType) // || injectType == InjectType.Redirect || mode == ProcessMode.Patch) + try { var code = new List(); codes.Add(methodId, code); @@ -1665,6 +1666,17 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, Console.WriteLine("patched: " + method); } } + catch(Exception e) + { + if (mode == ProcessMode.Inject) + { + Console.WriteLine("Warning: process " + method + " il throw " + e); + } + else + { + throw e; + } + } //Console.WriteLine("process finish:" + method); if (mode == ProcessMode.Inject) From 1cd8b22a56dac6e7eec2a82f9e2b955814f6ddaa Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 10 Oct 2019 10:12:07 +0800 Subject: [PATCH 004/103] =?UTF-8?q?=E5=88=A0=E9=99=A4=E7=BC=96=E8=AF=91?= =?UTF-8?q?=E7=9A=84dll=E5=92=8Cexe=EF=BC=8C=E5=BC=BA=E5=88=B6=E5=BF=85?= =?UTF-8?q?=E7=8E=B0=E8=87=AA=E8=A1=8C=E7=BC=96=E8=AF=91=E6=89=8D=E8=83=BD?= =?UTF-8?q?=E7=94=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/UnityProj/Assets/Plugins/IFix.Core.dll | Bin 65536 -> 0 bytes .../Assets/Plugins/IFix.Core.dll.meta | 20 ------------------ Source/UnityProj/IFixToolKit/IFix.exe | Bin 87552 -> 0 bytes Source/UnityProj/IFixToolKit/IFix.exe.mdb | Bin 34938 -> 0 bytes 4 files changed, 20 deletions(-) delete mode 100644 Source/UnityProj/Assets/Plugins/IFix.Core.dll delete mode 100644 Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta delete mode 100644 Source/UnityProj/IFixToolKit/IFix.exe delete mode 100644 Source/UnityProj/IFixToolKit/IFix.exe.mdb diff --git a/Source/UnityProj/Assets/Plugins/IFix.Core.dll b/Source/UnityProj/Assets/Plugins/IFix.Core.dll deleted file mode 100644 index ea63366816c5ebfc283a2143fe86344a2d8e9389..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 diff --git a/Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta b/Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta deleted file mode 100644 index 13364df..0000000 --- a/Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta +++ /dev/null @@ -1,20 +0,0 @@ -fileFormatVersion: 2 -guid: 7c6cf326f60d243479929e308c3123fb -timeCreated: 1519909605 -licenseType: Pro -PluginImporter: - serializedVersion: 1 - iconMap: {} - executionOrder: {} - isPreloaded: 0 - platformData: - Any: - enabled: 1 - settings: {} - Editor: - enabled: 0 - settings: - DefaultValueInitialized: true - userData: - assetBundleName: - assetBundleVariant: diff --git a/Source/UnityProj/IFixToolKit/IFix.exe b/Source/UnityProj/IFixToolKit/IFix.exe deleted file mode 100644 index 5514a311fa59b2c6d6d9134f47f60ae7d9165c73..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87552 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 PFvqCa|NZy>odo_5h;gD% diff --git a/Source/UnityProj/IFixToolKit/IFix.exe.mdb b/Source/UnityProj/IFixToolKit/IFix.exe.mdb deleted file mode 100644 index 36f8aeea0fc830b1e4823abff7c857e3e303f0ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 34938 zcmeHw349bq_J6X!=yayJy2RR(9BHk4yX_e+r0YV$hrh3|`8ivi_(2h_yVojDIGO*J`_qDm z(eJ$3X_I`Z{oI#@hQBXiXR^IxR$_)LEz#}FLb|oSp4DV}olR}#w)pGQT}mu|O$a}; zZ|XPY1{`|T)!_Kuv>-N3c@TuOL8IwUYtGeNxyOYRAt+>|I5e_^n^Hh4315E$D%lVm9|tGh+A zW!T>~g#$&FMJ3&t+$+s4lOG|nmylXS6{-?dtz{HCb_>MfqmFTj*0x$a6gB zB)y&9t^fq>)bccKa)K`1<;0XEHKc+;#_?czgtne(NXcYZUBhpXN@DBR7!?kdR%+^0 zJx6z?xfv}tH2J1B6m^Dwh|rgGbr*X+SC{AM^L@|z69R6rfRATk>%vUi%I$v{%6+1bzQ!pd#q^6VsK(sR$?C}9Euc_ zWlv#PkZObWHd)*vtGgcLVdaEQoT8mHB z9%Tl`9im`gRRnD{Bvw_uK8MU!&1|iENy?gXFGL;|x<2%NS?cACEUGp%{1&DtbX|ZfnPbTwfh-5p z2%hC~PRO8toaK#B`A+EKF#jw?Q~Ju-i2!25HYBxZ!`O2WsdlTBq(7K~^I`I}utDLh zEwC59#|x>9nJdEOmEo&=&ws{q@pT&u*%dDD4&UPo84NMVW6v*y%in}w#B+2_4w1;= zW&Zo%s=| zockigA{d&CJyv79b;6#ic*-l~Zn!+8#Ksa{l2);#I$Bu~heXIjBi@gIwh+bciQyEe zzry_WZ&*pAaHY;lM2|Kkihr3Xtv8{%CP5>AMC;)0rQ>j~F{)^cI2A-M6F0&=AfAGI zOYDbt$4N8cu97yxJt84BPV)fyf=ppkJ{|1j0-a(~o8BeOQo8UAxGvMi^{ zq&JT8i$AxNJg?N+QcTANXC`JPrrX{2ERw=a#q+xFnIr^5Z`rf#P(xmY95(~J={CTu z>KSyEOZ!sfA;w8T#EYq#id~`~q37c_sa9T(M@q>9Bd11syH9U^=sF!44rb316;*z) zg3vp8dz^Hl$I?lB@)eSvd&T5C4Kj<8N6SrYIj!V{+KNIM{pU`j|1=wXh$&pq2nG6X zqvP2dDc_4+R+_a!DcR}vax%t&oig2Ji6?bvOG_xXwnqkl_51kheJPAPi!EgJKr=y3UEX#K z-5LblT0!r~1od87d0@Gj;U~Og_%FR| z_%FX|_^)<0{LWns-&=35CmO#K(+xkpkKy+j$Sd(MiYB(Rp>W0jr)gXRnG5+vF~``{kt%IRC0gBra?Cw@wM7zq%SIXyAV9il=zGcr! zb0#KBWP>(9t+?8AdxgYcZ;*?GuoPy7_zgh4f*$!k%GUyp$Q-FtD#_haS*^`i$l5t3 z-ln=C7+LXpsvhGjjVfu(susVhAWwQ|*?d}$7Y0QkP?(X4mRq`8XwJ=SxLS0tlZ|0!rnO+%5P5q*_ z<0f@s#F`Htpw*6RozW{D1JiD4cK;+;5egG%-n{y6BwqvM?^j4`$yj!-qI|yM_Z6># zTrahvaP+@QtzS_C$*B3jkl&=QrhhdArsyS|QNF*je4z4)$|oy>a&u&NNQUH#hh!;~ ziJ`PBTG<_aB$|t%JK3v*baMdEpbd%7zyy<|N4d?f#d>s)UO{ZeOepC}v~n|gXchi$ zI&1FSCeSOe_|44t>LM0%eidbLl{H4p6zDt_qYdQS2t80m`LfC}BNS!eq3xmf)Wz)G z>s6E=tNaug`WJ+X%|co5sH)1is^hETB{4WD39~J687WSQEF2dlONzsumMjZWmfh`b zw-Ga7#5{oxNp!(MpM>A?FJgaK{F3A(YrfvZ<bDM zA9#1Ak}BD_!6toFRoPedI!YpmEH_yQb@#9*z|MFc!0JdK)eVpR^p3P5D;rFE{3*ka z?_%oMG0?G+G#0~;0zKKIyHoXCy>q^v;41IhlA4;$C|~o4a^jJ@k1+OYj*Om|8sV96 z_F>#&Rr|77^QtMUs;#cZE6I`URT9<`Mm|+vVcD!jHmQ2^d_C2b+L!4EX-_rfV72oP zeCuuY)-LZ`16-+U8h>qIb!Axfyy_3i>^b(@Der5ksc!yKL3L$Q_5FCs;v4WNq7J3z zOnZy-O||&{vPqPwE2^QeDF1);63ow8g>lz#7PIYnK4Tw=j#*B(F7!I@EC|7M*CX%!hag(Cd2xeia z5oTF1#2CTfToj`$iz(o526V)tY$^)Vny@Wm?F2lOhA~bGB2qpgVk*XFq=+{0y4G6X zqMP;`Y@c8;%4iW6Vw4|ZJT+PAI0~PgoYKRF=Eta+MEN zidwGBQmOnI<*Y*G#{>a?h`SZP3>vIbrMt{6_o0fn#Kr1TxJ%V_D&yB}RA*ESGj5vb z!)uDuB%4-W)AKxfOamR}CMq_jzLu9N>9AQfJwKm4ucYa-cIs+Fy<)8S6EP!*|A1A5 zcWn7;D_t$6C#bQu3hHocuqHmGb=2`o`q`)8ti4XXp?&E<448-y@PURhUJRd+R31xTWX8-ouqY7-O`BL`!45c74=)uuAOQdhZCckE*< zU&T-rWHwsi4WhEKBsPs@sU1OT#^|kH5$m0k_32~E-p5WO8CEh;usK{E*wE3%2Rvk! z@!3sicyS-2opiv2h?GwYxbi-Wq{U~gIv?S%v47DaPI;ci@W+*zj~8H#1zDuSMGt7E zYcprL9zri%14Dv_yeIw<$;PsIs08#*mlrapmX7$JPUPO)?|v6Ghe_s#AxN z$;Lnhx^A7-xIWKxWj$q8y={md1iKvbybjr7jO1c5C~=dlJJPW1l4N(eoEReqC1V; znJ!KQJ#*PymgO>BR&ksC=-Fw~^A5-vaNy*CUB5|7KBMKtlgffdCmJys@wdNBX^eP* zFA`AWSfVyBug#hSKst+G%_wH^xZk?3lV z@iJu8ZZ!Qm6+)A+YU<8PbY$3*neADplGRHFv%+I4`stLI@}X&o0mJB+DAAb}Q^tIy zqcawB12GQ=q|m5xKxm^Xwq$!!T4I(XqdUtlHrg=nTUILxPGs5RGCDcjy%N*fB_{Pi znOZ+0rX;tn3ZtQQbxMzm(UKi0Debwb(C$&{*|vtCl@VV8%*=|#x@|$u6bkPy}&otUX{qovxDZF+c7mb+}4oP-2ys=qh{mn^i+J75i?qw{&NT?i^P zU}e>jW|T^hOtBUXv8G_ATA_%0qZOOom|)K0JoL07>o2@*_<3v%gE!(|#On^>D7hU?RHintp#Ae$7x7610sFcnMg0_!Q<8wqEJYDBOPz*$y42W6iWnQYJ(4Pojob=+dt`2DipVW} z1MZE|i^@>MqB0lYUMMr8EJe&HdmQfZvi-|ZME`Qz;chRtt1>;hz1+6S6!S&7pUY9q zlBk*Gsn(ZK-$hZ(#_|gvqB>W~uc|VkQc^^JFcG|F-6aTGaM>%|*4S-Pl?a;7+LpJbrtvqqQjFWG(RAw!b!N zhu6~&weOkO=sL^l7|)i~*~5GNnL%W2wMAE9^vUFbuZl1zXHl5VcqBH{b#9q=a1O5>Fm zC7tSPYTW?|hTA|>hrr;?R-eYJh$TJ~Y9gQ%(9VJPTTK!JXMJ;Ag_bOSi`wS{UM#=%_)n0jv|-9l}L zVkUyIF`QEMrXBIlUg;p#lMGvYsmu!AQBN3^q`$-}n^n4gjrB8=n<(R-+7JsP#BAKU zIk+qHEQ!%oNvztGsT6ESde!DhHmu^{m&HIfrOB z+4D(ll*w)K+As^&R8rW)fw=}#_e7L3q_Xm0m`rbAf>e?&+gMjvK2_7yW4^gboi3!B z!`h{7luz0mMvA^^D;tKMcyT}o41E1kM7HNF%XvVYGB9pL9HtH=3DfARMRufTrpdly zDD0_C(A~~BJh!LYVK{{tr3ni+{L(XJQGDSQ5?>iCll95CYFiYM6Odmu2g1Js68&iLYyt z6%Viio842o!|M|27t(;B*YpOd`nV}OwF76RLp&&gq`DYH`)?Ou6HVcK%5GttayV|u zb0Ata$d!DZB%{(ty<`y`4(w_%*B2CXTyG94hR{&c(iqA}lxETbv;R2AjlQemWC_a{ zAm~_#7z(pkObr25%*0i9=CPt0>oqoG9ofap>Rke}VQ&MgpBeGWp7{6L3PKfGOm<6( zvGB&aZpDK208KN@1vVq525X6Kcb21DFSp&LhEUHCo8Q`!73K_vFG=XwVa~+%uqUNz zCD1{amNR>~dXy<6y`AYUQ2l zR>LtxpTbP|Fckst*`+KQ;5B?G8hRk3mmTYy)eUH%8bMZ zp=|w<1;fw};S?7>5HLR?n9Ec)a|!q<><3gmG8LPG$G$=XI)hlDTCs>4;xujJ3c@r4Lwr5T-gdx7RgW^9 z(~}?alZo94S!_-gE)F|bf*xHRwy6ZgoCxa|PBDYRf!Ep){zW*|I>higXTo#fjxGV5 zr!y|%R)m5595K`6>8B+Rnb@(CJ4`iqqty1&)R4PR{8DOFX?k*aB-}<{NA`m|sPv-J zMk>ck?<+%1$CjB5cR`tbWte*FhlYkhYHKKuCR)=2dMoVqiSMPSs!#ErKwFrqFN!y3 zp39>vu%V;X7FlC4EQ>#`uTZ8SOM*4*q3wFyS$Tty*}O&7r~aLw8>E1q}gd3u3M&(}LI#2VWMJy*;O(LHL% z@AUQjFI9g_S3Buy+HO5RyR&{A3(cwe6?8^xcy??z%nN)1D&M2-);&|S)LHqSJT?C% zmhr4S-E{@sYmWKe9QNYZz89stEt85%E1-}3}C2wXRu?1AjTJlK`mniVzNa1Q2 znGH`!A}WzYV%a2;Dw*rP4hI*l5~S;TEZZ4?c^8jrc0z2@EC`c$jqC9d=7^V-MK5oE znRVr&GgA;sV2K)Qq67GtGG4<81D=YtEGvRSa)J*fxE6TN3-hUO7Sc=RBkAg+DW95*m zOgX|gkWFAiLu1=m;7pbvh8g`&3tz`0P=vEv&(`Ufe!-?#W6QBK3sWea99e!NOVlEY zv;#$oEm(hfy{_iuiOp?W3)CtFTMKTl7wsXM*xaf$-=bDg-D(xhljF(BDKP&w#A>Q1 zU%hg9Yr)6bmdgd|_+%Xq@NbrS9)z_6%P*5a)W+PZpt5}rY>y+NKsVhB zt@I2dVoE8}^P6G>rnwxwcw^l0nsVl~OL*NPm+(&Eq31^;OvGi0>wv=QBT>YLTe3P_ z&)czKn$O6PVD-Mqn}w++BKBf#_VI2+-7&pBiB{m(T5JPj#aLB}ndUBZKbTzqOmDUj zvrpMm^$om4@4v1bc>Vh8Y{Dwkn{He(uN5yb;SaM^z63EIJy%oRo>bT;B;~!KeDucZ zHyA5y-Zzc+ij>ggiIL1VJehImm((ui(BRM;%I!DqA|Y&##J*idz99rZA}$;BL=j(D zn3kx_Ph60QFfJkkA`!ZtmE^NTWn1Fs2(T(*>RT2SjtWaTS(g2*QCZXt)$nYVvsb1h zU|urC>D?U?hF3yLz$p=m_iQ%*s8-!Ss-}e`_sUFjB(Y8Q%xD!%6GAwSY4XOOK+7^m za?Zw(;;;KL_8847Lq0}$5Ok8c>P;GA8s=Y%L(wXyOP64Yao2iO+GQczap@Cl8M?0>(E#-V($eLPYfY`iCyQ3nK>d- z89tslm8cx-wj+sElbn*4*d4u`!Fw!4roN>JDpWfYUYDR6?d9?MhM#!_{2MIp2LmUG zAHw~V;k-#*5tk#Gp}s-dE@?lX^4-D2V4+?iKDJfcW^4;)88UX}U_N0KX>FM3r=j=a zB}GG)B8m*dFtQ14+O%n`-i$YhYstzO`(8VQNtUrHl4+3??4yIJZxQ7TjA|?brDM?U z2(elX6=_bv>%oX^EUyS!z@)c|K~7p)OU(PR30NU0P>(ASY>PwtlsI>axmv(_WJ`#_ zFtaJTgiv#=XPVzZqp;Fh^@b=)OH_SChyxfN~*m^JypC>$F>>;P==vcyOMG zWoFAs@jTp1B4Trv-mzR$C}fawLJ<|4B?J;Ru(XKPURYLaWARNrmTeNmmcDUXHf*$- zni>&{f$&LPtuQ4A>r~PaR{NOrk?LUY8s4Eb#3h*x&6UwQyt{s!(Q#cX9$7i0Q>~7`UZiaeofsr~C=sM7^A#JdD~d(;aNS z?k@tj%nFK}amK$<>(}F8LR;oZbu)fp~RIK_pUE0NIFO8<$7?W<+0$m-kCDp^H z0unG(fe8+UY{h;C9*=Evh~O;xq^I)to)=P4T^5ba*tFxj?-a>w_&9=LOj@8SfFKP{ zOSrlHy$r-td}10JyknXu$^&Q^ROT@12ZkJ?DQ53*|iHC-8;k(VLhYyvEGnR==U_0%k~y>|~+ki=I86t)R6h#WSo>xDuqgzLfF zo@X*yQX@x%&E~UO*|XA^^@t3C5-cMqZ)Z8!e&w=8wF-B!#Ubc2W^d!RcbY$N=VUBbUOqFgW;YyN4A>i3Bti{{W+T$pF`1l^ zrOeD)khKsdQejz#|0`uRTIheKw6UZWu+r{wDZ5>VT}NF0rOo+QO3N+F|4d<@GYk8R zTlu?tV6Q>F3JV)9cRC^Kxr`Qp)g``aVQ#t$wP0_ z#xf4ieM_15*3!3@y;WG~nE$nf#{LnEA6T(Zyseyk`@-Abyj@sqtFZ6C&+C7F&oYjp z*7n;uUS!iU@AV4nlGW4z5Y5Lgo<2%$pQ(MOVddA`bXDQtf1hT*{mDg$sp;#hD!HM_ z0(4SQA*|`YU%5y+Ub0zD56M=BW{=4pn_WnCd!dhcJ~-e^^}pSy0!weUqriu(WCKwl zVtc;d`A%QuZr>sA41K4taHaoe3x~d6+rs!Z`EN?z-)8-7_TLJN7AcJS&qzxkkNh{V zbFEe=&&{g`MrG{8qLa}zt$bHm_3p>-e)4W%iDQKE_bsu*1y$a%kEufq(Rv=+MX(m+ zuR)9C{s*hjFR}Si&0@U%rXQ9|`qA}%bfX^?mi|E+=|5e1qk$Gb=Z*vQ-m~xirznav zzJIKdj)Cx=jPBX}Ntx517Wbzm{r%|Hgc;)f8YpTfDK)Nbi;U!F?QUa#i+^oBNJIDv z?K`mlI|->-={MAKD+j+gATg`YZ}6ff_SH47SqXN3C18KB{M?24{TIf@sRK!wHjw5H zq}NUv|Pv9M(q zw>s_|fgxH-BIb3Bb7UQz#w3k@>6y`A$jCpq z?Bj9Blb3zOFj7ViqY1-k;xNCm2MMeH3uX7Q!MEuGOAgKq|DGaX=o4T$Jm6(kGjl*4 zJJ2O<&mm<;4jss$gE;B#YeGT7h<`}kgQ~>WlK$WtIpr<$+!3VA8$nA)&@vpA_mw$Z zn0ntbvo#ifu_=DkE}+R54}KsWfdW{(B?pExzGJQ27(N^yNy>?lbbcgV82Klo;fR-p z>7z-RF`DL&rUj$_WHem#(r|VRDd)z}l`-@^&WZVCshTkJzbs2d^=ENuDjI{y)3=~Q zeUUZfxgInM4=wf3GS8ookjp+ouH}+)J(qsTrN8I;5%Onf-S1=4j86`%9Z$--@w8<; zZ5{7N!=FW}hJy}6s_sl6pxTq#T?=C#TR?QvzuCbLiW}UOFaBBW2<=nmLU= znC3@EHNkbip@BW!x6PwnVn$+jdsg)a8Wly={O{`shU09I(PU3eC*|~X`gS^9n(kLJ zn=t0SW6OXY1TWgzN^6m_{l-`@-rlEEVp=bIheSt~|7frn4SrK!MdlWo7qw*zE&Arw z|HE0c9&}hFX?!l?=NY8@GJ^)pq=7R7_;&Zcmcai!->{_$d&&MQOd9TG($aiVmgQ4H zKCRCWVAB5=uA*|yglmSEZ--}-a%480o=s%c)?acvzK&ZJ@|2SRZDbv5v4L{(5p`r#r;M{oeCUF}4ie>y7vIKk0me80b zGfU{hUtstjJ8WFNcnCB-C9AnSNPFZc*9oUE|LGq<`YPUzg1hb^6s~o z_cci76SAMJ!f16BeX)x6t@5Kd{Qj$>nNFA6B-%IIYfh9uu)`{1s1)z9ibP;FvH{zR zc$c+i4Jm8a(B?I?WsP6)f*v4j-R&9dAow%REMsfUKPuaQ{cbZ10I;u#tDYlkNjbWf z&a9=c*ZPsB3ajqhj{a@Z{Io=omLDie0dxAr805bjATSwLZ;UwBj+PaWvb=!S7tn?R zKiX;wUGFzs{avI57V?2@IR_;$`u>p{VBT$@i5qCr2EQ^`g(?3!e~T3259z1^(_~y6 z4jTAQlCc{}@oc0i8)@oBKN3`7#vew4pHvjp8^!vLz>@yM4ug@wgyGP~q#XX3PJK+L zKlY=d<9}WlMxX@7&AU?GCQ_zsqS>2h&L+P?gbR6p7%TsIX(+y;AIM@R45L7Uhp}RKurUjd6;buPyRAJg5MuDF&6e-$2BMU`d^%B8o_<9Q|XSdMhEp%mz9}V^Y^P(^s zY*hJP#W|mnGWSzj@+mFFW$!4Jv5Frqy!l7zCOP z_>5M57Er9W|K(!&m7`eO{#^^|6TF4nw2hR_+i2%D+O^HEa1Yu&+w}e#y?OfUuh(l> zbZgOr?j0?%IkvdnP$UAAGp7Cd_SvsKC*{=Vbn$cg_Hz`Noi4y30KIdUu3b>$@~9o8 zj^06IcJMG3h|?wFD^?b^2w@-YppRHss4izFx_jWvgc}uUvjyYY9OHW%q8941CuSw} z=z#D9cVd=X3=Va;;xc;R3k$e%mR;&7syH;x??TKHgK!aIVsb*C^ltckiKwtU@zd?N z6Q8|~tbvvC;glGy{i}a%H&Udln=ZHr2AoJdU=D9aQ2CXpiNbiG6GN z3Y*UFSw_K~t*nH*Tlq?1Os+tBl3uT*b^>RlqwqgETGRD<(Yp0;W9#~8HAKrBFhbK7 zB;dY)gvP#;&+JH2LT9Z?6RX-fR_~sxd!F=!c#k=YFKC^xm*3n3ZpCJAD}B{beaM=e zYwg@1VcKI+x~HqHKp%m>o%&R!N#)N`!@uk#&u&)x-u53PSXbv4>Xf0VQ5SL}AGvLWrOC z2rQxhSR*jxUpE~YRXVGin|n#UwU_SfrMo!Q=sThb@v-1A0{^Uu<@0@{ZQn=x_p$n8 zCs9!6dK0{DxrC7K_R(b)q6PCaX^QH*x>X6Ho)*QLl+ry8U!~!fImnj6CN0Z0U-M=S zQN~A8a2mJpS+8`QQ(?^*r#S@UHh6YA(5n)>SF|X&Lysb``&29kN2=V1}6> zq&RroRC5_ex#P81e&jzs-aM*mW_+R~{?__mlR+ej0y(5$rv+%30FX zWXbUZq@6fG=XngylBY<0NpDLYHi$PXPJ1Av`GhP@rsc3?sm zxrm|^wKNY};wV=HPFr%$Tt$&a9;MYsQ6w#xGA(N1?IuQR3u48>*8m)n#XP{zuj6D@ z?-FJ6G%k-SO1@@`%S%%UT^)L0;{p~TIGqUz7Z~$6pbbJmC6A%a)!YZ#>Td>ZsRf|T zg?V34wFY-zHs$vxpvfgLqGDaH_-uv@SZ=mHeA8p7d95!yu@s6nXnqQYoh>Sjd#*T@ z{l6sb(w8*i7^{D;(hU+$nM#+H?Ac;p=R!AspU3}bEy3u09@zH;D&K$MUiP9^VPM}A zn0yUz@oQ`WXR}6@i^m}8$LPi}y2;q!<$@?&`yc0mU$<41JpYcXXjnkk6-fC%80Z>o zVO;tC1Zh`K&`&4m=M#)8=22d*sE3oOsRy1SZO|zid5VjVe-w{5%3MU5cZ!x4jiNL~ zF3OHmXrQO)V9`)^0tI=PhEZ!ol`ftl<=azqgGYs$z%@0fK^EdUO-k-*8h4tNf`_o< zD=g$ggnV?G7PAmsq3Xm<=;kqf7K6_jZbOtWPSZXkij3uq)2ehO@Ml zl{bK*30{i6K1a&gb9DKfKSia@xTb+!q}Kk}-PgWpX&;M>9n8hXyAO!SDsdV}-poiI zbe@#K=V{b=8V|z)PmHO8KN~$Cdg(cI0W)zI=+p(eaG_`w;;uNO;my8?!y*@H@kReC zEKd@r{r7A%P;tVsMe$jwt)D(*YxjpUANo zej;}n@ortG+r=}67jkK#uIi{VGZ62x0`lh(3$_=igHW^xoEU*4o+ zJS2dIQJek zq8z(L$Big{G_V+cG~7bGUvJT!;+agjP0G~UH0?IaK7fY2vS!m?g($0U(-B(NVD>o9-oS2ABaeB9P# zodMN>4}#wZPy_fZ_!9t+0Zg~0X2bdg}(++3-~YaF92!-e+Bpm2d_)KGC4qfj0#-0lpBvhy4bA4F2bUX28dyqB;Va1OFQS z4!~2ue}R7$@HFsPRA3cA3*epMcL1~m{vs;V28adz5GwN|@K(Uz0NxhR8u)1V{Q%DZ z{~Q&y5taBX@K99LZTxNnyc+QGfH>fN;J*xb4){#?qXF^2+4t4z0onp@fy$Ht?SP+0 zMLAJ%&jY^${05*s@cO8b^89e@Pj@u=9x03Cr(hd&JP z67X@T8TfUjSjL07wGf z5W->sBm;jH!txDpJMbI8*8@_3*Mi`b2XqG>*$8s|q#*PFz6tnhfCIR*G2R381YW)g z^aLOk_&)gC0BOL7HWh@vfOOz}n}MHz4B%N1q8Q$f2-gTeAK+~v zTrB{91s(?BvH-GyAB4Xh(3i!Bps_34-vOTZ9O@bHH{g%PLk|Jo1^zw!vw(iUSGPsI z0Nw+h-3~MX`U7tTp?eZA0Jz#7{Q~fTz`p?gDPR!ro*huPfWg2&fB;Sa3<16k0=OP9 z6!<*|;4Q%Wz^l9jJqj2Gyi_Of2ap3i2txOF;KPCc1pEqM1n}ywLIwaMfp><`y#N>m z{E5z}U%+VKH6U~k0mcCT9R3EtSm5~(z=;44@ONJWzX7?xrPl@FN8sate+Ik&Fdq1D z2xEW11mNL`XoG->zz@J@*I7;iJ^_L`0x%hP6a+IAkOzDj{JDTBz}qK7PXML@XF_@# z_%z@ZftLVG2i^pJ9l#9W6(F#=5a5}>&jCLM_yG9Y9)hq0kPrMM`~!elz<-2)1uz@< z9tiaWz&zmB;9mgD2d+cFnUF64UKM^6U?K2l;Wq;;0`7#L1o#m6`|#fdd<6W_R6+O^ z_+sFlfj-fB47jXLGayxjlieF z9|!mt_-6R40iOVW?@hEbz$V~x;O7B015e0;o(60I-Wz^8U@P!vTp8}6W!^N%D z!e_vnz^@C~2Ap~c!Vkbd2mT1~D8P2$7vY}->;PWsE$9lsPT+OmR|V_>9tZy^z;57a z@Dl-hfak&=0N4xsBlxobUjW|+|1-co;GVb9&H(#?uYvy|-~jMMD2z^kgTRNv&juU< z{sH`nfWyGo!(RqC0{j&GgMg#JgZh9L;9ml-47@bp81T068v%|3Pl4YBZ~}Ng_-_GD z0?&s(5%3l8o$%KIP60m;|2W_@@UXu^hX6kV{88YQ0AB-d1-~)iEb#8|y8zAs9|iw! zfb+oT!=Dbg0DKqxO@MEJkIsf30$c>X68-|fx4_@+3wZz#ngObx*|SW3m@O-m#6uZ= z8hi_T4qt&EiAXGdB77FV7aSJ<5_}dv9zR%oe8!Z=Kg$B~m1%Zmvf=XE>)3sY0DQ=i zLW~74? Date: Thu, 10 Oct 2019 20:46:07 +0800 Subject: [PATCH 005/103] =?UTF-8?q?=E5=AE=9A=E4=BD=8Dtravis-ci=E5=8D=87?= =?UTF-8?q?=E7=BA=A7mono=E7=89=88=E6=9C=AC=E5=90=8E=E6=9C=89=E4=B8=AA?= =?UTF-8?q?=E7=94=A8=E4=BE=8B=E4=B8=8D=E8=BF=87=EF=BC=8C=E6=89=93=E5=8D=B0?= =?UTF-8?q?ci=E7=8E=AF=E5=A2=83=E4=B8=8B=E5=85=B6=E7=94=9F=E6=88=90?= =?UTF-8?q?=E7=9A=84=E6=8C=87=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index d3d5805..a59cd0b 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1102,6 +1102,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { var msIl = msIls[i]; //Console.WriteLine("msIl:" + msIl.OpCode.Code + ", idx:" + code.Count); + if (method.Name == "ToString" && method.DeclaringType.Name == "ValueTypeCounter") Console.WriteLine("il code:" + msIl.OpCode.Code + ",operand:" + msIl.Operand); string strCode = msIls[i].OpCode.Code.ToString(); if (strCode.EndsWith("_S")) From 090ccf5bea0549b6cb62e92b66208216220eb4b7 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 10 Oct 2019 21:21:32 +0800 Subject: [PATCH 006/103] =?UTF-8?q?1=E3=80=81=E5=9B=9E=E9=80=80ci=E5=AE=9A?= =?UTF-8?q?=E4=BD=8D=E7=9A=84=E6=8C=87=E4=BB=A4=E6=89=93=E5=8D=B0=EF=BC=9B?= =?UTF-8?q?=202=E3=80=81=E6=8A=9BTargetException=E7=9A=84=E6=97=B6?= =?UTF-8?q?=E5=80=99=EF=BC=8C=E6=89=93=E5=8D=B0=E6=9B=B4=E5=A4=9A=E4=BF=A1?= =?UTF-8?q?=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Src/Core/ReflectionMethodInvoker.cs | 63 +++++++++++-------- Source/VSProj/Src/Tools/CodeTranslator.cs | 1 - 2 files changed, 36 insertions(+), 28 deletions(-) diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index b1f01e9..798b527 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -183,33 +183,42 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI } } } - //catch (TargetInvocationException 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; - //} + catch (TargetException e) + { + Console.WriteLine("exception method: " + method + ", in " + method.DeclaringType + ", msg:" + + e.InnerException); + for (int i = 0; i < paramCount; i++) + { + Console.WriteLine("arg " + i + " type: " + (args[i] == null ? "null" : args[i].GetType() + .ToString()) + " value: " + args[i]); + } + throw 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++) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index a59cd0b..d3d5805 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1102,7 +1102,6 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { var msIl = msIls[i]; //Console.WriteLine("msIl:" + msIl.OpCode.Code + ", idx:" + code.Count); - if (method.Name == "ToString" && method.DeclaringType.Name == "ValueTypeCounter") Console.WriteLine("il code:" + msIl.OpCode.Code + ",operand:" + msIl.Operand); string strCode = msIls[i].OpCode.Code.ToString(); if (strCode.EndsWith("_S")) From 5a1208532681b7bcbf0f0745e0878052a7375ddd Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 10 Oct 2019 22:06:09 +0800 Subject: [PATCH 007/103] =?UTF-8?q?ci=E5=A4=B1=E8=B4=A5=E7=9A=84=E5=8E=9F?= =?UTF-8?q?=E5=9B=A0=EF=BC=9Atravis=E6=9B=B4=E6=96=B0mono=E5=90=8E?= =?UTF-8?q?=E5=AF=B9"ValueTypeCounter=20{=20"=20+=20i=20+=20"=20}"?= =?UTF-8?q?=E4=BA=A7=E7=94=9F=E7=9A=84=E6=8C=87=E4=BB=A4=E6=98=AF=E8=B0=83?= =?UTF-8?q?=E7=94=A8i=E7=9A=84tostring=EF=BC=8C=E7=84=B6=E5=90=8E=E8=B0=83?= =?UTF-8?q?=E7=94=A8string=E7=89=88=E6=9C=AC=E7=9A=84String::Concat?= =?UTF-8?q?=EF=BC=8C=E5=85=B6=E4=B8=ADi=E7=9A=84tostring=E6=98=AF=E7=94=A8?= =?UTF-8?q?Call=E6=8C=87=E4=BB=A4=E8=B0=83=E7=94=A8=EF=BC=8C=E8=80=8C?= =?UTF-8?q?=E5=8E=9F=E5=85=88=E7=9A=84=E6=8C=87=E4=BB=A4=E5=A4=84=E7=90=86?= =?UTF-8?q?=E8=AE=A4=E4=B8=BA=E7=94=A8Call=E6=8C=87=E4=BB=A4=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=90=8C=E7=AD=BE=E5=90=8D=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E4=B8=94=E5=BD=93=E5=89=8D=E6=96=B9=E6=B3=95=E5=AF=B9=E7=88=B6?= =?UTF-8?q?=E7=B1=BBoverrirde=E4=BA=86=EF=BC=8C=E5=B0=B1=E8=AE=A4=E4=B8=BA?= =?UTF-8?q?=E6=98=AFbase=E8=B0=83=E7=94=A8=EF=BC=8C=E5=85=B6=E5=AE=9E?= =?UTF-8?q?=E5=BA=94=E8=AF=A5=E8=BF=98=E9=9C=80=E8=A6=81=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=E8=A2=AB=E8=B0=83=E7=94=A8=E6=96=B9=E6=B3=95=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=98=AF=E5=9F=BA=E7=B1=BB=E7=9A=84=E6=96=B9=E6=B3=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Src/Core/ReflectionMethodInvoker.cs | 63 ++++++++----------- Source/VSProj/Src/Tools/CodeTranslator.cs | 38 ++++++++--- 2 files changed, 55 insertions(+), 46 deletions(-) diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index 798b527..b866cf2 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -183,42 +183,33 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI } } } - catch (TargetException e) - { - Console.WriteLine("exception method: " + method + ", in " + method.DeclaringType + ", msg:" - + e.InnerException); - for (int i = 0; i < paramCount; i++) - { - Console.WriteLine("arg " + i + " type: " + (args[i] == null ? "null" : args[i].GetType() - .ToString()) + " value: " + args[i]); - } - throw 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; - } + //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++) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index d3d5805..b8ad201 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1421,7 +1421,25 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, var methodIdInfo = getMethodId(methodToCall, method, or != null || directCallVirtual, injectTypePassToNext); - if (msIl.OpCode.Code == Code.Call && baseProxy != null + bool callingBaseMethod = false; + + try + { + var callingType = methodToCall.DeclaringType; + var baseType = method.DeclaringType.BaseType; + while (baseType != null) + { + if (callingType.IsSameType(baseType)) + { + callingBaseMethod = true; + break; + } + baseType = baseType.Resolve().BaseType; + } + } + catch { } + + if (callingBaseMethod && msIl.OpCode.Code == Code.Call && baseProxy != null && isTheSameDeclare(methodToCall, method)) { code.Add(new Core.Instruction @@ -1667,15 +1685,15 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } } catch(Exception e) - { - if (mode == ProcessMode.Inject) - { - Console.WriteLine("Warning: process " + method + " il throw " + e); - } - else - { - throw e; - } + { + if (mode == ProcessMode.Inject) + { + Console.WriteLine("Warning: process " + method + " il throw " + e); + } + else + { + throw e; + } } //Console.WriteLine("process finish:" + method); From d818d9d0573ca59762fa87a8349c3146fa15ac19 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 10 Oct 2019 22:17:49 +0800 Subject: [PATCH 008/103] unix lf --- Source/VSProj/Src/Tools/CodeTranslator.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index b8ad201..daf9c51 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1423,18 +1423,18 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, bool callingBaseMethod = false; - try - { + try + { var callingType = methodToCall.DeclaringType; var baseType = method.DeclaringType.BaseType; - while (baseType != null) - { - if (callingType.IsSameType(baseType)) - { - callingBaseMethod = true; - break; - } - baseType = baseType.Resolve().BaseType; + while (baseType != null) + { + if (callingType.IsSameType(baseType)) + { + callingBaseMethod = true; + break; + } + baseType = baseType.Resolve().BaseType; } } catch { } From b10ecc1959482e0e30b7b3ab872d84333fd65fbd Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 11 Oct 2019 09:41:21 +0800 Subject: [PATCH 009/103] =?UTF-8?q?=E6=8A=8AIFix.Core.dll=E7=9A=84meta?= =?UTF-8?q?=E6=96=87=E4=BB=B6=E6=8F=90=E4=BA=A4=EF=BC=8C=E9=98=B2=E6=AD=A2?= =?UTF-8?q?=E4=B8=8B=E8=BD=BD=E4=BB=A3=E7=A0=81=E5=90=8EAssets/Plugins?= =?UTF-8?q?=E7=9B=AE=E5=BD=95=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/Plugins/IFix.Core.dll.meta | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta diff --git a/Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta b/Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta new file mode 100644 index 0000000..ae7e328 --- /dev/null +++ b/Source/UnityProj/Assets/Plugins/IFix.Core.dll.meta @@ -0,0 +1,33 @@ +fileFormatVersion: 2 +guid: 7c6cf326f60d243479929e308c3123fb +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: From 3861a2cd5d2ba33e1d38babb12d128d018d86e1b Mon Sep 17 00:00:00 2001 From: Rayan Date: Fri, 11 Oct 2019 10:25:13 +0800 Subject: [PATCH 010/103] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=96=87=E6=9C=AC?= =?UTF-8?q?=E7=BC=96=E7=A0=81=EF=BC=8C=E9=81=BF=E5=85=8D=E5=9C=A8=E5=85=B6?= =?UTF-8?q?=E4=BB=96=E5=B9=B3=E5=8F=B0=E6=98=BE=E7=A4=BA=E4=B9=B1=E7=A0=81?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#28)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 文本编码从GB2312改成utf-8,避免显示乱码 * 文本编码从GB2312改成utf-8,避免显示乱码 --- Doc/faq.md | 30 ++-- Doc/quick_start_en.md | 2 +- Source/Misc/LiveDotNet/Editor/LiveDotNet.cs | 18 +- .../LiveDotNet/Editor/LiveDotNetConfig.cs | 6 +- Source/Misc/LiveDotNet/PatchReceiver.cs | 26 +-- Source/Misc/LiveDotNet/RotateCube.cs | 6 +- Source/UnityProj/Assets/Helloworld/Calc.cs | 4 +- .../Assets/Helloworld/Editor/HelloworldCfg.cs | 6 +- Source/VSProj/Src/Core/AnonymousStorey.cs | 2 +- Source/VSProj/Src/Core/GenericDelegate.cs | 56 +++--- Source/VSProj/Src/Core/ObjectClone.cs | 2 +- .../Src/Core/ReflectionMethodInvoker.cs | 10 +- Source/VSProj/Src/Core/StackOperation.cs | 28 +-- Source/VSProj/Src/Core/SwitchFlags.cs | 6 +- Source/VSProj/Src/Core/Utils.cs | 20 +-- Source/VSProj/Src/Core/WrappersManager.cs | 10 +- Source/VSProj/Src/PerfTest/PerfTest.cs | 10 +- Source/VSProj/Src/TestDLL/BaseTest.cs | 22 +-- Source/VSProj/Src/TestDLL/RedirectBaseTest.cs | 22 +-- Source/VSProj/Src/Tools/CSFix.cs | 22 +-- Source/VSProj/Src/Tools/CecilExtensions.cs | 94 +++++----- Source/VSProj/Src/Tools/CodeTranslator.cs | 164 +++++++++--------- Source/VSProj/Src/Tools/GenerateConfigure.cs | 32 ++-- Source/VSProj/Src/Version.cs | 2 +- 24 files changed, 300 insertions(+), 300 deletions(-) diff --git a/Doc/faq.md b/Doc/faq.md index 494bd3b..e613153 100644 --- a/Doc/faq.md +++ b/Doc/faq.md @@ -1,32 +1,32 @@ -## ִ��Patch for android����Patch for iosʱ������"please put template file for android/ios in IFixToolKit directory!�� +## 执行Patch for android或者Patch for ios时,报“"please put template file for android/ios in IFixToolKit directory!” -������������Ҫ����һ������ģ���ļ��ŵ�IFixToolKitĿ¼�� +解决这个错误需要制作一个编译模版文件放到IFixToolKit目录: -* ��������������android��ģ�棬��ִ��һ����ͨ��android�������ڹ����Ĺ����У���������Ŀ¼/Temp��Ŀ¼��UnityTempFile��ͷ���ļ�����������������һ����UnityTempFile��ͷ�����ļ�������ոմ���������ļ������Ը����ļ�ʱ������ļ���ͷ�������в�����ios������ôһ�У�-define:UNITY_IOS��android����-define:UNITY_ANDROID�����ұ���û��UNITY_EDITOR���ҵ�����������IFixToolKitĿ¼���������window��ȡ��UnityTempFile��������Ϊandroid.win.tpl�������mac�»�ȡ�ģ�������Ϊandroid.osx.tpl�����ⲽ����һ����Ŀ������㲻����unity�汾����������������꣬������һ�μ��ɣ� -* ios��ģ���ļ�����Ϊios.osx.tpl�������ϣ����window������ios����������һ�ݸ���Ϊios.win.tpl��������ļ��������ӵ�����dll��ϵͳ��dll��·����window��unity��װĿ¼�޸ġ� +* 假如你制作的是android的模版,请执行一次普通的android构建,在构建的过程中,到“工程目录/Temp”目录把UnityTempFile打头的文件都拷贝出来,其中一个“UnityTempFile开头”的文件就是你刚刚打包命令行文件,可以根据文件时间或者文件里头的命令行参数(ios会有这么一行:-define:UNITY_IOS,android会有-define:UNITY_ANDROID,而且必须没有UNITY_EDITOR)找到它,拷贝到IFixToolKit目录,如果你在window获取的UnityTempFile,重命名为android.win.tpl,如果是mac下获取的,重命名为android.osx.tpl;(这步对于一个项目,如果你不升级unity版本,不更改条件编译宏,仅需做一次即可) +* ios的模版文件改名为ios.osx.tpl,如果你希望在window下制作ios补丁,复制一份改名为ios.win.tpl,打开这个文件,把链接的引擎dll,系统级dll的路径按window的unity安装目录修改。 -## IL2CPP ���ֱ���`IL2CPP error for method 'System.Object IFix.Core.EvaluationStackOperation::ToObject(IFix.Core.Value*,IFix.Core.Value*,System.Object[],System.Type,IFix.Core.VirtualMachine,System.Boolean)'` +## IL2CPP 出现报错`IL2CPP error for method 'System.Object IFix.Core.EvaluationStackOperation::ToObject(IFix.Core.Value*,IFix.Core.Value*,System.Object[],System.Type,IFix.Core.VirtualMachine,System.Boolean)'` -Ӧ�����Լ��ֶ�����`IFix.Core.dll`���� +应该是自己手动编译`IFix.Core.dll`导致 -�޸�iFix.CoreԴ�������Ҫͨ��`build_for_unity.bat`�ű����й��� +修改iFix.Core源代码后,需要通过`build_for_unity.bat`脚本进行构建 -## ���� Patch ��ʱ������`Error: the new assembly must not be inject, please reimport the project!`���� +## 生成 Patch 的时候遇到`Error: the new assembly must not be inject, please reimport the project!`报错 -���� Patch �� dll�����ܽ���ע�� +生成 Patch 的 dll,不能进行注入 -## ���������������������δ��� +## 补丁制作的条件编译宏如何处理 -�����Unity2018.3�汾�����ϣ�����Unity������C#����ӿڣ�����InjectFix��Unity2018.3�汾ֱ��֧��Android��iOS�IJ������ɣ�ֱ��ִ�ж�Ӧ�˵����ɡ� +如果是Unity2018.3版本及以上,由于Unity开放了C#编译接口,所以InjectFix在Unity2018.3版本直接支持Android和iOS的补丁生成,直接执行对应菜单即可。 -���������Unity2018.3�汾����Ҫ�ñȽ��鷳�ķ�ʽ������Ӧƽ̨�ı��������Assembly-CSharp.dll���������Ȼ�����IFix.Editor.IFixEditor.GenPatchȥ���ɲ����� +但如果低于Unity2018.3版本,则要用比较麻烦的方式:按对应平台的编译参数把Assembly-CSharp.dll编译出来,然后调用IFix.Editor.IFixEditor.GenPatch去生成补丁。 -Unity�������ڹ��̵�TempĿ¼�½�һ���ļ����������в����ŵ��Ǹ��ļ���Ȼ��ִ�����ƣ�Ŀ¼�����Լ���unity��װ�������������������б��룺 +Unity编译是在工程的Temp目录新建一个文件,把命令行参数放到那个文件,然后执行类似(目录根据自己的unity安装情况而定)如下命令进行编译: ~~~bash "D:\Program Files\Unity201702\Editor\Data\MonoBleedingEdge\bin\mono.exe" "D:\Program Files\Unity201702\Editor\Data\MonoBleedingEdge\lib\mono\4.5\mcs.exe" @Temp/UnityTempFile-55a959adddae39f4aaa18507dd165989 ~~~ -����Գ���һ�α༭���µ��ֻ��汾�����Ȼ�󵽹���Ŀ¼�µ�TempĿ¼���Ǹ���ʱ�ļ�������������������Զ�ɾ��������Ҫ�ֿ죩�� +你可以尝试一次编辑器下的手机版本打包,然后到工程目录下的Temp目录把那个临时文件拷贝出来(编译完会自动删掉,所以要手快)。 -����ļ�������ط��������ģ������Ҫ��C#�ļ��б������Ը�Ϊ��̬��������ļ���C#�ļ��б����ݵ�ǰ��Ŀ���ɣ��������ֲ��䡣Ȼ��������ļ���Ϊ���������롣 +这个文件大多数地方都不会变的,变的主要是C#文件列表,可以改为动态生成这个文件:C#文件列表根据当前项目生成,其它保持不变。然后用这个文件作为输入来编译。 diff --git a/Doc/quick_start_en.md b/Doc/quick_start_en.md index c49c4b4..9790bd7 100644 --- a/Doc/quick_start_en.md +++ b/Doc/quick_start_en.md @@ -1,4 +1,4 @@ -## Quick Start +## Quick Start ### Access example diff --git a/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs b/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs index 2af7dff..164a819 100644 --- a/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs +++ b/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs @@ -14,10 +14,10 @@ namespace IFix.Editor { - //����������Ϣ�� - // 1��ƽ̨��ios��android�� - // 2���ֻ���ip��ַ - // 3���˿���Ϣ���˿���ϢҪ��PatchReceiver���ö�Ӧ�� + //输入三个信息: + // 1、平台(ios、android) + // 2、手机的ip地址 + // 3、端口信息,端口信息要和PatchReceiver配置对应上 public class LiveDotNet : EditorWindow { private int platformIndex = 0; @@ -41,8 +41,8 @@ void OnGUI() doPatch(); } - //1��IFixEditor.GenPlatformPatch���������ɲ����ļ� - //2�����͸��ֻ� + //1、IFixEditor.GenPlatformPatch会生成生成补丁文件 + //2、发送给手机 void doPatch() { IFixEditor.Platform platform = platformIndex == 0 ? IFixEditor.Platform.ios : IFixEditor.Platform.android; @@ -60,9 +60,9 @@ void doPatch() File.Delete(patchPath); } - //1�����ֻ�����TCP���� - //2������������ - //3���ر����� + //1、对手机建立TCP链接 + //2、发送整个包 + //3、关闭链接 void doSend(byte[] bytes, IPEndPoint remoteEndPoint) { try diff --git a/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs b/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs index 306688e..1c74cb5 100644 --- a/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs +++ b/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs @@ -9,8 +9,8 @@ using IFix; using System; -//1������������[Configure]��ǩ -//2�������EditorĿ¼ +//1、配置类必须打[Configure]标签 +//2、必须放Editor目录 [Configure] public class LiveDotNetConfig { @@ -21,7 +21,7 @@ static IEnumerable hotfix { return new List() { - //��ʾ���� + //演示的类 typeof(RotateCube) }; } diff --git a/Source/Misc/LiveDotNet/PatchReceiver.cs b/Source/Misc/LiveDotNet/PatchReceiver.cs index 9b1a367..2b4c565 100644 --- a/Source/Misc/LiveDotNet/PatchReceiver.cs +++ b/Source/Misc/LiveDotNet/PatchReceiver.cs @@ -5,9 +5,9 @@ * This file is subject to the terms and conditions defined in file 'LICENSE', which is part of this source code package. */ -//!!�����򵥵Ŀ�tcp�����յ�����û��У���ֱ��ִ�� -//!!�����м������������ƽʱ��������ʹ�� -//!!������Ϸ���������ɾ�� +//!!仅仅简单的开tcp,接收到数据没做校验就直接执行 +//!!所以切记这个仅仅用于平时开发调试使用 +//!!最终游戏发布包务必删除 #warning "Please remove PatchReceiver.cs from release package." using UnityEngine; @@ -22,32 +22,32 @@ namespace IFix { public class PatchReceiver : MonoBehaviour { - //Ĭ�ϵIJ����ļ������� + //默认的补丁文件保存名 const string PERSISTENT_FILE_NAME = "__LAST_RUN_SAVED_PATCH"; - //���ջ������Ĵ�С + //接收缓冲区的大小 const int BUFFER_SIZE = 1024; Stream patch = null; - //��Ҫ��LiveDotNet.cs�Ķ˿����� + //需要跟LiveDotNet.cs的端口配套 public int Port = 8080; - //�������Ϊtrue�Ļ��������ļ��ᱣ�浽�ļ�������Ӧ�ú���Ȼ��Ч + //这个设置为true的话,补丁文件会保存到文件,重启应用后仍然生效 public bool Persistent = false; Socket listener = null; string lastRunSavePath; - //1������ - //2��accpet�����Ӻ󣬽��ո������������� - //3����������Ϊ���������� + //1、监听 + //2、accpet到链接后,接收该链接所有数据 + //3、把数据作为补丁包加载 void ReceivePatch() { byte[] bytes = new byte[BUFFER_SIZE]; - //�������е�ַ + //监听所有地址 IPAddress ipAddress = IPAddress.Parse("0.0.0.0"); IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Port); @@ -107,7 +107,7 @@ void ReceivePatch() } } - //��������˳־û�����Awakeʱ�����ϴα���IJ����ļ� + //如果设置了持久化,在Awake时加载上次保存的补丁文件 void Awake() { lastRunSavePath = Application.persistentDataPath + Path.DirectorySeparatorChar + PERSISTENT_FILE_NAME; @@ -119,7 +119,7 @@ void Awake() } } DontDestroyOnLoad(gameObject); - //�����߳������ղ������������̣߳�����ͨ��patch�������������� + //启动线程来接收补丁,不卡主线程,两者通过patch变量来交接数据 new Thread(ReceivePatch).Start(); } diff --git a/Source/Misc/LiveDotNet/RotateCube.cs b/Source/Misc/LiveDotNet/RotateCube.cs index caa2c06..9672d75 100644 --- a/Source/Misc/LiveDotNet/RotateCube.cs +++ b/Source/Misc/LiveDotNet/RotateCube.cs @@ -8,7 +8,7 @@ using UnityEngine; using IFix; -//������ʾ�޸Ĵ��������ˢ�µ���� +//用来演示修改代码后,立即刷新到真机 public class RotateCube : MonoBehaviour { public Light theLight; @@ -16,9 +16,9 @@ public class RotateCube : MonoBehaviour [Patch] void Update() { - //��ת + //旋转 transform.Rotate(Vector3.up * Time.deltaTime * 20); - //�ı���ɫ + //改变颜色 theLight.color = new Color(Mathf.Sin(Time.time) / 2 + 0.5f, 0, 0, 1); } } diff --git a/Source/UnityProj/Assets/Helloworld/Calc.cs b/Source/UnityProj/Assets/Helloworld/Calc.cs index 3c58bce..364df68 100644 --- a/Source/UnityProj/Assets/Helloworld/Calc.cs +++ b/Source/UnityProj/Assets/Helloworld/Calc.cs @@ -7,10 +7,10 @@ namespace IFix.Test { - //HelloworldCfg.cs��������������� + //HelloworldCfg.cs里配置了这个类型 public class Calculator { - //�޸ij���ȷ���߼��󣬴�����ע�ͣ����ɵIJ����������ú��� + //修改成正确的逻辑后,打开如下注释,生成的补丁将修正该函数 //[Patch] public int Add(int a, int b) { diff --git a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs index 06f3467..6a151d9 100644 --- a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs +++ b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs @@ -9,8 +9,8 @@ using IFix; using System; -//1������������[Configure]��ǩ -//2�������EditorĿ¼ +//1、配置类必须打[Configure]标签 +//2、必须放Editor目录 [Configure] public class HelloworldCfg { @@ -23,7 +23,7 @@ static IEnumerable hotfix { typeof(Helloworld), typeof(IFix.Test.Calculator), - //AnotherClass��Pro Standard Assets�£�����뵽Assembly-CSharp-firstpass.dll�£�������ʾ��dll���޸� + //AnotherClass在Pro Standard Assets下,会编译到Assembly-CSharp-firstpass.dll下,用来演示多dll的修复 typeof(AnotherClass), }; } diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index e429c65..58c7e23 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -10,7 +10,7 @@ namespace IFix.Core { - //������ģ�� + //匿名类模拟 public class AnonymousStorey { Value[] unmanagedFields; diff --git a/Source/VSProj/Src/Core/GenericDelegate.cs b/Source/VSProj/Src/Core/GenericDelegate.cs index 4eb4c6f..f41d382 100644 --- a/Source/VSProj/Src/Core/GenericDelegate.cs +++ b/Source/VSProj/Src/Core/GenericDelegate.cs @@ -10,22 +10,22 @@ using System.Linq; using System.Reflection; -//ifix������հ�����Ահ���Ӧ��delegate���������� -//�����е������ԭ���Ǹ��ط������ñհ����޸�ʱ���˱հ�����ʱ�ᱨ�Ҳ����������Ĵ��� -//�����������ͨ��CustomBridage���������⣬���Ǻܶ�ʱ���û��޷�Ԥ֪��������� -//�������Ϊ�˼������������Ӱ�죺��������������4�����Ҿ�Ϊ�������ͣ� -//�޷���ֵ���߷���ֵ���������ͣ������ܹ�������ͨ�����ͣ��Զ������������� +//ifix会分析闭包,针对闭包对应的delegate生成适配器 +//但是有的情况是原来那个地方不是用闭包,修复时用了闭包,这时会报找不到适配器的错误。 +//这种问题可以通过CustomBridage配置来避免,但是很多时候用户无法预知这种情况。 +//这里就是为了减少这种情况的影响:参数个数不超过4个,且均为引用类型, +//无返回值或者返回值是引用类型,这里能够做到(通过泛型)自动生成适配器。 namespace IFix.Core { internal class GenericDelegateFactory { - //�޷���ֵ���ͷ��� + //无返回值泛型方法 static MethodInfo[] genericAction = null; - //�з���ֵ���ͷ��� + //有返回值泛型方法 static MethodInfo[] genericFunc = null; - //����delegate�������������Ļ��� + //泛型delegate适配器构造器的缓存 static Dictionary> genericDelegateCreatorCache = new Dictionary>(); @@ -54,7 +54,7 @@ internal static Delegate Create(Type delegateType, VirtualMachine virtualMachine Func genericDelegateCreator; if (!genericDelegateCreatorCache.TryGetValue(delegateType, out genericDelegateCreator)) { - //������ͷ�������δ��ʼ�� + //如果泛型方法数组未初始化 if (genericAction == null) { PreventStripping(null); @@ -73,20 +73,20 @@ internal static Delegate Create(Type delegateType, VirtualMachine virtualMachine || parameters.Any(p => p.ParameterType.IsValueType || p.ParameterType.IsByRef) ) { - //�������֧�ֵķ�Χ��������һ����Զ���ؿյĹ����� + //如果不在支持的范围,则生成一个永远返回空的构造器 genericDelegateCreator = (x) => null; } else { if (delegateMethod.ReturnType == typeof(void) && parameters.Length == 0) { - //���޲��޷���ֵ���⴦�� + //对无参无返回值特殊处理 var methodInfo = genericAction[0]; genericDelegateCreator = (o) => Delegate.CreateDelegate(delegateType, o, methodInfo); } else { - //���ݲ�������������ֵ�ҵ�����ʵ�� + //根据参数个数,返回值找到泛型实现 var typeArgs = parameters.Select(pinfo => pinfo.ParameterType); MethodInfo genericMethodInfo = null; if (delegateMethod.ReturnType == typeof(void)) @@ -96,39 +96,39 @@ internal static Delegate Create(Type delegateType, VirtualMachine virtualMachine else { genericMethodInfo = genericFunc[parameters.Length]; - //������з���ֵ����Ҫ���Ϸ���ֵ��Ϊ����ʵ�� + //如果是有返回值,需要加上返回值作为泛型实参 typeArgs = typeArgs.Concat(new Type[] { delegateMethod.ReturnType }); } - //ʵ�������ͷ��� + //实例化泛型方法 var methodInfo = genericMethodInfo.MakeGenericMethod(typeArgs.ToArray()); - //������ + //构造器 genericDelegateCreator = (o) => Delegate.CreateDelegate(delegateType, o, methodInfo); } } - //���湹�������´ε���ֱ�ӷ��� + //缓存构造器,下次调用直接返回 genericDelegateCreatorCache[delegateType] = genericDelegateCreator; } - //����delegate + //创建delegate return genericDelegateCreator(new GenericDelegate(virtualMachine, methodId, anonObj)); } } - //���������� + //泛型适配器 internal class GenericDelegate { - //ָ������������ + //指向的虚拟机对象 VirtualMachine virtualMachine; - //���������id + //虚拟机方法id int methodId; - //�󶨵��������� + //绑定的匿名对象 object anonObj; - //Ԥ���㣬�Ƿ�Ҫ��anonObj push�ı�־δ + //预计算,是否要把anonObj push的标志未 bool pushSelf; - //Ԥ���㣬�����anonObj����������Ҫ+1 + //预计算,如果有anonObj参数个数则要+1 int extraArgNum; internal GenericDelegate(VirtualMachine virtualMachine, int methodId, object anonObj) @@ -153,16 +153,16 @@ public void Action() public void Action(T1 p1) where T1 : class { - //����call���� + //创建call对象 Call call = Call.Begin(); if (pushSelf) { - //����а󶨵���������push + //如果有绑定的匿名对象,push call.PushObject(anonObj); } - //push��һ������ + //push第一个参数 call.PushObject(p1); - //����ָ��id����������� + //调用指定id的虚拟机方法 virtualMachine.Execute(methodId, ref call, 1 + extraArgNum); } @@ -237,7 +237,7 @@ public TResult Func(T1 p1) } call.PushObject(p1); virtualMachine.Execute(methodId, ref call, 1 + extraArgNum); - //��ջ�ϻ�ȡ��� + //从栈上获取结果 return (TResult)call.GetObject(); } diff --git a/Source/VSProj/Src/Core/ObjectClone.cs b/Source/VSProj/Src/Core/ObjectClone.cs index 656cb8c..76d193b 100644 --- a/Source/VSProj/Src/Core/ObjectClone.cs +++ b/Source/VSProj/Src/Core/ObjectClone.cs @@ -28,7 +28,7 @@ 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 = Expression.Lambda>(mce, p).Compile();//TODO: 需要用到jit么? } public object Clone(object obj) diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index b866cf2..073da8d 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -134,7 +134,7 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI if (isInstantiate || (method.IsConstructor && method.DeclaringType.IsValueType)) { - ret = ctor.Invoke(args);//TODO: Delegate������Delegate.CreateDelegate + ret = ctor.Invoke(args);//TODO: Delegate创建用Delegate.CreateDelegate } else { @@ -144,10 +144,10 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI instance = EvaluationStackOperation.ToObject(call.evaluationStackBase, call.argumentBase, managedStack, method.DeclaringType, virtualMachine, false); } - //Nullable��Ȼ��ֵ���ͣ�ֻ���������Ƿ�Ϊnull�ı�־λ����Ȼͨ������ַ�ķ�ʽ���з������ã� - //�����ڷ�������в�ͨ��������object���ͣ�boxing��object����null�����Իᴥ�� - //��Non-static method requires a target���쳣 - //������ֻ�����⴦��һ�� + //Nullable仍然是值类型,只是新增了是否为null的标志位,仍然通过传地址的方式进行方法调用, + //但这在反射调用行不通,参数是object类型,boxing到object就是null,所以会触发 + //“Non-static method requires a target”异常 + //所以这只能特殊处理一下 if (isNullableHasValue) { ret = (instance != null); diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index 1a300c0..1f6624d 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -40,8 +40,8 @@ public ThreadStackInfo() ManagedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; } - //ȥ���������������ԣ���̬���������������������������ͷŵĻ���ͨ��Marshal.AllocHGlobal����ķ��й� - //�ڴ�Ӧ��Ҳ���Զ��ͷŰɣ� + //去掉析构,正常而言,静态变量不会析构,如果整个虚拟机释放的话,通过Marshal.AllocHGlobal分配的非托管 + //内存应该也会自动释放吧? //~ThreadStackInfo() //{ // //VirtualMachine._Info("~ThreadStackInfo"); @@ -55,11 +55,11 @@ public ThreadStackInfo() // Marshal.FreeHGlobal(unmanagedStackHandler); //} - //����ThreadStatic�Ǻܺ��ʵķ���������˵Unity�µ�ThreadStatic��Crash�� - //Unity�ĵ���https://docs.unity3d.com/Manual/Attributes.html - //���issue���ӣ�https://issuetracker.unity3d.com/issues/ + //本来ThreadStatic是很合适的方案,但据说Unity下的ThreadStatic会Crash, + //Unity文档:https://docs.unity3d.com/Manual/Attributes.html + //相关issue链接:https://issuetracker.unity3d.com/issues/ // e-document-threadstatic-attribute-must-not-be-used-i-will-cause-crashes - //issue���ݣ� + //issue内容: //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 @@ -224,8 +224,8 @@ internal static void mSet(bool isArray, object root, object val, int layer, int[ internal static unsafe object ToObject(Value* evaluationStackBase, Value* evaluationStackPointer, object[] managedStack, Type type, VirtualMachine virtualMachine, bool valueTypeClone = true) { - //δ��ʼ����local���ÿ�����Ϊout����������� - //TODO: ��ֵ֤����out��������Ӧ����λ���Ƿ������null�� + //未初始化的local引用可能作为out参数反射调用 + //TODO: 验证值类型out参数,对应参数位置是否可以是null? switch (evaluationStackPointer->Type) { case ValueType.Integer: @@ -407,7 +407,7 @@ public static void PushObject(Value* evaluationStackBase, Value* evaluationStack } public static void UpdateReference(Value* evaluationStackBase, Value* evaluationStackPointer, - object[] managedStack, object obj, VirtualMachine virtualMachine, Type type) //����ר�� + object[] managedStack, object obj, VirtualMachine virtualMachine, Type type) //反射专用 { switch (evaluationStackPointer->Type) { @@ -460,7 +460,7 @@ public static void UpdateReference(Value* evaluationStackBase, Value* evaluation } break; } - case ValueType.StaticFieldReference://������ϣ�ֱ��return + case ValueType.StaticFieldReference://更新完毕,直接return { var fieldIndex = evaluationStackPointer->Value1; if (fieldIndex >= 0) @@ -487,7 +487,7 @@ unsafe public struct Call internal object[] managedStack; - internal Value* currentTop;//����push״̬ + internal Value* currentTop;//用于push状态 internal Value** topWriteBack; @@ -706,7 +706,7 @@ public T GetAsType(int offset = 0) return (T)GetObject(offset); } - public void PushObjectAsResult(object obj, Type type) //����ר�� + public void PushObjectAsResult(object obj, Type type) //反射专用 { EvaluationStackOperation.PushObject(evaluationStackBase, argumentBase, managedStack, obj, type); currentTop = argumentBase + 1; @@ -720,7 +720,7 @@ public void PushRef(int offset) currentTop++; } - public void UpdateReference(int offset, object obj, VirtualMachine virtualMachine, Type type) //����ר�� + public void UpdateReference(int offset, object obj, VirtualMachine virtualMachine, Type type) //反射专用 { EvaluationStackOperation.UpdateReference(ThreadStackInfo.Stack.UnmanagedStack->Base, argumentBase + offset, managedStack, obj, virtualMachine, type); @@ -728,7 +728,7 @@ public void PushRef(int offset) public static void End(ref Call call) { - //Top��ά�� + //Top的维护 //ThreadStackInfo.Stack.UnmanagedStack->Top = call.argumentBase; } } diff --git a/Source/VSProj/Src/Core/SwitchFlags.cs b/Source/VSProj/Src/Core/SwitchFlags.cs index 256c92a..3aeab23 100644 --- a/Source/VSProj/Src/Core/SwitchFlags.cs +++ b/Source/VSProj/Src/Core/SwitchFlags.cs @@ -9,19 +9,19 @@ namespace IFix { - //�л�������ִ�� + //切换到解析执行 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] public class InterpretAttribute : Attribute { } - //ֱ����Ҫ���ɲ����ķ����ϴ��ǩ + //直接在要做成补丁的方法上打标签 [AttributeUsage(AttributeTargets.Method)] public class PatchAttribute : Attribute { } - //�����ֶ�ָ��Ҫ����delegate����Ҫ���ڱհ�����interface������������﷨�ǣ����Ž� + //可以手动指定要生成delegate(主要用于闭包)、interface(比如迭代器语法糖)的桥接 [AttributeUsage(AttributeTargets.Class)] public class CustomBridgeAttribute : Attribute { diff --git a/Source/VSProj/Src/Core/Utils.cs b/Source/VSProj/Src/Core/Utils.cs index 1fe4a16..746451b 100644 --- a/Source/VSProj/Src/Core/Utils.cs +++ b/Source/VSProj/Src/Core/Utils.cs @@ -11,15 +11,15 @@ namespace IFix.Core { - //�����ʹ�ø������� + //虚拟机使用给工具类 public static class Utils { /// - /// �ж�һ�������Ƿ��ܸ�ֵ��һ��delegate���� + /// 判断一个方法是否能赋值到一个delegate变量 /// - /// delegate������������ͷ��invoke���� - /// ����ֵ�ķ��� - /// �Ƿ��ܸ�ֵ + /// delegate变量的类型里头的invoke方法 + /// 待赋值的方法 + /// 是否能赋值 public static bool IsAssignable(MethodInfo delegateMethod, MethodInfo method) { if (delegateMethod == null || method == null) @@ -49,15 +49,15 @@ public static bool IsAssignable(MethodInfo delegateMethod, MethodInfo method) return true; } - //�������Ļ��棬����������棬ÿ�ζ�����IsAssignableһ������ȡƥ���dz��� + //适配器的缓存,如果不做缓存,每次都调用IsAssignable一个个的取匹配会非常慢 static Dictionary delegateAdptCache = new Dictionary(); /// - /// ��һ��wrapper������ͷ�������ܹ����䵽�ض�delegate�ķ��� + /// 从一个wrapper对象里头,查找能够适配到特定delegate的方法 /// - /// wrapper���� - /// delegate���� - /// ����ǰ׺���ܹ��ų���һЩ���������繹�캯�� + /// wrapper对象 + /// delegate类型 + /// 方法前缀,能够排除掉一些方法,比如构造函数 /// public static Delegate TryAdapterToDelegate(object obj, Type delegateType, string perfix) { diff --git a/Source/VSProj/Src/Core/WrappersManager.cs b/Source/VSProj/Src/Core/WrappersManager.cs index 94a515f..7f2e564 100644 --- a/Source/VSProj/Src/Core/WrappersManager.cs +++ b/Source/VSProj/Src/Core/WrappersManager.cs @@ -9,16 +9,16 @@ namespace IFix.Core { - //�ýӿ���ע�����Զ�ʵ�� + //该接口由注入器自动实现 public interface WrappersManager { - //����һ��delegate�����anon�ǿվ��DZհ� + //创建一个delegate,如果anon非空就是闭包 Delegate CreateDelegate(Type type, int id, object anon); - //����һ��interface�Ž��� + //创建一个interface桥接器 AnonymousStorey CreateBridge(int fieldNum, int[] slots, VirtualMachine virtualMachine); - //����һ��wrapper���󣨻��ɲ��������߼����ã����������wrapper���飩 + //创建一个wrapper对象(会由补丁加载逻辑调用,创建后放入wrapper数组) object CreateWrapper(int id); - //��ʼ��wrapper���� + //初始化wrapper数组 object InitWrapperArray(int len); } } diff --git a/Source/VSProj/Src/PerfTest/PerfTest.cs b/Source/VSProj/Src/PerfTest/PerfTest.cs index 37d7afe..c54524f 100644 --- a/Source/VSProj/Src/PerfTest/PerfTest.cs +++ b/Source/VSProj/Src/PerfTest/PerfTest.cs @@ -14,7 +14,7 @@ namespace IFix.Test { public class PerfTest { - //��׼���ԣ��շ������� + //基准测试,空方法调用 static void Base() { int LOOPS = 10000000; @@ -31,12 +31,12 @@ static void Base() } } - //ͨ��Call�������add�������÷����߼����£�SimpleVirtualMachineBuilderͨ��Ӳ����ָ���� + //通过Call对象调用add方法,该方法逻辑如下,SimpleVirtualMachineBuilder通过硬编码指令获得 //int add(int a, int b) //{ // return a + b; //} - //ԭ������ͨ�����ַ�ʽ������������� + //原生方法通过这种方式调用虚拟机方法 static void SafeCall() { int LOOPS = 10000000; @@ -55,8 +55,8 @@ static void SafeCall() Console.WriteLine("SafeCall " + " : " + (LOOPS / (int)sw.Elapsed.TotalMilliseconds * 1000) + "\r\n"); } - //ֱ��ͨ��ָ�����ջ������add���� - //������ڲ������������ͨ�����ַ�ʽ + //直接通过指针操作栈,调用add方法 + //虚拟机内部方法间调用是通过这种方式 unsafe static void UnsafeCall() { IntPtr nativePointer = System.Runtime.InteropServices.Marshal.AllocHGlobal(sizeof(Value) diff --git a/Source/VSProj/Src/TestDLL/BaseTest.cs b/Source/VSProj/Src/TestDLL/BaseTest.cs index 797f570..8b784b5 100644 --- a/Source/VSProj/Src/TestDLL/BaseTest.cs +++ b/Source/VSProj/Src/TestDLL/BaseTest.cs @@ -155,11 +155,11 @@ public string F(List a) return "6"; } - //TODO: ����+���ü����� + //TODO: 泛型+引用及数组 - //TODO: ����ʵ��ͬʱ���������Ͳ������෺�Ͳ��� + //TODO: 泛型实参同时含函数泛型参数及类泛型参数 - //TODO: ����Ŀǰ���ͺ���������ִ�У����Է���ʵ���ڷ��ͺ����䴫�ݲ��ÿ��ǣ����������Ҫ֧�ַ��ͺ����Ľ���ִ�еĻ���Ҫ�������Ŀ��� + //TODO: 由于目前泛型函数不解析执行,所以泛型实参在泛型函数间传递不用考虑,但后续如果要支持泛型函数的解析执行的话,要加入这点的考虑 //public void F(List a) //{ @@ -445,14 +445,14 @@ public static void Ref(ref ValueTypeCounter l, ref ValueTypeCounter r) r = t; } - //1��leave��Ŀ�겻һ������finally block���������κεط� - //2��leaveҪ�ҵ����ڲ��finally��ת - //3��endfinally����������������leave��������������leave��Ŀ�꣬������ǣ����������쳣 - //4��Ϊ�˼���ע�����ע��಻try-catch���ɽ�������ջ���������ò���������Ҫ�������ò����ĸ��� - //5������leave��Ӧ���в���finally�IJ���������dz��� - //6��һ��finally block��ͷ��leaveָ������в�ͬ��Ŀ���ַ�����磺try{}catch{goto} - //7��leave�����һ��finally block�ڣ���Ŀ���ַ��finally��try block֮�⣬��ô���finally block����תǰִ�У� - // ����ж��������finally������ڵ���ִ�У����쳣��ʵҲ��������Ϊ������finally�� + //1、leave的目标不一定紧跟finally block,可以是任何地方 + //2、leave要找到最内层的finally跳转 + //3、endfinally有两种情况,如果是leave跳过来,则跳到leave的目标,如果不是,则重新抛异常 + //4、为了减少注入代码注入侧不try-catch,由解析器清栈,包括引用参数,所以要传入引用参数的个数 + //5、正常leave不应该有查找finally的操作,否则非常慢 + //6、一个finally block里头的leave指令,可以有不同的目标地址,比如:try{}catch{goto} + //7、leave如果在一个finally block内,而目标地址在finally的try block之外,那么这个finally block在跳转前执行, + // 如果有多个这样的finally,则从内到外执行(抛异常其实也可以理解为跳出了finally) public static void ExceptionBase(ref int p) { while (p != 100) diff --git a/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs b/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs index 0dad19a..54912ac 100644 --- a/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs +++ b/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs @@ -155,11 +155,11 @@ public string F(List a) return "6"; } - //TODO: ����+���ü����� + //TODO: 泛型+引用及数组 - //TODO: ����ʵ��ͬʱ���������Ͳ������෺�Ͳ��� + //TODO: 泛型实参同时含函数泛型参数及类泛型参数 - //TODO: ����Ŀǰ���ͺ���������ִ�У����Է���ʵ���ڷ��ͺ����䴫�ݲ��ÿ��ǣ����������Ҫ֧�ַ��ͺ����Ľ���ִ�еĻ���Ҫ�������Ŀ��� + //TODO: 由于目前泛型函数不解析执行,所以泛型实参在泛型函数间传递不用考虑,但后续如果要支持泛型函数的解析执行的话,要加入这点的考虑 //public void F(List a) //{ @@ -445,14 +445,14 @@ public static void Ref(ref ValueTypeCounter l, ref ValueTypeCounter r) r = t; } - //1��leave��Ŀ�겻һ������finally block���������κεط� - //2��leaveҪ�ҵ����ڲ��finally��ת - //3��endfinally����������������leave��������������leave��Ŀ�꣬������ǣ����������쳣 - //4��Ϊ�˼���ע�����ע��಻try-catch���ɽ�������ջ���������ò���������Ҫ�������ò����ĸ��� - //5������leave��Ӧ���в���finally�IJ���������dz��� - //6��һ��finally block��ͷ��leaveָ������в�ͬ��Ŀ���ַ�����磺try{}catch{goto} - //7��leave�����һ��finally block�ڣ���Ŀ���ַ��finally��try block֮�⣬��ô���finally block����תǰִ�У� - // ����ж��������finally������ڵ���ִ�У����쳣��ʵҲ��������Ϊ������finally�� + //1、leave的目标不一定紧跟finally block,可以是任何地方 + //2、leave要找到最内层的finally跳转 + //3、endfinally有两种情况,如果是leave跳过来,则跳到leave的目标,如果不是,则重新抛异常 + //4、为了减少注入代码注入侧不try-catch,由解析器清栈,包括引用参数,所以要传入引用参数的个数 + //5、正常leave不应该有查找finally的操作,否则非常慢 + //6、一个finally block里头的leave指令,可以有不同的目标地址,比如:try{}catch{goto} + //7、leave如果在一个finally block内,而目标地址在finally的try block之外,那么这个finally block在跳转前执行, + // 如果有多个这样的finally,则从内到外执行(抛异常其实也可以理解为跳出了finally) public static void ExceptionBase(ref int p) { while (p != 100) diff --git a/Source/VSProj/Src/Tools/CSFix.cs b/Source/VSProj/Src/Tools/CSFix.cs index d925d68..cd5fe69 100644 --- a/Source/VSProj/Src/Tools/CSFix.cs +++ b/Source/VSProj/Src/Tools/CSFix.cs @@ -53,15 +53,15 @@ static void Main(string[] args) bool readSymbols = true; try { - //���Զ�ȡ���� + //尝试读取符号 assembly = AssemblyDefinition.ReadAssembly(assmeblyPath, new ReaderParameters { ReadSymbols = true }); } catch { - //�����ȡ���������򲻶� + //如果读取不到符号则不读 Console.WriteLine("Warning: read " + assmeblyPath + " with symbol fail"); - //д���ʱ���������־ + //写入的时候用这个标志 readSymbols = false; assembly = AssemblyDefinition.ReadAssembly(assmeblyPath, new ReaderParameters { ReadSymbols = false }); @@ -71,7 +71,7 @@ static void Main(string[] args) bool isInheritInject = args[0] == "-inherit_inject"; int searchPathStart = isInheritInject ? 7 : 6; - //��resolver�����������·�� + //往resolver加入程序集搜索路径 foreach (var path in args.Skip(searchPathStart)) { try @@ -87,7 +87,7 @@ static void Main(string[] args) if (mode == ProcessMode.Inject) { - //�Բ����������⴦������������Ĭ��ȫ����ִ�� + //对测试用例特殊处理:测试用例默认全解析执行 configure = args[3] == "no_cfg" ? GenerateConfigure.Empty() : GenerateConfigure.FromFile(args[3]); @@ -96,8 +96,8 @@ static void Main(string[] args) throw new Exception("Do Not Support already!"); } - //ע���߼� - //TODO: tranlater�����ֲ�̫���� + //注入逻辑 + //TODO: tranlater的名字不太合适 if (tranlater.Process(assembly, ilfixAassembly, configure, mode) == CodeTranslator.ProcessResult.Processed) { @@ -112,13 +112,13 @@ static void Main(string[] args) } else { - //������������ + //补丁生成流程 configure = new PatchGenerateConfigure(assembly, args[4]); if (tranlater.Process(assembly, ilfixAassembly, configure, mode) == CodeTranslator.ProcessResult.Processed) { - //���ֳ����Ѿ���ע�룬��Ҫ�Ƿ�ֹ�Ѿ�ע��ĺ���������ע���߼��ᵼ����ѭ�� + //发现程序集已经被注入,主要是防止已经注入的函数包含的注入逻辑会导致死循环 Console.WriteLine("Error: the new assembly must not be inject, please reimport the project!"); return; } @@ -134,8 +134,8 @@ static void Main(string[] args) } finally { - //�������Ŷ�ȡ�� - //�������������window�»������ļ� + //清理符号读取器 + //如果不清理,在window下会锁定文件 if (assembly != null && assembly.MainModule.SymbolReader != null) { assembly.MainModule.SymbolReader.Dispose(); diff --git a/Source/VSProj/Src/Tools/CecilExtensions.cs b/Source/VSProj/Src/Tools/CecilExtensions.cs index 14a753c..f85d23a 100644 --- a/Source/VSProj/Src/Tools/CecilExtensions.cs +++ b/Source/VSProj/Src/Tools/CecilExtensions.cs @@ -18,10 +18,10 @@ namespace IFix static internal class CecilExtensions { /// - /// ��contextTypeΪ�����ģ����ҷ��Ͳ�����Ӧ��ʵ�� + /// 以contextType为上下文,查找泛型参数对应的实参 /// - /// ���Ͳ��� - /// ���������� + /// 泛型参数 + /// 上下文类型 /// public static TypeReference ResolveGenericArgument(this GenericParameter gp, TypeReference contextType) { @@ -54,10 +54,10 @@ public static TypeReference ResolveGenericArgument(this GenericParameter gp, Typ } /// - /// ��contextMethodΪ�����ģ����ҷ��Ͳ�����Ӧ��ʵ�� + /// 以contextMethod为上下文,查找泛型参数对应的实参 /// - /// ���Ͳ��� - /// �����ĺ��� + /// 泛型参数 + /// 上下文函数 /// public static TypeReference ResolveGenericArgument(this GenericParameter gp, MethodReference contextMethod) { @@ -70,8 +70,8 @@ public static TypeReference ResolveGenericArgument(this GenericParameter gp, Met } /// - /// ��䷺�Ͳ��������ֱ��TypeReferenceȡFullName�Ļ������Ͳ�������������ΪT������ʵ��������ȻΪT���� - /// �����ڲ������ҷ��ͷ���ʱ�������� + /// 填充泛型参数,如果直接TypeReference取FullName的话,泛型参数(比如名字为T)不会实例化(仍然为T), + /// 这样在补丁查找泛型方法时会有问题 /// /// /// @@ -141,10 +141,10 @@ static string getAssemblyName(TypeReference typeReference) } /// - /// ���Գ��򼯰汾�����Ա����������Ƿ�ָ��ͬ�������� + /// 忽略程序集版本号来对比两个类型是否指向同样的类型 /// - /// ����1 - /// ����2 + /// 参数1 + /// 参数2 /// public static bool AreEqualIgnoreAssemblyVersion(this TypeReference left, TypeReference right) { @@ -172,12 +172,12 @@ static TypeReference getElementType(TypeReference type, TypeReference contextTyp } /// - /// ��ȡһ�����͵�AssemblyQualifiedName + /// 获取一个类型的AssemblyQualifiedName /// - /// Ҫ��ȡAssemblyQualifiedName��type - /// ���������ͣ�������������� - /// ���Գ����� - /// ���ڷ������͵ĵݹ�ʱ�����Գ��򼯣���Ϊ������������д�귺�Ͳ���������д���� + /// 要获取AssemblyQualifiedName的type + /// 上下文类型,往往是其外层类 + /// 忽略程序集名 + /// 用于泛型类型的递归时,忽略程序集,因为泛型类型是填写完泛型参数后,再填写程序集 /// public static string GetAssemblyQualifiedName(this TypeReference typeReference, TypeReference contextType = null, bool skipAssemblyQualified = false, @@ -261,9 +261,9 @@ public static string GetAssemblyQualifiedName(this TypeReference typeReference, } /// - /// �ж�һ�������Ƿ���delegate + /// 判断一个类型是否是delegate /// - /// Ҫ�жϵ����� + /// 要判断的类型 /// public static bool IsDelegate(this TypeDefinition typeDefinition) { @@ -275,9 +275,9 @@ public static bool IsDelegate(this TypeDefinition typeDefinition) } /// - /// �ж�һ�������Dz��Ƿ��� + /// 判断一个类型是不是泛型 /// - /// Ҫ�жϵ����� + /// 要判断的类型 /// public static bool IsGeneric(this TypeReference type) { @@ -307,9 +307,9 @@ public static bool IsGeneric(this TypeReference type) } /// - /// �ж�һ�����͵ķ���ʵ���Ƿ������Ժ����ķ���ʵ�� + /// 判断一个类型的泛型实参是否有来自函数的泛型实参 /// - /// Ҫ�жϵ����� + /// 要判断的类型 /// public static bool HasGenericArgumentFromMethod(this TypeReference type) { @@ -340,9 +340,9 @@ public static bool HasGenericArgumentFromMethod(this TypeReference type) } /// - /// �ж�һ�������Dz��Ƿ��� + /// 判断一个方法是不是泛型 /// - /// Ҫ�жϵķ��� + /// 要判断的方法 /// public static bool IsGeneric(this MethodReference method) { @@ -366,9 +366,9 @@ public static bool IsGeneric(this MethodReference method) } /// - /// �ж�һ���ֶε������Dz��Ƿ��� + /// 判断一个字段的类型是不是泛型 /// - /// Ҫ�ж��ֶ� + /// 要判断字段 /// public static bool IsGeneric(this FieldReference field) { @@ -376,10 +376,10 @@ public static bool IsGeneric(this FieldReference field) } /// - /// �ж����������Dz���ͬһ�� + /// 判断两个类型是不是同一个 /// - /// ����1 - /// ����2 + /// 类型1 + /// 类型2 /// public static bool IsSameType(this TypeReference left, TypeReference right) { @@ -389,10 +389,10 @@ public static bool IsSameType(this TypeReference left, TypeReference right) } /// - /// �ж��������͵������Ƿ���ͬ + /// 判断两个类型的名字是否相同 /// - /// ����1 - /// ����2 + /// 类型1 + /// 类型2 /// public static bool IsSameName(this TypeReference left, TypeReference right) { @@ -400,10 +400,10 @@ public static bool IsSameName(this TypeReference left, TypeReference right) } /// - /// �ж�����������������ж���������ͼ�����ֵ���͵����֣��Ƿ���� + /// 判断两个方法,如果仅判断其参数类型及返回值类型的名字,是否相等 /// - /// ����1 - /// ����2 + /// 方法1 + /// 方法2 /// public static bool IsTheSame(this MethodReference left, MethodReference right) { @@ -438,9 +438,9 @@ public static bool IsTheSame(this MethodReference left, MethodReference right) } /// - /// �ж�һ�������Ƿ����������� + /// 判断一个方法是否是析构函数 /// - /// ���� + /// 方法 /// public static bool IsFinalizer(this MethodDefinition method) { @@ -449,10 +449,10 @@ public static bool IsFinalizer(this MethodDefinition method) } /// - /// ���Ե���һ������ + /// 尝试导入一个类型 /// - /// Ҫ��������� - /// ���뵽�ĸ�module + /// 要导入的类型 + /// 导入到哪个module /// // #lizard forgives public static TypeReference TryImport(this TypeReference toImport, ModuleDefinition module) @@ -461,7 +461,7 @@ public static TypeReference TryImport(this TypeReference toImport, ModuleDefinit { if (toImport.Name == "Boolean") { - return module.TypeSystem.Boolean; //���������ͣ�����ͨ��getMap��ȡ���� + return module.TypeSystem.Boolean; //用内置类型,否则通过getMap获取不到 } else if (toImport.Name == "Byte") { @@ -540,7 +540,7 @@ public static TypeReference TryImport(this TypeReference toImport, ModuleDefinit } /// - /// ���Ե���һ������ + /// 尝试导入一个方法 /// /// /// @@ -560,7 +560,7 @@ public static MethodReference TryImport(this MethodReference toImport, ModuleDef } /// - /// ����һ���������� + /// 生成一个泛型引用 /// /// /// @@ -651,7 +651,7 @@ public static bool IsMatch(this MethodReference left, MethodDefinition right, Ty } /// - /// ��������ǩ���Ƿ���ͬ + /// 两个方法签名是否相同 /// /// /// @@ -693,7 +693,7 @@ public static bool AreSignaturesEqual(MethodReference left, MethodReference righ public static bool CheckImplemention(this MethodReference itfMethod, MethodDefinition impl) { - //һ��������ж��ͬǩ����������ʱӦ��ͨ��Overrides����� + //一个类可能有多个同签名方法,这时应该通过Overrides来检查 if (impl.Overrides.Count > 0) { foreach (var o in impl.Overrides) @@ -811,7 +811,7 @@ public static void AnalysisMethod(MethodDefinition method, out InjectType inject id = -1; } - //���method��ע�뺯����������ע�����ͣ�id���Լ���Ӧ���º��� + //如果method是注入函数,返回其注入类型,id,以及对应的新函数 public static void AnalysisMethod(Dictionary>> searchData, MethodDefinition method, out InjectType injectType, out int id, out MethodDefinition foundMethod) { @@ -847,7 +847,7 @@ static void addTypeAndNestType(List result, TypeDefinition type) } /// - /// ��ȡһ��������ͷ�������ͣ���������Ƕ���� + /// 获取一个程序集里头所有类型,包括其内嵌类型 /// /// /// diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index daf9c51..9886af2 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -111,7 +111,7 @@ Dictionary> typeToSpecialGeneratedField Dictionary typeToCctor = new Dictionary(); /// - /// ��ȡ��д���ԣ�����public int a{get;set;}�����¼��������ɵ��ֶ� + /// 获取简写属性(例如public int a{get;set;}),事件等所生成的字段 /// /// /// @@ -149,7 +149,7 @@ where isCompilerGenerated(instruction.Operand as FieldReference) return ret; } - //�ٲ�������һ����ԭ������������ + //再补丁新增一个对原生方法的引用 int addExternType(TypeReference type, TypeReference contextType = null) { if (type.IsGenericParameter || type.HasGenericArgumentFromMethod()) @@ -179,8 +179,8 @@ int addExternType(TypeReference type, TypeReference contextType = null) return externTypes.Count - 1; } - //������ע��ģʽ�����Ҹú���������IFix�Ļ�������Ҫ���Ϊ����ʵ���Դ����id - //TODO: ������������ǰ���һ�������������̣�������Ҫ������Щ������������������������������ + //假如是注入模式,而且该函数配置是IFix的话,不需要真的为其访问的资源分配id + //TODO: 更理想的做法是剥离一个分析代码流程,仅分析要生产哪些适配器,反向适配器,反剪裁配置 bool doNoAdd(MethodDefinition caller) { InjectType injectType; @@ -188,7 +188,7 @@ bool doNoAdd(MethodDefinition caller) out injectType) && injectType == InjectType.Switch; } - //ԭ���ֶ� + //原生字段 int addRefField(FieldReference field, MethodDefinition caller) { if (doNoAdd(caller)) @@ -207,7 +207,7 @@ int addRefField(FieldReference field, MethodDefinition caller) return id; } - //������洢�ֶ� + //虚拟机存储字段 int addStoreField(FieldDefinition field, MethodDefinition caller) { if (doNoAdd(caller)) @@ -226,7 +226,7 @@ int addStoreField(FieldDefinition field, MethodDefinition caller) return id; } - //����һ���ַ�������ֵ + //新增一个字符串字面值 int addInternString(string str, MethodDefinition caller) { if (doNoAdd(caller)) @@ -244,7 +244,7 @@ int addInternString(string str, MethodDefinition caller) return id; } - //ԭ������������ + //原生方法的引用 int addExternMethod(MethodReference callee, MethodDefinition caller) { if (doNoAdd(caller)) @@ -331,7 +331,7 @@ bool checkILAndGetOffset(MethodDefinition method, } /// - /// �ж�һ�������Ƿ���һ���Ϸ�id + /// 判断一个名字是否是一个合法id /// /// /// @@ -391,7 +391,7 @@ bool checkILAndGetOffset(MethodDefinition method, //Console.WriteLine(i + " instruction:" + instructions[i].OpCode + " offset:" + offset); switch (instructions[i].OpCode.Code) { - case Code.Nop://�Ⱥ��� + case Code.Nop://先忽略 break; case Code.Constrained: { @@ -443,11 +443,11 @@ bool checkILAndGetOffset(MethodDefinition method, case Code.Ldflda: { FieldReference fr = instructions[i].Operand as FieldReference; - //��������ɵ��ֶΣ����Ҳ���Getter/Setter/Adder/Remover + //如果是生成的字段,而且不是Getter/Setter/Adder/Remover if (isCompilerGenerated(fr) && !method.IsSpecialName) { - if (!IsVaildIdentifierName(fr.Name)//���ǺϷ����֣��Ϳ϶���������� - //����ǺϷ����֣��������κ�SpecialName�������ã�Ҳ��Ϊ������� + if (!IsVaildIdentifierName(fr.Name)//不是合法名字,就肯定是随机变量 + //如果是合法名字,但不被任何SpecialName方法引用,也归为随机变量 || !isRefBySpecialMethod(fr as FieldDefinition)) { @@ -471,7 +471,7 @@ bool checkILAndGetOffset(MethodDefinition method, case Code.Ldsflda: { FieldReference fr = instructions[i].Operand as FieldReference; - //������������ɵľ�̬�ֶΣ����Ҳ��ܴ浽�����������Getter/Setter/Adder/Remover + //如果访问了生成的静态字段,而且不能存到虚拟机,不是Getter/Setter/Adder/Remover //if ((isCompilerGenerated(fr) || isCompilerGenerated(fr.DeclaringType)) // && !isFieldStoreInVitualMachine(fr) && !method.IsSpecialName) //{ @@ -493,8 +493,8 @@ bool checkILAndGetOffset(MethodDefinition method, case Code.Ldftn: case Code.Ldvirtftn: { - //LINQͨ����ldftn��Ҫ��֤ldftn�����صĺ����Ƿ񺬷Ƿ�ָ���֧�֣����������˸������ֶΣ� - //����һ������NotPlainObject�� + //LINQ通常是ldftn,要验证ldftn所加载的函数是否含非法指令(不支持,或者引用了个生成字段, + //或者一个生成NotPlainObject) MethodReference mr = instructions[i].Operand as MethodReference; if (mr != null && !mr.IsGeneric() && !isCompilerGeneratedByNotPlainObject(mr.DeclaringType)) @@ -510,7 +510,7 @@ bool checkILAndGetOffset(MethodDefinition method, // + ",caller=" + method); return false; } - //������������Ҫ�������ʵ�ַ��� + //编译器生成类要检查所有实现方法 if (instructions[i].OpCode.Code == Code.Newobj && isCompilerGeneratedPlainObject(mr.DeclaringType)) { @@ -576,12 +576,12 @@ Core.ExceptionHandler findExceptionHandler(Core.ExceptionHandler[] ehs, Core.Exc } /// - /// ����һ��ָ���쳣ʱ���쳣������ + /// 查找一个指令异常时的异常处理块 /// - /// ��ǰ�����������쳣������ - /// �쳣���� - /// ָ��ƫ�� - /// �쳣����������� + /// 当前函数的所有异常处理块 + /// 异常类型 + /// 指令偏移 + /// 异常处理块的索引 /// Core.ExceptionHandler findExceptionHandler(Core.ExceptionHandler[] ehs, Core.ExceptionHandlerType type, int offset, out int idx) @@ -660,11 +660,11 @@ MethodReference _findBase(TypeReference type, MethodDefinition method) MethodReference findBase(TypeDefinition type, MethodDefinition method) { - if (method.IsVirtual && !method.IsNewSlot) //����override + if (method.IsVirtual && !method.IsNewSlot) //表明override { try { - //TODO: �������֧�ַ��ͽ�������Ҫ��������ʵ�֣�xluaĿǰ����ֱ�Ӳ�֧��base���� + //TODO: 如果后续支持泛型解析,需要考虑这块的实现,xlua目前泛型直接不支持base调用 return _findBase(type.BaseType, method); } catch { } @@ -674,7 +674,7 @@ MethodReference findBase(TypeDefinition type, MethodDefinition method) const string BASE_RPOXY_PERFIX = "<>iFixBaseProxy_"; - //����2 + //方案2 //var method = typeof(object).GetMethod("ToString"); //var ftn = method.MethodHandle.GetFunctionPointer(); //var func = (Func)Activator.CreateInstance(typeof(Func), obj, ftn); @@ -783,8 +783,8 @@ bool isFieldAccessInject(MethodDefinition method, int methodId) return false; } - //�ֶ�ע�뷽ʽ�����߼� - //Ŀǰ�ò��ϣ�������֧�ַ����޸���Ҫ�õ� + //字段注入方式处理逻辑 + //目前用不上,但后续支持泛型修复需要用到 void fieldAccessInject(InjectType injectType, MethodDefinition method, int methodId) { var redirectBridge = getRedirectField(method); @@ -837,7 +837,7 @@ void fieldAccessInject(InjectType injectType, MethodDefinition method, int metho ilProcessor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Callvirt, redirectTo)); } - //idע�뷽ʽ�����߼� + //id注入方式处理逻辑 void idAccessInject(InjectType injectType, MethodDefinition method, int methodId) { addRedirectIdInfo(method, methodId); @@ -922,15 +922,15 @@ int allocMethodId(MethodDefinition method) } /// - /// ��ȡһ��������id - /// �ú����ᴥ��ָ���������� + /// 获取一个函数的id + /// 该函数会触发指令序列生成 /// - /// �����ú��� - /// ������ - /// �Ǹ��麯����������ָ�����У� - /// ���ǵ���ͨ������������ - /// �����ߵ�ע������ - /// ������ʾ��Ҫ�������ԭ����0��������ָ�������±� + /// 被调用函数 + /// 调用者 + /// 是个虚函数,会生成指令序列, + /// 但是调用通过反射来调用 + /// 调用者的注入类型 + /// 负数表示需要反射访问原生,0或正数是指令数组下标 // #lizard forgives unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, bool directCallVirtual = false, InjectType callerInjectType = InjectType.Switch) @@ -956,7 +956,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, }; } - //�����dll֮��ķ����������ǹ��캯����������������Ϊ�����֮�⣨extern���ķ��� + //如果是dll之外的方法,或者是构造函数,析构函数,作为虚拟机之外(extern)的方法 if (method == null || (method.IsConstructor && !isCompilerGeneratedPlainObject(method.DeclaringType)) || method.IsFinalizer() || method.IsAbstract || method.IsPInvokeImpl || method.Body == null @@ -984,7 +984,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, }; } - if (method.IsGeneric())//��ʱ��֧�ֽ������� + if (method.IsGeneric())//暂时不支持解析泛型 { return new MethodIdInfo() { Id = 0, Type = CallType.Invalid }; } @@ -1001,7 +1001,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, // || methodToInjectType[method] == InjectType.Redirect) { int stopPos; - //������֧��ָ��ķ�������Ϊ�����֮�⣨extern���ķ��� + //包含不支持指令的方法,作为虚拟机之外(extern)的方法 if (!checkILAndGetOffset(method, msIls, ilOffset, out stopPos)) { InjectType it; @@ -1009,7 +1009,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { if (mode == ProcessMode.Patch || it == InjectType.Redirect) { - // ��patch���ֲ�֧��ָ��Ӧ�ñ��� + // 打patch发现不支持指令应该报错 throw new InvalidDataException("not support il[" + msIls[stopPos] + "] in " + method + ", caller is " + caller); } @@ -1050,10 +1050,10 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, codes.Add(methodId, code); if (!codeMustWriteToPatch.Contains(methodId) && ( - mode == ProcessMode.Patch || //patch�׶������������Ͷ�Ҫд�벹�� + mode == ProcessMode.Patch || //patch阶段无论哪种类型都要写入补丁 (methodToInjectType.TryGetValue(method, out injectType) - && injectType == InjectType.Redirect) || //ע��׶Σ��ض���������Ҫд�벹�� - (callerInjectType == InjectType.Redirect) //���ض������ͺ������ã�Ҳ��Ҫд�벹�� + && injectType == InjectType.Redirect) || //注入阶段,重定向类型需要写入补丁 + (callerInjectType == InjectType.Redirect) //被重定向类型函数调用,也需要写入补丁 )) { codeMustWriteToPatch.Add(methodId); @@ -1062,7 +1062,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, code.Add(new Core.Instruction { Code = Core.Code.StackSpace, Operand = (body.Variables.Count << 16) | body.MaxStackSize }); // local | maxstack - //TODO: locals init������ֵ����Ҫnew����������Ҫ����λ + //TODO: locals init,复杂值类型要new,引用类型要留空位 Core.ExceptionHandler[] exceptionHandlers = new Core.ExceptionHandler[body.ExceptionHandlers.Count]; @@ -1117,7 +1117,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, //case Code.Conv_Ovf_I8: //case Code.Conv_Ovf_I8_Un: //case Code.Conv_Ovf_U8: - //case Code.Conv_Ovf_U8_Un: // ָ��ϲ� + //case Code.Conv_Ovf_U8_Un: // 指令合并 // code.Add(new Core.Instruction // { // Code = Core.Code.Conv_I8, @@ -1131,14 +1131,14 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, int leaveTo = ilOffset[msIl.Operand as Instruction]; if (exceptionHandler == null || (exceptionHandler.TryStart <= leaveTo - && exceptionHandler.TryEnd > leaveTo)) // �˻���Br + && exceptionHandler.TryEnd > leaveTo)) // 退化成Br { code.Add(new Core.Instruction { Code = Core.Code.Br, Operand = leaveTo - ilOffset[msIl] }); - code.Add(new Core.Instruction //��ָ�� + code.Add(new Core.Instruction //补指令 { Code = Core.Code.Nop, Operand = 0 @@ -1179,7 +1179,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, code.Add(new Core.Instruction { Code = Core.Code.Endfinally, - Operand = nextIdx // -1��ʾ����� + Operand = nextIdx // -1表示最外层 }); } break; @@ -1494,7 +1494,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, }); break; } - //TODO�� ������ɴ�������delegate��cache��ô���أ� + //TODO: 如果生成代码做了delegate的cache怎么办呢? else if (methodIdInfo.Type == CallType.Internal && (isCompilerGenerated(methodToCall as MethodDefinition) || isNewMethod(methodToCall as MethodDefinition)) ) @@ -1509,7 +1509,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, }); break; } - else //TODO������հ�����֧�ֵ�ָ����ô�죿 + else //TODO:如果闭包含不支持的指令怎么办? { code.Add(new Core.Instruction { @@ -1838,9 +1838,9 @@ void bridgeImplement(TypeReference itf) } /// - /// �Ž���ʵ��һ��������нӿڣ�һ����˵�Ǹ������� + /// 桥接器实现一个类的所有接口,一般来说是个匿名类 /// - /// Ҫʵ���Žӵ������� + /// 要实现桥接的匿名类 void addInterfacesOfTypeToBridge(TypeDefinition anonType) { if (anonType.Interfaces.Count == 0) @@ -1877,7 +1877,7 @@ void addInterfacesOfTypeToBridge(TypeDefinition anonType) continue; } } - else //Enumerator �﷨����ͷ���и��հ��﷨�ǣ�������������һ����˽�У��ǹ��еĺ��� + else //Enumerator 语法糖里头再有个闭包语法糖,会在类那生成一个非私有,非公有的函数 { continue; } @@ -1942,15 +1942,15 @@ void addInterfaceToBridge(TypeReference itf) } /// - /// ��ȡһ�������������� + /// 获取一个方法的适配器 /// - /// �����������ķ����� - /// ���������󶨵��������� - /// Ҫ����ķ��� - /// �Dz��DZհ� - /// �Ƿ�����������������delegate���������Ͳ��������� - /// �Ƿ��ǽӿ��Ž��� - /// ����id + /// 方法适配器的放置类 + /// 适配器所绑定的匿名对象 + /// 要适配的方法 + /// 是不是闭包 + /// 是否向基类收敛(如果是delegate适配器,就不能收敛) + /// 是否是接口桥接器 + /// 方法id /// // #lizard forgives MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, MethodReference method, @@ -1961,13 +1961,13 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, { md = method.Resolve(); } - //ԭʼ�������� + //原始参数类型 List parameterTypes = new List(); - //�������������ͣ�����ǿ��noBaselize�Ļ����������ͣ����ӷ�����ֵ���ͣ���תΪobject + //适配器参数类型,不是强制noBaselize的话,引用类型,复杂非引用值类型,均转为object List wrapperParameterTypes = new List(); List isOut = new List(); //List paramAttrs = new List(); - if (!md.IsStatic && !isClosure && !isInterfaceBridge) //������հ���this���Զ���������Ҫ��ʽ���� + if (!md.IsStatic && !isClosure && !isInterfaceBridge) //匿名类闭包的this是自动传,不需要显式参数 { isOut.Add(false); //paramAttrs.Add(Mono.Cecil.ParameterAttributes.None); @@ -2357,7 +2357,7 @@ TypeReference tryGetUnderlyingType(TypeReference type) return type; } - //����ֱ��ջ�ϱ�ʾ��ֵ���ͣ���boxing + //不能直接栈上表示的值类型,都boxing void emitLoadRef(Mono.Collections.Generic.Collection instructions, TypeReference type) { var underlyingTypetype = tryGetUnderlyingType(type); @@ -2824,7 +2824,7 @@ void addRedirectIdInfo(MethodDefinition method, int id) redirectIdMap.Add(method, redirectIdField); } - //�ȼ��ֶΣ�����������ϵ + //先加字段,建立关联关系 FieldDefinition getRedirectField(MethodDefinition method) { if (redirectMemberMap.ContainsKey(method)) @@ -2871,7 +2871,7 @@ void redirectFieldRename() { kv.Value.Name = "_rf_" + methodName + (id++); } - if (id > 1) //������ + if (id > 1) //有重载 { id = 0; foreach(var kv in methodGroup) @@ -2897,7 +2897,7 @@ void redirectFieldRename() } duplicateCheck.Add(kv.Value.Name); } - if (id > 1) //������ + if (id > 1) //有重载 { id = 0; foreach (var kv in methodGroup) @@ -2909,15 +2909,15 @@ void redirectFieldRename() } } - //1�����캯��������������ת����֧�ֵ�ָ�ת��ת�ĺ������º������壬����֧�ַ��� - //2����ת�ĺ���ͨ��������ã���ת����������ת������������ڲ���� - //3����ת��������֧��ֱ���ض���ɾ��ԭʵ�֣��������������Լ�����ԭʵ�������л����루��bug������ - //4����ת������Ҫ����wrap - //5��TODO���麯����base��δ�����˽�к����Ƿ���Ҫ������ڣ��򵥺���������getter/setter���Ƿ�Ҫת�� - //6��Ӧ��Ϊ����ֵ�������ɳ���ջ��������ֹ����GC - //7��Callvirt�������Ƿ�������麯�����麯��������ã����鲢�Ҷ�̬����ֱ�ӵ��� - //8�����͵�ͬ����һ��Type[]���� - //��������һ��dll�����dll+dif + //1、构造函数及析构函数不转,不支持的指令不转,转的函数留下函数定义,所以支持反射 + //2、不转的函数通过反射调用,已转函数调用已转函数在虚拟机内部完成 + //3、已转函数可以支持直接重定向并删除原实现(减包场景),以及保留原实现增加切换代码(修bug场景) + //4、已转函数需要生成wrap + //5、TODO:虚函数用base如何处理?私有函数是否需要保留入口?简单函数(比如getter/setter)是否要转? + //6、应该为基本值类型生成出入栈函数,防止过大GC + //7、Callvirt分析其是否真的是虚函数,虚函数反射调用,非虚并且动态方法直接调用 + //8、泛型等同多了一个Type[]参数 + //工具输入一个dll,输出dll+dif Dictionary methodToInjectType = new Dictionary(); bool hasRedirect = false; ProcessMode mode; @@ -2992,7 +2992,7 @@ void postProcessInterfaceBridge() // } //} - //Ϊgetter setter���Ӷ�Ӧ��property + //为getter setter增加对应的property foreach (var m in itfBridgeType.Methods) { if (m.IsSpecialName && !m.IsConstructor) @@ -3039,7 +3039,7 @@ void postProcessInterfaceBridge() } } - //bridge�Ĺ��캯�� + //bridge的构造函数 var methodIdFields = itfBridgeType.Fields.Where(f => f.Name.StartsWith(METHODIDPERFIX)).ToList(); int methodIdPerfixLen = METHODIDPERFIX.Length; methodIdFields.Sort((l, r) => int.Parse(l.Name.Substring(methodIdPerfixLen)) @@ -3090,7 +3090,7 @@ void postProcessInterfaceBridge() itfBridgeType.Methods.Add(ctorOfItfBridgeType); - //��WrappersManagerImpl���Ӵ����ӿ� + //在WrappersManagerImpl增加创建接口 var createBridge = new MethodDefinition("CreateBridge", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot @@ -3300,7 +3300,7 @@ public void Serialize(string filename) } } - //TODO: Ԥ����������link.xml֮����ļ� + //TODO: 预分析,生成link.xml之类的文件 public void Serialize(Stream output) { using (BinaryWriter writer = new BinaryWriter(output)) @@ -3386,7 +3386,7 @@ public void Serialize(Stream output) fieldType = objType; } writer.Write(addExternType(fieldType)); - //�ֶξ�̬���캯�� + //字段静态构造函数 writer.Write(typeToCctor[fieldsStoreInVirtualMachine[i].DeclaringType]); } diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 91cc013..ace464f 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -21,7 +21,7 @@ public static GenerateConfigure Empty() return new EmptyGenerateConfigure(); } - //�����򵥵Ĵ��ļ������������� + //仅仅简单的从文件加载类名而已 public static GenerateConfigure FromFile(string filename) { DefaultGenerateConfigure generateConfigure = new DefaultGenerateConfigure(); @@ -48,23 +48,23 @@ public static GenerateConfigure FromFile(string filename) } /// - /// ���һ����������ָ���ı�ǩ�����������õı�־λ + /// 如果一个方法打了指定的标签,返回其配置的标志位 /// - /// ��ǩ - /// Ҫ��ѯ�ķ��� - /// ����������û����õı�־λ + /// 标签 + /// 要查询的方法 + /// 输出参数,用户配置的标志位 /// public abstract bool TryGetConfigure(string tag, MethodReference method, out int flag); /// - /// �ж�һ�������Ƿ����������� + /// 判断一个方法是否是新增方法 /// - /// Ҫ��ѯ�ķ��� + /// 要查询的方法 /// public abstract bool IsNewMethod(MethodReference method); } - //�ڲ�����ר�� + //内部测试专用 public class EmptyGenerateConfigure : GenerateConfigure { public override bool TryGetConfigure(string tag, MethodReference method, out int flag) @@ -79,7 +79,7 @@ public override bool IsNewMethod(MethodReference method) } } - //ע������ʹ�� + //注入配置使用 public class DefaultGenerateConfigure : GenerateConfigure { internal Dictionary> configures @@ -99,7 +99,7 @@ public override bool IsNewMethod(MethodReference method) } } - //patch����ʹ�� + //patch配置使用 public class PatchGenerateConfigure : GenerateConfigure { public override bool TryGetConfigure(string tag, MethodReference method, out int flag) @@ -121,7 +121,7 @@ public override bool IsNewMethod(MethodReference method) return newMethods.Contains(method); } - //��ʱ��֧��redirect���͵ķ��� + //暂时不支持redirect类型的方法 HashSet redirectMethods = new HashSet(); HashSet switchMethods = new HashSet(); HashSet newMethods = new HashSet(); @@ -144,14 +144,14 @@ MethodDefinition findMatchMethod(Dictionary matchInfo, MethodReference method) { MethodMatchInfo[] mmis; @@ -187,7 +187,7 @@ bool isMatch(Dictionary matchInfo, MethodReference me return false; } - //��ȡ������Ϣ����Ҫ�Ƿ�����ǩ����Ϣ������+��������+����ֵ���� + //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 static Dictionary readMatchInfo(BinaryReader reader) { Dictionary matchInfo = new Dictionary(); @@ -219,7 +219,7 @@ static Dictionary readMatchInfo(BinaryReader reader) return matchInfo; } - //��ȡ������Ϣ��Ҫpatch�ķ����б������������б��� + //读取配置信息(要patch的方法列表,新增方法列表) public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) { Dictionary patchMethodInfo = null; diff --git a/Source/VSProj/Src/Version.cs b/Source/VSProj/Src/Version.cs index 990518b..1f96567 100644 --- a/Source/VSProj/Src/Version.cs +++ b/Source/VSProj/Src/Version.cs @@ -9,6 +9,6 @@ namespace IFix { public class Version { - public const string FILE_FORMAT = "0.0.6";//�ļ���ʽ�汾�� + public const string FILE_FORMAT = "0.0.6";//文件格式版本号 } } \ No newline at end of file From f46ff5e36881058a714734dd60bd87f37621e762 Mon Sep 17 00:00:00 2001 From: treert <909413016@qq.com> Date: Sat, 12 Oct 2019 10:07:30 +0800 Subject: [PATCH 011/103] =?UTF-8?q?=E3=80=90=E4=BC=98=E5=8C=96IFix?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E6=97=A5=E5=BF=97=E3=80=91=E4=BD=BF=E7=94=A8?= =?UTF-8?q?debug=E6=A8=A1=E5=BC=8F=E8=BF=90=E8=A1=8Cifix.exe=EF=BC=8C?= =?UTF-8?q?=E6=8A=A5=E9=94=99=E6=97=A5=E5=BF=97=E9=87=8C=E5=8C=85=E5=90=AB?= =?UTF-8?q?=E6=BA=90=E7=A0=81=E6=96=87=E4=BB=B6=E5=92=8C=E8=A1=8C=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=EF=BC=8C=E6=96=B9=E4=BE=BF=E6=9F=A5=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E3=80=82=20(#31)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 【优化IFix报错日志】使用debug模式运行ifix.exe,报错日志里包含源码文件和行信息,方便查问题。 #30 * 修改换行符为lf * 低于5.6的版本,mono执行也加上 --debug --- .../Assets/IFix/Editor/ILFixEditor.cs | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index d7bfef9..d37a170 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -92,9 +92,9 @@ public static void CallIFix(List args) Process hotfix_injection = new Process(); hotfix_injection.StartInfo.FileName = mono_path; #if UNITY_5_6_OR_NEWER - hotfix_injection.StartInfo.Arguments = "--runtime=v4.0.30319 \"" + inject_tool_path + "\" \"" + hotfix_injection.StartInfo.Arguments = "--debug --runtime=v4.0.30319 \"" + inject_tool_path + "\" \"" #else - hotfix_injection.StartInfo.Arguments = "\"" + inject_tool_path + "\" \"" + hotfix_injection.StartInfo.Arguments = "--debug \"" + inject_tool_path + "\" \"" #endif + string.Join("\" \"", args.ToArray()) + "\""; hotfix_injection.StartInfo.WindowStyle = ProcessWindowStyle.Hidden; @@ -373,9 +373,9 @@ static void doRestore(string ts) //cecil里的类名表示和.net标准并不一样,这里做些转换 static string GetCecilTypeName(Type type) { - if (type.IsByRef && type.GetElementType().IsGenericType) - { - return GetCecilTypeName(type.GetElementType()) + "&"; + if (type.IsByRef && type.GetElementType().IsGenericType) + { + return GetCecilTypeName(type.GetElementType()) + "&"; } else if (type.IsGenericType) { @@ -657,40 +657,40 @@ static void writeMethods(BinaryWriter writer, List methods) } } - static bool hasGenericParameter(Type type) - { - if (type.IsByRef || type.IsArray) - { - return hasGenericParameter(type.GetElementType()); - } - if (type.IsGenericType) - { - foreach (var typeArg in type.GetGenericArguments()) - { - if (hasGenericParameter(typeArg)) - { - return true; - } - } - return false; - } - return type.IsGenericParameter; + static bool hasGenericParameter(Type type) + { + if (type.IsByRef || type.IsArray) + { + return hasGenericParameter(type.GetElementType()); + } + if (type.IsGenericType) + { + foreach (var typeArg in type.GetGenericArguments()) + { + if (hasGenericParameter(typeArg)) + { + return true; + } + } + return false; + } + return type.IsGenericParameter; } - static bool hasGenericParameter(MethodBase method) - { - if (method.IsGenericMethodDefinition || method.IsGenericMethod) return true; - if (!method.IsConstructor && hasGenericParameter((method as MethodInfo).ReturnType)) return true; - - foreach (var param in method.GetParameters()) - { - if (hasGenericParameter(param.ParameterType)) - { - return true; - } - } - return false; - + static bool hasGenericParameter(MethodBase method) + { + if (method.IsGenericMethodDefinition || method.IsGenericMethod) return true; + if (!method.IsConstructor && hasGenericParameter((method as MethodInfo).ReturnType)) return true; + + foreach (var param in method.GetParameters()) + { + if (hasGenericParameter(param.ParameterType)) + { + return true; + } + } + return false; + } /// From 691c4d1dd7460da703639be08ca8c620854e590e Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 15 Oct 2019 10:43:53 +0800 Subject: [PATCH 012/103] =?UTF-8?q?=E6=B3=A8=E5=85=A5=E5=92=8C=E7=94=9F?= =?UTF-8?q?=E6=88=90patch=E5=8A=A0=E5=85=A5=E8=BF=9B=E5=BA=A6=E6=9D=A1=20f?= =?UTF-8?q?ix=20https://github.com/Tencent/InjectFix/issues/32?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/IFix/Editor/ILFixEditor.cs | 114 +++++++++++------- 1 file changed, 73 insertions(+), 41 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index d7bfef9..720d5c9 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -149,7 +149,16 @@ public static void InjectAssemblys() UnityEngine.Debug.LogError("compiling or playing"); return; } - InjectAllAssemblys(); + EditorUtility.DisplayProgressBar("Inject", "injecting...", 0); + try + { + InjectAllAssemblys(); + } + catch(Exception e) + { + UnityEngine.Debug.LogError(e); + } + EditorUtility.ClearProgressBar(); } public static bool AutoInject = true; //可以在外部禁用掉自动注入 @@ -373,9 +382,9 @@ static void doRestore(string ts) //cecil里的类名表示和.net标准并不一样,这里做些转换 static string GetCecilTypeName(Type type) { - if (type.IsByRef && type.GetElementType().IsGenericType) - { - return GetCecilTypeName(type.GetElementType()) + "&"; + if (type.IsByRef && type.GetElementType().IsGenericType) + { + return GetCecilTypeName(type.GetElementType()) + "&"; } else if (type.IsGenericType) { @@ -657,40 +666,40 @@ static void writeMethods(BinaryWriter writer, List methods) } } - static bool hasGenericParameter(Type type) - { - if (type.IsByRef || type.IsArray) - { - return hasGenericParameter(type.GetElementType()); - } - if (type.IsGenericType) - { - foreach (var typeArg in type.GetGenericArguments()) - { - if (hasGenericParameter(typeArg)) - { - return true; - } - } - return false; - } - return type.IsGenericParameter; + static bool hasGenericParameter(Type type) + { + if (type.IsByRef || type.IsArray) + { + return hasGenericParameter(type.GetElementType()); + } + if (type.IsGenericType) + { + foreach (var typeArg in type.GetGenericArguments()) + { + if (hasGenericParameter(typeArg)) + { + return true; + } + } + return false; + } + return type.IsGenericParameter; } - static bool hasGenericParameter(MethodBase method) - { - if (method.IsGenericMethodDefinition || method.IsGenericMethod) return true; - if (!method.IsConstructor && hasGenericParameter((method as MethodInfo).ReturnType)) return true; - - foreach (var param in method.GetParameters()) - { - if (hasGenericParameter(param.ParameterType)) - { - return true; - } - } - return false; - + static bool hasGenericParameter(MethodBase method) + { + if (method.IsGenericMethodDefinition || method.IsGenericMethod) return true; + if (!method.IsConstructor && hasGenericParameter((method as MethodInfo).ReturnType)) return true; + + foreach (var param in method.GetParameters()) + { + if (hasGenericParameter(param.ParameterType)) + { + return true; + } + } + return false; + } /// @@ -757,11 +766,20 @@ select Path.GetDirectoryName(asm.ManifestModule.FullyQualifiedName)).Distinct()) [MenuItem("InjectFix/Fix", false, 2)] public static void Patch() { - foreach (var assembly in injectAssemblys) + EditorUtility.DisplayProgressBar("Generate Patch for Edtior", "patching...", 0); + try + { + foreach (var assembly in injectAssemblys) + { + GenPatch(assembly, string.Format("./Library/ScriptAssemblies/{0}.dll", assembly), + "./Assets/Plugins/IFix.Core.dll", string.Format("{0}.patch.bytes", assembly)); + } + } + catch (Exception e) { - GenPatch(assembly, string.Format("./Library/ScriptAssemblies/{0}.dll", assembly), - "./Assets/Plugins/IFix.Core.dll", string.Format("{0}.patch.bytes", assembly)); + UnityEngine.Debug.LogError(e); } + EditorUtility.ClearProgressBar(); } #if UNITY_2018_3_OR_NEWER @@ -769,7 +787,14 @@ public static void Patch() public static void CompileToAndroid() { EditorUtility.DisplayProgressBar("Generate Patch for Android", "patching...", 0); - GenPlatformPatch(Platform.android, ""); + try + { + GenPlatformPatch(Platform.android, ""); + } + catch(Exception e) + { + UnityEngine.Debug.LogError(e); + } EditorUtility.ClearProgressBar(); } @@ -777,7 +802,14 @@ public static void CompileToAndroid() public static void CompileToIOS() { EditorUtility.DisplayProgressBar("Generate Patch for IOS", "patching...", 0); - GenPlatformPatch(Platform.ios, ""); + try + { + GenPlatformPatch(Platform.ios, ""); + } + catch(Exception e) + { + UnityEngine.Debug.LogError(e); + } EditorUtility.ClearProgressBar(); } #endif From 5ac9693689d4141d6d224e833053a901ec38d564 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 2 Dec 2019 19:51:13 +0800 Subject: [PATCH 013/103] =?UTF-8?q?=E9=97=AD=E5=8C=85=E4=B8=AD=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E4=B8=80=E4=B8=AA=E6=B3=9B=E5=9E=8B=EF=BC=8C=E5=9C=A8?= =?UTF-8?q?unity2018=E7=9A=84.net=203.5=E8=AE=BE=E7=BD=AE=E4=B8=8B?= =?UTF-8?q?=EF=BC=8C=E7=BC=96=E8=AF=91=E5=99=A8=E6=98=AF=E5=85=88=E7=94=9F?= =?UTF-8?q?=E6=88=90=E4=B8=80=E4=B8=AA=E6=B3=9B=E5=9E=8B=E7=9A=84=E9=97=AD?= =?UTF-8?q?=E5=8C=85=E5=AE=9E=E7=8E=B0=EF=BC=8C=E7=84=B6=E5=90=8E=E5=AE=9E?= =?UTF-8?q?=E4=BE=8B=E5=8C=96=EF=BC=8C=E5=BE=88=E5=A5=87=E6=80=AA=E7=9A=84?= =?UTF-8?q?=E5=81=9A=E6=B3=95=EF=BC=8C=E8=80=81=E7=89=88=E6=9C=ACunity?= =?UTF-8?q?=EF=BC=8C=E6=96=B0unity=E7=9A=84.net=204.0=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E9=83=BD=E4=B8=8D=E4=BC=9A=E8=BF=99=E6=A0=B7=EF=BC=8C=E5=85=88?= =?UTF-8?q?=E8=BF=94=E5=9B=9Efalse=EF=BC=8Cfix=20https://github.com/Tencen?= =?UTF-8?q?t/InjectFix/issues/35#issuecomment-560353428?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 9886af2..9cbf8a7 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -504,6 +504,10 @@ bool checkILAndGetOffset(MethodDefinition method, isCompilerGeneratedPlainObject(mr.DeclaringType))) { var md = mr as MethodDefinition; + if (md == null)//闭包中调用一个泛型,在unity2018的.net 3.5设置下,编译器是先生成一个泛型的闭包实现,然后实例化,很奇怪的做法,老版本unity,新unity的.net 4.0设置都不会这样,先返回false,不支持这种编译器 + { + return false; + } if (md.Body != null && !checkILAndGetOffset(md, md.Body.Instructions)) { //Console.WriteLine("check " + md + " fail il = " + md.Body.Instructions[p] From 1f73995376503dc3248f4d7a1692883b26c66371 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 12 Dec 2019 17:15:48 +0800 Subject: [PATCH 014/103] =?UTF-8?q?=E5=BD=93=E5=80=BC=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E6=97=A0override=E6=96=B9=E6=B3=95=E6=97=B6=EF=BC=8C=E4=B8=80?= =?UTF-8?q?=E4=BA=9B=E7=BC=96=E8=AF=91=E5=99=A8=E4=BB=8D=E7=84=B6=E7=94=9F?= =?UTF-8?q?=E6=88=90Constrained=EF=BC=8C=E8=BF=99=E7=A7=8D=E6=83=85?= =?UTF-8?q?=E5=86=B5=E4=B8=8B=E4=B9=8B=E5=89=8D=E7=9A=84=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=9C=A8=E5=87=BD=E6=95=B0=E5=90=AB=E5=8F=82=E6=95=B0=E6=97=B6?= =?UTF-8?q?=E5=A4=84=E7=90=86=E4=B8=8D=E5=BD=93=EF=BC=8Cfix=20https://gith?= =?UTF-8?q?ub.com/Tencent/InjectFix/issues/48?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 13 ++++++++++++- Source/VSProj/Src/Tools/CodeTranslator.cs | 19 +++++++------------ 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 12c3982..e57303b 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2220,7 +2220,18 @@ AnonymousStorey anonyObj evaluationStackPointer = rhs; } break; - //Constrained//0.04714472% delete + 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); + managedStack[pos] = obj; + ptr->Value1 = pos; + ptr->Type = ValueType.Object; + } + break; case Code.Switch://0.04518777% { int val = (evaluationStackPointer - 1)->Value1; diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 9cbf8a7..120dfda 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -504,9 +504,9 @@ bool checkILAndGetOffset(MethodDefinition method, isCompilerGeneratedPlainObject(mr.DeclaringType))) { var md = mr as MethodDefinition; - if (md == null)//闭包中调用一个泛型,在unity2018的.net 3.5设置下,编译器是先生成一个泛型的闭包实现,然后实例化,很奇怪的做法,老版本unity,新unity的.net 4.0设置都不会这样,先返回false,不支持这种编译器 - { - return false; + if (md == null)//闭包中调用一个泛型,在unity2018的.net 3.5设置下,编译器是先生成一个泛型的闭包实现,然后实例化,很奇怪的做法,老版本unity,新unity的.net 4.0设置都不会这样,先返回false,不支持这种编译器 + { + return false; } if (md.Body != null && !checkILAndGetOffset(md, md.Body.Instructions)) { @@ -1407,15 +1407,10 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (constrainedType.IsValueType && !hasOverrideMethod) { - code[code.Count - 2] = new Core.Instruction - { - Code = Core.Code.Ldobj, - Operand = lastInstruction.Operand, - }; - code[code.Count - 1] = new Core.Instruction - { - Code = Core.Code.Box, - Operand = lastInstruction.Operand, + code[code.Count - 2] = new Core.Instruction + { + Code = Core.Code.Nop, + Operand = methodToCall.Parameters.Count, }; } //code.RemoveAt(code.Count - 1); From 6c2716b8f9abf988373f5831e4617ce75bd71019 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 13 Jan 2020 15:43:17 +0800 Subject: [PATCH 015/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3unbox=E4=B8=80?= =?UTF-8?q?=E4=B8=AA=E6=9E=9A=E4=B8=BE=E5=8F=98=E9=87=8F=E6=97=B6=E6=8A=A5?= =?UTF-8?q?=E9=94=99=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/StackOperation.cs | 4 ++++ Source/VSProj/Src/Core/VirtualMachine.cs | 22 +++++++++++++--------- Source/VSProj/Src/Tools/CodeTranslator.cs | 8 ++++---- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index 1f6624d..e6521dd 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -88,6 +88,10 @@ unsafe internal static class EvaluationStackOperation { internal static void UnboxPrimitive(Value* evaluationStackPointer, object obj, Type type) { + if (obj.GetType().IsEnum) + { + obj = Convert.ChangeType(obj, type); + } if (obj is int) { evaluationStackPointer->Type = ValueType.Integer; diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index e57303b..6877b1a 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2059,6 +2059,10 @@ AnonymousStorey anonyObj { EvaluationStackOperation.UnboxPrimitive(ptr, obj, type); } + else if(type.IsEnum) + { + EvaluationStackOperation.UnboxPrimitive(ptr, obj, Enum.GetUnderlyingType(type)); + } else { ptr->Type = ValueType.ValueType; @@ -2221,15 +2225,15 @@ AnonymousStorey anonyObj } 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); - managedStack[pos] = obj; - ptr->Value1 = pos; - ptr->Type = ValueType.Object; + { + 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; } break; case Code.Switch://0.04518777% diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 120dfda..6abc198 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1407,10 +1407,10 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (constrainedType.IsValueType && !hasOverrideMethod) { - code[code.Count - 2] = new Core.Instruction - { - Code = Core.Code.Nop, - Operand = methodToCall.Parameters.Count, + code[code.Count - 2] = new Core.Instruction + { + Code = Core.Code.Nop, + Operand = methodToCall.Parameters.Count, }; } //code.RemoveAt(code.Count - 1); From 363481eb5d05116c19b9c3410afa0b7a94d19e97 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 14 Jan 2020 11:38:45 +0800 Subject: [PATCH 016/103] =?UTF-8?q?in=E5=85=B3=E9=94=AE=E5=AD=97=E4=BF=AE?= =?UTF-8?q?=E9=A5=B0=E5=8F=82=E6=95=B0=E7=9A=84=E6=94=AF=E6=8C=81=EF=BC=9A?= =?UTF-8?q?1=E3=80=81in=E4=BF=AE=E9=A5=B0=E7=9A=84=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E4=B8=8D=E7=94=A8=E4=BB=8E=E8=99=9A=E6=8B=9F=E6=9C=BA=E6=A0=88?= =?UTF-8?q?=E8=AE=BE=E7=BD=AE=E5=9B=9E=E5=8E=BB=EF=BC=9B2=E3=80=81?= =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=98=AF=E8=99=9A=E6=96=B9=E6=B3=95=EF=BC=8C?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=BC=9A=E8=A2=AB=E5=8C=85=E8=A3=B9=E5=9C=A8?= =?UTF-8?q?RequiredModifierType=E9=87=8C=E5=A4=B4=EF=BC=8C=E5=BA=94?= =?UTF-8?q?=E8=AF=A5=E5=8F=96=E5=87=BA=E7=9C=9F=E5=AE=9E=E7=B1=BB=E5=9E=8B?= =?UTF-8?q?=E3=80=82fix=20https://github.com/Tencent/InjectFix/issues/73?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 6abc198..74a3fec 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1965,10 +1965,12 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, //适配器参数类型,不是强制noBaselize的话,引用类型,复杂非引用值类型,均转为object List wrapperParameterTypes = new List(); List isOut = new List(); + List isIn = new List(); //List paramAttrs = new List(); if (!md.IsStatic && !isClosure && !isInterfaceBridge) //匿名类闭包的this是自动传,不需要显式参数 { isOut.Add(false); + isIn.Add(false); //paramAttrs.Add(Mono.Cecil.ParameterAttributes.None); if (method.DeclaringType.IsValueType) { @@ -1987,12 +1989,17 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, for (int i = 0; i < method.Parameters.Count; i++) { isOut.Add(method.Parameters[i].IsOut); + isIn.Add(method.Parameters[i].IsIn); //paramAttrs.Add(method.Parameters[i].Attributes); var paramType = method.Parameters[i].ParameterType; if (paramType.IsGenericParameter) { paramType = (paramType as GenericParameter).ResolveGenericArgument(method.DeclaringType); } + if (paramType.IsRequiredModifier) + { + paramType = (paramType as RequiredModifierType).ElementType; + } parameterTypes.Add(paramType); wrapperParameterTypes.Add(noBaselize ? paramType : wrapperParamerterType(paramType)); } @@ -2030,7 +2037,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, for (int j = 0; j < wrapperParameterTypes.Count; j++) { if (!wrapperParameterTypes[j].IsSameType(wrapperMethod.Parameters[j].ParameterType) - || isOut[j] != wrapperMethod.Parameters[j].IsOut) + || isOut[j] != wrapperMethod.Parameters[j].IsOut || isIn[j] != wrapperMethod.Parameters[j].IsIn) { paramMatch = false; break; @@ -2053,9 +2060,11 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, for (int i = 0; i < parameterTypes.Count; i++) { - refPos[i] = parameterTypes[i].IsByReference ? refCount++ : -1; - wrapperMethod.Parameters.Add(new ParameterDefinition("P" + i, isOut[i] ? ParameterAttributes.Out - : ParameterAttributes.None, wrapperParameterTypes[i].TryImport(assembly.MainModule))); + refPos[i] = (parameterTypes[i].IsByReference) ? refCount++ : -1; + var parameterAttributes = ParameterAttributes.None; + if (isOut[i]) parameterAttributes |= ParameterAttributes.Out; + if (isIn[i]) parameterAttributes |= ParameterAttributes.In; + wrapperMethod.Parameters.Add(new ParameterDefinition("P" + i, parameterAttributes, wrapperParameterTypes[i].TryImport(assembly.MainModule))); } var ilProcessor = wrapperMethod.Body.GetILProcessor(); @@ -2250,7 +2259,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, // Ref param for (int i = 0; i < parameterTypes.Count; i++) { - if (parameterTypes[i].IsByReference) + if (parameterTypes[i].IsByReference && ! isIn[i]) { emitLdarg(instructions, ilProcessor, i + 1); var paramRawType = tryGetUnderlyingType(getRawType(parameterTypes[i])); From 3ed5373aa8cd0ab3da4b05aee71e97ffe636109c Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 20 Jan 2020 11:01:54 +0800 Subject: [PATCH 017/103] =?UTF-8?q?=E6=8D=A2=E8=A1=8C=E7=AC=A6=E7=BB=9F?= =?UTF-8?q?=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/Instruction.cs | 2 +- Source/VSProj/Src/Core/StackOperation.cs | 6 +++--- Source/VSProj/Src/Core/VirtualMachine.cs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Source/VSProj/Src/Core/Instruction.cs b/Source/VSProj/Src/Core/Instruction.cs index 56ad778..55fd103 100644 --- a/Source/VSProj/Src/Core/Instruction.cs +++ b/Source/VSProj/Src/Core/Instruction.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. diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index e6521dd..74f1b9e 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -88,9 +88,9 @@ unsafe internal static class EvaluationStackOperation { internal static void UnboxPrimitive(Value* evaluationStackPointer, object obj, Type type) { - if (obj.GetType().IsEnum) - { - obj = Convert.ChangeType(obj, type); + if (obj.GetType().IsEnum) + { + obj = Convert.ChangeType(obj, type); } if (obj is int) { diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 6877b1a..7ca01a3 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2059,9 +2059,9 @@ AnonymousStorey anonyObj { EvaluationStackOperation.UnboxPrimitive(ptr, obj, type); } - else if(type.IsEnum) - { - EvaluationStackOperation.UnboxPrimitive(ptr, obj, Enum.GetUnderlyingType(type)); + else if(type.IsEnum) + { + EvaluationStackOperation.UnboxPrimitive(ptr, obj, Enum.GetUnderlyingType(type)); } else { From 4f00ce8eb1c1e238b6c72ee2aa9e0eaba2c47008 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 21 Jan 2020 13:18:47 +0800 Subject: [PATCH 018/103] =?UTF-8?q?=E7=BB=93=E6=9E=84=E4=BD=93=E5=B1=80?= =?UTF-8?q?=E9=83=A8=E5=8F=98=E9=87=8F=E6=B7=BB=E5=8A=A0=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E6=8C=87=E4=BB=A4=EF=BC=8Cfix=20https://github.com/Te?= =?UTF-8?q?ncent/InjectFix/issues/74?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 74a3fec..bd9f079 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1066,7 +1066,24 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, code.Add(new Core.Instruction { Code = Core.Code.StackSpace, Operand = (body.Variables.Count << 16) | body.MaxStackSize }); // local | maxstack - //TODO: locals init,复杂值类型要new,引用类型要留空位 + foreach(var variable in body.Variables) + { + if (variable.VariableType.IsValueType && !variable.VariableType.IsPrimitive) + { + Console.WriteLine("add Initobj for " + variable.VariableType); + code.Add(new Core.Instruction + { + Code = Core.Code.Ldloca, + Operand = variable.Index, + }); + + code.Add(new Core.Instruction + { + Code = Core.Code.Initobj, + Operand = addExternType(variable.VariableType) + }); + } + } Core.ExceptionHandler[] exceptionHandlers = new Core.ExceptionHandler[body.ExceptionHandlers.Count]; From 6e1bcfc1c29fac6292d940ce88941a0886529c3c Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 21 Jan 2020 13:20:43 +0800 Subject: [PATCH 019/103] =?UTF-8?q?=E5=88=9A=E5=88=9A=E7=9A=84=E6=8F=90?= =?UTF-8?q?=E4=BA=A4=E6=B2=A1=E5=8E=BB=E6=8E=89=E6=97=A5=E5=BF=97=E6=89=93?= =?UTF-8?q?=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index bd9f079..e97017f 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1070,7 +1070,6 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { if (variable.VariableType.IsValueType && !variable.VariableType.IsPrimitive) { - Console.WriteLine("add Initobj for " + variable.VariableType); code.Add(new Core.Instruction { Code = Core.Code.Ldloca, From 2a29e25fc06e208cd79c1b38419e14fa6e798b85 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 21 Jan 2020 13:28:18 +0800 Subject: [PATCH 020/103] =?UTF-8?q?=E6=9C=89=E4=BA=9B=E4=B8=A5=E6=A0=BC?= =?UTF-8?q?=E4=BA=9B=E7=9A=84=E7=BC=96=E8=AF=91=E5=99=A8=E4=BC=9A=E6=8A=A5?= =?UTF-8?q?=E6=9C=AA=E5=88=9D=E5=A7=8B=E5=8C=96=E8=AE=BF=E9=97=AE=EF=BC=8C?= =?UTF-8?q?fix=20https://github.com/Tencent/InjectFix/issues/67?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index e97017f..18c8891 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1117,7 +1117,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, bool typeofDetected = false; - Core.Instruction operand; + Core.Instruction operand = new Core.Instruction(); for (int i = 0; i < msIls.Count; i++) { var msIl = msIls[i]; From 4ab7bbea28b12e80dbe6e2fe6782d032125e2343 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 21 Jan 2020 15:51:40 +0800 Subject: [PATCH 021/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=B8=A6in=E5=8F=82?= =?UTF-8?q?=E6=95=B0=E4=B8=94override=E7=88=B6=E7=B1=BB=E7=9A=84=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E5=9C=A8=E5=88=B6=E4=BD=9C=E8=A1=A5=E4=B8=81=E6=97=B6?= =?UTF-8?q?=E8=A2=AB=E5=BF=BD=E7=95=A5=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C?= =?UTF-8?q?fix=20https://github.com/Tencent/InjectFix/issues/75?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 5 +++++ Source/VSProj/Src/Tools/GenerateConfigure.cs | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 18c8891..e37d088 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -152,6 +152,7 @@ where isCompilerGenerated(instruction.Operand as FieldReference) //再补丁新增一个对原生方法的引用 int addExternType(TypeReference type, TypeReference contextType = null) { + if (type.IsRequiredModifier) return addExternType((type as RequiredModifierType).ElementType, contextType); if (type.IsGenericParameter || type.HasGenericArgumentFromMethod()) { throw new InvalidProgramException("try to use a generic type definition"); @@ -3268,6 +3269,10 @@ void writeMethod(BinaryWriter writer, MethodReference method) { paramType = (paramType as GenericParameter).ResolveGenericArgument(method.DeclaringType); } + if (paramType.IsRequiredModifier) + { + paramType = (paramType as RequiredModifierType).ElementType; + } if (!externTypeToId.ContainsKey(paramType)) { throw new Exception("externTypeToId do not exist key: " + paramType diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index ace464f..3bd5aea 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -173,8 +173,13 @@ bool isMatch(Dictionary matchInfo, MethodReference me bool paramMatch = true; for(int i = 0; i < mmi.Parameters.Length; i++) { + var paramType = method.Parameters[i].ParameterType; + if (paramType.IsRequiredModifier) + { + paramType = (paramType as RequiredModifierType).ElementType; + } if (mmi.Parameters[i].IsOut != method.Parameters[i].IsOut - || mmi.Parameters[i].ParameterType != method.Parameters[i].ParameterType.FullName) + || mmi.Parameters[i].ParameterType != paramType.FullName) { paramMatch = false; break; From fa7c9a252e28eb3bdb5e441c2d2097c31a2d4ec2 Mon Sep 17 00:00:00 2001 From: chexiongsheng Date: Wed, 19 Feb 2020 18:06:12 +0800 Subject: [PATCH 022/103] support method filter for inject stage --- Source/UnityProj/Assets/Helloworld/Calc.cs | 10 ++ .../Assets/Helloworld/Editor/HelloworldCfg.cs | 7 + .../UnityProj/Assets/IFix/Editor/Configure.cs | 28 +++ .../Assets/IFix/Editor/ILFixEditor.cs | 24 +++ Source/VSProj/Src/Tools/GenerateConfigure.cs | 169 ++++++++++-------- 5 files changed, 159 insertions(+), 79 deletions(-) diff --git a/Source/UnityProj/Assets/Helloworld/Calc.cs b/Source/UnityProj/Assets/Helloworld/Calc.cs index 364df68..4d6bb5e 100644 --- a/Source/UnityProj/Assets/Helloworld/Calc.cs +++ b/Source/UnityProj/Assets/Helloworld/Calc.cs @@ -21,5 +21,15 @@ 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; + } } } diff --git a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs index 6a151d9..8651e8b 100644 --- a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs +++ b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs @@ -28,4 +28,11 @@ static IEnumerable hotfix }; } } + + [IFix.Filter] + static bool Filter(System.Reflection.MethodInfo methodInfo) + { + return methodInfo.DeclaringType.FullName == "IFix.Test.Calculator" + && (methodInfo.Name == "Div" || methodInfo.Name == "Mult"); + } } diff --git a/Source/UnityProj/Assets/IFix/Editor/Configure.cs b/Source/UnityProj/Assets/IFix/Editor/Configure.cs index 4289d6f..db469c2 100644 --- a/Source/UnityProj/Assets/IFix/Editor/Configure.cs +++ b/Source/UnityProj/Assets/IFix/Editor/Configure.cs @@ -39,6 +39,11 @@ public class ReverseWrapperAttribute : Attribute { } + [AttributeUsage(AttributeTargets.Method)] + public class FilterAttribute : Attribute + { + } + public static class Configure { // @@ -81,6 +86,29 @@ where type.IsDefined(typeof(ConfigureAttribute), false) return tagsMap; } + public static List GetFilters() + { + var types = from assembly in AppDomain.CurrentDomain.GetAssemblies() + where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder) + from type in assembly.GetTypes() + where type.IsDefined(typeof(ConfigureAttribute), false) + select type; + + List filters = new List(); + foreach (var type in types) + { + foreach (var method in type.GetMethods(BindingFlags.Static | BindingFlags.Public + | BindingFlags.NonPublic | BindingFlags.DeclaredOnly)) + { + if(method.IsDefined(typeof(IFix.FilterAttribute), false)) + { + filters.Add(method); + } + } + } + return filters; + } + public static IEnumerable GetTagMethods(Type tagType, string searchAssembly) { return (from assembly in AppDomain.CurrentDomain.GetAssemblies() diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 5996f7d..f574ea7 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -221,11 +221,15 @@ public static void InjectAssembly(string assembly) "IFix.ReverseWrapperAttribute", }); + var filters = Configure.GetFilters(); + var processCfgPath = "./process_cfg"; //该程序集是否有配置了些类,如果没有就跳过注入操作 bool hasSomethingToDo = false; + var blackList = new List(); + using (BinaryWriter writer = new BinaryWriter(new FileStream(processCfgPath, FileMode.Create, FileAccess.Write))) { @@ -250,8 +254,28 @@ public static void InjectAssembly(string assembly) { writer.Write(GetCecilTypeName(cfgItem.Key)); 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 filter in filters) + { + if ((bool)filter.Invoke(null, new object[] + { + method + })) + { + blackList.Add(method); + } + } + } + } } } + + writeMethods(writer, blackList); } if (hasSomethingToDo) diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 3bd5aea..505d580 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -42,6 +42,7 @@ public static GenerateConfigure FromFile(string filename) } generateConfigure.configures[configureName] = configure; } + generateConfigure.blackListMethodInfo = readMatchInfo(reader); } return generateConfigure; @@ -62,6 +63,86 @@ public static GenerateConfigure FromFile(string filename) /// 要查询的方法 /// public abstract bool IsNewMethod(MethodReference method); + + //参数类型信息 + internal class ParameterMatchInfo + { + public bool IsOut; + public string ParameterType; + } + + //方法签名信息 + internal class MethodMatchInfo + { + public string Name; + public string ReturnType; + public ParameterMatchInfo[] Parameters; + } + + //判断一个方法是否能够在matchInfo里头能查询到 + internal static bool isMatch(Dictionary matchInfo, MethodReference method) + { + MethodMatchInfo[] mmis; + if (matchInfo.TryGetValue(method.DeclaringType.FullName, out mmis)) + { + foreach (var mmi in mmis) + { + if (mmi.Name == method.Name && mmi.ReturnType == method.ReturnType.FullName + && mmi.Parameters.Length == method.Parameters.Count) + { + bool paramMatch = true; + for (int i = 0; i < mmi.Parameters.Length; i++) + { + var paramType = method.Parameters[i].ParameterType; + if (paramType.IsRequiredModifier) + { + paramType = (paramType as RequiredModifierType).ElementType; + } + if (mmi.Parameters[i].IsOut != method.Parameters[i].IsOut + || mmi.Parameters[i].ParameterType != paramType.FullName) + { + paramMatch = false; + break; + } + } + if (paramMatch) return true; + } + } + } + return false; + } + + //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 + internal static Dictionary readMatchInfo(BinaryReader reader) + { + Dictionary matchInfo = new Dictionary(); + + int typeCount = reader.ReadInt32(); + for (int k = 0; k < typeCount; k++) + { + string typeName = reader.ReadString(); + int methodCount = reader.ReadInt32(); + MethodMatchInfo[] methodMatchInfos = new MethodMatchInfo[methodCount]; + for (int i = 0; i < methodCount; i++) + { + MethodMatchInfo mmi = new MethodMatchInfo(); + mmi.Name = reader.ReadString(); + mmi.ReturnType = reader.ReadString(); + int parameterCount = reader.ReadInt32(); + mmi.Parameters = new ParameterMatchInfo[parameterCount]; + for (int p = 0; p < parameterCount; p++) + { + mmi.Parameters[p] = new ParameterMatchInfo(); + mmi.Parameters[p].IsOut = reader.ReadBoolean(); + mmi.Parameters[p].ParameterType = reader.ReadString(); + } + methodMatchInfos[i] = mmi; + } + matchInfo[typeName] = methodMatchInfos; + } + + return matchInfo; + } } //内部测试专用 @@ -85,10 +166,19 @@ public class DefaultGenerateConfigure : GenerateConfigure internal Dictionary> configures = new Dictionary>(); + internal Dictionary blackListMethodInfo = null; + public override bool TryGetConfigure(string tag, MethodReference method, out int flag) { Dictionary configure; flag = 0; + if(tag == "IFix.IFixAttribute" && blackListMethodInfo != null) + { + if(isMatch(blackListMethodInfo, method)) + { + return false; + } + } return (configures.TryGetValue(tag, out configure) && configure.TryGetValue(method.DeclaringType.FullName, out flag)); } @@ -144,85 +234,6 @@ MethodDefinition findMatchMethod(Dictionary matchInfo, MethodReference method) - { - MethodMatchInfo[] mmis; - if (matchInfo.TryGetValue(method.DeclaringType.FullName, out mmis)) - { - foreach(var mmi in mmis) - { - if (mmi.Name == method.Name && mmi.ReturnType == method.ReturnType.FullName - && mmi.Parameters.Length == method.Parameters.Count) - { - bool paramMatch = true; - for(int i = 0; i < mmi.Parameters.Length; i++) - { - var paramType = method.Parameters[i].ParameterType; - if (paramType.IsRequiredModifier) - { - paramType = (paramType as RequiredModifierType).ElementType; - } - if (mmi.Parameters[i].IsOut != method.Parameters[i].IsOut - || mmi.Parameters[i].ParameterType != paramType.FullName) - { - paramMatch = false; - break; - } - } - if (paramMatch) return true; - } - } - } - return false; - } - - //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 - static Dictionary readMatchInfo(BinaryReader reader) - { - Dictionary matchInfo = new Dictionary(); - - int typeCount = reader.ReadInt32(); - for (int k = 0; k < typeCount; k++) - { - string typeName = reader.ReadString(); - int methodCount = reader.ReadInt32(); - MethodMatchInfo[] methodMatchInfos = new MethodMatchInfo[methodCount]; - for (int i = 0; i < methodCount; i++) - { - MethodMatchInfo mmi = new MethodMatchInfo(); - mmi.Name = reader.ReadString(); - mmi.ReturnType = reader.ReadString(); - int parameterCount = reader.ReadInt32(); - mmi.Parameters = new ParameterMatchInfo[parameterCount]; - for (int p = 0; p < parameterCount; p++) - { - mmi.Parameters[p] = new ParameterMatchInfo(); - mmi.Parameters[p].IsOut = reader.ReadBoolean(); - mmi.Parameters[p].ParameterType = reader.ReadString(); - } - methodMatchInfos[i] = mmi; - } - matchInfo[typeName] = methodMatchInfos; - } - - return matchInfo; - } //读取配置信息(要patch的方法列表,新增方法列表) public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) From ac6abf5d8b345032d1e8adcf8d50064bc859fe60 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 17 Mar 2020 20:42:55 +0800 Subject: [PATCH 023/103] =?UTF-8?q?=E8=A7=84=E9=81=BFil2cpp=E5=9C=A8?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E4=B8=AA=E6=95=B0=E5=A4=A7=E4=BA=8E32767?= =?UTF-8?q?=E7=94=9F=E6=88=90=E4=BB=A3=E7=A0=81=E6=8A=A5=E9=94=99=E7=9A=84?= =?UTF-8?q?bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Src/Builder/FileVirtualMachineBuilder.cs | 23 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 90 ++- Source/VSProj/Src/Tools/GenerateConfigure.cs | 512 +++++++++--------- 3 files changed, 337 insertions(+), 288 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index 08f69f9..33d2a17 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -215,13 +215,19 @@ static FieldInfo getRedirectField(MethodBase method) return redirectField; } - static int getMapId(Type idMapType, MethodBase method) + static int getMapId(List idMapArray, MethodBase method) { IDTagAttribute id = Attribute.GetCustomAttribute(method, typeof(IDTagAttribute), false) as IDTagAttribute; int overrideId = id == null ? 0 : id.ID; var fieldName = string.Format("{0}-{1}{2}", method.DeclaringType.FullName.Replace('.', '-') .Replace('+', '-'), method.Name, overrideId); - var field = idMapType.GetField(fieldName); + FieldInfo field = null; + + for (int i = 0; i < idMapArray.Count; i++) + { + field = idMapArray[i].GetField(fieldName); + if (field != null) break; + } if (field == null) { throw new Exception(string.Format("cat not find id field: {0}, for {1}", fieldName, method)); @@ -450,8 +456,15 @@ unsafe static public VirtualMachine Load(Stream stream) } virtualMachine.WrappersManager = wrapperManager; - var idMapTypeName = reader.ReadString(); - var idMapType = Type.GetType(idMapTypeName, true); + var assemblyStr = reader.ReadString(); + var idMapList = new List(); + for(int i = 0; i < 100; i++) + { + + var idMapType = Type.GetType("IFix.IDMAP" + i + assemblyStr, false); + if (idMapType == null) break; + idMapList.Add(idMapType); + } lock (removers) { @@ -496,7 +509,7 @@ unsafe static public VirtualMachine Load(Stream stream) { var fixMethod = readMethod(reader, externTypes); var fixMethodId = reader.ReadInt32(); - var pos = getMapId(idMapType, fixMethod); + var pos = getMapId(idMapList, fixMethod); methodIdArray[i] = fixMethodId; posArray[i] = pos; if (pos > maxPos) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index e37d088..4739b9d 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1067,22 +1067,22 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, code.Add(new Core.Instruction { Code = Core.Code.StackSpace, Operand = (body.Variables.Count << 16) | body.MaxStackSize }); // local | maxstack - foreach(var variable in body.Variables) - { - if (variable.VariableType.IsValueType && !variable.VariableType.IsPrimitive) - { - code.Add(new Core.Instruction - { - Code = Core.Code.Ldloca, - Operand = variable.Index, - }); - - code.Add(new Core.Instruction - { - Code = Core.Code.Initobj, - Operand = addExternType(variable.VariableType) - }); - } + foreach(var variable in body.Variables) + { + if (variable.VariableType.IsValueType && !variable.VariableType.IsPrimitive) + { + code.Add(new Core.Instruction + { + Code = Core.Code.Ldloca, + Operand = variable.Index, + }); + + code.Add(new Core.Instruction + { + Code = Core.Code.Initobj, + Operand = addExternType(variable.VariableType) + }); + } } Core.ExceptionHandler[] exceptionHandlers = new Core.ExceptionHandler[body.ExceptionHandlers.Count]; @@ -1748,6 +1748,8 @@ public enum ProcessResult private TypeReference voidType; private TypeDefinition wrapperType; private TypeDefinition idMapType; + private TypeReference enumType; + private List idMapList; private TypeDefinition itfBridgeType; private int bridgeMethodId; private TypeReference anonymousStoreyTypeRef; @@ -2516,12 +2518,9 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) //end init itfBridgeType //begin init idMapper - var enumType = assembly.MainModule.ImportReference(typeof(System.Enum)); - idMapType = new TypeDefinition("IFix", "IDMAP", TypeAttributes.Public | TypeAttributes.Sealed, - enumType); - assembly.MainModule.Types.Add(idMapType); - idMapType.Fields.Add(new FieldDefinition("value__", FieldAttributes.Public | FieldAttributes.SpecialName - | FieldAttributes.RTSpecialName, assembly.MainModule.TypeSystem.Int32)); + enumType = assembly.MainModule.ImportReference(typeof(System.Enum)); + idMapList = new List(); + idMapType = null; //end init idMapper wrapperMethods = new List(); @@ -2594,6 +2593,24 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) initStackOp(Call, assembly.MainModule.TypeSystem.UIntPtr); } + const int MAX_ID_MAP_FIELD_COUNT = 32760; + + void idMapTypeCheck() + { + if (idMapType == null || idMapType.Fields.Count >= MAX_ID_MAP_FIELD_COUNT) + { + if (idMapType != null) + { + idMapList.Add(idMapType); + } + idMapType = new TypeDefinition("IFix", "IDMAP" + idMapList.Count, TypeAttributes.Public | TypeAttributes.Sealed, + enumType); + assembly.MainModule.Types.Add(idMapType); + idMapType.Fields.Add(new FieldDefinition("value__", FieldAttributes.Public | FieldAttributes.SpecialName + | FieldAttributes.RTSpecialName, assembly.MainModule.TypeSystem.Int32)); + } + } + void initStackOp(TypeDefinition call, TypeReference type) { pushMap[type] = importMethodReference(call, "Push" + type.Name); @@ -2842,6 +2859,7 @@ void addRedirectIdInfo(MethodDefinition method, int id) { throw new Exception("try inject method twice: " + method); } + idMapTypeCheck(); var redirectIdField = new FieldDefinition("tmp_r_field_" + redirectIdMap.Count, FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal | FieldAttributes.HasDefault, idMapType); idMapType.Fields.Add(redirectIdField); @@ -2932,6 +2950,8 @@ void redirectFieldRename() } } } + idMapList.Add(idMapType); + idMapType = null; } //1、构造函数及析构函数不转,不支持的指令不转,转的函数留下函数定义,所以支持反射 @@ -3269,9 +3289,9 @@ void writeMethod(BinaryWriter writer, MethodReference method) { paramType = (paramType as GenericParameter).ResolveGenericArgument(method.DeclaringType); } - if (paramType.IsRequiredModifier) - { - paramType = (paramType as RequiredModifierType).ElementType; + if (paramType.IsRequiredModifier) + { + paramType = (paramType as RequiredModifierType).ElementType; } if (!externTypeToId.ContainsKey(paramType)) { @@ -3431,8 +3451,24 @@ public void Serialize(Stream output) writeSlotInfo(writer, anonymousType); } - writer.Write(wrapperMgrImpl.GetAssemblyQualifiedName()); - writer.Write(idMapType.GetAssemblyQualifiedName()); + writer.Write(wrapperMgrImpl.GetAssemblyQualifiedName()); + + TypeDefinition idMap0 = null; + if (idMapList.Count == 0) + { + if (idMapType == null) + { + idMapTypeCheck(); + } + idMap0 = idMapType; + idMapType = null; + } + else + { + idMap0 = idMapList[0]; + } + var idMap0Name = idMap0.GetAssemblyQualifiedName(); + writer.Write(idMap0Name.Substring("IFix.IDMAP0".Length)); writer.Write(interpretMethods.Count); //Console.WriteLine("interpretMethods.Count:" + interpretMethods.Count); diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 505d580..7db128b 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -1,263 +1,263 @@ -/* - * 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 System.Collections.Generic; -using System.IO; -using Mono.Cecil; -using Mono.Cecil.Cil; -using System; -using System.Linq; - -namespace IFix -{ - public abstract class GenerateConfigure - { - public static GenerateConfigure Empty() - { - return new EmptyGenerateConfigure(); - } - - //仅仅简单的从文件加载类名而已 - public static GenerateConfigure FromFile(string filename) - { - DefaultGenerateConfigure generateConfigure = new DefaultGenerateConfigure(); - - using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open))) - { - int configureNum = reader.ReadInt32(); - for (int i = 0; i < configureNum; i++) - { - string configureName = reader.ReadString(); - Dictionary configure = new Dictionary(); - int cfgItemCount = reader.ReadInt32(); - for (int j = 0; j < cfgItemCount; j++) - { - string typeName = reader.ReadString(); - int flag = reader.ReadInt32(); - configure[typeName] = flag; - } - generateConfigure.configures[configureName] = configure; - } - generateConfigure.blackListMethodInfo = readMatchInfo(reader); - } - - return generateConfigure; - } - - /// - /// 如果一个方法打了指定的标签,返回其配置的标志位 - /// - /// 标签 - /// 要查询的方法 - /// 输出参数,用户配置的标志位 - /// - public abstract bool TryGetConfigure(string tag, MethodReference method, out int flag); - - /// - /// 判断一个方法是否是新增方法 - /// - /// 要查询的方法 - /// - public abstract bool IsNewMethod(MethodReference method); - - //参数类型信息 - internal class ParameterMatchInfo - { - public bool IsOut; - public string ParameterType; - } - - //方法签名信息 - internal class MethodMatchInfo - { - public string Name; - public string ReturnType; - public ParameterMatchInfo[] Parameters; - } - - //判断一个方法是否能够在matchInfo里头能查询到 - internal static bool isMatch(Dictionary matchInfo, MethodReference method) - { - MethodMatchInfo[] mmis; - if (matchInfo.TryGetValue(method.DeclaringType.FullName, out mmis)) - { - foreach (var mmi in mmis) - { - if (mmi.Name == method.Name && mmi.ReturnType == method.ReturnType.FullName - && mmi.Parameters.Length == method.Parameters.Count) - { - bool paramMatch = true; - for (int i = 0; i < mmi.Parameters.Length; i++) - { - var paramType = method.Parameters[i].ParameterType; - if (paramType.IsRequiredModifier) - { - paramType = (paramType as RequiredModifierType).ElementType; - } - if (mmi.Parameters[i].IsOut != method.Parameters[i].IsOut - || mmi.Parameters[i].ParameterType != paramType.FullName) - { - paramMatch = false; - break; - } - } - if (paramMatch) return true; - } - } - } - return false; - } - - //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 - internal static Dictionary readMatchInfo(BinaryReader reader) - { - Dictionary matchInfo = new Dictionary(); - - int typeCount = reader.ReadInt32(); - for (int k = 0; k < typeCount; k++) - { - string typeName = reader.ReadString(); - int methodCount = reader.ReadInt32(); - MethodMatchInfo[] methodMatchInfos = new MethodMatchInfo[methodCount]; - for (int i = 0; i < methodCount; i++) - { - MethodMatchInfo mmi = new MethodMatchInfo(); - mmi.Name = reader.ReadString(); - mmi.ReturnType = reader.ReadString(); - int parameterCount = reader.ReadInt32(); - mmi.Parameters = new ParameterMatchInfo[parameterCount]; - for (int p = 0; p < parameterCount; p++) - { - mmi.Parameters[p] = new ParameterMatchInfo(); - mmi.Parameters[p].IsOut = reader.ReadBoolean(); - mmi.Parameters[p].ParameterType = reader.ReadString(); - } - methodMatchInfos[i] = mmi; - } - matchInfo[typeName] = methodMatchInfos; - } - - return matchInfo; - } - } - - //内部测试专用 - public class EmptyGenerateConfigure : GenerateConfigure - { - public override bool TryGetConfigure(string tag, MethodReference method, out int flag) - { - flag = 0; - return true; - } - - public override bool IsNewMethod(MethodReference method) - { - return false; - } - } - - //注入配置使用 - public class DefaultGenerateConfigure : GenerateConfigure - { - internal Dictionary> configures - = new Dictionary>(); - - internal Dictionary blackListMethodInfo = null; - - public override bool TryGetConfigure(string tag, MethodReference method, out int flag) - { - Dictionary configure; - flag = 0; +/* + * 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 System.Collections.Generic; +using System.IO; +using Mono.Cecil; +using Mono.Cecil.Cil; +using System; +using System.Linq; + +namespace IFix +{ + public abstract class GenerateConfigure + { + public static GenerateConfigure Empty() + { + return new EmptyGenerateConfigure(); + } + + //仅仅简单的从文件加载类名而已 + public static GenerateConfigure FromFile(string filename) + { + DefaultGenerateConfigure generateConfigure = new DefaultGenerateConfigure(); + + using (BinaryReader reader = new BinaryReader(File.Open(filename, FileMode.Open))) + { + int configureNum = reader.ReadInt32(); + for (int i = 0; i < configureNum; i++) + { + string configureName = reader.ReadString(); + Dictionary configure = new Dictionary(); + int cfgItemCount = reader.ReadInt32(); + for (int j = 0; j < cfgItemCount; j++) + { + string typeName = reader.ReadString(); + int flag = reader.ReadInt32(); + configure[typeName] = flag; + } + generateConfigure.configures[configureName] = configure; + } + generateConfigure.blackListMethodInfo = readMatchInfo(reader); + } + + return generateConfigure; + } + + /// + /// 如果一个方法打了指定的标签,返回其配置的标志位 + /// + /// 标签 + /// 要查询的方法 + /// 输出参数,用户配置的标志位 + /// + public abstract bool TryGetConfigure(string tag, MethodReference method, out int flag); + + /// + /// 判断一个方法是否是新增方法 + /// + /// 要查询的方法 + /// + public abstract bool IsNewMethod(MethodReference method); + + //参数类型信息 + internal class ParameterMatchInfo + { + public bool IsOut; + public string ParameterType; + } + + //方法签名信息 + internal class MethodMatchInfo + { + public string Name; + public string ReturnType; + public ParameterMatchInfo[] Parameters; + } + + //判断一个方法是否能够在matchInfo里头能查询到 + internal static bool isMatch(Dictionary matchInfo, MethodReference method) + { + MethodMatchInfo[] mmis; + if (matchInfo.TryGetValue(method.DeclaringType.FullName, out mmis)) + { + foreach (var mmi in mmis) + { + if (mmi.Name == method.Name && mmi.ReturnType == method.ReturnType.FullName + && mmi.Parameters.Length == method.Parameters.Count) + { + bool paramMatch = true; + for (int i = 0; i < mmi.Parameters.Length; i++) + { + var paramType = method.Parameters[i].ParameterType; + if (paramType.IsRequiredModifier) + { + paramType = (paramType as RequiredModifierType).ElementType; + } + if (mmi.Parameters[i].IsOut != method.Parameters[i].IsOut + || mmi.Parameters[i].ParameterType != paramType.FullName) + { + paramMatch = false; + break; + } + } + if (paramMatch) return true; + } + } + } + return false; + } + + //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 + internal static Dictionary readMatchInfo(BinaryReader reader) + { + Dictionary matchInfo = new Dictionary(); + + int typeCount = reader.ReadInt32(); + for (int k = 0; k < typeCount; k++) + { + string typeName = reader.ReadString(); + int methodCount = reader.ReadInt32(); + MethodMatchInfo[] methodMatchInfos = new MethodMatchInfo[methodCount]; + for (int i = 0; i < methodCount; i++) + { + MethodMatchInfo mmi = new MethodMatchInfo(); + mmi.Name = reader.ReadString(); + mmi.ReturnType = reader.ReadString(); + int parameterCount = reader.ReadInt32(); + mmi.Parameters = new ParameterMatchInfo[parameterCount]; + for (int p = 0; p < parameterCount; p++) + { + mmi.Parameters[p] = new ParameterMatchInfo(); + mmi.Parameters[p].IsOut = reader.ReadBoolean(); + mmi.Parameters[p].ParameterType = reader.ReadString(); + } + methodMatchInfos[i] = mmi; + } + matchInfo[typeName] = methodMatchInfos; + } + + return matchInfo; + } + } + + //内部测试专用 + public class EmptyGenerateConfigure : GenerateConfigure + { + public override bool TryGetConfigure(string tag, MethodReference method, out int flag) + { + flag = 0; + return true; + } + + public override bool IsNewMethod(MethodReference method) + { + return false; + } + } + + //注入配置使用 + public class DefaultGenerateConfigure : GenerateConfigure + { + internal Dictionary> configures + = new Dictionary>(); + + internal Dictionary blackListMethodInfo = null; + + public override bool TryGetConfigure(string tag, MethodReference method, out int flag) + { + Dictionary configure; + flag = 0; if(tag == "IFix.IFixAttribute" && blackListMethodInfo != null) { if(isMatch(blackListMethodInfo, method)) { return false; } - } - return (configures.TryGetValue(tag, out configure) - && configure.TryGetValue(method.DeclaringType.FullName, out flag)); - } - - public override bool IsNewMethod(MethodReference method) - { - return false; - } - } - - //patch配置使用 - public class PatchGenerateConfigure : GenerateConfigure - { - public override bool TryGetConfigure(string tag, MethodReference method, out int flag) - { - flag = 0; - if (tag == "IFix.InterpretAttribute") - { - return redirectMethods.Contains(method); - } - else if (tag == "IFix.IFixAttribute") - { - return switchMethods.Contains(method); - } - return false; - } - - public override bool IsNewMethod(MethodReference method) - { - return newMethods.Contains(method); - } - - //暂时不支持redirect类型的方法 - HashSet redirectMethods = new HashSet(); - HashSet switchMethods = new HashSet(); - HashSet newMethods = new HashSet(); - - MethodDefinition findMatchMethod(Dictionary>> searchData, - MethodDefinition method) - { - Dictionary> methodsOfType; - List overloads; - if (searchData.TryGetValue(method.DeclaringType.FullName, out methodsOfType) - && methodsOfType.TryGetValue(method.Name, out overloads)) - { - foreach (var overload in overloads) - { - if (overload.IsTheSame(method)) - { - return overload; - } - } - } - return null; - } - - //读取配置信息(要patch的方法列表,新增方法列表) - public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) - { - Dictionary patchMethodInfo = null; - Dictionary newMethodInfo = null; - - using (BinaryReader reader = new BinaryReader(File.Open(cfgPath, FileMode.Open))) - { - patchMethodInfo = readMatchInfo(reader); - newMethodInfo = readMatchInfo(reader); - } - - foreach (var method in (from type in newAssembly.GetAllType() from method in type.Methods select method )) - { - if (isMatch(patchMethodInfo, method)) - { - switchMethods.Add(method); - } - if (isMatch(newMethodInfo, method)) - { - newMethods.Add(method); - } - } - } - } + } + return (configures.TryGetValue(tag, out configure) + && configure.TryGetValue(method.DeclaringType.FullName, out flag)); + } + + public override bool IsNewMethod(MethodReference method) + { + return false; + } + } + + //patch配置使用 + public class PatchGenerateConfigure : GenerateConfigure + { + public override bool TryGetConfigure(string tag, MethodReference method, out int flag) + { + flag = 0; + if (tag == "IFix.InterpretAttribute") + { + return redirectMethods.Contains(method); + } + else if (tag == "IFix.IFixAttribute") + { + return switchMethods.Contains(method); + } + return false; + } + + public override bool IsNewMethod(MethodReference method) + { + return newMethods.Contains(method); + } + + //暂时不支持redirect类型的方法 + HashSet redirectMethods = new HashSet(); + HashSet switchMethods = new HashSet(); + HashSet newMethods = new HashSet(); + + MethodDefinition findMatchMethod(Dictionary>> searchData, + MethodDefinition method) + { + Dictionary> methodsOfType; + List overloads; + if (searchData.TryGetValue(method.DeclaringType.FullName, out methodsOfType) + && methodsOfType.TryGetValue(method.Name, out overloads)) + { + foreach (var overload in overloads) + { + if (overload.IsTheSame(method)) + { + return overload; + } + } + } + return null; + } + + //读取配置信息(要patch的方法列表,新增方法列表) + public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) + { + Dictionary patchMethodInfo = null; + Dictionary newMethodInfo = null; + + using (BinaryReader reader = new BinaryReader(File.Open(cfgPath, FileMode.Open))) + { + patchMethodInfo = readMatchInfo(reader); + newMethodInfo = readMatchInfo(reader); + } + + foreach (var method in (from type in newAssembly.GetAllType() from method in type.Methods select method )) + { + if (isMatch(patchMethodInfo, method)) + { + switchMethods.Add(method); + } + if (isMatch(newMethodInfo, method)) + { + newMethods.Add(method); + } + } + } + } } \ No newline at end of file From 07c5294b789c31cb03f17cd763df193f3619c47e Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 20 Mar 2020 14:57:45 +0800 Subject: [PATCH 024/103] =?UTF-8?q?=E5=9C=A8=E8=BF=99=E4=B8=AA=E4=BF=AE?= =?UTF-8?q?=E6=94=B9https://github.com/Tencent/InjectFix/commit/4f00ce8eb1?= =?UTF-8?q?c1e238b6c72ee2aa9e0eaba2c47008=EF=BC=8C=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E4=BA=86=E7=BB=93=E6=9E=84=E4=BD=93=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E6=8C=87=E4=BB=A4=EF=BC=8C=E4=BD=86=E6=9C=AA=E5=AF=B9=E5=90=8E?= =?UTF-8?q?=E7=BB=AD=E6=8C=87=E4=BB=A4=E7=9A=84=E5=81=8F=E7=A7=BB=E8=BF=9B?= =?UTF-8?q?=E8=A1=8C=E4=BF=AE=E6=AD=A3=EF=BC=8C=E5=AF=BC=E8=87=B4=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E8=B7=B3=E8=BD=AC=E7=9B=AE=E6=A0=87=EF=BC=8C?= =?UTF-8?q?fix=20https://github.com/Tencent/InjectFix/issues/87?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 39 +++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 4739b9d..a5f5b82 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1067,6 +1067,8 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, code.Add(new Core.Instruction { Code = Core.Code.StackSpace, Operand = (body.Variables.Count << 16) | body.MaxStackSize }); // local | maxstack + int offsetAdd = 0; + foreach(var variable in body.Variables) { if (variable.VariableType.IsValueType && !variable.VariableType.IsPrimitive) @@ -1082,9 +1084,20 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, Code = Core.Code.Initobj, Operand = addExternType(variable.VariableType) }); + offsetAdd += 2; } } + if (offsetAdd > 0) + { + var ilNewOffset = new Dictionary(); + foreach (var kv in ilOffset) + { + ilNewOffset[kv.Key] = kv.Value + offsetAdd; + } + ilOffset = ilNewOffset; + } + Core.ExceptionHandler[] exceptionHandlers = new Core.ExceptionHandler[body.ExceptionHandlers.Count]; for (int i = 0; i < body.ExceptionHandlers.Count; i++) @@ -3451,21 +3464,21 @@ public void Serialize(Stream output) writeSlotInfo(writer, anonymousType); } - writer.Write(wrapperMgrImpl.GetAssemblyQualifiedName()); - + writer.Write(wrapperMgrImpl.GetAssemblyQualifiedName()); + TypeDefinition idMap0 = null; - if (idMapList.Count == 0) - { - if (idMapType == null) - { - idMapTypeCheck(); - } - idMap0 = idMapType; - idMapType = null; + if (idMapList.Count == 0) + { + if (idMapType == null) + { + idMapTypeCheck(); + } + idMap0 = idMapType; + idMapType = null; } - else - { - idMap0 = idMapList[0]; + else + { + idMap0 = idMapList[0]; } var idMap0Name = idMap0.GetAssemblyQualifiedName(); writer.Write(idMap0Name.Substring("IFix.IDMAP0".Length)); From 486801741d0878b751da1f9a8b2b8b64e9bcd430 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 23 Mar 2020 17:57:51 +0800 Subject: [PATCH 025/103] =?UTF-8?q?=E6=B3=A8=E5=85=A5=E6=AD=A5=E9=AA=A4?= =?UTF-8?q?=E4=B8=8D=E9=AA=8C=E8=AF=81=E5=86=85=E9=83=A8=E6=96=B9=E6=B3=95?= =?UTF-8?q?id=E6=98=AF=E5=90=A6=E8=B6=85=E8=BF=87ushort.MaxValue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index a5f5b82..9af13ed 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -919,7 +919,7 @@ int allocMethodId(MethodDefinition method) methodToId.Add(method, methodId); - if (methodId > ushort.MaxValue) + if (mode == ProcessMode.Patch && methodId > ushort.MaxValue) { throw new OverflowException("too many internal methods"); } From c5a938d52a1c2176e561d86af9b1150f47629603 Mon Sep 17 00:00:00 2001 From: JourneyHans Date: Tue, 21 Apr 2020 16:32:39 +0800 Subject: [PATCH 026/103] [Change] (#68) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [Change] 适配因为Unity2019.2.15f1打包流程修改而造成的问题,注入的Assembly文件夹先检测PlayerScriptAssemblies是否存在,不存在再处理ScriptAssemblies文件夹下的内容 * [Change] 修改命名风格,删掉不必要的打印 --- .../Assets/IFix/Editor/ILFixEditor.cs | 26 +++++++++++++++---- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index f574ea7..257a8f0 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -62,6 +62,9 @@ public class IFixEditor //备份文件的时间戳生成格式 const string TIMESTAMP_FORMAT = "yyyyMMddHHmmss"; + //注入的目标文件夹 + private static string targetAssembliesFolder = ""; + //system("mono ifix.exe [args]") public static void CallIFix(List args) { @@ -282,7 +285,7 @@ public static void InjectAssembly(string assembly) { var core_path = "./Assets/Plugins/IFix.Core.dll"; - var assembly_path = string.Format("./Library/ScriptAssemblies/{0}.dll", assembly); + 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 }; @@ -315,6 +318,8 @@ public static void InjectAllAssemblys() return; } + targetAssembliesFolder = GetScriptAssembliesFolder(); + foreach (var assembly in injectAssemblys) { InjectAssembly(assembly); @@ -325,6 +330,16 @@ public static void InjectAllAssemblys() AssetDatabase.Refresh(); } + private static string GetScriptAssembliesFolder() + { + var assembliesFolder = "PlayerScriptAssemblies"; + if (!Directory.Exists(string.Format("./Library/{0}/", assembliesFolder))) + { + assembliesFolder = "ScriptAssemblies"; + } + return assembliesFolder; + } + //默认的注入及备份程序集 //另外可以直接调用InjectAssembly对其它程序集进行注入。 static string[] injectAssemblys = new string[] @@ -344,7 +359,7 @@ static void doBackup(string ts) Directory.CreateDirectory(BACKUP_PATH); } - var scriptAssembliesDir = "./Library/ScriptAssemblies/"; + var scriptAssembliesDir = string.Format("./Library/{0}/", targetAssembliesFolder); foreach (var assembly in injectAssemblys) { @@ -375,7 +390,7 @@ static void doBackup(string ts) /// 时间戳 static void doRestore(string ts) { - var scriptAssembliesDir = "./Library/ScriptAssemblies/"; + var scriptAssembliesDir = string.Format("./Library/{0}/", targetAssembliesFolder); foreach (var assembly in injectAssemblys) { @@ -795,8 +810,9 @@ public static void Patch() { foreach (var assembly in injectAssemblys) { - GenPatch(assembly, string.Format("./Library/ScriptAssemblies/{0}.dll", assembly), - "./Assets/Plugins/IFix.Core.dll", string.Format("{0}.patch.bytes", assembly)); + var assembly_path = string.Format("./Library/{0}/{1}.dll", GetScriptAssembliesFolder(), assembly); + GenPatch(assembly, assembly_path, "./Assets/Plugins/IFix.Core.dll", + string.Format("{0}.patch.bytes", assembly)); } } catch (Exception e) From 5c540ec38ccfce780fe17b2798b176ab7192077d Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 24 Apr 2020 20:44:11 +0800 Subject: [PATCH 027/103] add Interpret class (#107) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 支持新增类 --- .../UnityProj/Assets/IFix/Editor/Configure.cs | 12 +++ .../Assets/IFix/Editor/ILFixEditor.cs | 11 +++ Source/VSProj/Src/Core/SwitchFlags.cs | 2 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 76 +++++++++++-------- Source/VSProj/Src/Tools/GenerateConfigure.cs | 44 ++++++++++- 5 files changed, 112 insertions(+), 33 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/Configure.cs b/Source/UnityProj/Assets/IFix/Editor/Configure.cs index db469c2..85bd117 100644 --- a/Source/UnityProj/Assets/IFix/Editor/Configure.cs +++ b/Source/UnityProj/Assets/IFix/Editor/Configure.cs @@ -121,5 +121,17 @@ from method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | Bin where method.IsDefined(tagType, false) select method); } + public static IEnumerable GetTagClasses(Type tagType, string searchAssembly) + { + return (from assembly in AppDomain.CurrentDomain.GetAssemblies() + where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder) + && (assembly.GetName().Name == searchAssembly) + where assembly.CodeBase.IndexOf("ScriptAssemblies") != -1 + from type in assembly.GetTypes() + where type.IsDefined(tagType, false) + select type + ); + + } } } diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 257a8f0..2e7914b 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -705,6 +705,15 @@ static void writeMethods(BinaryWriter writer, List methods) } } + static void writeClasses(BinaryWriter writer, List classes) + { + writer.Write(classes.Count); + foreach (var classGroup in classes) + { + writer.Write(GetCecilTypeName(classGroup)); + } + } + static bool hasGenericParameter(Type type) { if (type.IsByRef || type.IsArray) @@ -765,6 +774,7 @@ public static void GenPatch(string assembly, string assemblyCSharpPath } var newMethods = Configure.GetTagMethods(typeof(InterpretAttribute), assembly).ToList(); + var newClasses = Configure.GetTagClasses(typeof(InterpretAttribute), assembly).ToList(); genericMethod = newMethods.FirstOrDefault(m => hasGenericParameter(m)); if (genericMethod != null) { @@ -778,6 +788,7 @@ public static void GenPatch(string assembly, string assemblyCSharpPath { writeMethods(writer, patchMethods); writeMethods(writer, newMethods); + writeClasses(writer, newClasses); } List args = new List() { "-patch", corePath, assemblyCSharpPath, "null", diff --git a/Source/VSProj/Src/Core/SwitchFlags.cs b/Source/VSProj/Src/Core/SwitchFlags.cs index 3aeab23..82ea9d5 100644 --- a/Source/VSProj/Src/Core/SwitchFlags.cs +++ b/Source/VSProj/Src/Core/SwitchFlags.cs @@ -10,7 +10,7 @@ namespace IFix { //切换到解析执行 - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method)] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class)] public class InterpretAttribute : Attribute { } diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 9af13ed..c5e33d6 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -88,19 +88,28 @@ bool isCompilerGeneratedPlainObject(TypeReference type) var td = type as TypeDefinition; return td != null - && !td.IsInterface - //&& td.Interfaces.Count == 0 + && !td.IsInterface + //&& td.Interfaces.Count == 0 && isCompilerGenerated(type) && td.BaseType.IsSameType(objType); } + bool isCustomClassPlainObject(TypeReference type) + { + var td = type as TypeDefinition; + return td != null + && !td.IsInterface + && isNewClass(td) + && td.BaseType.IsSameType(objType); + } + bool isCompilerGeneratedByNotPlainObject(TypeReference type) { var td = type as TypeDefinition; return (type.IsGenericInstance || (td != null - && !td.IsInterface - //&& (!td.BaseType.IsSameType(objType) || td.Interfaces.Count != 0))) + && !td.IsInterface + //&& (!td.BaseType.IsSameType(objType) || td.Interfaces.Count != 0))) && !td.BaseType.IsSameType(objType))) && isCompilerGenerated(type); } @@ -131,7 +140,7 @@ HashSet getSpecialGeneratedFields(TypeDefinition type) var cctorInfo = getMethodId(cctor, null, false, InjectType.Redirect); typeToCctor[type] = cctorInfo.Type == CallType.Internal ? cctorInfo.Id : -2; } - } + } foreach (var field in ( from method in type.Methods where method.IsSpecialName && method.Body != null @@ -222,7 +231,7 @@ int addStoreField(FieldDefinition field, MethodDefinition caller) id = -(fieldsStoreInVirtualMachine.Count + 1); fieldToId.Add(field, id); fieldsStoreInVirtualMachine.Add(field); - addExternType(isCompilerGenerated(field.FieldType) ? objType : field.FieldType); + addExternType((isCompilerGenerated(field.FieldType) || isNewClass(field.FieldType as TypeDefinition)) ? objType : field.FieldType); } return id; } @@ -447,7 +456,7 @@ bool checkILAndGetOffset(MethodDefinition method, //如果是生成的字段,而且不是Getter/Setter/Adder/Remover if (isCompilerGenerated(fr) && !method.IsSpecialName) { - if (!IsVaildIdentifierName(fr.Name)//不是合法名字,就肯定是随机变量 + if (!IsVaildIdentifierName(fr.Name)//不是合法名字,就肯定是随机变量 //如果是合法名字,但不被任何SpecialName方法引用,也归为随机变量 || !isRefBySpecialMethod(fr as FieldDefinition)) @@ -497,12 +506,13 @@ bool checkILAndGetOffset(MethodDefinition method, //LINQ通常是ldftn,要验证ldftn所加载的函数是否含非法指令(不支持,或者引用了个生成字段, //或者一个生成NotPlainObject) MethodReference mr = instructions[i].Operand as MethodReference; - if (mr != null && !mr.IsGeneric() + if (mr != null && !mr.IsGeneric() && !isCompilerGeneratedByNotPlainObject(mr.DeclaringType)) { if (isCompilerGenerated(mr) || (/*instructions[i].OpCode.Code != Code.Newobj && */ - isCompilerGeneratedPlainObject(mr.DeclaringType))) + isCompilerGeneratedPlainObject(mr.DeclaringType)) + || isCustomClassPlainObject(mr.DeclaringType)) { var md = mr as MethodDefinition; if (md == null)//闭包中调用一个泛型,在unity2018的.net 3.5设置下,编译器是先生成一个泛型的闭包实现,然后实例化,很奇怪的做法,老版本unity,新unity的.net 4.0设置都不会这样,先返回false,不支持这种编译器 @@ -516,10 +526,10 @@ bool checkILAndGetOffset(MethodDefinition method, return false; } //编译器生成类要检查所有实现方法 - if (instructions[i].OpCode.Code == Code.Newobj - && isCompilerGeneratedPlainObject(mr.DeclaringType)) + if (instructions[i].OpCode.Code == Code.Newobj + && (isCompilerGeneratedPlainObject(mr.DeclaringType) || isCustomClassPlainObject(mr.DeclaringType))) { - foreach(var m in mr.DeclaringType.Resolve().Methods + foreach (var m in mr.DeclaringType.Resolve().Methods .Where(m => !m.IsConstructor)) { if (m.Body != null && !checkILAndGetOffset(m, m.Body.Instructions)) @@ -746,7 +756,7 @@ bool isFieldStoreInVitualMachine(FieldReference field) return false; } - if (!isCompilerGenerated(field) && !isCompilerGenerated(field.DeclaringType)) + if ((!isCompilerGenerated(field) && !isCompilerGenerated(field.DeclaringType)) || !isNewClass(field.DeclaringType as TypeDefinition)) { return false; } @@ -766,6 +776,10 @@ bool isNewMethod(MethodDefinition method) return configure.IsNewMethod(method); } + bool isNewClass(TypeDefinition type) + { + return configure.IsNewClass(type); + } Dictionary interpretMethods = new Dictionary(); void addInterpretMethod(MethodDefinition method, int methodId) @@ -962,11 +976,11 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } //如果是dll之外的方法,或者是构造函数,析构函数,作为虚拟机之外(extern)的方法 - if (method == null || (method.IsConstructor && !isCompilerGeneratedPlainObject(method.DeclaringType)) + if (method == null || (method.IsConstructor && !(isCompilerGeneratedPlainObject(method.DeclaringType) || isCustomClassPlainObject(method.DeclaringType))) || method.IsFinalizer() || method.IsAbstract || method.IsPInvokeImpl || method.Body == null || method.DeclaringType.IsInterface - || (!methodToInjectType.ContainsKey(method) && !isCompilerGenerated(method.DeclaringType) + || (!methodToInjectType.ContainsKey(method) && !(isCompilerGenerated(method.DeclaringType) || isNewClass(method.DeclaringType)) && !isCompilerGenerated(method) && !(mode == ProcessMode.Patch && isNewMethod(method)))) { //Console.WriteLine("do no tranlater:" + callee + "," + callee.GetType()); @@ -1088,14 +1102,14 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } } - if (offsetAdd > 0) - { - var ilNewOffset = new Dictionary(); - foreach (var kv in ilOffset) - { - ilNewOffset[kv.Key] = kv.Value + offsetAdd; - } - ilOffset = ilNewOffset; + if (offsetAdd > 0) + { + var ilNewOffset = new Dictionary(); + foreach (var kv in ilOffset) + { + ilNewOffset[kv.Key] = kv.Value + offsetAdd; + } + ilOffset = ilNewOffset; } Core.ExceptionHandler[] exceptionHandlers = new Core.ExceptionHandler[body.ExceptionHandlers.Count]; @@ -1396,8 +1410,8 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, break; } var methodToCall = msIl.Operand as MethodReference; - if (msIl.OpCode.Code == Code.Newobj && isCompilerGeneratedPlainObject( - methodToCall.DeclaringType)) + if (msIl.OpCode.Code == Code.Newobj && (isCompilerGeneratedPlainObject( + methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) { TypeDefinition td = methodToCall.DeclaringType as TypeDefinition; var anonymousCtorInfo = getMethodId(methodToCall, method, false, @@ -1511,7 +1525,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, var methodToCall = msIl.Operand as MethodReference; var methodIdInfo = getMethodId(methodToCall, method, false, injectTypePassToNext); if (methodIdInfo.Type == CallType.Internal - && isCompilerGeneratedPlainObject(methodToCall.DeclaringType)) // closure + && (isCompilerGeneratedPlainObject(methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) // closure { //Console.WriteLine("closure: " + methodToCall); getWrapperMethod(wrapperType, anonObjOfWrapper, methodToCall as MethodDefinition, @@ -1594,7 +1608,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, case Code.Ldflda: { var field = msIl.Operand as FieldReference; - if (isCompilerGeneratedPlainObject(field.DeclaringType)) + if (isCompilerGeneratedPlainObject(field.DeclaringType) || isCustomClassPlainObject(field.DeclaringType)) { var declaringType = field.DeclaringType as TypeDefinition; code.Add(new Core.Instruction @@ -1621,7 +1635,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, var fr = msIl.Operand as FieldReference; var fd = fr.Resolve(); bool storeInVitualMachine = (isCompilerGenerated(fr) - || isCompilerGenerated(fr.DeclaringType)) && + || isCompilerGenerated(fr.DeclaringType) || isNewClass(fr.DeclaringType as TypeDefinition)) && !getSpecialGeneratedFields(fr.DeclaringType.Resolve()).Contains(fd) && typeToCctor[fd.DeclaringType] > -2; if (!storeInVitualMachine && isCompilerGenerated(fr) && fd.Name.IndexOf("$cache") >= 0 @@ -2999,12 +3013,12 @@ public ProcessResult Process(AssemblyDefinition assembly, AssemblyDefinition ilf //makeCloneFast(ilfixAassembly); var allTypes = (from type in assembly.GetAllType() - where type.Namespace != "IFix" && !type.IsGeneric() && !isCompilerGenerated(type) + where type.Namespace != "IFix" && !type.IsGeneric() && !(isCompilerGenerated(type) || isNewClass(type)) select type); foreach (var method in ( from type in allTypes - where !isCompilerGenerated(type) && !type.HasGenericParameters + where !(isCompilerGenerated(type) || isNewClass(type)) && !type.HasGenericParameters from method in type.Methods where !method.IsConstructor && !isCompilerGenerated(method) && !method.HasGenericParameters select method)) @@ -3443,7 +3457,7 @@ public void Serialize(Stream output) for (int i = 0; i < fieldsStoreInVirtualMachine.Count; i++) { var fieldType = fieldsStoreInVirtualMachine[i].FieldType; - if (isCompilerGenerated(fieldType)) + if (isCompilerGenerated(fieldType) || isNewClass(fieldType as TypeDefinition)) { fieldType = objType; } diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 7db128b..7122bac 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -64,6 +64,7 @@ public static GenerateConfigure FromFile(string filename) /// public abstract bool IsNewMethod(MethodReference method); + public abstract bool IsNewClass(TypeReference type); //参数类型信息 internal class ParameterMatchInfo { @@ -112,6 +113,15 @@ internal static bool isMatch(Dictionary matchInfo, Me return false; } + internal static bool isMatchForClass(HashSet matchInfo, TypeReference type) + { + if (matchInfo.Contains(type.ToString())) + { + return true; + } + return false; + } + //读取方法信息,主要是方法的签名信息,名字+参数类型+返回值类型 internal static Dictionary readMatchInfo(BinaryReader reader) { @@ -143,6 +153,17 @@ internal static Dictionary readMatchInfo(BinaryReader return matchInfo; } + internal static HashSet readMatchInfoForClass(BinaryReader reader) + { + HashSet setMatchInfoForClass = new HashSet(); + int typeCount = reader.ReadInt32(); + for (int k = 0; k < typeCount; k++) + { + string className = reader.ReadString(); + setMatchInfoForClass.Add(className); + } + return setMatchInfoForClass; + } } //内部测试专用 @@ -158,6 +179,10 @@ public override bool IsNewMethod(MethodReference method) { return false; } + public override bool IsNewClass(TypeReference type) + { + return false; + } } //注入配置使用 @@ -187,6 +212,10 @@ public override bool IsNewMethod(MethodReference method) { return false; } + public override bool IsNewClass(TypeReference type) + { + return false; + } } //patch配置使用 @@ -211,11 +240,15 @@ public override bool IsNewMethod(MethodReference method) return newMethods.Contains(method); } + public override bool IsNewClass(TypeReference type) + { + return newClasses.Contains(type); + } //暂时不支持redirect类型的方法 HashSet redirectMethods = new HashSet(); HashSet switchMethods = new HashSet(); HashSet newMethods = new HashSet(); - + HashSet newClasses = new HashSet(); MethodDefinition findMatchMethod(Dictionary>> searchData, MethodDefinition method) { @@ -240,11 +273,13 @@ public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) { Dictionary patchMethodInfo = null; Dictionary newMethodInfo = null; + HashSet newClassInfo = null; using (BinaryReader reader = new BinaryReader(File.Open(cfgPath, FileMode.Open))) { patchMethodInfo = readMatchInfo(reader); newMethodInfo = readMatchInfo(reader); + newClassInfo = readMatchInfoForClass(reader); } foreach (var method in (from type in newAssembly.GetAllType() from method in type.Methods select method )) @@ -258,6 +293,13 @@ public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) newMethods.Add(method); } } + foreach (var clas in newAssembly.GetAllType()) + { + if (isMatchForClass(newClassInfo, clas)) + { + newClasses.Add(clas); + } + } } } } \ No newline at end of file From 0a7da391839bb52390ea19a3a42253fcd3744faa Mon Sep 17 00:00:00 2001 From: johnche Date: Sat, 25 Apr 2020 19:33:29 +0800 Subject: [PATCH 028/103] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E6=BC=94=E7=A4=BA=E4=BE=8B=E5=AD=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnityProj/Assets/NewClass/NewClassTest.cs | 136 ++++++++++++++++++ .../Assets/NewClass/NewClassTest.cs.meta | 11 ++ .../Assets/NewClass/VMBehaviourScript.cs | 25 ++++ .../Assets/NewClass/VMBehaviourScript.cs.meta | 11 ++ 4 files changed, 183 insertions(+) create mode 100644 Source/UnityProj/Assets/NewClass/NewClassTest.cs create mode 100644 Source/UnityProj/Assets/NewClass/NewClassTest.cs.meta create mode 100644 Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs create mode 100644 Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs.meta diff --git a/Source/UnityProj/Assets/NewClass/NewClassTest.cs b/Source/UnityProj/Assets/NewClass/NewClassTest.cs new file mode 100644 index 0000000..49ab8b4 --- /dev/null +++ b/Source/UnityProj/Assets/NewClass/NewClassTest.cs @@ -0,0 +1,136 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using IFix.Core; +using System.IO; + +//1、执行菜单“InjectFix/Fix”生成补丁; +//2、注释“NewBehaviourScript”,“SubSystem2”两个类,以及NewClassTest的Init函数里头new SubSystem2的那行语句; +//3、执行菜单“InjectFix/Inject”,模拟线上没有“NewBehaviourScript”,“SubSystem2”的版本; +//4、NewClassTest.cs拖到场景,运行看下效果,此时只加载SubSystem1; +//5、把生成的补丁拷贝到Resources下,再次运行看下效果; + +public interface IMonoBehaviour +{ + void Start();//简单demo,只定义了Start方法,实际Awake,Update,OnDestroy。。。都类似 + + void Update(); +} + +public class SubSystem1 : ISubsystem +{ + public bool running { get { return true; } } + + public void Start() + { + Debug.Log("SubSystem1.Start"); + } + + public void Stop() + { + Debug.Log("SubSystem1.Stop"); + } + + public void Destroy() + { + Debug.Log("SubSystem1.Destroy"); + } +} + +[IFix.Interpret] +public class NewBehaviourScript : IMonoBehaviour +{ + private int tick = 0; + + public void Start() + { + Debug.Log("NewBehaviourScript.Start"); + } + + public void Update() + { + if (tick++ % 60 == 0) + { + Debug.Log("NewBehaviourScript.Update"); + } + } +} + +[IFix.Interpret] +public class SubSystem2 : ISubsystem +{ + public bool running { get { return true; } } + + public void Start() + { + Debug.Log("SubSystem2.Start, create GameObject and attach a NewBehaviourScript"); + var go = new GameObject("hehe"); + var behaviour = go.AddComponent(typeof(VMBehaviourScript)) as VMBehaviourScript; + behaviour.VMMonoBehaviour = new NewBehaviourScript(); + } + + public void Stop() + { + Debug.Log("SubSystem2.Stop"); + } + + public void Destroy() + { + Debug.Log("SubSystem2.Destroy"); + } +} + + +public class NewClassTest : MonoBehaviour +{ + List subsystems = new List(); + + void Awake() + { + var patch = Resources.Load("Assembly-CSharp.patch"); + if (patch != null) + { + Debug.Log("loading Assembly-CSharp.patch ..."); + var sw = System.Diagnostics.Stopwatch.StartNew(); + PatchManager.Load(new MemoryStream(patch.bytes)); + Debug.Log("patch Assembly-CSharp.patch, using " + sw.ElapsedMilliseconds + " ms"); + } + Init(); + } + + [IFix.Patch] + private void Init() + { + subsystems.Add(new SubSystem1()); + //subsystems.Add(new SubSystem2()); + } + + + void Start() + { + foreach (var subSystem in subsystems) + { + subSystem.Start(); + } + } + + void OnDestroy() + { + foreach (var subSystem in subsystems) + { + subSystem.Destroy(); + } + } +} + + + +[IFix.CustomBridge] +public static class AdditionalBridge +{ + static List bridge = new List() + { + typeof(ISubsystem), + typeof(IMonoBehaviour) + }; +} \ No newline at end of file diff --git a/Source/UnityProj/Assets/NewClass/NewClassTest.cs.meta b/Source/UnityProj/Assets/NewClass/NewClassTest.cs.meta new file mode 100644 index 0000000..39848e8 --- /dev/null +++ b/Source/UnityProj/Assets/NewClass/NewClassTest.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 979878655427a4b4c835f28982c140ae +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs b/Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs new file mode 100644 index 0000000..0b89ca2 --- /dev/null +++ b/Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs @@ -0,0 +1,25 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class VMBehaviourScript : MonoBehaviour +{ + public IMonoBehaviour VMMonoBehaviour { get;set; } + + void Start() + { + if (VMMonoBehaviour != null) + { + VMMonoBehaviour.Start(); + } + } + + // Update is called once per frame + void Update() + { + if (VMMonoBehaviour != null) + { + VMMonoBehaviour.Update(); + } + } +} diff --git a/Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs.meta b/Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs.meta new file mode 100644 index 0000000..9f1ef76 --- /dev/null +++ b/Source/UnityProj/Assets/NewClass/VMBehaviourScript.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: b02b35b5e1bd10f48b1cdcad58a741d5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: From 783cae8e597d2e5f666a4f7031b9a6921e5f51af Mon Sep 17 00:00:00 2001 From: johnche Date: Sat, 25 Apr 2020 20:33:36 +0800 Subject: [PATCH 029/103] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E6=8D=A2=E8=A1=8C?= =?UTF-8?q?=E7=AC=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 38 +++++++++++------------ 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index c5e33d6..2eccf76 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -88,19 +88,19 @@ bool isCompilerGeneratedPlainObject(TypeReference type) var td = type as TypeDefinition; return td != null - && !td.IsInterface - //&& td.Interfaces.Count == 0 + && !td.IsInterface + //&& td.Interfaces.Count == 0 && isCompilerGenerated(type) && td.BaseType.IsSameType(objType); } - bool isCustomClassPlainObject(TypeReference type) - { - var td = type as TypeDefinition; - return td != null - && !td.IsInterface - && isNewClass(td) - && td.BaseType.IsSameType(objType); + bool isCustomClassPlainObject(TypeReference type) + { + var td = type as TypeDefinition; + return td != null + && !td.IsInterface + && isNewClass(td) + && td.BaseType.IsSameType(objType); } bool isCompilerGeneratedByNotPlainObject(TypeReference type) @@ -108,8 +108,8 @@ bool isCompilerGeneratedByNotPlainObject(TypeReference type) var td = type as TypeDefinition; return (type.IsGenericInstance || (td != null - && !td.IsInterface - //&& (!td.BaseType.IsSameType(objType) || td.Interfaces.Count != 0))) + && !td.IsInterface + //&& (!td.BaseType.IsSameType(objType) || td.Interfaces.Count != 0))) && !td.BaseType.IsSameType(objType))) && isCompilerGenerated(type); } @@ -140,7 +140,7 @@ HashSet getSpecialGeneratedFields(TypeDefinition type) var cctorInfo = getMethodId(cctor, null, false, InjectType.Redirect); typeToCctor[type] = cctorInfo.Type == CallType.Internal ? cctorInfo.Id : -2; } - } + } foreach (var field in ( from method in type.Methods where method.IsSpecialName && method.Body != null @@ -456,7 +456,7 @@ bool checkILAndGetOffset(MethodDefinition method, //如果是生成的字段,而且不是Getter/Setter/Adder/Remover if (isCompilerGenerated(fr) && !method.IsSpecialName) { - if (!IsVaildIdentifierName(fr.Name)//不是合法名字,就肯定是随机变量 + if (!IsVaildIdentifierName(fr.Name)//不是合法名字,就肯定是随机变量 //如果是合法名字,但不被任何SpecialName方法引用,也归为随机变量 || !isRefBySpecialMethod(fr as FieldDefinition)) @@ -506,7 +506,7 @@ bool checkILAndGetOffset(MethodDefinition method, //LINQ通常是ldftn,要验证ldftn所加载的函数是否含非法指令(不支持,或者引用了个生成字段, //或者一个生成NotPlainObject) MethodReference mr = instructions[i].Operand as MethodReference; - if (mr != null && !mr.IsGeneric() + if (mr != null && !mr.IsGeneric() && !isCompilerGeneratedByNotPlainObject(mr.DeclaringType)) { if (isCompilerGenerated(mr) @@ -526,7 +526,7 @@ bool checkILAndGetOffset(MethodDefinition method, return false; } //编译器生成类要检查所有实现方法 - if (instructions[i].OpCode.Code == Code.Newobj + if (instructions[i].OpCode.Code == Code.Newobj && (isCompilerGeneratedPlainObject(mr.DeclaringType) || isCustomClassPlainObject(mr.DeclaringType))) { foreach (var m in mr.DeclaringType.Resolve().Methods @@ -776,9 +776,9 @@ bool isNewMethod(MethodDefinition method) return configure.IsNewMethod(method); } - bool isNewClass(TypeDefinition type) - { - return configure.IsNewClass(type); + bool isNewClass(TypeDefinition type) + { + return configure.IsNewClass(type); } Dictionary interpretMethods = new Dictionary(); @@ -1410,7 +1410,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, break; } var methodToCall = msIl.Operand as MethodReference; - if (msIl.OpCode.Code == Code.Newobj && (isCompilerGeneratedPlainObject( + if (msIl.OpCode.Code == Code.Newobj && (isCompilerGeneratedPlainObject( methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) { TypeDefinition td = methodToCall.DeclaringType as TypeDefinition; From b0e4e8f391c1c81db5ed973cf17d2a43814ccf88 Mon Sep 17 00:00:00 2001 From: johnche Date: Sun, 26 Apr 2020 19:12:42 +0800 Subject: [PATCH 030/103] =?UTF-8?q?=E5=8C=BF=E5=90=8D=E7=B1=BB=EF=BC=8C?= =?UTF-8?q?=E6=96=B0=E7=B1=BB=E5=AF=B9=E8=B1=A1=E5=AD=97=E6=AE=B5=E6=9C=AA?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E8=AF=BB=EF=BC=8C=E4=BC=9A=E5=AF=BC?= =?UTF-8?q?=E8=87=B4=E5=AE=9A=E4=BD=8D=E5=88=B0=E9=94=99=E8=AF=AF=E7=9A=84?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=20fix=20?= =?UTF-8?q?https://github.com/Tencent/InjectFix/issues/100?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Src/Builder/FileVirtualMachineBuilder.cs | 18 ++++++++---- Source/VSProj/Src/Core/AnonymousStorey.cs | 16 +++++++++- Source/VSProj/Src/Core/VirtualMachine.cs | 4 +-- Source/VSProj/Src/Core/WrappersManager.cs | 2 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 29 ++++++++++++++++--- 5 files changed, 55 insertions(+), 14 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index 33d2a17..eb73f96 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -415,6 +415,11 @@ unsafe static public VirtualMachine Load(Stream stream) for (int i = 0; i < anonymousStoreyInfos.Length; i++) { int fieldNum = reader.ReadInt32(); + int[] fieldTypes = new int[fieldNum]; + for (int fieldIdx = 0; fieldIdx < fieldNum; ++fieldIdx) + { + fieldTypes[fieldIdx] = reader.ReadInt32(); + } int ctorId = reader.ReadInt32(); int ctorParamNum = reader.ReadInt32(); var slots = readSlotInfo(reader, itfMethodToId, externTypes, maxId); @@ -423,6 +428,7 @@ unsafe static public VirtualMachine Load(Stream stream) { CtorId = ctorId, FieldNum = fieldNum, + FieldTypes = fieldTypes, CtorParamNum = ctorParamNum, Slots = slots }; @@ -458,12 +464,12 @@ unsafe static public VirtualMachine Load(Stream stream) var assemblyStr = reader.ReadString(); var idMapList = new List(); - for(int i = 0; i < 100; i++) - { - - var idMapType = Type.GetType("IFix.IDMAP" + i + assemblyStr, false); - if (idMapType == null) break; - idMapList.Add(idMapType); + for(int i = 0; i < 100; i++) + { + + var idMapType = Type.GetType("IFix.IDMAP" + i + assemblyStr, false); + if (idMapType == null) break; + idMapList.Add(idMapType); } lock (removers) diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index 58c7e23..0fd3639 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -15,10 +15,23 @@ public class AnonymousStorey { Value[] unmanagedFields; object[] managedFields; - public AnonymousStorey(int fieldNum) + public AnonymousStorey(int fieldNum, int[] fieldTypes) { unmanagedFields = new Value[fieldNum]; managedFields = new object[fieldNum]; + for (int i = 0; i < fieldTypes.Length; ++i) + { + if (fieldTypes[i] == 1) + { + unmanagedFields[i].Type = ValueType.ValueType; + unmanagedFields[i].Value1 = i; + } + else if (fieldTypes[i] == 2) + { + unmanagedFields[i].Type = ValueType.Object; + unmanagedFields[i].Value1 = i; + } + } } unsafe internal void Ldfld(int fieldIndex, Value* evaluationStackBase, Value* evaluationStackPointer, @@ -72,6 +85,7 @@ unsafe internal void Set(int fieldIndex, object obj, Type type, VirtualMachine v public class AnonymousStoreyInfo { public int FieldNum = 0; + public int[] FieldTypes = null; public int CtorId = 0; public int CtorParamNum = 0; public int[] Slots = null; diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 7ca01a3..40221f5 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2292,8 +2292,8 @@ AnonymousStorey anonyObj var pn = anonymousStoreyInfo.CtorParamNum; //_Info("param count:" + pn + ", ctor id:" + anonymousStoreyInfo.CtorId); AnonymousStorey anonymousStorey = (anonymousStoreyInfo.Slots == null) - ? new AnonymousStorey(anonymousStoreyInfo.FieldNum) - : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, + ? new AnonymousStorey(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes) + : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, anonymousStoreyInfo.Slots, this); var pos = evaluationStackPointer; diff --git a/Source/VSProj/Src/Core/WrappersManager.cs b/Source/VSProj/Src/Core/WrappersManager.cs index 7f2e564..270dc1f 100644 --- a/Source/VSProj/Src/Core/WrappersManager.cs +++ b/Source/VSProj/Src/Core/WrappersManager.cs @@ -15,7 +15,7 @@ public interface WrappersManager //创建一个delegate,如果anon非空就是闭包 Delegate CreateDelegate(Type type, int id, object anon); //创建一个interface桥接器 - AnonymousStorey CreateBridge(int fieldNum, int[] slots, VirtualMachine virtualMachine); + AnonymousStorey CreateBridge(int fieldNum, int[] fieldTypes, int[] slots, VirtualMachine virtualMachine); //创建一个wrapper对象(会由补丁加载逻辑调用,创建后放入wrapper数组) object CreateWrapper(int id); //初始化wrapper数组 diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 2eccf76..c0f5e7f 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2533,7 +2533,7 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) var anonymousStoreyType = ilfixAassembly.MainModule.Types.Single(t => t.Name == "AnonymousStorey"); anonymousStoreyTypeRef = assembly.MainModule.ImportReference(anonymousStoreyType); anonymousStoreyCtorRef = assembly.MainModule.ImportReference( - anonymousStoreyType.Methods.Single(m => m.Name == ".ctor" && m.Parameters.Count == 1)); + anonymousStoreyType.Methods.Single(m => m.Name == ".ctor" && m.Parameters.Count == 2)); itfBridgeType = new TypeDefinition("IFix", INTERFACEBRIDGE, TypeAttributes.Class | TypeAttributes.Public, anonymousStoreyTypeRef); @@ -3122,6 +3122,8 @@ void postProcessInterfaceBridge() | MethodAttributes.RTSpecialName, voidType); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("fieldNum", Mono.Cecil.ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32)); + ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("fieldTypes", + Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("methodIdArray", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("virtualMachine", @@ -3129,17 +3131,18 @@ void postProcessInterfaceBridge() var instructions = ctorOfItfBridgeType.Body.Instructions; instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); + instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); var callBaseCtor = Instruction.Create(OpCodes.Call, anonymousStoreyCtorRef); instructions.Add(callBaseCtor); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); + instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); instructions.Add(Instruction.Create(OpCodes.Stfld, virualMachineFieldOfBridge)); for (int i = 0; i < methodIdFields.Count; i++) { instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); + instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); emitLdcI4(instructions, i); instructions.Add(Instruction.Create(OpCodes.Ldelem_I4)); instructions.Add(Instruction.Create(OpCodes.Stfld, methodIdFields[i])); @@ -3149,7 +3152,7 @@ void postProcessInterfaceBridge() var insertPoint = callBaseCtor.Next; var processor = ctorOfItfBridgeType.Body.GetILProcessor(); - processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Ldarg_2)); + processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Ldarg_3)); processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Ldlen)); processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Conv_I4)); processor.InsertBefore(insertPoint, createLdcI4(methodIdFields.Count)); @@ -3170,6 +3173,8 @@ void postProcessInterfaceBridge() | MethodAttributes.Final, anonymousStoreyTypeRef); createBridge.Parameters.Add(new ParameterDefinition("fieldNum", Mono.Cecil.ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32)); + createBridge.Parameters.Add(new ParameterDefinition("fieldTypes", Mono.Cecil.ParameterAttributes.None, + new ArrayType(assembly.MainModule.TypeSystem.Int32))); createBridge.Parameters.Add(new ParameterDefinition("slots", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); createBridge.Parameters.Add(new ParameterDefinition("virtualMachine", Mono.Cecil.ParameterAttributes.None, @@ -3178,6 +3183,7 @@ void postProcessInterfaceBridge() instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); + instructions.Add(createLdarg(createBridge.Body.GetILProcessor(), 4)); instructions.Add(Instruction.Create(OpCodes.Newobj, ctorOfItfBridgeType)); instructions.Add(Instruction.Create(OpCodes.Ret)); @@ -3473,6 +3479,21 @@ public void Serialize(Stream output) //Console.WriteLine("anonymous type: " + anonymousTypeInfos[i]); var anonymousType = anonymousTypeInfos[i].DeclaringType as TypeDefinition; writer.Write(anonymousType.Fields.Count); + for (int fieldIdx = 0; fieldIdx < anonymousType.Fields.Count; ++fieldIdx) + { + if (anonymousType.Fields[fieldIdx].FieldType.IsPrimitive) + { + writer.Write(0); + } + else if (anonymousType.Fields[fieldIdx].FieldType.IsValueType) + { + writer.Write(1); + } + else + { + writer.Write(2); + } + } writer.Write(methodToId[anonymousTypeInfos[i]]); writer.Write(anonymousTypeInfos[i].Parameters.Count); writeSlotInfo(writer, anonymousType); From 35973e76e718a76ae16286185c9f8307821bf143 Mon Sep 17 00:00:00 2001 From: treert <909413016@qq.com> Date: Mon, 27 Apr 2020 16:12:38 +0800 Subject: [PATCH 031/103] =?UTF-8?q?[fixbug]=20CustomBridge=20=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E8=B7=A8dll=E7=9A=84delegate=EF=BC=8CInjectFix=20?= =?UTF-8?q?=E6=97=B6=E6=8A=A5=E9=94=99=E3=80=82=20(#108)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: onemore --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index c0f5e7f..648c498 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3215,7 +3215,7 @@ from instruction in method.Body.Instructions } else { - getWrapperMethod(wrapperType, anonObjOfWrapper, invoke, true, true); + getWrapperMethod(wrapperType, anonObjOfWrapper, invoke.TryImport(t.Module), true, true); } } else if (td.IsInterface) From c9570577e4bf66c77b72ad17e972312d5e4a97cd Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Mon, 27 Apr 2020 16:14:15 +0800 Subject: [PATCH 032/103] =?UTF-8?q?=E4=BD=8E=E7=89=88=E6=9C=ACUnity=20?= =?UTF-8?q?=E6=B2=A1=E6=9C=89ISubsystem=20=E6=B7=BB=E5=8A=A0=EF=BC=8C?= =?UTF-8?q?=E5=B9=B6=E4=B8=94=E6=8A=8ANewClassTest=E6=B7=BB=E5=8A=A0?= =?UTF-8?q?=E5=88=B0=E6=B3=A8=E5=85=A5=E5=88=97=E8=A1=A8=20(#113)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Assets/NewClass/Editor/NewClassTestCfg.cs | 21 +++++++++++++ .../UnityProj/Assets/NewClass/NewClassTest.cs | 30 ++++++++++++++++--- Source/VSProj/Src/Core/AnonymousStorey.cs | 24 +++++++-------- 3 files changed, 59 insertions(+), 16 deletions(-) create mode 100644 Source/UnityProj/Assets/NewClass/Editor/NewClassTestCfg.cs diff --git a/Source/UnityProj/Assets/NewClass/Editor/NewClassTestCfg.cs b/Source/UnityProj/Assets/NewClass/Editor/NewClassTestCfg.cs new file mode 100644 index 0000000..d836926 --- /dev/null +++ b/Source/UnityProj/Assets/NewClass/Editor/NewClassTestCfg.cs @@ -0,0 +1,21 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using IFix; +using System; + +[Configure] +public class NewClassTestCfg { + + [IFix] + static IEnumerable hotfix + { + get + { + return new List() + { + typeof(NewClassTest) + }; + } + } +} diff --git a/Source/UnityProj/Assets/NewClass/NewClassTest.cs b/Source/UnityProj/Assets/NewClass/NewClassTest.cs index 49ab8b4..383e747 100644 --- a/Source/UnityProj/Assets/NewClass/NewClassTest.cs +++ b/Source/UnityProj/Assets/NewClass/NewClassTest.cs @@ -17,7 +17,29 @@ public interface IMonoBehaviour void Update(); } -public class SubSystem1 : ISubsystem + public interface ISubSystem + { + // + // 摘要: + // Will be true if asking the subsytem to start was successful. False in the case + // that the subsystem has stopped, was asked to stop or has not been started yet. + bool running { get; } + + // + // 摘要: + // Destroys this instance of a subsystem. + void Destroy(); + // + // 摘要: + // Starts an instance of a subsystem. + void Start(); + // + // 摘要: + // Stops an instance of a subsystem. + void Stop(); + } + +public class SubSystem1 : ISubSystem { public bool running { get { return true; } } @@ -57,7 +79,7 @@ public void Update() } [IFix.Interpret] -public class SubSystem2 : ISubsystem +public class SubSystem2 : ISubSystem { public bool running { get { return true; } } @@ -83,7 +105,7 @@ public void Destroy() public class NewClassTest : MonoBehaviour { - List subsystems = new List(); + List subsystems = new List(); void Awake() { @@ -130,7 +152,7 @@ public static class AdditionalBridge { static List bridge = new List() { - typeof(ISubsystem), + typeof(ISubSystem), typeof(IMonoBehaviour) }; } \ No newline at end of file diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index 0fd3639..905652e 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -19,18 +19,18 @@ public AnonymousStorey(int fieldNum, int[] fieldTypes) { unmanagedFields = new Value[fieldNum]; managedFields = new object[fieldNum]; - for (int i = 0; i < fieldTypes.Length; ++i) - { - if (fieldTypes[i] == 1) - { - unmanagedFields[i].Type = ValueType.ValueType; - unmanagedFields[i].Value1 = i; - } - else if (fieldTypes[i] == 2) - { - unmanagedFields[i].Type = ValueType.Object; - unmanagedFields[i].Value1 = i; - } + for (int i = 0; i < fieldTypes.Length; ++i) + { + if (fieldTypes[i] == 1) + { + unmanagedFields[i].Type = ValueType.ValueType; + unmanagedFields[i].Value1 = i; + } + else if (fieldTypes[i] == 2) + { + unmanagedFields[i].Type = ValueType.Object; + unmanagedFields[i].Value1 = i; + } } } From a7ca09d3db70105b1d1aec225253b58c4268eac2 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 27 Apr 2020 16:26:53 +0800 Subject: [PATCH 033/103] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E6=95=B4=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../UnityProj/Assets/NewClass/NewClassTest.cs | 34 ++++++------------- Source/VSProj/Src/Tools/CodeTranslator.cs | 28 +++++++-------- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/Source/UnityProj/Assets/NewClass/NewClassTest.cs b/Source/UnityProj/Assets/NewClass/NewClassTest.cs index 383e747..50d5f57 100644 --- a/Source/UnityProj/Assets/NewClass/NewClassTest.cs +++ b/Source/UnityProj/Assets/NewClass/NewClassTest.cs @@ -17,27 +17,16 @@ public interface IMonoBehaviour void Update(); } - public interface ISubSystem - { - // - // 摘要: - // Will be true if asking the subsytem to start was successful. False in the case - // that the subsystem has stopped, was asked to stop or has not been started yet. - bool running { get; } - - // - // 摘要: - // Destroys this instance of a subsystem. - void Destroy(); - // - // 摘要: - // Starts an instance of a subsystem. - void Start(); - // - // 摘要: - // Stops an instance of a subsystem. - void Stop(); - } +public interface ISubSystem +{ + bool running { get; } + + void Destroy(); + + void Start(); + + void Stop(); +} public class SubSystem1 : ISubSystem { @@ -102,7 +91,6 @@ public void Destroy() } } - public class NewClassTest : MonoBehaviour { List subsystems = new List(); @@ -124,7 +112,7 @@ void Awake() private void Init() { subsystems.Add(new SubSystem1()); - //subsystems.Add(new SubSystem2()); + subsystems.Add(new SubSystem2()); } diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 648c498..011b6c3 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3479,20 +3479,20 @@ public void Serialize(Stream output) //Console.WriteLine("anonymous type: " + anonymousTypeInfos[i]); var anonymousType = anonymousTypeInfos[i].DeclaringType as TypeDefinition; writer.Write(anonymousType.Fields.Count); - for (int fieldIdx = 0; fieldIdx < anonymousType.Fields.Count; ++fieldIdx) - { - if (anonymousType.Fields[fieldIdx].FieldType.IsPrimitive) - { - writer.Write(0); - } - else if (anonymousType.Fields[fieldIdx].FieldType.IsValueType) - { - writer.Write(1); - } - else - { - writer.Write(2); - } + for (int fieldIdx = 0; fieldIdx < anonymousType.Fields.Count; ++fieldIdx) + { + if (anonymousType.Fields[fieldIdx].FieldType.IsPrimitive) + { + writer.Write(0); + } + else if (anonymousType.Fields[fieldIdx].FieldType.IsValueType) + { + writer.Write(1); + } + else + { + writer.Write(2); + } } writer.Write(methodToId[anonymousTypeInfos[i]]); writer.Write(anonymousTypeInfos[i].Parameters.Count); From 6085a01c184b3bb8a1a34d6855d0dc6e47c9c7b8 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Wed, 29 Apr 2020 09:45:40 +0800 Subject: [PATCH 034/103] =?UTF-8?q?=E9=AA=8C=E8=AF=81=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E7=B1=BB=E5=90=8D=E6=98=AF=E5=90=A6=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=20(#114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 验证新增类的类名是否存在 * 验证 新增类的类名是否存在 --- .../Src/Builder/FileVirtualMachineBuilder.cs | 17 ++++++++++++++--- Source/VSProj/Src/Tools/CodeTranslator.cs | 13 ++++++++++++- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index eb73f96..be2af1d 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -416,9 +416,9 @@ unsafe static public VirtualMachine Load(Stream stream) { int fieldNum = reader.ReadInt32(); int[] fieldTypes = new int[fieldNum]; - for (int fieldIdx = 0; fieldIdx < fieldNum; ++fieldIdx) - { - fieldTypes[fieldIdx] = reader.ReadInt32(); + for (int fieldIdx = 0; fieldIdx < fieldNum; ++fieldIdx) + { + fieldTypes[fieldIdx] = reader.ReadInt32(); } int ctorId = reader.ReadInt32(); int ctorParamNum = reader.ReadInt32(); @@ -539,6 +539,17 @@ unsafe static public VirtualMachine Load(Stream stream) }; } + int newClassCount = reader.ReadInt32(); + for(int i = 0;i < newClassCount;i++) + { + var newClassFullName = reader.ReadString(); + var newClassName = Type.GetType(newClassFullName); + if (newClassName != null) + { + throw new Exception(newClassName + " class is expected to be a new class , but it already exists "); + } + } + return virtualMachine; } } diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 011b6c3..d1bdb80 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3527,7 +3527,18 @@ public void Serialize(Stream output) writeMethod(writer, kv.Key); writer.Write(kv.Value); } - } + var newClassTypes = (from type in assembly.GetAllType() + where type.Namespace != "IFix" && !type.IsGeneric() && isNewClass(type) + select type); + + var newClassList = newClassTypes.ToList(); + writer.Write(newClassList.Count); + foreach (var n in newClassList) + { + var str = n.GetAssemblyQualifiedName(); + writer.Write(str); + } + } //var allTypes = (from module in assembly.Modules // from type in module.Types From fc06552608ee6e7a9f6b943b35f63759645f7c82 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Thu, 30 Apr 2020 11:06:03 +0800 Subject: [PATCH 035/103] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BB=A3=E7=A0=81?= =?UTF-8?q?=E5=B0=8F=E7=BB=86=E8=8A=82=20(#115)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 验证新增类的类名是否存在 * 验证 新增类的类名是否存在 * 修改代码小细节 --- Source/VSProj/Src/Tools/CecilExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CecilExtensions.cs b/Source/VSProj/Src/Tools/CecilExtensions.cs index f85d23a..1321210 100644 --- a/Source/VSProj/Src/Tools/CecilExtensions.cs +++ b/Source/VSProj/Src/Tools/CecilExtensions.cs @@ -411,7 +411,7 @@ public static bool IsTheSame(this MethodReference left, MethodReference right) || left.Name != right.Name || !left.ReturnType.IsSameName(right.ReturnType) || !left.DeclaringType.IsSameName(right.DeclaringType) - || left.HasThis != left.HasThis + || left.HasThis != right.HasThis || left.GenericParameters.Count != right.GenericParameters.Count) { return false; From 55624c948ed153829235b2cf53116c887c640732 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 8 May 2020 11:40:43 +0800 Subject: [PATCH 036/103] =?UTF-8?q?=E5=8F=8D=E5=B0=84=E8=B0=83=E7=94=A8?= =?UTF-8?q?=E5=8E=9F=E7=94=9F=20=E5=8F=82=E6=95=B0[in][out]=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20fix=20https://github.com/Tencent/InjectFix/issues/1?= =?UTF-8?q?19=20(#122)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/ReflectionMethodInvoker.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index 073da8d..a4c7859 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -46,7 +46,7 @@ public ReflectionMethodInvoker(MethodBase method) for (int i = 0; i < paramerInfos.Length; i++) { - outFlags[i] = paramerInfos[i].IsOut; + outFlags[i] = !paramerInfos[i].IsIn && paramerInfos[i].IsOut; if (paramerInfos[i].ParameterType.IsByRef) { refFlags[i] = true; From 57482b978480d4025a9770b73cd09161b46b8871 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 8 May 2020 16:35:53 +0800 Subject: [PATCH 037/103] =?UTF-8?q?=E5=A6=82=E6=9E=9C=E6=98=AFTargetInvoca?= =?UTF-8?q?tionException=EF=BC=8Cthrow=E5=AE=83=E7=9A=84innerException?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/ReflectionMethodInvoker.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index a4c7859..5c62863 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -183,6 +183,10 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI } } } + catch (TargetInvocationException e) + { + throw e.InnerException; + } //catch (TargetException e) //{ // //VirtualMachine._Info("exception method: " + method + ", in " + method.DeclaringType + ", msg:" From 55f347090d9c365baa60143d9300c53dc02a11d3 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 11 May 2020 16:28:04 +0800 Subject: [PATCH 038/103] =?UTF-8?q?=E5=85=88=E5=8E=BB=E6=8E=89=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=B1=BB=E7=9A=84=E6=A0=87=E7=AD=BE=EF=BC=8C=E5=90=A6?= =?UTF-8?q?=E5=88=99Helloworld=E4=BE=8B=E5=AD=90=E5=8A=A0=E8=BD=BD?= =?UTF-8?q?=E8=A1=A5=E4=B8=81=E5=A4=B1=E8=B4=A5=20fix=20https://github.com?= =?UTF-8?q?/Tencent/InjectFix/issues/123?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/UnityProj/Assets/NewClass/NewClassTest.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UnityProj/Assets/NewClass/NewClassTest.cs b/Source/UnityProj/Assets/NewClass/NewClassTest.cs index 50d5f57..cdc97c4 100644 --- a/Source/UnityProj/Assets/NewClass/NewClassTest.cs +++ b/Source/UnityProj/Assets/NewClass/NewClassTest.cs @@ -48,7 +48,7 @@ public void Destroy() } } -[IFix.Interpret] +//[IFix.Interpret] public class NewBehaviourScript : IMonoBehaviour { private int tick = 0; @@ -67,7 +67,7 @@ public void Update() } } -[IFix.Interpret] +//[IFix.Interpret] public class SubSystem2 : ISubSystem { public bool running { get { return true; } } From 3fab5d0ed001fe14e11e0be3b2c36cb00d3dfaed Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Thu, 28 May 2020 14:48:18 +0800 Subject: [PATCH 039/103] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=B1=BB=E5=8F=AF=E4=BB=A5=E7=BB=A7=E6=89=BF=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E5=8A=9F=E8=83=BD=20(#130)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 反射调用原生 参数[in][out]问题 fix https://github.com/Tencent/InjectFix/issues/119 * 实现新增类继承新增类的功能 --- .../Src/Builder/FileVirtualMachineBuilder.cs | 9 +- Source/VSProj/Src/Core/AnonymousStorey.cs | 5 +- Source/VSProj/Src/Core/Instruction.cs | 1 + Source/VSProj/Src/Core/VirtualMachine.cs | 26 +- Source/VSProj/Src/Core/WrappersManager.cs | 2 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 294 ++++++++++++++++-- 6 files changed, 305 insertions(+), 32 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index be2af1d..ad44d0f 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -424,13 +424,20 @@ unsafe static public VirtualMachine Load(Stream stream) int ctorParamNum = reader.ReadInt32(); var slots = readSlotInfo(reader, itfMethodToId, externTypes, maxId); + int virtualMethodNum = reader.ReadInt32(); + int[] vTable = new int[virtualMethodNum]; + for (int vm = 0 ;vm < virtualMethodNum; vm++) + { + vTable[vm] = reader.ReadInt32(); + } anonymousStoreyInfos[i] = new AnonymousStoreyInfo() { CtorId = ctorId, FieldNum = fieldNum, FieldTypes = fieldTypes, CtorParamNum = ctorParamNum, - Slots = slots + Slots = slots, + VTable = vTable }; } diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index 905652e..5928a09 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -15,7 +15,8 @@ public class AnonymousStorey { Value[] unmanagedFields; object[] managedFields; - public AnonymousStorey(int fieldNum, int[] fieldTypes) + internal int typeId; + public AnonymousStorey(int fieldNum, int[] fieldTypes,int typeID) { unmanagedFields = new Value[fieldNum]; managedFields = new object[fieldNum]; @@ -32,6 +33,7 @@ public AnonymousStorey(int fieldNum, int[] fieldTypes) unmanagedFields[i].Value1 = i; } } + typeId = typeID; } unsafe internal void Ldfld(int fieldIndex, Value* evaluationStackBase, Value* evaluationStackPointer, @@ -89,5 +91,6 @@ public class AnonymousStoreyInfo public int CtorId = 0; public int CtorParamNum = 0; public int[] Slots = null; + public int[] VTable = null; } } \ No newline at end of file diff --git a/Source/VSProj/Src/Core/Instruction.cs b/Source/VSProj/Src/Core/Instruction.cs index 55fd103..39fb33d 100644 --- a/Source/VSProj/Src/Core/Instruction.cs +++ b/Source/VSProj/Src/Core/Instruction.cs @@ -85,6 +85,7 @@ public enum Code Conv_U4, Conv_U8, Callvirt, + Callvirtvirt, Cpobj, Ldobj, Ldstr, diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 40221f5..da3f748 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -633,6 +633,28 @@ public static void _Info(string a) //printStack("ret", evaluationStackPointer - 1); } break; + + case Code.Callvirtvirt: + { + 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); + } + break; case Code.CallExtern://部分来自Call部分来自Callvirt case Code.Newobj: // 2.334642% int methodId = pc->Operand & 0xFFFF; @@ -2292,8 +2314,8 @@ AnonymousStorey anonyObj var pn = anonymousStoreyInfo.CtorParamNum; //_Info("param count:" + pn + ", ctor id:" + anonymousStoreyInfo.CtorId); AnonymousStorey anonymousStorey = (anonymousStoreyInfo.Slots == null) - ? new AnonymousStorey(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes) - : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, + ? new AnonymousStorey(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, pc->Operand) + : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, pc->Operand, anonymousStoreyInfo.Slots, this); var pos = evaluationStackPointer; diff --git a/Source/VSProj/Src/Core/WrappersManager.cs b/Source/VSProj/Src/Core/WrappersManager.cs index 270dc1f..d351e37 100644 --- a/Source/VSProj/Src/Core/WrappersManager.cs +++ b/Source/VSProj/Src/Core/WrappersManager.cs @@ -15,7 +15,7 @@ public interface WrappersManager //创建一个delegate,如果anon非空就是闭包 Delegate CreateDelegate(Type type, int id, object anon); //创建一个interface桥接器 - AnonymousStorey CreateBridge(int fieldNum, int[] fieldTypes, int[] slots, VirtualMachine virtualMachine); + AnonymousStorey CreateBridge(int fieldNum, int[] fieldTypes, int typeIndex, int[] slots, VirtualMachine virtualMachine); //创建一个wrapper对象(会由补丁加载逻辑调用,创建后放入wrapper数组) object CreateWrapper(int id); //初始化wrapper数组 diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index d1bdb80..5756af4 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -42,6 +42,7 @@ class CodeTranslator private List fieldsStoreInVirtualMachine = new List(); private Dictionary fieldToId = new Dictionary(); + private Dictionary virtualMethodToIndex = new Dictionary(); const string Wrap_Perfix = "__Gen_Wrap_"; int nextAllocId = 0; @@ -100,7 +101,7 @@ bool isCustomClassPlainObject(TypeReference type) return td != null && !td.IsInterface && isNewClass(td) - && td.BaseType.IsSameType(objType); + && (td.BaseType.IsSameType(objType) || isCustomClassPlainObject(td.BaseType as TypeReference)); } bool isCompilerGeneratedByNotPlainObject(TypeReference type) @@ -618,11 +619,11 @@ Core.ExceptionHandler findExceptionHandler(Core.ExceptionHandler[] ehs, Core.Exc return ret; } - MethodDefinition findOverride(TypeDefinition type, MethodReference vmethod) + MethodDefinition findOverride(TypeDefinition type, MethodReference vmethod, bool allowAbstractMethod = false) { foreach (var method in type.Methods) { - if (method.IsVirtual && !method.IsAbstract && isTheSameDeclare(method, vmethod)) + if (method.IsVirtual && (allowAbstractMethod || !method.IsAbstract) && isTheSameDeclare(method, vmethod)) { return method; } @@ -673,6 +674,58 @@ MethodReference _findBase(TypeReference type, MethodDefinition method) return _findBase(td.BaseType, method); } + MethodReference _findInitDefineVirtualMethod(TypeReference type, MethodDefinition method) + { + TypeDefinition td = type.Resolve(); + if (td == null) + { + return null; + } + MethodReference baseM = null; + if (td.BaseType != null && isNewClass(td.BaseType as TypeDefinition)) + { + baseM = _findInitDefineVirtualMethod(td.BaseType, method); + } + if (baseM != null) + { + return baseM; + } + + var m = findOverride(td, method, true); + if (m != null) + { + if (type.IsGenericInstance) + { + return m.MakeGeneric(method.DeclaringType); + } + else + { + return m.TryImport(method.DeclaringType.Module); + } + } + return null; + } + + MethodReference findInitDefineVirtualMethod(TypeDefinition type, MethodDefinition method) + { + if (method.IsVirtual) + { + foreach (var objVirtualMethod in ObjectVirtualMethods) + { + if (isTheSameDeclare(objVirtualMethod,method)) + { + throw new NotImplementedException("Overriding the virtual methods of object is not supported yet"); + } + } + if (method.IsNewSlot) + { + return method; + } + return _findInitDefineVirtualMethod(type.BaseType, method); + } + return null; + } + MethodReference findBase(TypeDefinition type, MethodDefinition method) { if (method.IsVirtual && !method.IsNewSlot) //表明override @@ -729,6 +782,7 @@ enum CallType { Extern, Internal, + InteralVirtual, Invalid } @@ -965,9 +1019,31 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, Type = CallType.Extern }; } + if (method != null) + { + if (method.IsAbstract) + { + if (isCompilerGeneratedPlainObject(method.DeclaringType) || isCustomClassPlainObject(method.DeclaringType)) + { + return new MethodIdInfo() + { + Id = virtualMethodInVTableIndex(method), + Type = CallType.InteralVirtual + }; + } + } + } if (methodToId.ContainsKey(callee)) { + if (virtualMethodToIndex.ContainsKey(callee)) + { + return new MethodIdInfo() + { + Id = virtualMethodToIndex[callee], + Type = CallType.InteralVirtual + }; + } return new MethodIdInfo() { Id = methodToId[callee], @@ -1007,9 +1083,12 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { return new MethodIdInfo() { Id = 0, Type = CallType.Invalid }; } + MethodDefinition baseProxy = null; - var baseProxy = tryAddBaseProxy(method.DeclaringType, method); - + if (!isNewClass(method.DeclaringType as TypeDefinition)) + { + baseProxy = tryAddBaseProxy(method.DeclaringType, method); + } var body = method.Body; var msIls = body.Instructions; var ilOffset = new Dictionary(); @@ -1513,6 +1592,35 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, Operand = (paramCount << 16) | methodIdInfo.Id }); } + else if (methodIdInfo.Type == CallType.InteralVirtual) + { + if ((methodToCall as MethodDefinition).IsVirtual) + { + int idx = -1; + if(!virtualMethodToIndex.TryGetValue(methodToCall,out idx)) + { + idx = virtualMethodInVTableIndex(methodToCall as MethodDefinition); + } + code.Add(new Core.Instruction + { + Code = Core.Code.Callvirtvirt, + Operand = (paramCount << 16) | idx + }); + } + else + { + code.Add(new Core.Instruction + { + Code = (or != null) ? Core.Code.Call : + (Core.Code)Enum.Parse(typeof(Core.Code), strCode), + Operand = (paramCount << 16) | methodToId[method] + }); + if (msIl.OpCode.Code == Code.Newobj) + { + throw new InvalidProgramException("Newobj's Operand is not a constructor?"); + } + } + } else { throw new InvalidProgramException("call a generic method definition"); @@ -1611,10 +1719,17 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, if (isCompilerGeneratedPlainObject(field.DeclaringType) || isCustomClassPlainObject(field.DeclaringType)) { var declaringType = field.DeclaringType as TypeDefinition; + int baseFieldCount = 0; + var temp = declaringType; + while (temp.BaseType != null && isNewClass(temp.BaseType as TypeDefinition)) + { + baseFieldCount += (temp.BaseType as TypeDefinition).Fields.Count; + temp = temp.BaseType as TypeDefinition; + } code.Add(new Core.Instruction { Code = (Core.Code)Enum.Parse(typeof(Core.Code), strCode), - Operand = -(declaringType.Fields.IndexOf(field as FieldDefinition) + 1) + Operand = -(declaringType.Fields.IndexOf(field as FieldDefinition) + baseFieldCount + 1) }); //Console.WriteLine("anon obj field:" + field + ",idx:" + // declaringType.Fields.IndexOf(field as FieldDefinition)); @@ -1747,11 +1862,22 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, if (!directCallVirtual && method.IsVirtual) { - return new MethodIdInfo() + if (isNewClass(method.DeclaringType)) { - Id = addExternMethod(callee, caller), - Type = CallType.Extern - }; + return new MethodIdInfo() + { + Id = virtualMethodInVTableIndex(method), + Type = CallType.InteralVirtual + }; + } + else + { + return new MethodIdInfo() + { + Id = addExternMethod(callee, caller), + Type = CallType.Extern + }; + } } else { @@ -1859,7 +1985,8 @@ int addAnonymousCtor(MethodDefinition ctor) return id; } addInterfacesOfTypeToBridge(ctor.DeclaringType as TypeDefinition); - foreach(var method in ctor.DeclaringType.Methods.Where(m => !m.IsConstructor)) + var methods = ctor.DeclaringType.Methods.Where(m => !m.IsConstructor).ToList(); + foreach (var method in methods) { getMethodId(method, null, true, InjectType.Redirect); } @@ -1927,17 +2054,16 @@ void addInterfacesOfTypeToBridge(TypeDefinition anonType) continue; } - if (matchItfMethod == null) + if (matchItfMethod != null) { - throw new Exception("can not find base method for " + method); + toImplement.Add(matchItfMethod.DeclaringType); + //Console.WriteLine("add slot " + matchItfMethod + ",m=" + method); + interfaceSlot.Add(matchItfMethod, bridgeMethodId); + var impl = getWrapperMethod(itfBridgeType, null, method, false, true, true, bridgeMethodId); + addIDTag(impl, bridgeMethodId++); + impl.Overrides.Add(matchItfMethod); } - toImplement.Add(matchItfMethod.DeclaringType); - //Console.WriteLine("add slot " + matchItfMethod + ",m=" + method); - interfaceSlot.Add(matchItfMethod, bridgeMethodId); - var impl = getWrapperMethod(itfBridgeType, null, method, false, true, true, bridgeMethodId); - addIDTag(impl, bridgeMethodId++); - impl.Overrides.Add(matchItfMethod); } //Console.WriteLine("end type:" + anonType); @@ -2465,11 +2591,13 @@ void emitStoreRef(Mono.Collections.Generic.Collection instructions, OpCodes.Ldc_I4_3,OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7 }; private Dictionary ldinds = null; private Dictionary stinds = null; + private List ObjectVirtualMethods = null; void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) { this.assembly = assembly; objType = assembly.MainModule.TypeSystem.Object; + ObjectVirtualMethods = (from method in objType.Resolve().Methods where method.IsVirtual select method).ToList(); voidType = assembly.MainModule.TypeSystem.Void; wrapperType = new TypeDefinition("IFix", DYNAMICWRAPPER, Mono.Cecil.TypeAttributes.Class @@ -2533,7 +2661,7 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) var anonymousStoreyType = ilfixAassembly.MainModule.Types.Single(t => t.Name == "AnonymousStorey"); anonymousStoreyTypeRef = assembly.MainModule.ImportReference(anonymousStoreyType); anonymousStoreyCtorRef = assembly.MainModule.ImportReference( - anonymousStoreyType.Methods.Single(m => m.Name == ".ctor" && m.Parameters.Count == 2)); + anonymousStoreyType.Methods.Single(m => m.Name == ".ctor" && m.Parameters.Count == 3)); itfBridgeType = new TypeDefinition("IFix", INTERFACEBRIDGE, TypeAttributes.Class | TypeAttributes.Public, anonymousStoreyTypeRef); @@ -3124,6 +3252,8 @@ void postProcessInterfaceBridge() Mono.Cecil.ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32)); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("fieldTypes", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); + ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("typeIndex", + Mono.Cecil.ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32)); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("methodIdArray", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("virtualMachine", @@ -3132,17 +3262,18 @@ void postProcessInterfaceBridge() instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); + instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); var callBaseCtor = Instruction.Create(OpCodes.Call, anonymousStoreyCtorRef); instructions.Add(callBaseCtor); instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); + instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 5)); instructions.Add(Instruction.Create(OpCodes.Stfld, virualMachineFieldOfBridge)); for (int i = 0; i < methodIdFields.Count; i++) { instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); + instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); emitLdcI4(instructions, i); instructions.Add(Instruction.Create(OpCodes.Ldelem_I4)); instructions.Add(Instruction.Create(OpCodes.Stfld, methodIdFields[i])); @@ -3152,7 +3283,7 @@ void postProcessInterfaceBridge() var insertPoint = callBaseCtor.Next; var processor = ctorOfItfBridgeType.Body.GetILProcessor(); - processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Ldarg_3)); + processor.InsertBefore(insertPoint, createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Ldlen)); processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Conv_I4)); processor.InsertBefore(insertPoint, createLdcI4(methodIdFields.Count)); @@ -3175,6 +3306,8 @@ void postProcessInterfaceBridge() assembly.MainModule.TypeSystem.Int32)); createBridge.Parameters.Add(new ParameterDefinition("fieldTypes", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); + createBridge.Parameters.Add(new ParameterDefinition("typeIndex", Mono.Cecil.ParameterAttributes.None, + assembly.MainModule.TypeSystem.Int32)); createBridge.Parameters.Add(new ParameterDefinition("slots", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); createBridge.Parameters.Add(new ParameterDefinition("virtualMachine", Mono.Cecil.ParameterAttributes.None, @@ -3184,6 +3317,7 @@ void postProcessInterfaceBridge() instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); instructions.Add(createLdarg(createBridge.Body.GetILProcessor(), 4)); + instructions.Add(createLdarg(createBridge.Body.GetILProcessor(), 5)); instructions.Add(Instruction.Create(OpCodes.Newobj, ctorOfItfBridgeType)); instructions.Add(Instruction.Create(OpCodes.Ret)); @@ -3478,14 +3612,35 @@ public void Serialize(Stream output) { //Console.WriteLine("anonymous type: " + anonymousTypeInfos[i]); var anonymousType = anonymousTypeInfos[i].DeclaringType as TypeDefinition; - writer.Write(anonymousType.Fields.Count); - for (int fieldIdx = 0; fieldIdx < anonymousType.Fields.Count; ++fieldIdx) + List anonymousTypeFields = new List(); + if (isNewClass(anonymousTypeInfos[i].DeclaringType as TypeDefinition)) + { + var temp = anonymousType; + while (temp != null && isNewClass(temp as TypeDefinition)) + { + if (temp.Fields != null) + { + foreach (var fi in temp.Fields) + { + anonymousTypeFields.Add(fi); + } + } + temp = temp.BaseType as TypeDefinition; + } + } + else + { + anonymousTypeFields.AddRange(anonymousTypeInfos[i].DeclaringType.Fields); + } + writer.Write(anonymousTypeFields.Count); + + for (int field = 0; field < anonymousTypeFields.Count; field++) { - if (anonymousType.Fields[fieldIdx].FieldType.IsPrimitive) + if (anonymousTypeFields[field].FieldType.IsPrimitive) { writer.Write(0); } - else if (anonymousType.Fields[fieldIdx].FieldType.IsValueType) + else if (anonymousTypeFields[field].FieldType.IsValueType) { writer.Write(1); } @@ -3497,6 +3652,22 @@ public void Serialize(Stream output) writer.Write(methodToId[anonymousTypeInfos[i]]); writer.Write(anonymousTypeInfos[i].Parameters.Count); writeSlotInfo(writer, anonymousType); + List vT = getVirtualMethodForType(anonymousType); + writer.Write(vT == null ? 0:vT.Count); + if (vT != null) + { + int[] vTables = new int[vT.Count]; + for (int s = 0; s < vTables.Length; s++) + { + vTables[s] = -1; + } + writeVTable(anonymousType,vTables,vT); + + for (int k = 0; k < vTables.Length; k++) + { + writer.Write(vTables[k]); + } + } } writer.Write(wrapperMgrImpl.GetAssemblyQualifiedName()); @@ -3554,6 +3725,75 @@ public void Serialize(Stream output) // Console.WriteLine("hgp:" + method + ",type:" + method.GetType()); //} } + Dictionary> InternalTypeToVirtualMethods = new Dictionary>(); + public List getVirtualMethodForType(TypeDefinition type) + { + List virtualMethods; + if (InternalTypeToVirtualMethods.TryGetValue(type, out virtualMethods)) + { + return virtualMethods; + } + int index = 0; + if (type.BaseType != null && isNewClass(type.BaseType as TypeDefinition)) + { + virtualMethods = new List(getVirtualMethodForType(type.BaseType as TypeDefinition)); + } + else + { + virtualMethods = new List(); + } + index = virtualMethods.Count; + foreach (var method in type.Methods) + { + if (method.IsVirtual && method.IsNewSlot) + { + virtualMethods.Add(method); + } + } + + InternalTypeToVirtualMethods.Add(type, virtualMethods); + foreach (var vmethod in virtualMethods) + { + if (!virtualMethodToIndex.ContainsKey(vmethod)) + { + virtualMethodToIndex.Add(vmethod, index++); + } + } + return virtualMethods; + } + + public int virtualMethodInVTableIndex(MethodDefinition method) + { + var list = getVirtualMethodForType(method.DeclaringType); + var baseMethod = findInitDefineVirtualMethod(method.DeclaringType as TypeDefinition, method); + return list.FindIndex(li => li == baseMethod || li == method); + } + + public void writeVTable(TypeDefinition type,int[] vTables,List vT) + { + if (type.BaseType != null && isNewClass(type.BaseType as TypeDefinition)) + { + writeVTable(type.BaseType as TypeDefinition, vTables,vT); + } + foreach (var an in (from method in type.Methods + where method.IsVirtual + where !method.IsAbstract + select method)) + { + int index = 0; + if (!virtualMethodToIndex.TryGetValue(an,out index)) + { + index = virtualMethodInVTableIndex(an); + } + if (!methodToId.ContainsKey(an)) + { + vTables[index] = getMethodId(an, null, false).Id; + } + else + vTables[index] = methodToId[an]; + } + + } } } \ No newline at end of file From c6f23a5f1be8a1541e26ed2d83ae09c0629903f8 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Thu, 4 Jun 2020 16:08:58 +0800 Subject: [PATCH 040/103] =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=BB=A7=E6=89=BF?= =?UTF-8?q?=E6=97=B6=E9=87=8D=E5=86=99object=E7=9A=84=E8=99=9A=E5=87=BD?= =?UTF-8?q?=E6=95=B0=20(#136)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 反射调用原生 参数[in][out]问题 fix https://github.com/Tencent/InjectFix/issues/119 * 实现新增类继承新增类的功能 * 解决 新类重写object的虚方法 --- Source/VSProj/Src/Core/AnonymousStorey.cs | 69 +++++++- Source/VSProj/Src/Core/VirtualMachine.cs | 4 +- Source/VSProj/Src/Core/WrappersManager.cs | 2 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 183 ++++++++++++---------- 4 files changed, 170 insertions(+), 88 deletions(-) diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index 5928a09..856a63f 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -16,7 +16,13 @@ public class AnonymousStorey Value[] unmanagedFields; object[] managedFields; internal int typeId; - public AnonymousStorey(int fieldNum, int[] fieldTypes,int typeID) + protected VirtualMachine virtualMachine; + int equalMethodId; + int finalizeMethodId; + int getHashCodeMethodId; + int toStringMethodId; + + public AnonymousStorey(int fieldNum, int[] fieldTypes,int typeID, int[] vTable, VirtualMachine virtualMachine) { unmanagedFields = new Value[fieldNum]; managedFields = new object[fieldNum]; @@ -34,6 +40,11 @@ public AnonymousStorey(int fieldNum, int[] fieldTypes,int typeID) } } typeId = typeID; + this.virtualMachine = virtualMachine; + equalMethodId = vTable[0]; + finalizeMethodId = vTable[1]; + getHashCodeMethodId = vTable[2]; + toStringMethodId = vTable[3]; } unsafe internal void Ldfld(int fieldIndex, Value* evaluationStackBase, Value* evaluationStackPointer, @@ -82,6 +93,62 @@ unsafe internal void Set(int fieldIndex, object obj, Type type, VirtualMachine v EvaluationStackOperation.PushObject(b, b + fieldIndex, managedFields, obj, type); } } + + public bool ObjectEquals(object obj) + { + return base.Equals(obj); + } + + public override bool Equals(object obj) + { + if(equalMethodId == -1) + return ObjectEquals(obj); + Call call = Call.Begin(); + call.PushObject(this); + call.PushObject(obj); + virtualMachine.Execute(equalMethodId, ref call, 2, 0); + return call.GetBoolean(0); + } + + public int ObjectGetHashCode() + { + return base.GetHashCode(); + } + + public override int GetHashCode() + { + if(getHashCodeMethodId == -1) + return ObjectGetHashCode(); + Call call = Call.Begin(); + call.PushObject(this); + virtualMachine.Execute(getHashCodeMethodId, ref call, 1, 0); + return call.GetInt32(0); + } + + public string ObjectToString() + { + return base.ToString(); + } + + public override string ToString() + { + if (toStringMethodId == -1) + return ObjectToString(); + Call call = Call.Begin(); + call.PushObject(this); + virtualMachine.Execute(toStringMethodId, ref call, 1, 0); + return call.GetAsType(0); + } + + ~AnonymousStorey() + { + if (finalizeMethodId != -1) + { + Call call = Call.Begin(); + call.PushObject(this); + virtualMachine.Execute(finalizeMethodId, ref call, 1, 0); + } + } } public class AnonymousStoreyInfo diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index da3f748..d61c190 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2314,8 +2314,8 @@ AnonymousStorey anonyObj 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) - : wrappersManager.CreateBridge(anonymousStoreyInfo.FieldNum, anonymousStoreyInfo.FieldTypes, pc->Operand, + ? 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; diff --git a/Source/VSProj/Src/Core/WrappersManager.cs b/Source/VSProj/Src/Core/WrappersManager.cs index d351e37..f087ec0 100644 --- a/Source/VSProj/Src/Core/WrappersManager.cs +++ b/Source/VSProj/Src/Core/WrappersManager.cs @@ -15,7 +15,7 @@ public interface WrappersManager //创建一个delegate,如果anon非空就是闭包 Delegate CreateDelegate(Type type, int id, object anon); //创建一个interface桥接器 - AnonymousStorey CreateBridge(int fieldNum, int[] fieldTypes, int typeIndex, int[] slots, VirtualMachine virtualMachine); + AnonymousStorey CreateBridge(int fieldNum, int[] fieldTypes, int typeIndex, int[] vTable, int[] slots, VirtualMachine virtualMachine); //创建一个wrapper对象(会由补丁加载逻辑调用,创建后放入wrapper数组) object CreateWrapper(int id); //初始化wrapper数组 diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 5756af4..58e2441 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -138,7 +138,7 @@ HashSet getSpecialGeneratedFields(TypeDefinition type) var cctor = type.Methods.FirstOrDefault(m => m.Name == ".cctor"); if (cctor != null) { - var cctorInfo = getMethodId(cctor, null, false, InjectType.Redirect); + var cctorInfo = getMethodId(cctor, null,false, false, InjectType.Redirect); typeToCctor[type] = cctorInfo.Type == CallType.Internal ? cctorInfo.Id : -2; } } @@ -581,7 +581,7 @@ bool checkILAndGetOffset(MethodDefinition method, void processMethod(MethodDefinition method) { - getMethodId(method, null); + getMethodId(method, null,true); } Core.ExceptionHandler findExceptionHandler(Core.ExceptionHandler[] ehs, Core.ExceptionHandlerType type, @@ -710,11 +710,11 @@ MethodReference findInitDefineVirtualMethod(TypeDefinition type, MethodDefinitio { if (method.IsVirtual) { - foreach (var objVirtualMethod in ObjectVirtualMethods) + foreach (var objVirtualMethod in ObjectVirtualMethodDefinitionList) { if (isTheSameDeclare(objVirtualMethod,method)) { - throw new NotImplementedException("Overriding the virtual methods of object is not supported yet"); + return objVirtualMethod; } } if (method.IsNewSlot) @@ -746,34 +746,41 @@ MethodReference findBase(TypeDefinition type, MethodDefinition method) //var method = typeof(object).GetMethod("ToString"); //var ftn = method.MethodHandle.GetFunctionPointer(); //var func = (Func)Activator.CreateInstance(typeof(Func), obj, ftn); - MethodDefinition tryAddBaseProxy(TypeDefinition type, MethodDefinition method) + MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) { var mbase = findBase(type, method); if (mbase != null) { - var proxyMethod = new MethodDefinition(BASE_RPOXY_PERFIX + method.Name, MethodAttributes.Private, - method.ReturnType); - for(int i = 0; i < method.Parameters.Count; i++) + if (!isNewClass(type)) { - proxyMethod.Parameters.Add(new ParameterDefinition("P" + i, method.Parameters[i].IsOut - ? ParameterAttributes.Out : ParameterAttributes.None, method.Parameters[i].ParameterType)); - } - var instructions = proxyMethod.Body.Instructions; - var ilProcessor = proxyMethod.Body.GetILProcessor(); - int paramCount = method.Parameters.Count + 1; - for(int i = 0; i < paramCount; i++) - { - emitLdarg(instructions, ilProcessor, i); - if (i == 0 && type.IsValueType) + var proxyMethod = new MethodDefinition(BASE_RPOXY_PERFIX + method.Name, MethodAttributes.Private, + method.ReturnType); + for (int i = 0; i < method.Parameters.Count; i++) { - instructions.Add(Instruction.Create(OpCodes.Ldobj, type)); - instructions.Add(Instruction.Create(OpCodes.Box, type)); + proxyMethod.Parameters.Add(new ParameterDefinition("P" + i, method.Parameters[i].IsOut + ? ParameterAttributes.Out : ParameterAttributes.None, method.Parameters[i].ParameterType)); + } + var instructions = proxyMethod.Body.Instructions; + var ilProcessor = proxyMethod.Body.GetILProcessor(); + int paramCount = method.Parameters.Count + 1; + for (int i = 0; i < paramCount; i++) + { + emitLdarg(instructions, ilProcessor, i); + if (i == 0 && type.IsValueType) + { + instructions.Add(Instruction.Create(OpCodes.Ldobj, type)); + instructions.Add(Instruction.Create(OpCodes.Box, type)); + } } + instructions.Add(Instruction.Create(OpCodes.Call, mbase)); + instructions.Add(Instruction.Create(OpCodes.Ret)); + type.Methods.Add(proxyMethod); + return proxyMethod; + } + else if(isNewClass(type) && !isNewClass(type.BaseType as TypeDefinition)) + { + return objectVirtualMethodReferenceList.FirstOrDefault( m => m.Name == ("Object" + method.Name)); } - instructions.Add(Instruction.Create(OpCodes.Call, mbase)); - instructions.Add(Instruction.Create(OpCodes.Ret)); - type.Methods.Add(proxyMethod); - return proxyMethod; } return null; } @@ -1005,7 +1012,7 @@ int allocMethodId(MethodDefinition method) /// 调用者的注入类型 /// 负数表示需要反射访问原生,0或正数是指令数组下标 // #lizard forgives - unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, + unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, bool isCallvirt, bool directCallVirtual = false, InjectType callerInjectType = InjectType.Switch) { //Console.WriteLine("callee:" + callee + ", caller:" + caller); @@ -1021,7 +1028,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (method != null) { - if (method.IsAbstract) + if (method.IsAbstract && isCallvirt) { if (isCompilerGeneratedPlainObject(method.DeclaringType) || isCustomClassPlainObject(method.DeclaringType)) { @@ -1036,7 +1043,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (methodToId.ContainsKey(callee)) { - if (virtualMethodToIndex.ContainsKey(callee)) + if (isCallvirt && virtualMethodToIndex.ContainsKey(callee)) { return new MethodIdInfo() { @@ -1083,12 +1090,8 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { return new MethodIdInfo() { Id = 0, Type = CallType.Invalid }; } - MethodDefinition baseProxy = null; - - if (!isNewClass(method.DeclaringType as TypeDefinition)) - { - baseProxy = tryAddBaseProxy(method.DeclaringType, method); - } + + var baseProxy = tryAddBaseProxy(method.DeclaringType, method); var body = method.Body; var msIls = body.Instructions; var ilOffset = new Dictionary(); @@ -1493,7 +1496,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) { TypeDefinition td = methodToCall.DeclaringType as TypeDefinition; - var anonymousCtorInfo = getMethodId(methodToCall, method, false, + var anonymousCtorInfo = getMethodId(methodToCall, method, false, false, injectTypePassToNext); if (anonymousCtorInfo.Type != CallType.Internal) { @@ -1540,7 +1543,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } int paramCount = (methodToCall.Parameters.Count + (msIl.OpCode.Code != Code.Newobj && methodToCall.HasThis ? 1 : 0)); - var methodIdInfo = getMethodId(methodToCall, method, or != null || directCallVirtual, + var methodIdInfo = getMethodId(methodToCall, method, msIl.OpCode.Code == Code.Callvirt, or != null || directCallVirtual, injectTypePassToNext); bool callingBaseMethod = false; @@ -1628,10 +1631,10 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } break; case Code.Ldftn: - case Code.Ldvirtftn: + case Code.Ldvirtftn://TODO: 要不要处理下虚表? { var methodToCall = msIl.Operand as MethodReference; - var methodIdInfo = getMethodId(methodToCall, method, false, injectTypePassToNext); + var methodIdInfo = getMethodId(methodToCall, method, msIl.OpCode.Code == Code.Ldvirtftn, false, injectTypePassToNext); if (methodIdInfo.Type == CallType.Internal && (isCompilerGeneratedPlainObject(methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) // closure { @@ -1860,7 +1863,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, injectMethod(method, methodId); } - if (!directCallVirtual && method.IsVirtual) + if (!directCallVirtual && method.IsVirtual && isCallvirt) { if (isNewClass(method.DeclaringType)) { @@ -1909,7 +1912,7 @@ public enum ProcessResult private MethodReference anonymousStoreyCtorRef; private FieldDefinition virualMachineFieldOfWrapper; - private FieldDefinition virualMachineFieldOfBridge; + private FieldReference virualMachineFieldOfBridge; private FieldDefinition methodIdFieldOfWrapper; private FieldDefinition anonObjOfWrapper; private FieldDefinition wrapperArray; @@ -1988,7 +1991,7 @@ int addAnonymousCtor(MethodDefinition ctor) var methods = ctor.DeclaringType.Methods.Where(m => !m.IsConstructor).ToList(); foreach (var method in methods) { - getMethodId(method, null, true, InjectType.Redirect); + getMethodId(method, null,true, true, InjectType.Redirect); } id = anonymousTypeInfos.Count; anonymousTypeInfos.Add(ctor); @@ -2591,13 +2594,24 @@ void emitStoreRef(Mono.Collections.Generic.Collection instructions, OpCodes.Ldc_I4_3,OpCodes.Ldc_I4_4, OpCodes.Ldc_I4_5, OpCodes.Ldc_I4_6, OpCodes.Ldc_I4_7 }; private Dictionary ldinds = null; private Dictionary stinds = null; - private List ObjectVirtualMethods = null; + private List ObjectVirtualMethodDefinitionList = null; + private List objectVirtualMethodReferenceList = null; void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) { this.assembly = assembly; objType = assembly.MainModule.TypeSystem.Object; - ObjectVirtualMethods = (from method in objType.Resolve().Methods where method.IsVirtual select method).ToList(); + List supportedMethods = new List() { "Equals", "Finalize","GetHashCode", "ToString"}; + ObjectVirtualMethodDefinitionList = (from method in objType.Resolve().Methods where method.IsVirtual && supportedMethods.Contains(method.Name) select method).ToList(); + if (ObjectVirtualMethodDefinitionList.Count != 4) + { + throw new InvalidProgramException(); + } + ObjectVirtualMethodDefinitionList.OrderBy(t => t.FullName); + for (int methodIdx = 0; methodIdx < ObjectVirtualMethodDefinitionList.Count; methodIdx++) + { + virtualMethodToIndex.Add(ObjectVirtualMethodDefinitionList[methodIdx], methodIdx); + } voidType = assembly.MainModule.TypeSystem.Void; wrapperType = new TypeDefinition("IFix", DYNAMICWRAPPER, Mono.Cecil.TypeAttributes.Class @@ -2661,13 +2675,14 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) var anonymousStoreyType = ilfixAassembly.MainModule.Types.Single(t => t.Name == "AnonymousStorey"); anonymousStoreyTypeRef = assembly.MainModule.ImportReference(anonymousStoreyType); anonymousStoreyCtorRef = assembly.MainModule.ImportReference( - anonymousStoreyType.Methods.Single(m => m.Name == ".ctor" && m.Parameters.Count == 3)); + anonymousStoreyType.Methods.Single(m => m.Name == ".ctor" && m.Parameters.Count == 5)); + + objectVirtualMethodReferenceList = anonymousStoreyType.Methods.Where(m => m.Name.StartsWith("Object")). + Select(m => assembly.MainModule.ImportReference(m)).ToList(); itfBridgeType = new TypeDefinition("IFix", INTERFACEBRIDGE, TypeAttributes.Class | TypeAttributes.Public, anonymousStoreyTypeRef); - virualMachineFieldOfBridge = new FieldDefinition("virtualMachine", Mono.Cecil.FieldAttributes.Private, - VirtualMachineType); - itfBridgeType.Fields.Add(virualMachineFieldOfBridge); + virualMachineFieldOfBridge = assembly.MainModule.ImportReference(anonymousStoreyType.Fields.Single(f => f.Name == "virtualMachine")); assembly.MainModule.Types.Add(itfBridgeType); //end init itfBridgeType @@ -3254,6 +3269,8 @@ void postProcessInterfaceBridge() Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("typeIndex", Mono.Cecil.ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32)); + ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("vTable", + Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("methodIdArray", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); ctorOfItfBridgeType.Parameters.Add(new ParameterDefinition("virtualMachine", @@ -3263,17 +3280,15 @@ void postProcessInterfaceBridge() instructions.Add(Instruction.Create(OpCodes.Ldarg_1)); instructions.Add(Instruction.Create(OpCodes.Ldarg_2)); instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); + instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); + instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 6)); var callBaseCtor = Instruction.Create(OpCodes.Call, anonymousStoreyCtorRef); instructions.Add(callBaseCtor); - instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 5)); - instructions.Add(Instruction.Create(OpCodes.Stfld, virualMachineFieldOfBridge)); - for (int i = 0; i < methodIdFields.Count; i++) { instructions.Add(Instruction.Create(OpCodes.Ldarg_0)); - instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); + instructions.Add(createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 5)); emitLdcI4(instructions, i); instructions.Add(Instruction.Create(OpCodes.Ldelem_I4)); instructions.Add(Instruction.Create(OpCodes.Stfld, methodIdFields[i])); @@ -3283,7 +3298,7 @@ void postProcessInterfaceBridge() var insertPoint = callBaseCtor.Next; var processor = ctorOfItfBridgeType.Body.GetILProcessor(); - processor.InsertBefore(insertPoint, createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 4)); + processor.InsertBefore(insertPoint, createLdarg(ctorOfItfBridgeType.Body.GetILProcessor(), 5)); processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Ldlen)); processor.InsertBefore(insertPoint, Instruction.Create(OpCodes.Conv_I4)); processor.InsertBefore(insertPoint, createLdcI4(methodIdFields.Count)); @@ -3308,6 +3323,8 @@ void postProcessInterfaceBridge() new ArrayType(assembly.MainModule.TypeSystem.Int32))); createBridge.Parameters.Add(new ParameterDefinition("typeIndex", Mono.Cecil.ParameterAttributes.None, assembly.MainModule.TypeSystem.Int32)); + createBridge.Parameters.Add(new ParameterDefinition("vTable", Mono.Cecil.ParameterAttributes.None, + new ArrayType(assembly.MainModule.TypeSystem.Int32))); createBridge.Parameters.Add(new ParameterDefinition("slots", Mono.Cecil.ParameterAttributes.None, new ArrayType(assembly.MainModule.TypeSystem.Int32))); createBridge.Parameters.Add(new ParameterDefinition("virtualMachine", Mono.Cecil.ParameterAttributes.None, @@ -3318,6 +3335,7 @@ void postProcessInterfaceBridge() instructions.Add(Instruction.Create(OpCodes.Ldarg_3)); instructions.Add(createLdarg(createBridge.Body.GetILProcessor(), 4)); instructions.Add(createLdarg(createBridge.Body.GetILProcessor(), 5)); + instructions.Add(createLdarg(createBridge.Body.GetILProcessor(), 6)); instructions.Add(Instruction.Create(OpCodes.Newobj, ctorOfItfBridgeType)); instructions.Add(Instruction.Create(OpCodes.Ret)); @@ -3613,24 +3631,24 @@ public void Serialize(Stream output) //Console.WriteLine("anonymous type: " + anonymousTypeInfos[i]); var anonymousType = anonymousTypeInfos[i].DeclaringType as TypeDefinition; List anonymousTypeFields = new List(); - if (isNewClass(anonymousTypeInfos[i].DeclaringType as TypeDefinition)) - { - var temp = anonymousType; - while (temp != null && isNewClass(temp as TypeDefinition)) - { - if (temp.Fields != null) - { - foreach (var fi in temp.Fields) - { - anonymousTypeFields.Add(fi); - } - } - temp = temp.BaseType as TypeDefinition; + if (isNewClass(anonymousTypeInfos[i].DeclaringType as TypeDefinition)) + { + var temp = anonymousType; + while (temp != null && isNewClass(temp as TypeDefinition)) + { + if (temp.Fields != null) + { + foreach (var fi in temp.Fields) + { + anonymousTypeFields.Add(fi); + } + } + temp = temp.BaseType as TypeDefinition; } } - else - { - anonymousTypeFields.AddRange(anonymousTypeInfos[i].DeclaringType.Fields); + else + { + anonymousTypeFields.AddRange(anonymousTypeInfos[i].DeclaringType.Fields); } writer.Write(anonymousTypeFields.Count); @@ -3653,21 +3671,18 @@ public void Serialize(Stream output) writer.Write(anonymousTypeInfos[i].Parameters.Count); writeSlotInfo(writer, anonymousType); List vT = getVirtualMethodForType(anonymousType); - writer.Write(vT == null ? 0:vT.Count); - if (vT != null) + writer.Write(vT.Count); + int[] vTables = new int[vT.Count]; + for (int s = 0; s < vTables.Length; s++) { - int[] vTables = new int[vT.Count]; - for (int s = 0; s < vTables.Length; s++) - { - vTables[s] = -1; - } - writeVTable(anonymousType,vTables,vT); + vTables[s] = -1; + } + writeVTable(anonymousType,vTables,vT); - for (int k = 0; k < vTables.Length; k++) - { - writer.Write(vTables[k]); - } - } + for (int k = 0; k < vTables.Length; k++) + { + writer.Write(vTables[k]); + } } writer.Write(wrapperMgrImpl.GetAssemblyQualifiedName()); @@ -3733,16 +3748,16 @@ public List getVirtualMethodForType(TypeDefinition type) { return virtualMethods; } - int index = 0; + if (type.BaseType != null && isNewClass(type.BaseType as TypeDefinition)) { virtualMethods = new List(getVirtualMethodForType(type.BaseType as TypeDefinition)); } else { - virtualMethods = new List(); + virtualMethods = new List(ObjectVirtualMethodDefinitionList); } - index = virtualMethods.Count; + int index = virtualMethods.Count; foreach (var method in type.Methods) { if (method.IsVirtual && method.IsNewSlot) From 64e680bfd94ff1a3dc408b167d64717371cbb152 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 5 Jun 2020 16:20:49 +0800 Subject: [PATCH 041/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20=E8=B5=8B=E5=80=BC?= =?UTF-8?q?=E7=BB=99delegate=E7=9A=84=E6=98=AF=E4=B8=80=E4=B8=AA=E6=96=B0?= =?UTF-8?q?=E7=B1=BB=E7=9A=84=E8=99=9A=E5=87=BD=E6=95=B0=20(#140)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/Instruction.cs | 1 + Source/VSProj/Src/Core/VirtualMachine.cs | 12 ++++++++++++ Source/VSProj/Src/Tools/CodeTranslator.cs | 17 ++++++++++++++++- 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Core/Instruction.cs b/Source/VSProj/Src/Core/Instruction.cs index 39fb33d..cfe8843 100644 --- a/Source/VSProj/Src/Core/Instruction.cs +++ b/Source/VSProj/Src/Core/Instruction.cs @@ -86,6 +86,7 @@ public enum Code Conv_U8, Callvirt, Callvirtvirt, + Ldvirtftn2, Cpobj, Ldobj, Ldstr, diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index d61c190..288ee1e 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -655,6 +655,18 @@ public static void _Info(string a) 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.CallExtern://部分来自Call部分来自Callvirt case Code.Newobj: // 2.334642% int methodId = pc->Operand & 0xFFFF; diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 58e2441..3195867 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1631,13 +1631,28 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } break; case Code.Ldftn: - case Code.Ldvirtftn://TODO: 要不要处理下虚表? + case Code.Ldvirtftn: { var methodToCall = msIl.Operand as MethodReference; var methodIdInfo = getMethodId(methodToCall, method, msIl.OpCode.Code == Code.Ldvirtftn, false, injectTypePassToNext); if (methodIdInfo.Type == CallType.Internal && (isCompilerGeneratedPlainObject(methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) // closure { + if ((methodToCall as MethodDefinition).IsVirtual) + { + int methodIndex = -1; + if (!virtualMethodToIndex.TryGetValue(methodToCall,out methodIndex)) + { + methodIndex = virtualMethodInVTableIndex(methodToCall as MethodDefinition); + } + code.Add(new Core.Instruction + { + Code = Core.Code.Ldvirtftn2, + Operand = methodIndex + }); + break; + + } //Console.WriteLine("closure: " + methodToCall); getWrapperMethod(wrapperType, anonObjOfWrapper, methodToCall as MethodDefinition, true, true); From 0abc9c535ecc9bc35b28d29f5bf52ea7b065c2f8 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 5 Jun 2020 17:45:32 +0800 Subject: [PATCH 042/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20Unity=E7=89=88?= =?UTF-8?q?=E6=9C=AC=E4=B8=8D=E5=85=BC=E5=AE=B9=20=E8=80=8C=E5=87=BA?= =?UTF-8?q?=E7=8E=B0=E7=9A=84Ldelem=5FAny=E6=8C=87=E4=BB=A4=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20#fix=20https://github.com/Tencent/InjectFi?= =?UTF-8?q?x/issues/131=20(#143)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 27 ++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 288ee1e..b3e9ad9 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2177,7 +2177,17 @@ AnonymousStorey anonyObj ptr->Value1 = arr[idx]; } break; - //case Code.Ldelem_Any: //0.05657366% 泛型中使用?泛型不支持解析,所以不会碰到这指令 + case Code.Ldelem_Any: //0.05657366% + { + var arrPtr = evaluationStackPointer - 1 - 1; + int idx = (evaluationStackPointer - 1)->Value1; + var arrPos = arrPtr - evaluationStackBase; + 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); @@ -2355,7 +2365,20 @@ AnonymousStorey anonyObj evaluationStackPointer = pos + 1; } break; - //case Code.Stelem_Any: //0.03166702% 泛型中使用?泛型不支持解析,所以不会碰到这指令 + 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; + } + break; case Code.Conv_U2: //0.02917635% { var obj = evaluationStackPointer - 1; From f52a4f9e34bd2ac8387214e1f56c56444601b869 Mon Sep 17 00:00:00 2001 From: johnche Date: Thu, 18 Jun 2020 10:47:37 +0800 Subject: [PATCH 043/103] =?UTF-8?q?=E8=BF=99=E4=B8=AAcommit=EF=BC=8Chttps:?= =?UTF-8?q?//github.com/Tencent/InjectFix/commit/5a1208532681b7bcbf0f0745e?= =?UTF-8?q?0878052a7375ddd=EF=BC=8C=E5=BC=95=E5=85=A5=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8C=E5=A6=82=E6=9E=9C=E7=BB=A7=E6=89=BF=E4=BA=86?= =?UTF-8?q?=E5=88=AB=E7=9A=84=E7=A8=8B=E5=BA=8F=E9=9B=86=E7=9A=84=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=EF=BC=8C=E5=9C=A8override=E7=88=B6=E7=B1=BB=E7=9A=84?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E9=87=8C=E5=A4=B4=E7=94=A8base=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E7=88=B6=E7=B1=BB=E5=AE=9E=E7=8E=B0=EF=BC=8C=E4=BC=9A?= =?UTF-8?q?=E5=AF=BC=E8=87=B4=E6=AD=BB=E5=BE=AA=E7=8E=AF=EF=BC=8C=20fix=20?= =?UTF-8?q?https://github.com/Tencent/InjectFix/issues/153?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 3195867..5e9d8dd 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1550,8 +1550,8 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, try { - var callingType = methodToCall.DeclaringType; - var baseType = method.DeclaringType.BaseType; + var callingType = methodToCall.DeclaringType.Resolve(); + TypeReference baseType = method.DeclaringType.BaseType.Resolve(); while (baseType != null) { if (callingType.IsSameType(baseType)) From 0096a6a5d42cd97217f67ef83cab7a1bda1928ca Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 26 Jun 2020 13:37:17 +0800 Subject: [PATCH 044/103] fix https://github.com/Tencent/InjectFix/issues/156 --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 5e9d8dd..f5182e7 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2062,7 +2062,7 @@ void addInterfacesOfTypeToBridge(TypeDefinition anonType) } //implementMap[method] = matchItfMethod; - if (itfBridgeType.Interfaces.Any(ii => ii.InterfaceType.IsSameType(matchItfMethod.DeclaringType))) + if (matchItfMethod == null || itfBridgeType.Interfaces.Any(ii => ii.InterfaceType.IsSameType(matchItfMethod.DeclaringType))) { continue; } From e94f9f21559dbde8bd11d3a3d67dc583cd06f6cf Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Sun, 28 Jun 2020 16:16:29 +0800 Subject: [PATCH 045/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=B1=BB=E5=AE=9E=E7=8E=B0=E7=9A=84=E6=8E=A5=E5=8F=A3=E4=B8=AD?= =?UTF-8?q?=E6=9C=89event=E9=97=AE=E9=A2=98=20fix=20https://github.com/Ten?= =?UTF-8?q?cent/InjectFix/issues/154=20(#158)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index f5182e7..157e759 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3236,7 +3236,7 @@ void postProcessInterfaceBridge() if (!name.StartsWith("get_") && !name.StartsWith("set_")) { - throw new NotImplementedException("do not support special method: " + m); + continue; } var propName = name.Substring(4); From 1f4d045cc2855f609f17760e7677148ca52eaf02 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Wed, 1 Jul 2020 16:33:08 +0800 Subject: [PATCH 046/103] =?UTF-8?q?=E6=94=AF=E6=8C=81async=E7=89=B9?= =?UTF-8?q?=E6=80=A7=20fix=20https://github.com/Tencent/InjectFix/issues/1?= =?UTF-8?q?24=20(#160)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/AnonymousStorey.cs | 6 +- Source/VSProj/Src/Core/VirtualMachine.cs | 4 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 86 +++++++++++++++++------ 3 files changed, 72 insertions(+), 24 deletions(-) diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index 856a63f..341f90e 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -28,12 +28,14 @@ public AnonymousStorey(int fieldNum, int[] fieldTypes,int typeID, int[] vTable, managedFields = new object[fieldNum]; for (int i = 0; i < fieldTypes.Length; ++i) { - if (fieldTypes[i] == 1) + if (fieldTypes[i] > 0) { unmanagedFields[i].Type = ValueType.ValueType; unmanagedFields[i].Value1 = i; + int id = fieldTypes[i] - 1; + managedFields[i] = Activator.CreateInstance(virtualMachine.ExternTypes[id]); } - else if (fieldTypes[i] == 2) + else if (fieldTypes[i] == -2) { unmanagedFields[i].Type = ValueType.Object; unmanagedFields[i].Value1 = i; diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index b3e9ad9..48c256d 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -945,7 +945,9 @@ public static void _Info(string a) else { fieldIndex = -(fieldIndex + 1); - AnonymousStorey anonyObj = managedStack[ptr->Value1] as AnonymousStorey; + 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; diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 157e759..a40f231 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -283,7 +283,11 @@ int addExternMethod(MethodReference callee, MethodDefinition caller) { foreach (var typeArg in ((GenericInstanceMethod)callee).GenericArguments) { - addExternType(typeArg); + if (!isCompilerGenerated(typeArg)) + { + addExternType(typeArg); + } + } } @@ -1169,17 +1173,32 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, { if (variable.VariableType.IsValueType && !variable.VariableType.IsPrimitive) { - code.Add(new Core.Instruction + if (isCompilerGenerated(variable.VariableType)) { - Code = Core.Code.Ldloca, - Operand = variable.Index, - }); - - code.Add(new Core.Instruction + code.Add(new Core.Instruction + { + Code = Core.Code.Newanon, + Operand = addAnonymousCtor(null, variable.VariableType) + }); + code.Add(new Core.Instruction + { + Code = Core.Code.Stloc, + Operand = variable.Index + }); + } + else { - Code = Core.Code.Initobj, - Operand = addExternType(variable.VariableType) - }); + code.Add(new Core.Instruction + { + Code = Core.Code.Ldloca, + Operand = variable.Index, + }); + code.Add(new Core.Instruction + { + Code = Core.Code.Initobj, + Operand = addExternType(variable.VariableType) + }); + } offsetAdd += 2; } } @@ -1734,7 +1753,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, case Code.Ldflda: { var field = msIl.Operand as FieldReference; - if (isCompilerGeneratedPlainObject(field.DeclaringType) || isCustomClassPlainObject(field.DeclaringType)) + if (isCompilerGenerated(field.DeclaringType) || isCompilerGeneratedPlainObject(field.DeclaringType) || isCustomClassPlainObject(field.DeclaringType)) { var declaringType = field.DeclaringType as TypeDefinition; int baseFieldCount = 0; @@ -1995,22 +2014,42 @@ TypeReference getRawType(TypeReference type) private List anonymousTypeInfos = new List(); private Dictionary anonymousTypeToId = new Dictionary(); - int addAnonymousCtor(MethodDefinition ctor) + int addAnonymousCtor(MethodDefinition ctor, TypeReference variableType = null) { int id; - if (anonymousTypeToId.TryGetValue(ctor, out id)) + var ctorOrMethod = ctor != null ? ctor : (variableType as TypeDefinition).Methods[0]; + if (anonymousTypeToId.TryGetValue(ctorOrMethod, out id)) { return id; } - addInterfacesOfTypeToBridge(ctor.DeclaringType as TypeDefinition); - var methods = ctor.DeclaringType.Methods.Where(m => !m.IsConstructor).ToList(); + var typeDefinition = ctor != null ? (ctor.DeclaringType as TypeDefinition) : (variableType as TypeDefinition); + addInterfacesOfTypeToBridge(typeDefinition); + var methods = typeDefinition.Methods.Where(m => !m.IsConstructor).ToList(); + if(variableType != null) + { + for (int field = 0; field < typeDefinition.Fields.Count; field++) + { + if (typeDefinition.Fields[field].FieldType.IsValueType) + { + if (!isCompilerGenerated(typeDefinition.Fields[field].FieldType)) + { + if (!externTypes.Contains(typeDefinition.Fields[field].FieldType)) + { + addExternType(typeDefinition.Fields[field].FieldType); + } + } + } + } + } + foreach (var method in methods) { getMethodId(method, null,true, true, InjectType.Redirect); } id = anonymousTypeInfos.Count; - anonymousTypeInfos.Add(ctor); - anonymousTypeToId[ctor] = id; + var methodDefinition = ctor != null ? ctor : methods[0]; + anonymousTypeInfos.Add(methodDefinition); + anonymousTypeToId[methodDefinition] = id; return id; } @@ -2699,6 +2738,7 @@ void init(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly) anonymousStoreyTypeRef); virualMachineFieldOfBridge = assembly.MainModule.ImportReference(anonymousStoreyType.Fields.Single(f => f.Name == "virtualMachine")); assembly.MainModule.Types.Add(itfBridgeType); + addExternType(itfBridgeType); //end init itfBridgeType @@ -3402,9 +3442,13 @@ void writeMethod(BinaryWriter writer, MethodReference method) writer.Write(method.Name); var typeArgs = ((GenericInstanceMethod)method).GenericArguments; writer.Write(typeArgs.Count); - foreach (var typeArg in typeArgs) + for (int typeArg = 0;typeArg < typeArgs.Count;typeArg++) { - writer.Write(externTypeToId[typeArg]); + if (isCompilerGenerated(typeArgs[typeArg])) + { + typeArgs[typeArg] = itfBridgeType; + } + writer.Write(externTypeToId[typeArgs[typeArg]]); } writer.Write(method.Parameters.Count); //var genericParameters = ((GenericInstanceMethod)externMethod).ElementMethod.GenericParameters; @@ -3675,11 +3719,11 @@ public void Serialize(Stream output) } else if (anonymousTypeFields[field].FieldType.IsValueType) { - writer.Write(1); + writer.Write(externTypeToId[anonymousTypeFields[field].FieldType] + 1); } else { - writer.Write(2); + writer.Write(-2); } } writer.Write(methodToId[anonymousTypeInfos[i]]); From 85a3f7127e8648558d527f997a8baa37d2089871 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 6 Jul 2020 10:13:00 +0800 Subject: [PATCH 047/103] =?UTF-8?q?=E9=AB=98=E7=89=88=E6=9C=ACunity?= =?UTF-8?q?=E6=B2=A1=E6=9C=89gmsc=EF=BC=8C=E5=8F=AA=E6=9C=89msc=EF=BC=8C?= =?UTF-8?q?=E5=81=9A=E4=B8=8B=E5=85=BC=E5=AE=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/build_for_unity.bat | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/build_for_unity.bat b/Source/VSProj/build_for_unity.bat index 5049dde..d0ee967 100644 --- a/Source/VSProj/build_for_unity.bat +++ b/Source/VSProj/build_for_unity.bat @@ -1,5 +1,9 @@ @set UNITY_HOME=D:\Program Files\Unity523f1 -@set GMCS="%UNITY_HOME%\Editor\Data\Mono\bin\gmcs" +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 DLL_OUTPUT=..\UnityProj\Assets\Plugins\IFix.Core.dll @set TOOL_KIT_PATH=..\UnityProj\IFixToolKit From 081b67fdbfd2c94e43363394996ec774499ef7c7 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Mon, 13 Jul 2020 20:52:54 +0800 Subject: [PATCH 048/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20=E6=96=B0=E7=B1=BB?= =?UTF-8?q?=E5=AD=90=E7=B1=BB=E9=87=8D=E5=86=99=E7=88=B6=E7=B1=BB=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E6=97=B6base=E5=85=B3=E9=94=AE=E5=AD=97=E5=90=8E?= =?UTF-8?q?=E8=BF=98=E6=9C=89=E8=AF=AD=E5=8F=A5=E5=B9=B6=E6=9C=AA=E8=B5=B0?= =?UTF-8?q?=E5=88=B0=E7=9A=84=E9=97=AE=E9=A2=98=20fix=20https://github.com?= =?UTF-8?q?/Tencent/InjectFix/issues/161=20(#168)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index a40f231..ba7fe1a 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1047,13 +1047,17 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (methodToId.ContainsKey(callee)) { - if (isCallvirt && virtualMethodToIndex.ContainsKey(callee)) - { - return new MethodIdInfo() - { - Id = virtualMethodToIndex[callee], - Type = CallType.InteralVirtual - }; + if (isCallvirt) + { + getVirtualMethodForType(method.DeclaringType); + if (virtualMethodToIndex.ContainsKey(callee)) + { + return new MethodIdInfo() + { + Id = virtualMethodToIndex[callee], + Type = CallType.InteralVirtual + }; + } } return new MethodIdInfo() { From 53ccd7d84577f9e7fd49f6d25e9f648dbdf65b08 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Tue, 14 Jul 2020 10:16:53 +0800 Subject: [PATCH 049/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20=E5=8F=8C=E5=87=BB?= =?UTF-8?q?IFix.exe=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98=20fix=20https://gi?= =?UTF-8?q?thub.com/Tencent/InjectFix/issues/167=20(#169)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CSFix.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/VSProj/Src/Tools/CSFix.cs b/Source/VSProj/Src/Tools/CSFix.cs index cd5fe69..cf2721f 100644 --- a/Source/VSProj/Src/Tools/CSFix.cs +++ b/Source/VSProj/Src/Tools/CSFix.cs @@ -28,8 +28,8 @@ static void usage() static bool argsValid(string[] args) { - return (args[0] == "-inject" && args.Length >= 6) || (args[0] == "-patch" && args.Length >= 6) - || (args[0] == "-inherit_inject" && args.Length >= 7); + return (args.Length >= 6 && args[0] == "-inject") || (args.Length >= 6 && args[0] == "-patch") + || (args.Length >= 7 && args[0] == "-inherit_inject"); } // #lizard forgives From bc4f2b3636f79906a2086bdb675deb244d878ac3 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 24 Jul 2020 09:59:51 +0800 Subject: [PATCH 050/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20=E6=96=B9=E6=B3=95?= =?UTF-8?q?=E5=8F=82=E6=95=B0=E4=B8=AD=E7=9A=84struct=E8=A2=AB=E5=BD=93?= =?UTF-8?q?=E4=BD=9C=E5=BC=95=E7=94=A8=E7=B1=BB=E5=9E=8B=E5=A4=84=E7=90=86?= =?UTF-8?q?=20fix=20https://github.com/Tencent/InjectFix/iss=E2=80=A6=20(#?= =?UTF-8?q?183)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 解决 方法参数中的struct被当作引用类型处理 fix https://github.com/Tencent/InjectFix/issues/181 * 支持新增 struct fix https://github.com/Tencent/InjectFix/issues/170 --- Source/VSProj/Src/Core/SwitchFlags.cs | 2 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/Source/VSProj/Src/Core/SwitchFlags.cs b/Source/VSProj/Src/Core/SwitchFlags.cs index 82ea9d5..7f573ee 100644 --- a/Source/VSProj/Src/Core/SwitchFlags.cs +++ b/Source/VSProj/Src/Core/SwitchFlags.cs @@ -10,7 +10,7 @@ namespace IFix { //切换到解析执行 - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class)] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct)] public class InterpretAttribute : Attribute { } diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index ba7fe1a..c52d046 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1994,18 +1994,7 @@ TypeReference wrapperParamerterType(TypeReference type) } if (type.IsValueType) { - if (type.IsPrimitive) - { - return type; - } - try - { - if (type.Resolve().IsEnum) - { - return type; - } - } - catch { } + return type; } return objType; } From b0e60e4b93389d79a7ac3a1aa6eea24105acb55a Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 31 Jul 2020 15:51:20 +0800 Subject: [PATCH 051/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=20out=20struct?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=9C=A8Inject=E6=97=B6=E6=8A=A5=E9=94=99=20?= =?UTF-8?q?fix=20https://github.com/Tencent/InjectFix/issues/184=20(#187)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index c52d046..e406f38 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2308,7 +2308,8 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, { instructions.Add(Instruction.Create(OpCodes.Ldloca_S, call)); MethodReference push; - var wpt = wrapperParamerterType(paramRawType); + var wpt = wrapperParamerterType(paramRawType); + wpt = (wpt.IsValueType && !wpt.IsPrimitive) ? objType : wpt; if (pushMap.TryGetValue(wpt, out push)) { if (wpt == assembly.MainModule.TypeSystem.Object) From 7a6e6d30a5f2a17d8fc4ff175db21b4a1b717c4d Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 31 Jul 2020 16:20:45 +0800 Subject: [PATCH 052/103] =?UTF-8?q?=E4=BF=AE=E6=94=B9CecilExtensions.cs?= =?UTF-8?q?=E4=B8=8B=E7=9A=84TryImport=E5=87=BD=E6=95=B0=E7=9A=84=E5=88=A4?= =?UTF-8?q?=E7=A9=BA=E6=9D=A1=E4=BB=B6=E4=BD=8D=E7=BD=AE=20fix=20https://g?= =?UTF-8?q?ithub.com/Tencent/InjectFix/issues/180=20(#188)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CecilExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CecilExtensions.cs b/Source/VSProj/Src/Tools/CecilExtensions.cs index 1321210..bc9691b 100644 --- a/Source/VSProj/Src/Tools/CecilExtensions.cs +++ b/Source/VSProj/Src/Tools/CecilExtensions.cs @@ -457,6 +457,7 @@ public static bool IsFinalizer(this MethodDefinition method) // #lizard forgives public static TypeReference TryImport(this TypeReference toImport, ModuleDefinition module) { + if (toImport == null) return null; if (toImport.Namespace == "System") { if (toImport.Name == "Boolean") @@ -516,7 +517,6 @@ public static TypeReference TryImport(this TypeReference toImport, ModuleDefinit return module.TypeSystem.UIntPtr; } } - if (toImport == null) return null; if (toImport.IsGenericParameter) return toImport; if (toImport.IsGenericInstance) { From 31e1bd99e87ac6de39d67f4e7b094e06866d2f8c Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Mon, 3 Aug 2020 16:05:59 +0800 Subject: [PATCH 053/103] =?UTF-8?q?InjectFix=E4=BD=BF=E7=94=A8=E6=89=8B?= =?UTF-8?q?=E5=86=8C=20(#189)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 374 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100644 Doc/user_manual.md diff --git a/Doc/user_manual.md b/Doc/user_manual.md new file mode 100644 index 0000000..f6c2e2c --- /dev/null +++ b/Doc/user_manual.md @@ -0,0 +1,374 @@ +# IFix使用手册 + +### [IFix.Patch] + +##### 用途 + +​ 在补丁阶段使用;原生代码修复。如果发现某个函数有错误,就可以使用该标签给函数打补丁,打上这个标签的函数,童鞋们就可以随意修改该函数。 + +##### 用法 + +​ 该标签只能用在方法上,直接在要修改的函数上面标注一下这个标签即可。 + +##### 举例 + +​ 这个函数本来的意思是两个值相加,但现在写错了,所以可以给该函数打上[IFix.Patch]标签,然后修改就可以了 + +```c# +public int Add(int a,int b) +{ + return a*b; +} +``` + +```c# +[IFix.Patch] +public int Add(int a,int b) +{ + return a+b; +} +``` + +### [IFix.Interpret] + +##### 用途 + +​ 在补丁阶段使用;新增代码。在补丁阶段,童鞋们还有新的需求,想新增个函数或者类,可以用[IFix.Interpret]标签实现。 + +##### 用法 + +​ 该标签可以用在属性,方法,类型上,直接在要新增的代码上面标注一下这个标签即可。 + +##### 举例 + +​ 新增一个属性 + +```c# +private string name;//这个name字段是原生的 +[IFix.Interpret] +public string Name +{ + set + { + name = value; + } + get + { + return name; + } +} +``` + +​ 新增一个函数 + +```c# +[IFix.Interpret] +public int Sub(int a,int b) +{ + return a-b; +} +``` + +​ 新增一个类 + +```c# +[IFix.Interpret] +public class NewClass +{ + ... +} +``` + +### [IFix.CustomBridge] + +##### 用途 + +​ 在注入阶段使用; 把一个虚拟机的类适配到原生interface或者把一个虚拟机的函数适配到原生delegate。 + +​ 什么时候需要用到呢? + +- 修复代码赋值一个闭包到一个delegate变量; +- 修复代码的Unity协程用了yield return; +- 新增一个函数,赋值到一个delegate变量; +- 新增一个类,赋值到一个原生interface变量; +- 新增函数,用了yield return; + +##### 用法 + +​ 该标签只能用在类上,在童鞋们程序的某个地方,写上一个静态类,里面有一个静态属性,值就是接口类型 + +##### 举例 + +​ 新增一个类,该类实现了一个接口 + +```c# +public interface ISubSystem +{ + bool running { get; } + void Print(); +} + +[IFix.Interpret] +public class SubSystem : ISubSystem +{ + public bool running { get { return true; } } + public void Print() + { + UnityEngine.Debug.Log("SubSystem1.Print"); + } +} +``` + +​ 新增函数(或者修复代码[IFix.Patch]的Unity协程),用到了 yield return + +```c# +[IFix.Interpret] +public IEnumerator TestInterface() +{ + yield return new WaitForSeconds(1); + UnityEngine.Debug.Log("wait one second"); +} +``` + +​ 新增函数(或者修复代码[IFix.Patch]),赋值到一个delegate变量 + +```c# +public class Test +{ + public delegate int MyDelegate(int a, int b); + + [IFix.Interpret] + public MyDelegate TestDelegate() + { + return (a,b) => a + b; + } +} +``` + +``` +[IFix.CustomBridge] +public static class AdditionalBridge +{ + static List bridge = new List() + { + typeof(ISubSystem), + typeof(IEnumerator), + typeof(Test.MyDelegate) + }; +} +``` + + + +### [Configure] + +##### 用途 + +​ 在注入阶段使用;配置类,里面存储的是一些注入时需要注入或过滤的东西。 + +##### 用法 + +​ 该标签只能用在类上,该类必须在Editor文件夹下 。 + +##### 举例 + +```c# +[Configure] +public class TestCfg +{ + +} +``` + +### [IFix] + +##### 用途 + +​ 在注入阶段使用;用来存储所有你认为将来可能会需要修复的类的集合。该标签和[IFix.Patch]有关联,因为如果发现某个函数需要修复,直接打上[IFix.Patch]标签就可以了,但是前提是,这个需要修复的函数的类必须在[IFix]下。 + +##### 用法 + +​ 该标签只能用在属性上,Configure类中的一个静态属性,get得到的是可能会需要修复的函数所有类的集合 + +##### 举例 + +​ 认为Test类里面的函数可能会出错,所以把它们放到[IFix]标签下,当Test类中的Add函数需要修复,直接打标签修改即可。 + +```c# +[Configure] +public class TestCfg +{ + [IFix] + static IEnumerable hotfix + { + get + { + return new List() + { + typeof(Test) + }; + } + } +} + +public class Test +{ + [IFix.Patch] + public int Add(int a,int b) + { + return a+b; + } +} +``` + +### [ReverseWrapper] + +##### 用途 + +​ 在注入阶段使用;虚拟机内部的函数调用原生的方法时,是通过反射调用,如果某个原生方法被频繁调用,为了加快速度,可以通过该标签,用静态调用代替反射调用 。 + +##### 用法 + +​ 该标签只能用在属性上,Configure类中的一个静态属性,get得到的是虚拟机内部调用原生方法时,要通过静态调用而不是反射调用的类的集合。 + +##### 举例 + +​ 调用A类里的函数都是通过静态调用; + +```c# +public class A +{ + public void Print() + { + UnityEngine.Debug.Log("A.print()"); + } +} + +public class Test +{ + [IFix.Patch] + public int Add(int a,int b) + { + A a = new A(); + a.print(); //正常这里调用原生函数print()是通过反射调用,现在想通过静态调用 + return a+b; + } +} + +[Configure] +public class TestCfg +{ + [IFix] + static IEnumerable hotfix + { + get + { + return new List() + { + typeof(Test) + }; + } + } + [ReverseWrapper] + static IEnumerable reverse + { + get + { + return new List() + { + typeof(A) + }; + } + } +} + + +``` + +### [Filter] + +##### 用途 + +​ 在注入阶段使用;用来存储想要过滤的东西。在注入阶段,凡是在[IFix]标签下的属性里面的值,都会被注入适配代码,但是如果不想对某个函数进行注入,可以用该标签进行过滤。 + +##### 用法 + +​ 该标签只能用在方法上,Configure类中的一个静态方法。 + +##### 举例 + +​ 觉得Test类里的函数可能会需要修复,但是Test类里面的Div和Mult不可能有问题,可以把这两个函数过滤掉。 + +```c# +public class Test +{ + [IFix.Patch] + public int Add(int a,int b) + { + return a+b; + } + public int Sub(int a,int b) + { + return a-b; + } + public int Div(int a,int b) + { + return a/b; + } + public int Mult(int a,int b) + { + return a*b; + } +} + +[Configure] +public class TestCfg +{ + [IFix] + static IEnumerable hotfix + { + get + { + return new List() + { + typeof(Test) + }; + } + } + [Filter] + static bool Filter(System.Reflection.MethodInfo methodInfo) + { + return methodInfo.DeclaringType.FullName == "Test" + && (methodInfo.Name == "Div" || methodInfo.Name == "Mult"); + } +} + +``` + + + +### 注意事项 + +- 如果觉得某个类的函数可能会需要修复,那么一定要把该类放到Editor目录下[Configure]类的[IFix]静态字段里;然后才可以对某个函数进行[IFix.Patch]。 +- 涉及到interface和delegate,如果把一个虚拟机的类适配到原生interface或者把一个虚拟机的函数适配到原生delegate ,一定要放到[IFix.CustomBridge]类的静态字段里。 +- 打上[Configure]标签的类,必须放在Editor目录下。 +- [IFix],[ReverseWrapper],[Filter]这些标签必须放在打上[Configure]标签的类里。 +- 在[IFix.Patch]时,不支持修复泛型函数,不支持修复构造函数,不支持在原生类中新增字段。 +- 在[IFix.Interpret]时,不支持新增类继承原生类,不支持新增类是泛型类。 + + + + + +### 总结 + +| 标签 | 使用阶段 | 用途 | 用法 | +| :-----------------: | :------: | :------------------------: | :----------------------------------------------------------: | +| [IFix.Patch] | 补丁 | 修复函数 | 只能放在函数上 | +| [IFix.Interpret] | 补丁 | 新增属性,函数,类型 | 放在属性,函数,类型上 | +| [IFix.CustomBridge] | 注入 | interface和delegate桥接 | 只能放在单独写一个静态类上,存储虚拟机的类适配到原生interface或者虚拟机的函数适配到原生delegate | +| [Configure] | 注入 | 配置类 | 只能放在单独写一个存放在Editor目录下的类上 | +| [IFix] | 注入 | 可能需要修复函数的类的集合 | 只能放在[Configure]类的一个静态属性上 | +| [ReverseWrapper] | 注入 | 静态调用 | 只能放在[Configure]类的一个静态属性上 | +| [Filter] | 注入 | 不想发生注入的函数 | 只能放在[Configure]类的一个静态函数上 | + From 2f36c1f5398c2821097f576335b89c08042b8942 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Tue, 4 Aug 2020 10:37:17 +0800 Subject: [PATCH 054/103] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=89=8B=E5=86=8C=20(#191)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 67 +--------------------------------------------- 1 file changed, 1 insertion(+), 66 deletions(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index f6c2e2c..c242f12 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -221,70 +221,6 @@ public class Test } ``` -### [ReverseWrapper] - -##### 用途 - -​ 在注入阶段使用;虚拟机内部的函数调用原生的方法时,是通过反射调用,如果某个原生方法被频繁调用,为了加快速度,可以通过该标签,用静态调用代替反射调用 。 - -##### 用法 - -​ 该标签只能用在属性上,Configure类中的一个静态属性,get得到的是虚拟机内部调用原生方法时,要通过静态调用而不是反射调用的类的集合。 - -##### 举例 - -​ 调用A类里的函数都是通过静态调用; - -```c# -public class A -{ - public void Print() - { - UnityEngine.Debug.Log("A.print()"); - } -} - -public class Test -{ - [IFix.Patch] - public int Add(int a,int b) - { - A a = new A(); - a.print(); //正常这里调用原生函数print()是通过反射调用,现在想通过静态调用 - return a+b; - } -} - -[Configure] -public class TestCfg -{ - [IFix] - static IEnumerable hotfix - { - get - { - return new List() - { - typeof(Test) - }; - } - } - [ReverseWrapper] - static IEnumerable reverse - { - get - { - return new List() - { - typeof(A) - }; - } - } -} - - -``` - ### [Filter] ##### 用途 @@ -352,7 +288,7 @@ public class TestCfg - 如果觉得某个类的函数可能会需要修复,那么一定要把该类放到Editor目录下[Configure]类的[IFix]静态字段里;然后才可以对某个函数进行[IFix.Patch]。 - 涉及到interface和delegate,如果把一个虚拟机的类适配到原生interface或者把一个虚拟机的函数适配到原生delegate ,一定要放到[IFix.CustomBridge]类的静态字段里。 - 打上[Configure]标签的类,必须放在Editor目录下。 -- [IFix],[ReverseWrapper],[Filter]这些标签必须放在打上[Configure]标签的类里。 +- [IFix],[Filter]这些标签必须放在打上[Configure]标签的类里。 - 在[IFix.Patch]时,不支持修复泛型函数,不支持修复构造函数,不支持在原生类中新增字段。 - 在[IFix.Interpret]时,不支持新增类继承原生类,不支持新增类是泛型类。 @@ -369,6 +305,5 @@ public class TestCfg | [IFix.CustomBridge] | 注入 | interface和delegate桥接 | 只能放在单独写一个静态类上,存储虚拟机的类适配到原生interface或者虚拟机的函数适配到原生delegate | | [Configure] | 注入 | 配置类 | 只能放在单独写一个存放在Editor目录下的类上 | | [IFix] | 注入 | 可能需要修复函数的类的集合 | 只能放在[Configure]类的一个静态属性上 | -| [ReverseWrapper] | 注入 | 静态调用 | 只能放在[Configure]类的一个静态属性上 | | [Filter] | 注入 | 不想发生注入的函数 | 只能放在[Configure]类的一个静态函数上 | From 35cb0ab58ef5d80579777dc25c9256aed32145bc Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 4 Aug 2020 10:39:37 +0800 Subject: [PATCH 055/103] =?UTF-8?q?=E5=8A=A0=E4=B8=8A=E6=89=8B=E5=86=8C?= =?UTF-8?q?=E7=9A=84=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd46a9b..345091a 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,8 @@ ## 快速入门 -[如何使用?](./Doc/quick_start.md) +* [快速入门](./Doc/quick_start.md) +* [使用手册](./Doc/user_manual.md) ## 技术支持 From aa2fb09ed925cda33c3beec2b65dba461196c702 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Wed, 5 Aug 2020 10:31:16 +0800 Subject: [PATCH 056/103] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=8B=B1=E6=96=87?= =?UTF-8?q?=E7=89=88=E4=BD=BF=E7=94=A8=E6=89=8B=E5=86=8C=20(#193)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 2 +- Doc/user_manual_en.md | 300 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 301 insertions(+), 1 deletion(-) create mode 100644 Doc/user_manual_en.md diff --git a/Doc/user_manual.md b/Doc/user_manual.md index c242f12..e6ce7cf 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -95,7 +95,7 @@ public class NewClass ##### 用法 -​ 该标签只能用在类上,在童鞋们程序的某个地方,写上一个静态类,里面有一个静态属性,值就是接口类型 +​ 该标签只能用在类上,在童鞋们程序的某个地方,写上一个静态类,里面有一个静态字段,值就是interface和delegate的类型集合 ##### 举例 diff --git a/Doc/user_manual_en.md b/Doc/user_manual_en.md new file mode 100644 index 0000000..c742b52 --- /dev/null +++ b/Doc/user_manual_en.md @@ -0,0 +1,300 @@ +# IFix Manual + +### [IFix.Patch] + +##### use + +​ Used in the patch stage,native code fix. If you find an error in a function, you can use the label to patch the function, and the function with this label can modify the function at will. + +##### usage + +​ This label can only be used on functions, just mark this label directly on the function to be modified. + +##### eg + +​ This function originally meant to add two values, but now it is wrong, so you can label the function with [IFix.Patch] and modify it. + +```c# +public int Add(int a,int b) +{ + return a*b; +} +``` + +```c# +[IFix.Patch] +public int Add(int a,int b) +{ + return a+b; +} +``` + +### [IFix.Interpret] + +##### use + +​ Used in the patch stage, add code. In the patch stage, people still have new requirements. If you want to add a function or class, you can use the [IFix.Interpret] label to implement it. + +##### usage + +​ This label can be used in properties , functions, and classes. Just mark this label directly on the code to be added. + +##### eg + +​ Add a new property + +```c# +private string name;//The name field is native +[IFix.Interpret] +public string Name +{ + set + { + name = value; + } + get + { + return name; + } +} +``` + +​ Add a new function + +```c# +[IFix.Interpret] +public int Sub(int a,int b) +{ + return a-b; +} +``` + +​ Add a new class + +```c# +[IFix.Interpret] +public class NewClass +{ + ... +} +``` + +### [IFix.CustomBridge] + +##### use + +​ Used in the injection stage, adapt a virtual machine class to the native interface or adapt a virtual machine function to the native delegate. + +​ When do I need to use it? + +- Fix the code to assign a closure to a delegate variable; +- The Unity coroutine that fixes the code uses yield return; +- Add a function and assign it to a delegate variable; +- Add a new class and assign it to a native interface variable; +- Added function, using yield return; + +##### usage + +​ This label can only be used on the class. Somewhere in people's program, write a static class with a static field and the value is the type collection of interface and delegate. + +##### eg + +​ Add a new class, which implements an interface. + +```c# +public interface ISubSystem +{ + bool running { get; } + void Print(); +} + +[IFix.Interpret] +public class SubSystem : ISubSystem +{ + public bool running { get { return true; } } + public void Print() + { + UnityEngine.Debug.Log("SubSystem1.Print"); + } +} +``` + +​ Add a new function (or Unity coroutine with fixed code [IFix.Patch]), using yield return. + +```c# +[IFix.Interpret] +public IEnumerator TestInterface() +{ + yield return new WaitForSeconds(1); + UnityEngine.Debug.Log("wait one second"); +} +``` + +​ Add a new function (or fix the code [IFix.Patch]) and assign it to a delegate variable. + +```c# +public class Test +{ + public delegate int MyDelegate(int a, int b); + + [IFix.Interpret] + public MyDelegate TestDelegate() + { + return (a,b) => a + b; + } +} +``` + +```c# +[IFix.CustomBridge] +public static class AdditionalBridge +{ + static List bridge = new List() + { + typeof(ISubSystem), + typeof(IEnumerator), + typeof(Test.MyDelegate) + }; +} +``` + +### [Configure] + +##### use + +​ Used in the injection stage, configuration class, which stores some things that need to be injected or filtered during injection. + +##### usage + +​ The label can only be used on the class, the class must be in the Editor folder. + +##### eg + +```c# +[Configure] +public class TestCfg +{ + +} +``` + +### [IFix] + +##### use + +​ Used in the injection stage, used to store a collection of all classes that you think may need to be fixed in the future. This label is related to [IFix.Patch], because if you find that a function needs to be fixed, just label the [IFix.Patch] label , but the premise is that the class of the function that needs to be fixed must be under [IFix]. + +##### usage + +​ This label can only be used on properties, a static property in the Configure class, get is a collection of all classes of functions that may need to be fixed. + +##### eg + +​ I think the functions in the Test class may be wrong, so put them under the [IFix] label. When the Add function in the Test class needs to be fixed, just label it and modify it. + +```c# +[Configure] +public class TestCfg +{ + [IFix] + static IEnumerable hotfix + { + get + { + return new List() + { + typeof(Test) + }; + } + } +} + +public class Test +{ + [IFix.Patch] + public int Add(int a,int b) + { + return a+b; + } +} +``` + +### [Filter] + +##### use + +​ Used in the injection stage, used to store what you want to filter. In the injection stage, all values in the properties under the [IFix] label will be injected into the adaptation code, but if you don't want to inject a function, you can use this label to filter. + +##### usage + +​ This label can only be used on functions, a static function in the Configure class. + +##### eg + +​ I think the functions in the Test class may be wrong, so put them under the [IFix] label. When the Add function in the Test class needs to be fixed, just label it and modify it. + +```c# +public class Test +{ + [IFix.Patch] + public int Add(int a,int b) + { + return a+b; + } + public int Sub(int a,int b) + { + return a-b; + } + public int Div(int a,int b) + { + return a/b; + } + public int Mult(int a,int b) + { + return a*b; + } +} + +[Configure] +public class TestCfg +{ + [IFix] + static IEnumerable hotfix + { + get + { + return new List() + { + typeof(Test) + }; + } + } + [Filter] + static bool Filter(System.Reflection.MethodInfo methodInfo) + { + return methodInfo.DeclaringType.FullName == "Test" + && (methodInfo.Name == "Div" || methodInfo.Name == "Mult"); + } +} +``` + +### Precautions + +- If you think that a function of a certain class may need to be fixed, you must put the class in the [IFix] static field of the [Configure] class in the Editor directory, then you can perform [IFix.Patch] on a certain function. +- When it comes to interface and delegate, if you adapt a virtual machine class to a native interface or adapt a virtual machine function to a native delegate, you must put it in the static field of the [IFix.CustomBridge] class. +- The class marked with [Configure] must be placed in the Editor directory. +- [IFix], [Filter] These labels must be placed in the class marked with [Configure]. +- In [IFix.Patch], it does not support fixing generic functions, repairing constructors, or adding fields to native classes. +- In [IFix.Interpret], new classes are not supported to inherit native classes, and new classes are not supported as generic classes. + +### In conclusion + +| Label | Use stage | Use | Usage | +| :-----------------: | :-------: | :---------------------------------------------------------: | :----------------------------------------------------------: | +| [IFix.Patch] | patch | Fix function | Can only be placed on functions | +| [IFix.Interpret] | patch | New properties, functions, types | On properties, functions, types | +| [IFix.CustomBridge] | inject | interface and delegate bridge | It can only be placed on a separate static class, the class of the storage virtual machine is adapted to the native interface or the function of the virtual machine is adapted to the native delegate | +| [Configure] | inject | Configuration class | Can only be placed on a class that is written separately and stored in the Editor directory | +| [IFix] | inject | The collection of classes that may need to fix the function | Can only be placed on a static property of the [Configure] class | +| [Filter] | inject | Functions that do not want to be injected | Can only be placed on a static function of the [Configure] class | + From 3e1b240468e016b88daa338ab3f3f8a07783cf84 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 5 Aug 2020 10:33:26 +0800 Subject: [PATCH 057/103] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=96=87=E6=A1=A3?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 ++- README_en.md | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 345091a..0d379ed 100644 --- a/README.md +++ b/README.md @@ -31,10 +31,11 @@ * IFixToolKit拷贝到Unity项目的Assets同级目录 * Assets/IFix,Assets/Plugins拷贝到Unity项目的Assets下 -## 快速入门 +## 文档 * [快速入门](./Doc/quick_start.md) * [使用手册](./Doc/user_manual.md) +* [FAQ](./Doc/faq.md) ## 技术支持 diff --git a/README_en.md b/README_en.md index 6d22c08..73c9b06 100644 --- a/README_en.md +++ b/README_en.md @@ -29,7 +29,8 @@ Can be used for bug fixes in Unity, supporting Unity’s full range * Copy IFixToolKit to a sibling directory of Assets in the Unity project * Copy Assets/IFix and Assets/Plugins under Assets in the Unity project -## Quick Start - -[How to use? ](./Doc/quick_start_en.md) +## Doc +* [Quick Start](./Doc/quick_start_en.md) +* [Manual](./Doc/user_manual_en.md) +* [FAQ](./Doc/faq_en.md) From c8bccd0e2deefa5af8b969f021c92f9859b06ff2 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 10 Aug 2020 17:02:08 +0800 Subject: [PATCH 058/103] =?UTF-8?q?=E4=BF=AE=E5=A4=8Duint=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2ulong=E6=97=B6=E7=BB=93=E6=9E=9C=E4=B8=8D=E6=AD=A3?= =?UTF-8?q?=E7=A1=AE=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8Cfix=20https://gith?= =?UTF-8?q?ub.com/Tencent/InjectFix/issues/197?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 48c256d..38eaf11 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2226,7 +2226,7 @@ AnonymousStorey anonyObj switch (obj->Type) { case ValueType.Integer: - val = (ulong)obj->Value1; + val = *(uint*)&obj->Value1;//Conv_U8的操作数肯定是uint break; case ValueType.Long: pc++; From 6756f1de3349986191b780769db04b2f215f6029 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Wed, 12 Aug 2020 15:25:47 +0800 Subject: [PATCH 059/103] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=89=8B=E5=86=8C=20fix=20https://github.com/Tencent/InjectFix?= =?UTF-8?q?/issues/202=20(#204)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 4 +++- Doc/user_manual_en.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index e6ce7cf..0293de9 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -45,13 +45,15 @@ public int Add(int a,int b) ```c# private string name;//这个name字段是原生的 -[IFix.Interpret] + public string Name { + [IFix.Interpret] set { name = value; } + [IFix.Interpret] get { return name; diff --git a/Doc/user_manual_en.md b/Doc/user_manual_en.md index c742b52..e8059d9 100644 --- a/Doc/user_manual_en.md +++ b/Doc/user_manual_en.md @@ -45,13 +45,15 @@ public int Add(int a,int b) ```c# private string name;//The name field is native -[IFix.Interpret] + public string Name { + [IFix.Interpret] set { name = value; } + [IFix.Interpret] get { return name; From 7a77897ec79e8b64038dd3c2480998b01f790d73 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 25 Aug 2020 11:01:00 +0800 Subject: [PATCH 060/103] fix https://github.com/Tencent/InjectFix/issues/199 --- Source/VSProj/Src/Tools/CodeTranslator.cs | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index e406f38..7f06cd7 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1047,17 +1047,17 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (methodToId.ContainsKey(callee)) { - if (isCallvirt) - { - getVirtualMethodForType(method.DeclaringType); - if (virtualMethodToIndex.ContainsKey(callee)) - { - return new MethodIdInfo() - { - Id = virtualMethodToIndex[callee], - Type = CallType.InteralVirtual - }; - } + if (isCallvirt) + { + getVirtualMethodForType(method.DeclaringType); + if (virtualMethodToIndex.ContainsKey(callee)) + { + return new MethodIdInfo() + { + Id = virtualMethodToIndex[callee], + Type = CallType.InteralVirtual + }; + } } return new MethodIdInfo() { @@ -2018,7 +2018,7 @@ int addAnonymousCtor(MethodDefinition ctor, TypeReference variableType = null) var typeDefinition = ctor != null ? (ctor.DeclaringType as TypeDefinition) : (variableType as TypeDefinition); addInterfacesOfTypeToBridge(typeDefinition); var methods = typeDefinition.Methods.Where(m => !m.IsConstructor).ToList(); - if(variableType != null) + if(variableType != null || ctor.DeclaringType.Fields.Count > 0) { for (int field = 0; field < typeDefinition.Fields.Count; field++) { @@ -2308,7 +2308,7 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, { instructions.Add(Instruction.Create(OpCodes.Ldloca_S, call)); MethodReference push; - var wpt = wrapperParamerterType(paramRawType); + var wpt = wrapperParamerterType(paramRawType); wpt = (wpt.IsValueType && !wpt.IsPrimitive) ? objType : wpt; if (pushMap.TryGetValue(wpt, out push)) { From 39706a948da944ff12c5bcadeab8f89d39c524ff Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 31 Aug 2020 09:47:47 +0800 Subject: [PATCH 061/103] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E6=97=A0=E7=94=A8?= =?UTF-8?q?=E5=8F=98=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 38eaf11..f789389 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2183,7 +2183,6 @@ AnonymousStorey anonyObj { var arrPtr = evaluationStackPointer - 1 - 1; int idx = (evaluationStackPointer - 1)->Value1; - var arrPos = arrPtr - evaluationStackBase; var arr = managedStack[arrPtr->Value1] as Array; EvaluationStackOperation.PushObject(evaluationStackBase, arrPtr, managedStack, arr.GetValue(idx), arr.GetType().GetElementType()); From 9873ef5e5cdf581b211498171b84b3c45989bef0 Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 31 Aug 2020 09:48:29 +0800 Subject: [PATCH 062/103] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=98=AF=E5=90=A6?= =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=96=B0=E7=B1=BB=E5=B7=B2=E7=BB=8F=E5=AD=98?= =?UTF-8?q?=E5=9C=A8=E7=9A=84=E9=80=89=E9=A1=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Src/Builder/FileVirtualMachineBuilder.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index ad44d0f..7d9bf7f 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.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. @@ -266,7 +266,7 @@ static int[] readSlotInfo(BinaryReader reader, Dictionary itfMe } // #lizard forgives - unsafe static public VirtualMachine Load(Stream stream) + unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) { List nativePointers = new List(); @@ -546,14 +546,17 @@ unsafe static public VirtualMachine Load(Stream stream) }; } - int newClassCount = reader.ReadInt32(); - for(int i = 0;i < newClassCount;i++) + if (checkNew) { - var newClassFullName = reader.ReadString(); - var newClassName = Type.GetType(newClassFullName); - if (newClassName != null) + int newClassCount = reader.ReadInt32(); + for (int i = 0; i < newClassCount; i++) { - throw new Exception(newClassName + " class is expected to be a new class , but it already exists "); + var newClassFullName = reader.ReadString(); + var newClassName = Type.GetType(newClassFullName); + if (newClassName != null) + { + throw new Exception(newClassName + " class is expected to be a new class , but it already exists "); + } } } From aa6289ca78bbb381344354c7b6c0a4c8cab40adf Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Fri, 4 Sep 2020 16:37:23 +0800 Subject: [PATCH 063/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=8D=8F=E7=A8=8B=20=E6=B7=BB=E5=8A=A0IEnumerator=E5=88=B0CustomBridge=E6=8A=A5=E9=94=99=E9=97=AE=E9=A2=98=20f?= =?UTF-8?q?ix=20https://github.com/Tencent/InjectFix/issues/182=20(#227)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: annayxguo <“annayxguo@tencent.com”> --- Source/VSProj/Src/Tools/CodeTranslator.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 7f06cd7..cfb9658 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2489,9 +2489,9 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, instructions.Add(Instruction.Create(OpCodes.Ldloca_S, call)); emitLdcI4(instructions, refPos[i]); - if (getMap.ContainsKey(paramRawType)) + if (paramRawType.IsPrimitive && getMap.ContainsKey(paramRawType.Resolve())) { - instructions.Add(Instruction.Create(OpCodes.Callvirt, getMap[paramRawType])); + instructions.Add(Instruction.Create(OpCodes.Callvirt, getMap[paramRawType.Resolve()])); } else { @@ -2508,7 +2508,8 @@ MethodDefinition getWrapperMethod(TypeDefinition type, FieldDefinition anonObj, instructions.Add(Instruction.Create(OpCodes.Ldloca_S, call)); MethodReference get; emitLdcI4(instructions, refCount); - if (getMap.TryGetValue(tryGetUnderlyingType(returnType), out get)) + var returnRawType = tryGetUnderlyingType(returnType); + if (returnRawType.IsPrimitive && getMap.TryGetValue(returnRawType.Resolve(), out get)) { instructions.Add(Instruction.Create(OpCodes.Callvirt, get)); } @@ -2833,7 +2834,7 @@ void idMapTypeCheck() void initStackOp(TypeDefinition call, TypeReference type) { pushMap[type] = importMethodReference(call, "Push" + type.Name); - getMap[type] = importMethodReference(call, "Get" + type.Name); + getMap[type.Resolve()] = importMethodReference(call, "Get" + type.Name); nameToTypeReference[type.FullName] = type; } From e8821e101b2f90bfd2aa90fac878dfb7025e3671 Mon Sep 17 00:00:00 2001 From: johnche Date: Sat, 12 Sep 2020 15:05:31 +0800 Subject: [PATCH 064/103] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=B4=E6=98=8ECus?= =?UTF-8?q?tomBridge=E4=B8=8D=E8=83=BD=E6=94=BE=E5=88=B0Editor=E7=9B=AE?= =?UTF-8?q?=E5=BD=95=E7=9A=84=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index 0293de9..9056372 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -98,6 +98,7 @@ public class NewClass ##### 用法 ​ 该标签只能用在类上,在童鞋们程序的某个地方,写上一个静态类,里面有一个静态字段,值就是interface和delegate的类型集合 + !!注意,该类不能放到Editor目录 ##### 举例 @@ -147,7 +148,7 @@ public class Test } ``` -``` +```c# [IFix.CustomBridge] public static class AdditionalBridge { From 743a2d917faaab1c34f16d9fbf30ddf7231f8677 Mon Sep 17 00:00:00 2001 From: johnche Date: Sat, 12 Sep 2020 15:06:49 +0800 Subject: [PATCH 065/103] =?UTF-8?q?=E4=BC=98=E5=8C=96=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index 9056372..26c7861 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -305,7 +305,7 @@ public class TestCfg | :-----------------: | :------: | :------------------------: | :----------------------------------------------------------: | | [IFix.Patch] | 补丁 | 修复函数 | 只能放在函数上 | | [IFix.Interpret] | 补丁 | 新增属性,函数,类型 | 放在属性,函数,类型上 | -| [IFix.CustomBridge] | 注入 | interface和delegate桥接 | 只能放在单独写一个静态类上,存储虚拟机的类适配到原生interface或者虚拟机的函数适配到原生delegate | +| [IFix.CustomBridge] | 注入 | interface和delegate桥接 | 只能放在单独写一个静态类上,存储虚拟机的类适配到原生interface或者虚拟机的函数适配到原生delegate,该类不能放Editor目录 | | [Configure] | 注入 | 配置类 | 只能放在单独写一个存放在Editor目录下的类上 | | [IFix] | 注入 | 可能需要修复函数的类的集合 | 只能放在[Configure]类的一个静态属性上 | | [Filter] | 注入 | 不想发生注入的函数 | 只能放在[Configure]类的一个静态函数上 | From 086bfa167738ab0979da53d0c27dff8751c12d12 Mon Sep 17 00:00:00 2001 From: johnche Date: Sat, 12 Sep 2020 15:08:00 +0800 Subject: [PATCH 066/103] =?UTF-8?q?=E6=A0=BC=E5=BC=8F=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index 26c7861..2c19b90 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -98,6 +98,7 @@ public class NewClass ##### 用法 ​ 该标签只能用在类上,在童鞋们程序的某个地方,写上一个静态类,里面有一个静态字段,值就是interface和delegate的类型集合 + !!注意,该类不能放到Editor目录 ##### 举例 From 794a047e46d462f37658932b42d4832b3779b0ce Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Tue, 15 Sep 2020 10:18:53 +0800 Subject: [PATCH 067/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3ios=E7=9A=84async/awa?= =?UTF-8?q?it=E6=8A=A5=E9=94=99=20fix=20https://github.com/Tencent/InjectF?= =?UTF-8?q?ix/issues/222=20(#230)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 39 ++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index cfb9658..4915425 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -263,6 +263,15 @@ int addExternMethod(MethodReference callee, MethodDefinition caller) return ushort.MaxValue; } + if (callee.Name == "AwaitUnsafeOnCompleted") + { + + if (!awaitUnsafeOnCompletedMethods.Any(m => ((GenericInstanceMethod)callee).GenericArguments[0] == ((GenericInstanceMethod)m).GenericArguments[0])) + { + awaitUnsafeOnCompletedMethods.Add(callee); + } + } + if (externMethodToId.ContainsKey(callee)) { return externMethodToId[callee]; @@ -2162,6 +2171,29 @@ void addInterfaceToBridge(TypeReference itf) } } + void EmitRefAwaitUnsafeOnCompletedMethod() + { + MethodDefinition targetMethod = new MethodDefinition("RefAwaitUnsafeOnCompleteMethod", + Mono.Cecil.MethodAttributes.Public, assembly.MainModule.TypeSystem.Void); + var instructions = targetMethod.Body.Instructions; + var localBridge = new VariableDefinition(itfBridgeType); + targetMethod.Body.Variables.Add(localBridge); + for (int j = 0;j < awaitUnsafeOnCompletedMethods.Count;j++) + { + var localTaskAwaiter = new VariableDefinition(((GenericInstanceMethod)awaitUnsafeOnCompletedMethods[j]).GenericArguments[0]); + targetMethod.Body.Variables.Add(localTaskAwaiter); + var localAsync = new VariableDefinition(awaitUnsafeOnCompletedMethods[j].DeclaringType); + targetMethod.Body.Variables.Add(localAsync); + instructions.Add(Instruction.Create(OpCodes.Ldloca_S, localAsync)); + instructions.Add(Instruction.Create(OpCodes.Ldloca_S, localTaskAwaiter)); + instructions.Add(Instruction.Create(OpCodes.Ldloca_S, localBridge)); + instructions.Add(Instruction.Create(OpCodes.Call, makeGenericMethod(awaitUnsafeOnCompletedMethods[j].GetElementMethod(), ((GenericInstanceMethod)awaitUnsafeOnCompletedMethods[j]).GenericArguments[0], itfBridgeType))); + } + instructions.Add(Instruction.Create(OpCodes.Ret)); + itfBridgeType.Methods.Add(targetMethod); + } + + /// /// 获取一个方法的适配器 /// @@ -3187,6 +3219,7 @@ void redirectFieldRename() bool hasRedirect = false; ProcessMode mode; GenerateConfigure configure; + List awaitUnsafeOnCompletedMethods = new List(); public ProcessResult Process(AssemblyDefinition assembly, AssemblyDefinition ilfixAassembly, GenerateConfigure configure, ProcessMode mode) @@ -3242,7 +3275,11 @@ from method in type.Methods if (mode == ProcessMode.Inject) { redirectFieldRename(); - } + if (awaitUnsafeOnCompletedMethods.Count != 0) + { + EmitRefAwaitUnsafeOnCompletedMethod(); + } + } return ProcessResult.OK; } From 78a2947bc267bb83363bc5be7627b2f61649d281 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Tue, 22 Sep 2020 10:44:07 +0800 Subject: [PATCH 068/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E8=A1=A5=E4=B8=81?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E9=87=8C=E9=80=9A=E8=BF=87base=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E7=88=B6=E7=B1=BB=E5=87=BD=E6=95=B0=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#231)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 4915425..e0dd082 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1591,7 +1591,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, callingBaseMethod = true; break; } - baseType = baseType.Resolve().BaseType; + baseType = baseType.Resolve().BaseType.Resolve(); } } catch { } From 8118412fc9b543ffbf2f72f2eb4068e50e387a24 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 29 Sep 2020 16:57:08 +0800 Subject: [PATCH 069/103] fix https://github.com/Tencent/InjectFix/issues/236 --- Source/VSProj/Src/Tools/CodeTranslator.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index e0dd082..e2002fb 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -266,9 +266,9 @@ int addExternMethod(MethodReference callee, MethodDefinition caller) if (callee.Name == "AwaitUnsafeOnCompleted") { - if (!awaitUnsafeOnCompletedMethods.Any(m => ((GenericInstanceMethod)callee).GenericArguments[0] == ((GenericInstanceMethod)m).GenericArguments[0])) - { - awaitUnsafeOnCompletedMethods.Add(callee); + if (!awaitUnsafeOnCompletedMethods.Any(m => ((GenericInstanceMethod)callee).GenericArguments[0] == ((GenericInstanceMethod)m).GenericArguments[0])) + { + awaitUnsafeOnCompletedMethods.Add(callee); } } @@ -2179,7 +2179,7 @@ void EmitRefAwaitUnsafeOnCompletedMethod() var localBridge = new VariableDefinition(itfBridgeType); targetMethod.Body.Variables.Add(localBridge); for (int j = 0;j < awaitUnsafeOnCompletedMethods.Count;j++) - { + { var localTaskAwaiter = new VariableDefinition(((GenericInstanceMethod)awaitUnsafeOnCompletedMethods[j]).GenericArguments[0]); targetMethod.Body.Variables.Add(localTaskAwaiter); var localAsync = new VariableDefinition(awaitUnsafeOnCompletedMethods[j].DeclaringType); @@ -2606,6 +2606,7 @@ TypeReference tryGetUnderlyingType(TypeReference type) { try { + if (type.IsArray) return type; TypeDefinition typeDefinition = type.Resolve(); if (typeDefinition.IsEnum) { From c1dbe4b2f6287050d2ce4df2338e0fbb072f8c4d Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 28 Oct 2020 19:15:28 +0800 Subject: [PATCH 070/103] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index 2c19b90..dc2e79b 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -99,7 +99,7 @@ public class NewClass ​ 该标签只能用在类上,在童鞋们程序的某个地方,写上一个静态类,里面有一个静态字段,值就是interface和delegate的类型集合 - !!注意,该类不能放到Editor目录 + !!注意,该配置类不能放到Editor目录,且不能内嵌到另外一个类里头。 ##### 举例 From 71b63bd60263851320b50bc8af2fd0128f4d2a65 Mon Sep 17 00:00:00 2001 From: annayxguo <63293951+annayxguo@users.noreply.github.com> Date: Thu, 29 Oct 2020 10:40:46 +0800 Subject: [PATCH 071/103] =?UTF-8?q?=E6=B3=A8=E5=85=A5=E6=97=B6=E8=BF=87?= =?UTF-8?q?=E6=BB=A4=E6=8E=89=E8=BF=94=E5=9B=9E=E7=B1=BB=E5=9E=8B=E6=98=AF?= =?UTF-8?q?ref=20readonly=20fix=20https://github.com/Tencent/InjectFix/iss?= =?UTF-8?q?ues/243=20(#247)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index e2002fb..e573b8f 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3247,7 +3247,7 @@ public ProcessResult Process(AssemblyDefinition assembly, AssemblyDefinition ilf from type in allTypes where !(isCompilerGenerated(type) || isNewClass(type)) && !type.HasGenericParameters from method in type.Methods - where !method.IsConstructor && !isCompilerGenerated(method) && !method.HasGenericParameters + where !method.IsConstructor && !isCompilerGenerated(method) && !method.HasGenericParameters && !method.ReturnType.IsRequiredModifier select method)) { int flag; From 8bf73a7b00b3f4c4d16fd3b9ec05cdf4c0d60ba7 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 10 Nov 2020 15:54:37 +0800 Subject: [PATCH 072/103] =?UTF-8?q?=E4=B8=B0=E5=AF=8C=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E4=BF=A1=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index e2002fb..7de5f54 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -165,7 +165,7 @@ int addExternType(TypeReference type, TypeReference contextType = null) if (type.IsRequiredModifier) return addExternType((type as RequiredModifierType).ElementType, contextType); if (type.IsGenericParameter || type.HasGenericArgumentFromMethod()) { - throw new InvalidProgramException("try to use a generic type definition"); + throw new InvalidProgramException("try to use a generic type definition: " + type); } if (externTypeToId.ContainsKey(type)) { From 3084863419bc30a23201189432d2879c09c362a8 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 17 Nov 2020 11:35:06 +0800 Subject: [PATCH 073/103] =?UTF-8?q?=E6=9C=AA=E9=85=8D=E7=BD=AECustomBridge?= =?UTF-8?q?=E6=9C=89=E6=9B=B4=E5=8F=8B=E5=A5=BD=E7=9A=84=E6=8F=90=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index 7d9bf7f..13ab5f6 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -258,6 +258,10 @@ static int[] readSlotInfo(BinaryReader reader, Dictionary itfMe | BindingFlags.Instance)) { int methodId = reader.ReadInt32(); + if (!itfMethodToId.ContainsKey(method)) + { + throw new Exception("can not find slot for " + method + " of " + itf); + } slots[itfMethodToId[method]] = methodId; //VirtualMachine._Info(string.Format("<<< {0} [{1}]", method, methodId)); } From eec682870e8d3705f8b3196fa3d75aa3baeb2908 Mon Sep 17 00:00:00 2001 From: johnche Date: Tue, 17 Nov 2020 14:45:01 +0800 Subject: [PATCH 074/103] =?UTF-8?q?nullable=E6=9C=AC=E8=BA=AB=E6=98=AF?= =?UTF-8?q?=E5=80=BC=E7=B1=BB=E5=9E=8B=EF=BC=8C=E4=BD=86=E5=A6=82=E6=9E=9C?= =?UTF-8?q?=E6=B2=A1=E6=9C=89=E5=80=BC=E6=97=B6boxing=E5=90=8E=E4=BC=9A?= =?UTF-8?q?=E4=B8=BAnull=EF=BC=8C=E5=9C=A8clone=E6=97=B6=E5=BA=94=E8=AF=A5?= =?UTF-8?q?=E7=89=B9=E6=AE=8A=E5=A4=84=E7=90=86=EF=BC=8Cfix=20https://gith?= =?UTF-8?q?ub.com/Tencent/InjectFix/issues/210?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index f789389..67e5cc0 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -211,7 +211,8 @@ void store(Value* stackBase, Value* dst, Value* src, object[] managedStack) *dst = *src; if (dst->Type >= ValueType.Object) { - var obj = (dst->Type == ValueType.ValueType) ? objectClone.Clone(managedStack[src->Value1]) + 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; @@ -230,7 +231,9 @@ void copy(Value* stackBase, Value* dst, Value* src, object[] managedStack) *dst = *src; if (dst->Type == ValueType.ValueType) { - var obj = objectClone.Clone(managedStack[src->Value1]); + 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; } From f833bdb9743240f80accf615d41e2eedddcf6cb5 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 4 Dec 2020 10:36:46 +0800 Subject: [PATCH 075/103] =?UTF-8?q?=E6=8D=A2=E8=A1=8C=E7=AC=A6=E8=BD=AC?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs | 6 +++--- Source/VSProj/Src/Core/VirtualMachine.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index 13ab5f6..cad1342 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -258,9 +258,9 @@ static int[] readSlotInfo(BinaryReader reader, Dictionary itfMe | BindingFlags.Instance)) { int methodId = reader.ReadInt32(); - if (!itfMethodToId.ContainsKey(method)) - { - throw new Exception("can not find slot for " + method + " of " + itf); + if (!itfMethodToId.ContainsKey(method)) + { + throw new Exception("can not find slot for " + method + " of " + itf); } slots[itfMethodToId[method]] = methodId; //VirtualMachine._Info(string.Format("<<< {0} [{1}]", method, methodId)); diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 67e5cc0..900a379 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -231,8 +231,8 @@ 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后可能为空 + 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; From 59b09484c31446b301127f23121528fadae9f497 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 4 Dec 2020 10:39:52 +0800 Subject: [PATCH 076/103] =?UTF-8?q?base=E8=B0=83=E7=94=A8=E4=B8=8D?= =?UTF-8?q?=E4=B8=80=E5=AE=9A=E4=BC=9A=E6=9C=AC=E7=B1=BB=E7=88=B6=E7=B1=BB?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E8=B0=83=E7=94=A8=EF=BC=8C=E6=AF=94=E5=A6=82?= =?UTF-8?q?=E8=BF=AD=E4=BB=A3=E5=99=A8=E8=AF=AD=E6=B3=95=E7=B3=96=E9=87=8C?= =?UTF-8?q?=E5=A4=B4=EF=BC=8C=E5=9C=A8=E8=BF=AD=E4=BB=A3=E5=99=A8=E7=9A=84?= =?UTF-8?q?base=E8=B0=83=E7=94=A8=EF=BC=8C=E4=BC=9A=E5=87=BA=E7=8E=B0?= =?UTF-8?q?=E5=9C=A8=E7=BC=96=E8=AF=91=E5=99=A8=E7=94=9F=E6=88=90=E7=B1=BB?= =?UTF-8?q?=E9=87=8C=E5=A4=B4=EF=BC=8Cfix=20https://github.com/Tencent/Inj?= =?UTF-8?q?ectFix/issues/260?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 27 +++++------------------ 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 8aee877..dd6bfd9 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -755,6 +755,8 @@ MethodReference findBase(TypeDefinition type, MethodDefinition method) const string BASE_RPOXY_PERFIX = "<>iFixBaseProxy_"; + Dictionary baseProxys = new Dictionary(); + //方案2 //var method = typeof(object).GetMethod("ToString"); //var ftn = method.MethodHandle.GetFunctionPointer(); @@ -766,7 +768,8 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) { if (!isNewClass(type)) { - var proxyMethod = new MethodDefinition(BASE_RPOXY_PERFIX + method.Name, MethodAttributes.Private, + if (baseProxys.ContainsKey(mbase)) return baseProxys[mbase]; + var proxyMethod = new MethodDefinition(BASE_RPOXY_PERFIX + method.Name, MethodAttributes.Public, method.ReturnType); for (int i = 0; i < method.Parameters.Count; i++) { @@ -788,6 +791,7 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) instructions.Add(Instruction.Create(OpCodes.Call, mbase)); instructions.Add(Instruction.Create(OpCodes.Ret)); type.Methods.Add(proxyMethod); + baseProxys.Add(mbase, proxyMethod); return proxyMethod; } else if(isNewClass(type) && !isNewClass(type.BaseType as TypeDefinition)) @@ -1578,26 +1582,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, var methodIdInfo = getMethodId(methodToCall, method, msIl.OpCode.Code == Code.Callvirt, or != null || directCallVirtual, injectTypePassToNext); - bool callingBaseMethod = false; - - try - { - var callingType = methodToCall.DeclaringType.Resolve(); - TypeReference baseType = method.DeclaringType.BaseType.Resolve(); - while (baseType != null) - { - if (callingType.IsSameType(baseType)) - { - callingBaseMethod = true; - break; - } - baseType = baseType.Resolve().BaseType.Resolve(); - } - } - catch { } - - if (callingBaseMethod && msIl.OpCode.Code == Code.Call && baseProxy != null - && isTheSameDeclare(methodToCall, method)) + if (msIl.OpCode.Code == Code.Call && baseProxys.TryGetValue(methodToCall, out baseProxy)) { code.Add(new Core.Instruction { From 1d0db7abca772c0355a2dc3ee16cd4b2b7d9045e Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 7 Dec 2020 11:55:49 +0800 Subject: [PATCH 077/103] =?UTF-8?q?=E5=A4=9A=E4=B8=AA=E5=AD=90=E7=B1=BB?= =?UTF-8?q?=EF=BC=8C=E5=8F=AA=E5=AF=B9=E8=99=9A=E6=96=B9=E6=B3=95=E7=94=9F?= =?UTF-8?q?=E6=88=90=E4=B8=80=E4=B8=AAproxy=E7=9A=84=E8=AF=9D=EF=BC=8C?= =?UTF-8?q?=E5=90=8E=E7=BB=AD=E8=A1=A5=E4=B8=81=E6=97=B6=E4=B8=8D=E7=9F=A5?= =?UTF-8?q?=E9=81=93=E4=B9=8B=E5=89=8D=E7=94=9F=E6=88=90=E7=9A=84=E6=98=AF?= =?UTF-8?q?=E9=82=A3=E4=B8=AA=E7=B1=BB=E7=9A=84proxy=EF=BC=8C=E5=8F=AF?= =?UTF-8?q?=E8=83=BD=E4=BC=9A=E8=B0=83=E7=94=A8=E5=A4=B1=E8=B4=A5=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 38 ++++++++++++++++++++--- 1 file changed, 33 insertions(+), 5 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index dd6bfd9..eb5abff 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -755,7 +755,7 @@ MethodReference findBase(TypeDefinition type, MethodDefinition method) const string BASE_RPOXY_PERFIX = "<>iFixBaseProxy_"; - Dictionary baseProxys = new Dictionary(); + Dictionary> baseProxys = new Dictionary>(); //方案2 //var method = typeof(object).GetMethod("ToString"); @@ -768,7 +768,6 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) { if (!isNewClass(type)) { - if (baseProxys.ContainsKey(mbase)) return baseProxys[mbase]; var proxyMethod = new MethodDefinition(BASE_RPOXY_PERFIX + method.Name, MethodAttributes.Public, method.ReturnType); for (int i = 0; i < method.Parameters.Count; i++) @@ -791,7 +790,15 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) instructions.Add(Instruction.Create(OpCodes.Call, mbase)); instructions.Add(Instruction.Create(OpCodes.Ret)); type.Methods.Add(proxyMethod); - baseProxys.Add(mbase, proxyMethod); + + Dictionary typeToProxy; + if (!baseProxys.TryGetValue(mbase, out typeToProxy)) + { + typeToProxy = new Dictionary(); + baseProxys.Add(mbase, typeToProxy); + } + Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + mbase + ">>>>>>>>>>>>>>>>>>>" + type); + typeToProxy.Add(type, proxyMethod); return proxyMethod; } else if(isNewClass(type) && !isNewClass(type.BaseType as TypeDefinition)) @@ -802,6 +809,25 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) return null; } + MethodReference findProxy(TypeDefinition type, MethodReference methodToCall) + { + Dictionary typeToProxy; + if (baseProxys.TryGetValue(methodToCall, out typeToProxy)) + { + TypeDefinition ptype = type; + while (ptype != null) + { + if (typeToProxy.ContainsKey(ptype)) + { + return typeToProxy[ptype]; + } + ptype = ptype.DeclaringType; + } + } + return null; + + } + enum CallType { Extern, @@ -1112,7 +1138,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, return new MethodIdInfo() { Id = 0, Type = CallType.Invalid }; } - var baseProxy = tryAddBaseProxy(method.DeclaringType, method); + tryAddBaseProxy(method.DeclaringType, method); var body = method.Body; var msIls = body.Instructions; var ilOffset = new Dictionary(); @@ -1582,8 +1608,10 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, var methodIdInfo = getMethodId(methodToCall, method, msIl.OpCode.Code == Code.Callvirt, or != null || directCallVirtual, injectTypePassToNext); - if (msIl.OpCode.Code == Code.Call && baseProxys.TryGetValue(methodToCall, out baseProxy)) + if (msIl.OpCode.Code == Code.Call && baseProxys.ContainsKey(methodToCall)) { + var baseProxy = findProxy(method.DeclaringType, methodToCall); + if (baseProxy == null) throw new Exception("can not find the proxy for " + methodToCall + ", in " + method.DeclaringType); code.Add(new Core.Instruction { Code = Core.Code.CallExtern, From ca5ca337e6dc92d6b639b739c7cd49c55d9c691c Mon Sep 17 00:00:00 2001 From: johnche Date: Mon, 7 Dec 2020 11:56:38 +0800 Subject: [PATCH 078/103] =?UTF-8?q?=E4=B8=8A=E4=B8=AA=E6=8F=90=E4=BA=A4?= =?UTF-8?q?=E7=9A=84=E6=97=A5=E5=BF=97=E5=BF=98=E4=BA=86=E5=8E=BB=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index eb5abff..8ca80a5 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -797,7 +797,6 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) typeToProxy = new Dictionary(); baseProxys.Add(mbase, typeToProxy); } - Console.WriteLine(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>" + mbase + ">>>>>>>>>>>>>>>>>>>" + type); typeToProxy.Add(type, proxyMethod); return proxyMethod; } From b29ac8a2fad969ed21a7115c39767d16bc05d756 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 20 Jan 2021 18:11:41 +0800 Subject: [PATCH 079/103] fix https://github.com/Tencent/InjectFix/issues/275 --- Source/VSProj/Src/Core/VirtualMachine.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 900a379..2f73f43 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -2350,6 +2350,12 @@ AnonymousStorey anonyObj //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; } From 9f191818347a69d9017a2f67aa33dbb0f315fb9d Mon Sep 17 00:00:00 2001 From: San Lau Date: Thu, 4 Feb 2021 14:46:57 +0800 Subject: [PATCH 080/103] fixed build_for_unity.sh for MacOS (#266) --- Source/VSProj/build_for_unity.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Source/VSProj/build_for_unity.sh b/Source/VSProj/build_for_unity.sh index bed5f41..1938cfb 100755 --- a/Source/VSProj/build_for_unity.sh +++ b/Source/VSProj/build_for_unity.sh @@ -1,6 +1,9 @@ #!/usr/bin/env sh UNITY_HOME="/Applications/Unity2017/Unity.app" GMCS="$UNITY_HOME/Contents/Mono/bin/gmcs" +if [ ! -d $GMCS ]; then + GMCS="$UNITY_HOME/Contents/MonoBleedingEdge/bin/mcs" +fi MONO="$UNITY_HOME/Contents/MonoBleedingEdge/bin/mono" DLL_OUTPUT="../UnityProj/Assets/Plugins/IFix.Core.dll" TOOL_KIT_PATH="../UnityProj/IFixToolKit" From 4c7b70ea06690bbfbca5ef93901b0b44d8b650df Mon Sep 17 00:00:00 2001 From: Mercury <9930422+mercurylu@users.noreply.github.com> Date: Fri, 5 Feb 2021 11:04:45 +0800 Subject: [PATCH 081/103] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AD=97=E6=AE=B5?= =?UTF-8?q?=E6=94=AF=E6=8C=81,=E4=BB=A5=E5=8F=8A=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E7=9A=84=E7=B1=BB=E5=9E=8B=E8=BD=AC=E6=8D=A2?= =?UTF-8?q?=E6=94=AF=E6=8C=81=20(#277)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 新增字段支持 * 新增类型支持Castclass,Isinst,Box,Unbox Co-authored-by: mercurylu --- .../UnityProj/Assets/IFix/Editor/Configure.cs | 27 + .../Assets/IFix/Editor/ILFixEditor.cs | 36 + .../Src/Builder/FileVirtualMachineBuilder.cs | 42 +- Source/VSProj/Src/Core/StackOperation.cs | 89 ++- Source/VSProj/Src/Core/SwitchFlags.cs | 2 +- Source/VSProj/Src/Core/VirtualMachine.cs | 615 ++++++++++++++---- Source/VSProj/Src/Tools/CodeTranslator.cs | 160 ++++- Source/VSProj/Src/Tools/GenerateConfigure.cs | 209 +++++- 8 files changed, 1021 insertions(+), 159 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/Configure.cs b/Source/UnityProj/Assets/IFix/Editor/Configure.cs index 85bd117..5c6190a 100644 --- a/Source/UnityProj/Assets/IFix/Editor/Configure.cs +++ b/Source/UnityProj/Assets/IFix/Editor/Configure.cs @@ -121,6 +121,33 @@ from method in type.GetMethods(BindingFlags.Instance | BindingFlags.Static | Bin where method.IsDefined(tagType, false) select method); } + + public static IEnumerable GetTagFields(Type tagType, string searchAssembly) + { + return (from assembly in AppDomain.CurrentDomain.GetAssemblies() + where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder) + && (assembly.GetName().Name == searchAssembly) + where assembly.CodeBase.IndexOf("ScriptAssemblies") != -1 + from type in assembly.GetTypes() + from field in type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public + | BindingFlags.NonPublic) + where field.IsDefined(tagType, false) + select field); + } + + public static IEnumerable GetTagProperties(Type tagType, string searchAssembly) + { + return (from assembly in AppDomain.CurrentDomain.GetAssemblies() + where !(assembly.ManifestModule is System.Reflection.Emit.ModuleBuilder) + && (assembly.GetName().Name == searchAssembly) + where assembly.CodeBase.IndexOf("ScriptAssemblies") != -1 + from type in assembly.GetTypes() + from property in type.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public + | BindingFlags.NonPublic) + where property.IsDefined(tagType, false) + select property); + } + public static IEnumerable GetTagClasses(Type tagType, string searchAssembly) { return (from assembly in AppDomain.CurrentDomain.GetAssemblies() diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 2e7914b..adf0bd5 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -705,6 +705,38 @@ static void writeMethods(BinaryWriter writer, List methods) } } + static void writeFields(BinaryWriter writer, List fields) + { + var fieldGroups = fields.GroupBy(m => m.DeclaringType).ToList(); + writer.Write(fieldGroups.Count); + foreach (var fieldGroup in fieldGroups) + { + writer.Write(GetCecilTypeName(fieldGroup.Key)); + writer.Write(fieldGroup.Count()); + foreach (var field in fieldGroup) + { + writer.Write(field.Name); + writer.Write(GetCecilTypeName(field.FieldType)); + } + } + } + + static void writeProperties(BinaryWriter writer, List properties) + { + var PropertyGroups = properties.GroupBy(m => m.DeclaringType).ToList(); + writer.Write(PropertyGroups.Count); + foreach (var PropertyGroup in PropertyGroups) + { + writer.Write(GetCecilTypeName(PropertyGroup.Key)); + writer.Write(PropertyGroup.Count()); + foreach (var Property in PropertyGroup) + { + writer.Write(Property.Name); + writer.Write(GetCecilTypeName(Property.PropertyType)); + } + } + } + static void writeClasses(BinaryWriter writer, List classes) { writer.Write(classes.Count); @@ -774,6 +806,8 @@ public static void GenPatch(string assembly, string assemblyCSharpPath } var newMethods = Configure.GetTagMethods(typeof(InterpretAttribute), assembly).ToList(); + var newFields = Configure.GetTagFields(typeof(InterpretAttribute), assembly).ToList(); + var newProperties = Configure.GetTagProperties(typeof(InterpretAttribute), assembly).ToList(); var newClasses = Configure.GetTagClasses(typeof(InterpretAttribute), assembly).ToList(); genericMethod = newMethods.FirstOrDefault(m => hasGenericParameter(m)); if (genericMethod != null) @@ -788,6 +822,8 @@ public static void GenPatch(string assembly, string assemblyCSharpPath { writeMethods(writer, patchMethods); writeMethods(writer, newMethods); + writeFields(writer, newFields); + writeProperties(writer, newProperties); writeClasses(writer, newClasses); } diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index cad1342..eb1177c 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -279,6 +279,7 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) Type[] externTypes; MethodBase[] externMethods; List exceptionHandlers = new List(); + Dictionary newFieldInfo = new Dictionary(); string[] internStrings; FieldInfo[] fieldInfos; Type[] staticFieldTypes; @@ -375,13 +376,45 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) fieldInfos = new FieldInfo[reader.ReadInt32()]; for (int i = 0; i < fieldInfos.Length; i++) { - var type = externTypes[reader.ReadInt32()]; + var isNewField = reader.ReadBoolean(); + var declaringType = externTypes[reader.ReadInt32()]; var fieldName = reader.ReadString(); - fieldInfos[i] = type.GetField(fieldName, + + fieldInfos[i] = declaringType.GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static); - if (fieldInfos[i] == null) + + if(!isNewField) + { + if(fieldInfos[i] == null) + { + throw new Exception("can not load field [" + fieldName + "] " + " of " + declaringType); + } + } + else { - throw new Exception("can not load field [" + fieldName + "] of " + type); + var fieldType = externTypes[reader.ReadInt32()]; + var methodId = reader.ReadInt32(); + + if(fieldInfos[i] == null) + { + newFieldInfo.Add(i, new NewFieldInfo{ + Name = fieldName, + FieldType = fieldType, + DeclaringType = declaringType, + MethodId = methodId, + }); + } + else + { + if(fieldInfos[i].FieldType != fieldType) + { + throw new Exception("can not change existing field [" + declaringType + "." + fieldName + "]'s type " + " from " + fieldInfos[i].FieldType + " to " + fieldType); + } + else + { + throw new Exception(declaringType + "." + fieldName + " is expected to be a new field , but it already exists "); + } + } } } @@ -459,6 +492,7 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) ExceptionHandlers = exceptionHandlers.ToArray(), InternStrings = internStrings, FieldInfos = fieldInfos, + NewFieldInfos = newFieldInfo, AnonymousStoreyInfos = anonymousStoreyInfos, StaticFieldTypes = staticFieldTypes, Cctors = cctors diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index 74f1b9e..d0518ef 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -11,6 +11,7 @@ namespace IFix.Core using System.Reflection; using System.Runtime.InteropServices; using System.Threading; + using System.Collections.Generic; [StructLayout(LayoutKind.Sequential)] unsafe struct UnmanagedStack @@ -166,7 +167,7 @@ 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) + internal static object mGet(bool isArray, object root, int layer, int[] fieldIdList, FieldInfo[] fieldInfos, Dictionary newFieldInfos) { //Console.WriteLine("mGet " + root); var fieldId = fieldIdList[layer]; @@ -179,21 +180,33 @@ internal static object mGet(bool isArray, object root, int layer, int[] fieldIdL else { var fieldInfo = fieldInfos[fieldId]; + + if(fieldInfo == null) + { + return newFieldInfos[fieldId].GetValue(root); + } + return fieldInfo.GetValue(root); } } else { var fieldInfo = fieldInfos[fieldId]; + + if(fieldInfo == null) + { + 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)); + var ret = fieldInfo.GetValue(mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos)); //VirtualMachine._Info("after --- " + fieldInfo); return ret; } } internal static void mSet(bool isArray, object root, object val, int layer, int[] fieldIdList, - FieldInfo[] fieldInfos) + FieldInfo[] fieldInfos, Dictionary newFieldInfos) { var fieldId = fieldIdList[layer]; if (layer == 0) @@ -205,22 +218,37 @@ internal static void mSet(bool isArray, object root, object val, int layer, int[ else { var fieldInfo = fieldInfos[fieldId]; - //VirtualMachine._Info("set1 " + val.GetType() + " to " + fieldInfo + " of " + root.GetType() - // + ", root.hc = " + root.GetHashCode()); - fieldInfo.SetValue(root, val); + + if(fieldInfo == null) + { + newFieldInfos[fieldId].SetValue(root, val); + } + else + { + //VirtualMachine._Info("set1 " + val.GetType() + " to " + fieldInfo + " of " + root.GetType() + // + ", root.hc = " + root.GetHashCode()); + fieldInfo.SetValue(root, val); + } } } else { var fieldInfo = fieldInfos[fieldId]; //VirtualMachine._Info("before get " + fieldInfo); - var parent = mGet(isArray, root, layer - 1, fieldIdList, fieldInfos); + var parent = mGet(isArray, root, layer - 1, fieldIdList, fieldInfos, newFieldInfos); //VirtualMachine._Info("after get " + fieldInfo); //VirtualMachine._Info("before set " + fieldInfo); - fieldInfo.SetValue(parent, val); + if(fieldInfo == null) + { + newFieldInfos[fieldId].SetValue(parent, val); + } + else + { + fieldInfo.SetValue(parent, val); + } //VirtualMachine._Info("set2 " + val.GetType() + " to " + fieldInfo + " of " + parent.GetType()); //VirtualMachine._Info("after set " + fieldInfo); - mSet(isArray, root, parent, layer - 1, fieldIdList, fieldInfos); + mSet(isArray, root, parent, layer - 1, fieldIdList, fieldInfos, newFieldInfos); } } @@ -335,7 +363,7 @@ internal static unsafe object ToObject(Value* evaluationStackBase, Value* evalua var fieldIdList = fieldAddr.FieldIdList; return mGet(evaluationStackPointer->Value2 != -1, fieldAddr.Object, fieldIdList.Length - 1, - fieldIdList, virtualMachine.fieldInfos); + fieldIdList, virtualMachine.fieldInfos, virtualMachine.newFieldInfos); } else { @@ -343,6 +371,11 @@ internal static unsafe object ToObject(Value* evaluationStackBase, Value* evalua { 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 @@ -362,6 +395,12 @@ internal static unsafe object ToObject(Value* evaluationStackBase, Value* evalua if (fieldIndex >= 0) { 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 @@ -439,7 +478,7 @@ public static void UpdateReference(Value* evaluationStackBase, Value* evaluation //} mSet(evaluationStackPointer->Value2 != -1, fieldAddr.Object, obj, fieldIdList.Length - 1, - fieldIdList, virtualMachine.fieldInfos); + fieldIdList, virtualMachine.fieldInfos, virtualMachine.newFieldInfos); } else { @@ -448,12 +487,19 @@ public static void UpdateReference(Value* evaluationStackBase, Value* evaluation var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value2]; - //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); + 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); + } } else { @@ -470,7 +516,14 @@ public static void UpdateReference(Value* evaluationStackBase, Value* evaluation if (fieldIndex >= 0) { var fieldInfo = virtualMachine.fieldInfos[evaluationStackPointer->Value1]; - fieldInfo.SetValue(null, obj); + if(fieldInfo == null) + { + virtualMachine.newFieldInfos[evaluationStackPointer->Value1].SetValue(null, obj);; + } + else + { + fieldInfo.SetValue(null, obj); + } } else { diff --git a/Source/VSProj/Src/Core/SwitchFlags.cs b/Source/VSProj/Src/Core/SwitchFlags.cs index 7f573ee..b93d1a2 100644 --- a/Source/VSProj/Src/Core/SwitchFlags.cs +++ b/Source/VSProj/Src/Core/SwitchFlags.cs @@ -10,7 +10,7 @@ namespace IFix { //切换到解析执行 - [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct)] + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Field)] public class InterpretAttribute : Attribute { } diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 2f73f43..9cd9e8e 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -12,6 +12,7 @@ namespace IFix.Core using System.Collections.Generic; using System.Reflection; using System.IO; + using System.Linq; class RuntimeException : Exception { @@ -26,6 +27,162 @@ internal class FieldAddr public int[] FieldIdList; } + public class Cleanner + { + private static bool start = false; + + public static void Start() + { + start = true; + new Cleanner(); + } + + public static void Stop() + { + start = false; + } + + ~Cleanner() + { + if(start) + { + NewFieldInfo.Sweep(); + Start(); + } + } + } + + public class NewFieldInfo + { + public string Name; + public Type DeclaringType; + public Type FieldType; + public int MethodId; + + static readonly int staticObjectKey = 0; + + static readonly Dictionary> newFieldValues = new Dictionary>(); + + static readonly Dictionary objList = new Dictionary(); + + private object SetDefaultValue(object obj) + { + if(FieldType.IsValueType) + { + var ret = Activator.CreateInstance(FieldType); + SetValue(obj, ret); + return ret; + } + else + { + SetValue(obj, null); + return null; + } + } + + public static void Sweep() + { + foreach (var item in objList.ToList()) + { + if(!item.Value.IsAlive) + { + newFieldValues.Remove(item.Key); + objList.Remove(item.Key); + } + } + } + + public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) + { + if( MethodId >= 0 && !HasInitialize(obj) ) + { + Call call = Call.Begin(); + + try + { + virtualMachine.Execute(MethodId, ref call, 0, 0); + SetValue(obj, call.GetObject()); + } + catch(Exception e) + { + VirtualMachine._Info(e.ToString()); + } + } + } + + public int ObjectToIndex(object obj) + { + if(obj == null) + { + return staticObjectKey; + } + + return obj.GetHashCode(); + } + + public bool HasInitialize(object obj) + { + var index = ObjectToIndex(obj); + + if(!newFieldValues.ContainsKey(index)) + { + return false; + } + + Dictionary fieldValues = null; + newFieldValues.TryGetValue(index, out fieldValues); + if(!fieldValues.ContainsKey(Name)) + { + return false; + } + + return true; + } + + public object GetValue(object obj) + { + var index = ObjectToIndex(obj); + + Dictionary fieldValues = null; + newFieldValues.TryGetValue(index, out fieldValues); + if(fieldValues != null) + { + object val = null; + if(!fieldValues.TryGetValue(Name, out val)) + { + return SetDefaultValue(obj); + } + + return val; + } + else + { + return SetDefaultValue(obj); + } + } + + public void SetValue(object obj, object value) + { + var index = ObjectToIndex(obj); + + if(!newFieldValues.ContainsKey(index)) + { + newFieldValues.Add(index, new Dictionary()); + + 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 { Instruction tellUnity4IncludeInstructionFisrt; @@ -50,6 +207,8 @@ unsafe public class VirtualMachine internal FieldInfo[] fieldInfos; + internal Dictionary newFieldInfos; + AnonymousStoreyInfo[] anonymousStoreyInfos; Dictionary> overrideCache @@ -124,6 +283,18 @@ public FieldInfo[] FieldInfos } } + public Dictionary NewFieldInfos + { + get + { + return newFieldInfos; + } + set + { + newFieldInfos = value; + } + } + public AnonymousStoreyInfo[] AnonymousStoreyInfos { get @@ -177,6 +348,8 @@ internal VirtualMachine(Instruction** unmanaged_codes, Action on_dispose) { unmanagedCodes = unmanaged_codes; onDispose = on_dispose; + + Cleanner.Start(); } ~VirtualMachine() @@ -857,21 +1030,50 @@ public static void _Info(string a) { 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, fieldInfo.DeclaringType, this, false); + managedStack, declaringType, this, false); if (obj == null) { - throw new NullReferenceException(); + throw new NullReferenceException(declaringType + "." + fieldName); } //_Info("Ldfld:" + fieldInfo + ",obj=" + obj.GetType()); - var fieldValue = fieldInfo.GetValue(obj); + object fieldValue = null; + + if(fieldInfo == null) + { + newFieldInfos[fieldIndex].CheckInit(this, obj); + + fieldValue = newFieldInfos[fieldIndex].GetValue(obj); + } + else + { + fieldValue = fieldInfo.GetValue(obj); + } + //_Info("fieldValue:" + fieldValue); //throw new Exception("fieldValue=" + fieldValue); EvaluationStackOperation.PushObject(evaluationStackBase, ptr, managedStack, - fieldValue, fieldInfo.FieldType); + fieldValue, fieldType); } else { @@ -921,25 +1123,51 @@ public static void _Info(string a) { 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; + } + object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, fieldInfo.DeclaringType, this, false); + managedStack, declaringType, this, false); if (obj == null) { - throw new NullReferenceException(); + throw new NullReferenceException(declaringType + "." + fieldName); + } + + 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)); } - fieldInfo.SetValue(obj, EvaluationStackOperation.ToObject(evaluationStackBase, - evaluationStackPointer - 1, managedStack, fieldInfo.FieldType, this)); //如果field,array元素是值类型,需要重新update回去 if ((ptr->Type == ValueType.FieldReference || ptr->Type == ValueType.ChainFieldReference || ptr->Type == ValueType.StaticFieldReference || ptr->Type == ValueType.ArrayReference) - && fieldInfo.DeclaringType.IsValueType) + && declaringType.IsValueType) { EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, - managedStack, obj, this, fieldInfo.DeclaringType); + managedStack, obj, this, declaringType); } managedStack[ptr - evaluationStackBase] = null; managedStack[evaluationStackPointer - 1 - evaluationStackBase] = null; @@ -1044,13 +1272,25 @@ public static void _Info(string a) if (fieldIndex >= 0) { var fieldInfo = fieldInfos[fieldIndex]; + Type fieldType = null; + + object fieldValue = null; + if (fieldInfo == null) { - throwRuntimeException(new InvalidProgramException(), true); + newFieldInfos[fieldIndex].CheckInit(this, null); + + fieldType = newFieldInfos[fieldIndex].FieldType; + fieldValue = newFieldInfos[fieldIndex].GetValue(null); + } + else + { + fieldType = fieldInfo.FieldType; + fieldValue = fieldInfo.GetValue(null); } - var fieldValue = fieldInfo.GetValue(null); + EvaluationStackOperation.PushObject(evaluationStackBase, evaluationStackPointer, - managedStack, fieldValue, fieldInfo.FieldType); + managedStack, fieldValue, fieldType); } else { @@ -1232,9 +1472,10 @@ public static void _Info(string a) case Code.Castclass: //0.358122% { var ptr = evaluationStackPointer - 1; - var type = externTypes[pc->Operand]; + var type = pc->Operand >= 0 ? externTypes[pc->Operand] : typeof(AnonymousStorey); var obj = managedStack[ptr->Value1]; - if (obj != null && !type.IsAssignableFrom(obj.GetType())) + bool canAssign = type.IsAssignableFrom(obj.GetType()); + if (obj != null && (!canAssign || (canAssign && pc->Operand < 0 && (obj as AnonymousStorey).typeId != -(pc->Operand+1) ))) { throw new InvalidCastException(type + " is not assignable from " + obj.GetType()); @@ -1276,71 +1517,74 @@ public static void _Info(string a) case Code.Box://0.3100877% { var ptr = evaluationStackPointer - 1; - var type = externTypes[pc->Operand]; - var pos = (int)(ptr - evaluationStackBase); - switch (ptr->Type) + if(pc->Operand >= 0) { - 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; + 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; } @@ -1348,13 +1592,21 @@ public static void _Info(string a) case Code.Isinst://0.3074192% { var ptr = evaluationStackPointer - 1; - var type = externTypes[pc->Operand]; + 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; - managedStack[pos] = (obj != null && type.IsAssignableFrom(obj.GetType())) + bool canAssign = type.IsAssignableFrom(obj.GetType()); + managedStack[pos] = (obj != null && canAssign) ? obj : null; + if(pc->Operand < 0 && canAssign) + { + if((obj as AnonymousStorey).typeId != -(pc->Operand + 1)) + { + managedStack[pos] = null; + } + } } break; case Code.Bge: //Bge_S:0.2954996% Bge:0.005870852% @@ -1507,13 +1759,28 @@ public static void _Info(string a) if (fieldIndex >= 0) { var fieldInfo = fieldInfos[fieldIndex]; + Type filedType = null; + if (fieldInfo == null) { - throwRuntimeException(new InvalidProgramException(), true); + filedType = newFieldInfos[fieldIndex].FieldType; + } + else + { + filedType = fieldInfo.FieldType; } - fieldInfo.SetValue(null, EvaluationStackOperation.ToObject(evaluationStackBase, - evaluationStackPointer - 1, managedStack, fieldInfo.FieldType, this)); + var value = EvaluationStackOperation.ToObject(evaluationStackBase, + evaluationStackPointer - 1, managedStack, filedType, this); + + if (fieldInfo == null) + { + newFieldInfos[fieldIndex].SetValue(null, value); + } + else + { + fieldInfo.SetValue(null, value); + } } else { @@ -1532,18 +1799,33 @@ public static void _Info(string a) case Code.Ldflda: //0.240527% { var fieldInfo = pc->Operand >= 0 ? fieldInfos[pc->Operand] : null; + + Type declaringType = null; + Type fieldType = null; var ptr = evaluationStackPointer - 1; + + if(fieldInfo == null) + { + 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) && fieldInfo != null - && fieldInfo.FieldType.IsValueType) - { - if (pc->Operand < 0) - { - throwRuntimeException(new NotSupportedException( - "chain ref for compiler generated object!"), true); - } + || ptr->Type == ValueType.ArrayReference) && pc->Operand >= 0 + && fieldType.IsValueType) + { + // 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 @@ -1581,14 +1863,14 @@ public static void _Info(string a) managedStack[offset] = fieldAddr; ptr->Value2 = ptr->Type == ValueType.FieldReference ? -1 : -2; } - ptr->Type = ValueType.ChainFieldReference; } else { object obj = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, - managedStack, fieldInfo == null ? typeof(AnonymousStorey) - : fieldInfo.DeclaringType, this, false); + managedStack, pc->Operand < 0 ? typeof(AnonymousStorey) + : declaringType, this, false); + ptr->Type = ValueType.FieldReference; ptr->Value1 = (int)(ptr - evaluationStackBase); managedStack[ptr->Value1] = obj; @@ -1771,12 +2053,29 @@ public static void _Info(string a) { var fieldAddr = managedStack[ptr - evaluationStackBase] as FieldAddr; var fieldIdList = fieldAddr.FieldIdList; - fieldType - = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + + if(fieldInfos[fieldIdList[fieldIdList.Length - 1]] == null) + { + fieldType + = newFieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + } + else + { + fieldType + = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + } + } else { - fieldType = fieldInfos[ptr->Value2].FieldType; + if(fieldInfos[ptr->Value2] == null) + { + fieldType = newFieldInfos[ptr->Value2].FieldType; + } + else + { + fieldType = fieldInfos[ptr->Value2].FieldType; + } } EvaluationStackOperation.UpdateReference(evaluationStackBase, ptr, managedStack, EvaluationStackOperation.ToObject(evaluationStackBase, @@ -1808,9 +2107,28 @@ public static void _Info(string a) if (fieldIndex >= 0) { var fieldInfo = fieldInfos[fieldIndex]; - fieldInfo.SetValue(null, - EvaluationStackOperation.ToObject(evaluationStackBase, src, - managedStack, fieldInfo.FieldType, this)); + Type fieldType = null; + + 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 { @@ -1851,7 +2169,7 @@ public static void _Info(string a) break; default: throwRuntimeException(new InvalidProgramException(code - + " expect ref, but got " + ptr->Type), true); + + " expect ref, but got " + ptr->Type + " value1:" + ptr->Value1 + " value2:" + ptr->Value2), true); break; } } @@ -1874,12 +2192,18 @@ public static void _Info(string a) { case ValueType.FieldReference: { - //_Info("ptr->Value2:" + ptr->Value2); var fieldIndex = ptr->Value2; if (fieldIndex >= 0) { Type fieldType = null; - fieldType = fieldInfos[fieldIndex].FieldType; + if(fieldInfos[fieldIndex] == null) + { + fieldType = newFieldInfos[fieldIndex].FieldType; + } + else + { + fieldType = fieldInfos[fieldIndex].FieldType; + } //var fieldInfo = fieldInfos[ptr->Value2]; var val = EvaluationStackOperation.ToObject(evaluationStackBase, ptr, @@ -1899,18 +2223,22 @@ AnonymousStorey anonyObj break; case ValueType.ChainFieldReference: { - //_Info("ptr->Value2:" + ptr->Value2); Type fieldType = null; var fieldAddr = managedStack[ptr - evaluationStackBase] as FieldAddr; var fieldIdList = fieldAddr.FieldIdList; - //_Info("fieldIdList:" + fieldIdList); - fieldType = fieldInfos[fieldIdList[fieldIdList.Length - 1]].FieldType; + 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); } @@ -1929,8 +2257,23 @@ AnonymousStorey anonyObj 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, fieldInfo.GetValue(null), fieldInfo.FieldType); + managedStack, value, fieldType); } else { @@ -1960,7 +2303,7 @@ AnonymousStorey anonyObj break; default: throwRuntimeException(new InvalidProgramException(code - + " expect ref, but got " + ptr->Type), true); + + " expect ref, but got " + ptr->Type + " value1:" + ptr->Value1 + " value2:" + ptr->Value2), true); break; } } @@ -2083,35 +2426,38 @@ AnonymousStorey anonyObj case Code.Unbox_Any://0.0848605% { var ptr = evaluationStackPointer - 1; - var type = externTypes[pc->Operand]; - //var pos = (int)(ptr - evaluationStackBase); - var obj = managedStack[ptr->Value1]; - if (ptr->Type == ValueType.Object) + if(pc->Operand >= 0) { - if (type.IsValueType) + var type = externTypes[pc->Operand]; + //var pos = (int)(ptr - evaluationStackBase); + var obj = managedStack[ptr->Value1]; + if (ptr->Type == ValueType.Object) { - if (obj == null) - { - throw new NullReferenceException(); - } - else if(type.IsPrimitive) + if (type.IsValueType) { - EvaluationStackOperation.UnboxPrimitive(ptr, obj, type); - } - else if(type.IsEnum) - { - EvaluationStackOperation.UnboxPrimitive(ptr, obj, Enum.GetUnderlyingType(type)); + 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; + } } - else + //泛型函数是有可能Unbox_Any一个非值类型的 + else if (obj != null && !type.IsAssignableFrom(obj.GetType())) { - ptr->Type = ValueType.ValueType; + throw new InvalidCastException(); } } - //泛型函数是有可能Unbox_Any一个非值类型的 - else if (obj != null && !type.IsAssignableFrom(obj.GetType())) - { - throw new InvalidCastException(); - } } } break; @@ -3550,6 +3896,11 @@ AnonymousStorey anonyObj } } + public static void Sweep() + { + NewFieldInfo.Sweep(); + } + public string Statistics() { var sb = new System.Text.StringBuilder(); diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 8ca80a5..f30d120 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -119,6 +119,7 @@ Dictionary> typeToSpecialGeneratedField = new Dictionary>(); Dictionary typeToCctor = new Dictionary(); + Dictionary newFieldToCtor = new Dictionary(); /// /// 获取简写属性(例如public int a{get;set;}),事件等所生成的字段 @@ -171,6 +172,10 @@ int addExternType(TypeReference type, TypeReference contextType = null) { return externTypeToId[type]; } + if (isNewClass(type as TypeDefinition)) + { + throw new Exception(type + " is new class, cannot be treated as extern type"); + } if (isCompilerGenerated(type)) { throw new Exception(type + " is CompilerGenerated"); @@ -884,6 +889,11 @@ bool isNewClass(TypeDefinition type) return configure.IsNewClass(type); } + bool isNewField(FieldDefinition field) + { + return configure.isNewField(field); + } + Dictionary interpretMethods = new Dictionary(); void addInterpretMethod(MethodDefinition method, int methodId) { @@ -1758,15 +1768,23 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } break; case Code.Box: - case Code.Isinst: case Code.Unbox_Any: case Code.Unbox: + case Code.Castclass: + case Code.Isinst: + code.Add(new Core.Instruction + { + Code = (Core.Code)Enum.Parse(typeof(Core.Code), strCode), + Operand = isNewClass(msIl.Operand as TypeDefinition) ? + -addAnonymousCtor(null, msIl.Operand as TypeReference) - 1 + : addExternType(msIl.Operand as TypeReference) + }); + break; case Code.Newarr: case Code.Ldelema: case Code.Initobj: case Code.Ldobj: case Code.Stobj: - case Code.Castclass: code.Add(new Core.Instruction { Code = (Core.Code)Enum.Parse(typeof(Core.Code), strCode), @@ -3274,6 +3292,58 @@ from method in type.Methods } } + foreach (var cls in ( + from type in allTypes + where type.IsClass select type)) + { + foreach (var field in cls.Fields) + { + if(isNewField(field)) + { + var ctor = + (from method in cls.Methods + where method.IsConstructor && (field.IsStatic ? method.Name == ".cctor" : method.Name == ".ctor") + select method).FirstOrDefault(); + + if(ctor != null) + { + var ret = new Mono.Collections.Generic.Collection(); + foreach (var instruction in ctor.Body.Instructions) + { + + var code = instruction.OpCode.Code; + + if((code == Code.Stsfld || code == Code.Stfld) && (instruction.Operand as FieldDefinition) == field) + { + emitFieldCtor(field, ret); + break; + } + else + { + ret.Add(instruction); + } + + if(field.IsStatic) + { + if(code == Code.Stsfld) + { + ret.Clear(); + } + } + else + { + if(code == Code.Stfld) + { + ret.Clear(); + } + } + } + } + } + } + } + + foreach(var kv in methodToInjectType) { processMethod(kv.Key); @@ -3297,6 +3367,61 @@ from method in type.Methods return ProcessResult.OK; } + void emitFieldCtor(FieldDefinition field, Mono.Collections.Generic.Collection insertInstructions) + { + var staticConstructorAttributes = + MethodAttributes.Private | + MethodAttributes.HideBySig | + MethodAttributes.SpecialName | + MethodAttributes.RTSpecialName; + + MethodDefinition fieldDefaultValue = new MethodDefinition("<>__ctor_" + field.Name, staticConstructorAttributes, assembly.MainModule.TypeSystem.Object); + + var local0 = new VariableDefinition(assembly.MainModule.TypeSystem.Object); + var local1 = new VariableDefinition(assembly.MainModule.TypeSystem.Object); + + fieldDefaultValue.Body.Variables.Add(local0); + fieldDefaultValue.Body.Variables.Add(local1); + + var instructions = fieldDefaultValue.Body.Instructions; + instructions.Add(Instruction.Create(OpCodes.Nop)); + foreach (var instruction in insertInstructions) + { + if(!instruction.OpCode.Code.ToString().Contains("Ldarg")) + { + instructions.Add(instruction); + } + } + + var bp1 = Instruction.Create(OpCodes.Ret); + + if(field.FieldType.IsValueType) + { + instructions.Add(Instruction.Create(OpCodes.Box, field.FieldType)); + } + + instructions.Add(Instruction.Create(OpCodes.Stloc, local0)); + instructions.Add(Instruction.Create(OpCodes.Ldloc, local0)); + instructions.Add(Instruction.Create(OpCodes.Stloc, local1)); + instructions.Add(Instruction.Create(OpCodes.Br_S, bp1)); + instructions.Add(Instruction.Create(OpCodes.Ldloc, local1)); + instructions.Add(bp1); + + field.DeclaringType.Methods.Add(fieldDefaultValue); + + configure.AddNewMethod(fieldDefaultValue); + + methodToInjectType[fieldDefaultValue] = InjectType.Redirect; + hasRedirect = true; + + if (!newFieldToCtor.ContainsKey(field)) + { + var cctorInfo = getMethodId(fieldDefaultValue, null,false, false, InjectType.Redirect); + newFieldToCtor[field] = cctorInfo.Id; + } + } + + void postProcessInterfaceBridge() { //foreach(var g in itfBridgeType.Methods.GroupBy(m => m.Name).Select(g => g.ToList())) @@ -3646,6 +3771,17 @@ public void Serialize(Stream output) writer.Write(IFix.Core.Instruction.INSTRUCTION_FORMAT_MAGIC); writer.Write(itfBridgeType.GetAssemblyQualifiedName()); + // add field type + for (int i = 0; i < fields.Count; i++) + { + var fieldType = fields[i].FieldType; + if (isCompilerGenerated(fieldType) || isNewClass(fieldType as TypeDefinition)) + { + fieldType = objType; + } + addExternType(fieldType); + } + //---------------extern type--------------- writer.Write(externTypes.Count); for (int i = 0; i < externTypes.Count; i++) @@ -3711,8 +3847,28 @@ public void Serialize(Stream output) writer.Write(fields.Count); for (int i = 0; i < fields.Count; i++) { + bool newField = isNewField(fields[i] as FieldDefinition); + writer.Write(newField); writer.Write(addExternType(fields[i].DeclaringType)); writer.Write(fields[i].Name); + + if(newField) + { + var fieldType = fields[i].FieldType; + if (isCompilerGenerated(fieldType) || isNewClass(fieldType as TypeDefinition)) + { + fieldType = objType; + } + writer.Write(addExternType(fieldType)); + if(newFieldToCtor.ContainsKey(fields[i] as FieldDefinition)) + { + writer.Write(newFieldToCtor[fields[i] as FieldDefinition]); + } + else + { + writer.Write(-1); + } + } } writer.Write(fieldsStoreInVirtualMachine.Count); diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 7122bac..49a4788 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -65,6 +65,15 @@ public static GenerateConfigure FromFile(string filename) public abstract bool IsNewMethod(MethodReference method); public abstract bool IsNewClass(TypeReference type); + + public abstract bool isNewField(FieldReference field); + + public abstract void AddNewMethod(MethodReference method); + + public abstract void AddNewClass(TypeReference type); + + public abstract void AddNewField(FieldReference field); + //参数类型信息 internal class ParameterMatchInfo { @@ -80,6 +89,18 @@ internal class MethodMatchInfo public ParameterMatchInfo[] Parameters; } + internal class FieldMatchInfo + { + public string Name; + public string FieldType; + } + + internal class PropertyMatchInfo + { + public string Name; + public string PropertyType; + } + //判断一个方法是否能够在matchInfo里头能查询到 internal static bool isMatch(Dictionary matchInfo, MethodReference method) { @@ -113,6 +134,38 @@ internal static bool isMatch(Dictionary matchInfo, Me return false; } + internal static bool isMatchForField(Dictionary matchInfo, FieldReference field) + { + FieldMatchInfo[] mmis; + if (matchInfo.TryGetValue(field.DeclaringType.FullName, out mmis)) + { + foreach (var mmi in mmis) + { + if (mmi.Name == field.Name && mmi.FieldType == field.FieldType.FullName) + { + return true; + } + } + } + return false; + } + + internal static bool isMatchForProperty(Dictionary matchInfo, PropertyReference property) + { + PropertyMatchInfo[] mmis; + if (matchInfo.TryGetValue(property.DeclaringType.FullName, out mmis)) + { + foreach (var mmi in mmis) + { + if (mmi.Name == property.Name && mmi.PropertyType == property.PropertyType.FullName) + { + return true; + } + } + } + return false; + } + internal static bool isMatchForClass(HashSet matchInfo, TypeReference type) { if (matchInfo.Contains(type.ToString())) @@ -153,6 +206,53 @@ internal static Dictionary readMatchInfo(BinaryReader return matchInfo; } + + internal static Dictionary readFieldInfo(BinaryReader reader) + { + Dictionary matchInfo = new Dictionary(); + + int typeCount = reader.ReadInt32(); + for (int k = 0; k < typeCount; k++) + { + string typeName = reader.ReadString(); + int methodCount = reader.ReadInt32(); + FieldMatchInfo[] fieldMatchInfos = new FieldMatchInfo[methodCount]; + for (int i = 0; i < methodCount; i++) + { + FieldMatchInfo fmi = new FieldMatchInfo(); + fmi.Name = reader.ReadString(); + fmi.FieldType = reader.ReadString(); + fieldMatchInfos[i] = fmi; + } + matchInfo[typeName] = fieldMatchInfos; + } + + return matchInfo; + } + + internal static Dictionary readPropertyInfo(BinaryReader reader) + { + Dictionary matchInfo = new Dictionary(); + + int typeCount = reader.ReadInt32(); + for (int k = 0; k < typeCount; k++) + { + string typeName = reader.ReadString(); + int methodCount = reader.ReadInt32(); + PropertyMatchInfo[] propertyMatchInfos = new PropertyMatchInfo[methodCount]; + for (int i = 0; i < methodCount; i++) + { + PropertyMatchInfo pmi = new PropertyMatchInfo(); + pmi.Name = reader.ReadString(); + pmi.PropertyType = reader.ReadString(); + propertyMatchInfos[i] = pmi; + } + matchInfo[typeName] = propertyMatchInfos; + } + + return matchInfo; + } + internal static HashSet readMatchInfoForClass(BinaryReader reader) { HashSet setMatchInfoForClass = new HashSet(); @@ -183,6 +283,26 @@ public override bool IsNewClass(TypeReference type) { return false; } + + public override bool isNewField(FieldReference field) + { + return false; + } + + public override void AddNewMethod(MethodReference method) + { + + } + + public override void AddNewClass(TypeReference type) + { + + } + + public override void AddNewField(FieldReference field) + { + + } } //注入配置使用 @@ -216,6 +336,22 @@ public override bool IsNewClass(TypeReference type) { return false; } + public override bool isNewField(FieldReference field) + { + return false; + } + public override void AddNewMethod(MethodReference method) + { + + } + public override void AddNewClass(TypeReference type) + { + + } + public override void AddNewField(FieldReference field) + { + + } } //patch配置使用 @@ -244,11 +380,33 @@ public override bool IsNewClass(TypeReference type) { return newClasses.Contains(type); } + + public override bool isNewField(FieldReference field) + { + return newFields.Contains(field); + } + + public override void AddNewMethod(MethodReference method) + { + newMethods.Add(method); + } + + public override void AddNewClass(TypeReference type) + { + newClasses.Add(type); + } + + public override void AddNewField(FieldReference field) + { + newFields.Add(field); + } + //暂时不支持redirect类型的方法 HashSet redirectMethods = new HashSet(); HashSet switchMethods = new HashSet(); HashSet newMethods = new HashSet(); HashSet newClasses = new HashSet(); + HashSet newFields = new HashSet(); MethodDefinition findMatchMethod(Dictionary>> searchData, MethodDefinition method) { @@ -268,17 +426,28 @@ MethodDefinition findMatchMethod(Dictionary ca.AttributeType.FullName + == "System.Runtime.CompilerServices.CompilerGeneratedAttribute"); + } + //读取配置信息(要patch的方法列表,新增方法列表) public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) { Dictionary patchMethodInfo = null; Dictionary newMethodInfo = null; + Dictionary newFieldsInfo = null; + Dictionary newPropertiesInfo = null; HashSet newClassInfo = null; using (BinaryReader reader = new BinaryReader(File.Open(cfgPath, FileMode.Open))) { patchMethodInfo = readMatchInfo(reader); newMethodInfo = readMatchInfo(reader); + newFieldsInfo = readFieldInfo(reader); + newPropertiesInfo = readPropertyInfo(reader); newClassInfo = readMatchInfoForClass(reader); } @@ -290,14 +459,50 @@ public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) } if (isMatch(newMethodInfo, method)) { - newMethods.Add(method); + AddNewMethod(method); } } foreach (var clas in newAssembly.GetAllType()) { if (isMatchForClass(newClassInfo, clas)) { - newClasses.Add(clas); + AddNewClass(clas); + } + } + foreach (var property in (from type in newAssembly.GetAllType() from property in type.Properties select property)) + { + if (isMatchForProperty(newPropertiesInfo, property)) + { + AddNewMethod(property.SetMethod); + AddNewMethod(property.GetMethod); + + var defination = newAssembly.MainModule.GetType(property.DeclaringType.FullName); + foreach (var field in ( from method in defination.Methods + where method.IsSpecialName && method.Body != null + && method.Body.Instructions != null + from instruction in method.Body.Instructions + where instruction.OpCode.Code == Mono.Cecil.Cil.Code.Ldsfld + || instruction.OpCode.Code == Mono.Cecil.Cil.Code.Stsfld + || instruction.OpCode.Code == Mono.Cecil.Cil.Code.Ldsflda + || instruction.OpCode.Code == Mono.Cecil.Cil.Code.Ldfld + || instruction.OpCode.Code == Mono.Cecil.Cil.Code.Stfld + || instruction.OpCode.Code == Mono.Cecil.Cil.Code.Ldflda + where isCompilerGenerated(instruction.Operand as Mono.Cecil.FieldReference) + select (instruction.Operand as Mono.Cecil.FieldReference).Resolve()).Distinct()) + { + var backingField = property.DeclaringType.Fields.FirstOrDefault(f => f.FullName == field.FullName); + if(backingField != null) + { + AddNewField(backingField); + } + } + } + } + foreach (var field in (from type in newAssembly.GetAllType() from field in type.Fields select field )) + { + if (isMatchForField(newFieldsInfo, field)) + { + AddNewField(field); } } } From 5ce05cacbad62b54423f641bdfb895ebfb4f3ef5 Mon Sep 17 00:00:00 2001 From: Mercury <9930422+mercurylu@users.noreply.github.com> Date: Fri, 26 Feb 2021 16:35:22 +0800 Subject: [PATCH 082/103] Fix #282 (#283) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix #282 * Fix #279 优化默认值的构造代码 Co-authored-by: mercurylu --- Source/VSProj/Src/Core/VirtualMachine.cs | 83 +++++++++++++++++++---- Source/VSProj/Src/Tools/CodeTranslator.cs | 10 +-- 2 files changed, 71 insertions(+), 22 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 9cd9e8e..6df95c6 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -1474,11 +1474,41 @@ public static void _Info(string a) var ptr = evaluationStackPointer - 1; var type = pc->Operand >= 0 ? externTypes[pc->Operand] : typeof(AnonymousStorey); var obj = managedStack[ptr->Value1]; - bool canAssign = type.IsAssignableFrom(obj.GetType()); - if (obj != null && (!canAssign || (canAssign && pc->Operand < 0 && (obj as AnonymousStorey).typeId != -(pc->Operand+1) ))) + if (obj != null) { - throw new InvalidCastException(type + " is not assignable from " - + obj.GetType()); + bool canAssign = type.IsAssignableFrom(obj.GetType()); + if(!canAssign) + { + 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) ) + { + 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) + { + throw new InvalidCastException("AnonymousStorey typeid different, " + (obj as AnonymousStorey).typeId + " <-> " + -(pc->Operand+1)); + } + } } } break; @@ -1602,9 +1632,31 @@ public static void _Info(string a) ? obj : null; if(pc->Operand < 0 && canAssign) { - if((obj as AnonymousStorey).typeId != -(pc->Operand + 1)) + if((obj is AnonymousStorey) && (obj as AnonymousStorey).typeId != -(pc->Operand+1) ) { - managedStack[pos] = null; + 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; + } } } } @@ -1804,15 +1856,18 @@ public static void _Info(string a) Type fieldType = null; var ptr = evaluationStackPointer - 1; - if(fieldInfo == null) - { - fieldType = newFieldInfos[pc->Operand].FieldType; - declaringType = newFieldInfos[pc->Operand].DeclaringType; - } - else + if(pc->Operand >= 0) { - fieldType = fieldInfo.FieldType; - declaringType = fieldInfo.DeclaringType; + if(fieldInfo == null) + { + fieldType = newFieldInfos[pc->Operand].FieldType; + declaringType = newFieldInfos[pc->Operand].DeclaringType; + } + else + { + fieldType = fieldInfo.FieldType; + declaringType = fieldInfo.DeclaringType; + } } //栈顶也是字段引用,而且该字段是值类型,需要update上层对象 diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index f30d120..23a5859 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3371,6 +3371,7 @@ void emitFieldCtor(FieldDefinition field, Mono.Collections.Generic.Collection__ctor_" + field.Name, staticConstructorAttributes, assembly.MainModule.TypeSystem.Object); var local0 = new VariableDefinition(assembly.MainModule.TypeSystem.Object); - var local1 = new VariableDefinition(assembly.MainModule.TypeSystem.Object); fieldDefaultValue.Body.Variables.Add(local0); - fieldDefaultValue.Body.Variables.Add(local1); var instructions = fieldDefaultValue.Body.Instructions; instructions.Add(Instruction.Create(OpCodes.Nop)); @@ -3393,8 +3392,6 @@ void emitFieldCtor(FieldDefinition field, Mono.Collections.Generic.Collection Date: Tue, 2 Mar 2021 16:49:16 +0800 Subject: [PATCH 083/103] Fix #286 (#287) Co-authored-by: mercurylu --- Source/VSProj/Src/Tools/GenerateConfigure.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 49a4788..3b2ba80 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -475,9 +475,11 @@ public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) { AddNewMethod(property.SetMethod); AddNewMethod(property.GetMethod); + + var methods = new List{property.GetMethod, property.SetMethod}; var defination = newAssembly.MainModule.GetType(property.DeclaringType.FullName); - foreach (var field in ( from method in defination.Methods + foreach (var field in ( from method in methods where method.IsSpecialName && method.Body != null && method.Body.Instructions != null from instruction in method.Body.Instructions From 08ad61f6c2af4b4e73856f1581fa7023396d06ab Mon Sep 17 00:00:00 2001 From: chexiongsheng Date: Wed, 3 Mar 2021 10:33:35 +0800 Subject: [PATCH 084/103] Update faq.md --- Doc/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/faq.md b/Doc/faq.md index e613153..af468eb 100644 --- a/Doc/faq.md +++ b/Doc/faq.md @@ -13,7 +13,7 @@ ## 生成 Patch 的时候遇到`Error: the new assembly must not be inject, please reimport the project!`报错 -生成 Patch 的 dll,不能进行注入 +这个dll执行过注入,不能对注入过的dll生成patch,在Unit选工程根目录,右键选reimport ## 补丁制作的条件编译宏如何处理 From 1ef6a9c680cd3d502fbb683ab8ae0c85fdd48dd5 Mon Sep 17 00:00:00 2001 From: Mercury <9930422+mercurylu@users.noreply.github.com> Date: Wed, 10 Mar 2021 16:20:06 +0800 Subject: [PATCH 085/103] Fix #289 (#290) Co-authored-by: mercurylu --- Source/VSProj/Src/Core/VirtualMachine.cs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 6df95c6..cd28827 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -61,6 +61,8 @@ public class NewFieldInfo static readonly int staticObjectKey = 0; + static readonly object[] managedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; + static readonly Dictionary> newFieldValues = new Dictionary>(); static readonly Dictionary objList = new Dictionary(); @@ -96,12 +98,17 @@ public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) { if( MethodId >= 0 && !HasInitialize(obj) ) { - Call call = Call.Begin(); - + var stack = ThreadStackInfo.Stack; + var unmanagedStack = stack.UnmanagedStack; + try { - virtualMachine.Execute(MethodId, ref call, 0, 0); - SetValue(obj, call.GetObject()); + virtualMachine.Execute(MethodId, unmanagedStack->Top, managedStack, unmanagedStack->Base, 0); + + object value = managedStack[unmanagedStack->Top->Value1]; + managedStack[unmanagedStack->Top - unmanagedStack->Base] = null; + + SetValue(obj, value); } catch(Exception e) { From b912615ce137e4c28c5393293ae43775c708f4c0 Mon Sep 17 00:00:00 2001 From: Mercury <9930422+mercurylu@users.noreply.github.com> Date: Thu, 11 Mar 2021 20:16:51 +0800 Subject: [PATCH 086/103] update user manual (#292) Co-authored-by: mercurylu --- Doc/user_manual.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index dc2e79b..d0aa4fa 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -33,14 +33,24 @@ public int Add(int a,int b) ##### 用途 -​ 在补丁阶段使用;新增代码。在补丁阶段,童鞋们还有新的需求,想新增个函数或者类,可以用[IFix.Interpret]标签实现。 +​ 在补丁阶段使用;新增代码。在补丁阶段,童鞋们还有新的需求,想新增个字段,函数或者类,可以用[IFix.Interpret]标签实现。 ##### 用法 -​ 该标签可以用在属性,方法,类型上,直接在要新增的代码上面标注一下这个标签即可。 +​ 该标签可以用在字段,属性,方法,类型上,直接在要新增的代码上面标注一下这个标签即可。 ##### 举例 +​ 新增一个字段 + +```c# +public class Test +{ + [IFix.Interpret] + public int intValue = 0; +} +``` + ​ 新增一个属性 ```c# @@ -59,6 +69,13 @@ public string Name return name; } } + +[IFix.Interpret] +public string Id +{ + set; + get; +} ``` ​ 新增一个函数 @@ -305,7 +322,7 @@ public class TestCfg | 标签 | 使用阶段 | 用途 | 用法 | | :-----------------: | :------: | :------------------------: | :----------------------------------------------------------: | | [IFix.Patch] | 补丁 | 修复函数 | 只能放在函数上 | -| [IFix.Interpret] | 补丁 | 新增属性,函数,类型 | 放在属性,函数,类型上 | +| [IFix.Interpret] | 补丁 | 新增字段,属性,函数,类型 | 放在字段,属性,函数,类型上 | | [IFix.CustomBridge] | 注入 | interface和delegate桥接 | 只能放在单独写一个静态类上,存储虚拟机的类适配到原生interface或者虚拟机的函数适配到原生delegate,该类不能放Editor目录 | | [Configure] | 注入 | 配置类 | 只能放在单独写一个存放在Editor目录下的类上 | | [IFix] | 注入 | 可能需要修复函数的类的集合 | 只能放在[Configure]类的一个静态属性上 | From af8cf9f4b49d261440234ca2e1bb02ccd1cc213e Mon Sep 17 00:00:00 2001 From: lafirest Date: Thu, 18 Mar 2021 21:15:59 +0800 Subject: [PATCH 087/103] =?UTF-8?q?=E4=BF=AE=E5=A4=8Dasync=E5=87=BD?= =?UTF-8?q?=E6=95=B0=E4=B8=8D=E8=83=BD=E7=83=AD=E6=9B=B4=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=20(#298)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 122 ++++++++++++++++++---- 1 file changed, 100 insertions(+), 22 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 23a5859..b5ec6f1 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -797,10 +797,10 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) type.Methods.Add(proxyMethod); Dictionary typeToProxy; - if (!baseProxys.TryGetValue(mbase, out typeToProxy)) - { - typeToProxy = new Dictionary(); - baseProxys.Add(mbase, typeToProxy); + if (!baseProxys.TryGetValue(mbase, out typeToProxy)) + { + typeToProxy = new Dictionary(); + baseProxys.Add(mbase, typeToProxy); } typeToProxy.Add(type, proxyMethod); return proxyMethod; @@ -813,23 +813,23 @@ MethodReference tryAddBaseProxy(TypeDefinition type, MethodDefinition method) return null; } - MethodReference findProxy(TypeDefinition type, MethodReference methodToCall) - { - Dictionary typeToProxy; - if (baseProxys.TryGetValue(methodToCall, out typeToProxy)) - { - TypeDefinition ptype = type; - while (ptype != null) - { - if (typeToProxy.ContainsKey(ptype)) - { - return typeToProxy[ptype]; - } - ptype = ptype.DeclaringType; - } - } - return null; - + MethodReference findProxy(TypeDefinition type, MethodReference methodToCall) + { + Dictionary typeToProxy; + if (baseProxys.TryGetValue(methodToCall, out typeToProxy)) + { + TypeDefinition ptype = type; + while (ptype != null) + { + if (typeToProxy.ContainsKey(ptype)) + { + return typeToProxy[ptype]; + } + ptype = ptype.DeclaringType; + } + } + return null; + } enum CallType @@ -2223,6 +2223,82 @@ void EmitRefAwaitUnsafeOnCompletedMethod() itfBridgeType.Methods.Add(targetMethod); } + private void EmitAsyncBuilderStartMethod(IEnumerable allTypes) + { + var builders = new List(); + var genericBuilders = new List(); + + // 找到所有异步方法的builder + foreach(var typeDefinition in allTypes) + { + foreach(var nestedType in typeDefinition.NestedTypes) + { + var isStateMachine = + nestedType.Interfaces.Any(e => e.InterfaceType.Name == "IAsyncStateMachine"); + + if(!isStateMachine) + continue; + + var builder = nestedType.Fields.First(e => e.Name.EndsWith("builder")); + var builderType = builder.FieldType; + + if(builderType.ContainsGenericParameter) + continue; + + if(!builderType.IsValueType) + continue; + + if(builderType.IsGenericInstance) + { + if(genericBuilders.Any(e => ((GenericInstanceType) e).GenericArguments[0] + == ((GenericInstanceType) builderType).GenericArguments[0])) + continue; + + genericBuilders.Add(builderType); + } + else + { + if(builders.Contains(builderType)) + continue; + + builders.Add(builderType); + } + } + } + + // 生成Start函数引用 + builders.AddRange(genericBuilders); + + var targetMethod = new MethodDefinition($"RefAsyncBuilderStartMethod" + , MethodAttributes.Public + , assembly.MainModule.TypeSystem.Void); + var instructions = targetMethod.Body.Instructions; + var localBridge = new VariableDefinition(itfBridgeType); + targetMethod.Body.Variables.Add(localBridge); + + foreach(var builder in builders) + { + var start = new MethodReference("Start", voidType, builder) + { + HasThis = true, CallingConvention = MethodCallingConvention.Generic + }; + var genericParameter = new GenericParameter("!!0", start); + start.GenericParameters.Add(genericParameter); + var byReferenceType = new ByReferenceType(genericParameter); + start.Parameters.Add(new ParameterDefinition(byReferenceType)); + + var localBuilder = new VariableDefinition(builder); + targetMethod.Body.Variables.Add(localBuilder); + + instructions.Add(Instruction.Create(OpCodes.Ldloca_S, localBuilder)); + instructions.Add(Instruction.Create(OpCodes.Ldloca_S, localBridge)); + instructions.Add(Instruction.Create(OpCodes.Call, makeGenericMethod(start, itfBridgeType))); + } + + instructions.Add(Instruction.Create(OpCodes.Ret)); + itfBridgeType.Methods.Add(targetMethod); + } + /// /// 获取一个方法的适配器 @@ -3271,7 +3347,7 @@ public ProcessResult Process(AssemblyDefinition assembly, AssemblyDefinition ilf var allTypes = (from type in assembly.GetAllType() where type.Namespace != "IFix" && !type.IsGeneric() && !(isCompilerGenerated(type) || isNewClass(type)) - select type); + select type).ToList(); foreach (var method in ( from type in allTypes @@ -3362,6 +3438,8 @@ from type in allTypes { EmitRefAwaitUnsafeOnCompletedMethod(); } + + EmitAsyncBuilderStartMethod(allTypes); } return ProcessResult.OK; From 1b029961109d54a06a873e0d7804b446a2df0205 Mon Sep 17 00:00:00 2001 From: Mercury <9930422+mercurylu@users.noreply.github.com> Date: Thu, 18 Mar 2021 21:16:29 +0800 Subject: [PATCH 088/103] =?UTF-8?q?get/set=E5=87=BD=E6=95=B0=E5=8F=AA?= =?UTF-8?q?=E6=9C=89=E4=B8=80=E4=B8=AA=E6=83=85=E5=86=B5=E4=B8=8B=E5=A4=84?= =?UTF-8?q?=E7=90=86=E4=BC=9A=E6=8A=A5=E9=94=99=20(#295)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修复get/set函数只有一个情况下会报错 * 修复新增字段默认值初始化时堆栈计算的问题 Co-authored-by: mercurylu --- Source/VSProj/Src/Core/VirtualMachine.cs | 7 +++++-- Source/VSProj/Src/Tools/GenerateConfigure.cs | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index cd28827..da58e8c 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -103,10 +103,13 @@ public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) try { + var top = unmanagedStack->Top; + var @base = unmanagedStack->Base; + virtualMachine.Execute(MethodId, unmanagedStack->Top, managedStack, unmanagedStack->Base, 0); - object value = managedStack[unmanagedStack->Top->Value1]; - managedStack[unmanagedStack->Top - unmanagedStack->Base] = null; + object value = managedStack[top->Value1]; + managedStack[top - @base] = null; SetValue(obj, value); } diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 3b2ba80..68e6f7a 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -480,7 +480,7 @@ public PatchGenerateConfigure(AssemblyDefinition newAssembly, string cfgPath) var defination = newAssembly.MainModule.GetType(property.DeclaringType.FullName); foreach (var field in ( from method in methods - where method.IsSpecialName && method.Body != null + where method != null && method.IsSpecialName && method.Body != null && method.Body.Instructions != null from instruction in method.Body.Instructions where instruction.OpCode.Code == Mono.Cecil.Cil.Code.Ldsfld From ecd77d8d6097b225b26576667db753a437a6c1a0 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 19 Mar 2021 16:24:10 +0800 Subject: [PATCH 089/103] =?UTF-8?q?=E7=BC=96=E8=AF=91=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 14 +++++++------- Source/VSProj/Src/Tools/CodeTranslator.cs | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index da58e8c..4dab0d3 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -107,8 +107,8 @@ public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) var @base = unmanagedStack->Base; virtualMachine.Execute(MethodId, unmanagedStack->Top, managedStack, unmanagedStack->Base, 0); - - object value = managedStack[top->Value1]; + + object value = managedStack[top->Value1]; managedStack[top - @base] = null; SetValue(obj, value); @@ -2761,11 +2761,11 @@ AnonymousStorey anonyObj //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]; + 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; diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index b5ec6f1..fdab355 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2269,9 +2269,8 @@ private void EmitAsyncBuilderStartMethod(IEnumerable allTypes) // 生成Start函数引用 builders.AddRange(genericBuilders); - var targetMethod = new MethodDefinition($"RefAsyncBuilderStartMethod" - , MethodAttributes.Public - , assembly.MainModule.TypeSystem.Void); + var targetMethod = new MethodDefinition("RefAsyncBuilderStartMethod", MethodAttributes.Public, + assembly.MainModule.TypeSystem.Void); var instructions = targetMethod.Body.Instructions; var localBridge = new VariableDefinition(itfBridgeType); targetMethod.Body.Variables.Add(localBridge); From c29b1d28b6bbdc607a1d0ea05a9e734b132ed2ef Mon Sep 17 00:00:00 2001 From: chexiongsheng Date: Wed, 24 Mar 2021 10:55:01 +0800 Subject: [PATCH 090/103] =?UTF-8?q?=E5=8E=BB=E6=8E=89=E4=B8=8D=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E7=9A=84=E7=94=A8=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index d0aa4fa..1d9ce03 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -70,12 +70,6 @@ public string Name } } -[IFix.Interpret] -public string Id -{ - set; - get; -} ``` ​ 新增一个函数 From 25f0f0f89718dd55835bcef63410f45da5b6e5c7 Mon Sep 17 00:00:00 2001 From: chexiongsheng Date: Fri, 26 Mar 2021 11:11:15 +0800 Subject: [PATCH 091/103] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=89=8B=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Doc/user_manual.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Doc/user_manual.md b/Doc/user_manual.md index 1d9ce03..aa071d0 100644 --- a/Doc/user_manual.md +++ b/Doc/user_manual.md @@ -70,6 +70,13 @@ public string Name } } +[IFix.Interpret] +public string Id +{ + set; + get; +} + ``` ​ 新增一个函数 From 8d3768e82d0144d739c15da07821f55d985185e5 Mon Sep 17 00:00:00 2001 From: johnche Date: Fri, 30 Apr 2021 10:41:42 +0800 Subject: [PATCH 092/103] =?UTF-8?q?=E8=A7=A3=E5=86=B3=E5=AF=B9=E7=A9=BA?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1as=E6=8A=A5=E9=94=99=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98=EF=BC=8Cfix=20https://github.com/Tencent/InjectFix/is?= =?UTF-8?q?sues/311?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Core/VirtualMachine.cs | 67 +++++++++++++----------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 4dab0d3..ad48439 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -1637,36 +1637,43 @@ public static void _Info(string a) var obj = managedStack[ptr->Value1]; ptr->Type = ValueType.Object; ptr->Value1 = pos; - bool canAssign = type.IsAssignableFrom(obj.GetType()); - managedStack[pos] = (obj != null && 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; - } + 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; + } + } } } } From c55a06f04ad493175356360a9088d3c41b68dd2a Mon Sep 17 00:00:00 2001 From: Mercury <9930422+mercurylu@users.noreply.github.com> Date: Wed, 2 Jun 2021 15:00:35 +0800 Subject: [PATCH 093/103] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=E5=88=9D=E5=A7=8B=E5=8C=96=E8=BF=87=E7=A8=8B?= =?UTF-8?q?=E4=B8=AD=E7=B1=BB=E5=9E=8B=E4=B8=8D=E6=AD=A3=E7=A1=AE=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98=20(#319)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 会触发Ceq for diff type的error Co-authored-by: mercurylu --- Source/VSProj/Src/Core/StackOperation.cs | 12 ++++++++ Source/VSProj/Src/Core/VirtualMachine.cs | 35 ++++++++--------------- Source/VSProj/Src/Tools/CodeTranslator.cs | 8 +----- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index d0518ef..541d55c 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -561,6 +561,18 @@ public static Call Begin() }; } + internal static Call BeginForStack(ThreadStackInfo stack) + { + return new Call() + { + managedStack = stack.ManagedStack, + currentTop = stack.UnmanagedStack->Top, + argumentBase = stack.UnmanagedStack->Top, + evaluationStackBase = stack.UnmanagedStack->Base, + topWriteBack = &(stack.UnmanagedStack->Top) + }; + } + public void PushBoolean(bool b) { currentTop->Value1 = b ? 1 : 0; diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index ad48439..128099a 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -33,13 +33,16 @@ public class Cleanner public static void Start() { - start = true; - new Cleanner(); + if(!start) + { + start = true; + new Cleanner(); + } } public static void Stop() { - start = false; + start = false; } ~Cleanner() @@ -61,7 +64,7 @@ public class NewFieldInfo static readonly int staticObjectKey = 0; - static readonly object[] managedStack = new object[VirtualMachine.MAX_EVALUATION_STACK_SIZE]; + static readonly ThreadStackInfo stack = new ThreadStackInfo(); static readonly Dictionary> newFieldValues = new Dictionary>(); @@ -98,25 +101,9 @@ public unsafe void CheckInit(VirtualMachine virtualMachine, object obj) { if( MethodId >= 0 && !HasInitialize(obj) ) { - var stack = ThreadStackInfo.Stack; - var unmanagedStack = stack.UnmanagedStack; - - try - { - var top = unmanagedStack->Top; - var @base = unmanagedStack->Base; - - virtualMachine.Execute(MethodId, unmanagedStack->Top, managedStack, unmanagedStack->Base, 0); - - object value = managedStack[top->Value1]; - managedStack[top - @base] = null; - - SetValue(obj, value); - } - catch(Exception e) - { - VirtualMachine._Info(e.ToString()); - } + Call call = Call.BeginForStack(stack); + virtualMachine.Execute(MethodId, ref call, 0, 0); + SetValue(obj, call.GetObject()); } } @@ -365,6 +352,8 @@ internal VirtualMachine(Instruction** unmanaged_codes, Action on_dispose) ~VirtualMachine() { onDispose(); + + Cleanner.Stop(); unmanagedCodes = null; } diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index fdab355..59d8bdc 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -3455,12 +3455,8 @@ void emitFieldCtor(FieldDefinition field, Mono.Collections.Generic.Collection__ctor_" + field.Name, staticConstructorAttributes, assembly.MainModule.TypeSystem.Object); - var local0 = new VariableDefinition(assembly.MainModule.TypeSystem.Object); - - fieldDefaultValue.Body.Variables.Add(local0); - var instructions = fieldDefaultValue.Body.Instructions; - instructions.Add(Instruction.Create(OpCodes.Nop)); + foreach (var instruction in insertInstructions) { if(!instruction.OpCode.Code.ToString().Contains("Ldarg")) @@ -3474,8 +3470,6 @@ void emitFieldCtor(FieldDefinition field, Mono.Collections.Generic.Collection Date: Thu, 29 Jul 2021 16:08:17 +0800 Subject: [PATCH 094/103] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=94=9F=E6=88=90?= =?UTF-8?q?=E8=A1=A5=E4=B8=81=E6=97=B6=E5=AF=B9=E8=B0=83=E7=94=A8"?= =?UTF-8?q?=E8=BF=94=E5=9B=9Eref=E7=B1=BB=E5=9E=8B=E7=9A=84=E6=96=B9?= =?UTF-8?q?=E6=B3=95"=E6=83=85=E5=86=B5=E7=9A=84=E8=AD=A6=E5=91=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 59d8bdc..4935413 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1563,6 +1563,12 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, break; } var methodToCall = msIl.Operand as MethodReference; + if (methodToCall.ReturnType.IsByReference) + { + Console.WriteLine("Warning: method returning ByRef type is not supported. caller={0} callee={1}", + method.FullName, + methodToCall.FullName); + } if (msIl.OpCode.Code == Code.Newobj && (isCompilerGeneratedPlainObject( methodToCall.DeclaringType) || isCustomClassPlainObject(methodToCall.DeclaringType))) { From 131dcc200d0dfc919f6411c0719a1981652b7a14 Mon Sep 17 00:00:00 2001 From: johnche Date: Wed, 22 Sep 2021 12:57:25 +0800 Subject: [PATCH 095/103] =?UTF-8?q?=E8=8E=B7=E5=8F=96builder=E5=A6=82?= =?UTF-8?q?=E6=9E=9C=E5=87=BA=E7=8E=B0=E5=BC=82=E5=B8=B8=EF=BC=8C=E5=8F=AA?= =?UTF-8?q?=E6=89=93=E5=8D=B0=EF=BC=8C=E4=B8=8D=E4=B8=AD=E6=96=AD=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=EF=BC=8Cfix=20https://github.com/Tencent/InjectFix/is?= =?UTF-8?q?sues/332?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 51 +++++++++++++---------- 1 file changed, 29 insertions(+), 22 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 4935413..f716195 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2239,35 +2239,42 @@ private void EmitAsyncBuilderStartMethod(IEnumerable allTypes) { foreach(var nestedType in typeDefinition.NestedTypes) { - var isStateMachine = - nestedType.Interfaces.Any(e => e.InterfaceType.Name == "IAsyncStateMachine"); - - if(!isStateMachine) - continue; - - var builder = nestedType.Fields.First(e => e.Name.EndsWith("builder")); - var builderType = builder.FieldType; + try + { + var isStateMachine = + nestedType.Interfaces.Any(e => e.InterfaceType.Name == "IAsyncStateMachine"); - if(builderType.ContainsGenericParameter) - continue; + if(!isStateMachine) + continue; - if(!builderType.IsValueType) - continue; + var builder = nestedType.Fields.First(e => e.Name.EndsWith("builder")); + var builderType = builder.FieldType; - if(builderType.IsGenericInstance) - { - if(genericBuilders.Any(e => ((GenericInstanceType) e).GenericArguments[0] - == ((GenericInstanceType) builderType).GenericArguments[0])) + if(builderType.ContainsGenericParameter) continue; - genericBuilders.Add(builderType); - } - else - { - if(builders.Contains(builderType)) + if(!builderType.IsValueType) continue; - builders.Add(builderType); + if(builderType.IsGenericInstance) + { + if(genericBuilders.Any(e => ((GenericInstanceType) e).GenericArguments[0] + == ((GenericInstanceType) builderType).GenericArguments[0])) + continue; + + genericBuilders.Add(builderType); + } + else + { + if(builders.Contains(builderType)) + continue; + + builders.Add(builderType); + } + } + catch (Exception e) + { + Console.WriteLine("Warning: get builder in " + typeDefinition + " throw: " + e); } } } From 259b888090a78dd0084addea0b8af6c74a255d1e Mon Sep 17 00:00:00 2001 From: PresleyInGitHub <33973567+PresleyInGitHub@users.noreply.github.com> Date: Mon, 11 Oct 2021 15:28:24 +0800 Subject: [PATCH 096/103] =?UTF-8?q?Inject=E5=90=8E=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=E8=B0=83=E7=94=A8Unity=E5=8A=A0=E8=BD=BD=E6=B3=A8=E5=85=A5?= =?UTF-8?q?=E5=90=8E=E7=9A=84dll=E4=BB=A3=E7=A0=81=20(#340)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: linbo --- Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index adf0bd5..30661e4 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -162,6 +162,7 @@ public static void InjectAssemblys() UnityEngine.Debug.LogError(e); } EditorUtility.ClearProgressBar(); + EditorUtility.RequestScriptReload(); } public static bool AutoInject = true; //可以在外部禁用掉自动注入 From e3be7e9b7446292a9d8e0ae4e3f8229cf99c45b1 Mon Sep 17 00:00:00 2001 From: PresleyInGitHub <33973567+PresleyInGitHub@users.noreply.github.com> Date: Wed, 13 Oct 2021 09:13:33 +0800 Subject: [PATCH 097/103] =?UTF-8?q?EditorUtility.RequestScriptReload()?= =?UTF-8?q?=E6=98=AF2019.3.0=E4=B9=8B=E5=90=8E=E6=96=B0=E5=A2=9E=E7=9A=84A?= =?UTF-8?q?PI=20(#341)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Inject后显示调用Unity加载注入后的dll代码 * EditorUtility.RequestScriptReload()是2019.3.0之后新增的API Co-authored-by: linbo --- Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 30661e4..75c1575 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -162,7 +162,9 @@ public static void InjectAssemblys() UnityEngine.Debug.LogError(e); } EditorUtility.ClearProgressBar(); +#if UNITY_2019_3_OR_NEWER EditorUtility.RequestScriptReload(); +#endif } public static bool AutoInject = true; //可以在外部禁用掉自动注入 From b1676f1af13a29bbfa38332e968696f1353ee4a4 Mon Sep 17 00:00:00 2001 From: mercurylu Date: Fri, 10 Dec 2021 16:34:22 +0800 Subject: [PATCH 098/103] =?UTF-8?q?fix:=20Callvirt=E8=A2=AB=E9=94=99?= =?UTF-8?q?=E8=AF=AF=E7=9A=84=E7=94=9F=E6=88=90=E4=B8=BACallvirtvirt?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index f716195..f3c0fe6 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1095,7 +1095,7 @@ unsafe MethodIdInfo getMethodId(MethodReference callee, MethodDefinition caller, } if (methodToId.ContainsKey(callee)) { - if (isCallvirt) + if (isCallvirt && isNewClass(callee.DeclaringType as TypeDefinition)) { getVirtualMethodForType(method.DeclaringType); if (virtualMethodToIndex.ContainsKey(callee)) From 9d8e95072a88f577e95ad581ea6082f654337b4c Mon Sep 17 00:00:00 2001 From: xuyanghuang Date: Mon, 17 Jan 2022 18:33:31 +0800 Subject: [PATCH 099/103] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=AF=B9=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E5=AD=97=E6=AE=B5=E8=AE=BF=E9=97=AE=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index f3c0fe6..8139643 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -2239,7 +2239,7 @@ private void EmitAsyncBuilderStartMethod(IEnumerable allTypes) { foreach(var nestedType in typeDefinition.NestedTypes) { - try + try { var isStateMachine = nestedType.Interfaces.Any(e => e.InterfaceType.Name == "IAsyncStateMachine"); @@ -2272,9 +2272,9 @@ private void EmitAsyncBuilderStartMethod(IEnumerable allTypes) builders.Add(builderType); } } - catch (Exception e) - { - Console.WriteLine("Warning: get builder in " + typeDefinition + " throw: " + e); + catch (Exception e) + { + Console.WriteLine("Warning: get builder in " + typeDefinition + " throw: " + e); } } } @@ -3853,6 +3853,16 @@ public void Serialize(Stream output) for (int i = 0; i < fields.Count; i++) { var fieldType = fields[i].FieldType; + if (fieldType.IsGenericParameter) + { + var resolveType = ((GenericParameter)fieldType).ResolveGenericArgument(fields[i].DeclaringType); + if (resolveType != null) + { + addExternType(resolveType); + continue; + } + } + if (isCompilerGenerated(fieldType) || isNewClass(fieldType as TypeDefinition)) { fieldType = objType; From cb500cc16d2e7d5563a80e3e08ab12b87d43cc52 Mon Sep 17 00:00:00 2001 From: shaoyy <1447247302@qq.com> Date: Tue, 8 Feb 2022 11:07:41 +0800 Subject: [PATCH 100/103] =?UTF-8?q?=E6=B3=9B=E5=9E=8B=E6=8A=A5=E9=94=99?= =?UTF-8?q?=E6=97=B6=E8=BE=93=E5=87=BA=E6=9B=B4=E5=A4=9Alog=E4=BF=A1?= =?UTF-8?q?=E6=81=AF=20(#360)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/VSProj/Src/Tools/CodeTranslator.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 8139643..104bc51 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -166,7 +166,13 @@ int addExternType(TypeReference type, TypeReference contextType = null) if (type.IsRequiredModifier) return addExternType((type as RequiredModifierType).ElementType, contextType); if (type.IsGenericParameter || type.HasGenericArgumentFromMethod()) { - throw new InvalidProgramException("try to use a generic type definition: " + type); + var genericTypeInfo = "{None}"; + try { + var genericType = (GenericParameter)type; + var owner = (TypeDefinition)genericType.Owner; + genericTypeInfo = string.Format("{{Owner: {0}, Scope: {1}}}", owner.FullName, genericType.Scope.Name); + } catch { } + throw new InvalidProgramException("try to use a generic type definition: " + type + ", generic type info: " + genericTypeInfo); } if (externTypeToId.ContainsKey(type)) { From 4267aff030db46094ffee93db1491a374d845d56 Mon Sep 17 00:00:00 2001 From: HuangXiaowen1989 <47025751+HuangXiaowen1989@users.noreply.github.com> Date: Tue, 8 Feb 2022 11:10:58 +0800 Subject: [PATCH 101/103] =?UTF-8?q?checkNew=E5=8F=AF=E4=BB=A5=E6=8E=A7?= =?UTF-8?q?=E5=88=B6=E4=B8=8D=E6=A3=80=E6=9F=A5=E6=96=B0=E5=A2=9E=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=EF=BC=9B=E5=8F=8B=E5=96=84=E6=8F=90=E7=A4=BA=E7=A9=BA?= =?UTF-8?q?=E5=AE=9E=E4=BE=8B=E5=8F=8D=E5=B0=84=E5=BC=82=E5=B8=B8=E3=80=82?= =?UTF-8?q?=20(#346)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 修改空对象调用成员方法时的异常信息,方便定位出错代码。 * 修改空对象调用成员方法时的异常信息,方便定位出错代码。 * checkNew可以控制是否检查新增字段 Co-authored-by: huangxiaowen --- Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs | 3 ++- Source/VSProj/Src/Core/ReflectionMethodInvoker.cs | 9 ++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index eb1177c..400c853 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -412,7 +412,8 @@ unsafe static public VirtualMachine Load(Stream stream, bool checkNew = true) } else { - throw new Exception(declaringType + "." + fieldName + " is expected to be a new field , but it already exists "); + if(checkNew) + throw new Exception(declaringType + "." + fieldName + " is expected to be a new field , but it already exists "); } } } diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index 5c62863..2de7441 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -158,7 +158,14 @@ public unsafe void Invoke(VirtualMachine virtualMachine, ref Call call, bool isI } else { - ret = method.Invoke(instance, args); + if (method.IsStatic == false && 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); + } } } From 552da3654e74c4b08bbe2533699fb2306df5de7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=96=B5=E5=96=B5=E5=A4=A7=E4=BA=BA?= Date: Tue, 19 Apr 2022 11:56:25 +0800 Subject: [PATCH 102/103] fix: that cannot be built under linux unity (#365) --- Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 75c1575..402c054 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -68,7 +68,7 @@ public class IFixEditor //system("mono ifix.exe [args]") public static void CallIFix(List args) { -#if UNITY_EDITOR_OSX +#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX var mono_path = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName), "../MonoBleedingEdge/bin/mono"); if(!File.Exists(mono_path)) @@ -587,7 +587,7 @@ private static string getCompileArguments(Platform platform, string output) //TODO: 目前的做法挺繁琐的,需要用户去获取Unity的编译命令文件,更好的做法应该是直接 public static void Compile(string compileArgFile) { -#if UNITY_EDITOR_OSX +#if UNITY_EDITOR_OSX || UNITY_EDITOR_LINUX var monoPath = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName), "../MonoBleedingEdge/bin/mono"); var mcsPath = Path.Combine(Path.GetDirectoryName(typeof(UnityEngine.Debug).Module.FullyQualifiedName), From 5ba42eb8f63fe37134a3c78690f97d8425e13588 Mon Sep 17 00:00:00 2001 From: xuyanghuang Date: Mon, 7 Jul 2025 10:24:08 +0800 Subject: [PATCH 103/103] =?UTF-8?q?=E6=9B=B4=E6=96=B0LICENSE=E7=9A=84?= =?UTF-8?q?=E5=85=AC=E5=8F=B8=E4=B8=BB=E4=BD=93?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 2 +- Source/Misc/LiveDotNet/Editor/LiveDotNet.cs | 2 +- .../LiveDotNet/Editor/LiveDotNetConfig.cs | 2 +- Source/Misc/LiveDotNet/PatchReceiver.cs | 2 +- Source/Misc/LiveDotNet/RotateCube.cs | 2 +- Source/UnityProj/Assets/Helloworld/Calc.cs | 2 +- .../Assets/Helloworld/Editor/HelloworldCfg.cs | 2 +- .../UnityProj/Assets/Helloworld/Helloworld.cs | 14 ++-- .../UnityProj/Assets/IFix/Editor/Configure.cs | 2 +- .../Assets/IFix/Editor/ILFixEditor.cs | 2 +- .../Pro Standard Assets/AnotherClass.cs | 2 +- Source/VSProj/ShuffleInstruction.cs | 2 +- .../Src/Builder/FileVirtualMachineBuilder.cs | 2 +- .../Builder/SimpleVirtualMachineBuilder.cs | 2 +- Source/VSProj/Src/Core/AnonymousStorey.cs | 2 +- Source/VSProj/Src/Core/DataDefine.cs | 2 +- Source/VSProj/Src/Core/GenericDelegate.cs | 2 +- .../Src/Core/Il2CppSetOptionAttribute.cs | 2 +- Source/VSProj/Src/Core/Instruction.cs | 2 +- Source/VSProj/Src/Core/ObjectClone.cs | 2 +- .../Src/Core/ReflectionMethodInvoker.cs | 2 +- Source/VSProj/Src/Core/StackOperation.cs | 2 +- Source/VSProj/Src/Core/SwitchFlags.cs | 2 +- Source/VSProj/Src/Core/Utils.cs | 2 +- Source/VSProj/Src/Core/VirtualMachine.cs | 76 +++++++++---------- Source/VSProj/Src/Core/WrappersManager.cs | 2 +- Source/VSProj/Src/PerfTest/PerfTest.cs | 2 +- Source/VSProj/Src/TestDLL/BaseTest.cs | 2 +- Source/VSProj/Src/TestDLL/RedirectBaseTest.cs | 2 +- Source/VSProj/Src/Tools/CSFix.cs | 2 +- Source/VSProj/Src/Tools/CecilExtensions.cs | 2 +- Source/VSProj/Src/Tools/CodeTranslator.cs | 2 +- Source/VSProj/Src/Tools/GenerateConfigure.cs | 2 +- .../VSProj/Src/UnitTest/VirtualMachineTest.cs | 2 +- Source/VSProj/Src/Version.cs | 2 +- 35 files changed, 78 insertions(+), 78 deletions(-) diff --git a/LICENSE b/LICENSE index 2b192e9..b9b43f8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ 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. +Copyright (C) 2019 Tencent. All rights reserved. InjectFix is licensed under the MIT License, except for the third-party components listed below which may be subject to thier corresponding license terms. diff --git a/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs b/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs index 164a819..da3acdb 100644 --- a/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs +++ b/Source/Misc/LiveDotNet/Editor/LiveDotNet.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs b/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs index 1c74cb5..a638cd9 100644 --- a/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs +++ b/Source/Misc/LiveDotNet/Editor/LiveDotNetConfig.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/Misc/LiveDotNet/PatchReceiver.cs b/Source/Misc/LiveDotNet/PatchReceiver.cs index 2b4c565..f13aaae 100644 --- a/Source/Misc/LiveDotNet/PatchReceiver.cs +++ b/Source/Misc/LiveDotNet/PatchReceiver.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/Misc/LiveDotNet/RotateCube.cs b/Source/Misc/LiveDotNet/RotateCube.cs index 9672d75..cdabd21 100644 --- a/Source/Misc/LiveDotNet/RotateCube.cs +++ b/Source/Misc/LiveDotNet/RotateCube.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/UnityProj/Assets/Helloworld/Calc.cs b/Source/UnityProj/Assets/Helloworld/Calc.cs index 4d6bb5e..d92ac12 100644 --- a/Source/UnityProj/Assets/Helloworld/Calc.cs +++ b/Source/UnityProj/Assets/Helloworld/Calc.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs index 8651e8b..3af5f17 100644 --- a/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs +++ b/Source/UnityProj/Assets/Helloworld/Editor/HelloworldCfg.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/UnityProj/Assets/Helloworld/Helloworld.cs b/Source/UnityProj/Assets/Helloworld/Helloworld.cs index 9fc99ad..cf17496 100644 --- a/Source/UnityProj/Assets/Helloworld/Helloworld.cs +++ b/Source/UnityProj/Assets/Helloworld/Helloworld.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ @@ -50,16 +50,16 @@ void test() 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 + UnityEngine.Debug.Log("anotherClass.Call, ret = " + ret); + + //test for InjectFix/Fix(Android) InjectFix/Fix(IOS) Menu for unity 2018.3 or newer #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 diff --git a/Source/UnityProj/Assets/IFix/Editor/Configure.cs b/Source/UnityProj/Assets/IFix/Editor/Configure.cs index 5c6190a..6b033e8 100644 --- a/Source/UnityProj/Assets/IFix/Editor/Configure.cs +++ b/Source/UnityProj/Assets/IFix/Editor/Configure.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs index 402c054..ab14aa5 100644 --- a/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs +++ b/Source/UnityProj/Assets/IFix/Editor/ILFixEditor.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/UnityProj/Assets/Pro Standard Assets/AnotherClass.cs b/Source/UnityProj/Assets/Pro Standard Assets/AnotherClass.cs index 15ae8e9..4b0d42a 100644 --- a/Source/UnityProj/Assets/Pro Standard Assets/AnotherClass.cs +++ b/Source/UnityProj/Assets/Pro Standard Assets/AnotherClass.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/ShuffleInstruction.cs b/Source/VSProj/ShuffleInstruction.cs index aafb25b..73e02c2 100644 --- a/Source/VSProj/ShuffleInstruction.cs +++ b/Source/VSProj/ShuffleInstruction.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs index 400c853..c960641 100644 --- a/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/FileVirtualMachineBuilder.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs b/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs index 6641591..f7273c0 100644 --- a/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs +++ b/Source/VSProj/Src/Builder/SimpleVirtualMachineBuilder.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/AnonymousStorey.cs b/Source/VSProj/Src/Core/AnonymousStorey.cs index 341f90e..646883b 100644 --- a/Source/VSProj/Src/Core/AnonymousStorey.cs +++ b/Source/VSProj/Src/Core/AnonymousStorey.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/DataDefine.cs b/Source/VSProj/Src/Core/DataDefine.cs index 140117b..5e9830c 100644 --- a/Source/VSProj/Src/Core/DataDefine.cs +++ b/Source/VSProj/Src/Core/DataDefine.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/GenericDelegate.cs b/Source/VSProj/Src/Core/GenericDelegate.cs index f41d382..72c70b5 100644 --- a/Source/VSProj/Src/Core/GenericDelegate.cs +++ b/Source/VSProj/Src/Core/GenericDelegate.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/Il2CppSetOptionAttribute.cs b/Source/VSProj/Src/Core/Il2CppSetOptionAttribute.cs index 931c3e0..3554fd1 100644 --- a/Source/VSProj/Src/Core/Il2CppSetOptionAttribute.cs +++ b/Source/VSProj/Src/Core/Il2CppSetOptionAttribute.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/Instruction.cs b/Source/VSProj/Src/Core/Instruction.cs index cfe8843..0c7ef34 100644 --- a/Source/VSProj/Src/Core/Instruction.cs +++ b/Source/VSProj/Src/Core/Instruction.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/ObjectClone.cs b/Source/VSProj/Src/Core/ObjectClone.cs index 76d193b..646dbc7 100644 --- a/Source/VSProj/Src/Core/ObjectClone.cs +++ b/Source/VSProj/Src/Core/ObjectClone.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs index 2de7441..f4a6a52 100644 --- a/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs +++ b/Source/VSProj/Src/Core/ReflectionMethodInvoker.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/StackOperation.cs b/Source/VSProj/Src/Core/StackOperation.cs index 541d55c..083067b 100644 --- a/Source/VSProj/Src/Core/StackOperation.cs +++ b/Source/VSProj/Src/Core/StackOperation.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/SwitchFlags.cs b/Source/VSProj/Src/Core/SwitchFlags.cs index b93d1a2..93e5a50 100644 --- a/Source/VSProj/Src/Core/SwitchFlags.cs +++ b/Source/VSProj/Src/Core/SwitchFlags.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/Utils.cs b/Source/VSProj/Src/Core/Utils.cs index 746451b..370b98c 100644 --- a/Source/VSProj/Src/Core/Utils.cs +++ b/Source/VSProj/Src/Core/Utils.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Core/VirtualMachine.cs b/Source/VSProj/Src/Core/VirtualMachine.cs index 128099a..351cac6 100644 --- a/Source/VSProj/Src/Core/VirtualMachine.cs +++ b/Source/VSProj/Src/Core/VirtualMachine.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ @@ -1626,43 +1626,43 @@ public static void _Info(string a) 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; - } - } + 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; + } + } } } } diff --git a/Source/VSProj/Src/Core/WrappersManager.cs b/Source/VSProj/Src/Core/WrappersManager.cs index f087ec0..c92eed0 100644 --- a/Source/VSProj/Src/Core/WrappersManager.cs +++ b/Source/VSProj/Src/Core/WrappersManager.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/PerfTest/PerfTest.cs b/Source/VSProj/Src/PerfTest/PerfTest.cs index c54524f..2dfbe97 100644 --- a/Source/VSProj/Src/PerfTest/PerfTest.cs +++ b/Source/VSProj/Src/PerfTest/PerfTest.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/TestDLL/BaseTest.cs b/Source/VSProj/Src/TestDLL/BaseTest.cs index 8b784b5..85f19ce 100644 --- a/Source/VSProj/Src/TestDLL/BaseTest.cs +++ b/Source/VSProj/Src/TestDLL/BaseTest.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs b/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs index 54912ac..836cd84 100644 --- a/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs +++ b/Source/VSProj/Src/TestDLL/RedirectBaseTest.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Tools/CSFix.cs b/Source/VSProj/Src/Tools/CSFix.cs index cf2721f..615814b 100644 --- a/Source/VSProj/Src/Tools/CSFix.cs +++ b/Source/VSProj/Src/Tools/CSFix.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Tools/CecilExtensions.cs b/Source/VSProj/Src/Tools/CecilExtensions.cs index bc9691b..5c278ef 100644 --- a/Source/VSProj/Src/Tools/CecilExtensions.cs +++ b/Source/VSProj/Src/Tools/CecilExtensions.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Tools/CodeTranslator.cs b/Source/VSProj/Src/Tools/CodeTranslator.cs index 104bc51..561056b 100644 --- a/Source/VSProj/Src/Tools/CodeTranslator.cs +++ b/Source/VSProj/Src/Tools/CodeTranslator.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Tools/GenerateConfigure.cs b/Source/VSProj/Src/Tools/GenerateConfigure.cs index 68e6f7a..3fe8915 100644 --- a/Source/VSProj/Src/Tools/GenerateConfigure.cs +++ b/Source/VSProj/Src/Tools/GenerateConfigure.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs b/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs index 4f44926..4a5ebf5 100644 --- a/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs +++ b/Source/VSProj/Src/UnitTest/VirtualMachineTest.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */ diff --git a/Source/VSProj/Src/Version.cs b/Source/VSProj/Src/Version.cs index 1f96567..fa127ec 100644 --- a/Source/VSProj/Src/Version.cs +++ b/Source/VSProj/Src/Version.cs @@ -1,6 +1,6 @@ /* * 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. + * Copyright (C) 2019 Tencent. 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. */