changeset 57272:f1e6442241ca

8233035: Update JVMCI Reviewed-by: dlong
author kvn
date Tue, 29 Oct 2019 15:35:06 -0700
parents f4290bf1cc21
children 674131501e98
files src/hotspot/.mx.jvmci/suite.py src/hotspot/share/jvmci/jvmciCompilerToVM.cpp src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DebugInfoTest.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectFormattingTest.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectTestBase.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderData.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/VirtualObjectLayoutTest.java test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java
diffstat 20 files changed, 417 insertions(+), 85 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/.mx.jvmci/suite.py	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/hotspot/.mx.jvmci/suite.py	Tue Oct 29 15:35:06 2019 -0700
@@ -171,7 +171,9 @@
       "subDir" : "../../test/hotspot/jtreg/compiler/jvmci",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "mx:JUNIT",
         "TESTNG",
+        "jdk.vm.ci.code.test",
         "jdk.vm.ci.hotspot",
       ],
       "checkstyle" : "jdk.vm.ci.services",
--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp	Tue Oct 29 15:35:06 2019 -0700
@@ -22,6 +22,7 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/classLoaderData.inline.hpp"
 #include "classfile/javaClasses.inline.hpp"
 #include "classfile/stringTable.hpp"
 #include "classfile/symbolTable.hpp"
@@ -2032,7 +2033,7 @@
     JVMCI_THROW_0(NullPointerException);
   }
   InstanceKlass* ik = InstanceKlass::cast(JVMCIENV->asKlass(JVMCIENV->wrap(holder)));
-  if (ik->class_loader_data()->is_builtin_class_loader_data()) {
+  if (ik->class_loader_data()->is_boot_class_loader_data() || ik->class_loader_data()->is_platform_class_loader_data()) {
     return true;
   }
   return false;
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.code/src/jdk/vm/ci/code/VirtualObject.java	Tue Oct 29 15:35:06 2019 -0700
@@ -22,11 +22,11 @@
  */
 package jdk.vm.ci.code;
 
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.Set;
 
+import jdk.vm.ci.common.JVMCIError;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaValue;
 import jdk.vm.ci.meta.ResolvedJavaField;
@@ -74,8 +74,8 @@
      * @param id a unique id that identifies the object within the debug information for one
      *            position in the compiled code.
      * @param isAutoBox a flag that tells the runtime that the object may be a boxed primitive and
-     *            that it possibly needs to be obtained for the box cache instead of creating
-     *            a new instance.
+     *            that it possibly needs to be obtained for the box cache instead of creating a new
+     *            instance.
      * @return a new {@link VirtualObject} instance.
      */
     public static VirtualObject get(ResolvedJavaType type, int id, boolean isAutoBox) {
@@ -108,14 +108,32 @@
                         }
                     } else {
                         ResolvedJavaField[] fields = vo.type.getInstanceFields(true);
-                        assert fields.length == vo.values.length : vo.type + ", fields=" + Arrays.toString(fields) + ", values=" + Arrays.toString(vo.values);
-                        for (int i = 0; i < vo.values.length; i++) {
+                        int fieldIndex = 0;
+                        for (int i = 0; i < vo.values.length; i++, fieldIndex++) {
                             if (i != 0) {
                                 buf.append(',');
                             }
-                            buf.append(fields[i].getName()).append('=');
+                            if (fieldIndex >= fields.length) {
+                                buf.append("<missing field>");
+                            } else {
+                                ResolvedJavaField field = fields[fieldIndex];
+                                buf.append(field.getName());
+                                if (vo.slotKinds[i].getSlotCount() == 2 && field.getType().getJavaKind().getSlotCount() == 1) {
+                                    if (fieldIndex + 1 >= fields.length) {
+                                        buf.append("/<missing field>");
+                                    } else {
+                                        ResolvedJavaField field2 = fields[++fieldIndex];
+                                        buf.append('/').append(field2.getName());
+                                    }
+                                }
+                            }
+                            buf.append('=');
                             appendValue(buf, vo.values[i], visited);
                         }
+                        // Extra fields
+                        for (; fieldIndex < fields.length; fieldIndex++) {
+                            buf.append(fields[fieldIndex].getName()).append("=<missing value>");
+                        }
                     }
                 }
                 buf.append('}');
