somewhat weak debugger console hookup.

build shouldn't *look* different yet.

Moved Context::interpret() local vars into Context private, added accessors for
stuff, using JavaScript::Lexer to lex debugger commands.

Fixed sign comparison warning in icg.cpp
This commit is contained in:
rginda%netscape.com 2000-04-29 00:23:06 +00:00
Родитель d3f0962648
Коммит c9f14ba1b4
16 изменённых файлов: 684 добавлений и 150 удалений

Просмотреть файл

@ -11,7 +11,8 @@ objs = hash.o \
parser.o \
utilities.o \
world.o \
vmtypes.o
vmtypes.o \
debugger.o
gc_path = ../../gc/boehm/

151
js/js2/debugger.cpp Normal file
Просмотреть файл

@ -0,0 +1,151 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* 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):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include "world.h"
#include "debugger.h"
#include <string>
#include <ctype.h>
#include <assert.h>
namespace JavaScript {
namespace Debugger {
enum ShellCommand {
ASSEMBLE,
DISSASSEMBLE,
STEP,
PRINT,
PRINT2,
EXIT,
COMMAND_COUNT
};
static const char *shell_cmd_names[] = {
"assemble",
"dissassemble",
"step",
"print",
"print2",
"exit",
0
};
/* return true if str2 starts with/is str1
* XXX ignore case */
bool
startsWith (const String &str1, const String &str2)
{
uint n;
size_t m = str1.size();
if (m > str2.size())
return false;
for (n = 0; n < m; ++n)
if (str1[n] != str2[n])
return false;
return true;
}
bool
Shell::doCommand (Interpreter::Context */*context*/, const String &source)
{
Lexer lex (mWorld, source, widenCString("debugger console"), 0);
const String *cmd;
ShellCommand match = COMMAND_COUNT;
int ambig_matches = 0;
const Token &t = lex.get(true);
if (t.hasKind(Token::identifier))
cmd = &(t.getIdentifier());
else
{
mErr << "you idiot.\n";
return false;
}
for (int i = ASSEMBLE; i < COMMAND_COUNT; ++i)
{
String possibleMatch (widenCString(shell_cmd_names[i]));
if (startsWith(*cmd, possibleMatch))
{
if (cmd->size() == possibleMatch.size())
{
/* exact match */
ambig_matches = 0;
match = (ShellCommand)i;
break;
}
else if (match == COMMAND_COUNT) /* no match yet */
match = (ShellCommand)i;
else
++ambig_matches; /* something already matched,
* ambiguous command */
}
}
if (ambig_matches == 0)
switch (match)
{
case COMMAND_COUNT:
mErr << "Unknown command '" << *cmd << "'.\n";
break;
case ASSEMBLE:
case DISSASSEMBLE:
case STEP:
case PRINT:
default:
mErr << "Input '" << *cmd << "' matched command '" <<
shell_cmd_names[match] << "'.\n";
break;
}
else
mErr << "Ambiguous command '" << *cmd << "', " <<
(uint)(ambig_matches + 1) << " similar commands.\n";
return (ambig_matches == 0);
}
} /* namespace Debugger */
} /* namespace JavaScript */

Просмотреть файл

