/** * A helper for {@link ResolvedJavaMethod#getParameterAnnotations()} that handles the absence of * parameter annotations on bridge methods where the bridged method has parameter annotations. */ public static Annotation[][] getParameterAnnotations(ResolvedJavaMethod method) { Annotation[][] a = method.getParameterAnnotations(); if (a.length == 0 && method.isBridge()) { a = getBridgedMethod(method).getParameterAnnotations(); } return a; }
/** Invokes a given method via {@link Method#invoke(Object, Object...)}. */ default Object invoke(ResolvedJavaMethod method, Object receiver, Object... args) { try { JavaType[] parameterTypes = method.toParameterTypes(); Class<?>[] parameterClasses = new Class<?>[parameterTypes.length]; for (int i = 0; i < parameterClasses.length; ++i) { JavaType type = parameterTypes[i]; if (type.getJavaKind() != JavaKind.Object) { parameterClasses[i] = type.getJavaKind().toJavaClass(); } else { parameterClasses[i] = resolveClassForSnippet(parameterTypes[i]); } } Class<?> c = resolveClassForSnippet(method.getDeclaringClass()); if (method.isConstructor()) { Constructor<?> javaConstructor = c.getDeclaredConstructor(parameterClasses); javaConstructor.setAccessible(true); return javaConstructor.newInstance(args); } else { Method javaMethod = c.getDeclaredMethod(method.getName(), parameterClasses); javaMethod.setAccessible(true); return javaMethod.invoke(receiver, args); } } catch (IllegalAccessException | InstantiationException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException ex) { throw new IllegalArgumentException(ex); } }
/** * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this * graph is constructed. This ignores how many bytecodes in each constituent method are actually * parsed (which may be none for methods whose IR is retrieved from a cache or less than the full * amount for any given method due to profile guided branch pruning). */ public int getBytecodeSize() { int res = method.getCodeSize(); for (ResolvedJavaMethod e : inlinedMethods) { res += e.getCodeSize(); } return res; }
/** * A helper for {@link ResolvedJavaMethod#getParameterAnnotation(Class, int)} that handles the * absence of parameter annotations on bridge methods where the bridged method has parameter * annotations. */ public static <T extends Annotation> T getParameterAnnotation( Class<T> annotationClass, int parameterIndex, ResolvedJavaMethod method) { T a = method.getParameterAnnotation(annotationClass, parameterIndex); if (a == null && method.isBridge()) { a = getBridgedMethod(method).getParameterAnnotation(annotationClass, parameterIndex); } return a; }
/** * Gets the profiling info for a given method that is or will be part of this graph, taking into * account {@link #useProfilingInfo()}. */ public ProfilingInfo getProfilingInfo(ResolvedJavaMethod m) { if (useProfilingInfo && m != null) { return m.getProfilingInfo(); } else { return DefaultProfilingInfo.get(TriState.UNKNOWN); } }
protected MacroNode( NodeClass<? extends MacroNode> c, InvokeKind invokeKind, ResolvedJavaMethod targetMethod, int bci, StampPair returnStamp, ValueNode... arguments) { super(c, returnStamp.getTrustedStamp()); assert targetMethod.getSignature().getParameterCount(!targetMethod.isStatic()) == arguments.length; this.arguments = new NodeInputList<>(this, arguments); this.bci = bci; this.targetMethod = targetMethod; this.returnStamp = returnStamp; this.invokeKind = invokeKind; assert !isPlaceholderBci(bci); }
@SuppressWarnings("try") private void testImplicit(Integer i) { Assume.assumeTrue(config().useCompressedOops); Container c = new Container(); c.i = i; try (OverrideScope s = OptionValue.override(GraalOptions.OptImplicitNullChecks, true)) { ResolvedJavaMethod method = getResolvedJavaMethod("testSnippet"); Result expect = executeExpected(method, null, c); // make sure we don't get a profile that removes the implicit null check method.reprofile(); Result actual = executeActual(method, null, c); assertEquals(expect, actual); } }
static ResolvedJavaMethod findMethod( ResolvedJavaType type, String name, String descriptor, boolean isStatic) { if (isStatic && name.equals("<clinit>")) { ResolvedJavaMethod method = type.getClassInitializer(); if (method != null) { return method; } } ResolvedJavaMethod[] methodsToSearch = name.equals("<init>") ? type.getDeclaredConstructors() : type.getDeclaredMethods(); for (ResolvedJavaMethod method : methodsToSearch) { if (method.isStatic() == isStatic && method.getName().equals(name) && method.getSignature().toMethodDescriptor().equals(descriptor)) { return method; } } return null; }
@Override public void lower(LoweringTool tool) { StructuredGraph replacementGraph = getLoweredSnippetGraph(tool); InvokeNode invoke = replaceWithInvoke(); assert invoke.verify(); if (replacementGraph != null) { // Pull out the receiver null check so that a replaced // receiver can be lowered if necessary if (!targetMethod.isStatic()) { ValueNode nonNullReceiver = InliningUtil.nonNullReceiver(invoke); if (nonNullReceiver instanceof Lowerable) { ((Lowerable) nonNullReceiver).lower(tool); } } InliningUtil.inline(invoke, replacementGraph, false, null); Debug.dump(Debug.INFO_LOG_LEVEL, graph(), "After inlining replacement %s", replacementGraph); } else { if (isPlaceholderBci(invoke.bci())) { throw new GraalError("%s: cannot lower to invoke with placeholder BCI: %s", graph(), this); } if (invoke.stateAfter() == null) { ResolvedJavaMethod method = graph().method(); if (method.getAnnotation(MethodSubstitution.class) != null || method.getAnnotation(Snippet.class) != null) { // One cause for this is that a MacroNode is created for a method that // no longer needs a MacroNode. For example, Class.getComponentType() // only needs a MacroNode prior to JDK9 as it was given a non-native // implementation in JDK9. throw new GraalError( "%s macro created for call to %s in %s must be lowerable to a snippet or intrinsic graph. " + "Maybe a macro node is not needed for this method in the current JDK?", getClass().getSimpleName(), targetMethod.format("%h.%n(%p)"), graph()); } throw new GraalError("%s: cannot lower to invoke without state: %s", graph(), this); } invoke.lower(tool); } }
@Test public void test() throws Throwable { Method fooMethod = Foo.class.getDeclaredMethod("getName"); ResolvedJavaMethod foo1 = metaAccess.lookupJavaMethod(fooMethod); ResolvedJavaMethod foo2 = metaAccess.lookupJavaMethod(fooMethod); String foo1Code = Arrays.toString(foo1.getCode()); String foo2Code = Arrays.toString(foo2.getCode()); Assert.assertEquals("foo", Foo.getName()); redefineFoo(); System.gc(); // Make sure the transformation happened Assert.assertEquals("bar", Foo.getName()); Assert.assertEquals(foo1Code, Arrays.toString(foo1.getCode())); Assert.assertEquals(foo2Code, Arrays.toString(foo1.getCode())); }
/** * Gets the method bridged to by a {@linkplain ResolvedJavaMethod#isBridge() bridge} method. The * value returned is the method called by {@code method} that has the same name as {@code bridge}. * * @param bridge a bridge method * @return the method called by {@code bridge} whose name is the same as {@code bridge.getName()} */ public static ResolvedJavaMethod getBridgedMethod(ResolvedJavaMethod bridge) { assert bridge.isBridge(); Bytecode code = new ResolvedJavaMethodBytecode(bridge); BytecodeStream stream = new BytecodeStream(code.getCode()); int opcode = stream.currentBC(); ResolvedJavaMethod bridged = null; while (opcode != Bytecodes.END) { switch (opcode) { case INVOKEVIRTUAL: case INVOKESPECIAL: case INVOKESTATIC: case INVOKEINTERFACE: { int cpi = stream.readCPI(); ConstantPool cp = code.getConstantPool(); cp.loadReferencedType(cpi, opcode); ResolvedJavaMethod method = (ResolvedJavaMethod) cp.lookupMethod(cpi, opcode); if (method.getName().equals(bridge.getName())) { if (!assertionsEnabled()) { return method; } assert bridged == null || bridged.equals(method) : String.format( "Found calls to different methods named %s in bridge method %s%n callee 1: %s%n callee 2: %s", bridge.getName(), bridge.format("%R %H.%n(%P)"), bridged.format("%R %H.%n(%P)"), method.format("%R %H.%n(%P)")); bridged = method; } break; } } stream.next(); opcode = stream.currentBC(); } if (bridged == null) { throw new InternalError("Couldn't find method bridged by " + bridge.format("%R %H.%n(%P)")); } return bridged; }
@Override public Bytecode getBytecode(ResolvedJavaMethod method) { Classfile classfile = getClassfile(resolveToClass(method.getDeclaringClass().getName())); return classfile.getCode(method.getName(), method.getSignature().toMethodDescriptor()); }