New (incomplete but functional) implementation of operator overriding.

This commit is contained in:
rogerl%netscape.com 2001-01-11 00:03:05 +00:00
parent 23cd859c75
commit d13899b06c
34 changed files with 754 additions and 648 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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,

View File

@ -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));

View File

@ -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)) );
}

View File

@ -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 */
/**

View File

@ -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;

View File

@ -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)

View File

@ -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; }

View File

@ -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;
}

View File

@ -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();

View File

@ -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*") {

View File

@ -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"} =
{

View File

@ -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 */

View File

@ -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);
/********************************************************************/

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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,

View File

@ -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));

View File

@ -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)) );
}

View File

@ -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 */
/**

View File

@ -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;

View File

@ -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)

View File

@ -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; }

View File

@ -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;
}

View File

@ -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();

View File

@ -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 */

View File

@ -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);
/********************************************************************/

View File

@ -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*") {

View File

@ -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"} =
{