diff --git a/mozilla/js/js2/icode.h b/mozilla/js/js2/icode.h index c86cd0d8935..7ee58f52ec0 100644 --- a/mozilla/js/js2/icode.h +++ b/mozilla/js/js2/icode.h @@ -17,6 +17,7 @@ COMPARE_LE, /* dest, source1, source2 */ COMPARE_LT, /* dest, source1, source2 */ COMPARE_NE, /* dest, source1, source2 */ + CONSTRUCTOR_CALL, /* target class, index, this, args */ DEBUGGER, /* drop to the debugger */ DELETE_PROP, /* dest, object, prop name */ DIVIDE, /* dest, source1, source2 */ @@ -37,7 +38,7 @@ NAME_XCR, /* dest, name, value */ NEGATE, /* dest, source */ NEW_ARRAY, /* dest */ - NEW_CLASS, /* dest, class name */ + NEW_CLASS, /* dest, class */ NEW_FUNCTION, /* dest, ICodeModule */ NEW_OBJECT, /* dest */ NOP, /* do nothing and like it */ @@ -62,6 +63,7 @@ STRICT_EQ, /* dest, source1, source2 */ STRICT_NE, /* dest, source1, source2 */ SUBTRACT, /* dest, source1, source2 */ + SUPER, /* dest */ TEST, /* dest, source */ THROW, /* exception value */ TRYIN, /* catch target, finally target */ @@ -219,6 +221,22 @@ /* print() and printOperands() inherited from Instruction_3 */ }; + class ConstructorCall : public Instruction_4 { + public: + /* target class, index, this, args */ + ConstructorCall (JSClass* aOp1, uint32 aOp2, TypedRegister aOp3, RegisterList aOp4) : + Instruction_4 + (CONSTRUCTOR_CALL, aOp1, aOp2, aOp3, aOp4) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[CONSTRUCTOR_CALL] << "\t" << mOp1->getName() << ", " << mOp2 << ", " << "R" << mOp3.first << ", " << mOp4; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp3.first << '=' << registers[mOp3.first] << ", " << ArgList(mOp4, registers); + return f; + } + }; + class Debugger : public Instruction { public: /* drop to the debugger */ @@ -516,14 +534,14 @@ } }; - class NewClass : public Instruction_2 { + class NewClass : public Instruction_2 { public: - /* dest, class name */ - NewClass (TypedRegister aOp1, const StringAtom* aOp2) : - Instruction_2 + /* dest, class */ + NewClass (TypedRegister aOp1, JSClass* aOp2) : + Instruction_2 (NEW_CLASS, aOp1, aOp2) {}; virtual Formatter& print(Formatter& f) { - f << opcodeNames[NEW_CLASS] << "\t" << "R" << mOp1.first << ", " << "'" << *mOp2 << "'"; + f << opcodeNames[NEW_CLASS] << "\t" << "R" << mOp1.first << ", " << mOp2->getName(); return f; } virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { @@ -864,6 +882,22 @@ /* print() and printOperands() inherited from Arithmetic */ }; + class Super : public Instruction_1 { + public: + /* dest */ + Super (TypedRegister aOp1) : + Instruction_1 + (SUPER, aOp1) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[SUPER] << "\t" << "R" << mOp1.first; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1.first << '=' << registers[mOp1.first]; + return f; + } + }; + class Test : public Instruction_2 { public: /* dest, source */ @@ -994,74 +1028,76 @@ #else char *opcodeNames[] = { - "ADD ", - "AND ", - "BITNOT ", - "BRANCH ", - "BRANCH_FALSE ", - "BRANCH_TRUE ", - "CALL ", - "COMPARE_EQ ", - "COMPARE_GE ", - "COMPARE_GT ", - "COMPARE_IN ", - "COMPARE_LE ", - "COMPARE_LT ", - "COMPARE_NE ", - "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 ", - "TEST ", - "THROW ", - "TRYIN ", - "TRYOUT ", - "USHIFTRIGHT ", - "VAR_XCR ", - "WITHIN ", - "WITHOUT ", - "XOR ", + "ADD ", + "AND ", + "BITNOT ", + "BRANCH ", + "BRANCH_FALSE ", + "BRANCH_TRUE ", + "CALL ", + "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 ", }; #endif diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 8619e95eb94..cc0e9a4a153 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -182,7 +182,7 @@ TypedRegister ICodeGenerator::loadImmediate(double value) return dest; } -TypedRegister ICodeGenerator::loadString(String &value) +TypedRegister ICodeGenerator::loadString(const String &value) { TypedRegister dest(getTempRegister(), &String_Type); LoadString *instr = new LoadString(dest, new JSString(value)); @@ -206,7 +206,7 @@ TypedRegister ICodeGenerator::loadBoolean(bool value) return dest; } -TypedRegister ICodeGenerator::newObject() +TypedRegister ICodeGenerator::newObject(RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); NewObject *instr = new NewObject(dest); @@ -214,10 +214,10 @@ TypedRegister ICodeGenerator::newObject() return dest; } -TypedRegister ICodeGenerator::newClass(const StringAtom &name) +TypedRegister ICodeGenerator::newClass(JSClass *clazz) { TypedRegister dest(getTempRegister(), &Any_Type); - NewClass *instr = new NewClass(dest, &name); + NewClass *instr = new NewClass(dest, clazz); iCode->push_back(instr); return dest; } @@ -435,27 +435,49 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1, return dest; } -TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList args) +TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); - Call *instr = new Call(dest, target, &name, args); + Call *instr = new Call(dest, target, &name, *args); iCode->push_back(instr); return dest; } -TypedRegister ICodeGenerator::methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList args) +TypedRegister ICodeGenerator::methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); - MethodCall *instr = new MethodCall(dest, targetBase, targetValue, args); + MethodCall *instr = new MethodCall(dest, targetBase, targetValue, *args); iCode->push_back(instr); return dest; } -TypedRegister ICodeGenerator::staticCall(JSClass *c, const StringAtom &name, RegisterList args) +TypedRegister ICodeGenerator::staticCall(JSClass *c, const StringAtom &name, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); const JSSlot& slot = c->getStatic(name); - StaticCall *instr = new StaticCall(dest, c, slot.mIndex, args); + StaticCall *instr = new StaticCall(dest, c, slot.mIndex, *args); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::constructorCall(JSClass *c, const StringAtom &name, TypedRegister thisArg, RegisterList *args) +{ + const JSSlot& slot = c->getStatic(name); + ConstructorCall *instr = new ConstructorCall(c, slot.mIndex, thisArg, *args); + iCode->push_back(instr); +} + +void ICodeGenerator::constructorCall(JSClass *c, const String &name, TypedRegister thisArg, RegisterList *args) +{ + const JSSlot& slot = c->getStatic(name); + ConstructorCall *instr = new ConstructorCall(c, slot.mIndex, thisArg, *args); + iCode->push_back(instr); +} + +TypedRegister ICodeGenerator::super() +{ + TypedRegister dest(getTempRegister(), &Any_Type); + Super *instr = new Super(dest); iCode->push_back(instr); return dest; } @@ -647,8 +669,9 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n if (isSlotName(mClass, name, slotIndex, v.second)) return Slot; } - if (mClass->hasStatic(name, v.second)) { - return Static; + bool isConstructor = false; + if (mClass->hasStatic(name, v.second, isConstructor)) { + return (isConstructor) ? Constructor : Static; } } v.second = mGlobal->getType(name); @@ -659,24 +682,72 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n return Name; } -TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, RegisterList *args) +TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args) { ASSERT(p->getKind() == ExprNode::identifier); JSType *vType = &Any_Type; uint32 slotIndex; - TypedRegister ret; TypedRegister v; const StringAtom &name = (static_cast(p))->name; - LValueKind lValueKind = resolveIdentifier(name, ret, slotIndex); + LValueKind lValueKind = resolveIdentifier(name, v, slotIndex); TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type); switch (use) { + case ExprNode::addEquals: + case ExprNode::subtractEquals: + case ExprNode::multiplyEquals: + case ExprNode::divideEquals: + case ExprNode::moduloEquals: + case ExprNode::leftShiftEquals: + case ExprNode::rightShiftEquals: + case ExprNode::logicalRightShiftEquals: + case ExprNode::bitwiseAndEquals: + case ExprNode::bitwiseXorEquals: + case ExprNode::bitwiseOrEquals: + switch (lValueKind) { + case Var: + break; + case Name: + v = loadName(name); + break; + case Slot: + v = getSlot(thisBase, slotIndex); + break; + case Static: + case Constructor: + v = getStatic(mClass, name); + break; + default: + NOT_REACHED("Bad lvalue kind"); + } + ret = op(mapExprNodeToICodeOp(use), v, ret); + // fall thru... + case ExprNode::assignment: + switch (lValueKind) { + case Var: + move(v, ret); + break; + case Name: + saveName(name, ret); + break; + case Slot: + setSlot(thisBase, slotIndex, ret); + break; + case Static: + case Constructor: + setStatic(mClass, name, ret); + break; + default: + NOT_REACHED("Bad lvalue kind"); + } + break; case ExprNode::identifier: switch (lValueKind) { case Var: + ret = v; break; case Name: ret = loadName(name); @@ -685,6 +756,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = getSlot(thisBase, slotIndex); break; case Static: + case Constructor: ret = getStatic(mClass, name); break; default: @@ -695,7 +767,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: case ExprNode::preIncrement: switch (lValueKind) { case Var: - ret = op(xcrementOp, ret, loadImmediate(1.0)); + ret = op(xcrementOp, v, loadImmediate(1.0)); break; case Name: ret = loadName(name); @@ -707,6 +779,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: setSlot(thisBase, slotIndex, ret); break; case Static: + case Constructor: ret = op(xcrementOp, getStatic(mClass, name), loadImmediate(1.0)); setStatic(mClass, name, ret); break; @@ -718,7 +791,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: case ExprNode::postIncrement: switch (lValueKind) { case Var: - ret = varXcr(ret, xcrementOp); + ret = varXcr(v, xcrementOp); break; case Name: ret = nameXcr(name, xcrementOp); @@ -727,6 +800,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = slotXcr(thisBase, slotIndex, xcrementOp); break; case Static: + case Constructor: ret = staticXcr(mClass, name, xcrementOp); break; default: @@ -736,13 +810,17 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: case ExprNode::call: switch (lValueKind) { case Var: - ret = call(ret, name, *args); + ret = call(v, name, args); break; case Name: - ret = methodCall(TypedRegister(NotARegister, &Null_Type), loadString(name), *args); + ret = methodCall(TypedRegister(NotARegister, &Null_Type), loadString(name), args); break; case Static: - ret = staticCall(mClass, name, *args); + ret = staticCall(mClass, name, args); + break; + case Constructor: + ret = newClass(mClass); + constructorCall(mClass, name, ret, args); break; default: NOT_REACHED("Bad lvalue kind"); @@ -778,20 +856,21 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I // if (base.second == &Type_Type) { const JSValue &v = mGlobal->getVariable(baseName); + bool isConstructor; + ASSERT(v.isType()); // there's no other way that base.second could be &Type_Type, right? clazz = dynamic_cast(v.type); - if (clazz && clazz->hasStatic(fieldName, fieldType)) { - lValueKind = Static; + if (clazz && clazz->hasStatic(fieldName, fieldType, isConstructor)) { + lValueKind = (isConstructor) ? Constructor : Static; } } if (lValueKind == Property) { if (isSlotName(base.second, fieldName, slotIndex, fieldType)) lValueKind = Slot; else { + bool isConstructor; clazz = dynamic_cast(base.second); - if (clazz && clazz->hasStatic(fieldName, fieldType)) - lValueKind = Static; - else - lValueKind = Property; + if (clazz && clazz->hasStatic(fieldName, fieldType, isConstructor)) + lValueKind = (isConstructor) ? Constructor : Static; } } if ((lValueKind == Property) && (base.first == NotARegister)) @@ -802,11 +881,10 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I if (isSlotName(base.second, fieldName, slotIndex, fieldType)) lValueKind = Slot; else { + bool isConstructor; clazz = dynamic_cast(base.second); - if (clazz && clazz->hasStatic(fieldName, fieldType)) - lValueKind = Static; - else - lValueKind = Property; + if (clazz && clazz->hasStatic(fieldName, fieldType, isConstructor)) + lValueKind = (isConstructor) ? Constructor : Static; } } TypedRegister v; @@ -814,10 +892,14 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::call: switch (lValueKind) { case Static: - ret = staticCall(clazz, fieldName, *args); + ret = staticCall(clazz, fieldName, args); + break; + case Constructor: + ret = newClass(clazz); + constructorCall(clazz, fieldName, ret, args); break; case Property: - ret = methodCall(base, loadString(fieldName), *args); + ret = methodCall(base, loadString(fieldName), args); break; default: NOT_REACHED("Bad lvalue kind"); @@ -836,6 +918,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::bitwiseXorEquals: case ExprNode::bitwiseOrEquals: switch (lValueKind) { + case Constructor: case Static: v = getStatic(clazz, fieldName); break; @@ -856,6 +939,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I // fall thru... case ExprNode::assignment: switch (lValueKind) { + case Constructor: case Static: setStatic(clazz, fieldName, ret); break; @@ -872,6 +956,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::postDecrement: case ExprNode::postIncrement: switch (lValueKind) { + case Constructor: case Static: ret = staticXcr(clazz, fieldName, xcrementOp); break; @@ -887,6 +972,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::preDecrement: case ExprNode::preIncrement: switch (lValueKind) { + case Constructor: case Static: ret = op(xcrementOp, getStatic(clazz, fieldName), loadImmediate(1.0)); setStatic(clazz, fieldName, ret); @@ -960,11 +1046,27 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::New: { InvokeExprNode *i = static_cast(p); + RegisterList args; + ExprPairList *p = i->pairs; + while (p) { + args.push_back(genExpr(p->value)); + p = p->next; + } if (i->op->getKind() == ExprNode::identifier) { - ret = newClass(static_cast(i->op)->name); + const StringAtom &className = static_cast(i->op)->name; + const JSValue& value = mGlobal->getVariable(className); + if (value.isType()) { + JSClass* clazz = dynamic_cast(value.type); + if (clazz) { + ret = newClass(clazz); + constructorCall(clazz, className, ret, &args); + } + else + NOT_REACHED("New , where is not a known class"); // XXX Runtime error. + } } else - ret = newObject(); // XXX more + ret = newObject(&args); // XXX more ? } break; case ExprNode::Delete: @@ -991,12 +1093,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else if (i->op->getKind() == ExprNode::identifier) { - ret = handleIdentifier(static_cast(i->op), ExprNode::call, xcrementOp, &args); + ret = handleIdentifier(static_cast(i->op), ExprNode::call, xcrementOp, ret, &args); } else if (i->op->getKind() == ExprNode::index) { BinaryExprNode *b = static_cast(i->op); - ret = methodCall(genExpr(b->op1), genExpr(b->op2), args); + ret = methodCall(genExpr(b->op1), genExpr(b->op2), &args); } else ASSERT("WAH!"); @@ -1023,7 +1125,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, break; case ExprNode::identifier : { - ret = handleIdentifier(static_cast(p), ExprNode::identifier, xcrementOp, NULL); + ret = handleIdentifier(static_cast(p), ExprNode::identifier, xcrementOp, ret, NULL); } break; case ExprNode::number : @@ -1042,7 +1144,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else if (u->op->getKind() == ExprNode::identifier) { - ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, NULL); + ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, ret, NULL); } else if (u->op->getKind() == ExprNode::index) { @@ -1067,7 +1169,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else if (u->op->getKind() == ExprNode::identifier) { - ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, NULL); + ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, ret, NULL); } else if (u->op->getKind() == ExprNode::index) { @@ -1113,6 +1215,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, BinaryExprNode *b = static_cast(p); ret = genExpr(b->op2); if (b->op1->getKind() == ExprNode::identifier) { + ret = handleIdentifier(static_cast(b->op1), p->getKind(), xcrementOp, ret, NULL); +/* if (!isWithinWith()) { TypedRegister v = findVariable((static_cast(b->op1))->name); if (v.first != NotARegister) @@ -1122,6 +1226,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else saveName((static_cast(b->op1))->name, ret); +*/ } else if (b->op1->getKind() == ExprNode::dot) { @@ -1154,6 +1259,9 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, BinaryExprNode *b = static_cast(p); ret = genExpr(b->op2); if (b->op1->getKind() == ExprNode::identifier) { + + ret = handleIdentifier(static_cast(b->op1), p->getKind(), xcrementOp, ret, NULL); +/* if (!isWithinWith()) { TypedRegister v = findVariable((static_cast(b->op1))->name); if (v.first != NotARegister) { @@ -1171,6 +1279,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, ret = op(mapExprNodeToICodeOp(p->getKind()), v, ret); saveName((static_cast(b->op1))->name, ret); } +*/ } else if (b->op1->getKind() == ExprNode::dot) { @@ -1325,7 +1434,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::objectLiteral: { - ret = newObject(); + ret = newObject(NULL); PairListExprNode *plen = static_cast(p); ExprPairList *e = plen->pairs; while (e) { @@ -1362,14 +1471,6 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, return ret; } -/* - need pre-pass to find: - variable & function definitions, - contains 'with' or 'eval' - contains 'try {} catch {} finally {}' -*/ - - bool LabelEntry::containsLabel(const StringAtom *label) { if (labelSet) { @@ -1390,7 +1491,7 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin return false; } -ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f) +ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass) { bool isStatic = hasAttribute(f->attributes, Token::Static); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; @@ -1403,6 +1504,35 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f) icg.allocateParameter((static_cast(v->name))->name); v = v->next; } + if (isConstructor) { + TypedRegister thisValue = TypedRegister(0, mClass); + RegisterList args; + if (superclass) { + bool foundSuperCall = false; + BlockStmtNode *b = f->function.body; + if (b && b->statements && (b->statements->getKind() == StmtNode::expression)) { + ExprStmtNode *e = static_cast(b->statements); + if (e->expr->getKind() == ExprNode::call) { + InvokeExprNode *i = static_cast(e->expr); + if (i->op->getKind() == ExprNode::dot) { + BinaryExprNode *b = static_cast(i->op); + if ((b->op1->getKind() == ExprNode::This) && (b->op2->getKind() == ExprNode::qualify)) { + BinaryExprNode *q = static_cast(b->op2); + if (q->op1->getKind() == ExprNode::Super) { + // XXX verify that q->op2 is either the superclass name or a constructor for it + foundSuperCall = true; + } + } + } + } + } + if (!foundSuperCall) { // invoke the default superclass constructor + icg.constructorCall(superclass, superclass->getName(), thisValue, &args); + } + } + const StringAtom &initName = mWorld->identifiers[widenCString("__init__")]; // XXXXXXX + icg.constructorCall(mClass, initName, thisValue, &args); // ok, so it's mis-named + } icg.genStmt(f->function.body); return icg.complete(); @@ -1436,6 +1566,16 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) // is it ok for a partially defined class to appear in global scope? this is needed // to handle recursive types, such as linked list nodes. mGlobal->defineVariable(nameExpr->name, &Type_Type, JSValue(thisClass)); + + // Have to have this declared ahead of time so that it's slot can + // be discoverd when compiling constructors in the loop below. Could + // do a pre-processing loop to discover whether it is in fact empty + // and then pass that info through to the genFunction() call for each + // constructor. + const StringAtom &initName = mWorld->identifiers[widenCString("__init__")]; + thisClass->defineStatic(initName, &Function_Type); + + bool hasDefaultConstructor = false; if (classStmt->body) { JSScope* thisScope = thisClass->getScope(); ICodeGenerator ccg(mWorld, thisScope, thisClass, kNoFlags); // constructor code generator. @@ -1481,22 +1621,31 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } } break; + case StmtNode::Constructor: case StmtNode::Function: { FunctionStmtNode *f = static_cast(s); bool isStatic = hasAttribute(f->attributes, Token::Static); + bool isConstructor = (s->getKind() == StmtNode::Constructor); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; ICodeGenerator mcg(mWorld, thisScope, thisClass, flags); // method code generator. - ICodeModule *icm = mcg.genFunction(f); + ICodeModule *icm = mcg.genFunction(f, isConstructor, superclass); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; - if (isStatic) { - thisClass->defineStatic(name, &Function_Type); + if (isConstructor) { + if (name == nameExpr->name) + hasDefaultConstructor = true; + thisClass->defineConstructor(name); scg.setStatic(thisClass, name, scg.newFunction(icm)); } else - thisScope->defineFunction(name, icm); + if (isStatic) { + thisClass->defineStatic(name, &Function_Type); + scg.setStatic(thisClass, name, scg.newFunction(icm)); + } + else + thisScope->defineFunction(name, icm); } } break; @@ -1506,10 +1655,25 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } s = s->next; } + + // add the instance initializer + scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete())); + // invent a default constructor if necessary, it just calls the + // initializer and the superclass default constructor + if (!hasDefaultConstructor) { + TypedRegister thisValue = TypedRegister(0, thisClass); + RegisterList args; + ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod); + if (superclass) + icg.constructorCall(superclass, superclass->getName(), thisValue, &args); + icg.constructorCall(thisClass, initName, thisValue, &args); + thisClass->defineConstructor(nameExpr->name); + scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete())); + } // freeze the class. thisClass->complete(); - if (ccg.getICode()->size()) - thisClass->setInitializer(ccg.complete()); + + // REVISIT: using the scope of the class to store both methods and statics. if (scg.getICode()->size()) { Interpreter::Context cx(*mWorld, thisScope); @@ -1523,7 +1687,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) case StmtNode::Function: { FunctionStmtNode *f = static_cast(p); - ICodeModule *icm = genFunction(f); + ICodeModule *icm = genFunction(f, false, NULL); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; mGlobal->defineFunction(name, icm); diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index 7d2ee1e4bce..76fba721313 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -190,12 +190,12 @@ namespace ICG { void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); } - typedef enum {Var, Property, Slot, Static, Name} LValueKind; + typedef enum {Var, Property, Slot, Static, Constructor, Name} LValueKind; LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex); - TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, RegisterList *args); + TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args); TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args); - ICodeModule *genFunction(FunctionStmtNode *f); + ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass); public: @@ -241,9 +241,11 @@ namespace ICG { TypedRegister op(ICodeOp op, TypedRegister source); TypedRegister op(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); + 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); + void constructorCall(JSClass *c, const StringAtom &name, TypedRegister thisArg, RegisterList *args); + void constructorCall(JSClass *c, const String &name, TypedRegister thisArg, RegisterList *args); void move(TypedRegister destination, TypedRegister source); TypedRegister logicalNot(TypedRegister source); @@ -251,14 +253,15 @@ namespace ICG { TypedRegister loadBoolean(bool value); TypedRegister loadImmediate(double value); - TypedRegister loadString(String &value); + TypedRegister loadString(const String &value); TypedRegister loadString(const StringAtom &name); - TypedRegister newObject(); + TypedRegister newObject(RegisterList *args); TypedRegister newArray(); TypedRegister newFunction(ICodeModule *icm); - TypedRegister newClass(const StringAtom &name); + TypedRegister newClass(JSClass *clazz); + TypedRegister super(); TypedRegister loadName(const StringAtom &name); void saveName(const StringAtom &name, TypedRegister value); TypedRegister nameXcr(const StringAtom &name, ICodeOp op); diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index 6e68b2e2b94..05b04219456 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -481,6 +481,14 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) assert(mPC != endPC); Instruction* instruction = *mPC; switch (instruction->op()) { + case SUPER: + { + Super* su = static_cast(instruction); + ASSERT((*registers)[0].isObject()); // should be scope of current class + JSScope *s = static_cast((*registers)[0].object->getPrototype()); + (*registers)[dst(su).first] = s; + } + break; case METHOD_CALL: { MethodCall* call = static_cast(instruction); @@ -560,6 +568,38 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } + case CONSTRUCTOR_CALL: + { + ConstructorCall* call = static_cast(instruction); + JSClass* thisClass = op1(call); + const JSValue& value = (*thisClass)[op2(call)]; + // FIXME: throw runtime error if not a function value. + ASSERT(value.isFunction()); + JSFunction *target = value.function; + if (target->isNative()) { + RegisterList ¶ms = op4(call); + JSValues argv(params.size() + 1, kNullValue); + argv[0] = (*registers)[op3(call).first]; + JSValues::size_type i = 1; + for (RegisterList::const_iterator src = params.begin(), end = params.end(); + src != end; ++src, ++i) { + argv[i] = (*registers)[src->first]; + } + JSValue result = static_cast(target)->mCode(argv); + break; + } + else { + mLinkage = new Linkage(mLinkage, ++mPC, + mActivation, mGlobal, TypedRegister(NotARegister, &Any_Type)); + mActivation = new Activation(target->getICode(), mActivation, (*registers)[op3(call).first], op4(call)); + mGlobal = op1(call)->getScope(); + registers = &mActivation->mRegisters; + mPC = mActivation->mICode->its_iCode->begin(); + endPC = mActivation->mICode->its_iCode->end(); + continue; + } + } + case CALL: { Call* call = static_cast(instruction); @@ -667,36 +707,31 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case NEW_CLASS: { NewClass* nc = static_cast(instruction); - const JSValue& value = mGlobal->getVariable(*src1(nc)); - if (value.isType()) { - JSClass* thisClass = dynamic_cast(value.type); - if (thisClass) { - JSInstance* thisInstance = new(thisClass) JSInstance(thisClass); - (*registers)[dst(nc).first] = thisInstance; - JSValues args(1); - args[0] = thisInstance; - TypedRegister voidRegister(NotARegister, &None_Type); - InstructionIterator nextPC = ++mPC; - do { - // call the constructor(s), if any. - ICodeModule* init = thisClass->getInitializer(); - if (init) { - mLinkage = new Linkage(mLinkage, nextPC, - mActivation, mGlobal, voidRegister); - mActivation = new Activation(init, args); - registers = &mActivation->mRegisters; - nextPC = init->its_iCode->begin(); - endPC = init->its_iCode->end(); - } - thisClass = thisClass->getSuperClass(); - } while (thisClass); - - mPC = nextPC; - continue; + JSClass* thisClass = src1(nc); + JSInstance* thisInstance = new(thisClass) JSInstance(thisClass); + (*registers)[dst(nc).first] = thisInstance; +/* + JSValues args(1); + args[0] = thisInstance; + TypedRegister voidRegister(NotARegister, &None_Type); + InstructionIterator nextPC = ++mPC; + do { + // call the constructor(s), if any. + ICodeModule* init = thisClass->getInitializer(); + if (init) { + mLinkage = new Linkage(mLinkage, nextPC, + mActivation, mGlobal, voidRegister); + mActivation = new Activation(init, args); + registers = &mActivation->mRegisters; + nextPC = init->its_iCode->begin(); + endPC = init->its_iCode->end(); } - } else { - // XXX Runtime error. - } + thisClass = thisClass->getSuperClass(); + } while (thisClass); + + mPC = nextPC; + continue; +*/ } break; case NEW_FUNCTION: diff --git a/mozilla/js/js2/js2.cpp b/mozilla/js/js2/js2.cpp index b1c74c29098..45eb0061dfd 100644 --- a/mozilla/js/js2/js2.cpp +++ b/mozilla/js/js2/js2.cpp @@ -153,9 +153,6 @@ static ICodeModule* genCode(Context &cx, StmtNode *p, const String &fileName) icg.returnStmt(ret); ICodeModule *icm = icg.complete(); - -stdOut << icg; - icm->setFileName (fileName); return icm; } @@ -365,7 +362,6 @@ static void testCompile() icg.genStmt(s); s = s->next; } -// stdOut << icg; cx.interpret(icg.complete(), JSValues()); } } diff --git a/mozilla/js/js2/jsclasses.h b/mozilla/js/js2/jsclasses.h index c32bbe16977..83450dc37be 100644 --- a/mozilla/js/js2/jsclasses.h +++ b/mozilla/js/js2/jsclasses.h @@ -45,13 +45,19 @@ namespace JSClasses { using JSTypes::JSScope; using ICG::ICodeModule; + struct JSSlot { + typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc + JSType* mType; uint32 mIndex; + SlotFlags mFlags; - JSSlot() : mType(0) + JSSlot() : mType(0), mFlags(kNoFlag) { } + + bool isConstructor() const { return (mFlags & kIsConstructor) != 0; } }; #if defined(XP_MAC) @@ -79,7 +85,6 @@ namespace JSClasses { uint32 mStaticCount; JSSlots mStaticSlots; JSValue* mStaticData; - ICodeModule* mInitializer; // typedef std::vector > JSMethods; // JSMethods mMethods; public: @@ -88,8 +93,7 @@ namespace JSClasses { mScope(new JSScope(scope)), mSlotCount(superClass ? superClass->mSlotCount : 0), mStaticCount(0), - mStaticData(0), - mInitializer(0) + mStaticData(0) { // to "inherit" superClass methods. if (superClass) @@ -106,16 +110,6 @@ namespace JSClasses { return mScope; } - void setInitializer(ICodeModule* init) - { - mInitializer = init; - } - - ICodeModule* getInitializer() - { - return mInitializer; - } - const JSSlot& defineSlot(const String& name, JSType* type) { JSSlot& slot = mSlots[name]; @@ -156,17 +150,28 @@ namespace JSClasses { slot.mIndex = mStaticCount++; return slot; } + + const JSSlot& defineConstructor(const String& name) + { + JSSlot& slot = mStaticSlots[name]; + ASSERT(slot.mType == 0); + slot.mType = &JSTypes::Function_Type; + slot.mIndex = mStaticCount++; + slot.mFlags = JSSlot::kIsConstructor; + return slot; + } const JSSlot& getStatic(const String& name) { return mStaticSlots[name]; } - bool hasStatic(const String& name, JSType*& type) + bool hasStatic(const String& name, JSType*& type, bool &isConstructor) { JSSlots::const_iterator i = mStaticSlots.find(name); if (i != mStaticSlots.end()) { type = i->second.mType; + isConstructor = i->second.isConstructor(); return true; } return false; diff --git a/mozilla/js/js2/tools/gencode.pl b/mozilla/js/js2/tools/gencode.pl index 400632db320..0089f852a1d 100644 --- a/mozilla/js/js2/tools/gencode.pl +++ b/mozilla/js/js2/tools/gencode.pl @@ -108,6 +108,12 @@ $ops{"LOAD_NAME"} = rem => "dest, name", params => [ ("TypedRegister", "const StringAtom*" ) ] }; +$ops{"SUPER"} = + { + super => "Instruction_1", + rem => "dest", + params => [ ("TypedRegister" ) ] + }; $ops{"SAVE_NAME"} = { super => "Instruction_2", @@ -123,8 +129,8 @@ $ops{"NEW_OBJECT"} = $ops{"NEW_CLASS"} = { super => "Instruction_2", - rem => "dest, class name", - params => [ ("TypedRegister", "const StringAtom*") ] + rem => "dest, class", + params => [ ("TypedRegister", "JSClass*") ] }; $ops{"NEW_FUNCTION"} = { @@ -277,19 +283,25 @@ $ops{"CALL"} = { super => "Instruction_4", rem => "result, target, name, args", - params => [ ("TypedRegister" , "TypedRegister", "const StringAtom*", "RegisterList") ] + params => [ ("TypedRegister", "TypedRegister", "const StringAtom*", "RegisterList") ] }; $ops{"STATIC_CALL"} = { super => "Instruction_4", rem => "result, target class, index, args", - params => [ ("TypedRegister" , "JSClass*", "uint32", "RegisterList") ] + params => [ ("TypedRegister", "JSClass*", "uint32", "RegisterList") ] }; $ops{"METHOD_CALL"} = { super => "Instruction_4", rem => "result, target base, target value, args", - params => [ ("TypedRegister" , "TypedRegister" , "TypedRegister", "RegisterList") ] + params => [ ("TypedRegister", "TypedRegister", "TypedRegister", "RegisterList") ] + }; +$ops{"CONSTRUCTOR_CALL"} = + { + super => "Instruction_4", + rem => "target class, index, this, args", + params => [ ("JSClass*", "uint32", "TypedRegister", "RegisterList") ] }; $ops{"THROW"} = { diff --git a/mozilla/js/js2/vmtypes.h b/mozilla/js/js2/vmtypes.h index 550d0d2818a..2a1419ff59c 100644 --- a/mozilla/js/js2/vmtypes.h +++ b/mozilla/js/js2/vmtypes.h @@ -193,7 +193,7 @@ namespace VM { Operand3 mOp3; Operand4 mOp4; }; - + /********************************************************************/ /* Instruction groups */ diff --git a/mozilla/js2/src/icode.h b/mozilla/js2/src/icode.h index c86cd0d8935..7ee58f52ec0 100644 --- a/mozilla/js2/src/icode.h +++ b/mozilla/js2/src/icode.h @@ -17,6 +17,7 @@ COMPARE_LE, /* dest, source1, source2 */ COMPARE_LT, /* dest, source1, source2 */ COMPARE_NE, /* dest, source1, source2 */ + CONSTRUCTOR_CALL, /* target class, index, this, args */ DEBUGGER, /* drop to the debugger */ DELETE_PROP, /* dest, object, prop name */ DIVIDE, /* dest, source1, source2 */ @@ -37,7 +38,7 @@ NAME_XCR, /* dest, name, value */ NEGATE, /* dest, source */ NEW_ARRAY, /* dest */ - NEW_CLASS, /* dest, class name */ + NEW_CLASS, /* dest, class */ NEW_FUNCTION, /* dest, ICodeModule */ NEW_OBJECT, /* dest */ NOP, /* do nothing and like it */ @@ -62,6 +63,7 @@ STRICT_EQ, /* dest, source1, source2 */ STRICT_NE, /* dest, source1, source2 */ SUBTRACT, /* dest, source1, source2 */ + SUPER, /* dest */ TEST, /* dest, source */ THROW, /* exception value */ TRYIN, /* catch target, finally target */ @@ -219,6 +221,22 @@ /* print() and printOperands() inherited from Instruction_3 */ }; + class ConstructorCall : public Instruction_4 { + public: + /* target class, index, this, args */ + ConstructorCall (JSClass* aOp1, uint32 aOp2, TypedRegister aOp3, RegisterList aOp4) : + Instruction_4 + (CONSTRUCTOR_CALL, aOp1, aOp2, aOp3, aOp4) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[CONSTRUCTOR_CALL] << "\t" << mOp1->getName() << ", " << mOp2 << ", " << "R" << mOp3.first << ", " << mOp4; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp3.first << '=' << registers[mOp3.first] << ", " << ArgList(mOp4, registers); + return f; + } + }; + class Debugger : public Instruction { public: /* drop to the debugger */ @@ -516,14 +534,14 @@ } }; - class NewClass : public Instruction_2 { + class NewClass : public Instruction_2 { public: - /* dest, class name */ - NewClass (TypedRegister aOp1, const StringAtom* aOp2) : - Instruction_2 + /* dest, class */ + NewClass (TypedRegister aOp1, JSClass* aOp2) : + Instruction_2 (NEW_CLASS, aOp1, aOp2) {}; virtual Formatter& print(Formatter& f) { - f << opcodeNames[NEW_CLASS] << "\t" << "R" << mOp1.first << ", " << "'" << *mOp2 << "'"; + f << opcodeNames[NEW_CLASS] << "\t" << "R" << mOp1.first << ", " << mOp2->getName(); return f; } virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { @@ -864,6 +882,22 @@ /* print() and printOperands() inherited from Arithmetic */ }; + class Super : public Instruction_1 { + public: + /* dest */ + Super (TypedRegister aOp1) : + Instruction_1 + (SUPER, aOp1) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[SUPER] << "\t" << "R" << mOp1.first; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << "R" << mOp1.first << '=' << registers[mOp1.first]; + return f; + } + }; + class Test : public Instruction_2 { public: /* dest, source */ @@ -994,74 +1028,76 @@ #else char *opcodeNames[] = { - "ADD ", - "AND ", - "BITNOT ", - "BRANCH ", - "BRANCH_FALSE ", - "BRANCH_TRUE ", - "CALL ", - "COMPARE_EQ ", - "COMPARE_GE ", - "COMPARE_GT ", - "COMPARE_IN ", - "COMPARE_LE ", - "COMPARE_LT ", - "COMPARE_NE ", - "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 ", - "TEST ", - "THROW ", - "TRYIN ", - "TRYOUT ", - "USHIFTRIGHT ", - "VAR_XCR ", - "WITHIN ", - "WITHOUT ", - "XOR ", + "ADD ", + "AND ", + "BITNOT ", + "BRANCH ", + "BRANCH_FALSE ", + "BRANCH_TRUE ", + "CALL ", + "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 ", }; #endif diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 8619e95eb94..cc0e9a4a153 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -182,7 +182,7 @@ TypedRegister ICodeGenerator::loadImmediate(double value) return dest; } -TypedRegister ICodeGenerator::loadString(String &value) +TypedRegister ICodeGenerator::loadString(const String &value) { TypedRegister dest(getTempRegister(), &String_Type); LoadString *instr = new LoadString(dest, new JSString(value)); @@ -206,7 +206,7 @@ TypedRegister ICodeGenerator::loadBoolean(bool value) return dest; } -TypedRegister ICodeGenerator::newObject() +TypedRegister ICodeGenerator::newObject(RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); NewObject *instr = new NewObject(dest); @@ -214,10 +214,10 @@ TypedRegister ICodeGenerator::newObject() return dest; } -TypedRegister ICodeGenerator::newClass(const StringAtom &name) +TypedRegister ICodeGenerator::newClass(JSClass *clazz) { TypedRegister dest(getTempRegister(), &Any_Type); - NewClass *instr = new NewClass(dest, &name); + NewClass *instr = new NewClass(dest, clazz); iCode->push_back(instr); return dest; } @@ -435,27 +435,49 @@ TypedRegister ICodeGenerator::op(ICodeOp op, TypedRegister source1, return dest; } -TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList args) +TypedRegister ICodeGenerator::call(TypedRegister target, const StringAtom &name, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); - Call *instr = new Call(dest, target, &name, args); + Call *instr = new Call(dest, target, &name, *args); iCode->push_back(instr); return dest; } -TypedRegister ICodeGenerator::methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList args) +TypedRegister ICodeGenerator::methodCall(TypedRegister targetBase, TypedRegister targetValue, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); - MethodCall *instr = new MethodCall(dest, targetBase, targetValue, args); + MethodCall *instr = new MethodCall(dest, targetBase, targetValue, *args); iCode->push_back(instr); return dest; } -TypedRegister ICodeGenerator::staticCall(JSClass *c, const StringAtom &name, RegisterList args) +TypedRegister ICodeGenerator::staticCall(JSClass *c, const StringAtom &name, RegisterList *args) { TypedRegister dest(getTempRegister(), &Any_Type); const JSSlot& slot = c->getStatic(name); - StaticCall *instr = new StaticCall(dest, c, slot.mIndex, args); + StaticCall *instr = new StaticCall(dest, c, slot.mIndex, *args); + iCode->push_back(instr); + return dest; +} + +void ICodeGenerator::constructorCall(JSClass *c, const StringAtom &name, TypedRegister thisArg, RegisterList *args) +{ + const JSSlot& slot = c->getStatic(name); + ConstructorCall *instr = new ConstructorCall(c, slot.mIndex, thisArg, *args); + iCode->push_back(instr); +} + +void ICodeGenerator::constructorCall(JSClass *c, const String &name, TypedRegister thisArg, RegisterList *args) +{ + const JSSlot& slot = c->getStatic(name); + ConstructorCall *instr = new ConstructorCall(c, slot.mIndex, thisArg, *args); + iCode->push_back(instr); +} + +TypedRegister ICodeGenerator::super() +{ + TypedRegister dest(getTempRegister(), &Any_Type); + Super *instr = new Super(dest); iCode->push_back(instr); return dest; } @@ -647,8 +669,9 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n if (isSlotName(mClass, name, slotIndex, v.second)) return Slot; } - if (mClass->hasStatic(name, v.second)) { - return Static; + bool isConstructor = false; + if (mClass->hasStatic(name, v.second, isConstructor)) { + return (isConstructor) ? Constructor : Static; } } v.second = mGlobal->getType(name); @@ -659,24 +682,72 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n return Name; } -TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, RegisterList *args) +TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args) { ASSERT(p->getKind() == ExprNode::identifier); JSType *vType = &Any_Type; uint32 slotIndex; - TypedRegister ret; TypedRegister v; const StringAtom &name = (static_cast(p))->name; - LValueKind lValueKind = resolveIdentifier(name, ret, slotIndex); + LValueKind lValueKind = resolveIdentifier(name, v, slotIndex); TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type); switch (use) { + case ExprNode::addEquals: + case ExprNode::subtractEquals: + case ExprNode::multiplyEquals: + case ExprNode::divideEquals: + case ExprNode::moduloEquals: + case ExprNode::leftShiftEquals: + case ExprNode::rightShiftEquals: + case ExprNode::logicalRightShiftEquals: + case ExprNode::bitwiseAndEquals: + case ExprNode::bitwiseXorEquals: + case ExprNode::bitwiseOrEquals: + switch (lValueKind) { + case Var: + break; + case Name: + v = loadName(name); + break; + case Slot: + v = getSlot(thisBase, slotIndex); + break; + case Static: + case Constructor: + v = getStatic(mClass, name); + break; + default: + NOT_REACHED("Bad lvalue kind"); + } + ret = op(mapExprNodeToICodeOp(use), v, ret); + // fall thru... + case ExprNode::assignment: + switch (lValueKind) { + case Var: + move(v, ret); + break; + case Name: + saveName(name, ret); + break; + case Slot: + setSlot(thisBase, slotIndex, ret); + break; + case Static: + case Constructor: + setStatic(mClass, name, ret); + break; + default: + NOT_REACHED("Bad lvalue kind"); + } + break; case ExprNode::identifier: switch (lValueKind) { case Var: + ret = v; break; case Name: ret = loadName(name); @@ -685,6 +756,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = getSlot(thisBase, slotIndex); break; case Static: + case Constructor: ret = getStatic(mClass, name); break; default: @@ -695,7 +767,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: case ExprNode::preIncrement: switch (lValueKind) { case Var: - ret = op(xcrementOp, ret, loadImmediate(1.0)); + ret = op(xcrementOp, v, loadImmediate(1.0)); break; case Name: ret = loadName(name); @@ -707,6 +779,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: setSlot(thisBase, slotIndex, ret); break; case Static: + case Constructor: ret = op(xcrementOp, getStatic(mClass, name), loadImmediate(1.0)); setStatic(mClass, name, ret); break; @@ -718,7 +791,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: case ExprNode::postIncrement: switch (lValueKind) { case Var: - ret = varXcr(ret, xcrementOp); + ret = varXcr(v, xcrementOp); break; case Name: ret = nameXcr(name, xcrementOp); @@ -727,6 +800,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = slotXcr(thisBase, slotIndex, xcrementOp); break; case Static: + case Constructor: ret = staticXcr(mClass, name, xcrementOp); break; default: @@ -736,13 +810,17 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: case ExprNode::call: switch (lValueKind) { case Var: - ret = call(ret, name, *args); + ret = call(v, name, args); break; case Name: - ret = methodCall(TypedRegister(NotARegister, &Null_Type), loadString(name), *args); + ret = methodCall(TypedRegister(NotARegister, &Null_Type), loadString(name), args); break; case Static: - ret = staticCall(mClass, name, *args); + ret = staticCall(mClass, name, args); + break; + case Constructor: + ret = newClass(mClass); + constructorCall(mClass, name, ret, args); break; default: NOT_REACHED("Bad lvalue kind"); @@ -778,20 +856,21 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I // if (base.second == &Type_Type) { const JSValue &v = mGlobal->getVariable(baseName); + bool isConstructor; + ASSERT(v.isType()); // there's no other way that base.second could be &Type_Type, right? clazz = dynamic_cast(v.type); - if (clazz && clazz->hasStatic(fieldName, fieldType)) { - lValueKind = Static; + if (clazz && clazz->hasStatic(fieldName, fieldType, isConstructor)) { + lValueKind = (isConstructor) ? Constructor : Static; } } if (lValueKind == Property) { if (isSlotName(base.second, fieldName, slotIndex, fieldType)) lValueKind = Slot; else { + bool isConstructor; clazz = dynamic_cast(base.second); - if (clazz && clazz->hasStatic(fieldName, fieldType)) - lValueKind = Static; - else - lValueKind = Property; + if (clazz && clazz->hasStatic(fieldName, fieldType, isConstructor)) + lValueKind = (isConstructor) ? Constructor : Static; } } if ((lValueKind == Property) && (base.first == NotARegister)) @@ -802,11 +881,10 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I if (isSlotName(base.second, fieldName, slotIndex, fieldType)) lValueKind = Slot; else { + bool isConstructor; clazz = dynamic_cast(base.second); - if (clazz && clazz->hasStatic(fieldName, fieldType)) - lValueKind = Static; - else - lValueKind = Property; + if (clazz && clazz->hasStatic(fieldName, fieldType, isConstructor)) + lValueKind = (isConstructor) ? Constructor : Static; } } TypedRegister v; @@ -814,10 +892,14 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::call: switch (lValueKind) { case Static: - ret = staticCall(clazz, fieldName, *args); + ret = staticCall(clazz, fieldName, args); + break; + case Constructor: + ret = newClass(clazz); + constructorCall(clazz, fieldName, ret, args); break; case Property: - ret = methodCall(base, loadString(fieldName), *args); + ret = methodCall(base, loadString(fieldName), args); break; default: NOT_REACHED("Bad lvalue kind"); @@ -836,6 +918,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::bitwiseXorEquals: case ExprNode::bitwiseOrEquals: switch (lValueKind) { + case Constructor: case Static: v = getStatic(clazz, fieldName); break; @@ -856,6 +939,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I // fall thru... case ExprNode::assignment: switch (lValueKind) { + case Constructor: case Static: setStatic(clazz, fieldName, ret); break; @@ -872,6 +956,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::postDecrement: case ExprNode::postIncrement: switch (lValueKind) { + case Constructor: case Static: ret = staticXcr(clazz, fieldName, xcrementOp); break; @@ -887,6 +972,7 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I case ExprNode::preDecrement: case ExprNode::preIncrement: switch (lValueKind) { + case Constructor: case Static: ret = op(xcrementOp, getStatic(clazz, fieldName), loadImmediate(1.0)); setStatic(clazz, fieldName, ret); @@ -960,11 +1046,27 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::New: { InvokeExprNode *i = static_cast(p); + RegisterList args; + ExprPairList *p = i->pairs; + while (p) { + args.push_back(genExpr(p->value)); + p = p->next; + } if (i->op->getKind() == ExprNode::identifier) { - ret = newClass(static_cast(i->op)->name); + const StringAtom &className = static_cast(i->op)->name; + const JSValue& value = mGlobal->getVariable(className); + if (value.isType()) { + JSClass* clazz = dynamic_cast(value.type); + if (clazz) { + ret = newClass(clazz); + constructorCall(clazz, className, ret, &args); + } + else + NOT_REACHED("New , where is not a known class"); // XXX Runtime error. + } } else - ret = newObject(); // XXX more + ret = newObject(&args); // XXX more ? } break; case ExprNode::Delete: @@ -991,12 +1093,12 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else if (i->op->getKind() == ExprNode::identifier) { - ret = handleIdentifier(static_cast(i->op), ExprNode::call, xcrementOp, &args); + ret = handleIdentifier(static_cast(i->op), ExprNode::call, xcrementOp, ret, &args); } else if (i->op->getKind() == ExprNode::index) { BinaryExprNode *b = static_cast(i->op); - ret = methodCall(genExpr(b->op1), genExpr(b->op2), args); + ret = methodCall(genExpr(b->op1), genExpr(b->op2), &args); } else ASSERT("WAH!"); @@ -1023,7 +1125,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, break; case ExprNode::identifier : { - ret = handleIdentifier(static_cast(p), ExprNode::identifier, xcrementOp, NULL); + ret = handleIdentifier(static_cast(p), ExprNode::identifier, xcrementOp, ret, NULL); } break; case ExprNode::number : @@ -1042,7 +1144,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else if (u->op->getKind() == ExprNode::identifier) { - ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, NULL); + ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, ret, NULL); } else if (u->op->getKind() == ExprNode::index) { @@ -1067,7 +1169,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else if (u->op->getKind() == ExprNode::identifier) { - ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, NULL); + ret = handleIdentifier(static_cast(u->op), p->getKind(), xcrementOp, ret, NULL); } else if (u->op->getKind() == ExprNode::index) { @@ -1113,6 +1215,8 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, BinaryExprNode *b = static_cast(p); ret = genExpr(b->op2); if (b->op1->getKind() == ExprNode::identifier) { + ret = handleIdentifier(static_cast(b->op1), p->getKind(), xcrementOp, ret, NULL); +/* if (!isWithinWith()) { TypedRegister v = findVariable((static_cast(b->op1))->name); if (v.first != NotARegister) @@ -1122,6 +1226,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } else saveName((static_cast(b->op1))->name, ret); +*/ } else if (b->op1->getKind() == ExprNode::dot) { @@ -1154,6 +1259,9 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, BinaryExprNode *b = static_cast(p); ret = genExpr(b->op2); if (b->op1->getKind() == ExprNode::identifier) { + + ret = handleIdentifier(static_cast(b->op1), p->getKind(), xcrementOp, ret, NULL); +/* if (!isWithinWith()) { TypedRegister v = findVariable((static_cast(b->op1))->name); if (v.first != NotARegister) { @@ -1171,6 +1279,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, ret = op(mapExprNodeToICodeOp(p->getKind()), v, ret); saveName((static_cast(b->op1))->name, ret); } +*/ } else if (b->op1->getKind() == ExprNode::dot) { @@ -1325,7 +1434,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::objectLiteral: { - ret = newObject(); + ret = newObject(NULL); PairListExprNode *plen = static_cast(p); ExprPairList *e = plen->pairs; while (e) { @@ -1362,14 +1471,6 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, return ret; } -/* - need pre-pass to find: - variable & function definitions, - contains 'with' or 'eval' - contains 'try {} catch {} finally {}' -*/ - - bool LabelEntry::containsLabel(const StringAtom *label) { if (labelSet) { @@ -1390,7 +1491,7 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin return false; } -ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f) +ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass) { bool isStatic = hasAttribute(f->attributes, Token::Static); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; @@ -1403,6 +1504,35 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f) icg.allocateParameter((static_cast(v->name))->name); v = v->next; } + if (isConstructor) { + TypedRegister thisValue = TypedRegister(0, mClass); + RegisterList args; + if (superclass) { + bool foundSuperCall = false; + BlockStmtNode *b = f->function.body; + if (b && b->statements && (b->statements->getKind() == StmtNode::expression)) { + ExprStmtNode *e = static_cast(b->statements); + if (e->expr->getKind() == ExprNode::call) { + InvokeExprNode *i = static_cast(e->expr); + if (i->op->getKind() == ExprNode::dot) { + BinaryExprNode *b = static_cast(i->op); + if ((b->op1->getKind() == ExprNode::This) && (b->op2->getKind() == ExprNode::qualify)) { + BinaryExprNode *q = static_cast(b->op2); + if (q->op1->getKind() == ExprNode::Super) { + // XXX verify that q->op2 is either the superclass name or a constructor for it + foundSuperCall = true; + } + } + } + } + } + if (!foundSuperCall) { // invoke the default superclass constructor + icg.constructorCall(superclass, superclass->getName(), thisValue, &args); + } + } + const StringAtom &initName = mWorld->identifiers[widenCString("__init__")]; // XXXXXXX + icg.constructorCall(mClass, initName, thisValue, &args); // ok, so it's mis-named + } icg.genStmt(f->function.body); return icg.complete(); @@ -1436,6 +1566,16 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) // is it ok for a partially defined class to appear in global scope? this is needed // to handle recursive types, such as linked list nodes. mGlobal->defineVariable(nameExpr->name, &Type_Type, JSValue(thisClass)); + + // Have to have this declared ahead of time so that it's slot can + // be discoverd when compiling constructors in the loop below. Could + // do a pre-processing loop to discover whether it is in fact empty + // and then pass that info through to the genFunction() call for each + // constructor. + const StringAtom &initName = mWorld->identifiers[widenCString("__init__")]; + thisClass->defineStatic(initName, &Function_Type); + + bool hasDefaultConstructor = false; if (classStmt->body) { JSScope* thisScope = thisClass->getScope(); ICodeGenerator ccg(mWorld, thisScope, thisClass, kNoFlags); // constructor code generator. @@ -1481,22 +1621,31 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } } break; + case StmtNode::Constructor: case StmtNode::Function: { FunctionStmtNode *f = static_cast(s); bool isStatic = hasAttribute(f->attributes, Token::Static); + bool isConstructor = (s->getKind() == StmtNode::Constructor); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; ICodeGenerator mcg(mWorld, thisScope, thisClass, flags); // method code generator. - ICodeModule *icm = mcg.genFunction(f); + ICodeModule *icm = mcg.genFunction(f, isConstructor, superclass); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; - if (isStatic) { - thisClass->defineStatic(name, &Function_Type); + if (isConstructor) { + if (name == nameExpr->name) + hasDefaultConstructor = true; + thisClass->defineConstructor(name); scg.setStatic(thisClass, name, scg.newFunction(icm)); } else - thisScope->defineFunction(name, icm); + if (isStatic) { + thisClass->defineStatic(name, &Function_Type); + scg.setStatic(thisClass, name, scg.newFunction(icm)); + } + else + thisScope->defineFunction(name, icm); } } break; @@ -1506,10 +1655,25 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } s = s->next; } + + // add the instance initializer + scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete())); + // invent a default constructor if necessary, it just calls the + // initializer and the superclass default constructor + if (!hasDefaultConstructor) { + TypedRegister thisValue = TypedRegister(0, thisClass); + RegisterList args; + ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod); + if (superclass) + icg.constructorCall(superclass, superclass->getName(), thisValue, &args); + icg.constructorCall(thisClass, initName, thisValue, &args); + thisClass->defineConstructor(nameExpr->name); + scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete())); + } // freeze the class. thisClass->complete(); - if (ccg.getICode()->size()) - thisClass->setInitializer(ccg.complete()); + + // REVISIT: using the scope of the class to store both methods and statics. if (scg.getICode()->size()) { Interpreter::Context cx(*mWorld, thisScope); @@ -1523,7 +1687,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) case StmtNode::Function: { FunctionStmtNode *f = static_cast(p); - ICodeModule *icm = genFunction(f); + ICodeModule *icm = genFunction(f, false, NULL); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; mGlobal->defineFunction(name, icm); diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index 7d2ee1e4bce..76fba721313 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -190,12 +190,12 @@ namespace ICG { void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); } - typedef enum {Var, Property, Slot, Static, Name} LValueKind; + typedef enum {Var, Property, Slot, Static, Constructor, Name} LValueKind; LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex); - TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, RegisterList *args); + TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args); TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args); - ICodeModule *genFunction(FunctionStmtNode *f); + ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass); public: @@ -241,9 +241,11 @@ namespace ICG { TypedRegister op(ICodeOp op, TypedRegister source); TypedRegister op(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); + 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); + void constructorCall(JSClass *c, const StringAtom &name, TypedRegister thisArg, RegisterList *args); + void constructorCall(JSClass *c, const String &name, TypedRegister thisArg, RegisterList *args); void move(TypedRegister destination, TypedRegister source); TypedRegister logicalNot(TypedRegister source); @@ -251,14 +253,15 @@ namespace ICG { TypedRegister loadBoolean(bool value); TypedRegister loadImmediate(double value); - TypedRegister loadString(String &value); + TypedRegister loadString(const String &value); TypedRegister loadString(const StringAtom &name); - TypedRegister newObject(); + TypedRegister newObject(RegisterList *args); TypedRegister newArray(); TypedRegister newFunction(ICodeModule *icm); - TypedRegister newClass(const StringAtom &name); + TypedRegister newClass(JSClass *clazz); + TypedRegister super(); TypedRegister loadName(const StringAtom &name); void saveName(const StringAtom &name, TypedRegister value); TypedRegister nameXcr(const StringAtom &name, ICodeOp op); diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 6e68b2e2b94..05b04219456 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -481,6 +481,14 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) assert(mPC != endPC); Instruction* instruction = *mPC; switch (instruction->op()) { + case SUPER: + { + Super* su = static_cast(instruction); + ASSERT((*registers)[0].isObject()); // should be scope of current class + JSScope *s = static_cast((*registers)[0].object->getPrototype()); + (*registers)[dst(su).first] = s; + } + break; case METHOD_CALL: { MethodCall* call = static_cast(instruction); @@ -560,6 +568,38 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } + case CONSTRUCTOR_CALL: + { + ConstructorCall* call = static_cast(instruction); + JSClass* thisClass = op1(call); + const JSValue& value = (*thisClass)[op2(call)]; + // FIXME: throw runtime error if not a function value. + ASSERT(value.isFunction()); + JSFunction *target = value.function; + if (target->isNative()) { + RegisterList ¶ms = op4(call); + JSValues argv(params.size() + 1, kNullValue); + argv[0] = (*registers)[op3(call).first]; + JSValues::size_type i = 1; + for (RegisterList::const_iterator src = params.begin(), end = params.end(); + src != end; ++src, ++i) { + argv[i] = (*registers)[src->first]; + } + JSValue result = static_cast(target)->mCode(argv); + break; + } + else { + mLinkage = new Linkage(mLinkage, ++mPC, + mActivation, mGlobal, TypedRegister(NotARegister, &Any_Type)); + mActivation = new Activation(target->getICode(), mActivation, (*registers)[op3(call).first], op4(call)); + mGlobal = op1(call)->getScope(); + registers = &mActivation->mRegisters; + mPC = mActivation->mICode->its_iCode->begin(); + endPC = mActivation->mICode->its_iCode->end(); + continue; + } + } + case CALL: { Call* call = static_cast(instruction); @@ -667,36 +707,31 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case NEW_CLASS: { NewClass* nc = static_cast(instruction); - const JSValue& value = mGlobal->getVariable(*src1(nc)); - if (value.isType()) { - JSClass* thisClass = dynamic_cast(value.type); - if (thisClass) { - JSInstance* thisInstance = new(thisClass) JSInstance(thisClass); - (*registers)[dst(nc).first] = thisInstance; - JSValues args(1); - args[0] = thisInstance; - TypedRegister voidRegister(NotARegister, &None_Type); - InstructionIterator nextPC = ++mPC; - do { - // call the constructor(s), if any. - ICodeModule* init = thisClass->getInitializer(); - if (init) { - mLinkage = new Linkage(mLinkage, nextPC, - mActivation, mGlobal, voidRegister); - mActivation = new Activation(init, args); - registers = &mActivation->mRegisters; - nextPC = init->its_iCode->begin(); - endPC = init->its_iCode->end(); - } - thisClass = thisClass->getSuperClass(); - } while (thisClass); - - mPC = nextPC; - continue; + JSClass* thisClass = src1(nc); + JSInstance* thisInstance = new(thisClass) JSInstance(thisClass); + (*registers)[dst(nc).first] = thisInstance; +/* + JSValues args(1); + args[0] = thisInstance; + TypedRegister voidRegister(NotARegister, &None_Type); + InstructionIterator nextPC = ++mPC; + do { + // call the constructor(s), if any. + ICodeModule* init = thisClass->getInitializer(); + if (init) { + mLinkage = new Linkage(mLinkage, nextPC, + mActivation, mGlobal, voidRegister); + mActivation = new Activation(init, args); + registers = &mActivation->mRegisters; + nextPC = init->its_iCode->begin(); + endPC = init->its_iCode->end(); } - } else { - // XXX Runtime error. - } + thisClass = thisClass->getSuperClass(); + } while (thisClass); + + mPC = nextPC; + continue; +*/ } break; case NEW_FUNCTION: diff --git a/mozilla/js2/src/jsclasses.h b/mozilla/js2/src/jsclasses.h index c32bbe16977..83450dc37be 100644 --- a/mozilla/js2/src/jsclasses.h +++ b/mozilla/js2/src/jsclasses.h @@ -45,13 +45,19 @@ namespace JSClasses { using JSTypes::JSScope; using ICG::ICodeModule; + struct JSSlot { + typedef enum { kNoFlag = 0, kIsConstructor = 0x01 } SlotFlags; // <-- readonly, enumerable etc + JSType* mType; uint32 mIndex; + SlotFlags mFlags; - JSSlot() : mType(0) + JSSlot() : mType(0), mFlags(kNoFlag) { } + + bool isConstructor() const { return (mFlags & kIsConstructor) != 0; } }; #if defined(XP_MAC) @@ -79,7 +85,6 @@ namespace JSClasses { uint32 mStaticCount; JSSlots mStaticSlots; JSValue* mStaticData; - ICodeModule* mInitializer; // typedef std::vector > JSMethods; // JSMethods mMethods; public: @@ -88,8 +93,7 @@ namespace JSClasses { mScope(new JSScope(scope)), mSlotCount(superClass ? superClass->mSlotCount : 0), mStaticCount(0), - mStaticData(0), - mInitializer(0) + mStaticData(0) { // to "inherit" superClass methods. if (superClass) @@ -106,16 +110,6 @@ namespace JSClasses { return mScope; } - void setInitializer(ICodeModule* init) - { - mInitializer = init; - } - - ICodeModule* getInitializer() - { - return mInitializer; - } - const JSSlot& defineSlot(const String& name, JSType* type) { JSSlot& slot = mSlots[name]; @@ -156,17 +150,28 @@ namespace JSClasses { slot.mIndex = mStaticCount++; return slot; } + + const JSSlot& defineConstructor(const String& name) + { + JSSlot& slot = mStaticSlots[name]; + ASSERT(slot.mType == 0); + slot.mType = &JSTypes::Function_Type; + slot.mIndex = mStaticCount++; + slot.mFlags = JSSlot::kIsConstructor; + return slot; + } const JSSlot& getStatic(const String& name) { return mStaticSlots[name]; } - bool hasStatic(const String& name, JSType*& type) + bool hasStatic(const String& name, JSType*& type, bool &isConstructor) { JSSlots::const_iterator i = mStaticSlots.find(name); if (i != mStaticSlots.end()) { type = i->second.mType; + isConstructor = i->second.isConstructor(); return true; } return false; diff --git a/mozilla/js2/src/vmtypes.h b/mozilla/js2/src/vmtypes.h index 550d0d2818a..2a1419ff59c 100644 --- a/mozilla/js2/src/vmtypes.h +++ b/mozilla/js2/src/vmtypes.h @@ -193,7 +193,7 @@ namespace VM { Operand3 mOp3; Operand4 mOp4; }; - + /********************************************************************/ /* Instruction groups */ diff --git a/mozilla/js2/tests/cpp/js2_shell.cpp b/mozilla/js2/tests/cpp/js2_shell.cpp index b1c74c29098..45eb0061dfd 100644 --- a/mozilla/js2/tests/cpp/js2_shell.cpp +++ b/mozilla/js2/tests/cpp/js2_shell.cpp @@ -153,9 +153,6 @@ static ICodeModule* genCode(Context &cx, StmtNode *p, const String &fileName) icg.returnStmt(ret); ICodeModule *icm = icg.complete(); - -stdOut << icg; - icm->setFileName (fileName); return icm; } @@ -365,7 +362,6 @@ static void testCompile() icg.genStmt(s); s = s->next; } -// stdOut << icg; cx.interpret(icg.complete(), JSValues()); } } diff --git a/mozilla/js2/tools/gencode.pl b/mozilla/js2/tools/gencode.pl index 400632db320..0089f852a1d 100644 --- a/mozilla/js2/tools/gencode.pl +++ b/mozilla/js2/tools/gencode.pl @@ -108,6 +108,12 @@ $ops{"LOAD_NAME"} = rem => "dest, name", params => [ ("TypedRegister", "const StringAtom*" ) ] }; +$ops{"SUPER"} = + { + super => "Instruction_1", + rem => "dest", + params => [ ("TypedRegister" ) ] + }; $ops{"SAVE_NAME"} = { super => "Instruction_2", @@ -123,8 +129,8 @@ $ops{"NEW_OBJECT"} = $ops{"NEW_CLASS"} = { super => "Instruction_2", - rem => "dest, class name", - params => [ ("TypedRegister", "const StringAtom*") ] + rem => "dest, class", + params => [ ("TypedRegister", "JSClass*") ] }; $ops{"NEW_FUNCTION"} = { @@ -277,19 +283,25 @@ $ops{"CALL"} = { super => "Instruction_4", rem => "result, target, name, args", - params => [ ("TypedRegister" , "TypedRegister", "const StringAtom*", "RegisterList") ] + params => [ ("TypedRegister", "TypedRegister", "const StringAtom*", "RegisterList") ] }; $ops{"STATIC_CALL"} = { super => "Instruction_4", rem => "result, target class, index, args", - params => [ ("TypedRegister" , "JSClass*", "uint32", "RegisterList") ] + params => [ ("TypedRegister", "JSClass*", "uint32", "RegisterList") ] }; $ops{"METHOD_CALL"} = { super => "Instruction_4", rem => "result, target base, target value, args", - params => [ ("TypedRegister" , "TypedRegister" , "TypedRegister", "RegisterList") ] + params => [ ("TypedRegister", "TypedRegister", "TypedRegister", "RegisterList") ] + }; +$ops{"CONSTRUCTOR_CALL"} = + { + super => "Instruction_4", + rem => "target class, index, this, args", + params => [ ("JSClass*", "uint32", "TypedRegister", "RegisterList") ] }; $ops{"THROW"} = {