gecko-dev/ef/Driver/StandAloneJava/efmain.cpp

631 lines
21 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 <stdio.h>
#include <stdlib.h>
#include "JavaVM.h"
#include "prprf.h"
#include "plstr.h"
#include "Exceptions.h"
#include "StackWalker.h"
#include "NativeCodeCache.h" // for printMethodTable
#include "LogModule.h"
#ifdef __MWERKS__
#include <Console.h>
#include <OSUtils.h>
#endif
void realMain(void* arg);
struct StageName
{
char *name;
CompileStage stage;
};
const StageName stageNames[] =
{
{"r", csRead},
{"R", csRead},
{"read", csRead},
{"READ", csRead},
{"p", csPreprocess},
{"P", csPreprocess},
{"preprocess", csPreprocess},
{"PREPROCESS", csPreprocess},
{"g", csGenPrimitives},
{"G", csGenPrimitives},
{"genprimitives", csGenPrimitives},
{"GENPRIMITIVES", csGenPrimitives},
{"o", csOptimize},
{"O", csOptimize},
{"optimize", csOptimize},
{"OPTIMIZE", csOptimize},
{"i", csGenInstructions},
{"I", csGenInstructions},
{"instructions", csGenInstructions},
{"INSTRUCTIONS", csGenInstructions}
};
const nStageNames = sizeof(stageNames) / sizeof(StageName);
static bool getStage(const char *stageName, CompileStage &stage)
{
const StageName *sn = stageNames;
for (; sn != stageNames + nStageNames; sn++)
if (!PL_strcmp(stageName, sn->name)) {
stage = sn->stage;
return true;
}
return false;
}
/* Options
* -c, -classpath <canonical class-path>
* -a, -all Compile all methods.
* -m, -method <methodName> <sig> : Go to method whose simple name is
* <methodName> and signature is <sig>. The -s option
* specifies what to do with the method.
* -mn, -methodName <methodName> : Go to method whose simple name is
* <methodName>, which must not be overloaded. The -s option
* specifies what to do with the method.
* -s, -stage <stage: r, p, g, o, i> default is to generate instructions
* -v, -verbose : verbose messages
* -n, -noinvoke : do not invoke compiled method. This is automatically true
* if the compile stage is anything other than genInstructions.
* -l, -lib <libname> : canonical name of native library to load at init time
* -nosys, -nosystem : Don't initialize system class on start-up
* -ta, -traceAll: enable method tracing for all methods
* -bc, -breakCompile <className> <methodName> <signature>: Set a debug breakpoint just before compiling
* the method with the given fully qualified className, simple methodName and
* java signature.
* -be, -breakExec <className> <methodName> <signature>: Set a debug breakpoint just before executing
* the method with the given fully qualified className, simple methodName and
* java signature.
* -h, -help : Print help message
* -log <module-name> <level> : turn on logging for <module-name> at level <level>. By default, logs are logged
* to stderr; use -logfile to direct them to a file.
* -lf, -logFile <filename> : specify the file to put logs into. "stderr" is a valid filename and indicates
* stderr. -lf can be used more than once on the command-line; it over-rides the last value of
* -lf. This can be used to log different modules to different files. For example,
* -lf foo -log FieldOrMethod 4 -log ClassCentral 3 -lf stderr -log Codegen 5
* logs modules FieldOrMethod and ClassCentral to the file foo and the module
* Codegen to standard error.
* -ln, -logNames : print out a list of all log modules
* -debug : Enable debugging
* -ce, -catchHardwareExceptions : Catch all hardware exceptions (used in the debug builds only)
*/
struct Options {
CompileStage stage; /* Stage upto which method must be compiled */
bool compileAll; /* If true, compile all method in class */
bool verbose; /* Cause verbose output to be emitted when compiling */
bool initialize; /* If true, initialize system class */
bool invokeMethod; /* If false, do not invoke method after compiling */
bool emitHTML; /* If true, output a HTML file for each jit'd method */
bool traceAllMethods; /* If true, invoking any method generates a debugging trace */
const char *methodName; /* Name of method to compile */
const char *methodSig; /* Signature of method to compile */
const char *className; /* Name of class to load */
const char *classPath;
const char *logFileName;/* Name of the logFile -- if NULL, then logFile is stderr */
JavaObject **args; /* Command-line arguments to the class */
const char **argStrings;
int32 nArgs; /* Number of command-line arguments to the class */
const char *libNames[10]; /* Canonical names of libraries to be pre-loaded */
int numLibs; /* Number of libraries to be pre-loaded */
bool debug; /* Enable debugging */
bool catchHardwareExceptions; /* Catch hardware exceptions and asserts */
DebugDesc *compileBreakPoints; /* Descriptions of compile break points */
Uint32 nCompileBreakPoints; /* Number of compile break points */
Uint32 nCompileBreakSlots; /* Number of elements currently allocated in compileBreakPoints */
DebugDesc *execBreakPoints; /* Descriptions of exec break points */
Uint32 nExecBreakPoints; /* Number of exec break points */
Uint32 nExecBreakSlots; /* Number of elements currently allocated in execBreakPoints */
Options();
~Options();
bool parse(int argc, const char **argv);
void printHelp(const char *argv0);
private:
void setBreakPoints(Uint32 &nBreakPoints, Uint32 &nBreakSlots,
DebugDesc *&breakPoints, const char *argv[]);
};
#ifdef PR_LOGGING
static void printAvailableModules()
{
LogModuleObject *module;
int i;
PR_fprintf(PR_STDERR, "Here is the current list of log modules:\n\n");
i = 1;
for (module = LogModuleObject::getAllLogModules(); module; module = module->getNext())
PR_fprintf(PR_STDERR, "%2d. %s\n", i++, module->getName());
}
#endif
inline Options::Options():
stage(csGenInstructions),
compileAll(false),
verbose(false),
initialize(true),
invokeMethod(true),
emitHTML(0),
traceAllMethods(false),
methodName(0),
methodSig(0),
className(0),
classPath(0),
logFileName(0),
args(0),
argStrings(0),
nArgs(0),
numLibs(0),
debug(false),
catchHardwareExceptions(false),
compileBreakPoints(0),
nCompileBreakPoints(0),
nCompileBreakSlots(0),
execBreakPoints(0),
nExecBreakPoints(0),
nExecBreakSlots(0)
{}
inline Options::~Options()
{
if (args) {
delete [] args;
delete [] argStrings;
}
if (compileBreakPoints)
delete [] compileBreakPoints;
if (execBreakPoints)
delete [] execBreakPoints;
if (className)
VM::freeUtfClassName((char *) className);
}
#ifdef DEBUG
void Options::setBreakPoints(Uint32 &nBreakPoints, Uint32 &nBreakSlots,
DebugDesc *&breakPoints, const char *argv[])
{
if (nBreakPoints+1 > nBreakSlots) {
DebugDesc *temp = breakPoints;
breakPoints = new DebugDesc[nBreakSlots += 10];
for (Uint32 index = 0; index < nBreakSlots-10; index++)
breakPoints[index] = temp[index];
}
breakPoints[nBreakPoints].className = *++argv;
breakPoints[nBreakPoints].methodName = *++argv;
breakPoints[nBreakPoints].sig = *++argv;
nBreakPoints++;
}
#endif
void Options::printHelp(const char *argv0)
{
printf (
"Usage: %s [Options]* <javaClass> [java args]*\n"
"Options:\n"
" -c, -classpath <canonical class-path>\n"
" -a, -all Compile all methods.\n"
" -m, -method <methodName> <sig> :\n"
" Go to method whose simple name is <methodName> and signature\n"
" is <sig>. The -s option specifies what to do with the method.\n"
" -mn, -methodName <methodName> :\n"
" Go to method whose simple name is <methodName>, which must\n"
" not be overloaded. The -s option specifies what to do with\n"
" the method.\n"
" -s, -stage <stage: r, p, g, o, i> default is to generate instructions\n"
" -v, -verbose : verbose messages\n"
" -n, -noinvoke : do not invoke compiled method. This is automatically true\n"
" if the compile stage is anything other than genInstructions.\n"
" -l, -lib <libname> : canonical name of native library to load at init time\n"
" -nosys, -nosystem : Don't initialize system class on start-up\n"
#ifdef DEBUG
" -ta, -traceAll: enable method tracing for all methods\n"
" -html: output a HTML file for each jit'd method\n"
" -bc, -breakCompile <className> <methodName> <signature>:\n"
" Set a debug breakpoint just before compiling the method with\n"
" the given fully qualified className, simple methodName and\n"
" java signature.\n"
" -be, -breakExec <className> <methodName> <signature>:\n"
" Set a debug breakpoint just before executing the method with\n"
" the given fully qualified className, simple methodName and\n"
" java signature.\n"
#endif
" -h, -help : Print this help message\n"
" -log <module-name> <level> :\n"
" turn on logging for <module-name> at level <level>. By default,\n"
" logs are logged to stderr; use -logfile to direct them to a file.\n"
" -lf, -logFile <filename> :\n"
" specify the file to put logs into. \"stderr\" is a valid filename\n"
" and indicates stderr. -lf can be used more than once on the\n"
" command-line; it over-rides the last value of -lf. This can be\n"
" used to log different modules to different files. For example,\n"
" '-lf foo -log FieldOrMethod 4 -log ClassCentral 3 -lf stderr -log\n"
" Codegen 5' logs modules FieldOrMethod and ClassCentral to the\n"
" file foo and the module Codegen to standard error.\n"
" -ln, -logNames : print out a list of all log modules\n"
" -debug : Enable debugging\n"
" -ce, -catchHardwareExceptions :\n"
" Catch all hardware exceptions (used in the debug builds only)\n",
argv0);
}
bool Options::parse(int argc, const char **argv)
{
for (int i = 1; i < argc; i++) {
if (!PL_strcmp(argv[i], "-a") || !PL_strcmp(argv[i], "-all")) {
compileAll = true;
invokeMethod = false;
methodName = 0;
methodSig = 0;
#ifdef DEBUG
} else if (!PL_strcmp(argv[i], "-bc") || !PL_strcmp(argv[i], "-breakCompile")) {
setBreakPoints(nCompileBreakPoints, nCompileBreakSlots,
compileBreakPoints, &argv[i]);
i += 3;
} else if (!PL_strcmp(argv[i], "-be") || !PL_strcmp(argv[i], "-breakExec")) {
setBreakPoints(nExecBreakPoints, nExecBreakSlots,
execBreakPoints, &argv[i]);
i += 3;
#endif
} else if (!PL_strcmp(argv[i], "-c") || !PL_strcmp(argv[i], "-classpath")) {
classPath = argv[++i];
} else if (!PL_strcmp(argv[i], "-h") || !PL_strcmp(argv[i], "-help")) {
printHelp(argv[0]);
return false;
} else if (!PL_strcmp(argv[i], "-l") || !PL_strcmp(argv[i], "-lib")) {
libNames[numLibs++] = argv[++i];
} else if (!PL_strcmp(argv[i], "-m") || !PL_strcmp(argv[i], "-method")) {
compileAll = false;
methodName = argv[++i];
methodSig = argv[++i];
} else if (!PL_strcmp(argv[i], "-mn") || !PL_strcmp(argv[i], "-methodName")) {
compileAll = false;
methodName = argv[++i];
methodSig = 0;
} else if (!PL_strcmp(argv[i], "-n") || !PL_strcmp(argv[i], "-noinvoke")) {
invokeMethod = false;
} else if (!PL_strcmp(argv[i], "-html")) {
emitHTML = true;
} else if (!PL_strcmp(argv[i], "-v") || !PL_strcmp(argv[i], "-verbose")) {
verbose = true;
} else if (!PL_strcmp(argv[i], "-s") || !PL_strcmp(argv[i], "-stage")) {
const char *stageName = argv[++i];
if (!getStage(stageName, stage)) {
PR_fprintf(PR_STDERR, "%s: Bad stage argument %s\n", argv[0],
stageName);
return false;
}
if (stage != csGenInstructions)
invokeMethod = false;
} else if (!PL_strcmp(argv[i], "-nosys") || !PL_strcmp(argv[i], "-nosystem")) {
initialize = false;
} else if (!PL_strcmp(argv[i], "-ta") || !PL_strcmp(argv[i], "-traceAll")) {
traceAllMethods = true;
} else if (!PL_strcmp(argv[i], "-log")) {
#ifdef PR_LOGGING
/* Get the names of the log module, level and filename */
const char *logModuleName = argv[++i];
PRLogModuleLevel logLevel = (PRLogModuleLevel) atoi(argv[++i]);
/* Identify this module */
LogModuleObject *module = NULL;
for (module = LogModuleObject::getAllLogModules(); module; module = module->getNext()) {
if (!PL_strcmp(logModuleName, module->getName())) {
module->setLogLevel(logLevel);
if (logFileName)
module->setLogFile(logFileName);
break;
}
}
if (!module) {
fprintf(stderr, "Incorrect module name \"%s\" in -log option.\n", logModuleName);
printAvailableModules();
return false;
}
#else
i += 2;
#endif
} else if (!PL_strcmp(argv[i], "-lf") || !PL_strcmp(argv[i], "-logFile")) {
if (!PL_strcmp(argv[++i], "stderr"))
logFileName = 0;
else
logFileName = argv[i];
} else if (!PL_strcmp(argv[i], "-ln") || !PL_strcmp(argv[i], "-logNames")) {
#ifdef PR_LOGGING
printAvailableModules();
return false;
#else
PR_fprintf(PR_STDERR, "This copy of sajava does not support logging\n");
return false;
#endif
} else if (!PL_strcmp(argv[i], "-debug"))
debug = true;
else if (!PL_strcmp(argv[i], "-ce") || !PL_strcmp(argv[i], "-catchHardwareExceptions"))
catchHardwareExceptions = true;
else if (argv[i][0] == '-') {
PR_fprintf(PR_STDERR, "bad option %s\n", argv[i]);
return false;
} else { /* Must be a class name */
className = VM::getUtfClassName(argv[i++]);
#ifdef DEBUG_laurentm
for (Uint32 l = 0; l < strlen(className); l++)
if (className[l] == '.')
className[l] = '/';
#endif
if ((nArgs = argc-i) > 0) {
args = new JavaObject *[nArgs];
argStrings = new const char *[nArgs];
for (int j = 0; i < argc; i++, j++)
argStrings[j] = argv[i];
} else
args = 0;
break;
}
}
return true;
}
//------------------------------------------------------------------------------
#ifdef DEBUG_WALDEMAR
#define PREPEND_DEFAULT_OPTIONS
static const char *const defaultOptions[] = {
"-stage", "o",
"-all",
"-verbose",
"-noinvoke",
"-classpath", "/Full-Stutter/Java/java.jar:/Full-Stutter/Java/Tiny/Java Classes",
"-log", "FieldOrMethod", "3"};
#endif
#ifdef PREPEND_DEFAULT_OPTIONS
//
// Prepend user-specific default options from the defaultOptions array.
//
static void prependDefaultOptions(int &argc, const char **&argv)
{
int nDefaultOptions = sizeof(defaultOptions) / sizeof(const char *);
if (nDefaultOptions) {
int newArgC = argc + nDefaultOptions;
const char **newArgV = new const char *[newArgC];
const char **src = argv;
const char **dst = newArgV;
*dst++ = *src++;
copy(defaultOptions, defaultOptions+nDefaultOptions, dst);
dst += nDefaultOptions;
copy(src, src+argc-1, dst);
argc = newArgC;
argv = newArgV;
}
}
#endif
// We need to actually create a globally
// scoped thread before we use main, because on some platforms
// (NT) NSPR implicit initialization causes us to be on a fiber
// which means that if we mistakenly call any Win32 functions
// that call WaitForSingleObject, etc we end up hanging.
//
// The NSPR people say they will make this happen automagically
// (I won't hold my breath!) =)
#define MAIN_WRAPPER_RETURN(inWrapper, inRv) \
PR_BEGIN_MACRO \
inWrapper->rv = inRv; \
return; \
PR_END_MACRO
struct MainWrapper
{
int argc; // count of args
const char** argv; // vector of actual strings
int rv; // return value from main
};
int main(int argc, const char **argv)
{
MainWrapper mainWrapper = {argc, argv, -1};
PRThread* thread;
thread = PR_CreateThread(PR_USER_THREAD,
&realMain,
&mainWrapper,
PR_PRIORITY_NORMAL,
PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD,
0);
if (thread)
PR_JoinThread(thread);
else
trespass("could not create main thread");
PR_Cleanup();
return mainWrapper.rv;
}
void realMain(void* arg)
{
MainWrapper* mainWrapper = (MainWrapper*) arg;
int argc = mainWrapper->argc;
const char** argv = mainWrapper->argv;
#ifdef XP_MAC
argc = ccommand((char ***)&argv);
#endif
#ifdef PREPEND_DEFAULT_OPTIONS
prependDefaultOptions(argc, argv);
#endif
Options options;
if (!options.parse(argc, argv))
MAIN_WRAPPER_RETURN(mainWrapper, 1);
if (options.debug)
VM::debugger.enable();
if (options.classPath)
VM::setClassPath(options.classPath);
if (!options.className) {
PR_fprintf(PR_STDERR, "%s: Error: Class name expected.\n", argv[0]);
MAIN_WRAPPER_RETURN(mainWrapper, 1);
}
if (options.compileAll && options.methodName) {
PR_fprintf(PR_STDERR, "%s: Error: Cannot combine -all with -method.\n",
argv[0]);
MAIN_WRAPPER_RETURN(mainWrapper, 1);
}
try {
#ifdef DEBUG
VM::theVM.setCompileBreakPoints(options.compileBreakPoints, options.nCompileBreakPoints);
VM::theVM.setExecBreakPoints(options.execBreakPoints, options.nExecBreakPoints);
VM::theVM.setInhibitBackpatching(options.traceAllMethods);
VM::theVM.setEmitHTML(options.emitHTML);
#endif
VM::theVM.setNoInvoke(!options.invokeMethod);
VM::theVM.setCompileStage(options.stage);
VM::theVM.setVerbose(options.verbose);
VM::theVM.setCatchHardwareExceptions(options.catchHardwareExceptions);
#ifdef DEBUG
// Don't bother tracing system staticInit
VM::theVM.setTraceAllMethods(options.traceAllMethods);
#endif
VM::staticInit(options.initialize);
} catch (VerifyError err) {
printf("Error initializing VM: %d\n", err.cause);
MAIN_WRAPPER_RETURN(mainWrapper, 1);
}
int32 i;
/* Load all native libraries specified on the command-line */
for (i = 0; i < options.numLibs; i++) {
if (!VM::loadLibrary(options.libNames[i]))
printf("Warning: Cannot load library %s\n", options.libNames[i]);
}
/* Intern all command-line arguments and convert into strings */
for (i = 0; i < options.nArgs; i++)
options.args[i] = &VM::intern(options.argStrings[i]);
if (options.compileAll) {
try {
VM::theVM.compileMethods(options.className);
} catch (VerifyError err) {
PR_fprintf(PR_STDERR, "Error loading class/compiling methods: %d\n",
err.cause);
MAIN_WRAPPER_RETURN(mainWrapper, 1);
}
MAIN_WRAPPER_RETURN(mainWrapper, 0);
}
/* If we're here, we wish to execute a certain method */
// install the platform specific hardware exception handler
if (true || VM::debugger.getEnabled()) { // true->false delegates to debugger
#ifdef _WIN32
// Check if we want to catch the hardware exception.
if (VM::theVM.getCatchHardwareExceptions()) {
installHardwareExceptionHandler(win32HardwareThrowExit);
} else {
installHardwareExceptionHandler(win32HardwareThrow);
}
#endif
}
// if using the debugger ignore user's command to execute a class
if (VM::debugger.getEnabled())
{
printf("Command sequence is remote\n");
VM::debugger.waitForDebugger();
}
else
{
try
{
VM::theVM.execute(options.className, options.methodName,
options.methodSig,
options.args, options.nArgs);
} catch (VerifyError err) {
printf("Error loading class/executing method: %d\n", err.cause);
MAIN_WRAPPER_RETURN(mainWrapper, 1);
}
}
// remove the platform specific hardware exception handler
if (true || VM::debugger.getEnabled())
removeHardwareExceptionHandler();
MAIN_WRAPPER_RETURN(mainWrapper, 0);
}
#if __GNUC__ < 2 || __GNUC_MINOR__ < 91
// for gcc with -fhandle-exceptions
void terminate() {}
#endif
#if defined(_WIN32) && defined(DEBUG_LOG)
void stack(void *inPc)
{
stackWalker(inPc);
}
#endif