From 0deba46ad9f320ef09102b7c187152ae27d8c948 Mon Sep 17 00:00:00 2001 From: "rginda%netscape.com" Date: Fri, 23 Jun 2000 22:27:17 +0000 Subject: [PATCH] Added debugger opcode, change InstructionMap to a std::map, print source lines while tracing git-svn-id: svn://10.0.0.236/trunk@73101 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js/js2/debugger.cpp | 66 +++++++++++++++++++++++++---- mozilla/js/js2/debugger.h | 22 ++++++++-- mozilla/js/js2/icodegenerator.cpp | 22 ++++++++-- mozilla/js/js2/icodegenerator.h | 18 +++++--- mozilla/js/js2/interpreter.cpp | 7 +++ mozilla/js/js2/interpreter.h | 2 +- mozilla/js/js2/js2.cpp | 64 ++++++++++++++++++++++------ mozilla/js/js2/tools/gencode.pl | 5 +++ mozilla/js/js2/vmtypes.h | 17 ++++++++ mozilla/js2/src/debugger.cpp | 66 +++++++++++++++++++++++++---- mozilla/js2/src/debugger.h | 22 ++++++++-- mozilla/js2/src/icodegenerator.cpp | 22 ++++++++-- mozilla/js2/src/icodegenerator.h | 18 +++++--- mozilla/js2/src/interpreter.cpp | 7 +++ mozilla/js2/src/interpreter.h | 2 +- mozilla/js2/src/vmtypes.h | 17 ++++++++ mozilla/js2/tests/cpp/js2_shell.cpp | 64 ++++++++++++++++++++++------ mozilla/js2/tools/gencode.pl | 5 +++ 18 files changed, 374 insertions(+), 72 deletions(-) diff --git a/mozilla/js/js2/debugger.cpp b/mozilla/js/js2/debugger.cpp index fb534b65d7e..1028e3e769b 100644 --- a/mozilla/js/js2/debugger.cpp +++ b/mozilla/js/js2/debugger.cpp @@ -153,23 +153,68 @@ registers, or set the value of a single register."}, shell_cmds[i][2] << "\n"; } - static void - showCurrentOp(Context* cx, Formatter &aOut) + void + Shell::showSourceAtPC (Context *cx, InstructionIterator pc) + { + if (!mResolveFileCallback) + { + mErr << + "Source not available. (Debugger not properly initialized.)\n"; + return; + } + + ICodeModule *iCode = cx->getICode(); + + String fn = iCode->getFileName(); + const Reader *reader = mResolveFileCallback(fn); + if (!reader) + { + mErr << "Source not available.\n"; + return; + } + + InstructionMap::iterator pos_iter = + iCode->mInstructionMap->find (pc - iCode->its_iCode->begin()); + if (pos_iter == iCode->mInstructionMap->end()) + { + mErr << "Can't find that PC in the map.\n"; + return; + } + + uint32 lineNum = reader->posToLineNum (pos_iter->second); + const char16 *lineBegin, *lineEnd; + + reader->getLine (lineNum, lineBegin, lineEnd); + String sourceLine (lineBegin, lineEnd); + + mOut << fn << ":" << lineNum << " " << sourceLine << "\n"; + + } + + void + Shell::showOpAtPC(Context* cx, InstructionIterator pc) { ICodeModule *iCode = cx->getICode(); - JSValues ®isters = cx->getRegisters(); - InstructionIterator pc = cx->getPC(); - printFormat(aOut, "trace [%02u:%04u]: ", + if ((pc < iCode->its_iCode->begin()) || + (pc >= iCode->its_iCode->end())) + { + mErr << "PC Out Of Range."; + return; + } + + JSValues ®isters = cx->getRegisters(); + + printFormat(mOut, "trace [%02u:%04u]: ", iCode->mID, (pc - iCode->its_iCode->begin())); Instruction* i = *pc; stdOut << *i; if (i->op() != BRANCH && i->count() > 0) { - aOut << " ["; + mOut << " ["; i->printOperands(stdOut, registers); - aOut << "]\n"; + mOut << "]\n"; } else { - aOut << '\n'; + mOut << '\n'; } } @@ -178,7 +223,10 @@ registers, or set the value of a single register."}, { if (mTraceFlag) - showCurrentOp (cx, mOut); + { + showSourceAtPC (cx, cx->getPC()); + showOpAtPC (cx, cx->getPC()); + } if (!(mStopMask & event)) return; diff --git a/mozilla/js/js2/debugger.h b/mozilla/js/js2/debugger.h index 142e0a2551b..fc71d9d3ebd 100644 --- a/mozilla/js/js2/debugger.h +++ b/mozilla/js/js2/debugger.h @@ -46,6 +46,8 @@ namespace Debugger { using namespace Interpreter; + typedef const Reader *ResolveFileCallback (const String &fileName); + class Breakpoint { public: /* representation of a breakpoint */ @@ -114,9 +116,11 @@ namespace Debugger { class Shell : public Context::Listener { public: - Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr) : + Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr, + ResolveFileCallback *aCallback = 0) : mWorld(aWorld), mIn(aIn), mOut(aOut), mErr(aErr), - mStopMask(Context::EV_ALL), mTraceFlag(true) + mResolveFileCallback(aCallback), mStopMask(Context::EV_DEBUG), + mTraceFlag(true) { mDebugger = new ICodeDebugger(); } @@ -126,6 +130,14 @@ namespace Debugger { delete mDebugger; } + ResolveFileCallback + *setResolveFileCallback (ResolveFileCallback *aCallback) + { + ResolveFileCallback *rv = mResolveFileCallback; + mResolveFileCallback = aCallback; + return rv; + } + void listen(Context *context, Context::Event event); /** @@ -147,13 +159,17 @@ namespace Debugger { } private: - bool doCommand (Context *context, const String &aSource); + bool doCommand (Context *cx, const String &aSource); void doSetVariable (Lexer &lex); void doPrint (Context *cx, Lexer &lex); + + void showOpAtPC(Context* cx, InstructionIterator pc); + void showSourceAtPC(Context* cx, InstructionIterator pc); World &mWorld; FILE *mIn; Formatter &mOut, &mErr; + ResolveFileCallback *mResolveFileCallback; ICodeDebugger *mDebugger; uint32 mStopMask; bool mTraceFlag; diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 060fdde354e..88ae8f5eb0b 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -1211,7 +1211,12 @@ void ICodeGenerator::preprocess(StmtNode *p) genStmt(t->finally); } break; + + default: + break; + } + } TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) @@ -1280,6 +1285,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) hasMethods = true; } break; + default: + break; } s = s->next; } @@ -1347,6 +1354,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) throwStmt(genExpr(e->expr)); } break; + case StmtNode::Debugger: + { + debuggerStmt(); + } + break; case StmtNode::Return: { ExprStmtNode *e = static_cast(p); @@ -1590,7 +1602,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) invoke the finally handler on the (exceptional) way out of the try block assuming there are no catch clauses. */ - Register ex = NotARegister; + /*Register ex = NotARegister;*/ TryStmtNode *t = static_cast(p); Label *catchLabel = (t->catches) ? getLabel() : NULL; Label *finallyInvoker = (t->finally) ? getLabel() : NULL; @@ -1629,6 +1641,10 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } break; + case StmtNode::empty: + /* nada */ + break; + default: NOT_REACHED("unimplemented statement kind"); } @@ -1647,9 +1663,9 @@ Formatter& ICodeGenerator::print(Formatter& f) f << " Src : Instr" << "\n"; for (InstructionMap::iterator i = mInstructionMap->begin(); i != mInstructionMap->end(); i++) { - printDec( f, (*i)->first, 6); + printDec( f, (*i).first, 6); f << " : "; - printDec( f, (*i)->second, 6); + printDec( f, (*i).second, 6); f << "\n"; // f << (*i)->first << " : " << (*i)->second << "\n"; } diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index f26a2ebcc16..2f74822ef13 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -49,14 +49,14 @@ namespace ICG { using namespace JSTypes; typedef std::map > VariableList; - typedef std::pair InstructionMapping; - typedef std::vector InstructionMap; + typedef std::map > InstructionMap; class ICodeModule { public: ICodeModule(InstructionStream *iCode, VariableList *variables, - uint32 maxRegister, uint32 maxParameter, InstructionMap *instructionMap) : + uint32 maxRegister, uint32 maxParameter, + InstructionMap *instructionMap) : its_iCode(iCode), itsVariables(variables), itsParameterCount(maxParameter), itsMaxRegister(maxRegister), mID(++sMaxID), mInstructionMap(instructionMap) { } @@ -68,6 +68,8 @@ namespace ICG { } Formatter& print(Formatter& f); + void setFileName (String aFileName) { mFileName = aFileName; } + String getFileName () { return mFileName; } InstructionStream *its_iCode; VariableList *itsVariables; @@ -75,6 +77,7 @@ namespace ICG { uint32 itsMaxRegister; uint32 mID; InstructionMap *mInstructionMap; + String mFileName; static uint32 sMaxID; @@ -122,7 +125,8 @@ namespace ICG { World *mWorld; // used to register strings JSScope *mGlobal; // the scope for compiling within LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct - InstructionMap *mInstructionMap;// maps source position to instruction index + // maps source position to instruction index + InstructionMap *mInstructionMap; bool mWithinWith; // state from genStmt that indicates generating code beneath a with statement @@ -162,8 +166,8 @@ namespace ICG { void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; } - - void startStatement(uint32 pos) { mInstructionMap->push_back(new InstructionMapping(pos, iCode->size())); } + void startStatement(uint32 pos) + { (*mInstructionMap)[iCode->size()] = pos; } ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind); @@ -203,6 +207,8 @@ namespace ICG { void returnStmt(); void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); } + void debuggerStmt() + { iCode->push_back(new Debugger()); } TypedRegister allocateVariable(const StringAtom& name); TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName); diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index 109c275aa26..11784065155 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -910,6 +910,12 @@ using JSString throughout. mGlobal = mGlobal->getParent(); } break; + case DEBUGGER: + { + if (mListeners.size()) + broadcast(EV_DEBUG); + break; + } default: NOT_REACHED("bad opcode"); break; @@ -955,6 +961,7 @@ using JSString throughout. } rv = x.value; } + } return rv; diff --git a/mozilla/js/js2/interpreter.h b/mozilla/js/js2/interpreter.h index b8b549cbd43..ba250f7f291 100644 --- a/mozilla/js/js2/interpreter.h +++ b/mozilla/js/js2/interpreter.h @@ -53,7 +53,7 @@ namespace Interpreter { EV_NONE = 0x0000, EV_STEP = 0x0001, EV_THROW = 0x0002, - EV_TRAP = 0x0004, + EV_DEBUG = 0x0004, EV_ALL = 0xffff }; diff --git a/mozilla/js/js2/js2.cpp b/mozilla/js/js2/js2.cpp index f26823ef529..06a3df2d667 100644 --- a/mozilla/js/js2/js2.cpp +++ b/mozilla/js/js2/js2.cpp @@ -22,13 +22,23 @@ // JS2 shell. // +#if 0 +#define DEBUGGER_FOO +#define INTERPRET_INPUT +#else +#undef DEBUGGER_FOO +#undef INTERPRET_INPUT +#endif + #include #include "world.h" #include "interpreter.h" #include "icodegenerator.h" +#ifdef DEBUGGER_FOO #include "debugger.h" +#endif #if defined(XP_MAC) && !defined(XP_MAC_MPW) #include @@ -80,16 +90,30 @@ static bool promptLine(LineReader &inReader, string &s, const char *prompt) JavaScript::World world; -JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut, - JavaScript::stdOut); - +/* "filename" of the console */ +const String ConsoleName = widenCString(""); const bool showTokens = false; +#ifdef DEBUGGER_FOO +Reader *sourceReader; /* Reader for console file */ + +static +const Reader *ResolveFile (const String& fileName) +{ + if (fileName == ConsoleName) + return sourceReader; + else + return 0; +} + +JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut, + JavaScript::stdOut, &ResolveFile); +#endif static JSValue print(const JSValues &argv) { size_t n = argv.size(); - if (n > 1) { // the 'this' parameter in un-interesting + if (n > 1) { // the 'this' parameter is un-interesting stdOut << argv[1]; for (size_t i = 2; i < n; ++i) stdOut << ' ' << argv[i]; @@ -99,9 +123,10 @@ static JSValue print(const JSValues &argv) } -static void genCode(Context &cx, StmtNode *p) +static void genCode(Context &cx, StmtNode *p, const String &fileName) { ICodeGenerator icg(&cx.getWorld(), cx.getGlobalObject()); + icg.isScript(); TypedRegister ret(NotARegister, &None_Type); while (p) { @@ -110,29 +135,36 @@ static void genCode(Context &cx, StmtNode *p) p = p->next; } icg.returnStmt(ret); -// stdOut << '\n'; -// stdOut << icg; - JSValue result = cx.interpret(icg.complete(), JSValues()); + + ICodeModule *icm = icg.complete(); + icm->setFileName (fileName); + + JSValue result = cx.interpret(icm, JSValues()); stdOut << "result = " << result << "\n"; + + delete icm; + } static void readEvalPrint(FILE *in, World &world) { JSScope glob; Context cx(world, &glob); +#ifdef DEBUGGER_FOO + jsd.attachToContext (&cx); +#endif StringAtom& printName = world.identifiers[widenCString("print")]; glob.defineNativeFunction(printName, print); String buffer; string line; - String sourceLocation = widenCString("console"); LineReader inReader(in); while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) { appendChars(buffer, line.data(), line.size()); try { Arena a; - Parser p(world, a, buffer, sourceLocation); + Parser p(world, a, buffer, ConsoleName); if (showTokens) { Lexer &l = p.lexer; @@ -158,9 +190,13 @@ static void readEvalPrint(FILE *in, World &world) f.end(); } stdOut << '\n'; -#if 0 - // Generate code for parsedStatements, which is a linked list of zero or more statements - genCode(cx, parsedStatements); +#ifdef INTERPRET_INPUT +#ifdef DEBUGGER_FOO + sourceReader = &(p.lexer.reader); +#endif + // Generate code for parsedStatements, which is a linked + // list of zero or more statements + genCode(cx, parsedStatements, ConsoleName); #endif } clear(buffer); @@ -170,7 +206,7 @@ static void readEvalPrint(FILE *in, World &world) * of input rather than printing the error message. */ if (!(e.hasKind(Exception::syntaxError) && e.lineNum && e.pos == buffer.size() && - e.sourceFile == sourceLocation)) { + e.sourceFile == ConsoleName)) { stdOut << '\n' << e.fullMessage(); clear(buffer); } diff --git a/mozilla/js/js2/tools/gencode.pl b/mozilla/js/js2/tools/gencode.pl index 0ab8cf64708..02b9cdc302e 100644 --- a/mozilla/js/js2/tools/gencode.pl +++ b/mozilla/js/js2/tools/gencode.pl @@ -73,6 +73,11 @@ $ops{"NOP"} = super => "Instruction", rem => "do nothing and like it", }; +$ops{"DEBUGGER"} = + { + super => "Instruction", + rem => "drop to the debugger", + }; $ops{"MOVE"} = { super => "Instruction_2", diff --git a/mozilla/js/js2/vmtypes.h b/mozilla/js/js2/vmtypes.h index d354dda1898..168c7cbc7ce 100644 --- a/mozilla/js/js2/vmtypes.h +++ b/mozilla/js/js2/vmtypes.h @@ -66,6 +66,7 @@ namespace VM { COMPARE_LE, /* dest, source1, source2 */ COMPARE_LT, /* dest, source1, source2 */ COMPARE_NE, /* dest, source1, source2 */ + DEBUGGER, /* drop to the debugger */ DIVIDE, /* dest, source1, source2 */ ELEM_XCR, /* dest, base, index, value */ FUNCTION, /* Defines a function */ @@ -130,6 +131,7 @@ namespace VM { "COMPARE_LE ", "COMPARE_LT ", "COMPARE_NE ", + "DEBUGGER ", "DIVIDE ", "ELEM_XCR ", "FUNCTION ", @@ -555,6 +557,21 @@ namespace VM { /* print() and printOperands() inherited from Instruction_3 */ }; + class Debugger : public Instruction { + public: + /* drop to the debugger */ + Debugger () : + Instruction + (DEBUGGER) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[DEBUGGER]; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) { + return f; + } + }; + class Divide : public Arithmetic { public: /* dest, source1, source2 */ diff --git a/mozilla/js2/src/debugger.cpp b/mozilla/js2/src/debugger.cpp index fb534b65d7e..1028e3e769b 100644 --- a/mozilla/js2/src/debugger.cpp +++ b/mozilla/js2/src/debugger.cpp @@ -153,23 +153,68 @@ registers, or set the value of a single register."}, shell_cmds[i][2] << "\n"; } - static void - showCurrentOp(Context* cx, Formatter &aOut) + void + Shell::showSourceAtPC (Context *cx, InstructionIterator pc) + { + if (!mResolveFileCallback) + { + mErr << + "Source not available. (Debugger not properly initialized.)\n"; + return; + } + + ICodeModule *iCode = cx->getICode(); + + String fn = iCode->getFileName(); + const Reader *reader = mResolveFileCallback(fn); + if (!reader) + { + mErr << "Source not available.\n"; + return; + } + + InstructionMap::iterator pos_iter = + iCode->mInstructionMap->find (pc - iCode->its_iCode->begin()); + if (pos_iter == iCode->mInstructionMap->end()) + { + mErr << "Can't find that PC in the map.\n"; + return; + } + + uint32 lineNum = reader->posToLineNum (pos_iter->second); + const char16 *lineBegin, *lineEnd; + + reader->getLine (lineNum, lineBegin, lineEnd); + String sourceLine (lineBegin, lineEnd); + + mOut << fn << ":" << lineNum << " " << sourceLine << "\n"; + + } + + void + Shell::showOpAtPC(Context* cx, InstructionIterator pc) { ICodeModule *iCode = cx->getICode(); - JSValues ®isters = cx->getRegisters(); - InstructionIterator pc = cx->getPC(); - printFormat(aOut, "trace [%02u:%04u]: ", + if ((pc < iCode->its_iCode->begin()) || + (pc >= iCode->its_iCode->end())) + { + mErr << "PC Out Of Range."; + return; + } + + JSValues ®isters = cx->getRegisters(); + + printFormat(mOut, "trace [%02u:%04u]: ", iCode->mID, (pc - iCode->its_iCode->begin())); Instruction* i = *pc; stdOut << *i; if (i->op() != BRANCH && i->count() > 0) { - aOut << " ["; + mOut << " ["; i->printOperands(stdOut, registers); - aOut << "]\n"; + mOut << "]\n"; } else { - aOut << '\n'; + mOut << '\n'; } } @@ -178,7 +223,10 @@ registers, or set the value of a single register."}, { if (mTraceFlag) - showCurrentOp (cx, mOut); + { + showSourceAtPC (cx, cx->getPC()); + showOpAtPC (cx, cx->getPC()); + } if (!(mStopMask & event)) return; diff --git a/mozilla/js2/src/debugger.h b/mozilla/js2/src/debugger.h index 142e0a2551b..fc71d9d3ebd 100644 --- a/mozilla/js2/src/debugger.h +++ b/mozilla/js2/src/debugger.h @@ -46,6 +46,8 @@ namespace Debugger { using namespace Interpreter; + typedef const Reader *ResolveFileCallback (const String &fileName); + class Breakpoint { public: /* representation of a breakpoint */ @@ -114,9 +116,11 @@ namespace Debugger { class Shell : public Context::Listener { public: - Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr) : + Shell (World &aWorld, FILE *aIn, Formatter &aOut, Formatter &aErr, + ResolveFileCallback *aCallback = 0) : mWorld(aWorld), mIn(aIn), mOut(aOut), mErr(aErr), - mStopMask(Context::EV_ALL), mTraceFlag(true) + mResolveFileCallback(aCallback), mStopMask(Context::EV_DEBUG), + mTraceFlag(true) { mDebugger = new ICodeDebugger(); } @@ -126,6 +130,14 @@ namespace Debugger { delete mDebugger; } + ResolveFileCallback + *setResolveFileCallback (ResolveFileCallback *aCallback) + { + ResolveFileCallback *rv = mResolveFileCallback; + mResolveFileCallback = aCallback; + return rv; + } + void listen(Context *context, Context::Event event); /** @@ -147,13 +159,17 @@ namespace Debugger { } private: - bool doCommand (Context *context, const String &aSource); + bool doCommand (Context *cx, const String &aSource); void doSetVariable (Lexer &lex); void doPrint (Context *cx, Lexer &lex); + + void showOpAtPC(Context* cx, InstructionIterator pc); + void showSourceAtPC(Context* cx, InstructionIterator pc); World &mWorld; FILE *mIn; Formatter &mOut, &mErr; + ResolveFileCallback *mResolveFileCallback; ICodeDebugger *mDebugger; uint32 mStopMask; bool mTraceFlag; diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 060fdde354e..88ae8f5eb0b 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -1211,7 +1211,12 @@ void ICodeGenerator::preprocess(StmtNode *p) genStmt(t->finally); } break; + + default: + break; + } + } TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) @@ -1280,6 +1285,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) hasMethods = true; } break; + default: + break; } s = s->next; } @@ -1347,6 +1354,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) throwStmt(genExpr(e->expr)); } break; + case StmtNode::Debugger: + { + debuggerStmt(); + } + break; case StmtNode::Return: { ExprStmtNode *e = static_cast(p); @@ -1590,7 +1602,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) invoke the finally handler on the (exceptional) way out of the try block assuming there are no catch clauses. */ - Register ex = NotARegister; + /*Register ex = NotARegister;*/ TryStmtNode *t = static_cast(p); Label *catchLabel = (t->catches) ? getLabel() : NULL; Label *finallyInvoker = (t->finally) ? getLabel() : NULL; @@ -1629,6 +1641,10 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } break; + case StmtNode::empty: + /* nada */ + break; + default: NOT_REACHED("unimplemented statement kind"); } @@ -1647,9 +1663,9 @@ Formatter& ICodeGenerator::print(Formatter& f) f << " Src : Instr" << "\n"; for (InstructionMap::iterator i = mInstructionMap->begin(); i != mInstructionMap->end(); i++) { - printDec( f, (*i)->first, 6); + printDec( f, (*i).first, 6); f << " : "; - printDec( f, (*i)->second, 6); + printDec( f, (*i).second, 6); f << "\n"; // f << (*i)->first << " : " << (*i)->second << "\n"; } diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index f26a2ebcc16..2f74822ef13 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -49,14 +49,14 @@ namespace ICG { using namespace JSTypes; typedef std::map > VariableList; - typedef std::pair InstructionMapping; - typedef std::vector InstructionMap; + typedef std::map > InstructionMap; class ICodeModule { public: ICodeModule(InstructionStream *iCode, VariableList *variables, - uint32 maxRegister, uint32 maxParameter, InstructionMap *instructionMap) : + uint32 maxRegister, uint32 maxParameter, + InstructionMap *instructionMap) : its_iCode(iCode), itsVariables(variables), itsParameterCount(maxParameter), itsMaxRegister(maxRegister), mID(++sMaxID), mInstructionMap(instructionMap) { } @@ -68,6 +68,8 @@ namespace ICG { } Formatter& print(Formatter& f); + void setFileName (String aFileName) { mFileName = aFileName; } + String getFileName () { return mFileName; } InstructionStream *its_iCode; VariableList *itsVariables; @@ -75,6 +77,7 @@ namespace ICG { uint32 itsMaxRegister; uint32 mID; InstructionMap *mInstructionMap; + String mFileName; static uint32 sMaxID; @@ -122,7 +125,8 @@ namespace ICG { World *mWorld; // used to register strings JSScope *mGlobal; // the scope for compiling within LabelStack mLabelStack; // stack of LabelEntry objects, one per nested looping construct - InstructionMap *mInstructionMap;// maps source position to instruction index + // maps source position to instruction index + InstructionMap *mInstructionMap; bool mWithinWith; // state from genStmt that indicates generating code beneath a with statement @@ -162,8 +166,8 @@ namespace ICG { void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; } - - void startStatement(uint32 pos) { mInstructionMap->push_back(new InstructionMapping(pos, iCode->size())); } + void startStatement(uint32 pos) + { (*mInstructionMap)[iCode->size()] = pos; } ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind); @@ -203,6 +207,8 @@ namespace ICG { void returnStmt(); void throwStmt(TypedRegister r) { iCode->push_back(new Throw(r)); } + void debuggerStmt() + { iCode->push_back(new Debugger()); } TypedRegister allocateVariable(const StringAtom& name); TypedRegister allocateVariable(const StringAtom& name, const StringAtom& typeName); diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 109c275aa26..11784065155 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -910,6 +910,12 @@ using JSString throughout. mGlobal = mGlobal->getParent(); } break; + case DEBUGGER: + { + if (mListeners.size()) + broadcast(EV_DEBUG); + break; + } default: NOT_REACHED("bad opcode"); break; @@ -955,6 +961,7 @@ using JSString throughout. } rv = x.value; } + } return rv; diff --git a/mozilla/js2/src/interpreter.h b/mozilla/js2/src/interpreter.h index b8b549cbd43..ba250f7f291 100644 --- a/mozilla/js2/src/interpreter.h +++ b/mozilla/js2/src/interpreter.h @@ -53,7 +53,7 @@ namespace Interpreter { EV_NONE = 0x0000, EV_STEP = 0x0001, EV_THROW = 0x0002, - EV_TRAP = 0x0004, + EV_DEBUG = 0x0004, EV_ALL = 0xffff }; diff --git a/mozilla/js2/src/vmtypes.h b/mozilla/js2/src/vmtypes.h index d354dda1898..168c7cbc7ce 100644 --- a/mozilla/js2/src/vmtypes.h +++ b/mozilla/js2/src/vmtypes.h @@ -66,6 +66,7 @@ namespace VM { COMPARE_LE, /* dest, source1, source2 */ COMPARE_LT, /* dest, source1, source2 */ COMPARE_NE, /* dest, source1, source2 */ + DEBUGGER, /* drop to the debugger */ DIVIDE, /* dest, source1, source2 */ ELEM_XCR, /* dest, base, index, value */ FUNCTION, /* Defines a function */ @@ -130,6 +131,7 @@ namespace VM { "COMPARE_LE ", "COMPARE_LT ", "COMPARE_NE ", + "DEBUGGER ", "DIVIDE ", "ELEM_XCR ", "FUNCTION ", @@ -555,6 +557,21 @@ namespace VM { /* print() and printOperands() inherited from Instruction_3 */ }; + class Debugger : public Instruction { + public: + /* drop to the debugger */ + Debugger () : + Instruction + (DEBUGGER) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[DEBUGGER]; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& /*registers*/) { + return f; + } + }; + class Divide : public Arithmetic { public: /* dest, source1, source2 */ diff --git a/mozilla/js2/tests/cpp/js2_shell.cpp b/mozilla/js2/tests/cpp/js2_shell.cpp index f26823ef529..06a3df2d667 100644 --- a/mozilla/js2/tests/cpp/js2_shell.cpp +++ b/mozilla/js2/tests/cpp/js2_shell.cpp @@ -22,13 +22,23 @@ // JS2 shell. // +#if 0 +#define DEBUGGER_FOO +#define INTERPRET_INPUT +#else +#undef DEBUGGER_FOO +#undef INTERPRET_INPUT +#endif + #include #include "world.h" #include "interpreter.h" #include "icodegenerator.h" +#ifdef DEBUGGER_FOO #include "debugger.h" +#endif #if defined(XP_MAC) && !defined(XP_MAC_MPW) #include @@ -80,16 +90,30 @@ static bool promptLine(LineReader &inReader, string &s, const char *prompt) JavaScript::World world; -JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut, - JavaScript::stdOut); - +/* "filename" of the console */ +const String ConsoleName = widenCString(""); const bool showTokens = false; +#ifdef DEBUGGER_FOO +Reader *sourceReader; /* Reader for console file */ + +static +const Reader *ResolveFile (const String& fileName) +{ + if (fileName == ConsoleName) + return sourceReader; + else + return 0; +} + +JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut, + JavaScript::stdOut, &ResolveFile); +#endif static JSValue print(const JSValues &argv) { size_t n = argv.size(); - if (n > 1) { // the 'this' parameter in un-interesting + if (n > 1) { // the 'this' parameter is un-interesting stdOut << argv[1]; for (size_t i = 2; i < n; ++i) stdOut << ' ' << argv[i]; @@ -99,9 +123,10 @@ static JSValue print(const JSValues &argv) } -static void genCode(Context &cx, StmtNode *p) +static void genCode(Context &cx, StmtNode *p, const String &fileName) { ICodeGenerator icg(&cx.getWorld(), cx.getGlobalObject()); + icg.isScript(); TypedRegister ret(NotARegister, &None_Type); while (p) { @@ -110,29 +135,36 @@ static void genCode(Context &cx, StmtNode *p) p = p->next; } icg.returnStmt(ret); -// stdOut << '\n'; -// stdOut << icg; - JSValue result = cx.interpret(icg.complete(), JSValues()); + + ICodeModule *icm = icg.complete(); + icm->setFileName (fileName); + + JSValue result = cx.interpret(icm, JSValues()); stdOut << "result = " << result << "\n"; + + delete icm; + } static void readEvalPrint(FILE *in, World &world) { JSScope glob; Context cx(world, &glob); +#ifdef DEBUGGER_FOO + jsd.attachToContext (&cx); +#endif StringAtom& printName = world.identifiers[widenCString("print")]; glob.defineNativeFunction(printName, print); String buffer; string line; - String sourceLocation = widenCString("console"); LineReader inReader(in); while (promptLine(inReader, line, buffer.empty() ? "js> " : "> ")) { appendChars(buffer, line.data(), line.size()); try { Arena a; - Parser p(world, a, buffer, sourceLocation); + Parser p(world, a, buffer, ConsoleName); if (showTokens) { Lexer &l = p.lexer; @@ -158,9 +190,13 @@ static void readEvalPrint(FILE *in, World &world) f.end(); } stdOut << '\n'; -#if 0 - // Generate code for parsedStatements, which is a linked list of zero or more statements - genCode(cx, parsedStatements); +#ifdef INTERPRET_INPUT +#ifdef DEBUGGER_FOO + sourceReader = &(p.lexer.reader); +#endif + // Generate code for parsedStatements, which is a linked + // list of zero or more statements + genCode(cx, parsedStatements, ConsoleName); #endif } clear(buffer); @@ -170,7 +206,7 @@ static void readEvalPrint(FILE *in, World &world) * of input rather than printing the error message. */ if (!(e.hasKind(Exception::syntaxError) && e.lineNum && e.pos == buffer.size() && - e.sourceFile == sourceLocation)) { + e.sourceFile == ConsoleName)) { stdOut << '\n' << e.fullMessage(); clear(buffer); } diff --git a/mozilla/js2/tools/gencode.pl b/mozilla/js2/tools/gencode.pl index 0ab8cf64708..02b9cdc302e 100644 --- a/mozilla/js2/tools/gencode.pl +++ b/mozilla/js2/tools/gencode.pl @@ -73,6 +73,11 @@ $ops{"NOP"} = super => "Instruction", rem => "do nothing and like it", }; +$ops{"DEBUGGER"} = + { + super => "Instruction", + rem => "drop to the debugger", + }; $ops{"MOVE"} = { super => "Instruction_2",