From 3957e9b3534fbf948a947f65c5c3ff1bb09c3a98 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Wed, 6 Oct 2021 18:26:10 +0200 Subject: [PATCH 1/2] Fail gracefully when invoking method pointers to null or uncompiled methods. --- ....java => InvalidMethodPointerHandler.java} | 33 ++++++++++++++----- .../ClassInitializationFeature.java | 5 ++- .../oracle/svm/hosted/image/NativeImage.java | 29 ++++++++++++++-- .../hosted/image/NativeImageHeapWriter.java | 12 ++----- .../oracle/svm/hosted/meta/MethodPointer.java | 22 +++++++++---- .../svm/hosted/meta/UniverseBuilder.java | 6 ++-- 6 files changed, 74 insertions(+), 33 deletions(-) rename substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/{InvalidVTableEntryHandler.java => InvalidMethodPointerHandler.java} (65%) diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidVTableEntryHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java similarity index 65% rename from substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidVTableEntryHandler.java rename to substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java index 43b7f36d57f5..1d8e548f8c29 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidVTableEntryHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java @@ -43,16 +43,33 @@ import com.oracle.svm.util.ReflectionUtil; /** - * Provides a stub method that can be used to fill otherwise unused vtable slots. Instead of a - * segfault, this method provides a full diagnostic output with a stack trace. + * Provides stub methods that can be used for uninitialized method pointers. Instead of a segfault, + * the stubs provide full diagnostic output with a stack trace. */ -public final class InvalidVTableEntryHandler { - public static final Method HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidVTableEntryHandler.class, "invalidVTableEntryHandler"); - public static final String MSG = "Fatal error: Virtual method call used an illegal vtable entry that was seen as unused by the static analysis"; +public final class InvalidMethodPointerHandler { + public static final Method INVALID_VTABLE_ENTRY_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "invalidVTableEntryHandler"); + public static final String INVALID_VTABLE_ENTRY_MSG = "Fatal error: Virtual method call used an illegal vtable entry that was seen as unused by the static analysis"; + + public static final Method METHOD_POINTER_INVALID_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "methodPointerInvalidHandler"); + public static final String METHOD_POINTER_INVALID_MSG = "Fatal error: Method pointer invoked on a method that is null, was not registered for compilation, or was not seen as invoked by the static analysis"; @StubCallingConvention @NeverInline("We need a separate frame that stores all registers") private static void invalidVTableEntryHandler() { + Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); + CodePointer callerIP = KnownIntrinsics.readReturnAddress(); + failFatally(callerSP, callerIP, INVALID_VTABLE_ENTRY_MSG); + } + + @StubCallingConvention + @NeverInline("We need a separate frame that stores all registers") + private static void methodPointerInvalidHandler() { + Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); + CodePointer callerIP = KnownIntrinsics.readReturnAddress(); + failFatally(callerSP, callerIP, METHOD_POINTER_INVALID_MSG); + } + + private static void failFatally(Pointer callerSP, CodePointer callerIP, String message) { VMThreads.StatusSupport.setStatusIgnoreSafepoints(); StackOverflowCheck.singleton().disableStackOverflowChecksForFatalError(); @@ -63,13 +80,11 @@ private static void invalidVTableEntryHandler() { * from the method that has the illegal vtable call. That can be helpful when debugging the * cause of the fatal error. */ - Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); - CodePointer callerIP = KnownIntrinsics.readReturnAddress(); LogHandler logHandler = ImageSingletons.lookup(LogHandler.class); - Log log = Log.enterFatalContext(logHandler, callerIP, MSG, null); + Log log = Log.enterFatalContext(logHandler, callerIP, message, null); if (log != null) { SubstrateDiagnostics.printFatalError(log, callerSP, callerIP, WordFactory.nullPointer(), true); - log.string(MSG).newline(); + log.string(message).newline(); } logHandler.fatalError(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java index deda2c6fc758..5572fe9892a1 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java @@ -44,6 +44,7 @@ import org.graalvm.compiler.graph.Node; import org.graalvm.compiler.options.OptionValues; import org.graalvm.compiler.phases.util.Providers; +import org.graalvm.nativeimage.c.function.CFunctionPointer; import com.oracle.graal.pointsto.constraints.UnsupportedFeatureException; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; @@ -354,11 +355,13 @@ private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImp * information. */ assert type.isLinked(); + CFunctionPointer classInitializerFunction = null; AnalysisMethod classInitializer = type.getClassInitializer(); if (classInitializer != null) { assert classInitializer.getCode() != null; access.registerAsCompiled(classInitializer); + classInitializerFunction = MethodPointer.factory(classInitializer); } - return new ClassInitializationInfo(MethodPointer.factory(classInitializer)); + return new ClassInitializationInfo(classInitializerFunction); } } 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 ef1f7597e74b..d43e640168db 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 @@ -59,6 +59,7 @@ import org.graalvm.compiler.debug.Indent; import org.graalvm.nativeimage.ImageSingletons; import org.graalvm.nativeimage.c.function.CFunctionPointer; +import org.graalvm.nativeimage.hosted.Feature; import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.AnalysisType; @@ -77,9 +78,11 @@ import com.oracle.svm.core.BuildArtifacts; import com.oracle.svm.core.BuildArtifacts.ArtifactType; import com.oracle.svm.core.FrameAccess; +import com.oracle.svm.core.InvalidMethodPointerHandler; import com.oracle.svm.core.Isolates; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.c.CConst; import com.oracle.svm.core.c.CGlobalDataImpl; import com.oracle.svm.core.c.CHeader; @@ -96,6 +99,7 @@ import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.option.HostedOptionValues; import com.oracle.svm.core.util.UserError; +import com.oracle.svm.hosted.FeatureImpl; import com.oracle.svm.hosted.NativeImageOptions; import com.oracle.svm.hosted.c.CGlobalDataFeature; import com.oracle.svm.hosted.c.NativeLibraries; @@ -564,14 +568,24 @@ private static boolean checkEmbeddedOffset(ProgbitsSectionImpl sectionImpl, fina return true; } - private static void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) { + private void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, final int offset, final RelocatableBuffer.Info info) { assert info.getTargetObject() instanceof CFunctionPointer : "Wrong type for FunctionPointer relocation: " + info.getTargetObject().toString(); final int functionPointerRelocationSize = 8; assert info.getRelocationSize() == functionPointerRelocationSize : "Function relocation: " + info.getRelocationSize() + " should be " + functionPointerRelocationSize + " bytes."; // References to functions are via relocations to the symbol for the function. - ResolvedJavaMethod method = ((MethodPointer) info.getTargetObject()).getMethod(); + MethodPointer methodPointer = (MethodPointer) info.getTargetObject(); + HostedMethod target = null; + boolean valid = methodPointer.isValid(); + if (valid) { + ResolvedJavaMethod method = methodPointer.getMethod(); + target = (method instanceof HostedMethod) ? (HostedMethod) method : heap.getUniverse().lookup(method); + valid = target.isCompiled(); + } + if (!valid) { + target = metaAccess.lookupJavaMethod(InvalidMethodPointerHandler.METHOD_POINTER_INVALID_HANDLER_METHOD); + } // A reference to a method. Mark the relocation site using the symbol name. - sectionImpl.markRelocationSite(offset, RelocationKind.getDirect(functionPointerRelocationSize), localSymbolNameForMethod(method), false, 0L); + sectionImpl.markRelocationSite(offset, RelocationKind.getDirect(functionPointerRelocationSize), localSymbolNameForMethod(target), false, 0L); } private static boolean isAddendAligned(Architecture arch, long addend, RelocationKind kind) { @@ -956,3 +970,12 @@ protected NativeTextSectionImpl(RelocatableBuffer relocatableBuffer, ObjectFile protected final NativeImageCodeCache codeCache; } } + +@AutomaticFeature +final class MethodPointerInvalidHandlerFeature implements Feature { + @Override + public void beforeAnalysis(BeforeAnalysisAccess a) { + FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a; + access.registerAsCompiled(InvalidMethodPointerHandler.METHOD_POINTER_INVALID_HANDLER_METHOD); + } +} 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 71c4684c9081..a06325b43b60 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 @@ -55,13 +55,11 @@ import com.oracle.svm.hosted.image.NativeImageHeap.ObjectInfo; import com.oracle.svm.hosted.meta.HostedClass; import com.oracle.svm.hosted.meta.HostedField; -import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.MaterializedConstantFields; import com.oracle.svm.hosted.meta.MethodPointer; import jdk.vm.ci.meta.JavaConstant; import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; import sun.misc.Unsafe; /** @@ -242,14 +240,8 @@ private void addNonDataRelocation(RelocatableBuffer buffer, int index, Relocated mustBeReferenceAligned(index); assert pointer instanceof CFunctionPointer : "unknown relocated pointer " + pointer; assert pointer instanceof MethodPointer : "cannot create relocation for unknown FunctionPointer " + pointer; - - ResolvedJavaMethod method = ((MethodPointer) pointer).getMethod(); - HostedMethod hMethod = method instanceof HostedMethod ? (HostedMethod) method : heap.getUniverse().lookup(method); - if (hMethod.isCompiled()) { - // Only compiled methods inserted in vtables require relocation. - int pointerSize = ConfigurationValues.getTarget().wordSize; - addDirectRelocationWithoutAddend(buffer, index, pointerSize, pointer); - } + int pointerSize = ConfigurationValues.getTarget().wordSize; + addDirectRelocationWithoutAddend(buffer, index, pointerSize, pointer); } private static void writePrimitive(RelocatableBuffer buffer, int index, JavaConstant con) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java index d6c92fbcf01e..9aa3dd79710c 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java @@ -29,32 +29,40 @@ import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.word.ComparableWord; +import com.oracle.svm.core.InvalidMethodPointerHandler; + import jdk.vm.ci.meta.ResolvedJavaMethod; /** * A pointer to the compiled code of a method. */ public class MethodPointer implements CFunctionPointer { + private static final MethodPointer INVALID = new MethodPointer(null); private final ResolvedJavaMethod method; public static CFunctionPointer factory(ResolvedJavaMethod method) { - if (method == null) { - return null; - } else { - return new MethodPointer(method); - } + return (method != null) ? new MethodPointer(method) : INVALID; } protected MethodPointer(ResolvedJavaMethod method) { - assert method != null; this.method = method; } + public boolean isValid() { + return (method != null); + } + public ResolvedJavaMethod getMethod() { + assert isValid(); return method; } + /** + * Always {@code false} because even a pointer to {@code null} or to a method that is not + * compiled will eventually be replaced by + * {@link InvalidMethodPointerHandler#METHOD_POINTER_INVALID_HANDLER_METHOD}. + */ @Override public boolean isNull() { return false; @@ -62,7 +70,7 @@ public boolean isNull() { @Override public boolean isNonNull() { - return true; + return !isNull(); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index b4e1414aa82c..84b69d9d54c7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -63,7 +63,7 @@ import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.graal.pointsto.results.AbstractAnalysisResultsBuilder; import com.oracle.svm.core.FunctionPointerHolder; -import com.oracle.svm.core.InvalidVTableEntryHandler; +import com.oracle.svm.core.InvalidMethodPointerHandler; import com.oracle.svm.core.StaticFieldsSupport; import com.oracle.svm.core.SubstrateOptions; import com.oracle.svm.core.SubstrateUtil; @@ -674,7 +674,7 @@ private void buildVTables() { * To avoid segfaults when jumping to address 0, all unused vtable entries are filled with a * stub that reports a fatal error. */ - HostedMethod invalidVTableEntryHandler = hMetaAccess.lookupJavaMethod(InvalidVTableEntryHandler.HANDLER_METHOD); + HostedMethod invalidVTableEntryHandler = hMetaAccess.lookupJavaMethod(InvalidMethodPointerHandler.INVALID_VTABLE_ENTRY_HANDLER_METHOD); for (HostedType type : hUniverse.getTypes()) { if (type.isArray()) { @@ -999,6 +999,6 @@ final class InvalidVTableEntryFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess a) { BeforeAnalysisAccessImpl access = (BeforeAnalysisAccessImpl) a; - access.registerAsCompiled(InvalidVTableEntryHandler.HANDLER_METHOD); + access.registerAsCompiled(InvalidMethodPointerHandler.INVALID_VTABLE_ENTRY_HANDLER_METHOD); } } From 31469571fa38a34ca7e5da48bf67263ed6acdd35 Mon Sep 17 00:00:00 2001 From: Peter Hofer Date: Thu, 7 Oct 2021 15:46:27 +0200 Subject: [PATCH 2/2] Disallow MethodPointer for null targets entirely. --- .../graal/llvm/LLVMNativeImageCodeCache.java | 2 +- .../svm/core/InvalidMethodPointerHandler.java | 8 +++--- .../graal/hosted/DeoptimizationFeature.java | 2 +- .../ClassInitializationFeature.java | 4 +-- .../code/CEntryPointCallStubSupport.java | 2 +- .../code/CEntryPointLiteralFeature.java | 2 +- .../hosted/image/LIRNativeImageCodeCache.java | 2 +- .../oracle/svm/hosted/image/NativeImage.java | 15 ++++------- .../oracle/svm/hosted/meta/MethodPointer.java | 27 +++++-------------- .../svm/hosted/meta/UniverseBuilder.java | 2 +- .../svm/jni/access/JNIAccessibleMethod.java | 12 ++++----- .../functions/JNIFunctionTablesFeature.java | 6 ++--- .../svm/reflect/hosted/ReflectionFeature.java | 2 +- 13 files changed, 33 insertions(+), 53 deletions(-) diff --git a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java index c931cf6b2cc2..9ee35d616beb 100644 --- a/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.core.graal.llvm/src/com/oracle/svm/core/graal/llvm/LLVMNativeImageCodeCache.java @@ -207,7 +207,7 @@ private void linkCompiledBatches(BatchExecutor executor, DebugContext debug, int stackMapDumper.close(); HostedMethod firstMethod = (HostedMethod) getFirstCompilation().getMethods()[0]; - buildRuntimeMetadata(MethodPointer.factory(firstMethod), WordFactory.signed(textSectionInfo.getCodeSize())); + buildRuntimeMetadata(new MethodPointer(firstMethod), WordFactory.signed(textSectionInfo.getCodeSize())); } private void llvmOptimize(DebugContext debug, String outputPath, String inputPath) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java index 1d8e548f8c29..4b759ea3e307 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/InvalidMethodPointerHandler.java @@ -50,8 +50,8 @@ public final class InvalidMethodPointerHandler { public static final Method INVALID_VTABLE_ENTRY_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "invalidVTableEntryHandler"); public static final String INVALID_VTABLE_ENTRY_MSG = "Fatal error: Virtual method call used an illegal vtable entry that was seen as unused by the static analysis"; - public static final Method METHOD_POINTER_INVALID_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "methodPointerInvalidHandler"); - public static final String METHOD_POINTER_INVALID_MSG = "Fatal error: Method pointer invoked on a method that is null, was not registered for compilation, or was not seen as invoked by the static analysis"; + public static final Method METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD = ReflectionUtil.lookupMethod(InvalidMethodPointerHandler.class, "methodPointerNotCompiledHandler"); + public static final String METHOD_POINTER_NOT_COMPILED_MSG = "Fatal error: Method pointer invoked on a method that was not compiled because it was not seen as invoked by the static analysis nor was it directly registered for compilation"; @StubCallingConvention @NeverInline("We need a separate frame that stores all registers") @@ -63,10 +63,10 @@ private static void invalidVTableEntryHandler() { @StubCallingConvention @NeverInline("We need a separate frame that stores all registers") - private static void methodPointerInvalidHandler() { + private static void methodPointerNotCompiledHandler() { Pointer callerSP = KnownIntrinsics.readCallerStackPointer(); CodePointer callerIP = KnownIntrinsics.readReturnAddress(); - failFatally(callerSP, callerIP, METHOD_POINTER_INVALID_MSG); + failFatally(callerSP, callerIP, METHOD_POINTER_NOT_COMPILED_MSG); } private static void failFatally(Pointer callerSP, CodePointer callerIP, String message) { diff --git a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java index 3fee955d70b4..0180a73028dd 100644 --- a/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java +++ b/substratevm/src/com.oracle.svm.graal/src/com/oracle/svm/graal/hosted/DeoptimizationFeature.java @@ -126,6 +126,6 @@ public void beforeCompilation(BeforeCompilationAccess a) { CompilationAccessImpl config = (CompilationAccessImpl) a; config.registerAsImmutable(ImageSingletons.lookup(DeoptimizationSupport.class)); HostedMetaAccess metaAccess = config.getMetaAccess(); - DeoptimizationSupport.setDeoptStubPointer(MethodPointer.factory(metaAccess.lookupJavaMethod(deoptStubMethod))); + DeoptimizationSupport.setDeoptStubPointer(new MethodPointer(metaAccess.lookupJavaMethod(deoptStubMethod))); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java index 5572fe9892a1..9060a15a291a 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/classinitialization/ClassInitializationFeature.java @@ -341,7 +341,7 @@ private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImp /* Synthesize a VerifyError to be thrown at run time. */ AnalysisMethod throwVerifyError = access.getMetaAccess().lookupJavaMethod(ExceptionSynthesizer.throwExceptionMethod(VerifyError.class)); access.registerAsCompiled(throwVerifyError); - return new ClassInitializationInfo(MethodPointer.factory(throwVerifyError)); + return new ClassInitializationInfo(new MethodPointer(throwVerifyError)); } catch (Throwable t) { /* * All other linking errors will be reported as NoClassDefFoundError when initialization @@ -360,7 +360,7 @@ private static ClassInitializationInfo buildRuntimeInitializationInfo(FeatureImp if (classInitializer != null) { assert classInitializer.getCode() != null; access.registerAsCompiled(classInitializer); - classInitializerFunction = MethodPointer.factory(classInitializer); + classInitializerFunction = new MethodPointer(classInitializer); } return new ClassInitializationInfo(classInitializerFunction); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java index c6eb898ece3b..90a80cb80adf 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointCallStubSupport.java @@ -110,7 +110,7 @@ public AnalysisMethod registerJavaStubForMethod(AnalysisMethod method) { if (value == null) { assert !bb.getUniverse().sealed(); AnalysisMethod nativeStub = registerStubForMethod(method, () -> CEntryPointData.create(method)); - CFunctionPointer nativeStubAddress = MethodPointer.factory(nativeStub); + CFunctionPointer nativeStubAddress = new MethodPointer(nativeStub); String stubName = SubstrateUtil.uniqueShortName(method); ResolvedJavaType holderClass = bb.getMetaAccess().lookupJavaType(IsolateLeaveStub.class).getWrapped(); CEntryPointJavaCallStubMethod stub = new CEntryPointJavaCallStubMethod(method.getWrapped(), stubName, holderClass, nativeStubAddress); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java index c5fd686aad87..1e69f5e974f8 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/CEntryPointLiteralFeature.java @@ -81,7 +81,7 @@ public Object apply(Object source) { * Only during compilation and native image writing, we do the actual * replacement. */ - return MethodPointer.factory(hStub); + return new MethodPointer(hStub); } } return source; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java index a1ae28bde450..19e985859367 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/LIRNativeImageCodeCache.java @@ -103,7 +103,7 @@ public void layoutMethods(DebugContext debug, String imageName, BigBang bb, Fork codeCacheSize = NumUtil.roundUp(codeCacheSize + compilation.getTargetCodeSize(), SubstrateOptions.codeAlignment()); } - buildRuntimeMetadata(MethodPointer.factory(firstMethod), WordFactory.unsigned(codeCacheSize)); + buildRuntimeMetadata(new MethodPointer(firstMethod), WordFactory.unsigned(codeCacheSize)); } } 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 d43e640168db..b41457106299 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 @@ -574,15 +574,10 @@ private void markFunctionRelocationSite(final ProgbitsSectionImpl sectionImpl, f assert info.getRelocationSize() == functionPointerRelocationSize : "Function relocation: " + info.getRelocationSize() + " should be " + functionPointerRelocationSize + " bytes."; // References to functions are via relocations to the symbol for the function. MethodPointer methodPointer = (MethodPointer) info.getTargetObject(); - HostedMethod target = null; - boolean valid = methodPointer.isValid(); - if (valid) { - ResolvedJavaMethod method = methodPointer.getMethod(); - target = (method instanceof HostedMethod) ? (HostedMethod) method : heap.getUniverse().lookup(method); - valid = target.isCompiled(); - } - if (!valid) { - target = metaAccess.lookupJavaMethod(InvalidMethodPointerHandler.METHOD_POINTER_INVALID_HANDLER_METHOD); + ResolvedJavaMethod method = methodPointer.getMethod(); + HostedMethod target = (method instanceof HostedMethod) ? (HostedMethod) method : heap.getUniverse().lookup(method); + if (!target.isCompiled()) { + target = metaAccess.lookupJavaMethod(InvalidMethodPointerHandler.METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD); } // A reference to a method. Mark the relocation site using the symbol name. sectionImpl.markRelocationSite(offset, RelocationKind.getDirect(functionPointerRelocationSize), localSymbolNameForMethod(target), false, 0L); @@ -976,6 +971,6 @@ final class MethodPointerInvalidHandlerFeature implements Feature { @Override public void beforeAnalysis(BeforeAnalysisAccess a) { FeatureImpl.BeforeAnalysisAccessImpl access = (FeatureImpl.BeforeAnalysisAccessImpl) a; - access.registerAsCompiled(InvalidMethodPointerHandler.METHOD_POINTER_INVALID_HANDLER_METHOD); + access.registerAsCompiled(InvalidMethodPointerHandler.METHOD_POINTER_NOT_COMPILED_HANDLER_METHOD); } } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java index 9aa3dd79710c..d2af190eba9b 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/MethodPointer.java @@ -26,43 +26,28 @@ import static com.oracle.svm.core.util.VMError.shouldNotReachHere; +import java.util.Objects; + import org.graalvm.nativeimage.c.function.CFunctionPointer; import org.graalvm.word.ComparableWord; -import com.oracle.svm.core.InvalidMethodPointerHandler; - import jdk.vm.ci.meta.ResolvedJavaMethod; /** * A pointer to the compiled code of a method. */ -public class MethodPointer implements CFunctionPointer { - private static final MethodPointer INVALID = new MethodPointer(null); - +public final class MethodPointer implements CFunctionPointer { private final ResolvedJavaMethod method; - public static CFunctionPointer factory(ResolvedJavaMethod method) { - return (method != null) ? new MethodPointer(method) : INVALID; - } - - protected MethodPointer(ResolvedJavaMethod method) { + public MethodPointer(ResolvedJavaMethod method) { + Objects.requireNonNull(method); this.method = method; } - public boolean isValid() { - return (method != null); - } - public ResolvedJavaMethod getMethod() { - assert isValid(); return method; } - /** - * Always {@code false} because even a pointer to {@code null} or to a method that is not - * compiled will eventually be replaced by - * {@link InvalidMethodPointerHandler#METHOD_POINTER_INVALID_HANDLER_METHOD}. - */ @Override public boolean isNull() { return false; @@ -70,7 +55,7 @@ public boolean isNull() { @Override public boolean isNonNull() { - return !isNull(); + return true; } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java index 84b69d9d54c7..c4fd6a6496f4 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/meta/UniverseBuilder.java @@ -925,7 +925,7 @@ private void buildHubs() { * We install a CodePointer in the vtable; when generating relocation info, we will * know these point into .text */ - vtable[idx] = MethodPointer.factory(type.vtable[idx]); + vtable[idx] = new MethodPointer(type.vtable[idx]); } // pointer maps in Dynamic Hub diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java index adefdc5ab15d..5c85406a0397 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/access/JNIAccessibleMethod.java @@ -124,13 +124,13 @@ public boolean isStatic() { void finishBeforeCompilation(CompilationAccessImpl access) { HostedUniverse hUniverse = access.getUniverse(); AnalysisUniverse aUniverse = access.getUniverse().getBigBang().getUniverse(); - varargsCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(varargsCallWrapperMethod))); - arrayCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(arrayCallWrapperMethod))); - valistCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(valistCallWrapperMethod))); + varargsCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(varargsCallWrapperMethod))); + arrayCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(arrayCallWrapperMethod))); + valistCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(valistCallWrapperMethod))); if (!Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers)) { - varargsNonvirtualCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(varargsNonvirtualCallWrapperMethod))); - arrayNonvirtualCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(arrayNonvirtualCallWrapperMethod))); - valistNonvirtualCallWrapper = MethodPointer.factory(hUniverse.lookup(aUniverse.lookup(valistNonvirtualCallWrapperMethod))); + varargsNonvirtualCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(varargsNonvirtualCallWrapperMethod))); + arrayNonvirtualCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(arrayNonvirtualCallWrapperMethod))); + valistNonvirtualCallWrapper = new MethodPointer(hUniverse.lookup(aUniverse.lookup(valistNonvirtualCallWrapperMethod))); } setHidingSubclasses(access.getMetaAccess(), this::anyMatchIgnoreReturnType); } diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java index c317c23ac4ef..602e68473758 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/functions/JNIFunctionTablesFeature.java @@ -192,7 +192,7 @@ private static CFunctionPointer prepareCallTrampoline(CompilationAccessImpl acce HostedMethod hostedTrampoline = access.getUniverse().lookup(analysisTrampoline); hostedTrampoline.compilationInfo.setCustomParseFunction(trampolineMethod.createCustomParseFunction()); hostedTrampoline.compilationInfo.setCustomCompileFunction(trampolineMethod.createCustomCompileFunction()); - return MethodPointer.factory(hostedTrampoline); + return new MethodPointer(hostedTrampoline); } private static ResolvedJavaMethod getSingleMethod(MetaAccessProvider metaAccess, Class holder) { @@ -203,7 +203,7 @@ private static ResolvedJavaMethod getSingleMethod(MetaAccessProvider metaAccess, private static CFunctionPointer getStubFunctionPointer(CompilationAccessImpl access, HostedMethod method) { AnalysisMethod stub = CEntryPointCallStubSupport.singleton().getStubForMethod(method.getWrapped()); - return MethodPointer.factory(access.getUniverse().lookup(stub)); + return new MethodPointer(access.getUniverse().lookup(stub)); } private void fillJNIInvocationInterfaceTable(CompilationAccessImpl access, CFunctionPointer[] table, CFunctionPointer defaultValue) { @@ -236,7 +236,7 @@ private void fillJNIFunctionsTable(CompilationAccessImpl access, CFunctionPointe HostedMethod hostedMethod = access.getUniverse().lookup(analysisMethod); int offset = field.getOffsetInfo().getProperty(); - setFunctionPointerTable(table, offset, MethodPointer.factory(hostedMethod)); + setFunctionPointerTable(table, offset, new MethodPointer(hostedMethod)); } for (CallVariant variant : CallVariant.values()) { CFunctionPointer trampoline = prepareCallTrampoline(access, variant, false); diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java index 827c4ea7d274..02684b29ba1e 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionFeature.java @@ -154,7 +154,7 @@ private Object createAccessor(Executable member) { private CFunctionPointer register(ResolvedJavaMethod method) { AnalysisMethod aMethod = method instanceof AnalysisMethod ? (AnalysisMethod) method : analysisAccess.getUniverse().lookup(method); analysisAccess.registerAsCompiled(aMethod); - return MethodPointer.factory(aMethod); + return new MethodPointer(aMethod); } protected ResolvedJavaMethod createReflectiveInvokeMethod(String name, ResolvedJavaMethod prototype, Method method) {