8225810: Update JVMCI

Reviewed-by: never, dnsimon
This commit is contained in:
Vladimir Kozlov 2019-06-21 16:21:13 -07:00
parent c956e7ca8d
commit 3b0ee5a6d8
15 changed files with 380 additions and 43 deletions

View File

@ -568,6 +568,33 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jcla
return JVMCIENV->get_jobject(result); return JVMCIENV->get_jobject(result);
C2V_END C2V_END
C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jobject jvmci_type))
if (jvmci_type == NULL) {
JVMCI_THROW_0(NullPointerException);
}
JVMCIObject jvmci_type_object = JVMCIENV->wrap(jvmci_type);
JVMCIKlassHandle array_klass(THREAD);
if (JVMCIENV->isa_HotSpotResolvedPrimitiveType(jvmci_type_object)) {
BasicType type = JVMCIENV->kindToBasicType(JVMCIENV->get_HotSpotResolvedPrimitiveType_kind(jvmci_type_object), JVMCI_CHECK_0);
if (type == T_VOID) {
return NULL;
}
array_klass = Universe::typeArrayKlassObj(type);
if (array_klass == NULL) {
JVMCI_THROW_MSG_NULL(InternalError, err_msg("No array klass for primitive type %s", type2name(type)));
}
} else {
Klass* klass = JVMCIENV->asKlass(jvmci_type);
if (klass == NULL) {
JVMCI_THROW_0(NullPointerException);
}
array_klass = klass->array_klass(CHECK_NULL);
}
JVMCIObject result = JVMCIENV->get_jvmci_type(array_klass, JVMCI_CHECK_NULL);
return JVMCIENV->get_jobject(result);
C2V_END
C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror)) C2V_VMENTRY_NULL(jobject, lookupClass, (JNIEnv* env, jobject, jclass mirror))
requireInHotSpot("lookupClass", JVMCI_CHECK_NULL); requireInHotSpot("lookupClass", JVMCI_CHECK_NULL);
if (mirror == NULL) { if (mirror == NULL) {
@ -2578,6 +2605,18 @@ C2V_VMENTRY_0(jboolean, addFailedSpeculation, (JNIEnv* env, jobject, jlong faile
return FailedSpeculation::add_failed_speculation(NULL, (FailedSpeculation**)(address) failed_speculations_address, (address) speculation, speculation_len); return FailedSpeculation::add_failed_speculation(NULL, (FailedSpeculation**)(address) failed_speculations_address, (address) speculation, speculation_len);
} }
C2V_VMENTRY(void, callSystemExit, (JNIEnv* env, jobject, jint status))
JavaValue result(T_VOID);
JavaCallArguments jargs(1);
jargs.push_int(status);
JavaCalls::call_static(&result,
SystemDictionary::System_klass(),
vmSymbols::exit_method_name(),
vmSymbols::int_void_signature(),
&jargs,
CHECK);
}
#define CC (char*) /*cast a literal from (const char*)*/ #define CC (char*) /*cast a literal from (const char*)*/
#define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f)) #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &(c2v_ ## f))
@ -2624,6 +2663,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "hasNeverInlineDirective", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(hasNeverInlineDirective)}, {CC "hasNeverInlineDirective", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(hasNeverInlineDirective)},
{CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)}, {CC "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)},
{CC "lookupType", CC "(" STRING HS_RESOLVED_KLASS "Z)" HS_RESOLVED_TYPE, FN_PTR(lookupType)}, {CC "lookupType", CC "(" STRING HS_RESOLVED_KLASS "Z)" HS_RESOLVED_TYPE, FN_PTR(lookupType)},
{CC "getArrayType", CC "(" HS_RESOLVED_TYPE ")" HS_RESOLVED_KLASS, FN_PTR(getArrayType)},
{CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)}, {CC "lookupClass", CC "(" CLASS ")" HS_RESOLVED_TYPE, FN_PTR(lookupClass)},
{CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)}, {CC "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)},
{CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)}, {CC "lookupNameAndTypeRefIndexInPool", CC "(" HS_CONSTANT_POOL "I)I", FN_PTR(lookupNameAndTypeRefIndexInPool)},
@ -2723,6 +2763,7 @@ JNINativeMethod CompilerToVM::methods[] = {
{CC "getFailedSpeculationsAddress", CC "(" HS_RESOLVED_METHOD ")J", FN_PTR(getFailedSpeculationsAddress)}, {CC "getFailedSpeculationsAddress", CC "(" HS_RESOLVED_METHOD ")J", FN_PTR(getFailedSpeculationsAddress)},
{CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)}, {CC "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)},
{CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)}, {CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)},
{CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)},
}; };
int CompilerToVM::methods_count() { int CompilerToVM::methods_count() {

View File

@ -1361,6 +1361,9 @@ Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
return Handle(THREAD, obj); return Handle(THREAD, obj);
} else if (isa_IndirectHotSpotObjectConstantImpl(constant)) { } else if (isa_IndirectHotSpotObjectConstantImpl(constant)) {
jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant); jlong object_handle = get_IndirectHotSpotObjectConstantImpl_objectHandle(constant);
if (object_handle == 0L) {
JVMCI_THROW_MSG_(NullPointerException, "Foreign object reference has been cleared", Handle());
}
oop result = resolve_handle(object_handle); oop result = resolve_handle(object_handle);
if (result == NULL) { if (result == NULL) {
JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle()); JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());

View File

@ -770,6 +770,12 @@ final class CompilerToVM {
*/ */
native HotSpotResolvedJavaType getComponentType(HotSpotResolvedObjectTypeImpl type); native HotSpotResolvedJavaType getComponentType(HotSpotResolvedObjectTypeImpl type);
/**
* Get the array class for {@code type}. This can't be done symbolically since anonymous types
* can't be looked up by name.
*/
native HotSpotResolvedObjectTypeImpl getArrayType(HotSpotResolvedJavaType type);
/** /**
* Forces initialization of {@code type}. * Forces initialization of {@code type}.
*/ */
@ -978,4 +984,9 @@ final class CompilerToVM {
* @see HotSpotJVMCIRuntime#detachCurrentThread() * @see HotSpotJVMCIRuntime#detachCurrentThread()
*/ */
native void detachCurrentThread(); native void detachCurrentThread();
/**
* @see HotSpotJVMCIRuntime#exitHotSpot(int)
*/
native void callSystemExit(int status);
} }

View File

@ -87,4 +87,9 @@ public class HotSpotCompilationRequest extends CompilationRequest {
public int getId() { public int getId() {
return id; return id;
} }
@Override
public String toString() {
return id + ":" + super.toString();
}
} }

