Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,11 @@ public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaT
throw new UnsupportedOperationException();
}

@Override
public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
throw new UnsupportedOperationException();
}

@Override
public Assumptions.AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) {
throw new UnsupportedOperationException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ public void cleanupAfterAnalysis() {
typeFlow = null;
invokedBy = null;
implementationInvokedBy = null;
contextInsensitiveInvoke.set(null);
if (parsedGraphCacheState.get() instanceof AnalysisParsedGraph) {
parsedGraphCacheState.set(GRAPH_CACHE_CLEARED);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,16 @@ public boolean hasSubTypes() {

@Override
public AnalysisMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
/*
* Not needed on Substrate VM for now. We also do not have the necessary information
* available to implement it for JIT compilation at image run time. So we want to make sure
* that Graal is not using this method, and only resolveConcreteMethod instead.
*/
throw GraalError.unimplemented();
}

@Override
public AnalysisMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
Object resolvedMethod = resolvedMethods.get(method);
if (resolvedMethod == null) {
ResolvedJavaMethod substMethod = universe.substitutions.resolve(((AnalysisMethod) method).wrapped);
Expand All @@ -934,7 +944,7 @@ public AnalysisMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType
*/
ResolvedJavaType substCallerType = substMethod.getDeclaringClass();

Object newResolvedMethod = universe.lookup(wrapped.resolveMethod(substMethod, substCallerType));
Object newResolvedMethod = universe.lookup(wrapped.resolveConcreteMethod(substMethod, substCallerType));
if (newResolvedMethod == null) {
newResolvedMethod = NULL_METHOD;
}
Expand All @@ -945,18 +955,12 @@ public AnalysisMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType
}

/**
* Wrapper for resolveConcreteMethod() that ignores the callerType parameter. The method that
* does the resolution, resolveMethod() above, ignores the callerType parameter and uses
* substMethod.getDeclaringClass() instead since we don't want any access checks in the
* analysis.
* Wrapper for resolveConcreteMethod() without the callerType parameter. We ignore the
* callerType parameter and use substMethod.getDeclaringClass() instead since we don't want any
* access checks in the analysis.
*/
public AnalysisMethod resolveConcreteMethod(ResolvedJavaMethod method) {
return (AnalysisMethod) WrappedJavaType.super.resolveConcreteMethod(method, null);
}

@Override
public AnalysisMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
return (AnalysisMethod) WrappedJavaType.super.resolveConcreteMethod(method, callerType);
return resolveConcreteMethod(method, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ final class HostedImageHeapChunkWriter implements ImageHeapChunkWriter {
private final int spaceOffsetAt;
private final int offsetToPreviousChunkAt;
private final int offsetToNextChunkAt;
private final RememberedSet rememberedSet = RememberedSet.get();

HostedImageHeapChunkWriter(ByteBuffer heapBuffer, long layoutToBufferOffsetAddend) {
buffer = heapBuffer;
Expand Down Expand Up @@ -94,13 +95,13 @@ private void writeHeader(int chunkOffset, long topOffset, long endOffset, long o
@Override
public void enableRememberedSetForAlignedChunk(int chunkPosition, List<ImageHeapObject> objects) {
int chunkOffset = getChunkOffsetInBuffer(chunkPosition);
RememberedSet.get().enableRememberedSetForAlignedChunk(new HostedByteBufferPointer(buffer, chunkOffset), chunkPosition, objects);
rememberedSet.enableRememberedSetForAlignedChunk(new HostedByteBufferPointer(buffer, chunkOffset), chunkPosition, objects);
}

@Override
public void enableRememberedSetForUnalignedChunk(int chunkPosition) {
int chunkOffset = getChunkOffsetInBuffer(chunkPosition);
RememberedSet.get().enableRememberedSetForUnalignedChunk(new HostedByteBufferPointer(buffer, chunkOffset));
rememberedSet.enableRememberedSetForUnalignedChunk(new HostedByteBufferPointer(buffer, chunkOffset));
}

static void putObjectReference(ByteBuffer buffer, int offset, long value) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,12 @@ public static void enableRememberedSet(HostedByteBufferPointer chunk, int chunkP
FirstObjectTable.initializeTable(getFirstObjectTableStart(chunk), getFirstObjectTableSize());

Pointer fotStart = getFirstObjectTableStart(chunk);
UnsignedWord objectsStartOffset = AlignedHeapChunk.getObjectsStartOffset();
for (ImageHeapObject obj : objects) {
long offsetWithinChunk = obj.getOffset() - chunkPosition;
assert offsetWithinChunk > 0 && WordFactory.unsigned(offsetWithinChunk).aboveOrEqual(AlignedHeapChunk.getObjectsStartOffset());
assert offsetWithinChunk > 0 && WordFactory.unsigned(offsetWithinChunk).aboveOrEqual(objectsStartOffset);

UnsignedWord startOffset = WordFactory.unsigned(offsetWithinChunk).subtract(AlignedHeapChunk.getObjectsStartOffset());
UnsignedWord startOffset = WordFactory.unsigned(offsetWithinChunk).subtract(objectsStartOffset);
UnsignedWord endOffset = startOffset.add(WordFactory.unsigned(obj.getSize()));
FirstObjectTable.setTableForObject(fotStart, startOffset, endOffset);
// The remembered set bit in the header will be set by the code that writes the objects.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,9 @@ public void encodeSnippets() {
snippetNodeClasses = encoder.getNodeClasses();

snippetInvocationPlugins = makeInvocationPlugins(getGraphBuilderPlugins(), builder, Function.identity());

/* Original graphs are no longer necessary, release memory. */
builder.graphs.clear();
}

@Platforms(Platform.HOSTED_ONLY.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public JavaConstant readValue(MetaAccessProvider suppliedMetaAccess, AnalysisFie
private static JavaConstant readUninitializedStaticValue(AnalysisField field) {
JavaKind kind = field.getJavaKind();

boolean canHaveConstantValueAttribute = kind.isPrimitive() || field.getType().toJavaName(true).equals("java.lang.String");
boolean canHaveConstantValueAttribute = kind.isPrimitive() || field.getType().getName().equals("Ljava/lang/String;");
if (!canHaveConstantValueAttribute || !field.isFinal()) {
return JavaConstant.defaultForKind(kind);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaT
return original.resolveMethod(method, callerType);
}

@Override
public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) {
return original.resolveConcreteMethod(method, callerType);
}

@Override
public Assumptions.AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) {
return original.findUniqueConcreteMethod(method);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
package com.oracle.svm.hosted.code;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

import org.graalvm.compiler.nodes.ConstantNode;
import org.graalvm.compiler.nodes.StructuredGraph;
Expand All @@ -40,6 +41,11 @@ public class CompilationInfo {
protected final HostedMethod method;

protected final AtomicBoolean inParseQueue = new AtomicBoolean(false);
/**
* No need for this flag to be atomic, because {@link CompileQueue#compilations} is used to
* ensure each method is compiled only once.
*/
protected boolean inCompileQueue;

protected volatile StructuredGraph graph;

Expand Down Expand Up @@ -72,6 +78,11 @@ public class CompilationInfo {
protected long numDeoptEntryPoints;
protected long numDuringCallEntryPoints;

/* Statistics collected when method is put into compile queue. */
protected final AtomicLong numDirectCalls = new AtomicLong();
protected final AtomicLong numVirtualCalls = new AtomicLong();
protected final AtomicLong numEntryPointCalls = new AtomicLong();

public CompilationInfo(HostedMethod method) {
this.method = method;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.IdentityHashMap;
Expand Down Expand Up @@ -199,6 +198,8 @@ public interface CompileFunction {

private volatile boolean inliningProgress;

private final boolean printMethodHistogram = NativeImageOptions.PrintMethodHistogram.getValue();

public abstract static class CompileReason {
/**
* For debugging only: chaining of the compile reason, so that you can track the compilation
Expand Down Expand Up @@ -259,19 +260,12 @@ public class CompileTask implements DebugContextRunnable {

public final HostedMethod method;
protected final CompileReason reason;
protected final List<CompileReason> allReasons;
public CompilationResult result;
public final CompilationIdentifier compilationIdentifier;

public CompileTask(HostedMethod method, CompileReason reason) {
this.method = method;
this.reason = reason;
if (NativeImageOptions.PrintMethodHistogram.getValue()) {
this.allReasons = Collections.synchronizedList(new ArrayList<CompileReason>());
this.allReasons.add(reason);
} else {
this.allReasons = null;
}
compilationIdentifier = new SubstrateHostedCompilationIdentifier(method);
}

Expand Down Expand Up @@ -372,6 +366,15 @@ public void finish(DebugContext debug) {
// timer.
RestrictHeapAccessAnnotationChecker.check(debug, universe, universe.getMethods());

/*
* The graph in the analysis universe is no longer necessary. This clears the graph for
* methods that were not "parsed", i.e., method that were reached by the static analysis
* but are no longer reachable now.
*/
for (HostedMethod method : universe.getMethods()) {
method.wrapped.setAnalyzedGraph(null);
}

if (SubstrateOptions.AOTInline.getValue() && SubstrateOptions.AOTTrivialInline.getValue()) {
try (StopTimer ignored = new Timer(imageName, "(inline)").start()) {
inlineTrivialMethods(debug);
Expand All @@ -386,7 +389,7 @@ public void finish(DebugContext debug) {
} catch (InterruptedException ie) {
throw new InterruptImageBuilding();
}
if (NativeImageOptions.PrintMethodHistogram.getValue()) {
if (printMethodHistogram) {
printMethodHistogram();
}
}
Expand Down Expand Up @@ -471,14 +474,10 @@ private void printMethodHistogram() {
} else {
sizeNonDeoptMethods += result.getTargetCodeSize();
numberOfNonDeopt += 1;
System.out.format(" ; %6d; %5d; %5d; %4d; %4d;", 0, 0, 0, 0, 0);
System.out.format(" ; %6d; %5d; %5d; %5d; %4d; %4d;", 0, 0, 0, 0, 0, 0);
}

System.out.format(" %4d; %4d; %4d; %s\n",
task.allReasons.stream().filter(t -> t instanceof EntryPointReason).count(),
task.allReasons.stream().filter(t -> t instanceof DirectCallReason).count(),
task.allReasons.stream().filter(t -> t instanceof VirtualCallReason).count(),
method.format("%H.%n(%p) %r"));
System.out.format(" %4d; %4d; %4d; %s%n", ci.numEntryPointCalls.get(), ci.numDirectCalls.get(), ci.numVirtualCalls.get(), method.format("%H.%n(%p) %r"));
}
}
System.out.println();
Expand Down Expand Up @@ -1108,21 +1107,39 @@ private static void handleSpecialization(final HostedMethod method, CallTargetNo
}

protected void ensureCompiled(HostedMethod method, CompileReason reason) {
CompilationInfo compilationInfo = method.compilationInfo;

if (printMethodHistogram) {
if (reason instanceof DirectCallReason) {
compilationInfo.numDirectCalls.incrementAndGet();
} else if (reason instanceof VirtualCallReason) {
compilationInfo.numVirtualCalls.incrementAndGet();
} else if (reason instanceof EntryPointReason) {
compilationInfo.numEntryPointCalls.incrementAndGet();
}
}

/*
* Fast non-atomic check if method is already scheduled for compilation, to avoid frequent
* access of the ConcurrentHashMap.
*/
if (compilationInfo.inCompileQueue) {
return;
}

CompileTask task = new CompileTask(method, reason);
CompileTask oldTask = compilations.putIfAbsent(method, task);
if (oldTask != null) {
// Method is already scheduled for compilation.
if (oldTask.allReasons != null) {
oldTask.allReasons.add(reason);
}
return;
}
if (method.compilationInfo.specializedArguments != null) {
compilationInfo.inCompileQueue = true;

if (compilationInfo.specializedArguments != null) {
// Do the specialization: replace the argument locals with the constant arguments.
StructuredGraph graph = method.compilationInfo.graph;
StructuredGraph graph = compilationInfo.graph;

int idx = 0;
for (ConstantNode argument : method.compilationInfo.specializedArguments) {
for (ConstantNode argument : compilationInfo.specializedArguments) {
ParameterNode local = graph.getParameter(idx++);
if (local != null) {
local.replaceAndDelete(ConstantNode.forConstant(argument.asJavaConstant(), runtimeConfig.getProviders().getMetaAccess(), graph));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -688,21 +688,6 @@ private void markDataRelocationSiteFromText(RelocatableBuffer buffer, final Prog
}
}

/**
* Given a java.lang.reflect.Method, compute the symbol name of its start address (if any) in
* the image. The symbol name returned is the one that would be used for local references (e.g.
* for relocation), so is guaranteed to exist if the method is in the image. However, it is not
* necessarily visible for linking from other objects.
*
* @param m a java.lang.reflect.Method
* @return its symbol name as it would appear in the image (regardless of whether it actually
* does)
*/
public static String localSymbolNameForMethod(java.lang.reflect.Method m) {
/* We don't mangle local symbols, because they never need be referenced by an assembler. */
return SubstrateUtil.uniqueShortName(m);
}

/**
* Given a {@link ResolvedJavaMethod}, compute what symbol name of its start address (if any) in
* the image. The symbol name returned is the one that would be used for local references (e.g.
Expand All @@ -715,7 +700,7 @@ public static String localSymbolNameForMethod(java.lang.reflect.Method m) {
*/
public static String localSymbolNameForMethod(ResolvedJavaMethod sm) {
/* We don't mangle local symbols, because they never need be referenced by an assembler. */
return SubstrateOptions.ImageSymbolsPrefix.getValue() + SubstrateUtil.uniqueShortName(sm);
return SubstrateOptions.ImageSymbolsPrefix.getValue() + (sm instanceof HostedMethod ? ((HostedMethod) sm).getUniqueShortName() : SubstrateUtil.uniqueShortName(sm));
}

/**
Expand Down Expand Up @@ -745,7 +730,7 @@ public static String globalSymbolNameForMethod(java.lang.reflect.Method m) {
* does)
*/
public static String globalSymbolNameForMethod(ResolvedJavaMethod sm) {
return mangleName(SubstrateUtil.uniqueShortName(sm));
return mangleName((sm instanceof HostedMethod ? ((HostedMethod) sm).getUniqueShortName() : SubstrateUtil.uniqueShortName(sm)));
}

@Override
Expand Down Expand Up @@ -892,7 +877,7 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f
// 1. fq with return type
for (Map.Entry<HostedMethod, CompilationResult> ent : codeCache.getCompilations().entrySet()) {
final String symName = localSymbolNameForMethod(ent.getKey());
final String signatureString = SubstrateUtil.uniqueShortName(ent.getKey());
final String signatureString = ent.getKey().getUniqueShortName();
final HostedMethod existing = methodsBySignature.get(signatureString);
HostedMethod current = ent.getKey();
if (existing != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,9 @@ static class AddObjectData {
final Object reason;
}

public static final class ObjectInfo implements ImageHeapObject {
private final int imageHeapOffsetInAddressSpace = Heap.getHeap().getImageHeapOffsetInAddressSpace();

public final class ObjectInfo implements ImageHeapObject {
private final Object object;
private final HostedClass clazz;
private final long size;
Expand Down Expand Up @@ -689,7 +691,7 @@ public long getAddress() {
* the beginning of the heap. So, all heap-base-relative addresses must be adjusted by
* that offset.
*/
return Heap.getHeap().getImageHeapOffsetInAddressSpace() + getOffset();
return imageHeapOffsetInAddressSpace + getOffset();
}

/**
Expand Down
Loading