This feature makes it easier for you to migrate Java™ applications that use native code from the 31-bit SDK to the
64-bit SDK, with minimal changes to the native code.
Before you begin
This feature requires APAR PH28966 on z/OS® 2.3 or
later.
If your 31-bit C or C++ JNI code uses direct byte buffers, ensure that the native buffer storage
is allocated in the 31-bit memory range, otherwise the code will not be able to access it. The JNI
function
GetDirectBufferAddress() checks whether it was called from JNI C or C++
code that is running in 31-bit addressing mode (AMODE 31). If so, the function returns either the
buffer address, if it is in the 31-bit range, or
null
. To create a direct buffer
and ensure that the native buffer memory is in the 31-bit range, you might have to modify your C or
C++ code as follows:
- Allocate the 31-bit memory by using the appropriate function. If the C or C++ code will run in
AMODE 31, use the malloc() function to allocate the memory. If the C or C++ code
will run in AMODE 64, use the __malloc31() function to request memory in the
31-bit range.
- Create the Java direct byte buffer that references this
31-bit memory by passing the buffer in the address parameter of the
NewDirectByteBuffer()
function:
jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity);
For
more information about this function, see the Oracle JNI documentation.
- Track the resulting ByteBuffer object. When the object is no longer used by
any Java methods, free the native buffer memory. This step is
required because the JVM does not free the native buffer memory when it processes the
ByteBuffer object during garbage collection.
About this task
Usually, Java applications that run 31-bit native code
can run only with a 31-bit SDK; mixing 31-bit code and 64-bit code in the same process space is
challenging because of the incompatibility of the pointer sizes and memory addressability between
these two types of code.
With APAR PH28966 on z/OS 2.3 and later, z/OS
Language Environment® (LE) provides the
capability to run AMODE 31 programs and AMODE 64 programs in the same address space. Separate LE
environments are established for each addressing mode (AMODE). The IBM SDK takes advantage of this capability to simplify the migration of Java applications that use 31-bit native code to the 64-bit SDK.
The Invocation and JNI APIs in the 64-bit SDK allow 31-bit native code to compile, link, and
inter-operate with the 64-bit SDK. The 64-bit VM also supports the loading and invocation of 31-bit
native libraries and functions.
As part of this feature, the 64-bit SDK provides the following files:
- A 31-bit compatible set of C/C++ JNI header files, which contain JNI data and argument types to
support Invocation and JNI APIs. These files are in the
directory, where
javahome is the JAVA_HOME path of your IBM SDK installation. JNI types that represent object references
and other VM constructs, like
jobject
, jarray
,
jclass
, jmethodID
, and jfieldID
, are updated to
be 64-bit representations.Note: Because the C language does not provide a way to define a 64-bit
pointer
type in a 31-bit application, a primitive 64-bit long long
data type is used instead. This might lead to compiler warnings for code that assigns or compares
JNI object references with NULL
. You might need to update the code to assign or
compare with 0
instead.
- A 31-bit shared library, libjvm31.so, with a matching
libjvm31.x side-deck file to enable 31-bit native code to link and resolve the
Invocation and JNI APIs.
The high level steps to use this feature are as follows:
- Recompile any C or C++ native code that references JNI constructs against the
include/jni31 set of JNI header files, and link against the
libjvm31.so library.
- Run your Java application with the 64-bit SDK, specifying
the
-XX:+Enable3164Interoperability
VM option.
Limitations:
- The 31-bit native application must be a single-thread. The 64-bit Java application can be multi-threaded but only a single Java application thread is allowed to inter-operate across the AMODE boundary. If a
second application thread tries to load a 31-bit library or call a 31-bit C or C++ function, a
java.lang.UnsatisfiedLinkError is usually thrown.
- You must compile the 31-bit native application with standard CALL linkage; XPLINK is not
supported.
- LE Condition handling support is not available across the AMODE boundary. Specifically,
-XCEEHDLR
, -Xsignal:userConditionHandler=percolate
, and related
options are not supported. LE conditions are not converted into Java exceptions.
- Signal chaining is not supported across the AMODE boundary.
- Environment variables are copied across the AMODE boundary on the first transition only.
Subsequent updates in one AMODE environment are not propagated back to the other; instead, the
variables are tracked separately in each AMODE environment. For more information, see
Environment variables propagation to secondary Language Environment in Introduction to AMODE 31 and AMODE 64 programs interoperability.
Procedure
-
Recompile your 31-bit C or C++ code, link, and bind it into a shared library that can be loaded
and called dynamically from a Java application running with a
64-bit IBM SDK.
You must set the JNI include directory to
and use the
libjvm31.x side-deck file from the 64-bit SDK. The native code must be compiled
with standard CALL linkage; XPLINK is not supported. For example, the following command creates a
shared library called libSample.so
for a C program called
Sample.c
:
- XL C/C++
-
xlc -W "l,dll" -W "c,langlvl(extended),float(ieee),dll,exportall" -o libSample.so -I$JAVA_HOME/include -I$JAVA_HOME/include/zos Sample.c $JAVA_HOME/lib/j9vm/libjvm31.x
where
$JAVA_HOME
is the JAVA_HOME path of your IBM SDK installation.
The
XL C/C++ specific elements in the compile and link commands are as follows:
Table 1. XL command specific
elements
Option |
Description |
xlc |
The command that runs the C compiler. |
-W "l,dll" |
The option -W is passed to the bind phase of the compiler. The binder
creates a shared library .dll file. Standard CALL linkage is used by default
for 31-bit C or C++ code. |
-W "c, langlvl(extended)
,float(ieee),dll,exportall"
|
The option -W is passed to the compile phase of the compiler.
langlvl(extended) enables language extensions that are used by the JNI header
files, such as long long .
float(ieee) tells the compiler to generate binary IEEE754 floating-point
numbers and instructions, which match the float and double
primitive types of the Java language.
dll tells the compiler to produce DLL code. The DLL code can export or import
functions and external variables.
exportall specifies that call functions in the shared library are callable by
external programs.
|
- Open XL C/C++
-
Note that for 31-bit compiles, Open XL 2.1 is required. Open XL 1.1 does not support 31-bit
compiles.
ibm-clang -fvisibility=default -o libSample.so -I$JAVA_HOME/include -I$JAVA_HOME/include/zos Sample.c $JAVA_HOME/lib/j9vm/libjvm31.x
where
$JAVA_HOME is the JAVA_HOME path of your IBM SDK installation.
The
Open XL C/C++ specific elements in the compile and link commands are as follows:
Table 2. Open XL command specific
elements
Option |
Description |
ibm-clang |
The command that runs the Open XL C compiler. |
-fvisibility=default |
This option exports all externally defined functions and variables in the compilation unit so
that a DLL application can use them. |
- Shared elements in the compile and link commands
-
The remaining shared elements in the compile and link commands are as follows:
Table 3. Common elements for XL and Open
XL
Option |
Description |
-o libSample.so |
The output file, which is the shared library that you want to build. The name (the text
between lib and .so ) should match the name that you used in the
System.load(filename) or
System.loadLibrary(libname) methods in your Java application. |
-I$JAVA_HOME/include |
Tells the compiler to look in the $JAVA_HOME/include
directory, in addition to the default directories, for header files (in this case, special JNI
header files for running 31-bit native code with the 64-bit SDK). Change $JAVA_HOME to be the
JAVA_HOME path of your IBM SDK
installation. |
-I$JAVA_HOME/include/zos |
Tells the compiler to look in the $JAVA_HOME /include/zos directory, in addition to the
default directories, for header files (in this case, JNI header files). |
Sample.c |
Your C program. |
$JAVA_HOME /lib/j9vm/libjvm31.x
|
The side-deck file that enables 31-bit native code to link and resolve the Invocation and JNI
APIs. |
-
Run the Java application on the 64-bit VM, either
directly on the command line or from a C or C++ application:
- Starting the VM from the command line
- Specify the
-XX:+Enable3164Interoperability
command-line option to enable
64-bit Java applications to load the 31-bit native library and
invoke the methods implemented within it.
- If your Java application uses the
System.loadLibrary(libname)
method, which does not
accept a path, you must also specify the location of your shared library. You can specify the location only by using the -Djava.library.path
system property option on the command line. The path that is mentioned in LIBPATH
environment variable is not used for searching the libraries. This is a change in behavior from Java
17 onwards. In Java 11 and earlier versions, you could specify the location either by using the
-Djava.library.path
system property option on the command line or by using the
LIBPATH
environment variable.
For
example:java -XX:+Enable3164Interoperability -Djava.library.path=. Sample
- Starting the VM from a C or C++ application
- If you are using the JNI_CreateJavaVM Invocation API to instantiate a VM
instance from your C or C++ application, pass the
-XX:+Enable3164Interoperability
option as a VM argument.
Results
You should now be able to use your existing 31-bit native code from the Java application running on the 64-bit VM, and vice versa. If you see an error
message similar to the following, check that you specified the
-XX:+Enable3164Interoperability
option on the command line or in the
JNI_CreateJavaVM API when you ran your
application:
An AMODE64 application is attempting to load an AMODE31 DLL load module.