View File

@ -223,6 +223,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
// so that -XX:+JVMCIPrintProperties shows the option. // so that -XX:+JVMCIPrintProperties shows the option.
InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."), InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."), PrintConfig(Boolean.class, false, "Prints VM configuration available via JVMCI."),
AuditHandles(Boolean.class, false, "Record stack trace along with scoped foreign object reference wrappers " +
"to debug issue with a wrapper being used after its scope has closed."),
TraceMethodDataFilter(String.class, null, TraceMethodDataFilter(String.class, null,
"Enables tracing of profiling info when read by JVMCI.", "Enables tracing of profiling info when read by JVMCI.",
"Empty value: trace all methods", "Empty value: trace all methods",
@ -687,9 +689,11 @@ assert factories != null : "sanity";
return Collections.unmodifiableMap(backends); return Collections.unmodifiableMap(backends);
} }
@SuppressWarnings("try")
@VMEntryPoint @VMEntryPoint
private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) { private HotSpotCompilationRequestResult compileMethod(HotSpotResolvedJavaMethod method, int entryBCI, long compileState, int id) {
CompilationRequestResult result = getCompiler().compileMethod(new HotSpotCompilationRequest(method, entryBCI, compileState, id)); HotSpotCompilationRequest request = new HotSpotCompilationRequest(method, entryBCI, compileState, id);
CompilationRequestResult result = getCompiler().compileMethod(request);
assert result != null : "compileMethod must always return something"; assert result != null : "compileMethod must always return something";
HotSpotCompilationRequestResult hsResult; HotSpotCompilationRequestResult hsResult;
if (result instanceof HotSpotCompilationRequestResult) { if (result instanceof HotSpotCompilationRequestResult) {
@ -704,7 +708,6 @@ assert factories != null : "sanity";
hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes); hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes);
} }
} }
return hsResult; return hsResult;
} }
@ -1032,4 +1035,14 @@ assert factories != null : "sanity";
public void excludeFromJVMCICompilation(Module...modules) { public void excludeFromJVMCICompilation(Module...modules) {
this.excludeFromJVMCICompilation = modules.clone(); this.excludeFromJVMCICompilation = modules.clone();
} }
/**
* Calls {@link System#exit(int)} in HotSpot's runtime.
*/
public void exitHotSpot(int status) {
if (!IS_IN_NATIVE_IMAGE) {
System.exit(status);
}
compilerToVm.callSystemExit(status);
}
} }

