예제 #1
0
        /// <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());
        }
예제 #2
0
        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);
        }
예제 #3
0
 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)));
 }
예제 #4
0
        /// <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);
        }
예제 #5
0
파일: JavaClass.cs 프로젝트: yongaru/uno
            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));
            }
예제 #6
0
        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);
        }
예제 #7
0
    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);
    }
예제 #8
0
        /// <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());
        }
예제 #9
0
 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);
 }
예제 #10
0
        /// <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));
        }
예제 #11
0
 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()
     });
 }
예제 #12
0
        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);
            }
        }
예제 #13
0
        /// <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);
        }
예제 #15
0
        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.");
        }
예제 #16
0
        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);
        }
예제 #17
0
        /// <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);
        }
        /// <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);
        }
예제 #19
0
        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));
        }
예제 #20
0
        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);
            }
        }
예제 #21
0
        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());
            }
        }
예제 #22
0
        /// <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());
        }
예제 #23
0
        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);
        }
예제 #24
0
        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);
        }
예제 #25
0
        /// <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);
        }
예제 #26
0
        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('}');
        }
예제 #27
0
        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);
        }
예제 #28
0
        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);
        }
예제 #29
0
        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);
        }
예제 #30
0
        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);
        }
예제 #31
0
        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));
            }
        }
예제 #32
0
        /*
         *
         * 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);
            }
        }