001/* 002 * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. 008 * 009 * This code is distributed in the hope that it will be useful, but WITHOUT 010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 011 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 012 * version 2 for more details (a copy is included in the LICENSE file that 013 * accompanied this code). 014 * 015 * You should have received a copy of the GNU General Public License version 016 * 2 along with this work; if not, write to the Free Software Foundation, 017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 018 * 019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 020 * or visit www.oracle.com if you need additional information or have any 021 * questions. 022 */ 023package com.oracle.graal.api.replacements; 024 025import java.lang.reflect.*; 026import java.util.*; 027 028import jdk.internal.jvmci.meta.*; 029 030/** 031 * Reflection operations on values represented as {@linkplain JavaConstant constants} for the 032 * processing of snippets. Snippets need a direct access to the value of object constants, which is 033 * not allowed in other parts of Graal to enforce compiler-VM separation. 034 * <p> 035 * This interface must not be used in Graal code that is not related to snippet processing. 036 */ 037public interface SnippetReflectionProvider { 038 039 /** 040 * Creates a boxed {@link Kind#Object object} constant. 041 * 042 * @param object the object value to box 043 * @return a constant containing {@code object} 044 */ 045 JavaConstant forObject(Object object); 046 047 /** 048 * Gets the object reference a given constant represents if it is of a given type. The constant 049 * must have kind {@link Kind#Object}. 050 * 051 * @param type the expected type of the object represented by {@code constant}. If the object is 052 * required to be of this type, then wrap the call to this method in 053 * {@link Objects#requireNonNull(Object)}. 054 * @param constant an object constant 055 * @return the object value represented by {@code constant} cast to {@code type} if it is an 056 * {@link Class#isInstance(Object) instance of} {@code type} otherwise {@code null} 057 */ 058 <T> T asObject(Class<T> type, JavaConstant constant); 059 060 /** 061 * Gets the object reference a given constant represents if it is of a given type. The constant 062 * must have kind {@link Kind#Object}. 063 * 064 * @param type the expected type of the object represented by {@code constant}. If the object is 065 * required to be of this type, then wrap the call to this method in 066 * {@link Objects#requireNonNull(Object)}. 067 * @param constant an object constant 068 * @return the object value represented by {@code constant} if it is an 069 * {@link ResolvedJavaType#isInstance(JavaConstant) instance of} {@code type} otherwise 070 * {@code null} 071 */ 072 Object asObject(ResolvedJavaType type, JavaConstant constant); 073 074 /** 075 * Creates a boxed constant for the given kind from an Object. The object needs to be of the 076 * Java boxed type corresponding to the kind. 077 * 078 * @param kind the kind of the constant to create 079 * @param value the Java boxed value: a {@link Byte} instance for {@link Kind#Byte}, etc. 080 * @return the boxed copy of {@code value} 081 */ 082 JavaConstant forBoxed(Kind kind, Object value); 083 084 /** 085 * Resolves a parameter or return type involved in snippet code to a {@link Class}. 086 */ 087 static Class<?> resolveClassForSnippet(JavaType type) throws ClassNotFoundException { 088 try { 089 return Class.forName(type.toClassName()); 090 } catch (ClassNotFoundException e) { 091 // Support for -XX:-UseJVMCIClassLoader 092 return Class.forName(type.toClassName(), false, ClassLoader.getSystemClassLoader()); 093 } 094 } 095 096 /** 097 * Invokes a given method via {@link Method#invoke(Object, Object...)}. 098 */ 099 default Object invoke(ResolvedJavaMethod method, Object receiver, Object... args) { 100 try { 101 JavaType[] parameterTypes = method.toParameterTypes(); 102 Class<?>[] parameterClasses = new Class<?>[parameterTypes.length]; 103 for (int i = 0; i < parameterClasses.length; ++i) { 104 JavaType type = parameterTypes[i]; 105 if (type.getKind() != Kind.Object) { 106 parameterClasses[i] = type.getKind().toJavaClass(); 107 } else { 108 parameterClasses[i] = resolveClassForSnippet(parameterTypes[i]); 109 } 110 } 111 112 Class<?> c = resolveClassForSnippet(method.getDeclaringClass()); 113 if (method.isConstructor()) { 114 Constructor<?> javaConstructor = c.getDeclaredConstructor(parameterClasses); 115 javaConstructor.setAccessible(true); 116 return javaConstructor.newInstance(args); 117 } else { 118 Method javaMethod = c.getDeclaredMethod(method.getName(), parameterClasses); 119 javaMethod.setAccessible(true); 120 return javaMethod.invoke(receiver, args); 121 } 122 } catch (IllegalAccessException | InstantiationException | InvocationTargetException | ClassNotFoundException | NoSuchMethodException ex) { 123 throw new IllegalArgumentException(ex); 124 } 125 } 126 127 /** 128 * Gets the constant value of this field. Note that a {@code static final} field may not be 129 * considered constant if its declaring class is not yet initialized or if it is a well known 130 * field that can be updated via other means (e.g., {@link System#setOut(java.io.PrintStream)}). 131 * 132 * @param receiver object from which this field's value is to be read. This value is ignored if 133 * this field is static. 134 * @return the constant value of this field or {@code null} if this field is not considered 135 * constant by the runtime 136 */ 137 default Object readConstantFieldValue(JavaField field, Object receiver) { 138 try { 139 Class<?> c = resolveClassForSnippet(field.getDeclaringClass()); 140 Field javaField = c.getDeclaredField(field.getName()); 141 javaField.setAccessible(true); 142 return javaField.get(receiver); 143 } catch (IllegalAccessException | ClassNotFoundException | NoSuchFieldException ex) { 144 throw new IllegalArgumentException(ex); 145 } 146 } 147 148 /** 149 * Creates a new array with a given type as the component type and the specified length. This 150 * method is similar to {@link Array#newInstance(Class, int)}. 151 */ 152 default Object newArray(ResolvedJavaType componentType, int length) { 153 try { 154 return Array.newInstance(resolveClassForSnippet(componentType), length); 155 } catch (ClassNotFoundException e) { 156 throw new IllegalArgumentException(e); 157 } 158 } 159 160 /** 161 * Gets the value to bind to a parameter in a {@link SubstitutionGuard} constructor. 162 * 163 * @param type the type of a parameter in a {@link SubstitutionGuard} constructor 164 * @return the value that should be bound to the parameter when invoking the constructor or null 165 * if this provider cannot provide a value of the requested type 166 */ 167 Object getSubstitutionGuardParameter(Class<?> type); 168 169 /** 170 * Gets the value to bind to an injected parameter in a node intrinsic. 171 * 172 * @param type the type of a parameter in a node intrinsic constructor 173 * @return the value that should be bound to the parameter when invoking the constructor or null 174 * if this provider cannot provide a value of the requested type 175 */ 176 Object getInjectedNodeIntrinsicParameter(ResolvedJavaType type); 177}