зеркало из https://github.com/mozilla/pjs.git
icodegenerator.cpp
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:
Родитель
7cf4cc8527
Коммит
7615ee9226
|
@ -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 */
|
||||
|
|
193
js/js2/js2.cpp
193
js/js2/js2.cpp
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
753
js/js2/vmtypes.h
753
js/js2/vmtypes.h
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче