diff --git a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SnippetResolvedJavaType.java b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SnippetResolvedJavaType.java index 9020656454e6..31052deb36c6 100644 --- a/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SnippetResolvedJavaType.java +++ b/compiler/src/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/SnippetResolvedJavaType.java @@ -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 findUniqueConcreteMethod(ResolvedJavaMethod method) { throw new UnsupportedOperationException(); diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java index a0dfa20a2b01..2b3b68039363 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisMethod.java @@ -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); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java index 765374a38ffb..de9a4020dde5 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/meta/AnalysisType.java @@ -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); @@ -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; } @@ -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 diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HostedImageHeapChunkWriter.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HostedImageHeapChunkWriter.java index d8eeb425afa6..3fca7eddd401 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HostedImageHeapChunkWriter.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/HostedImageHeapChunkWriter.java @@ -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; @@ -94,13 +95,13 @@ private void writeHeader(int chunkOffset, long topOffset, long endOffset, long o @Override public void enableRememberedSetForAlignedChunk(int chunkPosition, List 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) { diff --git a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java index 3f2222e0cb08..f6a8f2be9dc0 100644 --- a/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java +++ b/substratevm/src/com.oracle.svm.core.genscavenge/src/com/oracle/svm/core/genscavenge/remset/AlignedChunkRememberedSet.java @@ -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. diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java index ae1439052142..9704776347dd 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/graal/meta/SubstrateReplacements.java @@ -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) diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java index 13516ccce6ca..b67be844f287 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/ameta/AnalysisConstantReflectionProvider.java @@ -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); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java index 27ba47a8b9f8..873e46aa8ea8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/annotation/ConstantAnnotationMarkerSubstitutionType.java @@ -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 findUniqueConcreteMethod(ResolvedJavaMethod method) { return original.findUniqueConcreteMethod(method); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java index 350adb0936d0..3d3938dec910 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompilationInfo.java @@ -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; @@ -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; @@ -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; } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java index b96f3be1c73d..fd9868c3c448 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CompileQueue.java @@ -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; @@ -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 @@ -259,19 +260,12 @@ public class CompileTask implements DebugContextRunnable { public final HostedMethod method; protected final CompileReason reason; - protected final List 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()); - this.allReasons.add(reason); - } else { - this.allReasons = null; - } compilationIdentifier = new SubstrateHostedCompilationIdentifier(method); } @@ -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); @@ -386,7 +389,7 @@ public void finish(DebugContext debug) { } catch (InterruptedException ie) { throw new InterruptImageBuilding(); } - if (NativeImageOptions.PrintMethodHistogram.getValue()) { + if (printMethodHistogram) { printMethodHistogram(); } } @@ -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(); @@ -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)); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index 2e1c2033181e..7437c7c6ee00 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -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. @@ -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)); } /** @@ -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 @@ -892,7 +877,7 @@ protected void writeTextSection(DebugContext debug, final Section textSection, f // 1. fq with return type for (Map.Entry 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) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java index dc0b48ce3545..22afc4b3ebf1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeap.java @@ -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; @@ -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(); } /** diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java index 5c63e2c324ad..71c4684c9081 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImageHeapWriter.java @@ -34,6 +34,7 @@ import org.graalvm.compiler.core.common.NumUtil; import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.debug.Indent; +import org.graalvm.compiler.serviceprovider.GraalUnsafeAccess; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.nativeimage.c.function.RelocatedPointer; @@ -61,11 +62,15 @@ import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; +import sun.misc.Unsafe; /** * Writes the native image heap into one or multiple {@link RelocatableBuffer}s. */ public final class NativeImageHeapWriter { + + private static final Unsafe UNSAFE = GraalUnsafeAccess.getUnsafe(); + private final NativeImageHeap heap; private final ImageHeapLayoutInfo heapLayout; private long sectionOffsetOfARelocatablePointer; @@ -157,14 +162,16 @@ private void write(RelocatableBuffer buffer, int index, JavaConstant con, Object } } + private final boolean useHeapBase = NativeImageHeap.useHeapBase(); + private final CompressEncoding compressEncoding = ImageSingletons.lookup(CompressEncoding.class); + void writeReference(RelocatableBuffer buffer, int index, Object target, Object reason) { assert !(target instanceof WordBase) : "word values are not references"; mustBeReferenceAligned(index); if (target != null) { ObjectInfo targetInfo = heap.getObjectInfo(target); verifyTargetDidNotChange(target, reason, targetInfo); - if (NativeImageHeap.useHeapBase()) { - CompressEncoding compressEncoding = ImageSingletons.lookup(CompressEncoding.class); + if (useHeapBase) { int shift = compressEncoding.getShift(); writeReferenceValue(buffer, index, targetInfo.getAddress() >>> shift); } else { @@ -380,11 +387,10 @@ private void writeObject(ObjectInfo info, RelocatableBuffer buffer) { writeConstant(buffer, elementIndex, kind, element, info); } } else { - for (int i = 0; i < length; i++) { - final int elementIndex = info.getIndexInBuffer(objectLayout.getArrayElementOffset(kind, i)); - final Object element = Array.get(array, i); - writeConstant(buffer, elementIndex, kind, element, info); - } + int elementIndex = info.getIndexInBuffer(objectLayout.getArrayElementOffset(kind, 0)); + int elementTypeSize = UNSAFE.arrayIndexScale(array.getClass()); + assert elementTypeSize == kind.getByteCount(); + UNSAFE.copyMemory(array, UNSAFE.arrayBaseOffset(array.getClass()), buffer.getBackingArray(), Unsafe.ARRAY_BYTE_BASE_OFFSET + elementIndex, length * elementTypeSize); } } else { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java index 0982e43663cc..6f5d24334322 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedMethod.java @@ -42,6 +42,7 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.results.StaticAnalysisResults; +import com.oracle.svm.core.SubstrateUtil; import com.oracle.svm.core.annotate.AlwaysInline; import com.oracle.svm.core.annotate.StubCallingConvention; import com.oracle.svm.core.deopt.Deoptimizer; @@ -92,6 +93,8 @@ public class HostedMethod implements SharedMethod, WrappedJavaMethod, GraphProvi public final CompilationInfo compilationInfo; private final LocalVariableTable localVariableTable; + private final String uniqueShortName; + public HostedMethod(HostedUniverse universe, AnalysisMethod wrapped, HostedType holder, Signature signature, ConstantPool constantPool, ExceptionHandler[] handlers) { this.wrapped = wrapped; this.holder = holder; @@ -99,6 +102,7 @@ public HostedMethod(HostedUniverse universe, AnalysisMethod wrapped, HostedType this.constantPool = constantPool; this.handlers = handlers; this.compilationInfo = new CompilationInfo(this); + this.uniqueShortName = SubstrateUtil.uniqueShortName(this); LocalVariableTable newLocalVariableTable = null; if (wrapped.getLocalVariableTable() != null) { @@ -160,6 +164,10 @@ public boolean isCompiled() { return compiled; } + public String getUniqueShortName() { + return uniqueShortName; + } + /* * Release compilation related information. */ diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java index 376d57ac97bb..7eb6fcfe75d8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/HostedType.java @@ -27,7 +27,6 @@ import static com.oracle.svm.core.util.VMError.shouldNotReachHere; import java.lang.annotation.Annotation; -import java.util.Arrays; import org.graalvm.word.WordBase; @@ -310,49 +309,31 @@ public final ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType } @Override - public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod m, ResolvedJavaType ct) { + public ResolvedJavaMethod resolveConcreteMethod(ResolvedJavaMethod m, ResolvedJavaType callerType) { HostedMethod method = (HostedMethod) m; - HostedType callerType = (HostedType) ct; - if (isWordType()) { + AnalysisMethod aResult = wrapped.resolveConcreteMethod(method.wrapped); + HostedMethod hResult; + if (aResult == null) { + hResult = null; + } else if (!aResult.isImplementationInvoked() && !isWordType()) { /* - * We do not keep any method information on word types on our own, so ask the hosting VM - * for the answer. + * Filter out methods that are not seen as invoked by the static analysis, e.g., because + * the declaring type is not instantiated. Word types are an exception, because methods + * of word types are never marked as invoked (they are always intrinsified). */ - return wrappedResolveMethod(method, callerType); + hResult = null; + } else { + hResult = universe.lookup(aResult); } - /* Use the same algorithm that is also used for SubstrateType during runtime compilation. */ - ResolvedJavaMethod found = SharedType.super.resolveConcreteMethod(method, callerType); - /* Check that our algorithm returns the same result as the hosting VM. */ - - /* - * For abstract classes, our result can be different than the result from HotSpot. It is - * unclear what concrete method resolution on an abstract class means. - */ - assert isAbstract() || (found == null || checkWrappedResolveMethod(method, found, callerType)); - - return found; - } - - private boolean checkWrappedResolveMethod(HostedMethod method, ResolvedJavaMethod found, HostedType callerType) { - /* - * The static analysis can determine that the resolved wrapped method is not reachable, case - * in which wrappedResolveMethod returns null. + /** + * Check that the SharedType implementation, which is used for JIT compilation, gives the + * same result as the hosted implementation. */ - ResolvedJavaMethod wrappedMethod = wrappedResolveMethod(method, callerType); - return wrappedMethod == null || found.equals(wrappedMethod); - } + assert hResult == null || isWordType() || hResult.equals(SharedType.super.resolveConcreteMethod(method, callerType)); - private ResolvedJavaMethod wrappedResolveMethod(HostedMethod method, HostedType callerType) { - AnalysisMethod orig = wrapped.resolveConcreteMethod(method.wrapped, callerType.wrapped); - ResolvedJavaMethod result = orig == null ? null : universe.lookup(orig); - - if (result != null && !isWordType() && !Arrays.asList(method.getImplementations()).contains(result)) { - /* Our static analysis found out that this method is not reachable. */ - result = null; - } - return result; + return hResult; } @Override