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.jni;
014
015import static org.jikesrvm.runtime.ExitStatus.*;
016import static org.jikesrvm.runtime.JavaSizeConstants.BITS_IN_BYTE;
017import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_CHAR;
018import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_INT;
019import static org.jikesrvm.runtime.JavaSizeConstants.BYTES_IN_SHORT;
020import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_CHAR;
021import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_DOUBLE;
022import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_FLOAT;
023import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_INT;
024import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_LONG;
025import static org.jikesrvm.runtime.JavaSizeConstants.LOG_BYTES_IN_SHORT;
026import static org.jikesrvm.runtime.UnboxedSizeConstants.BYTES_IN_ADDRESS;
027import static org.jikesrvm.runtime.SysCall.sysCall;
028
029import java.lang.reflect.Constructor;
030import java.lang.reflect.Field;
031import java.lang.reflect.Method;
032import java.nio.Buffer;
033
034import org.jikesrvm.Properties;
035import org.jikesrvm.VM;
036import org.jikesrvm.architecture.JNIHelpers;
037import org.jikesrvm.classloader.Atom;
038import org.jikesrvm.classloader.MemberReference;
039import org.jikesrvm.classloader.NativeMethod;
040import org.jikesrvm.classloader.RVMArray;
041import org.jikesrvm.classloader.RVMClass;
042import org.jikesrvm.classloader.RVMClassLoader;
043import org.jikesrvm.classloader.RVMField;
044import org.jikesrvm.classloader.RVMMethod;
045import org.jikesrvm.classloader.RVMType;
046import org.jikesrvm.classloader.TypeReference;
047import org.jikesrvm.classloader.UTF8Convert;
048import org.jikesrvm.mm.mminterface.MemoryManager;
049import org.jikesrvm.objectmodel.ObjectModel;
050import org.jikesrvm.runtime.BootRecord;
051import org.jikesrvm.runtime.Magic;
052import org.jikesrvm.runtime.Memory;
053import org.jikesrvm.runtime.Reflection;
054import org.jikesrvm.runtime.RuntimeEntrypoints;
055import org.jikesrvm.util.AddressInputStream;
056import org.vmmagic.pragma.NativeBridge;
057import org.vmmagic.unboxed.Address;
058import org.vmmagic.unboxed.AddressArray;
059import org.vmmagic.unboxed.Extent;
060import org.vmmagic.unboxed.Offset;
061
062/**
063 * This class implements the 232 JNI functions.
064 * All methods here will be specially compiled with the necessary prolog to
065 * perform the transition from native code (Linux/OSX convention) to RVM.
066 * For this reason, no Java methods (including the JNI methods here) can call
067 * any methods in this class from within Java.  These JNI methods are to
068 * be invoked from native C or C++.   They're all declared private to enforce
069 * this discipline.  <br>
070 *
071 * NOTE: Some of the JNIFunctions here are overwritten by C implementations
072 * for IA32. See the bootloader for the implementations of these functions. <br>
073 *
074 * The first argument for all the functions is the JNIEnvironment object
075 * of the thread. <br>
076 *
077 * The second argument is a JREF index for either the RVMClass object
078 * or the object instance itself.  To get the actual object, we use
079 * the access method in JNIEnvironment and cast the reference as
080 * needed. <br>
081 *
082 * NOTE:
083 * <ol>
084 * <li> JREF index refers to the index into the side table of references
085 * maintained by the JNIEnvironment for each thread. Except for some cases
086 * of array access, no references are passed directly to the native code;
087 * rather, the references are kept in the table and the index is passed to the
088 * native procedure.  The JREF index are used by the JNI code to retrieve the
089 * corresponding reference. </li>
090 *
091 * <li> Strings from C are seen as raw address (int) and need to be cloned as
092 * Java Strings </li>
093 *
094 * <li> Because of many of the transformation above, the method signature of the
095 * JNI functions may not match its definition in the jni.h file </li>
096 *
097 * <li> For exception handling, all JNI functions are wrapped in Try/Catch block
098 * to catch all exception generated during JNI call, then these exceptions
099 * or the appropriate exception to be thrown according to the spec is recorded
100 * in JNIEnvironment.pendingException.  When the native code returns to the
101 * the Java caller, the epilogue in the glue code will check for the pending
102 * exception and deliver it to the caller as if executing an athrow bytecode
103 * in the caller. </li>
104 * </ol>
105 *
106 * Known Problems with our JNI implementation:
107 * <ol>
108 * <li>We can not return a global reference (whether weak
109 *     or strong) from a JNI function.  We can only return local refs.
110 * <li>We do not implement all of the invocation API; we don't support the
111 *      concept of a regular native program that links with "libjava" and
112 *      creates and destroys virtual machines.
113 * <li>Similarly, we can not attach and detach a native threads to and from
114 *     the VM.
115 * <li>We don't really free local refs when we call the
116 *      {@link #PopLocalFrame} method.
117 * </ol>
118 */
119@SuppressWarnings({"unused", "UnusedDeclaration"})
120// methods are called from native code
121@NativeBridge
122public class JNIFunctions {
123
124  private static final String ERROR_MSG_WRONG_IMPLEMENTATION =
125      "Architectures other than PowerPC should use C var args processing " +
126      "and the C implementation for this function!";
127
128  // one message for each JNI function called from native
129  public static final boolean traceJNI = Properties.verboseJNI;
130
131  // number of JNI function entries
132  public static final int FUNCTIONCOUNT = 232; // JNI 1.4
133
134  /**
135   * GetVersion: the version of the JNI
136   * @param env A JREF index for the JNI environment object
137   * @return 0x00010004 for JNI 1.4, 0x00010002 for JNI 1.2,
138   *        0x00010001 for JNI 1.1,
139   */
140  private static int GetVersion(JNIEnvironment env) {
141    if (traceJNI) VM.sysWrite("JNI called: GetVersion  \n");
142    RuntimeEntrypoints.checkJNICountDownToGC();
143
144    return 0x00010004;          // JNI 1.4
145  }
146
147  /**
148   * DefineClass:  Loads a class from a buffer of raw class data.
149   * @param env A JREF index for the JNI environment object
150   * @param classNameAddress a raw address to a null-terminated string in C for the class name
151   * @param classLoader a JREF index for the class loader assigned to the defined class
152   * @param data buffer containing the <tt>.class</tt> file
153   * @param dataLen buffer length
154   * @return a JREF index for the Java Class object, or 0 if not found
155   * @throws ClassFormatError if the class data does not specify a valid class
156   * @throws ClassCircularityError (not implemented)
157   * @throws OutOfMemoryError (not implemented)
158   */
159  private static int DefineClass(JNIEnvironment env, Address classNameAddress, int classLoader, Address data,
160                                 int dataLen) {
161    if (traceJNI) VM.sysWrite("JNI called: DefineClass  \n");
162    RuntimeEntrypoints.checkJNICountDownToGC();
163
164    try {
165      String classString = null;
166      if (!classNameAddress.isZero()) {
167        JNIGenericHelpers.createStringFromC(classNameAddress);
168      }
169      ClassLoader cl;
170      if (classLoader == 0) {
171        cl = RVMClass.getClassLoaderFromStackFrame(1);
172      } else {
173        cl = (ClassLoader) env.getJNIRef(classLoader);
174      }
175      AddressInputStream reader = new AddressInputStream(data, Extent.fromIntZeroExtend(dataLen));
176
177      final RVMType vmType = RVMClassLoader.defineClassInternal(classString, reader, cl);
178      return env.pushJNIRef(vmType.getClassForType());
179    } catch (Throwable unexpected) {
180      if (traceJNI) unexpected.printStackTrace(System.err);
181      env.recordException(unexpected);
182      return 0;
183    }
184
185  }
186
187  /**
188   * FindClass:  given a class name, find its RVMClass, or 0 if not found
189   * @param env A JREF index for the JNI environment object
190   * @param classNameAddress a raw address to a null-terminated string in C for the class name
191   * @return a JREF index for the Java Class object, or 0 if not found
192   * @throws ClassFormatError (not implemented)
193   * @throws ClassCircularityError (not implemented)
194   * @throws NoClassDefFoundError if the class cannot be found
195   * @throws OutOfMemoryError (not implemented)
196   * @throws ExceptionInInitializerError (not implemented)
197   */
198  private static int FindClass(JNIEnvironment env, Address classNameAddress) {
199    if (traceJNI) VM.sysWrite("JNI called: FindClass  \n");
200    RuntimeEntrypoints.checkJNICountDownToGC();
201
202    String classString = null;
203    try {
204      classString = JNIGenericHelpers.createStringFromC(classNameAddress);
205      classString = classString.replace('/', '.');
206      if (classString.startsWith("L") && classString.endsWith(";")) {
207        classString = classString.substring(1, classString.length() - 1);
208      }
209      if (traceJNI) VM.sysWriteln(classString);
210      ClassLoader cl = RVMClass.getClassLoaderFromStackFrame(1);
211      Class<?> matchedClass = Class.forName(classString.replace('/', '.'), true, cl);
212      int result = env.pushJNIRef(matchedClass);
213      if (traceJNI) VM.sysWriteln("FindClass returning ",result);
214      return result;
215    } catch (ClassNotFoundException e) {
216      if (traceJNI) e.printStackTrace(System.err);
217      env.recordException(new NoClassDefFoundError(classString));
218      return 0;
219    } catch (Throwable unexpected) {
220      if (traceJNI) {
221        if (VM.fullyBooted) {
222          unexpected.printStackTrace(System.err);
223        } else {
224          VM.sysWrite("Unexpected exception ", unexpected.getClass().toString());
225          VM.sysWriteln(" to early in VM boot up to print ", unexpected.getMessage());
226        }
227      }
228      env.recordException(unexpected);
229      return 0;
230    }
231  }
232
233  /**
234   * GetSuperclass: find the superclass given a class
235   * @param env A JREF index for the JNI environment object
236   * @param classJREF a JREF index for the class object
237   * @return a JREF index for the super class object, or 0 if the given class
238   *         is java.lang.Object or an interface
239   */
240  private static int GetSuperclass(JNIEnvironment env, int classJREF) {
241    if (traceJNI) VM.sysWrite("JNI called: GetSuperclass  \n");
242    RuntimeEntrypoints.checkJNICountDownToGC();
243
244    try {
245      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
246      Class<?> supercls = cls.getSuperclass();
247      return supercls == null ? 0 : env.pushJNIRef(supercls);
248    } catch (Throwable unexpected) {
249      if (traceJNI) unexpected.printStackTrace(System.err);
250      env.recordException(unexpected);
251      return 0;
252    }
253  }
254
255  /**
256   * IsAssignableFrom:  determine if an an object of class or interface cls1
257   * can be cast to the class or interface cls2
258   * @param env A JREF index for the JNI environment object
259   * @param firstClassJREF a JREF index for the first class object
260   * @param secondClassJREF a JREF index for the second class object
261   * @return true if cls1 can be assigned to cls2
262   */
263  private static boolean IsAssignableFrom(JNIEnvironment env, int firstClassJREF, int secondClassJREF) {
264    if (traceJNI) VM.sysWrite("JNI called: IsAssignableFrom  \n");
265    RuntimeEntrypoints.checkJNICountDownToGC();
266
267    try {
268      Class<?> cls1 = (Class<?>) env.getJNIRef(firstClassJREF);
269      Class<?> cls2 = (Class<?>) env.getJNIRef(secondClassJREF);
270      return !(cls1 == null || cls2 == null) && cls2.isAssignableFrom(cls1);
271    } catch (Throwable unexpected) {
272      if (traceJNI) unexpected.printStackTrace(System.err);
273      env.recordException(unexpected);
274      return false;
275    }
276  }
277
278  /**
279   * Throw:  register a {@link Throwable} object as a pending exception, to be
280   *         delivered on return to the Java caller
281   * @param env A JREF index for the JNI environment object
282   * @param exceptionJREF A JREF index for the {@link Throwable} object to be
283   *        thrown
284   * @return 0 if successful, -1 if not
285   */
286  private static int Throw(JNIEnvironment env, int exceptionJREF) {
287    if (traceJNI) VM.sysWrite("JNI called: Throw  \n");
288    RuntimeEntrypoints.checkJNICountDownToGC();
289
290    try {
291      env.recordException((Throwable) env.getJNIRef(exceptionJREF));
292      return 0;
293    } catch (Throwable unexpected) {
294      if (traceJNI) unexpected.printStackTrace(System.err);
295      env.recordException(unexpected);
296      return -1;
297    }
298  }
299
300  /**
301   * ThrowNew
302   * @param env A JREF index for the JNI environment object
303   * @param throwableClassJREF a JREF index for the class object of the exception
304   * @param exceptionNameAddress an address of the string in C
305   * @return 0 if successful, -1 otherwise
306   */
307  private static int ThrowNew(JNIEnvironment env, int throwableClassJREF, Address exceptionNameAddress) {
308    if (traceJNI) VM.sysWrite("JNI called: ThrowNew  \n");
309    RuntimeEntrypoints.checkJNICountDownToGC();
310
311    try {
312      Class<?> cls = (Class<?>) env.getJNIRef(throwableClassJREF);
313      // find the constructor that has a string as a parameter
314      Class<?>[] argClasses = new Class[1];
315      argClasses[0] = RVMType.JavaLangStringType.getClassForType();
316      Constructor<?> constMethod = cls.getConstructor(argClasses);
317      // prepare the parameter list for reflective invocation
318      Object[] argObjs = new Object[1];
319      argObjs[0] = JNIGenericHelpers.createStringFromC(exceptionNameAddress);
320
321      // invoke the constructor to obtain a new Throwable object
322      env.recordException((Throwable) constMethod.newInstance(argObjs));
323      return 0;
324    } catch (Throwable unexpected) {
325      if (traceJNI) unexpected.printStackTrace(System.err);
326      env.recordException(unexpected);
327      return -1;
328    }
329
330  }
331
332  /**
333   * ExceptionOccurred
334   * @param env A JREF index for the JNI environment object
335   * @return a JREF index for the pending exception or null if nothing pending
336   */
337  private static int ExceptionOccurred(JNIEnvironment env) {
338    if (traceJNI) VM.sysWrite("JNI called: ExceptionOccurred  \n");
339    RuntimeEntrypoints.checkJNICountDownToGC();
340
341    try {
342      Throwable e = env.getException();
343      if (e == null) {
344        return 0;
345      } else {
346        if (traceJNI) System.err.println(e.toString());
347        return env.pushJNIRef(e);
348      }
349    } catch (Throwable unexpected) {
350      if (traceJNI) unexpected.printStackTrace(System.err);
351      env.recordException(unexpected);
352      return env.pushJNIRef(unexpected);
353    }
354  }
355
356  /**
357   * ExceptionDescribe: print the exception description and the stack trace back,
358   *                    then clear the exception
359   * @param env A JREF index for the JNI environment object
360   */
361  private static void ExceptionDescribe(JNIEnvironment env) {
362    if (traceJNI) VM.sysWrite("JNI called: ExceptionDescribe  \n");
363    RuntimeEntrypoints.checkJNICountDownToGC();
364
365    try {
366      Throwable e = env.getException();
367      if (e != null) {
368        env.recordException(null);
369        e.printStackTrace(System.err);
370      }
371    } catch (Throwable unexpected) {
372      if (traceJNI) unexpected.printStackTrace(System.err);
373      env.recordException(null);            // clear old exception and register new one
374      env.recordException(unexpected);
375    }
376  }
377
378  /**
379   * ExceptionClear
380   * @param env A JREF index for the JNI environment object
381   */
382  private static void ExceptionClear(JNIEnvironment env) {
383    if (traceJNI) VM.sysWrite("JNI called: ExceptionClear  \n");
384    RuntimeEntrypoints.checkJNICountDownToGC();
385
386    try {
387      env.recordException(null);
388    } catch (Throwable unexpected) {
389      if (traceJNI) unexpected.printStackTrace(System.err);
390      env.recordException(null);            // clear old exception and register new one
391      env.recordException(unexpected);
392    }
393  }
394
395  /**
396   * FatalError: print a message and terminate the VM
397   * @param env A JREF index for the JNI environment object
398   * @param messageAddress an address of the string in C
399   */
400  private static void FatalError(JNIEnvironment env, Address messageAddress) {
401    if (traceJNI) VM.sysWrite("JNI called: FatalError  \n");
402    RuntimeEntrypoints.checkJNICountDownToGC();
403
404    try {
405      VM.sysWrite(JNIGenericHelpers.createStringFromC(messageAddress));
406      System.exit(EXIT_STATUS_JNI_TROUBLE);
407    } catch (Throwable unexpected) {
408      if (traceJNI) unexpected.printStackTrace(System.err);
409      System.exit(EXIT_STATUS_RECURSIVELY_SHUTTING_DOWN);
410    }
411  }
412
413  private static int NewGlobalRef(JNIEnvironment env, int objectJREF) {
414    if (traceJNI) VM.sysWrite("JNI called: NewGlobalRef\n");
415    RuntimeEntrypoints.checkJNICountDownToGC();
416
417    try {
418      Object obj1 = env.getJNIRef(objectJREF);
419      return JNIGlobalRefTable.newGlobalRef(obj1);
420    } catch (Throwable unexpected) {
421      if (traceJNI) unexpected.printStackTrace(System.err);
422      env.recordException(unexpected);
423      return 0;
424    }
425  }
426
427  private static void DeleteGlobalRef(JNIEnvironment env, int refJREF) {
428    if (traceJNI) VM.sysWrite("JNI called: DeleteGlobalRef\n");
429    RuntimeEntrypoints.checkJNICountDownToGC();
430
431    try {
432      JNIGlobalRefTable.deleteGlobalRef(refJREF);
433    } catch (Throwable unexpected) {
434      if (traceJNI) unexpected.printStackTrace(System.err);
435      env.recordException(unexpected);
436    }
437  }
438
439  private static void DeleteLocalRef(JNIEnvironment env, int objJREF) {
440    if (traceJNI) VM.sysWrite("JNI called: DeleteLocalRef\n");
441    RuntimeEntrypoints.checkJNICountDownToGC();
442
443    try {
444      env.deleteJNIRef(objJREF);
445    } catch (ArrayIndexOutOfBoundsException e) {
446      VM.sysFail("JNI refs array confused, or DeleteLocalRef gave us a bad JREF argument:", objJREF);
447    } catch (Throwable unexpected) {
448      if (traceJNI) unexpected.printStackTrace(System.err);
449      env.recordException(unexpected);
450    }
451  }
452
453  /**
454   * IsSameObject: determine if two references point to the same object
455   * @param env A JREF index for the JNI environment object
456   * @param obj1JREF A JREF index for the first object
457   * @param obj2JREF A JREF index for the second object
458   * @return <code>true</code> if it's the same object, false otherwise
459   */
460  private static boolean IsSameObject(JNIEnvironment env, int obj1JREF, int obj2JREF) {
461    if (traceJNI) VM.sysWrite("JNI called: IsSameObject  \n");
462    RuntimeEntrypoints.checkJNICountDownToGC();
463
464    try {
465      Object obj1 = env.getJNIRef(obj1JREF);
466      Object obj2 = env.getJNIRef(obj2JREF);
467      return obj1 == obj2;
468    } catch (Throwable unexpected) {
469      if (traceJNI) unexpected.printStackTrace(System.err);
470      env.recordException(null);            // clear old exception and register new one
471      env.recordException(unexpected);
472      return false;
473    }
474  }
475
476  /**
477   * AllocObject:  allocate the space for an object without running any constructor
478   *               the header is filled and the fields are initialized to null
479   * @param env A JREF index for the JNI environment object
480   * @param classJREF a JREF index for the class object
481   * @return a JREF index for the uninitialized object
482   * @throws InstantiationException if the class is abstract or is an interface
483   * @throws OutOfMemoryError if no more memory to allocate
484   */
485  private static int AllocObject(JNIEnvironment env, int classJREF) throws InstantiationException, OutOfMemoryError {
486    if (traceJNI) VM.sysWrite("JNI called: AllocObject  \n");
487    RuntimeEntrypoints.checkJNICountDownToGC();
488
489    try {
490      Class<?> javaCls = (Class<?>) env.getJNIRef(classJREF);
491      RVMType type = java.lang.JikesRVMSupport.getTypeForClass(javaCls);
492      if (type.isArrayType() || type.isPrimitiveType() || type.isUnboxedType()) {
493        env.recordException(new InstantiationException());
494        return 0;
495      }
496      RVMClass cls = type.asClass();
497      if (cls.isAbstract() || cls.isInterface()) {
498        env.recordException(new InstantiationException());
499        return 0;
500      }
501      Object newObj = RuntimeEntrypoints.resolvedNewScalar(cls);
502      return env.pushJNIRef(newObj);
503    } catch (Throwable unexpected) {
504      if (traceJNI) unexpected.printStackTrace(System.err);
505      env.recordException(unexpected);
506      return 0;
507    }
508  }
509
510  /**
511   * NewObject: create a new object instance
512   * NOTE:  the vararg's are not visible in the method signature here;
513   *        they are saved in the caller frame and the glue frame
514   * <p>
515   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
516   * with a C implementation in the bootloader when the VM starts.</strong>
517   * @param env A JREF index for the JNI environment object
518   * @param classJREF a JREF index for the class object
519   * @param methodID id of a MethodReference
520   * @return the new object instance
521   * @throws InstantiationException if the class is abstract or is an interface
522   * @throws OutOfMemoryError if no more memory to allocate
523   */
524  private static int NewObject(JNIEnvironment env, int classJREF, int methodID) throws Exception {
525    if (VM.VerifyAssertions) {
526      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
527    }
528    if (traceJNI) VM.sysWrite("JNI called: NewObject  \n");
529    RuntimeEntrypoints.checkJNICountDownToGC();
530
531    try {
532      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
533      RVMClass vmcls = java.lang.JikesRVMSupport.getTypeForClass(cls).asClass();
534
535      if (vmcls.isAbstract() || vmcls.isInterface()) {
536        env.recordException(new InstantiationException());
537        return 0;
538      }
539
540      Object newobj = JNIHelpers.invokeInitializer(cls, methodID, Address.zero(), false, true);
541
542      return env.pushJNIRef(newobj);
543    } catch (Throwable unexpected) {
544      if (traceJNI) unexpected.printStackTrace(System.err);
545      env.recordException(unexpected);
546      return 0;
547    }
548  }
549
550  /**
551   * NewObjectV: create a new object instance
552   * @param env A JREF index for the JNI environment object
553   * @param classJREF a JREF index for the class object
554   * @param methodID id of a MethodReference
555   * @param argAddress a raw address to a variable argument list, each element is 1-word or
556   *                   2-words of the appropriate type for the constructor invocation
557   * @return the new object instance
558   * @throws InstantiationException if the class is abstract or is an interface
559   * @throws OutOfMemoryError if no more memory to allocate
560   */
561  private static int NewObjectV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
562      throws Exception {
563    if (traceJNI) VM.sysWrite("JNI called: NewObjectV  \n");
564    RuntimeEntrypoints.checkJNICountDownToGC();
565
566    try {
567      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
568      RVMClass vmcls = java.lang.JikesRVMSupport.getTypeForClass(cls).asClass();
569      if (vmcls.isAbstract() || vmcls.isInterface()) {
570        env.recordException(new InstantiationException());
571        return 0;
572      }
573
574      Object newobj = JNIHelpers.invokeInitializer(cls, methodID, argAddress, false, false);
575
576      return env.pushJNIRef(newobj);
577    } catch (Throwable unexpected) {
578      if (traceJNI) unexpected.printStackTrace(System.err);
579      env.recordException(unexpected);
580      return 0;
581    }
582  }
583
584  /**
585   * NewObjectA: create a new object instance
586   * @param env A JREF index for the JNI environment object
587   * @param classJREF a JREF index for the class object
588   * @param methodID id of a MethodReference
589   * @param argAddress a raw address to an array of unions in C, each element is 2-word and
590   *                   hold an argument of the appropriate type for the constructor invocation
591   * @throws InstantiationException if the class is abstract or is an interface
592   * @throws OutOfMemoryError if no more memory to allocate
593   * @return the new object instance
594   */
595  private static int NewObjectA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
596      throws Exception {
597    if (traceJNI) VM.sysWrite("JNI called: NewObjectA  \n");
598    RuntimeEntrypoints.checkJNICountDownToGC();
599
600    try {
601      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
602      RVMClass vmcls = java.lang.JikesRVMSupport.getTypeForClass(cls).asClass();
603
604      if (vmcls.isAbstract() || vmcls.isInterface()) {
605        env.recordException(new InstantiationException());
606        return 0;
607      }
608
609      Object newobj = JNIHelpers.invokeInitializer(cls, methodID, argAddress, true, false);
610
611      return env.pushJNIRef(newobj);
612    } catch (Throwable unexpected) {
613      if (traceJNI) unexpected.printStackTrace(System.err);
614      env.recordException(unexpected);
615      return 0;
616    }
617  }
618
619  /**
620   * GetObjectClass
621   * @param env A JREF index for the JNI environment object
622   * @param objJREF a JREF index for the object to check
623   * @return a JREF index for the Class object
624   */
625  private static int GetObjectClass(JNIEnvironment env, int objJREF) {
626    if (traceJNI) VM.sysWrite("JNI called: GetObjectClass  \n");
627    RuntimeEntrypoints.checkJNICountDownToGC();
628
629    try {
630      Object obj = env.getJNIRef(objJREF);
631      return env.pushJNIRef(obj.getClass());
632    } catch (Throwable unexpected) {
633      if (traceJNI) unexpected.printStackTrace(System.err);
634      env.recordException(unexpected);
635      return 0;
636    }
637  }
638
639  /**
640   * IsInstanceOf: determine if an object is an instance of the class.
641   * <p>
642   * NOTE: the function behaviour is defined via the behaviour of checkcast
643   * and NOT instanceof as the name of this function would suggest. See
644   * the JNI spec for details.
645   *
646   * @param env A JREF index for the JNI environment object
647   * @param objJREF a JREF index for the object to check
648   * @param classJREF a JREF index for the class to check
649   * @return true if the object is an instance of the class
650   */
651  private static int IsInstanceOf(JNIEnvironment env, int objJREF, int classJREF) {
652    if (traceJNI) VM.sysWrite("JNI called: IsInstanceOf  \n");
653    RuntimeEntrypoints.checkJNICountDownToGC();
654
655    try {
656      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
657      Object obj = env.getJNIRef(objJREF);
658      // "null instanceof T" is always false but the function behaviour is defined via
659      // checkcast. So we're actually checking "(T) null" which will always succeed.
660      if (obj == null) return 1;
661      RVMType RHStype = ObjectModel.getObjectType(obj);
662      RVMType LHStype = java.lang.JikesRVMSupport.getTypeForClass(cls);
663      return (LHStype == RHStype || RuntimeEntrypoints.isAssignableWith(LHStype, RHStype)) ? 1 : 0;
664    } catch (Throwable unexpected) {
665      if (traceJNI) unexpected.printStackTrace(System.err);
666      env.recordException(unexpected);
667      return 0;
668    }
669  }
670
671  /**
672   * GetMethodID:  get the virtual method ID given the name and the signature
673   * @param env A JREF index for the JNI environment object
674   * @param classJREF a JREF index for the class object
675   * @param methodNameAddress a raw address to a null-terminated string in C for the method name
676   * @param methodSigAddress a raw address to a null-terminated string in C for the method signature
677   * @return id of a MethodReference
678   * @throws NoSuchMethodError if the method cannot be found
679   * @throws ExceptionInInitializerError if the class or interface static initializer fails
680   * @throws OutOfMemoryError if the system runs out of memory
681   */
682  private static int GetMethodID(JNIEnvironment env, int classJREF, Address methodNameAddress,
683                                 Address methodSigAddress) {
684    if (traceJNI) VM.sysWrite("JNI called: GetMethodID  \n");
685    RuntimeEntrypoints.checkJNICountDownToGC();
686
687    try {
688      // obtain the names as String from the native space
689      String methodString = JNIGenericHelpers.createStringFromC(methodNameAddress);
690      Atom methodName = Atom.findOrCreateAsciiAtom(methodString);
691      String sigString = JNIGenericHelpers.createStringFromC(methodSigAddress);
692      Atom sigName = Atom.findOrCreateAsciiAtom(sigString);
693
694      // get the target class
695      Class<?> jcls = (Class<?>) env.getJNIRef(classJREF);
696      RVMType type = java.lang.JikesRVMSupport.getTypeForClass(jcls);
697      if (!type.isClassType()) {
698        env.recordException(new NoSuchMethodError());
699        return 0;
700      }
701
702      RVMClass klass = type.asClass();
703      if (!klass.isInitialized()) {
704        RuntimeEntrypoints.initializeClassForDynamicLink(klass);
705      }
706
707      // Find the target method
708      final RVMMethod meth;
709      if (methodString.equals("<init>")) {
710        meth = klass.findInitializerMethod(sigName);
711      } else {
712        meth = klass.findVirtualMethod(methodName, sigName);
713      }
714
715      if (meth == null) {
716        env.recordException(new NoSuchMethodError(klass + ": " + methodName + " " + sigName));
717        return 0;
718      }
719
720      if (traceJNI) VM.sysWrite("got method " + meth + "\n");
721      return meth.getId();
722    } catch (Throwable unexpected) {
723      if (traceJNI) unexpected.printStackTrace(System.err);
724      env.recordException(unexpected);
725      return 0;
726    }
727  }
728
729  /**
730   * CallObjectMethod:  invoke a virtual method that returns an object
731   *                           arguments passed using the vararg ... style
732   * NOTE:  the vararg's are not visible in the method signature here;
733   *        they are saved in the caller frame and the glue frame
734   * <p>
735   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
736   * with a C implementation in the bootloader when the VM starts.</strong>
737   * @param env A JREF index for the JNI environment object
738   * @param objJREF a JREF index for the object instance
739   * @param methodID id of a MethodReference
740   * @return the JREF index for the object returned from the method invocation
741   * @throws Exception exceptions thrown by the called method
742   */
743  private static int CallObjectMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
744    if (VM.VerifyAssertions) {
745      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
746    }
747    if (traceJNI) VM.sysWrite("JNI called: CallObjectMethod  \n");
748    RuntimeEntrypoints.checkJNICountDownToGC();
749
750    try {
751      Object obj = env.getJNIRef(objJREF);
752      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, null, false);
753      return env.pushJNIRef(returnObj);
754    } catch (Throwable unexpected) {
755      if (traceJNI) unexpected.printStackTrace(System.err);
756      env.recordException(unexpected);
757      return 0;
758    }
759  }
760
761  /**
762   * CallObjectMethodV:  invoke a virtual method that returns an object
763   * @param env A JREF index for the JNI environment object
764   * @param objJREF a JREF index for the object instance
765   * @param methodID id of a MethodReference
766   * @param argAddress a raw address to a variable argument list, each element is
767   *              1-word or 2-words of the appropriate type for the method invocation
768   * @return the JREF index for the object returned from the method invocation
769   * @throws Exception exceptions thrown by the called method
770   */
771  private static int CallObjectMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
772      throws Exception {
773    if (traceJNI) VM.sysWrite("JNI called: CallObjectMethodV  \n");
774    RuntimeEntrypoints.checkJNICountDownToGC();
775
776    try {
777      Object obj = env.getJNIRef(objJREF);
778      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, null, false);
779      return env.pushJNIRef(returnObj);
780    } catch (Throwable unexpected) {
781      if (traceJNI) unexpected.printStackTrace(System.err);
782      env.recordException(unexpected);
783      return 0;
784    }
785  }
786
787  /**
788   * CallObjectMethodA:  invoke a virtual method that returns an object value
789   * @param env A JREF index for the JNI environment object
790   * @param objJREF a JREF index for the object instance
791   * @param methodID id of a MethodReference
792   * @param argAddress address of an array of jvalues (jvalue*)
793   * @return the JREF index for the object returned from the method invocation
794   * @throws Exception exceptions thrown by the called method
795   */
796  private static int CallObjectMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
797      throws Exception {
798    if (traceJNI) VM.sysWrite("JNI called: CallObjectMethodA  \n");
799    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, null /* return type */, false);
800    return env.pushJNIRef(returnObj);
801  }
802
803  /**
804   * CallBooleanMethod:  invoke a virtual method that returns a boolean value
805   *                           arguments passed using the vararg ... style
806   * NOTE:  the vararg's are not visible in the method signature here;
807   *        they are saved in the caller frame and the glue frame
808   * <p>
809   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
810   * with a C implementation in the bootloader when the VM starts.</strong>
811   * @param env A JREF index for the JNI environment object
812   * @param objJREF a JREF index for the object instance
813   * @param methodID id of a MethodReference
814   * @return the boolean value returned from the method invocation
815   * @throws Exception exceptions thrown by the called method
816   */
817  private static boolean CallBooleanMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
818    if (VM.VerifyAssertions) {
819      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
820    }
821    if (traceJNI) VM.sysWrite("JNI called: CallBooleanMethod  \n");
822    RuntimeEntrypoints.checkJNICountDownToGC();
823
824    try {
825      Object obj = env.getJNIRef(objJREF);
826      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Boolean, false);
827      return Reflection.unwrapBoolean(returnObj);     // should be a wrapper for a boolean value
828    } catch (Throwable unexpected) {
829      if (traceJNI) unexpected.printStackTrace(System.err);
830      env.recordException(unexpected);
831      return false;
832    }
833  }
834
835  /**
836   * CallBooleanMethodV:  invoke a virtual method that returns a boolean value
837   * @param env A JREF index for the JNI environment object
838   * @param objJREF a JREF index for the object instance
839   * @param methodID id of a MethodReference
840   * @param argAddress a raw address to a variable argument list, each element is
841   *              1-word or 2-words of the appropriate type for the method invocation
842   * @return the boolean value returned from the method invocation
843   * @throws Exception exceptions thrown by the called method
844   */
845  private static boolean CallBooleanMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
846      throws Exception {
847    if (traceJNI) VM.sysWrite("JNI called: CallBooleanMethodV  \n");
848    RuntimeEntrypoints.checkJNICountDownToGC();
849
850    try {
851      Object obj = env.getJNIRef(objJREF);
852      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Boolean, false);
853      return Reflection.unwrapBoolean(returnObj);     // should be a wrapper for a boolean value
854    } catch (Throwable unexpected) {
855      if (traceJNI) unexpected.printStackTrace(System.err);
856      env.recordException(unexpected);
857      return false;
858    }
859  }
860
861  /**
862   * CallBooleanMethodA:  invoke a virtual method that returns a boolean value
863   * @param env A JREF index for the JNI environment object
864   * @param objJREF a JREF index for the object instance
865   * @param methodID id of a MethodReference
866   * @param argAddress address of an array of jvalues (jvalue*)
867   * @return the boolean value returned from the method invocation
868   * @throws Exception exceptions thrown by the called method
869   */
870  private static boolean CallBooleanMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
871      throws Exception {
872    if (traceJNI) VM.sysWrite("JNI called: CallBooleanMethodA  \n");
873    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Boolean, false);
874    return Reflection.unwrapBoolean(returnObj);
875  }
876
877  /**
878   * CallByteMethod:  invoke a virtual method that returns a byte value
879   *                           arguments passed using the vararg ... style
880   * NOTE:  the vararg's are not visible in the method signature here;
881   *        they are saved in the caller frame and the glue frame
882   * <p>
883   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
884   * with a C implementation in the bootloader when the VM starts.</strong>
885   * @param env A JREF index for the JNI environment object
886   * @param objJREF a JREF index for the object instance
887   * @param methodID id of a MethodReference
888   * @return the byte value returned from the method invocation
889   * @throws Exception exceptions thrown by the called method
890   */
891  private static byte CallByteMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
892    if (VM.VerifyAssertions) {
893      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
894    }
895    if (traceJNI) VM.sysWrite("JNI called: CallByteMethod  \n");
896    RuntimeEntrypoints.checkJNICountDownToGC();
897
898    try {
899      Object obj = env.getJNIRef(objJREF);
900      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Byte, false);
901      return Reflection.unwrapByte(returnObj);     // should be a wrapper for a byte value
902    } catch (Throwable unexpected) {
903      if (traceJNI) unexpected.printStackTrace(System.err);
904      env.recordException(unexpected);
905      return 0;
906    }
907  }
908
909  /**
910   * CallByteMethodV:  invoke a virtual method that returns a byte value
911   * @param env A JREF index for the JNI environment object
912   * @param objJREF a JREF index for the object instance
913   * @param methodID id of a MethodReference
914   * @param argAddress a raw address to a variable argument list, each element is
915   *              1-word or 2-words of the appropriate type for the method invocation
916   * @return the byte value returned from the method invocation
917   * @throws Exception exceptions thrown by the called method
918   */
919  private static byte CallByteMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
920      throws Exception {
921    if (traceJNI) VM.sysWrite("JNI called: CallByteMethodV  \n");
922    RuntimeEntrypoints.checkJNICountDownToGC();
923
924    try {
925      Object obj = env.getJNIRef(objJREF);
926      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Byte, false);
927      return Reflection.unwrapByte(returnObj);     // should be a wrapper for a byte value
928    } catch (Throwable unexpected) {
929      if (traceJNI) unexpected.printStackTrace(System.err);
930      env.recordException(unexpected);
931      return 0;
932    }
933  }
934
935  /**
936   * CallByteMethodA:  invoke a virtual method that returns a byte value
937   * @param env A JREF index for the JNI environment object
938   * @param objJREF a JREF index for the object instance
939   * @param methodID id of a MethodReference
940   * @param argAddress address of an array of jvalues (jvalue*)
941   * @return the byte value returned from the method invocation
942   * @throws Exception exceptions thrown by the called method
943   */
944  private static byte CallByteMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
945      throws Exception {
946    if (traceJNI) VM.sysWrite("JNI called: CallByteMethodA  \n");
947    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Byte, false);
948    return Reflection.unwrapByte(returnObj);
949  }
950
951  /**
952   * CallCharMethod:  invoke a virtual method that returns a char value
953   *                           arguments passed using the vararg ... style
954   * NOTE:  the vararg's are not visible in the method signature here;
955   *        they are saved in the caller frame and the glue frame
956   * <p>
957   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
958   * with a C implementation in the bootloader when the VM starts.</strong>
959   * @param env A JREF index for the JNI environment object
960   * @param objJREF a JREF index for the object instance
961   * @param methodID id of a MethodReference
962   * @return the char value returned from the method invocation
963   * @throws Exception exceptions thrown by the called method
964   */
965  private static char CallCharMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
966    if (VM.VerifyAssertions) {
967      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
968    }
969    if (traceJNI) VM.sysWrite("JNI called: CallCharMethod  \n");
970    RuntimeEntrypoints.checkJNICountDownToGC();
971
972    try {
973      Object obj = env.getJNIRef(objJREF);
974      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Char, false);
975      return Reflection.unwrapChar(returnObj);     // should be a wrapper for a char value
976    } catch (Throwable unexpected) {
977      if (traceJNI) unexpected.printStackTrace(System.err);
978      env.recordException(unexpected);
979      return 0;
980    }
981  }
982
983  /**
984   * CallCharMethodV:  invoke a virtual method that returns a char value
985   * @param env A JREF index for the JNI environment object
986   * @param objJREF a JREF index for the object instance
987   * @param methodID id of a MethodReference
988   * @param argAddress a raw address to a variable argument list, each element is
989   *              1-word or 2-words of the appropriate type for the method invocation
990   * @return the char value returned from the method invocation
991   * @throws Exception exceptions thrown by the called method
992   */
993  private static char CallCharMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
994      throws Exception {
995    if (traceJNI) VM.sysWrite("JNI called: CallCharMethodV  \n");
996    RuntimeEntrypoints.checkJNICountDownToGC();
997
998    try {
999      Object obj = env.getJNIRef(objJREF);
1000      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Char, false);
1001      return Reflection.unwrapChar(returnObj);     // should be a wrapper for a char value
1002    } catch (Throwable unexpected) {
1003      if (traceJNI) unexpected.printStackTrace(System.err);
1004      env.recordException(unexpected);
1005      return 0;
1006    }
1007  }
1008
1009  /**
1010   * CallCharMethodA:  invoke a virtual method that returns a char value
1011   * @param env A JREF index for the JNI environment object
1012   * @param objJREF a JREF index for the object instance
1013   * @param methodID id of a MethodReference
1014   * @param argAddress address of an array of jvalues (jvalue*)
1015   * @return the char value returned from the method invocation
1016   * @throws Exception exceptions thrown by the called method
1017   */
1018  private static char CallCharMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1019      throws Exception {
1020    if (traceJNI) VM.sysWrite("JNI called: CallCharMethodA  \n");
1021    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Char, false);
1022    return Reflection.unwrapChar(returnObj);
1023  }
1024
1025  /**
1026   * CallShortMethod:  invoke a virtual method that returns a short value
1027   *                           arguments passed using the vararg ... style
1028   * NOTE:  the vararg's are not visible in the method signature here;
1029   *        they are saved in the caller frame and the glue frame
1030   * <p>
1031   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1032   * with a C implementation in the bootloader when the VM starts.</strong>
1033   * @param env A JREF index for the JNI environment object
1034   * @param objJREF a JREF index for the object instance
1035   * @param methodID id of a MethodReference
1036   * @return the short value returned from the method invocation
1037   * @throws Exception exceptions thrown by the called method
1038   */
1039  private static short CallShortMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
1040    if (VM.VerifyAssertions) {
1041      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1042    }
1043    if (traceJNI) VM.sysWrite("JNI called: CallShortMethod  \n");
1044    RuntimeEntrypoints.checkJNICountDownToGC();
1045
1046    try {
1047      Object obj = env.getJNIRef(objJREF);
1048      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Short, false);
1049      return Reflection.unwrapShort(returnObj);     // should be a wrapper for a short value
1050    } catch (Throwable unexpected) {
1051      if (traceJNI) unexpected.printStackTrace(System.err);
1052      env.recordException(unexpected);
1053      return 0;
1054    }
1055  }
1056
1057  /**
1058   * CallShortMethodV:  invoke a virtual method that returns a short value
1059   * @param env A JREF index for the JNI environment object
1060   * @param objJREF a JREF index for the object instance
1061   * @param methodID id of a MethodReference
1062   * @param argAddress a raw address to a variable argument list, each element is
1063   *              1-word or 2-words of the appropriate type for the method invocation
1064   * @return the short value returned from the method invocation
1065   * @throws Exception exceptions thrown by the called method
1066   */
1067  private static short CallShortMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1068      throws Exception {
1069    if (traceJNI) VM.sysWrite("JNI called: CallShortMethodV  \n");
1070    RuntimeEntrypoints.checkJNICountDownToGC();
1071
1072    try {
1073      Object obj = env.getJNIRef(objJREF);
1074      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Short, false);
1075      return Reflection.unwrapShort(returnObj);     // should be a wrapper for a short value
1076    } catch (Throwable unexpected) {
1077      if (traceJNI) unexpected.printStackTrace(System.err);
1078      env.recordException(unexpected);
1079      return 0;
1080    }
1081  }
1082
1083  /**
1084   * CallShortMethodA:  invoke a virtual method that returns a short value
1085   * @param env A JREF index for the JNI environment object
1086   * @param objJREF a JREF index for the object instance
1087   * @param methodID id of a MethodReference
1088   * @param argAddress address of an array of jvalues (jvalue*)
1089   * @return the short value returned from the method invocation
1090   * @throws Exception exceptions thrown by the called method
1091   */
1092  private static short CallShortMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1093      throws Exception {
1094    if (traceJNI) VM.sysWrite("JNI called: CallShortMethodA  \n");
1095    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Short, false);
1096    return Reflection.unwrapShort(returnObj);
1097  }
1098
1099  /**
1100   * CallIntMethod:  invoke a virtual method that returns a int value
1101   *                           arguments passed using the vararg ... style
1102   * NOTE:  the vararg's are not visible in the method signature here;
1103   *        they are saved in the caller frame and the glue frame
1104   * <p>
1105   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1106   * with a C implementation in the bootloader when the VM starts.</strong>
1107   * @param env A JREF index for the JNI environment object
1108   * @param objJREF a JREF index for the object instance
1109   * @param methodID id of a MethodReference
1110   * @return the int value returned from the method invocation
1111   * @throws Exception exceptions thrown by the called method
1112   */
1113  private static int CallIntMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
1114    if (VM.VerifyAssertions) {
1115      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1116    }
1117    if (traceJNI) VM.sysWrite("JNI called: CallIntMethod  \n");
1118    RuntimeEntrypoints.checkJNICountDownToGC();
1119
1120    try {
1121      Object obj = env.getJNIRef(objJREF);
1122      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Int, false);
1123      return Reflection.unwrapInt(returnObj);     // should be a wrapper for an integer value
1124    } catch (Throwable unexpected) {
1125      if (traceJNI) unexpected.printStackTrace(System.err);
1126      env.recordException(unexpected);
1127      return 0;
1128    }
1129  }
1130
1131  /**
1132   * CallIntMethodV:  invoke a virtual method that returns an int value
1133   * @param env A JREF index for the JNI environment object
1134   * @param objJREF a JREF index for the object instance
1135   * @param methodID id of a MethodReference
1136   * @param argAddress a raw address to a variable argument list, each element is
1137   *              1-word or 2-words of the appropriate type for the method invocation
1138   * @return the int value returned from the method invocation
1139   * @throws Exception exceptions thrown by the called method
1140   */
1141  private static int CallIntMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1142      throws Exception {
1143    if (traceJNI) VM.sysWrite("JNI called: CallIntMethodV  \n");
1144    RuntimeEntrypoints.checkJNICountDownToGC();
1145
1146    try {
1147      Object obj = env.getJNIRef(objJREF);
1148      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Int, false);
1149      return Reflection.unwrapInt(returnObj);     // should be a wrapper for an integer value
1150    } catch (Throwable unexpected) {
1151      if (traceJNI) unexpected.printStackTrace(System.err);
1152      env.recordException(unexpected);
1153      return 0;
1154    }
1155  }
1156
1157  /**
1158   * CallIntMethodA:  invoke a virtual method that returns an integer value
1159   * @param env A JREF index for the JNI environment object
1160   * @param objJREF a JREF index for the object instance
1161   * @param methodID id of a MethodReference
1162   * @param argAddress address of an array of jvalues (jvalue*)
1163   * @return the integer value returned from the method invocation
1164   * @throws Exception exceptions thrown by the called method
1165   */
1166  private static int CallIntMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1167      throws Exception {
1168    if (traceJNI) VM.sysWrite("JNI called: CallIntMethodA  \n");
1169    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Int, false);
1170    return Reflection.unwrapInt(returnObj);
1171  }
1172
1173  /**
1174   * CallLongMethod:  invoke a virtual method that returns a long value
1175   *                           arguments passed using the vararg ... style
1176   * NOTE:  the vararg's are not visible in the method signature here;
1177   *        they are saved in the caller frame and the glue frame
1178   * <p>
1179   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1180   * with a C implementation in the bootloader when the VM starts.</strong>
1181   * @param env A JREF index for the JNI environment object
1182   * @param objJREF a JREF index for the object instance
1183   * @param methodID id of a MethodReference
1184   * @return the long value returned from the method invocation
1185   * @throws Exception exceptions thrown by the called method
1186   */
1187  private static long CallLongMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
1188    if (VM.VerifyAssertions) {
1189      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1190    }
1191    if (traceJNI) VM.sysWrite("JNI called: CallLongMethod  \n");
1192    RuntimeEntrypoints.checkJNICountDownToGC();
1193
1194    try {
1195      Object obj = env.getJNIRef(objJREF);
1196      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Long, false);
1197      return Reflection.unwrapLong(returnObj);     // should be a wrapper for a long value
1198    } catch (Throwable unexpected) {
1199      if (traceJNI) unexpected.printStackTrace(System.err);
1200      env.recordException(unexpected);
1201      return 0;
1202    }
1203  }
1204
1205  /**
1206   * CallLongMethodV:  invoke a virtual method that returns a long value
1207   * @param env A JREF index for the JNI environment object
1208   * @param objJREF a JREF index for the object instance
1209   * @param methodID id of a MethodReference
1210   * @param argAddress a raw address to a variable argument list, each element is
1211   *              1-word or 2-words of the appropriate type for the method invocation
1212   * @return the long value returned from the method invocation
1213   * @throws Exception exceptions thrown by the called method
1214   */
1215  private static long CallLongMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1216      throws Exception {
1217    if (traceJNI) VM.sysWrite("JNI called: CallLongMethodV  \n");
1218    RuntimeEntrypoints.checkJNICountDownToGC();
1219
1220    try {
1221      Object obj = env.getJNIRef(objJREF);
1222      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Long, false);
1223      return Reflection.unwrapLong(returnObj);     // should be a wrapper for a long value
1224    } catch (Throwable unexpected) {
1225      if (traceJNI) unexpected.printStackTrace(System.err);
1226      env.recordException(unexpected);
1227      return 0;
1228    }
1229  }
1230
1231  /**
1232   * CallLongMethodA:  invoke a virtual method that returns a long value
1233   * @param env A JREF index for the JNI environment object
1234   * @param objJREF a JREF index for the object instance
1235   * @param methodID id of a MethodReference
1236   * @param argAddress address of an array of jvalues (jvalue*)
1237   * @return the long value returned from the method invocation
1238   * @throws Exception exceptions thrown by the called method
1239   */
1240  private static long CallLongMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1241      throws Exception {
1242    if (traceJNI) VM.sysWrite("JNI called: CallLongMethodA  \n");
1243    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Long, false);
1244    return Reflection.unwrapLong(returnObj);
1245  }
1246
1247  /**
1248   * CallFloatMethod:  invoke a virtual method that returns a float value
1249   *                           arguments passed using the vararg ... style
1250   * NOTE:  the vararg's are not visible in the method signature here;
1251   *        they are saved in the caller frame and the glue frame
1252   * <p>
1253   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1254   * with a C implementation in the bootloader when the VM starts.</strong>
1255   * @param env A JREF index for the JNI environment object
1256   * @param objJREF a JREF index for the object instance
1257   * @param methodID id of a MethodReference
1258   * @return the float value returned from the method invocation
1259   * @throws Exception exceptions thrown by the called method
1260   */
1261  private static float CallFloatMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
1262    if (VM.VerifyAssertions) {
1263      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1264    }
1265    if (traceJNI) VM.sysWrite("JNI called: CallFloatMethod  \n");
1266    RuntimeEntrypoints.checkJNICountDownToGC();
1267
1268    try {
1269      Object obj = env.getJNIRef(objJREF);
1270      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Float, false);
1271      return Reflection.unwrapFloat(returnObj);     // should be a wrapper for a float value
1272    } catch (Throwable unexpected) {
1273      if (traceJNI) unexpected.printStackTrace(System.err);
1274      env.recordException(unexpected);
1275      return 0;
1276    }
1277  }
1278
1279  /**
1280   * CallFloatMethodV:  invoke a virtual method that returns a float value
1281   * @param env A JREF index for the JNI environment object
1282   * @param objJREF a JREF index for the object instance
1283   * @param methodID id of a MethodReference
1284   * @param argAddress a raw address to a variable argument list, each element is
1285   *              1-word or 2-words of the appropriate type for the method invocation
1286   * @return the float value returned from the method invocation
1287   * @throws Exception exceptions thrown by the called method
1288   */
1289  private static float CallFloatMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1290      throws Exception {
1291    if (traceJNI) VM.sysWrite("JNI called: CallFloatMethodV  \n");
1292    RuntimeEntrypoints.checkJNICountDownToGC();
1293
1294    try {
1295      Object obj = env.getJNIRef(objJREF);
1296      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Float, false);
1297      return Reflection.unwrapFloat(returnObj);     // should be a wrapper for a float value
1298    } catch (Throwable unexpected) {
1299      if (traceJNI) unexpected.printStackTrace(System.err);
1300      env.recordException(unexpected);
1301      return 0;
1302    }
1303  }
1304
1305  /**
1306   * CallFloatMethodA:  invoke a virtual method that returns a float value
1307   * @param env A JREF index for the JNI environment object
1308   * @param objJREF a JREF index for the object instance
1309   * @param methodID id of a MethodReference
1310   * @param argAddress address of an array of jvalues (jvalue*)
1311   * @return the float value returned from the method invocation
1312   * @throws Exception exceptions thrown by the called method
1313   */
1314  private static float CallFloatMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1315      throws Exception {
1316    if (traceJNI) VM.sysWrite("JNI called: CallFloatMethodA  \n");
1317    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Float, false);
1318    return Reflection.unwrapFloat(returnObj);
1319  }
1320
1321  /**
1322   * CallDoubleMethod:  invoke a virtual method that returns a double value
1323   *                           arguments passed using the vararg ... style
1324   * NOTE:  the vararg's are not visible in the method signature here;
1325   *        they are saved in the caller frame and the glue frame
1326   * <p>
1327   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1328   * with a C implementation in the bootloader when the VM starts.</strong>
1329   * @param env A JREF index for the JNI environment object
1330   * @param objJREF a JREF index for the object instance
1331   * @param methodID id of a MethodReference
1332   * @return the double value returned from the method invocation
1333   * @throws Exception exceptions thrown by the called method
1334   */
1335  private static double CallDoubleMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
1336    if (VM.VerifyAssertions) {
1337      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1338    }
1339    if (traceJNI) VM.sysWrite("JNI called: CallDoubleMethod  \n");
1340    RuntimeEntrypoints.checkJNICountDownToGC();
1341
1342    try {
1343      Object obj = env.getJNIRef(objJREF);
1344      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Double, false);
1345      return Reflection.unwrapDouble(returnObj);     // should be a wrapper for a double value
1346    } catch (Throwable unexpected) {
1347      if (traceJNI) unexpected.printStackTrace(System.err);
1348      env.recordException(unexpected);
1349      return 0;
1350    }
1351  }
1352
1353  /**
1354   * CallDoubleMethodV:  invoke a virtual method that returns a double value
1355   * @param env A JREF index for the JNI environment object
1356   * @param objJREF a JREF index for the object instance
1357   * @param methodID id of a MethodReference
1358   * @param argAddress a raw address to a variable argument list, each element is
1359   *              1-word or 2-words of the appropriate type for the method invocation
1360   * @return the double value returned from the method invocation
1361   * @throws Exception exceptions thrown by the called method
1362   */
1363  private static double CallDoubleMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1364      throws Exception {
1365    if (traceJNI) VM.sysWrite("JNI called: CallDoubleMethodV  \n");
1366    RuntimeEntrypoints.checkJNICountDownToGC();
1367
1368    try {
1369      Object obj = env.getJNIRef(objJREF);
1370      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Double, false);
1371      return Reflection.unwrapDouble(returnObj);     // should be a wrapper for a double value
1372    } catch (Throwable unexpected) {
1373      if (traceJNI) unexpected.printStackTrace(System.err);
1374      env.recordException(unexpected);
1375      return 0;
1376    }
1377  }
1378
1379  /**
1380   * CallDoubleMethodA:  invoke a virtual method that returns a double value
1381   * @param env A JREF index for the JNI environment object
1382   * @param objJREF a JREF index for the object instance
1383   * @param methodID id of a MethodReference
1384   * @param argAddress address of an array of jvalues (jvalue*)
1385   * @return the double value returned from the method invocation
1386   * @throws Exception exceptions thrown by the called method
1387   */
1388  private static double CallDoubleMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1389      throws Exception {
1390    if (traceJNI) VM.sysWrite("JNI called: CallDoubleMethodA  \n");
1391    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Double, false);
1392    return Reflection.unwrapDouble(returnObj);
1393  }
1394
1395  /**
1396   * CallVoidMethod:  invoke a virtual method that returns a void value
1397   *                           arguments passed using the vararg ... style
1398   * NOTE:  the vararg's are not visible in the method signature here;
1399   *        they are saved in the caller frame and the glue frame
1400   * <p>
1401   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1402   * with a C implementation in the bootloader when the VM starts.</strong>
1403   * @param env A JREF index for the JNI environment object
1404   * @param objJREF a JREF index for the object instance
1405   * @param methodID id of a MethodReference
1406   * @throws Exception exceptions thrown by the called method
1407   */
1408  private static void CallVoidMethod(JNIEnvironment env, int objJREF, int methodID) throws Exception {
1409    if (VM.VerifyAssertions) {
1410      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1411    }
1412    if (traceJNI) VM.sysWrite("JNI called: CallVoidMethod  \n");
1413    RuntimeEntrypoints.checkJNICountDownToGC();
1414
1415    try {
1416      Object obj = env.getJNIRef(objJREF);
1417      JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Void, false);
1418    } catch (Throwable unexpected) {
1419      if (traceJNI) unexpected.printStackTrace(System.err);
1420      env.recordException(unexpected);
1421    }
1422  }
1423
1424  /**
1425   * CallVoidMethodV:  invoke a virtual method that returns void
1426   * @param env A JREF index for the JNI environment object
1427   * @param objJREF a JREF index for the object instance
1428   * @param methodID id of a MethodReference
1429   * @param argAddress a raw address to a variable argument list, each element is
1430   *              1-word or 2-words of the appropriate type for the method invocation
1431   * @throws Exception exceptions thrown by the called method
1432   */
1433  private static void CallVoidMethodV(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1434      throws Exception {
1435    if (traceJNI) VM.sysWrite("JNI called: CallVoidMethodV  \n");
1436    RuntimeEntrypoints.checkJNICountDownToGC();
1437
1438    try {
1439      Object obj = env.getJNIRef(objJREF);
1440      JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Void, false);
1441    } catch (Throwable unexpected) {
1442      if (traceJNI) unexpected.printStackTrace(System.err);
1443      env.recordException(unexpected);
1444    }
1445  }
1446
1447  /**
1448   * CallVoidMethodA:  invoke a virtual method that returns void
1449   * @param env A JREF index for the JNI environment object
1450   * @param objJREF a JREF index for the object instance
1451   * @param methodID id of a MethodReference
1452   * @param argAddress address of an array of jvalues (jvalue*)
1453   * @throws Exception exceptions thrown by the called method
1454   */
1455  private static void CallVoidMethodA(JNIEnvironment env, int objJREF, int methodID, Address argAddress)
1456      throws Exception {
1457    if (traceJNI) VM.sysWrite("JNI called: CallVoidMethodA  \n");
1458    JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Void, false);
1459  }
1460
1461  /**
1462   * CallNonvirtualObjectMethod:  invoke a virtual method that returns an object
1463   *                           arguments passed using the vararg ... style
1464   * NOTE:  the vararg's are not visible in the method signature here;
1465   *        they are saved in the caller frame and the glue frame
1466   * <p>
1467   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1468   * with a C implementation in the bootloader when the VM starts.</strong>
1469   * @param env A JREF index for the JNI environment object
1470   * @param objJREF a JREF index for the object instance
1471   * @param classJREF a JREF index for the class object that declares this method
1472   * @param methodID id of a MethodReference
1473   * @return the JREF index for the object returned from the method invocation
1474   * @throws Exception exceptions thrown by the called method
1475   */
1476  private static int CallNonvirtualObjectMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1477      throws Exception {
1478    if (VM.VerifyAssertions) {
1479      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1480    }
1481    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualObjectMethod  \n");
1482    RuntimeEntrypoints.checkJNICountDownToGC();
1483
1484    try {
1485      Object obj = env.getJNIRef(objJREF);
1486      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, null, true);
1487      return env.pushJNIRef(returnObj);
1488    } catch (Throwable unexpected) {
1489      if (traceJNI) unexpected.printStackTrace(System.err);
1490      env.recordException(unexpected);
1491      return 0;
1492    }
1493  }
1494
1495  /**
1496   * CallNonvirtualObjectMethodV:  invoke a virtual method that returns an object
1497   * @param env A JREF index for the JNI environment object
1498   * @param objJREF a JREF index for the object instance
1499   * @param classJREF a JREF index for the class object that declares this method
1500   * @param methodID id of a MethodReference
1501   * @param argAddress a raw address to a variable argument list, each element is
1502   *              1-word or 2-words of the appropriate type for the method invocation
1503   * @return the JREF index for the object returned from the method invocation
1504   * @throws Exception exceptions thrown by the called method
1505   */
1506  private static int CallNonvirtualObjectMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1507                                                 Address argAddress) throws Exception {
1508    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualObjectMethodV  \n");
1509    RuntimeEntrypoints.checkJNICountDownToGC();
1510
1511    try {
1512      Object obj = env.getJNIRef(objJREF);
1513      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, null, true);
1514      return env.pushJNIRef(returnObj);
1515    } catch (Throwable unexpected) {
1516      if (traceJNI) unexpected.printStackTrace(System.err);
1517      env.recordException(unexpected);
1518      return 0;
1519    }
1520  }
1521
1522  /**
1523   * CallNonvirtualNonvirtualObjectMethodA:  invoke a virtual method that returns an object value
1524   * @param env A JREF index for the JNI environment object
1525   * @param objJREF a JREF index for the object instance
1526   * @param classJREF a JREF index for the class object that declares this method
1527   * @param methodID id of a MethodReference
1528   * @param argAddress address of an array of jvalues (jvalue*)
1529   * @return the JREF index for the object returned from the method invocation
1530   * @throws Exception exceptions thrown by the called method
1531   */
1532  private static int CallNonvirtualObjectMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1533                                                 Address argAddress) throws Exception {
1534    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualObjectMethodA  \n");
1535    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, null /* return type */, true);
1536    return env.pushJNIRef(returnObj);
1537  }
1538
1539  /**
1540   * CallNonvirtualBooleanMethod:  invoke a virtual method that returns a boolean value
1541   *                           arguments passed using the vararg ... style
1542   * NOTE:  the vararg's are not visible in the method signature here;
1543   *        they are saved in the caller frame and the glue frame
1544   * <p>
1545   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1546   * with a C implementation in the bootloader when the VM starts.</strong>
1547   * @param env A JREF index for the JNI environment object
1548   * @param objJREF a JREF index for the object instance
1549   * @param classJREF a JREF index for the class object that declares this method
1550   * @param methodID id of a MethodReference
1551   * @return the boolean value returned from the method invocation
1552   * @throws Exception exceptions thrown by the called method
1553   */
1554  private static boolean CallNonvirtualBooleanMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1555      throws Exception {
1556    if (VM.VerifyAssertions) {
1557      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1558    }
1559    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualBooleanMethod  \n");
1560    RuntimeEntrypoints.checkJNICountDownToGC();
1561
1562    try {
1563      Object obj = env.getJNIRef(objJREF);
1564      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Boolean, true);
1565      return Reflection.unwrapBoolean(returnObj);     // should be a wrapper for a boolean value
1566    } catch (Throwable unexpected) {
1567      if (traceJNI) unexpected.printStackTrace(System.err);
1568      env.recordException(unexpected);
1569      return false;
1570    }
1571  }
1572
1573  /**
1574   * CallNonvirtualBooleanMethodV:  invoke a virtual method that returns a boolean value
1575   * @param env A JREF index for the JNI environment object
1576   * @param objJREF a JREF index for the object instance
1577   * @param classJREF a JREF index for the class object that declares this method
1578   * @param methodID id of a MethodReference
1579   * @param argAddress a raw address to a variable argument list, each element is
1580   *              1-word or 2-words of the appropriate type for the method invocation
1581   * @return the boolean value returned from the method invocation
1582   * @throws Exception exceptions thrown by the called method
1583   */
1584  private static boolean CallNonvirtualBooleanMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1585                                                      Address argAddress) throws Exception {
1586    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualBooleanMethodV  \n");
1587    RuntimeEntrypoints.checkJNICountDownToGC();
1588
1589    try {
1590      Object obj = env.getJNIRef(objJREF);
1591      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Boolean, true);
1592      return Reflection.unwrapBoolean(returnObj);     // should be a wrapper for a boolean value
1593    } catch (Throwable unexpected) {
1594      if (traceJNI) unexpected.printStackTrace(System.err);
1595      env.recordException(unexpected);
1596      return false;
1597    }
1598  }
1599
1600  /**
1601   * CallNonvirtualBooleanMethodA:  invoke a virtual method that returns a boolean value
1602   * @param env A JREF index for the JNI environment object
1603   * @param objJREF a JREF index for the object instance
1604   * @param classJREF a JREF index for the class object that declares this method
1605   * @param methodID id of a MethodReference
1606   * @param argAddress address of an array of jvalues (jvalue*)
1607   * @return the boolean value returned from the method invocation
1608   * @throws Exception exceptions thrown by the called method
1609   */
1610  private static boolean CallNonvirtualBooleanMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1611                                                      Address argAddress) throws Exception {
1612    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualBooleanMethodA  \n");
1613    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Boolean, true);
1614    return Reflection.unwrapBoolean(returnObj);
1615  }
1616
1617  /**
1618   * CallNonvirtualByteMethod:  invoke a virtual method that returns a byte value
1619   *                           arguments passed using the vararg ... style
1620   * NOTE:  the vararg's are not visible in the method signature here;
1621   *        they are saved in the caller frame and the glue frame
1622   * <p>
1623   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1624   * with a C implementation in the bootloader when the VM starts.</strong>
1625   * @param env A JREF index for the JNI environment object
1626   * @param objJREF a JREF index for the object instance
1627   * @param classJREF a JREF index for the class object that declares this method
1628   * @param methodID id of a MethodReference
1629   * @return the byte value returned from the method invocation
1630   * @throws Exception exceptions thrown by the called method
1631   */
1632  private static byte CallNonvirtualByteMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1633      throws Exception {
1634    if (VM.VerifyAssertions) {
1635      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1636    }
1637    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualByteMethod  \n");
1638    RuntimeEntrypoints.checkJNICountDownToGC();
1639
1640    try {
1641      Object obj = env.getJNIRef(objJREF);
1642      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Byte, true);
1643      return Reflection.unwrapByte(returnObj);     // should be a wrapper for a byte value
1644    } catch (Throwable unexpected) {
1645      if (traceJNI) unexpected.printStackTrace(System.err);
1646      env.recordException(unexpected);
1647      return 0;
1648    }
1649  }
1650
1651  /**
1652   * CallNonvirtualByteMethodV:  invoke a virtual method that returns a byte value
1653   * @param env A JREF index for the JNI environment object
1654   * @param objJREF a JREF index for the object instance
1655   * @param methodID id of a MethodReference
1656   * @param classJREF a JREF index for the class object that declares this method
1657   * @param argAddress a raw address to a variable argument list, each element is
1658   *              1-word or 2-words of the appropriate type for the method invocation
1659   * @return the byte value returned from the method invocation
1660   * @throws Exception exceptions thrown by the called method
1661   */
1662  private static byte CallNonvirtualByteMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1663                                                Address argAddress) throws Exception {
1664    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualByteMethodV  \n");
1665    RuntimeEntrypoints.checkJNICountDownToGC();
1666
1667    try {
1668      Object obj = env.getJNIRef(objJREF);
1669      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Byte, true);
1670      return Reflection.unwrapByte(returnObj);     // should be a wrapper for a byte value
1671    } catch (Throwable unexpected) {
1672      if (traceJNI) unexpected.printStackTrace(System.err);
1673      env.recordException(unexpected);
1674      return 0;
1675    }
1676  }
1677
1678  /**
1679   * CallNonvirtualByteMethodA:  invoke a virtual method that returns a byte value
1680   * @param env A JREF index for the JNI environment object
1681   * @param objJREF a JREF index for the object instance
1682   * @param methodID id of a MethodReference
1683   * @param classJREF a JREF index for the class object that declares this method
1684   * @param argAddress address of an array of jvalues (jvalue*)
1685   * @return the byte value returned from the method invocation
1686   * @throws Exception exceptions thrown by the called method
1687   */
1688  private static byte CallNonvirtualByteMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1689                                                Address argAddress) throws Exception {
1690    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualByteMethodA  \n");
1691    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Byte, true);
1692    return Reflection.unwrapByte(returnObj);
1693  }
1694
1695  /**
1696   * CallNonvirtualCharMethod:  invoke a virtual method that returns a char value
1697   *                           arguments passed using the vararg ... style
1698   * NOTE:  the vararg's are not visible in the method signature here;
1699   *        they are saved in the caller frame and the glue frame
1700   * <p>
1701   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1702   * with a C implementation in the bootloader when the VM starts.</strong>
1703   * @param env A JREF index for the JNI environment object
1704   * @param objJREF a JREF index for the object instance
1705   * @param classJREF a JREF index for the class object that declares this method
1706   * @param methodID id of a MethodReference
1707   * @return the char value returned from the method invocation
1708   * @throws Exception exceptions thrown by the called method
1709   */
1710  private static char CallNonvirtualCharMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1711      throws Exception {
1712    if (VM.VerifyAssertions) {
1713      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1714    }
1715    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualCharMethod  \n");
1716    RuntimeEntrypoints.checkJNICountDownToGC();
1717
1718    try {
1719      Object obj = env.getJNIRef(objJREF);
1720      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Char, true);
1721      return Reflection.unwrapChar(returnObj);     // should be a wrapper for a char value
1722    } catch (Throwable unexpected) {
1723      if (traceJNI) unexpected.printStackTrace(System.err);
1724      env.recordException(unexpected);
1725      return 0;
1726    }
1727  }
1728
1729  /**
1730   * CallNonvirtualCharMethodV:  invoke a virtual method that returns a char value
1731   * @param env A JREF index for the JNI environment object
1732   * @param objJREF a JREF index for the object instance
1733   * @param classJREF a JREF index for the class object that declares this method
1734   * @param methodID id of a MethodReference
1735   * @param argAddress a raw address to a variable argument list, each element is
1736   *              1-word or 2-words of the appropriate type for the method invocation
1737   * @return the char value returned from the method invocation
1738   * @throws Exception exceptions thrown by the called method
1739   */
1740  private static char CallNonvirtualCharMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1741                                                Address argAddress) throws Exception {
1742    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualCharMethodV  \n");
1743    RuntimeEntrypoints.checkJNICountDownToGC();
1744
1745    try {
1746      Object obj = env.getJNIRef(objJREF);
1747      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Char, true);
1748      return Reflection.unwrapChar(returnObj);     // should be a wrapper for a char value
1749    } catch (Throwable unexpected) {
1750      if (traceJNI) unexpected.printStackTrace(System.err);
1751      env.recordException(unexpected);
1752      return 0;
1753    }
1754  }
1755
1756  /**
1757   * CallNonvirtualCharMethodA:  invoke a virtual method that returns a char value
1758   * @param env A JREF index for the JNI environment object
1759   * @param objJREF a JREF index for the object instance
1760   * @param classJREF a JREF index for the class object that declares this method
1761   * @param methodID id of a MethodReference
1762   * @param argAddress address of an array of jvalues (jvalue*)
1763   * @return the char value returned from the method invocation
1764   * @throws Exception exceptions thrown by the called method
1765   */
1766  private static char CallNonvirtualCharMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1767                                                Address argAddress) throws Exception {
1768    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualCharMethodA  \n");
1769    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Char, true);
1770    return Reflection.unwrapChar(returnObj);
1771  }
1772
1773  /**
1774   * CallNonvirtualShortMethod:  invoke a virtual method that returns a short value
1775   *                           arguments passed using the vararg ... style
1776   * NOTE:  the vararg's are not visible in the method signature here;
1777   *        they are saved in the caller frame and the glue frame
1778   * <p>
1779   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1780   * with a C implementation in the bootloader when the VM starts.</strong>
1781   * @param env A JREF index for the JNI environment object
1782   * @param objJREF a JREF index for the object instance
1783   * @param classJREF a JREF index for the class object that declares this method
1784   * @param methodID id of a MethodReference
1785   * @return the short value returned from the method invocation
1786   * @throws Exception exceptions thrown by the called method
1787   */
1788  private static short CallNonvirtualShortMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1789      throws Exception {
1790    if (VM.VerifyAssertions) {
1791      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1792    }
1793    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualShortMethod  \n");
1794    RuntimeEntrypoints.checkJNICountDownToGC();
1795
1796    try {
1797      Object obj = env.getJNIRef(objJREF);
1798      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Short, true);
1799      return Reflection.unwrapShort(returnObj);     // should be a wrapper for a short value
1800    } catch (Throwable unexpected) {
1801      if (traceJNI) unexpected.printStackTrace(System.err);
1802      env.recordException(unexpected);
1803      return 0;
1804    }
1805  }
1806
1807  /**
1808   * CallNonvirtualShortMethodV:  invoke a virtual method that returns a short value
1809   * @param env A JREF index for the JNI environment object
1810   * @param objJREF a JREF index for the object instance
1811   * @param classJREF a JREF index for the class object that declares this method
1812   * @param methodID id of a MethodReference
1813   * @param argAddress a raw address to a variable argument list, each element is
1814   *              1-word or 2-words of the appropriate type for the method invocation
1815   * @return the short value returned from the method invocation
1816   * @throws Exception exceptions thrown by the called method
1817   */
1818  private static short CallNonvirtualShortMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1819                                                  Address argAddress) throws Exception {
1820    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualShortMethodV  \n");
1821    RuntimeEntrypoints.checkJNICountDownToGC();
1822
1823    try {
1824      Object obj = env.getJNIRef(objJREF);
1825      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Short, true);
1826      return Reflection.unwrapShort(returnObj);     // should be a wrapper for a short value
1827    } catch (Throwable unexpected) {
1828      if (traceJNI) unexpected.printStackTrace(System.err);
1829      env.recordException(unexpected);
1830      return 0;
1831    }
1832  }
1833
1834  /**
1835   * CallNonvirtualShortMethodA:  invoke a virtual method that returns a short value
1836   * @param env A JREF index for the JNI environment object
1837   * @param objJREF a JREF index for the object instance
1838   * @param classJREF a JREF index for the class object that declares this method
1839   * @param methodID id of a MethodReference
1840   * @param argAddress address of an array of jvalues (jvalue*)
1841   * @return the short value returned from the method invocation
1842   * @throws Exception exceptions thrown by the called method
1843   */
1844  private static short CallNonvirtualShortMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1845                                                  Address argAddress) throws Exception {
1846    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualShortMethodA  \n");
1847    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Short, true);
1848    return Reflection.unwrapShort(returnObj);
1849  }
1850
1851  /**
1852   * CallNonvirtualIntMethod:  invoke a virtual method that returns a int value
1853   *                           arguments passed using the vararg ... style
1854   * NOTE:  the vararg's are not visible in the method signature here;
1855   *        they are saved in the caller frame and the glue frame
1856   * <p>
1857   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1858   * with a C implementation in the bootloader when the VM starts.</strong>
1859   * @param env A JREF index for the JNI environment object
1860   * @param objJREF a JREF index for the object instance
1861   * @param classJREF a JREF index for the class object that declares this method
1862   * @param methodID id of a MethodReference
1863   * @return the int value returned from the method invocation
1864   * @throws Exception exceptions thrown by the called method
1865   */
1866  private static int CallNonvirtualIntMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1867      throws Exception {
1868    if (VM.VerifyAssertions) {
1869      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1870    }
1871    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualIntMethod  \n");
1872    RuntimeEntrypoints.checkJNICountDownToGC();
1873
1874    try {
1875      Object obj = env.getJNIRef(objJREF);
1876      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Int, true);
1877      return Reflection.unwrapInt(returnObj);     // should be a wrapper for an integer value
1878    } catch (Throwable unexpected) {
1879      if (traceJNI) unexpected.printStackTrace(System.err);
1880      env.recordException(unexpected);
1881      return 0;
1882    }
1883  }
1884
1885  /**
1886   * CallNonvirtualIntMethodV:  invoke a virtual method that returns an int value
1887   * @param env A JREF index for the JNI environment object
1888   * @param objJREF a JREF index for the object instance
1889   * @param classJREF a JREF index for the class object that declares this method
1890   * @param methodID id of a MethodReference
1891   * @param argAddress a raw address to a variable argument list, each element is
1892   *              1-word or 2-words of the appropriate type for the method invocation
1893   * @return the int value returned from the method invocation
1894   * @throws Exception exceptions thrown by the called method
1895   */
1896  private static int CallNonvirtualIntMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1897                                              Address argAddress) throws Exception {
1898    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualIntMethodV  \n");
1899    RuntimeEntrypoints.checkJNICountDownToGC();
1900
1901    try {
1902      Object obj = env.getJNIRef(objJREF);
1903      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Int, true);
1904      return Reflection.unwrapInt(returnObj);     // should be a wrapper for an integer value
1905    } catch (Throwable unexpected) {
1906      if (traceJNI) unexpected.printStackTrace(System.err);
1907      env.recordException(unexpected);
1908      return 0;
1909    }
1910  }
1911
1912  /**
1913   * CallNonvirtualIntMethodA:  invoke a virtual method that returns an integer value
1914   * @param env A JREF index for the JNI environment object
1915   * @param objJREF a JREF index for the object instance
1916   * @param classJREF a JREF index for the class object that declares this method
1917   * @param methodID id of a MethodReference
1918   * @param argAddress address of an array of jvalues (jvalue*)
1919   * @return the integer value returned from the method invocation
1920   * @throws Exception exceptions thrown by the called method
1921   */
1922  private static int CallNonvirtualIntMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1923                                              Address argAddress) throws Exception {
1924    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualIntMethodA  \n");
1925    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Int, true);
1926    return Reflection.unwrapInt(returnObj);
1927  }
1928
1929  /**
1930   * CallNonvirtualLongMethod:  invoke a virtual method that returns a long value
1931   *                           arguments passed using the vararg ... style
1932   * NOTE:  the vararg's are not visible in the method signature here;
1933   *        they are saved in the caller frame and the glue frame
1934   * <p>
1935   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
1936   * with a C implementation in the bootloader when the VM starts.</strong>
1937   * @param env A JREF index for the JNI environment object
1938   * @param objJREF a JREF index for the object instance
1939   * @param classJREF a JREF index for the class object that declares this method
1940   * @param methodID id of a MethodReference
1941   * @return the long value returned from the method invocation
1942   * @throws Exception exceptions thrown by the called method
1943   */
1944  private static long CallNonvirtualLongMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
1945      throws Exception {
1946    if (VM.VerifyAssertions) {
1947      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
1948    }
1949    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualLongMethod  \n");
1950    RuntimeEntrypoints.checkJNICountDownToGC();
1951
1952    try {
1953      Object obj = env.getJNIRef(objJREF);
1954      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Long, true);
1955      return Reflection.unwrapLong(returnObj);     // should be a wrapper for a long value
1956    } catch (Throwable unexpected) {
1957      if (traceJNI) unexpected.printStackTrace(System.err);
1958      env.recordException(unexpected);
1959      return 0;
1960    }
1961  }
1962
1963  /**
1964   * CallNonvirtualLongMethodV:  invoke a virtual method that returns a long value
1965   * @param env A JREF index for the JNI environment object
1966   * @param objJREF a JREF index for the object instance
1967   * @param classJREF a JREF index for the class object that declares this method
1968   * @param methodID id of a MethodReference
1969   * @param argAddress a raw address to a variable argument list, each element is
1970   *              1-word or 2-words of the appropriate type for the method invocation
1971   * @return the long value returned from the method invocation
1972   * @throws Exception exceptions thrown by the called method
1973   */
1974  private static long CallNonvirtualLongMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
1975                                                Address argAddress) throws Exception {
1976    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualLongMethodV  \n");
1977    RuntimeEntrypoints.checkJNICountDownToGC();
1978
1979    try {
1980      Object obj = env.getJNIRef(objJREF);
1981      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Long, true);
1982      return Reflection.unwrapLong(returnObj);     // should be a wrapper for a long value
1983    } catch (Throwable unexpected) {
1984      if (traceJNI) unexpected.printStackTrace(System.err);
1985      env.recordException(unexpected);
1986      return 0;
1987    }
1988  }
1989
1990  /**
1991   * CallNonvirtualLongMethodA:  invoke a virtual method that returns a long value
1992   * @param env A JREF index for the JNI environment object
1993   * @param objJREF a JREF index for the object instance
1994   * @param classJREF a JREF index for the class object that declares this method
1995   * @param methodID id of a MethodReference
1996   * @param argAddress address of an array of jvalues (jvalue*)
1997   * @return the long value returned from the method invocation
1998   * @throws Exception exceptions thrown by the called method
1999   */
2000  private static long CallNonvirtualLongMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2001                                                Address argAddress) throws Exception {
2002    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualLongMethodA  \n");
2003    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Long, true);
2004    return Reflection.unwrapLong(returnObj);
2005  }
2006
2007  /**
2008   * CallNonvirtualFloatMethod:  invoke a virtual method that returns a float value
2009   *                           arguments passed using the vararg ... style
2010   * NOTE:  the vararg's are not visible in the method signature here;
2011   *        they are saved in the caller frame and the glue frame
2012   * <p>
2013   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2014   * with a C implementation in the bootloader when the VM starts.</strong>
2015   * @param env A JREF index for the JNI environment object
2016   * @param objJREF a JREF index for the object instance
2017   * @param classJREF a JREF index for the class object that declares this method
2018   * @param methodID id of a MethodReference
2019   * @return the float value returned from the method invocation
2020   * @throws Exception exceptions thrown by the called method
2021   */
2022  private static float CallNonvirtualFloatMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
2023      throws Exception {
2024    if (VM.VerifyAssertions) {
2025      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2026    }
2027    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualFloatMethod  \n");
2028    RuntimeEntrypoints.checkJNICountDownToGC();
2029
2030    try {
2031      Object obj = env.getJNIRef(objJREF);
2032      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Float, true);
2033      return Reflection.unwrapFloat(returnObj);     // should be a wrapper for a float value
2034    } catch (Throwable unexpected) {
2035      if (traceJNI) unexpected.printStackTrace(System.err);
2036      env.recordException(unexpected);
2037      return 0;
2038    }
2039  }
2040
2041  /**
2042   * CallNonvirtualFloatMethodV:  invoke a virtual method that returns a float value
2043   * @param env A JREF index for the JNI environment object
2044   * @param objJREF a JREF index for the object instance
2045   * @param classJREF a JREF index for the class object that declares this method
2046   * @param methodID id of a MethodReference
2047   * @param argAddress a raw address to a variable argument list, each element is
2048   *              1-word or 2-words of the appropriate type for the method invocation
2049   * @return the float value returned from the method invocation
2050   * @throws Exception exceptions thrown by the called method
2051   */
2052  private static float CallNonvirtualFloatMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2053                                                  Address argAddress) throws Exception {
2054    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualFloatMethodV  \n");
2055    RuntimeEntrypoints.checkJNICountDownToGC();
2056
2057    try {
2058      Object obj = env.getJNIRef(objJREF);
2059      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Float, true);
2060      return Reflection.unwrapFloat(returnObj);     // should be a wrapper for a float value
2061    } catch (Throwable unexpected) {
2062      if (traceJNI) unexpected.printStackTrace(System.err);
2063      env.recordException(unexpected);
2064      return 0;
2065    }
2066  }
2067
2068  /**
2069   * CallNonvirtualFloatMethodA:  invoke a virtual method that returns a float value
2070   * @param env A JREF index for the JNI environment object
2071   * @param objJREF a JREF index for the object instance
2072   * @param classJREF a JREF index for the class object that declares this method
2073   * @param methodID id of a MethodReference
2074   * @param argAddress address of an array of jvalues (jvalue*)
2075   * @return the float value returned from the method invocation
2076   * @throws Exception exceptions thrown by the called method
2077   */
2078  private static float CallNonvirtualFloatMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2079                                                  Address argAddress) throws Exception {
2080    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualFloatMethodA  \n");
2081    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Float, true);
2082    return Reflection.unwrapFloat(returnObj);
2083  }
2084
2085  /**
2086   * CallNonvirtualDoubleMethod:  invoke a virtual method that returns a double value
2087   *                           arguments passed using the vararg ... style
2088   * NOTE:  the vararg's are not visible in the method signature here;
2089   *        they are saved in the caller frame and the glue frame
2090   * <p>
2091   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2092   * with a C implementation in the bootloader when the VM starts.</strong>
2093   * @param env A JREF index for the JNI environment object
2094   * @param objJREF a JREF index for the object instance
2095   * @param classJREF a JREF index for the class object that declares this method
2096   * @param methodID id of a MethodReference
2097   * @return the double value returned from the method invocation
2098   * @throws Exception exceptions thrown by the called method
2099   */
2100  private static double CallNonvirtualDoubleMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
2101      throws Exception {
2102    if (VM.VerifyAssertions) {
2103      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2104    }
2105    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualDoubleMethod  \n");
2106    RuntimeEntrypoints.checkJNICountDownToGC();
2107
2108    try {
2109      Object obj = env.getJNIRef(objJREF);
2110      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Double, true);
2111      return Reflection.unwrapDouble(returnObj);     // should be a wrapper for a double value
2112    } catch (Throwable unexpected) {
2113      if (traceJNI) unexpected.printStackTrace(System.err);
2114      env.recordException(unexpected);
2115      return 0;
2116    }
2117  }
2118
2119  /**
2120   * CallNonvirtualDoubleMethodV:  invoke a virtual method that returns a double value
2121   * @param env A JREF index for the JNI environment object
2122   * @param objJREF a JREF index for the object instance
2123   * @param classJREF a JREF index for the class object that declares this method
2124   * @param methodID id of a MethodReference
2125   * @param argAddress a raw address to a variable argument list, each element is
2126   *              1-word or 2-words of the appropriate type for the method invocation
2127   * @return the double value returned from the method invocation
2128   * @throws Exception exceptions thrown by the called method
2129   */
2130  private static double CallNonvirtualDoubleMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2131                                                    Address argAddress) throws Exception {
2132    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualDoubleMethodV  \n");
2133    RuntimeEntrypoints.checkJNICountDownToGC();
2134
2135    try {
2136      Object obj = env.getJNIRef(objJREF);
2137      Object returnObj = JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Double, true);
2138      return Reflection.unwrapDouble(returnObj);     // should be a wrapper for a double value
2139    } catch (Throwable unexpected) {
2140      if (traceJNI) unexpected.printStackTrace(System.err);
2141      env.recordException(unexpected);
2142      return 0;
2143    }
2144  }
2145
2146  /**
2147   * CallNonvirtualDoubleMethodA:  invoke a virtual method that returns a double value
2148   * @param env A JREF index for the JNI environment object
2149   * @param objJREF a JREF index for the object instance
2150   * @param classJREF a JREF index for the class object that declares this method
2151   * @param methodID id of a MethodReference
2152   * @param argAddress address of an array of jvalues (jvalue*)
2153   * @return the double value returned from the method invocation
2154   * @throws Exception exceptions thrown by the called method
2155   */
2156  private static double CallNonvirtualDoubleMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2157                                                    Address argAddress) throws Exception {
2158    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualDoubleMethodA  \n");
2159    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Double, true);
2160    return Reflection.unwrapDouble(returnObj);
2161  }
2162
2163  /**
2164   * CallNonvirtualVoidMethod:  invoke a virtual method that returns a void value
2165   *                           arguments passed using the vararg ... style
2166   * NOTE:  the vararg's are not visible in the method signature here;
2167   *        they are saved in the caller frame and the glue frame
2168   * <p>
2169   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2170   * with a C implementation in the bootloader when the VM starts.</strong>
2171   * @param env A JREF index for the JNI environment object
2172   * @param objJREF a JREF index for the object instance
2173   * @param classJREF a JREF index for the class object that declares this method
2174   * @param methodID id of a MethodReference
2175   * @throws Exception exceptions thrown by the called method
2176   */
2177  private static void CallNonvirtualVoidMethod(JNIEnvironment env, int objJREF, int classJREF, int methodID)
2178      throws Exception {
2179    if (VM.VerifyAssertions) {
2180      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2181    }
2182    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualVoidMethod  \n");
2183    RuntimeEntrypoints.checkJNICountDownToGC();
2184
2185    try {
2186      Object obj = env.getJNIRef(objJREF);
2187      JNIHelpers.invokeWithDotDotVarArg(obj, methodID, TypeReference.Void, true);
2188    } catch (Throwable unexpected) {
2189      if (traceJNI) unexpected.printStackTrace(System.err);
2190      env.recordException(unexpected);
2191    }
2192  }
2193
2194  /**
2195   * CallNonvirtualVoidMethodV:  invoke a virtual method that returns void
2196   * @param env A JREF index for the JNI environment object
2197   * @param objJREF a JREF index for the object instance
2198   * @param classJREF a JREF index for the class object that declares this method
2199   * @param methodID id of a MethodReference
2200   * @param argAddress a raw address to a variable argument list, each element is
2201   *              1-word or 2-words of the appropriate type for the method invocation
2202   * @throws Exception exceptions thrown by the called method
2203   */
2204  private static void CallNonvirtualVoidMethodV(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2205                                                Address argAddress) throws Exception {
2206    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualVoidMethodV  \n");
2207    RuntimeEntrypoints.checkJNICountDownToGC();
2208
2209    try {
2210      Object obj = env.getJNIRef(objJREF);
2211      JNIHelpers.invokeWithVarArg(obj, methodID, argAddress, TypeReference.Void, true);
2212    } catch (Throwable unexpected) {
2213      if (traceJNI) unexpected.printStackTrace(System.err);
2214      env.recordException(unexpected);
2215    }
2216  }
2217
2218  /**
2219   * CallNonvirtualVoidMethodA:  invoke a virtual method that returns void
2220   * @param env A JREF index for the JNI environment object
2221   * @param objJREF a JREF index for the object instance
2222   * @param classJREF a JREF index for the class object that declares this method
2223   * @param methodID id of a MethodReference
2224   * @param argAddress address of an array of jvalues (jvalue*)
2225   * @throws Exception exceptions thrown by the called method
2226   */
2227  private static void CallNonvirtualVoidMethodA(JNIEnvironment env, int objJREF, int classJREF, int methodID,
2228                                                Address argAddress) throws Exception {
2229    if (traceJNI) VM.sysWrite("JNI called: CallNonvirtualVoidMethodA  \n");
2230    JNIGenericHelpers.callMethodJValuePtr(env, objJREF, methodID, argAddress, TypeReference.Void, true);
2231  }
2232
2233  /**
2234   * GetFieldID:  return a field id, which can be cached in native code and reused
2235   * @param env A JREF index for the JNI environment object
2236   * @param classJREF a JREF index for the RVMClass object
2237   * @param fieldNameAddress a raw address to a null-terminated string in C for the field name
2238   * @param descriptorAddress a raw address to a null-terminated string in C for the descriptor
2239   * @return the fieldID of an instance field given the class, field name
2240   *         and type. Return 0 if the field is not found
2241   * @throws NoSuchFieldError if the specified field cannot be found
2242   * @throws ExceptionInInitializerError if the class initializer fails
2243   * @throws OutOfMemoryError if the system runs out of memory
2244   */
2245  private static int GetFieldID(JNIEnvironment env, int classJREF, Address fieldNameAddress,
2246                                Address descriptorAddress) {
2247    if (traceJNI) VM.sysWrite("JNI called: GetFieldID  \n");
2248    RuntimeEntrypoints.checkJNICountDownToGC();
2249
2250    try {
2251      if (traceJNI)
2252        VM.sysWriteln("called GetFieldID with classJREF = ",classJREF);
2253      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
2254      if (VM.VerifyAssertions) VM._assert(cls != null);
2255      String fieldString = JNIGenericHelpers.createStringFromC(fieldNameAddress);
2256      Atom fieldName = Atom.findOrCreateAsciiAtom(fieldString);
2257
2258      String descriptorString = JNIGenericHelpers.createStringFromC(descriptorAddress);
2259      Atom descriptor = Atom.findOrCreateAsciiAtom(descriptorString);
2260
2261      // list of all instance fields including superclasses.
2262      // Iterate in reverse order since if there are multiple instance
2263      // fields of the same name & descriptor we want to find the most derived one.
2264      RVMField[] fields = java.lang.JikesRVMSupport.getTypeForClass(cls).getInstanceFields();
2265      for (int i = fields.length - 1; i >= 0; i--) {
2266        RVMField f = fields[i];
2267        if (f.getName() == fieldName && f.getDescriptor() == descriptor) {
2268          return f.getId();
2269        }
2270      }
2271
2272      // create exception and return 0 if not found
2273      env.recordException(new NoSuchFieldError(fieldString + ", " + descriptorString + " of " + cls));
2274      return 0;
2275    } catch (Throwable unexpected) {
2276      if (traceJNI) unexpected.printStackTrace(System.err);
2277      env.recordException(unexpected);
2278      return 0;
2279    }
2280  }
2281
2282  /**
2283   * GetObjectField: read a instance field of type Object
2284   * @param env A JREF index for the JNI environment object
2285   * @param objJREF a JREF index for the target object
2286   * @param fieldID the id for the RVMField that describes this field
2287   * @return the value of the Object field, converted to a JREF index
2288   *         or 0 if the fieldID is incorrect
2289   */
2290  private static int GetObjectField(JNIEnvironment env, int objJREF, int fieldID) {
2291    if (traceJNI) VM.sysWrite("JNI called: GetObjectField  \n");
2292    RuntimeEntrypoints.checkJNICountDownToGC();
2293
2294    try {
2295      Object obj = env.getJNIRef(objJREF);
2296      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2297      Object objVal = field.getObjectUnchecked(obj);
2298      return env.pushJNIRef(objVal);
2299    } catch (Throwable unexpected) {
2300      if (traceJNI) unexpected.printStackTrace(System.err);
2301      env.recordException(unexpected);
2302      return 0;
2303    }
2304  }
2305
2306  /**
2307   * GetBooleanField: read an instance field of type boolean
2308   * @param env A JREF index for the JNI environment object
2309   * @param objJREF a JREF index for the target object
2310   * @param fieldID the id for the RVMField that describes this field
2311   * @return the value of the boolean field, or 0 if the fieldID is incorrect
2312   */
2313  private static int GetBooleanField(JNIEnvironment env, int objJREF, int fieldID) {
2314    if (traceJNI) VM.sysWrite("JNI called: GetBooleanField  \n");
2315    RuntimeEntrypoints.checkJNICountDownToGC();
2316
2317    try {
2318      Object obj = env.getJNIRef(objJREF);
2319      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2320      return field.getBooleanValueUnchecked(obj) ? 1 : 0;
2321    } catch (Throwable unexpected) {
2322      if (traceJNI) unexpected.printStackTrace(System.err);
2323      env.recordException(unexpected);
2324      return 0;
2325    }
2326  }
2327
2328  /**
2329   * GetByteField:  read an instance field of type byte
2330   * @param env A JREF index for the JNI environment object
2331   * @param objJREF a JREF index for the target object
2332   * @param fieldID the id for the RVMField that describes this field
2333   * @return the value of the byte field, or 0 if the fieldID is incorrect
2334   */
2335  private static int GetByteField(JNIEnvironment env, int objJREF, int fieldID) {
2336    if (traceJNI) VM.sysWrite("JNI called: GetByteField  \n");
2337    RuntimeEntrypoints.checkJNICountDownToGC();
2338
2339    try {
2340      Object obj = env.getJNIRef(objJREF);
2341      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2342      return field.getByteValueUnchecked(obj);
2343    } catch (Throwable unexpected) {
2344      if (traceJNI) unexpected.printStackTrace(System.err);
2345      env.recordException(unexpected);
2346      return 0;
2347    }
2348  }
2349
2350  /**
2351   * GetCharField:  read an instance field of type character
2352   * @param env A JREF index for the JNI environment object
2353   * @param objJREF a JREF index for the target object
2354   * @param fieldID the id for the RVMField that describes this field
2355   * @return the value of the character field, or 0 if the fieldID is incorrect
2356   */
2357  private static int GetCharField(JNIEnvironment env, int objJREF, int fieldID) {
2358    if (traceJNI) VM.sysWrite("JNI called: GetCharField  \n");
2359    RuntimeEntrypoints.checkJNICountDownToGC();
2360
2361    try {
2362      Object obj = env.getJNIRef(objJREF);
2363      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2364      return field.getCharValueUnchecked(obj);
2365    } catch (Throwable unexpected) {
2366      if (traceJNI) unexpected.printStackTrace(System.err);
2367      env.recordException(unexpected);
2368      return 0;
2369    }
2370  }
2371
2372  /**
2373   * GetShortField:  read an instance field of type short
2374   * @param env A JREF index for the JNI environment object
2375   * @param objJREF a JREF index for the target object
2376   * @param fieldID the id for the RVMField that describes this field
2377   * @return the value of the short field, or 0 if the fieldID is incorrect
2378   */
2379  private static int GetShortField(JNIEnvironment env, int objJREF, int fieldID) {
2380    if (traceJNI) VM.sysWrite("JNI called: GetShortField  \n");
2381    RuntimeEntrypoints.checkJNICountDownToGC();
2382
2383    try {
2384      Object obj = env.getJNIRef(objJREF);
2385      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2386      return field.getShortValueUnchecked(obj);
2387    } catch (Throwable unexpected) {
2388      if (traceJNI) unexpected.printStackTrace(System.err);
2389      env.recordException(unexpected);
2390      return 0;
2391    }
2392  }
2393
2394  /**
2395   * GetIntField:  read an instance field of type integer
2396   * @param env A JREF index for the JNI environment object
2397   * @param objJREF a JREF index for the target object
2398   * @param fieldID the id for the RVMField that describes this field
2399   * @return the value of the integer field, or 0 if the fieldID is incorrect
2400   */
2401  private static int GetIntField(JNIEnvironment env, int objJREF, int fieldID) {
2402    if (traceJNI) VM.sysWrite("JNI called: GetIntField  \n");
2403    RuntimeEntrypoints.checkJNICountDownToGC();
2404
2405    try {
2406      Object obj = env.getJNIRef(objJREF);
2407      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2408      return field.getIntValueUnchecked(obj);
2409    } catch (Throwable unexpected) {
2410      if (traceJNI) unexpected.printStackTrace(System.err);
2411      env.recordException(unexpected);
2412      return 0;
2413    }
2414  }
2415
2416  /**
2417   * GetLongField:  read an instance field of type long
2418   * @param env A JREF index for the JNI environment object
2419   * @param objJREF a JREF index for the target object
2420   * @param fieldID the id for the RVMField that describes this field
2421   * @return the value of the long field or 0 if the fieldID is incorrect
2422   */
2423  private static long GetLongField(JNIEnvironment env, int objJREF, int fieldID) {
2424    if (traceJNI) VM.sysWrite("JNI called: GetLongField  \n");
2425    RuntimeEntrypoints.checkJNICountDownToGC();
2426
2427    try {
2428      Object obj = env.getJNIRef(objJREF);
2429      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2430      return field.getLongValueUnchecked(obj);
2431    } catch (Throwable unexpected) {
2432      if (traceJNI) unexpected.printStackTrace(System.err);
2433      env.recordException(unexpected);
2434      return 0L;
2435    }
2436  }
2437
2438  /**
2439   * GetFloatField:  read an instance field of type float
2440   * @param env A JREF index for the JNI environment object
2441   * @param objJREF a JREF index for the target object
2442   * @param fieldID the id for the RVMField that describes this field
2443   * @return the value of the float field or 0 if the fieldID is incorrect
2444   */
2445  private static float GetFloatField(JNIEnvironment env, int objJREF, int fieldID) {
2446    if (traceJNI) VM.sysWrite("JNI called: GetFloatField  \n");
2447    RuntimeEntrypoints.checkJNICountDownToGC();
2448
2449    try {
2450      Object obj = env.getJNIRef(objJREF);
2451      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2452      return field.getFloatValueUnchecked(obj);
2453    } catch (Throwable unexpected) {
2454      if (traceJNI) unexpected.printStackTrace(System.err);
2455      env.recordException(unexpected);
2456      return 0f;
2457    }
2458  }
2459
2460  /**
2461   * GetDoubleField:  read an instance field of type double
2462   * @param env A JREF index for the JNI environment object
2463   * @param objJREF a JREF index for the target object
2464   * @param fieldID the id for the RVMField that describes this field
2465   * @return the value of the double field or 0 if the fieldID is incorrect
2466   */
2467  private static double GetDoubleField(JNIEnvironment env, int objJREF, int fieldID) {
2468    if (traceJNI) VM.sysWrite("JNI called: GetDoubleField  \n");
2469    RuntimeEntrypoints.checkJNICountDownToGC();
2470
2471    try {
2472      Object obj = env.getJNIRef(objJREF);
2473      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2474      return field.getDoubleValueUnchecked(obj);
2475    } catch (Throwable unexpected) {
2476      if (traceJNI) unexpected.printStackTrace(System.err);
2477      env.recordException(unexpected);
2478      return 0.0;
2479    }
2480  }
2481
2482  /**
2483   * SetObjectField: set a instance field of type Object
2484   * @param env A JREF index for the JNI environment object
2485   * @param objJREF a JREF index for the target object
2486   * @param fieldID the id for the RVMField that describes this field
2487   * @param valueJREF a JREF index for the value to assign
2488   */
2489  private static void SetObjectField(JNIEnvironment env, int objJREF, int fieldID, int valueJREF) {
2490    if (traceJNI) VM.sysWrite("JNI called: SetObjectField  \n");
2491    RuntimeEntrypoints.checkJNICountDownToGC();
2492
2493    try {
2494      Object obj = env.getJNIRef(objJREF);
2495      Object value = env.getJNIRef(valueJREF);
2496      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2497      field.setObjectValueUnchecked(obj, value);
2498    } catch (Throwable unexpected) {
2499      if (traceJNI) unexpected.printStackTrace(System.err);
2500      env.recordException(unexpected);
2501    }
2502  }
2503
2504  /**
2505   * SetBooleanField: set an instance field of type boolean
2506   * @param env A JREF index for the JNI environment object
2507   * @param objJREF a JREF index for the target object
2508   * @param fieldID the id for the RVMField that describes this field
2509   * @param value   boolean value to assign
2510   */
2511  private static void SetBooleanField(JNIEnvironment env, int objJREF, int fieldID, boolean value) {
2512    if (traceJNI) VM.sysWrite("JNI called: SetBooleanField  \n");
2513    RuntimeEntrypoints.checkJNICountDownToGC();
2514
2515    try {
2516      Object obj = env.getJNIRef(objJREF);
2517      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2518      field.setBooleanValueUnchecked(obj, value);
2519    } catch (Throwable unexpected) {
2520      if (traceJNI) unexpected.printStackTrace(System.err);
2521      env.recordException(unexpected);
2522    }
2523  }
2524
2525  /**
2526   * SetByteField: set an instance field of type byte
2527   * @param env A JREF index for the JNI environment object
2528   * @param objJREF a JREF index for the target object
2529   * @param fieldID the id for the RVMField that describes this field
2530   * @param value   byte value to assign
2531   */
2532  private static void SetByteField(JNIEnvironment env, int objJREF, int fieldID, byte value) {
2533    if (traceJNI) VM.sysWrite("JNI called: SetByteField  \n");
2534    RuntimeEntrypoints.checkJNICountDownToGC();
2535
2536    try {
2537      Object obj = env.getJNIRef(objJREF);
2538      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2539      field.setByteValueUnchecked(obj, value);
2540    } catch (Throwable unexpected) {
2541      if (traceJNI) unexpected.printStackTrace(System.err);
2542      env.recordException(unexpected);
2543    }
2544  }
2545
2546  /**
2547   * SetCharField: set an instance field of type char
2548   * @param env A JREF index for the JNI environment object
2549   * @param objJREF a JREF index for the target object
2550   * @param fieldID the id for the RVMField that describes this field
2551   * @param value   char value to assign
2552   */
2553  private static void SetCharField(JNIEnvironment env, int objJREF, int fieldID, char value) {
2554    if (traceJNI) VM.sysWrite("JNI called: SetCharField  \n");
2555    RuntimeEntrypoints.checkJNICountDownToGC();
2556
2557    try {
2558      Object obj = env.getJNIRef(objJREF);
2559      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2560      field.setCharValueUnchecked(obj, value);
2561    } catch (Throwable unexpected) {
2562      if (traceJNI) unexpected.printStackTrace(System.err);
2563      env.recordException(unexpected);
2564    }
2565  }
2566
2567  /**
2568   * SetShortField: set an instance field of type short
2569   * @param env A JREF index for the JNI environment object
2570   * @param objJREF a JREF index for the target object
2571   * @param fieldID the id for the RVMField that describes this field
2572   * @param value   short value to assign
2573   */
2574  private static void SetShortField(JNIEnvironment env, int objJREF, int fieldID, short value) {
2575    if (traceJNI) VM.sysWrite("JNI called: SetShortField  \n");
2576    RuntimeEntrypoints.checkJNICountDownToGC();
2577
2578    try {
2579      Object obj = env.getJNIRef(objJREF);
2580      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2581      field.setShortValueUnchecked(obj, value);
2582    } catch (Throwable unexpected) {
2583      if (traceJNI) unexpected.printStackTrace(System.err);
2584      env.recordException(unexpected);
2585    }
2586  }
2587
2588  /**
2589   * SetIntField: set an instance field of type integer
2590   * @param env A JREF index for the JNI environment object
2591   * @param objJREF a JREF index for the target object
2592   * @param fieldID the id for the RVMField that describes this field
2593   * @param value   integer value to assign
2594   */
2595  private static void SetIntField(JNIEnvironment env, int objJREF, int fieldID, int value) {
2596    if (traceJNI) VM.sysWrite("JNI called: SetIntField  \n");
2597    RuntimeEntrypoints.checkJNICountDownToGC();
2598
2599    try {
2600      Object obj = env.getJNIRef(objJREF);
2601      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2602      field.setIntValueUnchecked(obj, value);
2603    } catch (Throwable unexpected) {
2604      if (traceJNI) unexpected.printStackTrace(System.err);
2605      env.recordException(unexpected);
2606    }
2607  }
2608
2609  /**
2610   * SetLongField: set an instance field of type long
2611   * @param env A JREF index for the JNI environment object
2612   * @param objJREF a JREF index for the target object
2613   * @param fieldID the id for the RVMField that describes this field
2614   * @param value   long value to assign
2615   */
2616  private static void SetLongField(JNIEnvironment env, int objJREF, int fieldID, long value) {
2617    if (traceJNI) VM.sysWrite("JNI called: SetLongField  \n");
2618    RuntimeEntrypoints.checkJNICountDownToGC();
2619
2620    try {
2621      Object obj = env.getJNIRef(objJREF);
2622      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2623      field.setLongValueUnchecked(obj, value);
2624    } catch (Throwable unexpected) {
2625      if (traceJNI) unexpected.printStackTrace(System.err);
2626      env.recordException(unexpected);
2627    }
2628  }
2629
2630  /**
2631   * SetFloatField: set an instance field of type float
2632   * @param env A JREF index for the JNI environment object
2633   * @param objJREF a JREF index for the target object
2634   * @param fieldID the id for the RVMField that describes this field
2635   * @param value   float value to assign
2636   */
2637  private static void SetFloatField(JNIEnvironment env, int objJREF, int fieldID, float value) {
2638    if (traceJNI) VM.sysWrite("JNI called: SetFloatField  \n");
2639    RuntimeEntrypoints.checkJNICountDownToGC();
2640
2641    try {
2642      Object obj = env.getJNIRef(objJREF);
2643      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2644      field.setFloatValueUnchecked(obj, value);
2645    } catch (Throwable unexpected) {
2646      if (traceJNI) unexpected.printStackTrace(System.err);
2647      env.recordException(unexpected);
2648    }
2649  }
2650
2651  /**
2652   * SetDoubleField: set an instance field of type double
2653   * @param env A JREF index for the JNI environment object
2654   * @param objJREF a JREF index for the target object
2655   * @param fieldID the id for the RVMField that describes this field
2656   * @param value   double value to assign
2657   */
2658  private static void SetDoubleField(JNIEnvironment env, int objJREF, int fieldID, double value) {
2659    if (traceJNI) VM.sysWrite("JNI called: SetDoubleField  \n");
2660    RuntimeEntrypoints.checkJNICountDownToGC();
2661
2662    try {
2663      Object obj = env.getJNIRef(objJREF);
2664      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
2665      field.setDoubleValueUnchecked(obj, value);
2666    } catch (Throwable unexpected) {
2667      if (traceJNI) unexpected.printStackTrace(System.err);
2668      env.recordException(unexpected);
2669    }
2670  }
2671
2672  /**
2673   * GetStaticMethodID:  return the method ID for invocation later
2674   * @param env A JREF index for the JNI environment object
2675   * @param classJREF a JREF index for the class object
2676   * @param methodNameAddress a raw address to a null-terminated string in C for the method name
2677   * @param methodSigAddress a raw address to a null-terminated string in C for (TODO: document me)
2678   * @return a method ID or null if it fails
2679   * @throws NoSuchMethodError if the method is not found
2680   * @throws ExceptionInInitializerError if the initializer fails
2681   * @throws OutOfMemoryError if the system runs out of memory
2682   */
2683  private static int GetStaticMethodID(JNIEnvironment env, int classJREF, Address methodNameAddress,
2684                                       Address methodSigAddress) {
2685    if (traceJNI) VM.sysWrite("JNI called: GetStaticMethodID  \n");
2686    RuntimeEntrypoints.checkJNICountDownToGC();
2687
2688    try {
2689      // obtain the names as String from the native space
2690      String methodString = JNIGenericHelpers.createStringFromC(methodNameAddress);
2691      Atom methodName = Atom.findOrCreateAsciiAtom(methodString);
2692      String sigString = JNIGenericHelpers.createStringFromC(methodSigAddress);
2693      Atom sigName = Atom.findOrCreateAsciiAtom(sigString);
2694
2695      // get the target class
2696      Class<?> jcls = (Class<?>) env.getJNIRef(classJREF);
2697      RVMType type = java.lang.JikesRVMSupport.getTypeForClass(jcls);
2698      if (!type.isClassType()) {
2699        env.recordException(new NoSuchMethodError());
2700        return 0;
2701      }
2702
2703      RVMClass klass = type.asClass();
2704      if (!klass.isInitialized()) {
2705        RuntimeEntrypoints.initializeClassForDynamicLink(klass);
2706      }
2707
2708      // Find the target method
2709      RVMMethod meth = klass.findStaticMethod(methodName, sigName);
2710      if (meth == null) {
2711        env.recordException(new NoSuchMethodError());
2712        return 0;
2713      }
2714
2715      if (traceJNI) VM.sysWrite("got method " + meth + "\n");
2716      return meth.getId();
2717    } catch (Throwable unexpected) {
2718      if (traceJNI) unexpected.printStackTrace(System.err);
2719      env.recordException(unexpected);
2720      return 0;
2721    }
2722  }
2723
2724  /**
2725   * CallStaticObjectMethod:  invoke a static method that returns an object value
2726   *                          arguments passed using the vararg ... style
2727   * NOTE:  the vararg's are not visible in the method signature here; they are saved
2728   *        in the caller frame and the glue frame
2729   * <p>
2730   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2731   * with a C implementation in the bootloader when the VM starts.</strong>
2732   * @param env A JREF index for the JNI environment object
2733   * @param classJREF a JREF index for the class object
2734   * @param methodID id of a MethodReference
2735   * @return the JREF index for the object returned from the method invocation
2736   * @throws Exception exceptions thrown by the called method
2737   */
2738  private static int CallStaticObjectMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
2739    if (VM.VerifyAssertions) {
2740      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2741    }
2742    if (traceJNI) VM.sysWrite("JNI called: CallStaticObjectMethod  \n");
2743    RuntimeEntrypoints.checkJNICountDownToGC();
2744
2745    try {
2746      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, null);
2747      return env.pushJNIRef(returnObj);
2748    } catch (Throwable unexpected) {
2749      if (traceJNI) unexpected.printStackTrace(System.err);
2750      env.recordException(unexpected);
2751      return 0;
2752    }
2753  }
2754
2755  /**
2756   * CallStaticObjectMethodV:  invoke a static method that returns an object
2757   * @param env A JREF index for the JNI environment object
2758   * @param classJREF a JREF index for the class object
2759   * @param methodID id of a MethodReference
2760   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
2761   *                   of the appropriate type for the method invocation
2762   * @return the JREF index for the object returned from the method invocation
2763   * @throws Exception exceptions thrown by the called method
2764   */
2765  private static int CallStaticObjectMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
2766      throws Exception {
2767    if (traceJNI) VM.sysWrite("JNI called: CallStaticObjectMethodV  \n");
2768    RuntimeEntrypoints.checkJNICountDownToGC();
2769
2770    try {
2771      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, null);
2772      return env.pushJNIRef(returnObj);
2773    } catch (Throwable unexpected) {
2774      if (traceJNI) unexpected.printStackTrace(System.err);
2775      env.recordException(unexpected);
2776      return 0;
2777    }
2778  }
2779
2780  /**
2781   * CallStaticObjectMethodA:  invoke a static method that returns an object
2782   * @param env A JREF index for the JNI environment object
2783   * @param classJREF a JREF index for the class object
2784   * @param methodID id of a MethodReference
2785   * @param argAddress address of an array of jvalues (jvalue*)
2786   * @return the JREF index for the object returned from the method invocation
2787   * @throws Exception exceptions thrown by the called method
2788   */
2789  private static int CallStaticObjectMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
2790      throws Exception {
2791    if (traceJNI) VM.sysWrite("JNI called: CallStaticObjectMethodA  \n");
2792    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, null /* return type */, true);
2793    return env.pushJNIRef(returnObj);
2794  }
2795
2796  /**
2797   * CallStaticBooleanMethod:  invoke a static method that returns a boolean value
2798   *                           arguments passed using the vararg ... style
2799   * NOTE:  the vararg's are not visible in the method signature here; they are saved
2800   *        in the caller frame and the glue frame
2801   * <p>
2802   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2803   * with a C implementation in the bootloader when the VM starts.</strong>
2804   * @param env A JREF index for the JNI environment object
2805   * @param classJREF a JREF index for the class object
2806   * @param methodID id of a MethodReference
2807   * @return the boolean value returned from the method invocation
2808   * @throws Exception exceptions thrown by the called method
2809   */
2810  private static boolean CallStaticBooleanMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
2811    if (VM.VerifyAssertions) {
2812      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2813    }
2814    if (traceJNI) VM.sysWrite("JNI called: CallStaticBooleanMethod  \n");
2815    RuntimeEntrypoints.checkJNICountDownToGC();
2816
2817    try {
2818      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Boolean);
2819      return Reflection.unwrapBoolean(returnObj);     // should be a wrapper for a boolean value
2820    } catch (Throwable unexpected) {
2821      if (traceJNI) unexpected.printStackTrace(System.err);
2822      env.recordException(unexpected);
2823      return false;
2824    }
2825  }
2826
2827  /**
2828   * CallStaticBooleanMethodV:  invoke a static method that returns a boolean value
2829   * @param env A JREF index for the JNI environment object
2830   * @param classJREF a JREF index for the class object
2831   * @param methodID id of a MethodReference
2832   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
2833   *                   of the appropriate type for the method invocation
2834   * @return the boolean value returned from the method invocation
2835   * @throws Exception exceptions thrown by the called method
2836   */
2837  private static boolean CallStaticBooleanMethodV(JNIEnvironment env, int classJREF, int methodID,
2838                                                  Address argAddress) throws Exception {
2839    if (traceJNI) VM.sysWrite("JNI called: CallStaticBooleanMethodV  \n");
2840    RuntimeEntrypoints.checkJNICountDownToGC();
2841
2842    try {
2843      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Boolean);
2844      return Reflection.unwrapBoolean(returnObj);     // should be a wrapper for a boolean value
2845    } catch (Throwable unexpected) {
2846      if (traceJNI) unexpected.printStackTrace(System.err);
2847      env.recordException(unexpected);
2848      return false;
2849    }
2850  }
2851
2852  /**
2853   * CallStaticBooleanMethodA:  invoke a static method that returns a boolean value
2854   * @param env A JREF index for the JNI environment object
2855   * @param classJREF a JREF index for the class object
2856   * @param methodID id of a MethodReference
2857   * @param argAddress address of an array of jvalues (jvalue*)
2858   * @return the boolean value returned from the method invocation
2859   * @throws Exception exceptions thrown by the called method
2860   */
2861  private static boolean CallStaticBooleanMethodA(JNIEnvironment env, int classJREF, int methodID,
2862                                                  Address argAddress) throws Exception {
2863    if (traceJNI) VM.sysWrite("JNI called: CallStaticBooleanMethodA  \n");
2864    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Boolean, true);
2865    return Reflection.unwrapBoolean(returnObj);
2866  }
2867
2868  /**
2869   * CallStaticByteMethod:  invoke a static method that returns a byte value
2870   *                        arguments passed using the vararg ... style
2871   * NOTE:  the vararg's are not visible in the method signature here; they are saved
2872   *        in the caller frame and the glue frame
2873   * <p>
2874   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2875   * with a C implementation in the bootloader when the VM starts.</strong>
2876   * @param env A JREF index for the JNI environment object
2877   * @param classJREF a JREF index for the class object
2878   * @param methodID id of a MethodReference
2879   * @return the byte value returned from the method invocation
2880   * @throws Exception exceptions thrown by the called method
2881   */
2882  private static byte CallStaticByteMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
2883    if (VM.VerifyAssertions) {
2884      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2885    }
2886    if (traceJNI) VM.sysWrite("JNI called: CallStaticByteMethod  \n");
2887    RuntimeEntrypoints.checkJNICountDownToGC();
2888
2889    try {
2890      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Byte);
2891      return Reflection.unwrapByte(returnObj);     // should be a wrapper for a byte value
2892    } catch (Throwable unexpected) {
2893      if (traceJNI) unexpected.printStackTrace(System.err);
2894      env.recordException(unexpected);
2895      return 0;
2896    }
2897  }
2898
2899  /**
2900   * CallStaticByteMethodV:  invoke a static method that returns a byte value
2901   * @param env A JREF index for the JNI environment object
2902   * @param classJREF a JREF index for the class object
2903   * @param methodID id of a MethodReference
2904   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
2905   *                   of the appropriate type for the method invocation
2906   * @return the byte value returned from the method invocation
2907   * @throws Exception exceptions thrown by the called method
2908   */
2909  private static byte CallStaticByteMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
2910      throws Exception {
2911    if (traceJNI) VM.sysWrite("JNI called: CallStaticByteMethodV  \n");
2912    RuntimeEntrypoints.checkJNICountDownToGC();
2913
2914    try {
2915      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Byte);
2916      return Reflection.unwrapByte(returnObj);     // should be a wrapper for a byte value
2917    } catch (Throwable unexpected) {
2918      if (traceJNI) unexpected.printStackTrace(System.err);
2919      env.recordException(unexpected);
2920      return 0;
2921    }
2922  }
2923
2924  /**
2925   * CallStaticByteMethodA:  invoke a static method that returns a byte value
2926   * @param env A JREF index for the JNI environment object
2927   * @param classJREF a JREF index for the class object
2928   * @param methodID id of a MethodReference
2929   * @param argAddress address of an array of jvalues (jvalue*)
2930   * @return the byte value returned from the method invocation
2931   * @throws Exception exceptions thrown by the called method
2932   */
2933  private static byte CallStaticByteMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
2934      throws Exception {
2935    if (traceJNI) VM.sysWrite("JNI called: CallStaticByteMethodA  \n");
2936    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Byte, true);
2937    return Reflection.unwrapByte(returnObj);
2938  }
2939
2940  /**
2941   * CallStaticCharMethod:  invoke a static method that returns a char value
2942   *                        arguments passed using the vararg ... style
2943   * NOTE:  the vararg's are not visible in the method signature here; they are saved
2944   *        in the caller frame and the glue frame
2945   * <p>
2946   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
2947   * with a C implementation in the bootloader when the VM starts.</strong>
2948   * @param env A JREF index for the JNI environment object
2949   * @param classJREF a JREF index for the class object
2950   * @param methodID id of a MethodReference
2951   * @return the char value returned from the method invocation
2952   * @throws Exception exceptions thrown by the called method
2953   */
2954  private static char CallStaticCharMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
2955    if (VM.VerifyAssertions) {
2956      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
2957    }
2958    if (traceJNI) VM.sysWrite("JNI called: CallStaticCharMethod  \n");
2959    RuntimeEntrypoints.checkJNICountDownToGC();
2960
2961    try {
2962      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Char);
2963      return Reflection.unwrapChar(returnObj);     // should be a wrapper for a char value
2964    } catch (Throwable unexpected) {
2965      if (traceJNI) unexpected.printStackTrace(System.err);
2966      env.recordException(unexpected);
2967      return 0;
2968    }
2969  }
2970
2971  /**
2972   * CallStaticCharMethodV:  invoke a static method that returns a char value
2973   * @param env A JREF index for the JNI environment object
2974   * @param classJREF a JREF index for the class object
2975   * @param methodID id of a MethodReference
2976   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
2977   *                   of the appropriate type for the method invocation
2978   * @return the char value returned from the method invocation
2979   * @throws Exception exceptions thrown by the called method
2980   */
2981  private static char CallStaticCharMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
2982      throws Exception {
2983    if (traceJNI) VM.sysWrite("JNI called: CallStaticCharMethodV  \n");
2984    RuntimeEntrypoints.checkJNICountDownToGC();
2985
2986    try {
2987      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Char);
2988      return Reflection.unwrapChar(returnObj);     // should be a wrapper for a char value
2989    } catch (Throwable unexpected) {
2990      if (traceJNI) unexpected.printStackTrace(System.err);
2991      env.recordException(unexpected);
2992      return 0;
2993    }
2994  }
2995
2996  /**
2997   * CallStaticCharMethodA:  invoke a static method that returns a char value
2998   * @param env A JREF index for the JNI environment object
2999   * @param classJREF a JREF index for the class object
3000   * @param methodID id of a MethodReference
3001   * @param argAddress address of an array of jvalues (jvalue*)
3002   * @return the char value returned from the method invocation
3003   * @throws Exception exceptions thrown by the called method
3004   */
3005  private static char CallStaticCharMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3006      throws Exception {
3007    if (traceJNI) VM.sysWrite("JNI called: CallStaticCharMethodA  \n");
3008    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Char, true);
3009    return Reflection.unwrapChar(returnObj);
3010  }
3011
3012  /**
3013   * CallStaticShortMethod:  invoke a static method that returns a short value
3014   *                         arguments passed using the vararg ... style
3015   * NOTE:  the vararg's are not visible in the method signature here; they are saved
3016   *        in the caller frame and the glue frame
3017   * <p>
3018   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
3019   * with a C implementation in the bootloader when the VM starts.</strong>
3020   * @param env A JREF index for the JNI environment object
3021   * @param classJREF a JREF index for the class object
3022   * @param methodID id of a MethodReference
3023   * @return the short value returned from the method invocation
3024   * @throws Exception exceptions thrown by the called method
3025   */
3026  private static short CallStaticShortMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
3027    if (VM.VerifyAssertions) {
3028      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
3029    }
3030    if (traceJNI) VM.sysWrite("JNI called: CallStaticShortMethod  \n");
3031    RuntimeEntrypoints.checkJNICountDownToGC();
3032
3033    try {
3034      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Short);
3035      return Reflection.unwrapShort(returnObj);     // should be a wrapper for an short value
3036    } catch (Throwable unexpected) {
3037      if (traceJNI) unexpected.printStackTrace(System.err);
3038      env.recordException(unexpected);
3039      return 0;
3040    }
3041  }
3042
3043  /**
3044   * CallStaticShortMethodV:  invoke a static method that returns a short value
3045   * @param env A JREF index for the JNI environment object
3046   * @param classJREF a JREF index for the class object
3047   * @param methodID id of a MethodReference
3048   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
3049   *                   of the appropriate type for the method invocation
3050   * @return the short value returned from the method invocation
3051   * @throws Exception exceptions thrown by the called method
3052   */
3053  private static short CallStaticShortMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3054      throws Exception {
3055    if (traceJNI) VM.sysWrite("JNI called: CallStaticShortMethodV  \n");
3056    RuntimeEntrypoints.checkJNICountDownToGC();
3057
3058    try {
3059      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Short);
3060      return Reflection.unwrapShort(returnObj);     // should be a wrapper for a short value
3061    } catch (Throwable unexpected) {
3062      if (traceJNI) unexpected.printStackTrace(System.err);
3063      env.recordException(unexpected);
3064      return 0;
3065    }
3066  }
3067
3068  /**
3069   * CallStaticShortMethodA:  invoke a static method that returns a short value
3070   * @param env A JREF index for the JNI environment object
3071   * @param classJREF a JREF index for the class object
3072   * @param methodID id of a MethodReference
3073   * @param argAddress address of an array of jvalues (jvalue*)
3074   * @return the short value returned from the method invocation
3075   * @throws Exception exceptions thrown by the called method
3076   */
3077  private static short CallStaticShortMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3078      throws Exception {
3079    if (traceJNI) VM.sysWrite("JNI called: CallStaticShortMethodA  \n");
3080    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Short, true);
3081    return Reflection.unwrapShort(returnObj);
3082  }
3083
3084  /**
3085   * CallStaticIntMethod:  invoke a static method that returns an integer value
3086   *                       arguments passed using the vararg ... style
3087   * NOTE:  the vararg's are not visible in the method signature here; they are saved
3088   *        in the caller frame and the glue frame
3089   * <p>
3090   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
3091   * with a C implementation in the bootloader when the VM starts.</strong>
3092   * @param env A JREF index for the JNI environment object
3093   * @param classJREF a JREF index for the class object
3094   * @param methodID id of a MethodReference
3095   * @return the integer value returned from the method invocation
3096   * @throws Exception exceptions thrown by the called method
3097   */
3098  private static int CallStaticIntMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
3099    if (VM.VerifyAssertions) {
3100      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
3101    }
3102    if (traceJNI) VM.sysWrite("JNI called: CallStaticIntMethod  \n");
3103    RuntimeEntrypoints.checkJNICountDownToGC();
3104
3105    try {
3106      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Int);
3107      return Reflection.unwrapInt(returnObj);     // should be a wrapper for an integer value
3108    } catch (Throwable unexpected) {
3109      if (traceJNI) unexpected.printStackTrace(System.err);
3110      env.recordException(unexpected);
3111      return 0;
3112    }
3113  }
3114
3115  /**
3116   * CallStaticIntMethodV:  invoke a static method that returns an integer value
3117   * @param env A JREF index for the JNI environment object
3118   * @param classJREF a JREF index for the class object
3119   * @param methodID id of a MethodReference
3120   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
3121   *                   of the appropriate type for the method invocation
3122   * @return the integer value returned from the method invocation
3123   * @throws Exception exceptions thrown by the called method
3124   */
3125  private static int CallStaticIntMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3126      throws Exception {
3127    if (traceJNI) VM.sysWrite("JNI called: CallStaticIntMethodV  \n");
3128    RuntimeEntrypoints.checkJNICountDownToGC();
3129
3130    try {
3131      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Int);
3132      return Reflection.unwrapInt(returnObj);     // should be a wrapper for an integer value
3133    } catch (Throwable unexpected) {
3134      if (traceJNI) unexpected.printStackTrace(System.err);
3135      env.recordException(unexpected);
3136      return 0;
3137    }
3138  }
3139
3140  /**
3141   * CallStaticIntMethodA:  invoke a static method that returns an integer value
3142   * @param env A JREF index for the JNI environment object
3143   * @param classJREF a JREF index for the class object
3144   * @param methodID id of a MethodReference
3145   * @param argAddress a raw address to an array of unions in C, each element is 2-word and hold an argument
3146   *                   of the appropriate type for the method invocation
3147   * @return the integer value returned from the method invocation
3148   * @throws Exception exceptions thrown by the called method
3149   */
3150  private static int CallStaticIntMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3151      throws Exception {
3152    if (traceJNI) VM.sysWrite("JNI called: CallStaticIntMethodA  \n");
3153    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Int, true);
3154    return Reflection.unwrapInt(returnObj);
3155  }
3156
3157  /**
3158   * CallStaticLongMethod:  invoke a static method that returns a long value
3159   *                        arguments passed using the vararg ... style
3160   * NOTE:  the vararg's are not visible in the method signature here; they are saved
3161   *        in the caller frame and the glue frame
3162   * <p>
3163   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
3164   * with a C implementation in the bootloader when the VM starts.</strong>
3165   * @param env A JREF index for the JNI environment object
3166   * @param classJREF a JREF index for the class object
3167   * @param methodID id of a MethodReference
3168   * @return the long value returned from the method invocation
3169   * @throws Exception exceptions thrown by the called method
3170   */
3171  private static long CallStaticLongMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
3172    if (VM.VerifyAssertions) {
3173      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
3174    }
3175    if (traceJNI) VM.sysWrite("JNI called: CallStaticLongMethod  \n");
3176    RuntimeEntrypoints.checkJNICountDownToGC();
3177
3178    try {
3179      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Long);
3180      return Reflection.unwrapLong(returnObj);     // should be a wrapper for a long value
3181    } catch (Throwable unexpected) {
3182      if (traceJNI) unexpected.printStackTrace(System.err);
3183      env.recordException(unexpected);
3184      return 0L;
3185    }
3186  }
3187
3188  /**
3189   * CallStaticLongMethodV:  invoke a static method that returns a long value
3190   * @param env A JREF index for the JNI environment object
3191   * @param classJREF a JREF index for the class object
3192   * @param methodID id of a MethodReference
3193   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
3194   *                   of the appropriate type for the method invocation
3195   * @return the long value returned from the method invocation
3196   * @throws Exception exceptions thrown by the called method
3197   */
3198  private static long CallStaticLongMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3199      throws Exception {
3200    if (traceJNI) VM.sysWrite("JNI called: CallStaticLongMethodV  \n");
3201    RuntimeEntrypoints.checkJNICountDownToGC();
3202
3203    try {
3204      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Long);
3205      return Reflection.unwrapLong(returnObj);     // should be a wrapper for a long value
3206    } catch (Throwable unexpected) {
3207      if (traceJNI) unexpected.printStackTrace(System.err);
3208      env.recordException(unexpected);
3209      return 0L;
3210    }
3211  }
3212
3213  /**
3214   * CallStaticLongMethodA:  invoke a static method that returns a long value
3215   * @param env A JREF index for the JNI environment object
3216   * @param classJREF a JREF index for the class object
3217   * @param methodID id of a MethodReference
3218   * @param argAddress address of an array of jvalues (jvalue*)
3219   * @return the long value returned from the method invocation
3220   * @throws Exception exceptions thrown by the called method
3221   */
3222  private static long CallStaticLongMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3223      throws Exception {
3224    if (traceJNI) VM.sysWrite("JNI called: CallStaticLongMethodA  \n");
3225    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Long, true);
3226    return Reflection.unwrapLong(returnObj);
3227  }
3228
3229  /**
3230   * CallStaticFloagMethod:  invoke a static method that returns a float value
3231   *                         arguments passed using the vararg ... style
3232   * NOTE:  the vararg's are not visible in the method signature here; they are saved
3233   *        in the caller frame and the glue frame
3234   * <p>
3235   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
3236   * with a C implementation in the bootloader when the VM starts.</strong>
3237   * @param env A JREF index for the JNI environment object
3238   * @param classJREF a JREF index for the class object
3239   * @param methodID id of a MethodReference
3240   * @return the float value returned from the method invocation
3241   * @throws Exception exceptions thrown by the called method
3242   */
3243  private static float CallStaticFloatMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
3244    if (VM.VerifyAssertions) {
3245      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
3246    }
3247    if (traceJNI) VM.sysWrite("JNI called: CallStaticFloatMethod  \n");
3248    RuntimeEntrypoints.checkJNICountDownToGC();
3249
3250    try {
3251      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Float);
3252      return Reflection.unwrapFloat(returnObj);     // should be a wrapper for a float value
3253    } catch (Throwable unexpected) {
3254      if (traceJNI) unexpected.printStackTrace(System.err);
3255      env.recordException(unexpected);
3256      return 0f;
3257    }
3258  }
3259
3260  /**
3261   * CallStaticFloatMethodV:  invoke a static method that returns a float value
3262   * @param env A JREF index for the JNI environment object
3263   * @param classJREF a JREF index for the class object
3264   * @param methodID id of a MethodReference
3265   * @param argAddress a raw address to a variable argument list, each element is 1-word or 2-words
3266   *                   of the appropriate type for the method invocation
3267   * @return the float value returned from the method invocation
3268   * @throws Exception exceptions thrown by the called method
3269   */
3270  private static float CallStaticFloatMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3271      throws Exception {
3272    if (traceJNI) VM.sysWrite("JNI called: CallStaticFloatMethodV  \n");
3273    RuntimeEntrypoints.checkJNICountDownToGC();
3274
3275    try {
3276      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Float);
3277      return Reflection.unwrapFloat(returnObj);     // should be a wrapper for a float value
3278    } catch (Throwable unexpected) {
3279      if (traceJNI) unexpected.printStackTrace(System.err);
3280      env.recordException(unexpected);
3281      return 0f;
3282    }
3283  }
3284
3285  /**
3286   * CallStaticFloatMethodA:  invoke a static method that returns a float value
3287   * @param env A JREF index for the JNI environment object
3288   * @param classJREF a JREF index for the class object
3289   * @param methodID id of a MethodReference
3290   * @param argAddress address of an array of jvalues (jvalue*)
3291   * @return the float value returned from the method invocation
3292   * @throws Exception exceptions thrown by the called method
3293   */
3294  private static float CallStaticFloatMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3295      throws Exception {
3296    if (traceJNI) VM.sysWrite("JNI called: CallStaticFloatMethodA  \n");
3297    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Float, true);
3298    return Reflection.unwrapFloat(returnObj);
3299  }
3300
3301  /**
3302   * CallStaticDoubleMethod:  invoke a static method that returns a double value
3303   *                          arguments passed using the vararg ... style
3304   * NOTE:  the vararg's are not visible in the method signature here; they are saved
3305   *        in the caller frame and the glue frame
3306   * <p>
3307   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
3308   * with a C implementation in the bootloader when the VM starts.</strong>
3309   * @param env A JREF index for the JNI environment object
3310   * @param classJREF a JREF index for the class object
3311   * @param methodID an id of a MethodReference
3312   * @return the double value returned from the method invocation
3313   * @throws Exception exceptions thrown by the called method
3314   */
3315  private static double CallStaticDoubleMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
3316    if (VM.VerifyAssertions) {
3317      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
3318    }
3319    if (traceJNI) VM.sysWrite("JNI called: CallStaticDoubleMethod  \n");
3320    RuntimeEntrypoints.checkJNICountDownToGC();
3321
3322    try {
3323      Object returnObj = JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Double);
3324      return Reflection.unwrapDouble(returnObj);     // should be a wrapper for a double value
3325    } catch (Throwable unexpected) {
3326      if (traceJNI) unexpected.printStackTrace(System.err);
3327      env.recordException(unexpected);
3328      return 0;
3329    }
3330  }
3331
3332  /**
3333   * CallStaticDoubleMethodV:  invoke a static method that returns a double value
3334   * @param env A JREF index for the JNI environment object
3335   * @param classJREF a JREF index for the class object
3336   * @param methodID an id of a MethodReference
3337   * @param argAddress a raw address to a  variable argument list, each element is 1-word or 2-words
3338   *                   of the appropriate type for the method invocation
3339   * @return the double value returned from the method invocation
3340   * @throws Exception exceptions thrown by the called method
3341   */
3342  private static double CallStaticDoubleMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3343      throws Exception {
3344    if (traceJNI) VM.sysWrite("JNI called: CallStaticDoubleMethodV  \n");
3345    RuntimeEntrypoints.checkJNICountDownToGC();
3346
3347    try {
3348      Object returnObj = JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Double);
3349      return Reflection.unwrapDouble(returnObj);     // should be a wrapper for a double value
3350    } catch (Throwable unexpected) {
3351      if (traceJNI) unexpected.printStackTrace(System.err);
3352      env.recordException(unexpected);
3353      return 0;
3354    }
3355  }
3356
3357  /**
3358   * CallStaticDoubleMethodA:  invoke a static method that returns a double value
3359   * @param env A JREF index for the JNI environment object
3360   * @param classJREF a JREF index for the class object
3361   * @param methodID id of a MethodReference
3362   * @param argAddress address of an array of jvalues (jvalue*)
3363   * @return the double value returned from the method invocation
3364   * @throws Exception exceptions thrown by the called method
3365   */
3366  private static double CallStaticDoubleMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3367      throws Exception {
3368    if (traceJNI) VM.sysWrite("JNI called: CallStaticDoubleMethodA  \n");
3369    Object returnObj = JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Double, true);
3370    return Reflection.unwrapDouble(returnObj);
3371  }
3372
3373  /**
3374   * CallStaticVoidMethod:  invoke a static method that returns void
3375   *                       arguments passed using the vararg ... style
3376   * NOTE:  the vararg's are not visible in the method signature here; they are saved
3377   *        in the caller frame and the glue frame
3378   * <p>
3379   * <strong>NOTE: This implementation is NOT used for IA32. On IA32, it is overwritten
3380   * with a C implementation in the bootloader when the VM starts.</strong>
3381   * @param env A JREF index for the JNI environment object
3382   * @param classJREF a JREF index for the class object
3383   * @param methodID id of a MethodReference
3384   * @throws Exception exceptions thrown by the called method
3385   */
3386  private static void CallStaticVoidMethod(JNIEnvironment env, int classJREF, int methodID) throws Exception {
3387    if (VM.VerifyAssertions) {
3388      VM._assert(VM.BuildForPowerPC, ERROR_MSG_WRONG_IMPLEMENTATION);
3389    }
3390    if (traceJNI) VM.sysWrite("JNI called: CallStaticVoidMethod  \n");
3391    RuntimeEntrypoints.checkJNICountDownToGC();
3392
3393    try {
3394      JNIHelpers.invokeWithDotDotVarArg(methodID, TypeReference.Void);
3395    } catch (Throwable unexpected) {
3396      if (traceJNI) unexpected.printStackTrace(System.err);
3397      env.recordException(unexpected);
3398    }
3399  }
3400
3401  /**
3402   * CallStaticVoidMethodA:  invoke a static method that returns void
3403   * @param env A JREF index for the JNI environment object
3404   * @param classJREF a JREF index for the class object
3405   * @param methodID id of a MethodReference
3406   * @param argAddress a raw address to an array of unions in C, each element is 2-word and hold an argument
3407   *                   of the appropriate type for the method invocation
3408   * @throws Exception exceptions thrown by the called method
3409   */
3410  private static void CallStaticVoidMethodV(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3411      throws Exception {
3412    if (traceJNI) VM.sysWrite("JNI called: CallStaticVoidMethodV  \n");
3413    RuntimeEntrypoints.checkJNICountDownToGC();
3414
3415    try {
3416      JNIHelpers.invokeWithVarArg(methodID, argAddress, TypeReference.Void);
3417    } catch (Throwable unexpected) {
3418      if (traceJNI) unexpected.printStackTrace(System.err);
3419      env.recordException(unexpected);
3420    }
3421  }
3422
3423  /**
3424   * CallStaticVoidMethodA:  invoke a static method that returns void
3425   * @param env A JREF index for the JNI environment object
3426   * @param classJREF a JREF index for the class object
3427   * @param methodID id of a MethodReference
3428   * @param argAddress address of an array of jvalues (jvalue*)
3429   * @throws Exception exceptions thrown by the called method
3430   */
3431  private static void CallStaticVoidMethodA(JNIEnvironment env, int classJREF, int methodID, Address argAddress)
3432      throws Exception {
3433    if (traceJNI) VM.sysWrite("JNI called: CallStaticVoidMethodA  \n");
3434    JNIGenericHelpers.callMethodJValuePtr(env, 0, methodID, argAddress, TypeReference.Void, true);
3435  }
3436
3437  /**
3438   * GetStaticFieldID:  return a field id which can be cached in native code and reused
3439   * @param env A JREF index for the JNI environment object
3440   * @param classJREF a JREF index for the RVMClass object
3441   * @param fieldNameAddress a raw address to a null-terminated string in C for the field name
3442   * @param descriptorAddress a raw address to a null-terminated string in C for the descriptor
3443   * @return the offset of a static field given the class, field name
3444   *         and type. Return 0 if the field is not found
3445   * @throws NoSuchFieldError if the specified field cannot be found
3446   * @throws ExceptionInInitializerError if the class initializer fails
3447   * @throws OutOfMemoryError if the system runs out of memory
3448   */
3449  private static int GetStaticFieldID(JNIEnvironment env, int classJREF, Address fieldNameAddress,
3450                                      Address descriptorAddress) {
3451    if (traceJNI) VM.sysWrite("JNI called: GetStaticFieldID  \n");
3452    RuntimeEntrypoints.checkJNICountDownToGC();
3453
3454    try {
3455      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
3456
3457      String fieldString = JNIGenericHelpers.createStringFromC(fieldNameAddress);
3458      Atom fieldName = Atom.findOrCreateAsciiAtom(fieldString);
3459      String descriptorString = JNIGenericHelpers.createStringFromC(descriptorAddress);
3460      Atom descriptor = Atom.findOrCreateAsciiAtom(descriptorString);
3461
3462      RVMType rvmType = java.lang.JikesRVMSupport.getTypeForClass(cls);
3463      if (rvmType.isClassType()) {
3464        // First search for the fields in the class and its superclasses
3465        for (RVMClass curClass = rvmType.asClass(); curClass != null; curClass = curClass.getSuperClass()) {
3466          for (RVMField field : curClass.getStaticFields()) {
3467            if (field.getName() == fieldName && field.getDescriptor() == descriptor) {
3468              return field.getId();
3469            }
3470          }
3471        }
3472        // Now search all implemented interfaces (includes inherited interfaces)
3473        for (RVMClass curClass : rvmType.asClass().getAllImplementedInterfaces()) {
3474          for (RVMField field : curClass.getStaticFields()) {
3475            if (field.getName() == fieldName && field.getDescriptor() == descriptor) {
3476              return field.getId();
3477            }
3478          }
3479        }
3480      }
3481
3482      env.recordException(new NoSuchFieldError(fieldString + ", " + descriptorString + " of " + cls));
3483      return 0;
3484    } catch (Throwable unexpected) {
3485      if (traceJNI) unexpected.printStackTrace(System.err);
3486      env.recordException(unexpected);
3487      return 0;
3488    }
3489  }
3490
3491  /**
3492   * GetStaticObjectField: read a static field of type Object
3493   * @param env A JREF index for the JNI environment object
3494   * @param classJREF a JREF index for the RVMClass object
3495   * @param fieldID the id for the RVMField that describes this field
3496   * @return the value of the Object field, converted to a JREF index
3497   *         or 0 if the fieldID is incorrect
3498   */
3499  private static int GetStaticObjectField(JNIEnvironment env, int classJREF, int fieldID) {
3500    if (traceJNI) VM.sysWrite("JNI called: GetStaticObjectField  \n");
3501    RuntimeEntrypoints.checkJNICountDownToGC();
3502
3503    try {
3504      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3505      Object value = field.getObjectUnchecked(null);
3506      return env.pushJNIRef(value);
3507    } catch (Throwable unexpected) {
3508      if (traceJNI) unexpected.printStackTrace(System.err);
3509      env.recordException(unexpected);
3510      return 0;
3511    }
3512  }
3513
3514  /**
3515   * GetStaticBooleanField: read a static field of type boolean
3516   * @param env A JREF index for the JNI environment object
3517   * @param classJREF a JREF index for the RVMClass object
3518   * @param fieldID the id for the RVMField that describes this field
3519   * @return the value of the boolean field, or 0 if the fieldID is incorrect
3520   */
3521  private static int GetStaticBooleanField(JNIEnvironment env, int classJREF, int fieldID) {
3522    if (traceJNI) VM.sysWrite("JNI called: GetStaticBooleanField  \n");
3523    RuntimeEntrypoints.checkJNICountDownToGC();
3524
3525    try {
3526      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3527      return field.getBooleanValueUnchecked(null) ? 1 : 0;
3528    } catch (Throwable unexpected) {
3529      if (traceJNI) unexpected.printStackTrace(System.err);
3530      env.recordException(unexpected);
3531      return 0;
3532    }
3533  }
3534
3535  /**
3536   * GetStaticByteField:  read a static field of type byte
3537   * @param env A JREF index for the JNI environment object
3538   * @param classJREF a JREF index for the RVMClass object
3539   * @param fieldID the id for the RVMField that describes this field
3540   * @return the value of the byte field, or 0 if the fieldID is incorrect
3541   */
3542  private static int GetStaticByteField(JNIEnvironment env, int classJREF, int fieldID) {
3543    if (traceJNI) VM.sysWrite("JNI called: GetStaticByteField  \n");
3544    RuntimeEntrypoints.checkJNICountDownToGC();
3545
3546    try {
3547      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3548      return field.getByteValueUnchecked(null);
3549    } catch (Throwable unexpected) {
3550      if (traceJNI) unexpected.printStackTrace(System.err);
3551      env.recordException(unexpected);
3552      return 0;
3553    }
3554  }
3555
3556  /**
3557   * GetStaticCharField:  read a static field of type character
3558   * @param env A JREF index for the JNI environment object
3559   * @param classJREF a JREF index for the RVMClass object
3560   * @param fieldID the id for the RVMField that describes this field
3561   * @return the value of the character field, or 0 if the fieldID is incorrect
3562   */
3563  private static int GetStaticCharField(JNIEnvironment env, int classJREF, int fieldID) {
3564    if (traceJNI) VM.sysWrite("JNI called: GetStaticCharField  \n");
3565    RuntimeEntrypoints.checkJNICountDownToGC();
3566
3567    try {
3568      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3569      return field.getCharValueUnchecked(null);
3570    } catch (Throwable unexpected) {
3571      if (traceJNI) unexpected.printStackTrace(System.err);
3572      env.recordException(unexpected);
3573      return 0;
3574    }
3575  }
3576
3577  /**
3578   * GetStaticShortField:  read a static field of type short
3579   * @param env A JREF index for the JNI environment object
3580   * @param classJREF a JREF index for the RVMClass object
3581   * @param fieldID the id for the RVMField that describes this field
3582   * @return the value of the short field, or 0 if the fieldID is incorrect
3583   */
3584  private static int GetStaticShortField(JNIEnvironment env, int classJREF, int fieldID) {
3585    if (traceJNI) VM.sysWrite("JNI called: GetStaticShortField  \n");
3586    RuntimeEntrypoints.checkJNICountDownToGC();
3587
3588    try {
3589      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3590      return field.getShortValueUnchecked(null);
3591    } catch (Throwable unexpected) {
3592      if (traceJNI) unexpected.printStackTrace(System.err);
3593      env.recordException(unexpected);
3594      return 0;
3595    }
3596  }
3597
3598  /**
3599   * GetStaticIntField:  read a static field of type integer
3600   * @param env A JREF index for the JNI environment object
3601   * @param classJREF a JREF index for the RVMClass object
3602   * @param fieldID the id for the RVMField that describes this field
3603   * @return the value of the integer field, or 0 if the fieldID is incorrect
3604   */
3605  private static int GetStaticIntField(JNIEnvironment env, int classJREF, int fieldID) {
3606    if (traceJNI) VM.sysWrite("JNI called: GetStaticIntField  \n");
3607    RuntimeEntrypoints.checkJNICountDownToGC();
3608
3609    try {
3610      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3611      return field.getIntValueUnchecked(null);
3612    } catch (Throwable unexpected) {
3613      if (traceJNI) unexpected.printStackTrace(System.err);
3614      env.recordException(unexpected);
3615      return 0;
3616    }
3617  }
3618
3619  /**
3620   * GetStaticLongField:  read a static field of type long
3621   * @param env A JREF index for the JNI environment object
3622   * @param classJREF a JREF index for the RVMClass object
3623   * @param fieldID the id for the RVMField that describes this field
3624   * @return the value of the long field or 0 if the fieldID is incorrect
3625   */
3626  private static long GetStaticLongField(JNIEnvironment env, int classJREF, int fieldID) {
3627    if (traceJNI) VM.sysWrite("JNI called: GetStaticLongField  \n");
3628    RuntimeEntrypoints.checkJNICountDownToGC();
3629
3630    try {
3631      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3632      return field.getLongValueUnchecked(null);
3633    } catch (Throwable unexpected) {
3634      if (traceJNI) unexpected.printStackTrace(System.err);
3635      env.recordException(unexpected);
3636      return 0;
3637    }
3638  }
3639
3640  /**
3641   * GetStaticFloatField:  read a static field of type float
3642   * @param env A JREF index for the JNI environment object
3643   * @param classJREF a JREF index for the RVMClass object
3644   * @param fieldID the id for the RVMField that describes this field
3645   * @return the value of the float field or 0 if the fieldID is incorrect
3646   */
3647  private static float GetStaticFloatField(JNIEnvironment env, int classJREF, int fieldID) {
3648    if (traceJNI) VM.sysWrite("JNI called: GetStaticFloatField  \n");
3649    RuntimeEntrypoints.checkJNICountDownToGC();
3650
3651    try {
3652      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3653      return field.getFloatValueUnchecked(null);
3654    } catch (Throwable unexpected) {
3655      if (traceJNI) unexpected.printStackTrace(System.err);
3656      env.recordException(unexpected);
3657      return 0;
3658    }
3659  }
3660
3661  /**
3662   * GetStaticDoubleField:  read a static field of type double
3663   * @param env A JREF index for the JNI environment object
3664   * @param classJREF a JREF index for the RVMClass object
3665   * @param fieldID the id for the RVMField that describes this field
3666   * @return the value of the double field or 0 if the fieldID is incorrect
3667   */
3668  private static double GetStaticDoubleField(JNIEnvironment env, int classJREF, int fieldID) {
3669    if (traceJNI) VM.sysWrite("JNI called: GetStaticDoubleField  \n");
3670    RuntimeEntrypoints.checkJNICountDownToGC();
3671
3672    try {
3673      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3674      return field.getDoubleValueUnchecked(null);
3675    } catch (Throwable unexpected) {
3676      if (traceJNI) unexpected.printStackTrace(System.err);
3677      env.recordException(unexpected);
3678      return 0;
3679    }
3680  }
3681
3682  /**
3683   * SetStaticObjectField:  set a static field of type Object
3684   * @param env         A JREF index for the JNI environment object
3685   * @param classJREF   A JREF index for the {@link RVMClass} object
3686   * @param fieldID     The id for the {@link RVMField} that describes this
3687   *                    field
3688   * @param objectJREF  A JREF index of the value to assign
3689   */
3690  private static void SetStaticObjectField(JNIEnvironment env, int classJREF, int fieldID, int objectJREF) {
3691    if (traceJNI) VM.sysWrite("JNI called: SetStaticObjectField  \n");
3692    RuntimeEntrypoints.checkJNICountDownToGC();
3693
3694    try {
3695      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3696      Object ref = env.getJNIRef(objectJREF);
3697      field.setObjectValueUnchecked(null, ref);
3698    } catch (Throwable unexpected) {
3699      if (traceJNI) unexpected.printStackTrace(System.err);
3700      env.recordException(unexpected);
3701    }
3702  }
3703
3704  /**
3705   * SetStaticBooleanField:  set a static field of type boolean
3706   * @param env A JREF index for the JNI environment object
3707   * @param classJREF A JREF index for the RVMClass object
3708   * @param fieldID the id for the RVMField that describes this field
3709   * @param fieldValue  The value to assign
3710   */
3711  private static void SetStaticBooleanField(JNIEnvironment env, int classJREF, int fieldID, boolean fieldValue) {
3712    if (traceJNI) VM.sysWrite("JNI called: SetStaticBooleanField  \n");
3713    RuntimeEntrypoints.checkJNICountDownToGC();
3714
3715    try {
3716      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3717      field.setBooleanValueUnchecked(null, fieldValue);
3718    } catch (Throwable unexpected) {
3719      if (traceJNI) unexpected.printStackTrace(System.err);
3720      env.recordException(unexpected);
3721    }
3722  }
3723
3724  /**
3725   * SetStaticByteField:  set a static field of type byte
3726   * @param env A JREF index for the JNI environment object
3727   * @param classJREF a JREF index for the RVMClass object
3728   * @param fieldID the id for the RVMField that describes this field
3729   * @param fieldValue the value to assign
3730   */
3731  private static void SetStaticByteField(JNIEnvironment env, int classJREF, int fieldID, byte fieldValue) {
3732    if (traceJNI) VM.sysWrite("JNI called: SetStaticByteField  \n");
3733    RuntimeEntrypoints.checkJNICountDownToGC();
3734
3735    try {
3736      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3737      field.setByteValueUnchecked(null, fieldValue);
3738    } catch (Throwable unexpected) {
3739      if (traceJNI) unexpected.printStackTrace(System.err);
3740      env.recordException(unexpected);
3741    }
3742  }
3743
3744  /**
3745   * SetStaticCharField:  set a static field of type char
3746   * @param env A JREF index for the JNI environment object
3747   * @param classJREF a JREF index for the RVMClass object
3748   * @param fieldID the id for the RVMField that describes this field
3749   * @param fieldValue  The value to assign
3750   */
3751  private static void SetStaticCharField(JNIEnvironment env, int classJREF, int fieldID, char fieldValue) {
3752    if (traceJNI) VM.sysWrite("JNI called: SetStaticCharField  \n");
3753    RuntimeEntrypoints.checkJNICountDownToGC();
3754
3755    try {
3756      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3757      field.setCharValueUnchecked(null, fieldValue);
3758    } catch (Throwable unexpected) {
3759      if (traceJNI) unexpected.printStackTrace(System.err);
3760      env.recordException(unexpected);
3761    }
3762  }
3763
3764  /**
3765   * SetStaticShortField:  set a static field of type short
3766   * @param env A JREF index for the JNI environment object
3767   * @param classJREF a JREF index for the RVMClass object
3768   * @param fieldID the id for the RVMField that describes this field
3769   * @param fieldValue  The value to assign
3770   */
3771  private static void SetStaticShortField(JNIEnvironment env, int classJREF, int fieldID, short fieldValue) {
3772    if (traceJNI) VM.sysWrite("JNI called: SetStaticShortField  \n");
3773    RuntimeEntrypoints.checkJNICountDownToGC();
3774
3775    try {
3776      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3777      field.setShortValueUnchecked(null, fieldValue);
3778    } catch (Throwable unexpected) {
3779      if (traceJNI) unexpected.printStackTrace(System.err);
3780      env.recordException(unexpected);
3781    }
3782  }
3783
3784  /**
3785   * SetStaticIntField:  set a static field of type integer
3786   * @param env A JREF index for the JNI environment object
3787   * @param classJREF a JREF index for the RVMClass object
3788   * @param fieldID the id for the RVMField that describes this field
3789   * @param fieldValue  The value to assign
3790   */
3791  private static void SetStaticIntField(JNIEnvironment env, int classJREF, int fieldID, int fieldValue) {
3792    if (traceJNI) VM.sysWrite("JNI called: SetStaticIntField  \n");
3793    RuntimeEntrypoints.checkJNICountDownToGC();
3794
3795    try {
3796      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3797      field.setIntValueUnchecked(null, fieldValue);
3798    } catch (Throwable unexpected) {
3799      if (traceJNI) unexpected.printStackTrace(System.err);
3800      env.recordException(unexpected);
3801    }
3802  }
3803
3804  /**
3805   * SetStaticLongField:  set a static field of type long
3806   * @param env A JREF index for the JNI environment object
3807   * @param classJREF a JREF index for the RVMClass object
3808   * @param fieldID the id for the RVMField that describes this field
3809   * @param fieldValue  The value to assign
3810   */
3811  private static void SetStaticLongField(JNIEnvironment env, int classJREF, int fieldID, long fieldValue) {
3812    if (traceJNI) VM.sysWrite("JNI called: SetStaticLongField  \n");
3813    RuntimeEntrypoints.checkJNICountDownToGC();
3814
3815    try {
3816      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3817      field.setLongValueUnchecked(null, fieldValue);
3818    } catch (Throwable unexpected) {
3819      if (traceJNI) unexpected.printStackTrace(System.err);
3820      env.recordException(unexpected);
3821    }
3822  }
3823
3824  /**
3825   * SetStaticFloatField:  set a static field of type float
3826   * @param env A JREF index for the JNI environment object
3827   * @param classJREF a JREF index for the RVMClass object
3828   * @param fieldID the id for the RVMField that describes this field
3829   * @param fieldValue  The value to assign
3830   */
3831  private static void SetStaticFloatField(JNIEnvironment env, int classJREF, int fieldID, float fieldValue) {
3832    if (traceJNI) VM.sysWrite("JNI called: SetStaticFloatField  \n");
3833    RuntimeEntrypoints.checkJNICountDownToGC();
3834
3835    try {
3836      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3837      field.setFloatValueUnchecked(null, fieldValue);
3838    } catch (Throwable unexpected) {
3839      if (traceJNI) unexpected.printStackTrace(System.err);
3840      env.recordException(unexpected);
3841    }
3842  }
3843
3844  /**
3845   * SetStaticDoubleField:  set a static field of type float
3846   * @param env A JREF index for the JNI environment object
3847   * @param classJREF a JREF index for the RVMClass object
3848   * @param fieldID the id for the RVMField that describes this field
3849   * @param fieldValue  The value to assign
3850   */
3851  private static void SetStaticDoubleField(JNIEnvironment env, int classJREF, int fieldID, double fieldValue) {
3852    if (traceJNI) VM.sysWrite("JNI called: SetStaticDoubleField  \n");
3853    RuntimeEntrypoints.checkJNICountDownToGC();
3854
3855    try {
3856      RVMField field = MemberReference.getFieldRef(fieldID).resolve();
3857      field.setDoubleValueUnchecked(null, fieldValue);
3858    } catch (Throwable unexpected) {
3859      if (traceJNI) unexpected.printStackTrace(System.err);
3860      env.recordException(unexpected);
3861    }
3862  }
3863
3864  /**
3865   * NewString: create a String Object from C array of unicode chars
3866   * @param env A JREF index for the JNI environment object
3867   * @param uchars address of C array of 16 bit unicode characters
3868   * @param len the number of chars in the C array
3869   * @return the allocated String Object, converted to a JREF index
3870   *         or 0 if an OutOfMemoryError Exception has been thrown
3871   * @throws OutOfMemoryError if the system runs out of memory
3872   */
3873  private static int NewString(JNIEnvironment env, Address uchars, int len) {
3874    if (traceJNI) VM.sysWrite("JNI called: NewString  \n");
3875    RuntimeEntrypoints.checkJNICountDownToGC();
3876
3877    try {
3878      final char[] contents = new char[len];
3879      Memory.memcopy(Magic.objectAsAddress(contents), uchars, len * 2);
3880      return env.pushJNIRef(java.lang.JikesRVMSupport.newStringWithoutCopy(contents, 0, len));
3881    } catch (Throwable unexpected) {
3882      if (traceJNI) unexpected.printStackTrace(System.err);
3883      env.recordException(unexpected);
3884      return 0;
3885    }
3886  }
3887
3888  /**
3889   * GetStringLength:  return the length of a String
3890   * @param env A JREF index for the JNI environment object
3891   * @param objJREF a JREF index for the String object
3892   * @return the length of the String
3893   */
3894  private static int GetStringLength(JNIEnvironment env, int objJREF) {
3895    if (traceJNI) VM.sysWrite("JNI called: GetStringLength  \n");
3896    RuntimeEntrypoints.checkJNICountDownToGC();
3897
3898    try {
3899      String str = (String) env.getJNIRef(objJREF);
3900      return str.length();
3901    } catch (Throwable unexpected) {
3902      if (traceJNI) unexpected.printStackTrace(System.err);
3903      env.recordException(unexpected);
3904      return 0;
3905    }
3906  }
3907
3908  /**
3909   * GetStringChars:  return address of buffer containing contents of a String
3910   * @param env A JREF index for the JNI environment object
3911   * @param strJREF a JREF index for the String object
3912   * @param isCopyAddress address of isCopy jboolean (an int)
3913   * @return address of a copy of the String unicode characters
3914   *         and *isCopy is set to 1 (TRUE)
3915   * @throws OutOfMemoryError if the system runs out of memory
3916   */
3917  private static Address GetStringChars(JNIEnvironment env, int strJREF, Address isCopyAddress) {
3918    if (traceJNI) VM.sysWrite("JNI called: GetStringChars  \n");
3919    RuntimeEntrypoints.checkJNICountDownToGC();
3920
3921    String str = (String) env.getJNIRef(strJREF);
3922    char[] strChars = java.lang.JikesRVMSupport.getBackingCharArray(str);
3923    int strOffset = java.lang.JikesRVMSupport.getStringOffset(str);
3924    int len = java.lang.JikesRVMSupport.getStringLength(str);
3925
3926    // alloc non moving buffer in C heap for a copy of string contents
3927    Address copyBuffer = sysCall.sysMalloc(len * 2);
3928    if (copyBuffer.isZero()) {
3929      env.recordException(new OutOfMemoryError());
3930      return Address.zero();
3931    }
3932    try {
3933      Address strBase = Magic.objectAsAddress(strChars);
3934      Address srcBase = strBase.plus(strOffset * 2);
3935      Memory.memcopy(copyBuffer, srcBase, len * 2);
3936
3937      /* Set caller's isCopy boolean to true, if we got a valid (non-null)
3938         address */
3939      JNIGenericHelpers.setBoolStar(isCopyAddress, true);
3940
3941      return copyBuffer;
3942    } catch (Throwable unexpected) {
3943      if (traceJNI) unexpected.printStackTrace(System.err);
3944      env.recordException(unexpected);
3945      sysCall.sysFree(copyBuffer);
3946      return Address.zero();
3947    }
3948  }
3949
3950  /**
3951   * ReleaseStringChars:  release buffer obtained via GetStringChars
3952   * @param env A JREF index for the JNI environment object
3953   * @param objJREF a JREF index for the String object
3954   * @param bufAddress address of buffer to release
3955   */
3956  private static void ReleaseStringChars(JNIEnvironment env, int objJREF, Address bufAddress) {
3957    if (traceJNI) VM.sysWrite("JNI called: ReleaseStringChars  \n");
3958    RuntimeEntrypoints.checkJNICountDownToGC();
3959
3960    try {
3961      sysCall.sysFree(bufAddress);
3962    } catch (Throwable unexpected) {
3963      if (traceJNI) unexpected.printStackTrace(System.err);
3964      env.recordException(unexpected);
3965    }
3966  }
3967
3968  /**
3969   * NewStringUTF: create a String Object from C array of utf8 bytes
3970   * @param env A JREF index for the JNI environment object
3971   * @param utf8bytes address of C array of 8 bit utf8 bytes
3972   * @return the allocated String Object, converted to a JREF index
3973   *         or 0 if an OutOfMemoryError Exception has been thrown
3974   * @throws OutOfMemoryError if the system runs out of memory
3975   */
3976  private static int NewStringUTF(JNIEnvironment env, Address utf8bytes) {
3977    if (traceJNI) VM.sysWrite("JNI called: NewStringUTF  \n");
3978    RuntimeEntrypoints.checkJNICountDownToGC();
3979
3980    try {
3981      String returnString = JNIGenericHelpers.createUTFStringFromC(utf8bytes);
3982      return env.pushJNIRef(returnString);
3983    } catch (Throwable unexpected) {
3984      if (traceJNI) unexpected.printStackTrace(System.err);
3985      env.recordException(unexpected);
3986      return 0;
3987    }
3988  }
3989
3990  /**
3991   * GetStringUTFLength: return number of bytes to represent a String in UTF8 format
3992   * @param env A JREF index for the JNI environment object
3993   * @param objJREF a JREF index for the String object
3994   * @return number of bytes to represent in UTF8 format
3995   */
3996  private static int GetStringUTFLength(JNIEnvironment env, int objJREF) {
3997    if (traceJNI) VM.sysWrite("JNI called: GetStringUTFLength  \n");
3998    RuntimeEntrypoints.checkJNICountDownToGC();
3999
4000    try {
4001      String str = (String) env.getJNIRef(objJREF);
4002      return UTF8Convert.utfLength(str);
4003    } catch (Throwable unexpected) {
4004      if (traceJNI) unexpected.printStackTrace(System.err);
4005      env.recordException(unexpected);
4006      return 0;
4007    }
4008  }
4009
4010  /**
4011   * GetStringUTFChars:  return address of buffer containing contents of a String
4012   * @param env A JREF index for the JNI environment object
4013   * @param strJREF a JREF index for the String object
4014   * @param isCopyAddress address of isCopy jboolean (an int)
4015   * @return address of a copy of the String unicode characters
4016   *         and *isCopy is set to 1 (TRUE)
4017   * @throws OutOfMemoryError if the system runs out of memory
4018   */
4019  private static Address GetStringUTFChars(JNIEnvironment env, int strJREF, Address isCopyAddress) {
4020    if (traceJNI) VM.sysWrite("JNI called: GetStringUTFChars  \n");
4021    RuntimeEntrypoints.checkJNICountDownToGC();
4022
4023    String str = (String) env.getJNIRef(strJREF);
4024    if (str == null) {
4025      return Address.zero();
4026    }
4027
4028    // Get length of C string
4029    int len = UTF8Convert.utfLength(str) + 1; // for terminating zero
4030
4031    // alloc non moving buffer in C heap for string
4032    Address copyBuffer = sysCall.sysMalloc(len);
4033    if (copyBuffer.isZero()) {
4034      env.recordException(new OutOfMemoryError());
4035      return Address.zero();
4036    }
4037    try {
4038      JNIGenericHelpers.createUTFForCFromString(str, copyBuffer, len);
4039      JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4040      return copyBuffer;
4041    } catch (Throwable unexpected) {
4042      if (traceJNI) unexpected.printStackTrace(System.err);
4043      env.recordException(unexpected);
4044      return Address.zero();
4045    }
4046  }
4047
4048  /**
4049   * ReleaseStringUTFChars:  release buffer obtained via GetStringUTFChars
4050   * @param env A JREF index for the JNI environment object
4051   * @param objJREF a JREF index for the String object
4052   * @param bufAddress address of buffer to release
4053   */
4054  private static void ReleaseStringUTFChars(JNIEnvironment env, int objJREF, Address bufAddress) {
4055    if (traceJNI) VM.sysWrite("JNI called: ReleaseStringUTFChars  \n");
4056    RuntimeEntrypoints.checkJNICountDownToGC();
4057
4058    try {
4059      sysCall.sysFree(bufAddress);
4060    } catch (Throwable unexpected) {
4061      if (traceJNI) unexpected.printStackTrace(System.err);
4062      env.recordException(unexpected);
4063    }
4064  }
4065
4066  /**
4067   * GetArrayLength: return array length
4068   * @param env A JREF index for the JNI environment object
4069   * @param arrayJREF a JREF index for the source array
4070   * @return the array length, or -1 if it's not an array
4071   */
4072  private static int GetArrayLength(JNIEnvironment env, int arrayJREF) {
4073    if (traceJNI) VM.sysWrite("JNI called: GetArrayLength  \n");
4074    RuntimeEntrypoints.checkJNICountDownToGC();
4075
4076    try {
4077      Object theArray = env.getJNIRef(arrayJREF);
4078      RVMType arrayType = Magic.getObjectType(theArray);
4079      return arrayType.isArrayType() ? Magic.getArrayLength(theArray) : -1;
4080    } catch (Throwable unexpected) {
4081      if (traceJNI) unexpected.printStackTrace(System.err);
4082      env.recordException(unexpected);
4083      return -1;
4084    }
4085  }
4086
4087  /**
4088   * NewObjectArray: create a new Object array
4089   * @param env A JREF index for the JNI environment object
4090   * @param length the size of the new array
4091   * @param classJREF a JREF index for the class of the element
4092   * @param initElementJREF a JREF index for the value to initialize the array elements
4093   * @return the new Object array initialized
4094   * @throws OutOfMemoryError if the system runs out of memory
4095   */
4096  private static int NewObjectArray(JNIEnvironment env, int length, int classJREF, int initElementJREF) {
4097    if (traceJNI) VM.sysWrite("JNI called: NewObjectArray  \n");
4098    RuntimeEntrypoints.checkJNICountDownToGC();
4099
4100    try {
4101      Object initElement = env.getJNIRef(initElementJREF);
4102      Class<?> cls = (Class<?>) env.getJNIRef(classJREF);
4103
4104      if (cls == null) {
4105        throw new NullPointerException();
4106      }
4107      if (length < 0) {
4108        throw new NegativeArraySizeException();
4109      }
4110
4111      RVMArray arrayType = java.lang.JikesRVMSupport.getTypeForClass(cls).getArrayTypeForElementType();
4112      if (!arrayType.isInitialized()) {
4113        arrayType.resolve();
4114        arrayType.instantiate();
4115        arrayType.initialize();
4116      }
4117      Object[] newArray = (Object[]) RuntimeEntrypoints.resolvedNewArray(length, arrayType);
4118
4119      if (initElement != null) {
4120        for (int i = 0; i < length; i++) {
4121          newArray[i] = initElement;
4122        }
4123      }
4124
4125      return env.pushJNIRef(newArray);
4126    } catch (Throwable unexpected) {
4127      if (traceJNI) unexpected.printStackTrace(System.err);
4128      env.recordException(unexpected);
4129      return 0;
4130    }
4131  }
4132
4133  /**
4134   * GetObjectArrayElement: retrieve an object from an object array
4135   * @param env A JREF index for the JNI environment object
4136   * @param arrayJREF a JREF index for the source array
4137   * @param index the index for the targeted element
4138   * @return the object at the specified index
4139   * @throws ArrayIndexOutOfBoundsException if the index is out of range
4140   */
4141  private static int GetObjectArrayElement(JNIEnvironment env, int arrayJREF, int index) {
4142    if (traceJNI) VM.sysWrite("JNI called: GetObjectArrayElement  \n");
4143    RuntimeEntrypoints.checkJNICountDownToGC();
4144
4145    try {
4146      Object[] sourceArray = (Object[]) env.getJNIRef(arrayJREF);
4147
4148      if (sourceArray == null) {
4149        return 0;
4150      }
4151
4152      RVMArray arrayType = Magic.getObjectType(sourceArray).asArray();
4153      RVMType elementType = arrayType.getElementType();
4154      if (elementType.isPrimitiveType() || elementType.isUnboxedType()) {
4155        return 0;
4156      }
4157
4158      if (index >= Magic.getArrayLength(sourceArray)) {
4159        env.recordException(new ArrayIndexOutOfBoundsException());
4160        return 0;
4161      }
4162
4163      return env.pushJNIRef(sourceArray[index]);
4164    } catch (Throwable unexpected) {
4165      if (traceJNI) unexpected.printStackTrace(System.err);
4166      env.recordException(unexpected);
4167      return 0;
4168    }
4169  }
4170
4171  /**
4172   * SetObjectArrayElement: store an object into an object array
4173   * @param env A JREF index for the JNI environment object
4174   * @param arrayJREF a JREF index for the source array
4175   * @param index the index for the targeted element
4176   * @param objectJREF a JREF index for the object to store into the array
4177   * @throws ArrayStoreException if the element types do not match
4178   *            ArrayIndexOutOfBoundsException if the index is out of range
4179   */
4180  private static void SetObjectArrayElement(JNIEnvironment env, int arrayJREF, int index, int objectJREF) {
4181    if (traceJNI) VM.sysWrite("JNI called: SetObjectArrayElement  \n");
4182    RuntimeEntrypoints.checkJNICountDownToGC();
4183
4184    try {
4185      Object[] sourceArray = (Object[]) env.getJNIRef(arrayJREF);
4186      Object elem = env.getJNIRef(objectJREF);
4187      sourceArray[index] = elem;
4188    } catch (Throwable e) {
4189      env.recordException(e);
4190    }
4191  }
4192
4193  /**
4194   * NewBooleanArray: create a new boolean array
4195   * @param env A JREF index for the JNI environment object
4196   * @param length the size of the new array
4197   * @return the new boolean array
4198   * @throws OutOfMemoryError if the system runs out of memory
4199   */
4200  private static int NewBooleanArray(JNIEnvironment env, int length) {
4201    if (traceJNI) VM.sysWrite("JNI called: NewBooleanArray  \n");
4202    RuntimeEntrypoints.checkJNICountDownToGC();
4203
4204    try {
4205      boolean[] newArray = new boolean[length];
4206      return env.pushJNIRef(newArray);
4207    } catch (Throwable unexpected) {
4208      if (traceJNI) unexpected.printStackTrace(System.err);
4209      env.recordException(unexpected);
4210      return 0;
4211    }
4212  }
4213
4214  /**
4215   * NewByteArray: create a new byte array
4216   * @param env A JREF index for the JNI environment object
4217   * @param length the size of the new array
4218   * @return the new byte array
4219   * @throws OutOfMemoryError if the system runs out of memory
4220   */
4221  private static int NewByteArray(JNIEnvironment env, int length) {
4222    if (traceJNI) VM.sysWrite("JNI called: NewByteArray  \n");
4223    RuntimeEntrypoints.checkJNICountDownToGC();
4224
4225    try {
4226      byte[] newArray = new byte[length];
4227      return env.pushJNIRef(newArray);
4228    } catch (Throwable unexpected) {
4229      if (traceJNI) unexpected.printStackTrace(System.err);
4230      env.recordException(unexpected);
4231      return 0;
4232    }
4233  }
4234
4235  /**
4236   * NewCharArray: create a new char array
4237   * @param env A JREF index for the JNI environment object
4238   * @param length the size of the new array
4239   * @return the new char array
4240   * @throws OutOfMemoryError if the system runs out of memory
4241   */
4242  private static int NewCharArray(JNIEnvironment env, int length) {
4243    if (traceJNI) VM.sysWrite("JNI called: NewCharArray  \n");
4244    RuntimeEntrypoints.checkJNICountDownToGC();
4245
4246    try {
4247      char[] newArray = new char[length];
4248      return env.pushJNIRef(newArray);
4249    } catch (Throwable unexpected) {
4250      if (traceJNI) unexpected.printStackTrace(System.err);
4251      env.recordException(unexpected);
4252      return 0;
4253    }
4254  }
4255
4256  /**
4257   * NewShortArray: create a new short array
4258   * @param env A JREF index for the JNI environment object
4259   * @param length the size of the new array
4260   * @return the new short array
4261   * @throws OutOfMemoryError if the system runs out of memory
4262   */
4263  private static int NewShortArray(JNIEnvironment env, int length) {
4264    if (traceJNI) VM.sysWrite("JNI called: NewShortArray  \n");
4265    RuntimeEntrypoints.checkJNICountDownToGC();
4266
4267    try {
4268      short[] newArray = new short[length];
4269      return env.pushJNIRef(newArray);
4270    } catch (Throwable unexpected) {
4271      if (traceJNI) unexpected.printStackTrace(System.err);
4272      env.recordException(unexpected);
4273      return 0;
4274    }
4275  }
4276
4277  /**
4278   * NewIntArray: create a new integer array
4279   * @param env A JREF index for the JNI environment object
4280   * @param length the size of the new array
4281   * @return the new integer array
4282   * @throws OutOfMemoryError if the system runs out of memory
4283   */
4284  private static int NewIntArray(JNIEnvironment env, int length) {
4285    if (traceJNI) VM.sysWrite("JNI called: NewIntArray  \n");
4286    RuntimeEntrypoints.checkJNICountDownToGC();
4287
4288    try {
4289      int[] newArray = new int[length];
4290      return env.pushJNIRef(newArray);
4291    } catch (Throwable unexpected) {
4292      if (traceJNI) unexpected.printStackTrace(System.err);
4293      env.recordException(unexpected);
4294      return 0;
4295    }
4296  }
4297
4298  /**
4299   * NewLongArray: create a new long array
4300   * @param env A JREF index for the JNI environment object
4301   * @param length the size of the new array
4302   * @return the new long array
4303   * @throws OutOfMemoryError if the system runs out of memory
4304   */
4305  private static int NewLongArray(JNIEnvironment env, int length) {
4306    if (traceJNI) VM.sysWrite("JNI called: NewLongArray  \n");
4307    RuntimeEntrypoints.checkJNICountDownToGC();
4308
4309    try {
4310      long[] newArray = new long[length];
4311      return env.pushJNIRef(newArray);
4312    } catch (Throwable unexpected) {
4313      if (traceJNI) unexpected.printStackTrace(System.err);
4314      env.recordException(unexpected);
4315      return 0;
4316    }
4317  }
4318
4319  /**
4320   * NewFloatArray: create a new float array
4321   * @param env A JREF index for the JNI environment object
4322   * @param length the size of the new array
4323   * @return the new float array
4324   * @throws OutOfMemoryError if the system runs out of memory
4325   */
4326  private static int NewFloatArray(JNIEnvironment env, int length) {
4327    if (traceJNI) VM.sysWrite("JNI called: NewFloatArray  \n");
4328    RuntimeEntrypoints.checkJNICountDownToGC();
4329
4330    try {
4331      float[] newArray = new float[length];
4332      return env.pushJNIRef(newArray);
4333    } catch (Throwable unexpected) {
4334      if (traceJNI) unexpected.printStackTrace(System.err);
4335      env.recordException(unexpected);
4336      return 0;
4337    }
4338  }
4339
4340  /**
4341   * NewDoubleArray: create a new double array
4342   * @param env A JREF index for the JNI environment object
4343   * @param length the size of the new array
4344   * @return the new long array
4345   * @throws OutOfMemoryError if the system runs out of memory
4346   */
4347  private static int NewDoubleArray(JNIEnvironment env, int length) {
4348    if (traceJNI) VM.sysWrite("JNI called: NewDoubleArray  \n");
4349    RuntimeEntrypoints.checkJNICountDownToGC();
4350
4351    try {
4352      double[] newArray = new double[length];
4353      return env.pushJNIRef(newArray);
4354    } catch (Throwable unexpected) {
4355      if (traceJNI) unexpected.printStackTrace(System.err);
4356      env.recordException(unexpected);
4357      return 0;
4358    }
4359  }
4360
4361  /**
4362   * GetBooleanArrayElements: get all the elements of a boolean array
4363   * @param env A JREF index for the JNI environment object
4364   * @param arrayJREF a JREF index for the source array
4365   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4366   * @return A pointer to the boolean array and the isCopy flag is set to true if it's a copy
4367   *         or false if it's a direct pointer
4368   * @throws OutOfMemoryError if the system runs out of memory
4369   */
4370  private static Address GetBooleanArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4371    if (traceJNI) VM.sysWrite("JNI called: GetBooleanArrayElements  \n");
4372    RuntimeEntrypoints.checkJNICountDownToGC();
4373
4374    try {
4375      boolean[] sourceArray = (boolean[]) env.getJNIRef(arrayJREF);
4376      int size = sourceArray.length;
4377
4378      // alloc non moving buffer in C heap for a copy of string contents
4379      Address copyBuffer = sysCall.sysMalloc(size);
4380      if (copyBuffer.isZero()) {
4381        env.recordException(new OutOfMemoryError());
4382        return Address.zero();
4383      }
4384
4385      Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size);
4386
4387      /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4388         address */
4389      JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4390
4391      return copyBuffer;
4392    } catch (Throwable unexpected) {
4393      if (traceJNI) unexpected.printStackTrace(System.err);
4394      env.recordException(unexpected);
4395      return Address.zero();
4396    }
4397  }
4398
4399  /**
4400   * GetByteArrayElements: get all the elements of a byte array
4401   * @param env A JREF index for the JNI environment object
4402   * @param arrayJREF a JREF index for the source array
4403   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4404   * @return A pointer to the byte array and the isCopy flag is set to true if it's a copy
4405   *         or false if it's a direct pointer
4406   * @throws OutOfMemoryError if the system runs out of memory
4407   */
4408  private static Address GetByteArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4409    if (traceJNI) VM.sysWrite("JNI called: GetByteArrayElements \n");
4410    RuntimeEntrypoints.checkJNICountDownToGC();
4411
4412    try {
4413      byte[] sourceArray = (byte[]) env.getJNIRef(arrayJREF);
4414      int size = sourceArray.length;
4415
4416      if (MemoryManager.willNeverMove(sourceArray)) {
4417        /* return a direct pointer */
4418        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4419        return Magic.objectAsAddress(sourceArray);
4420      } else {
4421        // alloc non moving buffer in C heap for a copy of string contents
4422        Address copyBuffer = sysCall.sysMalloc(size);
4423
4424        if (copyBuffer.isZero()) {
4425          env.recordException(new OutOfMemoryError());
4426          return Address.zero();
4427        }
4428
4429        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size);
4430
4431        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4432           address */
4433        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4434
4435        return copyBuffer;
4436      }
4437    } catch (Throwable unexpected) {
4438      if (traceJNI) unexpected.printStackTrace(System.err);
4439      env.recordException(unexpected);
4440      return Address.zero();
4441    }
4442  }
4443
4444  /**
4445   * GetCharArrayElements: get all the elements of a char array
4446   * @param env A JREF index for the JNI environment object
4447   * @param arrayJREF a JREF index for the source array
4448   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4449   * @return A pointer to the char array and the isCopy flag is set to true if it's a copy
4450   *         or false if it's a direct pointer
4451   * @throws OutOfMemoryError if the system runs out of memory
4452   */
4453  private static Address GetCharArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4454    if (traceJNI) VM.sysWrite("JNI called: GetCharArrayElements  \n");
4455    RuntimeEntrypoints.checkJNICountDownToGC();
4456
4457    try {
4458      char[] sourceArray = (char[]) env.getJNIRef(arrayJREF);
4459      int size = sourceArray.length;
4460
4461      if (MemoryManager.willNeverMove(sourceArray)) {
4462        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4463        return Magic.objectAsAddress(sourceArray);
4464      } else {
4465        // alloc non moving buffer in C heap for a copy of string contents
4466        Address copyBuffer = sysCall.sysMalloc(size * BYTES_IN_CHAR);
4467        if (copyBuffer.isZero()) {
4468          env.recordException(new OutOfMemoryError());
4469          return Address.zero();
4470        }
4471
4472        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size * BYTES_IN_CHAR);
4473
4474        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4475         address */
4476        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4477
4478        return copyBuffer;
4479      }
4480    } catch (Throwable unexpected) {
4481      if (traceJNI) unexpected.printStackTrace(System.err);
4482      env.recordException(unexpected);
4483      return Address.zero();
4484    }
4485  }
4486
4487  /**
4488   * GetShortArrayElements: get all the elements of a short array
4489   * @param env A JREF index for the JNI environment object
4490   * @param arrayJREF a JREF index for the source array
4491   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4492   * @return A pointer to the short array and the isCopy flag is set to true if it's a copy
4493   *         or false if it's a direct pointer
4494   * @throws OutOfMemoryError if the system runs out of memory
4495   */
4496  private static Address GetShortArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4497    if (traceJNI) VM.sysWrite("JNI called: GetShortArrayElements  \n");
4498    RuntimeEntrypoints.checkJNICountDownToGC();
4499
4500    try {
4501      short[] sourceArray = (short[]) env.getJNIRef(arrayJREF);
4502      int size = sourceArray.length;
4503
4504      if (MemoryManager.willNeverMove(sourceArray)) {
4505        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4506        return Magic.objectAsAddress(sourceArray);
4507      } else {
4508        // alloc non moving buffer in C heap for a copy of string contents
4509        Address copyBuffer = sysCall.sysMalloc(size * BYTES_IN_SHORT);
4510        if (copyBuffer.isZero()) {
4511          env.recordException(new OutOfMemoryError());
4512          return Address.zero();
4513        }
4514
4515        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size * BYTES_IN_SHORT);
4516
4517        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4518         address */
4519        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4520
4521        return copyBuffer;
4522      }
4523    } catch (Throwable unexpected) {
4524      if (traceJNI) unexpected.printStackTrace(System.err);
4525      env.recordException(unexpected);
4526      return Address.zero();
4527    }
4528  }
4529
4530  /**
4531   * GetIntArrayElements: get all the elements of an integer array
4532   * @param env A JREF index for the JNI environment object
4533   * @param arrayJREF a JREF index for the source array
4534   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4535   * @return A pointer to the integer array and the isCopy flag is set to true if it's a copy
4536   *         or false if it's a direct pointer
4537   * @throws OutOfMemoryError if the system runs out of memory
4538   */
4539  private static Address GetIntArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4540    if (traceJNI) VM.sysWrite("JNI called: GetIntArrayElements  \n");
4541    RuntimeEntrypoints.checkJNICountDownToGC();
4542
4543    try {
4544      int[] sourceArray = (int[]) env.getJNIRef(arrayJREF);
4545      int size = sourceArray.length;
4546
4547      if (MemoryManager.willNeverMove(sourceArray)) {
4548        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4549        return Magic.objectAsAddress(sourceArray);
4550      } else {
4551        // alloc non moving buffer in C heap for a copy of array contents
4552        Address copyBuffer = sysCall.sysMalloc(size << LOG_BYTES_IN_INT);
4553        if (copyBuffer.isZero()) {
4554          env.recordException(new OutOfMemoryError());
4555          return Address.zero();
4556        }
4557        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size << LOG_BYTES_IN_INT);
4558
4559        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4560         address */
4561        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4562
4563        return copyBuffer;
4564      }
4565    } catch (Throwable unexpected) {
4566      if (traceJNI) unexpected.printStackTrace(System.err);
4567      env.recordException(unexpected);
4568      return Address.zero();
4569    }
4570  }
4571
4572  /**
4573   * GetLongArrayElements: get all the elements of a long array
4574   * @param env A JREF index for the JNI environment object
4575   * @param arrayJREF a JREF index for the source array
4576   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4577   * @return A pointer to the long array and the isCopy flag is set to true if it's a copy
4578   *         or false if it's a direct pointer
4579   * @throws OutOfMemoryError if the system runs out of memory
4580   */
4581  private static Address GetLongArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4582    if (traceJNI) VM.sysWrite("JNI called: GetLongArrayElements  \n");
4583    RuntimeEntrypoints.checkJNICountDownToGC();
4584
4585    try {
4586      long[] sourceArray = (long[]) env.getJNIRef(arrayJREF);
4587      int size = sourceArray.length;
4588
4589      if (MemoryManager.willNeverMove(sourceArray)) {
4590        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4591        return Magic.objectAsAddress(sourceArray);
4592      } else {
4593        // alloc non moving buffer in C heap for a copy of string contents
4594        Address copyBuffer = sysCall.sysMalloc(size << LOG_BYTES_IN_LONG);
4595        if (copyBuffer.isZero()) {
4596          env.recordException(new OutOfMemoryError());
4597          return Address.zero();
4598        }
4599        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size << LOG_BYTES_IN_LONG);
4600
4601        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4602         address */
4603        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4604
4605        return copyBuffer;
4606      }
4607    } catch (Throwable unexpected) {
4608      if (traceJNI) unexpected.printStackTrace(System.err);
4609      env.recordException(unexpected);
4610      return Address.zero();
4611    }
4612  }
4613
4614  /**
4615   * GetFloatArrayElements: get all the elements of a float array
4616   * @param env A JREF index for the JNI environment object
4617   * @param arrayJREF a JREF index for the source array
4618   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4619   * @return A pointer to the float array and the isCopy flag is set to true if it's a copy
4620   *         or false if it's a direct pointer
4621   * @throws OutOfMemoryError if the system runs out of memory
4622   */
4623  private static Address GetFloatArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4624    if (traceJNI) VM.sysWrite("JNI called: GetFloatArrayElements  \n");
4625    RuntimeEntrypoints.checkJNICountDownToGC();
4626
4627    try {
4628      float[] sourceArray = (float[]) env.getJNIRef(arrayJREF);
4629      int size = sourceArray.length;
4630
4631      if (MemoryManager.willNeverMove(sourceArray)) {
4632        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4633        return Magic.objectAsAddress(sourceArray);
4634      } else {
4635        // alloc non moving buffer in C heap for a copy of string contents
4636        Address copyBuffer = sysCall.sysMalloc(size << LOG_BYTES_IN_FLOAT);
4637        if (copyBuffer.isZero()) {
4638          env.recordException(new OutOfMemoryError());
4639          return Address.zero();
4640        }
4641
4642        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size << LOG_BYTES_IN_FLOAT);
4643
4644        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4645         address */
4646        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4647
4648        return copyBuffer;
4649      }
4650    } catch (Throwable unexpected) {
4651      if (traceJNI) unexpected.printStackTrace(System.err);
4652      env.recordException(unexpected);
4653      return Address.zero();
4654    }
4655  }
4656
4657  /**
4658   * GetDoubleArrayElements: get all the elements of a double array
4659   * @param env A JREF index for the JNI environment object
4660   * @param arrayJREF a JREF index for the source array
4661   * @param isCopyAddress address of a flag to indicate whether the returned array is a copy or a direct pointer
4662   * @return A pointer to the double array and the isCopy flag is set to true if it's a copy
4663   *         or false if it's a direct pointer
4664   * @throws OutOfMemoryError if the system runs out of memory
4665   */
4666  private static Address GetDoubleArrayElements(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
4667    if (traceJNI) VM.sysWrite("JNI called: GetDoubleArrayElements  \n");
4668    RuntimeEntrypoints.checkJNICountDownToGC();
4669
4670    try {
4671      double[] sourceArray = (double[]) env.getJNIRef(arrayJREF);
4672      int size = sourceArray.length;
4673
4674      if (MemoryManager.willNeverMove(sourceArray)) {
4675        JNIGenericHelpers.setBoolStar(isCopyAddress, false);
4676        return Magic.objectAsAddress(sourceArray);
4677      } else {
4678        // alloc non moving buffer in C heap for a copy of string contents
4679        Address copyBuffer = sysCall.sysMalloc(size << LOG_BYTES_IN_DOUBLE);
4680        if (copyBuffer.isZero()) {
4681          env.recordException(new OutOfMemoryError());
4682          return Address.zero();
4683        }
4684        Memory.memcopy(copyBuffer, Magic.objectAsAddress(sourceArray), size << LOG_BYTES_IN_DOUBLE);
4685
4686        /* Set caller's isCopy boolean to true, if we got a valid (non-null)
4687         address */
4688        JNIGenericHelpers.setBoolStar(isCopyAddress, true);
4689
4690        return copyBuffer;
4691      }
4692    } catch (Throwable unexpected) {
4693      if (traceJNI) unexpected.printStackTrace(System.err);
4694      env.recordException(unexpected);
4695      return Address.zero();
4696    }
4697  }
4698
4699  /**
4700   * ReleaseBooleanArrayElements: free the native copy of the array, update changes to Java array as indicated
4701   * @param env A JREF index for the JNI environment object
4702   * @param arrayJREF a JREF index for the source array
4703   * @param copyBufferAddress the address of the copy of the array
4704   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4705   *    releaseMode 0:  copy back and free the buffer
4706   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4707   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4708   */
4709  private static void ReleaseBooleanArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4710                                                  int releaseMode) {
4711    if (traceJNI) VM.sysWrite("JNI called: ReleaseBooleanArrayElements  \n");
4712    RuntimeEntrypoints.checkJNICountDownToGC();
4713
4714    try {
4715      boolean[] sourceArray = (boolean[]) env.getJNIRef(arrayJREF);
4716
4717      // If a direct pointer was given to the user, no need to update or release
4718      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4719        int size = sourceArray.length;
4720
4721        // mode 0 and mode 1:  copy back the buffer
4722        if ((releaseMode == 0 || releaseMode == 1) && size != 0) {
4723          for (int i = 0; i < size; i += BYTES_IN_INT) {
4724            Address addr = copyBufferAddress.plus(i);
4725            int data = addr.loadInt();
4726            if (VM.LittleEndian) {
4727              if (i < size) sourceArray[i] = ((data) & 0x000000ff) != 0;
4728              if (i + 1 < size) sourceArray[i + 1] = ((data >>> BITS_IN_BYTE) & 0x000000ff) != 0;
4729              if (i + 2 < size) sourceArray[i + 2] = ((data >>> (2 * BITS_IN_BYTE)) & 0x000000ff) != 0;
4730              if (i + 3 < size) sourceArray[i + 3] = ((data >>> (3 * BITS_IN_BYTE)) & 0x000000ff) != 0;
4731            } else {
4732              if (i < size) sourceArray[i] = ((data >>> (3 * BITS_IN_BYTE)) & 0x000000ff) != 0;
4733              if (i + 1 < size) sourceArray[i + 1] = ((data >>> (2 * BITS_IN_BYTE)) & 0x000000ff) != 0;
4734              if (i + 2 < size) sourceArray[i + 2] = ((data >>> BITS_IN_BYTE) & 0x000000ff) != 0;
4735              if (i + 3 < size) sourceArray[i + 3] = ((data) & 0x000000ff) != 0;
4736            }
4737          }
4738        }
4739
4740        // mode 0 and mode 2:  free the buffer
4741        if (releaseMode == 0 || releaseMode == 2) {
4742          sysCall.sysFree(copyBufferAddress);
4743        }
4744      }
4745    } catch (Throwable unexpected) {
4746      if (traceJNI) unexpected.printStackTrace(System.err);
4747      env.recordException(unexpected);
4748    }
4749  }
4750
4751  /**
4752   * ReleaseByteArrayElements: free the native copy of the array, update changes to Java array as indicated
4753   * @param env A JREF index for the JNI environment object
4754   * @param arrayJREF a JREF index for the source array
4755   * @param copyBufferAddress the address of the copy of the array
4756   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4757   *    releaseMode 0:  copy back and free the buffer
4758   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4759   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4760   */
4761  private static void ReleaseByteArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4762                                               int releaseMode) {
4763    if (traceJNI) VM.sysWrite("JNI called: ReleaseByteArrayElements  releaseMode=", releaseMode);
4764    RuntimeEntrypoints.checkJNICountDownToGC();
4765
4766    try {
4767      byte[] sourceArray = (byte[]) env.getJNIRef(arrayJREF);
4768
4769      // If a direct pointer was given to the user, no need to update or release
4770      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4771        int size = sourceArray.length;
4772        if (traceJNI) VM.sysWrite(" size=", size);
4773
4774        // mode 0 and mode 1:  copy back the buffer
4775        if ((releaseMode == 0 || releaseMode == 1) && size != 0) {
4776          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size);
4777        }
4778
4779        // mode 0 and mode 2:  free the buffer
4780        if (releaseMode == 0 || releaseMode == 2) {
4781          sysCall.sysFree(copyBufferAddress);
4782        }
4783      } else {
4784        // Nothing to be done
4785      }
4786    } catch (Throwable unexpected) {
4787      if (traceJNI) unexpected.printStackTrace(System.err);
4788      env.recordException(unexpected);
4789    }
4790    if (traceJNI) VM.sysWrite("\n");
4791  }
4792
4793  /**
4794   * ReleaseCharArrayElements: free the native copy of the array, update changes to Java array as indicated
4795   * @param env A JREF index for the JNI environment object
4796   * @param arrayJREF a JREF index for the source array
4797   * @param copyBufferAddress the address of the copy of the array
4798   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4799   *    releaseMode 0:  copy back and free the buffer
4800   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4801   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4802   */
4803  private static void ReleaseCharArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4804                                               int releaseMode) {
4805    if (traceJNI) VM.sysWrite("JNI called: ReleaseCharArrayElements \n");
4806    RuntimeEntrypoints.checkJNICountDownToGC();
4807
4808    try {
4809      char[] sourceArray = (char[]) env.getJNIRef(arrayJREF);
4810
4811      // If a direct pointer was given to the user, no need to update or release
4812      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4813        int size = sourceArray.length;
4814
4815        // mode 0 and mode 1:  copy back the buffer
4816        if ((releaseMode == 0 || releaseMode == 1) && size != 0) {
4817          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size << LOG_BYTES_IN_CHAR);
4818        }
4819
4820        // mode 0 and mode 2:  free the buffer
4821        if (releaseMode == 0 || releaseMode == 2) {
4822          sysCall.sysFree(copyBufferAddress);
4823        }
4824      }
4825    } catch (Throwable unexpected) {
4826      if (traceJNI) unexpected.printStackTrace(System.err);
4827      env.recordException(unexpected);
4828    }
4829  }
4830
4831  /**
4832   * ReleaseShortArrayElements: free the native copy of the array, update changes to Java array as indicated
4833   * @param env A JREF index for the JNI environment object
4834   * @param arrayJREF a JREF index for the source array
4835   * @param copyBufferAddress the address of the copy of the array
4836   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4837   *    releaseMode 0:  copy back and free the buffer
4838   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4839   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4840   */
4841  private static void ReleaseShortArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4842                                                int releaseMode) {
4843    if (traceJNI) VM.sysWrite("JNI called: ReleaseShortArrayElements  \n");
4844    RuntimeEntrypoints.checkJNICountDownToGC();
4845
4846    try {
4847      short[] sourceArray = (short[]) env.getJNIRef(arrayJREF);
4848
4849      // If a direct pointer was given to the user, no need to update or release
4850      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4851        int size = sourceArray.length;
4852
4853        // mode 0 and mode 1:  copy back the buffer
4854        if ((releaseMode == 0 || releaseMode == 1) && size != 0) {
4855          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size << LOG_BYTES_IN_SHORT);
4856        }
4857
4858        // mode 0 and mode 2:  free the buffer
4859        if (releaseMode == 0 || releaseMode == 2) {
4860          sysCall.sysFree(copyBufferAddress);
4861        }
4862      }
4863    } catch (Throwable unexpected) {
4864      if (traceJNI) unexpected.printStackTrace(System.err);
4865      env.recordException(unexpected);
4866    }
4867  }
4868
4869  /**
4870   * ReleaseIntArrayElements: free the native copy of the array, update changes to Java array as indicated
4871   * @param env A JREF index for the JNI environment object
4872   * @param arrayJREF a JREF index for the source array
4873   * @param copyBufferAddress the address of the copy of the array
4874   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4875   *    releaseMode 0:  copy back and free the buffer
4876   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4877   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4878   */
4879  private static void ReleaseIntArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4880                                              int releaseMode) {
4881    if (traceJNI) VM.sysWrite("JNI called: ReleaseIntArrayElements  \n");
4882    RuntimeEntrypoints.checkJNICountDownToGC();
4883
4884    try {
4885      int[] sourceArray = (int[]) env.getJNIRef(arrayJREF);
4886
4887      // If a direct pointer was given to the user, no need to update or release
4888      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4889        int size = sourceArray.length;
4890
4891        // mode 0 and mode 1:  copy back the buffer
4892        if (releaseMode == 0 || releaseMode == 1) {
4893          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size << LOG_BYTES_IN_INT);
4894        }
4895
4896        // mode 0 and mode 2:  free the buffer
4897        if (releaseMode == 0 || releaseMode == 2) {
4898          sysCall.sysFree(copyBufferAddress);
4899        }
4900      }
4901    } catch (Throwable unexpected) {
4902      if (traceJNI) unexpected.printStackTrace(System.err);
4903      env.recordException(unexpected);
4904    }
4905  }
4906
4907  /**
4908   * ReleaseLongArrayElements: free the native copy of the array, update changes to Java array as indicated
4909   * @param env A JREF index for the JNI environment object
4910   * @param arrayJREF a JREF index for the source array
4911   * @param copyBufferAddress the address of the copy of the array
4912   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4913   *    releaseMode 0:  copy back and free the buffer
4914   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4915   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4916   */
4917  private static void ReleaseLongArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4918                                               int releaseMode) {
4919    if (traceJNI) VM.sysWrite("JNI called: ReleaseLongArrayElements  \n");
4920    RuntimeEntrypoints.checkJNICountDownToGC();
4921
4922    try {
4923      long[] sourceArray = (long[]) env.getJNIRef(arrayJREF);
4924
4925      // If a direct pointer was given to the user, no need to update or release
4926      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4927        int size = sourceArray.length;
4928
4929        // mode 0 and mode 1:  copy back the buffer
4930        if (releaseMode == 0 || releaseMode == 1) {
4931          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size << LOG_BYTES_IN_LONG);
4932        }
4933
4934        // mode 0 and mode 2:  free the buffer
4935        if (releaseMode == 0 || releaseMode == 2) {
4936          sysCall.sysFree(copyBufferAddress);
4937        }
4938      }
4939    } catch (Throwable unexpected) {
4940      if (traceJNI) unexpected.printStackTrace(System.err);
4941      env.recordException(unexpected);
4942    }
4943  }
4944
4945  /**
4946   * ReleaseFloatArrayElements: free the native copy of the array, update changes to Java array as indicated
4947   * @param env A JREF index for the JNI environment object
4948   * @param arrayJREF a JREF index for the source array
4949   * @param copyBufferAddress the address of the copy of the array
4950   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4951   *    releaseMode 0:  copy back and free the buffer
4952   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4953   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4954   */
4955  private static void ReleaseFloatArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4956                                                int releaseMode) {
4957    if (traceJNI) VM.sysWrite("JNI called: ReleaseFloatArrayElements  \n");
4958    RuntimeEntrypoints.checkJNICountDownToGC();
4959
4960    try {
4961      float[] sourceArray = (float[]) env.getJNIRef(arrayJREF);
4962
4963      // If a direct pointer was given to the user, no need to update or release
4964      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
4965        int size = sourceArray.length;
4966
4967        // mode 0 and mode 1:  copy back the buffer
4968        if (releaseMode == 0 || releaseMode == 1) {
4969          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size << LOG_BYTES_IN_FLOAT);
4970        }
4971
4972        // mode 0 and mode 2:  free the buffer
4973        if (releaseMode == 0 || releaseMode == 2) {
4974          sysCall.sysFree(copyBufferAddress);
4975        }
4976      }
4977    } catch (Throwable unexpected) {
4978      if (traceJNI) unexpected.printStackTrace(System.err);
4979      env.recordException(unexpected);
4980    }
4981  }
4982
4983  /**
4984   * ReleaseDoubleArrayElements: free the native copy of the array, update changes to Java array as indicated
4985   * @param env A JREF index for the JNI environment object
4986   * @param arrayJREF a JREF index for the source array
4987   * @param copyBufferAddress the address of the copy of the array
4988   * @param releaseMode one of 3 codes to indicate whether to copy back or free the array:
4989   *    releaseMode 0:  copy back and free the buffer
4990   *    releaseMode 1:  JNI_COMMIT, copy back but do not free the buffer
4991   *    releaseMode 2:  JNI_ABORT, free the buffer with copying back
4992   */
4993  private static void ReleaseDoubleArrayElements(JNIEnvironment env, int arrayJREF, Address copyBufferAddress,
4994                                                 int releaseMode) {
4995    if (traceJNI) VM.sysWrite("JNI called: ReleaseDoubleArrayElements  \n");
4996    RuntimeEntrypoints.checkJNICountDownToGC();
4997
4998    try {
4999      double[] sourceArray = (double[]) env.getJNIRef(arrayJREF);
5000
5001      // If a direct pointer was given to the user, no need to update or release
5002      if (Magic.objectAsAddress(sourceArray).NE(copyBufferAddress)) {
5003        int size = sourceArray.length;
5004
5005        // mode 0 and mode 1:  copy back the buffer
5006        if (releaseMode == 0 || releaseMode == 1) {
5007          Memory.memcopy(Magic.objectAsAddress(sourceArray), copyBufferAddress, size << LOG_BYTES_IN_DOUBLE);
5008        }
5009
5010        // mode 0 and mode 2:  free the buffer
5011        if (releaseMode == 0 || releaseMode == 2) {
5012          sysCall.sysFree(copyBufferAddress);
5013        }
5014      }
5015    } catch (Throwable unexpected) {
5016      if (traceJNI) unexpected.printStackTrace(System.err);
5017      env.recordException(unexpected);
5018    }
5019  }
5020
5021  /**
5022   * GetBooleanArrayRegion: copy a region of the array into the native buffer
5023   * @param env A JREF index for the JNI environment object
5024   * @param arrayJREF a JREF index for the source array
5025   * @param startIndex the starting index to copy
5026   * @param length the number of elements to copy
5027   * @param bufAddress the destination address in native to copy to
5028   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5029   */
5030  private static void GetBooleanArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5031                                            Address bufAddress) {
5032    if (traceJNI) VM.sysWrite("JNI called: GetBooleanArrayRegion  \n");
5033    RuntimeEntrypoints.checkJNICountDownToGC();
5034
5035    try {
5036      boolean[] sourceArray = (boolean[]) env.getJNIRef(arrayJREF);
5037
5038      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5039        env.recordException(new ArrayIndexOutOfBoundsException());
5040        return;
5041      }
5042      Memory.memcopy(bufAddress, Magic.objectAsAddress(sourceArray).plus(startIndex), length);
5043    } catch (Throwable unexpected) {
5044      if (traceJNI) unexpected.printStackTrace(System.err);
5045      env.recordException(unexpected);
5046    }
5047  }
5048
5049  /**
5050   * GetByteArrayRegion: copy a region of the array into the native buffer
5051   * @param env A JREF index for the JNI environment object
5052   * @param arrayJREF a JREF index for the source array
5053   * @param startIndex the starting index to copy
5054   * @param length the number of elements to copy
5055   * @param bufAddress the destination address in native to copy to
5056   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5057   */
5058  private static void GetByteArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5059                                         Address bufAddress) {
5060    if (traceJNI) VM.sysWrite("JNI called: GetByteArrayRegion  \n");
5061    RuntimeEntrypoints.checkJNICountDownToGC();
5062
5063    try {
5064      byte[] sourceArray = (byte[]) env.getJNIRef(arrayJREF);
5065
5066      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5067        env.recordException(new ArrayIndexOutOfBoundsException());
5068        return;
5069      }
5070
5071      Memory.memcopy(bufAddress, Magic.objectAsAddress(sourceArray).plus(startIndex), length);
5072    } catch (Throwable unexpected) {
5073      if (traceJNI) unexpected.printStackTrace(System.err);
5074      env.recordException(unexpected);
5075    }
5076  }
5077
5078  /**
5079   * GetCharArrayRegion: copy a region of the array into the native buffer
5080   * @param env A JREF index for the JNI environment object
5081   * @param arrayJREF a JREF index for the source array
5082   * @param startIndex the starting index to copy
5083   * @param length the number of elements to copy
5084   * @param bufAddress the destination address in native to copy to
5085   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5086   */
5087  private static void GetCharArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5088                                         Address bufAddress) {
5089    if (traceJNI) VM.sysWrite("JNI called: GetCharArrayRegion  \n");
5090    RuntimeEntrypoints.checkJNICountDownToGC();
5091
5092    try {
5093      char[] sourceArray = (char[]) env.getJNIRef(arrayJREF);
5094
5095      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5096        env.recordException(new ArrayIndexOutOfBoundsException());
5097        return;
5098      }
5099
5100      Memory.memcopy(bufAddress,
5101                        Magic.objectAsAddress(sourceArray).plus(startIndex << LOG_BYTES_IN_CHAR),
5102                        length << LOG_BYTES_IN_CHAR);
5103    } catch (Throwable unexpected) {
5104      if (traceJNI) unexpected.printStackTrace(System.err);
5105      env.recordException(unexpected);
5106    }
5107  }
5108
5109  /**
5110   * GetShortArrayRegion: copy a region of the array into the native buffer
5111   * @param env A JREF index for the JNI environment object
5112   * @param arrayJREF a JREF index for the source array
5113   * @param startIndex the starting index to copy
5114   * @param length the number of elements to copy
5115   * @param bufAddress the destination address in native to copy to
5116   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5117   */
5118  private static void GetShortArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5119                                          Address bufAddress) {
5120    if (traceJNI) VM.sysWrite("JNI called: GetShortArrayRegion  \n");
5121    RuntimeEntrypoints.checkJNICountDownToGC();
5122
5123    try {
5124      short[] sourceArray = (short[]) env.getJNIRef(arrayJREF);
5125
5126      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5127        env.recordException(new ArrayIndexOutOfBoundsException());
5128        return;
5129      }
5130
5131      Memory.memcopy(bufAddress,
5132                        Magic.objectAsAddress(sourceArray).plus(startIndex << LOG_BYTES_IN_SHORT),
5133                        length << LOG_BYTES_IN_SHORT);
5134    } catch (Throwable unexpected) {
5135      if (traceJNI) unexpected.printStackTrace(System.err);
5136      env.recordException(unexpected);
5137    }
5138  }
5139
5140  /**
5141   * GetIntArrayRegion: copy a region of the array into the native buffer
5142   * @param env A JREF index for the JNI environment object
5143   * @param arrayJREF a JREF index for the source array
5144   * @param startIndex the starting index to copy
5145   * @param length the number of elements to copy
5146   * @param bufAddress the destination address in native to copy to
5147   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5148   */
5149  private static void GetIntArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5150                                        Address bufAddress) {
5151    if (traceJNI) VM.sysWrite("JNI called: GetIntArrayRegion  \n");
5152    RuntimeEntrypoints.checkJNICountDownToGC();
5153
5154    try {
5155      int[] sourceArray = (int[]) env.getJNIRef(arrayJREF);
5156
5157      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5158        env.recordException(new ArrayIndexOutOfBoundsException());
5159        return;
5160      }
5161
5162      Memory.memcopy(bufAddress,
5163                        Magic.objectAsAddress(sourceArray).plus(startIndex << LOG_BYTES_IN_INT),
5164                        length << LOG_BYTES_IN_INT);
5165    } catch (Throwable unexpected) {
5166      if (traceJNI) unexpected.printStackTrace(System.err);
5167      env.recordException(unexpected);
5168    }
5169  }
5170
5171  /**
5172   * GetLongArrayRegion: copy a region of the array into the native buffer
5173   * @param env A JREF index for the JNI environment object
5174   * @param arrayJREF a JREF index for the source array
5175   * @param startIndex the starting index to copy
5176   * @param length the number of elements to copy
5177   * @param bufAddress the destination address in native to copy to
5178   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5179   */
5180  private static void GetLongArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5181                                         Address bufAddress) {
5182    if (traceJNI) VM.sysWrite("JNI called: GetLongArrayRegion   \n");
5183    RuntimeEntrypoints.checkJNICountDownToGC();
5184
5185    try {
5186      long[] sourceArray = (long[]) env.getJNIRef(arrayJREF);
5187
5188      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5189        env.recordException(new ArrayIndexOutOfBoundsException());
5190        return;
5191      }
5192
5193      Memory.memcopy(bufAddress,
5194                        Magic.objectAsAddress(sourceArray).plus(startIndex << LOG_BYTES_IN_LONG),
5195                        length << LOG_BYTES_IN_LONG);
5196    } catch (Throwable unexpected) {
5197      if (traceJNI) unexpected.printStackTrace(System.err);
5198      env.recordException(unexpected);
5199    }
5200  }
5201
5202  /**
5203   * GetFloatArrayRegion: copy a region of the array into the native buffer
5204   * @param env A JREF index for the JNI environment object
5205   * @param arrayJREF a JREF index for the source array
5206   * @param startIndex the starting index to copy
5207   * @param length the number of elements to copy
5208   * @param bufAddress the destination address in native to copy to
5209   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5210   */
5211  private static void GetFloatArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5212                                          Address bufAddress) {
5213    if (traceJNI) VM.sysWrite("JNI called: GetFloatArrayRegion    \n");
5214    RuntimeEntrypoints.checkJNICountDownToGC();
5215
5216    try {
5217      float[] sourceArray = (float[]) env.getJNIRef(arrayJREF);
5218
5219      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5220        env.recordException(new ArrayIndexOutOfBoundsException());
5221        return;
5222      }
5223
5224      Memory.memcopy(bufAddress,
5225                        Magic.objectAsAddress(sourceArray).plus(startIndex << LOG_BYTES_IN_FLOAT),
5226                        length << LOG_BYTES_IN_FLOAT);
5227    } catch (Throwable unexpected) {
5228      if (traceJNI) unexpected.printStackTrace(System.err);
5229      env.recordException(unexpected);
5230    }
5231  }
5232
5233  /**
5234   * GetDoubleArrayRegion: copy a region of the array into the native buffer
5235   * @param env A JREF index for the JNI environment object
5236   * @param arrayJREF a JREF index for the source array
5237   * @param startIndex the starting index to copy
5238   * @param length the number of elements to copy
5239   * @param bufAddress the destination address in native to copy to
5240   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5241   */
5242  private static void GetDoubleArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5243                                           Address bufAddress) {
5244    if (traceJNI) VM.sysWrite("JNI called: GetDoubleArrayRegion   \n");
5245    RuntimeEntrypoints.checkJNICountDownToGC();
5246
5247    try {
5248      double[] sourceArray = (double[]) env.getJNIRef(arrayJREF);
5249
5250      if ((startIndex < 0) || (startIndex + length > sourceArray.length)) {
5251        env.recordException(new ArrayIndexOutOfBoundsException());
5252        return;
5253      }
5254
5255      Memory.memcopy(bufAddress,
5256                        Magic.objectAsAddress(sourceArray).plus(startIndex << LOG_BYTES_IN_DOUBLE),
5257                        length << LOG_BYTES_IN_DOUBLE);
5258    } catch (Throwable unexpected) {
5259      if (traceJNI) unexpected.printStackTrace(System.err);
5260      env.recordException(unexpected);
5261    }
5262  }
5263
5264  /**
5265   * SetBooleanArrayRegion: copy a region of the native buffer into the array (1 byte element)
5266   * @param env A JREF index for the JNI environment object
5267   * @param arrayJREF a JREF index for the destination array
5268   * @param startIndex the starting index to copy
5269   * @param length the number of elements to copy
5270   * @param bufAddress the source address in native to copy from
5271   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5272   */
5273  private static void SetBooleanArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5274                                            Address bufAddress) {
5275    if (traceJNI) VM.sysWrite("JNI called: SetBooleanArrayRegion  \n");
5276    RuntimeEntrypoints.checkJNICountDownToGC();
5277
5278    try {
5279      boolean[] destinationArray = (boolean[]) env.getJNIRef(arrayJREF);
5280
5281      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5282        env.recordException(new ArrayIndexOutOfBoundsException());
5283        return;
5284      }
5285
5286      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex), bufAddress, length);
5287    } catch (Throwable unexpected) {
5288      if (traceJNI) unexpected.printStackTrace(System.err);
5289      env.recordException(unexpected);
5290    }
5291  }
5292
5293  /**
5294   * SetByteArrayRegion: copy a region of the native buffer into the array (1 byte element)
5295   * @param env A JREF index for the JNI environment object
5296   * @param arrayJREF a JREF index for the destination array
5297   * @param startIndex the starting index to copy
5298   * @param length the number of elements to copy
5299   * @param bufAddress the source address in native to copy from
5300   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5301   */
5302  private static void SetByteArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5303                                         Address bufAddress) {
5304    if (traceJNI) VM.sysWrite("JNI called: SetByteArrayRegion  \n");
5305    RuntimeEntrypoints.checkJNICountDownToGC();
5306
5307    try {
5308      byte[] destinationArray = (byte[]) env.getJNIRef(arrayJREF);
5309
5310      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5311        env.recordException(new ArrayIndexOutOfBoundsException());
5312        return;
5313      }
5314
5315      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex), bufAddress, length);
5316    } catch (Throwable unexpected) {
5317      if (traceJNI) unexpected.printStackTrace(System.err);
5318      env.recordException(unexpected);
5319    }
5320  }
5321
5322  /**
5323   * SetCharArrayRegion: copy a region of the native buffer into the array (2 byte element)
5324   * @param env A JREF index for the JNI environment object
5325   * @param arrayJREF a JREF index for the destination array
5326   * @param startIndex the starting index to copy
5327   * @param length the number of elements to copy
5328   * @param bufAddress the source address in native to copy from
5329   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5330   */
5331  private static void SetCharArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5332                                         Address bufAddress) {
5333    if (traceJNI) VM.sysWrite("JNI called: SetCharArrayRegion  \n");
5334    RuntimeEntrypoints.checkJNICountDownToGC();
5335
5336    try {
5337      char[] destinationArray = (char[]) env.getJNIRef(arrayJREF);
5338
5339      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5340        env.recordException(new ArrayIndexOutOfBoundsException());
5341        return;
5342      }
5343
5344      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex << LOG_BYTES_IN_CHAR),
5345                        bufAddress,
5346                        length << LOG_BYTES_IN_CHAR);
5347    } catch (Throwable unexpected) {
5348      if (traceJNI) unexpected.printStackTrace(System.err);
5349      env.recordException(unexpected);
5350    }
5351  }
5352
5353  /**
5354   * SetShortArrayRegion: copy a region of the native buffer into the array (2 byte element)
5355   * @param env A JREF index for the JNI environment object
5356   * @param arrayJREF a JREF index for the destination array
5357   * @param startIndex the starting index to copy
5358   * @param length the number of elements to copy
5359   * @param bufAddress the source address in native to copy from
5360   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5361   */
5362  private static void SetShortArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5363                                          Address bufAddress) {
5364    if (traceJNI) VM.sysWrite("JNI called: SetShortArrayRegion  \n");
5365    RuntimeEntrypoints.checkJNICountDownToGC();
5366
5367    try {
5368      short[] destinationArray = (short[]) env.getJNIRef(arrayJREF);
5369
5370      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5371        env.recordException(new ArrayIndexOutOfBoundsException());
5372        return;
5373      }
5374
5375      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex << LOG_BYTES_IN_SHORT),
5376                        bufAddress,
5377                        length << LOG_BYTES_IN_SHORT);
5378    } catch (Throwable unexpected) {
5379      if (traceJNI) unexpected.printStackTrace(System.err);
5380      env.recordException(unexpected);
5381    }
5382  }
5383
5384  /**
5385   * SetIntArrayRegion: copy a region of the native buffer into the array
5386   * @param env A JREF index for the JNI environment object
5387   * @param arrayJREF a JREF index for the destination array
5388   * @param startIndex the starting index to copy
5389   * @param length the number of elements to copy
5390   * @param bufAddress the source address in native to copy from
5391   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5392   */
5393  private static void SetIntArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5394                                        Address bufAddress) {
5395    if (traceJNI) VM.sysWrite("JNI called: SetIntArrayRegion  \n");
5396    RuntimeEntrypoints.checkJNICountDownToGC();
5397
5398    try {
5399      int[] destinationArray = (int[]) env.getJNIRef(arrayJREF);
5400
5401      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5402        env.recordException(new ArrayIndexOutOfBoundsException());
5403        return;
5404      }
5405
5406      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex << LOG_BYTES_IN_INT),
5407                        bufAddress,
5408                        length << LOG_BYTES_IN_INT);
5409    } catch (Throwable unexpected) {
5410      if (traceJNI) unexpected.printStackTrace(System.err);
5411      env.recordException(unexpected);
5412    }
5413  }
5414
5415  /**
5416   * SetLongArrayRegion: copy a region of the native buffer into the array
5417   * @param env A JREF index for the JNI environment object
5418   * @param arrayJREF a JREF index for the destination array
5419   * @param startIndex the starting index to copy
5420   * @param length the number of elements to copy
5421   * @param bufAddress the source address in native to copy from
5422   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5423   */
5424  private static void SetLongArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5425                                         Address bufAddress) {
5426    if (traceJNI) VM.sysWrite("JNI called: SetLongArrayRegion  \n");
5427    RuntimeEntrypoints.checkJNICountDownToGC();
5428
5429    try {
5430      long[] destinationArray = (long[]) env.getJNIRef(arrayJREF);
5431
5432      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5433        env.recordException(new ArrayIndexOutOfBoundsException());
5434        return;
5435      }
5436
5437      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex << LOG_BYTES_IN_LONG),
5438                        bufAddress,
5439                        length << LOG_BYTES_IN_LONG);
5440    } catch (Throwable unexpected) {
5441      if (traceJNI) unexpected.printStackTrace(System.err);
5442      env.recordException(unexpected);
5443    }
5444  }
5445
5446  /**
5447   * SetFloatArrayRegion: copy a region of the native buffer into the array
5448   * @param env A JREF index for the JNI environment object
5449   * @param arrayJREF a JREF index for the destination array
5450   * @param startIndex the starting index to copy
5451   * @param length the number of elements to copy
5452   * @param bufAddress the source address in native to copy from
5453   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5454   */
5455  private static void SetFloatArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5456                                          Address bufAddress) {
5457    if (traceJNI) VM.sysWrite("JNI called: SetFloatArrayRegion  \n");
5458    RuntimeEntrypoints.checkJNICountDownToGC();
5459
5460    try {
5461      float[] destinationArray = (float[]) env.getJNIRef(arrayJREF);
5462
5463      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5464        env.recordException(new ArrayIndexOutOfBoundsException());
5465        return;
5466      }
5467
5468      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex << LOG_BYTES_IN_FLOAT),
5469                        bufAddress,
5470                        length << LOG_BYTES_IN_FLOAT);
5471    } catch (Throwable unexpected) {
5472      if (traceJNI) unexpected.printStackTrace(System.err);
5473      env.recordException(unexpected);
5474    }
5475  }
5476
5477  /**
5478   * SetDoubleArrayRegion: copy a region of the native buffer into the array
5479   * @param env A JREF index for the JNI environment object
5480   * @param arrayJREF a JREF index for the destination array
5481   * @param startIndex the starting index to copy
5482   * @param length the number of elements to copy
5483   * @param bufAddress the source address in native to copy from
5484   * @throws ArrayIndexOutOfBoundsException if one of the indices in the region is not valid
5485   */
5486  private static void SetDoubleArrayRegion(JNIEnvironment env, int arrayJREF, int startIndex, int length,
5487                                           Address bufAddress) {
5488    if (traceJNI) VM.sysWrite("JNI called: SetDoubleArrayRegion  \n");
5489    RuntimeEntrypoints.checkJNICountDownToGC();
5490
5491    try {
5492      double[] destinationArray = (double[]) env.getJNIRef(arrayJREF);
5493
5494      if ((startIndex < 0) || (startIndex + length > destinationArray.length)) {
5495        env.recordException(new ArrayIndexOutOfBoundsException());
5496        return;
5497      }
5498
5499      Memory.memcopy(Magic.objectAsAddress(destinationArray).plus(startIndex << LOG_BYTES_IN_DOUBLE),
5500                        bufAddress,
5501                        length << LOG_BYTES_IN_DOUBLE);
5502    } catch (Throwable unexpected) {
5503      if (traceJNI) unexpected.printStackTrace(System.err);
5504      env.recordException(unexpected);
5505    }
5506  }
5507
5508  /**
5509   * RegisterNatives: registers implementation of native methods
5510   * @param env A JREF index for the JNI environment object
5511   * @param classJREF a JREF index for the class to register native methods in
5512   * @param methodsAddress the address of an array of native methods to be registered
5513   * @param nmethods the number of native methods in the array
5514   * @return 0 is successful -1 if failed
5515   * @throws NoSuchMethodError if a specified method cannot be found or is not native
5516   */
5517  private static int RegisterNatives(JNIEnvironment env, int classJREF, Address methodsAddress, int nmethods) {
5518    if (traceJNI) VM.sysWrite("JNI called: RegisterNatives  \n");
5519    RuntimeEntrypoints.checkJNICountDownToGC();
5520
5521    try {
5522      // get the target class
5523      Class<?> jcls = (Class<?>) env.getJNIRef(classJREF);
5524      RVMType type = java.lang.JikesRVMSupport.getTypeForClass(jcls);
5525      if (!type.isClassType()) {
5526        env.recordException(new NoSuchMethodError());
5527        return 0;
5528      }
5529
5530      RVMClass klass = type.asClass();
5531      if (!klass.isInitialized()) {
5532        RuntimeEntrypoints.initializeClassForDynamicLink(klass);
5533      }
5534
5535      // Create list of methods and verify them to avoid partial success
5536      NativeMethod[] methods = new NativeMethod[nmethods];
5537      AddressArray symbols = AddressArray.create(nmethods);
5538
5539      Address curMethod = methodsAddress;
5540      for (int i = 0; i < nmethods; i++) {
5541        String methodString = JNIGenericHelpers.createStringFromC(curMethod.loadAddress());
5542        Atom methodName = Atom.findOrCreateAsciiAtom(methodString);
5543        String sigString =
5544            JNIGenericHelpers.createStringFromC(curMethod.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS)));
5545        Atom sigName = Atom.findOrCreateAsciiAtom(sigString);
5546
5547        // Find the target method
5548        RVMMethod meth = klass.findDeclaredMethod(methodName, sigName);
5549
5550        if (meth == null || !meth.isNative()) {
5551          env.recordException(new NoSuchMethodError(klass + ": " + methodName + " " + sigName));
5552          return -1;
5553        }
5554        methods[i] = (NativeMethod) meth;
5555        symbols.set(i, curMethod.loadAddress(Offset.fromIntSignExtend(BYTES_IN_ADDRESS * 2)));
5556        curMethod = curMethod.plus(3 * BYTES_IN_ADDRESS);
5557      }
5558
5559      // Register methods
5560      for (int i = 0; i < nmethods; i++) {
5561        methods[i].registerNativeSymbol(symbols.get(i));
5562      }
5563
5564      return 0;
5565    } catch (Throwable unexpected) {
5566      if (traceJNI) unexpected.printStackTrace(System.err);
5567      env.recordException(unexpected);
5568      return -1;
5569    }
5570  }
5571
5572  /**
5573   * UnregisterNatives: unregisters native methods
5574   * @param env A JREF index for the JNI environment object
5575   * @param classJREF a JREF index for the class to register native methods in
5576   * @return 0 is successful -1 if failed
5577   */
5578  private static int UnregisterNatives(JNIEnvironment env, int classJREF) {
5579    if (traceJNI) VM.sysWrite("JNI called: UnregisterNatives  \n");
5580    RuntimeEntrypoints.checkJNICountDownToGC();
5581
5582    try {
5583
5584      // get the target class
5585      Class<?> jcls = (Class<?>) env.getJNIRef(classJREF);
5586      RVMType type = java.lang.JikesRVMSupport.getTypeForClass(jcls);
5587      if (!type.isClassType()) {
5588        env.recordException(new NoClassDefFoundError());
5589        return -1;
5590      }
5591
5592      RVMClass klass = type.asClass();
5593      if (!klass.isInitialized()) {
5594        return 0;
5595      }
5596
5597      klass.unregisterNativeMethods();
5598      return 0;
5599    } catch (Throwable unexpected) {
5600      if (traceJNI) unexpected.printStackTrace(System.err);
5601      env.recordException(unexpected);
5602      return -1;
5603    }
5604  }
5605
5606  /**
5607   * MonitorEnter
5608   * @param env A JREF index for the JNI environment object
5609   * @param objJREF a JREF index for the object to lock
5610   * @return 0 if the object is locked successfully, -1 if not
5611   */
5612  private static int MonitorEnter(JNIEnvironment env, int objJREF) {
5613    if (traceJNI) VM.sysWrite("JNI called: MonitorEnter  \n");
5614    RuntimeEntrypoints.checkJNICountDownToGC();
5615
5616    try {
5617      Object obj = env.getJNIRef(objJREF);
5618      ObjectModel.genericLock(obj);
5619      return 0;
5620    } catch (Throwable unexpected) {
5621      if (traceJNI) unexpected.printStackTrace(System.err);
5622      return -1;
5623    }
5624  }
5625
5626  /**
5627   * MonitorExit
5628   * @param env A JREF index for the JNI environment object
5629   * @param objJREF a JREF index for the object to unlock
5630   * @return 0 if the object is unlocked successfully, -1 if not
5631   */
5632  private static int MonitorExit(JNIEnvironment env, int objJREF) {
5633    if (traceJNI) VM.sysWrite("JNI called: MonitorExit  \n");
5634    RuntimeEntrypoints.checkJNICountDownToGC();
5635
5636    try {
5637      Object obj = env.getJNIRef(objJREF);
5638      ObjectModel.genericUnlock(obj);
5639      return 0;
5640    } catch (Throwable unexpected) {
5641      if (traceJNI) unexpected.printStackTrace(System.err);
5642      return -1;
5643    }
5644  }
5645
5646  private static int GetJavaVM(JNIEnvironment env, Address StarStarJavaVM) {
5647    if (traceJNI) VM.sysWrite("JNI called: GetJavaVM \n");
5648    RuntimeEntrypoints.checkJNICountDownToGC();
5649
5650    try {
5651      if (traceJNI) VM.sysWriteln(StarStarJavaVM);
5652      Address JavaVM = BootRecord.the_boot_record.sysJavaVM;
5653      StarStarJavaVM.store(JavaVM);
5654
5655      return 0;
5656    } catch (Throwable unexpected) {
5657      if (traceJNI) unexpected.printStackTrace(System.err);
5658      return -1;
5659    }
5660  }
5661
5662  /*******************************************************************
5663   * These functions were added in Java 2  (JNI 1.2)
5664   */
5665
5666  /**
5667   * FromReflectedMethod
5668   * @param env A JREF index for the JNI environment object
5669   * @param methodJREF a JREF index for the java.lang.reflect.Method or
5670   * java.lang.reflect.Constructor object.
5671   * @return the jmethodID corresponding to methodJREF
5672   */
5673  private static int FromReflectedMethod(JNIEnvironment env, int methodJREF) {
5674    if (traceJNI) VM.sysWrite("JNI called: FromReflectedMethod \n");
5675    RuntimeEntrypoints.checkJNICountDownToGC();
5676
5677    Object methodObj = env.getJNIRef(methodJREF);
5678    RVMMethod meth;
5679    if (methodObj instanceof Constructor) {
5680      meth = java.lang.reflect.JikesRVMSupport.getMethodOf((Constructor<?>) methodObj);
5681    } else {
5682      meth = java.lang.reflect.JikesRVMSupport.getMethodOf((Method) methodObj);
5683    }
5684
5685    if (traceJNI) VM.sysWrite("got method " + meth + "\n");
5686    return meth.getId();
5687  }
5688
5689  /**
5690   * FromReflectedField
5691   * @param env A JREF index for the JNI environment object
5692   * @param fieldJREF a JREF index for a java.lang.reflect.Field methodID
5693   * @return the jfieldID corresponding to fieldJREF
5694   * */
5695  private static int FromReflectedField(JNIEnvironment env, int fieldJREF) {
5696    if (traceJNI) VM.sysWrite("JNI called: FromReflectedField \n");
5697    RuntimeEntrypoints.checkJNICountDownToGC();
5698
5699    Field fieldObj = (Field) env.getJNIRef(fieldJREF);
5700    RVMField f = java.lang.reflect.JikesRVMSupport.getFieldOf(fieldObj);
5701    if (traceJNI) VM.sysWrite("got field " + f + "\n");
5702    return f.getId();
5703  }
5704
5705  /**
5706   * ToReflectedMethod
5707   * @param env A JREF index for the JNI environment object
5708   * @param clsJREF The JREF index of the class from which methodID was
5709   * derived.
5710   * @param methodID a jmethodID to turn into a reflected method
5711   * @param isStatic argument that is not specified in Sun's JNI 1.2 spec,
5712   *            but IS present in the 1.4.2 JDK's implementation!  Our
5713   *            implementation will just ignore it, in any case.  This is a
5714   *            good example of why the same entity
5715   *            shouldn't get to write both the spec and the reference
5716   *            implementation.
5717   * @return a JREF index for the java.lang.reflect.Method or
5718   * java.lang.reflect.Constructor object associated with methodID.
5719   */
5720  private static int ToReflectedMethod(JNIEnvironment env, int clsJREF, int methodID, boolean isStatic) {
5721    if (traceJNI) VM.sysWrite("JNI called: ToReflectedMethod \n");
5722    RuntimeEntrypoints.checkJNICountDownToGC();
5723
5724    RVMMethod targetMethod = MemberReference.getMethodRef(methodID).resolve();
5725    Object ret;
5726    if (targetMethod.isObjectInitializer()) {
5727      ret = java.lang.reflect.JikesRVMSupport.createConstructor(targetMethod);
5728    } else {
5729      ret = java.lang.reflect.JikesRVMSupport.createMethod(targetMethod);
5730    }
5731    return env.pushJNIRef(ret);
5732  }
5733
5734  /**
5735   * ToReflectedField
5736   * @param env A JREF index for the JNI environment object
5737   * @param clsJREF The JREF index of the class from which fieldID was
5738   * derived.
5739   * @param fieldID a jfieldID
5740   * @param isStatic argument that is not specified in Sun's JNI 1.2 spec,
5741   *            but IS present in the 1.4.2 JDK's implementation!  Our
5742   *            implementation will just ignore it, in any case.  This is a
5743   *            good example of why the same entity
5744   *            shouldn't get to write both the spec and the reference
5745   *            implementation.
5746   * @return a JREF index for the java.lang.reflect.Field object associated
5747   *         with fieldID.
5748   */
5749  private static int ToReflectedField(JNIEnvironment env, int clsJREF, int fieldID, boolean isStatic) {
5750    if (traceJNI) VM.sysWrite("JNI called: ToReflectedField \n");
5751    RuntimeEntrypoints.checkJNICountDownToGC();
5752
5753    RVMField field = MemberReference.getFieldRef(fieldID).resolve();
5754    return env.pushJNIRef(java.lang.reflect.JikesRVMSupport.createField(field));
5755  }
5756
5757  /** Push a local frame for local references.
5758   * We could implement this more fancily, but it seems that we hardly need
5759   * to, since we allow an unlimited number of local refs.  One could force
5760   * running out of memory in a long-running loop in JNI, of course.
5761   *
5762   * @param capacity number of local references to allow. This parameter
5763   *  is ignored since we don't put any limits on the number of local
5764   *  references.
5765   * @param env A JREF index for the JNI environment object
5766   * @return always 0
5767   */
5768  private static int PushLocalFrame(JNIEnvironment env, int capacity) {
5769    if (traceJNI) VM.sysWrite("JNI called: PushLocalFrame \n");
5770    RuntimeEntrypoints.checkJNICountDownToGC();
5771
5772    return 0;                   // OK
5773  }
5774
5775  private static int PopLocalFrame(JNIEnvironment env, int resultJREF) {
5776    if (traceJNI) VM.sysWrite("JNI called: PopLocalFrame \n");
5777    RuntimeEntrypoints.checkJNICountDownToGC();
5778
5779    // do nothing.
5780    return resultJREF;
5781  }
5782
5783  /**
5784   * NewLocalRef
5785   *
5786   * @param env A JREF index for the JNI environment object
5787   * @param oldJREF JREF index of an existing reference.
5788   * @return a new local reference that refers to the same object as oldJREF.
5789   *       C NULL pointer if the oldJREF refers to null.
5790   */
5791  private static int NewLocalRef(JNIEnvironment env, int oldJREF) {
5792    if (traceJNI) VM.sysWrite("JNI called: NewLocalRef \n");
5793    RuntimeEntrypoints.checkJNICountDownToGC();
5794
5795    Object oldObj = env.getJNIRef(oldJREF);
5796    /* pushJNIRef automatically handles null refs properly. */
5797    return env.pushJNIRef(oldObj);
5798  }
5799
5800  /**
5801   * EnsureLocalCapacity
5802   *
5803   * @param env A JREF index for the JNI environment object
5804   * @param capacity how many more local references do we want to ensure can
5805   * be created?
5806   * @return 0 on success.  The JNI spec says that on failure this throws
5807   * OutOfMemoryError and returns a negative number.  But we don't have to
5808   * worry about that at all.
5809   */
5810  private static int EnsureLocalCapacity(JNIEnvironment env, int capacity) {
5811    if (traceJNI) VM.sysWrite("JNI called: EnsureLocalCapacity \n");
5812    RuntimeEntrypoints.checkJNICountDownToGC();
5813
5814    return 0;                   // success!
5815  }
5816
5817  /** GetStringRegion:  Copy a region of Unicode characters from a string to
5818   *  the given buffer.
5819   *
5820   *  @param env A JREF index for the JNI environment object
5821   *  @param strJREF a JREF index for the String object
5822   *  @param start index to start reading characters from the string
5823   *  @param len how many characters to read
5824   *  @param buf the buffer to copy the region into
5825   *  @throws StringIndexOutOfBoundsException if asked for an out-of-range
5826   *        region of the string.
5827   */
5828  private static void GetStringRegion(JNIEnvironment env, int strJREF, int start, int len, Address buf) {
5829    if (traceJNI) VM.sysWrite("JNI called: GetStringRegion \n");
5830    RuntimeEntrypoints.checkJNICountDownToGC();
5831
5832    try {
5833      String str = (String) env.getJNIRef(strJREF);
5834      char[] strChars = java.lang.JikesRVMSupport.getBackingCharArray(str);
5835      int strOffset = java.lang.JikesRVMSupport.getStringOffset(str);
5836      int strLen = java.lang.JikesRVMSupport.getStringLength(str);
5837      if (strLen < start + len) {
5838        env.recordException(new StringIndexOutOfBoundsException());
5839        return;
5840      }
5841      Address strBase = Magic.objectAsAddress(strChars);
5842      Address srcBase = strBase.plus(strOffset * 2).plus(start * 2);
5843      Memory.memcopy(buf, srcBase, len * 2);
5844
5845    } catch (Throwable unexpected) {
5846      if (traceJNI) unexpected.printStackTrace(System.err);
5847      env.recordException(unexpected);
5848    }
5849  }
5850
5851  /** GetStringUTFRegion:  Copy a region of Unicode characters from a string to
5852   *  the given buffer, as UTF8 characters.
5853   *
5854   *  @param env A JREF index for the JNI environment object
5855   *  @param strJREF a JREF index for the String object
5856   *  @param start index to start reading characters from the string
5857   *  @param len how many characters to read from the string
5858   *  @param buf the buffer to copy the region into -- assume it's big enough
5859   *  @throws StringIndexOutOfBoundsException if asked for an out-of-range
5860   *        region of the string.
5861   */
5862  private static void GetStringUTFRegion(JNIEnvironment env, int strJREF, int start, int len, Address buf) {
5863    if (traceJNI) VM.sysWrite("JNI called: GetStringUTFRegion \n");
5864    RuntimeEntrypoints.checkJNICountDownToGC();
5865
5866    try {
5867      String str = (String) env.getJNIRef(strJREF);
5868      String region = str.substring(start, start + len);
5869      // Get length of C string
5870      int utflen = UTF8Convert.utfLength(region) + 1; // for terminating zero
5871      JNIGenericHelpers.createUTFForCFromString(region, buf, utflen);
5872    } catch (Throwable unexpected) {
5873      if (traceJNI) unexpected.printStackTrace(System.err);
5874      env.recordException(unexpected);
5875    }
5876  }
5877
5878  /**
5879   * GetPrimitiveArrayCritical: return a direct pointer to the primitive array
5880   * and disable GC so that the array will not be moved.  This function
5881   * is intended to be paired with the ReleasePrimitiveArrayCritical function
5882   * within a short time so that GC will be reenabled
5883   *
5884   * @param env A JREF index for the JNI environment object
5885   * @param arrayJREF a JREF index for the primitive array in Java
5886   * @param isCopyAddress address of isCopy jboolean (an int)
5887   * @return The address of the primitive array, and the jboolean pointed to by isCopyAddress is set to false, indicating that this is not a copy.   Address zero (null) on error.
5888   * @throws OutOfMemoryError is specified but will not be thrown in this implementation
5889   *            since no copy will be made
5890   */
5891  private static Address GetPrimitiveArrayCritical(JNIEnvironment env, int arrayJREF, Address isCopyAddress) {
5892
5893    if (traceJNI) VM.sysWrite("JNI called: GetPrimitiveArrayCritical \n");
5894    RuntimeEntrypoints.checkJNICountDownToGC();
5895
5896    try {
5897      Object primitiveArray = env.getJNIRef(arrayJREF);
5898
5899      // not an array, return null
5900      if (!primitiveArray.getClass().isArray()) {
5901        return Address.zero();
5902      }
5903
5904      /* Set caller's isCopy boolean to false, if we got a valid (non-null)
5905         address */
5906      JNIGenericHelpers.setBoolStar(isCopyAddress, false);
5907
5908      // For array of primitive, return the object address, which is the array itself
5909      VM.disableGC(true);
5910      return Magic.objectAsAddress(primitiveArray);
5911    } catch (Throwable unexpected) {
5912      if (traceJNI) unexpected.printStackTrace(System.err);
5913      env.recordException(unexpected);
5914      return Address.zero();
5915    }
5916  }
5917
5918  /**
5919   * ReleasePrimitiveArrayCritical: this function is intended to be paired
5920   * with the GetPrimitiveArrayCritical function.
5921   * Since the native code has direct access
5922   * to the array, no copyback update is necessary;  GC is simply reenabled.
5923   * @param env A JREF index for the JNI environment object
5924   * @param arrayJREF a JREF index for the primitive array in Java
5925   * @param arrayCopyAddress the address of the array copy
5926   * @param mode a flag indicating whether to update the Java array with the
5927   *            copy and whether to free the copy. For this implementation,
5928   *            no copy was made so this flag has no effect.
5929   */
5930  private static void ReleasePrimitiveArrayCritical(JNIEnvironment env, int arrayJREF, Address arrayCopyAddress,
5931                                                    int mode) {
5932    if (traceJNI) VM.sysWrite("JNI called: ReleasePrimitiveArrayCritical \n");
5933    RuntimeEntrypoints.checkJNICountDownToGC();
5934
5935    try {
5936      VM.enableGC(true);
5937    } catch (Throwable unexpected) {
5938      if (traceJNI) unexpected.printStackTrace(System.err);
5939      env.recordException(unexpected);
5940    }
5941  }
5942
5943  /** GetStringCritical:
5944   * Like GetStringChars and ReleaseStringChars, but in some VM environments
5945   * the VM may be able to avoid making a copy.   Native code must not issue
5946   * arbitrary JNI calls and must not cause the current thread to block.<p>
5947   *
5948   * NOTE: Our interpretation of the JNI specification is that callers cannot
5949   * expect that changes in the array for the String are propagated back. Our
5950   * implementation assumes that the String will not be changed.
5951   *
5952   * @param env A JREF index for the JNI environment object
5953   * @param strJREF a JREF index for the string in Java
5954   * @param isCopyAddress address of isCopy jboolean (an int)
5955   * @return The address of the backing array; address zero (null) on error, and the jboolean pointed to by isCopyAddress is set to false, indicating that this is not a copy.
5956   */
5957  private static Address GetStringCritical(JNIEnvironment env, int strJREF, Address isCopyAddress) {
5958    if (traceJNI) VM.sysWrite("JNI called: GetStringCritical \n");
5959    RuntimeEntrypoints.checkJNICountDownToGC();
5960
5961    String str = (String) env.getJNIRef(strJREF);
5962    char[] strChars = java.lang.JikesRVMSupport.getBackingCharArray(str);
5963    int strOffset = java.lang.JikesRVMSupport.getStringOffset(str);
5964
5965    /* Set caller's isCopy boolean to false, if we got a valid (non-null)
5966       address */
5967    JNIGenericHelpers.setBoolStar(isCopyAddress, false);
5968
5969    VM.disableGC(true);
5970    Address strBase = Magic.objectAsAddress(strChars);
5971    return strBase.plus(strOffset * 2);
5972  }
5973
5974  /**
5975   * ReleaseStringCritical: this function is intended to be paired with the
5976   * GetStringCritical function.  Since the native code has direct access
5977   * to the string's backing array of characters, no copyback update is
5978   * necessary;  GC is simply reenabled.
5979   *
5980   * @param env A JREF index for the JNI environment object
5981   * @param strJREF a JREF index for the string in Java (ignored)
5982   * @param carray the pointer returned by GetStringCritical (ignored)
5983   */
5984  private static void ReleaseStringCritical(JNIEnvironment env, int strJREF, Address carray) {
5985    if (traceJNI) VM.sysWrite("JNI called: ReleaseStringCritical \n");
5986    RuntimeEntrypoints.checkJNICountDownToGC();
5987
5988    try {
5989      VM.enableGC(true);
5990    } catch (Throwable unexpected) {
5991      if (traceJNI) unexpected.printStackTrace(System.err);
5992      env.recordException(unexpected);
5993    }
5994  }
5995
5996  private static int NewWeakGlobalRef(JNIEnvironment env, int objectJREF) {
5997    if (traceJNI) VM.sysWrite("JNI called: NewWeakGlobalRef \n");
5998    RuntimeEntrypoints.checkJNICountDownToGC();
5999
6000    try {
6001      Object obj1 = env.getJNIRef(objectJREF);
6002      return JNIGlobalRefTable.newWeakRef(obj1);
6003    } catch (Throwable unexpected) {
6004      if (traceJNI) unexpected.printStackTrace(System.err);
6005      env.recordException(unexpected);
6006      return 0;
6007    }
6008  }
6009
6010  private static void DeleteWeakGlobalRef(JNIEnvironment env, int refJREF) {
6011    if (traceJNI) VM.sysWrite("JNI called: DeleteWeakGlobalRef \n");
6012    RuntimeEntrypoints.checkJNICountDownToGC();
6013
6014    try {
6015      JNIGlobalRefTable.deleteWeakRef(refJREF);
6016    } catch (Throwable unexpected) {
6017      if (traceJNI) unexpected.printStackTrace(System.err);
6018      env.recordException(unexpected);
6019    }
6020  }
6021
6022  private static int ExceptionCheck(JNIEnvironment env) {
6023    if (traceJNI) VM.sysWrite("JNI called: ExceptionCheck \n");
6024    RuntimeEntrypoints.checkJNICountDownToGC();
6025
6026    return env.getException() == null ? 0 : 1;
6027  }
6028
6029  /*
6030   * These functions are in JNI 1.4
6031   */
6032
6033  private static int NewDirectByteBuffer(JNIEnvironment env, Address address, long capacity) {
6034    if (traceJNI) VM.sysWrite("JNI called: NewDirectByteBuffer \n");
6035    RuntimeEntrypoints.checkJNICountDownToGC();
6036
6037    try {
6038      Buffer buffer = java.nio.JikesRVMSupport.newDirectByteBuffer(address, capacity);
6039      return env.pushJNIRef(buffer);
6040    } catch (Throwable unexpected) {
6041      if (traceJNI) unexpected.printStackTrace(System.err);
6042      env.recordException(unexpected);
6043      return 0;
6044    }
6045  }
6046
6047  private static Address GetDirectBufferAddress(JNIEnvironment env, int bufJREF) {
6048    if (traceJNI) VM.sysWrite("JNI called: GetDirectBufferAddress \n");
6049    RuntimeEntrypoints.checkJNICountDownToGC();
6050
6051    try {
6052      Buffer buffer = (Buffer) env.getJNIRef(bufJREF);
6053      //if (buffer instanceof ByteBuffer) {
6054      //  VM.sysWrite("ByteBuffer, ");
6055      //  if (((ByteBuffer)buffer).isDirect())
6056      //    VM.sysWrite("Direct, ");
6057      //}
6058      //VM.sysWriteln("Direct buffer address = ",result);
6059      return java.nio.JikesRVMSupport.getDirectBufferAddress(buffer);
6060    } catch (Throwable unexpected) {
6061      if (traceJNI) unexpected.printStackTrace(System.err);
6062      env.recordException(unexpected);
6063      return Address.zero();
6064    }
6065  }
6066
6067  private static long GetDirectBufferCapacity(JNIEnvironment env, int bufJREF) {
6068    if (traceJNI) VM.sysWrite("JNI called: GetDirectBufferCapacity \n");
6069    RuntimeEntrypoints.checkJNICountDownToGC();
6070
6071    try {
6072      Buffer buffer = (Buffer) env.getJNIRef(bufJREF);
6073      return buffer.capacity();
6074    } catch (Throwable unexpected) {
6075      if (traceJNI) unexpected.printStackTrace(System.err);
6076      env.recordException(unexpected);
6077      return -1;
6078    }
6079  }
6080
6081  /*
6082   * Empty Slots
6083   */
6084
6085  private static int reserved0(JNIEnvironment env) {
6086    VM.sysWrite("JNI ERROR: reserved function slot not implemented, exiting ...\n");
6087    VM.sysExit(EXIT_STATUS_UNSUPPORTED_INTERNAL_OP);
6088    return -1;
6089  }
6090
6091  private static int reserved1(JNIEnvironment env) {
6092    VM.sysWrite("JNI ERROR: reserved function slot not implemented, exiting ...\n");
6093    VM.sysExit(EXIT_STATUS_UNSUPPORTED_INTERNAL_OP);
6094    return -1;
6095  }
6096
6097  private static int reserved2(JNIEnvironment env) {
6098    VM.sysWrite("JNI ERROR: reserved function slot not implemented, exiting ...\n");
6099    VM.sysExit(EXIT_STATUS_UNSUPPORTED_INTERNAL_OP);
6100    return -1;
6101  }
6102
6103  private static int reserved3(JNIEnvironment env) {
6104    VM.sysWrite("JNI ERROR: reserved function slot not implemented, exiting ...\n");
6105    VM.sysExit(EXIT_STATUS_UNSUPPORTED_INTERNAL_OP);
6106    return -1;
6107  }
6108}