Files
tubestation/ef/Runtime/NativeMethods/md/x86/x86NativeMethodStubs.cpp
1999-11-02 06:38:29 +00:00

125 lines
4.0 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is mozilla.org code.
*
* The Initial Developer of the Original Code is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s):
*/
#include "NativeMethodStubs.h"
#include "NativeCodeCache.h"
#include "MemoryAccess.h"
#include "jni.h"
extern JNIEnv *jniEnv;
extern void throwJNIExceptionIfNeeded();
// XXX This will eventually have to be done on a per-thread basis!!
static Uint32 JNIReturnAddressInteger = 0;
static void *JNIReturnAddress = &JNIReturnAddressInteger;
// Stub sizes
static const JNIStaticStubSize = 34;
static const JNIInstanceStubSize = 32;
// x86 opcodes that we're interested in
static const Uint8 popEax = 0x58;
static const Uint8 pushl = 0x68;
static const Uint8 jmpl = 0xe9;
static const Uint8 pushEax = 0x50;
static const Uint8 calll = 0xe8;
static const Uint8 moveFromEax = 0xa3;
static const Uint16 jmplIndirectLow = 0xff;
static const Uint16 jmplIndirectHigh = 0x25;
#define writeRelativeDisplacement(symbol) \
writeLittleWordUnaligned(where, reinterpret_cast<Uint32>(symbol) - Uint32(where + 4));\
where += 4;
#define writeGlobalLocation(symbol) \
writeLittleWordUnaligned(where, reinterpret_cast<Uint32>(symbol));\
where += 4;
/* Generate stub glue for a native JNI function.
* The net effect is to generate code that does the following:
*
* pop eax // Save return address in EAX
* mov JNIReturnAddress, eax // Tuck return address safely away
* push declaringClass // Push declaring class; static methods only
* push JNIenv // Push JNI pointer
* call nativeMethod // Jump to the actual JNI native method
* push eax // Store the return value on the stack
* call throwJNIExceptionIfNeeded // Check and throw JNI exceptions if needed
* pop eax // Restore the return value
* jmp [JNIReturnAddress] // jump to previously stored return address
*/
void *generateJNIGlue(const Method &method,
void *nativeFunction)
{
void* stub;
int stubSize = (method.getModifiers() & CR_METHOD_STATIC) ?
JNIStaticStubSize : JNIInstanceStubSize;
assert(method.getModifiers() & CR_METHOD_NATIVE);
assert(nativeFunction);
// Write out the JNI stub
stub = NativeCodeCache::sNativeCodeCache.acquireMemory(stubSize);
Uint8* where = (Uint8*) stub;
*where++ = popEax; // popl eax
*where++ = moveFromEax;
writeGlobalLocation(JNIReturnAddress);
// We're pushing arguments right-to-left, so the jclass
// argument is pushed before the JNIEnv.
if (method.getModifiers() & CR_METHOD_STATIC) {
*where++ = pushl; // pushl
writeGlobalLocation((method.getDeclaringClass()));
}
*where++ = pushl; // pushl
writeGlobalLocation(jniEnv);
// Put the return address back on the stack
//*where++ = pushEax; // push eax
*where++ = calll; // call
writeRelativeDisplacement(nativeFunction);
// Store the return value on the stack
*where++ = pushEax; // push eax
// Call throwJNIExceptionIfNeeded
*where++ = calll;
writeRelativeDisplacement(&throwJNIExceptionIfNeeded);
// Restore return value
*where++ = popEax; // pop eax
// Get back to where we once belonged...
*where++ = jmplIndirectLow;
*where++ = jmplIndirectHigh;
writeGlobalLocation(JNIReturnAddress);
return stub;
}