Merge
This commit is contained in:
commit
d9b1bb5860
src
hotspot/share
java.base/share/classes/java
jdk.compiler/share/classes/com/sun
jdk.incubator.foreign/share/classes/jdk/internal/foreign
AbstractMemorySegmentImpl.javaConfinedScope.javaNativeSymbolImpl.javaResourceScopeImpl.javaSharedScope.java
jdk.jfr/share/classes/jdk/jfr/internal
test
hotspot/jtreg/compiler
jdk
java/foreign
jdk/jfr/event/gc/collection
sun/security/pkcs12
langtools/tools/javac
micro/org/openjdk/bench/jdk/incubator/foreign
@ -2072,9 +2072,11 @@ void GraphBuilder::invoke(Bytecodes::Code code) {
|
||||
}
|
||||
|
||||
// check if we could do inlining
|
||||
if (!PatchALot && Inline && target->is_loaded() && callee_holder->is_linked() && !patch_for_appendix) {
|
||||
if (!PatchALot && Inline && target->is_loaded() && !patch_for_appendix &&
|
||||
callee_holder->is_loaded()) { // the effect of symbolic reference resolution
|
||||
|
||||
// callee is known => check if we have static binding
|
||||
if ((code == Bytecodes::_invokestatic && callee_holder->is_initialized()) || // invokestatic involves an initialization barrier on resolved klass
|
||||
if ((code == Bytecodes::_invokestatic && klass->is_initialized()) || // invokestatic involves an initialization barrier on declaring class
|
||||
code == Bytecodes::_invokespecial ||
|
||||
(code == Bytecodes::_invokevirtual && target->is_final_method()) ||
|
||||
code == Bytecodes::_invokedynamic) {
|
||||
|
@ -476,8 +476,9 @@ ciKlass* ciBytecodeStream::get_declared_method_holder() {
|
||||
constantPoolHandle cpool(THREAD, _method->get_Method()->constants());
|
||||
bool ignore;
|
||||
// report as MethodHandle for invokedynamic, which is syntactically classless
|
||||
if (cur_bc() == Bytecodes::_invokedynamic)
|
||||
return CURRENT_ENV->get_klass_by_name(_holder, ciSymbols::java_lang_invoke_MethodHandle(), false);
|
||||
if (cur_bc() == Bytecodes::_invokedynamic) {
|
||||
return CURRENT_ENV->MethodHandle_klass();
|
||||
}
|
||||
return CURRENT_ENV->get_klass_by_index(cpool, get_method_holder_index(), ignore, _holder);
|
||||
}
|
||||
|
||||
|
@ -683,6 +683,7 @@ class InvokerBytecodeGenerator {
|
||||
}
|
||||
|
||||
private static MemberName resolveFrom(String name, MethodType type, Class<?> holder) {
|
||||
assert(!UNSAFE.shouldBeInitialized(holder)) : holder + "not initialized";
|
||||
MemberName member = new MemberName(holder, name, type, REF_invokeStatic);
|
||||
MemberName resolvedMember = MemberName.getFactory().resolveOrNull(REF_invokeStatic, member, holder, LM_TRUSTED);
|
||||
traceLambdaForm(name, type, holder, resolvedMember);
|
||||
|
@ -767,7 +767,11 @@ public abstract class Buffer {
|
||||
final void checkScope() {
|
||||
ScopedMemoryAccess.Scope scope = scope();
|
||||
if (scope != null) {
|
||||
scope.checkValidState();
|
||||
try {
|
||||
scope.checkValidState();
|
||||
} catch (ScopedMemoryAccess.Scope.ScopedAccessError e) {
|
||||
throw new IllegalStateException("This segment is already closed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,6 +87,11 @@ public abstract class DocTrees extends Trees {
|
||||
/**
|
||||
* Returns the doc comment tree, if any, for the Tree node identified by a given TreePath.
|
||||
* Returns {@code null} if no doc comment was found.
|
||||
*
|
||||
* @implNote The default implementation of this method returns the same
|
||||
* {@code DocCommentTree} instance for repeated invocations
|
||||
* with the same argument.
|
||||
*
|
||||
* @param path the path for the tree node
|
||||
* @return the doc comment tree
|
||||
*/
|
||||
@ -95,6 +100,11 @@ public abstract class DocTrees extends Trees {
|
||||
/**
|
||||
* Returns the doc comment tree of the given element.
|
||||
* Returns {@code null} if no doc comment was found.
|
||||
*
|
||||
* @implNote The default implementation of this method returns the same
|
||||
* {@code DocCommentTree} instance for repeated invocations
|
||||
* with the same argument.
|
||||
*
|
||||
* @param e an element whose documentation is required
|
||||
* @return the doc comment tree
|
||||
*
|
||||
@ -109,6 +119,9 @@ public abstract class DocTrees extends Trees {
|
||||
* Returns {@code null} if no doc comment was found.
|
||||
* Future releases may support additional file types.
|
||||
*
|
||||
* @implNote The default implementation of this method returns a
|
||||
* new {@code DocCommentTree} instance for each invocation.
|
||||
*
|
||||
* @param fileObject the content container
|
||||
* @return the doc comment tree
|
||||
* @since 9
|
||||
@ -123,6 +136,9 @@ public abstract class DocTrees extends Trees {
|
||||
* Returns {@code null} if no doc comment was found.
|
||||
* Future releases may support additional file types.
|
||||
*
|
||||
* @implNote The default implementation of this method returns a
|
||||
* new {@code DocCommentTree} instance for each invocation.
|
||||
*
|
||||
* @param e an element whose path is used as a reference
|
||||
* @param relativePath the relative path from the Element
|
||||
* @return the doc comment tree
|
||||
|
@ -507,10 +507,16 @@ public class JavacTrees extends DocTrees {
|
||||
}
|
||||
|
||||
ClassSymbol sym = (ClassSymbol) types.skipTypeVars(tsym.type, false).tsym;
|
||||
|
||||
Symbol msym = (memberName == sym.name)
|
||||
? findConstructor(sym, paramTypes)
|
||||
: findMethod(sym, memberName, paramTypes);
|
||||
? findConstructor(sym, paramTypes, true)
|
||||
: findMethod(sym, memberName, paramTypes, true);
|
||||
|
||||
if (msym == null) {
|
||||
msym = (memberName == sym.name)
|
||||
? findConstructor(sym, paramTypes, false)
|
||||
: findMethod(sym, memberName, paramTypes, false);
|
||||
}
|
||||
|
||||
if (paramTypes != null) {
|
||||
// explicit (possibly empty) arg list given, so cannot be a field
|
||||
return msym;
|
||||
@ -608,10 +614,10 @@ public class JavacTrees extends DocTrees {
|
||||
return null;
|
||||
}
|
||||
|
||||
MethodSymbol findConstructor(ClassSymbol tsym, List<Type> paramTypes) {
|
||||
MethodSymbol findConstructor(ClassSymbol tsym, List<Type> paramTypes, boolean strict) {
|
||||
for (Symbol sym : tsym.members().getSymbolsByName(names.init)) {
|
||||
if (sym.kind == MTH) {
|
||||
if (hasParameterTypes((MethodSymbol) sym, paramTypes)) {
|
||||
if (hasParameterTypes((MethodSymbol) sym, paramTypes, strict)) {
|
||||
return (MethodSymbol) sym;
|
||||
}
|
||||
}
|
||||
@ -619,12 +625,13 @@ public class JavacTrees extends DocTrees {
|
||||
return null;
|
||||
}
|
||||
|
||||
private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes) {
|
||||
return searchMethod(tsym, methodName, paramTypes, new HashSet<>());
|
||||
private MethodSymbol findMethod(ClassSymbol tsym, Name methodName, List<Type> paramTypes, boolean strict) {
|
||||
return searchMethod(tsym, methodName, paramTypes, strict, new HashSet<>());
|
||||
}
|
||||
|
||||
private MethodSymbol searchMethod(ClassSymbol tsym, Name methodName,
|
||||
List<Type> paramTypes, Set<ClassSymbol> searched) {
|
||||
List<Type> paramTypes, boolean strict,
|
||||
Set<ClassSymbol> searched) {
|
||||
//### Note that this search is not necessarily what the compiler would do!
|
||||
|
||||
// do not match constructors
|
||||
@ -662,7 +669,7 @@ public class JavacTrees extends DocTrees {
|
||||
for (Symbol sym : tsym.members().getSymbolsByName(methodName)) {
|
||||
if (sym != null &&
|
||||
sym.kind == MTH) {
|
||||
if (hasParameterTypes((MethodSymbol) sym, paramTypes)) {
|
||||
if (hasParameterTypes((MethodSymbol) sym, paramTypes, strict)) {
|
||||
return (MethodSymbol) sym;
|
||||
}
|
||||
}
|
||||
@ -675,7 +682,7 @@ public class JavacTrees extends DocTrees {
|
||||
// search superclass
|
||||
Type superclass = tsym.getSuperclass();
|
||||
if (superclass.tsym != null) {
|
||||
MethodSymbol msym = searchMethod((ClassSymbol) superclass.tsym, methodName, paramTypes, searched);
|
||||
MethodSymbol msym = searchMethod((ClassSymbol) superclass.tsym, methodName, paramTypes, strict, searched);
|
||||
if (msym != null) {
|
||||
return msym;
|
||||
}
|
||||
@ -686,7 +693,7 @@ public class JavacTrees extends DocTrees {
|
||||
for (List<Type> l = intfs; l.nonEmpty(); l = l.tail) {
|
||||
Type intf = l.head;
|
||||
if (intf.isErroneous()) continue;
|
||||
MethodSymbol msym = searchMethod((ClassSymbol) intf.tsym, methodName, paramTypes, searched);
|
||||
MethodSymbol msym = searchMethod((ClassSymbol) intf.tsym, methodName, paramTypes, strict, searched);
|
||||
if (msym != null) {
|
||||
return msym;
|
||||
}
|
||||
@ -695,7 +702,7 @@ public class JavacTrees extends DocTrees {
|
||||
// search enclosing class
|
||||
ClassSymbol encl = tsym.owner.enclClass();
|
||||
if (encl != null) {
|
||||
MethodSymbol msym = searchMethod(encl, methodName, paramTypes, searched);
|
||||
MethodSymbol msym = searchMethod(encl, methodName, paramTypes, strict, searched);
|
||||
if (msym != null) {
|
||||
return msym;
|
||||
}
|
||||
@ -704,7 +711,7 @@ public class JavacTrees extends DocTrees {
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean hasParameterTypes(MethodSymbol method, List<Type> paramTypes) {
|
||||
private boolean hasParameterTypes(MethodSymbol method, List<Type> paramTypes, boolean strict) {
|
||||
if (paramTypes == null)
|
||||
return true;
|
||||
|
||||
@ -712,7 +719,7 @@ public class JavacTrees extends DocTrees {
|
||||
return false;
|
||||
|
||||
List<Type> methodParamTypes = method.asType().getParameterTypes();
|
||||
if (!Type.isErroneous(paramTypes) && types.isSubtypes(paramTypes, methodParamTypes)) {
|
||||
if (!strict && !Type.isErroneous(paramTypes) && types.isSubtypes(paramTypes, methodParamTypes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1999, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1999, 2022, 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
|
||||
@ -292,10 +292,16 @@ public class ClassFinder {
|
||||
ClassSymbol c = (ClassSymbol) sym;
|
||||
dependencies.push(c, CompletionCause.CLASS_READER);
|
||||
annotate.blockAnnotations();
|
||||
c.members_field = new Scope.ErrorScope(c); // make sure it's always defined
|
||||
Scope.ErrorScope members = new Scope.ErrorScope(c);
|
||||
c.members_field = members; // make sure it's always defined
|
||||
completeOwners(c.owner);
|
||||
completeEnclosing(c);
|
||||
fillIn(c);
|
||||
//if an enclosing class is completed from the source,
|
||||
//this class might have been completed already as well,
|
||||
//avoid attempts to re-complete it:
|
||||
if (c.members_field == members) {
|
||||
fillIn(c);
|
||||
}
|
||||
} finally {
|
||||
annotate.unblockAnnotationsNoFlush();
|
||||
dependencies.pop();
|
||||
|
@ -364,11 +364,7 @@ public abstract non-sealed class AbstractMemorySegmentImpl extends MemorySegment
|
||||
}
|
||||
|
||||
void checkValidState() {
|
||||
try {
|
||||
scope.checkValidState();
|
||||
} catch (ScopedMemoryAccess.Scope.ScopedAccessError ex) {
|
||||
throw new IllegalStateException("This segment is already closed");
|
||||
}
|
||||
scope.checkValidStateSlow();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -39,10 +39,7 @@ import java.lang.ref.Cleaner;
|
||||
*/
|
||||
final class ConfinedScope extends ResourceScopeImpl {
|
||||
|
||||
private boolean closed; // = false
|
||||
private int lockCount = 0;
|
||||
private int asyncReleaseCount = 0;
|
||||
private final Thread owner;
|
||||
|
||||
static final VarHandle ASYNC_RELEASE_COUNT;
|
||||
|
||||
@ -55,40 +52,29 @@ final class ConfinedScope extends ResourceScopeImpl {
|
||||
}
|
||||
|
||||
public ConfinedScope(Thread owner, Cleaner cleaner) {
|
||||
super(new ConfinedResourceList(), cleaner);
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
@ForceInline
|
||||
public final void checkValidState() {
|
||||
if (owner != Thread.currentThread()) {
|
||||
throw new IllegalStateException("Attempted access outside owning thread");
|
||||
}
|
||||
if (closed) {
|
||||
throw new IllegalStateException("Already closed");
|
||||
}
|
||||
super(owner, new ConfinedResourceList(), cleaner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAlive() {
|
||||
return !closed;
|
||||
return state != CLOSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void acquire0() {
|
||||
checkValidState();
|
||||
if (lockCount == MAX_FORKS) {
|
||||
checkValidStateSlow();
|
||||
if (state == MAX_FORKS) {
|
||||
throw new IllegalStateException("Scope keep alive limit exceeded");
|
||||
}
|
||||
lockCount++;
|
||||
state++;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ForceInline
|
||||
public void release0() {
|
||||
if (Thread.currentThread() == owner) {
|
||||
lockCount--;
|
||||
state--;
|
||||
} else {
|
||||
// It is possible to end up here in two cases: this scope was kept alive by some other confined scope
|
||||
// which is implicitly released (in which case the release call comes from the cleaner thread). Or,
|
||||
@ -99,19 +85,14 @@ final class ConfinedScope extends ResourceScopeImpl {
|
||||
}
|
||||
|
||||
void justClose() {
|
||||
this.checkValidState();
|
||||
if (lockCount == 0 || lockCount - ((int)ASYNC_RELEASE_COUNT.getVolatile(this)) == 0) {
|
||||
closed = true;
|
||||
checkValidStateSlow();
|
||||
if (state == 0 || state - ((int)ASYNC_RELEASE_COUNT.getVolatile(this)) == 0) {
|
||||
state = CLOSED;
|
||||
} else {
|
||||
throw new IllegalStateException("Scope is kept alive by " + lockCount + " scopes");
|
||||
throw new IllegalStateException("Scope is kept alive by " + state + " scopes");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread ownerThread() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* A confined resource list; no races are possible here.
|
||||
*/
|
||||
|
@ -28,11 +28,12 @@ package jdk.internal.foreign;
|
||||
import jdk.incubator.foreign.MemoryAddress;
|
||||
import jdk.incubator.foreign.NativeSymbol;
|
||||
import jdk.incubator.foreign.ResourceScope;
|
||||
import jdk.internal.misc.ScopedMemoryAccess;
|
||||
|
||||
public record NativeSymbolImpl(String name, MemoryAddress address, ResourceScope scope) implements NativeSymbol, Scoped {
|
||||
@Override
|
||||
public MemoryAddress address() {
|
||||
((ResourceScopeImpl)scope).checkValidState();
|
||||
((ResourceScopeImpl)scope).checkValidStateSlow();
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,8 @@ import jdk.incubator.foreign.SegmentAllocator;
|
||||
import jdk.internal.misc.ScopedMemoryAccess;
|
||||
import jdk.internal.vm.annotation.ForceInline;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.VarHandle;
|
||||
import java.lang.ref.Cleaner;
|
||||
import java.lang.ref.Reference;
|
||||
import java.util.Objects;
|
||||
@ -53,6 +55,23 @@ public abstract non-sealed class ResourceScopeImpl implements ResourceScope, Seg
|
||||
|
||||
final ResourceList resourceList;
|
||||
final Cleaner.Cleanable cleanable;
|
||||
final Thread owner;
|
||||
|
||||
static final int ALIVE = 0;
|
||||
static final int CLOSING = -1;
|
||||
static final int CLOSED = -2;
|
||||
|
||||
int state = ALIVE;
|
||||
|
||||
static final VarHandle STATE;
|
||||
|
||||
static {
|
||||
try {
|
||||
STATE = MethodHandles.lookup().findVarHandle(ResourceScopeImpl.class, "state", int.class);
|
||||
} catch (Throwable ex) {
|
||||
throw new ExceptionInInitializerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
static final int MAX_FORKS = Integer.MAX_VALUE;
|
||||
|
||||
@ -89,7 +108,8 @@ public abstract non-sealed class ResourceScopeImpl implements ResourceScope, Seg
|
||||
}
|
||||
}
|
||||
|
||||
protected ResourceScopeImpl(ResourceList resourceList, Cleaner cleaner) {
|
||||
protected ResourceScopeImpl(Thread owner, ResourceList resourceList, Cleaner cleaner) {
|
||||
this.owner = owner;
|
||||
this.resourceList = resourceList;
|
||||
cleanable = (cleaner != null) ?
|
||||
cleaner.register(this, resourceList) : null;
|
||||
@ -147,7 +167,9 @@ public abstract non-sealed class ResourceScopeImpl implements ResourceScope, Seg
|
||||
* Returns "owner" thread of this scope.
|
||||
* @return owner thread (or null for a shared scope)
|
||||
*/
|
||||
public abstract Thread ownerThread();
|
||||
public final Thread ownerThread() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true, if this scope is still alive. This method may be called in any thread.
|
||||
@ -155,14 +177,23 @@ public abstract non-sealed class ResourceScopeImpl implements ResourceScope, Seg
|
||||
*/
|
||||
public abstract boolean isAlive();
|
||||
|
||||
|
||||
/**
|
||||
* This is a faster version of {@link #checkValidStateSlow()}, which is called upon memory access, and which
|
||||
* relies on invariants associated with the memory scope implementations (typically, volatile access
|
||||
* to the closed state bit is replaced with plain access, and ownership check is removed where not needed.
|
||||
* Should be used with care.
|
||||
* relies on invariants associated with the memory scope implementations (volatile access
|
||||
* to the closed state bit is replaced with plain access). This method should be monomorphic,
|
||||
* to avoid virtual calls in the memory access hot path. This method is not intended as general purpose method
|
||||
* and should only be used in the memory access handle hot path; for liveness checks triggered by other API methods,
|
||||
* please use {@link #checkValidStateSlow()}.
|
||||
*/
|
||||
public abstract void checkValidState();
|
||||
@ForceInline
|
||||
public final void checkValidState() {
|
||||
if (owner != null && owner != Thread.currentThread()) {
|
||||
throw new IllegalStateException("Attempted access outside owning thread");
|
||||
}
|
||||
if (state < ALIVE) {
|
||||
throw ScopedAccessError.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that this scope is still alive (see {@link #isAlive()}).
|
||||
@ -170,7 +201,7 @@ public abstract non-sealed class ResourceScopeImpl implements ResourceScope, Seg
|
||||
* a confined scope and this method is called outside of the owner thread.
|
||||
*/
|
||||
public final void checkValidStateSlow() {
|
||||
if (ownerThread() != null && Thread.currentThread() != ownerThread()) {
|
||||
if (owner != null && Thread.currentThread() != owner) {
|
||||
throw new IllegalStateException("Attempted access outside owning thread");
|
||||
} else if (!isAlive()) {
|
||||
throw new IllegalStateException("Already closed");
|
||||
|
@ -45,36 +45,8 @@ class SharedScope extends ResourceScopeImpl {
|
||||
|
||||
private static final ScopedMemoryAccess SCOPED_MEMORY_ACCESS = ScopedMemoryAccess.getScopedMemoryAccess();
|
||||
|
||||
private static final int ALIVE = 0;
|
||||
private static final int CLOSING = -1;
|
||||
private static final int CLOSED = -2;
|
||||
|
||||
private int state = ALIVE;
|
||||
|
||||
private static final VarHandle STATE;
|
||||
|
||||
static {
|
||||
try {
|
||||
STATE = MethodHandles.lookup().findVarHandle(jdk.internal.foreign.SharedScope.class, "state", int.class);
|
||||
} catch (Throwable ex) {
|
||||
throw new ExceptionInInitializerError(ex);
|
||||
}
|
||||
}
|
||||
|
||||
SharedScope(Cleaner cleaner) {
|
||||
super(new SharedResourceList(), cleaner);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Thread ownerThread() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkValidState() {
|
||||
if (state < ALIVE) {
|
||||
throw ScopedAccessError.INSTANCE;
|
||||
}
|
||||
super(null, new SharedResourceList(), cleaner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, 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
|
||||
@ -280,9 +280,12 @@ public final class MetadataRepository {
|
||||
if (staleMetadata) {
|
||||
storeDescriptorInJVM();
|
||||
}
|
||||
awaitUniqueTimestamp();
|
||||
jvm.setOutput(filename);
|
||||
long nanos = jvm.getChunkStartNanos();
|
||||
// Each chunk needs a unique start timestamp and
|
||||
// if the clock resolution is low, two chunks may
|
||||
// get the same timestamp. Utils.getChunkStartNanos()
|
||||
// ensures the timestamp is unique for the next chunk
|
||||
long chunkStart = Utils.getChunkStartNanos();
|
||||
if (filename != null) {
|
||||
RepositoryFiles.notifyNewFile();
|
||||
}
|
||||
@ -293,29 +296,7 @@ public final class MetadataRepository {
|
||||
}
|
||||
unregistered = false;
|
||||
}
|
||||
return Utils.epochNanosToInstant(nanos);
|
||||
}
|
||||
|
||||
// Each chunk needs a unique start timestamp and
|
||||
// if the clock resolution is low, two chunks may
|
||||
// get the same timestamp.
|
||||
private void awaitUniqueTimestamp() {
|
||||
if (outputChange == null) {
|
||||
outputChange = Instant.now();
|
||||
return;
|
||||
}
|
||||
while (true) {
|
||||
Instant time = Instant.now();
|
||||
if (!time.equals(outputChange)) {
|
||||
outputChange = time;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(0, 100);
|
||||
} catch (InterruptedException iex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
return Utils.epochNanosToInstant(chunkStart);
|
||||
}
|
||||
|
||||
private void unregisterUnloaded() {
|
||||
|
@ -248,7 +248,7 @@ public final class PlatformRecorder {
|
||||
}
|
||||
currentChunk = newChunk;
|
||||
jvm.beginRecording();
|
||||
startNanos = jvm.getChunkStartNanos();
|
||||
startNanos = Utils.getChunkStartNanos();
|
||||
startTime = Utils.epochNanosToInstant(startNanos);
|
||||
if (currentChunk != null) {
|
||||
currentChunk.setStartTime(startTime);
|
||||
@ -269,7 +269,7 @@ public final class PlatformRecorder {
|
||||
startTime = MetadataRepository.getInstance().setOutput(p);
|
||||
newChunk.setStartTime(startTime);
|
||||
}
|
||||
startNanos = jvm.getChunkStartNanos();
|
||||
startNanos = Utils.getChunkStartNanos();
|
||||
startTime = Utils.epochNanosToInstant(startNanos);
|
||||
recording.setStartTime(startTime);
|
||||
recording.setState(RecordingState.RUNNING);
|
||||
@ -316,7 +316,7 @@ public final class PlatformRecorder {
|
||||
}
|
||||
}
|
||||
OldObjectSample.emit(recording);
|
||||
recording.setFinalStartnanos(jvm.getChunkStartNanos());
|
||||
recording.setFinalStartnanos(Utils.getChunkStartNanos());
|
||||
|
||||
if (endPhysical) {
|
||||
RequestEngine.doChunkEnd();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2022, 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
|
||||
@ -97,6 +97,7 @@ public final class Utils {
|
||||
* The possible data race is benign and is worth of not introducing any contention here.
|
||||
*/
|
||||
private static Metrics[] metrics;
|
||||
private static Instant lastTimestamp;
|
||||
|
||||
public static void checkAccessFlightRecorder() throws SecurityException {
|
||||
@SuppressWarnings("removal")
|
||||
@ -866,4 +867,30 @@ public final class Utils {
|
||||
throw new IllegalArgumentException("'" + name + "' is not a valid Java identifier");
|
||||
}
|
||||
}
|
||||
|
||||
public static long getChunkStartNanos() {
|
||||
long nanos = JVM.getJVM().getChunkStartNanos();
|
||||
// JVM::getChunkStartNanos() may return a bumped timestamp, +1 ns or +2 ns.
|
||||
// Spin here to give Instant.now() a chance to catch up.
|
||||
awaitUniqueTimestamp();
|
||||
return nanos;
|
||||
}
|
||||
|
||||
private static void awaitUniqueTimestamp() {
|
||||
if (lastTimestamp == null) {
|
||||
lastTimestamp = Instant.now(); // lazy initialization
|
||||
}
|
||||
while (true) {
|
||||
Instant time = Instant.now();
|
||||
if (!time.equals(lastTimestamp)) {
|
||||
lastTimestamp = time;
|
||||
return;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(0, 100);
|
||||
} catch (InterruptedException iex) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
158
test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java
Normal file
158
test/hotspot/jtreg/compiler/inlining/ResolvedClassTest.java
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8279515
|
||||
*
|
||||
* @requires vm.flagless
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* @library /test/lib /
|
||||
*
|
||||
* @run driver compiler.jsr292.ResolvedClassTest
|
||||
*/
|
||||
|
||||
package compiler.jsr292;
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class ResolvedClassTest {
|
||||
/* ======================================================================== */
|
||||
static void testStatic() throws IOException {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
|
||||
"-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining",
|
||||
"-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestStatic.class.getName() + "::test",
|
||||
TestStatic.class.getName());
|
||||
|
||||
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
|
||||
|
||||
analyzer.shouldHaveExitValue(0);
|
||||
|
||||
analyzer.shouldNotContain("TestStatic$A::m (1 bytes) not inlineable");
|
||||
analyzer.shouldNotContain("TestStatic$A::m (1 bytes) no static binding");
|
||||
|
||||
analyzer.shouldContain("TestStatic$A::m (1 bytes) inline");
|
||||
}
|
||||
|
||||
static class TestStatic {
|
||||
static class A {
|
||||
static void m() {}
|
||||
}
|
||||
static class B extends A {}
|
||||
|
||||
// @DontInline
|
||||
static void test() {
|
||||
B.m(); // invokestatic B "m" => A::m
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 20_000; i++) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
static void testStaticInit() throws IOException {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
|
||||
"-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining",
|
||||
"-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestStaticInit.class.getName() + "::test",
|
||||
TestStaticInit.class.getName());
|
||||
|
||||
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
|
||||
|
||||
analyzer.shouldHaveExitValue(0);
|
||||
|
||||
analyzer.shouldContain("TestStaticInit$A::m (1 bytes) no static binding");
|
||||
}
|
||||
|
||||
static class TestStaticInit {
|
||||
static class A {
|
||||
static {
|
||||
for (int i = 0; i < 20_000; i++) {
|
||||
TestStaticInit.test();
|
||||
}
|
||||
}
|
||||
|
||||
static void m() {}
|
||||
}
|
||||
static class B extends A {}
|
||||
|
||||
// @DontInline
|
||||
static void test() {
|
||||
B.m(); // A::<clinit> => test() => A::m()
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
A.m(); // trigger initialization of A
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
static void testIndy() throws IOException {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
|
||||
"-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining",
|
||||
"-Xbatch", "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly," + TestIndy.class.getName() + "::test",
|
||||
TestIndy.class.getName());
|
||||
|
||||
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
|
||||
|
||||
analyzer.shouldHaveExitValue(0);
|
||||
|
||||
analyzer.shouldNotContain("java.lang.invoke.Invokers$Holder::linkToTargetMethod (9 bytes) not inlineable");
|
||||
|
||||
analyzer.shouldContain("java.lang.invoke.Invokers$Holder::linkToTargetMethod (9 bytes) force inline by annotation");
|
||||
analyzer.shouldContain("java/lang/invoke/MethodHandle::invokeBasic (not loaded) not inlineable");
|
||||
}
|
||||
|
||||
static class TestIndy {
|
||||
static String str = "";
|
||||
|
||||
// @DontInline
|
||||
static void test() {
|
||||
String s1 = "" + str; // indy (linked)
|
||||
|
||||
for (int i = 0; i < 200_000; i++) {} // trigger OSR compilation
|
||||
|
||||
String s2 = "" + str; // indy (not linked)
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
test();
|
||||
}
|
||||
}
|
||||
|
||||
/* ======================================================================== */
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
testStatic();
|
||||
testStaticInit();
|
||||
testIndy();
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @requires vm.compiler2.enabled
|
||||
* @bug 8273277
|
||||
* @summary Skeleton predicates sometimes need to be negated
|
||||
* @run main compiler.loopopts.TestSkeletonPredicateNegation
|
||||
|
@ -369,7 +369,7 @@ public class TestByteBuffer {
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause instanceof IllegalStateException) {
|
||||
//all get/set buffer operation should fail because of the scope check
|
||||
assertTrue(ex.getCause().getMessage().contains("Already closed"));
|
||||
assertTrue(ex.getCause().getMessage().contains("already closed"));
|
||||
} else {
|
||||
//all other exceptions were unexpected - fail
|
||||
fail("Unexpected exception", cause);
|
||||
@ -406,7 +406,7 @@ public class TestByteBuffer {
|
||||
handle.invoke(e.getValue());
|
||||
fail();
|
||||
} catch (IllegalStateException ex) {
|
||||
assertTrue(ex.getMessage().contains("Already closed"));
|
||||
assertTrue(ex.getMessage().contains("already closed"));
|
||||
} catch (UnsupportedOperationException ex) {
|
||||
//skip
|
||||
} catch (Throwable ex) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2022, 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
|
||||
@ -40,7 +40,8 @@ public class TestGCCauseWithG1ConcurrentMark {
|
||||
String testID = "G1ConcurrentMark";
|
||||
String[] vmFlags = {"-XX:+UseG1GC", "-XX:+ExplicitGCInvokesConcurrent"};
|
||||
String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full};
|
||||
String[] gcCauses = {"G1 Evacuation Pause", "G1 Preventive Collection", "G1 Compaction Pause", "System.gc()"};
|
||||
String[] gcCauses = {"GCLocker Initiated GC", "G1 Evacuation Pause", "G1 Preventive Collection",
|
||||
"G1 Compaction Pause", "System.gc()"};
|
||||
GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2022, 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
|
||||
@ -40,7 +40,8 @@ public class TestGCCauseWithG1FullCollection {
|
||||
String testID = "G1FullCollection";
|
||||
String[] vmFlags = {"-XX:+UseG1GC"};
|
||||
String[] gcNames = {GCHelper.gcG1New, GCHelper.gcG1Old, GCHelper.gcG1Full};
|
||||
String[] gcCauses = {"G1 Evacuation Pause", "G1 Preventive Collection", "G1 Compaction Pause", "System.gc()"};
|
||||
String[] gcCauses = {"GCLocker Initiated GC", "G1 Evacuation Pause", "G1 Preventive Collection",
|
||||
"G1 Compaction Pause", "System.gc()"};
|
||||
GCGarbageCollectionUtil.test(testID, vmFlags, gcNames, gcCauses);
|
||||
}
|
||||
}
|
||||
|
@ -462,7 +462,7 @@ public class KeytoolOpensslInteropTest {
|
||||
"pkcs12", "-in", "ksnormal", "-passin", "pass:changeit",
|
||||
"-info", "-nokeys", "-nocerts");
|
||||
output1.shouldHaveExitValue(0)
|
||||
.shouldMatch("MAC:.*sha256.*Iteration 10000")
|
||||
.shouldContain("MAC:").shouldContain("sha256").shouldContain("Iteration 10000")
|
||||
.shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC,"
|
||||
+ " Iteration 10000, PRF hmacWithSHA256")
|
||||
.shouldContain("PKCS7 Encrypted data: PBES2, PBKDF2, AES-256-CBC,"
|
||||
@ -505,7 +505,7 @@ public class KeytoolOpensslInteropTest {
|
||||
"ksnewic", "-passin", "pass:changeit", "-info", "-nokeys",
|
||||
"-nocerts");
|
||||
output1.shouldHaveExitValue(0)
|
||||
.shouldMatch("MAC:.*sha256.*Iteration 5555")
|
||||
.shouldContain("MAC:").shouldContain("sha256").shouldContain("Iteration 5555")
|
||||
.shouldContain("Shrouded Keybag: PBES2, PBKDF2, AES-256-CBC,"
|
||||
+ " Iteration 7777, PRF hmacWithSHA256")
|
||||
.shouldContain("Shrouded Keybag: pbeWithSHA1And128BitRC4,"
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 7021614
|
||||
* @bug 7021614 8278373
|
||||
* @summary extend com.sun.source API to support parsing javadoc comments
|
||||
* @summary check references in at-see and {at-link} tags
|
||||
* @modules jdk.compiler
|
||||
@ -39,19 +39,23 @@ import com.sun.source.doctree.SeeTree;
|
||||
import com.sun.source.doctree.TextTree;
|
||||
import com.sun.source.util.DocTreePath;
|
||||
import com.sun.source.util.DocTreePathScanner;
|
||||
import com.sun.source.util.DocTreeScanner;
|
||||
import com.sun.source.util.DocTrees;
|
||||
import com.sun.source.util.TreePath;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.annotation.processing.AbstractProcessor;
|
||||
import javax.annotation.processing.ProcessingEnvironment;
|
||||
import javax.annotation.processing.RoundEnvironment;
|
||||
import javax.annotation.processing.SupportedAnnotationTypes;
|
||||
import javax.lang.model.SourceVersion;
|
||||
import javax.lang.model.element.Element;
|
||||
import javax.lang.model.element.ExecutableElement;
|
||||
import javax.lang.model.element.QualifiedNameable;
|
||||
import javax.lang.model.element.TypeElement;
|
||||
import javax.lang.model.type.DeclaredType;
|
||||
import javax.lang.model.type.TypeMirror;
|
||||
import javax.tools.Diagnostic.Kind;
|
||||
|
||||
/**
|
||||
@ -174,8 +178,18 @@ public class ReferenceTest extends AbstractProcessor {
|
||||
if (label.size() > 0 && label.get(0) instanceof TextTree)
|
||||
expect = ((TextTree) label.get(0)).getBody();
|
||||
|
||||
if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) {
|
||||
error(tree, "Unexpected value found: " + found +", expected: " + expect);
|
||||
if (expect.startsWith("signature:")) {
|
||||
expect = expect.substring("signature:".length());
|
||||
|
||||
String signature = found.getKind().name() + ":" + elementSignature(found);
|
||||
|
||||
if (!expect.equalsIgnoreCase(signature)) {
|
||||
error(tree, "Unexpected value found: " + signature +", expected: " + expect);
|
||||
}
|
||||
} else {
|
||||
if (!expect.equalsIgnoreCase(found == null ? "bad" : found.getKind().name())) {
|
||||
error(tree, "Unexpected value found: " + found +", expected: " + expect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,6 +197,29 @@ public class ReferenceTest extends AbstractProcessor {
|
||||
trees.printMessage(Kind.ERROR, msg, tree, dc, path.getCompilationUnit());
|
||||
}
|
||||
}
|
||||
|
||||
String elementSignature(Element el) {
|
||||
return switch (el.getKind()) {
|
||||
case METHOD -> elementSignature(el.getEnclosingElement()) + "." + el.getSimpleName() + "(" + executableParamNames((ExecutableElement) el) + ")";
|
||||
case CLASS, INTERFACE -> ((QualifiedNameable) el).getQualifiedName().toString();
|
||||
default -> throw new AssertionError("Unhandled Element kind: " + el.getKind());
|
||||
};
|
||||
}
|
||||
|
||||
String executableParamNames(ExecutableElement ee) {
|
||||
return ee.getParameters()
|
||||
.stream()
|
||||
.map(p -> type2Name(p.asType()))
|
||||
.collect(Collectors.joining(", "));
|
||||
}
|
||||
|
||||
String type2Name(TypeMirror type) {
|
||||
return switch (type.getKind()) {
|
||||
case DECLARED -> elementSignature(((DeclaredType) type).asElement());
|
||||
case INT, LONG -> type.toString();
|
||||
default -> throw new AssertionError("Unhandled type kind: " + type.getKind());
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,6 +236,17 @@ public class ReferenceTest extends AbstractProcessor {
|
||||
* @see #varargs(int... args) Method
|
||||
* @see #varargs(int[]) Method
|
||||
* @see #varargs(int[] args) Method
|
||||
*
|
||||
* @see #methodSearch(String) signature:METHOD:ReferenceTestExtras.methodSearch(java.lang.String)
|
||||
* @see #methodSearch(StringBuilder) signature:METHOD:ReferenceTestExtras.methodSearch(java.lang.CharSequence)
|
||||
* @see #methodSearchPrimitive1(int, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(int, int)
|
||||
* @see #methodSearchPrimitive1(long, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(long, int)
|
||||
* @see #methodSearchPrimitive1(int, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(int, long)
|
||||
* @see #methodSearchPrimitive1(long, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive1(long, long)
|
||||
* @see #methodSearchPrimitive2(int, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(int, int)
|
||||
* @see #methodSearchPrimitive2(long, int) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(long, int)
|
||||
* @see #methodSearchPrimitive2(int, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(int, long)
|
||||
* @see #methodSearchPrimitive2(long, long) signature:METHOD:ReferenceTestExtras.methodSearchPrimitive2(long, long)
|
||||
*/
|
||||
class ReferenceTestExtras {
|
||||
int ReferenceTestExtras; // field
|
||||
@ -214,6 +262,20 @@ class ReferenceTestExtras {
|
||||
void m(int i, int j) { }
|
||||
|
||||
void varargs(int... args) { }
|
||||
|
||||
void methodSearch(Object o) {}
|
||||
void methodSearch(String s) {}
|
||||
void methodSearch(CharSequence cs) {}
|
||||
|
||||
void methodSearchPrimitive1(int i, int j) {}
|
||||
void methodSearchPrimitive1(long i, int j) {}
|
||||
void methodSearchPrimitive1(int i, long j) {}
|
||||
void methodSearchPrimitive1(long i, long j) {}
|
||||
|
||||
void methodSearchPrimitive2(long i, long j) {}
|
||||
void methodSearchPrimitive2(int i, long j) {}
|
||||
void methodSearchPrimitive2(long i, int j) {}
|
||||
void methodSearchPrimitive2(int i, int j) {}
|
||||
}
|
||||
|
||||
|
||||
|
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2022, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8278930
|
||||
* @summary Check that when a package has Elements listed from both from classes and sources,
|
||||
* and then a nested class is completed, it is not first completed from source via
|
||||
* its enclosing class, and then again for itself.
|
||||
* @library /tools/javac/lib
|
||||
* @modules java.compiler
|
||||
* jdk.compiler
|
||||
* @run main TestListPackageFromAPI
|
||||
*/
|
||||
|
||||
import com.sun.source.util.JavacTask;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.lang.model.element.PackageElement;
|
||||
import javax.tools.DiagnosticListener;
|
||||
import javax.tools.ForwardingJavaFileManager;
|
||||
import javax.tools.JavaFileManager;
|
||||
import javax.tools.JavaFileObject;
|
||||
import javax.tools.JavaFileObject.Kind;
|
||||
import javax.tools.SimpleJavaFileObject;
|
||||
import javax.tools.StandardLocation;
|
||||
import javax.tools.ToolProvider;
|
||||
|
||||
public class TestListPackageFromAPI {
|
||||
|
||||
public static void main(String... args) throws IOException, URISyntaxException, InterruptedException {
|
||||
try (JavaFileManager fm = ToolProvider.getSystemJavaCompiler().getStandardFileManager(null, null, null)) {
|
||||
List<JavaFileObject> testClasses = List.of(
|
||||
new TestFileObject("Test"),
|
||||
new TestFileObject("Test$Nested")
|
||||
);
|
||||
List<JavaFileObject> testSources = List.of(
|
||||
new TestFileObject("Test",
|
||||
"""
|
||||
class Test {
|
||||
public static class Nested {}
|
||||
}
|
||||
""")
|
||||
);
|
||||
JavaFileManager testFM = new ForwardingJavaFileManagerImpl(fm, testClasses, testSources);
|
||||
DiagnosticListener<JavaFileObject> noErrors = d -> { throw new AssertionError("Should not happen: " + d); };
|
||||
JavacTask task = (JavacTask) ToolProvider.getSystemJavaCompiler().getTask(null, testFM, noErrors, null, null, List.of(new TestFileObject("Input", "")));
|
||||
PackageElement pack = task.getElements().getPackageElement("");
|
||||
pack.getEnclosedElements().forEach(e -> System.err.println(e));
|
||||
}
|
||||
}
|
||||
|
||||
private static class TestFileObject extends SimpleJavaFileObject {
|
||||
|
||||
private final String className;
|
||||
private final String code;
|
||||
|
||||
public TestFileObject(String className) throws URISyntaxException {
|
||||
super(new URI("mem://" + className + ".class"), Kind.CLASS);
|
||||
this.className = className;
|
||||
this.code = null;
|
||||
}
|
||||
|
||||
public TestFileObject(String className, String code) throws URISyntaxException {
|
||||
super(new URI("mem://" + className + ".java"), Kind.SOURCE);
|
||||
this.className = className;
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
|
||||
if (code == null) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModified() {
|
||||
return getKind() == Kind.CLASS ? 0 : 1000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class ForwardingJavaFileManagerImpl extends ForwardingJavaFileManager<JavaFileManager> {
|
||||
|
||||
private final List<JavaFileObject> testClasses;
|
||||
private final List<JavaFileObject> testSources;
|
||||
|
||||
public ForwardingJavaFileManagerImpl(JavaFileManager fileManager, List<JavaFileObject> testClasses, List<JavaFileObject> testSources) {
|
||||
super(fileManager);
|
||||
this.testClasses = testClasses;
|
||||
this.testSources = testSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<JavaFileObject> list(JavaFileManager.Location location, String packageName, Set<JavaFileObject.Kind> kinds, boolean recurse) throws IOException {
|
||||
if (packageName.isEmpty()) {
|
||||
List<JavaFileObject> result = new ArrayList<>();
|
||||
if (location == StandardLocation.CLASS_PATH && kinds.contains(Kind.CLASS)) {
|
||||
result.addAll(testClasses);
|
||||
} else if (location == StandardLocation.SOURCE_PATH && kinds.contains(Kind.SOURCE)) {
|
||||
result.addAll(testSources);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return super.list(location, packageName, kinds, recurse);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasLocation(Location location) {
|
||||
return location == StandardLocation.CLASS_PATH ||
|
||||
location == StandardLocation.SOURCE_PATH ||
|
||||
super.hasLocation(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inferBinaryName(JavaFileManager.Location location, JavaFileObject file) {
|
||||
if (file instanceof TestFileObject testFO) {
|
||||
return testFO.className;
|
||||
}
|
||||
return super.inferBinaryName(location, file);
|
||||
}
|
||||
}
|
||||
}
|
@ -58,7 +58,7 @@ public class LoopOverPollutedSegments {
|
||||
|
||||
static final Unsafe unsafe = Utils.unsafe;
|
||||
|
||||
MemorySegment nativeSegment, heapSegmentBytes, heapSegmentFloats;
|
||||
MemorySegment nativeSegment, nativeSharedSegment, heapSegmentBytes, heapSegmentFloats;
|
||||
byte[] arr;
|
||||
long addr;
|
||||
|
||||
@ -73,6 +73,7 @@ public class LoopOverPollutedSegments {
|
||||
}
|
||||
arr = new byte[ALLOC_SIZE];
|
||||
nativeSegment = MemorySegment.allocateNative(ALLOC_SIZE, 4, ResourceScope.newConfinedScope());
|
||||
nativeSharedSegment = MemorySegment.allocateNative(ALLOC_SIZE, 4, ResourceScope.newSharedScope());
|
||||
heapSegmentBytes = MemorySegment.ofArray(new byte[ALLOC_SIZE]);
|
||||
heapSegmentFloats = MemorySegment.ofArray(new float[ELEM_SIZE]);
|
||||
|
||||
@ -81,6 +82,8 @@ public class LoopOverPollutedSegments {
|
||||
unsafe.putInt(arr, Unsafe.ARRAY_BYTE_BASE_OFFSET + (i * 4), i);
|
||||
nativeSegment.setAtIndex(JAVA_INT, i, i);
|
||||
nativeSegment.setAtIndex(JAVA_FLOAT, i, i);
|
||||
nativeSharedSegment.setAtIndex(JAVA_INT, i, i);
|
||||
nativeSharedSegment.setAtIndex(JAVA_FLOAT, i, i);
|
||||
intHandle.set(nativeSegment, (long)i, i);
|
||||
heapSegmentBytes.setAtIndex(JAVA_INT, i, i);
|
||||
heapSegmentBytes.setAtIndex(JAVA_FLOAT, i, i);
|
||||
|
Loading…
x
Reference in New Issue
Block a user