@ -33,9 +33,29 @@
/* this is all vapor, don't take it to serious yet */
#ifndef debugger_h
#define debugger_h
#include "utilities.h"
#include "interpreter.h"
namespace JavaScript {
namespace Debugger {
class Shell {
public:
Shell (World &aWorld, Formatter &aOut, Formatter &aErr) :
mWorld(aWorld), mOut(aOut), mErr(aErr) {}
bool doCommand (Interpreter::Context *context,
const String &aSource);
private:
World &mWorld;
Formatter &mOut, &mErr;
};
#if 0
typedef void (debuggerCallback) (Context *aContext, ICodeDebugger *aICD);
class Breakpoint {
@ -78,6 +98,9 @@ namespace Debugger {
KILL
};
/**
* tell the debugger what to do when the debuggerCallback returns
*/
void setNextAction (DebuggerAction aAction);
/**
@ -105,6 +128,9 @@ namespace Debugger {
}; /* class ICodeDebugger */
#endif /* 0 */
} /* namespace Debugger */
} /* namespace JavaScript */
#endif /* debugger_h */

Просмотреть файл

@ -66,7 +66,7 @@ namespace ICG {
iCode = new InstructionStream();
if (hasTryStatement)
exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]);
for (int i = 0; i < switchStatementNesting; i++) {
for (uint i = 0; i < switchStatementNesting; i++) {
String s = widenCString("__switchControlVariable__");
char num[8];
sprintf(num, "%.2d", i);

Просмотреть файл

@ -33,7 +33,6 @@
#include "interpreter.h"
#include "world.h"
#include "vmtypes.h"
namespace JavaScript {
namespace JSTypes {
@ -126,9 +125,9 @@ struct Linkage : public Context::Frame, public gc_base {
{
}
Context::Frame* getNext() { return mNext; }
Context::Frame* getNext() { return mNext; }
void getState(InstructionIterator& pc, JSValues*& registers, ICodeModule*& iCode)
void getState(InstructionIterator& pc, JSValues*& registers, ICodeModule*& iCode)
{
pc = mReturnPC;
registers = &mActivation->mRegisters;
@ -138,34 +137,38 @@ struct Linkage : public Context::Frame, public gc_base {
JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
// initial activation.
Activation* activation = new Activation(iCode, args);
JSValues* registers = &activation->mRegisters;
assert(mActivation == 0); /* recursion == bad */
JSValue rv;
mActivation = new Activation(iCode, args);
JSValues* registers = &mActivation->mRegisters;
mICode = iCode;
InstructionIterator begin_pc = iCode->its_iCode->begin();
InstructionIterator pc = begin_pc;
mPc = begin_pc;
// stack of all catch/finally handlers available for the current activation
std::stack<InstructionIterator> subroutineStack; // to implement jsr/rts for finally code
// to implement jsr/rts for finally code
std::stack<InstructionIterator> subroutineStack;
while (true) {
try {
// tell any listeners about the current execution state.
// XXX should only do this if we're single stepping/tracing.
if (mListeners.size()) {
broadcast(pc, registers, activation->mICode);
}
Instruction* instruction = *pc;
if (mListeners.size())
broadcast(STEP);
Instruction* instruction = *mPc;
switch (instruction->op()) {
case CALL:
{
Call* call = static_cast<Call*>(instruction);
mLinkage = new Linkage(mLinkage, ++pc, begin_pc, activation,
op1(call));
ICodeModule* target =
(*registers)[op2(call)].function->getICode();
activation = new Activation(target, activation, op3(call));
registers = &activation->mRegisters;
begin_pc = pc = target->its_iCode->begin();
mLinkage = new Linkage(mLinkage, ++mPc, begin_pc,
mActivation, op1(call));
mICode = (*registers)[op2(call)].function->getICode();
mActivation = new Activation(mICode, mActivation, op3(call));
registers = &mActivation->mRegisters;
begin_pc = mPc = mICode->its_iCode->begin();
}
continue;
@ -174,13 +177,17 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSValue result;
Linkage *linkage = mLinkage;
if (!linkage)
return result;
{
rv = result;
goto out;
}
mLinkage = linkage->mNext;
activation = linkage->mActivation;
registers = &activation->mRegisters;
mActivation = linkage->mActivation;
registers = &mActivation->mRegisters;
(*registers)[linkage->mResult] = result;
pc = linkage->mReturnPC;
mPc = linkage->mReturnPC;
begin_pc = linkage->mBasePC;
mICode = mActivation->mICode;
}
continue;
@ -192,13 +199,17 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
result = (*registers)[op1(ret)];
Linkage* linkage = mLinkage;
if (!linkage)
return result;
{
rv = result;
goto out;
}
mLinkage = linkage->mNext;
activation = linkage->mActivation;
registers = &activation->mRegisters;
mActivation = linkage->mActivation;
registers = &mActivation->mRegisters;
(*registers)[linkage->mResult] = result;
pc = linkage->mReturnPC;
mPc = linkage->mReturnPC;
begin_pc = linkage->mBasePC;
mICode = mActivation->mICode;
}
continue;
case MOVE:
@ -281,7 +292,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
GenericBranch* bra =
static_cast<GenericBranch*>(instruction);
pc = begin_pc + ofs(bra);
mPc = begin_pc + ofs(bra);
continue;
}
break;
@ -290,7 +301,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 < 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -300,7 +311,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 <= 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -310,7 +321,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 == 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -320,7 +331,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 != 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -330,7 +341,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 >= 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -340,7 +351,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 > 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -396,7 +407,8 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
(*registers)[dst(nt)] = JSValue(int32(!(*registers)[src1(nt)].i32));
(*registers)[dst(nt)] =
JSValue(int32(!(*registers)[src1(nt)].i32));
}
break;
@ -409,28 +421,29 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case TRY:
{ // push the catch handler address onto the try stack
Try* tri = static_cast<Try*>(instruction);
activation->catchStack.push_back(new Handler(op1(tri), op2(tri)));
mActivation->catchStack.push_back(new Handler(op1(tri),
op2(tri)));
}
break;
case ENDTRY :
{
Handler *h = activation->catchStack.back();
activation->catchStack.pop_back();
Handler *h = mActivation->catchStack.back();
mActivation->catchStack.pop_back();
delete h;
}
break;
case JSR :
{
subroutineStack.push(++pc);
subroutineStack.push(++mPc);
Jsr* jsr = static_cast<Jsr*>(instruction);
uint32 offset = ofs(jsr);
pc = begin_pc + offset;
mPc = begin_pc + offset;
continue;
}
case RTS :
{
ASSERT(!subroutineStack.empty());
pc = subroutineStack.top();
mPc = subroutineStack.top();
subroutineStack.pop();
continue;
}
@ -441,24 +454,24 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
// increment the program counter.
++pc;
++mPc;
}
catch (JSException x) {
if (mLinkage) {
if (activation->catchStack.empty()) {
if (mActivation->catchStack.empty()) {
Linkage *pLinkage = mLinkage;
for (; pLinkage != NULL; pLinkage = pLinkage->mNext) {
if (!pLinkage->mActivation->catchStack.empty()) {
activation = pLinkage->mActivation;
Handler *h = activation->catchStack.back();
registers = &activation->mRegisters;
mActivation = pLinkage->mActivation;
Handler *h = mActivation->catchStack.back();
registers = &mActivation->mRegisters;
begin_pc = pLinkage->mBasePC;
if (h->catchTarget) {
pc = begin_pc + h->catchTarget->mOffset;
mPc = begin_pc + h->catchTarget->mOffset;
}
else {
ASSERT(h->finallyTarget);
pc = begin_pc + h->finallyTarget->mOffset;
mPc = begin_pc + h->finallyTarget->mOffset;
}
mLinkage = pLinkage;
break;
@ -468,22 +481,34 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
continue;
}
else {
Handler *h = activation->catchStack.back();
Handler *h = mActivation->catchStack.back();
if (h->catchTarget) {
pc = begin_pc + h->catchTarget->mOffset;
mPc = begin_pc + h->catchTarget->mOffset;
}
else {
ASSERT(h->finallyTarget);
pc = begin_pc + h->finallyTarget->mOffset;
mPc = begin_pc + h->finallyTarget->mOffset;
}
continue;
}
}
return x.value;
rv = x.value;
}
}
out:
delete mActivation;
mActivation = 0;
return rv;
} /* interpret */
JSValues &Context::getRegisters()
{
return mActivation->mRegisters;
}
void Context::addListener(Listener* listener)
{
mListeners.push_back(listener);
@ -493,7 +518,8 @@ typedef std::vector<Context::Listener*>::iterator ListenerIterator;
void Context::removeListener(Listener* listener)
{
for (ListenerIterator i = mListeners.begin(), e = mListeners.end(); i != e; ++i) {
for (ListenerIterator i = mListeners.begin(), e = mListeners.end();
i != e; ++i) {
if (*i == listener) {
mListeners.erase(i);
break;
@ -501,11 +527,12 @@ void Context::removeListener(Listener* listener)
}
}
void Context::broadcast(InstructionIterator pc, JSValues* registers, ICodeModule* iCode)
void Context::broadcast(InterpretStage Stage)
{
for (ListenerIterator i = mListeners.begin(), e = mListeners.end(); i != e; ++i) {
for (ListenerIterator i = mListeners.begin(), e = mListeners.end();
i != e; ++i) {
Listener* listener = *i;
listener->listen(this, pc, registers, iCode);
listener->listen(this, Stage);
}
}

Просмотреть файл

@ -22,6 +22,7 @@
#include "utilities.h"
#include "jstypes.h"
#include "vmtypes.h"
#include "icodegenerator.h"
#include "gc_allocator.h"
@ -31,14 +32,20 @@ namespace Interpreter {
using namespace ICG;
using namespace JSTypes;
struct Activation;
enum InterpretStage {
STEP,
CATCH,
TRAP
};
struct Linkage;
class Context : public gc_base {
public:
explicit Context(World& world, JSNamespace* aGlobal)
: mWorld(world), mGlobal(aGlobal), mLinkage(0)
{
}
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0) {}
JSNamespace* getGlobalObject() { return mGlobal; }
@ -49,9 +56,21 @@ namespace Interpreter {
return t;
}
InstructionIterator getPC()
{
return mPc;
}
JSValues &getRegisters();
ICodeModule *getICode()
{
return mICode;
}
class Listener {
public:
virtual void listen(Context* context, InstructionIterator pc, JSValues* registers, ICodeModule* iCode) = 0;
virtual void listen(Context *context, InterpretStage Stage) = 0;
};
void addListener(Listener* listener);
@ -60,7 +79,8 @@ namespace Interpreter {
class Frame {
public:
virtual Frame* getNext() = 0;
virtual void getState(InstructionIterator& pc, JSValues*& registers, ICodeModule*& iCode) = 0;
virtual void getState(InstructionIterator& pc, JSValues*& registers,
ICodeModule*& iCode) = 0;
};
Frame* getFrames();
@ -68,13 +88,17 @@ namespace Interpreter {
JSValue interpret(ICodeModule* iCode, const JSValues& args);
private:
void broadcast(InstructionIterator pc, JSValues* registers, ICodeModule* iCode);
void broadcast(InterpretStage Stage);
private:
World& mWorld;
JSNamespace* mGlobal;
Linkage* mLinkage;
std::vector<Listener*> mListeners;
Activation* mActivation;
ICodeModule *mICode;
InstructionIterator mPc;
}; /* class Context */
} /* namespace Interpreter */

Просмотреть файл

@ -28,6 +28,7 @@
#include "interpreter.h"
#include "icodegenerator.h"
#include "debugger.h"
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
#include <SIOUX.h>
@ -79,6 +80,8 @@ static bool promptLine(LineReader &inReader, string &s,
}
JavaScript::World world;
JavaScript::Debugger::Shell jsd(world, JavaScript::stdOut, JavaScript::stdOut);
const bool showTokens = true;
static void readEvalPrint(FILE *in, World &world)
@ -123,27 +126,60 @@ static void readEvalPrint(FILE *in, World &world)
stdOut << '\n';
}
#if 0
class Tracer : public Context::Listener {
void listen(Context* context, InterpretStage stage)
{
static String lastLine (widenCString("\n"));
String line;
ICodeModule *iCode = context->getICode();
InstructionIterator pc = context->getPC();
stdOut << "jsd [pc:";
printFormat (stdOut, "%04X", (pc - iCode->its_iCode->begin()));
stdOut << ", reason:" << (uint)stage << "]> ";
std::getline(cin, line);
if (line.size() == 0)
line = lastLine;
else
{
line.append(widenCString("\n"));
lastLine = line;
}
jsd.doCommand(context, line);
}
};
#else
/**
* Poor man's instruction tracing facility.
*/
class Tracer : public Context::Listener {
typedef InstructionStream::difference_type InstructionOffset;
void listen(Context* /*context*/, InstructionIterator pc,
JSValues* registers, ICodeModule* iCode)
void listen(Context* context, InterpretStage /*stage*/)
{
ICodeModule *iCode = context->getICode();
JSValues &registers = context->getRegisters();
InstructionIterator pc = context->getPC();
InstructionOffset offset = (pc - iCode->its_iCode->begin());
printFormat(stdOut, "%04X: ", offset);
Instruction* i = *pc;
stdOut << *i;
if (i->op() != BRANCH && i->count() > 0) {
stdOut << " [";
i->printOperands(stdOut, *registers);
i->printOperands(stdOut, registers);
stdOut << "]\n";
} else {
stdOut << '\n';
}
}
};
#endif
static void testICG(World &world)
{
@ -553,15 +589,17 @@ int main(int argc, char **argv)
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
#endif
JavaScript::World world;
#if 1
assert(JavaScript::Shell::testFactorial(world, 5) == 120);
assert(JavaScript::Shell::testObjects(world, 5) == 5);
assert(JavaScript::Shell::testProto(world, 5) == 5);
using namespace JavaScript::Shell;
assert(testFactorial(world, 5) == 120);
assert(testObjects(world, 5) == 5);
assert(testProto(world, 5) == 5);
// JavaScript::Shell::testICG(world);
assert(JavaScript::Shell::testFunctionCall(world, 5) == 5);
assert(testFunctionCall(world, 5) == 5);
#endif
JavaScript::Shell::readEvalPrint(stdin, world);
readEvalPrint(stdin, world);
return 0;
// return ProcessArgs(argv + 1, argc - 1);
}

Просмотреть файл

@ -202,9 +202,9 @@ namespace VM {
typedef std::vector<Label *> LabelList;
typedef LabelList::iterator LabelIterator;
/********************************************************************/
/* 1, 2 and 3 operand opcode templates */
template <typename Operand1>

Просмотреть файл

@ -11,7 +11,8 @@ objs = hash.o \
parser.o \
utilities.o \
world.o \
vmtypes.o
vmtypes.o \
debugger.o
gc_path = ../../gc/boehm/

151
js2/src/debugger.cpp Normal file
Просмотреть файл

@ -0,0 +1,151 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* 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 oqr
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the JavaScript 2 Prototype.
*
* 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):
*
* Alternatively, the contents of this file may be used under the
* terms of the GNU Public License (the "GPL"), in which case the
* provisions of the GPL are applicable instead of those above.
* If you wish to allow use of your version of this file only
* under the terms of the GPL and not to allow others to use your
* version of this file under the NPL, indicate your decision by
* deleting the provisions above and replace them with the notice
* and other provisions required by the GPL. If you do not delete
* the provisions above, a recipient may use your version of this
* file under either the NPL or the GPL.
*/
#include "world.h"
#include "debugger.h"
#include <string>
#include <ctype.h>
#include <assert.h>
namespace JavaScript {
namespace Debugger {
enum ShellCommand {
ASSEMBLE,
DISSASSEMBLE,
STEP,
PRINT,
PRINT2,
EXIT,
COMMAND_COUNT
};
static const char *shell_cmd_names[] = {
"assemble",
"dissassemble",
"step",
"print",
"print2",
"exit",
0
};
/* return true if str2 starts with/is str1
* XXX ignore case */
bool
startsWith (const String &str1, const String &str2)
{
uint n;
size_t m = str1.size();
if (m > str2.size())
return false;
for (n = 0; n < m; ++n)
if (str1[n] != str2[n])
return false;
return true;
}
bool
Shell::doCommand (Interpreter::Context */*context*/, const String &source)
{
Lexer lex (mWorld, source, widenCString("debugger console"), 0);
const String *cmd;
ShellCommand match = COMMAND_COUNT;
int ambig_matches = 0;
const Token &t = lex.get(true);
if (t.hasKind(Token::identifier))
cmd = &(t.getIdentifier());
else
{
mErr << "you idiot.\n";
return false;
}
for (int i = ASSEMBLE; i < COMMAND_COUNT; ++i)
{
String possibleMatch (widenCString(shell_cmd_names[i]));
if (startsWith(*cmd, possibleMatch))
{
if (cmd->size() == possibleMatch.size())
{
/* exact match */
ambig_matches = 0;
match = (ShellCommand)i;
break;
}
else if (match == COMMAND_COUNT) /* no match yet */
match = (ShellCommand)i;
else
++ambig_matches; /* something already matched,
* ambiguous command */
}
}
if (ambig_matches == 0)
switch (match)
{
case COMMAND_COUNT:
mErr << "Unknown command '" << *cmd << "'.\n";
break;
case ASSEMBLE:
case DISSASSEMBLE:
case STEP:
case PRINT:
default:
mErr << "Input '" << *cmd << "' matched command '" <<
shell_cmd_names[match] << "'.\n";
break;
}
else
mErr << "Ambiguous command '" << *cmd << "', " <<
(uint)(ambig_matches + 1) << " similar commands.\n";
return (ambig_matches == 0);
}
} /* namespace Debugger */
} /* namespace JavaScript */

Просмотреть файл

@ -33,9 +33,29 @@
/* this is all vapor, don't take it to serious yet */
#ifndef debugger_h
#define debugger_h
#include "utilities.h"
#include "interpreter.h"
namespace JavaScript {
namespace Debugger {
class Shell {
public:
Shell (World &aWorld, Formatter &aOut, Formatter &aErr) :
mWorld(aWorld), mOut(aOut), mErr(aErr) {}
bool doCommand (Interpreter::Context *context,
const String &aSource);
private:
World &mWorld;
Formatter &mOut, &mErr;
};
#if 0
typedef void (debuggerCallback) (Context *aContext, ICodeDebugger *aICD);
class Breakpoint {
@ -78,6 +98,9 @@ namespace Debugger {
KILL
};
/**
* tell the debugger what to do when the debuggerCallback returns
*/
void setNextAction (DebuggerAction aAction);
/**
@ -105,6 +128,9 @@ namespace Debugger {
}; /* class ICodeDebugger */
#endif /* 0 */
} /* namespace Debugger */
} /* namespace JavaScript */
#endif /* debugger_h */

Просмотреть файл

@ -66,7 +66,7 @@ namespace ICG {
iCode = new InstructionStream();
if (hasTryStatement)
exceptionRegister = allocateVariable(world->identifiers[widenCString("__exceptionObject__")]);
for (int i = 0; i < switchStatementNesting; i++) {
for (uint i = 0; i < switchStatementNesting; i++) {
String s = widenCString("__switchControlVariable__");
char num[8];
sprintf(num, "%.2d", i);

Просмотреть файл

@ -33,7 +33,6 @@
#include "interpreter.h"
#include "world.h"
#include "vmtypes.h"
namespace JavaScript {
namespace JSTypes {
@ -126,9 +125,9 @@ struct Linkage : public Context::Frame, public gc_base {
{
}
Context::Frame* getNext() { return mNext; }
Context::Frame* getNext() { return mNext; }
void getState(InstructionIterator& pc, JSValues*& registers, ICodeModule*& iCode)
void getState(InstructionIterator& pc, JSValues*& registers, ICodeModule*& iCode)
{
pc = mReturnPC;
registers = &mActivation->mRegisters;
@ -138,34 +137,38 @@ struct Linkage : public Context::Frame, public gc_base {
JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
// initial activation.
Activation* activation = new Activation(iCode, args);
JSValues* registers = &activation->mRegisters;
assert(mActivation == 0); /* recursion == bad */
JSValue rv;
mActivation = new Activation(iCode, args);
JSValues* registers = &mActivation->mRegisters;
mICode = iCode;
InstructionIterator begin_pc = iCode->its_iCode->begin();
InstructionIterator pc = begin_pc;
mPc = begin_pc;
// stack of all catch/finally handlers available for the current activation
std::stack<InstructionIterator> subroutineStack; // to implement jsr/rts for finally code
// to implement jsr/rts for finally code
std::stack<InstructionIterator> subroutineStack;
while (true) {
try {
// tell any listeners about the current execution state.
// XXX should only do this if we're single stepping/tracing.
if (mListeners.size()) {
broadcast(pc, registers, activation->mICode);
}
Instruction* instruction = *pc;
if (mListeners.size())
broadcast(STEP);
Instruction* instruction = *mPc;
switch (instruction->op()) {
case CALL:
{
Call* call = static_cast<Call*>(instruction);
mLinkage = new Linkage(mLinkage, ++pc, begin_pc, activation,
op1(call));
ICodeModule* target =
(*registers)[op2(call)].function->getICode();
activation = new Activation(target, activation, op3(call));
registers = &activation->mRegisters;
begin_pc = pc = target->its_iCode->begin();
mLinkage = new Linkage(mLinkage, ++mPc, begin_pc,
mActivation, op1(call));
mICode = (*registers)[op2(call)].function->getICode();
mActivation = new Activation(mICode, mActivation, op3(call));
registers = &mActivation->mRegisters;
begin_pc = mPc = mICode->its_iCode->begin();
}
continue;
@ -174,13 +177,17 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSValue result;
Linkage *linkage = mLinkage;
if (!linkage)
return result;
{
rv = result;
goto out;
}
mLinkage = linkage->mNext;
activation = linkage->mActivation;
registers = &activation->mRegisters;
mActivation = linkage->mActivation;
registers = &mActivation->mRegisters;
(*registers)[linkage->mResult] = result;
pc = linkage->mReturnPC;
mPc = linkage->mReturnPC;
begin_pc = linkage->mBasePC;
mICode = mActivation->mICode;
}
continue;
@ -192,13 +199,17 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
result = (*registers)[op1(ret)];
Linkage* linkage = mLinkage;
if (!linkage)
return result;
{
rv = result;
goto out;
}
mLinkage = linkage->mNext;
activation = linkage->mActivation;
registers = &activation->mRegisters;
mActivation = linkage->mActivation;
registers = &mActivation->mRegisters;
(*registers)[linkage->mResult] = result;
pc = linkage->mReturnPC;
mPc = linkage->mReturnPC;
begin_pc = linkage->mBasePC;
mICode = mActivation->mICode;
}
continue;
case MOVE:
@ -281,7 +292,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
{
GenericBranch* bra =
static_cast<GenericBranch*>(instruction);
pc = begin_pc + ofs(bra);
mPc = begin_pc + ofs(bra);
continue;
}
break;
@ -290,7 +301,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 < 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -300,7 +311,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 <= 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -310,7 +321,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 == 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -320,7 +331,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 != 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -330,7 +341,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 >= 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -340,7 +351,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 > 0) {
pc = begin_pc + ofs(bc);
mPc = begin_pc + ofs(bc);
continue;
}
}
@ -396,7 +407,8 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
(*registers)[dst(nt)] = JSValue(int32(!(*registers)[src1(nt)].i32));
(*registers)[dst(nt)] =
JSValue(int32(!(*registers)[src1(nt)].i32));
}
break;
@ -409,28 +421,29 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
case TRY:
{ // push the catch handler address onto the try stack
Try* tri = static_cast<Try*>(instruction);
activation->catchStack.push_back(new Handler(op1(tri), op2(tri)));
mActivation->catchStack.push_back(new Handler(op1(tri),
op2(tri)));
}
break;
case ENDTRY :
{
Handler *h = activation->catchStack.back();
activation->catchStack.pop_back();
Handler *h = mActivation->catchStack.back();
mActivation->catchStack.pop_back();
delete h;
}
break;
case JSR :
{
subroutineStack.push(++pc);
subroutineStack.push(++mPc);
Jsr* jsr = static_cast<Jsr*>(instruction);
uint32 offset = ofs(jsr);
pc = begin_pc + offset;
mPc = begin_pc + offset;
continue;
}
case RTS :
{
ASSERT(!subroutineStack.empty());
pc = subroutineStack.top();
mPc = subroutineStack.top();
subroutineStack.pop();
continue;
}
@ -441,24 +454,24 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
// increment the program counter.
++pc;
++mPc;
}
catch (JSException x) {
if (mLinkage) {
if (activation->catchStack.empty()) {
if (mActivation->catchStack.empty()) {
Linkage *pLinkage = mLinkage;
for (; pLinkage != NULL; pLinkage = pLinkage->mNext) {
if (!pLinkage->mActivation->catchStack.empty()) {
activation = pLinkage->mActivation;
Handler *h = activation->catchStack.back();
registers = &activation->mRegisters;
mActivation = pLinkage->mActivation;
Handler *h = mActivation->catchStack.back();
registers = &mActivation->mRegisters;
begin_pc = pLinkage->mBasePC;
if (h->catchTarget) {
pc = begin_pc + h->catchTarget->mOffset;
mPc = begin_pc + h->catchTarget->mOffset;
}
else {
ASSERT(h->finallyTarget);
pc = begin_pc + h->finallyTarget->mOffset;
mPc = begin_pc + h->finallyTarget->mOffset;
}
mLinkage = pLinkage;
break;
@ -468,22 +481,34 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
continue;
}
else {
Handler *h = activation->catchStack.back();
Handler *h = mActivation->catchStack.back();
if (h->catchTarget) {
pc = begin_pc + h->catchTarget->mOffset;
mPc = begin_pc + h->catchTarget->mOffset;
}
else {
ASSERT(h->finallyTarget);
pc = begin_pc + h->finallyTarget->mOffset;
mPc = begin_pc + h->finallyTarget->mOffset;
}
continue;
}
}
return x.value;
rv = x.value;
}
}
out:
delete mActivation;
mActivation = 0;
return rv;
} /* interpret */
JSValues &Context::getRegisters()
{
return mActivation->mRegisters;
}
void Context::addListener(Listener* listener)
{
mListeners.push_back(listener);
@ -493,7 +518,8 @@ typedef std::vector<Context::Listener*>::iterator ListenerIterator;
void Context::removeListener(Listener* listener)
{
for (ListenerIterator i = mListeners.begin(), e = mListeners.end(); i != e; ++i) {
for (ListenerIterator i = mListeners.begin(), e = mListeners.end();
i != e; ++i) {
if (*i == listener) {
mListeners.erase(i);
break;
@ -501,11 +527,12 @@ void Context::removeListener(Listener* listener)
}
}
void Context::broadcast(InstructionIterator pc, JSValues* registers, ICodeModule* iCode)
void Context::broadcast(InterpretStage Stage)
{
for (ListenerIterator i = mListeners.begin(), e = mListeners.end(); i != e; ++i) {
for (ListenerIterator i = mListeners.begin(), e = mListeners.end();
i != e; ++i) {
Listener* listener = *i;
listener->listen(this, pc, registers, iCode);
listener->listen(this, Stage);
}
}

Просмотреть файл

@ -22,6 +22,7 @@
#include "utilities.h"
#include "jstypes.h"
#include "vmtypes.h"
#include "icodegenerator.h"
#include "gc_allocator.h"
@ -31,14 +32,20 @@ namespace Interpreter {
using namespace ICG;
using namespace JSTypes;
struct Activation;
enum InterpretStage {
STEP,
CATCH,
TRAP
};
struct Linkage;
class Context : public gc_base {
public:
explicit Context(World& world, JSNamespace* aGlobal)
: mWorld(world), mGlobal(aGlobal), mLinkage(0)
{
}
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0) {}
JSNamespace* getGlobalObject() { return mGlobal; }
@ -49,9 +56,21 @@ namespace Interpreter {
return t;
}
InstructionIterator getPC()
{
return mPc;
}
JSValues &getRegisters();
ICodeModule *getICode()
{
return mICode;
}
class Listener {
public:
virtual void listen(Context* context, InstructionIterator pc, JSValues* registers, ICodeModule* iCode) = 0;
virtual void listen(Context *context, InterpretStage Stage) = 0;
};
void addListener(Listener* listener);
@ -60,7 +79,8 @@ namespace Interpreter {
class Frame {
public:
virtual Frame* getNext() = 0;
virtual void getState(InstructionIterator& pc, JSValues*& registers, ICodeModule*& iCode) = 0;
virtual void getState(InstructionIterator& pc, JSValues*& registers,
ICodeModule*& iCode) = 0;
};
Frame* getFrames();
@ -68,13 +88,17 @@ namespace Interpreter {
JSValue interpret(ICodeModule* iCode, const JSValues& args);
private:
void broadcast(InstructionIterator pc, JSValues* registers, ICodeModule* iCode);
void broadcast(InterpretStage Stage);
private:
World& mWorld;
JSNamespace* mGlobal;
Linkage* mLinkage;
std::vector<Listener*> mListeners;
Activation* mActivation;
ICodeModule *mICode;
InstructionIterator mPc;
}; /* class Context */
} /* namespace Interpreter */

Просмотреть файл

@ -202,9 +202,9 @@ namespace VM {
typedef std::vector<Label *> LabelList;
typedef LabelList::iterator LabelIterator;
/********************************************************************/
/* 1, 2 and 3 operand opcode templates */
template <typename Operand1>

Просмотреть файл

@ -28,6 +28,7 @@
#include "interpreter.h"
#include "icodegenerator.h"
#include "debugger.h"
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
#include <SIOUX.h>
@ -79,6 +80,8 @@ static bool promptLine(LineReader &inReader, string &s,
}
JavaScript::World world;
JavaScript::Debugger::Shell jsd(world, JavaScript::stdOut, JavaScript::stdOut);
const bool showTokens = true;
static void readEvalPrint(FILE *in, World &world)
@ -123,27 +126,60 @@ static void readEvalPrint(FILE *in, World &world)
stdOut << '\n';
}
#if 0
class Tracer : public Context::Listener {
void listen(Context* context, InterpretStage stage)
{
static String lastLine (widenCString("\n"));
String line;
ICodeModule *iCode = context->getICode();
InstructionIterator pc = context->getPC();
stdOut << "jsd [pc:";
printFormat (stdOut, "%04X", (pc - iCode->its_iCode->begin()));
stdOut << ", reason:" << (uint)stage << "]> ";
std::getline(cin, line);
if (line.size() == 0)
line = lastLine;
else
{
line.append(widenCString("\n"));
lastLine = line;
}
jsd.doCommand(context, line);
}
};
#else
/**
* Poor man's instruction tracing facility.
*/
class Tracer : public Context::Listener {
typedef InstructionStream::difference_type InstructionOffset;
void listen(Context* /*context*/, InstructionIterator pc,
JSValues* registers, ICodeModule* iCode)
void listen(Context* context, InterpretStage /*stage*/)
{
ICodeModule *iCode = context->getICode();
JSValues &registers = context->getRegisters();
InstructionIterator pc = context->getPC();
InstructionOffset offset = (pc - iCode->its_iCode->begin());
printFormat(stdOut, "%04X: ", offset);
Instruction* i = *pc;
stdOut << *i;
if (i->op() != BRANCH && i->count() > 0) {
stdOut << " [";
i->printOperands(stdOut, *registers);
i->printOperands(stdOut, registers);
stdOut << "]\n";
} else {
stdOut << '\n';
}
}
};
#endif
static void testICG(World &world)
{
@ -553,15 +589,17 @@ int main(int argc, char **argv)
#if defined(XP_MAC) && !defined(XP_MAC_MPW)
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
#endif
JavaScript::World world;
#if 1
assert(JavaScript::Shell::testFactorial(world, 5) == 120);
assert(JavaScript::Shell::testObjects(world, 5) == 5);
assert(JavaScript::Shell::testProto(world, 5) == 5);
using namespace JavaScript::Shell;
assert(testFactorial(world, 5) == 120);
assert(testObjects(world, 5) == 5);
assert(testProto(world, 5) == 5);
// JavaScript::Shell::testICG(world);
assert(JavaScript::Shell::testFunctionCall(world, 5) == 5);
assert(testFunctionCall(world, 5) == 5);
#endif
JavaScript::Shell::readEvalPrint(stdin, world);
readEvalPrint(stdin, world);
return 0;
// return ProcessArgs(argv + 1, argc - 1);
}