View File

@ -0,0 +1,121 @@
/*
* 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;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import jdk.vm.ci.services.Services;
/**
* A mechanism for limiting the lifetime of a foreign object reference encapsulated in a
* {@link HotSpotObjectConstant}.
*
* A {@link HotSpotObjectConstant} allocated in a {@linkplain #openLocalScope local} scope will have
* its reference to any foreign object cleared when the scope {@linkplain #close() closes}. This
* allows the foreign memory manager to reclaim the foreign object (once there are no other strong
* references to it).
*
* {@link HotSpotObjectConstantScope}s have no impact on {@link HotSpotObjectConstant}s that do not
* encapsulate a foreign object reference.
*
* The object returned by {@link #enterGlobalScope()} or {@link #openLocalScope(Object)} should
* always be used in a try-with-resources statement. Failure to close a scope will almost certainly
* result in foreign objects being leaked.
*/
public final class HotSpotObjectConstantScope implements AutoCloseable {
static final ThreadLocal<HotSpotObjectConstantScope> CURRENT = new ThreadLocal<>();
private final HotSpotObjectConstantScope parent;
private List<IndirectHotSpotObjectConstantImpl> foreignObjects;
/**
* An object whose {@link Object#toString()} value describes a non-global scope. This is
* {@code null} iff this is a global scope.
*/
final Object localScopeDescription;
/**
* Opens a local scope that upon closing, will release foreign object references encapsulated by
* {@link HotSpotObjectConstant}s created in the scope.
*
* @param description an non-null object whose {@link Object#toString()} value describes the
* scope being opened
* @return {@code null} if the current runtime does not support remote object references
*/
public static HotSpotObjectConstantScope openLocalScope(Object description) {
return Services.IS_IN_NATIVE_IMAGE ? new HotSpotObjectConstantScope(Objects.requireNonNull(description)) : null;
}
/**
* Enters the global scope. This is useful to escape a local scope for execution that will
* create foreign object references that need to outlive the local scope.
*
* Foreign object references encapsulated by {@link HotSpotObjectConstant}s created in the
* global scope are only subject to reclamation once the {@link HotSpotObjectConstant} wrapper
* dies.
*
* @return {@code null} if the current runtime does not support remote object references or if
* this thread is currently in the global scope
*/
public static HotSpotObjectConstantScope enterGlobalScope() {
return Services.IS_IN_NATIVE_IMAGE && CURRENT.get() != null ? new HotSpotObjectConstantScope(null) : null;
}
private HotSpotObjectConstantScope(Object localScopeDescription) {
this.parent = CURRENT.get();
CURRENT.set(this);
this.localScopeDescription = localScopeDescription;
}
/**
* Determines if this scope is global.
*/
boolean isGlobal() {
return localScopeDescription == null;
}
void add(IndirectHotSpotObjectConstantImpl obj) {
assert !isGlobal();
if (foreignObjects == null) {
foreignObjects = new ArrayList<>();
}
foreignObjects.add(obj);
}
@VMEntryPoint
@Override
public void close() {
if (CURRENT.get() != this) {
throw new IllegalStateException("Cannot close non-active scope");
}
if (foreignObjects != null) {
for (IndirectHotSpotObjectConstantImpl obj : foreignObjects) {
obj.clear(localScopeDescription);
}
foreignObjects = null;
}
CURRENT.set(parent);
}
}

View File

