This commit is contained in:
rogerl%netscape.com 2000-06-21 22:32:21 +00:00
Родитель 6beafca960
Коммит 3783f2c99e
16 изменённых файлов: 714 добавлений и 138 удалений

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

@ -159,6 +159,14 @@ TypedRegister ICodeGenerator::loadString(String &value)
return dest;
}
TypedRegister ICodeGenerator::loadString(const StringAtom &value)
{
TypedRegister dest(getRegister(), &String_Type);
LoadString *instr = new LoadString(dest, new JSString(value));
iCode->push_back(instr);
return dest;
}
TypedRegister ICodeGenerator::loadBoolean(bool value)
{
TypedRegister dest(getRegister(), &Boolean_Type);
@ -175,6 +183,14 @@ TypedRegister ICodeGenerator::newObject()
return dest;
}
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm)
{
TypedRegister dest(getRegister(), &Function_Type);
NewFunction *instr = new NewFunction(dest, icm);
iCode->push_back(instr);
return dest;
}
TypedRegister ICodeGenerator::newArray()
{
TypedRegister dest(getRegister(), &Array_Type);
@ -183,8 +199,6 @@ TypedRegister ICodeGenerator::newArray()
return dest;
}
TypedRegister ICodeGenerator::loadName(const StringAtom &name)
{
TypedRegister dest(getRegister(), &Any_Type);
@ -343,18 +357,20 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1,
return dest;
}
TypedRegister ICodeGenerator::call(TypedRegister target, RegisterList args)
TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList args)
{
TypedRegister dest(getRegister(), &Any_Type);
Call *instr = new Call(dest, target, args);
Call *instr = new Call(dest, target, &name, args);
iCode->push_back(instr);
return dest;
}
void ICodeGenerator::callVoid(TypedRegister target, RegisterList args)
TypedRegister ICodeGenerator::methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList args)
{
Call *instr = new Call(TypedRegister(NotARegister, &Void_Type), target, args);
TypedRegister dest(getRegister(), &Any_Type);
MethodCall *instr = new MethodCall(dest, targetBase, targetValue, args);
iCode->push_back(instr);
return dest;
}
void ICodeGenerator::branch(Label *label)
@ -514,8 +530,6 @@ static bool generatedBoolean(ExprNode *p)
return false;
}
/*
if trueBranch OR falseBranch are not null, the sub-expression should generate
a conditional branch to the appropriate target. If either branch is NULL, it
@ -563,14 +577,36 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::call :
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
TypedRegister fn = genExpr(i->op);
RegisterList args;
ExprPairList *p = i->pairs;
while (p) {
args.push_back(genExpr(p->value));
p = p->next;
}
ret = call(fn, args);
if (i->op->getKind() == ExprNode::dot) {
BinaryExprNode *b = static_cast<BinaryExprNode *>(i->op);
ret = methodCall(genExpr(b->op1), loadString(static_cast<IdentifierExprNode *>(b->op2)->name), args);
}
else
if (i->op->getKind() == ExprNode::identifier) {
if (!mWithinWith) {
TypedRegister v = findVariable((static_cast<IdentifierExprNode *>(i->op))->name);
if (v.first != NotARegister)
ret = call(v, static_cast<IdentifierExprNode *>(i->op)->name, args);
else
ret = call(TypedRegister(NotARegister, &Null_Type), static_cast<IdentifierExprNode *>(i->op)->name, args);
}
else
ret = methodCall(TypedRegister(NotARegister, &Null_Type), loadString(static_cast<IdentifierExprNode *>(i->op)->name), args);
}
else
if (i->op->getKind() == ExprNode::index) {
BinaryExprNode *b = static_cast<BinaryExprNode *>(i->op);
ret = methodCall(genExpr(b->op1), genExpr(b->op2), args);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::index :
@ -588,6 +624,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = getProperty(base, static_cast<IdentifierExprNode *>(b->op2)->name);
}
break;
case ExprNode::This :
{
ret = TypedRegister(0, &Any_Type);
}
break;
case ExprNode::identifier :
{
if (!mWithinWith) {
@ -644,6 +685,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = op(ADD, ret, loadImmediate(1.0));
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::postIncrement:
@ -673,6 +716,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
TypedRegister index = genExpr(b->op2);
ret = elementInc(base, index);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::preDecrement:
@ -712,6 +757,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = op(SUBTRACT, ret, loadImmediate(1.0));
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::postDecrement:
@ -741,6 +788,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
TypedRegister index = genExpr(b->op2);
ret = elementInc(base, index);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::plus:
@ -798,6 +847,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
TypedRegister index = genExpr(lb->op2);
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::addEquals:
@ -850,6 +901,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = op(mapExprNodeToICodeOp(p->getKind()), v, ret);
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::equal:
@ -988,7 +1041,6 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::objectLiteral:
{
ret = newObject();
PairListExprNode *plen = static_cast<PairListExprNode *>(p);
ExprPairList *e = plen->pairs;
while (e) {
@ -999,6 +1051,25 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
}
break;
case ExprNode::functionLiteral:
{
FunctionExprNode *f = static_cast<FunctionExprNode *>(p);
ICodeGenerator icg(mWorld, mGlobal);
icg.allocateParameter(mWorld->identifiers[widenCString("this")]); // always parameter #0
VariableBinding *v = f->function.parameters;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name);
v = v->next;
}
icg.preprocess(f->function.body);
icg.genStmt(f->function.body);
//stdOut << icg;
ICodeModule *icm = icg.complete();
ret = newFunction(icm);
}
break;
default:
{
NOT_REACHED("Unsupported ExprNode kind");
@ -1044,7 +1115,7 @@ void ICodeGenerator::preprocess(StmtNode *p)
VariableBinding *v = vs->bindings;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
if (v->type->getKind() == ExprNode::identifier)
if (v->type && (v->type->getKind() == ExprNode::identifier))
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name,
(static_cast<IdentifierExprNode *>(v->type))->name);
else
@ -1141,6 +1212,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
{
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(p);
ICodeGenerator icg(mWorld, mGlobal);
icg.allocateParameter(mWorld->identifiers[widenCString("this")]); // always parameter #0
VariableBinding *v = f->function.parameters;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
@ -1472,6 +1544,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
}
break;
case StmtNode::Class:
{
}
break;
default:
NOT_REACHED("unimplemented statement kind");
}

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

@ -219,8 +219,8 @@ namespace ICG {
TypedRegister op(ICodeOp op, TypedRegister source);
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister call(TypedRegister target, RegisterList args);
void callVoid(TypedRegister target, RegisterList args);
TypedRegister call(TypedRegister target, const StringAtom &name, RegisterList args);
TypedRegister methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList args);
void move(TypedRegister destination, TypedRegister source);
TypedRegister logicalNot(TypedRegister source);
@ -229,9 +229,11 @@ namespace ICG {
TypedRegister loadBoolean(bool value);
TypedRegister loadImmediate(double value);
TypedRegister loadString(String &value);
TypedRegister loadString(const StringAtom &name);
TypedRegister newObject();
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister loadName(const StringAtom &name);
void saveName(const StringAtom &name, TypedRegister value);

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

@ -89,12 +89,13 @@ struct Activation : public gc_base {
}
}
Activation(ICodeModule* iCode, Activation* caller,
Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg,
const RegisterList& list)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
// copy caller's parameter list to initial registers.
JSValues::iterator dest = mRegisters.begin();
*dest++ = thisArg;
const JSValues& params = caller->mRegisters;
for (RegisterList::const_iterator src = list.begin(),
end = list.end(); src != end; ++src, ++dest) {
@ -102,12 +103,6 @@ struct Activation : public gc_base {
}
}
Activation(ICodeModule* iCode, const JSValue arg)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
mRegisters[0] = arg;
}
Activation(ICodeModule* iCode, const JSValue arg1, const JSValue arg2)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
@ -489,26 +484,78 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
break;
case CALL:
case METHOD_CALL:
{
Call* call = static_cast<Call*>(instruction);
JSFunction *target = (*registers)[op2(call).first].function;
MethodCall* call = static_cast<MethodCall*>(instruction);
ASSERT((*registers)[op3(call).first].isString());
JSValue base;
JSValue prop;
if (op2(call).first == NotARegister) {
base = mGlobal->getReference(prop, *((*registers)[op3(call).first].string));
}
else {
base = (*registers)[op2(call).first];
ASSERT(base.tag == JSValue::object_tag); // XXX runtime error
base = base.object->getReference(prop, *((*registers)[op3(call).first].string));
}
ASSERT(prop.isFunction()); // XXX runtime error
JSFunction *target = prop.function;
if (target->isNative()) {
RegisterList &params = op3(call);
JSValues argv(params.size());
JSValues::size_type i = 0;
RegisterList &params = op4(call);
JSValues argv(params.size() + 1);
argv[0] = base;
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
}
if (op2(call).first != NotARegister)
(*registers)[op2(call).first] = static_cast<JSNativeFunction*>(target)->mCode(argv);
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(argv);
if (op1(call).first != NotARegister)
(*registers)[op1(call).first] = result;
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, op1(call));
mActivation = new Activation(target->getICode(), mActivation, op3(call));
mActivation = new Activation(target->getICode(), mActivation, base, op4(call));
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
}
}
case CALL:
{
Call* call = static_cast<Call*>(instruction);
JSFunction *target;
if (op2(call).first == NotARegister) {
ASSERT(mGlobal->getVariable(*op3(call)).isFunction());
target = mGlobal->getVariable(*op3(call)).function;
}
else {
ASSERT((*registers)[op2(call).first].isFunction()); // XXX runtime error
target = (*registers)[op2(call).first].function;
}
if (target->isNative()) {
RegisterList &params = op4(call);
JSValues argv(params.size() + 1);
argv[0] = kNull;
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
}
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(argv);
if (op1(call).first != NotARegister)
(*registers)[op1(call).first] = result;
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, op1(call));
mActivation = new Activation(target->getICode(), mActivation, kNull, op4(call));
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
@ -577,6 +624,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
(*registers)[dst(no).first] = JSValue(new JSObject());
}
break;
case NEW_FUNCTION:
{
NewFunction* nf = static_cast<NewFunction*>(instruction);
(*registers)[dst(nf).first] = JSValue(new JSFunction(src1(nf)));
}
break;
case NEW_ARRAY:
{
NewArray* na = static_cast<NewArray*>(instruction);
@ -591,6 +644,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSObject* object = value.object;
(*registers)[dst(gp).first] = object->getProperty(*src2(gp));
}
// XXX runtime error
}
break;
case SET_PROP:
@ -787,6 +841,7 @@ using JSString throughout.
(*registers)[dst(bn).first] = JSValue(~(*registers)[src1(bn).first].toInt32().i32);
}
break;
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
@ -794,6 +849,7 @@ using JSString throughout.
(*registers)[dst(nt).first] = JSValue(!(*registers)[src1(nt).first].boolean);
}
break;
case THROW:
{
Throw* thrw = static_cast<Throw*>(instruction);

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

@ -89,9 +89,9 @@ const bool showTokens = false;
static JSValue print(const JSValues &argv)
{
size_t n = argv.size();
if (n > 0) {
stdOut << argv[0];
for (size_t i = 1; i < n; ++i)
if (n > 1) { // the 'this' parameter in un-interesting
stdOut << argv[1];
for (size_t i = 2; i < n; ++i)
stdOut << ' ' << argv[i];
}
stdOut << "\n";
@ -99,13 +99,13 @@ static JSValue print(const JSValues &argv)
}
static void genCode(World &world, Context &cx, StmtNode *p)
static void genCode(Context &cx, StmtNode *p)
{
JSScope glob;
ICodeGenerator icg(&world, &glob);
ICodeGenerator icg(&cx.getWorld(), cx.getGlobalObject());
icg.isScript();
TypedRegister ret(NotARegister, &None_Type);
while (p) {
icg.preprocess(p);
ret = icg.genStmt(p);
p = p->next;
}
@ -160,7 +160,7 @@ static void readEvalPrint(FILE *in, World &world)
stdOut << '\n';
#if 0
// Generate code for parsedStatements, which is a linked list of zero or more statements
genCode(world, cx, parsedStatements);
genCode(cx, parsedStatements);
#endif
}
clear(buffer);
@ -232,9 +232,15 @@ void testCompile()
JSScope glob;
ICodeGenerator icg(&world, &glob);
icg.isScript();
while (parsedStatements) {
icg.genStmt(parsedStatements);
parsedStatements = parsedStatements->next;
StmtNode *s = parsedStatements;
while (s) {
icg.preprocess(s);
s = s->next;
}
s = parsedStatements;
while (s) {
icg.genStmt(s);
s = s->next;
}
cx.interpret(icg.complete(), JSValues());
}
@ -253,7 +259,7 @@ int main(int argc, char **argv)
#endif
using namespace JavaScript;
using namespace Shell;
#if 0
#if 1
testCompile();
#endif
readEvalPrint(stdin, world);

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

@ -45,6 +45,7 @@ const JSValue kUndefinedValue;
const JSValue kNaN = JSValue(nan);
const JSValue kTrue = JSValue(true);
const JSValue kFalse = JSValue(false);
const JSValue kNull = JSValue((JSObject*)NULL);
const JSType Any_Type = JSType(NULL);
const JSType Integer_Type = JSType(&Any_Type);
@ -94,6 +95,8 @@ const JSType *JSValue::getType() const
return &Integer_Type;
case JSValue::u32_tag:
return &Integer_Type;
case JSValue::integer_tag:
return &Integer_Type;
case JSValue::f64_tag:
return &Number_Type;
case JSValue::object_tag:
@ -123,6 +126,7 @@ bool JSValue::isNaN() const
case i32_tag:
case u32_tag:
return false;
case integer_tag:
case f64_tag:
return JSDOUBLE_IS_NaN(f64);
default:
@ -143,6 +147,7 @@ int JSValue::operator==(const JSValue& value) const
CASE(object); CASE(array); CASE(function); CASE(string);
CASE(boolean);
#undef CASE
case integer_tag : return (this->f64 == value.f64);
// question: are all undefined values equal to one another?
case undefined_tag: return 1;
}
@ -173,6 +178,7 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::u32_tag:
f << float64(value.u32);
break;
case JSValue::integer_tag:
case JSValue::f64_tag:
f << value.f64;
break;
@ -197,6 +203,34 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::undefined_tag:
f << "undefined";
break;
case JSValue::type_tag:
if (value.type == &Any_Type) // yuck (see yuck comment below)
f << "Any_Type";
else if (value.type == &Integer_Type)
f << "Integer_Type";
else if (value.type == &Number_Type)
f << "Number_Type";
else if (value.type == &Character_Type)
f << "Character_Type";
else if (value.type == &String_Type)
f << "String_Type";
else if (value.type == &Function_Type)
f << "Function_Type";
else if (value.type == &Array_Type)
f << "Array_Type";
else if (value.type == &Type_Type)
f << "Type_Type";
else if (value.type == &Boolean_Type)
f << "Boolean_Type";
else if (value.type == &Null_Type)
f << "Null_Type";
else if (value.type == &Void_Type)
f << "Void_Type";
else if (value.type == &None_Type)
f << "None_Type";
else
f << "Unknown_Type";
break;
default:
NOT_REACHED("Bad tag");
}
@ -209,6 +243,7 @@ JSValue JSValue::toPrimitive(ECMA_type /*hint*/) const
switch (tag) {
case i32_tag:
case u32_tag:
case integer_tag:
case f64_tag:
case string_tag:
case boolean_tag:
@ -258,6 +293,7 @@ JSValue JSValue::valueToString(const JSValue& value) // can assume value is not
case u32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0);
break;
case integer_tag:
case f64_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0);
break;
@ -291,6 +327,7 @@ JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not
return JSValue((float64)value.i32);
case u32_tag:
return JSValue((float64)value.u32);
case integer_tag:
case f64_tag:
return value;
case string_tag:
@ -316,6 +353,18 @@ JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not
}
}
JSValue JSValue::valueToInteger(const JSValue& value)
{
JSValue result = valueToNumber(value);
ASSERT(result.tag == f64_tag);
result.tag = i64_tag;
bool neg = (result.f64 < 0);
result.f64 = floor((neg) ? -result.f64 : result.f64);
result.f64 = (neg) ? -result.f64 : result.f64;
return result;
}
JSValue JSValue::valueToBoolean(const JSValue& value)
{
switch (value.tag) {
@ -323,6 +372,7 @@ JSValue JSValue::valueToBoolean(const JSValue& value)
return JSValue(value.i32 != 0);
case u32_tag:
return JSValue(value.u32 != 0);
case integer_tag:
case f64_tag:
return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64));
case string_tag:
@ -354,6 +404,7 @@ JSValue JSValue::valueToInt32(const JSValue& value)
case u32_tag:
d = value.u32;
break;
case integer_tag:
case f64_tag:
d = value.f64;
break;
@ -425,6 +476,22 @@ JSValue JSValue::valueToUInt32(const JSValue& value)
return JSValue((uint32)d);
}
JSValue JSValue::convert(const JSType *toType)
{
if (toType == &Any_Type) // yuck, something wrong with this
// maybe the base types should be
// a family of classes, not just instances
// of JSType ???
return *this;
else if (toType == &Integer_Type)
return valueToInteger(*this);
else
// etc...
return kUndefinedValue;
}
JSFunction::~JSFunction()
{
delete mICode;
@ -451,6 +518,13 @@ JSString::JSString(const char* str)
std::transform(str, str + n, begin(), JavaScript::widen);
}
JSString::operator String()
{
return String(begin(), size());
}
// # of sub-type relationship between this type and the other type
// (== MAX_INT if other is not a base type)

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

