src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java
changeset 54669 ad45b3802d4e
parent 54601 c40b2a190173
child 54914 9feb4852536f
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Wed May 01 12:41:26 2019 -0400
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider/src/org/graalvm/compiler/serviceprovider/GraalServices.java	Wed May 01 12:31:29 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,22 +29,38 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import java.util.concurrent.atomic.AtomicLong;
+import java.util.function.Supplier;
 
+import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup.SpeculationContextObject;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
+import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
 import jdk.vm.ci.runtime.JVMCI;
 import jdk.vm.ci.services.JVMCIPermission;
 import jdk.vm.ci.services.Services;
 
+import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
+import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
+
 /**
- * JDK 9+ version of {@link GraalServices}.
+ * JDK 13+ version of {@link GraalServices}.
  */
 public final class GraalServices {
 
+    private static final Map<Class<?>, List<?>> servicesCache = IS_BUILDING_NATIVE_IMAGE ? new HashMap<>() : null;
+
     private GraalServices() {
     }
 
@@ -54,8 +70,37 @@
      * @throws SecurityException if on JDK8 and a security manager is present and it denies
      *             {@link JVMCIPermission}
      */
+    @SuppressWarnings("unchecked")
     public static <S> Iterable<S> load(Class<S> service) {
-        Iterable<S> iterable = ServiceLoader.load(service);
+        if (IS_IN_NATIVE_IMAGE || IS_BUILDING_NATIVE_IMAGE) {
+            List<?> list = servicesCache.get(service);
+            if (list != null) {
+                return (Iterable<S>) list;
+            }
+            if (IS_IN_NATIVE_IMAGE) {
+                throw new InternalError(String.format("No %s providers found when building native image", service.getName()));
+            }
+        }
+
+        Iterable<S> providers = load0(service);
+
+        if (IS_BUILDING_NATIVE_IMAGE) {
+            synchronized (servicesCache) {
+                ArrayList<S> providersList = new ArrayList<>();
+                for (S provider : providers) {
+                    providersList.add(provider);
+                }
+                providers = providersList;
+                servicesCache.put(service, providersList);
+                return providers;
+            }
+        }
+
+        return providers;
+    }
+
+    protected static <S> Iterable<S> load0(Class<S> service) {
+        Iterable<S> iterable = ServiceLoader.load(service, GraalServices.class.getClassLoader());
         return new Iterable<>() {
             @Override
             public Iterator<S> iterator() {
@@ -90,6 +135,8 @@
      * @param other all JVMCI packages will be opened to the module defining this class
      */
     static void openJVMCITo(Class<?> other) {
+        if (IS_IN_NATIVE_IMAGE) return;
+
         Module jvmciModule = JVMCI_MODULE;
         Module otherModule = other.getModule();
         if (jvmciModule != otherModule) {
@@ -98,7 +145,7 @@
                     // JVMCI initialization opens all JVMCI packages
                     // to Graal which is a prerequisite for Graal to
                     // open JVMCI packages to other modules.
-                    JVMCI.initialize();
+                    JVMCI.getRuntime();
 
                     jvmciModule.addOpens(pkg, otherModule);
                 }
@@ -179,6 +226,7 @@
         final int groupId;
         final String groupName;
         final Object[] context;
+        private SpeculationReasonEncoding encoding;
 
         DirectSpeculationReason(int groupId, String groupName, Object[] context) {
             this.groupId = groupId;
@@ -204,6 +252,123 @@
         public String toString() {
             return String.format("%s@%d%s", groupName, groupId, Arrays.toString(context));
         }
+
+        @Override
+        public SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
+            if (encoding == null) {
+                encoding = encodingSupplier.get();
+                encoding.addInt(groupId);
+                for (Object o : context) {
+                    if (o == null) {
+                        encoding.addInt(0);
+                    } else {
+                        addNonNullObject(encoding, o);
+                    }
+                }
+            }
+            return encoding;
+        }
+
+        static void addNonNullObject(SpeculationReasonEncoding encoding, Object o) {
+            Class<? extends Object> c = o.getClass();
+            if (c == String.class) {
+                encoding.addString((String) o);
+            } else if (c == Byte.class) {
+                encoding.addByte((Byte) o);
+            } else if (c == Short.class) {
+                encoding.addShort((Short) o);
+            } else if (c == Character.class) {
+                encoding.addShort((Character) o);
+            } else if (c == Integer.class) {
+                encoding.addInt((Integer) o);
+            } else if (c == Long.class) {
+                encoding.addLong((Long) o);
+            } else if (c == Float.class) {
+                encoding.addInt(Float.floatToRawIntBits((Float) o));
+            } else if (c == Double.class) {
+                encoding.addLong(Double.doubleToRawLongBits((Double) o));
+            } else if (o instanceof Enum) {
+                encoding.addInt(((Enum<?>) o).ordinal());
+            } else if (o instanceof ResolvedJavaMethod) {
+                encoding.addMethod((ResolvedJavaMethod) o);
+            } else if (o instanceof ResolvedJavaType) {
+                encoding.addType((ResolvedJavaType) o);
+            } else if (o instanceof ResolvedJavaField) {
+                encoding.addField((ResolvedJavaField) o);
+            } else if (o instanceof SpeculationContextObject) {
+                SpeculationContextObject sco = (SpeculationContextObject) o;
+                // These are compiler objects which all have the same class
+                // loader so the class name uniquely identifies the class.
+                encoding.addString(o.getClass().getName());
+                sco.accept(new EncodingAdapter(encoding));
+            } else if (o.getClass() == BytecodePosition.class) {
+                BytecodePosition p = (BytecodePosition) o;
+                while (p != null) {
+                    encoding.addInt(p.getBCI());
+                    encoding.addMethod(p.getMethod());
+                    p = p.getCaller();
+                }
+            } else {
+                throw new IllegalArgumentException("Unsupported type for encoding: " + c.getName());
+            }
+        }
+    }
+
+    static class EncodingAdapter implements SpeculationContextObject.Visitor {
+        private final SpeculationReasonEncoding encoding;
+
+        EncodingAdapter(SpeculationReasonEncoding encoding) {
+            this.encoding = encoding;
+        }
+
+        @Override
+        public void visitBoolean(boolean v) {
+            encoding.addByte(v ? 1 : 0);
+        }
+
+        @Override
+        public void visitByte(byte v) {
+            encoding.addByte(v);
+        }
+
+        @Override
+        public void visitChar(char v) {
+            encoding.addShort(v);
+        }
+
+        @Override
+        public void visitShort(short v) {
+            encoding.addInt(v);
+        }
+
+        @Override
+        public void visitInt(int v) {
+            encoding.addInt(v);
+        }
+
+        @Override
+        public void visitLong(long v) {
+            encoding.addLong(v);
+        }
+
+        @Override
+        public void visitFloat(float v) {
+            encoding.addInt(Float.floatToRawIntBits(v));
+        }
+
+        @Override
+        public void visitDouble(double v) {
+            encoding.addLong(Double.doubleToRawLongBits(v));
+        }
+
+        @Override
+        public void visitObject(Object v) {
+            if (v == null) {
+                encoding.addInt(0);
+            } else {
+                DirectSpeculationReason.addNonNullObject(encoding, v);
+            }
+        }
     }
 
     static SpeculationReason createSpeculationReason(int groupId, String groupName, Object... context) {