mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-25 03:49:42 +00:00
New (incomplete but functional) implementation of operator overriding.
This commit is contained in:
parent
23cd859c75
commit
d13899b06c
@ -388,11 +388,11 @@
|
||||
}
|
||||
};
|
||||
|
||||
class GenericBinaryOP : public Instruction_4<TypedRegister, BinaryOperator::BinaryOp, TypedRegister, TypedRegister> {
|
||||
class GenericBinaryOP : public Instruction_4<TypedRegister, ExprNode::Kind, TypedRegister, TypedRegister> {
|
||||
public:
|
||||
/* dest, op, source1, source2 */
|
||||
GenericBinaryOP (TypedRegister aOp1, BinaryOperator::BinaryOp aOp2, TypedRegister aOp3, TypedRegister aOp4) :
|
||||
Instruction_4<TypedRegister, BinaryOperator::BinaryOp, TypedRegister, TypedRegister>
|
||||
GenericBinaryOP (TypedRegister aOp1, ExprNode::Kind aOp2, TypedRegister aOp3, TypedRegister aOp4) :
|
||||
Instruction_4<TypedRegister, ExprNode::Kind, TypedRegister, TypedRegister>
|
||||
(GENERIC_BINARY_OP, aOp1, aOp2, aOp3, aOp4) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[GENERIC_BINARY_OP] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4;
|
||||
|
@ -44,11 +44,17 @@ namespace ICodeASM {
|
||||
using namespace LexUtils;
|
||||
|
||||
static char *keyword_offset = "offset";
|
||||
static char *keyword_binaryops[] = {"add", "subtract", "multiply", "divide",
|
||||
static char *keyword_exprNodeKinds[] = {"add", "subtract", "multiply", "divide",
|
||||
"remainder", "leftshift", "rightshift",
|
||||
"logicalrightshift", "bitwiseor",
|
||||
"bitwisexor", "bitwiseand", "less",
|
||||
"lessorequal", "equal", "identical", 0};
|
||||
static ExprNode::Kind exprNodeOps[] =
|
||||
{ ExprNode::add, ExprNode::subtract, ExprNode::multiply, ExprNode::divide,
|
||||
ExprNode::modulo, ExprNode::leftShift, ExprNode::rightShift,
|
||||
ExprNode::logicalRightShift, ExprNode::bitwiseOr,
|
||||
ExprNode::bitwiseXor, ExprNode::bitwiseAnd, ExprNode::lessThan,
|
||||
ExprNode::lessThanOrEqual, ExprNode::equal, ExprNode::identical };
|
||||
|
||||
void
|
||||
ICodeParser::parseSourceFromString (const string8 &source)
|
||||
@ -158,8 +164,8 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
string8_citer
|
||||
ICodeParser::parseBinaryOpOperand (string8_citer begin, string8_citer end,
|
||||
VM::BinaryOperator::BinaryOp *rval)
|
||||
ICodeParser::parseExprNodeKindOperand (string8_citer begin, string8_citer end,
|
||||
ExprNode::Kind *rval)
|
||||
{
|
||||
TokenLocation tl = seekTokenStart (begin, end);
|
||||
|
||||
@ -168,10 +174,10 @@ namespace ICodeASM {
|
||||
string8 *str;
|
||||
end = lexAlpha (tl.begin, end, &str);
|
||||
|
||||
for (int i = 0; keyword_binaryops[i] != 0; ++i)
|
||||
if (cmp_nocase (*str, keyword_binaryops[i], keyword_binaryops[i] +
|
||||
strlen (keyword_binaryops[i]) + 1) == 0) {
|
||||
*rval = static_cast<VM::BinaryOperator::BinaryOp>(i);
|
||||
for (int i = 0; keyword_exprNodeKinds[i] != 0; ++i)
|
||||
if (cmp_nocase (*str, keyword_exprNodeKinds[i], keyword_exprNodeKinds[i] +
|
||||
strlen (keyword_exprNodeKinds[i]) + 1) == 0) {
|
||||
*rval = exprNodeOps[i];
|
||||
delete str;
|
||||
return end;
|
||||
}
|
||||
@ -381,8 +387,7 @@ namespace ICodeASM {
|
||||
switch (icodemap[icodeID].otype[i])
|
||||
{
|
||||
CASE_TYPE(ArgumentList, VM::ArgumentList *, reinterpret_cast);
|
||||
CASE_TYPE(BinaryOp, VM::BinaryOperator::BinaryOp,
|
||||
static_cast);
|
||||
CASE_TYPE(ExprNodeKind, ExprNode::Kind, static_cast);
|
||||
CASE_TYPE(Bool, bool, static_cast);
|
||||
CASE_TYPE(Double, double, static_cast);
|
||||
CASE_TYPE(ICodeModule, string *, reinterpret_cast);
|
||||
|
@ -53,7 +53,7 @@ namespace ICodeASM {
|
||||
enum OperandType {
|
||||
otNone = 0,
|
||||
otArgumentList,
|
||||
otBinaryOp,
|
||||
otExprNodeKind,
|
||||
otBool,
|
||||
otDouble,
|
||||
otICodeModule,
|
||||
@ -108,8 +108,8 @@ namespace ICodeASM {
|
||||
parseArgumentListOperand (string8_citer begin, string8_citer end,
|
||||
VM::ArgumentList **rval);
|
||||
string8_citer
|
||||
parseBinaryOpOperand (string8_citer begin, string8_citer end,
|
||||
VM::BinaryOperator::BinaryOp *rval);
|
||||
parseExprNodeKindOperand (string8_citer begin, string8_citer end,
|
||||
JavaScript::ExprNode::Kind *rval);
|
||||
string8_citer
|
||||
parseBoolOperand (string8_citer begin, string8_citer end,
|
||||
bool *rval);
|
||||
|
@ -456,7 +456,7 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1,
|
||||
iCode->push_back(instr);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1,
|
||||
TypedRegister source2)
|
||||
{
|
||||
@ -469,7 +469,7 @@ TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1,
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
else {
|
||||
GenericBinaryOP *instr = new GenericBinaryOP(dest, BinaryOperator::mapICodeOp(op), source1, source2);
|
||||
GenericBinaryOP *instr = new GenericBinaryOP(dest, mapICodeOpToExprNode(op), source1, source2);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
return dest;
|
||||
@ -596,7 +596,48 @@ Label *ICodeGenerator::setLabel(Label *l)
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
ExprNode::Kind ICodeGenerator::mapICodeOpToExprNode(ICodeOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case ADD:
|
||||
return ExprNode::add;
|
||||
case SUBTRACT:
|
||||
return ExprNode::subtract;
|
||||
case MULTIPLY:
|
||||
return ExprNode::multiply;
|
||||
case DIVIDE:
|
||||
return ExprNode::divide;
|
||||
case REMAINDER:
|
||||
return ExprNode::modulo;
|
||||
case SHIFTLEFT:
|
||||
return ExprNode::leftShift;
|
||||
case SHIFTRIGHT:
|
||||
return ExprNode::rightShift;
|
||||
case USHIFTRIGHT:
|
||||
return ExprNode::logicalRightShift;
|
||||
case AND:
|
||||
return ExprNode::bitwiseAnd;
|
||||
case OR:
|
||||
return ExprNode::bitwiseOr;
|
||||
case XOR:
|
||||
return ExprNode::bitwiseXor;
|
||||
case POSATE:
|
||||
return ExprNode::plus;
|
||||
case NEGATE:
|
||||
return ExprNode::minus;
|
||||
case BITNOT:
|
||||
return ExprNode::complement;
|
||||
case COMPARE_EQ:
|
||||
return ExprNode::equal;
|
||||
case COMPARE_LT:
|
||||
return ExprNode::lessThan;
|
||||
case COMPARE_LE:
|
||||
return ExprNode::lessThanOrEqual;
|
||||
case STRICT_EQ:
|
||||
return ExprNode::identical;
|
||||
}
|
||||
return ExprNode::none;
|
||||
}
|
||||
|
||||
|
||||
ICodeOp ICodeGenerator::mapExprNodeToICodeOp(ExprNode::Kind kind)
|
||||
@ -1709,6 +1750,18 @@ JSType *ICodeGenerator::extractType(ExprNode *t)
|
||||
return type;
|
||||
}
|
||||
|
||||
JSType *ICodeGenerator::getParameterType(FunctionDefinition &function, int index)
|
||||
{
|
||||
VariableBinding *v = function.parameters;
|
||||
while (v) {
|
||||
if (index-- == 0)
|
||||
return extractType(v->type);
|
||||
else
|
||||
v = v->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::genFunction(FunctionDefinition &function, bool isStatic, bool isConstructor, JSClass *superclass)
|
||||
{
|
||||
ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags;
|
||||
@ -1901,27 +1954,31 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(s);
|
||||
bool isStatic = hasAttribute(f->attributes, Token::Static);
|
||||
bool isConstructor = (s->getKind() == StmtNode::Constructor);
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor)
|
||||
thisClass->defineConstructor(name);
|
||||
else
|
||||
if (isStatic)
|
||||
thisClass->defineStatic(name, &Function_Type);
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f->function.prefix == FunctionName::Operator) {
|
||||
thisClass->defineOperator(f->function.op, getParameterType(f->function, 0), getParameterType(f->function, 1), NULL);
|
||||
}
|
||||
else
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor)
|
||||
thisClass->defineConstructor(name);
|
||||
else
|
||||
if (isStatic)
|
||||
thisClass->defineStatic(name, &Function_Type);
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1990,30 +2047,34 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
|
||||
ICodeGenerator mcg(classContext, NULL, thisClass, flags); // method code generator.
|
||||
ICodeModule *icm = mcg.genFunction(f->function, isStatic, isConstructor, superclass);
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor) {
|
||||
if (name == nameExpr->name)
|
||||
hasDefaultConstructor = true;
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
if (isStatic)
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f->function.prefix == FunctionName::Operator) {
|
||||
thisClass->defineOperator(f->function.op, getParameterType(f->function, 0), getParameterType(f->function, 1), new JSFunction(icm));
|
||||
}
|
||||
else
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor) {
|
||||
if (name == nameExpr->name)
|
||||
hasDefaultConstructor = true;
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
if (isStatic)
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -266,7 +266,7 @@ namespace ICG {
|
||||
void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; }
|
||||
|
||||
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
|
||||
|
||||
ExprNode::Kind mapICodeOpToExprNode(ICodeOp op);
|
||||
|
||||
bool isTopLevel() { return (mFlags & kIsTopLevel) != 0; }
|
||||
bool isWithinWith() { return (mFlags & kIsWithinWith) != 0; }
|
||||
@ -300,7 +300,8 @@ namespace ICG {
|
||||
void readICode(const char *fileName);
|
||||
|
||||
JSType *extractType(ExprNode *t);
|
||||
|
||||
JSType *getParameterType(FunctionDefinition &function, int index);
|
||||
|
||||
TypedRegister genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch = false,
|
||||
Label *trueBranch = NULL,
|
||||
|
@ -73,7 +73,7 @@ namespace ICodeASM {
|
||||
{"DIRECT_CALL", {otRegister, otJSFunction, otArgumentList}},
|
||||
{"DIVIDE", {otRegister, otRegister, otRegister}},
|
||||
{"ELEM_XCR", {otRegister, otRegister, otRegister, otDouble}},
|
||||
{"GENERIC_BINARY_OP", {otRegister, otBinaryOp, otRegister, otRegister}},
|
||||
{"GENERIC_BINARY_OP", {otRegister, otExprNodeKind, otRegister, otRegister}},
|
||||
{"GET_CLOSURE", {otRegister, otUInt32}},
|
||||
{"GET_ELEMENT", {otRegister, otRegister, otRegister}},
|
||||
{"GET_METHOD", {otRegister, otRegister, otUInt32}},
|
||||
@ -203,7 +203,7 @@ namespace ICodeASM {
|
||||
i = new ElemXcr (TypedRegister(static_cast<Register>(node->operand[0].data), 0), TypedRegister(static_cast<Register>(node->operand[1].data), 0), TypedRegister(static_cast<Register>(node->operand[2].data), 0), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 22:
|
||||
i = new GenericBinaryOP (TypedRegister(static_cast<Register>(node->operand[0].data), 0), static_cast<BinaryOperator::BinaryOp>(node->operand[1].data), TypedRegister(static_cast<Register>(node->operand[2].data), 0), TypedRegister(static_cast<Register>(node->operand[3].data), 0));
|
||||
i = new GenericBinaryOP (TypedRegister(static_cast<Register>(node->operand[0].data), 0), static_cast<ExprNode::Kind>(node->operand[1].data), TypedRegister(static_cast<Register>(node->operand[2].data), 0), TypedRegister(static_cast<Register>(node->operand[3].data), 0));
|
||||
break;
|
||||
case 23:
|
||||
i = new GetClosure (TypedRegister(static_cast<Register>(node->operand[0].data), 0), static_cast<uint32>(node->operand[1].data));
|
||||
|
@ -375,80 +375,6 @@ static JSValue identical_Default(const JSValue& r1, const JSValue& r2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static JSValue defineAdd(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// should be three args, first two are types, third is a function.
|
||||
ASSERT(argv[0].isType());
|
||||
ASSERT(argv[1].isType());
|
||||
ASSERT(argv[2].isFunction());
|
||||
|
||||
// XXX need to prove that argv[2].function takes T1 and T2 as args and returns Boolean for the relational operators ?
|
||||
|
||||
cx->addBinaryOperator(BinaryOperator::Add, new BinaryOperator(argv[0].type, argv[1].type, argv[2].function));
|
||||
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
#define DEFINE_OBO(NAME) \
|
||||
static JSValue define##NAME(Context *cx, const JSValues& argv) \
|
||||
{ \
|
||||
ASSERT(argv[0].isType()); \
|
||||
ASSERT(argv[1].isType()); \
|
||||
ASSERT(argv[2].isFunction()); \
|
||||
cx->addBinaryOperator(BinaryOperator::##NAME, \
|
||||
new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); \
|
||||
return kUndefinedValue; \
|
||||
} \
|
||||
|
||||
DEFINE_OBO(Subtract)
|
||||
DEFINE_OBO(Multiply)
|
||||
DEFINE_OBO(Divide)
|
||||
DEFINE_OBO(Remainder)
|
||||
DEFINE_OBO(LeftShift)
|
||||
DEFINE_OBO(RightShift)
|
||||
DEFINE_OBO(LogicalRightShift)
|
||||
DEFINE_OBO(BitwiseOr)
|
||||
DEFINE_OBO(BitwiseXor)
|
||||
DEFINE_OBO(BitwiseAnd)
|
||||
DEFINE_OBO(Less)
|
||||
DEFINE_OBO(LessOrEqual)
|
||||
DEFINE_OBO(Equal)
|
||||
DEFINE_OBO(Identical)
|
||||
|
||||
void Context::initOperatorsPackage()
|
||||
{
|
||||
// hack - the following should be available only after importing the 'Operators' package
|
||||
// (hmm, how will that work - the import needs to connect the functions into this mechanism
|
||||
// do we watch for the specific package name???)
|
||||
|
||||
struct OBO {
|
||||
char *name;
|
||||
JSNativeFunction::JSCode fun;
|
||||
} OBOs[] = {
|
||||
{ "defineAdd", defineAdd },
|
||||
{ "defineSubtract", defineSubtract },
|
||||
{ "defineMultiply", defineMultiply },
|
||||
{ "defineDivide", defineDivide },
|
||||
{ "defineRemainder", defineRemainder },
|
||||
{ "defineLeftShift", defineLeftShift },
|
||||
{ "defineRightShift", defineRightShift },
|
||||
{ "defineLogicalRightShift",defineLogicalRightShift },
|
||||
{ "defineBitwiseOr", defineBitwiseOr },
|
||||
{ "defineBitwiseXor", defineBitwiseXor },
|
||||
{ "defineBitwiseAnd", defineBitwiseAnd },
|
||||
{ "defineLess", defineLess },
|
||||
{ "defineLessOrEqual", defineLessOrEqual },
|
||||
{ "defineEqual", defineEqual },
|
||||
{ "defineIdentical", defineIdentical },
|
||||
};
|
||||
|
||||
for (uint i = 0; i < sizeof(OBOs) / sizeof(struct OBO); i++)
|
||||
mGlobal->defineNativeFunction(mWorld.identifiers[widenCString(OBOs[i].name)], OBOs[i].fun);
|
||||
|
||||
mHasOperatorsPackageLoaded = true;
|
||||
}
|
||||
|
||||
void Context::initContext()
|
||||
{
|
||||
// if global has a parent, assume it's been initialized already.
|
||||
@ -499,55 +425,73 @@ void Context::initContext()
|
||||
JSMath::initMathObject(mGlobal);
|
||||
JSArray::initArrayObject(mGlobal);
|
||||
|
||||
// This initializes the state of the binary operator overload mechanism.
|
||||
// One could argue that it is unneccessary to do this until the 'Operators'
|
||||
// package is loaded and that all (un-typed) binary operators should use a
|
||||
// form of icode that performed the inline operation instead.
|
||||
JSBinaryOperator::JSBinaryCode defaultFunction[] = {
|
||||
add_Default,
|
||||
subtract_Default,
|
||||
multiply_Default,
|
||||
divide_Default,
|
||||
remainder_Default,
|
||||
shiftLeft_Default,
|
||||
shiftRight_Default,
|
||||
UshiftRight_Default,
|
||||
or_Default,
|
||||
xor_Default,
|
||||
and_Default,
|
||||
less_Default,
|
||||
lessOrEqual_Default,
|
||||
equal_Default,
|
||||
identical_Default
|
||||
};
|
||||
|
||||
for (BinaryOperator::BinaryOp b = BinaryOperator::BinaryOperatorFirst;
|
||||
b < BinaryOperator::BinaryOperatorCount;
|
||||
b = (BinaryOperator::BinaryOp)(b + 1) )
|
||||
addBinaryOperator(b, new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(defaultFunction[b])));
|
||||
|
||||
}
|
||||
|
||||
const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op)
|
||||
JSBinaryOperator::JSBinaryCode getDefaultFunction(ExprNode::Kind op)
|
||||
{
|
||||
int32 bestDist1 = JSType::NoRelation;
|
||||
int32 bestDist2 = JSType::NoRelation;
|
||||
BinaryOperatorList::iterator candidate = NULL;
|
||||
switch (op) {
|
||||
case ExprNode::add: return add_Default;
|
||||
case ExprNode::subtract: return subtract_Default;
|
||||
case ExprNode::multiply: return multiply_Default;
|
||||
case ExprNode::divide: return divide_Default;
|
||||
case ExprNode::modulo: return remainder_Default;
|
||||
case ExprNode::leftShift: return shiftLeft_Default;
|
||||
case ExprNode::rightShift: return shiftRight_Default;
|
||||
case ExprNode::logicalRightShift: return UshiftRight_Default;
|
||||
case ExprNode::bitwiseOr: return or_Default;
|
||||
case ExprNode::bitwiseXor: return xor_Default;
|
||||
case ExprNode::bitwiseAnd: return and_Default;
|
||||
case ExprNode::lessThan: return less_Default;
|
||||
case ExprNode::lessThanOrEqual: return lessOrEqual_Default;
|
||||
case ExprNode::equal: return equal_Default;
|
||||
case ExprNode::identical: return identical_Default;
|
||||
default:
|
||||
NOT_REACHED("bad op");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (BinaryOperatorList::iterator i = mBinaryOperators[op].begin();
|
||||
i != mBinaryOperators[op].end(); i++)
|
||||
{
|
||||
int32 dist1 = operand1.getType()->distance((*i)->t1);
|
||||
int32 dist2 = operand2.getType()->distance((*i)->t2);
|
||||
|
||||
if ((dist1 < bestDist1) && (dist2 < bestDist2)) {
|
||||
bestDist1 = dist1;
|
||||
bestDist2 = dist2;
|
||||
candidate = i;
|
||||
const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, ExprNode::Kind op)
|
||||
{
|
||||
JSClass *class1 = operand1.isObject() ? dynamic_cast<JSClass*>(operand1.object->getType()) : NULL;
|
||||
JSClass *class2 = operand2.isObject() ? dynamic_cast<JSClass*>(operand2.object->getType()) : NULL;
|
||||
|
||||
if (class1 || class2) {
|
||||
JSOperatorList applicableList;
|
||||
// find all the applicable operators
|
||||
while (class1) {
|
||||
class1->addApplicableOperators(applicableList, op, operand1.getType(), operand2.getType());
|
||||
class1 = class1->getSuperClass();
|
||||
}
|
||||
while (class2) {
|
||||
class2->addApplicableOperators(applicableList, op, operand1.getType(), operand2.getType());
|
||||
class2 = class2->getSuperClass();
|
||||
}
|
||||
if (applicableList.size() == 0)
|
||||
return JSValue(new JSBinaryOperator(getDefaultFunction(op)) );
|
||||
else {
|
||||
if (applicableList.size() == 1)
|
||||
return JSValue(applicableList[0]->mFunction);
|
||||
else {
|
||||
int32 bestDist1 = JSType::NoRelation;
|
||||
int32 bestDist2 = JSType::NoRelation;
|
||||
JSOperator *candidate = NULL;
|
||||
for (JSOperatorList::iterator i = applicableList.begin(), end = applicableList.end(); i != end; i++) {
|
||||
int32 dist1 = operand1.getType()->distance((*i)->mOperand1);
|
||||
int32 dist2 = operand2.getType()->distance((*i)->mOperand2);
|
||||
if ((dist1 < bestDist1) && (dist2 < bestDist2)) {
|
||||
bestDist1 = dist1;
|
||||
bestDist2 = dist2;
|
||||
candidate = *i;
|
||||
}
|
||||
}
|
||||
ASSERT(candidate);
|
||||
return JSValue(candidate->mFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(candidate);
|
||||
return JSValue((*candidate)->function);
|
||||
return JSValue(new JSBinaryOperator(getDefaultFunction(op)) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace Interpreter {
|
||||
void initContext();
|
||||
public:
|
||||
explicit Context(World& world, JSScope* aGlobal)
|
||||
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false), mCurrentClosure(0) { initContext(); }
|
||||
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mCurrentClosure(0) { initContext(); }
|
||||
|
||||
World& getWorld() { return mWorld; }
|
||||
JSScope* getGlobalObject() { return mGlobal; }
|
||||
@ -83,11 +83,7 @@ namespace Interpreter {
|
||||
|
||||
void loadClass(const char *fileName);
|
||||
|
||||
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
|
||||
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);
|
||||
|
||||
|
||||
bool hasOperatorsPackageLoaded() { return mHasOperatorsPackageLoaded; }
|
||||
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, ExprNode::Kind op);
|
||||
|
||||
private:
|
||||
void broadcast(Event event);
|
||||
@ -103,13 +99,10 @@ namespace Interpreter {
|
||||
ListenerList mListeners;
|
||||
Activation* mActivation;
|
||||
ICodeModule* mICode;
|
||||
bool mHasOperatorsPackageLoaded;
|
||||
JSClosure* mCurrentClosure;
|
||||
|
||||
InstructionIterator mPC;
|
||||
|
||||
BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount];
|
||||
|
||||
}; /* class Context */
|
||||
|
||||
/**
|
||||
|
@ -76,6 +76,15 @@ namespace JSClasses {
|
||||
typedef std::vector<MethodEntry, gc_allocator<MethodEntry> > JSMethods;
|
||||
typedef std::vector<JSFunction*, gc_allocator<JSFunction*> > JSFunctions;
|
||||
|
||||
struct JSOperator {
|
||||
JSType *mOperand1;
|
||||
JSType *mOperand2;
|
||||
JSFunction *mFunction;
|
||||
JSOperator(JSType *op1, JSType *op2, JSFunction *f) : mOperand1(op1), mOperand2(op2), mFunction(f) { }
|
||||
};
|
||||
typedef std::vector<JSOperator *, gc_allocator<JSOperator *> > JSOperatorList;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a class in the JavaScript 2 (ECMA 4) language.
|
||||
* Since a class defines a scope, and is defined in a scope,
|
||||
@ -83,6 +92,7 @@ namespace JSClasses {
|
||||
* class definition.
|
||||
*/
|
||||
class JSClass : public JSType {
|
||||
|
||||
protected:
|
||||
JSScope* mScope;
|
||||
uint32 mSlotCount;
|
||||
@ -95,6 +105,7 @@ namespace JSClasses {
|
||||
bool mHasSetters;
|
||||
JSFunctions mGetters; // allocated at 'complete()' time
|
||||
JSFunctions mSetters;
|
||||
JSOperatorList *mOperators[ExprNode::kindsEnd];
|
||||
public:
|
||||
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
|
||||
: JSType(name, superClass),
|
||||
@ -112,7 +123,9 @@ namespace JSClasses {
|
||||
for (JSSlots::iterator si = superClass->mSlots.begin(); si != sEnd; si++)
|
||||
if (si->second.isVirtual())
|
||||
mSlots[si->first] = si->second;
|
||||
}
|
||||
}
|
||||
for (uint32 i = 0; i < ExprNode::kindsEnd; i++)
|
||||
mOperators[i] = NULL;
|
||||
}
|
||||
|
||||
JSClass* getSuperClass()
|
||||
@ -305,6 +318,35 @@ namespace JSClasses {
|
||||
}
|
||||
}
|
||||
|
||||
void defineOperator(ExprNode::Kind op, JSType *operand1, JSType *operand2, JSFunction *f)
|
||||
{
|
||||
if (!mOperators[op])
|
||||
mOperators[op] = new JSOperatorList();
|
||||
else {
|
||||
for (JSOperatorList::iterator i = mOperators[op]->begin(),
|
||||
end = mOperators[op]->end(); i != end; ++i) {
|
||||
if (((*i)->mOperand1 == operand1)
|
||||
&& ((*i)->mOperand2 == operand2)) {
|
||||
(*i)->mFunction = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mOperators[op]->push_back(new JSOperator(operand1, operand2, f));
|
||||
}
|
||||
|
||||
void addApplicableOperators(JSOperatorList &list, ExprNode::Kind op, const JSType *operand1, const JSType *operand2)
|
||||
{
|
||||
if (mOperators[op]) {
|
||||
for (JSOperatorList::iterator i = mOperators[op]->begin(),
|
||||
end = mOperators[op]->end(); i != end; ++i) {
|
||||
if (operand1->isSubTypeOf((*i)->mOperand1) && operand2->isSubTypeOf((*i)->mOperand2)) {
|
||||
list.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void defineMethod(const String& name, JSFunction *f)
|
||||
{
|
||||
uint32 slot;
|
||||
@ -345,27 +387,10 @@ namespace JSClasses {
|
||||
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
|
||||
return gc_base::operator new(n);
|
||||
}
|
||||
|
||||
void* operator new(size_t n, uint32 slotCount)
|
||||
{
|
||||
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
|
||||
return gc_base::operator new(n);
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void* /*ptr*/) {}
|
||||
void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {}
|
||||
void operator delete(void* /*ptr*/, uint32 /*slotCount*/) {}
|
||||
|
||||
JSInstance(uint32 slotCount)
|
||||
{
|
||||
mType = NULL;
|
||||
// initialize extra slots with undefined.
|
||||
if (slotCount > 0) {
|
||||
std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1),
|
||||
JSTypes::kUndefinedValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSInstance(JSClass* thisClass)
|
||||
{
|
||||
mType = thisClass;
|
||||
|
@ -929,6 +929,16 @@ JSString::operator String()
|
||||
}
|
||||
|
||||
|
||||
bool JSType::isSubTypeOf(const JSType *other) const
|
||||
{
|
||||
if (other == this)
|
||||
return true;
|
||||
if (mBaseType == NULL)
|
||||
return false;
|
||||
return mBaseType->isSubTypeOf(other);
|
||||
}
|
||||
|
||||
|
||||
// # of sub-type relationship between this type and the other type
|
||||
// (== MAX_INT if other is not a base type)
|
||||
|
||||
|
@ -702,6 +702,8 @@ namespace JSTypes {
|
||||
|
||||
const String& getName() const { return mName; }
|
||||
|
||||
bool isSubTypeOf(const JSType *other) const;
|
||||
|
||||
int32 distance(const JSType *other) const;
|
||||
|
||||
JSFunction *getConstructor() const { return mConstructor; }
|
||||
|
@ -355,6 +355,7 @@ const char *const JS::Token::kindNames[kindsEnd] = {
|
||||
"namespace", // Namespace
|
||||
"set", // Set
|
||||
"use", // Use
|
||||
"operator", // Operator
|
||||
|
||||
"identifier" // identifier
|
||||
};
|
||||
@ -494,6 +495,7 @@ const uchar JS::Token::kindFlags[kindsEnd] = {
|
||||
followAttr|followGet, // Namespace
|
||||
isAttr|followGet, // Set
|
||||
followGet, // Use
|
||||
isAttr, // Operator
|
||||
|
||||
isAttr|followGet // identifier
|
||||
};
|
||||
@ -1205,7 +1207,7 @@ const int32 functionHeaderIndent = 9; // Indentation of function signature
|
||||
const int32 namespaceHeaderIndent = 4; // Indentation of class, interface, or namespace header
|
||||
|
||||
|
||||
static const char functionPrefixNames[3][5] = {"", "get ", "set "};
|
||||
static const char functionPrefixNames[3][5] = {"", "get ", "set " };
|
||||
|
||||
// Print this onto f. name must be non-nil.
|
||||
void JS::FunctionName::print(PrettyPrinter &f) const
|
||||
@ -2801,6 +2803,7 @@ void JS::Parser::parseFunctionName(FunctionName &fn)
|
||||
t = &lexer.get(true);
|
||||
}
|
||||
}
|
||||
|
||||
fn.name = parseQualifiedIdentifier(*t, true);
|
||||
}
|
||||
|
||||
@ -2923,6 +2926,75 @@ JS::BlockStmtNode *JS::Parser::parseBody(SemicolonState *semicolonState)
|
||||
}
|
||||
}
|
||||
|
||||
JS::ExprNode::Kind JS::Parser::validateOperatorName(const Token &name)
|
||||
{
|
||||
Lexer operatorLexer(getWorld(), copyTokenChars(name), getReader().sourceLocation); // XXX line number ???
|
||||
|
||||
const Token &t = operatorLexer.get(false); // XXX preferRegExp ???
|
||||
|
||||
// XXX switch to a table lookup instead
|
||||
switch (t.getKind()) {
|
||||
default:
|
||||
syntaxError("Illegal operator name");
|
||||
|
||||
case Token::complement:
|
||||
return ExprNode::complement;
|
||||
case Token::increment:
|
||||
return ExprNode::postIncrement;
|
||||
case Token::decrement:
|
||||
return ExprNode::postDecrement;
|
||||
case Token::Const:
|
||||
return ExprNode::none; // XXX
|
||||
|
||||
case Token::plus:
|
||||
return ExprNode::add;
|
||||
case Token::minus:
|
||||
return ExprNode::subtract;
|
||||
case Token::times:
|
||||
return ExprNode::multiply;
|
||||
case Token::divide:
|
||||
return ExprNode::divide;
|
||||
case Token::modulo:
|
||||
return ExprNode::modulo;
|
||||
case Token::leftShift:
|
||||
return ExprNode::leftShift;
|
||||
case Token::rightShift:
|
||||
return ExprNode::rightShift;
|
||||
case Token::logicalRightShift:
|
||||
return ExprNode::logicalRightShift;
|
||||
case Token::lessThan:
|
||||
return ExprNode::lessThan;
|
||||
case Token::lessThanOrEqual:
|
||||
return ExprNode::lessThanOrEqual;
|
||||
case Token::equal:
|
||||
return ExprNode::equal;
|
||||
case Token::bitwiseAnd:
|
||||
return ExprNode::bitwiseAnd;
|
||||
case Token::bitwiseXor:
|
||||
return ExprNode::bitwiseXor;
|
||||
case Token::bitwiseOr:
|
||||
return ExprNode::bitwiseOr;
|
||||
case Token::identical:
|
||||
return ExprNode::identical;
|
||||
case Token::In:
|
||||
return ExprNode::In;
|
||||
|
||||
case Token::openParenthesis:
|
||||
return ExprNode::call;
|
||||
|
||||
case Token::New:
|
||||
return ExprNode::New;
|
||||
|
||||
case Token::openBracket:
|
||||
return ExprNode::index;
|
||||
|
||||
case Token::Delete:
|
||||
return ExprNode::Delete;
|
||||
}
|
||||
|
||||
return ExprNode::none;
|
||||
|
||||
}
|
||||
|
||||
// Parse and return a statement that takes zero or more initial attributes, which have already been parsed.
|
||||
// If noIn is false, allow the in operator.
|
||||
@ -2975,7 +3047,17 @@ JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *at
|
||||
if (lineBreakBefore(t2) || !(f->function.name = makeIdentifierExpression(t2)))
|
||||
syntaxError("Constructor name expected");
|
||||
} else
|
||||
parseFunctionName(f->function);
|
||||
if (attributes && attributes->contains(Token::Operator)) {
|
||||
// expecting a string literal matching one of the legal operator names
|
||||
const Token &t2 = lexer.get(false);
|
||||
if (!t2.hasKind(Token::string))
|
||||
syntaxError("Operator name (as string literal) expected");
|
||||
f->function.prefix = FunctionName::Operator;
|
||||
f->function.op = validateOperatorName(t2);
|
||||
f->function.name = NULL;
|
||||
}
|
||||
else
|
||||
parseFunctionName(f->function);
|
||||
parseFunctionSignature(f->function);
|
||||
f->function.body = parseBody(&semicolonState);
|
||||
return f;
|
||||
@ -3839,3 +3921,9 @@ JS::ExprNode *JS::Parser::parseResultSignature() {
|
||||
}
|
||||
|
||||
|
||||
bool JS::IdentifierList::contains(Token::Kind kind) {
|
||||
if (name.tokenKind == kind)
|
||||
return true;
|
||||
else
|
||||
return (next) ? next->contains(kind) : false;
|
||||
}
|
||||
|
@ -228,6 +228,7 @@ namespace JavaScript {
|
||||
Namespace, // namespace
|
||||
Set, // set
|
||||
Use, // use
|
||||
Operator, // operator
|
||||
|
||||
identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code)
|
||||
|
||||
@ -243,7 +244,8 @@ namespace JavaScript {
|
||||
#define CASE_TOKEN_ATTRIBUTE_IDENTIFIER \
|
||||
Token::Get: \
|
||||
case Token::Set: \
|
||||
case Token::identifier
|
||||
case Token::identifier: \
|
||||
case Token::Operator \
|
||||
|
||||
#define CASE_TOKEN_NONRESERVED \
|
||||
Token::Attribute: \
|
||||
@ -417,20 +419,6 @@ namespace JavaScript {
|
||||
struct AttributeStmtNode;
|
||||
struct BlockStmtNode;
|
||||
|
||||
struct FunctionName {
|
||||
enum Prefix {
|
||||
normal, // No prefix
|
||||
Get, // get
|
||||
Set // set
|
||||
};
|
||||
|
||||
Prefix prefix; // The name's prefix, if any
|
||||
ExprNode *name; // The name; nil if omitted
|
||||
|
||||
FunctionName(): prefix(normal), name(0) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct IdentifierList;
|
||||
struct VariableBinding: ParseNode {
|
||||
@ -446,18 +434,6 @@ namespace JavaScript {
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct FunctionDefinition: FunctionName {
|
||||
VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any
|
||||
VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none
|
||||
VariableBinding *namedParameters; // The first parameter after the named parameter marker. May or may not have aliases.
|
||||
VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none
|
||||
ExprNode *resultType; // Result type expression or nil if not provided
|
||||
BlockStmtNode *body; // Body; nil if none
|
||||
|
||||
void print(PrettyPrinter &f, bool isConstructor, const AttributeStmtNode *attributes, bool noSemi) const;
|
||||
};
|
||||
|
||||
|
||||
struct ExprNode: ParseNode {
|
||||
enum Kind { // Actual class Operands // Keep synchronized with kindNames
|
||||
none,
|
||||
@ -565,11 +541,39 @@ namespace JavaScript {
|
||||
bool isPostfix() const {return kind >= identifier && kind <= at;}
|
||||
|
||||
virtual void print(PrettyPrinter &f) const;
|
||||
friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;}
|
||||
};
|
||||
|
||||
// Print e onto f.
|
||||
inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) {ASSERT(e); e->print(f); return f;}
|
||||
|
||||
struct FunctionName {
|
||||
enum Prefix {
|
||||
normal, // No prefix
|
||||
Get, // get
|
||||
Set, // set
|
||||
Operator // operator
|
||||
};
|
||||
|
||||
Prefix prefix; // The name's prefix, if any
|
||||
ExprNode::Kind op; // The operator, if appropriate
|
||||
ExprNode *name; // The name; nil if omitted
|
||||
|
||||
FunctionName(): prefix(normal), name(0) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
struct FunctionDefinition: FunctionName {
|
||||
VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any
|
||||
VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none
|
||||
VariableBinding *namedParameters; // The first parameter after the named parameter marker. May or may not have aliases.
|
||||
VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none
|
||||
ExprNode *resultType; // Result type expression or nil if not provided
|
||||
BlockStmtNode *body; // Body; nil if none
|
||||
|
||||
void print(PrettyPrinter &f, bool isConstructor, const AttributeStmtNode *attributes, bool noSemi) const;
|
||||
};
|
||||
|
||||
|
||||
struct IdentifierExprNode: ExprNode {
|
||||
const StringAtom &name; // The identifier
|
||||
@ -763,6 +767,7 @@ namespace JavaScript {
|
||||
const StringAtom &name; // The identifier
|
||||
|
||||
explicit IdentifierList(const StringAtom &name): next(0), name(name) {}
|
||||
bool contains(Token::Kind kind);
|
||||
};
|
||||
|
||||
struct AttributeStmtNode: StmtNode {
|
||||
@ -1052,6 +1057,7 @@ namespace JavaScript {
|
||||
enum AttributeStatement {asAny, asBlock, asConstVar};
|
||||
StmtNode *parseBlock(bool inSwitch, bool noCloseBrace);
|
||||
BlockStmtNode *parseBody(SemicolonState *semicolonState);
|
||||
ExprNode::Kind validateOperatorName(const Token &name);
|
||||
StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, bool noIn, SemicolonState &semicolonState);
|
||||
StmtNode *parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState);
|
||||
StmtNode *parseAnnotatedBlock();
|
||||
|
@ -136,8 +136,8 @@ sub get_map {
|
||||
for $p (@params) {
|
||||
if ($p eq "ArgumentList*") {
|
||||
push (@ot, "otArgumentList");
|
||||
} elsif ($p eq "BinaryOperator::BinaryOp") {
|
||||
push (@ot, "otBinaryOp");
|
||||
} elsif ($p eq "ExprNode::Kind") {
|
||||
push (@ot, "otExprNodeKind");
|
||||
} elsif ($p eq "ICodeModule*") {
|
||||
push (@ot, "otICodeModule");
|
||||
} elsif ($p eq "JSClass*") {
|
||||
|
@ -131,7 +131,7 @@ $ops{"GENERIC_BINARY_OP"} =
|
||||
{
|
||||
super => "Instruction_4",
|
||||
rem => "dest, op, source1, source2",
|
||||
params => [ ("TypedRegister", "BinaryOperator::BinaryOp", "TypedRegister", "TypedRegister") ]
|
||||
params => [ ("TypedRegister", "ExprNode::Kind", "TypedRegister", "TypedRegister") ]
|
||||
};
|
||||
$ops{"MOVE"} =
|
||||
{
|
||||
|
@ -120,57 +120,6 @@ Formatter& operator<< (Formatter &f, InstructionStream &is)
|
||||
return f;
|
||||
}
|
||||
|
||||
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 LessOrEqual;
|
||||
case COMPARE_EQ : return Equal;
|
||||
case STRICT_EQ : return Identical;
|
||||
default :
|
||||
NOT_REACHED("Unsupported binary op");
|
||||
return (BinaryOp)-1;
|
||||
}
|
||||
}
|
||||
|
||||
Formatter& operator<< (Formatter &f, BinaryOperator::BinaryOp &b)
|
||||
{
|
||||
switch (b) {
|
||||
case BinaryOperator::Add: return f << "Add";
|
||||
case BinaryOperator::Subtract: return f << "Subtract";
|
||||
case BinaryOperator::Multiply: return f << "Multiply";
|
||||
case BinaryOperator::Divide: return f << "Divide";
|
||||
case BinaryOperator::Remainder: return f << "Remainder";
|
||||
case BinaryOperator::LeftShift: return f << "LeftShift";
|
||||
case BinaryOperator::RightShift: return f << "RightShift";
|
||||
case BinaryOperator::LogicalRightShift: return f << "LogicalRightShift";
|
||||
|
||||
case BinaryOperator::BitwiseAnd: return f << "BitwiseAnd";
|
||||
case BinaryOperator::BitwiseOr: return f << "BitwiseOr";
|
||||
case BinaryOperator::BitwiseXor: return f << "BitwiseXor";
|
||||
|
||||
case BinaryOperator::Less: return f << "Less";
|
||||
case BinaryOperator::LessOrEqual: return f << "LessOrEqual";
|
||||
case BinaryOperator::Equal: return f << "Equal";
|
||||
case BinaryOperator::Identical: return f << "Identical";
|
||||
default :
|
||||
NOT_REACHED("inner peace, either");
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace VM */
|
||||
} /* namespace JavaScript */
|
||||
|
@ -255,37 +255,6 @@ namespace VM {
|
||||
void setTarget(Label *label) { mOp1 = label; }
|
||||
};
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
class BinaryOperator {
|
||||
public:
|
||||
|
||||
// Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right??
|
||||
typedef enum {
|
||||
BinaryOperatorFirst,
|
||||
Add = BinaryOperatorFirst, Subtract, Multiply, Divide,
|
||||
Remainder, LeftShift, RightShift, LogicalRightShift,
|
||||
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual,
|
||||
Equal, Identical, BinaryOperatorCount
|
||||
} BinaryOp;
|
||||
|
||||
BinaryOperator(const JSType *t1, const JSType *t2, JSBinaryOperator *function) :
|
||||
t1(t1), t2(t2), function(function) { }
|
||||
|
||||
BinaryOperator(const JSType *t1, const JSType *t2, JSFunction *function) :
|
||||
t1(t1), t2(t2), function(function) { }
|
||||
|
||||
static BinaryOp mapICodeOp(ICodeOp op);
|
||||
|
||||
const JSType *t1;
|
||||
const JSType *t2;
|
||||
JSFunction *function;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<BinaryOperator *> BinaryOperatorList;
|
||||
|
||||
Formatter& operator<<(Formatter &f, BinaryOperator::BinaryOp &b);
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
|
@ -388,11 +388,11 @@
|
||||
}
|
||||
};
|
||||
|
||||
class GenericBinaryOP : public Instruction_4<TypedRegister, BinaryOperator::BinaryOp, TypedRegister, TypedRegister> {
|
||||
class GenericBinaryOP : public Instruction_4<TypedRegister, ExprNode::Kind, TypedRegister, TypedRegister> {
|
||||
public:
|
||||
/* dest, op, source1, source2 */
|
||||
GenericBinaryOP (TypedRegister aOp1, BinaryOperator::BinaryOp aOp2, TypedRegister aOp3, TypedRegister aOp4) :
|
||||
Instruction_4<TypedRegister, BinaryOperator::BinaryOp, TypedRegister, TypedRegister>
|
||||
GenericBinaryOP (TypedRegister aOp1, ExprNode::Kind aOp2, TypedRegister aOp3, TypedRegister aOp4) :
|
||||
Instruction_4<TypedRegister, ExprNode::Kind, TypedRegister, TypedRegister>
|
||||
(GENERIC_BINARY_OP, aOp1, aOp2, aOp3, aOp4) {};
|
||||
virtual Formatter& print(Formatter& f) {
|
||||
f << opcodeNames[GENERIC_BINARY_OP] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4;
|
||||
|
@ -44,11 +44,17 @@ namespace ICodeASM {
|
||||
using namespace LexUtils;
|
||||
|
||||
static char *keyword_offset = "offset";
|
||||
static char *keyword_binaryops[] = {"add", "subtract", "multiply", "divide",
|
||||
static char *keyword_exprNodeKinds[] = {"add", "subtract", "multiply", "divide",
|
||||
"remainder", "leftshift", "rightshift",
|
||||
"logicalrightshift", "bitwiseor",
|
||||
"bitwisexor", "bitwiseand", "less",
|
||||
"lessorequal", "equal", "identical", 0};
|
||||
static ExprNode::Kind exprNodeOps[] =
|
||||
{ ExprNode::add, ExprNode::subtract, ExprNode::multiply, ExprNode::divide,
|
||||
ExprNode::modulo, ExprNode::leftShift, ExprNode::rightShift,
|
||||
ExprNode::logicalRightShift, ExprNode::bitwiseOr,
|
||||
ExprNode::bitwiseXor, ExprNode::bitwiseAnd, ExprNode::lessThan,
|
||||
ExprNode::lessThanOrEqual, ExprNode::equal, ExprNode::identical };
|
||||
|
||||
void
|
||||
ICodeParser::parseSourceFromString (const string8 &source)
|
||||
@ -158,8 +164,8 @@ namespace ICodeASM {
|
||||
}
|
||||
|
||||
string8_citer
|
||||
ICodeParser::parseBinaryOpOperand (string8_citer begin, string8_citer end,
|
||||
VM::BinaryOperator::BinaryOp *rval)
|
||||
ICodeParser::parseExprNodeKindOperand (string8_citer begin, string8_citer end,
|
||||
ExprNode::Kind *rval)
|
||||
{
|
||||
TokenLocation tl = seekTokenStart (begin, end);
|
||||
|
||||
@ -168,10 +174,10 @@ namespace ICodeASM {
|
||||
string8 *str;
|
||||
end = lexAlpha (tl.begin, end, &str);
|
||||
|
||||
for (int i = 0; keyword_binaryops[i] != 0; ++i)
|
||||
if (cmp_nocase (*str, keyword_binaryops[i], keyword_binaryops[i] +
|
||||
strlen (keyword_binaryops[i]) + 1) == 0) {
|
||||
*rval = static_cast<VM::BinaryOperator::BinaryOp>(i);
|
||||
for (int i = 0; keyword_exprNodeKinds[i] != 0; ++i)
|
||||
if (cmp_nocase (*str, keyword_exprNodeKinds[i], keyword_exprNodeKinds[i] +
|
||||
strlen (keyword_exprNodeKinds[i]) + 1) == 0) {
|
||||
*rval = exprNodeOps[i];
|
||||
delete str;
|
||||
return end;
|
||||
}
|
||||
@ -381,8 +387,7 @@ namespace ICodeASM {
|
||||
switch (icodemap[icodeID].otype[i])
|
||||
{
|
||||
CASE_TYPE(ArgumentList, VM::ArgumentList *, reinterpret_cast);
|
||||
CASE_TYPE(BinaryOp, VM::BinaryOperator::BinaryOp,
|
||||
static_cast);
|
||||
CASE_TYPE(ExprNodeKind, ExprNode::Kind, static_cast);
|
||||
CASE_TYPE(Bool, bool, static_cast);
|
||||
CASE_TYPE(Double, double, static_cast);
|
||||
CASE_TYPE(ICodeModule, string *, reinterpret_cast);
|
||||
|
@ -53,7 +53,7 @@ namespace ICodeASM {
|
||||
enum OperandType {
|
||||
otNone = 0,
|
||||
otArgumentList,
|
||||
otBinaryOp,
|
||||
otExprNodeKind,
|
||||
otBool,
|
||||
otDouble,
|
||||
otICodeModule,
|
||||
@ -108,8 +108,8 @@ namespace ICodeASM {
|
||||
parseArgumentListOperand (string8_citer begin, string8_citer end,
|
||||
VM::ArgumentList **rval);
|
||||
string8_citer
|
||||
parseBinaryOpOperand (string8_citer begin, string8_citer end,
|
||||
VM::BinaryOperator::BinaryOp *rval);
|
||||
parseExprNodeKindOperand (string8_citer begin, string8_citer end,
|
||||
JavaScript::ExprNode::Kind *rval);
|
||||
string8_citer
|
||||
parseBoolOperand (string8_citer begin, string8_citer end,
|
||||
bool *rval);
|
||||
|
@ -456,7 +456,7 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1,
|
||||
iCode->push_back(instr);
|
||||
return dest;
|
||||
}
|
||||
|
||||
|
||||
TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1,
|
||||
TypedRegister source2)
|
||||
{
|
||||
@ -469,7 +469,7 @@ TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1,
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
else {
|
||||
GenericBinaryOP *instr = new GenericBinaryOP(dest, BinaryOperator::mapICodeOp(op), source1, source2);
|
||||
GenericBinaryOP *instr = new GenericBinaryOP(dest, mapICodeOpToExprNode(op), source1, source2);
|
||||
iCode->push_back(instr);
|
||||
}
|
||||
return dest;
|
||||
@ -596,7 +596,48 @@ Label *ICodeGenerator::setLabel(Label *l)
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
|
||||
ExprNode::Kind ICodeGenerator::mapICodeOpToExprNode(ICodeOp op)
|
||||
{
|
||||
switch (op) {
|
||||
case ADD:
|
||||
return ExprNode::add;
|
||||
case SUBTRACT:
|
||||
return ExprNode::subtract;
|
||||
case MULTIPLY:
|
||||
return ExprNode::multiply;
|
||||
case DIVIDE:
|
||||
return ExprNode::divide;
|
||||
case REMAINDER:
|
||||
return ExprNode::modulo;
|
||||
case SHIFTLEFT:
|
||||
return ExprNode::leftShift;
|
||||
case SHIFTRIGHT:
|
||||
return ExprNode::rightShift;
|
||||
case USHIFTRIGHT:
|
||||
return ExprNode::logicalRightShift;
|
||||
case AND:
|
||||
return ExprNode::bitwiseAnd;
|
||||
case OR:
|
||||
return ExprNode::bitwiseOr;
|
||||
case XOR:
|
||||
return ExprNode::bitwiseXor;
|
||||
case POSATE:
|
||||
return ExprNode::plus;
|
||||
case NEGATE:
|
||||
return ExprNode::minus;
|
||||
case BITNOT:
|
||||
return ExprNode::complement;
|
||||
case COMPARE_EQ:
|
||||
return ExprNode::equal;
|
||||
case COMPARE_LT:
|
||||
return ExprNode::lessThan;
|
||||
case COMPARE_LE:
|
||||
return ExprNode::lessThanOrEqual;
|
||||
case STRICT_EQ:
|
||||
return ExprNode::identical;
|
||||
}
|
||||
return ExprNode::none;
|
||||
}
|
||||
|
||||
|
||||
ICodeOp ICodeGenerator::mapExprNodeToICodeOp(ExprNode::Kind kind)
|
||||
@ -1709,6 +1750,18 @@ JSType *ICodeGenerator::extractType(ExprNode *t)
|
||||
return type;
|
||||
}
|
||||
|
||||
JSType *ICodeGenerator::getParameterType(FunctionDefinition &function, int index)
|
||||
{
|
||||
VariableBinding *v = function.parameters;
|
||||
while (v) {
|
||||
if (index-- == 0)
|
||||
return extractType(v->type);
|
||||
else
|
||||
v = v->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ICodeModule *ICodeGenerator::genFunction(FunctionDefinition &function, bool isStatic, bool isConstructor, JSClass *superclass)
|
||||
{
|
||||
ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags;
|
||||
@ -1901,27 +1954,31 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
FunctionStmtNode *f = static_cast<FunctionStmtNode *>(s);
|
||||
bool isStatic = hasAttribute(f->attributes, Token::Static);
|
||||
bool isConstructor = (s->getKind() == StmtNode::Constructor);
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor)
|
||||
thisClass->defineConstructor(name);
|
||||
else
|
||||
if (isStatic)
|
||||
thisClass->defineStatic(name, &Function_Type);
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f->function.prefix == FunctionName::Operator) {
|
||||
thisClass->defineOperator(f->function.op, getParameterType(f->function, 0), getParameterType(f->function, 1), NULL);
|
||||
}
|
||||
else
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor)
|
||||
thisClass->defineConstructor(name);
|
||||
else
|
||||
if (isStatic)
|
||||
thisClass->defineStatic(name, &Function_Type);
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, NULL, extractType(f->function.resultType));
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1990,30 +2047,34 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet)
|
||||
|
||||
ICodeGenerator mcg(classContext, NULL, thisClass, flags); // method code generator.
|
||||
ICodeModule *icm = mcg.genFunction(f->function, isStatic, isConstructor, superclass);
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor) {
|
||||
if (name == nameExpr->name)
|
||||
hasDefaultConstructor = true;
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
if (isStatic)
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (f->function.prefix == FunctionName::Operator) {
|
||||
thisClass->defineOperator(f->function.op, getParameterType(f->function, 0), getParameterType(f->function, 1), new JSFunction(icm));
|
||||
}
|
||||
else
|
||||
if (f->function.name->getKind() == ExprNode::identifier) {
|
||||
const StringAtom& name = (static_cast<IdentifierExprNode *>(f->function.name))->name;
|
||||
if (isConstructor) {
|
||||
if (name == nameExpr->name)
|
||||
hasDefaultConstructor = true;
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
}
|
||||
else
|
||||
if (isStatic)
|
||||
scg.setStatic(thisClass, name, scg.newFunction(icm));
|
||||
else {
|
||||
switch (f->function.prefix) {
|
||||
case FunctionName::Get:
|
||||
thisClass->setGetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::Set:
|
||||
thisClass->setSetter(name, new JSFunction(icm), icm->mResultType);
|
||||
break;
|
||||
case FunctionName::normal:
|
||||
thisClass->defineMethod(name, new JSFunction(icm));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -266,7 +266,7 @@ namespace ICG {
|
||||
void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; }
|
||||
|
||||
ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind);
|
||||
|
||||
ExprNode::Kind mapICodeOpToExprNode(ICodeOp op);
|
||||
|
||||
bool isTopLevel() { return (mFlags & kIsTopLevel) != 0; }
|
||||
bool isWithinWith() { return (mFlags & kIsWithinWith) != 0; }
|
||||
@ -300,7 +300,8 @@ namespace ICG {
|
||||
void readICode(const char *fileName);
|
||||
|
||||
JSType *extractType(ExprNode *t);
|
||||
|
||||
JSType *getParameterType(FunctionDefinition &function, int index);
|
||||
|
||||
TypedRegister genExpr(ExprNode *p,
|
||||
bool needBoolValueInBranch = false,
|
||||
Label *trueBranch = NULL,
|
||||
|
@ -73,7 +73,7 @@ namespace ICodeASM {
|
||||
{"DIRECT_CALL", {otRegister, otJSFunction, otArgumentList}},
|
||||
{"DIVIDE", {otRegister, otRegister, otRegister}},
|
||||
{"ELEM_XCR", {otRegister, otRegister, otRegister, otDouble}},
|
||||
{"GENERIC_BINARY_OP", {otRegister, otBinaryOp, otRegister, otRegister}},
|
||||
{"GENERIC_BINARY_OP", {otRegister, otExprNodeKind, otRegister, otRegister}},
|
||||
{"GET_CLOSURE", {otRegister, otUInt32}},
|
||||
{"GET_ELEMENT", {otRegister, otRegister, otRegister}},
|
||||
{"GET_METHOD", {otRegister, otRegister, otUInt32}},
|
||||
@ -203,7 +203,7 @@ namespace ICodeASM {
|
||||
i = new ElemXcr (TypedRegister(static_cast<Register>(node->operand[0].data), 0), TypedRegister(static_cast<Register>(node->operand[1].data), 0), TypedRegister(static_cast<Register>(node->operand[2].data), 0), static_cast<double>(node->operand[3].data));
|
||||
break;
|
||||
case 22:
|
||||
i = new GenericBinaryOP (TypedRegister(static_cast<Register>(node->operand[0].data), 0), static_cast<BinaryOperator::BinaryOp>(node->operand[1].data), TypedRegister(static_cast<Register>(node->operand[2].data), 0), TypedRegister(static_cast<Register>(node->operand[3].data), 0));
|
||||
i = new GenericBinaryOP (TypedRegister(static_cast<Register>(node->operand[0].data), 0), static_cast<ExprNode::Kind>(node->operand[1].data), TypedRegister(static_cast<Register>(node->operand[2].data), 0), TypedRegister(static_cast<Register>(node->operand[3].data), 0));
|
||||
break;
|
||||
case 23:
|
||||
i = new GetClosure (TypedRegister(static_cast<Register>(node->operand[0].data), 0), static_cast<uint32>(node->operand[1].data));
|
||||
|
@ -375,80 +375,6 @@ static JSValue identical_Default(const JSValue& r1, const JSValue& r2)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static JSValue defineAdd(Context *cx, const JSValues& argv)
|
||||
{
|
||||
// should be three args, first two are types, third is a function.
|
||||
ASSERT(argv[0].isType());
|
||||
ASSERT(argv[1].isType());
|
||||
ASSERT(argv[2].isFunction());
|
||||
|
||||
// XXX need to prove that argv[2].function takes T1 and T2 as args and returns Boolean for the relational operators ?
|
||||
|
||||
cx->addBinaryOperator(BinaryOperator::Add, new BinaryOperator(argv[0].type, argv[1].type, argv[2].function));
|
||||
|
||||
return kUndefinedValue;
|
||||
}
|
||||
|
||||
#define DEFINE_OBO(NAME) \
|
||||
static JSValue define##NAME(Context *cx, const JSValues& argv) \
|
||||
{ \
|
||||
ASSERT(argv[0].isType()); \
|
||||
ASSERT(argv[1].isType()); \
|
||||
ASSERT(argv[2].isFunction()); \
|
||||
cx->addBinaryOperator(BinaryOperator::##NAME, \
|
||||
new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); \
|
||||
return kUndefinedValue; \
|
||||
} \
|
||||
|
||||
DEFINE_OBO(Subtract)
|
||||
DEFINE_OBO(Multiply)
|
||||
DEFINE_OBO(Divide)
|
||||
DEFINE_OBO(Remainder)
|
||||
DEFINE_OBO(LeftShift)
|
||||
DEFINE_OBO(RightShift)
|
||||
DEFINE_OBO(LogicalRightShift)
|
||||
DEFINE_OBO(BitwiseOr)
|
||||
DEFINE_OBO(BitwiseXor)
|
||||
DEFINE_OBO(BitwiseAnd)
|
||||
DEFINE_OBO(Less)
|
||||
DEFINE_OBO(LessOrEqual)
|
||||
DEFINE_OBO(Equal)
|
||||
DEFINE_OBO(Identical)
|
||||
|
||||
void Context::initOperatorsPackage()
|
||||
{
|
||||
// hack - the following should be available only after importing the 'Operators' package
|
||||
// (hmm, how will that work - the import needs to connect the functions into this mechanism
|
||||
// do we watch for the specific package name???)
|
||||
|
||||
struct OBO {
|
||||
char *name;
|
||||
JSNativeFunction::JSCode fun;
|
||||
} OBOs[] = {
|
||||
{ "defineAdd", defineAdd },
|
||||
{ "defineSubtract", defineSubtract },
|
||||
{ "defineMultiply", defineMultiply },
|
||||
{ "defineDivide", defineDivide },
|
||||
{ "defineRemainder", defineRemainder },
|
||||
{ "defineLeftShift", defineLeftShift },
|
||||
{ "defineRightShift", defineRightShift },
|
||||
{ "defineLogicalRightShift",defineLogicalRightShift },
|
||||
{ "defineBitwiseOr", defineBitwiseOr },
|
||||
{ "defineBitwiseXor", defineBitwiseXor },
|
||||
{ "defineBitwiseAnd", defineBitwiseAnd },
|
||||
{ "defineLess", defineLess },
|
||||
{ "defineLessOrEqual", defineLessOrEqual },
|
||||
{ "defineEqual", defineEqual },
|
||||
{ "defineIdentical", defineIdentical },
|
||||
};
|
||||
|
||||
for (uint i = 0; i < sizeof(OBOs) / sizeof(struct OBO); i++)
|
||||
mGlobal->defineNativeFunction(mWorld.identifiers[widenCString(OBOs[i].name)], OBOs[i].fun);
|
||||
|
||||
mHasOperatorsPackageLoaded = true;
|
||||
}
|
||||
|
||||
void Context::initContext()
|
||||
{
|
||||
// if global has a parent, assume it's been initialized already.
|
||||
@ -499,55 +425,73 @@ void Context::initContext()
|
||||
JSMath::initMathObject(mGlobal);
|
||||
JSArray::initArrayObject(mGlobal);
|
||||
|
||||
// This initializes the state of the binary operator overload mechanism.
|
||||
// One could argue that it is unneccessary to do this until the 'Operators'
|
||||
// package is loaded and that all (un-typed) binary operators should use a
|
||||
// form of icode that performed the inline operation instead.
|
||||
JSBinaryOperator::JSBinaryCode defaultFunction[] = {
|
||||
add_Default,
|
||||
subtract_Default,
|
||||
multiply_Default,
|
||||
divide_Default,
|
||||
remainder_Default,
|
||||
shiftLeft_Default,
|
||||
shiftRight_Default,
|
||||
UshiftRight_Default,
|
||||
or_Default,
|
||||
xor_Default,
|
||||
and_Default,
|
||||
less_Default,
|
||||
lessOrEqual_Default,
|
||||
equal_Default,
|
||||
identical_Default
|
||||
};
|
||||
|
||||
for (BinaryOperator::BinaryOp b = BinaryOperator::BinaryOperatorFirst;
|
||||
b < BinaryOperator::BinaryOperatorCount;
|
||||
b = (BinaryOperator::BinaryOp)(b + 1) )
|
||||
addBinaryOperator(b, new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(defaultFunction[b])));
|
||||
|
||||
}
|
||||
|
||||
const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op)
|
||||
JSBinaryOperator::JSBinaryCode getDefaultFunction(ExprNode::Kind op)
|
||||
{
|
||||
int32 bestDist1 = JSType::NoRelation;
|
||||
int32 bestDist2 = JSType::NoRelation;
|
||||
BinaryOperatorList::iterator candidate = NULL;
|
||||
switch (op) {
|
||||
case ExprNode::add: return add_Default;
|
||||
case ExprNode::subtract: return subtract_Default;
|
||||
case ExprNode::multiply: return multiply_Default;
|
||||
case ExprNode::divide: return divide_Default;
|
||||
case ExprNode::modulo: return remainder_Default;
|
||||
case ExprNode::leftShift: return shiftLeft_Default;
|
||||
case ExprNode::rightShift: return shiftRight_Default;
|
||||
case ExprNode::logicalRightShift: return UshiftRight_Default;
|
||||
case ExprNode::bitwiseOr: return or_Default;
|
||||
case ExprNode::bitwiseXor: return xor_Default;
|
||||
case ExprNode::bitwiseAnd: return and_Default;
|
||||
case ExprNode::lessThan: return less_Default;
|
||||
case ExprNode::lessThanOrEqual: return lessOrEqual_Default;
|
||||
case ExprNode::equal: return equal_Default;
|
||||
case ExprNode::identical: return identical_Default;
|
||||
default:
|
||||
NOT_REACHED("bad op");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (BinaryOperatorList::iterator i = mBinaryOperators[op].begin();
|
||||
i != mBinaryOperators[op].end(); i++)
|
||||
{
|
||||
int32 dist1 = operand1.getType()->distance((*i)->t1);
|
||||
int32 dist2 = operand2.getType()->distance((*i)->t2);
|
||||
|
||||
if ((dist1 < bestDist1) && (dist2 < bestDist2)) {
|
||||
bestDist1 = dist1;
|
||||
bestDist2 = dist2;
|
||||
candidate = i;
|
||||
const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, ExprNode::Kind op)
|
||||
{
|
||||
JSClass *class1 = operand1.isObject() ? dynamic_cast<JSClass*>(operand1.object->getType()) : NULL;
|
||||
JSClass *class2 = operand2.isObject() ? dynamic_cast<JSClass*>(operand2.object->getType()) : NULL;
|
||||
|
||||
if (class1 || class2) {
|
||||
JSOperatorList applicableList;
|
||||
// find all the applicable operators
|
||||
while (class1) {
|
||||
class1->addApplicableOperators(applicableList, op, operand1.getType(), operand2.getType());
|
||||
class1 = class1->getSuperClass();
|
||||
}
|
||||
while (class2) {
|
||||
class2->addApplicableOperators(applicableList, op, operand1.getType(), operand2.getType());
|
||||
class2 = class2->getSuperClass();
|
||||
}
|
||||
if (applicableList.size() == 0)
|
||||
return JSValue(new JSBinaryOperator(getDefaultFunction(op)) );
|
||||
else {
|
||||
if (applicableList.size() == 1)
|
||||
return JSValue(applicableList[0]->mFunction);
|
||||
else {
|
||||
int32 bestDist1 = JSType::NoRelation;
|
||||
int32 bestDist2 = JSType::NoRelation;
|
||||
JSOperator *candidate = NULL;
|
||||
for (JSOperatorList::iterator i = applicableList.begin(), end = applicableList.end(); i != end; i++) {
|
||||
int32 dist1 = operand1.getType()->distance((*i)->mOperand1);
|
||||
int32 dist2 = operand2.getType()->distance((*i)->mOperand2);
|
||||
if ((dist1 < bestDist1) && (dist2 < bestDist2)) {
|
||||
bestDist1 = dist1;
|
||||
bestDist2 = dist2;
|
||||
candidate = *i;
|
||||
}
|
||||
}
|
||||
ASSERT(candidate);
|
||||
return JSValue(candidate->mFunction);
|
||||
}
|
||||
}
|
||||
}
|
||||
ASSERT(candidate);
|
||||
return JSValue((*candidate)->function);
|
||||
return JSValue(new JSBinaryOperator(getDefaultFunction(op)) );
|
||||
}
|
||||
|
||||
|
||||
|
@ -40,7 +40,7 @@ namespace Interpreter {
|
||||
void initContext();
|
||||
public:
|
||||
explicit Context(World& world, JSScope* aGlobal)
|
||||
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false), mCurrentClosure(0) { initContext(); }
|
||||
: mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mCurrentClosure(0) { initContext(); }
|
||||
|
||||
World& getWorld() { return mWorld; }
|
||||
JSScope* getGlobalObject() { return mGlobal; }
|
||||
@ -83,11 +83,7 @@ namespace Interpreter {
|
||||
|
||||
void loadClass(const char *fileName);
|
||||
|
||||
void addBinaryOperator(BinaryOperator::BinaryOp op, BinaryOperator *fn) { mBinaryOperators[op].push_back(fn); }
|
||||
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op);
|
||||
|
||||
|
||||
bool hasOperatorsPackageLoaded() { return mHasOperatorsPackageLoaded; }
|
||||
const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, ExprNode::Kind op);
|
||||
|
||||
private:
|
||||
void broadcast(Event event);
|
||||
@ -103,13 +99,10 @@ namespace Interpreter {
|
||||
ListenerList mListeners;
|
||||
Activation* mActivation;
|
||||
ICodeModule* mICode;
|
||||
bool mHasOperatorsPackageLoaded;
|
||||
JSClosure* mCurrentClosure;
|
||||
|
||||
InstructionIterator mPC;
|
||||
|
||||
BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount];
|
||||
|
||||
}; /* class Context */
|
||||
|
||||
/**
|
||||
|
@ -76,6 +76,15 @@ namespace JSClasses {
|
||||
typedef std::vector<MethodEntry, gc_allocator<MethodEntry> > JSMethods;
|
||||
typedef std::vector<JSFunction*, gc_allocator<JSFunction*> > JSFunctions;
|
||||
|
||||
struct JSOperator {
|
||||
JSType *mOperand1;
|
||||
JSType *mOperand2;
|
||||
JSFunction *mFunction;
|
||||
JSOperator(JSType *op1, JSType *op2, JSFunction *f) : mOperand1(op1), mOperand2(op2), mFunction(f) { }
|
||||
};
|
||||
typedef std::vector<JSOperator *, gc_allocator<JSOperator *> > JSOperatorList;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a class in the JavaScript 2 (ECMA 4) language.
|
||||
* Since a class defines a scope, and is defined in a scope,
|
||||
@ -83,6 +92,7 @@ namespace JSClasses {
|
||||
* class definition.
|
||||
*/
|
||||
class JSClass : public JSType {
|
||||
|
||||
protected:
|
||||
JSScope* mScope;
|
||||
uint32 mSlotCount;
|
||||
@ -95,6 +105,7 @@ namespace JSClasses {
|
||||
bool mHasSetters;
|
||||
JSFunctions mGetters; // allocated at 'complete()' time
|
||||
JSFunctions mSetters;
|
||||
JSOperatorList *mOperators[ExprNode::kindsEnd];
|
||||
public:
|
||||
JSClass(JSScope* scope, const String& name, JSClass* superClass = 0)
|
||||
: JSType(name, superClass),
|
||||
@ -112,7 +123,9 @@ namespace JSClasses {
|
||||
for (JSSlots::iterator si = superClass->mSlots.begin(); si != sEnd; si++)
|
||||
if (si->second.isVirtual())
|
||||
mSlots[si->first] = si->second;
|
||||
}
|
||||
}
|
||||
for (uint32 i = 0; i < ExprNode::kindsEnd; i++)
|
||||
mOperators[i] = NULL;
|
||||
}
|
||||
|
||||
JSClass* getSuperClass()
|
||||
@ -305,6 +318,35 @@ namespace JSClasses {
|
||||
}
|
||||
}
|
||||
|
||||
void defineOperator(ExprNode::Kind op, JSType *operand1, JSType *operand2, JSFunction *f)
|
||||
{
|
||||
if (!mOperators[op])
|
||||
mOperators[op] = new JSOperatorList();
|
||||
else {
|
||||
for (JSOperatorList::iterator i = mOperators[op]->begin(),
|
||||
end = mOperators[op]->end(); i != end; ++i) {
|
||||
if (((*i)->mOperand1 == operand1)
|
||||
&& ((*i)->mOperand2 == operand2)) {
|
||||
(*i)->mFunction = f;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mOperators[op]->push_back(new JSOperator(operand1, operand2, f));
|
||||
}
|
||||
|
||||
void addApplicableOperators(JSOperatorList &list, ExprNode::Kind op, const JSType *operand1, const JSType *operand2)
|
||||
{
|
||||
if (mOperators[op]) {
|
||||
for (JSOperatorList::iterator i = mOperators[op]->begin(),
|
||||
end = mOperators[op]->end(); i != end; ++i) {
|
||||
if (operand1->isSubTypeOf((*i)->mOperand1) && operand2->isSubTypeOf((*i)->mOperand2)) {
|
||||
list.push_back(*i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void defineMethod(const String& name, JSFunction *f)
|
||||
{
|
||||
uint32 slot;
|
||||
@ -345,27 +387,10 @@ namespace JSClasses {
|
||||
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
|
||||
return gc_base::operator new(n);
|
||||
}
|
||||
|
||||
void* operator new(size_t n, uint32 slotCount)
|
||||
{
|
||||
if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1);
|
||||
return gc_base::operator new(n);
|
||||
}
|
||||
|
||||
|
||||
void operator delete(void* /*ptr*/) {}
|
||||
void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {}
|
||||
void operator delete(void* /*ptr*/, uint32 /*slotCount*/) {}
|
||||
|
||||
JSInstance(uint32 slotCount)
|
||||
{
|
||||
mType = NULL;
|
||||
// initialize extra slots with undefined.
|
||||
if (slotCount > 0) {
|
||||
std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1),
|
||||
JSTypes::kUndefinedValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
JSInstance(JSClass* thisClass)
|
||||
{
|
||||
mType = thisClass;
|
||||
|
@ -929,6 +929,16 @@ JSString::operator String()
|
||||
}
|
||||
|
||||
|
||||
bool JSType::isSubTypeOf(const JSType *other) const
|
||||
{
|
||||
if (other == this)
|
||||
return true;
|
||||
if (mBaseType == NULL)
|
||||
return false;
|
||||
return mBaseType->isSubTypeOf(other);
|
||||
}
|
||||
|
||||
|
||||
// # of sub-type relationship between this type and the other type
|
||||
// (== MAX_INT if other is not a base type)
|
||||
|
||||
|
@ -702,6 +702,8 @@ namespace JSTypes {
|
||||
|
||||
const String& getName() const { return mName; }
|
||||
|
||||
bool isSubTypeOf(const JSType *other) const;
|
||||
|
||||
int32 distance(const JSType *other) const;
|
||||
|
||||
JSFunction *getConstructor() const { return mConstructor; }
|
||||
|
@ -355,6 +355,7 @@ const char *const JS::Token::kindNames[kindsEnd] = {
|
||||
"namespace", // Namespace
|
||||
"set", // Set
|
||||
"use", // Use
|
||||
"operator", // Operator
|
||||
|
||||
"identifier" // identifier
|
||||
};
|
||||
@ -494,6 +495,7 @@ const uchar JS::Token::kindFlags[kindsEnd] = {
|
||||
followAttr|followGet, // Namespace
|
||||
isAttr|followGet, // Set
|
||||
followGet, // Use
|
||||
isAttr, // Operator
|
||||
|
||||
isAttr|followGet // identifier
|
||||
};
|
||||
@ -1205,7 +1207,7 @@ const int32 functionHeaderIndent = 9; // Indentation of function signature
|
||||
const int32 namespaceHeaderIndent = 4; // Indentation of class, interface, or namespace header
|
||||
|
||||
|
||||
static const char functionPrefixNames[3][5] = {"", "get ", "set "};
|
||||
static const char functionPrefixNames[3][5] = {"", "get ", "set " };
|
||||
|
||||
// Print this onto f. name must be non-nil.
|
||||
void JS::FunctionName::print(PrettyPrinter &f) const
|
||||
@ -2801,6 +2803,7 @@ void JS::Parser::parseFunctionName(FunctionName &fn)
|
||||
t = &lexer.get(true);
|
||||
}
|
||||
}
|
||||
|
||||
fn.name = parseQualifiedIdentifier(*t, true);
|
||||
}
|
||||
|
||||
@ -2923,6 +2926,75 @@ JS::BlockStmtNode *JS::Parser::parseBody(SemicolonState *semicolonState)
|
||||
}
|
||||
}
|
||||
|
||||
JS::ExprNode::Kind JS::Parser::validateOperatorName(const Token &name)
|
||||
{
|
||||
Lexer operatorLexer(getWorld(), copyTokenChars(name), getReader().sourceLocation); // XXX line number ???
|
||||
|
||||
const Token &t = operatorLexer.get(false); // XXX preferRegExp ???
|
||||
|
||||
// XXX switch to a table lookup instead
|
||||
switch (t.getKind()) {
|
||||
default:
|
||||
syntaxError("Illegal operator name");
|
||||
|
||||
case Token::complement:
|
||||
return ExprNode::complement;
|
||||
case Token::increment:
|
||||
return ExprNode::postIncrement;
|
||||
case Token::decrement:
|
||||
return ExprNode::postDecrement;
|
||||
case Token::Const:
|
||||
return ExprNode::none; // XXX
|
||||
|
||||
case Token::plus:
|
||||
return ExprNode::add;
|
||||
case Token::minus:
|
||||
return ExprNode::subtract;
|
||||
case Token::times:
|
||||
return ExprNode::multiply;
|
||||
case Token::divide:
|
||||
return ExprNode::divide;
|
||||
case Token::modulo:
|
||||
return ExprNode::modulo;
|
||||
case Token::leftShift:
|
||||
return ExprNode::leftShift;
|
||||
case Token::rightShift:
|
||||
return ExprNode::rightShift;
|
||||
case Token::logicalRightShift:
|
||||
return ExprNode::logicalRightShift;
|
||||
case Token::lessThan:
|
||||
return ExprNode::lessThan;
|
||||
case Token::lessThanOrEqual:
|
||||
return ExprNode::lessThanOrEqual;
|
||||
case Token::equal:
|
||||
return ExprNode::equal;
|
||||
case Token::bitwiseAnd:
|
||||
return ExprNode::bitwiseAnd;
|
||||
case Token::bitwiseXor:
|
||||
return ExprNode::bitwiseXor;
|
||||
case Token::bitwiseOr:
|
||||
return ExprNode::bitwiseOr;
|
||||
case Token::identical:
|
||||
return ExprNode::identical;
|
||||
case Token::In:
|
||||
return ExprNode::In;
|
||||
|
||||
case Token::openParenthesis:
|
||||
return ExprNode::call;
|
||||
|
||||
case Token::New:
|
||||
return ExprNode::New;
|
||||
|
||||
case Token::openBracket:
|
||||
return ExprNode::index;
|
||||
|
||||
case Token::Delete:
|
||||
return ExprNode::Delete;
|
||||
}
|
||||
|
||||
return ExprNode::none;
|
||||
|
||||
}
|
||||
|
||||
// Parse and return a statement that takes zero or more initial attributes, which have already been parsed.
|
||||
// If noIn is false, allow the in operator.
|
||||
@ -2975,7 +3047,17 @@ JS::StmtNode *JS::Parser::parseAttributeStatement(uint32 pos, IdentifierList *at
|
||||
if (lineBreakBefore(t2) || !(f->function.name = makeIdentifierExpression(t2)))
|
||||
syntaxError("Constructor name expected");
|
||||
} else
|
||||
parseFunctionName(f->function);
|
||||
if (attributes && attributes->contains(Token::Operator)) {
|
||||
// expecting a string literal matching one of the legal operator names
|
||||
const Token &t2 = lexer.get(false);
|
||||
if (!t2.hasKind(Token::string))
|
||||
syntaxError("Operator name (as string literal) expected");
|
||||
f->function.prefix = FunctionName::Operator;
|
||||
f->function.op = validateOperatorName(t2);
|
||||
f->function.name = NULL;
|
||||
}
|
||||
else
|
||||
parseFunctionName(f->function);
|
||||
parseFunctionSignature(f->function);
|
||||
f->function.body = parseBody(&semicolonState);
|
||||
return f;
|
||||
@ -3839,3 +3921,9 @@ JS::ExprNode *JS::Parser::parseResultSignature() {
|
||||
}
|
||||
|
||||
|
||||
bool JS::IdentifierList::contains(Token::Kind kind) {
|
||||
if (name.tokenKind == kind)
|
||||
return true;
|
||||
else
|
||||
return (next) ? next->contains(kind) : false;
|
||||
}
|
||||
|
@ -228,6 +228,7 @@ namespace JavaScript {
|
||||
Namespace, // namespace
|
||||
Set, // set
|
||||
Use, // use
|
||||
Operator, // operator
|
||||
|
||||
identifier, // Non-keyword identifier (may be same as a keyword if it contains an escape code)
|
||||
|
||||
@ -243,7 +244,8 @@ namespace JavaScript {
|
||||
#define CASE_TOKEN_ATTRIBUTE_IDENTIFIER \
|
||||
Token::Get: \
|
||||
case Token::Set: \
|
||||
case Token::identifier
|
||||
case Token::identifier: \
|
||||
case Token::Operator \
|
||||
|
||||
#define CASE_TOKEN_NONRESERVED \
|
||||
Token::Attribute: \
|
||||
@ -417,20 +419,6 @@ namespace JavaScript {
|
||||
struct AttributeStmtNode;
|
||||
struct BlockStmtNode;
|
||||
|
||||
struct FunctionName {
|
||||
enum Prefix {
|
||||
normal, // No prefix
|
||||
Get, // get
|
||||
Set // set
|
||||
};
|
||||
|
||||
Prefix prefix; // The name's prefix, if any
|
||||
ExprNode *name; // The name; nil if omitted
|
||||
|
||||
FunctionName(): prefix(normal), name(0) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct IdentifierList;
|
||||
struct VariableBinding: ParseNode {
|
||||
@ -446,18 +434,6 @@ namespace JavaScript {
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
|
||||
struct FunctionDefinition: FunctionName {
|
||||
VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any
|
||||
VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none
|
||||
VariableBinding *namedParameters; // The first parameter after the named parameter marker. May or may not have aliases.
|
||||
VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none
|
||||
ExprNode *resultType; // Result type expression or nil if not provided
|
||||
BlockStmtNode *body; // Body; nil if none
|
||||
|
||||
void print(PrettyPrinter &f, bool isConstructor, const AttributeStmtNode *attributes, bool noSemi) const;
|
||||
};
|
||||
|
||||
|
||||
struct ExprNode: ParseNode {
|
||||
enum Kind { // Actual class Operands // Keep synchronized with kindNames
|
||||
none,
|
||||
@ -565,11 +541,39 @@ namespace JavaScript {
|
||||
bool isPostfix() const {return kind >= identifier && kind <= at;}
|
||||
|
||||
virtual void print(PrettyPrinter &f) const;
|
||||
friend Formatter &operator<<(Formatter &f, Kind k) {f << kindName(k); return f;}
|
||||
};
|
||||
|
||||
// Print e onto f.
|
||||
inline PrettyPrinter &operator<<(PrettyPrinter &f, const ExprNode *e) {ASSERT(e); e->print(f); return f;}
|
||||
|
||||
struct FunctionName {
|
||||
enum Prefix {
|
||||
normal, // No prefix
|
||||
Get, // get
|
||||
Set, // set
|
||||
Operator // operator
|
||||
};
|
||||
|
||||
Prefix prefix; // The name's prefix, if any
|
||||
ExprNode::Kind op; // The operator, if appropriate
|
||||
ExprNode *name; // The name; nil if omitted
|
||||
|
||||
FunctionName(): prefix(normal), name(0) {}
|
||||
|
||||
void print(PrettyPrinter &f) const;
|
||||
};
|
||||
struct FunctionDefinition: FunctionName {
|
||||
VariableBinding *parameters; // Linked list of all parameters, including optional and rest parameters, if any
|
||||
VariableBinding *optParameters; // Pointer to first non-required parameter inside parameters list; nil if none
|
||||
VariableBinding *namedParameters; // The first parameter after the named parameter marker. May or may not have aliases.
|
||||
VariableBinding *restParameter; // Pointer to rest parameter inside parameters list; nil if none
|
||||
ExprNode *resultType; // Result type expression or nil if not provided
|
||||
BlockStmtNode *body; // Body; nil if none
|
||||
|
||||
void print(PrettyPrinter &f, bool isConstructor, const AttributeStmtNode *attributes, bool noSemi) const;
|
||||
};
|
||||
|
||||
|
||||
struct IdentifierExprNode: ExprNode {
|
||||
const StringAtom &name; // The identifier
|
||||
@ -763,6 +767,7 @@ namespace JavaScript {
|
||||
const StringAtom &name; // The identifier
|
||||
|
||||
explicit IdentifierList(const StringAtom &name): next(0), name(name) {}
|
||||
bool contains(Token::Kind kind);
|
||||
};
|
||||
|
||||
struct AttributeStmtNode: StmtNode {
|
||||
@ -1052,6 +1057,7 @@ namespace JavaScript {
|
||||
enum AttributeStatement {asAny, asBlock, asConstVar};
|
||||
StmtNode *parseBlock(bool inSwitch, bool noCloseBrace);
|
||||
BlockStmtNode *parseBody(SemicolonState *semicolonState);
|
||||
ExprNode::Kind validateOperatorName(const Token &name);
|
||||
StmtNode *parseAttributeStatement(uint32 pos, IdentifierList *attributes, const Token &t, bool noIn, SemicolonState &semicolonState);
|
||||
StmtNode *parseAttributesAndStatement(const Token *t, AttributeStatement as, SemicolonState &semicolonState);
|
||||
StmtNode *parseAnnotatedBlock();
|
||||
|
@ -120,57 +120,6 @@ Formatter& operator<< (Formatter &f, InstructionStream &is)
|
||||
return f;
|
||||
}
|
||||
|
||||
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 LessOrEqual;
|
||||
case COMPARE_EQ : return Equal;
|
||||
case STRICT_EQ : return Identical;
|
||||
default :
|
||||
NOT_REACHED("Unsupported binary op");
|
||||
return (BinaryOp)-1;
|
||||
}
|
||||
}
|
||||
|
||||
Formatter& operator<< (Formatter &f, BinaryOperator::BinaryOp &b)
|
||||
{
|
||||
switch (b) {
|
||||
case BinaryOperator::Add: return f << "Add";
|
||||
case BinaryOperator::Subtract: return f << "Subtract";
|
||||
case BinaryOperator::Multiply: return f << "Multiply";
|
||||
case BinaryOperator::Divide: return f << "Divide";
|
||||
case BinaryOperator::Remainder: return f << "Remainder";
|
||||
case BinaryOperator::LeftShift: return f << "LeftShift";
|
||||
case BinaryOperator::RightShift: return f << "RightShift";
|
||||
case BinaryOperator::LogicalRightShift: return f << "LogicalRightShift";
|
||||
|
||||
case BinaryOperator::BitwiseAnd: return f << "BitwiseAnd";
|
||||
case BinaryOperator::BitwiseOr: return f << "BitwiseOr";
|
||||
case BinaryOperator::BitwiseXor: return f << "BitwiseXor";
|
||||
|
||||
case BinaryOperator::Less: return f << "Less";
|
||||
case BinaryOperator::LessOrEqual: return f << "LessOrEqual";
|
||||
case BinaryOperator::Equal: return f << "Equal";
|
||||
case BinaryOperator::Identical: return f << "Identical";
|
||||
default :
|
||||
NOT_REACHED("inner peace, either");
|
||||
return f;
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace VM */
|
||||
} /* namespace JavaScript */
|
||||
|
@ -255,37 +255,6 @@ namespace VM {
|
||||
void setTarget(Label *label) { mOp1 = label; }
|
||||
};
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
class BinaryOperator {
|
||||
public:
|
||||
|
||||
// Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right??
|
||||
typedef enum {
|
||||
BinaryOperatorFirst,
|
||||
Add = BinaryOperatorFirst, Subtract, Multiply, Divide,
|
||||
Remainder, LeftShift, RightShift, LogicalRightShift,
|
||||
BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual,
|
||||
Equal, Identical, BinaryOperatorCount
|
||||
} BinaryOp;
|
||||
|
||||
BinaryOperator(const JSType *t1, const JSType *t2, JSBinaryOperator *function) :
|
||||
t1(t1), t2(t2), function(function) { }
|
||||
|
||||
BinaryOperator(const JSType *t1, const JSType *t2, JSFunction *function) :
|
||||
t1(t1), t2(t2), function(function) { }
|
||||
|
||||
static BinaryOp mapICodeOp(ICodeOp op);
|
||||
|
||||
const JSType *t1;
|
||||
const JSType *t2;
|
||||
JSFunction *function;
|
||||
|
||||
};
|
||||
|
||||
typedef std::vector<BinaryOperator *> BinaryOperatorList;
|
||||
|
||||
Formatter& operator<<(Formatter &f, BinaryOperator::BinaryOp &b);
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
|
@ -136,8 +136,8 @@ sub get_map {
|
||||
for $p (@params) {
|
||||
if ($p eq "ArgumentList*") {
|
||||
push (@ot, "otArgumentList");
|
||||
} elsif ($p eq "BinaryOperator::BinaryOp") {
|
||||
push (@ot, "otBinaryOp");
|
||||
} elsif ($p eq "ExprNode::Kind") {
|
||||
push (@ot, "otExprNodeKind");
|
||||
} elsif ($p eq "ICodeModule*") {
|
||||
push (@ot, "otICodeModule");
|
||||
} elsif ($p eq "JSClass*") {
|
||||
|
@ -131,7 +131,7 @@ $ops{"GENERIC_BINARY_OP"} =
|
||||
{
|
||||
super => "Instruction_4",
|
||||
rem => "dest, op, source1, source2",
|
||||
params => [ ("TypedRegister", "BinaryOperator::BinaryOp", "TypedRegister", "TypedRegister") ]
|
||||
params => [ ("TypedRegister", "ExprNode::Kind", "TypedRegister", "TypedRegister") ]
|
||||
};
|
||||
$ops{"MOVE"} =
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user