/* Code for dealing with binary/native code through the dlopen interface.
 * includes code for loading pre-compiled classes, as well as code for
 * loading native methods of interpreted classes. */

#if ARCH_x86 || ARCH_sparc || ARCH_mips
/* Dynamic loading supported on Linux/Intel, Solaris/SPARC, and Irix/MIPS */
#define HAVE_DLSYM 1
#endif /* ARCH_x86 || ARCH_sparc || ARCH_mips */

#ifdef SCOUT
#undef HAVE_DLSYM
#define HAVE_TCLASS_NAME_LIST (1)
#endif /* SCOUT */

#include <stdio.h>
#include <stdlib.h>
#include "toba.h"
#include "java_lang_Class.h"
#include "java_lang_String.h"
#include "toba_classfile_Names.h" /* This is available regardless of OPTION_JIT */
#include "runtime.h"

#if HAVE_DLSYM
#include <dlfcn.h>

/* dlopen handle to internal classes from the shared libraries we
 * start up with. */
static void *self_handle;

#endif /* HAVE_DLSYM */

#if HAVE_TCLASS_NAME_LIST
/* Any executable program has within it an array containing the
 * addresses of all Toba Classes that are defined within the
 * executable.  Need this to implement Class.forName when dynamic
 * loading is not available.  The list is null-terminated. */
extern Class tclass_name_list [];
#endif /* HAVE_TCLASS_NAME_LIST */

void binary_loader_init()
{
    /* initialize toba.Names: we're going to call Names.hashclass */
    initclass(&cl_toba_classfile_Names.C);

#if HAVE_DLSYM
    /* Make our normal shared library available for access from the 
     * binary loader. Since we're linked with it already, we only need
     * call dlopen with a 0 argument to make them available to the 
     * world. */
    self_handle = dlopen(0, RTLD_NOW | RTLD_GLOBAL);
#endif /* HAVE_DLSYM */

#if HAVE_TCLASS_NAME_LIST
    /* Let loadClass know about all the goodies we have stowed away.  We
     * register these in the system class loader's hash table, so we know
     * we don't have to load class data for nor resolve them. */
    {
       Class * clp = tclass_name_list;

       if (NULL == clp) {
          throwInternalError ("Missing tclass_name_list; can't do lookups.");
       }
       while (NULL != *clp) {
          register_class (*clp);
          ++clp;
       }
    }
#endif /* HAVE_TCLASS_NAME_LIST */
}

/** Given the (fully-qualified) name of a Java class, find it in whatever
  * way we have to. */
struct in_java_lang_Class *
load_native_system_class(struct in_java_lang_String *classname)
{
    struct in_java_lang_String *symname, *leader, *hashedname;
    char * csymname;
    Class c;

    leader = javastring("cl_");
    hashedname = hashclass_S_3GcHE(classname);
    symname = leader->class->M.concat_S_WOS31.f(leader, hashedname);
    csymname = cstring (symname);

    /* Assume we won't find it. */
    c = NULL;

    /* First thing, see if we already know where it is */

#if HAVE_DLSYM
    /* 
     * XXX we probably want to change this to walk the
     * entire toba.class.path at some point
     */
    c = dlsym(self_handle, csymname);
#if 0
    fprintf (stderr, "self-search for %s returned %x\n", csymname, c);
#endif
#endif /* HAVE_DLSYM */

    if (c != 0) {
        initclass(c);
	return (struct in_java_lang_Class *)&c->classclass;
    }

    return 0;
}


Boolean
load_native_library(struct in_java_lang_String *filename)
{
    void *new_handle = NULL;

#if HAVE_DLSYM
    new_handle = dlopen(cstring(filename), RTLD_NOW | RTLD_GLOBAL);
#endif /* HAVE_DLSYM */

    if (new_handle != 0)
	return 1;
    else
	return 0;
}

void *
load_native_method(struct in_java_lang_String *clname,
		   struct in_java_lang_String *methname, 
		   struct in_java_lang_String *sig)
{
    void *sym = NULL;
    struct in_java_lang_String *symname;

    symname = hashmethod_SSS_akCel(methname, clname, sig);

#if HAVE_DLSYM
    sym = dlsym(self_handle, cstring(symname));
#endif /* HAVE_DLSYM */
    
    return sym;
}