@@ -126,6 +144,55 @@
         return buf;
     }
 
+    public interface LayoutVerifier {
+        int getOffset(ResolvedJavaField field);
+
+        default JavaKind getStorageKind(ResolvedJavaField field) {
+            return field.getType().getJavaKind();
+        }
+    }
+
+    public void verifyLayout(LayoutVerifier verifier) {
+        if (!type.isArray()) {
+            ResolvedJavaField[] fields = type.getInstanceFields(true);
+            int fieldIndex = 0;
+            for (int i = 0; i < values.length; i++, fieldIndex++) {
+                JavaKind slotKind = slotKinds[i];
+                if (fieldIndex >= fields.length) {
+                    throw new JVMCIError("Not enough fields for the values provided for %s", toString());
+                } else {
+                    ResolvedJavaField field = fields[fieldIndex];
+                    JavaKind fieldKind = verifier.getStorageKind(field);
+                    if (slotKind.getSlotCount() == 2 && fieldKind == JavaKind.Int) {
+                        int offset = verifier.getOffset(field);
+                        if (offset % 8 != 0) {
+                            throw new JVMCIError("Double word value stored across two ints must be aligned %s", toString());
+                        }
+
+                        if (fieldIndex + 1 >= fields.length) {
+                            throw new JVMCIError("Missing second field for double word value stored in two ints %s", toString());
+                        }
+                        ResolvedJavaField field2 = fields[fieldIndex + 1];
+                        if (field2.getType().getJavaKind() != JavaKind.Int) {
+                            throw new JVMCIError("Second field for double word value stored in two ints must be int but got %s in %s", field2.getType().getJavaKind(), toString());
+                        }
+                        int offset2 = verifier.getOffset(field2);
+                        if (offset + 4 != offset2) {
+                            throw new JVMCIError("Double word value stored across two ints must be sequential %s", toString());
+                        }
+                        fieldIndex++;
+                    } else if (fieldKind.getStackKind() != slotKind.getStackKind()) {
+                        throw new JVMCIError("Expected value of kind %s but got %s for field %s in %s", fieldKind, slotKind, field, toString());
+                    }
+                }
+            }
+            // Extra fields
+            if (fieldIndex < fields.length) {
+                throw new JVMCIError("Not enough values provided for fields in %s", this);
+            }
+        }
+    }
+
     @Override
     public String toString() {
         Set<VirtualObject> visited = Collections.newSetFromMap(new IdentityHashMap<VirtualObject, Boolean>());
@@ -170,16 +237,18 @@
      * the box is in the cache range and try to return a cached object.
      */
     public boolean isAutoBox() {
-      return isAutoBox;
+        return isAutoBox;
     }
 
     /**
      * Sets the value of the box flag.
-     * @param isAutoBox a flag that tells the runtime that the object may be a boxed primitive and that
-     *            it possibly needs to be obtained for the box cache instead of creating a new instance.
+     *
+     * @param isAutoBox a flag that tells the runtime that the object may be a boxed primitive and
+     *            that it possibly needs to be obtained for the box cache instead of creating a new
+     *            instance.
      */
     public void setIsAutoBox(boolean isAutoBox) {
-      this.isAutoBox = isAutoBox;
+        this.isAutoBox = isAutoBox;
     }
 
     /**
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/Cleaner.java	Tue Oct 29 15:35:06 2019 -0700
@@ -32,7 +32,7 @@
  * A cleaner tracks a referent object and includes some {@linkplain #doCleanup() cleanup code} that
  * is run some time after the referent object has become weakly-reachable.
  *
- * This is like {@link sun.misc.Cleaner} but with weak semantics instead of phantom. Objects
+ * This is like {@link java.lang.ref.Cleaner} but with weak semantics instead of phantom. Objects
  * referenced by this might be referenced by {@link ResolvedJavaType} which is kept alive by a
  * {@link WeakReference} so we need equivalent reference strength.
  */
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java	Tue Oct 29 15:35:06 2019 -0700
@@ -56,7 +56,7 @@
     private static native void registerNatives();
 
     /**
-     * These values mirror the equivalent values from {@link Unsafe} but are approriate for the JVM
+     * These values mirror the equivalent values from {@code Unsafe} but are appropriate for the JVM
      * being compiled against.
      */
     // Checkstyle: stop
@@ -514,10 +514,10 @@
 
     /**
      * Reads an object pointer within a VM data structure. That is, any {@link VMField} whose
-     * {@link VMField#type type} is {@code "oop"} (e.g.,
-     * {@code Klass::_java_mirror}, {@code JavaThread::_threadObj}).
+     * {@link VMField#type type} is {@code "oop"} (e.g., {@code Klass::_java_mirror},
+     * {@code JavaThread::_threadObj}).
      *
-     * Note that {@link Unsafe#getObject(Object, long)} cannot be used for this since it does a
+     * Note that {@code Unsafe.getObject(Object, long)} cannot be used for this since it does a
      * {@code narrowOop} read if the VM is using compressed oops whereas oops within VM data
      * structures are (currently) always uncompressed.
      *
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotCompiledCode.java	Tue Oct 29 15:35:06 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 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
@@ -25,10 +25,12 @@
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.code.CompiledCode;
 import jdk.vm.ci.code.StackSlot;
+import jdk.vm.ci.code.VirtualObject;
 import jdk.vm.ci.code.site.DataPatch;
 import jdk.vm.ci.code.site.Infopoint;
 import jdk.vm.ci.code.site.Site;
 import jdk.vm.ci.meta.Assumptions.Assumption;
+import jdk.vm.ci.meta.ResolvedJavaField;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
 /**
@@ -156,9 +158,23 @@
                 if (info.debugInfo != null) {
                     BytecodeFrame frame = info.debugInfo.frame();
                     assert frame == null || frame.validateFormat();
+                    if (info.debugInfo.getVirtualObjectMapping() != null) {
+                        for (VirtualObject v : info.debugInfo.getVirtualObjectMapping()) {
+                            verifyVirtualObject(v);
+                        }
+                    }
                 }
             }
         }
         return true;
     }
+
+    public static void verifyVirtualObject(VirtualObject v) {
+        v.verifyLayout(new VirtualObject.LayoutVerifier() {
+            @Override
+            public int getOffset(ResolvedJavaField field) {
+                return field.getOffset();
+            }
+        });
+    }
 }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java	Tue Oct 29 15:35:06 2019 -0700
@@ -31,25 +31,19 @@
 import java.io.OutputStream;
 import java.io.PrintStream;
 import java.io.Serializable;
-
 import java.lang.invoke.CallSite;
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MethodHandle;
-import java.lang.module.ModuleDescriptor.Requires;
 import java.lang.ref.WeakReference;
-
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.ServiceLoader;
 import java.util.function.Predicate;
 
-import jdk.internal.misc.Unsafe;
-
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.CompilationRequestResult;
 import jdk.vm.ci.code.CompiledCode;
@@ -187,9 +181,15 @@
                     // initialized.
                     JVMCI.getRuntime();
                 }
-                // Make sure all the primitive box caches are populated (required to properly materialize boxed primitives
+                // Make sure all the primitive box caches are populated (required to properly
+                // materialize boxed primitives
                 // during deoptimization).
-                Object[] boxCaches = { Boolean.valueOf(false), Byte.valueOf((byte)0), Short.valueOf((short) 0), Character.valueOf((char) 0), Integer.valueOf(0), Long.valueOf(0) };
+                Boolean.valueOf(false);
+                Byte.valueOf((byte) 0);
+                Short.valueOf((short) 0);
+                Character.valueOf((char) 0);
+                Integer.valueOf(0);
+                Long.valueOf(0);
             }
         }
         return result;
@@ -338,7 +338,7 @@
 
     private static HotSpotJVMCIBackendFactory findFactory(String architecture) {
         Iterable<HotSpotJVMCIBackendFactory> factories = getHotSpotJVMCIBackendFactories();
-assert factories != null : "sanity";
+        assert factories != null : "sanity";
         for (HotSpotJVMCIBackendFactory factory : factories) {
             if (factory.getArchitecture().equalsIgnoreCase(architecture)) {
                 return factory;
@@ -391,33 +391,35 @@
     @NativeImageReinitialize private volatile ClassValue<WeakReferenceHolder<HotSpotResolvedJavaType>> resolvedJavaType;
 
     /**
-     * To avoid calling ClassValue.remove to refresh the weak reference, which
-     * under certain circumstances can lead to an infinite loop, we use a
-     * permanent holder with a mutable field that we refresh.
+     * To avoid calling ClassValue.remove to refresh the weak reference, which under certain
+     * circumstances can lead to an infinite loop, we use a permanent holder with a mutable field
+     * that we refresh.
      */
     private static class WeakReferenceHolder<T> {
         private volatile WeakReference<T> ref;
+
         WeakReferenceHolder(T value) {
             set(value);
         }
+
         void set(T value) {
-            ref = new WeakReference<T>(value);
+            ref = new WeakReference<>(value);
         }
+
         T get() {
             return ref.get();
         }
-    };
+    }
 
     @NativeImageReinitialize private HashMap<Long, WeakReference<ResolvedJavaType>> resolvedJavaTypes;
 
     /**
-     * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can
-     * be read from the VM.
+     * Stores the value set by {@link #excludeFromJVMCICompilation(Module...)} so that it can be
+     * read from the VM.
      */
     @SuppressWarnings("unused")//
     @NativeImageReinitialize private Module[] excludeFromJVMCICompilation;
 
