--- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Thu Oct 24 12:18:32 2019 -0700
+++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp Thu Oct 24 16:58:39 2019 -0700
@@ -2330,6 +2330,16 @@
return true;
C2V_END
+C2V_VMENTRY_PREFIX(jlong, getCurrentJavaThread, (JNIEnv* env, jobject c2vm))
+ if (base_thread == NULL) {
+ // Called from unattached JVMCI shared library thread
+ return 0L;
+ }
+ JVMCITraceMark jtm("getCurrentJavaThread");
+ assert(base_thread->is_Java_thread(), "just checking");
+ return (jlong) p2i(base_thread);
+C2V_END
+
C2V_VMENTRY_PREFIX(jboolean, attachCurrentThread, (JNIEnv* env, jobject c2vm, jboolean as_daemon))
if (base_thread == NULL) {
// Called from unattached JVMCI shared library thread
@@ -2743,6 +2753,7 @@
{CC "deleteGlobalHandle", CC "(J)V", FN_PTR(deleteGlobalHandle)},
{CC "registerNativeMethods", CC "(" CLASS ")[J", FN_PTR(registerNativeMethods)},
{CC "isCurrentThreadAttached", CC "()Z", FN_PTR(isCurrentThreadAttached)},
+ {CC "getCurrentJavaThread", CC "()J", FN_PTR(getCurrentJavaThread)},
{CC "attachCurrentThread", CC "(Z)Z", FN_PTR(attachCurrentThread)},
{CC "detachCurrentThread", CC "()V", FN_PTR(detachCurrentThread)},
{CC "translate", CC "(" OBJECT ")J", FN_PTR(translate)},
--- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Thu Oct 24 12:18:32 2019 -0700
+++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp Thu Oct 24 16:58:39 2019 -0700
@@ -180,6 +180,7 @@
nonstatic_field(JavaThread, _pending_transfer_to_interpreter, bool) \
nonstatic_field(JavaThread, _jvmci_counters, jlong*) \
nonstatic_field(JavaThread, _should_post_on_exceptions_flag, int) \
+ nonstatic_field(JavaThread, _jni_environment, JNIEnv) \
nonstatic_field(JavaThread, _reserved_stack_activation, address) \
\
static_field(java_lang_Class, _klass_offset, int) \
@@ -538,6 +539,7 @@
declare_constant(FieldInfo::field_slots) \
\
declare_constant(InstanceKlass::linked) \
+ declare_constant(InstanceKlass::being_initialized) \
declare_constant(InstanceKlass::fully_initialized) \
declare_constant(InstanceKlass::_misc_is_unsafe_anonymous) \
\
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/CompilerToVM.java Thu Oct 24 16:58:39 2019 -0700
@@ -967,6 +967,11 @@
native boolean isCurrentThreadAttached();
/**
+ * @see HotSpotJVMCIRuntime#getCurrentJavaThread()
+ */
+ native long getCurrentJavaThread();
+
+ /**
* @see HotSpotJVMCIRuntime#attachCurrentThread
*/
native boolean attachCurrentThread(boolean asDaemon);
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotJVMCIRuntime.java Thu Oct 24 16:58:39 2019 -0700
@@ -999,6 +999,14 @@
}
/**
+ * Gets the address of the HotSpot {@code JavaThread} C++ object for the current thread. This
+ * will return {@code 0} if called from an unattached JVMCI shared library thread.
+ */
+ public long getCurrentJavaThread() {
+ return compilerToVm.getCurrentJavaThread();
+ }
+
+ /**
* Ensures the current thread is attached to the peer runtime.
*
* @param asDaemon if the thread is not yet attached, should it be attached as a daemon
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedJavaType.java Thu Oct 24 16:58:39 2019 -0700
@@ -52,4 +52,13 @@
}
return arrayOfType;
}
+
+ /**
+ * Checks whether this type is currently being initialized. If a type is being initialized it
+ * implies that it was {@link #isLinked() linked} and that the static initializer is currently
+ * being run.
+ *
+ * @return {@code true} if this type is being initialized
+ */
+ abstract boolean isBeingInitialized();
}
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedObjectTypeImpl.java Thu Oct 24 16:58:39 2019 -0700
@@ -360,6 +360,11 @@
}
@Override
+ public boolean isBeingInitialized() {
+ return isArray() ? false : getInitState() == config().instanceKlassStateBeingInitialized;
+ }
+
+ @Override
public boolean isLinked() {
return isArray() ? true : getInitState() >= config().instanceKlassStateLinked;
}
@@ -379,7 +384,7 @@
public void initialize() {
if (!isInitialized()) {
runtime().compilerToVm.ensureInitialized(this);
- assert isInitialized();
+ assert isInitialized() || isBeingInitialized();
}
}
@@ -578,11 +583,6 @@
return new AssumptionResult<>(resolvedMethod);
}
- if (resolvedMethod.canBeStaticallyBound()) {
- // No assumptions are required.
- return new AssumptionResult<>(resolvedMethod);
- }
-
ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this);
if (result != null) {
return new AssumptionResult<>(result, new ConcreteMethod(method, this, result));
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotResolvedPrimitiveType.java Thu Oct 24 16:58:39 2019 -0700
@@ -150,6 +150,11 @@
}
@Override
+ public boolean isBeingInitialized() {
+ return false;
+ }
+
+ @Override
public boolean isLinked() {
return true;
}
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotSpeculationEncoding.java Thu Oct 24 16:58:39 2019 -0700
@@ -29,7 +29,6 @@
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
-import jdk.vm.ci.common.JVMCIError;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
@@ -37,8 +36,8 @@
/**
* Implements a {@link SpeculationReasonEncoding} that {@linkplain #getByteArray() produces} a byte
* array. Data is added via a {@link DataOutputStream}. When producing the final byte array, if the
- * total length of data exceeds the length of a SHA-1 digest, then a SHA-1 digest of the data is
- * produced instead.
+ * total length of data exceeds the length of a SHA-1 digest and a SHA-1 digest algorithm is
+ * available, then a SHA-1 digest of the data is produced instead.
*/
final class HotSpotSpeculationEncoding extends ByteArrayOutputStream implements SpeculationReasonEncoding {
@@ -152,21 +151,33 @@
}
/**
- * Prototype SHA1 digest that is cloned before use.
+ * Prototype SHA1 digest.
*/
- private static final MessageDigest SHA1 = getSHA1();
- private static final int SHA1_LENGTH = SHA1.getDigestLength();
+ private static final MessageDigest SHA1;
- private static MessageDigest getSHA1() {
+ /**
+ * Cloning the prototype is quicker than calling {@link MessageDigest#getInstance(String)} every
+ * time.
+ */
+ private static final boolean SHA1_IS_CLONEABLE;
+ private static final int SHA1_LENGTH;
+
+ static {
+ MessageDigest sha1 = null;
+ boolean sha1IsCloneable = false;
try {
- MessageDigest sha1 = MessageDigest.getInstance("SHA-1");
+ sha1 = MessageDigest.getInstance("SHA-1");
sha1.clone();
- return sha1;
- } catch (CloneNotSupportedException | NoSuchAlgorithmException e) {
+ sha1IsCloneable = true;
+ } catch (NoSuchAlgorithmException e) {
// Should never happen given that SHA-1 is mandated in a
- // compliant Java platform implementation.
- throw new JVMCIError("Expect a cloneable implementation of a SHA-1 message digest to be available", e);
+ // compliant Java platform implementation. However, be
+ // conservative and fall back to not using a digest.
+ } catch (CloneNotSupportedException e) {
}
+ SHA1 = sha1;
+ SHA1_IS_CLONEABLE = sha1IsCloneable;
+ SHA1_LENGTH = SHA1 == null ? 20 : SHA1.getDigestLength();
}
/**
@@ -175,12 +186,12 @@
*/
byte[] getByteArray() {
if (result == null) {
- if (count > SHA1_LENGTH) {
+ if (SHA1 != null && count > SHA1_LENGTH) {
try {
- MessageDigest md = (MessageDigest) SHA1.clone();
+ MessageDigest md = SHA1_IS_CLONEABLE ? (MessageDigest) SHA1.clone() : MessageDigest.getInstance("SHA-1");
md.update(buf, 0, count);
result = md.digest();
- } catch (CloneNotSupportedException e) {
+ } catch (CloneNotSupportedException | NoSuchAlgorithmException e) {
throw new InternalError(e);
}
} else {
--- a/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Thu Oct 24 12:18:32 2019 -0700
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/HotSpotVMConfig.java Thu Oct 24 16:58:39 2019 -0700
@@ -107,6 +107,7 @@
final int instanceKlassStateLinked = getConstant("InstanceKlass::linked", Integer.class);
final int instanceKlassStateFullyInitialized = getConstant("InstanceKlass::fully_initialized", Integer.class);
+ final int instanceKlassStateBeingInitialized = getConstant("InstanceKlass::being_initialized", Integer.class);
final int instanceKlassMiscIsUnsafeAnonymous = getConstant("InstanceKlass::_misc_is_unsafe_anonymous", Integer.class);
final int annotationsFieldAnnotationsOffset = getFieldOffset("Annotations::_fields_annotations", Integer.class, "Array<AnnotationArray*>*");
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.hotspot/src/jdk/vm/ci/hotspot/SharedHotSpotSpeculationLog.java Thu Oct 24 16:58:39 2019 -0700
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2014, 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;
+
+/**
+ * A wrapper that holds a strong reference to a "master" speculation log that
+ * {@linkplain HotSpotSpeculationLog#managesFailedSpeculations() manages} the failed speculations
+ * list.
+ */
+public class SharedHotSpotSpeculationLog extends HotSpotSpeculationLog {
+ private final HotSpotSpeculationLog masterLog;
+
+ public SharedHotSpotSpeculationLog(HotSpotSpeculationLog masterLog) {
+ super(masterLog.getFailedSpeculationsAddress());
+ this.masterLog = masterLog;
+ }
+
+ @Override
+ public String toString() {
+ return masterLog.toString();
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.ci/share/classes/jdk.vm.ci.meta/src/jdk/vm/ci/meta/EncodedSpeculationReason.java Thu Oct 24 16:58:39 2019 -0700
@@ -0,0 +1,115 @@
+/*
+ * 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.meta;
+
+import java.util.Arrays;
+import java.util.function.Supplier;
+
+import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
+
+/**
+ * An implementation of {@link SpeculationReason} based on encoded values.
+ */
+public class EncodedSpeculationReason implements SpeculationReason {
+ final int groupId;
+ final String groupName;
+ final Object[] context;
+ private SpeculationLog.SpeculationReasonEncoding encoding;
+
+ public EncodedSpeculationReason(int groupId, String groupName, Object[] context) {
+ this.groupId = groupId;
+ this.groupName = groupName;
+ this.context = context;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof EncodedSpeculationReason) {
+ if (obj instanceof EncodedSpeculationReason) {
+ EncodedSpeculationReason that = (EncodedSpeculationReason) obj;
+ return this.groupId == that.groupId && Arrays.equals(this.context, that.context);
+ }
+ return false;
+ }
+ return false;
+ }
+
+ @Override
+ public SpeculationLog.SpeculationReasonEncoding encode(Supplier<SpeculationLog.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(SpeculationLog.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 {
+ throw new IllegalArgumentException("Unsupported type for encoding: " + c.getName());
+ }
+ }
+
+ @Override
+ public int hashCode() {
+ return groupId + Arrays.hashCode(this.context);
+ }
+
+ @Override
+ public String toString() {
+ return String.format("%s@%d%s", groupName, groupId, Arrays.toString(context));
+ }
+}
--- a/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotSpeculationLog.java Thu Oct 24 12:18:32 2019 -0700
+++ b/test/hotspot/jtreg/compiler/jvmci/jdk.vm.ci.hotspot.test/src/jdk/vm/ci/hotspot/test/TestHotSpotSpeculationLog.java Thu Oct 24 16:58:39 2019 -0700
@@ -78,7 +78,8 @@
public synchronized void testFailedSpeculations() {
HotSpotSpeculationLog log = new HotSpotSpeculationLog();
DummyReason reason1 = new DummyReason("dummy1");
- DummyReason reason2 = new DummyReason("dummy2");
+ String longName = new String(new char[2000]).replace('\0', 'X');
+ DummyReason reason2 = new DummyReason(longName);
Assert.assertTrue(log.maySpeculate(reason1));
Assert.assertTrue(log.maySpeculate(reason2));