1998-12-04 00:10:47 +03:00
|
|
|
/* -*- 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.0 (the "NPL"); you may not use this file except in
|
|
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
|
|
* http://www.mozilla.org/NPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* NPL.
|
|
|
|
*
|
|
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
|
|
* Communications Corporation. Portions created by Netscape are
|
|
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
|
|
* Reserved.
|
|
|
|
*/
|
|
|
|
#include "JavaVM.h"
|
|
|
|
#include "prprf.h"
|
|
|
|
#include "plstr.h"
|
|
|
|
#include "LogModule.h"
|
|
|
|
#include "Debugger.h"
|
1998-12-11 07:03:13 +03:00
|
|
|
#ifdef USE_JVMDI
|
1998-12-04 00:10:47 +03:00
|
|
|
#include "jvmdi.h"
|
1998-12-11 07:03:13 +03:00
|
|
|
#endif
|
1998-12-04 00:10:47 +03:00
|
|
|
#include "Thread.h"
|
|
|
|
#include "JniRuntime.h"
|
|
|
|
|
|
|
|
Pool envPool;
|
|
|
|
ClassWorld world(envPool);
|
|
|
|
StringPool sp(envPool);
|
|
|
|
Pool debuggerPool;
|
|
|
|
|
|
|
|
UT_DEFINE_LOG_MODULE(HiMom);
|
|
|
|
UT_DEFINE_LOG_MODULE(VM);
|
|
|
|
|
|
|
|
VM VM::theVM;
|
|
|
|
|
|
|
|
/* Initialize the VM. If initialize is true, attempts to run
|
|
|
|
* the static initializers to initialize the System class on
|
|
|
|
* start-up.
|
|
|
|
*/
|
|
|
|
void VM::staticInit(bool initialize)
|
|
|
|
{
|
|
|
|
NativeMethodDispatcher::staticInit();
|
|
|
|
InterfaceDispatchTable::staticInit(envPool);
|
|
|
|
Standard::initStandardObjects(central);
|
|
|
|
JavaString::staticInit();
|
|
|
|
JNIInitialize();
|
|
|
|
|
|
|
|
/* Intern a few strings which we'll need */
|
|
|
|
/* FIX-ME Why do we need them??? */
|
|
|
|
sp.intern("<clinit>");
|
|
|
|
sp.intern("()V");
|
|
|
|
|
|
|
|
if (initialize) {
|
|
|
|
bool loadedSysLibrary;
|
|
|
|
|
|
|
|
Monitor::staticInit();
|
|
|
|
|
|
|
|
/* Load package library */
|
|
|
|
if (!(loadedSysLibrary = (NativeMethodDispatcher::loadLibrary("Package") != 0)))
|
|
|
|
UT_LOG(VM, PR_LOG_ALWAYS, ("\tCannot load package library!\n"));
|
|
|
|
|
|
|
|
if (loadedSysLibrary) {
|
|
|
|
/* execute System::initializeSystemClass() to get us up and going */
|
|
|
|
theVM.execute("java/lang/System", "initializeSystemClass", "()V", 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread::staticInit();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the class path used to search for class files */
|
|
|
|
void VM::setClassPath(const char *classPath)
|
|
|
|
{
|
|
|
|
central.setClassPath(classPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load a native library. libName is the canonical name of the library.
|
|
|
|
* This routine returns true on success, false on failure.
|
|
|
|
*/
|
|
|
|
bool VM::loadLibrary(const char *libName)
|
|
|
|
{
|
|
|
|
return (NativeMethodDispatcher::loadLibrary(libName) != 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
const Class &VM::getStandardClass(StandardClass clz)
|
|
|
|
{
|
|
|
|
return (Standard::get(clz));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Execute the method whose simple name is given by methodName and signature
|
|
|
|
* string is given by signature in the class given by className.
|
|
|
|
* If the method is not overloaded, signature can be nil.
|
|
|
|
* If invokeMethod is false, then just compile the method but do not
|
|
|
|
* execute it.
|
|
|
|
*/
|
|
|
|
void VM::execute(const char *className,
|
|
|
|
const char *methodName,
|
|
|
|
const char *signature,
|
|
|
|
JavaObject *args[],
|
|
|
|
Int32 nArgs)
|
|
|
|
{
|
|
|
|
ClassFileSummary *cfs = ¢ral.addClass(className);
|
|
|
|
|
|
|
|
if (compileStage < csPreprocess)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Search for specified method */
|
|
|
|
Method *method;
|
|
|
|
|
|
|
|
if (!methodName) {
|
|
|
|
methodName = sp.get("main");
|
|
|
|
signature = sp.get("([Ljava/lang/String;)V");
|
|
|
|
|
|
|
|
if (!methodName || !signature)
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
methodName = sp.get(methodName);
|
|
|
|
if (signature)
|
|
|
|
signature = sp.get(signature);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((method = cfs->getMethod(methodName, signature)) != 0) {
|
|
|
|
// MethodDescriptor descriptor(*method);
|
|
|
|
|
|
|
|
void *code;
|
|
|
|
code = method->compile();
|
|
|
|
|
1998-12-11 07:03:13 +03:00
|
|
|
#ifdef USE_JVMDI
|
1998-12-04 00:10:47 +03:00
|
|
|
if (debugger.getEnabled())
|
|
|
|
JVMDI_SetBreakpoint((JNIEnv *) code, 0, 0, 0);
|
1998-12-11 07:03:13 +03:00
|
|
|
#endif
|
1998-12-04 00:10:47 +03:00
|
|
|
|
|
|
|
if (!noInvoke) {
|
|
|
|
/* You can only jump to a static method */
|
|
|
|
if ((method->getModifiers() & CR_METHOD_STATIC)) {
|
|
|
|
if (!PL_strcmp(methodName, "main")) {
|
|
|
|
const Type *type = (const Class *) central.addClass("java/lang/String").getThisClass();
|
|
|
|
const Array &typeOfArray = type->getArrayType();
|
|
|
|
void *mem = malloc(arrayObjectEltsOffset + getTypeKindSize(tkObject)*nArgs);
|
|
|
|
JavaArray *argsArray = new (mem) JavaArray(typeOfArray, nArgs);
|
|
|
|
|
|
|
|
/* Copy args into the array */
|
|
|
|
JavaObject **argsInArray = (JavaObject **) ((char *) mem+arrayObjectEltsOffset);
|
|
|
|
for (int32 i = 0; i < nArgs; i++)
|
|
|
|
argsInArray[i] = args[i];
|
|
|
|
|
|
|
|
args = new JavaObject*[1];
|
|
|
|
args[0] = argsArray;
|
|
|
|
nArgs = 1;
|
|
|
|
}
|
|
|
|
//method->invoke(0, args, nArgs);
|
|
|
|
Thread::invoke(method,NULL,args,nArgs);
|
|
|
|
|
|
|
|
} else
|
|
|
|
UT_LOG(VM, PR_LOG_ALWAYS, ("specified method is not static; cannot execute\n"));
|
|
|
|
}
|
|
|
|
|
|
|
|
} else
|
|
|
|
UT_LOG(VM, PR_LOG_ALWAYS, ("Could not find method %s.\n", methodName));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
ClassCentral VM::central(envPool, world, sp, 0);
|
|
|
|
DebuggerState VM::debugger(debuggerPool);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Compile and dump the methods in the file read into cfs.
|
|
|
|
* Run the compiler's stages
|
|
|
|
* up to and including the given stage. Use the envPool for temporary
|
|
|
|
* storage.
|
|
|
|
*/
|
|
|
|
void VM::compileMethods(const char *className)
|
|
|
|
{
|
|
|
|
ClassFileSummary &cfs = central.addClass(className);
|
|
|
|
|
|
|
|
uint nMethods = cfs.getMethodCount();
|
|
|
|
const Method **methods = cfs.getMethods();
|
|
|
|
|
|
|
|
for (uint16 i =0; i < nMethods; i++) {
|
|
|
|
Method *method = const_cast<Method *>(methods[i]);
|
|
|
|
|
|
|
|
method->compile();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Intern a string, expected to be in UTF8 format, and return a reference
|
|
|
|
* to the interned string object.
|
|
|
|
*/
|
|
|
|
JavaString &VM::intern(const char *str)
|
|
|
|
{
|
|
|
|
const char *internedp = sp.intern(str);
|
|
|
|
return *sp.getStringObj(internedp);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
|
|
|
|
/* Copy breakPointsIn into breakpointsOut, allocating memory as neccessary */
|
|
|
|
inline void VM::setBreakPoints(DebugDesc *breakPointsIn, Uint32 numBreakPointsIn,
|
|
|
|
DebugDesc *&breakPointsOut, Uint32 &numBreakPointsOut)
|
|
|
|
{
|
|
|
|
if (breakPointsOut)
|
|
|
|
delete [] breakPointsOut;
|
|
|
|
|
|
|
|
breakPointsOut = new DebugDesc[(numBreakPointsOut = numBreakPointsIn)];
|
|
|
|
|
|
|
|
for (Uint32 i = 0; i < numBreakPointsIn; i++) {
|
|
|
|
/* Replace slashes with dots, since the fully qualified class name is stored with dots
|
|
|
|
* as the separators
|
|
|
|
*/
|
|
|
|
for (char *cnameTemp = const_cast<char *>(breakPointsIn[i].className); *cnameTemp; cnameTemp++)
|
|
|
|
if (*cnameTemp == '/') *cnameTemp = '.';
|
|
|
|
|
|
|
|
breakPointsOut[i].className = sp.intern(breakPointsIn[i].className);
|
|
|
|
breakPointsOut[i].methodName = sp.intern(breakPointsIn[i].methodName);
|
|
|
|
|
|
|
|
/* Replace all dots in the signature with slashes */
|
|
|
|
for (char *bTemp = const_cast<char *>(breakPointsIn[i].sig); *bTemp;
|
|
|
|
bTemp++)
|
|
|
|
if (*bTemp == '.') *bTemp = '/';
|
|
|
|
|
|
|
|
breakPointsOut[i].sig = sp.intern(breakPointsIn[i].sig);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Specify a list of methods to break into when compiling the method */
|
|
|
|
void VM::setCompileBreakPoints(DebugDesc *breakPoints, Uint32 numBreakPoints)
|
|
|
|
{
|
|
|
|
setBreakPoints(breakPoints, numBreakPoints, compileBreakPoints, nCompileBreakPoints);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Specify a list of methods to break into when running the method */
|
|
|
|
void VM::setExecBreakPoints(DebugDesc *breakPoints, Uint32 numBreakPoints)
|
|
|
|
{
|
|
|
|
setBreakPoints(breakPoints, numBreakPoints, execBreakPoints, nExecBreakPoints);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Construct and return a fully qualified class-name
|
|
|
|
* from the input name, which is a fully qualified
|
|
|
|
* java class name.
|
|
|
|
* getUtfClassName("java.lang.String") = "java/lang/String"
|
|
|
|
*/
|
|
|
|
char *VM::getUtfClassName(const char *name)
|
|
|
|
{
|
|
|
|
char *utfClassName = PL_strdup(name);
|
|
|
|
|
|
|
|
for (char *t = utfClassName; *t; t++)
|
|
|
|
if (*t == '.') *t = '/';
|
|
|
|
|
|
|
|
return utfClassName;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free the name returned by getUtfClassName() */
|
|
|
|
void VM::freeUtfClassName(char *name)
|
|
|
|
{
|
|
|
|
free(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VM::~VM()
|
|
|
|
{
|
|
|
|
if (execBreakPoints)
|
|
|
|
delete [] execBreakPoints;
|
|
|
|
|
|
|
|
if (compileBreakPoints)
|
|
|
|
delete [] compileBreakPoints;
|
|
|
|
}
|
|
|
|
|