Added operator overloading support

This commit is contained in:
rogerl%netscape.com 2000-05-23 00:08:29 +00:00
Родитель e562e8eb21
Коммит 932d63213b
12 изменённых файлов: 760 добавлений и 696 удалений

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

@ -284,10 +284,11 @@ Register ICodeGenerator::op(ICodeOp op, Register source)
{
Register dest = getRegister();
ASSERT(source != NotARegister);
Compare *instr = new Compare (op, dest, source);
Unary *instr = new Unary (op, dest, source);
iCode->push_back(instr);
return dest;
}
void ICodeGenerator::move(Register destination, Register source)
{
@ -295,12 +296,14 @@ void ICodeGenerator::move(Register destination, Register source)
ASSERT(source != NotARegister);
Move *instr = new Move(destination, source);
iCode->push_back(instr);
}
}
void ICodeGenerator::complement(Register destination, Register source)
Register ICodeGenerator::not(Register source)
{
Not *instr = new Not(destination, source);
Register dest = getRegister();
Not *instr = new Not(dest, source);
iCode->push_back(instr);
return dest;
}
Register ICodeGenerator::test(Register source)
@ -921,30 +924,33 @@ ICodeOp ICodeGenerator::mapExprNodeToICodeOp(ExprNode::Kind kind)
case ExprNode::minus:
return NEGATE;
case ExprNode::complement:
return NOT;
return BITNOT;
// relational
case ExprNode::equal:
return COMPARE_EQ;
case ExprNode::notEqual:
return COMPARE_NE;
case ExprNode::lessThan:
return COMPARE_LT;
case ExprNode::lessThanOrEqual:
return COMPARE_LE;
case ExprNode::greaterThan:
return COMPARE_GT;
case ExprNode::greaterThanOrEqual:
return COMPARE_GE;
case ExprNode::identical:
return STRICT_EQ;
case ExprNode::notIdentical:
return STRICT_NE;
case ExprNode::In:
return COMPARE_IN;
case ExprNode::Instanceof:
return INSTANCEOF;
case ExprNode::equal:
return COMPARE_EQ;
case ExprNode::lessThan:
return COMPARE_LT;
case ExprNode::lessThanOrEqual:
return COMPARE_LE;
case ExprNode::identical:
return STRICT_EQ;
// these get reversed by the generator
case ExprNode::notEqual:
return COMPARE_EQ;
case ExprNode::greaterThan:
return COMPARE_LT;
case ExprNode::greaterThanOrEqual:
return COMPARE_LE;
case ExprNode::notIdentical:
return STRICT_EQ;
default:
NOT_REACHED("Unimplemented kind");
@ -1155,13 +1161,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
}
break;
case ExprNode::equal:
case ExprNode::notEqual:
case ExprNode::lessThan:
case ExprNode::lessThanOrEqual:
case ExprNode::greaterThan:
case ExprNode::greaterThanOrEqual:
case ExprNode::identical:
case ExprNode::notIdentical:
case ExprNode::In:
case ExprNode::Instanceof:
{
@ -1180,6 +1182,47 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
}
}
break;
case ExprNode::greaterThan:
case ExprNode::greaterThanOrEqual:
{
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
Register r1 = genExpr(b->op1);
Register r2 = genExpr(b->op2);
ret = op(mapExprNodeToICodeOp(p->getKind()), r2, r1); // will return reverse case
if (trueBranch || falseBranch) {
if (trueBranch == NULL)
branchNotConditional(falseBranch, ret);
else {
branchConditional(trueBranch, ret);
if (falseBranch)
branch(falseBranch);
}
}
}
break;
case ExprNode::notEqual:
case ExprNode::notIdentical:
{
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
Register r1 = genExpr(b->op1);
Register r2 = genExpr(b->op2);
ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2);
if (trueBranch || falseBranch) {
if (trueBranch == NULL)
branchNotConditional(falseBranch, ret);
else {
branchConditional(trueBranch, ret);
if (falseBranch)
branch(falseBranch);
}
}
else
ret = not(ret);
}
break;
case ExprNode::logicalAnd:
{
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
@ -1253,7 +1296,7 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
break;
default:
{
assert (0); /* quiet linux warnings */
NOT_REACHED("Unsupported ExprNode kind");
}
}
return ret;

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

