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    }