Subject Re: [Firebird-Architect] Re: Java Stored Procedures
Author Jim Starkey
Roman Rokytskyy wrote:

>>Sure. The classloader loads stuff on demand. There is no way to
>>force it to load all dependencies of a class.
>>
>>
>
>Can you explain this a bit more? JVM specification requires the
>implementation to follow the strict class initialization procedure.
>Java applications rely on this late binding behavior. But that does
>not mean that particular classloader cannot cache binary definitions
>in memory to avoid disk access.
>
>
I've never seen a class loader that loaded all referenced classes. JVMs
load classes on demand, i.e the first actual reference. If a class is
referenced in code that has been executed, the class won't be loaded.

To do it any other way would impose a miserable startup cost as every
class in creation would have to be loaded before execution. Java was
designed from the beginning to load classes incrementally on an
as-needed basis.

>So, do you simply load .class files into memory from the disk, or do
>you fully initialize the loaded classes before JVM asks you to do
>this? If later, then this violates the JVM specification.
>
>
Like all other JVMs, I load classes on demand. Nothing the in JVM
specification requires any different behavior. If you have any doubts,
use a JVM the lists classes as they're loaded.

>>How do you catch native calls back into the engine? I suppose you
>>could put the whole thing, JVM and all, into a shared library and
>>have a base class do a loadLibrary on itself, but that means that
>>JVM can't be statically linked in. On refection, maybe that's a
>>good thing.
>>
>>
I'll append the code at the end. (The code is copyrighted, all rights
reserved, and is explicitly not open source.) When it doesn't find an
entrypoint, the stuff at the end dumps out function declarations and
skeletons into a file for inclusion in my JavaNativeMethods.cpp file.

>
>In our case JVM is not statically bound but dynamically loaded using
>shared library specified in the config. This allows us to load any
>compliant JVM. And yes, the callback goes via
>loadLibrary("javaespudf") which contains all needed entrypoints.
>
>
>
Good enough. You don't need me to tell you that it works.

Here's the class load code:

void JavaMethod::resolveEntrypoint(ENV_DCL)
{
char fullName [1024], *p = fullName;

for (char *q = "Java_"; *q;)
*p++ = *q++;

WCHAR *w = javaClass->className->string;
WCHAR *end;

for (end = w + javaClass->className->length; w < end; ++w)
*p++ = (*w == '/') ? '_' : (char) *w;

w = methodName->string;
*p++ = '_';

for (end = w + methodName->length; w < end;)
*p++ = (char) *w++;

*p = 0;

// Try to resolve name internally

if (nativeMethod = findNativeMethod (fullName))
return;

// Try to resolve it against known libraries

if (nativeMethod = (NativeFn) javaClass->java->resolveEntrypoint
(fullName, numberArgs))
return;

// Expand name to include signature

*p++ = '_';
*p++ = '_';

for (w = descriptor->string, end = w + descriptor->length, ++w;
w < end && *w != ')';)
{
char c = (char) *w++;
if (c == '_')
{ *p++ = '_'; *p++ = '1'; }
else if (c == '_')
{ *p++ = ';'; *p++ = '2'; }
else if (c == '_')
{ *p++ = '['; *p++ = '3'; }
else
*p++ = c;
}

*p = 0;

if (nativeMethod = (NativeFn) javaClass->java->resolveEntrypoint
(fullName, numberArgs))
return;

// Not going so good. Generate a template for an internal
// implementation, just in case.

FILE *output = fopen ("foo.cpp", "w");

if (output)
{
fprintf (output, "\n/* %s */\n\n", (const char *) javaClass->name);
JavaGenNative::genNativeMethods (javaClass, output, genPrototypes);
fprintf (output, "\n/* %s */\n\n", (const char *) javaClass->name);
JavaGenNative::genNativeMethods (javaClass, output, genHeader);
fprintf (output, "\n/* %s */\n\n", (const char *) javaClass->name);
JavaGenNative::genNativeMethods (javaClass, output, genBody);
fclose (output);
}

thread->unsatisfiedLinkError (ENV, "method \"%s\" (%s) of class \"%s\"",
(const char*) methodName->getString(),
(const char*) descriptor->getString(),
(const char*)
javaClass->className->getString());
}

NativeFn findNativeMethod (const char *name)
{
for (NativeMethod *method = hashTable [JString::hash (name, HASH_SIZE)];
method; method = method->collision)
if (!strcmp (name, method->name))
return method->fn;

return NULL;
}




--

Jim Starkey
Netfrastructure, Inc.
978 526-1376