diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/LookupMode.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/LookupMode.java
new file mode 100644
index 000000000000..c11ab6b177b1
--- /dev/null
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/LookupMode.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2025, 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.truffle.espresso.shared.lookup;
+
+import com.oracle.truffle.espresso.classfile.Constants;
+import com.oracle.truffle.espresso.shared.meta.ModifiersProvider;
+
+/**
+ * Provides a simple way of filtering elements with {@linkplain ModifiersProvider modifiers} (such
+ * as classes, methods or fields), based on their declared flags.
+ */
+public final class LookupMode {
+ public static final LookupMode ALL = new LookupMode(0, 0);
+ public static final LookupMode INSTANCE_ONLY = new LookupMode(0, Constants.ACC_STATIC);
+ public static final LookupMode STATIC_ONLY = new LookupMode(Constants.ACC_STATIC, 0);
+ public static final LookupMode NON_STATIC_NON_PRIVATE = new LookupMode(0, Constants.ACC_STATIC | Constants.ACC_PRIVATE);
+ public static final LookupMode PUBLIC_NON_STATIC = new LookupMode(Constants.ACC_PUBLIC, Constants.ACC_STATIC);
+
+ private final int positives;
+ private final int negatives;
+
+ /**
+ * Creates a new element filter.
+ *
+ * @param positives The flags that need to be set
+ * @param negatives The flags that must not be set.
+ */
+ public LookupMode(int positives, int negatives) {
+ assert (positives & negatives) == 0 : "Empty mode: +" + Integer.toHexString(positives) + " and -" + Integer.toHexString(negatives);
+ this.positives = positives;
+ this.negatives = negatives;
+ }
+
+ /**
+ * Returns whether the given element is accepted by {@code this} filter. If {@code m} is
+ * {@code null}, then this method returns {@code false}.
+ */
+ public boolean include(ModifiersProvider m) {
+ if (m == null) {
+ return false;
+ }
+ int flags = m.getModifiers();
+ return hasPositives(flags) && hasNoNegatives(flags);
+ }
+
+ /**
+ * Combines this filter with another.
+ *
+ * Calling the resulting {@link #include(ModifiersProvider e)} is equivalent to
+ * {@code this.include(e) && other.include(e)}.
+ */
+ public LookupMode combine(LookupMode other) {
+ int newPositives = this.positives | other.negatives;
+ int newNegatives = this.negatives | other.negatives;
+ if (newPositives == positives && newNegatives == negatives) {
+ return this;
+ }
+ if (newPositives == other.positives && newNegatives == other.negatives) {
+ return other;
+ }
+ return new LookupMode(newPositives, newNegatives);
+ }
+
+ private boolean hasPositives(int flags) {
+ return (flags & positives) == positives;
+ }
+
+ private boolean hasNoNegatives(int flags) {
+ return (flags & negatives) == 0;
+ }
+}
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/LookupSuccessInvocationFailure.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/LookupSuccessInvocationFailure.java
new file mode 100644
index 000000000000..e1fb102a2cb9
--- /dev/null
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/LookupSuccessInvocationFailure.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2025, 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.truffle.espresso.shared.lookup;
+
+import java.io.Serial;
+
+import com.oracle.truffle.espresso.shared.meta.MethodAccess;
+
+/**
+ * Checked exception thrown by the {@link MethodLookup} helper class when method lookup succeeds,
+ * but direct invocation of the resulting method should trigger
+ * {@link IncompatibleClassChangeError}.
+ *
+ * Use of a checked exceptions should ensure that the result is not accidentally passed along or
+ * invoked without consideration.
+ */
+public final class LookupSuccessInvocationFailure extends Exception {
+ @Serial private static final long serialVersionUID = 1794882806666028197L;
+
+ LookupSuccessInvocationFailure(MethodAccess, ?, ?> m) {
+ super(null, null);
+ this.m = m;
+ }
+
+ private final transient MethodAccess, ?, ?> m;
+
+ /**
+ * Obtain the result of method lookup.
+ */
+ @SuppressWarnings("unchecked")
+ public > M getResult() {
+ return (M) m;
+ }
+
+ @SuppressWarnings("sync-override")
+ @Override
+ public Throwable fillInStackTrace() {
+ return this;
+ }
+}
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/MethodLookup.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/MethodLookup.java
new file mode 100644
index 000000000000..2d1856c12d84
--- /dev/null
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/lookup/MethodLookup.java
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2025, 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.truffle.espresso.shared.lookup;
+
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import com.oracle.truffle.espresso.classfile.ParserKlass;
+import com.oracle.truffle.espresso.classfile.descriptors.Name;
+import com.oracle.truffle.espresso.classfile.descriptors.ParserSymbols;
+import com.oracle.truffle.espresso.classfile.descriptors.Signature;
+import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
+import com.oracle.truffle.espresso.shared.meta.MethodAccess;
+import com.oracle.truffle.espresso.shared.meta.TypeAccess;
+import com.oracle.truffle.espresso.shared.resolver.CallKind;
+
+/**
+ * This class provides implementations of method lookups as defined by the Java Virtual Machine
+ * Specifications.
+ *
+ * Some of these methods may throw a checked {@link LookupSuccessInvocationFailure}. This indicates
+ * that, while lookup succeeded, the result of that lookup is not applicable for a
+ * {@link CallKind#DIRECT direct} invocation, and should fail with
+ * {@link IncompatibleClassChangeError} if ever directly invoked.
+ */
+public final class MethodLookup {
+ // region public interface
+
+ /**
+ * Lookup in the declared methods of {@code type} for a method with the specified {@code name}
+ * and {@code signature}.
+ */
+ public static , M extends MethodAccess> M lookupDeclaredMethod(C type, Symbol name, Symbol signature, LookupMode lookup) {
+ return lookupDeclaredMethodImpl(type, name, signature, lookup);
+ }
+
+ /**
+ * Lookup in the declared methods of {@code type} for a
+ * {@link MethodAccess#isDeclaredSignaturePolymorphic() signature polymorphic declared method}
+ * with the specified {@code name}.
+ */
+ public static , M extends MethodAccess> M lookupDeclaredSignaturePolymorphicMethod(C type, Symbol name, LookupMode lookup) {
+ return lookupDeclaredSignaturePolymorphicMethodImpl(type, name, lookup);
+ }
+
+ /**
+ * Performs {@code method lookup} on this class for the given method name and method signature,
+ * according to JVMS-5.4.3.3.
+ *
+ * @see TypeAccess#lookupMethod(Symbol, Symbol)
+ */
+ public static , M extends MethodAccess> M lookupMethod(C type, Symbol name, Symbol signature, LookupMode lookup)
+ throws LookupSuccessInvocationFailure {
+ return lookupMethodImpl(type, name, signature, lookup);
+ }
+
+ /**
+ * Performs {@code interface method lookup} on this class for the given method name and method
+ * signature, according to JVMS-5.4.3.4.
+ *
+ * @see TypeAccess#lookupInterfaceMethod(Symbol, Symbol)
+ */
+ public static , M extends MethodAccess> M lookupInterfaceMethod(C type, Symbol name, Symbol signature)
+ throws LookupSuccessInvocationFailure {
+ return lookupInterfaceMethodImpl(type, name, signature);
+ }
+
+ /**
+ * Returns the set {@code S} of {@code maximally-specific} methods from the given set.
+ *
+ * This means that, for every method {@code C.m} in {@code S}, there is no method from the
+ * original set {@code C'.m'} such that {@code C} is a super type of {@code C'}.
+ */
+ public static , M extends MethodAccess> Set resolveMaximallySpecific(Iterable candidates) {
+ Set currentMaxs = new HashSet<>();
+ for (M candidate : candidates) {
+ if (isLocalMax(candidate, currentMaxs)) {
+ currentMaxs.add(candidate);
+ }
+ }
+ return currentMaxs;
+ }
+
+ // endregion public interface
+
+ // region IMPL
+
+ private MethodLookup() {
+ }
+
+ private static , M extends MethodAccess> M lookupDeclaredMethodImpl(C type, Symbol name, Symbol signature, LookupMode lookup) {
+ M polymorphic = lookupDeclaredSignaturePolymorphicMethodImpl(type, name, lookup);
+ if (polymorphic != null) {
+ return polymorphic.findSignaturePolymorphicIntrinsic(signature);
+ }
+ return lookupInList(type.getDeclaredMethodsList(), name, signature, lookup);
+ }
+
+ private static , M extends MethodAccess> M lookupInDeclaredAndImplicit(C type, Symbol name, Symbol signature, LookupMode lookup) {
+ // First, try to locate method in this type's declared methods.
+ M declared = lookupDeclaredMethodImpl(type, name, signature, lookup);
+ if (declared != null) {
+ return declared;
+ }
+
+ // If the miranda methods are readily available, try to locate the method in it.
+ List mirandas = type.getImplicitInterfaceMethodsList();
+ if (mirandas != null) {
+ M inMirandas = lookupInList(mirandas, name, signature, lookup);
+ if (inMirandas != null) {
+ return inMirandas;
+ }
+ }
+ return null;
+ }
+
+ private static , M extends MethodAccess> M lookupMethodImpl(C type, Symbol name, Symbol signature, LookupMode lookup)
+ throws LookupSuccessInvocationFailure {
+ M declared = lookupInDeclaredAndImplicit(type, name, signature, lookup);
+ if (declared != null) {
+ return declared;
+ }
+
+ // Delegate to super type.
+ C current = type.getSuperClass();
+ while (current != null) {
+ M fromSuper = lookupInDeclaredAndImplicit(current, name, signature, lookup);
+ if (fromSuper != null) {
+ return fromSuper;
+ }
+ current = current.getSuperClass();
+ }
+
+ /*
+ * Note: In the case where the implicit interface methods are available for the entire super
+ * type hierarchy and the lookup is failing, this call is unnecessary.
+ *
+ * This should be fine as:
+ *
+ * - If in the hierarchy, even one type does not have its implicit interface methods
+ * available, then this class becomes necessary.
+ *
+ * - Most lookups usually succeed, and will not reach here.
+ */
+ return lookupMethodInInterfaces(type, name, signature);
+ }
+
+ private static , M extends MethodAccess> M lookupDeclaredSignaturePolymorphicMethodImpl(C type, Symbol name, LookupMode lookup) {
+ if (!ParserKlass.isSignaturePolymorphicHolderType(type.getSymbolicType())) {
+ return null;
+ }
+ for (M m : type.getDeclaredMethodsList()) {
+ if (lookup.include(m) && m.isDeclaredSignaturePolymorphic()) {
+ if (name == m.getSymbolicName()) {
+ return m;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static , M extends MethodAccess> M lookupInterfaceMethodImpl(C type, Symbol name, Symbol signature)
+ throws LookupSuccessInvocationFailure {
+ assert type.isInterface();
+ // Simple case: This class declares the requested method
+ M declaredMethod = lookupDeclaredMethod(type, name, signature, LookupMode.ALL);
+ if (declaredMethod != null) {
+ return declaredMethod;
+ }
+
+ // Look in the methods of java.lang.Object
+ C objectType = type.getSuperClass();
+ assert objectType.getSymbolicType() == ParserSymbols.ParserTypes.java_lang_Object : "An interface should always declare j.l.Object as its super class.";
+ M objectMethod = lookupDeclaredMethod(objectType, name, signature, LookupMode.PUBLIC_NON_STATIC);
+ if (objectMethod != null) {
+ return objectMethod;
+ }
+
+ // If miranda methods are immediately available, do a linear search.
+ List implicitMethods = type.getImplicitInterfaceMethodsList();
+ if (implicitMethods != null) {
+ return lookupInList(implicitMethods, name, signature, LookupMode.ALL);
+ } else {
+ return lookupMethodInInterfaces(type, name, signature);
+ }
+ }
+
+ private static , M extends MethodAccess> M lookupMethodInInterfaces(C type, Symbol name, Symbol signature)
+ throws LookupSuccessInvocationFailure {
+ // Do lookup in super interfaces
+ Set candidates = new HashSet<>();
+ for (C superInterface : getTransitiveSuperInterfaces(type)) {
+ M candidate = lookupDeclaredMethodImpl(superInterface, name, signature, LookupMode.NON_STATIC_NON_PRIVATE);
+ if (candidate != null) {
+ candidates.add(candidate);
+ }
+ }
+ if (candidates.isEmpty()) {
+ return null;
+ }
+ if (candidates.size() == 1) {
+ return candidates.iterator().next();
+ }
+
+ // Search for the maximally-specific methods
+ Set maximallySpecific = resolveMaximallySpecific(candidates);
+
+ if (maximallySpecific.size() == 1) {
+ return maximallySpecific.iterator().next();
+ }
+
+ // Search for a unique non-abstract maximally-specific method.
+ M uniqueNonAbstract = null;
+ for (M candidate : maximallySpecific) {
+ if (!candidate.isAbstract()) {
+ if (uniqueNonAbstract != null) {
+ // Not unique: chose one arbitrarily, and notify that direct invocation should
+ // fail.
+ throw new LookupSuccessInvocationFailure(candidate);
+ }
+ uniqueNonAbstract = candidate;
+ }
+ }
+ if (uniqueNonAbstract != null) {
+ return uniqueNonAbstract;
+ }
+ // Only abstract maximally-specific methods. Choose one arbitrarily.
+ M result = maximallySpecific.iterator().next();
+ assert result.isAbstract();
+ return result;
+ }
+
+ /**
+ * Compares the declaring classes of both given methods, and returns the method whose declaring
+ * class is a sub-type of the other's, or {@code null} if the declaring classes are from
+ * unrelated hierarchies.
+ */
+ private static , M extends MethodAccess> M mostSpecific(M m1, M m2) {
+ if (m2.getDeclaringClass().isAssignableFrom(m1.getDeclaringClass())) {
+ return m1;
+ }
+ if (m1.getDeclaringClass().isAssignableFrom(m2.getDeclaringClass())) {
+ return m2;
+ }
+ return null;
+ }
+
+ /**
+ * This method compares the given {@code candidate} method with each method in the
+ * {@code currentMaxs} set to determine if it is a local maximum with respect to the set of
+ * current local maximums ({@code currentMaxs}):
+ *
+ * - If it is more specific than a method in {@code currentMaxs}: that method is no longer
+ * considered a local maximum and is removed from the set.
+ * - If a method in {@code currentMaxs} is more specific than it: We can be certain the
+ * {@code candidate} will not be a local maximum, and we can early return {@code false}
+ * - Otherwise, it is a local maximum, and this method returns {@code true}
+ *
+ */
+ private static , M extends MethodAccess> boolean isLocalMax(M candidate, Set currentMaxs) {
+ Iterator maxIterator = currentMaxs.iterator();
+ while (maxIterator.hasNext()) {
+ M currentMax = maxIterator.next();
+ M mostSpecific = mostSpecific(candidate, currentMax);
+ if (mostSpecific == candidate) {
+ /* candidate's is a subtype of currentMax's: it is more specific. */
+ maxIterator.remove();
+ } else if (mostSpecific == currentMax) {
+ /*
+ * candidate's is a super-type of currentMax's: it is less specific and can be
+ * discarded.
+ */
+ return false;
+ } else {
+
+ /*
+ * If candidate and currentMax are unrelated, there is nothing to do but compare the
+ * candidate to the next current maximally-specific method.
+ */
+ assert mostSpecific == null;
+ }
+ }
+ /*
+ * No method in the currentMaxs was more specific: Our candidate is therefore a new
+ * maximally-specific method (wrt the current position in the candidates set).
+ */
+ return true;
+ }
+
+ private static > Set getTransitiveSuperInterfaces(C type) {
+ HashSet result = new HashSet<>();
+ C current = type;
+ while (current != null) {
+ for (C interfaceClass : current.getSuperInterfacesList()) {
+ collectInterfaces(interfaceClass, result);
+ }
+ current = current.getSuperClass();
+ }
+ return result;
+ }
+
+ private static > void collectInterfaces(C interfaceClass, HashSet result) {
+ if (result.add(interfaceClass)) {
+ for (C superInterface : interfaceClass.getSuperInterfacesList()) {
+ collectInterfaces(superInterface, result);
+ }
+ }
+ }
+
+ private static > M lookupInList(List methods, Symbol name, Symbol signature, LookupMode lookup) {
+ for (M m : methods) {
+ if (lookup.include(m)) {
+ if (name == m.getSymbolicName() && signature == m.getSymbolicSignature()) {
+ return m;
+ }
+ }
+ }
+ return null;
+ }
+ // endregion IMPL
+}
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/MethodAccess.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/MethodAccess.java
index 9d8ee8a0c0cf..42d799a3c058 100644
--- a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/MethodAccess.java
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/MethodAccess.java
@@ -24,7 +24,10 @@
*/
package com.oracle.truffle.espresso.shared.meta;
+import com.oracle.truffle.espresso.classfile.ClassfileParser;
+import com.oracle.truffle.espresso.classfile.Constants;
import com.oracle.truffle.espresso.classfile.ExceptionHandler;
+import com.oracle.truffle.espresso.classfile.ParserMethod;
import com.oracle.truffle.espresso.classfile.attributes.CodeAttribute;
import com.oracle.truffle.espresso.classfile.descriptors.Signature;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
@@ -79,9 +82,26 @@ default Symbol[] getParsedSymbolicSignature(SymbolPool symbolPool) {
*
* Note that this may return false for instantiations of such signature polymorphic method
* returned by {@link #createSignaturePolymorphicIntrinsic(Symbol)}.
+ *
+ * @implNote If this method was derived from the result of {@link ClassfileParser}, then this
+ * can simply be implemented by checking that the
+ * {@link Constants#ACC_SIGNATURE_POLYMORPHIC signature polymorphic} flag is set in
+ * the {@link ParserMethod#getFlags() parser flags}.
*/
boolean isDeclaredSignaturePolymorphic();
+ /**
+ * Tries to locate an instantiation of this {@linkplain #isDeclaredSignaturePolymorphic()
+ * signature polymorphic declared method} for the given {@code signature}, or creates one if not
+ * found.
+ *
+ * @implNote This method can be implemented by using the helper method
+ * {@link MethodHandleIntrinsics#findIntrinsic(MethodAccess, Symbol, RuntimeAccess)}.
+ * Doing so requires a valid implementation for
+ * {@link #createSignaturePolymorphicIntrinsic(Symbol)}
+ */
+ M findSignaturePolymorphicIntrinsic(Symbol signature);
+
/**
* Instantiates a {@linkplain #isDeclaredSignaturePolymorphic() signature polymorphic} method
* for a specific signature.
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/TypeAccess.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/TypeAccess.java
index 743ecd3969f9..19a3df598628 100644
--- a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/TypeAccess.java
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/meta/TypeAccess.java
@@ -24,12 +24,20 @@
*/
package com.oracle.truffle.espresso.shared.meta;
+import java.util.List;
+
import com.oracle.truffle.espresso.classfile.ConstantPool;
import com.oracle.truffle.espresso.classfile.descriptors.Name;
import com.oracle.truffle.espresso.classfile.descriptors.Signature;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
import com.oracle.truffle.espresso.classfile.descriptors.Type;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
+import com.oracle.truffle.espresso.shared.lookup.LookupSuccessInvocationFailure;
+import com.oracle.truffle.espresso.shared.lookup.MethodLookup;
import com.oracle.truffle.espresso.shared.resolver.LinkResolver;
+import com.oracle.truffle.espresso.shared.vtable.PartialType;
+import com.oracle.truffle.espresso.shared.vtable.Tables;
+import com.oracle.truffle.espresso.shared.vtable.VTable;
/**
* Represents a {@link Class}, and provides access to various lookups and runtime metadata.
@@ -64,6 +72,11 @@ public interface TypeAccess, M extends MethodAcces
*/
C getSuperClass();
+ /**
+ * Returns the direct super interfaces of this class.
+ */
+ List getSuperInterfacesList();
+
/**
* Returns the host class of this VM-anonymous class, or {@code null} if this class is not a
* VM-anonymous class.
@@ -99,6 +112,79 @@ public interface TypeAccess, M extends MethodAcces
*/
F lookupField(Symbol name, Symbol type);
+ /**
+ * Returns a list reflecting all the methods and constructors declared by this type.
+ */
+ List getDeclaredMethodsList();
+
+ /**
+ * Returns a list containing all the interface methods that can be called on this type, that are
+ * not declared by this type or its super types.
+ *
+ * Such methods are sometimes called {@code miranda methods}.
+ *
+ * This method may return {@code null} if obtaining these methods is not trivial.
+ *
+ * @see Tables#getImplicitInterfaceMethods()
+ * @implNote If this type's VTable was created using
+ * {@link VTable#create(PartialType, boolean, boolean, boolean)}, this method can
+ * simply return the result of {@link Tables#getImplicitInterfaceMethods()}
+ */
+ List getImplicitInterfaceMethodsList();
+
+ /**
+ * Returns the {@link MethodAccess method} appearing in this type's virtual table at index
+ * {@code vtableIndex}.
+ *
+ * If {@code vtableIndex} is not within bounds of this type's virtual table length, this method
+ * should return {@code null}.
+ */
+ M lookupVTableEntry(int vtableIndex);
+
+ /**
+ * @return {@code true} if {@code other} is a subtype of {@code this}, {@code false} otherwise.
+ */
+ boolean isAssignableFrom(C other);
+
+ /**
+ * @return {@code true} if this class represents the {@link Object} class, {@code false}
+ * otherwise.
+ */
+ default boolean isJavaLangObject() {
+ return getSuperClass() == null;
+ }
+
+ /**
+ * Whether this class extends the "magic accessor".
+ */
+ boolean isMagicAccessor();
+
+ /**
+ * The {@link ConstantPool} associated with this class.
+ */
+ ConstantPool getConstantPool();
+
+ /**
+ * Resolves a class in the runtime constant pool of this type, then returns it. Further calls to
+ * this method with the same cpi should not trigger class loading. Resolution errors should not
+ * be saved in the constant pool.
+ *
+ * @param cpi The constant pool index in which to find the class constant
+ * @throws IllegalArgumentException If there is no
+ * {@link com.oracle.truffle.espresso.classfile.ConstantPool.Tag#CLASS} in the
+ * constant pool at index {@code cpi}.
+ */
+ C resolveClassConstantInPool(int cpi);
+
+ /**
+ * If this type declares a method with the given method {@code name} and {@code signature},
+ * returns that method. Returns {@code null} otherwise.
+ */
+ @SuppressWarnings("unchecked")
+ default M lookupDeclaredMethod(Symbol name, Symbol signature) {
+ return MethodLookup.lookupDeclaredMethod((C) this, name, signature, LookupMode.ALL);
+ }
+
/**
* Performs method lookup on this class for the given method name and method signature,
* according to JVMS-5.4.3.3.
@@ -126,8 +212,8 @@ public interface TypeAccess, M extends MethodAcces
*
* - If the maximally-specific superinterface methods of {@link TypeAccess C} for the name and
* signature specified by the method reference include exactly one method that is not
- * {@link ModifiersProvider#isAbstract() abstract} , then this method is chosen and method
- * lookup succeeds.
+ * {@link ModifiersProvider#isAbstract() abstract}, then this method is chosen and method lookup
+ * succeeds.
* - Otherwise, if any superinterface of {@link TypeAccess C} declares a method with the name
* and signature specified that is neither {@link ModifiersProvider#isPrivate() private} nor
* {@link ModifiersProvider#isStatic() static}, one of these is arbitrarily chosen and method
@@ -136,17 +222,23 @@ public interface TypeAccess, M extends MethodAcces
*
*
*/
- M lookupMethod(Symbol name, Symbol signature);
+ @SuppressWarnings("unchecked")
+ default M lookupMethod(Symbol name, Symbol signature) throws LookupSuccessInvocationFailure {
+ return MethodLookup.lookupMethod((C) this, name, signature, LookupMode.ALL);
+ }
/**
* Same as {@link #lookupMethod(Symbol, Symbol)}, but ignores
* {@link ModifiersProvider#isStatic() static} methods.
*/
- M lookupInstanceMethod(Symbol name, Symbol signature);
+ @SuppressWarnings("unchecked")
+ default M lookupInstanceMethod(Symbol name, Symbol signature) throws LookupSuccessInvocationFailure {
+ return MethodLookup.lookupMethod((C) this, name, signature, LookupMode.INSTANCE_ONLY);
+ }
/**
* Performs interface method lookup on this class for the given method name and method
- * signature, according to JVMS-5.4.3.3.
+ * signature, according to JVMS-5.4.3.4.
*
*
* - This lookup does not need to throw {@link ErrorType#IncompatibleClassChangeError} if this
@@ -166,55 +258,17 @@ public interface TypeAccess, M extends MethodAcces
*
- Otherwise, method lookup fails and returns {@code null}.
*
*/
- M lookupInterfaceMethod(Symbol name, Symbol signature);
-
- /**
- * Returns the {@link MethodAccess method} appearing in this type's virtual table at index
- * {@code vtableIndex}.
- *
- * If {@code vtableIndex} is not within bounds of this type's virtual table length, this method
- * should return {@code null}.
- */
- M lookupVTableEntry(int vtableIndex);
+ @SuppressWarnings("unchecked")
+ default M lookupInterfaceMethod(Symbol name, Symbol signature) throws LookupSuccessInvocationFailure {
+ return MethodLookup.lookupInterfaceMethod((C) this, name, signature);
+ }
/**
* Attempts to find a signature polymorphic method declared in this class as described in
* JVMS-5.4.3.3 & 2.9.3. If no such method is found, returns null.
*/
- M lookupDeclaredSignaturePolymorphicMethod(Symbol name);
-
- /**
- * @return {@code true} if {@code other} is a subtype of {@code this}, {@code false} otherwise.
- */
- boolean isAssignableFrom(C other);
-
- /**
- * @return {@code true} if this class represents the {@link Object} class, {@code false}
- * otherwise.
- */
- default boolean isJavaLangObject() {
- return getSuperClass() == null;
+ @SuppressWarnings("unchecked")
+ default M lookupDeclaredSignaturePolymorphicMethod(Symbol name) {
+ return MethodLookup.lookupDeclaredSignaturePolymorphicMethod((C) this, name, LookupMode.ALL);
}
-
- /**
- * Whether this class extends the "magic accessor".
- */
- boolean isMagicAccessor();
-
- /**
- * The {@link ConstantPool} associated with this class.
- */
- ConstantPool getConstantPool();
-
- /**
- * Resolves a class in the runtime constant pool of this type, then returns it. Further calls to
- * this method with the same cpi should not trigger class loading. Resolution errors should not
- * be saved in the constant pool.
- *
- * @param cpi The constant pool index in which to find the class constant
- * @throws IllegalArgumentException If there is no
- * {@link com.oracle.truffle.espresso.classfile.ConstantPool.Tag#CLASS} in the
- * constant pool at index {@code cpi}.
- */
- C resolveClassConstantInPool(int cpi);
}
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java
index f9397d2d6832..f477ae2825bc 100644
--- a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/resolver/LinkResolver.java
@@ -28,6 +28,7 @@
import com.oracle.truffle.espresso.classfile.descriptors.Signature;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
import com.oracle.truffle.espresso.classfile.descriptors.Type;
+import com.oracle.truffle.espresso.shared.lookup.LookupSuccessInvocationFailure;
import com.oracle.truffle.espresso.shared.meta.ErrorType;
import com.oracle.truffle.espresso.shared.meta.FieldAccess;
import com.oracle.truffle.espresso.shared.meta.MethodAccess;
@@ -171,7 +172,7 @@ public static , C extends TypeAccess,
R runtime, C accessingKlass,
Symbol name, Symbol signature, C symbolicHolder,
boolean interfaceLookup,
- boolean accessCheck, boolean loadingConstraints) {
+ boolean accessCheck, boolean loadingConstraints) throws LookupSuccessInvocationFailure {
return resolveMethodSymbolImpl(runtime, accessingKlass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints, true);
}
@@ -196,9 +197,11 @@ public static , C extends TypeAccess,
R runtime, C accessingKlass,
Symbol name, Symbol signature, C symbolicHolder,
boolean interfaceLookup,
- boolean accessCheck, boolean loadingConstraints) {
+ boolean accessCheck, boolean loadingConstraints) throws LookupSuccessInvocationFailure {
try {
return resolveMethodSymbolImpl(runtime, accessingKlass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints, false);
+ } catch (LookupSuccessInvocationFailure e) {
+ throw e;
} catch (Throwable e) {
if (runtime.getErrorType(e) != null) {
throw runtime.fatal(e, "No exception was expected");
@@ -391,7 +394,7 @@ private static , C extends TypeAccess,
private static , C extends TypeAccess, M extends MethodAccess, F extends FieldAccess> M resolveMethodSymbolImpl(R runtime,
C accessingKlass, Symbol name,
Symbol signature, C symbolicHolder,
- boolean interfaceLookup, boolean accessCheck, boolean loadingConstraints, boolean throwExceptions) {
+ boolean interfaceLookup, boolean accessCheck, boolean loadingConstraints, boolean throwExceptions) throws LookupSuccessInvocationFailure {
M resolved;
if (interfaceLookup != symbolicHolder.isInterface()) {
if (throwExceptions) {
@@ -552,7 +555,18 @@ private static , C extends TypeAccess,
currentKlass.getSuperClass() != null &&
symbolicHolder != currentKlass.getSuperClass() &&
symbolicHolder.isAssignableFrom(currentKlass)) {
- resolved = currentKlass.getSuperClass().lookupInstanceMethod(resolved.getSymbolicName(), resolved.getSymbolicSignature());
+ try {
+ resolved = currentKlass.getSuperClass().lookupInstanceMethod(resolved.getSymbolicName(), resolved.getSymbolicSignature());
+ } catch (LookupSuccessInvocationFailure e) {
+ if (throwExceptions) {
+ throw runtime.throwError(ErrorType.IncompatibleClassChangeError,
+ "Unable to find a unique non-abstract maximally-specific instance method for an INVOKESPECIAL call-site: '%s.%s%s'",
+ resolved.getDeclaringClass().getJavaName(),
+ resolved.getSymbolicName(),
+ resolved.getSymbolicSignature());
+ }
+ return null;
+ }
}
}
callKind = CallKind.DIRECT;
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/verifier/MethodVerifier.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/verifier/MethodVerifier.java
index 7c3a9051d0af..6678849f9614 100644
--- a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/verifier/MethodVerifier.java
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/verifier/MethodVerifier.java
@@ -267,6 +267,7 @@
import com.oracle.truffle.espresso.classfile.descriptors.TypeSymbols;
import com.oracle.truffle.espresso.classfile.descriptors.Validation;
import com.oracle.truffle.espresso.classfile.descriptors.ValidationException;
+import com.oracle.truffle.espresso.shared.lookup.LookupSuccessInvocationFailure;
import com.oracle.truffle.espresso.shared.meta.FieldAccess;
import com.oracle.truffle.espresso.shared.meta.KnownTypes;
import com.oracle.truffle.espresso.shared.meta.MemberAccess;
@@ -2188,7 +2189,6 @@ private boolean checkHostAccess(Operand methodHolder) {
}
// Helper methods
-
private void checkProtectedMember(Operand stackOp, Symbol holderType, int memberIndex, boolean method) {
/*
* 4.10.1.8.
@@ -2214,7 +2214,12 @@ private void checkProtectedMember(Operand stackOp, Symbol hold
/* Non-failing method lookup. */
Symbol name = pool.methodName(memberIndex);
Symbol methodSignature = pool.methodSignature(memberIndex);
- member = holderOp.getKlass(this).lookupMethod(name, methodSignature);
+ try {
+ member = holderOp.getKlass(this).lookupMethod(name, methodSignature);
+ } catch (LookupSuccessInvocationFailure e) {
+ // We are not planning to invoke, so we can safely ignore that hint.
+ member = e. getResult();
+ }
} else {
/* Non-failing field lookup. */
Symbol fieldName = pool.fieldName(memberIndex);
diff --git a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/vtable/VTable.java b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/vtable/VTable.java
index cd95b89572be..79f0bd4c7d33 100644
--- a/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/vtable/VTable.java
+++ b/espresso-shared/src/com.oracle.truffle.espresso.shared/src/com/oracle/truffle/espresso/shared/vtable/VTable.java
@@ -24,19 +24,20 @@
*/
package com.oracle.truffle.espresso.shared.vtable;
+import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
import java.util.List;
+import java.util.Set;
import org.graalvm.collections.EconomicMap;
-import org.graalvm.collections.EconomicSet;
import org.graalvm.collections.Equivalence;
import org.graalvm.collections.MapCursor;
import com.oracle.truffle.espresso.classfile.descriptors.Name;
import com.oracle.truffle.espresso.classfile.descriptors.Signature;
import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
+import com.oracle.truffle.espresso.shared.lookup.MethodLookup;
import com.oracle.truffle.espresso.shared.meta.FieldAccess;
import com.oracle.truffle.espresso.shared.meta.MethodAccess;
import com.oracle.truffle.espresso.shared.meta.TypeAccess;
@@ -412,32 +413,19 @@ private PartialMethod resolveImpl(MethodKey k, Builder b, bool
private PartialMethod resolveConcrete() {
M candidate = null;
for (Location loc : vLocations) {
- candidate = mostSpecific(loc.value, candidate, true);
+ if (candidate == null) {
+ candidate = loc.value;
+ } else {
+ // Here, the classes are known to be from the same hierarchy, so a single
+ // type check is needed.
+ candidate = loc.value.getDeclaringClass().isAssignableFrom(candidate.getDeclaringClass()) ? candidate : loc.value;
+ }
}
return candidate;
}
private PartialMethod resolveMaximallySpecific() {
- EconomicSet maximallySpecific = EconomicSet.create(Equivalence.IDENTITY);
- locationLoop: //
- for (Location loc : iLocations) {
- Iterator iter = maximallySpecific.iterator();
- while (iter.hasNext()) {
- M next = iter.next();
- M mostSpecific = mostSpecific(loc.value, next, false);
- if (mostSpecific == next) {
- // An existing declaring class was already more specific.
- continue locationLoop;
- } else if (mostSpecific == loc.value) {
- // The current declaring class is more specific: replace.
- iter.remove();
- } else {
- assert mostSpecific == null;
- // The declaring classes are unrelated
- }
- }
- maximallySpecific.add(loc.value);
- }
+ Set maximallySpecific = MethodLookup.resolveMaximallySpecific(new IMethodsList());
M nonAbstractMaximallySpecific = null;
for (M m : maximallySpecific) {
if (!m.isAbstract()) {
@@ -463,24 +451,6 @@ private PartialMethod resolveMaximallySpecific() {
return maximallySpecific.iterator().next();
}
- private M mostSpecific(M m1, M m2, boolean totalOrder) {
- assert m1 != null;
- if (m2 == null) {
- return m1;
- }
- if (m2.getDeclaringClass().isAssignableFrom(m1.getDeclaringClass())) {
- return m1;
- }
- if (totalOrder) {
- assert m1.getDeclaringClass().isAssignableFrom(m2.getDeclaringClass());
- return m2;
- }
- if (m1.getDeclaringClass().isAssignableFrom(m2.getDeclaringClass())) {
- return m2;
- }
- return null;
- }
-
private class Location implements Comparable {
private final M value;
private final int index;
@@ -495,6 +465,18 @@ public int compareTo(Location o) {
return Integer.compare(this.index, o.index);
}
}
+
+ private final class IMethodsList extends AbstractList {
+ @Override
+ public M get(int index) {
+ return iLocations.get(index).value;
+ }
+
+ @Override
+ public int size() {
+ return iLocations.size();
+ }
+ }
}
private enum LocationKind {
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/cds/Writer.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/cds/Writer.java
index b6e595fbdd04..087338f056b1 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/cds/Writer.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/cds/Writer.java
@@ -43,7 +43,6 @@
import com.oracle.truffle.espresso.impl.ClassRegistry;
import com.oracle.truffle.espresso.impl.Field;
import com.oracle.truffle.espresso.impl.Klass;
-import com.oracle.truffle.espresso.impl.Klass.LookupMode;
import com.oracle.truffle.espresso.impl.Method;
import com.oracle.truffle.espresso.impl.ModuleTable;
import com.oracle.truffle.espresso.impl.PackageTable;
@@ -52,6 +51,7 @@
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.OS;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.vm.InterpreterToVM;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java
index c9bd500968aa..9a235a634642 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ArrayKlass.java
@@ -130,9 +130,9 @@ public Field[] getDeclaredFields() {
}
@Override
- public Method lookupMethod(Symbol methodName, Symbol signature, LookupMode mode) {
+ public Method lookupMethod(Symbol methodName, Symbol signature) {
KLASS_LOOKUP_METHOD_COUNT.inc();
- return getSuperKlass().lookupMethod(methodName, signature, mode);
+ return getSuperKlass().lookupMethod(methodName, signature);
}
@Override
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EspressoMethodTableBuilder.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EspressoMethodTableBuilder.java
index b23695a5cd36..fa74676cc48e 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EspressoMethodTableBuilder.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/EspressoMethodTableBuilder.java
@@ -189,7 +189,7 @@ private static Method.MethodVersion[] toEspressoVTable(List extends PartialMet
// Poison pill handling is done in Miranda translation.
if (m.isSelectionFailure()) {
assert entry.isProxy();
- entry.setPoisonPill();
+ entry = entry.forFailing();
}
vtable[vtableIndex] = entry.getMethodVersion();
vtableIndex++;
@@ -220,7 +220,7 @@ private static Method.MethodVersion[] toEspressoITable(List extends PartialMet
for (PartialMethod m : table) {
Method entry = m.asMethodAccess();
if (m.isSelectionFailure()) {
- entry = new Method(entry).setPoisonPill();
+ entry = entry.forFailing();
}
itable[itableIndex] = entry.getMethodVersion();
itableIndex++;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java
index fc934f7681eb..bd2a83288ef2 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Klass.java
@@ -26,7 +26,10 @@
import static com.oracle.truffle.espresso.vm.InterpreterToVM.instanceOf;
import java.lang.reflect.Modifier;
+import java.util.Arrays;
+import java.util.Collections;
import java.util.Comparator;
+import java.util.List;
import java.util.function.IntFunction;
import org.graalvm.collections.EconomicSet;
@@ -103,7 +106,8 @@
import com.oracle.truffle.espresso.runtime.dispatch.staticobject.InteropLookupAndInvoke;
import com.oracle.truffle.espresso.runtime.dispatch.staticobject.InteropLookupAndInvokeFactory;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
-import com.oracle.truffle.espresso.shared.meta.SignaturePolymorphicIntrinsic;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
+import com.oracle.truffle.espresso.shared.lookup.LookupSuccessInvocationFailure;
import com.oracle.truffle.espresso.shared.meta.TypeAccess;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.vm.InterpreterToVM;
@@ -1366,30 +1370,6 @@ public StaticObject allocateReferenceArray(int length, IntFunction
// region Lookup
- public enum LookupMode {
- ALL(true, true),
- INSTANCE_ONLY(true, false),
- STATIC_ONLY(false, true);
-
- private final boolean instances;
- private final boolean statics;
-
- LookupMode(boolean instances, boolean statics) {
- this.instances = instances;
- this.statics = statics;
- }
-
- public boolean include(Member> m) {
- if (m == null) {
- return false;
- }
- if (statics && m.isStatic()) {
- return true;
- }
- return instances && !m.isStatic();
- }
- }
-
public final Field requireDeclaredField(Symbol fieldName, Symbol fieldType) {
Field obj = lookupDeclaredField(fieldName, fieldType);
if (obj == null) {
@@ -1487,20 +1467,10 @@ public final Method requireDeclaredMethod(Symbol methodName, Symbol methodName, Symbol signature) {
- return lookupDeclaredMethod(methodName, signature, LookupMode.ALL);
- }
-
- @ExplodeLoop
public final Method lookupDeclaredMethod(Symbol methodName, Symbol signature, LookupMode lookupMode) {
- KLASS_LOOKUP_DECLARED_METHOD_COUNT.inc();
- // TODO(peterssen): Improve lookup performance.
- for (Method method : getDeclaredMethods()) {
- if (lookupMode.include(method)) {
- if (methodName.equals(method.getName()) && signature.equals(method.getRawSignature())) {
- return method;
- }
- }
+ Method result = lookupDeclaredMethod(methodName, signature);
+ if (lookupMode.include(result)) {
+ return result;
}
return null;
}
@@ -1555,17 +1525,6 @@ protected static int fastLookupImpl(Klass target, ObjectKlass.KlassVersion[] kla
return -1; // not found
}
- /**
- * Give the accessing klass if there is a chance the method to be resolved is a method handle
- * intrinsics.
- */
- public abstract Method lookupMethod(Symbol methodName, Symbol signature, LookupMode lookupMode);
-
- @Override
- public final Method lookupMethod(Symbol methodName, Symbol signature) {
- return lookupMethod(methodName, signature, LookupMode.ALL);
- }
-
public final Method vtableLookup(int vtableIndex) {
if (this instanceof ObjectKlass) {
return ((ObjectKlass) this).vtableLookupImpl(vtableIndex);
@@ -1578,41 +1537,6 @@ public final Method vtableLookup(int vtableIndex) {
return null;
}
- public Method lookupSignaturePolymorphicMethod(Symbol methodName, Symbol signature, LookupMode lookupMode) {
- Method m = lookupSignaturePolymorphicDeclaredMethod(methodName, lookupMode);
- if (m != null) {
- return findMethodHandleIntrinsic(m, signature);
- }
- return null;
- }
-
- public Method lookupSignaturePolymorphicDeclaredMethod(Symbol methodName, LookupMode lookupMode) {
- for (Method m : getDeclaredMethods()) {
- if (lookupMode.include(m)) {
- if (m.getName() == methodName && m.isDeclaredSignaturePolymorphic()) {
- return m;
- }
- }
- }
- return null;
- }
-
- @Override
- public Method lookupDeclaredSignaturePolymorphicMethod(Symbol methodName) {
- return lookupSignaturePolymorphicDeclaredMethod(methodName, LookupMode.ALL);
- }
-
- @TruffleBoundary
- private Method findMethodHandleIntrinsic(Method m, Symbol signature) {
- assert m.isDeclaredSignaturePolymorphic();
- SignaturePolymorphicIntrinsic iid = SignaturePolymorphicIntrinsic.getId(m);
- Symbol sig = signature;
- if (iid.isStaticSignaturePolymorphic()) {
- sig = getSignatures().toBasic(signature, true);
- }
- return m.findIntrinsic(sig);
- }
-
/**
* Returns the access flags provided by the .class file, e.g. ignores inner class access flags.
*/
@@ -1884,16 +1808,70 @@ public final Klass getSuperClass() {
}
@Override
- public final Method lookupInterfaceMethod(Symbol methodName, Symbol methodSignature) {
+ public List getSuperInterfacesList() {
+ return Arrays.asList(getSuperInterfaces());
+ }
+
+ @Override
+ public List getDeclaredMethodsList() {
+ return Method.versionsToMethodList(this.getDeclaredMethodVersions());
+ }
+
+ @Override
+ public List getImplicitInterfaceMethodsList() {
+ if (isInterface()) {
+ return null;
+ }
if (this instanceof ObjectKlass) {
- return ((ObjectKlass) this).resolveInterfaceMethod(methodName, methodSignature);
+ return Method.versionsToMethodList(((ObjectKlass) this).getMirandaMethods());
}
- return null;
+ return Collections.emptyList();
+ }
+
+ @TruffleBoundary
+ public final Method lookupDeclaredMethod(Symbol methodName, Symbol signature) {
+ KLASS_LOOKUP_DECLARED_METHOD_COUNT.inc();
+ return TypeAccess.super.lookupDeclaredMethod(methodName, signature);
}
@Override
+ @TruffleBoundary
+ public Method lookupDeclaredSignaturePolymorphicMethod(Symbol methodName) {
+ KLASS_LOOKUP_DECLARED_METHOD_COUNT.inc();
+ return TypeAccess.super.lookupDeclaredSignaturePolymorphicMethod(methodName);
+ }
+
+ @Override
+ @TruffleBoundary
+ public Method lookupMethod(Symbol methodName, Symbol signature) {
+ try {
+ KLASS_LOOKUP_METHOD_COUNT.inc();
+ return TypeAccess.super.lookupMethod(methodName, signature);
+ } catch (LookupSuccessInvocationFailure e) {
+ return e. getResult().forFailing();
+ }
+ }
+
+ @Override
+ @TruffleBoundary
public final Method lookupInstanceMethod(Symbol methodName, Symbol methodSignature) {
- return lookupMethod(methodName, methodSignature, LookupMode.INSTANCE_ONLY);
+ try {
+ KLASS_LOOKUP_METHOD_COUNT.inc();
+ return TypeAccess.super.lookupInstanceMethod(methodName, methodSignature);
+ } catch (LookupSuccessInvocationFailure e) {
+ return e. getResult().forFailing();
+ }
+ }
+
+ @Override
+ @TruffleBoundary
+ public final Method lookupInterfaceMethod(Symbol methodName, Symbol methodSignature) {
+ try {
+ KLASS_LOOKUP_METHOD_COUNT.inc();
+ return TypeAccess.super.lookupInterfaceMethod(methodName, methodSignature);
+ } catch (LookupSuccessInvocationFailure e) {
+ return e. getResult().forFailing();
+ }
}
@Override
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java
index d24a13026af2..815ba663b80f 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/Method.java
@@ -54,8 +54,10 @@
import java.io.PrintStream;
import java.lang.invoke.VarHandle;
import java.lang.reflect.Modifier;
+import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
@@ -135,6 +137,7 @@
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.EspressoException;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
import com.oracle.truffle.espresso.shared.meta.ErrorType;
import com.oracle.truffle.espresso.shared.meta.MethodAccess;
import com.oracle.truffle.espresso.shared.meta.ModifiersProvider;
@@ -228,6 +231,23 @@ private Method(Method method, CodeAttribute split) {
this.isLeaf = getContext().getClassHierarchyOracle().createLeafAssumptionForNewMethod(this);
}
+ public static List versionsToMethodList(Method.MethodVersion[] versions) {
+ if (versions == null) {
+ return Collections.emptyList();
+ }
+ return new AbstractList<>() {
+ @Override
+ public Method get(int index) {
+ return versions[index].getMethod();
+ }
+
+ @Override
+ public int size() {
+ return versions.length;
+ }
+ };
+ }
+
public Method identity() {
return proxy;
}
@@ -753,7 +773,7 @@ public static Method getHostReflectiveConstructorRoot(StaticObject seed, Meta me
Klass holder = meta.java_lang_reflect_Constructor_clazz.getObject(rootMethod).getMirrorKlass(meta);
Symbol signature = rebuildConstructorSignature(meta, rootMethod);
assert signature != null;
- Method method = holder.lookupDeclaredMethod(Names._init_, signature, Klass.LookupMode.INSTANCE_ONLY);
+ Method method = holder.lookupDeclaredMethod(Names._init_, signature, LookupMode.INSTANCE_ONLY);
assert method != null;
// remember the mapping for the next query
meta.HIDDEN_CONSTRUCTOR_KEY.setHiddenObject(rootMethod, method);
@@ -791,23 +811,10 @@ public static ByteSequence getSignatureFromGuestDescription(@JavaType(Class[].cl
// Polymorphic signature method 'creation'
- Method findIntrinsic(Symbol signature) {
- return getContext().getMethodHandleIntrinsics().findIntrinsic(this, signature, getContext());
- }
-
- @Override
- public boolean isDeclaredSignaturePolymorphic() {
- return (getModifiers() & ACC_SIGNATURE_POLYMORPHIC) != 0;
- }
-
public int getVTableIndex() {
return getMethodVersion().getVTableIndex();
}
- void setITableIndex(int i) {
- getMethodVersion().setITableIndex(i);
- }
-
public int getITableIndex() {
return getMethodVersion().getITableIndex();
}
@@ -820,9 +827,19 @@ public boolean isVirtualCall() {
return !isStatic() && !isConstructor() && !isPrivate() && !getDeclaringKlass().isInterface();
}
- public Method setPoisonPill() {
- getMethodVersion().setPoisonPill();
- return this;
+ public Method forFailing() {
+ if (isProxy()) {
+ getMethodVersion().setPoisonPill();
+ return this;
+ }
+ Method m = new Method(this);
+ m.getMethodVersion().setPoisonPill();
+ if (this.hasVTableIndex()) {
+ m.getMethodVersion().setVTableIndex(this.getVTableIndex());
+ } else {
+ m.getMethodVersion().setITableIndex(this.getITableIndex());
+ }
+ return m;
}
public String report(int curBCI) {
@@ -1179,45 +1196,6 @@ public StaticObject apply(int j) {
return instance;
}
- /**
- * Returns the maximally specific method between the two given methods. If they are both
- * maximally-specific, returns a proxy of the second, to which a poison pill has been set.
- *
- * Determining maximally specific method works as follow:
- *
If both methods are abstract, return any of the two.
- * If exactly one is non-abstract, return it.
- * If both are non-abstract, check if one of the declaring class subclasses the other. If
- * that is the case, return the method that is lower in the hierarchy. Otherwise, return a
- * freshly spawned proxy method pointing to either of them, which is set to fail on invocation.
- */
- public static MethodVersion resolveMaximallySpecific(Method m1, Method m2) {
- ObjectKlass k1 = m1.getDeclaringKlass();
- ObjectKlass k2 = m2.getDeclaringKlass();
- if (k1.isAssignableFrom(k2)) {
- return m2.getMethodVersion();
- } else if (k2.isAssignableFrom(k1)) {
- return m1.getMethodVersion();
- } else {
- boolean b1 = m1.isAbstract();
- boolean b2 = m2.isAbstract();
- if (b1 && b2) {
- return m1.getMethodVersion();
- }
- if (b1) {
- return m2.getMethodVersion();
- }
- if (b2) {
- return m1.getMethodVersion();
- }
- // JVM specs:
- // Can *declare* ambiguous default method (in bytecodes only, javac wouldn't compile
- // it). (5.4.3.3.)
- //
- // But if you try to *use* them, specs dictate to fail. (6.5.invoke{virtual,interface})
- return new Method(m2).setPoisonPill().getMethodVersion();
- }
- }
-
// region MethodAccess impl
@Override
@@ -1237,6 +1215,11 @@ public boolean isAbstract() {
return super.isAbstract();
}
+ @Override
+ public boolean isDeclaredSignaturePolymorphic() {
+ return ((rawFlags & ACC_SIGNATURE_POLYMORPHIC)) != 0;
+ }
+
@Override
public boolean shouldSkipLoadingConstraints() {
return isPolySignatureIntrinsic();
@@ -1274,6 +1257,12 @@ public boolean hasPoisonPill() {
return getMethodVersion().poisonPill;
}
+ @Override
+ @TruffleBoundary
+ public Method findSignaturePolymorphicIntrinsic(Symbol signature) {
+ return getContext().getMethodHandleIntrinsics().findIntrinsic(this, signature, getContext());
+ }
+
// endregion MethodAccess impl
// region MethodRef impl
@@ -1766,9 +1755,8 @@ public int getITableIndex() {
return itableIndex;
}
- public Method.MethodVersion setPoisonPill() {
+ private void setPoisonPill() {
poisonPill = true;
- return this;
}
public ExceptionHandler[] getExceptionHandlers() {
@@ -1901,7 +1889,7 @@ private CallTarget findCallTarget() {
* The method was obtained through a regular lookup (since it is in the declared
* methods). Delegate it to a polysignature method lookup.
*/
- target = declaringKlass.lookupSignaturePolymorphicMethod(getName(), getRawSignature(), Klass.LookupMode.ALL).getCallTarget();
+ target = getMethod().findSignaturePolymorphicIntrinsic(getRawSignature()).getCallTarget();
}
if (target == null) {
@@ -1928,7 +1916,7 @@ private CallTarget lookupWithNativePrefixes() {
}
// before using the prefix-stripped method name, make sure we have a
// non-native wrapper method, if not we can't link
- Method wrapperMethod = getDeclaringKlass().lookupDeclaredMethod(resolvedName, getRawSignature(), isStatic() ? Klass.LookupMode.STATIC_ONLY : Klass.LookupMode.INSTANCE_ONLY);
+ Method wrapperMethod = getDeclaringKlass().lookupDeclaredMethod(resolvedName, getRawSignature(), isStatic() ? LookupMode.STATIC_ONLY : LookupMode.INSTANCE_ONLY);
if (wrapperMethod == null || wrapperMethod.isNative()) {
return null;
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java
index fe88147d0a3a..d162e7b11352 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/ObjectKlass.java
@@ -25,7 +25,6 @@
import static com.oracle.truffle.espresso.classfile.Constants.ACC_FINALIZER;
import static com.oracle.truffle.espresso.classfile.Constants.ACC_SUPER;
import static com.oracle.truffle.espresso.classfile.Constants.JVM_ACC_WRITTEN_FLAGS;
-import static com.oracle.truffle.espresso.classfile.ParserKlass.isSignaturePolymorphicHolderType;
import java.io.PrintStream;
import java.lang.ref.WeakReference;
@@ -83,7 +82,6 @@
import com.oracle.truffle.espresso.classfile.descriptors.TypeSymbols;
import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool;
import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Names;
-import com.oracle.truffle.espresso.descriptors.EspressoSymbols.Types;
import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry;
import com.oracle.truffle.espresso.impl.PackageTable.PackageEntry;
import com.oracle.truffle.espresso.meta.EspressoError;
@@ -1097,100 +1095,6 @@ int findVirtualMethodIndex(Symbol methodName, Symbol signature,
return -1;
}
- @TruffleBoundary
- public Method resolveInterfaceMethod(Symbol methodName, Symbol signature) {
- assert isInterface();
- /*
- * 2. Otherwise, if C declares a method with the name and descriptor specified by the
- * interface method reference, method lookup succeeds.
- */
- for (Method m : getDeclaredMethods()) {
- if (methodName == m.getName() && signature == m.getRawSignature()) {
- return m;
- }
- }
- /*
- * 3. Otherwise, if the class Object declares a method with the name and descriptor
- * specified by the interface method reference, which has its ACC_PUBLIC flag set and does
- * not have its ACC_STATIC flag set, method lookup succeeds.
- */
- assert getSuperKlass().getType() == Types.java_lang_Object;
- Method m = getSuperKlass().lookupDeclaredMethod(methodName, signature);
- if (m != null && m.isPublic() && !m.isStatic()) {
- return m;
- }
-
- Method resolved = null;
- /*
- * Interfaces are sorted, superinterfaces first; traverse in reverse order to get
- * maximally-specific first.
- */
- for (int i = getiKlassTable().length - 1; i >= 0; i--) {
- ObjectKlass superInterf = getiKlassTable()[i].getKlass();
- for (Method.MethodVersion superMVersion : superInterf.getInterfaceMethodsTable()) {
- Method superM = superMVersion.getMethod();
- /*
- * Methods in superInterf.getInterfaceMethodsTable() are all non-static non-private
- * methods declared in superInterf.
- */
- if (methodName == superM.getName() && signature == superM.getRawSignature()) {
- if (resolved == null) {
- resolved = superM;
- } else {
- /*
- * 4. Otherwise, if the maximally-specific superinterface methods
- * (§5.4.3.3) of C for the name and descriptor specified by the method
- * reference include exactly one method that does not have its ACC_ABSTRACT
- * flag set, then this method is chosen and method lookup succeeds.
- *
- * 5. Otherwise, if any superinterface of C declares a method with the name
- * and descriptor specified by the method reference that has neither its
- * ACC_PRIVATE flag nor its ACC_STATIC flag set, one of these is arbitrarily
- * chosen and method lookup succeeds.
- */
- resolved = Method.resolveMaximallySpecific(resolved, superM).getMethod();
- if (resolved.getITableIndex() == -1) {
- /*
- * Multiple maximally specific: this method has a poison pill.
- *
- * NOTE: Since java 9, we can invokespecial interface methods (ie: a
- * call directly to the resolved method, rather than after an interface
- * lookup). We are looking up a method taken from the implemented
- * interface (and not from a currently non-existing itable of the
- * implementing interface). This difference, and the possibility of
- * invokespecial, means that we cannot return the looked up method
- * directly in case of multiple maximally specific method. thus, we
- * spawn a new proxy method, attached to no method table, just to fail
- * if invokespecial.
- */
- assert (resolved.identity() == superM.identity());
- resolved.setITableIndex(superM.getITableIndex());
- }
- }
- }
- }
- }
- return resolved;
- }
-
- @Override
- public Method lookupMethod(Symbol methodName, Symbol signature, LookupMode lookupMode) {
- KLASS_LOOKUP_METHOD_COUNT.inc();
- Method method = lookupDeclaredMethod(methodName, signature, lookupMode);
- if (method == null) {
- // Implicit interface methods.
- method = lookupMirandas(methodName, signature);
- }
- if (method == null && isSignaturePolymorphicHolderType(getType())) {
- method = lookupSignaturePolymorphicMethod(methodName, signature, lookupMode);
- }
- if (method == null && getSuperKlass() != null) {
- CompilerAsserts.partialEvaluationConstant(this);
- method = getSuperKlass().lookupMethod(methodName, signature, lookupMode);
- }
- return method;
- }
-
public Field[] getFieldTable() {
if (!getContext().advancedRedefinitionEnabled()) {
return fieldTable;
@@ -1235,19 +1139,6 @@ public Field[] getStaticFieldTable() {
}
}
- private Method lookupMirandas(Symbol methodName, Symbol signature) {
- if (getMirandaMethods() == null) {
- return null;
- }
- for (Method.MethodVersion miranda : getMirandaMethods()) {
- Method method = miranda.getMethod();
- if (method.getName() == methodName && method.getRawSignature() == signature) {
- return method;
- }
- }
- return null;
- }
-
void print(PrintStream out) {
out.println(getType());
for (Method m : getDeclaredMethods()) {
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java
index 9f4e35fcd254..6ffa0c7aad10 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/impl/PrimitiveKlass.java
@@ -26,9 +26,6 @@
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.espresso.classfile.JavaKind;
-import com.oracle.truffle.espresso.classfile.descriptors.Name;
-import com.oracle.truffle.espresso.classfile.descriptors.Signature;
-import com.oracle.truffle.espresso.classfile.descriptors.Symbol;
import com.oracle.truffle.espresso.constantpool.RuntimeConstantPool;
import com.oracle.truffle.espresso.impl.ModuleTable.ModuleEntry;
import com.oracle.truffle.espresso.impl.ObjectKlass.KlassVersion;
@@ -108,11 +105,6 @@ public Method.MethodVersion[] getDeclaredMethodVersions() {
return Method.EMPTY_VERSION_ARRAY;
}
- @Override
- public Method lookupMethod(Symbol methodName, Symbol signature, LookupMode lookupMode) {
- return null;
- }
-
@Override
public Field[] getDeclaredFields() {
return Field.EMPTY_ARRAY;
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java
index 58d612671c5b..3e38dcac05d2 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/jni/JniEnv.java
@@ -111,6 +111,7 @@
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.EspressoException;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
import com.oracle.truffle.espresso.substitutions.CallableFromNative;
import com.oracle.truffle.espresso.substitutions.GenerateNativeEnv;
import com.oracle.truffle.espresso.substitutions.Inject;
@@ -448,7 +449,7 @@ private WeakHandles methodIds() {
if (fieldType != null) {
// Lookup only if name and type are known symbols.
klass.safeInitialize();
- field = klass.lookupField(fieldName, fieldType, Klass.LookupMode.INSTANCE_ONLY);
+ field = klass.lookupField(fieldName, fieldType, LookupMode.INSTANCE_ONLY);
assert field == null || field.getType().equals(fieldType);
}
}
@@ -492,7 +493,7 @@ private WeakHandles methodIds() {
Klass klass = clazz.getMirrorKlass(getMeta());
klass.safeInitialize();
// Lookup only if name and type are known symbols.
- field = klass.lookupField(fieldName, fieldType, Klass.LookupMode.STATIC_ONLY);
+ field = klass.lookupField(fieldName, fieldType, LookupMode.STATIC_ONLY);
assert field == null || field.getType().equals(fieldType);
}
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
index 9c791ca429bc..01df9528ded8 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/BytecodeNode.java
@@ -2321,6 +2321,7 @@ public BaseQuickNode generifyInlinedMethodNode(int top, int opcode, int curBCI,
resolvedInvoke = getResolvedInvoke(opcode, readOriginalCPI(curBCI));
} else {
assert !resolvedCall.getResolvedMethod().isInvokeIntrinsic() : "An inlined method may never be an invokeGeneric.";
+ assert resolvedCall.getCallKind() != CallKind.ITABLE_LOOKUP : "A bytecode-inlined method may not be from an interface dispatch.";
resolvedInvoke = new ResolvedInvoke(resolvedCall, null);
}
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java
index 18c4ab3352f7..f5e33da20593 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/commands/ReferenceProcessCache.java
@@ -39,6 +39,7 @@
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.EspressoException;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
import com.oracle.truffle.espresso.threads.ThreadState;
import com.oracle.truffle.espresso.threads.Transition;
@@ -135,7 +136,7 @@ private static Klass findSharedSecrets(EspressoContext context) {
private static Field findJlaField(Klass sharedSecrets) {
for (Symbol type : JAVA_LANG_ACCESS_TYPES) {
- Field f = sharedSecrets.lookupField(Names.javaLangAccess, type, Klass.LookupMode.STATIC_ONLY);
+ Field f = sharedSecrets.lookupField(Names.javaLangAccess, type, LookupMode.STATIC_ONLY);
if (f != null) {
return f;
}
@@ -145,7 +146,7 @@ private static Field findJlaField(Klass sharedSecrets) {
private static Method findRunFinalizer(EspressoContext context) {
for (Symbol signature : RUN_FINALIZER_SIGNATURES) {
- Method m = context.getMeta().java_lang_ref_Finalizer.lookupMethod(Names.runFinalizer, signature, Klass.LookupMode.INSTANCE_ONLY);
+ Method m = context.getMeta().java_lang_ref_Finalizer.lookupMethod(Names.runFinalizer, signature);
if (m != null) {
return m;
}
@@ -157,9 +158,9 @@ private static Method findProcessPendingReferences(EspressoContext context) {
Method processPendingReferenceMethod;
if (context.getJavaVersion().java8OrEarlier()) {
processPendingReferenceMethod = context.getMeta().java_lang_ref_Reference.lookupDeclaredMethod(Names.tryHandlePending, Signatures._boolean_boolean,
- Klass.LookupMode.STATIC_ONLY);
+ LookupMode.STATIC_ONLY);
} else {
- processPendingReferenceMethod = context.getMeta().java_lang_ref_Reference.lookupDeclaredMethod(Names.processPendingReferences, Signatures._void, Klass.LookupMode.STATIC_ONLY);
+ processPendingReferenceMethod = context.getMeta().java_lang_ref_Reference.lookupDeclaredMethod(Names.processPendingReferences, Signatures._void, LookupMode.STATIC_ONLY);
}
if (processPendingReferenceMethod == null) {
throw EspressoError.shouldNotReachHere("Could not find pending reference processing method.");
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java
index ee606dea2413..c2dbfc470c99 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/nodes/interop/PolyglotTypeMappings.java
@@ -55,6 +55,7 @@
import com.oracle.truffle.espresso.meta.Meta;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
import com.oracle.truffle.espresso.threads.ThreadState;
import com.oracle.truffle.espresso.threads.Transition;
import com.oracle.truffle.espresso.vm.VM;
@@ -440,7 +441,7 @@ public static final class BuiltinExceptionTypeConverter implements InternalTypeC
public BuiltinExceptionTypeConverter(ObjectKlass klass) {
this.exceptionKlass = klass;
- this.messageConstructor = klass.lookupDeclaredMethod(Names._init_, Signatures._void_String, Klass.LookupMode.INSTANCE_ONLY);
+ this.messageConstructor = klass.lookupDeclaredMethod(Names._init_, Signatures._void_String, LookupMode.INSTANCE_ONLY);
}
@Override
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoLinkResolver.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoLinkResolver.java
index ff4d987c341c..1ce1be165bca 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoLinkResolver.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/runtime/EspressoLinkResolver.java
@@ -29,6 +29,7 @@
import com.oracle.truffle.espresso.impl.Field;
import com.oracle.truffle.espresso.impl.Klass;
import com.oracle.truffle.espresso.impl.Method;
+import com.oracle.truffle.espresso.shared.lookup.LookupSuccessInvocationFailure;
import com.oracle.truffle.espresso.shared.resolver.CallSiteType;
import com.oracle.truffle.espresso.shared.resolver.FieldAccessType;
import com.oracle.truffle.espresso.shared.resolver.LinkResolver;
@@ -63,14 +64,22 @@ public static Method resolveMethodSymbol(EspressoContext ctx, Klass accessingKla
Symbol name, Symbol signature, Klass symbolicHolder,
boolean interfaceLookup,
boolean accessCheck, boolean loadingConstraints) {
- return LinkResolver.resolveMethodSymbol(ctx, accessingKlass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ try {
+ return LinkResolver.resolveMethodSymbol(ctx, accessingKlass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ } catch (LookupSuccessInvocationFailure e) {
+ return e. getResult().forFailing();
+ }
}
public static Method resolveMethodSymbolOrNull(EspressoContext ctx, Klass accessingKlass,
Symbol name, Symbol signature, Klass symbolicHolder,
boolean interfaceLookup,
boolean accessCheck, boolean loadingConstraints) {
- return LinkResolver.resolveMethodSymbolOrNull(ctx, accessingKlass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ try {
+ return LinkResolver.resolveMethodSymbolOrNull(ctx, accessingKlass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ } catch (LookupSuccessInvocationFailure e) {
+ return e. getResult().forFailing();
+ }
}
public static ResolvedCall resolveCallSiteOrThrow(EspressoContext ctx, Klass currentKlass, Method symbolicResolution, CallSiteType callSiteType, Klass symbolicHolder) {
diff --git a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/polyglot/Target_com_oracle_truffle_espresso_polyglot_TypeLiteral.java b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/polyglot/Target_com_oracle_truffle_espresso_polyglot_TypeLiteral.java
index af10c006f10a..a124439b5102 100644
--- a/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/polyglot/Target_com_oracle_truffle_espresso_polyglot_TypeLiteral.java
+++ b/espresso/src/com.oracle.truffle.espresso/src/com/oracle/truffle/espresso/substitutions/polyglot/Target_com_oracle_truffle_espresso_polyglot_TypeLiteral.java
@@ -39,6 +39,7 @@
import com.oracle.truffle.espresso.nodes.interop.GetTypeLiteralNode;
import com.oracle.truffle.espresso.runtime.EspressoContext;
import com.oracle.truffle.espresso.runtime.staticobject.StaticObject;
+import com.oracle.truffle.espresso.shared.lookup.LookupMode;
import com.oracle.truffle.espresso.substitutions.EspressoSubstitutions;
import com.oracle.truffle.espresso.substitutions.JavaType;
import com.oracle.truffle.espresso.substitutions.Substitution;
@@ -126,14 +127,14 @@ private EspressoType extractEspressoType(StaticObject type, EspressoContext cont
}
private static Klass rawType(StaticObject type) {
- Method method = type.getKlass().lookupDeclaredMethod(Names.getRawType, Signatures.Class, Klass.LookupMode.INSTANCE_ONLY);
+ Method method = type.getKlass().lookupDeclaredMethod(Names.getRawType, Signatures.Class, LookupMode.INSTANCE_ONLY);
assert method != null;
StaticObject rawGuestClass = (StaticObject) method.invokeDirectVirtual(type);
return rawGuestClass.getMirrorKlass();
}
private EspressoType[] typeArguments(StaticObject type, EspressoContext context) {
- Method method = type.getKlass().lookupDeclaredMethod(Names.getActualTypeArguments, Signatures.Type_array, Klass.LookupMode.INSTANCE_ONLY);
+ Method method = type.getKlass().lookupDeclaredMethod(Names.getActualTypeArguments, Signatures.Type_array, LookupMode.INSTANCE_ONLY);
assert method != null;
StaticObject typesArray = (StaticObject) method.invokeDirectVirtual(type);
StaticObject[] types = typesArray.unwrap(context.getLanguage());
diff --git a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaMethodAccess.java b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaMethodAccess.java
index 598df1c099d5..8ac78719189c 100644
--- a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaMethodAccess.java
+++ b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/CremaMethodAccess.java
@@ -39,6 +39,7 @@
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
import com.oracle.svm.espresso.classfile.descriptors.Type;
import com.oracle.svm.espresso.classfile.descriptors.TypeSymbols;
+import com.oracle.svm.espresso.shared.lookup.LookupSuccessInvocationFailure;
import com.oracle.svm.espresso.shared.meta.MethodAccess;
import jdk.vm.ci.meta.JavaKind;
@@ -101,7 +102,12 @@ static InterpreterResolvedJavaMethod toJVMCI(Executable executable) {
sb.append('V');
}
Symbol signature = SymbolsSupport.getSignatures().lookupValidSignature(sb.toString());
- return holder.lookupMethod(name, signature);
+ try {
+ return holder.lookupMethod(name, signature);
+ } catch (LookupSuccessInvocationFailure e) {
+ // GR-70938
+ return e.getResult();
+ }
}
static JavaType toJavaType(Symbol typeSymbol) {
diff --git a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaMethod.java b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaMethod.java
index 36c5d7380a8f..4b832ecb4ce1 100644
--- a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaMethod.java
+++ b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaMethod.java
@@ -336,6 +336,11 @@ public final boolean isCallerSensitive() {
return (flags & ACC_CALLER_SENSITIVE) != 0;
}
+ @Override
+ public InterpreterResolvedJavaMethod findSignaturePolymorphicIntrinsic(Symbol methodSignature) {
+ return (InterpreterResolvedJavaMethod) CremaSupport.singleton().findMethodHandleIntrinsic(this, methodSignature);
+ }
+
@Override
public final boolean isDeclaredSignaturePolymorphic() {
// Note: might not be true for the instantiation of polymorphic signature intrinsics.
diff --git a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaType.java b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaType.java
index 020e428e52b6..6985455920b2 100644
--- a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaType.java
+++ b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedJavaType.java
@@ -53,6 +53,8 @@
* closed world e.g. instantiable, instantiated, effectively final ...
*/
public abstract class InterpreterResolvedJavaType implements ResolvedJavaType, CremaTypeAccess {
+ public static final InterpreterResolvedJavaType[] EMPTY_ARRAY = new InterpreterResolvedJavaType[0];
+
private final Symbol type;
protected final Class> clazz;
private final JavaConstant clazzConstant;
diff --git a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedObjectType.java b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedObjectType.java
index 2a243181f986..b827458cac87 100644
--- a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedObjectType.java
+++ b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedObjectType.java
@@ -25,8 +25,8 @@
package com.oracle.svm.interpreter.metadata;
import static com.oracle.svm.core.BuildPhaseProvider.AfterAnalysis;
-import static com.oracle.svm.espresso.classfile.ParserKlass.isSignaturePolymorphicHolderType;
+import java.util.Arrays;
import java.util.List;
import org.graalvm.nativeimage.Platform;
@@ -36,14 +36,12 @@
import com.oracle.svm.core.StaticFieldsSupport;
import com.oracle.svm.core.heap.UnknownObjectField;
import com.oracle.svm.core.hub.DynamicHub;
-import com.oracle.svm.core.hub.crema.CremaSupport;
import com.oracle.svm.core.hub.registry.SymbolsSupport;
import com.oracle.svm.core.layeredimagesingleton.MultiLayeredImageSingleton;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.espresso.classfile.ParserKlass;
import com.oracle.svm.espresso.classfile.descriptors.ByteSequence;
import com.oracle.svm.espresso.classfile.descriptors.Name;
-import com.oracle.svm.espresso.classfile.descriptors.Signature;
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
import com.oracle.svm.espresso.classfile.descriptors.Type;
import com.oracle.svm.espresso.classfile.descriptors.TypeSymbols;
@@ -352,10 +350,26 @@ public final InterpreterResolvedJavaType findLeastCommonAncestor(InterpreterReso
}
@Override
- public final InterpreterResolvedJavaType getSuperClass() {
+ public final InterpreterResolvedObjectType getSuperClass() {
return this.superclass;
}
+ @Override
+ public final List getSuperInterfacesList() {
+ return Arrays.asList(getInterfaces());
+ }
+
+ @Override
+ public List getDeclaredMethodsList() {
+ return Arrays.asList(declaredMethods);
+ }
+
+ @Override
+ public List getImplicitInterfaceMethodsList() {
+ // GR-70607: get mirandas.
+ return null;
+ }
+
@Override
public final InterpreterResolvedJavaType getHostType() {
throw VMError.unimplemented("getHostType");
@@ -386,79 +400,4 @@ public final InterpreterResolvedJavaField lookupField(Symbol name, Symbol<
return null;
}
- @Override
- public final InterpreterResolvedJavaMethod lookupMethod(Symbol name, Symbol signature) {
- InterpreterResolvedObjectType current = this;
- InterpreterResolvedJavaMethod method = current.lookupDeclaredMethod(name, signature);
- if (method != null) {
- return method;
- }
-
- current = current.getSuperclass();
- while (current != null) {
- method = current.lookupDeclaredMethod(name, signature);
- if (method != null) {
- return method;
- }
- current = current.getSuperclass();
- }
- return null;
- }
-
- private InterpreterResolvedJavaMethod lookupDeclaredMethod(Symbol name, Symbol signature) {
- if (isSignaturePolymorphicHolderType(getSymbolicType())) {
- InterpreterResolvedJavaMethod method = lookupSignaturePolymorphicMethod(name, signature);
- if (method != null) {
- return method;
- }
- }
- for (InterpreterResolvedJavaMethod method : this.declaredMethods) {
- if (name.equals(method.getSymbolicName()) && signature.equals(method.getSymbolicSignature())) {
- return method;
- }
- }
- return null;
- }
-
- private InterpreterResolvedJavaMethod lookupSignaturePolymorphicMethod(Symbol methodName, Symbol signature) {
- InterpreterResolvedJavaMethod m = lookupDeclaredSignaturePolymorphicMethod(methodName);
- if (m != null) {
- return (InterpreterResolvedJavaMethod) CremaSupport.singleton().findMethodHandleIntrinsic(m, signature);
- }
- return null;
- }
-
- @Override
- public final InterpreterResolvedJavaMethod lookupInstanceMethod(Symbol name, Symbol signature) {
- InterpreterResolvedObjectType current = this;
- while (current != null) {
- for (InterpreterResolvedJavaMethod method : current.declaredMethods) {
- if (!method.isStatic() && name.equals(method.getSymbolicName()) && signature.equals(method.getSymbolicSignature())) {
- return method;
- }
- }
- current = current.getSuperclass();
- }
- return null;
- }
-
- @Override
- public final InterpreterResolvedJavaMethod lookupInterfaceMethod(Symbol name, Symbol signature) {
- assert isInterface();
- InterpreterResolvedJavaMethod result = lookupDeclaredMethod(name, signature);
- if (result != null) {
- return result;
- }
- throw VMError.unimplemented("lookupInterfaceMethod");
- }
-
- @Override
- public InterpreterResolvedJavaMethod lookupDeclaredSignaturePolymorphicMethod(Symbol methodName) {
- for (InterpreterResolvedJavaMethod m : getDeclaredMethods()) {
- if (m.getSymbolicName() == methodName && m.isDeclaredSignaturePolymorphic()) {
- return m;
- }
- }
- return null;
- }
}
diff --git a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedPrimitiveType.java b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedPrimitiveType.java
index 67bed668e834..ae4027117a8f 100644
--- a/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedPrimitiveType.java
+++ b/substratevm/src/com.oracle.svm.interpreter.metadata/src/com/oracle/svm/interpreter/metadata/InterpreterResolvedPrimitiveType.java
@@ -25,6 +25,7 @@
package com.oracle.svm.interpreter.metadata;
import java.lang.reflect.Modifier;
+import java.util.Collections;
import java.util.List;
import com.oracle.svm.core.hub.registry.SymbolsSupport;
@@ -121,8 +122,13 @@ public ResolvedJavaType getSuperclass() {
}
@Override
- public ResolvedJavaType[] getInterfaces() {
- return new ResolvedJavaType[0];
+ public InterpreterResolvedJavaType[] getInterfaces() {
+ return InterpreterResolvedJavaType.EMPTY_ARRAY;
+ }
+
+ @Override
+ public List getSuperInterfacesList() {
+ return Collections.emptyList();
}
@Override
@@ -135,6 +141,16 @@ public InterpreterResolvedJavaMethod[] getDeclaredMethods(boolean link) {
return InterpreterResolvedJavaMethod.EMPTY_ARRAY;
}
+ @Override
+ public List getDeclaredMethodsList() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List getImplicitInterfaceMethodsList() {
+ return null;
+ }
+
@Override
public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) {
return InterpreterResolvedJavaField.EMPTY_ARRAY;
diff --git a/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/CremaLinkResolver.java b/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/CremaLinkResolver.java
index 8687cd09456b..4e0f69d204a0 100644
--- a/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/CremaLinkResolver.java
+++ b/substratevm/src/com.oracle.svm.interpreter/src/com/oracle/svm/interpreter/CremaLinkResolver.java
@@ -28,6 +28,7 @@
import com.oracle.svm.espresso.classfile.descriptors.Signature;
import com.oracle.svm.espresso.classfile.descriptors.Symbol;
import com.oracle.svm.espresso.classfile.descriptors.Type;
+import com.oracle.svm.espresso.shared.lookup.LookupSuccessInvocationFailure;
import com.oracle.svm.espresso.shared.resolver.CallSiteType;
import com.oracle.svm.espresso.shared.resolver.FieldAccessType;
import com.oracle.svm.espresso.shared.resolver.LinkResolver;
@@ -67,14 +68,24 @@ public static InterpreterResolvedJavaMethod resolveMethodSymbol(CremaRuntimeAcce
Symbol name, Symbol signature, InterpreterResolvedJavaType symbolicHolder,
boolean interfaceLookup,
boolean accessCheck, boolean loadingConstraints) {
- return LinkResolver.resolveMethodSymbol(runtime, accessingClass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ try {
+ return LinkResolver.resolveMethodSymbol(runtime, accessingClass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ } catch (LookupSuccessInvocationFailure e) {
+ // GR-70938 Somehow communicate to the caller this info.
+ return e.getResult();
+ }
}
public static InterpreterResolvedJavaMethod resolveMethodSymbolOrNull(CremaRuntimeAccess runtime, InterpreterResolvedJavaType accessingClass,
Symbol name, Symbol signature, InterpreterResolvedJavaType symbolicHolder,
boolean interfaceLookup,
boolean accessCheck, boolean loadingConstraints) {
- return LinkResolver.resolveMethodSymbolOrNull(runtime, accessingClass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ try {
+ return LinkResolver.resolveMethodSymbolOrNull(runtime, accessingClass, name, signature, symbolicHolder, interfaceLookup, accessCheck, loadingConstraints);
+ } catch (LookupSuccessInvocationFailure e) {
+ // GR-70938 Somehow communicate to the caller this info.
+ return e.getResult();
+ }
}
public static ResolvedCall resolveCallSiteOrThrow(