add m prefix to base and offset label members

interpreter.cpp,h
dual license
wrap interpret in a Context class
add RETURN_VOID case

js2.cpp
update to use context class
remove #if 0 code that'll probably never be used anyway.

jstypes.h
add defineProperty/function to JSObject

vmtypes.h
regerated opcode classes:
  added RETURN_VOID, removed LOAD/SAVE_VAR
  reverted bacl to the smaller print function (thanks to RETURN_VOID)
  fixed branch printing issue
  inherit print() from super if possible

tools/gencode.pl
generate smaller print functions again
don't generate print function if superclass can take care of it.
This commit is contained in:
rginda%netscape.com 2000-04-21 00:04:14 +00:00
Родитель 7cf4cc8527
Коммит 7615ee9226
18 изменённых файлов: 1264 добавлений и 2378 удалений

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

@ -1,3 +1,6 @@
debugger.o: debugger.cpp world.h utilities.h systemtypes.h hash.h \
parser.h interpreter.h jstypes.h gc_allocator.h vmtypes.h numerics.h \
icodegenerator.h
gc_allocator.o: gc_allocator.cpp gc_allocator.h gc_container.h
hash.o: hash.cpp hash.h utilities.h systemtypes.h
icodegenerator.o: icodegenerator.cpp numerics.h utilities.h \

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