@ -93,6 +93,7 @@ namespace JSTypes {
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
integer_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
undefined_tag
} tag;
@ -122,10 +123,12 @@ namespace JSTypes {
bool isObject() const { return ((tag == object_tag) || (tag == function_tag) || (tag == array_tag)); }
bool isString() const { return (tag == string_tag); }
bool isBoolean() const { return (tag == boolean_tag); }
bool isNumber() const { return (tag == f64_tag); }
bool isNumber() const { return (tag == f64_tag) || (tag == integer_tag); }
/* this is correct wrt ECMA, The i32 & u32 kinds
will have to be converted to doubles anyway because
will have to be converted (to doubles?) anyway because
we can't have overflow happening in generic arithmetic */
bool isUndefined() const { return (tag == undefined_tag); }
bool isNull() const { return ((tag == object_tag) && (this->object == NULL)); }
bool isNaN() const;
@ -139,9 +142,12 @@ namespace JSTypes {
JSValue toPrimitive(ECMA_type hint = NoHint) const;
JSValue convert(const JSType *toType);
static JSValue valueToString(const JSValue& value);
static JSValue valueToNumber(const JSValue& value);
static JSValue valueToInteger(const JSValue& value);
static JSValue valueToInt32(const JSValue& value);
static JSValue valueToUInt32(const JSValue& value);
static JSValue valueToBoolean(const JSValue& value);
@ -176,6 +182,20 @@ namespace JSTypes {
extern const JSValue kNaN;
extern const JSValue kTrue;
extern const JSValue kFalse;
extern const JSValue kNull;
extern const JSType Any_Type;
extern const JSType Integer_Type;
extern const JSType Number_Type;
extern const JSType Character_Type;
extern const JSType String_Type;
extern const JSType Function_Type;
extern const JSType Array_Type;
extern const JSType Type_Type;
extern const JSType Boolean_Type;
extern const JSType Null_Type;
extern const JSType Void_Type;
extern const JSType None_Type;
/**
* Basic behavior of all JS objects, mapping a name to a value,
@ -204,6 +224,20 @@ namespace JSTypes {
return kUndefinedValue;
}
// return the property AND the object it's found in
// (would rather return references, but couldn't get that to work)
const JSValue getReference(JSValue &prop, const String& name)
{
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end()) {
prop = i->second;
return JSValue(this);
}
if (mPrototype)
return mPrototype->getReference(prop, name);
return kUndefinedValue;
}
JSValue& setProperty(const String& name, const JSValue& value)
{
return (mProperties[name] = value);
@ -329,6 +363,8 @@ namespace JSTypes {
explicit JSString(const String& str);
explicit JSString(const String* str);
explicit JSString(const char* str);
operator String();
};
class JSException : public gc_base {
@ -414,20 +450,6 @@ namespace JSTypes {
};
extern const JSType Any_Type;
extern const JSType Integer_Type;
extern const JSType Number_Type;
extern const JSType Character_Type;
extern const JSType String_Type;
extern const JSType Function_Type;
extern const JSType Array_Type;
extern const JSType Type_Type;
extern const JSType Boolean_Type;
extern const JSType Null_Type;
extern const JSType Void_Type;
extern const JSType None_Type;
} /* namespace JSTypes */
} /* namespace JavaScript */

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

@ -115,6 +115,12 @@ $ops{"NEW_OBJECT"} =
rem => "dest",
params => [ ("TypedRegister") ]
};
$ops{"NEW_FUNCTION"} =
{
super => "Instruction_2",
rem => "dest, ICodeModule",
params => [ ("TypedRegister", "ICodeModule *") ]
};
$ops{"NEW_ARRAY"} =
{
super => "Instruction_1",
@ -216,9 +222,15 @@ $ops{"RETURN_VOID"} =
};
$ops{"CALL"} =
{
super => "Instruction_3",
rem => "result, target, args",
params => [ ("TypedRegister" , "TypedRegister", "RegisterList") ]
super => "Instruction_4",
rem => "result, target, name, args",
params => [ ("TypedRegister" , "TypedRegister", "const StringAtom*", "RegisterList") ]
};
$ops{"METHOD_CALL"} =
{
super => "Instruction_4",
rem => "result, target base, target value, args",
params => [ ("TypedRegister" , "TypedRegister" , "TypedRegister", "RegisterList") ]
};
$ops{"THROW"} =
{
@ -452,6 +464,8 @@ sub get_print_body {
push (@oplist, "\"'\" << *mOp$op << \"'\"");
} elsif ($type =~ /bool/) {
push (@oplist, "\"'\" << ((mOp$op) ? \"true\" : \"false\") << \"'\"");
} elsif ($type =~ /ICodeModule/) {
push (@oplist, "\"ICodeModule\"");
} else {
push (@oplist, "mOp$op");
}

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

@ -58,7 +58,7 @@ namespace VM {
BRANCH, /* target label */
BRANCH_FALSE, /* target label, condition */
BRANCH_TRUE, /* target label, condition */
CALL, /* result, target, args */
CALL, /* result, target, name, args */
COMPARE_EQ, /* dest, source1, source2 */
COMPARE_GE, /* dest, source1, source2 */
COMPARE_GT, /* dest, source1, source2 */
@ -77,11 +77,13 @@ namespace VM {
LOAD_IMMEDIATE, /* dest, immediate value (double) */
LOAD_NAME, /* dest, name */
LOAD_STRING, /* dest, immediate value (string) */
METHOD_CALL, /* result, target base, target value, args */
MOVE, /* dest, source */
MULTIPLY, /* dest, source1, source2 */
NAME_XCR, /* dest, name, value */
NEGATE, /* dest, source */
NEW_ARRAY, /* dest */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_OBJECT, /* dest */
NOP, /* do nothing and like it */
NOT, /* dest, source */
@ -139,11 +141,13 @@ namespace VM {
"LOAD_IMMEDIATE",
"LOAD_NAME ",
"LOAD_STRING ",
"METHOD_CALL ",
"MOVE ",
"MULTIPLY ",
"NAME_XCR ",
"NEGATE ",
"NEW_ARRAY ",
"NEW_FUNCTION ",
"NEW_OBJECT ",
"NOP ",
"NOT ",
@ -472,18 +476,18 @@ namespace VM {
/* print() and printOperands() inherited from GenericBranch */
};
class Call : public Instruction_3<TypedRegister, TypedRegister, RegisterList> {
class Call : public Instruction_4<TypedRegister, TypedRegister, const StringAtom*, RegisterList> {
public:
/* result, target, args */
Call (TypedRegister aOp1, TypedRegister aOp2, RegisterList aOp3) :
Instruction_3<TypedRegister, TypedRegister, RegisterList>
(CALL, aOp1, aOp2, aOp3) {};
/* result, target, name, args */
Call (TypedRegister aOp1, TypedRegister aOp2, const StringAtom* aOp3, RegisterList aOp4) :
Instruction_4<TypedRegister, TypedRegister, const StringAtom*, RegisterList>
(CALL, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[CALL] << "\t" << "R" << mOp1.first << ", " << "R" << mOp2.first << ", " << mOp3;
f << opcodeNames[CALL] << "\t" << "R" << mOp1.first << ", " << "R" << mOp2.first << ", " << "'" << *mOp3 << "'" << ", " << mOp4;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << ArgList(mOp3, registers);
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << ArgList(mOp4, registers);
return f;
}
};
@ -696,6 +700,22 @@ namespace VM {
}
};
class MethodCall : public Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList> {
public:
/* result, target base, target value, args */
MethodCall (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, RegisterList aOp4) :
Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList>
(METHOD_CALL, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[METHOD_CALL] << "\t" << "R" << mOp1.first << ", " << "R" << mOp2.first << ", " << "R" << mOp3.first << ", " << mOp4;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first] << ", " << ArgList(mOp4, registers);
return f;
}
};
class Move : public Instruction_2<TypedRegister, TypedRegister> {
public:
/* dest, source */
@ -769,6 +789,22 @@ namespace VM {
}
};
class NewFunction : public Instruction_2<TypedRegister, ICodeModule *> {
public:
/* dest, ICodeModule */
NewFunction (TypedRegister aOp1, ICodeModule * aOp2) :
Instruction_2<TypedRegister, ICodeModule *>
(NEW_FUNCTION, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_FUNCTION] << "\t" << "R" << mOp1.first << ", " << "ICodeModule";
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1.first << '=' << registers[mOp1.first];
return f;
}
};
class NewObject : public Instruction_1<TypedRegister> {
public:
/* dest */
@ -1132,6 +1168,7 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
} /* namespace VM */
} /* namespace JavaScript */

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

@ -159,6 +159,14 @@ TypedRegister ICodeGenerator::loadString(String &value)
return dest;
}
TypedRegister ICodeGenerator::loadString(const StringAtom &value)
{
TypedRegister dest(getRegister(), &String_Type);
LoadString *instr = new LoadString(dest, new JSString(value));
iCode->push_back(instr);
return dest;
}
TypedRegister ICodeGenerator::loadBoolean(bool value)
{
TypedRegister dest(getRegister(), &Boolean_Type);
@ -175,6 +183,14 @@ TypedRegister ICodeGenerator::newObject()
return dest;
}
TypedRegister ICodeGenerator::newFunction(ICodeModule *icm)
{
TypedRegister dest(getRegister(), &Function_Type);
NewFunction *instr = new NewFunction(dest, icm);
iCode->push_back(instr);
return dest;
}
TypedRegister ICodeGenerator::newArray()
{
TypedRegister dest(getRegister(), &Array_Type);
@ -183,8 +199,6 @@ TypedRegister ICodeGenerator::newArray()
return dest;
}
TypedRegister ICodeGenerator::loadName(const StringAtom &name)
{
TypedRegister dest(getRegister(), &Any_Type);
@ -343,18 +357,20 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1,
return dest;
}
TypedRegister ICodeGenerator::call(TypedRegister target, RegisterList args)
TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList args)
{
TypedRegister dest(getRegister(), &Any_Type);
Call *instr = new Call(dest, target, args);
Call *instr = new Call(dest, target, &name, args);
iCode->push_back(instr);
return dest;
}
void ICodeGenerator::callVoid(TypedRegister target, RegisterList args)
TypedRegister ICodeGenerator::methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList args)
{
Call *instr = new Call(TypedRegister(NotARegister, &Void_Type), target, args);
TypedRegister dest(getRegister(), &Any_Type);
MethodCall *instr = new MethodCall(dest, targetBase, targetValue, args);
iCode->push_back(instr);
return dest;
}
void ICodeGenerator::branch(Label *label)
@ -514,8 +530,6 @@ static bool generatedBoolean(ExprNode *p)
return false;
}
/*
if trueBranch OR falseBranch are not null, the sub-expression should generate
a conditional branch to the appropriate target. If either branch is NULL, it
@ -563,14 +577,36 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::call :
{
InvokeExprNode *i = static_cast<InvokeExprNode *>(p);
TypedRegister fn = genExpr(i->op);
RegisterList args;
ExprPairList *p = i->pairs;
while (p) {
args.push_back(genExpr(p->value));
p = p->next;
}
ret = call(fn, args);
if (i->op->getKind() == ExprNode::dot) {
BinaryExprNode *b = static_cast<BinaryExprNode *>(i->op);
ret = methodCall(genExpr(b->op1), loadString(static_cast<IdentifierExprNode *>(b->op2)->name), args);
}
else
if (i->op->getKind() == ExprNode::identifier) {
if (!mWithinWith) {
TypedRegister v = findVariable((static_cast<IdentifierExprNode *>(i->op))->name);
if (v.first != NotARegister)
ret = call(v, static_cast<IdentifierExprNode *>(i->op)->name, args);
else
ret = call(TypedRegister(NotARegister, &Null_Type), static_cast<IdentifierExprNode *>(i->op)->name, args);
}
else
ret = methodCall(TypedRegister(NotARegister, &Null_Type), loadString(static_cast<IdentifierExprNode *>(i->op)->name), args);
}
else
if (i->op->getKind() == ExprNode::index) {
BinaryExprNode *b = static_cast<BinaryExprNode *>(i->op);
ret = methodCall(genExpr(b->op1), genExpr(b->op2), args);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::index :
@ -588,6 +624,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = getProperty(base, static_cast<IdentifierExprNode *>(b->op2)->name);
}
break;
case ExprNode::This :
{
ret = TypedRegister(0, &Any_Type);
}
break;
case ExprNode::identifier :
{
if (!mWithinWith) {
@ -644,6 +685,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = op(ADD, ret, loadImmediate(1.0));
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::postIncrement:
@ -673,6 +716,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
TypedRegister index = genExpr(b->op2);
ret = elementInc(base, index);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::preDecrement:
@ -712,6 +757,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = op(SUBTRACT, ret, loadImmediate(1.0));
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::postDecrement:
@ -741,6 +788,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
TypedRegister index = genExpr(b->op2);
ret = elementInc(base, index);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::plus:
@ -798,6 +847,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
TypedRegister index = genExpr(lb->op2);
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::addEquals:
@ -850,6 +901,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
ret = op(mapExprNodeToICodeOp(p->getKind()), v, ret);
setElement(base, index, ret);
}
else
ASSERT("WAH!");
}
break;
case ExprNode::equal:
@ -988,7 +1041,6 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
case ExprNode::objectLiteral:
{
ret = newObject();
PairListExprNode *plen = static_cast<PairListExprNode *>(p);
ExprPairList *e = plen->pairs;
while (e) {
@ -999,6 +1051,25 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p,
}
break;
case ExprNode::functionLiteral:
{
FunctionExprNode *f = static_cast<FunctionExprNode *>(p);
ICodeGenerator icg(mWorld, mGlobal);
icg.allocateParameter(mWorld->identifiers[widenCString("this")]); // always parameter #0
VariableBinding *v = f->function.parameters;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
icg.allocateParameter((static_cast<IdentifierExprNode *>(v->name))->name);
v = v->next;
}
icg.preprocess(f->function.body);
icg.genStmt(f->function.body);
//stdOut << icg;
ICodeModule *icm = icg.complete();
ret = newFunction(icm);
}
break;
default:
{
NOT_REACHED("Unsupported ExprNode kind");
@ -1044,7 +1115,7 @@ void ICodeGenerator::preprocess(StmtNode *p)
VariableBinding *v = vs->bindings;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
if (v->type->getKind() == ExprNode::identifier)
if (v->type && (v->type->getKind() == ExprNode::identifier))
allocateVariable((static_cast<IdentifierExprNode *>(v->name))->name,
(static_cast<IdentifierExprNode *>(v->type))->name);
else
@ -1141,6 +1212,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
{
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(p);
ICodeGenerator icg(mWorld, mGlobal);
icg.allocateParameter(mWorld->identifiers[widenCString("this")]); // always parameter #0
VariableBinding *v = f->function.parameters;
while (v) {
if (v->name && (v->name->getKind() == ExprNode::identifier))
@ -1472,6 +1544,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
}
break;
case StmtNode::Class:
{
}
break;
default:
NOT_REACHED("unimplemented statement kind");
}

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

@ -219,8 +219,8 @@ namespace ICG {
TypedRegister op(ICodeOp op, TypedRegister source);
TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2);
TypedRegister call(TypedRegister target, RegisterList args);
void callVoid(TypedRegister target, RegisterList args);
TypedRegister call(TypedRegister target, const StringAtom &name, RegisterList args);
TypedRegister methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList args);
void move(TypedRegister destination, TypedRegister source);
TypedRegister logicalNot(TypedRegister source);
@ -229,9 +229,11 @@ namespace ICG {
TypedRegister loadBoolean(bool value);
TypedRegister loadImmediate(double value);
TypedRegister loadString(String &value);
TypedRegister loadString(const StringAtom &name);
TypedRegister newObject();
TypedRegister newArray();
TypedRegister newFunction(ICodeModule *icm);
TypedRegister loadName(const StringAtom &name);
void saveName(const StringAtom &name, TypedRegister value);

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

@ -89,12 +89,13 @@ struct Activation : public gc_base {
}
}
Activation(ICodeModule* iCode, Activation* caller,
Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg,
const RegisterList& list)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
// copy caller's parameter list to initial registers.
JSValues::iterator dest = mRegisters.begin();
*dest++ = thisArg;
const JSValues& params = caller->mRegisters;
for (RegisterList::const_iterator src = list.begin(),
end = list.end(); src != end; ++src, ++dest) {
@ -102,12 +103,6 @@ struct Activation : public gc_base {
}
}
Activation(ICodeModule* iCode, const JSValue arg)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
mRegisters[0] = arg;
}
Activation(ICodeModule* iCode, const JSValue arg1, const JSValue arg2)
: mRegisters(iCode->itsMaxRegister + 1), mICode(iCode)
{
@ -489,26 +484,78 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
}
break;
case CALL:
case METHOD_CALL:
{
Call* call = static_cast<Call*>(instruction);
JSFunction *target = (*registers)[op2(call).first].function;
MethodCall* call = static_cast<MethodCall*>(instruction);
ASSERT((*registers)[op3(call).first].isString());
JSValue base;
JSValue prop;
if (op2(call).first == NotARegister) {
base = mGlobal->getReference(prop, *((*registers)[op3(call).first].string));
}
else {
base = (*registers)[op2(call).first];
ASSERT(base.tag == JSValue::object_tag); // XXX runtime error
base = base.object->getReference(prop, *((*registers)[op3(call).first].string));
}
ASSERT(prop.isFunction()); // XXX runtime error
JSFunction *target = prop.function;
if (target->isNative()) {
RegisterList &params = op3(call);
JSValues argv(params.size());
JSValues::size_type i = 0;
RegisterList &params = op4(call);
JSValues argv(params.size() + 1);
argv[0] = base;
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
}
if (op2(call).first != NotARegister)
(*registers)[op2(call).first] = static_cast<JSNativeFunction*>(target)->mCode(argv);
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(argv);
if (op1(call).first != NotARegister)
(*registers)[op1(call).first] = result;
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, op1(call));
mActivation = new Activation(target->getICode(), mActivation, op3(call));
mActivation = new Activation(target->getICode(), mActivation, base, op4(call));
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
}
}
case CALL:
{
Call* call = static_cast<Call*>(instruction);
JSFunction *target;
if (op2(call).first == NotARegister) {
ASSERT(mGlobal->getVariable(*op3(call)).isFunction());
target = mGlobal->getVariable(*op3(call)).function;
}
else {
ASSERT((*registers)[op2(call).first].isFunction()); // XXX runtime error
target = (*registers)[op2(call).first].function;
}
if (target->isNative()) {
RegisterList &params = op4(call);
JSValues argv(params.size() + 1);
argv[0] = kNull;
JSValues::size_type i = 1;
for (RegisterList::const_iterator src = params.begin(), end = params.end();
src != end; ++src, ++i) {
argv[i] = (*registers)[src->first];
}
JSValue result = static_cast<JSNativeFunction*>(target)->mCode(argv);
if (op1(call).first != NotARegister)
(*registers)[op1(call).first] = result;
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, op1(call));
mActivation = new Activation(target->getICode(), mActivation, kNull, op4(call));
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
@ -577,6 +624,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
(*registers)[dst(no).first] = JSValue(new JSObject());
}
break;
case NEW_FUNCTION:
{
NewFunction* nf = static_cast<NewFunction*>(instruction);
(*registers)[dst(nf).first] = JSValue(new JSFunction(src1(nf)));
}
break;
case NEW_ARRAY:
{
NewArray* na = static_cast<NewArray*>(instruction);
@ -591,6 +644,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args)
JSObject* object = value.object;
(*registers)[dst(gp).first] = object->getProperty(*src2(gp));
}
// XXX runtime error
}
break;
case SET_PROP:
@ -787,6 +841,7 @@ using JSString throughout.
(*registers)[dst(bn).first] = JSValue(~(*registers)[src1(bn).first].toInt32().i32);
}
break;
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
@ -794,6 +849,7 @@ using JSString throughout.
(*registers)[dst(nt).first] = JSValue(!(*registers)[src1(nt).first].boolean);
}
break;
case THROW:
{
Throw* thrw = static_cast<Throw*>(instruction);

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

@ -45,6 +45,7 @@ const JSValue kUndefinedValue;
const JSValue kNaN = JSValue(nan);
const JSValue kTrue = JSValue(true);
const JSValue kFalse = JSValue(false);
const JSValue kNull = JSValue((JSObject*)NULL);
const JSType Any_Type = JSType(NULL);
const JSType Integer_Type = JSType(&Any_Type);
@ -94,6 +95,8 @@ const JSType *JSValue::getType() const
return &Integer_Type;
case JSValue::u32_tag:
return &Integer_Type;
case JSValue::integer_tag:
return &Integer_Type;
case JSValue::f64_tag:
return &Number_Type;
case JSValue::object_tag:
@ -123,6 +126,7 @@ bool JSValue::isNaN() const
case i32_tag:
case u32_tag:
return false;
case integer_tag:
case f64_tag:
return JSDOUBLE_IS_NaN(f64);
default:
@ -143,6 +147,7 @@ int JSValue::operator==(const JSValue& value) const
CASE(object); CASE(array); CASE(function); CASE(string);
CASE(boolean);
#undef CASE
case integer_tag : return (this->f64 == value.f64);
// question: are all undefined values equal to one another?
case undefined_tag: return 1;
}
@ -173,6 +178,7 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::u32_tag:
f << float64(value.u32);
break;
case JSValue::integer_tag:
case JSValue::f64_tag:
f << value.f64;
break;
@ -197,6 +203,34 @@ Formatter& operator<<(Formatter& f, const JSValue& value)
case JSValue::undefined_tag:
f << "undefined";
break;
case JSValue::type_tag:
if (value.type == &Any_Type) // yuck (see yuck comment below)
f << "Any_Type";
else if (value.type == &Integer_Type)
f << "Integer_Type";
else if (value.type == &Number_Type)
f << "Number_Type";
else if (value.type == &Character_Type)
f << "Character_Type";
else if (value.type == &String_Type)
f << "String_Type";
else if (value.type == &Function_Type)
f << "Function_Type";
else if (value.type == &Array_Type)
f << "Array_Type";
else if (value.type == &Type_Type)
f << "Type_Type";
else if (value.type == &Boolean_Type)
f << "Boolean_Type";
else if (value.type == &Null_Type)
f << "Null_Type";
else if (value.type == &Void_Type)
f << "Void_Type";
else if (value.type == &None_Type)
f << "None_Type";
else
f << "Unknown_Type";
break;
default:
NOT_REACHED("Bad tag");
}
@ -209,6 +243,7 @@ JSValue JSValue::toPrimitive(ECMA_type /*hint*/) const
switch (tag) {
case i32_tag:
case u32_tag:
case integer_tag:
case f64_tag:
case string_tag:
case boolean_tag:
@ -258,6 +293,7 @@ JSValue JSValue::valueToString(const JSValue& value) // can assume value is not
case u32_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.u32, dtosStandard, 0);
break;
case integer_tag:
case f64_tag:
chrp = doubleToStr(buf, dtosStandardBufferSize, value.f64, dtosStandard, 0);
break;
@ -291,6 +327,7 @@ JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not
return JSValue((float64)value.i32);
case u32_tag:
return JSValue((float64)value.u32);
case integer_tag:
case f64_tag:
return value;
case string_tag:
@ -316,6 +353,18 @@ JSValue JSValue::valueToNumber(const JSValue& value) // can assume value is not
}
}
JSValue JSValue::valueToInteger(const JSValue& value)
{
JSValue result = valueToNumber(value);
ASSERT(result.tag == f64_tag);
result.tag = i64_tag;
bool neg = (result.f64 < 0);
result.f64 = floor((neg) ? -result.f64 : result.f64);
result.f64 = (neg) ? -result.f64 : result.f64;
return result;
}
JSValue JSValue::valueToBoolean(const JSValue& value)
{
switch (value.tag) {
@ -323,6 +372,7 @@ JSValue JSValue::valueToBoolean(const JSValue& value)
return JSValue(value.i32 != 0);
case u32_tag:
return JSValue(value.u32 != 0);
case integer_tag:
case f64_tag:
return JSValue(!(value.f64 == 0.0) || JSDOUBLE_IS_NaN(value.f64));
case string_tag:
@ -354,6 +404,7 @@ JSValue JSValue::valueToInt32(const JSValue& value)
case u32_tag:
d = value.u32;
break;
case integer_tag:
case f64_tag:
d = value.f64;
break;
@ -425,6 +476,22 @@ JSValue JSValue::valueToUInt32(const JSValue& value)
return JSValue((uint32)d);
}
JSValue JSValue::convert(const JSType *toType)
{
if (toType == &Any_Type) // yuck, something wrong with this
// maybe the base types should be
// a family of classes, not just instances
// of JSType ???
return *this;
else if (toType == &Integer_Type)
return valueToInteger(*this);
else
// etc...
return kUndefinedValue;
}
JSFunction::~JSFunction()
{
delete mICode;
@ -451,6 +518,13 @@ JSString::JSString(const char* str)
std::transform(str, str + n, begin(), JavaScript::widen);
}
JSString::operator String()
{
return String(begin(), size());
}
// # of sub-type relationship between this type and the other type
// (== MAX_INT if other is not a base type)

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

@ -93,6 +93,7 @@ namespace JSTypes {
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
integer_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
undefined_tag
} tag;
@ -122,10 +123,12 @@ namespace JSTypes {
bool isObject() const { return ((tag == object_tag) || (tag == function_tag) || (tag == array_tag)); }
bool isString() const { return (tag == string_tag); }
bool isBoolean() const { return (tag == boolean_tag); }
bool isNumber() const { return (tag == f64_tag); }
bool isNumber() const { return (tag == f64_tag) || (tag == integer_tag); }
/* this is correct wrt ECMA, The i32 & u32 kinds
will have to be converted to doubles anyway because
will have to be converted (to doubles?) anyway because
we can't have overflow happening in generic arithmetic */
bool isUndefined() const { return (tag == undefined_tag); }
bool isNull() const { return ((tag == object_tag) && (this->object == NULL)); }
bool isNaN() const;
@ -139,9 +142,12 @@ namespace JSTypes {
JSValue toPrimitive(ECMA_type hint = NoHint) const;
JSValue convert(const JSType *toType);
static JSValue valueToString(const JSValue& value);
static JSValue valueToNumber(const JSValue& value);
static JSValue valueToInteger(const JSValue& value);
static JSValue valueToInt32(const JSValue& value);
static JSValue valueToUInt32(const JSValue& value);
static JSValue valueToBoolean(const JSValue& value);
@ -176,6 +182,20 @@ namespace JSTypes {
extern const JSValue kNaN;
extern const JSValue kTrue;
extern const JSValue kFalse;
extern const JSValue kNull;
extern const JSType Any_Type;
extern const JSType Integer_Type;
extern const JSType Number_Type;
extern const JSType Character_Type;
extern const JSType String_Type;
extern const JSType Function_Type;
extern const JSType Array_Type;
extern const JSType Type_Type;
extern const JSType Boolean_Type;
extern const JSType Null_Type;
extern const JSType Void_Type;
extern const JSType None_Type;
/**
* Basic behavior of all JS objects, mapping a name to a value,
@ -204,6 +224,20 @@ namespace JSTypes {
return kUndefinedValue;
}
// return the property AND the object it's found in
// (would rather return references, but couldn't get that to work)
const JSValue getReference(JSValue &prop, const String& name)
{
JSProperties::const_iterator i = mProperties.find(name);
if (i != mProperties.end()) {
prop = i->second;
return JSValue(this);
}
if (mPrototype)
return mPrototype->getReference(prop, name);
return kUndefinedValue;
}
JSValue& setProperty(const String& name, const JSValue& value)
{
return (mProperties[name] = value);
@ -329,6 +363,8 @@ namespace JSTypes {
explicit JSString(const String& str);
explicit JSString(const String* str);
explicit JSString(const char* str);
operator String();
};
class JSException : public gc_base {
@ -414,20 +450,6 @@ namespace JSTypes {
};
extern const JSType Any_Type;
extern const JSType Integer_Type;
extern const JSType Number_Type;
extern const JSType Character_Type;
extern const JSType String_Type;
extern const JSType Function_Type;
extern const JSType Array_Type;
extern const JSType Type_Type;
extern const JSType Boolean_Type;
extern const JSType Null_Type;
extern const JSType Void_Type;
extern const JSType None_Type;
} /* namespace JSTypes */
} /* namespace JavaScript */

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

@ -58,7 +58,7 @@ namespace VM {
BRANCH, /* target label */
BRANCH_FALSE, /* target label, condition */
BRANCH_TRUE, /* target label, condition */
CALL, /* result, target, args */
CALL, /* result, target, name, args */
COMPARE_EQ, /* dest, source1, source2 */
COMPARE_GE, /* dest, source1, source2 */
COMPARE_GT, /* dest, source1, source2 */
@ -77,11 +77,13 @@ namespace VM {
LOAD_IMMEDIATE, /* dest, immediate value (double) */
LOAD_NAME, /* dest, name */
LOAD_STRING, /* dest, immediate value (string) */
METHOD_CALL, /* result, target base, target value, args */
MOVE, /* dest, source */
MULTIPLY, /* dest, source1, source2 */
NAME_XCR, /* dest, name, value */
NEGATE, /* dest, source */
NEW_ARRAY, /* dest */
NEW_FUNCTION, /* dest, ICodeModule */
NEW_OBJECT, /* dest */
NOP, /* do nothing and like it */
NOT, /* dest, source */
@ -139,11 +141,13 @@ namespace VM {
"LOAD_IMMEDIATE",
"LOAD_NAME ",
"LOAD_STRING ",
"METHOD_CALL ",
"MOVE ",
"MULTIPLY ",
"NAME_XCR ",
"NEGATE ",
"NEW_ARRAY ",
"NEW_FUNCTION ",
"NEW_OBJECT ",
"NOP ",
"NOT ",
@ -472,18 +476,18 @@ namespace VM {
/* print() and printOperands() inherited from GenericBranch */
};
class Call : public Instruction_3<TypedRegister, TypedRegister, RegisterList> {
class Call : public Instruction_4<TypedRegister, TypedRegister, const StringAtom*, RegisterList> {
public:
/* result, target, args */
Call (TypedRegister aOp1, TypedRegister aOp2, RegisterList aOp3) :
Instruction_3<TypedRegister, TypedRegister, RegisterList>
(CALL, aOp1, aOp2, aOp3) {};
/* result, target, name, args */
Call (TypedRegister aOp1, TypedRegister aOp2, const StringAtom* aOp3, RegisterList aOp4) :
Instruction_4<TypedRegister, TypedRegister, const StringAtom*, RegisterList>
(CALL, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[CALL] << "\t" << "R" << mOp1.first << ", " << "R" << mOp2.first << ", " << mOp3;
f << opcodeNames[CALL] << "\t" << "R" << mOp1.first << ", " << "R" << mOp2.first << ", " << "'" << *mOp3 << "'" << ", " << mOp4;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << ArgList(mOp3, registers);
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << ArgList(mOp4, registers);
return f;
}
};
@ -696,6 +700,22 @@ namespace VM {
}
};
class MethodCall : public Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList> {
public:
/* result, target base, target value, args */
MethodCall (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, RegisterList aOp4) :
Instruction_4<TypedRegister, TypedRegister, TypedRegister, RegisterList>
(METHOD_CALL, aOp1, aOp2, aOp3, aOp4) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[METHOD_CALL] << "\t" << "R" << mOp1.first << ", " << "R" << mOp2.first << ", " << "R" << mOp3.first << ", " << mOp4;
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp2.first << '=' << registers[mOp2.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first] << ", " << ArgList(mOp4, registers);
return f;
}
};
class Move : public Instruction_2<TypedRegister, TypedRegister> {
public:
/* dest, source */
@ -769,6 +789,22 @@ namespace VM {
}
};
class NewFunction : public Instruction_2<TypedRegister, ICodeModule *> {
public:
/* dest, ICodeModule */
NewFunction (TypedRegister aOp1, ICodeModule * aOp2) :
Instruction_2<TypedRegister, ICodeModule *>
(NEW_FUNCTION, aOp1, aOp2) {};
virtual Formatter& print(Formatter& f) {
f << opcodeNames[NEW_FUNCTION] << "\t" << "R" << mOp1.first << ", " << "ICodeModule";
return f;
}
virtual Formatter& printOperands(Formatter& f, const JSValues& registers) {
f << "R" << mOp1.first << '=' << registers[mOp1.first];
return f;
}
};
class NewObject : public Instruction_1<TypedRegister> {
public:
/* dest */
@ -1132,6 +1168,7 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
} /* namespace VM */
} /* namespace JavaScript */

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

@ -89,9 +89,9 @@ const bool showTokens = false;
static JSValue print(const JSValues &argv)
{
size_t n = argv.size();
if (n > 0) {
stdOut << argv[0];
for (size_t i = 1; i < n; ++i)
if (n > 1) { // the 'this' parameter in un-interesting
stdOut << argv[1];
for (size_t i = 2; i < n; ++i)
stdOut << ' ' << argv[i];
}
stdOut << "\n";
@ -99,13 +99,13 @@ static JSValue print(const JSValues &argv)
}
static void genCode(World &world, Context &cx, StmtNode *p)
static void genCode(Context &cx, StmtNode *p)
{
JSScope glob;
ICodeGenerator icg(&world, &glob);
ICodeGenerator icg(&cx.getWorld(), cx.getGlobalObject());
icg.isScript();
TypedRegister ret(NotARegister, &None_Type);
while (p) {
icg.preprocess(p);
ret = icg.genStmt(p);
p = p->next;
}
@ -160,7 +160,7 @@ static void readEvalPrint(FILE *in, World &world)
stdOut << '\n';
#if 0
// Generate code for parsedStatements, which is a linked list of zero or more statements
genCode(world, cx, parsedStatements);
genCode(cx, parsedStatements);
#endif
}
clear(buffer);
@ -232,9 +232,15 @@ void testCompile()
JSScope glob;
ICodeGenerator icg(&world, &glob);
icg.isScript();
while (parsedStatements) {
icg.genStmt(parsedStatements);
parsedStatements = parsedStatements->next;
StmtNode *s = parsedStatements;
while (s) {
icg.preprocess(s);
s = s->next;
}
s = parsedStatements;
while (s) {
icg.genStmt(s);
s = s->next;
}
cx.interpret(icg.complete(), JSValues());
}
@ -253,7 +259,7 @@ int main(int argc, char **argv)
#endif
using namespace JavaScript;
using namespace Shell;
#if 0
#if 1
testCompile();
#endif
readEvalPrint(stdin, world);

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

@ -115,6 +115,12 @@ $ops{"NEW_OBJECT"} =
rem => "dest",
params => [ ("TypedRegister") ]
};
$ops{"NEW_FUNCTION"} =
{
super => "Instruction_2",
rem => "dest, ICodeModule",
params => [ ("TypedRegister", "ICodeModule *") ]
};
$ops{"NEW_ARRAY"} =
{
super => "Instruction_1",
@ -216,9 +222,15 @@ $ops{"RETURN_VOID"} =
};
$ops{"CALL"} =
{
super => "Instruction_3",
rem => "result, target, args",
params => [ ("TypedRegister" , "TypedRegister", "RegisterList") ]
super => "Instruction_4",
rem => "result, target, name, args",
params => [ ("TypedRegister" , "TypedRegister", "const StringAtom*", "RegisterList") ]
};
$ops{"METHOD_CALL"} =
{
super => "Instruction_4",
rem => "result, target base, target value, args",
params => [ ("TypedRegister" , "TypedRegister" , "TypedRegister", "RegisterList") ]
};
$ops{"THROW"} =
{
@ -452,6 +464,8 @@ sub get_print_body {
push (@oplist, "\"'\" << *mOp$op << \"'\"");
} elsif ($type =~ /bool/) {
push (@oplist, "\"'\" << ((mOp$op) ? \"true\" : \"false\") << \"'\"");
} elsif ($type =~ /ICodeModule/) {
push (@oplist, "\"ICodeModule\"");
} else {
push (@oplist, "mOp$op");
}