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 }