/*
 * Copyright (c) 2020, 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 org.graalvm.compiler.hotspot;

import static jdk.vm.ci.services.Services.IS_IN_NATIVE_IMAGE;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import jdk.vm.ci.meta.Assumptions;
import jdk.vm.ci.meta.JavaConstant;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.MetaUtil;
import jdk.vm.ci.meta.ResolvedJavaField;
import jdk.vm.ci.meta.ResolvedJavaMethod;
import jdk.vm.ci.meta.ResolvedJavaType;
import jdk.vm.ci.meta.UnresolvedJavaType;

A minimal implementation of ResolvedJavaType for use by libgraal. Libgraal snippets have their own hierarchy of these types because they represent a distinct type system that's overlapping with the platform type system. These types are also transient in the graph and should disappear from the graph once the snippet is inlined and optimized. HotSpotResolvedJavaType can't be used here because the Graal classes may not be available in the host VM and even if they are, loading them causes unnecessary class loading. The Substrate type system could be used but it is implementation overkill for the purposes of libgraal.
/** * A minimal implementation of {@link ResolvedJavaType} for use by libgraal. * * Libgraal snippets have their own hierarchy of these types because they represent a distinct type * system that's overlapping with the platform type system. These types are also transient in the * graph and should disappear from the graph once the snippet is inlined and optimized. * * {@link jdk.vm.ci.hotspot.HotSpotResolvedJavaType HotSpotResolvedJavaType} can't be used here * because the Graal classes may not be available in the host VM and even if they are, loading them * causes unnecessary class loading. The Substrate type system could be used but it is * implementation overkill for the purposes of libgraal. */
public final class SnippetResolvedJavaType implements ResolvedJavaType { private final Class<?> javaClass; private List<SnippetResolvedJavaMethod> methods; private SnippetResolvedJavaType arrayOfType; public SnippetResolvedJavaType(Class<?> javaClass) { this.javaClass = javaClass; } public void setArrayOfType(SnippetResolvedJavaType arrayOfType) { assert this.arrayOfType == null || this.arrayOfType.equals(arrayOfType); this.arrayOfType = arrayOfType; } synchronized SnippetResolvedJavaMethod add(SnippetResolvedJavaMethod method) { if (IS_IN_NATIVE_IMAGE) { throw new InternalError("immutable"); } if (methods == null) { methods = new ArrayList<>(1); } // This in inefficient but is only use during image building for a small number of methods. int index = methods.indexOf(method); if (index == -1) { methods.add(method); return method; } else { return methods.get(index); } } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } SnippetResolvedJavaType that = (SnippetResolvedJavaType) o; return Objects.equals(javaClass, that.javaClass); } @Override public int hashCode() { return Objects.hash(javaClass); } @Override public boolean hasFinalizer() { throw new UnsupportedOperationException(); } @Override public Assumptions.AssumptionResult<Boolean> hasFinalizableSubclass() { throw new UnsupportedOperationException(); } @Override public int getModifiers() { return javaClass.getModifiers(); } @Override public boolean isInterface() { return javaClass.isInterface(); } @Override public boolean isInstanceClass() { throw new UnsupportedOperationException(); } @Override public boolean isPrimitive() { return javaClass.isPrimitive(); } @Override public boolean isEnum() { return javaClass.isEnum(); } @Override public boolean isInitialized() { throw new UnsupportedOperationException(); } @Override public void initialize() { } @Override public boolean isLinked() { throw new UnsupportedOperationException(); } @Override public boolean isAssignableFrom(ResolvedJavaType other) { if (other instanceof SnippetResolvedJavaType) { return javaClass.isAssignableFrom(((SnippetResolvedJavaType) other).javaClass); } return false; } @Override public ResolvedJavaType lookupType(UnresolvedJavaType unresolvedJavaType, boolean resolve) { // UnresolvedJavaTypes can't be resolved relative to SnippetResolvedJavatypes throw new NoClassDefFoundError(); } @Override public ResolvedJavaType getHostClass() { throw new UnsupportedOperationException(); } @Override public boolean isInstance(JavaConstant obj) { if (obj instanceof SnippetObjectConstant) { return javaClass.isAssignableFrom(((SnippetObjectConstant) obj).object.getClass()); } return false; } @Override public ResolvedJavaType getSuperclass() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaType[] getInterfaces() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaType getSingleImplementor() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaType findLeastCommonAncestor(ResolvedJavaType otherType) { if (getClass() != otherType.getClass()) { throw new InternalError("mixing type systems: " + this + " " + otherType); } if (this.equals(otherType)) { return this; } throw new UnsupportedOperationException("LCA: " + this + " " + otherType); } @Override public Assumptions.AssumptionResult<ResolvedJavaType> findLeafConcreteSubtype() { if (isLeaf()) { return new Assumptions.AssumptionResult<>(this); } return null; } @Override public boolean isJavaLangObject() { return false; } @Override public String getName() { return MetaUtil.toInternalName(javaClass.getName()); } @Override public ResolvedJavaType getComponentType() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaType getArrayClass() { assert arrayOfType != null; return arrayOfType; } @Override public JavaKind getJavaKind() { return JavaKind.Object; } @Override public ResolvedJavaType resolve(ResolvedJavaType accessingClass) { return this; } @Override public ResolvedJavaMethod resolveMethod(ResolvedJavaMethod method, ResolvedJavaType callerType) { throw new UnsupportedOperationException(); } @Override public Assumptions.AssumptionResult<ResolvedJavaMethod> findUniqueConcreteMethod(ResolvedJavaMethod method) { throw new UnsupportedOperationException(); } @Override public ResolvedJavaField[] getInstanceFields(boolean includeSuperclasses) { throw new UnsupportedOperationException(); } @Override public ResolvedJavaField[] getStaticFields() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaField findInstanceFieldWithOffset(long offset, JavaKind expectedKind) { throw new UnsupportedOperationException(); } @Override public String getSourceFileName() { throw new UnsupportedOperationException(); } @Override public boolean isLocal() { throw new UnsupportedOperationException(); } @Override public boolean isMember() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaType getEnclosingType() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaMethod[] getDeclaredConstructors() { throw new UnsupportedOperationException(); } @Override public ResolvedJavaMethod[] getDeclaredMethods() { if (methods == null) { return new ResolvedJavaMethod[0]; } return methods.toArray(new ResolvedJavaMethod[methods.size()]); } @Override public ResolvedJavaMethod getClassInitializer() { throw new UnsupportedOperationException(); } @Override public boolean isCloneableWithAllocation() { throw new UnsupportedOperationException(); } @Override public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { throw new UnsupportedOperationException(); } @Override public Annotation[] getAnnotations() { throw new UnsupportedOperationException(); } @Override public Annotation[] getDeclaredAnnotations() { throw new UnsupportedOperationException(); } @Override public boolean isArray() { return javaClass.isArray(); } @Override public String toString() { return "SnippetResolvedJavaType{" + "javaClass=" + javaClass + '}'; } }