diff --git a/mozilla/js/js2/icode.h b/mozilla/js/js2/icode.h index d689203d3df..635dd80362e 100644 --- a/mozilla/js/js2/icode.h +++ b/mozilla/js/js2/icode.h @@ -23,6 +23,7 @@ DELETE_PROP, /* dest, object, prop name */ DIVIDE, /* dest, source1, source2 */ ELEM_XCR, /* dest, base, index, value */ + GENERIC_BINARY_OP, /* dest, op, source1, source2 */ GET_ELEMENT, /* dest, base, index */ GET_PROP, /* dest, object, prop name */ GET_SLOT, /* dest, object, slot number */ @@ -310,6 +311,22 @@ } }; + class GenericBinaryOP : public Instruction_4 { + public: + /* dest, op, source1, source2 */ + GenericBinaryOP (TypedRegister aOp1, BinaryOperator::BinaryOp aOp2, TypedRegister aOp3, TypedRegister aOp4) : + Instruction_4 + (GENERIC_BINARY_OP, aOp1, aOp2, aOp3, aOp4) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[GENERIC_BINARY_OP] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first] << ", " << "R" << mOp4.first << '=' << registers[mOp4.first]; + return f; + } + }; + class GetElement : public Instruction_3 { public: /* dest, base, index */ @@ -1045,77 +1062,78 @@ #else char *opcodeNames[] = { - "ADD ", - "AND ", - "BITNOT ", - "BRANCH ", - "BRANCH_FALSE ", - "BRANCH_TRUE ", - "CALL ", - "CAST ", - "COMPARE_EQ ", - "COMPARE_GE ", - "COMPARE_GT ", - "COMPARE_IN ", - "COMPARE_LE ", - "COMPARE_LT ", - "COMPARE_NE ", - "CONSTRUCTOR_CALL", - "DEBUGGER ", - "DELETE_PROP ", - "DIVIDE ", - "ELEM_XCR ", - "GET_ELEMENT ", - "GET_PROP ", - "GET_SLOT ", - "GET_STATIC ", - "INSTANCEOF ", - "JSR ", - "LOAD_BOOLEAN ", - "LOAD_IMMEDIATE ", - "LOAD_NAME ", - "LOAD_STRING ", - "METHOD_CALL ", - "MOVE ", - "MULTIPLY ", - "NAME_XCR ", - "NEGATE ", - "NEW_ARRAY ", - "NEW_CLASS ", - "NEW_FUNCTION ", - "NEW_OBJECT ", - "NOP ", - "NOT ", - "OR ", - "POSATE ", - "PROP_XCR ", - "REMAINDER ", - "RETURN ", - "RETURN_VOID ", - "RTS ", - "SAVE_NAME ", - "SET_ELEMENT ", - "SET_PROP ", - "SET_SLOT ", - "SET_STATIC ", - "SHIFTLEFT ", - "SHIFTRIGHT ", - "SLOT_XCR ", - "STATIC_CALL ", - "STATIC_XCR ", - "STRICT_EQ ", - "STRICT_NE ", - "SUBTRACT ", - "SUPER ", - "TEST ", - "THROW ", - "TRYIN ", - "TRYOUT ", - "USHIFTRIGHT ", - "VAR_XCR ", - "WITHIN ", - "WITHOUT ", - "XOR ", + "ADD ", + "AND ", + "BITNOT ", + "BRANCH ", + "BRANCH_FALSE ", + "BRANCH_TRUE ", + "CALL ", + "CAST ", + "COMPARE_EQ ", + "COMPARE_GE ", + "COMPARE_GT ", + "COMPARE_IN ", + "COMPARE_LE ", + "COMPARE_LT ", + "COMPARE_NE ", + "CONSTRUCTOR_CALL ", + "DEBUGGER ", + "DELETE_PROP ", + "DIVIDE ", + "ELEM_XCR ", + "GENERIC_BINARY_OP", + "GET_ELEMENT ", + "GET_PROP ", + "GET_SLOT ", + "GET_STATIC ", + "INSTANCEOF ", + "JSR ", + "LOAD_BOOLEAN ", + "LOAD_IMMEDIATE ", + "LOAD_NAME ", + "LOAD_STRING ", + "METHOD_CALL ", + "MOVE ", + "MULTIPLY ", + "NAME_XCR ", + "NEGATE ", + "NEW_ARRAY ", + "NEW_CLASS ", + "NEW_FUNCTION ", + "NEW_OBJECT ", + "NOP ", + "NOT ", + "OR ", + "POSATE ", + "PROP_XCR ", + "REMAINDER ", + "RETURN ", + "RETURN_VOID ", + "RTS ", + "SAVE_NAME ", + "SET_ELEMENT ", + "SET_PROP ", + "SET_SLOT ", + "SET_STATIC ", + "SHIFTLEFT ", + "SHIFTRIGHT ", + "SLOT_XCR ", + "STATIC_CALL ", + "STATIC_XCR ", + "STRICT_EQ ", + "STRICT_NE ", + "SUBTRACT ", + "SUPER ", + "TEST ", + "THROW ", + "TRYIN ", + "TRYOUT ", + "USHIFTRIGHT ", + "VAR_XCR ", + "WITHIN ", + "WITHOUT ", + "XOR ", }; #endif diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 6bd936e773e..f1f606e7f83 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -441,6 +441,17 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1, return dest; } +TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1, + TypedRegister source2) +{ + ASSERT(source1.first != NotARegister); + ASSERT(source2.first != NotARegister); + TypedRegister dest(getTempRegister(), &Any_Type); + GenericBinaryOP *instr = new GenericBinaryOP(dest, BinaryOperator::mapICodeOp(op), source1, source2); + iCode->push_back(instr); + return dest; +} + TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); @@ -1227,7 +1238,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, BinaryExprNode *b = static_cast(p); TypedRegister r1 = genExpr(b->op1); TypedRegister r2 = genExpr(b->op2); - ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + + if ((r1.second == &Integer_Type) && (r2.second == &Integer_Type)) { + op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + } + + ret = binaryOp(mapExprNodeToICodeOp(p->getKind()), r1, r2); } break; case ExprNode::assignment: diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index a05e97146a5..83f4a42e530 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -241,6 +241,7 @@ namespace ICG { TypedRegister op(ICodeOp op, TypedRegister source); TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2); + TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2); TypedRegister call(TypedRegister target, const StringAtom &name, RegisterList *args); TypedRegister methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList *args); TypedRegister staticCall(JSClass *c, const StringAtom &name, RegisterList *args); diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index 89a6be6214d..16532311ff7 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -51,6 +51,7 @@ namespace Interpreter { #define src1(i) op2(i) #define src2(i) op3(i) #define ofs(i) (i->getOffset()) +#define val2(i) op2(i) #define val3(i) op3(i) #define val4(i) op4(i) @@ -376,92 +377,7 @@ static JSValue identical_Default(const JSValue& r1, const JSValue& r2) } -class BinaryOperator { -public: - - // Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right?? - typedef enum { - Add, Subtract, Multiply, Divide, - Remainder, LeftShift, RightShift, LogicalRightShift, - BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual, - Equal, Identical - } 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; - -}; - -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; - } -} - - - -typedef std::vector BinaryOperatorList; -BinaryOperatorList binaryOperators[15]; - - -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 -}; - -class InitBinaryOperators { - -public: - InitBinaryOperators() { - - for (int i = BinaryOperator::Add; i <= BinaryOperator::Identical; i++) - binaryOperators[i].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(defaultFunction[i]))); - } -} initializer = InitBinaryOperators(); - -static JSValue defineAdd(const JSValues& argv) +static JSValue defineAdd(Context *cx, const JSValues& argv) { // should be three args, first two are types, third is a function. ASSERT(argv[0].isType()); @@ -470,19 +386,18 @@ static JSValue defineAdd(const JSValues& argv) // XXX need to prove that argv[2].function takes T1 and T2 as args and returns Boolean for the relational operators ? -// stdOut << *argv[2].function->getICode(); - binaryOperators[BinaryOperator::Add].push_back(new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); + 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(const JSValues& argv) \ + static JSValue define##NAME(Context *cx, const JSValues& argv) \ { \ ASSERT(argv[0].isType()); \ ASSERT(argv[1].isType()); \ ASSERT(argv[2].isFunction()); \ - binaryOperators[BinaryOperator::##NAME].push_back( \ + cx->addBinaryOperator(BinaryOperator::##NAME, \ new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); \ return kUndefinedValue; \ } \ @@ -502,6 +417,39 @@ 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 (int 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. @@ -530,44 +478,39 @@ void Context::initContext() for (int i = 0; i < sizeof(PDTs) / sizeof(struct PDT); i++) mGlobal->defineVariable(widenCString(PDTs[i].name), &Type_Type, JSValue(PDTs[i].type)); - -// 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; - JSValue (*fun)(const JSValues& argv); - } 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 }, + 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 (i = 0; i < sizeof(OBOs) / sizeof(struct OBO); i++) - mGlobal->defineNativeFunction(mWorld.identifiers[widenCString(OBOs[i].name)], OBOs[i].fun); + 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]))); + } -static const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op) +const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op) { int32 bestDist1 = JSType::NoRelation; int32 bestDist2 = JSType::NoRelation; BinaryOperatorList::iterator candidate = NULL; - for (BinaryOperatorList::iterator i = binaryOperators[op].begin(); - i != binaryOperators[op].end(); i++) + 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); @@ -650,7 +593,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - JSValue result = static_cast(target)->mCode(argv); + JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) (*registers)[op1(call).first] = result; break; @@ -685,7 +628,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - JSValue result = static_cast(target)->mCode(argv); + JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) (*registers)[op1(call).first] = result; break; @@ -719,7 +662,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - /*JSValue result = static_cast(target)->mCode(argv);*/ + /*JSValue result = static_cast(target)->mCode(this, argv);*/ break; } else { @@ -755,7 +698,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - JSValue result = static_cast(target)->mCode(argv); + JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) (*registers)[op1(call).first] = result; break; @@ -1025,6 +968,32 @@ using JSString throughout. } } break; + case GENERIC_BINARY_OP: + { + GenericBinaryOP* gbo = static_cast(instruction); + JSValue& dest = (*registers)[dst(gbo).first]; + JSValue& r1 = (*registers)[val3(gbo).first]; + JSValue& r2 = (*registers)[val4(gbo).first]; + const JSValue ovr = findBinaryOverride(r1, r2, val2(gbo)); + JSFunction *target = ovr.function; + if (target->isNative()) { + JSValues argv(2); + argv[0] = r1; + argv[1] = r2; + dest = static_cast(target)->mCode(r1, r2); + break; + } + else { + mLinkage = new Linkage(mLinkage, ++mPC, + mActivation, mGlobal, dst(gbo)); + mActivation = new Activation(target->getICode(), r1, r2); + registers = &mActivation->mRegisters; + mPC = mActivation->mICode->its_iCode->begin(); + endPC = mActivation->mICode->its_iCode->end(); + continue; + } + } + break; case SHIFTLEFT: case SHIFTRIGHT: case USHIFTRIGHT: @@ -1046,10 +1015,10 @@ using JSString throughout. // overridden, so we should use a different dispatch and execute the default // behaviour inline instead, // - Arithmetic* mul = static_cast(instruction); - JSValue& dest = (*registers)[dst(mul).first]; - JSValue& r1 = (*registers)[src1(mul).first]; - JSValue& r2 = (*registers)[src2(mul).first]; + Arithmetic* a = static_cast(instruction); + JSValue& dest = (*registers)[dst(a).first]; + JSValue& r1 = (*registers)[src1(a).first]; + JSValue& r2 = (*registers)[src2(a).first]; const JSValue ovr = findBinaryOverride(r1, r2, BinaryOperator::mapICodeOp(instruction->op())); JSFunction *target = ovr.function; if (target->isNative()) { @@ -1061,7 +1030,7 @@ using JSString throughout. } else { mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, dst(mul)); + mActivation, mGlobal, dst(a)); mActivation = new Activation(target->getICode(), r1, r2); registers = &mActivation->mRegisters; mPC = mActivation->mICode->its_iCode->begin(); diff --git a/mozilla/js/js2/interpreter.h b/mozilla/js/js2/interpreter.h index 4e3d0069792..09b904fc8b5 100644 --- a/mozilla/js/js2/interpreter.h +++ b/mozilla/js/js2/interpreter.h @@ -35,12 +35,12 @@ namespace Interpreter { struct Activation; struct Linkage; - + class Context : public gc_base { void initContext(); public: explicit Context(World& world, JSScope* aGlobal) - : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0) { initContext(); } + : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); } World& getWorld() { return mWorld; } JSScope* getGlobalObject() { return mGlobal; } @@ -77,12 +77,18 @@ namespace Interpreter { JSValue interpret(ICodeModule* iCode, const JSValues& args); void doCall(JSFunction *target, Instruction *pc); - ICodeModule* genCode(StmtNode *p, const String &fileName); JSValue readEvalFile(FILE* in, const String& 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; } + private: void broadcast(Event event); + void initOperatorsPackage(); private: World& mWorld; @@ -92,7 +98,12 @@ namespace Interpreter { typedef ListenerList::iterator ListenerIterator; ListenerList mListeners; Activation* mActivation; + bool mHasOperatorsPackageLoaded; + InstructionIterator mPC; + + BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount]; + }; /* class Context */ } /* namespace Interpreter */ diff --git a/mozilla/js/js2/js2.cpp b/mozilla/js/js2/js2.cpp index 8c0dbd3ebf9..29ad3ed8303 100644 --- a/mozilla/js/js2/js2.cpp +++ b/mozilla/js/js2/js2.cpp @@ -115,7 +115,7 @@ JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut, JavaScript::stdOut, &ResolveFile); #endif -static JSValue print(const JSValues &argv) +static JSValue print(Context *cx, const JSValues &argv) { size_t n = argv.size(); if (n > 1) { // the 'this' parameter is un-interesting @@ -127,7 +127,7 @@ static JSValue print(const JSValues &argv) return kUndefinedValue; } -static JSValue dump(const JSValues &argv) +static JSValue dump(Context *cx, const JSValues &argv) { size_t n = argv.size(); if (n > 1) { // the 'this' parameter is un-interesting @@ -148,25 +148,21 @@ static JSValue dump(const JSValues &argv) inline char narrow(char16 ch) { return char(ch); } -static JSValue load(const JSValues &argv) +static JSValue load(Context *cx, const JSValues &argv) { JSValue result; size_t n = argv.size(); if (n > 1) { - ASSERT(argv[0].isObject()); - JSScope *scope = dynamic_cast(argv[0].object); - ASSERT(scope); for (size_t i = 1; i < n; ++i) { JSValue val = argv[i].toString(); if (val.isString()) { - Context cx(world, scope); String fileName(*val.string); std::string str(fileName.length(), char()); std::transform(fileName.begin(), fileName.end(), str.begin(), narrow); FILE* f = fopen(str.c_str(), "r"); if (f) { - result = cx.readEvalFile(f, fileName); + result = cx->readEvalFile(f, fileName); fclose(f); } } diff --git a/mozilla/js/js2/jstypes.h b/mozilla/js/js2/jstypes.h index db40c3ec525..2503218d0a9 100644 --- a/mozilla/js/js2/jstypes.h +++ b/mozilla/js/js2/jstypes.h @@ -46,17 +46,23 @@ namespace JavaScript { namespace ICG { class ICodeModule; } /* namespace ICG */ +namespace Interpreter { + class Context; +} /* namespace Interpreter */ } /* namespace JavaScript */ namespace JavaScript { namespace JSTypes { + using ICG::ICodeModule; + using Interpreter::Context; class JSObject; class JSArray; class JSFunction; class JSString; class JSType; + class Context; /** * All JavaScript data types. @@ -350,7 +356,7 @@ namespace JSTypes { class JSNativeFunction : public JSFunction { public: - typedef JSValue (*JSCode)(const JSValues& argv); + typedef JSValue (*JSCode)(Context *cx, const JSValues& argv); JSCode mCode; JSNativeFunction(JSCode code) : mCode(code) {} virtual bool isNative() { return true; } diff --git a/mozilla/js/js2/tools/gencode.pl b/mozilla/js/js2/tools/gencode.pl index 33ed4aabe03..d44a5c2705d 100644 --- a/mozilla/js/js2/tools/gencode.pl +++ b/mozilla/js/js2/tools/gencode.pl @@ -78,6 +78,12 @@ $ops{"DEBUGGER"} = super => "Instruction", rem => "drop to the debugger", }; +$ops{"GENERIC_BINARY_OP"} = + { + super => "Instruction_4", + rem => "dest, op, source1, source2", + params => [ ("TypedRegister", "BinaryOperator::BinaryOp", "TypedRegister", "TypedRegister") ] + }; $ops{"MOVE"} = { super => "Instruction_2", diff --git a/mozilla/js/js2/vmtypes.cpp b/mozilla/js/js2/vmtypes.cpp index f153170d0ae..b0fa2a92e6d 100644 --- a/mozilla/js/js2/vmtypes.cpp +++ b/mozilla/js/js2/vmtypes.cpp @@ -120,6 +120,58 @@ 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 */ diff --git a/mozilla/js/js2/vmtypes.h b/mozilla/js/js2/vmtypes.h index c5dc086ed3a..26b4f1f0ca2 100644 --- a/mozilla/js/js2/vmtypes.h +++ b/mozilla/js/js2/vmtypes.h @@ -263,6 +263,38 @@ namespace VM { /********************************************************************/ + 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 BinaryOperatorList; + + Formatter& operator<<(Formatter &f, BinaryOperator::BinaryOp &b); + + /********************************************************************/ + #include "icode.h" } /* namespace VM */ diff --git a/mozilla/js2/src/icode.h b/mozilla/js2/src/icode.h index d689203d3df..635dd80362e 100644 --- a/mozilla/js2/src/icode.h +++ b/mozilla/js2/src/icode.h @@ -23,6 +23,7 @@ DELETE_PROP, /* dest, object, prop name */ DIVIDE, /* dest, source1, source2 */ ELEM_XCR, /* dest, base, index, value */ + GENERIC_BINARY_OP, /* dest, op, source1, source2 */ GET_ELEMENT, /* dest, base, index */ GET_PROP, /* dest, object, prop name */ GET_SLOT, /* dest, object, slot number */ @@ -310,6 +311,22 @@ } }; + class GenericBinaryOP : public Instruction_4 { + public: + /* dest, op, source1, source2 */ + GenericBinaryOP (TypedRegister aOp1, BinaryOperator::BinaryOp aOp2, TypedRegister aOp3, TypedRegister aOp4) : + Instruction_4 + (GENERIC_BINARY_OP, aOp1, aOp2, aOp3, aOp4) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[GENERIC_BINARY_OP] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1.first << '=' << registers[mOp1.first] << ", " << "R" << mOp3.first << '=' << registers[mOp3.first] << ", " << "R" << mOp4.first << '=' << registers[mOp4.first]; + return f; + } + }; + class GetElement : public Instruction_3 { public: /* dest, base, index */ @@ -1045,77 +1062,78 @@ #else char *opcodeNames[] = { - "ADD ", - "AND ", - "BITNOT ", - "BRANCH ", - "BRANCH_FALSE ", - "BRANCH_TRUE ", - "CALL ", - "CAST ", - "COMPARE_EQ ", - "COMPARE_GE ", - "COMPARE_GT ", - "COMPARE_IN ", - "COMPARE_LE ", - "COMPARE_LT ", - "COMPARE_NE ", - "CONSTRUCTOR_CALL", - "DEBUGGER ", - "DELETE_PROP ", - "DIVIDE ", - "ELEM_XCR ", - "GET_ELEMENT ", - "GET_PROP ", - "GET_SLOT ", - "GET_STATIC ", - "INSTANCEOF ", - "JSR ", - "LOAD_BOOLEAN ", - "LOAD_IMMEDIATE ", - "LOAD_NAME ", - "LOAD_STRING ", - "METHOD_CALL ", - "MOVE ", - "MULTIPLY ", - "NAME_XCR ", - "NEGATE ", - "NEW_ARRAY ", - "NEW_CLASS ", - "NEW_FUNCTION ", - "NEW_OBJECT ", - "NOP ", - "NOT ", - "OR ", - "POSATE ", - "PROP_XCR ", - "REMAINDER ", - "RETURN ", - "RETURN_VOID ", - "RTS ", - "SAVE_NAME ", - "SET_ELEMENT ", - "SET_PROP ", - "SET_SLOT ", - "SET_STATIC ", - "SHIFTLEFT ", - "SHIFTRIGHT ", - "SLOT_XCR ", - "STATIC_CALL ", - "STATIC_XCR ", - "STRICT_EQ ", - "STRICT_NE ", - "SUBTRACT ", - "SUPER ", - "TEST ", - "THROW ", - "TRYIN ", - "TRYOUT ", - "USHIFTRIGHT ", - "VAR_XCR ", - "WITHIN ", - "WITHOUT ", - "XOR ", + "ADD ", + "AND ", + "BITNOT ", + "BRANCH ", + "BRANCH_FALSE ", + "BRANCH_TRUE ", + "CALL ", + "CAST ", + "COMPARE_EQ ", + "COMPARE_GE ", + "COMPARE_GT ", + "COMPARE_IN ", + "COMPARE_LE ", + "COMPARE_LT ", + "COMPARE_NE ", + "CONSTRUCTOR_CALL ", + "DEBUGGER ", + "DELETE_PROP ", + "DIVIDE ", + "ELEM_XCR ", + "GENERIC_BINARY_OP", + "GET_ELEMENT ", + "GET_PROP ", + "GET_SLOT ", + "GET_STATIC ", + "INSTANCEOF ", + "JSR ", + "LOAD_BOOLEAN ", + "LOAD_IMMEDIATE ", + "LOAD_NAME ", + "LOAD_STRING ", + "METHOD_CALL ", + "MOVE ", + "MULTIPLY ", + "NAME_XCR ", + "NEGATE ", + "NEW_ARRAY ", + "NEW_CLASS ", + "NEW_FUNCTION ", + "NEW_OBJECT ", + "NOP ", + "NOT ", + "OR ", + "POSATE ", + "PROP_XCR ", + "REMAINDER ", + "RETURN ", + "RETURN_VOID ", + "RTS ", + "SAVE_NAME ", + "SET_ELEMENT ", + "SET_PROP ", + "SET_SLOT ", + "SET_STATIC ", + "SHIFTLEFT ", + "SHIFTRIGHT ", + "SLOT_XCR ", + "STATIC_CALL ", + "STATIC_XCR ", + "STRICT_EQ ", + "STRICT_NE ", + "SUBTRACT ", + "SUPER ", + "TEST ", + "THROW ", + "TRYIN ", + "TRYOUT ", + "USHIFTRIGHT ", + "VAR_XCR ", + "WITHIN ", + "WITHOUT ", + "XOR ", }; #endif diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 6bd936e773e..f1f606e7f83 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -441,6 +441,17 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1, return dest; } +TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1, + TypedRegister source2) +{ + ASSERT(source1.first != NotARegister); + ASSERT(source2.first != NotARegister); + TypedRegister dest(getTempRegister(), &Any_Type); + GenericBinaryOP *instr = new GenericBinaryOP(dest, BinaryOperator::mapICodeOp(op), source1, source2); + iCode->push_back(instr); + return dest; +} + TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); @@ -1227,7 +1238,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, BinaryExprNode *b = static_cast(p); TypedRegister r1 = genExpr(b->op1); TypedRegister r2 = genExpr(b->op2); - ret = op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + + if ((r1.second == &Integer_Type) && (r2.second == &Integer_Type)) { + op(mapExprNodeToICodeOp(p->getKind()), r1, r2); + } + + ret = binaryOp(mapExprNodeToICodeOp(p->getKind()), r1, r2); } break; case ExprNode::assignment: diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index a05e97146a5..83f4a42e530 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -241,6 +241,7 @@ namespace ICG { TypedRegister op(ICodeOp op, TypedRegister source); TypedRegister op(ICodeOp op, TypedRegister source1, TypedRegister source2); + TypedRegister binaryOp(ICodeOp op, TypedRegister source1, TypedRegister source2); TypedRegister call(TypedRegister target, const StringAtom &name, RegisterList *args); TypedRegister methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList *args); TypedRegister staticCall(JSClass *c, const StringAtom &name, RegisterList *args); diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 89a6be6214d..16532311ff7 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -51,6 +51,7 @@ namespace Interpreter { #define src1(i) op2(i) #define src2(i) op3(i) #define ofs(i) (i->getOffset()) +#define val2(i) op2(i) #define val3(i) op3(i) #define val4(i) op4(i) @@ -376,92 +377,7 @@ static JSValue identical_Default(const JSValue& r1, const JSValue& r2) } -class BinaryOperator { -public: - - // Wah, here's a third enumeration of opcodes - ExprNode, ICodeOp and now here, this can't be right?? - typedef enum { - Add, Subtract, Multiply, Divide, - Remainder, LeftShift, RightShift, LogicalRightShift, - BitwiseOr, BitwiseXor, BitwiseAnd, Less, LessOrEqual, - Equal, Identical - } 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; - -}; - -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; - } -} - - - -typedef std::vector BinaryOperatorList; -BinaryOperatorList binaryOperators[15]; - - -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 -}; - -class InitBinaryOperators { - -public: - InitBinaryOperators() { - - for (int i = BinaryOperator::Add; i <= BinaryOperator::Identical; i++) - binaryOperators[i].push_back(new BinaryOperator(&Any_Type, &Any_Type, new JSBinaryOperator(defaultFunction[i]))); - } -} initializer = InitBinaryOperators(); - -static JSValue defineAdd(const JSValues& argv) +static JSValue defineAdd(Context *cx, const JSValues& argv) { // should be three args, first two are types, third is a function. ASSERT(argv[0].isType()); @@ -470,19 +386,18 @@ static JSValue defineAdd(const JSValues& argv) // XXX need to prove that argv[2].function takes T1 and T2 as args and returns Boolean for the relational operators ? -// stdOut << *argv[2].function->getICode(); - binaryOperators[BinaryOperator::Add].push_back(new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); + 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(const JSValues& argv) \ + static JSValue define##NAME(Context *cx, const JSValues& argv) \ { \ ASSERT(argv[0].isType()); \ ASSERT(argv[1].isType()); \ ASSERT(argv[2].isFunction()); \ - binaryOperators[BinaryOperator::##NAME].push_back( \ + cx->addBinaryOperator(BinaryOperator::##NAME, \ new BinaryOperator(argv[0].type, argv[1].type, argv[2].function)); \ return kUndefinedValue; \ } \ @@ -502,6 +417,39 @@ 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 (int 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. @@ -530,44 +478,39 @@ void Context::initContext() for (int i = 0; i < sizeof(PDTs) / sizeof(struct PDT); i++) mGlobal->defineVariable(widenCString(PDTs[i].name), &Type_Type, JSValue(PDTs[i].type)); - -// 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; - JSValue (*fun)(const JSValues& argv); - } 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 }, + 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 (i = 0; i < sizeof(OBOs) / sizeof(struct OBO); i++) - mGlobal->defineNativeFunction(mWorld.identifiers[widenCString(OBOs[i].name)], OBOs[i].fun); + 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]))); + } -static const JSValue findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op) +const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, BinaryOperator::BinaryOp op) { int32 bestDist1 = JSType::NoRelation; int32 bestDist2 = JSType::NoRelation; BinaryOperatorList::iterator candidate = NULL; - for (BinaryOperatorList::iterator i = binaryOperators[op].begin(); - i != binaryOperators[op].end(); i++) + 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); @@ -650,7 +593,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - JSValue result = static_cast(target)->mCode(argv); + JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) (*registers)[op1(call).first] = result; break; @@ -685,7 +628,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - JSValue result = static_cast(target)->mCode(argv); + JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) (*registers)[op1(call).first] = result; break; @@ -719,7 +662,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - /*JSValue result = static_cast(target)->mCode(argv);*/ + /*JSValue result = static_cast(target)->mCode(this, argv);*/ break; } else { @@ -755,7 +698,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) src != end; ++src, ++i) { argv[i] = (*registers)[src->first]; } - JSValue result = static_cast(target)->mCode(argv); + JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) (*registers)[op1(call).first] = result; break; @@ -1025,6 +968,32 @@ using JSString throughout. } } break; + case GENERIC_BINARY_OP: + { + GenericBinaryOP* gbo = static_cast(instruction); + JSValue& dest = (*registers)[dst(gbo).first]; + JSValue& r1 = (*registers)[val3(gbo).first]; + JSValue& r2 = (*registers)[val4(gbo).first]; + const JSValue ovr = findBinaryOverride(r1, r2, val2(gbo)); + JSFunction *target = ovr.function; + if (target->isNative()) { + JSValues argv(2); + argv[0] = r1; + argv[1] = r2; + dest = static_cast(target)->mCode(r1, r2); + break; + } + else { + mLinkage = new Linkage(mLinkage, ++mPC, + mActivation, mGlobal, dst(gbo)); + mActivation = new Activation(target->getICode(), r1, r2); + registers = &mActivation->mRegisters; + mPC = mActivation->mICode->its_iCode->begin(); + endPC = mActivation->mICode->its_iCode->end(); + continue; + } + } + break; case SHIFTLEFT: case SHIFTRIGHT: case USHIFTRIGHT: @@ -1046,10 +1015,10 @@ using JSString throughout. // overridden, so we should use a different dispatch and execute the default // behaviour inline instead, // - Arithmetic* mul = static_cast(instruction); - JSValue& dest = (*registers)[dst(mul).first]; - JSValue& r1 = (*registers)[src1(mul).first]; - JSValue& r2 = (*registers)[src2(mul).first]; + Arithmetic* a = static_cast(instruction); + JSValue& dest = (*registers)[dst(a).first]; + JSValue& r1 = (*registers)[src1(a).first]; + JSValue& r2 = (*registers)[src2(a).first]; const JSValue ovr = findBinaryOverride(r1, r2, BinaryOperator::mapICodeOp(instruction->op())); JSFunction *target = ovr.function; if (target->isNative()) { @@ -1061,7 +1030,7 @@ using JSString throughout. } else { mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, dst(mul)); + mActivation, mGlobal, dst(a)); mActivation = new Activation(target->getICode(), r1, r2); registers = &mActivation->mRegisters; mPC = mActivation->mICode->its_iCode->begin(); diff --git a/mozilla/js2/src/interpreter.h b/mozilla/js2/src/interpreter.h index 4e3d0069792..09b904fc8b5 100644 --- a/mozilla/js2/src/interpreter.h +++ b/mozilla/js2/src/interpreter.h @@ -35,12 +35,12 @@ namespace Interpreter { struct Activation; struct Linkage; - + class Context : public gc_base { void initContext(); public: explicit Context(World& world, JSScope* aGlobal) - : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0) { initContext(); } + : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); } World& getWorld() { return mWorld; } JSScope* getGlobalObject() { return mGlobal; } @@ -77,12 +77,18 @@ namespace Interpreter { JSValue interpret(ICodeModule* iCode, const JSValues& args); void doCall(JSFunction *target, Instruction *pc); - ICodeModule* genCode(StmtNode *p, const String &fileName); JSValue readEvalFile(FILE* in, const String& 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; } + private: void broadcast(Event event); + void initOperatorsPackage(); private: World& mWorld; @@ -92,7 +98,12 @@ namespace Interpreter { typedef ListenerList::iterator ListenerIterator; ListenerList mListeners; Activation* mActivation; + bool mHasOperatorsPackageLoaded; + InstructionIterator mPC; + + BinaryOperatorList mBinaryOperators[BinaryOperator::BinaryOperatorCount]; + }; /* class Context */ } /* namespace Interpreter */ diff --git a/mozilla/js2/src/jstypes.h b/mozilla/js2/src/jstypes.h index db40c3ec525..2503218d0a9 100644 --- a/mozilla/js2/src/jstypes.h +++ b/mozilla/js2/src/jstypes.h @@ -46,17 +46,23 @@ namespace JavaScript { namespace ICG { class ICodeModule; } /* namespace ICG */ +namespace Interpreter { + class Context; +} /* namespace Interpreter */ } /* namespace JavaScript */ namespace JavaScript { namespace JSTypes { + using ICG::ICodeModule; + using Interpreter::Context; class JSObject; class JSArray; class JSFunction; class JSString; class JSType; + class Context; /** * All JavaScript data types. @@ -350,7 +356,7 @@ namespace JSTypes { class JSNativeFunction : public JSFunction { public: - typedef JSValue (*JSCode)(const JSValues& argv); + typedef JSValue (*JSCode)(Context *cx, const JSValues& argv); JSCode mCode; JSNativeFunction(JSCode code) : mCode(code) {} virtual bool isNative() { return true; } diff --git a/mozilla/js2/src/vmtypes.cpp b/mozilla/js2/src/vmtypes.cpp index f153170d0ae..b0fa2a92e6d 100644 --- a/mozilla/js2/src/vmtypes.cpp +++ b/mozilla/js2/src/vmtypes.cpp @@ -120,6 +120,58 @@ 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 */ diff --git a/mozilla/js2/src/vmtypes.h b/mozilla/js2/src/vmtypes.h index c5dc086ed3a..26b4f1f0ca2 100644 --- a/mozilla/js2/src/vmtypes.h +++ b/mozilla/js2/src/vmtypes.h @@ -263,6 +263,38 @@ namespace VM { /********************************************************************/ + 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 BinaryOperatorList; + + Formatter& operator<<(Formatter &f, BinaryOperator::BinaryOp &b); + + /********************************************************************/ + #include "icode.h" } /* namespace VM */ diff --git a/mozilla/js2/tests/cpp/js2_shell.cpp b/mozilla/js2/tests/cpp/js2_shell.cpp index 8c0dbd3ebf9..29ad3ed8303 100644 --- a/mozilla/js2/tests/cpp/js2_shell.cpp +++ b/mozilla/js2/tests/cpp/js2_shell.cpp @@ -115,7 +115,7 @@ JavaScript::Debugger::Shell jsd(world, stdin, JavaScript::stdOut, JavaScript::stdOut, &ResolveFile); #endif -static JSValue print(const JSValues &argv) +static JSValue print(Context *cx, const JSValues &argv) { size_t n = argv.size(); if (n > 1) { // the 'this' parameter is un-interesting @@ -127,7 +127,7 @@ static JSValue print(const JSValues &argv) return kUndefinedValue; } -static JSValue dump(const JSValues &argv) +static JSValue dump(Context *cx, const JSValues &argv) { size_t n = argv.size(); if (n > 1) { // the 'this' parameter is un-interesting @@ -148,25 +148,21 @@ static JSValue dump(const JSValues &argv) inline char narrow(char16 ch) { return char(ch); } -static JSValue load(const JSValues &argv) +static JSValue load(Context *cx, const JSValues &argv) { JSValue result; size_t n = argv.size(); if (n > 1) { - ASSERT(argv[0].isObject()); - JSScope *scope = dynamic_cast(argv[0].object); - ASSERT(scope); for (size_t i = 1; i < n; ++i) { JSValue val = argv[i].toString(); if (val.isString()) { - Context cx(world, scope); String fileName(*val.string); std::string str(fileName.length(), char()); std::transform(fileName.begin(), fileName.end(), str.begin(), narrow); FILE* f = fopen(str.c_str(), "r"); if (f) { - result = cx.readEvalFile(f, fileName); + result = cx->readEvalFile(f, fileName); fclose(f); } } diff --git a/mozilla/js2/tools/gencode.pl b/mozilla/js2/tools/gencode.pl index 33ed4aabe03..d44a5c2705d 100644 --- a/mozilla/js2/tools/gencode.pl +++ b/mozilla/js2/tools/gencode.pl @@ -78,6 +78,12 @@ $ops{"DEBUGGER"} = super => "Instruction", rem => "drop to the debugger", }; +$ops{"GENERIC_BINARY_OP"} = + { + super => "Instruction_4", + rem => "dest, op, source1, source2", + params => [ ("TypedRegister", "BinaryOperator::BinaryOp", "TypedRegister", "TypedRegister") ] + }; $ops{"MOVE"} = { super => "Instruction_2",