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 */
013package org.jikesrvm.runtime;
014
015import org.jikesrvm.classloader.RVMMethod;
016import org.vmmagic.pragma.Inline;
017import 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 */
025public abstract class ReflectionBase {
026
027  @NoInline
028  private static void throwIllegalArgumentException() throws IllegalArgumentException {
029    throw new IllegalArgumentException();
030  }
031
032  @Inline
033  protected static boolean unboxAsBoolean(Object obj) {
034    if ((obj == null) || !(obj instanceof Boolean)) {
035      throwIllegalArgumentException();
036    }
037    return ((Boolean)obj).booleanValue();
038  }
039
040  @Inline
041  protected static Object boxAsBoolean(boolean b) {
042    return b;
043  }
044
045  @Inline
046  protected static byte unboxAsByte(Object obj) {
047    if ((obj == null) || !(obj instanceof Byte)) {
048      throwIllegalArgumentException();
049    }
050    return ((Byte)obj).byteValue();
051  }
052
053  @Inline
054  protected static Object boxAsByte(byte b) {
055    return b;
056  }
057
058  @Inline
059  protected static short unboxAsShort(Object obj) {
060    if ((obj == null) || (!(obj instanceof Short) && !(obj instanceof Byte))) {
061      throwIllegalArgumentException();
062    }
063    return ((Number)obj).shortValue();
064  }
065
066  @Inline
067  protected static Object boxAsShort(short s) {
068    return s;
069  }
070
071  @Inline
072  protected static char unboxAsChar(Object obj) {
073    if ((obj == null) || !(obj instanceof Character)) {
074      throwIllegalArgumentException();
075    }
076    return ((Character)obj).charValue();
077  }
078
079  @Inline
080  protected static Object boxAsChar(char c) {
081    return c;
082  }
083
084  @Inline
085  protected static int unboxAsInt(Object obj) {
086    if ((obj == null) ||
087        (!(obj instanceof Integer) && !(obj instanceof Character) &&
088         !(obj instanceof Short) && !(obj instanceof Byte))) {
089      throwIllegalArgumentException();
090    }
091    return ((Number)obj).intValue();
092  }
093
094  @Inline
095  protected static Object boxAsInt(int i) {
096    return i;
097  }
098
099  @Inline
100  protected static long unboxAsLong(Object obj) {
101    if ((obj == null) ||
102        (!(obj instanceof Long) && !(obj instanceof Integer) &&
103         !(obj instanceof Character) && !(obj instanceof Short) &&
104         !(obj instanceof Byte))) {
105      throwIllegalArgumentException();
106    }
107    return ((Number)obj).longValue();
108  }
109
110  @Inline
111  protected static Object boxAsLong(long l) {
112    return l;
113  }
114
115  @Inline
116  protected static float unboxAsFloat(Object obj) {
117    if ((obj == null) || !(obj instanceof Float)) {
118      throwIllegalArgumentException();
119    }
120    return ((Float)obj).floatValue();
121  }
122
123  @Inline
124  protected static Object boxAsFloat(float f) {
125    return f;
126  }
127
128  @Inline
129  protected static double unboxAsDouble(Object obj) {
130    if ((obj == null) ||
131        (!(obj instanceof Double) && !(obj instanceof Float))) {
132      throwIllegalArgumentException();
133    }
134    return ((Number)obj).doubleValue();
135  }
136
137  @Inline
138  protected static Object boxAsDouble(double d) {
139    return d;
140  }
141
142  /**
143   * Invoke reflective method being wrapped by this object, internal method
144   * specific part.
145   * @param obj object for virtual method invocation
146   * @param args arguments to method call
147   * @return the object that is the result of the invoke
148   */
149  public abstract Object invokeInternal(Object obj, Object[] args);
150
151  /**
152   * Invoke reflective method being wrapped by this object
153   * @param method the method to invoke
154   * @param obj object for virtual method invocation
155   * @param args arguments to method call
156   * @return the object that is the result of the invoke
157   */
158  public final Object invoke(RVMMethod method, Object obj, Object[] args) {
159    int argsLength = args == null ? 0 : args.length;
160    if (method.getParameterTypes().length != argsLength) {
161      throwIllegalArgumentException();
162    }
163    try {
164      return invokeInternal(obj, args);
165    } catch (ClassCastException e) {
166      // FIXME: This is fragile and ill-advised way to handle this situation
167      //        I think A more robust way to handle it would be to put in the appropriate
168      //        try/catch structure in the generated bytecodes and handle it there.
169      if (e.getStackTrace().length == (new Throwable()).getStackTrace().length + 6) {
170        throw new IllegalArgumentException("argument type mismatch", e);
171      } else {
172        throw e;
173      }
174    }
175  }
176
177  /**
178   * Reflective method invoker that performs no invocation
179   */
180  public static final ReflectionBase nullInvoker = new ReflectionBase() {
181    @Override
182    public Object invokeInternal(Object obj, Object[] args) {
183      return null;
184    }
185  };
186}