Native Code Interface Specification
 In this topic

*How Object References are Stored Internally

*Implications for the Existing Native Code Interface

*Consequences

 

Java & Native Code    PreviousRNINext
Native Code Interface Specification     Previous RNI Next

 


Existing Native Code Interface

Typically when writing Java applications, developers may want to use existing libraries of native code, or call out to routines written in native code for performance reasons. The following is an example (using the current native code interface provided by in the Sun Java VM) of how this is done.

An example of a Java method declaration, which is implemeted in native code, is as follows.

package myPackage;

class  myClass {
	public static native int myMethod  (myOtherClass  myObj);
}

This example declares a static, native method named myMethod within the class myClass in the package myPackage. The method takes myObj (an object of type myOtherClass) as its parameter.

The following example shows how this method can be then be called from within the Java code by invoking (for example):


...
int i;
myOtherClass myObj = new myOtherClass;

i = myClass.myMethod (myObj);
...

The interfacing between Java and C is handled by a program called msjavah. It takes the previous native declaration and produces the following two pieces of code from it.

  1. A C header file that can be used in C code which defines an appropriate prototype method and structure declaration for the containing class.
  2. A stub function that is placed in the same file as the implementation.

The C native code implementation of the method myMethod looks like the following example:


int myPackage_myClass_myMethod (HObject *AlwaysNull, HmyOtherClass *myObj)
{
myOtherClass *mO = unhand (myObj);

	// body of the implementation of the function ...
	// e.g. mO->member; 
}

The function is defined with an initial first parameter (AlwaysNull) that is present only for historical reasons (it is always 0 in current Microsoft VM implementations). Note that in the Microsoft Native Code Interface the convention is kept for source code compatibility.

The stub (which msjavah generates) would look like the following:


Java_myPackage_myClass_myMethod_stub (ExecEnv *, paramblock * pPB);

When the function myMethod is called from Java, it is this stub that is called. The parameter block in that stub is unwrapped, pushed onto the stack, and then the myPackage_myClass_myMethod function is called in C. The Java code passes the parameter block from the frame, the stubs unwrap it, and then the stubs pass it on to the actual function that you're interested in calling.

The final piece to calling is the unhand macro used in the C function previously mentioned. This macro relies on the internal object representation (a double indirection between the myObj handle and the data; see below) to provide an actual pointer to the data in C. It is necessary to use the unhand macro to access the object data. Microsoft recommends that unhand be used each time an object is accessed, since the object may have been garbage collected within Java, and a pointer reference to it obtained previously may then point to invalid data. Although existing virtual machines (VMs) other than the Microsoft VM attempt to find and ensure validity of all unhanded object references in any C code that may have been called, there are cases where this attempt may not be sufficient to prevent pointers from becoming invalid.

How Object References are Stored Internally

The following diagram describes the internal storage details of objects within the existing native code system.

Essentially, everywhere that a reference to an object is stored there is a pointer to the handle, which then references the object.

Implications for the Existing Native Code Interface

  • An extra indirection (using the unhand macro) is required to get to every object referenced.
  • Despite the use of unhand, if you have an unhanded value referencing an object, that object may be moved by garbage collection, and the reference that you have could become invalid. To avoid this, when garbage collection occurs under this model, the VM suspends all the threads that were running in Java code and tries to find out where the end of the native stacks are. It then conservatively scans the entire C stack and register set of all threads for any DWORDS that might possibly point into objects. If any are found, these objects are not moved when the garbage collection heap is compacted. Unfortunately, there are cases where this attempt could fail to find all outstanding unhanded references. It is also a somewhat time-consuming process.
  • If there are many different pointers, it's extremely difficult for a compiler to enregister unhanded pointers (given restrictions on the numbers of registers in certain machine architectures). As a result, there will constantly be memory reads, which is generally less efficient.

Conservative scanning, or garbage collection, is the term used when nothing is known about the data that is being checked. It may just be characters or some other simple data type, but if it looks like it may be a pointer, it is treated as such to err on the side of caution. Since the data is not known to be a pointer, it cannot be modified to refer to a new copy of the object that it seems to point to. Instead, the object in question must be fixed in memory and made immovable.

Consequences

The main consequences are loss in performance with native code (which is one of the reasons why native code is used in the first place), and potentially non-deterministic errors when unhand has been used unsafely.

Top © 1998 Microsoft Corporation. All rights reserved. Terms of use.