@ -22,11 +22,15 @@
*/ */
package jdk.vm.ci.hotspot; package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.ResolvedJavaType;
public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType { public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType {
HotSpotResolvedObjectTypeImpl arrayOfType;
HotSpotResolvedJavaType(String name) { HotSpotResolvedJavaType(String name) {
super(name); super(name);
} }
@ -40,4 +44,12 @@ public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements
} }
abstract JavaConstant getJavaMirror(); abstract JavaConstant getJavaMirror();
@Override
public HotSpotResolvedObjectType getArrayClass() {
if (arrayOfType == null) {
arrayOfType = runtime().compilerToVm.getArrayType(this);
}
return arrayOfType;
}
} }

View File

@ -72,7 +72,6 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
private volatile HotSpotResolvedJavaField[] instanceFields; private volatile HotSpotResolvedJavaField[] instanceFields;
private volatile HotSpotResolvedObjectTypeImpl[] interfaces; private volatile HotSpotResolvedObjectTypeImpl[] interfaces;
private HotSpotConstantPool constantPool; private HotSpotConstantPool constantPool;
private HotSpotResolvedObjectType arrayOfType;
private final JavaConstant mirror; private final JavaConstant mirror;
private HotSpotResolvedObjectTypeImpl superClass; private HotSpotResolvedObjectTypeImpl superClass;
@ -103,18 +102,25 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
* Creates the JVMCI mirror for a {@link Class} object. * Creates the JVMCI mirror for a {@link Class} object.
* *
* <b>NOTE</b>: Creating an instance of this class does not install the mirror for the * <b>NOTE</b>: Creating an instance of this class does not install the mirror for the
* {@link Class} type. {@link #fromMetaspace} instead. * {@link Class} type.
* </p> * </p>
* *
* @param metadataPointer the Klass* to create the mirror for * @param metadataPointer the Klass* to create the mirror for
*/ */
@SuppressWarnings("try")
HotSpotResolvedObjectTypeImpl(long metadataPointer, String name) { HotSpotResolvedObjectTypeImpl(long metadataPointer, String name) {
super(name); super(name);
this.metadataPointer = metadataPointer;
this.mirror = runtime().compilerToVm.getJavaMirror(this);
assert metadataPointer != 0; assert metadataPointer != 0;
this.metadataPointer = metadataPointer;
// The mirror object must be in the global scope since
// this object will be cached in HotSpotJVMCIRuntime.resolvedJavaTypes
// and live across more than one compilation.
try (HotSpotObjectConstantScope global = HotSpotObjectConstantScope.enterGlobalScope()) {
this.mirror = runtime().compilerToVm.getJavaMirror(this);
assert getName().charAt(0) != '[' || isArray() : getName(); assert getName().charAt(0) != '[' || isArray() : getName();
} }
}
/** /**
* Gets the metaspace Klass for this type. * Gets the metaspace Klass for this type.
@ -146,18 +152,6 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset); return UNSAFE.getInt(getMetaspaceKlass() + config.klassAccessFlagsOffset);
} }
@Override
public HotSpotResolvedObjectType getArrayClass() {
if (arrayOfType == null) {
try {
arrayOfType = (HotSpotResolvedObjectType) runtime().compilerToVm.lookupType("[" + getName(), this, true);
} catch (ClassNotFoundException e) {
throw new JVMCIError(e);
}
}
return arrayOfType;
}
@Override @Override
public ResolvedJavaType getComponentType() { public ResolvedJavaType getComponentType() {
return runtime().compilerToVm.getComponentType(this); return runtime().compilerToVm.getComponentType(this);
@ -580,6 +574,11 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
return null; return null;
} }
if (resolvedMethod.canBeStaticallyBound()) {
// No assumptions are required.
return new AssumptionResult<>(resolvedMethod);
}
ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this); ResolvedJavaMethod result = resolvedMethod.uniqueConcreteMethod(this);
if (result != null) { if (result != null) {
return new AssumptionResult<>(result, new ConcreteMethod(method, this, result)); return new AssumptionResult<>(result, new ConcreteMethod(method, this, result));

View File

@ -46,7 +46,6 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
@NativeImageReinitialize static HotSpotResolvedPrimitiveType[] primitives; @NativeImageReinitialize static HotSpotResolvedPrimitiveType[] primitives;
private JavaKind kind; private JavaKind kind;
private HotSpotResolvedObjectType arrayClass;
HotSpotObjectConstantImpl mirror; HotSpotObjectConstantImpl mirror;
/** /**
@ -87,14 +86,7 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
if (kind == JavaKind.Void) { if (kind == JavaKind.Void) {
return null; return null;
} }
if (arrayClass == null) { return super.getArrayClass();
try {
arrayClass = (HotSpotResolvedObjectType) runtime().compilerToVm.lookupType("[" + kind.getTypeChar(), null, true);
} catch (ClassNotFoundException e) {
throw new JVMCIError(e);
}
}
return arrayClass;
} }
@Override @Override

View File

@ -24,17 +24,52 @@ package jdk.vm.ci.hotspot;
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime; import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.Option;
import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaConstant;
/**
* Encapsulates a JNI reference to an object in the HotSpot heap.
*
* {@link IndirectHotSpotObjectConstantImpl} objects are only allocated in the shared library heap.
*
* @see HotSpotObjectConstantScope
*/
final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl { final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl {
/** /**
* An object handle in {@code JVMCI::_jvmci_handles}. * An object handle in {@code JVMCI::_object_handles}.
*/
private long objectHandle;
/**
* Lazily computed hash code.
*/ */
final long objectHandle;
private int hashCode; private int hashCode;
final IndirectHotSpotObjectConstantImpl base; final IndirectHotSpotObjectConstantImpl base;
private static class Audit {
final Object scope;
final long handle;
final Throwable origin;
Audit(Object scope, long handle, Throwable origin) {
this.scope = scope;
this.handle = handle;
this.origin = origin;
}
}
/**
* Details useful to audit a scoped handle used after its creating scope closes. Set to an
* {@link Audit} object if {@link HotSpotJVMCIRuntime.Option#AuditHandles} is true otherwise to
* {@link HotSpotObjectConstantScope#localScopeDescription}.
*/
private Object rawAudit;
@SuppressWarnings("serial")
@VMEntryPoint @VMEntryPoint
private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister) { private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister) {
super(compressed); super(compressed);
@ -42,20 +77,80 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl
this.objectHandle = objectHandle; this.objectHandle = objectHandle;
this.base = null; this.base = null;
if (!skipRegister) { if (!skipRegister) {
HotSpotObjectConstantScope scope = HotSpotObjectConstantScope.CURRENT.get();
if (scope != null && !scope.isGlobal()) {
scope.add(this);
if (HotSpotJVMCIRuntime.Option.AuditHandles.getBoolean()) {
rawAudit = new Audit(scope.localScopeDescription, objectHandle, new Throwable() {
@Override
public String toString() {
return "Created " + objectHandle;
}
});
}
} else {
HandleCleaner.create(this, objectHandle); HandleCleaner.create(this, objectHandle);
} }
} }
}
private IndirectHotSpotObjectConstantImpl(IndirectHotSpotObjectConstantImpl base, boolean compressed) { private IndirectHotSpotObjectConstantImpl(IndirectHotSpotObjectConstantImpl base, boolean compressed) {
super(compressed); super(compressed);
// This is a variant of an original object that only varies in compress vs uncompressed. // This is a variant of an original object that only varies in compress vs uncompressed.
// Instead of creating a new handle, reference that object and objectHandle. // Instead of creating a new handle, reference that object and objectHandle.
this.objectHandle = base.objectHandle; this.objectHandle = base.getHandle();
// There should only be on level of indirection to the base object. // There should only be one level of indirection to the base object.
assert base.base == null || base.base.base == null; assert base.base == null || base.base.base == null;
this.base = base.base != null ? base.base : base; this.base = base.base != null ? base.base : base;
} }
long getHandle() {
checkHandle();
return objectHandle;
}
private void checkHandle() {
if (objectHandle == 0L) {
String message;
if (rawAudit instanceof Audit) {
Audit audit = (Audit) rawAudit;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PrintStream ps = new PrintStream(baos);
ps.println("Foreign object reference " + audit.handle + " created in scope '" + audit.scope + "' is no longer valid. Origin: {");
audit.origin.printStackTrace(ps);
ps.print('}');
ps.flush();
message = baos.toString();
} else {
message = "Foreign object reference created in scope '" + rawAudit + "' is no longer valid. " +
"Set property " + Option.AuditHandles.getPropertyName() + "=true to show origin of invalid foreign references.";
}
throw new NullPointerException(message);
}
}
boolean isValid() {
return objectHandle != 0L;
}
@Override
public HotSpotResolvedObjectType getType() {
checkHandle();
return super.getType();
}
/**
* Clears the foreign object reference.
*/
void clear(Object scopeDescription) {
checkHandle();
CompilerToVM.compilerToVM().deleteGlobalHandle(objectHandle);
if (rawAudit == null) {
rawAudit = scopeDescription;
}
objectHandle = 0L;
}
@Override @Override
public JavaConstant compress() { public JavaConstant compress() {
assert !compressed; assert !compressed;
@ -70,6 +165,7 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl
@Override @Override
public int getIdentityHashCode() { public int getIdentityHashCode() {
checkHandle();
int hash = hashCode; int hash = hashCode;
if (hash == 0) { if (hash == 0) {
hash = runtime().compilerToVm.getIdentityHashCode(this); hash = runtime().compilerToVm.getIdentityHashCode(this);

View File

@ -114,7 +114,7 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
} }
IndirectHotSpotObjectConstantImpl indirectX = (IndirectHotSpotObjectConstantImpl) x; IndirectHotSpotObjectConstantImpl indirectX = (IndirectHotSpotObjectConstantImpl) x;
IndirectHotSpotObjectConstantImpl indirectY = (IndirectHotSpotObjectConstantImpl) y; IndirectHotSpotObjectConstantImpl indirectY = (IndirectHotSpotObjectConstantImpl) y;
return runtime().compilerToVm.equals(x, indirectX.objectHandle, y, indirectY.objectHandle); return runtime().compilerToVm.equals(x, indirectX.getHandle(), y, indirectY.getHandle());
} }
@Override @Override
@ -288,6 +288,10 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
DirectHotSpotObjectConstantImpl direct = (DirectHotSpotObjectConstantImpl) object; DirectHotSpotObjectConstantImpl direct = (DirectHotSpotObjectConstantImpl) object;
return "CompilerObject<" + direct.object.getClass().getName() + ">"; return "CompilerObject<" + direct.object.getClass().getName() + ">";
} }
IndirectHotSpotObjectConstantImpl indirect = (IndirectHotSpotObjectConstantImpl) object;
if (!indirect.isValid()) {
return "Instance<null>";
}
return "Instance<" + object.getType().toJavaName() + ">"; return "Instance<" + object.getType().toJavaName() + ">";
} }

