1 /*
   2  * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 
  25 
  26 package jdk.tools.jaotc;
  27 
  28 import java.lang.annotation.Annotation;
  29 import java.util.Arrays;
  30 import java.util.HashSet;
  31 import java.util.List;
  32 import java.util.Set;
  33 import java.util.stream.Collectors;
  34 
  35 import org.graalvm.compiler.api.directives.GraalDirectives;
  36 import org.graalvm.compiler.api.replacements.ClassSubstitution;
  37 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  38 import org.graalvm.compiler.api.replacements.Snippet;
  39 import org.graalvm.compiler.debug.GraalError;
  40 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  41 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
  42 import org.graalvm.compiler.hotspot.word.MetaspacePointer;
  43 import org.graalvm.compiler.replacements.Snippets;
  44 import jdk.internal.vm.compiler.word.WordBase;
  45 
  46 import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
  47 import jdk.vm.ci.meta.MetaAccessProvider;
  48 import jdk.vm.ci.meta.ResolvedJavaMethod;
  49 import jdk.vm.ci.meta.ResolvedJavaType;
  50 import jdk.vm.ci.hotspot.HotSpotConstantPool;
  51 
  52 final class GraalFilters {
  53     private List<ResolvedJavaType> specialClasses;
  54     private List<ResolvedJavaType> specialArgumentAndReturnTypes;
  55 
  56     private static Set<Class<?>> skipAnnotations = new HashSet<>();
  57 
  58     static {
  59         skipAnnotations.add(NodeIntrinsic.class);
  60         skipAnnotations.add(Snippet.class);
  61         skipAnnotations.add(MethodSubstitution.class);
  62     }
  63 
  64     boolean shouldCompileMethod(ResolvedJavaMethod method) {
  65         // NodeIntrinsics cannot be compiled.
  66         if (hasExcludedAnnotation(method)) {
  67             return false;
  68         }
  69 
  70         ResolvedJavaType declaringClass = method.getDeclaringClass();
  71         // Check for special magical types in the signature, like Word or MetaspacePointer. Those
  72         // are definitely snippets.
  73         List<ResolvedJavaType> signatureTypes = Arrays.asList(method.toParameterTypes()).stream().map(p -> p.resolve(declaringClass)).collect(Collectors.toList());
  74         signatureTypes.add(method.getSignature().getReturnType(null).resolve(declaringClass));
  75         if (signatureTypes.stream().flatMap(t -> specialArgumentAndReturnTypes.stream().filter(s -> s.isAssignableFrom(t))).findAny().isPresent()) {
  76             return false;
  77         }
  78         return true;
  79     }
  80 
  81     private static boolean hasExcludedAnnotation(ResolvedJavaMethod method) {
  82         for (Annotation annotation : method.getAnnotations()) {
  83             if (skipAnnotations.contains(annotation.annotationType())) {
  84                 return true;
  85             }
  86         }
  87         return false;
  88     }
  89 
  90     boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) {
  91         if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) {
  92             return false;
  93         }
  94         // Skip klass with Condy until Graal is fixed.
  95         if (((HotSpotConstantPool) ((HotSpotResolvedObjectType) klass).getConstantPool()).hasDynamicConstant()) {
  96             return false;
  97         }
  98         return true;
  99     }
 100 
 101     // Don't compile methods in classes and their subtypes that are in the list.
 102     private static List<ResolvedJavaType> getSpecialClasses(MetaAccessProvider meta) {
 103         // @formatter:off
 104         return Arrays.asList(meta.lookupJavaType(Snippets.class),
 105             meta.lookupJavaType(HotSpotClassSubstitutions.class),
 106             meta.lookupJavaType(GraalDirectives.class),
 107             meta.lookupJavaType(ClassSubstitution.class));
 108         // @formatter:on
 109     }
 110 
 111     // Don't compile methods that have have the listed class or their subtypes in their signature.
 112     private static List<ResolvedJavaType> getSpecialArgumentAndReturnTypes(MetaAccessProvider meta) {
 113         // @formatter:off
 114         return Arrays.asList(meta.lookupJavaType(WordBase.class),
 115             meta.lookupJavaType(MetaspacePointer.class));
 116         // @formatter:on
 117     }
 118 
 119     GraalFilters(MetaAccessProvider metaAccess) {
 120         specialClasses = getSpecialClasses(metaAccess);
 121         specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess);
 122     }
 123 
 124     static boolean shouldIgnoreException(Throwable e) {
 125         if (e instanceof GraalError) {
 126             String m = e.getMessage();
 127             if (m.contains("ArrayKlass::_component_mirror")) {
 128                 // When compiling Graal, ignore errors in JDK8 snippets.
 129                 return true;
 130             }
 131         }
 132 
 133         if (e instanceof org.graalvm.compiler.java.BytecodeParser.BytecodeParserError) {
 134             Throwable cause = e.getCause();
 135             if (cause instanceof GraalError) {
 136                 String m = cause.getMessage();
 137                 // When compiling Graal suppress attempts to compile snippet fragments that bottom
 138                 // out with node intrinsics. These are unfortunately not explicitly marked, so we
 139                 // have to try to compile them and bail out if we think it's a snippet.
 140                 if (m.contains("@NodeIntrinsic method") && m.contains("must only be called from within a replacement")) {
 141                     return true;
 142                 }
 143             }
 144         }
 145         return false;
 146     }
 147 }