1 /*
   2  * Copyright (c) 2016, 2017, 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 package jdk.tools.jaotc;
  25 
  26 import java.lang.annotation.Annotation;
  27 import java.util.Arrays;
  28 import java.util.HashSet;
  29 import java.util.List;
  30 import java.util.Set;
  31 import java.util.stream.Collectors;
  32 
  33 import jdk.vm.ci.meta.MetaAccessProvider;
  34 import jdk.vm.ci.meta.ResolvedJavaMethod;
  35 import jdk.vm.ci.meta.ResolvedJavaType;
  36 
  37 import org.graalvm.compiler.api.directives.GraalDirectives;
  38 import org.graalvm.compiler.api.replacements.ClassSubstitution;
  39 import org.graalvm.compiler.api.replacements.MethodSubstitution;
  40 import org.graalvm.compiler.api.replacements.Snippet;
  41 import org.graalvm.compiler.debug.GraalError;
  42 import org.graalvm.compiler.graph.Node.NodeIntrinsic;
  43 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
  44 import org.graalvm.compiler.hotspot.word.MetaspacePointer;
  45 import org.graalvm.compiler.replacements.Snippets;
  46 import org.graalvm.word.WordBase;
  47 
  48 final class GraalFilters {
  49     private List<ResolvedJavaType> specialClasses;
  50     private List<ResolvedJavaType> specialArgumentAndReturnTypes;
  51 
  52     private static Set<Class<?>> skipAnnotations = new HashSet<>();
  53 
  54     static {
  55         skipAnnotations.add(NodeIntrinsic.class);
  56         skipAnnotations.add(Snippet.class);
  57         skipAnnotations.add(MethodSubstitution.class);
  58     }
  59 
  60     boolean shouldCompileMethod(ResolvedJavaMethod method) {
  61         // NodeIntrinsics cannot be compiled.
  62         if (hasExcludedAnnotation(method)) {
  63             return false;
  64         }
  65 
  66         ResolvedJavaType declaringClass = method.getDeclaringClass();
  67         // Check for special magical types in the signature, like Word or MetaspacePointer. Those
  68         // are definitely snippets.
  69         List<ResolvedJavaType> signatureTypes = Arrays.asList(method.toParameterTypes()).stream().map(p -> p.resolve(declaringClass)).collect(Collectors.toList());
  70         signatureTypes.add(method.getSignature().getReturnType(null).resolve(declaringClass));
  71         if (signatureTypes.stream().flatMap(t -> specialArgumentAndReturnTypes.stream().filter(s -> s.isAssignableFrom(t))).findAny().isPresent()) {
  72             return false;
  73         }
  74         return true;
  75     }
  76 
  77     private static boolean hasExcludedAnnotation(ResolvedJavaMethod method) {
  78         for (Annotation annotation : method.getAnnotations()) {
  79             if (skipAnnotations.contains(annotation.annotationType())) {
  80                 return true;
  81             }
  82         }
  83         return false;
  84     }
  85 
  86     boolean shouldCompileAnyMethodInClass(ResolvedJavaType klass) {
  87         if (specialClasses.stream().filter(s -> s.isAssignableFrom(klass)).findAny().isPresent()) {
  88             return false;
  89         }
  90         return true;
  91     }
  92 
  93     // Don't compile methods in classes and their subtypes that are in the list.
  94     private static List<ResolvedJavaType> getSpecialClasses(MetaAccessProvider meta) {
  95         // @formatter:off
  96         return Arrays.asList(meta.lookupJavaType(Snippets.class),
  97             meta.lookupJavaType(HotSpotClassSubstitutions.class),
  98             meta.lookupJavaType(GraalDirectives.class),
  99             meta.lookupJavaType(ClassSubstitution.class));
 100         // @formatter:on
 101     }
 102 
 103     // Don't compile methods that have have the listed class or their subtypes in their signature.
 104     private static List<ResolvedJavaType> getSpecialArgumentAndReturnTypes(MetaAccessProvider meta) {
 105         // @formatter:off
 106         return Arrays.asList(meta.lookupJavaType(WordBase.class),
 107             meta.lookupJavaType(MetaspacePointer.class));
 108         // @formatter:on
 109     }
 110 
 111     GraalFilters(MetaAccessProvider metaAccess) {
 112         specialClasses = getSpecialClasses(metaAccess);
 113         specialArgumentAndReturnTypes = getSpecialArgumentAndReturnTypes(metaAccess);
 114     }
 115 
 116     static boolean shouldIgnoreException(Throwable e) {
 117         if (e instanceof GraalError) {
 118             String m = e.getMessage();
 119             if (m.contains("ArrayKlass::_component_mirror")) {
 120                 // When compiling Graal, ignore errors in JDK8 snippets.
 121                 return true;
 122             }
 123         }
 124 
 125         if (e instanceof org.graalvm.compiler.java.BytecodeParser.BytecodeParserError) {
 126             Throwable cause = e.getCause();
 127             if (cause instanceof GraalError) {
 128                 String m = cause.getMessage();
 129                 // When compiling Graal suppress attempts to compile snippet fragments that bottom
 130                 // out with node intrinsics. These are unfortunately not explicitly marked, so we
 131                 // have to try to compile them and bail out if we think it's a snippet.
 132                 if (m.contains("@NodeIntrinsic method") && m.contains("must only be called from within a replacement")) {
 133                     return true;
 134                 }
 135             }
 136         }
 137         return false;
 138     }
 139 }