View File

@ -86,6 +86,29 @@ public class MetaUtil {
} }
} }
/**
* Classes for lambdas can have {@code /} characters that are not package separators. These are
* distinguished by being followed by a character that is not a
* {@link Character#isJavaIdentifierStart(char)} (e.g.,
* "jdk.vm.ci.runtime.test.TypeUniverse$$Lambda$1/869601985").
*/
private static String replacePackageSeparatorsWithDot(String name) {
int length = name.length();
int i = 0;
StringBuilder buf = new StringBuilder(length);
while (i < length - 1) {
char ch = name.charAt(i);
if (ch == '/' && Character.isJavaIdentifierStart(name.charAt(i + 1))) {
buf.append('.');
} else {
buf.append(ch);
}
i++;
}
buf.append(name.charAt(length - 1));
return buf.toString();
}
/** /**
* Converts a type name in internal form to an external form. * Converts a type name in internal form to an external form.
* *
@ -99,7 +122,7 @@ public class MetaUtil {
public static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) { public static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) {
switch (name.charAt(0)) { switch (name.charAt(0)) {
case 'L': { case 'L': {
String result = name.substring(1, name.length() - 1).replace('/', '.'); String result = replacePackageSeparatorsWithDot(name.substring(1, name.length() - 1));
if (!qualified) { if (!qualified) {
final int lastDot = result.lastIndexOf('.'); final int lastDot = result.lastIndexOf('.');
if (lastDot != -1) { if (lastDot != -1) {
@ -109,7 +132,7 @@ public class MetaUtil {
return result; return result;
} }
case '[': case '[':
return classForNameCompatible ? name.replace('/', '.') : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]"; return classForNameCompatible ? replacePackageSeparatorsWithDot(name) : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]";
default: default:
if (name.length() != 1) { if (name.length() != 1) {
throw new IllegalArgumentException("Illegal internal name: " + name); throw new IllegalArgumentException("Illegal internal name: " + name);

View File

@ -68,11 +68,16 @@ public class TestMetaAccessProvider extends TypeUniverse {
metaAccess.encodeDeoptActionAndReason(DEOPT_ACTION, DEOPT_REASON, DEBUG_IDS[3]).asInt() metaAccess.encodeDeoptActionAndReason(DEOPT_ACTION, DEOPT_REASON, DEBUG_IDS[3]).asInt()
}; };
private static boolean isUnsafeAnoymous(ResolvedJavaType type) {
return type.getHostClass() != null;
}
@Test @Test
public void lookupJavaTypeTest() { public void lookupJavaTypeTest() {
for (Class<?> c : classes) { for (Class<?> c : classes) {
ResolvedJavaType type = metaAccess.lookupJavaType(c); ResolvedJavaType type = metaAccess.lookupJavaType(c);
assertNotNull(c.toString(), type); assertNotNull(c.toString(), type);
if (!isUnsafeAnoymous(type)) {
assertEquals(c.toString(), type.getName(), toInternalName(c.getName())); assertEquals(c.toString(), type.getName(), toInternalName(c.getName()));
assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName())); assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName()));
assertEquals(c.toString(), c.getName(), type.toClassName()); assertEquals(c.toString(), c.getName(), type.toClassName());
@ -81,6 +86,7 @@ public class TestMetaAccessProvider extends TypeUniverse {
} }
} }
} }
}
@Test(expected = IllegalArgumentException.class) @Test(expected = IllegalArgumentException.class)
public void lookupJavaTypeNegativeTest() { public void lookupJavaTypeNegativeTest() {
@ -92,7 +98,9 @@ public class TestMetaAccessProvider extends TypeUniverse {
ResolvedJavaType[] result = metaAccess.lookupJavaTypes(classes.toArray(new Class<?>[classes.size()])); ResolvedJavaType[] result = metaAccess.lookupJavaTypes(classes.toArray(new Class<?>[classes.size()]));
int counter = 0; int counter = 0;
for (Class<?> aClass : classes) { for (Class<?> aClass : classes) {
if (!isUnsafeAnoymous(result[counter])) {
assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName()); assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName());
}
counter++; counter++;
} }
} }

View File

@ -161,7 +161,11 @@ public class TestResolvedJavaType extends TypeUniverse {
for (Class<?> c : classes) { for (Class<?> c : classes) {
ResolvedJavaType type = metaAccess.lookupJavaType(c); ResolvedJavaType type = metaAccess.lookupJavaType(c);
ResolvedJavaType host = type.getHostClass(); ResolvedJavaType host = type.getHostClass();
if (!type.equals(predicateType)) {
assertNull(host); assertNull(host);
} else {
assertNotNull(host);
}
} }
class LocalClass {} class LocalClass {}

View File

@ -51,6 +51,7 @@ import java.util.Map;
import java.util.Queue; import java.util.Queue;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static java.lang.reflect.Modifier.isFinal; import static java.lang.reflect.Modifier.isFinal;
@ -68,6 +69,7 @@ public class TypeUniverse {
public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection(); public static final ConstantReflectionProvider constantReflection = JVMCI.getRuntime().getHostJVMCIBackend().getConstantReflection();
public static final Collection<Class<?>> classes = new HashSet<>(); public static final Collection<Class<?>> classes = new HashSet<>();
public static final Set<ResolvedJavaType> javaTypes; public static final Set<ResolvedJavaType> javaTypes;
public static final ResolvedJavaType predicateType;
public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>(); public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
private static List<ConstantValue> constants; private static List<ConstantValue> constants;
@ -116,6 +118,9 @@ public class TypeUniverse {
for (Class<?> c : initialClasses) { for (Class<?> c : initialClasses) {
addClass(c); addClass(c);
} }
Predicate<String> predicate = s -> s.length() == 1;
addClass(predicate.getClass());
predicateType = metaAccess.lookupJavaType(predicate.getClass());
javaTypes = Collections.unmodifiableSet(classes.stream().map(c -> metaAccess.lookupJavaType(c)).collect(Collectors.toSet())); javaTypes = Collections.unmodifiableSet(classes.stream().map(c -> metaAccess.lookupJavaType(c)).collect(Collectors.toSet()));
} }