diff --git a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java index 5bfc6e6bcae7..3fc2ae9f6d2f 100644 --- a/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java +++ b/compiler/src/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FrameState.java @@ -382,6 +382,11 @@ public FrameState duplicateModified(JavaKind popKind, JavaKind pushedSlotKind, V return duplicateModified(graph(), bci, rethrowException, duringCall, popKind, new JavaKind[]{pushedSlotKind}, new ValueNode[]{pushedValue}, pushedVirtualObjectMappings); } + public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues, + List pushedVirtualObjectMappings) { + return duplicateModified(graph, newBci, newRethrowException, newDuringCall, popKind, pushedSlotKinds, pushedValues, pushedVirtualObjectMappings, true); + } + /** * Creates a copy of this frame state with one stack element of type popKind popped from the * stack and the values in pushedValues pushed on the stack. The pushedValues will be formatted @@ -389,7 +394,7 @@ public FrameState duplicateModified(JavaKind popKind, JavaKind pushedSlotKind, V * changed to newBci. */ public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean newRethrowException, boolean newDuringCall, JavaKind popKind, JavaKind[] pushedSlotKinds, ValueNode[] pushedValues, - List pushedVirtualObjectMappings) { + List pushedVirtualObjectMappings, boolean checkStackDepth) { List copiedVirtualObjectMappings = null; ArrayList copy; if (newRethrowException && !rethrowException && popKind == JavaKind.Void) { @@ -422,7 +427,7 @@ public FrameState duplicateModified(StructuredGraph graph, int newBci, boolean n int newStackSize = copy.size() - localsSize; copy.addAll(values.subList(localsSize + stackSize, values.size())); - assert checkStackDepth(bci, stackSize, duringCall, rethrowException, newBci, newStackSize, newDuringCall, newRethrowException); + assert !checkStackDepth || checkStackDepth(bci, stackSize, duringCall, rethrowException, newBci, newStackSize, newDuringCall, newRethrowException); return graph.add(new FrameState(outerFrameState(), code, newBci, copy, localsSize, newStackSize, newRethrowException, newDuringCall, monitorIds, copiedVirtualObjectMappings != null ? copiedVirtualObjectMappings : virtualObjectMappings)); } diff --git a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java index 48f50a43b078..359c96c86e74 100644 --- a/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java +++ b/substratevm/src/com.oracle.graal.pointsto/src/com/oracle/graal/pointsto/infrastructure/WrappedSignature.java @@ -49,7 +49,7 @@ public int getParameterCount(boolean receiver) { public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { ResolvedJavaType parameterType; try { - parameterType = wrapped.getParameterType(index, defaultAccessingClass).resolve(defaultAccessingClass); + parameterType = resolve(wrapped.getParameterType(index, defaultAccessingClass)); } catch (LinkageError e) { /* * Type resolution fails if the parameter type is missing. Just erase the type by @@ -64,7 +64,7 @@ public JavaType getParameterType(int index, ResolvedJavaType accessingClass) { public JavaType getReturnType(ResolvedJavaType accessingClass) { ResolvedJavaType returnType; try { - returnType = wrapped.getReturnType(defaultAccessingClass).resolve(defaultAccessingClass); + returnType = resolve(wrapped.getReturnType(defaultAccessingClass)); } catch (LinkageError e) { /* * Type resolution fails if the return type is missing. Just erase the type by returning @@ -74,4 +74,18 @@ public JavaType getReturnType(ResolvedJavaType accessingClass) { } return universe.lookup(returnType); } + + /** + * We must not invoke {@link JavaType#resolve} on an already resolved type because it can + * actually fail the accessibility check when synthetic methods and synthetic signatures are + * involved. + */ + private ResolvedJavaType resolve(JavaType type) { + if (type instanceof ResolvedJavaType) { + return (ResolvedJavaType) type; + } else { + return type.resolve(defaultAccessingClass); + } + } + } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodHolder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodHolder.java index e3dcbcc37d7b..1746841771b0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodHolder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodHolder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2021, 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 @@ -31,6 +31,7 @@ * of a constructor). */ @InternalVMMethod +@FactoryMethodMarker public final class FactoryMethodHolder { private FactoryMethodHolder() { } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodMarker.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodMarker.java new file mode 100644 index 000000000000..0b6168e68d8d --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryMethodMarker.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021, 2021, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.code; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface FactoryMethodMarker { +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryThrowMethodHolder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryThrowMethodHolder.java new file mode 100644 index 000000000000..779b3091a83a --- /dev/null +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/code/FactoryThrowMethodHolder.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021, 2021, 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package com.oracle.svm.core.code; + +import com.oracle.svm.core.jdk.InternalVMMethod; + +/** + * Holder class for generated factory methods (methods that combine object allocation and invocation + * of a constructor) that then immediately throw the allocated objects (which must be an exception + * type). + */ +@InternalVMMethod +@FactoryMethodMarker +public final class FactoryThrowMethodHolder { + private FactoryThrowMethodHolder() { + } +} diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/InternalVMMethod.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/InternalVMMethod.java index 337965f6ad8f..0d33fc0e1ad4 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/InternalVMMethod.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/InternalVMMethod.java @@ -24,14 +24,11 @@ */ package com.oracle.svm.core.jdk; -import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import org.graalvm.util.DirectAnnotationAccess; - /** * Annotation for types whose methods must be ignored for certain kinds of stack walks, such as by * Reflection.getCallerClass(). All methods in the annotated type have the same level of visibility. @@ -39,17 +36,4 @@ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface InternalVMMethod { - - @InternalVMMethod() - class Holder { - - /** Instance of the annotation, useful when the annotation is manually injected. */ - public static final InternalVMMethod INSTANCE = DirectAnnotationAccess.getAnnotation(Holder.class, InternalVMMethod.class); - - /** - * Array that contains only the instance of the annotation, useful when the annotation is - * manually injected. - */ - public static final Annotation[] ARRAY = new Annotation[]{INSTANCE}; - } } diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/ReflectionAccessorHolder.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/ReflectionAccessorHolder.java index 2b7044246374..74fdeae7af51 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/ReflectionAccessorHolder.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/ReflectionAccessorHolder.java @@ -30,7 +30,6 @@ import com.oracle.svm.core.annotate.NeverInline; import com.oracle.svm.core.jdk.InternalVMMethod; -import com.oracle.svm.core.reflect.SubstrateConstructorAccessor.ConstructorNewInstanceFunctionPointer; import com.oracle.svm.core.reflect.SubstrateMethodAccessor.MethodInvokeFunctionPointer; import com.oracle.svm.core.util.VMError; @@ -47,21 +46,13 @@ public final class ReflectionAccessorHolder { * Signature prototype for invoking a method via a {@link SubstrateMethodAccessor}. Must match * the signature of {@link MethodInvokeFunctionPointer#invoke} */ - static Object invokePrototype(boolean invokeSpecial, Object obj, Object[] args) { - throw VMError.shouldNotReachHere("Only used as a prototype for generated methods"); - } - - /** - * Signature prototype for allocating a new instance via a {@link SubstrateConstructorAccessor}. - * Must match * the signature of {@link ConstructorNewInstanceFunctionPointer#invoke} - */ - static Object newInstancePrototype(Object[] args) { + private static Object invokePrototype(boolean invokeSpecial, Object obj, Object[] args) { throw VMError.shouldNotReachHere("Only used as a prototype for generated methods"); } /* * Methods for throwing exceptions when a method or constructor is used in an illegal way. These - * methods are invoked via function pointers, so must have the same signature as the prototypes + * methods are invoked via function pointers, so must have the same signature as the prototype * above. */ @@ -70,7 +61,7 @@ private static void methodHandleInvokeError(boolean invokeSpecial, Object obj, O throw new InvocationTargetException(new UnsupportedOperationException("MethodHandle.invoke() and MethodHandle.invokeExact() cannot be invoked through reflection")); } - private static Object newInstanceError(Object[] args) throws InstantiationException { + private static Object newInstanceError(boolean invokeSpecial, Object obj, Object[] args) throws InstantiationException { throw new InstantiationException("Only non-abstract instance classes can be instantiated using reflection"); } @@ -80,30 +71,25 @@ private static Object newInstanceError(Object[] args) throws InstantiationExcept */ @NeverInline("Exception slow path") - private static InvocationTargetException throwInvocationTargetException(Throwable target) throws InvocationTargetException { - throw new InvocationTargetException(target); - } - - @NeverInline("Exception slow path") - private static void throwIllegalArgumentExceptionForMethod(Object member, Object obj, Object[] args) { - throwIllegalArgumentException(member, false, obj, args); + private static void throwIllegalArgumentExceptionWithReceiver(Object member, Object obj, Object[] args) { + throwIllegalArgumentException(member, true, obj, args); } @NeverInline("Exception slow path") - private static void throwIllegalArgumentExceptionForConstructor(Object member, Object[] args) { - throwIllegalArgumentException(member, true, null, args); + private static void throwIllegalArgumentExceptionWithoutReceiver(Object member, Object[] args) { + throwIllegalArgumentException(member, false, null, args); } /** - * We do not know which check in the generated metod caused the exception, so we cannot print + * We do not know which check in the generated method caused the exception, so we cannot print * detailed information about that. But printing the signature of the method and all the types * of the actual arguments should make it obvious what the problem is. */ - private static void throwIllegalArgumentException(Object member, boolean constructor, Object obj, Object[] args) { + private static void throwIllegalArgumentException(Object member, boolean withReceiver, Object obj, Object[] args) { String sep = System.lineSeparator(); StringBuilder msg = new StringBuilder(); msg.append("Illegal arguments for invoking ").append(member); - if (!constructor) { + if (withReceiver) { msg.append(sep).append(" obj: ").append(obj == null ? "null" : obj.getClass().getTypeName()); } if (args == null) { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java index 6902ece0f28e..a72c9397d31b 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/reflect/SubstrateConstructorAccessor.java @@ -30,19 +30,13 @@ import org.graalvm.nativeimage.c.function.CFunctionPointer; -import com.oracle.svm.core.annotate.InvokeJavaFunctionPointer; import com.oracle.svm.core.jdk.InternalVMMethod; +import com.oracle.svm.core.reflect.SubstrateMethodAccessor.MethodInvokeFunctionPointer; import com.oracle.svm.core.util.VMError; @InternalVMMethod public abstract class SubstrateConstructorAccessor { - interface ConstructorNewInstanceFunctionPointer extends CFunctionPointer { - /** Must match the signature of {@link ReflectionAccessorHolder#newInstancePrototype}. */ - @InvokeJavaFunctionPointer - Object invoke(Object[] args); - } - private final Executable member; private final CFunctionPointer newInstanceFunctionPointer; @@ -52,11 +46,11 @@ protected SubstrateConstructorAccessor(Executable member, CFunctionPointer newIn } public Object newInstance(Object[] args) { - ConstructorNewInstanceFunctionPointer functionPointer = (ConstructorNewInstanceFunctionPointer) this.newInstanceFunctionPointer; + MethodInvokeFunctionPointer functionPointer = (MethodInvokeFunctionPointer) this.newInstanceFunctionPointer; if (functionPointer.isNull()) { throw newInstanceError(); } - return functionPointer.invoke(args); + return functionPointer.invoke(false, null, args); } private RuntimeException newInstanceError() { diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java index 1785e6b91cf0..313d40d936ee 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/snippets/ImplicitExceptions.java @@ -30,6 +30,7 @@ import com.oracle.svm.core.SubstrateDiagnostics; import com.oracle.svm.core.annotate.RestrictHeapAccess; +import com.oracle.svm.core.code.FactoryMethodMarker; import com.oracle.svm.core.jdk.InternalVMMethod; import com.oracle.svm.core.jdk.StackTraceUtils; import com.oracle.svm.core.snippets.SnippetRuntime.SubstrateForeignCallDescriptor; @@ -45,6 +46,7 @@ * therefore these methods are filtered in exception stack traces (see {@link StackTraceUtils}). */ @InternalVMMethod +@FactoryMethodMarker public class ImplicitExceptions { public static final String NO_STACK_MSG = "[no exception stack trace available because exception is thrown from code that must be allocation free]"; diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java index 53a8e5cae1e5..79a58cbdd929 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/SVMHost.java @@ -559,6 +559,11 @@ public void methodAfterParsingHook(BigBang bb, AnalysisMethod method, Structured if (parseOnce) { optimizeAfterParsing(bb, graph); + /* + * Do a complete Canonicalizer run once before graph encoding, to clean up any + * leftover uncanonicalized nodes. + */ + CanonicalizerPhase.create().apply(graph, bb.getProviders()); } for (BiConsumer methodAfterParsingHook : methodAfterParsingHooks) { @@ -571,11 +576,6 @@ protected void optimizeAfterParsing(BigBang bb, StructuredGraph graph) { new ImplicitAssertionsPhase().apply(graph, bb.getProviders()); new BoxNodeIdentityPhase().apply(graph, bb.getProviders()); new PartialEscapePhase(false, false, CanonicalizerPhase.create(), null, options).apply(graph, bb.getProviders()); - /* - * Do a complete Canonicalizer run once before graph encoding, to clean up any leftover - * uncanonicalized nodes. - */ - CanonicalizerPhase.create().apply(graph, bb.getProviders()); } @Override diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java index c8e9215afbfe..f918ea5482fa 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethod.java @@ -24,10 +24,14 @@ */ package com.oracle.svm.hosted.code; +import java.lang.annotation.Annotation; +import java.util.Objects; + import org.graalvm.compiler.debug.DebugContext; import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; import org.graalvm.compiler.nodes.InvokeWithExceptionNode; import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.UnwindNode; import org.graalvm.compiler.nodes.ValueNode; import org.graalvm.compiler.nodes.java.AbstractNewObjectNode; import org.graalvm.nativeimage.ImageSingletons; @@ -36,8 +40,10 @@ import com.oracle.graal.pointsto.meta.AnalysisMethod; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.SubstrateUtil; +import com.oracle.svm.core.annotate.NeverInlineTrivial; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.phases.HostedGraphKit; +import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.ConstantPool; import jdk.vm.ci.meta.MetaAccessProvider; @@ -48,15 +54,49 @@ public final class FactoryMethod extends NonBytecodeStaticMethod { private final ResolvedJavaMethod targetConstructor; + private final boolean throwAllocatedObject; - FactoryMethod(ResolvedJavaMethod targetConstructor, ResolvedJavaType declaringClass, Signature signature, ConstantPool constantPool) { + FactoryMethod(ResolvedJavaMethod targetConstructor, ResolvedJavaType declaringClass, Signature signature, ConstantPool constantPool, boolean throwAllocatedObject) { super(SubstrateUtil.uniqueShortName(targetConstructor), declaringClass, signature, constantPool); this.targetConstructor = targetConstructor; + this.throwAllocatedObject = throwAllocatedObject; assert targetConstructor.isConstructor(); assert !(targetConstructor instanceof AnalysisMethod) && !(targetConstructor instanceof HostedMethod); } + /** + * Even though factory methods have few Graal nodes and are therefore considered "trivial", we + * do not want them inlined immediately by the trivial method inliner because we know that the + * machine code for allocations is large. Note that this does not preclude later inlining of the + * method as part of the regular AOT compilation pipeline. + */ + @NeverInlineTrivial("FactoryMethod") + @SuppressWarnings("unused") + private static void annotationHolder() { + } + + private static final NeverInlineTrivial INLINE_ANNOTATION = Objects.requireNonNull( + ReflectionUtil.lookupMethod(FactoryMethod.class, "annotationHolder").getAnnotation(NeverInlineTrivial.class)); + + @Override + public T getAnnotation(Class annotationClass) { + if (annotationClass.isInstance(INLINE_ANNOTATION)) { + return annotationClass.cast(INLINE_ANNOTATION); + } + return null; + } + + @Override + public Annotation[] getAnnotations() { + return new Annotation[]{INLINE_ANNOTATION}; + } + + @Override + public Annotation[] getDeclaredAnnotations() { + return new Annotation[]{INLINE_ANNOTATION}; + } + @Override public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, HostedProviders providers, Purpose purpose) { FactoryMethodSupport support = ImageSingletons.lookup(FactoryMethodSupport.class); @@ -76,7 +116,11 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, kit.inline(invoke, "Constructor in FactoryMethod", "FactoryMethod"); } - kit.createReturn(newInstance, newInstance.getStackKind()); + if (throwAllocatedObject) { + kit.append(new UnwindNode(newInstance)); + } else { + kit.createReturn(newInstance, newInstance.getStackKind()); + } return kit.finalizeGraph(); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java index 5c56a6b13d4e..6311df988e90 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/code/FactoryMethodSupport.java @@ -35,16 +35,17 @@ import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMetaAccess; import com.oracle.graal.pointsto.meta.AnalysisMethod; +import com.oracle.graal.pointsto.meta.AnalysisType; import com.oracle.graal.pointsto.meta.AnalysisUniverse; import com.oracle.svm.core.annotate.AutomaticFeature; import com.oracle.svm.core.code.FactoryMethodHolder; +import com.oracle.svm.core.code.FactoryThrowMethodHolder; import com.oracle.svm.hosted.meta.HostedMetaAccess; import com.oracle.svm.hosted.meta.HostedMethod; import com.oracle.svm.hosted.meta.HostedUniverse; import com.oracle.svm.hosted.phases.HostedGraphKit; import jdk.vm.ci.meta.ConstantPool; -import jdk.vm.ci.meta.MetaAccessProvider; import jdk.vm.ci.meta.ResolvedJavaMethod; import jdk.vm.ci.meta.ResolvedJavaType; import jdk.vm.ci.meta.Signature; @@ -56,8 +57,9 @@ public static FactoryMethodSupport singleton() { } private final Map factoryMethods = new ConcurrentHashMap<>(); + private final Map factoryThrowMethods = new ConcurrentHashMap<>(); - public ResolvedJavaMethod lookup(UniverseMetaAccess metaAccess, ResolvedJavaMethod constructor) { + public ResolvedJavaMethod lookup(UniverseMetaAccess metaAccess, ResolvedJavaMethod constructor, boolean throwAllocatedObject) { HostedUniverse hUniverse; AnalysisMetaAccess aMetaAccess; if (metaAccess instanceof HostedMetaAccess) { @@ -68,15 +70,24 @@ public ResolvedJavaMethod lookup(UniverseMetaAccess metaAccess, ResolvedJavaMeth aMetaAccess = (AnalysisMetaAccess) metaAccess; } AnalysisUniverse aUniverse = aMetaAccess.getUniverse(); - MetaAccessProvider unwrappedMetaAccess = aMetaAccess.getWrapped(); AnalysisMethod aConstructor = constructor instanceof HostedMethod ? ((HostedMethod) constructor).getWrapped() : (AnalysisMethod) constructor; - FactoryMethod factoryMethod = factoryMethods.computeIfAbsent(aConstructor, key -> { + Map methods = throwAllocatedObject ? factoryThrowMethods : factoryMethods; + FactoryMethod factoryMethod = methods.computeIfAbsent(aConstructor, key -> { + /* + * Computing the signature types via the analysis universe ensures that we have all + * substitutions applied and all types already resolved. + */ + ResolvedJavaType[] unwrappedParameterTypes = new ResolvedJavaType[aConstructor.getSignature().getParameterCount(false)]; + for (int i = 0; i < unwrappedParameterTypes.length; i++) { + unwrappedParameterTypes[i] = ((AnalysisType) aConstructor.getSignature().getParameterType(i, null)).getWrappedWithoutResolve(); + } + ResolvedJavaType unwrappedReturnType = (throwAllocatedObject ? aMetaAccess.lookupJavaType(void.class) : aConstructor.getDeclaringClass()).getWrappedWithoutResolve(); + Signature unwrappedSignature = new SimpleSignature(unwrappedParameterTypes, unwrappedReturnType); ResolvedJavaMethod unwrappedConstructor = aConstructor.getWrapped(); - ResolvedJavaType declaringClass = unwrappedMetaAccess.lookupJavaType(FactoryMethodHolder.class); - Signature signature = new SimpleSignature(unwrappedConstructor.toParameterTypes(), unwrappedConstructor.getDeclaringClass()); - ConstantPool constantPool = unwrappedConstructor.getConstantPool(); - return new FactoryMethod(unwrappedConstructor, declaringClass, signature, constantPool); + ResolvedJavaType unwrappedDeclaringClass = (aMetaAccess.lookupJavaType(throwAllocatedObject ? FactoryThrowMethodHolder.class : FactoryMethodHolder.class)).getWrappedWithoutResolve(); + ConstantPool unwrappedConstantPool = unwrappedConstructor.getConstantPool(); + return new FactoryMethod(unwrappedConstructor, unwrappedDeclaringClass, unwrappedSignature, unwrappedConstantPool, throwAllocatedObject); }); AnalysisMethod aFactoryMethod = aUniverse.lookup(factoryMethod); diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java index 14169e0e815f..c943d03dc374 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/phases/ImplicitAssertionsPhase.java @@ -48,7 +48,9 @@ import org.graalvm.compiler.nodes.java.NewInstanceNode; import org.graalvm.compiler.nodes.spi.CoreProviders; import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.util.GuardedAnnotationAccess; +import com.oracle.svm.core.code.FactoryMethodMarker; import com.oracle.svm.core.snippets.ImplicitExceptions; import com.oracle.svm.util.ReflectionUtil; @@ -71,10 +73,10 @@ public class ImplicitAssertionsPhase extends BasePhase { @Override protected void run(StructuredGraph graph, CoreProviders context) { - if (graph.method().getDeclaringClass().equals(context.getMetaAccess().lookupJavaType(ImplicitExceptions.class))) { + if (GuardedAnnotationAccess.isAnnotationPresent(graph.method().getDeclaringClass(), FactoryMethodMarker.class)) { /* - * ImplicitExceptions contains final target methods invoked by the intrinsification, - * i.e., the methods that actually will perform the allocations at run time. + * Factory methods, which includes methods in ImplicitExceptions, are the methods that + * actually perform the allocations at run time. */ return; } diff --git a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIJavaCallWrapperMethod.java b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIJavaCallWrapperMethod.java index e64d32071014..378d7e23a191 100644 --- a/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIJavaCallWrapperMethod.java +++ b/substratevm/src/com.oracle.svm.jni/src/com/oracle/svm/jni/hosted/JNIJavaCallWrapperMethod.java @@ -331,7 +331,7 @@ public StructuredGraph buildGraph(DebugContext debug, ResolvedJavaMethod method, private static ValueNode createNewObjectCall(UniverseMetaAccess metaAccess, JNIGraphKit kit, ResolvedJavaMethod constructor, FrameStateBuilder state, ValueNode... argsWithReceiver) { assert constructor.isConstructor() : "Cannot create a NewObject call to the non-constructor method " + constructor; - ResolvedJavaMethod factoryMethod = FactoryMethodSupport.singleton().lookup(metaAccess, constructor); + ResolvedJavaMethod factoryMethod = FactoryMethodSupport.singleton().lookup(metaAccess, constructor, false); int bci = kit.bci(); ValueNode[] argsWithoutReceiver = Arrays.copyOfRange(argsWithReceiver, 1, argsWithReceiver.length); 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 151d1681cbf1..d9c49998cd01 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 @@ -27,7 +27,6 @@ // Checkstyle: allow reflection import java.lang.invoke.MethodHandle; -import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Field; import java.lang.reflect.Method; @@ -85,9 +84,8 @@ public class ReflectionFeature implements GraalFeature { final Map accessors = new ConcurrentHashMap<>(); private static final Method invokePrototype = ReflectionUtil.lookupMethod(ReflectionAccessorHolder.class, "invokePrototype", boolean.class, Object.class, Object[].class); - private static final Method newInstancePrototype = ReflectionUtil.lookupMethod(ReflectionAccessorHolder.class, "newInstancePrototype", Object[].class); private static final Method methodHandleInvokeErrorMethod = ReflectionUtil.lookupMethod(ReflectionAccessorHolder.class, "methodHandleInvokeError", boolean.class, Object.class, Object[].class); - private static final Method newInstanceErrorMethod = ReflectionUtil.lookupMethod(ReflectionAccessorHolder.class, "newInstanceError", Object[].class); + private static final Method newInstanceErrorMethod = ReflectionUtil.lookupMethod(ReflectionAccessorHolder.class, "newInstanceError", boolean.class, Object.class, Object[].class); FeatureImpl.BeforeAnalysisAccessImpl analysisAccess; @@ -109,24 +107,24 @@ Object getOrCreateAccessor(Executable member) { * instances use function pointer calls to invocation stubs. The invocation stubs unpack the * Object[] array arguments and invoke the actual method. * - * The stubs are methods with manually created Graal IR: {@link ReflectiveInvokeMethod} and - * {@link ReflectiveNewInstanceMethod}. Since they are only invoked via function pointers and - * never at a normal call site, they need to be registered for compilation manually. From the - * point of view of the static analysis, they are root methods. + * The stubs are methods with manually created Graal IR: {@link ReflectiveInvokeMethod}. Since + * they are only invoked via function pointers and never at a normal call site, they need to be + * registered for compilation manually. From the point of view of the static analysis, they are + * root methods. * * {@link ConcurrentHashMap#computeIfAbsent} guarantees that this method is called only once per * member, so no further synchronization is necessary. */ private Object createAccessor(Executable member) { String name = SubstrateUtil.uniqueShortName(member); + ResolvedJavaMethod prototype = analysisAccess.getMetaAccess().lookupJavaMethod(invokePrototype).getWrapped(); if (member instanceof Method) { ResolvedJavaMethod invokeMethod; if (member.getDeclaringClass() == MethodHandle.class && (member.getName().equals("invoke") || member.getName().equals("invokeExact"))) { /* Method handles must not be invoked via reflection. */ invokeMethod = analysisAccess.getMetaAccess().lookupJavaMethod(methodHandleInvokeErrorMethod); } else { - ResolvedJavaMethod prototype = analysisAccess.getMetaAccess().lookupJavaMethod(invokePrototype).getWrapped(); - invokeMethod = createReflectiveInvokeMethod(name, prototype, (Method) member); + invokeMethod = new ReflectiveInvokeMethod(name, prototype, member); } return ImageSingletons.lookup(SubstrateReflectionAccessorFactory.class).createMethodAccessor(member, register(invokeMethod)); @@ -142,8 +140,7 @@ private Object createAccessor(Executable member) { */ newInstanceMethod = analysisAccess.getMetaAccess().lookupJavaMethod(newInstanceErrorMethod); } else { - ResolvedJavaMethod prototype = analysisAccess.getMetaAccess().lookupJavaMethod(newInstancePrototype).getWrapped(); - newInstanceMethod = createReflectiveNewInstanceMethod(name, prototype, (Constructor) member); + newInstanceMethod = new ReflectiveInvokeMethod(name, prototype, member); } return ImageSingletons.lookup(SubstrateReflectionAccessorFactory.class).createConstructorAccessor(member, register(newInstanceMethod)); } @@ -155,14 +152,6 @@ private CFunctionPointer register(ResolvedJavaMethod method) { return new MethodPointer(aMethod); } - protected ResolvedJavaMethod createReflectiveInvokeMethod(String name, ResolvedJavaMethod prototype, Method method) { - return new ReflectiveInvokeMethod(name, prototype, method); - } - - protected ResolvedJavaMethod createReflectiveNewInstanceMethod(String name, ResolvedJavaMethod prototype, Constructor constructor) { - return new ReflectiveNewInstanceMethod(name, prototype, constructor); - } - protected void inspectAccessibleField(@SuppressWarnings("unused") Field field) { } diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionGraphKit.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionGraphKit.java index 86afda24ca46..6c679620abdd 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionGraphKit.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectionGraphKit.java @@ -26,7 +26,9 @@ // Checkstyle: allow reflection +import java.lang.reflect.Constructor; import java.lang.reflect.Executable; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -60,12 +62,15 @@ import org.graalvm.compiler.nodes.java.InstanceOfNode; import org.graalvm.compiler.nodes.type.StampTool; +import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.svm.core.graal.nodes.LoweredDeadEndNode; import com.oracle.svm.core.meta.SubstrateObjectConstant; import com.oracle.svm.core.reflect.ReflectionAccessorHolder; import com.oracle.svm.core.util.VMError; +import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.phases.HostedGraphKit; +import com.oracle.svm.util.ReflectionUtil; import jdk.vm.ci.meta.JavaKind; import jdk.vm.ci.meta.ResolvedJavaMethod; @@ -137,20 +142,23 @@ public void emitIllegalArgumentException(Executable member, ValueNode obj, Value ResolvedJavaMethod targetMethod; ValueNode[] arguments; if (obj == null) { - targetMethod = findMethod(ReflectionAccessorHolder.class, "throwIllegalArgumentExceptionForConstructor", true); + targetMethod = findMethod(ReflectionAccessorHolder.class, "throwIllegalArgumentExceptionWithoutReceiver", true); arguments = new ValueNode[]{memberNode, args}; } else { - targetMethod = findMethod(ReflectionAccessorHolder.class, "throwIllegalArgumentExceptionForMethod", true); + targetMethod = findMethod(ReflectionAccessorHolder.class, "throwIllegalArgumentExceptionWithReceiver", true); arguments = new ValueNode[]{memberNode, obj, args}; } createJavaCallWithExceptionAndUnwind(CallTargetNode.InvokeKind.Static, targetMethod, arguments); append(new LoweredDeadEndNode()); } + private static final Constructor invocationTargetExceptionConstructor = ReflectionUtil.lookupConstructor(InvocationTargetException.class, Throwable.class); + public void emitInvocationTargetException() { AbstractMergeNode merge = continueWithMerge(invocationTargetExceptionPaths); ValueNode exception = createPhi(invocationTargetExceptionPaths, merge); - ResolvedJavaMethod throwInvocationTargetException = findMethod(ReflectionAccessorHolder.class, "throwInvocationTargetException", true); + ResolvedJavaMethod throwInvocationTargetException = FactoryMethodSupport.singleton().lookup((UniverseMetaAccess) getMetaAccess(), + getMetaAccess().lookupJavaMethod(invocationTargetExceptionConstructor), true); createJavaCallWithExceptionAndUnwind(CallTargetNode.InvokeKind.Static, throwInvocationTargetException, exception); append(new LoweredDeadEndNode()); } diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveInvokeMethod.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveInvokeMethod.java index d8489dacb74c..457183385bdb 100644 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveInvokeMethod.java +++ b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveInvokeMethod.java @@ -29,7 +29,7 @@ import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0; import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0; -import java.lang.reflect.Method; +import java.lang.reflect.Executable; import java.util.ArrayList; import java.util.List; @@ -55,10 +55,12 @@ import org.graalvm.compiler.nodes.spi.CanonicalizerTool; import org.graalvm.compiler.phases.common.inlining.InliningUtil; +import com.oracle.graal.pointsto.infrastructure.UniverseMetaAccess; import com.oracle.graal.pointsto.meta.HostedProviders; import com.oracle.graal.pointsto.phases.SubstrateIntrinsicGraphBuilder; import com.oracle.svm.core.meta.SharedMethod; import com.oracle.svm.core.reflect.SubstrateMethodAccessor; +import com.oracle.svm.hosted.code.FactoryMethodSupport; import com.oracle.svm.hosted.code.NonBytecodeStaticMethod; import jdk.vm.ci.meta.JavaKind; @@ -67,9 +69,9 @@ public class ReflectiveInvokeMethod extends NonBytecodeStaticMethod { - private final Method method; + private final Executable method; - public ReflectiveInvokeMethod(String name, ResolvedJavaMethod prototype, Method method) { + public ReflectiveInvokeMethod(String name, ResolvedJavaMethod prototype, Executable method) { super(name, prototype.getDeclaringClass(), prototype.getSignature(), prototype.getConstantPool()); this.method = method; } @@ -91,12 +93,21 @@ public StructuredGraph buildGraph(DebugContext ctx, ResolvedJavaMethod m, Hosted graphKit.getFrameState().clearLocals(); ResolvedJavaMethod targetMethod = providers.getMetaAccess().lookupJavaMethod(method); + if (targetMethod.isStatic() || targetMethod.isConstructor()) { + graphKit.emitEnsureInitializedCall(targetMethod.getDeclaringClass()); + } + if (targetMethod.isConstructor()) { + /* + * For a constructor, we invoke a synthetic static factory method that combines both the + * allocation and the constructor invocation. + */ + targetMethod = FactoryMethodSupport.singleton().lookup((UniverseMetaAccess) providers.getMetaAccess(), targetMethod, false); + } + Class[] argTypes = method.getParameterTypes(); int receiverOffset = targetMethod.isStatic() ? 0 : 1; ValueNode[] args = new ValueNode[argTypes.length + receiverOffset]; - if (targetMethod.isStatic()) { - graphKit.emitEnsureInitializedCall(targetMethod.getDeclaringClass()); - } else { + if (!targetMethod.isStatic()) { /* * The specification explicitly demands a NullPointerException and not a * IllegalArgumentException when the receiver of a non-static method is null @@ -112,11 +123,12 @@ public StructuredGraph buildGraph(DebugContext ctx, ResolvedJavaMethod m, Hosted graphKit.fillArgsArray(argumentArray, receiverOffset, args, argTypes); InvokeKind invokeKind; + assert !targetMethod.isConstructor() : "Constructors are already rewritten to static factory methods"; if (targetMethod.isStatic()) { invokeKind = InvokeKind.Static; } else if (targetMethod.isInterface()) { invokeKind = InvokeKind.Interface; - } else if (targetMethod.canBeStaticallyBound() || targetMethod.isConstructor()) { + } else if (targetMethod.canBeStaticallyBound()) { invokeKind = InvokeKind.Special; } else { invokeKind = InvokeKind.Virtual; @@ -172,7 +184,7 @@ public StructuredGraph buildGraph(DebugContext ctx, ResolvedJavaMethod m, Hosted } graphKit.createReturn(returnValue, JavaKind.Object); - graphKit.emitIllegalArgumentException(method, receiver, argumentArray); + graphKit.emitIllegalArgumentException(method, invokeKind == InvokeKind.Static ? null : receiver, argumentArray); graphKit.emitInvocationTargetException(); for (InvokeWithExceptionNode invoke : invokes) { diff --git a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveNewInstanceMethod.java b/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveNewInstanceMethod.java deleted file mode 100644 index 28b89df01ccb..000000000000 --- a/substratevm/src/com.oracle.svm.reflect/src/com/oracle/svm/reflect/hosted/ReflectiveNewInstanceMethod.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2021, 2021, 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ -package com.oracle.svm.reflect.hosted; - -// Checkstyle: allow reflection - -import java.lang.reflect.Constructor; - -import org.graalvm.compiler.debug.DebugContext; -import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind; -import org.graalvm.compiler.nodes.InvokeWithExceptionNode; -import org.graalvm.compiler.nodes.StructuredGraph; -import org.graalvm.compiler.nodes.ValueNode; -import org.graalvm.compiler.nodes.java.NewInstanceNode; - -import com.oracle.graal.pointsto.meta.HostedProviders; -import com.oracle.svm.hosted.code.NonBytecodeStaticMethod; - -import jdk.vm.ci.meta.JavaKind; -import jdk.vm.ci.meta.ResolvedJavaMethod; -import jdk.vm.ci.meta.ResolvedJavaType; - -public class ReflectiveNewInstanceMethod extends NonBytecodeStaticMethod { - - private final Constructor constructor; - - public ReflectiveNewInstanceMethod(String name, ResolvedJavaMethod prototype, Constructor constructor) { - super(name, prototype.getDeclaringClass(), prototype.getSignature(), prototype.getConstantPool()); - this.constructor = constructor; - } - - @Override - public StructuredGraph buildGraph(DebugContext ctx, ResolvedJavaMethod m, HostedProviders providers, Purpose purpose) { - ReflectionGraphKit graphKit = new ReflectionGraphKit(ctx, providers, m); - - ValueNode argumentArray = graphKit.loadLocal(0, JavaKind.Object); - /* Clear all locals, so that they are not alive and spilled at method calls. */ - graphKit.getFrameState().clearLocals(); - - ResolvedJavaMethod targetMethod = providers.getMetaAccess().lookupJavaMethod(constructor); - graphKit.emitEnsureInitializedCall(targetMethod.getDeclaringClass()); - - Class[] argTypes = constructor.getParameterTypes(); - ValueNode[] args = new ValueNode[argTypes.length + 1]; - args[0] = graphKit.append(createNewInstanceNode(targetMethod.getDeclaringClass())); - graphKit.fillArgsArray(argumentArray, 1, args, argTypes); - - InvokeWithExceptionNode invoke = graphKit.createJavaCallWithException(InvokeKind.Special, targetMethod, args); - graphKit.exceptionPart(); - graphKit.branchToInvocationTargetException(graphKit.exceptionObject()); - graphKit.endInvokeWithException(); - graphKit.createReturn(args[0], JavaKind.Object); - - graphKit.emitIllegalArgumentException(constructor, null, argumentArray); - graphKit.emitInvocationTargetException(); - processInvoke(graphKit, invoke); - - return graphKit.finalizeGraph(); - } - - protected ValueNode createNewInstanceNode(ResolvedJavaType type) { - return new NewInstanceNode(type, true); - } - - @SuppressWarnings("unused") - protected void processInvoke(ReflectionGraphKit graphKit, InvokeWithExceptionNode invoke) { - } -}