8225810: Update JVMCI
Reviewed-by: never, dnsimon
This commit is contained in:
parent
c956e7ca8d
commit
3b0ee5a6d8
@ -568,6 +568,33 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, jcla
|
||||
return JVMCIENV->get_jobject(result);
|
||||
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))
|
||||
requireInHotSpot("lookupClass", JVMCI_CHECK_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);
|
||||
}
|
||||
|
||||
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 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 "shouldInlineMethod", CC "(" HS_RESOLVED_METHOD ")Z", FN_PTR(shouldInlineMethod)},
|
||||
{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 "lookupNameInPool", CC "(" HS_CONSTANT_POOL "I)" STRING, FN_PTR(lookupNameInPool)},
|
||||
{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 "releaseFailedSpeculations", CC "(J)V", FN_PTR(releaseFailedSpeculations)},
|
||||
{CC "addFailedSpeculation", CC "(J[B)Z", FN_PTR(addFailedSpeculation)},
|
||||
{CC "callSystemExit", CC "(I)V", FN_PTR(callSystemExit)},
|
||||
};
|
||||
|
||||
int CompilerToVM::methods_count() {
|
||||
|
@ -1361,6 +1361,9 @@ Handle JVMCIEnv::asConstant(JVMCIObject constant, JVMCI_TRAPS) {
|
||||
return Handle(THREAD, obj);
|
||||
} else if (isa_IndirectHotSpotObjectConstantImpl(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);
|
||||
if (result == NULL) {
|
||||
JVMCI_THROW_MSG_(InternalError, "Constant was unexpectedly NULL", Handle());
|
||||
|
@ -770,6 +770,12 @@ final class CompilerToVM {
|
||||
*/
|
||||
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}.
|
||||
*/
|
||||
@ -978,4 +984,9 @@ final class CompilerToVM {
|
||||
* @see HotSpotJVMCIRuntime#detachCurrentThread()
|
||||
*/
|
||||
native void detachCurrentThread();
|
||||
|
||||
/**
|
||||
* @see HotSpotJVMCIRuntime#exitHotSpot(int)
|
||||
*/
|
||||
native void callSystemExit(int status);
|
||||
}
|
||||
|
@ -87,4 +87,9 @@ public class HotSpotCompilationRequest extends CompilationRequest {
|
||||
public int getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return id + ":" + super.toString();
|
||||
}
|
||||
}
|
||||
|
@ -223,6 +223,8 @@ public final class HotSpotJVMCIRuntime implements JVMCIRuntime {
|
||||
// so that -XX:+JVMCIPrintProperties shows the option.
|
||||
InitTimer(Boolean.class, false, "Specifies if initialization timing is enabled."),
|
||||
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,
|
||||
"Enables tracing of profiling info when read by JVMCI.",
|
||||
"Empty value: trace all methods",
|
||||
@ -687,9 +689,11 @@ assert factories != null : "sanity";
|
||||
return Collections.unmodifiableMap(backends);
|
||||
}
|
||||
|
||||
@SuppressWarnings("try")
|
||||
@VMEntryPoint
|
||||
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";
|
||||
HotSpotCompilationRequestResult hsResult;
|
||||
if (result instanceof HotSpotCompilationRequestResult) {
|
||||
@ -704,7 +708,6 @@ assert factories != null : "sanity";
|
||||
hsResult = HotSpotCompilationRequestResult.success(inlinedBytecodes);
|
||||
}
|
||||
}
|
||||
|
||||
return hsResult;
|
||||
}
|
||||
|
||||
@ -1032,4 +1035,14 @@ assert factories != null : "sanity";
|
||||
public void excludeFromJVMCICompilation(Module...modules) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -22,11 +22,15 @@
|
||||
*/
|
||||
package jdk.vm.ci.hotspot;
|
||||
|
||||
import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
|
||||
|
||||
import jdk.vm.ci.meta.JavaConstant;
|
||||
import jdk.vm.ci.meta.ResolvedJavaType;
|
||||
|
||||
public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements ResolvedJavaType {
|
||||
|
||||
HotSpotResolvedObjectTypeImpl arrayOfType;
|
||||
|
||||
HotSpotResolvedJavaType(String name) {
|
||||
super(name);
|
||||
}
|
||||
@ -40,4 +44,12 @@ public abstract class HotSpotResolvedJavaType extends HotSpotJavaType implements
|
||||
}
|
||||
|
||||
abstract JavaConstant getJavaMirror();
|
||||
|
||||
@Override
|
||||
public HotSpotResolvedObjectType getArrayClass() {
|
||||
if (arrayOfType == null) {
|
||||
arrayOfType = runtime().compilerToVm.getArrayType(this);
|
||||
}
|
||||
return arrayOfType;
|
||||
}
|
||||
}
|
||||
|
@ -72,7 +72,6 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
||||
private volatile HotSpotResolvedJavaField[] instanceFields;
|
||||
private volatile HotSpotResolvedObjectTypeImpl[] interfaces;
|
||||
private HotSpotConstantPool constantPool;
|
||||
private HotSpotResolvedObjectType arrayOfType;
|
||||
private final JavaConstant mirror;
|
||||
private HotSpotResolvedObjectTypeImpl superClass;
|
||||
|
||||
@ -103,17 +102,24 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
||||
* 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
|
||||
* {@link Class} type. {@link #fromMetaspace} instead.
|
||||
* {@link Class} type.
|
||||
* </p>
|
||||
*
|
||||
* @param metadataPointer the Klass* to create the mirror for
|
||||
*/
|
||||
@SuppressWarnings("try")
|
||||
HotSpotResolvedObjectTypeImpl(long metadataPointer, String name) {
|
||||
super(name);
|
||||
this.metadataPointer = metadataPointer;
|
||||
this.mirror = runtime().compilerToVm.getJavaMirror(this);
|
||||
assert metadataPointer != 0;
|
||||
assert getName().charAt(0) != '[' || isArray() : getName();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -146,18 +152,6 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
||||
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
|
||||
public ResolvedJavaType getComponentType() {
|
||||
return runtime().compilerToVm.getComponentType(this);
|
||||
@ -580,6 +574,11 @@ final class HotSpotResolvedObjectTypeImpl extends HotSpotResolvedJavaType implem
|
||||
return null;
|
||||
}
|
||||
|
||||
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));
|
||||
|
@ -46,7 +46,6 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
|
||||
@NativeImageReinitialize static HotSpotResolvedPrimitiveType[] primitives;
|
||||
|
||||
private JavaKind kind;
|
||||
private HotSpotResolvedObjectType arrayClass;
|
||||
HotSpotObjectConstantImpl mirror;
|
||||
|
||||
/**
|
||||
@ -87,14 +86,7 @@ public final class HotSpotResolvedPrimitiveType extends HotSpotResolvedJavaType
|
||||
if (kind == JavaKind.Void) {
|
||||
return null;
|
||||
}
|
||||
if (arrayClass == null) {
|
||||
try {
|
||||
arrayClass = (HotSpotResolvedObjectType) runtime().compilerToVm.lookupType("[" + kind.getTypeChar(), null, true);
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new JVMCIError(e);
|
||||
}
|
||||
}
|
||||
return arrayClass;
|
||||
return super.getArrayClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -24,17 +24,52 @@ package jdk.vm.ci.hotspot;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
/**
|
||||
* 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;
|
||||
|
||||
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
|
||||
private IndirectHotSpotObjectConstantImpl(long objectHandle, boolean compressed, boolean skipRegister) {
|
||||
super(compressed);
|
||||
@ -42,7 +77,20 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl
|
||||
this.objectHandle = objectHandle;
|
||||
this.base = null;
|
||||
if (!skipRegister) {
|
||||
HandleCleaner.create(this, objectHandle);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,12 +98,59 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl
|
||||
super(compressed);
|
||||
// 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.
|
||||
this.objectHandle = base.objectHandle;
|
||||
// There should only be on level of indirection to the base object.
|
||||
this.objectHandle = base.getHandle();
|
||||
// There should only be one level of indirection to the base object.
|
||||
assert base.base == null || base.base.base == null;
|
||||
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
|
||||
public JavaConstant compress() {
|
||||
assert !compressed;
|
||||
@ -70,6 +165,7 @@ final class IndirectHotSpotObjectConstantImpl extends HotSpotObjectConstantImpl
|
||||
|
||||
@Override
|
||||
public int getIdentityHashCode() {
|
||||
checkHandle();
|
||||
int hash = hashCode;
|
||||
if (hash == 0) {
|
||||
hash = runtime().compilerToVm.getIdentityHashCode(this);
|
||||
|
@ -114,7 +114,7 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
|
||||
}
|
||||
IndirectHotSpotObjectConstantImpl indirectX = (IndirectHotSpotObjectConstantImpl) x;
|
||||
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
|
||||
@ -288,6 +288,10 @@ class SharedLibraryJVMCIReflection extends HotSpotJVMCIReflection {
|
||||
DirectHotSpotObjectConstantImpl direct = (DirectHotSpotObjectConstantImpl) object;
|
||||
return "CompilerObject<" + direct.object.getClass().getName() + ">";
|
||||
}
|
||||
IndirectHotSpotObjectConstantImpl indirect = (IndirectHotSpotObjectConstantImpl) object;
|
||||
if (!indirect.isValid()) {
|
||||
return "Instance<null>";
|
||||
}
|
||||
return "Instance<" + object.getType().toJavaName() + ">";
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
@ -99,7 +122,7 @@ public class MetaUtil {
|
||||
public static String internalNameToJava(String name, boolean qualified, boolean classForNameCompatible) {
|
||||
switch (name.charAt(0)) {
|
||||
case 'L': {
|
||||
String result = name.substring(1, name.length() - 1).replace('/', '.');
|
||||
String result = replacePackageSeparatorsWithDot(name.substring(1, name.length() - 1));
|
||||
if (!qualified) {
|
||||
final int lastDot = result.lastIndexOf('.');
|
||||
if (lastDot != -1) {
|
||||
@ -109,7 +132,7 @@ public class MetaUtil {
|
||||
return result;
|
||||
}
|
||||
case '[':
|
||||
return classForNameCompatible ? name.replace('/', '.') : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]";
|
||||
return classForNameCompatible ? replacePackageSeparatorsWithDot(name) : internalNameToJava(name.substring(1), qualified, classForNameCompatible) + "[]";
|
||||
default:
|
||||
if (name.length() != 1) {
|
||||
throw new IllegalArgumentException("Illegal internal name: " + name);
|
||||
|
@ -68,16 +68,22 @@ public class TestMetaAccessProvider extends TypeUniverse {
|
||||
metaAccess.encodeDeoptActionAndReason(DEOPT_ACTION, DEOPT_REASON, DEBUG_IDS[3]).asInt()
|
||||
};
|
||||
|
||||
private static boolean isUnsafeAnoymous(ResolvedJavaType type) {
|
||||
return type.getHostClass() != null;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lookupJavaTypeTest() {
|
||||
for (Class<?> c : classes) {
|
||||
ResolvedJavaType type = metaAccess.lookupJavaType(c);
|
||||
assertNotNull(c.toString(), type);
|
||||
assertEquals(c.toString(), type.getName(), toInternalName(c.getName()));
|
||||
assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName()));
|
||||
assertEquals(c.toString(), c.getName(), type.toClassName());
|
||||
if (!type.isArray()) {
|
||||
assertEquals(c.toString(), c.getName(), type.toJavaName());
|
||||
if (!isUnsafeAnoymous(type)) {
|
||||
assertEquals(c.toString(), type.getName(), toInternalName(c.getName()));
|
||||
assertEquals(c.toString(), type.getName(), toInternalName(type.toJavaName()));
|
||||
assertEquals(c.toString(), c.getName(), type.toClassName());
|
||||
if (!type.isArray()) {
|
||||
assertEquals(c.toString(), c.getName(), type.toJavaName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -92,7 +98,9 @@ public class TestMetaAccessProvider extends TypeUniverse {
|
||||
ResolvedJavaType[] result = metaAccess.lookupJavaTypes(classes.toArray(new Class<?>[classes.size()]));
|
||||
int counter = 0;
|
||||
for (Class<?> aClass : classes) {
|
||||
assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName());
|
||||
if (!isUnsafeAnoymous(result[counter])) {
|
||||
assertEquals("Unexpected javaType: " + result[counter] + " while expecting of class: " + aClass, result[counter].toClassName(), aClass.getName());
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
@ -161,7 +161,11 @@ public class TestResolvedJavaType extends TypeUniverse {
|
||||
for (Class<?> c : classes) {
|
||||
ResolvedJavaType type = metaAccess.lookupJavaType(c);
|
||||
ResolvedJavaType host = type.getHostClass();
|
||||
assertNull(host);
|
||||
if (!type.equals(predicateType)) {
|
||||
assertNull(host);
|
||||
} else {
|
||||
assertNotNull(host);
|
||||
}
|
||||
}
|
||||
|
||||
class LocalClass {}
|
||||
|
@ -51,6 +51,7 @@ import java.util.Map;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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 Collection<Class<?>> classes = new HashSet<>();
|
||||
public static final Set<ResolvedJavaType> javaTypes;
|
||||
public static final ResolvedJavaType predicateType;
|
||||
public static final Map<Class<?>, Class<?>> arrayClasses = new HashMap<>();
|
||||
|
||||
private static List<ConstantValue> constants;
|
||||
@ -116,6 +118,9 @@ public class TypeUniverse {
|
||||
for (Class<?> c : initialClasses) {
|
||||
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()));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user