@ -212,7 +212,7 @@ namespace ICG {
void callVoid(Register target, RegisterList args);
void move(Register destination, Register source);
void complement(Register destination, Register source);
Register not(Register source);
Register test(Register source);
Register compare(ICodeOp op, Register source1, Register source2);

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

@ -171,21 +171,174 @@ void Context::doCall(JSFunction *target, Instruction *pc)
}
}
*/
JSValue multiply_number(const JSValues& argv)
{
return JSValue (argv[0].f64 * argv[1].f64);
}
JSValue multiply_object(const JSValues& argv)
JSValue shiftLeft_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(argv[0].toNumber());
JSValue num2(argv[1].toNumber());
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
return JSValue(num1.i32 << (num2.u32 & 0x1F));
}
JSValue shiftRight_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
return JSValue(num1.i32 >> (num2.u32 & 0x1F));
}
JSValue UshiftRight_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toUInt32());
JSValue num2(r2.toUInt32());
return JSValue(num1.u32 >> (num2.u32 & 0x1F));
}
JSValue and_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
return JSValue(num1.i32 & num2.i32);
}
JSValue or_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
return JSValue(num1.i32 | num2.i32);
}
JSValue xor_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
return JSValue(num1.i32 ^ num2.i32);
}
JSValue add_Default(const JSValue& r1, const JSValue& r2)
{
//
// could also handle these as separate entries in the override table for add
// by specifying add(String, Any), add(Any, String), add(String, String)
//
if (r1.isString() || r2.isString()) {
JSValue r = r1.toString();
JSString& str1 = *r.string;
JSString& str2 = *r2.toString().string;
str1 += str2;
return r;
}
else {
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 + num2.f64);
}
}
JSValue add_String1(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 + num2.f64);
}
JSValue subtract_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 - num2.f64);
}
JSValue multiply_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 * num2.f64);
}
JSValue divide_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 / num2.f64);
}
JSValue remainder_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(fmod(num1.f64, num2.f64));
}
JSValue less_Default(const JSValue& r1, const JSValue& r2)
{
JSValue lv = r1.toPrimitive(JSValue::Number);
JSValue rv = r2.toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
return JSValue();
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
return JSValue();
else
return JSValue(lv.f64 < rv.f64);
}
}
JSValue lessEqual_Default(const JSValue& r1, const JSValue& r2)
{
JSValue lv = r1.toPrimitive(JSValue::Number);
JSValue rv = r2.toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
return JSValue();
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
return JSValue();
else
return JSValue(lv.f64 <= rv.f64);
}
}
JSValue equal_Default(const JSValue& r1, const JSValue& r2)
{
JSValue lv = r1.toPrimitive(JSValue::Number);
JSValue rv = r2.toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
return JSValue();
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
return JSValue();
else
return JSValue(lv.f64 == rv.f64);
}
}
JSValue identical_Default(const JSValue& r1, const JSValue& r2)
{
if (r1.getType() != r2.getType())
return kFalse;
if (r1.isUndefined() )
return kTrue;
if (r1.isNull())
return kTrue;
if (r1.isNumber()) {
if (r1.isNaN())
return kFalse;
if (r2.isNaN())
return kFalse;
return JSValue(r1.f64 == r2.f64);
}
else {
if (r1.isString())
return kFalse; // XXX implement me!! w_strcmp??
if (r1.isBoolean())
return JSValue(r1.boolean == r2.boolean);
if (r1.isObject())
return JSValue(r1.object == r2.object);
return kFalse;
}
}
class BinaryOperator {
public:
// Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right??
typedef enum {
Add, Subtract, Multiply, Divide,
Remainder, LeftShift, RightShift, LogicalRightShift,
@ -193,15 +346,45 @@ public:
Equal, Identical
} BinaryOp;
BinaryOperator(const JSType *t1, const JSType *t2, JSFunction *function) :
BinaryOperator(const JSType *t1, const JSType *t2, JSBinaryOperator *function) :
t1(t1), t2(t2), function(function) { }
static BinaryOp mapICodeOp(ICodeOp op);
const JSType *t1;
const JSType *t2;
JSFunction *function;
JSBinaryOperator *function;
};
BinaryOperator::BinaryOp BinaryOperator::mapICodeOp(ICodeOp op) {
// a table later... or maybe we need a grand opcode re-unification
switch (op) {
case ADD : return Add;
case SUBTRACT : return Subtract;
case MULTIPLY : return Multiply;
case DIVIDE : return Divide;
case REMAINDER : return Remainder;
case SHIFTLEFT : return LeftShift;
case SHIFTRIGHT : return RightShift;
case USHIFTRIGHT: return LogicalRightShift;
case AND : return BitwiseAnd;
case OR : return BitwiseOr;
case XOR : return BitwiseXor;
case COMPARE_LT : return Less;
case COMPARE_LE : return LessEqual;
case COMPARE_EQ : return Equal;
case STRICT_EQ : return Identical;
default :
NOT_REACHED("Unsupported binary op");
return (BinaryOp)-1;
}
}
typedef std::vector<BinaryOperator *> BinaryOperatorList;
BinaryOperatorList binaryOperators[15];
@ -210,8 +393,21 @@ BinaryOperatorList binaryOperators[15];
class InitBinaryOperators {
public:
InitBinaryOperators() {
binaryOperators[BinaryOperator::Multiply].push_back(new BinaryOperator(&Number_Type, &Number_Type, new JSNativeFunction(multiply_number)));
binaryOperators[BinaryOperator::Multiply].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSNativeFunction(multiply_object)));
binaryOperators[BinaryOperator::Add].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(add_Default)));
binaryOperators[BinaryOperator::Subtract].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(subtract_Default)));
binaryOperators[BinaryOperator::Multiply].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(multiply_Default)));
binaryOperators[BinaryOperator::Divide].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(divide_Default)));
binaryOperators[BinaryOperator::Remainder].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(remainder_Default)));
binaryOperators[BinaryOperator::LeftShift].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(shiftLeft_Default)));
binaryOperators[BinaryOperator::RightShift].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(shiftRight_Default)));
binaryOperators[BinaryOperator::LogicalRightShift].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(UshiftRight_Default)));
binaryOperators[BinaryOperator::BitwiseOr].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(or_Default)));
binaryOperators[BinaryOperator::BitwiseXor].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(xor_Default)));
binaryOperators[BinaryOperator::BitwiseAnd].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(and_Default)));
binaryOperators[BinaryOperator::Less].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(less_Default)));
binaryOperators[BinaryOperator::LessEqual].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(lessEqual_Default)));
binaryOperators[BinaryOperator::Equal].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(equal_Default)));
binaryOperators[BinaryOperator::Identical].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(identical_Default)));
}
} initializer = InitBinaryOperators();
@ -439,68 +635,6 @@ using JSString throughout.
continue;
}
break;
/*
case BRANCH_LT:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 < 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_LE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 <= 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_EQ:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 == 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_NE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 != 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_GE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 >= 0) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
case BRANCH_GT:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 > 0) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
*/
case BRANCH_TRUE:
{
GenericBranch* bc =
@ -524,158 +658,44 @@ using JSString throughout.
}
break;
case SHIFTLEFT:
{
Arithmetic* shl = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shl)];
JSValue& r1 = (*registers)[src1(shl)];
JSValue& r2 = (*registers)[src2(shl)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 << (num2.u32 & 0x1F);
}
break;
case SHIFTRIGHT:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 >> (num2.u32 & 0x1F);
}
break;
case USHIFTRIGHT:
{
Arithmetic* ushr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(ushr)];
JSValue& r1 = (*registers)[src1(ushr)];
JSValue& r2 = (*registers)[src2(ushr)];
JSValue num1(r1.toUInt32());
JSValue num2(r2.toUInt32());
dest = num1.u32 >> (num2.u32 & 0x1F);
}
break;
case AND:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 & num2.i32;
}
break;
case OR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 | num2.i32;
}
break;
case XOR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 ^ num2.i32;
}
break;
case ADD:
{
// could get clever here with Functional forms.
Arithmetic* add = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(add)];
JSValue& r1 = (*registers)[src1(add)];
JSValue& r2 = (*registers)[src2(add)];
if (r1.isString() || r2.isString()) {
dest = r1.toString();
JSString& str1 = *dest.string;
JSString& str2 = *r2.toString().string;
str1 += str2;
}
else {
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 + num2.f64;
}
}
break;
case SUBTRACT:
{
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(sub)];
JSValue& r1 = (*registers)[src1(sub)];
JSValue& r2 = (*registers)[src2(sub)];
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 - num2.f64;
}
break;
case MULTIPLY:
case DIVIDE:
case REMAINDER:
case COMPARE_LT:
case COMPARE_LE:
case COMPARE_EQ:
case STRICT_EQ:
{
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(mul)];
JSValue& r1 = (*registers)[src1(mul)];
JSValue& r2 = (*registers)[src2(mul)];
const JSValue ovr = findBinaryOverride(r1, r2, BinaryOperator::Multiply);
if (ovr.isFunction()) {
JSFunction *target = ovr.function;
if (target->isNative()) {
JSValues argv(2);
argv[0] = r1;
argv[1] = r2;
dest = static_cast<JSNativeFunction*>(target)->mCode(argv);
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, dst(mul));
mActivation = new Activation(target->getICode(), r1, r2);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
}
const JSValue ovr = findBinaryOverride(r1, r2, BinaryOperator::mapICodeOp(instruction->op()));
JSFunction *target = ovr.function;
if (target->isNative()) {
JSValues argv(2);
argv[0] = r1;
argv[1] = r2;
dest = static_cast<JSBinaryOperator*>(target)->mCode(r1, r2);
break;
}
else {
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 * num2.f64;
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, dst(mul));
mActivation = new Activation(target->getICode(), r1, r2);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
}
}
break;
case DIVIDE:
{
Arithmetic* div = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(div)];
JSValue& r1 = (*registers)[src1(div)];
JSValue& r2 = (*registers)[src2(div)];
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 / num2.f64;
}
break;
case REMAINDER:
{
Arithmetic* rem = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(rem)];
JSValue& r1 = (*registers)[src1(rem)];
JSValue& r2 = (*registers)[src2(rem)];
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = fmod(num1.f64, num2.f64);
}
break;
case PROP_XCR:
{
@ -701,51 +721,6 @@ using JSString throughout.
}
break;
case COMPARE_LT:
case COMPARE_LE:
case COMPARE_EQ:
case COMPARE_NE:
case COMPARE_GT:
case COMPARE_GE:
{
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(cmp)];
JSValue lv = (*registers)[src1(cmp)].toPrimitive(JSValue::Number);
JSValue rv = (*registers)[src2(cmp)].toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
dest = JSValue();
else {
// FIXME, does this do the right thing for +/- infinity?
switch (instruction->op()) {
case COMPARE_LT:
dest = JSValue(lv.f64 < rv.f64); break;
case COMPARE_LE:
dest = JSValue(lv.f64 <= rv.f64); break;
case COMPARE_EQ:
dest = JSValue(lv.f64 == rv.f64); break;
case COMPARE_NE:
dest = JSValue(lv.f64 != rv.f64); break;
case COMPARE_GT:
dest = JSValue(lv.f64 > rv.f64); break;
case COMPARE_GE:
dest = JSValue(lv.f64 >= rv.f64); break;
default:
assert(0); /* quiet linux warnings */
}
// float64 diff = lv.f64 - rv.f64;
// dest = JSValue( (int32) (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
}
}
}
break;
case TEST:
{
Test* tst = static_cast<Test*>(instruction);
@ -770,15 +745,13 @@ using JSString throughout.
(*registers)[dst(bn)] = JSValue(~(*registers)[src1(bn)].toInt32().i32);
}
break;
/*
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
(*registers)[dst(nt)] =
JSValue(int32(!(*registers)[src1(nt)].i32));
ASSERT((*registers)[src1(nt)].isBoolean());
(*registers)[dst(nt)] = JSValue(!(*registers)[src1(nt)].boolean);
}
break;
*/
case THROW:
{
Throw* thrw = static_cast<Throw*>(instruction);

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

@ -109,6 +109,8 @@ const JSType *JSValue::getType() const
return &Boolean_Type;
case JSValue::undefined_tag:
return &Void_Type;
case JSValue::type_tag:
return &Type_Type;
default:
NOT_REACHED("Bad tag");
return &None_Type;

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

@ -77,6 +77,7 @@ namespace JSTypes {
JSArray* array;
JSFunction *function;
JSString *string;
JSType *type;
bool boolean;
};
@ -92,7 +93,7 @@ namespace JSTypes {
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
undefined_tag
} tag;
@ -105,6 +106,7 @@ namespace JSTypes {
explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {}
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
explicit JSValue(JSType* type) : type(type), tag(type_tag) {}
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
@ -114,6 +116,7 @@ namespace JSTypes {
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); }
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
JSType*& operator=(JSType* type) { return (tag = type_tag, this->type = type); }
bool isFunction() const { return (tag == function_tag); }
bool isObject() const { return ((tag == object_tag) || (tag == function_tag) || (tag == array_tag)); }
@ -123,6 +126,8 @@ namespace JSTypes {
/* this is correct wrt ECMA, The i32 & u32 kinds
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;
JSValue toString() const { return (isString() ? *this : valueToString(*this)); }
@ -293,6 +298,14 @@ namespace JSTypes {
virtual bool isNative() { return true; }
};
class JSBinaryOperator : public JSFunction {
public:
typedef JSValue (*JSBinaryCode)(const JSValue& arg1, const JSValue& arg2);
JSBinaryCode mCode;
JSBinaryOperator(JSBinaryCode code) : mCode(code) {}
virtual bool isNative() { return true; }
};
#if defined(XP_UNIX)
// bastring.cc defines a funky operator new that assumes a byte-allocator.
typedef string_char_traits<char16> JSCharTraits;

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

@ -112,6 +112,7 @@ namespace VM {
};
/********************************************************************/
static char *opcodeNames[] = {
@ -349,9 +350,9 @@ namespace VM {
}
};
class Compare : public Instruction_2<Register, Register> {
class Unary : public Instruction_2<Register, Register> {
public:
Compare(ICodeOp aOpcode, Register aDest, Register aSrc) :
Unary(ICodeOp aOpcode, Register aDest, Register aSrc) :
Instruction_2<Register, Register>(aOpcode, aDest, aSrc) {}
virtual Formatter& print (Formatter& f) {
f << opcodeNames[mOpcode] << "\tR" << mOp1 << ", R" << mOp2;
@ -531,67 +532,67 @@ namespace VM {
}
};
class CompareEQ : public Compare {
class CompareEQ : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareEQ (Register aOp1, Register aOp2) :
Compare
(COMPARE_EQ, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareEQ (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_EQ, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareGE : public Compare {
class CompareGE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareGE (Register aOp1, Register aOp2) :
Compare
(COMPARE_GE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareGE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_GE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareGT : public Compare {
class CompareGT : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareGT (Register aOp1, Register aOp2) :
Compare
(COMPARE_GT, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareGT (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_GT, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareIN : public Compare {
class CompareIN : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareIN (Register aOp1, Register aOp2) :
Compare
(COMPARE_IN, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareIN (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_IN, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareLE : public Compare {
class CompareLE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareLE (Register aOp1, Register aOp2) :
Compare
(COMPARE_LE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareLE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_LE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareLT : public Compare {
class CompareLT : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareLT (Register aOp1, Register aOp2) :
Compare
(COMPARE_LT, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareLT (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_LT, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareNE : public Compare {
class CompareNE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareNE (Register aOp1, Register aOp2) :
Compare
(COMPARE_NE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareNE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_NE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class Divide : public Arithmetic {
@ -621,7 +622,7 @@ namespace VM {
class GetElement : public Instruction_3<Register, Register, Register> {
public:
/* dest, array, index */
/* dest, base, index */
GetElement (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(GET_ELEMENT, aOp1, aOp2, aOp3) {};
@ -651,13 +652,13 @@ namespace VM {
}
};
class Instanceof : public Compare {
class Instanceof : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
Instanceof (Register aOp1, Register aOp2) :
Compare
(INSTANCEOF, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
Instanceof (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(INSTANCEOF, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class Jsr : public GenericBranch {
@ -973,7 +974,7 @@ namespace VM {
class SetElement : public Instruction_3<Register, Register, Register> {
public:
/* base, source1, source2 */
/* base, index, value */
SetElement (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(SET_ELEMENT, aOp1, aOp2, aOp3) {};
@ -1021,22 +1022,22 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
class StrictEQ : public Compare {
class StrictEQ : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
StrictEQ (Register aOp1, Register aOp2) :
Compare
(STRICT_EQ, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
StrictEQ (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(STRICT_EQ, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class StrictNE : public Compare {
class StrictNE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
StrictNE (Register aOp1, Register aOp2) :
Compare
(STRICT_NE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
StrictNE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(STRICT_NE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class Subtract : public Arithmetic {

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

@ -284,10 +284,11 @@ Register ICodeGenerator::op(ICodeOp op, Register source)
{
Register dest = getRegister();
ASSERT(source != NotARegister);
Compare *instr = new Compare (op, dest, source);
Unary *instr = new Unary (op, dest, source);
iCode->push_back(instr);
return dest;
}
void ICodeGenerator::move(Register destination, Register source)
{
@ -295,12 +296,14 @@ void ICodeGenerator::move(Register destination, Register source)
ASSERT(source != NotARegister);
Move *instr = new Move(destination, source);
iCode->push_back(instr);
}
}
void ICodeGenerator::complement(Register destination, Register source)
Register ICodeGenerator::not(Register source)
{
Not *instr = new Not(destination, source);
Register dest = getRegister();
Not *instr = new Not(dest, source);
iCode->push_back(instr);
return dest;
}
Register ICodeGenerator::test(Register source)
@ -921,30 +924,33 @@ ICodeOp ICodeGenerator::mapExprNodeToICodeOp(ExprNode::Kind kind)
case ExprNode::minus:
return NEGATE;
case ExprNode::complement:
return NOT;
return BITNOT;
// relational
case ExprNode::equal:
return COMPARE_EQ;
case ExprNode::notEqual:
return COMPARE_NE;
case ExprNode::lessThan:
return COMPARE_LT;
case ExprNode::lessThanOrEqual:
return COMPARE_LE;
case ExprNode::greaterThan:
return COMPARE_GT;
case ExprNode::greaterThanOrEqual:
return COMPARE_GE;
case ExprNode::identical:
return STRICT_EQ;
case ExprNode::notIdentical:
return STRICT_NE;
case ExprNode::In:
return COMPARE_IN;
case ExprNode::Instanceof:
return INSTANCEOF;
case ExprNode::equal:
return COMPARE_EQ;
case ExprNode::lessThan:
return COMPARE_LT;
case ExprNode::lessThanOrEqual:
return COMPARE_LE;
case ExprNode::identical:
return STRICT_EQ;
// these get reversed by the generator
case ExprNode::notEqual:
return COMPARE_EQ;
case ExprNode::greaterThan:
return COMPARE_LT;
case ExprNode::greaterThanOrEqual:
return COMPARE_LE;
case ExprNode::notIdentical:
return STRICT_EQ;
default:
NOT_REACHED("Unimplemented kind");
@ -1155,13 +1161,9 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
}
break;
case ExprNode::equal:
case ExprNode::notEqual:
case ExprNode::lessThan:
case ExprNode::lessThanOrEqual:
case ExprNode::greaterThan:
case ExprNode::greaterThanOrEqual:
case ExprNode::identical:
case ExprNode::notIdentical:
case ExprNode::In:
case ExprNode::Instanceof:
{
@ -1180,6 +1182,47 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
}
}
break;
case ExprNode::greaterThan:
case ExprNode::greaterThanOrEqual:
{
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
Register r1 = genExpr(b->op1);
Register r2 = genExpr(b->op2);
ret = op(mapExprNodeToICodeOp(p->getKind()), r2, r1); // will return reverse case
if (trueBranch || falseBranch) {
if (trueBranch == NULL)
branchNotConditional(falseBranch, ret);
else {
branchConditional(trueBranch, ret);
if (falseBranch)
branch(falseBranch);
}
}
}
break;
case ExprNode::notEqual:
case ExprNode::notIdentical:
{
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
Register r1 = genExpr(b->op1);
Register r2 = genExpr(b->op2);
ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2);
if (trueBranch || falseBranch) {
if (trueBranch == NULL)
branchNotConditional(falseBranch, ret);
else {
branchConditional(trueBranch, ret);
if (falseBranch)
branch(falseBranch);
}
}
else
ret = not(ret);
}
break;
case ExprNode::logicalAnd:
{
BinaryExprNode *b = static_cast<BinaryExprNode *>(p);
@ -1253,7 +1296,7 @@ Register ICodeGenerator::genExpr(ExprNode *p, bool needBoolValueInBranch, Label
break;
default:
{
assert (0); /* quiet linux warnings */
NOT_REACHED("Unsupported ExprNode kind");
}
}
return ret;

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

@ -212,7 +212,7 @@ namespace ICG {
void callVoid(Register target, RegisterList args);
void move(Register destination, Register source);
void complement(Register destination, Register source);
Register not(Register source);
Register test(Register source);
Register compare(ICodeOp op, Register source1, Register source2);

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

@ -171,21 +171,174 @@ void Context::doCall(JSFunction *target, Instruction *pc)
}
}
*/
JSValue multiply_number(const JSValues& argv)
{
return JSValue (argv[0].f64 * argv[1].f64);
}
JSValue multiply_object(const JSValues& argv)
JSValue shiftLeft_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(argv[0].toNumber());
JSValue num2(argv[1].toNumber());
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
return JSValue(num1.i32 << (num2.u32 & 0x1F));
}
JSValue shiftRight_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
return JSValue(num1.i32 >> (num2.u32 & 0x1F));
}
JSValue UshiftRight_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toUInt32());
JSValue num2(r2.toUInt32());
return JSValue(num1.u32 >> (num2.u32 & 0x1F));
}
JSValue and_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
return JSValue(num1.i32 & num2.i32);
}
JSValue or_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
return JSValue(num1.i32 | num2.i32);
}
JSValue xor_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
return JSValue(num1.i32 ^ num2.i32);
}
JSValue add_Default(const JSValue& r1, const JSValue& r2)
{
//
// could also handle these as separate entries in the override table for add
// by specifying add(String, Any), add(Any, String), add(String, String)
//
if (r1.isString() || r2.isString()) {
JSValue r = r1.toString();
JSString& str1 = *r.string;
JSString& str2 = *r2.toString().string;
str1 += str2;
return r;
}
else {
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 + num2.f64);
}
}
JSValue add_String1(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 + num2.f64);
}
JSValue subtract_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 - num2.f64);
}
JSValue multiply_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 * num2.f64);
}
JSValue divide_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(num1.f64 / num2.f64);
}
JSValue remainder_Default(const JSValue& r1, const JSValue& r2)
{
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
return JSValue(fmod(num1.f64, num2.f64));
}
JSValue less_Default(const JSValue& r1, const JSValue& r2)
{
JSValue lv = r1.toPrimitive(JSValue::Number);
JSValue rv = r2.toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
return JSValue();
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
return JSValue();
else
return JSValue(lv.f64 < rv.f64);
}
}
JSValue lessEqual_Default(const JSValue& r1, const JSValue& r2)
{
JSValue lv = r1.toPrimitive(JSValue::Number);
JSValue rv = r2.toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
return JSValue();
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
return JSValue();
else
return JSValue(lv.f64 <= rv.f64);
}
}
JSValue equal_Default(const JSValue& r1, const JSValue& r2)
{
JSValue lv = r1.toPrimitive(JSValue::Number);
JSValue rv = r2.toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
return JSValue();
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
return JSValue();
else
return JSValue(lv.f64 == rv.f64);
}
}
JSValue identical_Default(const JSValue& r1, const JSValue& r2)
{
if (r1.getType() != r2.getType())
return kFalse;
if (r1.isUndefined() )
return kTrue;
if (r1.isNull())
return kTrue;
if (r1.isNumber()) {
if (r1.isNaN())
return kFalse;
if (r2.isNaN())
return kFalse;
return JSValue(r1.f64 == r2.f64);
}
else {
if (r1.isString())
return kFalse; // XXX implement me!! w_strcmp??
if (r1.isBoolean())
return JSValue(r1.boolean == r2.boolean);
if (r1.isObject())
return JSValue(r1.object == r2.object);
return kFalse;
}
}
class BinaryOperator {
public:
// Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right??
typedef enum {
Add, Subtract, Multiply, Divide,
Remainder, LeftShift, RightShift, LogicalRightShift,
@ -193,15 +346,45 @@ public:
Equal, Identical
} BinaryOp;
BinaryOperator(const JSType *t1, const JSType *t2, JSFunction *function) :
BinaryOperator(const JSType *t1, const JSType *t2, JSBinaryOperator *function) :
t1(t1), t2(t2), function(function) { }
static BinaryOp mapICodeOp(ICodeOp op);
const JSType *t1;
const JSType *t2;
JSFunction *function;
JSBinaryOperator *function;
};
BinaryOperator::BinaryOp BinaryOperator::mapICodeOp(ICodeOp op) {
// a table later... or maybe we need a grand opcode re-unification
switch (op) {
case ADD : return Add;
case SUBTRACT : return Subtract;
case MULTIPLY : return Multiply;
case DIVIDE : return Divide;
case REMAINDER : return Remainder;
case SHIFTLEFT : return LeftShift;
case SHIFTRIGHT : return RightShift;
case USHIFTRIGHT: return LogicalRightShift;
case AND : return BitwiseAnd;
case OR : return BitwiseOr;
case XOR : return BitwiseXor;
case COMPARE_LT : return Less;
case COMPARE_LE : return LessEqual;
case COMPARE_EQ : return Equal;
case STRICT_EQ : return Identical;
default :
NOT_REACHED("Unsupported binary op");
return (BinaryOp)-1;
}
}
typedef std::vector<BinaryOperator *> BinaryOperatorList;
BinaryOperatorList binaryOperators[15];
@ -210,8 +393,21 @@ BinaryOperatorList binaryOperators[15];
class InitBinaryOperators {
public:
InitBinaryOperators() {
binaryOperators[BinaryOperator::Multiply].push_back(new BinaryOperator(&Number_Type, &Number_Type, new JSNativeFunction(multiply_number)));
binaryOperators[BinaryOperator::Multiply].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSNativeFunction(multiply_object)));
binaryOperators[BinaryOperator::Add].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(add_Default)));
binaryOperators[BinaryOperator::Subtract].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(subtract_Default)));
binaryOperators[BinaryOperator::Multiply].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(multiply_Default)));
binaryOperators[BinaryOperator::Divide].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(divide_Default)));
binaryOperators[BinaryOperator::Remainder].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(remainder_Default)));
binaryOperators[BinaryOperator::LeftShift].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(shiftLeft_Default)));
binaryOperators[BinaryOperator::RightShift].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(shiftRight_Default)));
binaryOperators[BinaryOperator::LogicalRightShift].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(UshiftRight_Default)));
binaryOperators[BinaryOperator::BitwiseOr].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(or_Default)));
binaryOperators[BinaryOperator::BitwiseXor].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(xor_Default)));
binaryOperators[BinaryOperator::BitwiseAnd].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(and_Default)));
binaryOperators[BinaryOperator::Less].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(less_Default)));
binaryOperators[BinaryOperator::LessEqual].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(lessEqual_Default)));
binaryOperators[BinaryOperator::Equal].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(equal_Default)));
binaryOperators[BinaryOperator::Identical].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(identical_Default)));
}
} initializer = InitBinaryOperators();
@ -439,68 +635,6 @@ using JSString throughout.
continue;
}
break;
/*
case BRANCH_LT:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 < 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_LE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 <= 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_EQ:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 == 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_NE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 != 0) {
mPC = mActivation->mICode->its_iCode->begin() + ofs(bc);
continue;
}
}
break;
case BRANCH_GE:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 >= 0) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
case BRANCH_GT:
{
GenericBranch* bc =
static_cast<GenericBranch*>(instruction);
if ((*registers)[src1(bc)].i32 > 0) {
mPC = begin_pc + ofs(bc);
continue;
}
}
break;
*/
case BRANCH_TRUE:
{
GenericBranch* bc =
@ -524,158 +658,44 @@ using JSString throughout.
}
break;
case SHIFTLEFT:
{
Arithmetic* shl = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shl)];
JSValue& r1 = (*registers)[src1(shl)];
JSValue& r2 = (*registers)[src2(shl)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 << (num2.u32 & 0x1F);
}
break;
case SHIFTRIGHT:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toUInt32());
dest = num1.i32 >> (num2.u32 & 0x1F);
}
break;
case USHIFTRIGHT:
{
Arithmetic* ushr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(ushr)];
JSValue& r1 = (*registers)[src1(ushr)];
JSValue& r2 = (*registers)[src2(ushr)];
JSValue num1(r1.toUInt32());
JSValue num2(r2.toUInt32());
dest = num1.u32 >> (num2.u32 & 0x1F);
}
break;
case AND:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 & num2.i32;
}
break;
case OR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 | num2.i32;
}
break;
case XOR:
{
Arithmetic* shr = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(shr)];
JSValue& r1 = (*registers)[src1(shr)];
JSValue& r2 = (*registers)[src2(shr)];
JSValue num1(r1.toInt32());
JSValue num2(r2.toInt32());
dest = num1.i32 ^ num2.i32;
}
break;
case ADD:
{
// could get clever here with Functional forms.
Arithmetic* add = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(add)];
JSValue& r1 = (*registers)[src1(add)];
JSValue& r2 = (*registers)[src2(add)];
if (r1.isString() || r2.isString()) {
dest = r1.toString();
JSString& str1 = *dest.string;
JSString& str2 = *r2.toString().string;
str1 += str2;
}
else {
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 + num2.f64;
}
}
break;
case SUBTRACT:
{
Arithmetic* sub = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(sub)];
JSValue& r1 = (*registers)[src1(sub)];
JSValue& r2 = (*registers)[src2(sub)];
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 - num2.f64;
}
break;
case MULTIPLY:
case DIVIDE:
case REMAINDER:
case COMPARE_LT:
case COMPARE_LE:
case COMPARE_EQ:
case STRICT_EQ:
{
Arithmetic* mul = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(mul)];
JSValue& r1 = (*registers)[src1(mul)];
JSValue& r2 = (*registers)[src2(mul)];
const JSValue ovr = findBinaryOverride(r1, r2, BinaryOperator::Multiply);
if (ovr.isFunction()) {
JSFunction *target = ovr.function;
if (target->isNative()) {
JSValues argv(2);
argv[0] = r1;
argv[1] = r2;
dest = static_cast<JSNativeFunction*>(target)->mCode(argv);
break;
}
else {
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, dst(mul));
mActivation = new Activation(target->getICode(), r1, r2);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
}
const JSValue ovr = findBinaryOverride(r1, r2, BinaryOperator::mapICodeOp(instruction->op()));
JSFunction *target = ovr.function;
if (target->isNative()) {
JSValues argv(2);
argv[0] = r1;
argv[1] = r2;
dest = static_cast<JSBinaryOperator*>(target)->mCode(r1, r2);
break;
}
else {
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 * num2.f64;
mLinkage = new Linkage(mLinkage, ++mPC,
mActivation, dst(mul));
mActivation = new Activation(target->getICode(), r1, r2);
registers = &mActivation->mRegisters;
mPC = mActivation->mICode->its_iCode->begin();
continue;
}
}
break;
case DIVIDE:
{
Arithmetic* div = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(div)];
JSValue& r1 = (*registers)[src1(div)];
JSValue& r2 = (*registers)[src2(div)];
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = num1.f64 / num2.f64;
}
break;
case REMAINDER:
{
Arithmetic* rem = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(rem)];
JSValue& r1 = (*registers)[src1(rem)];
JSValue& r2 = (*registers)[src2(rem)];
JSValue num1(r1.toNumber());
JSValue num2(r2.toNumber());
dest = fmod(num1.f64, num2.f64);
}
break;
case PROP_XCR:
{
@ -701,51 +721,6 @@ using JSString throughout.
}
break;
case COMPARE_LT:
case COMPARE_LE:
case COMPARE_EQ:
case COMPARE_NE:
case COMPARE_GT:
case COMPARE_GE:
{
Arithmetic* cmp = static_cast<Arithmetic*>(instruction);
JSValue& dest = (*registers)[dst(cmp)];
JSValue lv = (*registers)[src1(cmp)].toPrimitive(JSValue::Number);
JSValue rv = (*registers)[src2(cmp)].toPrimitive(JSValue::Number);
if (lv.isString() && rv.isString()) {
// XXX FIXME urgh, call w_strcmp ??? on a JSString ???
}
else {
lv = lv.toNumber();
rv = rv.toNumber();
if (lv.isNaN() || rv.isNaN())
dest = JSValue();
else {
// FIXME, does this do the right thing for +/- infinity?
switch (instruction->op()) {
case COMPARE_LT:
dest = JSValue(lv.f64 < rv.f64); break;
case COMPARE_LE:
dest = JSValue(lv.f64 <= rv.f64); break;
case COMPARE_EQ:
dest = JSValue(lv.f64 == rv.f64); break;
case COMPARE_NE:
dest = JSValue(lv.f64 != rv.f64); break;
case COMPARE_GT:
dest = JSValue(lv.f64 > rv.f64); break;
case COMPARE_GE:
dest = JSValue(lv.f64 >= rv.f64); break;
default:
assert(0); /* quiet linux warnings */
}
// float64 diff = lv.f64 - rv.f64;
// dest = JSValue( (int32) (diff == 0.0 ? 0 : (diff > 0.0 ? 1 : -1)));
}
}
}
break;
case TEST:
{
Test* tst = static_cast<Test*>(instruction);
@ -770,15 +745,13 @@ using JSString throughout.
(*registers)[dst(bn)] = JSValue(~(*registers)[src1(bn)].toInt32().i32);
}
break;
/*
case NOT:
{
Not* nt = static_cast<Not*>(instruction);
(*registers)[dst(nt)] =
JSValue(int32(!(*registers)[src1(nt)].i32));
ASSERT((*registers)[src1(nt)].isBoolean());
(*registers)[dst(nt)] = JSValue(!(*registers)[src1(nt)].boolean);
}
break;
*/
case THROW:
{
Throw* thrw = static_cast<Throw*>(instruction);

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

@ -109,6 +109,8 @@ const JSType *JSValue::getType() const
return &Boolean_Type;
case JSValue::undefined_tag:
return &Void_Type;
case JSValue::type_tag:
return &Type_Type;
default:
NOT_REACHED("Bad tag");
return &None_Type;

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

@ -77,6 +77,7 @@ namespace JSTypes {
JSArray* array;
JSFunction *function;
JSString *string;
JSType *type;
bool boolean;
};
@ -92,7 +93,7 @@ namespace JSTypes {
i32_tag, u32_tag,
i64_tag, u64_tag,
f32_tag, f64_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag,
object_tag, array_tag, function_tag, string_tag, boolean_tag, type_tag,
undefined_tag
} tag;
@ -105,6 +106,7 @@ namespace JSTypes {
explicit JSValue(JSFunction* function) : function(function), tag(function_tag) {}
explicit JSValue(JSString* string) : string(string), tag(string_tag) {}
explicit JSValue(bool boolean) : boolean(boolean), tag(boolean_tag) {}
explicit JSValue(JSType* type) : type(type), tag(type_tag) {}
int32& operator=(int32 i32) { return (tag = i32_tag, this->i32 = i32); }
uint32& operator=(uint32 u32) { return (tag = u32_tag, this->u32 = u32); }
@ -114,6 +116,7 @@ namespace JSTypes {
JSFunction*& operator=(JSFunction* function) { return (tag = function_tag, this->function = function); }
JSString*& operator=(JSString* string) { return (tag = string_tag, this->string = string); }
bool& operator=(bool boolean) { return (tag = boolean_tag, this->boolean = boolean); }
JSType*& operator=(JSType* type) { return (tag = type_tag, this->type = type); }
bool isFunction() const { return (tag == function_tag); }
bool isObject() const { return ((tag == object_tag) || (tag == function_tag) || (tag == array_tag)); }
@ -123,6 +126,8 @@ namespace JSTypes {
/* this is correct wrt ECMA, The i32 & u32 kinds
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;
JSValue toString() const { return (isString() ? *this : valueToString(*this)); }
@ -293,6 +298,14 @@ namespace JSTypes {
virtual bool isNative() { return true; }
};
class JSBinaryOperator : public JSFunction {
public:
typedef JSValue (*JSBinaryCode)(const JSValue& arg1, const JSValue& arg2);
JSBinaryCode mCode;
JSBinaryOperator(JSBinaryCode code) : mCode(code) {}
virtual bool isNative() { return true; }
};
#if defined(XP_UNIX)
// bastring.cc defines a funky operator new that assumes a byte-allocator.
typedef string_char_traits<char16> JSCharTraits;

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

@ -112,6 +112,7 @@ namespace VM {
};
/********************************************************************/
static char *opcodeNames[] = {
@ -349,9 +350,9 @@ namespace VM {
}
};
class Compare : public Instruction_2<Register, Register> {
class Unary : public Instruction_2<Register, Register> {
public:
Compare(ICodeOp aOpcode, Register aDest, Register aSrc) :
Unary(ICodeOp aOpcode, Register aDest, Register aSrc) :
Instruction_2<Register, Register>(aOpcode, aDest, aSrc) {}
virtual Formatter& print (Formatter& f) {
f << opcodeNames[mOpcode] << "\tR" << mOp1 << ", R" << mOp2;
@ -531,67 +532,67 @@ namespace VM {
}
};
class CompareEQ : public Compare {
class CompareEQ : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareEQ (Register aOp1, Register aOp2) :
Compare
(COMPARE_EQ, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareEQ (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_EQ, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareGE : public Compare {
class CompareGE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareGE (Register aOp1, Register aOp2) :
Compare
(COMPARE_GE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareGE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_GE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareGT : public Compare {
class CompareGT : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareGT (Register aOp1, Register aOp2) :
Compare
(COMPARE_GT, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareGT (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_GT, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareIN : public Compare {
class CompareIN : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareIN (Register aOp1, Register aOp2) :
Compare
(COMPARE_IN, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareIN (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_IN, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareLE : public Compare {
class CompareLE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareLE (Register aOp1, Register aOp2) :
Compare
(COMPARE_LE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareLE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_LE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareLT : public Compare {
class CompareLT : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareLT (Register aOp1, Register aOp2) :
Compare
(COMPARE_LT, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareLT (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_LT, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class CompareNE : public Compare {
class CompareNE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
CompareNE (Register aOp1, Register aOp2) :
Compare
(COMPARE_NE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
CompareNE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(COMPARE_NE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class Divide : public Arithmetic {
@ -621,7 +622,7 @@ namespace VM {
class GetElement : public Instruction_3<Register, Register, Register> {
public:
/* dest, array, index */
/* dest, base, index */
GetElement (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(GET_ELEMENT, aOp1, aOp2, aOp3) {};
@ -651,13 +652,13 @@ namespace VM {
}
};
class Instanceof : public Compare {
class Instanceof : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
Instanceof (Register aOp1, Register aOp2) :
Compare
(INSTANCEOF, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
Instanceof (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(INSTANCEOF, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class Jsr : public GenericBranch {
@ -973,7 +974,7 @@ namespace VM {
class SetElement : public Instruction_3<Register, Register, Register> {
public:
/* base, source1, source2 */
/* base, index, value */
SetElement (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(SET_ELEMENT, aOp1, aOp2, aOp3) {};
@ -1021,22 +1022,22 @@ namespace VM {
/* print() and printOperands() inherited from Arithmetic */
};
class StrictEQ : public Compare {
class StrictEQ : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
StrictEQ (Register aOp1, Register aOp2) :
Compare
(STRICT_EQ, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
StrictEQ (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(STRICT_EQ, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class StrictNE : public Compare {
class StrictNE : public Instruction_3<Register, Register, Register> {
public:
/* dest, source */
StrictNE (Register aOp1, Register aOp2) :
Compare
(STRICT_NE, aOp1, aOp2) {};
/* print() and printOperands() inherited from Compare */
/* dest, source1, source2 */
StrictNE (Register aOp1, Register aOp2, Register aOp3) :
Instruction_3<Register, Register, Register>
(STRICT_NE, aOp1, aOp2, aOp3) {};
/* print() and printOperands() inherited from Instruction_3<Register, Register, Register> */
};
class Subtract : public Arithmetic {