001 /*
002 * This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 * This file is licensed to You under the Eclipse Public License (EPL);
005 * You may not use this file except in compliance with the License. You
006 * may obtain a copy of the License at
007 *
008 * http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 * See the COPYRIGHT.txt file distributed with this work for information
011 * regarding copyright ownership.
012 */
013 package org.jikesrvm.runtime;
014
015 import org.jikesrvm.classloader.RVMMethod;
016 import org.vmmagic.pragma.Inline;
017 import org.vmmagic.pragma.NoInline;
018
019 /**
020 * Base class for all reflective method invoker classes, contains utility
021 * methods that are invoked to unwrap the reflective arguments. Also contains
022 * {@link #invoke(RVMMethod, Object, Object[])} that is called to perform the reflective
023 * method call.
024 */
025 public abstract class ReflectionBase {
026
027 /** Throw error with argument */
028 @NoInline
029 private static void throwIllegalArgumentException() throws IllegalArgumentException {
030 throw new IllegalArgumentException();
031 }
032
033 /** Unwrap boolean for call */
034 @Inline
035 protected static boolean unboxAsBoolean(Object obj) {
036 if ((obj == null) || !(obj instanceof Boolean)) {
037 throwIllegalArgumentException();
038 }
039 return ((Boolean)obj).booleanValue();
040 }
041
042 /** Wrap result as boolean */
043 @Inline
044 protected static Object boxAsBoolean(boolean b) {
045 return b;
046 }
047
048 /** Unwrap boolean for call */
049 @Inline
050 protected static byte unboxAsByte(Object obj) {
051 if ((obj == null) || !(obj instanceof Byte)) {
052 throwIllegalArgumentException();
053 }
054 return ((Byte)obj).byteValue();
055 }
056
057 /** Wrap result as byte */
058 @Inline
059 protected static Object boxAsByte(byte b) {
060 return b;
061 }
062
063 /** Unwrap short for call */
064 @Inline
065 protected static short unboxAsShort(Object obj) {
066 if ((obj == null) || (!(obj instanceof Short) && !(obj instanceof Byte))) {
067 throwIllegalArgumentException();
068 }
069 return ((Number)obj).shortValue();
070 }
071
072 /** Wrap result as short */
073 @Inline
074 protected static Object boxAsShort(short s) {
075 return s;
076 }
077
078 /** Unwrap char for call */
079 @Inline
080 protected static char unboxAsChar(Object obj) {
081 if ((obj == null) || !(obj instanceof Character)) {
082 throwIllegalArgumentException();
083 }
084 return ((Character)obj).charValue();
085 }
086
087 /** Wrap result as char */
088 @Inline
089 protected static Object boxAsChar(char c) {
090 return c;
091 }
092
093 /** Unwrap int for call */
094 @Inline
095 protected static int unboxAsInt(Object obj) {
096 if ((obj == null) ||
097 (!(obj instanceof Integer) && !(obj instanceof Character) &&
098 !(obj instanceof Short) && !(obj instanceof Byte))) {
099 throwIllegalArgumentException();
100 }
101 return ((Number)obj).intValue();
102 }
103
104 /** Wrap result as int */
105 @Inline
106 protected static Object boxAsInt(int i) {
107 return i;
108 }
109
110 /** Unwrap long for call */
111 @Inline
112 protected static long unboxAsLong(Object obj) {
113 if ((obj == null) ||
114 (!(obj instanceof Long) && !(obj instanceof Integer) &&
115 !(obj instanceof Character) && (obj instanceof Short) &&
116 !(obj instanceof Byte))) {
117 throwIllegalArgumentException();
118 }
119 return ((Number)obj).longValue();
120 }
121
122 /** Wrap result as long */
123 @Inline
124 protected static Object boxAsLong(long l) {
125 return l;
126 }
127
128 /** Unwrap float for call */
129 @Inline
130 protected static float unboxAsFloat(Object obj) {
131 if ((obj == null) || !(obj instanceof Float)) {
132 throwIllegalArgumentException();
133 }
134 return ((Float)obj).floatValue();
135 }
136
137 /** Wrap result as float */
138 @Inline
139 protected static Object boxAsFloat(float f) {
140 return f;
141 }
142
143 /** Unwrap double for call */
144 @Inline
145 protected static double unboxAsDouble(Object obj) {
146 if ((obj == null) ||
147 (!(obj instanceof Double) && !(obj instanceof Float))) {
148 throwIllegalArgumentException();
149 }
150 return ((Number)obj).doubleValue();
151 }
152
153 /** Wrap result as double */
154 @Inline
155 protected static Object boxAsDouble(double d) {
156 return d;
157 }
158
159 /**
160 * Invoke reflective method being wrapped by this object, internal method
161 * specific part.
162 * @param obj object for virtual method invocation
163 * @param args arguments to method call
164 * @return the object that is the result of the invoke
165 */
166 public abstract Object invokeInternal(Object obj, Object[] args);
167
168 /**
169 * Invoke reflective method being wrapped by this object
170 * @param obj object for virtual method invocation
171 * @param args arguments to method call
172 * @return the object that is the result of the invoke
173 */
174 public final Object invoke(RVMMethod method, Object obj, Object[] args) {
175 int argsLength = args == null ? 0 : args.length;
176 if (method.getParameterTypes().length != argsLength) {
177 throwIllegalArgumentException();
178 }
179 try {
180 return invokeInternal(obj, args);
181 } catch (ClassCastException e) {
182 // FIXME: This is fragile and ill-advised way to handle this situation
183 // I think A more robust way to handle it would be to put in the appropriate
184 // try/catch structure in the generated bytecodes and handle it there.
185 if (e.getStackTrace().length == (new Throwable()).getStackTrace().length+6) {
186 throw new IllegalArgumentException("argument type mismatch", e);
187 } else {
188 throw e;
189 }
190 }
191 }
192
193 /**
194 * Reflective method invoker that performs no invocation
195 */
196 public static final ReflectionBase nullInvoker = new ReflectionBase() {
197 @Override
198 public Object invokeInternal(Object obj, Object[] args) {return null;}
199 };
200 }