-
     private final Map<Class<? extends Architecture>, JVMCIBackend> backends = new HashMap<>();
 
     private volatile List<HotSpotVMEventListener> vmEventListeners;
@@ -508,7 +510,7 @@
         if (resolvedJavaType == null) {
             synchronized (this) {
                 if (resolvedJavaType == null) {
-                    resolvedJavaType = new ClassValue<WeakReferenceHolder<HotSpotResolvedJavaType>>() {
+                    resolvedJavaType = new ClassValue<>() {
                         @Override
                         protected WeakReferenceHolder<HotSpotResolvedJavaType> computeValue(Class<?> type) {
                             return new WeakReferenceHolder<>(createClass(type));
@@ -522,8 +524,7 @@
         HotSpotResolvedJavaType javaType = ref.get();
         if (javaType == null) {
             /*
-             * If the referent has become null, create a new value and
-             * update cached weak reference.
+             * If the referent has become null, create a new value and update cached weak reference.
              */
             javaType = createClass(javaClass);
             ref.set(javaType);
@@ -591,7 +592,7 @@
      *            compiler.
      */
     public Predicate<ResolvedJavaType> getIntrinsificationTrustPredicate(Class<?>... compilerLeafClasses) {
-        return new Predicate<ResolvedJavaType>() {
+        return new Predicate<>() {
             @Override
             public boolean test(ResolvedJavaType type) {
                 if (type instanceof HotSpotResolvedObjectTypeImpl) {
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java	Tue Oct 29 15:35:06 2019 -0700
@@ -563,6 +563,10 @@
          * a deopt instead since they can't really be used if they aren't linked yet.
          */
         if (!declaredHolder.isAssignableFrom(this) || this.isArray() || this.equals(declaredHolder) || !isLinked() || isInterface()) {
+            if (hmethod.canBeStaticallyBound()) {
+                // No assumptions are required.
+                return new AssumptionResult<>(hmethod);
+            }
             ResolvedJavaMethod result = hmethod.uniqueConcreteMethod(declaredHolder);
             if (result != null) {
                 return new AssumptionResult<>(result, new ConcreteMethod(method, declaredHolder, result));
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/JVMCIServiceLocator.java	Tue Oct 29 15:35:06 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
@@ -23,7 +23,6 @@
 package jdk.vm.ci.services;
 
 import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
-import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -81,7 +80,7 @@
         result = ServiceLoader.load(JVMCIServiceLocator.class, ClassLoader.getSystemClassLoader());
         if (IS_BUILDING_NATIVE_IMAGE) {
             ArrayList<JVMCIServiceLocator> l = new ArrayList<>();
-            for (JVMCIServiceLocator locator: result) {
+            for (JVMCIServiceLocator locator : result) {
                 l.add(locator);
             }
             l.trimToSize();
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/Services.java	Tue Oct 29 15:35:06 2019 -0700
@@ -33,7 +33,6 @@
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.Properties;
 import java.util.ServiceLoader;
 import java.util.Set;
 
@@ -45,9 +44,6 @@
  */
 public final class Services {
 
-    // This class must be compilable and executable on JDK 8 since it's used in annotation
-    // processors while building JDK 9 so use of API added in JDK 9 is made via reflection.
-
     /**
      * Guards code that should be run when building an JVMCI shared library but should be excluded
      * from (being compiled into) the library. Such code must be directly guarded by an {@code if}
@@ -73,8 +69,12 @@
     private Services() {
     }
 
-    private static volatile Map<String, String> savedProperties = VM.getSavedProperties();
-    static final boolean JVMCI_ENABLED = Boolean.parseBoolean(savedProperties.get("jdk.internal.vm.ci.enabled"));
+    /**
+     * In a native image, this field is initialized by {@link #initializeSavedProperties(byte[])}.
+     */
+    private static volatile Map<String, String> savedProperties;
+
+    static final boolean JVMCI_ENABLED = Boolean.parseBoolean(VM.getSavedProperties().get("jdk.internal.vm.ci.enabled"));
 
     /**
      * Checks that JVMCI is enabled in the VM and throws an error if it isn't.
@@ -90,9 +90,22 @@
      */
     public static Map<String, String> getSavedProperties() {
         checkJVMCIEnabled();
-        SecurityManager sm = System.getSecurityManager();
-        if (sm != null) {
-            sm.checkPermission(new JVMCIPermission());
+        if (IS_IN_NATIVE_IMAGE) {
+            if (savedProperties == null) {
+                throw new InternalError("Saved properties not initialized");
+            }
+        } else {
+            if (savedProperties == null) {
+                synchronized (Services.class) {
+                    if (savedProperties == null) {
+                        SecurityManager sm = System.getSecurityManager();
+                        if (sm != null) {
+                            sm.checkPermission(new JVMCIPermission());
+                        }
+                        savedProperties = VM.getSavedProperties();
+                    }
+                }
+            }
         }
         return savedProperties;
     }
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.services/src/jdk/vm/ci/services/SuppressFBWarnings.java	Tue Oct 29 15:35:06 2019 -0700
@@ -4,9 +4,7 @@
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
+ * published by the Free Software Foundation.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DebugInfoTest.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/DebugInfoTest.java	Tue Oct 29 15:35:06 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -62,32 +62,32 @@
             /*
              * Ensure that any objects mentioned in the VirtualObjects are also in the OopMap.
              */
-            List<Location> newLocations = new ArrayList<Location>(Arrays.asList(objects));
-            List<Location> newDerived = new ArrayList<Location>(Arrays.asList(derivedBase));
+            List<Location> newLocations = new ArrayList<>(Arrays.asList(objects));
+            List<Location> newDerived = new ArrayList<>(Arrays.asList(derivedBase));
             int[] newSizeInBytes = sizeInBytes;
             VirtualObject[] vobjs = compiler.compile(asm, values);
             if (vobjs != null) {
                 for (VirtualObject obj : vobjs) {
                     JavaValue[] objValues = obj.getValues();
                     for (int i = 0; i < objValues.length; i++) {
-                            if (obj.getSlotKind(i) == JavaKind.Object) {
-                                    Location oopLocation = null;
-                                    int bytes = -1;
-                                    if (objValues[i] instanceof RegisterValue) {
-                                            RegisterValue reg = (RegisterValue) objValues[i];
-                                            oopLocation = Location.register(reg.getRegister());
-                                            bytes = reg.getValueKind().getPlatformKind().getSizeInBytes();
-                                    } else if (objValues[i] instanceof StackSlot) {
-                                            StackSlot slot = (StackSlot) objValues[i];
-                                            oopLocation = Location.stack(asm.getOffset(slot));
-                                            bytes = slot.getValueKind().getPlatformKind().getSizeInBytes();
-                                    }
-                                    if (oopLocation != null && !newLocations.contains(oopLocation)) {
-                                            newLocations.add(oopLocation);
-                                            newDerived.add(null);
-                                            newSizeInBytes = Arrays.copyOf(newSizeInBytes, newSizeInBytes.length + 1);
-                                        newSizeInBytes[newSizeInBytes.length - 1] = bytes;
-                                }
+                        if (obj.getSlotKind(i) == JavaKind.Object) {
+                            Location oopLocation = null;
+                            int bytes = -1;
+                            if (objValues[i] instanceof RegisterValue) {
+                                RegisterValue reg = (RegisterValue) objValues[i];
+                                oopLocation = Location.register(reg.getRegister());
+                                bytes = reg.getValueKind().getPlatformKind().getSizeInBytes();
+                            } else if (objValues[i] instanceof StackSlot) {
+                                StackSlot slot = (StackSlot) objValues[i];
+                                oopLocation = Location.stack(asm.getOffset(slot));
+                                bytes = slot.getValueKind().getPlatformKind().getSizeInBytes();
+                            }
+                            if (oopLocation != null && !newLocations.contains(oopLocation)) {
+                                newLocations.add(oopLocation);
+                                newDerived.add(null);
+                                newSizeInBytes = Arrays.copyOf(newSizeInBytes, newSizeInBytes.length + 1);
+                                newSizeInBytes[newSizeInBytes.length - 1] = bytes;
+                            }
                         }
                     }
                 }
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/NativeCallTest.java	Tue Oct 29 15:35:06 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 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
@@ -77,7 +77,8 @@
     @Test
     public void testF32SDILDS() {
         int sCount = 32;
-        Object[] remainingArgs = new Object[]{ // Pairs of <Object>, <Class>
+        // Pairs of <Object>, <Class>
+        Object[] remainingArgs = new Object[]{
                         1.2345678F, float.class,
                         3.212434D, double.class,
                         43921652, int.class,
@@ -101,7 +102,8 @@
     @Test
     public void testI32SDILDS() {
         int sCount = 32;
-        Object[] remainingArgs = new Object[]{ // Pairs of <Object>, <Class>
+        // Pairs of <Object>, <Class>
+        Object[] remainingArgs = new Object[]{
                         1.2345678F, float.class,
                         3.212434D, double.class,
                         43921652, int.class,
@@ -143,6 +145,8 @@
         }
     }
 
+    // Checkstyle: stop
+
     public static native long getFF();
 
     public static native float _FF(float a, float b);
@@ -187,6 +191,7 @@
                     double d18, double d19, double d1a, double d1b, double d1c, double d1d, double d1e, double d1f,
                     float a, double b, int c, long d, double e, float f);
 
+    @SuppressWarnings("unused")
     public static float D32SDILDS(double d00, double d01, double d02, double d03, double d04, double d05, double d06, double d07,
                     double d08, double d09, double d0a, double d0b, double d0c, double d0d, double d0e, double d0f,
                     double d10, double d11, double d12, double d13, double d14, double d15, double d16, double d17,
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestAssembler.java	Tue Oct 29 15:35:06 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 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
@@ -206,7 +206,7 @@
 
     private StackSlot deoptRescue;
 
-    public ValueKindFactory<TestValueKind> valueKindFactory = new ValueKindFactory<TestAssembler.TestValueKind>() {
+    public ValueKindFactory<TestValueKind> valueKindFactory = new ValueKindFactory<>() {
         public TestValueKind getValueKind(JavaKind javaKind) {
             return (TestValueKind) TestAssembler.this.getValueKind(javaKind);
         }
@@ -389,7 +389,7 @@
     public abstract void emitLoad(AllocatableValue av, Object prim);
 
     /**
-     * Emit a call to a fixed address <code>addr</code>
+     * Emit a call to a fixed address <code>addr</code>.
      */
     public abstract void emitCall(long addr);
 
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/TestHotSpotVMConfig.java	Tue Oct 29 15:35:06 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, 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
@@ -42,6 +42,7 @@
 
     public final int classMirrorHandleOffset = getFieldOffset("Klass::_java_mirror", Integer.class, "OopHandle");
 
+    // Checkstyle: stop
     public final int MARKID_DEOPT_HANDLER_ENTRY = getConstant("CodeInstaller::DEOPT_HANDLER_ENTRY", Integer.class);
     public final long handleDeoptStub = getFieldValue("CompilerToVM::Data::SharedRuntime_deopt_blob_unpack", Long.class, "address");
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectFormattingTest.java	Tue Oct 29 15:35:06 2019 -0700
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.vm.ci.code.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class VirtualObjectFormattingTest extends VirtualObjectTestBase {
+
+    @Test
+    public void testFormat() {
+        testBase();
+    }
+
+    @Override
+    protected void test(ResolvedJavaType klass, JavaValue[] kinds, JavaKind[] values, boolean malformed) {
+        // Verify that VirtualObject.toString will produce output without throwing exceptions or
+        // asserting.
+        VirtualObject virtual = VirtualObject.get(klass, 0);
+        virtual.setValues(kinds, values);
+        Assert.assertTrue(!virtual.toString().equals(""));
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectTestBase.java	Tue Oct 29 15:35:06 2019 -0700
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.vm.ci.code.test;
+
+import java.util.Arrays;
+
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaField;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.runtime.JVMCI;
+
+public abstract class VirtualObjectTestBase {
+
+    public static class SimpleObject {
+        int i1;
+        int i2;
+        int i3;
+        int i4;
+        int i5;
+        int i6;
+    }
+
+    public static JavaConstant getValue(JavaKind kind) {
+        long dummyValue = kind.ordinal();
+        dummyValue = dummyValue | dummyValue << 8;
+        dummyValue = dummyValue | dummyValue << 16;
+        dummyValue = dummyValue | dummyValue << 32;
+        if (kind.isNumericInteger()) {
+            return JavaConstant.forIntegerKind(kind, dummyValue);
+        } else if (kind == JavaKind.Float) {
+            return JavaConstant.forDouble(Double.longBitsToDouble(dummyValue));
+        } else if (kind == JavaKind.Float) {
+            return JavaConstant.forFloat(Float.intBitsToFloat((int) dummyValue));
+        } else {
+            return JavaConstant.NULL_POINTER;
+        }
+    }
+
+    public static JavaValue[] getJavaValues(JavaKind[] kinds) {
+        JavaValue[] values = new JavaValue[kinds.length];
+        for (int i = 0; i < kinds.length; i++) {
+            values[i] = getValue(kinds[i]);
+        }
+        return values;
+    }
+
+    /**
+     * Subclasses are expected to override this method to provide their own verification logic using
+     * the normal JUnit {@link org.junit.Assert} methods.
+     *
+     * @param klass class for the {@link jdk.vm.ci.code.VirtualObject}
+     * @param kinds {@link JavaKind Javakinds} for values
+     * @param values {@link JavaValue values} for materializing the
+     *            {@link jdk.vm.ci.code.VirtualObject}
+     * @param malformed indicates whether the resulting virtual object is considered to be properly
+     *            formed relative to the fields of {@code klass}
+     * @throws AssertionError if a problem is detected
+     */
+    protected abstract void test(ResolvedJavaType klass, JavaValue[] kinds, JavaKind[] values, boolean malformed);
+
+    public void testBase() {
+        MetaAccessProvider metaAccess = JVMCI.getRuntime().getHostJVMCIBackend().getMetaAccess();
+
+        ResolvedJavaType simple = metaAccess.lookupJavaType(SimpleObject.class);
+        ResolvedJavaField[] fields = simple.getInstanceFields(true);
+
+        JavaKind[] fieldKinds = new JavaKind[fields.length];
+        for (int i = 0; i < fields.length; i++) {
+            fieldKinds[i] = fields[i].getType().getJavaKind();
+        }
+
+        // Generate a straightforward VirtualObject with values that match to declared field types.
+        JavaKind[] kinds = fieldKinds.clone();
+        JavaValue[] values = getJavaValues(kinds);
+        test(simple, values, kinds, false);
+
+        // Spread a long value across two int fields
+        kinds = Arrays.copyOf(fieldKinds, fieldKinds.length - 1);
+        kinds[1] = JavaKind.Long;
+        test(simple, getJavaValues(kinds), kinds, false);
+
+        // Produce a long value for the final int field so there is no matching int field for the
+        // second half of the long
+        kinds = fieldKinds.clone();
+        kinds[kinds.length - 1] = JavaKind.Long;
+        test(simple, getJavaValues(kinds), kinds, true);
+
+        // Not enough values for the fields.
+        kinds = Arrays.copyOf(fieldKinds, fieldKinds.length - 1);
+        test(simple, getJavaValues(kinds), kinds, true);
+
+        // Too many values for the fields.
+        kinds = Arrays.copyOf(fieldKinds, fieldKinds.length + 1);
+        kinds[kinds.length - 1] = JavaKind.Int;
+        test(simple, getJavaValues(kinds), kinds, true);
+    }
+}
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderData.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/MethodHandleAccessProviderData.java	Tue Oct 29 15:35:06 2019 -0700
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 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
@@ -173,6 +173,7 @@
     }
 
     // can't use nested classes for storing these test methods. see JDK-8010319
+    @SuppressWarnings("unused")
     private void privateMethod() {
         // empty
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/VirtualObjectLayoutTest.java	Tue Oct 29 15:35:06 2019 -0700
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package jdk.vm.ci.hotspot.test;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.code.VirtualObject;
+import jdk.vm.ci.code.test.VirtualObjectTestBase;
+import jdk.vm.ci.common.JVMCIError;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.JavaValue;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+public class VirtualObjectLayoutTest extends VirtualObjectTestBase {
+
+    @Override
+    protected void test(ResolvedJavaType klass, JavaValue[] values, JavaKind[] kinds, boolean error) {
+        // Verify that the layout checking will correctly report errors
+        VirtualObject virtual = VirtualObject.get(klass, 0);
+        virtual.setValues(values, kinds);
+        try {
+            HotSpotCompiledCode.verifyVirtualObject(virtual);
+        } catch (JVMCIError e) {
+            Assert.assertTrue("Unexpected error verifying " + virtual, error);
+            return;
+        }
+        Assert.assertFalse("Expected error but passed verifying " + virtual, error);
+    }
+
+    @Test
+    public void testFormat() {
+        testBase();
+    }
+}
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java	Tue Oct 29 13:52:04 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.runtime.test/src/jdk/vm/ci/runtime/test/TestSpeculationLog.java	Tue Oct 29 15:35:06 2019 -0700
@@ -4,9 +4,7 @@
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.  Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
+ * published by the Free Software Foundation.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or