void FixBody(MethodBody body, TypeDefinition localDesigner) { Dictionary <Instruction, int> instructions = new Dictionary <Instruction, int>(); var processor = body.GetILProcessor(); string designerFullName = $"{localDesigner.FullName}/"; foreach (var i in body.Instructions) { string line = i.ToString(); if (line.Contains(designerFullName) && !instructions.ContainsKey(i)) { var match = opCodeRegex.Match(line); if (match.Success && match.Groups.Count == 5) { string key = match.Groups[4].Value.Replace(designerFullName, string.Empty); if (designerConstants.ContainsKey(key) && !instructions.ContainsKey(i)) { instructions.Add(i, designerConstants [key]); } } } } if (instructions.Count > 0) { Context.LogMessage($" Fixing up {body.Method.FullName}"); } foreach (var i in instructions) { var newCode = Extensions.CreateLoadArraySizeOrOffsetInstruction(i.Value); Context.LogMessage($" Replacing {i.Key}"); Context.LogMessage($" With {newCode}"); processor.Replace(i.Key, newCode); } }
void UpdateMagicPrefill(TypeDefinition magicType) { var fieldTypesMap = magicType.Fields.FirstOrDefault(f => f.Name == "typesMap"); if (fieldTypesMap == null) { return; } var methodPrefill = Extensions.GetMethod(magicType, "Prefill"); if (methodPrefill == null) { return; } var typeDictionary = _context.GetType("mscorlib", "System.Collections.Generic.Dictionary`2"); var ctorDictionary = Extensions.GetMethod(typeDictionary, ".ctor", new string[] { "System.Int32" }); var methodSetItem = Extensions.GetMethod(typeDictionary, "set_Item", new string[] { "TKey", "TValue" }); var genericTypeDictionary = new GenericInstanceType(typeDictionary); genericTypeDictionary.GenericArguments.Add(_context.GetType("mscorlib", "System.String")); genericTypeDictionary.GenericArguments.Add(_context.GetType("mscorlib", "System.Int32")); var genericMethodDictionaryCtor = CreateGenericMethodReference(ctorDictionary, genericTypeDictionary); var genericMethodDictionarySetItem = CreateGenericMethodReference(methodSetItem, genericTypeDictionary); var importedMethodSetItem = magicType.Module.ImportReference(genericMethodDictionarySetItem); var instructions = methodPrefill.Body.Instructions; instructions.Clear(); instructions.Add(Extensions.CreateLoadArraySizeOrOffsetInstruction(marshalTypes.Count)); instructions.Add(Instruction.Create(OpCodes.Newobj, magicType.Module.ImportReference(genericMethodDictionaryCtor))); instructions.Add(Instruction.Create(OpCodes.Stsfld, fieldTypesMap)); int idx = 0; foreach (var type in marshalTypes) { instructions.Add(Instruction.Create(OpCodes.Ldsfld, fieldTypesMap)); instructions.Add(Instruction.Create(OpCodes.Ldstr, type.FullName.Replace("/__<$>_jni_marshal_methods", "").Replace("/", "+"))); instructions.Add(Extensions.CreateLoadArraySizeOrOffsetInstruction(idx++)); instructions.Add(Instruction.Create(OpCodes.Callvirt, importedMethodSetItem)); } instructions.Add(Instruction.Create(OpCodes.Ret)); }
bool UpdateMarshalRegisterMethod(MethodDefinition method, HashSet <string> markedMethods) { var instructions = method.Body.Instructions; var arraySizeUpdated = false; var idx = 0; var arrayOffset = 0; while (idx < instructions.Count) { if (!arraySizeUpdated && idx + 1 < instructions.Count) { int length; if (IsLdcI4(instructions [idx++], out length) && instructions [idx].OpCode == OpCodes.Newarr) { instructions [idx - 1] = Extensions.CreateLoadArraySizeOrOffsetInstruction(markedMethods.Count); idx++; arraySizeUpdated = true; continue; } } else if (idx + 9 < instructions.Count) { var chunkStart = idx; if (instructions [idx++].OpCode != OpCodes.Dup) { continue; } int offset; var offsetIdx = idx; if (!IsLdcI4(instructions [idx++], out offset)) { continue; } if (instructions [idx++].OpCode != OpCodes.Ldstr) { continue; } if (instructions [idx++].OpCode != OpCodes.Ldstr) { continue; } if (instructions [idx++].OpCode != OpCodes.Ldnull) { continue; } if (instructions [idx++].OpCode != OpCodes.Ldftn) { continue; } if (!(instructions [idx - 1].Operand is MethodReference mr)) { continue; } if (instructions [idx++].OpCode != OpCodes.Newobj) { continue; } if (instructions [idx++].OpCode != OpCodes.Newobj) { continue; } var chunkEnd = idx; if (instructions [idx++].OpCode != OpCodes.Stelem_Any) { continue; } if (markedMethods.Contains(mr.Name)) { instructions [offsetIdx] = Extensions.CreateLoadArraySizeOrOffsetInstruction(arrayOffset++); continue; } for (int i = 0; i <= chunkEnd - chunkStart; i++) { instructions.RemoveAt(chunkStart); } idx = chunkStart; } else { break; } } if (!arraySizeUpdated || arrayOffset != markedMethods.Count) { _context.LogMessage($"Unable to update {method} size updated {arraySizeUpdated} counts {arrayOffset} {markedMethods.Count}"); return(false); } MarkMethod(method); return(true); }