/* -*- 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(symbol) - Uint32(where + 4));\ where += 4; #define writeGlobalLocation(symbol) \ writeLittleWordUnaligned(where, reinterpret_cast(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; }