Пример #1
0
        public MethodBody GetMethodBody(MethodDefinition targetMethod, XMethodDefinition sourceMethod)
        {
            var javaType  = (XBuilder.JavaTypeDefinition)sourceMethod.DeclaringType;
            var className = javaType.ClassFile.ClassName;
            var source    = javaType.ClassFile.Loader.TryGetClassSource(className);

            if (source == null)
            {
                return(null);
            }

            DexLookup dex       = GetOrCreateDex(source, waitForResult: true);
            var       methodDef = dex.GetMethod(targetMethod.Owner.Fullname, targetMethod.Name, targetMethod.Prototype.ToSignature());

            return(methodDef == null ? null : methodDef.Body);
        }
        public CacheEntry GetFromCacheImpl(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            if (_initialize == null)
            {
                return(null);
            }
            _initialize.Wait();

            if (!IsEnabled)
            {
                return(null);
            }

            if (sourceMethod.ScopeId == null || sourceMethod.ScopeId == "(none)")
            {
                return(null);
            }

            if (IsUnderlyingCodeModified(sourceMethod))
            {
                return(null);
            }

            Tuple <TypeEntry, MethodEntry> entry;

            string typeScopeId   = sourceMethod.DeclaringType.ScopeId;
            string methodScopeId = sourceMethod.ScopeId;

            MethodDefinition cachedMethod;

            if (_methodsByScopeId.TryGetValue(Tuple.Create(typeScopeId, methodScopeId), out entry))
            {
                cachedMethod = _dexLookup.GetMethod(entry.Item1.DexName, entry.Item2.DexName, entry.Item2.DexSignature);
            }
            else
            {
                // try directly in the dexlookup, for jar imports
                cachedMethod = _dexLookup.GetMethod(typeScopeId.Replace("/", "."), targetMethod.Name, targetMethod.Prototype.ToSignature());
            }

            if (cachedMethod == null)
            {
                return(null);
            }

            if (cachedMethod.Body == null)
            {
                // I believe there is a bug in MethodExplicitInterfaceConverter generating
                // stubs for interfaces if they derive from an imported interface.
                // Bail out for now until this is fixed.
                DLog.Debug(DContext.CompilerCodeGenerator, "Compiler cache: no method body found on cached version of {0}, even though one was expected.", sourceMethod);
                return(null);
            }

            try
            {
                if (!Equals(cachedMethod.Prototype, targetMethod.Prototype))
                {
                    throw new Exception("internal error, got the wrong method.");
                }

                var body = DexMethodBodyCloner.Clone(targetMethod, cachedMethod);
                FixReferences(body, compiler, targetPackage);

                string className = entry != null ? entry.Item1.DexName : body.Owner.Owner.Fullname;
                var    @class    = _dexLookup.GetClass(className);

                return(new CacheEntry(body, entry != null ? entry.Item2 : null, entry != null ? _map.GetSourceCodePositions(entry.Item2) : null, @class.SourceFile));
            }
            catch (CompilerCacheResolveException ex)
            {
                // This happens at the moment for methods using fields in the __generated class,
                // as well as for references to generated methods (mostly explicit interfac stubs)
                // during the IL conversion phase.
                // This also seems to happen for Framework-nested classes, maybe because these do
                // not get an entry in the map file. This should be fixed.
                // The number of these failures in my test is 890 out of ~12000. We gracefully
                // handle errors by re-compiling the method body.
                Debug.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return(null);
            }
            catch (Exception ex)
            {
                DLog.Warning(DContext.CompilerCodeGenerator, "Compiler cache: exception while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message);
                Trace.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message));
                return(null);
            }
        }