зеркало из https://github.com/mozilla/gecko-dev.git
Added operator overloading support
This commit is contained in:
Родитель
e562e8eb21
Коммит
932d63213b
|
@ -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;
|
||||
|
|
129
js/js2/vmtypes.h
129
js/js2/vmtypes.h
|
@ -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 {
|
||||
|
|
Загрузка…
Ссылка в новой задаче