@ -61,8 +61,8 @@ namespace ICG {
ASSERT(stitcher.empty());
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
ASSERT((*i)->base == iCode);
ASSERT((*i)->offset <= iCode->size());
ASSERT((*i)->mBase == iCode);
ASSERT((*i)->mOffset <= iCode->size());
}
#endif
@ -217,14 +217,14 @@ namespace ICG {
void ICodeGenerator::setLabel(Label *l)
{
l->base = iCode;
l->offset = static_cast<int32>(iCode->size());
l->mBase = iCode;
l->mOffset = static_cast<int32>(iCode->size());
}
void ICodeGenerator::setLabel(InstructionStream *stream, Label *l)
{
l->base = stream;
l->offset = static_cast<int32>(stream->size());
l->mBase = stream;
l->mOffset = static_cast<int32>(stream->size());
}
/********************************************************************/
@ -236,9 +236,9 @@ namespace ICG {
// themselves?) in order to avoid running this loop unnecessarily.
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
if ((*i)->base == sideStream) {
(*i)->base = iCode;
(*i)->offset += iCode->size();
if ((*i)->mBase == sideStream) {
(*i)->mBase = iCode;
(*i)->mOffset += iCode->size();
}
}
@ -611,7 +611,7 @@ namespace ICG {
for (LabelList::iterator k = labels.begin();
k != labels.end(); k++)
if ((ptrdiff_t)(*k)->offset == (i - iCode->begin())) {
if ((ptrdiff_t)(*k)->mOffset == (i - iCode->begin())) {
f << "#" << (uint32)(i - iCode->begin()) << "\t";
isLabel = true;
break;

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

@ -173,7 +173,7 @@ namespace ICG {
// expression statements
void beginStatement(uint32 /*pos*/) { resetTopRegister(); }
void returnStatement() { iCode->push_back(new Return()); }
void returnStatement() { iCode->push_back(new ReturnVoid()); }
void returnStatement(Register result) \
{ iCode->push_back(new Return(result)); }

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

@ -1,31 +1,41 @@
// -*- 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) 2000 Netscape Communications Corporation. All
// Rights Reserved.
/* -*- 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 "interpreter.h"
#include "world.h"
#include "vmtypes.h"
namespace JavaScript {
namespace Interpreter {
using namespace JSTypes;
// operand access macros.
#define op1(i) (i->o1())
#define op2(i) (i->o2())
@ -37,23 +47,8 @@ namespace Interpreter {
#define src2(i) op3(i)
#define ofs(i) (i->getOffset())
static JSObject globals;
JSValue& defineGlobalProperty(const String& name, const JSValue& value)
{
return (globals[name] = value);
}
// FIXME: need to copy the ICodeModule's instruction stream.
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value;
value.function = new JSFunction(iCode);
return defineGlobalProperty(name, value);
}
JSValue interpret(ICodeModule* iCode, const JSValues& args)
JSValue
Context::interpret(ICodeModule* iCode, const JSValues& args)
{
// stack of JSFrames.
// XXX is a linked list of activation's sufficient?
@ -81,10 +76,26 @@ namespace Interpreter {
begin_pc = pc = target->its_iCode->begin();
}
continue;
case RETURN_VOID:
{
JSValue result(NotARegister);
if (frames.empty())
return result;
JSFrame *frame = frames.top();
frames.pop();
activation = frame->itsActivation;
registers = &activation->mRegisters;
(*registers)[frame->itsResult] = result;
pc = frame->itsReturnPC;
begin_pc = frame->itsBasePC;
}
continue;
case RETURN:
{
Return* ret = static_cast<Return*>(instruction);
JSValue result;
JSValue result(NotARegister);
if (op1(ret) != NotARegister)
result = (*registers)[op1(ret)];
if (frames.empty())
@ -107,13 +118,13 @@ namespace Interpreter {
case LOAD_NAME:
{
LoadName* ln = static_cast<LoadName*>(instruction);
(*registers)[dst(ln)] = globals[*src1(ln)];
(*registers)[dst(ln)] = mGlobal[*src1(ln)];
}
break;
case SAVE_NAME:
{
SaveName* sn = static_cast<SaveName*>(instruction);
globals[*dst(sn)] = (*registers)[src1(sn)];
mGlobal[*dst(sn)] = (*registers)[src1(sn)];
}
break;
case NEW_OBJECT:
@ -295,5 +306,4 @@ namespace Interpreter {
} /* interpret */
} /* namespace Interpreter */
} /* namespace JavaScript */

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

@ -23,20 +23,36 @@
#include "utilities.h"
#include "jstypes.h"
#include "icodegenerator.h"
#include "gc_allocator.h"
namespace JavaScript {
namespace Interpreter {
using namespace ICG;
using namespace JSTypes;
class Context : public gc_base {
public:
explicit Context(World& /*world */, JSObject& aGlobal) :
mGlobal(aGlobal) {};
JSValue interpret(ICodeModule* iCode, const JSValues& args);
JSValue& defineGlobalProperty(const String& name,
const JSValue& value);
JSValue& defineFunction(const String& name, ICodeModule* iCode);
JSObject& setGlobalObject(JSObject& aGlobal)
{
JSObject &t = mGlobal;
mGlobal = aGlobal;
return t;
}
} /* namespace Interpreter */
JSObject& getGlobalObject()
{
return mGlobal;
}
private:
/* World mWorld; */
JSObject& mGlobal;
}; /* class Interpreter */
} /* namespace JavaScript */
#endif /* interpreter_h */

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

@ -56,7 +56,6 @@ static void initConsole(StringPtr consoleName,
namespace JavaScript {
namespace Shell {
using namespace Interpreter;
// Interactively read a line from the input stream in and put it into
// s Return false if reached the end of input before reading anything.
@ -100,7 +99,7 @@ namespace JavaScript {
t.print(stdOut, true);
}
} else {
ExprNode *parseTree = p.parsePostfixExpression();
/*ExprNode *parseTree = */ p.parsePostfixExpression();
}
clear(buffer);
stdOut << '\n';
@ -117,166 +116,7 @@ namespace JavaScript {
}
}
stdOut << '\n';
#if 0
do {
bufp = buffer;
*bufp = '\0';
/*
* Accumulate lines until we get a 'compilable unit' - one that either
* generates an error (before running out of source) or that compiles
* cleanly. This should be whenever we get a complete statement that
* coincides with the end of a line.
*/
startline = lineNum;
do {
if (!GetLine(cx, bufp, file,
startline == lineNum ? "js> " : "")) {
hitEOF = JS_TRUE;
break;
}
bufp += strlen(bufp);
lineNum++;
} while (!JS_BufferIsCompilableUnit(cx, obj, buffer,
strlen(buffer)));
} while (!hitEOF);
fprintf(stdout, "\n");
return;
#endif
}
#if 0
static int ProcessInputFile(JSContext *cx, JSObject *obj,
char *filename)
{
JSBool ok, hitEOF;
JSScript *script;
jsval result;
JSString *str;
char buffer[4096];
char *bufp;
int startline;
FILE *file;
if (filename && strcmp(filename, "-")) {
file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Can't open \"%s\": %s", filename,
strerror(errno));
return 1;
}
} else {
file = stdin;
}
if (!isatty(fileno(file))) {
/*
* It's not interactive - just execute it.
*
* Support the UNIX #! shell hack; gobble the first line
* if it starts with '#'.
*/
int ch = fgetc(file);
if (ch == '#') {
while((ch = fgetc(file)) != EOF)
if (ch == '\n' || ch == '\r')
break;
} else
ungetc(ch, file);
script = JS_CompileFileHandle(cx, obj, filename, file);
if (script)
(void)JS_ExecuteScript(cx, obj, script, &result);
return;
}
/* It's an interactive filehandle;
* drop into read-eval-print loop. */
int32 lineNum = 1;
hitEOF = JS_FALSE;
do {
bufp = buffer;
*bufp = '\0';
/*
* Accumulate lines until we get a 'compilable unit' -
* one that either generates an error (before running out of
* source) or that compiles cleanly. This should be whenever
* we get a complete statement that coincides with the end of a
* line.
*/
startline = lineNum;
do {
if (!GetLine(cx, bufp, file,
startline == lineNum ? "js> " : "")) {
hitEOF = JS_TRUE;
break;
}
bufp += strlen(bufp);
lineNum++;
} while (!JS_BufferIsCompilableUnit(cx, obj, buffer,
strlen(buffer)));
} while (!hitEOF);
fprintf(stdout, "\n");
return;
}
static int
usage(void)
{
stdErr << "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n";
return 2;
}
static int
ProcessArgs(char **argv, int argc)
{
int i;
char *filename = NULL;
jsint length;
jsval *vector;
jsval *p;
JSObject *argsObj;
JSBool isInteractive = JS_TRUE;
for (i=0; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'f':
if (i+1 == argc) {
return usage();
}
filename = argv[i+1];
/* "-f -" means read from stdin */
if (filename[0] == '-' && filename[1] == '\0')
filename = NULL;
ProcessInputFile(filename);
filename = NULL;
/* XXX: js -f foo.js should interpret foo.js and
* then drop into interactive mode, but that
* breaks the test harness.
*/
isInteractive = JS_FALSE;
i++;
break;
default:
return usage();
}
} else {
filename = argv[i++];
isInteractive = JS_FALSE;
break;
}
}
if (filename || isInteractive)
ProcessInputFile(filename);
return gExitCode;
}
#endif
#include "icodegenerator.h"
@ -365,14 +205,17 @@ namespace JavaScript {
static float64 testFunctionCall(World &world, float64 n)
{
JSObject glob;
Context cx(world, glob);
uint32 position = 0;
StringAtom& global = world.identifiers[widenCString("global")];
//StringAtom& global = world.identifiers[widenCString("global")];
StringAtom& sum = world.identifiers[widenCString("sum")];
ICodeGenerator fun;
// function sum(n) { if (n > 1) return 1 + sum(n - 1); else return 1; }
// n is bound to var #0.
Register r_n = fun.allocateVariable(world.identifiers[widenCString("n")]);
Register r_n =
fun.allocateVariable(world.identifiers[widenCString("n")]);
fun.beginStatement(position);
Register r1 = fun.op(COMPARE_GT, r_n, fun.loadImmediate(1.0));
fun.beginIfStatement(position, r1);
@ -401,11 +244,10 @@ namespace JavaScript {
stdOut << script;
// preset the global property "sum" to contain the above function
defineFunction(sum, funCode);
glob.defineFunction(sum, funCode);
JSValue result = interpret(script.complete(), JSValues());
JSValue result = cx.interpret(script.complete(), JSValues());
stdOut << "sum(" << n << ") = " << result.f64 << "\n";
return result.f64;
@ -413,6 +255,8 @@ namespace JavaScript {
static float64 testFactorial(World &world, float64 n)
{
JSObject glob;
Context cx(world, glob);
// generate code for factorial, and interpret it.
uint32 position = 0;
ICodeGenerator icg;
@ -450,7 +294,7 @@ namespace JavaScript {
// preset the global property "fact" to contain the above function
StringAtom& fact = world.identifiers[widenCString("fact")];
defineFunction(fact, icm);
glob.defineFunction(fact, icm);
// now a script :
// return fact(n);
@ -462,7 +306,7 @@ namespace JavaScript {
stdOut << script;
// test the iCode interpreter.
JSValue result = interpret(script.complete(), JSValues());
JSValue result = cx.interpret(script.complete(), JSValues());
stdOut << "fact(" << n << ") = " << result.f64 << "\n";
delete icm;
@ -472,6 +316,8 @@ namespace JavaScript {
static float64 testObjects(World &world, int32 n)
{
JSObject glob;
Context cx(world, glob);
// create some objects, put some properties, and retrieve them.
uint32 position = 0;
ICodeGenerator initCG;
@ -519,12 +365,12 @@ namespace JavaScript {
// run initialization code.
JSValues args;
interpret(initCode, args);
cx.interpret(initCode, args);
// call the increment function some number of times.
JSValue result;
while (n-- > 0)
result = interpret(incrCode, args);
result = cx.interpret(incrCode, args);
stdOut << "result = " << result.f64 << "\n";
@ -533,11 +379,12 @@ namespace JavaScript {
return result.f64;
}
}
}
} /* namespace Shell */
} /* namespace JavaScript */
int main(int argc, char **argv)
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);

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

@ -100,6 +100,7 @@ namespace JSTypes {
* gc_allocator. This is all in flux.
*/
class JSMap : public gc_base {
protected:
std::map<String, JSValue, std::less<String>,
gc_map_allocator> properties;
public:
@ -109,12 +110,33 @@ namespace JSTypes {
}
};
class JSFunction : public JSMap {
ICodeModule* mICode;
public:
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
ICodeModule* getICode() { return mICode; }
};
/**
* Private representation of a JavaScript object.
* This will change over time, so it is treated as an opaque
* type everywhere else but here.
*/
class JSObject : public JSMap {};
class JSObject : public JSMap {
public:
JSValue& defineProperty(const String& name, JSValue &v)
{
return (properties[name] = v);
}
// FIXME: need to copy the ICodeModule's instruction stream.
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value;
value.function = new JSFunction(iCode);
return properties[name] = value;
}
};
/**
* Private representation of a JavaScript array.
@ -164,13 +186,6 @@ namespace JSTypes {
}
};
class JSFunction : public JSMap {
ICodeModule* mICode;
public:
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
ICodeModule* getICode() { return mICode; }
};
/**
* Represents the current function's invocation state.
*/
@ -203,8 +218,8 @@ namespace JSTypes {
};
/**
* Stores saved state from the *previous* activation, the current activation is
* alive and well in locals of the interpreter loop.
* Stores saved state from the *previous* activation, the current
* activation is alive and well in locals of the interpreter loop.
*/
struct JSFrame : public gc_base {
JSFrame(InstructionIterator returnPC, InstructionIterator basePC,

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

@ -10,6 +10,7 @@ my $opcode_maxlen = 0;
my $compare_op =
{
super => "Compare",
super_has_print => 1,
rem => "dest, source",
params => [ ("Register", "Register") ]
};
@ -17,6 +18,7 @@ my $compare_op =
my $math_op =
{
super => "Arithmetic",
super_has_print => 1,
rem => "dest, source1, source2",
params => [ ("Register", "Register", "Register") ]
};
@ -24,6 +26,7 @@ my $math_op =
my $cbranch_op =
{
super => "GenericBranch",
super_has_print => 1,
rem => "target label, condition",
params => [ ("Label*", "Register") ]
};
@ -41,18 +44,6 @@ $ops{"MOVE"} =
rem => "dest, source",
params => [ ("Register", "Register") ]
};
$ops{"LOAD_VAR"} =
{
super => "Instruction_2",
rem => "dest, index of frame slot",
params => [ ("Register", "uint32" ) ]
};
$ops{"SAVE_VAR"} =
{
super => "Instruction_2",
rem => "index of frame slot, source",
params => [ ("uint32", "Register") ]
};
$ops{"LOAD_IMMEDIATE"} =
{
super => "Instruction_2",
@ -138,8 +129,13 @@ $ops{"BRANCH_GT"} = $cbranch_op;
$ops{"RETURN"} =
{
super => "Instruction_1",
rem => "return value or NotARegister",
params => [ ("Register = NotARegister") ]
rem => "return value",
params => [ ("Register") ]
};
$ops{"RETURN_VOID"} =
{
super => "Instruction",
rem => "Return without a value"
};
$ops{"CALL"} =
{
@ -179,7 +175,6 @@ sub collect {
my ($dec_list, $call_list, $template_list) =
&get_paramlists(@{$c->{"params"}});
my $params = $call_list ? $opname . ", " . $call_list : $opname;
my $printbody = &get_printbody(split (", ", $template_list));
if ($super =~ /Instruction_\d/) {
$super .= "<" . $template_list . ">";
@ -193,14 +188,22 @@ sub collect {
$init_tab . $tab . "$cname ($dec_list) :\n" .
$init_tab . $tab . $tab . "$super\n" .
"$init_tab$tab$tab($params) " .
"{};\n" .
$init_tab . $tab .
"{};\n");
if (!$c->{"super_has_print"}) {
my $printbody = &get_printbody(split (", ", $template_list));
$class_decs .= ($init_tab . $tab .
"virtual Formatter& print (Formatter& f) {\n" .
$init_tab . $tab . $tab . "f << opcodeNames[$opname];\n" .
$printbody .
$init_tab . $tab . $tab . "f << opcodeNames[$opname]" .
$printbody . ";\n" .
$init_tab . $tab . $tab . "return f;\n" .
$init_tab . $tab . "}\n" .
$init_tab . "};\n\n");
$init_tab . $tab . "}\n");
} else {
$class_decs .= $init_tab . $tab .
"/* print() inherited from $super */\n";
}
$class_decs .= $init_tab . "};\n\n";
}
sub spew {
@ -259,10 +262,10 @@ sub get_paramlists {
}
$pfx = $deref = "";
$member = "op$op";
$member = "mOp$op";
push (@dec, "$type op$op" . "A$default");
push (@call, "op$op" . "A");
push (@dec, "$type aOp$op" . "$default");
push (@call, "aOp$op");
push (@template, $type);
$op++;
}
@ -281,25 +284,21 @@ sub get_printbody {
print "type $type\n";
if ($type eq "Register") {
push (@oplist, $in . "if (op$op == NotARegister) {\n" .
$in . $tab . "f << \"R~\";\n" .
$in . "} else {\n" .
$in . $tab . "f << \"R\" << op$op;\n" .
$in . "}\n");
push (@oplist, "\"R\" << mOp$op");
} elsif ($type eq "Label*") {
push (@oplist, $in . "f << \"Offset \" << op$op->offset;\n");
push (@oplist, "\"Offset \" << mOp$op->mOffset");
} elsif ($type eq "StringAtom*") {
push (@oplist, $in . "f << \"'\" << *op$op << \"'\";\n");
push (@oplist, "\"'\" << *mOp$op << \"'\"");
} else {
push (@oplist, $in . "f << op$op;\n");
push (@oplist, "mOp$op");
}
$op++;
}
my $rv = join ($in . "f << \", \";\n", @oplist);
my $rv = join (" << \", \" << ", @oplist);
if ($rv ne "") {
$rv = $in . "f << \"\\t\";\n" . $rv;
$rv = " << \"\\t\" << " . $rv;
}
}

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1,3 +1,6 @@
debugger.o: debugger.cpp world.h utilities.h systemtypes.h hash.h \
parser.h interpreter.h jstypes.h gc_allocator.h vmtypes.h numerics.h \
icodegenerator.h
gc_allocator.o: gc_allocator.cpp gc_allocator.h gc_container.h
hash.o: hash.cpp hash.h utilities.h systemtypes.h
icodegenerator.o: icodegenerator.cpp numerics.h utilities.h \

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

@ -61,8 +61,8 @@ namespace ICG {
ASSERT(stitcher.empty());
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
ASSERT((*i)->base == iCode);
ASSERT((*i)->offset <= iCode->size());
ASSERT((*i)->mBase == iCode);
ASSERT((*i)->mOffset <= iCode->size());
}
#endif
@ -217,14 +217,14 @@ namespace ICG {
void ICodeGenerator::setLabel(Label *l)
{
l->base = iCode;
l->offset = static_cast<int32>(iCode->size());
l->mBase = iCode;
l->mOffset = static_cast<int32>(iCode->size());
}
void ICodeGenerator::setLabel(InstructionStream *stream, Label *l)
{
l->base = stream;
l->offset = static_cast<int32>(stream->size());
l->mBase = stream;
l->mOffset = static_cast<int32>(stream->size());
}
/********************************************************************/
@ -236,9 +236,9 @@ namespace ICG {
// themselves?) in order to avoid running this loop unnecessarily.
for (LabelList::iterator i = labels.begin();
i != labels.end(); i++) {
if ((*i)->base == sideStream) {
(*i)->base = iCode;
(*i)->offset += iCode->size();
if ((*i)->mBase == sideStream) {
(*i)->mBase = iCode;
(*i)->mOffset += iCode->size();
}
}
@ -611,7 +611,7 @@ namespace ICG {
for (LabelList::iterator k = labels.begin();
k != labels.end(); k++)
if ((ptrdiff_t)(*k)->offset == (i - iCode->begin())) {
if ((ptrdiff_t)(*k)->mOffset == (i - iCode->begin())) {
f << "#" << (uint32)(i - iCode->begin()) << "\t";
isLabel = true;
break;

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

@ -173,7 +173,7 @@ namespace ICG {
// expression statements
void beginStatement(uint32 /*pos*/) { resetTopRegister(); }
void returnStatement() { iCode->push_back(new Return()); }
void returnStatement() { iCode->push_back(new ReturnVoid()); }
void returnStatement(Register result) \
{ iCode->push_back(new Return(result)); }

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

@ -1,31 +1,41 @@
// -*- 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) 2000 Netscape Communications Corporation. All
// Rights Reserved.
/* -*- 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 "interpreter.h"
#include "world.h"
#include "vmtypes.h"
namespace JavaScript {
namespace Interpreter {
using namespace JSTypes;
// operand access macros.
#define op1(i) (i->o1())
#define op2(i) (i->o2())
@ -37,23 +47,8 @@ namespace Interpreter {
#define src2(i) op3(i)
#define ofs(i) (i->getOffset())
static JSObject globals;
JSValue& defineGlobalProperty(const String& name, const JSValue& value)
{
return (globals[name] = value);
}
// FIXME: need to copy the ICodeModule's instruction stream.
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value;
value.function = new JSFunction(iCode);
return defineGlobalProperty(name, value);
}
JSValue interpret(ICodeModule* iCode, const JSValues& args)
JSValue
Context::interpret(ICodeModule* iCode, const JSValues& args)
{
// stack of JSFrames.
// XXX is a linked list of activation's sufficient?
@ -81,10 +76,26 @@ namespace Interpreter {
begin_pc = pc = target->its_iCode->begin();
}
continue;
case RETURN_VOID:
{
JSValue result(NotARegister);
if (frames.empty())
return result;
JSFrame *frame = frames.top();
frames.pop();
activation = frame->itsActivation;
registers = &activation->mRegisters;
(*registers)[frame->itsResult] = result;
pc = frame->itsReturnPC;
begin_pc = frame->itsBasePC;
}
continue;
case RETURN:
{
Return* ret = static_cast<Return*>(instruction);
JSValue result;
JSValue result(NotARegister);
if (op1(ret) != NotARegister)
result = (*registers)[op1(ret)];
if (frames.empty())
@ -107,13 +118,13 @@ namespace Interpreter {
case LOAD_NAME:
{
LoadName* ln = static_cast<LoadName*>(instruction);
(*registers)[dst(ln)] = globals[*src1(ln)];
(*registers)[dst(ln)] = mGlobal[*src1(ln)];
}
break;
case SAVE_NAME:
{
SaveName* sn = static_cast<SaveName*>(instruction);
globals[*dst(sn)] = (*registers)[src1(sn)];
mGlobal[*dst(sn)] = (*registers)[src1(sn)];
}
break;
case NEW_OBJECT:
@ -295,5 +306,4 @@ namespace Interpreter {
} /* interpret */
} /* namespace Interpreter */
} /* namespace JavaScript */

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

@ -23,20 +23,36 @@
#include "utilities.h"
#include "jstypes.h"
#include "icodegenerator.h"
#include "gc_allocator.h"
namespace JavaScript {
namespace Interpreter {
using namespace ICG;
using namespace JSTypes;
class Context : public gc_base {
public:
explicit Context(World& /*world */, JSObject& aGlobal) :
mGlobal(aGlobal) {};
JSValue interpret(ICodeModule* iCode, const JSValues& args);
JSValue& defineGlobalProperty(const String& name,
const JSValue& value);
JSValue& defineFunction(const String& name, ICodeModule* iCode);
JSObject& setGlobalObject(JSObject& aGlobal)
{
JSObject &t = mGlobal;
mGlobal = aGlobal;
return t;
}
} /* namespace Interpreter */
JSObject& getGlobalObject()
{
return mGlobal;
}
private:
/* World mWorld; */
JSObject& mGlobal;
}; /* class Interpreter */
} /* namespace JavaScript */
#endif /* interpreter_h */

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

@ -100,6 +100,7 @@ namespace JSTypes {
* gc_allocator. This is all in flux.
*/
class JSMap : public gc_base {
protected:
std::map<String, JSValue, std::less<String>,
gc_map_allocator> properties;
public:
@ -109,12 +110,33 @@ namespace JSTypes {
}
};
class JSFunction : public JSMap {
ICodeModule* mICode;
public:
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
ICodeModule* getICode() { return mICode; }
};
/**
* Private representation of a JavaScript object.
* This will change over time, so it is treated as an opaque
* type everywhere else but here.
*/
class JSObject : public JSMap {};
class JSObject : public JSMap {
public:
JSValue& defineProperty(const String& name, JSValue &v)
{
return (properties[name] = v);
}
// FIXME: need to copy the ICodeModule's instruction stream.
JSValue& defineFunction(const String& name, ICodeModule* iCode)
{
JSValue value;
value.function = new JSFunction(iCode);
return properties[name] = value;
}
};
/**
* Private representation of a JavaScript array.
@ -164,13 +186,6 @@ namespace JSTypes {
}
};
class JSFunction : public JSMap {
ICodeModule* mICode;
public:
JSFunction(ICodeModule* iCode) : mICode(iCode) {}
ICodeModule* getICode() { return mICode; }
};
/**
* Represents the current function's invocation state.
*/
@ -203,8 +218,8 @@ namespace JSTypes {
};
/**
* Stores saved state from the *previous* activation, the current activation is
* alive and well in locals of the interpreter loop.
* Stores saved state from the *previous* activation, the current
* activation is alive and well in locals of the interpreter loop.
*/
struct JSFrame : public gc_base {
JSFrame(InstructionIterator returnPC, InstructionIterator basePC,

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -56,7 +56,6 @@ static void initConsole(StringPtr consoleName,
namespace JavaScript {
namespace Shell {
using namespace Interpreter;
// Interactively read a line from the input stream in and put it into
// s Return false if reached the end of input before reading anything.
@ -100,7 +99,7 @@ namespace JavaScript {
t.print(stdOut, true);
}
} else {
ExprNode *parseTree = p.parsePostfixExpression();
/*ExprNode *parseTree = */ p.parsePostfixExpression();
}
clear(buffer);
stdOut << '\n';
@ -117,166 +116,7 @@ namespace JavaScript {
}
}
stdOut << '\n';
#if 0
do {
bufp = buffer;
*bufp = '\0';
/*
* Accumulate lines until we get a 'compilable unit' - one that either
* generates an error (before running out of source) or that compiles
* cleanly. This should be whenever we get a complete statement that
* coincides with the end of a line.
*/
startline = lineNum;
do {
if (!GetLine(cx, bufp, file,
startline == lineNum ? "js> " : "")) {
hitEOF = JS_TRUE;
break;
}
bufp += strlen(bufp);
lineNum++;
} while (!JS_BufferIsCompilableUnit(cx, obj, buffer,
strlen(buffer)));
} while (!hitEOF);
fprintf(stdout, "\n");
return;
#endif
}
#if 0
static int ProcessInputFile(JSContext *cx, JSObject *obj,
char *filename)
{
JSBool ok, hitEOF;
JSScript *script;
jsval result;
JSString *str;
char buffer[4096];
char *bufp;
int startline;
FILE *file;
if (filename && strcmp(filename, "-")) {
file = fopen(filename, "r");
if (!file) {
fprintf(stderr, "Can't open \"%s\": %s", filename,
strerror(errno));
return 1;
}
} else {
file = stdin;
}
if (!isatty(fileno(file))) {
/*
* It's not interactive - just execute it.
*
* Support the UNIX #! shell hack; gobble the first line
* if it starts with '#'.
*/
int ch = fgetc(file);
if (ch == '#') {
while((ch = fgetc(file)) != EOF)
if (ch == '\n' || ch == '\r')
break;
} else
ungetc(ch, file);
script = JS_CompileFileHandle(cx, obj, filename, file);
if (script)
(void)JS_ExecuteScript(cx, obj, script, &result);
return;
}
/* It's an interactive filehandle;
* drop into read-eval-print loop. */
int32 lineNum = 1;
hitEOF = JS_FALSE;
do {
bufp = buffer;
*bufp = '\0';
/*
* Accumulate lines until we get a 'compilable unit' -
* one that either generates an error (before running out of
* source) or that compiles cleanly. This should be whenever
* we get a complete statement that coincides with the end of a
* line.
*/
startline = lineNum;
do {
if (!GetLine(cx, bufp, file,
startline == lineNum ? "js> " : "")) {
hitEOF = JS_TRUE;
break;
}
bufp += strlen(bufp);
lineNum++;
} while (!JS_BufferIsCompilableUnit(cx, obj, buffer,
strlen(buffer)));
} while (!hitEOF);
fprintf(stdout, "\n");
return;
}
static int
usage(void)
{
stdErr << "usage: js [-s] [-w] [-v version] [-f scriptfile] [scriptfile] [scriptarg...]\n";
return 2;
}
static int
ProcessArgs(char **argv, int argc)
{
int i;
char *filename = NULL;
jsint length;
jsval *vector;
jsval *p;
JSObject *argsObj;
JSBool isInteractive = JS_TRUE;
for (i=0; i < argc; i++) {
if (argv[i][0] == '-') {
switch (argv[i][1]) {
case 'f':
if (i+1 == argc) {
return usage();
}
filename = argv[i+1];
/* "-f -" means read from stdin */
if (filename[0] == '-' && filename[1] == '\0')
filename = NULL;
ProcessInputFile(filename);
filename = NULL;
/* XXX: js -f foo.js should interpret foo.js and
* then drop into interactive mode, but that
* breaks the test harness.
*/
isInteractive = JS_FALSE;
i++;
break;
default:
return usage();
}
} else {
filename = argv[i++];
isInteractive = JS_FALSE;
break;
}
}
if (filename || isInteractive)
ProcessInputFile(filename);
return gExitCode;
}
#endif
#include "icodegenerator.h"
@ -365,14 +205,17 @@ namespace JavaScript {
static float64 testFunctionCall(World &world, float64 n)
{
JSObject glob;
Context cx(world, glob);
uint32 position = 0;
StringAtom& global = world.identifiers[widenCString("global")];
//StringAtom& global = world.identifiers[widenCString("global")];
StringAtom& sum = world.identifiers[widenCString("sum")];
ICodeGenerator fun;
// function sum(n) { if (n > 1) return 1 + sum(n - 1); else return 1; }
// n is bound to var #0.
Register r_n = fun.allocateVariable(world.identifiers[widenCString("n")]);
Register r_n =
fun.allocateVariable(world.identifiers[widenCString("n")]);
fun.beginStatement(position);
Register r1 = fun.op(COMPARE_GT, r_n, fun.loadImmediate(1.0));
fun.beginIfStatement(position, r1);
@ -401,11 +244,10 @@ namespace JavaScript {
stdOut << script;
// preset the global property "sum" to contain the above function
defineFunction(sum, funCode);
glob.defineFunction(sum, funCode);
JSValue result = interpret(script.complete(), JSValues());
JSValue result = cx.interpret(script.complete(), JSValues());
stdOut << "sum(" << n << ") = " << result.f64 << "\n";
return result.f64;
@ -413,6 +255,8 @@ namespace JavaScript {
static float64 testFactorial(World &world, float64 n)
{
JSObject glob;
Context cx(world, glob);
// generate code for factorial, and interpret it.
uint32 position = 0;
ICodeGenerator icg;
@ -450,7 +294,7 @@ namespace JavaScript {
// preset the global property "fact" to contain the above function
StringAtom& fact = world.identifiers[widenCString("fact")];
defineFunction(fact, icm);
glob.defineFunction(fact, icm);
// now a script :
// return fact(n);
@ -462,7 +306,7 @@ namespace JavaScript {
stdOut << script;
// test the iCode interpreter.
JSValue result = interpret(script.complete(), JSValues());
JSValue result = cx.interpret(script.complete(), JSValues());
stdOut << "fact(" << n << ") = " << result.f64 << "\n";
delete icm;
@ -472,6 +316,8 @@ namespace JavaScript {
static float64 testObjects(World &world, int32 n)
{
JSObject glob;
Context cx(world, glob);
// create some objects, put some properties, and retrieve them.
uint32 position = 0;
ICodeGenerator initCG;
@ -519,12 +365,12 @@ namespace JavaScript {
// run initialization code.
JSValues args;
interpret(initCode, args);
cx.interpret(initCode, args);
// call the increment function some number of times.
JSValue result;
while (n-- > 0)
result = interpret(incrCode, args);
result = cx.interpret(incrCode, args);
stdOut << "result = " << result.f64 << "\n";
@ -533,11 +379,12 @@ namespace JavaScript {
return result.f64;
}
}
}
} /* namespace Shell */
} /* namespace JavaScript */
int main(int argc, char **argv)
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);

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

@ -10,6 +10,7 @@ my $opcode_maxlen = 0;
my $compare_op =
{
super => "Compare",
super_has_print => 1,
rem => "dest, source",
params => [ ("Register", "Register") ]
};
@ -17,6 +18,7 @@ my $compare_op =
my $math_op =
{
super => "Arithmetic",
super_has_print => 1,
rem => "dest, source1, source2",
params => [ ("Register", "Register", "Register") ]
};
@ -24,6 +26,7 @@ my $math_op =
my $cbranch_op =
{
super => "GenericBranch",
super_has_print => 1,
rem => "target label, condition",
params => [ ("Label*", "Register") ]
};
@ -41,18 +44,6 @@ $ops{"MOVE"} =
rem => "dest, source",
params => [ ("Register", "Register") ]
};
$ops{"LOAD_VAR"} =
{
super => "Instruction_2",
rem => "dest, index of frame slot",
params => [ ("Register", "uint32" ) ]
};
$ops{"SAVE_VAR"} =
{
super => "Instruction_2",
rem => "index of frame slot, source",
params => [ ("uint32", "Register") ]
};
$ops{"LOAD_IMMEDIATE"} =
{
super => "Instruction_2",
@ -138,8 +129,13 @@ $ops{"BRANCH_GT"} = $cbranch_op;
$ops{"RETURN"} =
{
super => "Instruction_1",
rem => "return value or NotARegister",
params => [ ("Register = NotARegister") ]
rem => "return value",
params => [ ("Register") ]
};
$ops{"RETURN_VOID"} =
{
super => "Instruction",
rem => "Return without a value"
};
$ops{"CALL"} =
{
@ -179,7 +175,6 @@ sub collect {
my ($dec_list, $call_list, $template_list) =
&get_paramlists(@{$c->{"params"}});
my $params = $call_list ? $opname . ", " . $call_list : $opname;
my $printbody = &get_printbody(split (", ", $template_list));
if ($super =~ /Instruction_\d/) {
$super .= "<" . $template_list . ">";
@ -193,14 +188,22 @@ sub collect {
$init_tab . $tab . "$cname ($dec_list) :\n" .
$init_tab . $tab . $tab . "$super\n" .
"$init_tab$tab$tab($params) " .
"{};\n" .
$init_tab . $tab .
"{};\n");
if (!$c->{"super_has_print"}) {
my $printbody = &get_printbody(split (", ", $template_list));
$class_decs .= ($init_tab . $tab .
"virtual Formatter& print (Formatter& f) {\n" .
$init_tab . $tab . $tab . "f << opcodeNames[$opname];\n" .
$printbody .
$init_tab . $tab . $tab . "f << opcodeNames[$opname]" .
$printbody . ";\n" .
$init_tab . $tab . $tab . "return f;\n" .
$init_tab . $tab . "}\n" .
$init_tab . "};\n\n");
$init_tab . $tab . "}\n");
} else {
$class_decs .= $init_tab . $tab .
"/* print() inherited from $super */\n";
}
$class_decs .= $init_tab . "};\n\n";
}
sub spew {
@ -259,10 +262,10 @@ sub get_paramlists {
}
$pfx = $deref = "";
$member = "op$op";
$member = "mOp$op";
push (@dec, "$type op$op" . "A$default");
push (@call, "op$op" . "A");
push (@dec, "$type aOp$op" . "$default");
push (@call, "aOp$op");
push (@template, $type);
$op++;
}
@ -281,25 +284,21 @@ sub get_printbody {
print "type $type\n";
if ($type eq "Register") {
push (@oplist, $in . "if (op$op == NotARegister) {\n" .
$in . $tab . "f << \"R~\";\n" .
$in . "} else {\n" .
$in . $tab . "f << \"R\" << op$op;\n" .
$in . "}\n");
push (@oplist, "\"R\" << mOp$op");
} elsif ($type eq "Label*") {
push (@oplist, $in . "f << \"Offset \" << op$op->offset;\n");
push (@oplist, "\"Offset \" << mOp$op->mOffset");
} elsif ($type eq "StringAtom*") {
push (@oplist, $in . "f << \"'\" << *op$op << \"'\";\n");
push (@oplist, "\"'\" << *mOp$op << \"'\"");
} else {
push (@oplist, $in . "f << op$op;\n");
push (@oplist, "mOp$op");
}
$op++;
}
my $rv = join ($in . "f << \", \";\n", @oplist);
my $rv = join (" << \", \" << ", @oplist);
if ($rv ne "") {
$rv = $in . "f << \"\\t\";\n" . $rv;
$rv = " << \"\\t\" << " . $rv;
}
}