/**************************************************************************** * * Native.cpp (for Microsoft's JDK version 1.5.1) * * This file implements the native routines declared in Native.java. * The code here is Microsoft-specific. It is closely related to the * other Native.cpp included (Sun's version.) This version has been * modified from the "original" version to use more of Sun's #define * statements. * * This code was developed by Matthew Mead for CS510 Java Implementation. * A few of the examples were derived from Microsoft's documentation, * specifically, the countPrimes algorithm. * */ #include #include #include "Nativec.h" // Some useful defines I liked from Sun's stuff #define JNIEXPORT __declspec(dllexport) #define JNICALL __cdecl #define jboolean long #define jbyte char #define jchar long #define jdouble double #define jfloat float #define jint long #define jlong int64_t #define jshort long #define jstring Hjava_lang_String * #define jobjectArray HArrayOfObject * #define jobject HObject * #define jclass ClassClass * #define jfieldID jint /**************************************************************************** * Java declaration: * native public void displayHelloWorld(); * * The canonical first method. * */ JNIEXPORT void JNICALL Native_displayHelloWorld (HNative *self) { printf("Hello world!\n"); return; } /**************************************************************************** * Java declaration: * native public void initializeByteArray(int Count, byte Value); * * Initializes an array 'Count' times with the value 'Value'. This function * is mainly used to test the performance of array accesses in native * code. * */ JNIEXPORT void JNICALL Native_initializeByteArray(HNative *self, HArrayOfByte *byteArray, jint Count, jbyte Value) { // Get length of the array unsigned int len = obj_length(byteArray); // Loop through the array 'Count' times, assigning 'Value' to each // element. for (long i = 0; i < Count; i++) for (unsigned long j = 0; j < len; j++) (byteArray->body)[j] = Value; } /**************************************************************************** * Java declaration: * native public jobjectArray returnRectArray(int size); * * This function creates an array of 'size' Rectangles and returns them * to the Java caller. First, the array is created, then each element * is assigned a Rectangle object. * */ JNIEXPORT jobjectArray JNICALL Native_returnRectArray(HNative *self, jint size) { // Get a handle on the Rectangle class jclass cls = FindClass(NULL, "java/awt/Rectangle", false); if (cls == 0) { printf("Can't FindClass(java/awt/Rectangle)\n"); return NULL; } // Create an array of Rectangle objects jobjectArray array = (jobjectArray) ClassArrayAlloc(T_CLASS, size, "java/awt/Rectangle"); // Now initialize each one to a Rectangle for (int i = 0; i < size; i++) { // Create a new Rectangle object jobject element = execute_java_constructor(NULL, "java/awt/Rectangle", NULL, "(IIII)", 0, 0, 5 * i, 10 * i); // Assign the Rectangle to an element of the array (array->body)[i] = element; } // Return whole array to caller return array; } /**************************************************************************** * Java declaration: * native public void printObjectArray(Object[] array); * * Given an array of Objects, each element is printed using the * 'toString' method of the Object. * */ JNIEXPORT void JNICALL Native_printObjectArray(HNative *self, HArrayOfObject *objArray) { // Get length of the array unsigned int len = obj_length(objArray); // Make sure we have at least one object in the array if (len < 1) return; // Get an element of the array so we can get the right 'toString' method HObject *ob = (objArray->body)[0]; // Loop the the array of objects and print out each one using // the 'toString' method of its ancestor class Object for (unsigned int i = 0; i < len; i++) { // Get the next element from the array HObject *element = (objArray->body)[i]; // Call the 'toString' method, which returns a String representation of // the object. We must 'cast' the return value to a jstring because // method returns a generic object. jstring s = (jstring) execute_java_dynamic_method(NULL, (long *)element, "toString", "()Ljava/lang/String;"); // Make a C-string from the Java string char *buf = new char[s->count + 1]; char *str = javaString2CString(s, buf, s->count + 1); // Print the C-string printf("%s\n", buf); // Free string buffer delete[] buf; } } /**************************************************************************** * Java declaration: * native public void VoidVoid(); * * This function takes no arguments and returns nothing. Just used to * demonstrate the most simplistic function call. Also used to time * function call overhead in the simplest case. * */ JNIEXPORT void JNICALL Native_VoidVoid(HNative *self) { return; } /**************************************************************************** * Java declaration: * native public String toStringWithPrint(); * * This is the traditional 'toString' method with a twist. It calls back * into Java to do the real work. There is a Native method called toString * which formats the object's members for printing. This function simply * calls it. * * The net effect is this: The Java object calls a native method which, * in turn, calls back to the Java object. The Java could have simply * made a call to it's own 'toString' method. This of course is for * demonstration purposes only. Don't do this at work!! * */ JNIEXPORT jstring JNICALL Native_toStringWithPrint (HNative *self) { // Get the method from the object jstring s = (jstring) execute_java_dynamic_method(NULL, (long *)self, "toString", "()Ljava/lang/String;"); // Make a C-string from the Java string char *buf = new char[s->count + 1]; char *str = javaString2CString(s, buf, s->count + 1); // Now, print the C-string here printf("%s\n", buf); // Free buffer delete[] buf; // Return the formatted string return s; } /**************************************************************************** * Java declaration: * native public void causeException(); * * Causes an exception in the JVM, but fails to catch it. Thus, it is * propagated back to the JVM. * */ JNIEXPORT void JNICALL Native_causeException(HNative *self) { // Cause an exception, don't handle it SignalError(NULL, "java/lang/Error", "False exception here"); // An exception has occurred, but it has not been suppressed. // The JVM will detect it and catch it. } /**************************************************************************** * Java declaration: * native public void handleException(); * * Causes an exception in the JVM, but detects it and supresses it * */ JNIEXPORT void JNICALL Native_handleException(HNative *self) { bool_t exception; // Cause an exception, then handle it SignalError(NULL, "java/lang/Error", "False exception here"); // Check for exception exception = exceptionOccurred(NULL); // exception is non-zero if an exception occurred if (exception) { // Just display a message printf("Exception handled in Main.cpp: %i\n", exception); // Clear the exception so the JVM doesn't react to it exceptionClear(NULL); // If you want to display a message about the exception, // in addition to clearing it, you call DescribeException. // This call will print out a description of the exception // and then clear the exception // // exceptionDescribe(NULL); } } /**************************************************************************** * Java declaration: * native public void printWXYZ(); * * Prints out four members of the Native object, w, x, y, and z. This * function acts sort of like the traditional 'toString' method in Java. * The members are declared in Native.java as such: * * public String w; // public Object * public int x; // public * private int y; // private (no protection here) * public static int z; // public static * * This is easier than Sun's method because we can access the members * of the Java class directly. */ JNIEXPORT void JNICALL Native_printWXYZ(HNative *self) { jint x, y, z; jstring w; // Easy access to non-static members, compare this with Sun's method w = self->w; x = self->x; y = self->y; // Get class so we can get static member jclass cls = Object_GetClass((long *)self); // Wow, is this ugly or what? z = Field_GetInt((long *)self, Class_GetField(cls, "z")); // Get the characters from the jstring char *buf = new char[w->count + 1]; char *str = javaString2CString(w, buf, w->count + 1); // Sort of like the traditional 'toString' output printf("[w = %s, x = %li, y = %li, z = %li]\n", str, x, y, z); // Release memory (required or else memory leaks) delete[] buf; } /**************************************************************************** * Java declaration: * native public String printLine(String text); * * Prints a Java string, and returns a Java string * */ JNIEXPORT jstring JNICALL Native_printLine(HNative *self, jstring string) { // Get the characters from the jstring char *buf = new char[string->count + 1]; char *str = javaString2CString(string, buf, string->count + 1); // Print them to the screen printf("In Native code, string is: %s\n", str); // Release memory (required or else memory leaks) delete[] buf; // Create a new string and return it return makeJavaString("String from Native code", 23); } /**************************************************************************** * Java declaration: * native public static int countPrimes(byte[] array); * * This is a sample algorithm that I got from Microsoft's documentation. * I used it as the initial test case. I may have modified it slightly. * * The interesting point in this example is that the function is declared * as 'static' in the Java code. The only difference at the native level * is that the second parameter is a 'jclass' instead of a 'jobject'. * Most functions are non-static, and so require a handle to the object * rather than the class. * */ JNIEXPORT jint JNICALL Native_countPrimes(HNative *self, HArrayOfByte *array) { unsigned long count = 0; unsigned long i, len; // Get length of the array len = obj_length(array); // Initialize all elements for (i = 0; i < len; i++) (array->body)[i] = 1; // Set each element at a non-prime index to 0 for (i = 2; i < len; i++) { if ((array->body)[i] != 0) { unsigned long k; for (k = i + i; k < len; k += i) (array->body)[k] = 0; count++; } } // The number of primes between 1 and array.length return count; }