/// <summary> /// Gets the attributes of the given type. /// </summary> /// <typeparam name="T">The type of the attributes.</typeparam> /// <param name="jm">The java method.</param> /// <returns>The attributes of the given type.</returns> public static T[] GetAttributes <T>(this JavaMethod jm) where T : IJavaAttribute { Guard.NotNull(ref jm, nameof(jm)); return(jm.Attributes.Where(x => x is T).Select(x => (T)x).ToArray()); }
public JavaMethod ResoverMethod() { if (this.Method != null) { return(this.Method); } var d = this.ConstantPool.Class; var c = this.ResoverClass(); if (!c.IsInterface()) { throw new Exception(); } var result = FindMethodInInterface(c); if (result == null) { throw new Exception(); } if (!result.IsAccessTo(d)) { throw new Exception(); } this.Method = result; return(result); }
IEnumerable <ApiComparisonReport> CompareMethod(JavaMethod rm, JavaMethod tm) { return(Enumerable.Empty <ApiComparisonReport> () // .Concat (CompareProperty (nameof (rf.Deprecated), rf, tf, _ => _.Deprecated)) .Concat(CompareProperty(nameof(rm.Abstract), rm, tm, _ => _.Abstract)) .Concat(CompareProperty(nameof(rm.Static), rm, tm, _ => _.Static))); }
/// <summary> /// Gets the descriptor of a method. /// </summary> /// <param name="jm">The java method.</param> /// <param name="jc">The java class.</param> /// <returns>The descriptor of the java method.</returns> public static string GetDescriptor(this JavaMethod jm, JavaClass jc) { Guard.NotNull(ref jc, nameof(jc)); Guard.NotNull(ref jm, nameof(jm)); return(jc.GetConstant <JavaConstantUtf8>(jm.DescriptorIndex).Value); }
public void AddForeignMethod(ForeignMethod fm, ExpandInterceptor expandInterceptor) { var jmtd = new JavaMethod(fm, _helpers, _convert, expandInterceptor, _environment); _methods.Add(jmtd); _blockHost.NativeJavaMethods.Add(jmtd.GenJavaEntrypointMethod(this)); }
public unsafe void RunClient() { Console.WriteLine("Launching Hardware Monitor Editor"); JavaMethod nativeLaunch = jvm.GetStaticVoidMethod(APPLICATION_CORE_CLASS_PATH, APPLICATION_CORE_LAUNCH_APPLICATION_FUNCTION); jvm.CallStaticVoidMethod(nativeLaunch); }
static bool SkipMethodByReturnType(JavaMethod method) { // discard bridge methods that only change the return types int n = method.Parameters?.Count ?? 0; foreach (var otherMethod in method.Class.Methods) { if (otherMethod != method && otherMethod.Name == method.Name && method.Name != "<init>") { int n2 = otherMethod.Parameters?.Count ?? 0; if (n == n2) { bool same = true; for (int i = 0; i < n && same; i++) { same = method.Parameters[i].Type.Equals(otherMethod.Parameters[i].Type); } if (same) { if (method.ReturnType.ClassName != method.Class.Name && otherMethod.ReturnType.ClassName == method.Class.Name) { return(true); } } } } } return(false); }
/// <summary> /// Gets the attribute of the given type. /// </summary> /// <typeparam name="T">The type of the attribute.</typeparam> /// <param name="jm">The java method.</param> /// <returns>The attribute of the given type.</returns> public static T GetAttribute <T>(this JavaMethod jm) where T : IJavaAttribute { Guard.NotNull(ref jm, nameof(jm)); return(jm.GetAttributes <T>().FirstOrDefault()); }
void LoadDll(string file, string sourceIdentifier = null) { foreach (var ta in AssemblyDefinition.ReadAssembly(file).Modules.SelectMany(m => m.Types.SelectMany(t => FlattenTypeHierarchy(t))) .Where(ta => !ta.Name.EndsWith("Invoker", StringComparison.Ordinal) && !ta.Name.EndsWith("Implementor", StringComparison.Ordinal)) .Select(t => new Tuple <TypeDefinition, CustomAttribute> (t, GetRegisteredAttribute(t))) .Where(p => p.Item2 != null)) { var td = ta.Item1; var tatt = PopulateRegisterAttributeInfo(ta.Item2, true); var pkg = Api.Packages.FirstOrDefault(p => p.Name == tatt.Package); if (pkg == null) { Api.Packages.Add(pkg = new JavaPackage(Api) { Name = tatt.Package }); } var type = td.IsInterface ? (JavaType) new JavaInterface(pkg) : new JavaClass(pkg); type.Name = tatt.Name; type.SetExtension(td); pkg.Types.Add(type); foreach (var fa in td.Fields .Select(f => new Tuple <FieldDefinition, CustomAttribute> (f, GetRegisteredAttribute(f))) .Where(p => p.Item2 != null)) { var matt = PopulateRegisterAttributeInfo(fa.Item2); var f = new JavaField(type) { Name = matt.Name, Static = fa.Item1.IsStatic, Final = fa.Item1.HasConstant }; f.SetExtension(fa.Item1); type.Members.Add(f); } foreach (var ma in GetAllMethods(td) .Where(m => m != null) .Select(m => new Tuple <MethodDefinition, CustomAttribute> (m, GetRegisteredAttribute(m))) .Where(p => p.Item2 != null)) { var matt = PopulateRegisterAttributeInfo(ma.Item2); var m = new JavaMethod(type) { Name = matt.Name, Abstract = ma.Item1.IsAbstract, Static = ma.Item1.IsStatic }; var jniParameters = matt.JniSignature.Substring(0, matt.JniSignature.IndexOf(')')).Substring(1); m.Return = ParseJniParameters(matt.JniSignature.Substring(matt.JniSignature.IndexOf(')') + 1)).First(); m.Parameters = ParseJniParameters(jniParameters) .Zip(ma.Item1.Parameters, (s, mp) => new { Type = s, ManagedParameter = mp }) .Select(_ => new JavaParameter(m) { Name = _.ManagedParameter.Name, Type = _.Type }) .ToArray(); m.SetExtension(ma.Item1); type.Members.Add(m); } } FillSourceIdentifier(Api, sourceIdentifier ?? file); }
/// <summary> /// Gets the return type of a method. /// </summary> /// <param name="jm">The java method.</param> /// <param name="jc">The java class.</param> /// <returns>The return type of the java method.</returns> public static string GetReturnType(this JavaMethod jm, JavaClass jc) { Guard.NotNull(ref jc, nameof(jc)); Guard.NotNull(ref jm, nameof(jm)); string descriptor = jm.GetDescriptor(jc); return(DescriptorHelper.GetReturn(descriptor)); }
public static MetadataJavaMethod ToMetadata(this JavaMethod method) { return(new MetadataJavaMethod { AccessFlags = (JavaAccessFlags)method.Flags, ReturnType = method.Type.GetSignature(), Name = method.Name, Parameters = method.Parameters.Select(p => p.ToMetadata()).ToArray() }); }
internal static void BuildJavaCode(JavaMethod newMethod, CilMethod myMethod, MethodDefinition defMethod, int numCastableInterfaces) { var body = defMethod.Body; if (body.Instructions.Count == 0) { throw CilMain.Where.Exception("input method is empty"); } if (body.Instructions[body.Instructions.Count - 1].Offset > 0xFFF0) { throw CilMain.Where.Exception("input method is too large"); } CodeBuilder o = null; try { o = new CodeBuilder(); o.defMethod = defMethod; o.defMethodBody = defMethod.Body; o.newMethod = newMethod; o.method = myMethod; o.numCastableInterfaces = numCastableInterfaces; o.Process(); } catch (Exception e) { if (e is JavaException) { throw; } #if DEBUGDIAG Console.WriteLine(e); #endif if (o != null && o.cilInst != null) { if (o.lineNumber != 0) { CilMain.Where.Push($"line {o.lineNumber}"); } CilMain.Where.Push( $"'{o.cilInst.OpCode.Name}' instruction at offset {o.cilInst.Offset,0:X4}"); } string msg = e.Message; if (e is InvalidProgramException) { msg = "unexpected opcode or operands"; } throw CilMain.Where.Exception(msg); } }
/// <summary> /// Reads methods from the stream. /// </summary> /// <param name="stream">The stream to read the methods from.</param> /// <param name="count">The number of methods to read.</param> /// <param name="constantPool">The constant pool used for finding the attribute names.</param> /// <returns>The methods read from the stream.</returns> private static JavaMethod[] ReadMethods(Stream stream, int count, JavaConstantPool constantPool) { JavaMethod[] result = new JavaMethod[count]; for (int i = 0; i < count; i++) { result[i] = ReadMethod(stream, constantPool); } return(result); }
static CacheInvalidatorCallback() { using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream("Com.MihaiConsulting.Cache.JuggerNET.CacheInvalidatorCallback.class")) { Byte[] buffer = new Byte[resourceStream.Length]; resourceStream.Read(buffer, 0, (int)resourceStream.Length); _cmj_theClass.ByteCode = buffer; } _constructor = new JavaMethod(_cmj_theClass, null, "<init>", "(J[J)V", false); }
private JavaAttributeCode GetCode(JavaMethod method) { foreach (IJavaAttribute attribute in method.Attributes) { if (attribute is JavaAttributeCode code) { return(code); } } throw new Exception("No code attribute found."); }
public JavaMethod ResoverMethod() { if (this.Method != null) { return(Method); } var d = this.ConstantPool.Class; var c = this.ResoverClass(); //从d访问c的方法 if (c.IsInterface()) { throw new Exception(); } //先从继承链中找 var target = c; JavaMethod findedMethod = null; while (target != null) { findedMethod = c.Methods.FirstOrDefault(x => x.Name == this.Name && x.Descriptor == this.Desc); if (findedMethod == null) { target = target.SuperClass; } else { break; } } if (findedMethod == null) { foreach (var inte in c.Interfaces) { findedMethod = FindMethodInInterface(inte); if (findedMethod != null) { break; } } } if (findedMethod == null) { throw new Exception(); } if (!findedMethod.IsAccessTo(d)) { throw new Exception(); } Method = findedMethod; return(findedMethod); }
/// <summary> /// Initializes the <see cref="CacheChannelEventListenerCallback" /> class. /// </summary> static CacheChannelEventListenerCallback() { // Load the Java callback class bytecode from Com.Tridion.Cache.CacheChannelEventListenerCallback using (Stream resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(typeof(CacheChannelEventListenerCallback), "CacheChannelEventListenerCallback")) { Byte[] buffer = new Byte[resourceStream.Length]; resourceStream.Read(buffer, 0, (int)resourceStream.Length); _cmj_theClass.ByteCode = buffer; } mConstructor = new JavaMethod(_cmj_theClass, null, "<init>", "(J[J)V", false); }
private static IReadOnlyCollection <JavaMethod> GetJavaMethods(JavaClass javaClass) { var methods = new List <JavaMethod>(); foreach (var method in javaClass.Methods) { var javaMethod = new JavaMethod(); javaMethod.MethodName = method.NameAsStr; javaMethod.Signature = GetMethodSignature(javaClass, method); methods.Add(javaMethod); } return(new ReadOnlyCollection <JavaMethod>(methods)); }
private static void EmitMethod(MethodDefinition method, JavaClass jc, JavaMethod jm) { ModuleDefinition module = method.Module; string[] parameterTypes = jm.GetParameterTypes(jc); byte[] code = jm.GetCode(); ILProcessor il = method.Body?.GetILProcessor(); if (il != null && code != null) { new IlEmitter(il, module).EmitMethod(jc, code, method.IsStatic, parameterTypes); } }
public unsafe void UpdateNative(IntPtr env, IntPtr clazz) { UpdateSensors(); foreach (var pair in sensorObjects) { ParameterBuilder builder = new ParameterBuilder().AddFloat(pair.Value.Value.Value); // // Populate the sensor object JavaMethod setValueMethod = jvm.GetMethod(SENSOR_REQUEST_CLASS_PATH, SENSOR_REQUEST_SET_VALUE_FUNCTION, builder.GetParameterString()); jvm.CallVoidMethod(pair.Key, setValueMethod, builder.Build()); } }
/// <summary> /// Gets the parameter names of a method. /// </summary> /// <param name="jm">The java method.</param> /// <param name="jc">The java class.</param> /// <returns>The parameter names of the java method.</returns> public static string[] GetParameterNames(this JavaMethod jm, JavaClass jc) { Guard.NotNull(ref jc, nameof(jc)); Guard.NotNull(ref jm, nameof(jm)); JavaAttributeMethodParameters attribute = jm.GetAttribute <JavaAttributeMethodParameters>(); if (attribute == null) { int count = jm.GetParameterTypes(jc).Length; return(Enumerable.Range(0, count).Select(x => $"obj{x}").ToArray()); } return(attribute.Parameters.Select(x => jc.GetConstant <JavaConstantUtf8>(x.NameIndex).Value).ToArray()); }
public static void ConstructorTest() { JavaMethodAccessFlags flags = JavaMethodAccessFlags.Native | JavaMethodAccessFlags.Private; ushort us1 = 1; ushort us2 = 2; ushort us3 = 3; IJavaAttribute[] attributes = new IJavaAttribute[2]; JavaMethod jm = new JavaMethod(flags, us1, us2, us3, attributes); AssertThat(jm.AccessFlags).IsEqualTo(flags); AssertThat(jm.NameIndex).IsEqualTo(us1); AssertThat(jm.DescriptorIndex).IsEqualTo(us2); AssertThat(jm.AttributesCount).IsEqualTo(us3); AssertThat(jm.Attributes).ContainsExactly(attributes); }
internal static JavaCode CreateHelperMethod(JavaClass theClass, JavaMethodRef methodType, int maxLocals, int maxStack) { var newMethod = new JavaMethod(theClass, methodType); newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE; var code = newMethod.Code = new JavaCode(); code.Method = newMethod; code.Instructions = new List <JavaCode.Instruction>(); code.MaxLocals = maxLocals; code.MaxStack = maxStack; theClass.Methods.Add(newMethod); return(code); }
/// <summary> /// Gets the type attributes. /// </summary> /// <param name="jm">The java method.</param> /// <returns>The type attributes of the method.</returns> public static MethodAttributes GetAttributes(this JavaMethod jm) { Guard.NotNull(ref jm, nameof(jm)); JavaMethodAccessFlags accessFlags = jm.AccessFlags; MethodAttributes result = MethodAttributes.HideBySig; if (accessFlags.HasFlag(JavaMethodAccessFlags.Abstract)) { result |= MethodAttributes.Abstract; } if (accessFlags.HasFlag(JavaMethodAccessFlags.Final)) { result |= MethodAttributes.Final; } else { result |= MethodAttributes.Virtual; } if (accessFlags.HasFlag(JavaMethodAccessFlags.Public)) { result |= MethodAttributes.Public; } if (accessFlags.HasFlag(JavaMethodAccessFlags.Private)) { result |= MethodAttributes.Private; } if (accessFlags.HasFlag(JavaMethodAccessFlags.Protected)) { result |= MethodAttributes.Family; } if (accessFlags.HasFlag(JavaMethodAccessFlags.Static)) { result |= MethodAttributes.Static; } return(result); }
private void AppendMethod(StringBuilder sb, JavaClass jc, JavaMethod method) { if (method.AccessFlags.HasFlag(JavaMethodAccessFlags.Public)) { sb.Append("public "); } else if (method.AccessFlags.HasFlag(JavaMethodAccessFlags.Private)) { sb.Append("private "); } else if (method.AccessFlags.HasFlag(JavaMethodAccessFlags.Protected)) { sb.Append("protected "); } if (method.AccessFlags.HasFlag(JavaMethodAccessFlags.Static)) { sb.Append("static "); } else if (method.AccessFlags.HasFlag(JavaMethodAccessFlags.Abstract)) { sb.Append("abstract "); } string descriptor = ((JavaConstantUtf8)jc.ConstantPool[method.DescriptorIndex]).Value; sb.Append(GetReturnType(descriptor)).Append(" "); sb.Append(((JavaConstantUtf8)jc.ConstantPool[method.NameIndex]).Value).Append('('); sb.Append(string.Join(", ", GetParameterTypes(descriptor))); sb.Append("){"); sb.Append('}'); }
public static void CreateSuppressibleFinalize(JavaMethod innerMethod, CilType declType, JavaClass theClass) { // // if the class defines a finalizer method Finalize() then: // // - create a flag field that tracks whether finalization is suppressed // // - implement interface system.GC.FinalizeSuppressible, and its Set() // method, which sets the flag field // // - create a wrapper method that checks the flag field and possibly // invokes the original finalizer // // see also: system.GC in baselib // var flagField = new JavaField(); flagField.Name = "-finalize-suppressed"; flagField.Type = CilType.From(JavaType.BooleanType); flagField.Class = theClass; flagField.Flags = JavaAccessFlags.ACC_PRIVATE | JavaAccessFlags.ACC_VOLATILE; if (theClass.Fields == null) { theClass.Fields = new List <JavaField>(); } theClass.Fields.Add(flagField); // // implement the interface method // var ifcMethod = new JavaMethod("system-GC$SuppressibleFinalize-Set", JavaType.VoidType); ifcMethod.Class = theClass; ifcMethod.Flags = JavaAccessFlags.ACC_PUBLIC; var code = ifcMethod.Code = new JavaCode(); code.Method = ifcMethod; code.Instructions = new List <JavaCode.Instruction>(); code.MaxLocals = code.MaxStack = 2; code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0x12 /* ldc */, null, (int)1); code.NewInstruction(0xB5 /* putfield */, declType, flagField); code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null); theClass.Methods.Add(ifcMethod); theClass.AddInterface("system.GC$SuppressibleFinalize"); // // create the wrapper method // var outerMethod = new JavaMethod(theClass, innerMethod); outerMethod.Flags = JavaAccessFlags.ACC_PROTECTED; innerMethod.Flags = JavaAccessFlags.ACC_PRIVATE; innerMethod.Name += "---inner"; // prepare to generate instructions code = outerMethod.Code = new JavaCode(); code.Method = outerMethod; code.Instructions = new List <JavaCode.Instruction>(); code.StackMap = new JavaStackMap(); code.StackMap.SaveFrame((ushort)0, false, CilMain.Where); code.MaxLocals = code.MaxStack = 1; // // check the flag field to determine if suppressed // code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB4 /* getfield */, declType, flagField); code.NewInstruction(0x9A /* ifne != zero */, null, (ushort)0xFFFE); code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB7 /* invokespecial */, declType, innerMethod); code.NewInstruction(JavaType.VoidType.ReturnOpcode, null, null, /* label */ 0xFFFE); code.StackMap.SaveFrame((ushort)0xFFFE, true, CilMain.Where); theClass.Methods.Add(outerMethod); }
public static JavaMethod CreateSyncWrapper(JavaMethod innerMethod, CilType declType) { // // if method is decorated with [MethodImplOptions.Synchronized], // create a wrapper method that locks the object (for instance methods) // or the type (for static methods), and then calls the original method, // which we make private and rename to have a unique suffix // if (innerMethod.Name == "<init>") { throw CilMain.Where.Exception("[Synchronized] is not supported on constructors"); } var outerMethod = new JavaMethod(innerMethod.Class, innerMethod); outerMethod.Flags = innerMethod.Flags; innerMethod.Flags &= ~(JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_PROTECTED); innerMethod.Flags |= JavaAccessFlags.ACC_PRIVATE; innerMethod.Name += "---inner"; // count the size of locals in the parameters, plus one. we have to // add one for an instance method, to account for the 'this' argument. // and if a static method, we have to add one for the lock object. var numLocals = 1; for (int i = outerMethod.Parameters.Count; i-- > 0;) { numLocals += outerMethod.Parameters[i].Type.Category; } // prepare to generate instructions var code = outerMethod.Code = new JavaCode(); code.Method = outerMethod; code.Instructions = new List <JavaCode.Instruction>(); code.MaxLocals = numLocals + 1; var exception = new JavaAttribute.Code.Exception(); exception.start = /* label */ 1; exception.endPlus1 = /* label */ 2; exception.handler = /* label */ 3; exception.catchType = CodeExceptions.ThrowableType.ClassName; code.Exceptions = new List <JavaAttribute.Code.Exception>(); code.Exceptions.Add(exception); code.StackMap = new JavaStackMap(); code.StackMap.SaveFrame((ushort)0, false, CilMain.Where); // get a reference to 'this' (for instance methods) // or to the type object (for static methods), // then lock on the reference pushed on the stack int lockedObjectIndex; if ((outerMethod.Flags & JavaAccessFlags.ACC_STATIC) == 0) { code.NewInstruction(0x19 /* aload */, null, (int)0); code.StackMap.PushStack(JavaType.ObjectType); code.StackMap.SetLocal(0, JavaType.ObjectType); lockedObjectIndex = 0; } else { GenericUtil.LoadMaybeGeneric(declType, code); code.NewInstruction(0x59 /* dup */, null, null); code.StackMap.PushStack(JavaType.ObjectType); code.StackMap.PopStack(CilMain.Where); code.NewInstruction(0x3A /* astore */, null, (int)numLocals); code.StackMap.SetLocal((int)numLocals, JavaType.ObjectType); lockedObjectIndex = (int)numLocals; } code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, "system.threading.Monitor"), new JavaMethodRef( "Enter", JavaType.VoidType, JavaType.ObjectType)); code.StackMap.PopStack(CilMain.Where); code.NewInstruction(0x00 /* nop */, null, null, /* label */ 1); code.StackMap.SaveFrame((ushort)1, false, CilMain.Where); // push all arguments for the call to the inner method byte callOpcode; int localIndex = 0; if ((outerMethod.Flags & JavaAccessFlags.ACC_STATIC) == 0) { code.StackMap.PushStack(JavaType.ObjectType); code.NewInstruction(0x19 /* aload */, null, (int)0); localIndex++; callOpcode = 0xB7; // invokespecial } else { callOpcode = 0xB8; // invokestatic } for (int i = 0; i < outerMethod.Parameters.Count; i++) { var paramType = outerMethod.Parameters[i].Type; code.StackMap.PushStack(paramType); code.NewInstruction(paramType.LoadOpcode, null, (int)localIndex); localIndex += paramType.Category; } code.NewInstruction(callOpcode, declType, innerMethod); // if we get here, then no exception was thrown in the // inner method, we need to unlock and return the result code.StackMap.ClearStack(); if (!innerMethod.ReturnType.Equals(JavaType.VoidType)) { code.StackMap.PushStack(innerMethod.ReturnType); } code.NewInstruction(0x00 /* nop */, null, null, /* label */ 2); code.StackMap.SaveFrame((ushort)2, false, CilMain.Where); code.NewInstruction(0x19 /* aload */, null, lockedObjectIndex); code.StackMap.PushStack(JavaType.ObjectType); code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, "system.threading.Monitor"), new JavaMethodRef( "Exit", JavaType.VoidType, JavaType.ObjectType)); code.NewInstruction(innerMethod.ReturnType.ReturnOpcode, null, null); // if we get here, then an exception was thrown, unlock // and rethrow the exception code.StackMap.ClearStack(); code.StackMap.PushStack(CodeExceptions.ThrowableType); code.NewInstruction(0x00 /* nop */, null, null, /* label */ 3); code.StackMap.SaveFrame((ushort)3, true, CilMain.Where); code.NewInstruction(0x19 /* aload */, null, lockedObjectIndex); code.StackMap.PushStack(JavaType.ObjectType); code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, "system.threading.Monitor"), new JavaMethodRef( "Exit", JavaType.VoidType, JavaType.ObjectType)); code.StackMap.PopStack(CilMain.Where); code.NewInstruction(0xBF /* athrow */, null, null); code.StackMap.ClearStack(); code.MaxStack = code.StackMap.GetMaxStackSize(CilMain.Where); return(outerMethod); }
public static JavaMethod BuildPlainProxy(CilInterfaceMethod ifcMethod, CilType intoType, List <CilInterfaceMethod> classMethods) { CilMethod targetMethod = null; foreach (var clsMethod in classMethods) { if (clsMethod.Method.IsExplicitImpl) { // no need for a proxy if we already have an override method, // which has the same name as the proxy: interface$method if (ifcMethod.Method.Name == clsMethod.Method.Name) { return(null); } } else if (ifcMethod.PlainCompare(clsMethod)) { // more than one method may match, if a derived type overrides // or hides a method that also exists in a base type. but the // derived (primary) type methods always come first. if (targetMethod == null) { targetMethod = clsMethod.Method; } } } if (targetMethod == null) { throw CilMain.Where.Exception( $"missing method '{ifcMethod.Method}' " + $"(for interface '{ifcMethod.Method.DeclType}')"); } if (targetMethod.IsRetainName) { // method retains is name, so it doesn't require a proxy bridge return(null); } // // create proxy method // var newMethod = new JavaMethod(null, targetMethod); newMethod.Name = ifcMethod.Method.Name; newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE; var code = newMethod.Code = new JavaCode(); code.Method = newMethod; code.Instructions = new List <JavaCode.Instruction>(); // // push 'this' and all other parameters // code.NewInstruction(0x19 /* aload */, null, (int)0); int numArgs = newMethod.Parameters.Count; int index = 1; for (int i = 0; i < numArgs; i++) { var arg = targetMethod.Parameters[i].Type; code.NewInstruction(arg.LoadOpcode, null, (int)index); index += arg.Category; } // // invoke proxy target method and return // code.NewInstruction(0xB6 /* invokevirtual */, intoType, targetMethod); code.NewInstruction(targetMethod.ReturnType.ReturnOpcode, null, null); code.MaxLocals = code.MaxStack = index; return(newMethod); }
public static void BuildGenericProxy2(CilInterfaceMethod ifcMethod, CilMethod targetMethod, bool parentField, CilType intoType, JavaClass ifcClass) { // // create proxy method // var targetMethod2 = targetMethod.WithGenericParameters; var ifcMethod2 = ifcMethod.Method.WithGenericParameters; var newMethod = new JavaMethod(ifcClass, targetMethod2); newMethod.Name = ifcMethod2.Name; newMethod.Flags = JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_BRIDGE; var code = newMethod.Code = new JavaCode(); code.Method = newMethod; code.Instructions = new List <JavaCode.Instruction>(); // // push a reference to the parent object // code.NewInstruction(0x19 /* aload */, null, (int)0); if (parentField) { code.NewInstruction(0xB4 /* getfield */, new JavaType(0, 0, ifcClass.Name), new JavaFieldRef(ParentFieldName, intoType)); } // // push all other parameters // int numArgs = newMethod.Parameters.Count; int index = 1; int maxStack = 1; for (int i = 0; i < numArgs; i++) { var ifcArg = ifcMethod2.Parameters[i].Type; code.NewInstruction(ifcArg.LoadOpcode, null, (int)index); index += ifcArg.Category; var clsArg = (CilType)targetMethod2.Parameters[i].Type; if (JavaType.ObjectType.Equals(ifcArg)) { if (!clsArg.IsReference) { var boxedArg = new BoxedType(clsArg, false); code.NewInstruction(0xC0 /* checkcast */, boxedArg, null); boxedArg.GetValue(code); } else if (!JavaType.ObjectType.Equals(clsArg)) { code.NewInstruction(0xC0 /* checkcast */, clsArg, null); } // a parameter in the target method may be a concrete type, // but if it is a generic java.lang.Object in the interface, // then it must be a generic java.lang.Object in the proxy newMethod.Parameters[i] = new JavaFieldRef("", ifcArg); } maxStack += clsArg.Category; } // // invoke proxy target method // code.NewInstruction(0xB6 /* invokevirtual */, intoType, targetMethod2); // // return value from method // var clsRet = (CilType)targetMethod2.ReturnType; var ifcRet = ifcMethod2.ReturnType; if (JavaType.ObjectType.Equals(ifcRet)) { if (!clsRet.IsReference) { var boxedArg = new BoxedType(clsRet, false); boxedArg.BoxValue(code); } // the return value in the target method may be a concrete type, // but if it is a generic java.lang.Object in the interface, // then it must also be a generic java.lang.Object in the proxy newMethod.ReturnType = ifcRet; code.NewInstruction(ifcRet.ReturnOpcode, null, null); } else { code.NewInstruction(clsRet.ReturnOpcode, null, null); } code.MaxLocals = index; code.MaxStack = maxStack; ifcClass.Methods.Add(newMethod); }
public static void ImportMethods(JavaClass jclass, TypeDefinition cilType, int numCastableInterfaces) { if (cilType.HasMethods) { int n = cilType.Methods.Count; if (n > 0) { jclass.Methods = new List <JavaMethod>(n); for (int i = 0; i < n; i++) { var defMethod = cilType.Methods[i]; /* * if (defMethod.HasCustomAttribute("Discard")) * continue; // if decorated with [java.attr.Discard], don't export to java */ var genericMark = CilMain.GenericStack.Mark(); var myMethod = CilMain.GenericStack.EnterMethod(defMethod); var newMethod = new JavaMethod(jclass, myMethod.WithGenericParameters); newMethod.Flags = AttributesToAccessFlags( defMethod.Attributes, defMethod.HasOverrides, (cilType.HasNestedTypes || cilType.HasGenericParameters)); if (myMethod.IsStatic & myMethod.IsConstructor) { newMethod.Flags &= ~(JavaAccessFlags.ACC_PUBLIC | JavaAccessFlags.ACC_PRIVATE | JavaAccessFlags.ACC_PROTECTED); } if (defMethod.HasBody) { CilMain.Where.Push($"method '{defMethod.Name}'"); CodeBuilder.BuildJavaCode(newMethod, myMethod, defMethod, numCastableInterfaces); if ((defMethod.ImplAttributes & MethodImplAttributes.Synchronized) != 0) { // if method is decorated with [MethodImplOptions.Synchronized], // create a wrapper method that locks appropriately jclass.Methods.Add( CodeBuilder.CreateSyncWrapper(newMethod, myMethod.DeclType)); } else if (defMethod.Name == "Finalize" && (!defMethod.HasParameters) && defMethod.IsVirtual) { // if method is a finalizer, create a wrapper method that // checks if finalization was suppressed for the object CodeBuilder.CreateSuppressibleFinalize( newMethod, myMethod.DeclType, jclass); } if (defMethod.IsVirtual) { InterfaceBuilder.BuildOverloadProxy( cilType, defMethod, myMethod, jclass); } else if (!myMethod.IsConstructor) { newMethod.Flags |= JavaAccessFlags.ACC_FINAL; } CilMain.Where.Pop(); } else { if ((!defMethod.IsAbstract) && (defMethod.IsInternalCall || defMethod.IsPInvokeImpl)) { // skip native methods continue; } // clear ACC_STATIC and access, set ACC_ABSTRACT and ACC_PUBLIC newMethod.Flags = (newMethod.Flags | JavaAccessFlags.ACC_ABSTRACT | JavaAccessFlags.ACC_PUBLIC) & ~(JavaAccessFlags.ACC_STATIC | JavaAccessFlags.ACC_PRIVATE | JavaAccessFlags.ACC_PROTECTED); } jclass.Methods.Add(newMethod); CilMain.GenericStack.Release(genericMark); if (myMethod.IsConstructor) { var dummyClass = CreateDummyClassForConstructor(myMethod, jclass); if (dummyClass != null) { CilMain.JavaClasses.Add(dummyClass); } } else if (myMethod.WithGenericParameters != myMethod && (!myMethod.IsRetainName)) { jclass.Methods.Add( Delegate.CreateCapturingBridgeMethod( newMethod, myMethod.Parameters, cilType.IsInterface)); } } } } else { jclass.Methods = new List <JavaMethod>(0); } JavaClass CreateDummyClassForConstructor(CilMethod theMethod, JavaClass theClass) { if (!theMethod.HasDummyClassArg) { return(null); } return(CilMain.CreateInnerClass( theClass, theMethod.Parameters[ theMethod.Parameters.Count - 1].Type.ClassName)); } }
/* * * The DroidDoc format from API Level 16 to 23, the format is: * * - All pages have ToC links and body (unlike standard JavaDoc which is based on HTML frames). * - The actual doc section is a div element whose id is "doc-col". * - The "doc-col" div element has a section div element whose id is "jd-header" and another one with id "jd-content". * - "jd-header" div element contains the type signature (modifiers, name, and inheritance). * - Here we care only about type name and kind (whether it is a class or interface). * - Generic arguments are insignificant. * - In the following terms I explain the "correct" (or "expected") document structure, but in fact * Google completely broke it and it is impossible to retrieve the document tree like this. * We workaround this issue by changing the strategy "iterate children of 'jd-content'" * with "iterate descendants of 'jd-content'"... It occurs only in API Level 15 or later. * - "jd-content" div element contains a collection of sections. Each section consists of: * - an "h2" element whose value text indicates the section name ("Public Constructors", "Protected Methods" etc.) * - There was an issue in javax/xml/validation/SchemaFactory.html in API Level 15 that the method details contain * "h2" and confuses the parser. To workaround this, we accept only limited kind of values. * - the content, which follows the h2 element. * - The section content is a collection of members. Each member consists of: * - an anchor ("A") element with "name" attribute, and * - a div element which contains an h4 child element whose class contains "jd-details-title". * - The h4 element contains the member signature. We parse it and retrieve the method name and list of parameters. * - Parameters are tokenized by ", ". * - Note that the splitter contains a white space which disambiguates any use of generic arguments (we don't want to split "Foo<K,V> bar" as "Foo<K" and "V> bar") * * API Level 10 to 15 has slightly different format: * * - There is no "doc-col" element. But "jd-header" and "jd-content" are still alive. * */ public void Import(ImporterOptions options) { options.DiagnosticWriter.WriteLine(options.DocumentDirectory); string referenceDocsTopDir = Path.Combine(options.DocumentDirectory, "reference"); var htmlFiles = Directory.GetDirectories(referenceDocsTopDir).SelectMany(d => Directory.GetFiles(d, "*.html", SearchOption.AllDirectories)); var api = new JavaApi(); foreach (var htmlFile in htmlFiles) { // skip irrelevant files. if (excludes.Any(x => htmlFile.EndsWith(x, StringComparison.OrdinalIgnoreCase))) { continue; } var packageName = Path.GetDirectoryName(htmlFile).Substring(referenceDocsTopDir.Length + 1).Replace('/', '.'); if (options.FrameworkOnly && non_frameworks.Any(n => packageName.StartsWith(n, StringComparison.Ordinal))) { continue; } options.DiagnosticWriter.WriteLine("-- " + htmlFile); var doc = new HtmlLoader().GetJavaDocFile(htmlFile); var header = doc.Descendants().FirstOrDefault(e => e.Attribute("id")?.Value == "jd-header"); var content = doc.Descendants().FirstOrDefault(e => e.Attribute("id")?.Value == "jd-content"); if (header == null || content == null) { continue; } var apiSignatureTokens = header.Value.Replace('\r', ' ').Replace('\n', ' ').Replace('\t', ' ').Trim(); if (apiSignatureTokens.Contains("extends ")) { apiSignatureTokens = apiSignatureTokens.Substring(0, apiSignatureTokens.IndexOf("extends ", StringComparison.Ordinal)).Trim(); } if (apiSignatureTokens.Contains("implements ")) { apiSignatureTokens = apiSignatureTokens.Substring(0, apiSignatureTokens.IndexOf("implements ", StringComparison.Ordinal)).Trim(); } bool isClass = apiSignatureTokens.Contains("class"); options.DiagnosticWriter.WriteLine(apiSignatureTokens); var javaPackage = api.Packages.FirstOrDefault(p => p.Name == packageName); if (javaPackage == null) { javaPackage = new JavaPackage(api) { Name = packageName }; api.Packages.Add(javaPackage); } var javaType = isClass ? (JavaType) new JavaClass(javaPackage) : new JavaInterface(javaPackage); javaType.Name = apiSignatureTokens.Substring(apiSignatureTokens.LastIndexOf(' ') + 1); javaPackage.Types.Add(javaType); string sectionType = null; var sep = new string [] { ", " }; var ssep = new char [] { ' ' }; foreach (var child in content.Descendants()) { if (child.Name == "h2") { var value = child.Value; switch (value) { case "Public Constructors": case "Protected Constructors": case "Public Methods": case "Protected Methods": sectionType = value; break; } continue; } if (sectionType == null) { continue; } if (child.Name != "a" || child.Attribute("name") == null) { continue; } var h4 = child.XPathSelectElement("following-sibling::div/h4[contains(@class, 'jd-details-title')]"); if (h4 == null) { continue; } string sigTypeOnly = child.Attribute("name").Value; string sigTypeAndName = h4.Value.Replace('\n', ' ').Replace('\r', ' ').Trim(); if (!sigTypeAndName.Contains('(')) { continue; } JavaMethodBase javaMethod = null; string name = sigTypeAndName.Substring(0, sigTypeAndName.IndexOf('(')).Split(ssep, StringSplitOptions.RemoveEmptyEntries).Last(); switch (sectionType) { case "Public Constructors": case "Protected Constructors": javaMethod = new JavaConstructor(javaType) { Name = name }; break; case "Public Methods": case "Protected Methods": string mname = sigTypeAndName.Substring(0, sigTypeAndName.IndexOf('(')); javaMethod = new JavaMethod(javaType) { Name = name }; break; } javaType.Members.Add(javaMethod); var paramTypes = SplitTypes(sigTypeOnly.Substring(sigTypeOnly.IndexOf('(') + 1).TrimEnd(')'), 0).ToArray(); var parameters = sigTypeAndName.Substring(sigTypeAndName.IndexOf('(') + 1).TrimEnd(')') .Split(sep, StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()) .ToArray(); foreach (var p in paramTypes.Zip(parameters, (to, tn) => new { Type = to, TypeAndName = tn }) .Select(pp => new { Type = pp.Type, Name = pp.TypeAndName.Split(' ') [1] })) { javaMethod.Parameters.Add(new JavaParameter(javaMethod) { Name = p.Name, Type = p.Type }); } } javaType.Members = javaType.Members.OfType <JavaMethodBase> () .OrderBy(m => m.Name + "(" + string.Join(",", m.Parameters.Select(p => p.Type)) + ")") .ToArray(); } foreach (var pkg in api.Packages) { pkg.Types = pkg.Types.OrderBy(t => t.Name).ToArray(); } api.Packages = api.Packages.OrderBy(p => p.Name).ToArray(); if (options.OutputTextFile != null) { api.WriteParameterNamesText(options.OutputTextFile); } if (options.OutputXmlFile != null) { api.WriteParameterNamesXml(options.OutputXmlFile); } }