diff --git a/mozilla/js/js2/icode.h b/mozilla/js/js2/icode.h index eb934525239..ad34f49c45a 100644 --- a/mozilla/js/js2/icode.h +++ b/mozilla/js/js2/icode.h @@ -41,7 +41,7 @@ NEGATE, /* dest, source */ NEW_ARRAY, /* dest */ NEW_CLASS, /* dest, class */ - NEW_FUNCTION, /* dest, ICodeModule */ + NEW_FUNCTION, /* dest, ICodeModule, Function Definition */ NEW_OBJECT, /* dest, constructor */ NOP, /* do nothing and like it */ NOT, /* dest, source */ @@ -143,11 +143,11 @@ /* print() and printOperands() inherited from GenericBranch */ }; - class Call : public Instruction_4 { + class Call : public Instruction_4 { public: /* result, target, this, args */ - Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, RegisterList aOp4) : - Instruction_4 + Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, ArgumentList aOp4) : + Instruction_4 (CALL, aOp1, aOp2, aOp3, aOp4) {}; virtual Formatter& print(Formatter& f) { f << opcodeNames[CALL] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4; @@ -269,11 +269,11 @@ } }; - class DirectCall : public Instruction_3 { + class DirectCall : public Instruction_3 { public: /* result, target, args */ - DirectCall (TypedRegister aOp1, JSFunction * aOp2, RegisterList aOp3) : - Instruction_3 + DirectCall (TypedRegister aOp1, JSFunction * aOp2, ArgumentList aOp3) : + Instruction_3 (DIRECT_CALL, aOp1, aOp2, aOp3) {}; virtual Formatter& print(Formatter& f) { f << opcodeNames[DIRECT_CALL] << "\t" << mOp1 << ", " << "JSFunction" << ", " << mOp3; @@ -583,14 +583,14 @@ } }; - class NewFunction : public Instruction_2 { + class NewFunction : public Instruction_3 { public: - /* dest, ICodeModule */ - NewFunction (TypedRegister aOp1, ICodeModule* aOp2) : - Instruction_2 - (NEW_FUNCTION, aOp1, aOp2) {}; + /* dest, ICodeModule, Function Definition */ + NewFunction (TypedRegister aOp1, ICodeModule* aOp2, FunctionDefinition* aOp3) : + Instruction_3 + (NEW_FUNCTION, aOp1, aOp2, aOp3) {}; virtual Formatter& print(Formatter& f) { - f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule"; + f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule" << ", " << "FunctionDefinition"; return f; } virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { diff --git a/mozilla/js/js2/icodegenerator.cpp b/mozilla/js/js2/icodegenerator.cpp index 4ec254d82b9..ceec514d1dc 100644 --- a/mozilla/js/js2/icodegenerator.cpp +++ b/mozilla/js/js2/icodegenerator.cpp @@ -79,7 +79,10 @@ ICodeGenerator::ICodeGenerator(World *world, JSScope *global, JSClass *aClass, I mGlobal(global), mInstructionMap(new InstructionMap()), mClass(aClass), - mFlags(flags) + mFlags(flags), + pLabels(NULL), + mHasRestParameter(false), + mHasNamedRestParameter(false) { iCode = new InstructionStream(); iCodeOwner = true; @@ -171,7 +174,23 @@ ICodeModule *ICodeGenerator::complete() } } */ - ICodeModule* module = new ICodeModule(iCode, variableList, mPermanentRegister.size(), 0, mInstructionMap); + ICodeModule* module = new ICodeModule(iCode, + variableList, + mPermanentRegister.size(), + mParameterCount, + mInstructionMap, + mHasRestParameter, + mHasNamedRestParameter); + if (pLabels) { + uint32 i; + uint32 parameterInits = pLabels->size() - 1; // there's an extra label at the end for the actual entryPoint + module->mNonOptionalParameterCount -= parameterInits; + module->mParameterInit = new uint32[parameterInits]; + for (i = 0; i < parameterInits; i++) { + module->mParameterInit[i] = (*pLabels)[i]->mOffset; + } + module->mEntryPoint = (*pLabels)[i]->mOffset; + } iCodeOwner = false; // give ownership to the module. return module; } @@ -227,10 +246,10 @@ TypedRegister ICodeGenerator::newClass(JSClass *clazz) return dest; } -TypedRegister ICodeGenerator::newFunction(ICodeModule *icm) +TypedRegister ICodeGenerator::newFunction(ICodeModule *icm, FunctionDefinition *def) { TypedRegister dest(getTempRegister(), &Function_Type); - NewFunction *instr = new NewFunction(dest, icm); + NewFunction *instr = new NewFunction(dest, icm, def); iCode->push_back(instr); return dest; } @@ -458,7 +477,7 @@ TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1, return dest; } -TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, RegisterList *args) +TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, ArgumentList *args) { TypedRegister dest(getTempRegister(), &Any_Type); Call *instr = new Call(dest, target, thisArg, *args); @@ -466,7 +485,7 @@ TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, return dest; } -TypedRegister ICodeGenerator::directCall(JSFunction *target, RegisterList *args) +TypedRegister ICodeGenerator::directCall(JSFunction *target, ArgumentList *args) { TypedRegister dest(getTempRegister(), &Any_Type); DirectCall *instr = new DirectCall(dest, target, *args); @@ -537,10 +556,11 @@ Label *ICodeGenerator::getLabel() return labels.back(); } -void ICodeGenerator::setLabel(Label *l) +Label *ICodeGenerator::setLabel(Label *l) { l->mBase = iCode; l->mOffset = iCode->size(); + return l; } /************************************************************************/ @@ -711,7 +731,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n return Name; } -TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args) +TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args) { ASSERT(p->getKind() == ExprNode::identifier); @@ -836,26 +856,28 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: NOT_REACHED("Bad lvalue kind"); } break; - case ExprNode::call: - switch (lValueKind) { - case Var: - ret = call(v, TypedRegister(NotARegister, &Null_Type), args); - break; - case Name: - ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args); - break; - case Method: - ret = call(getMethod(thisBase, slotIndex), thisBase, args); - break; - case Static: - ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args); - break; - case Constructor: - ret = newClass(mClass); - call(getStatic(mClass, name), ret, args); - break; - default: - NOT_REACHED("Bad lvalue kind"); + case ExprNode::call: + { + switch (lValueKind) { + case Var: + ret = call(v, TypedRegister(NotARegister, &Null_Type), args); + break; + case Name: + ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args); + break; + case Method: + ret = call(getMethod(thisBase, slotIndex), thisBase, args); + break; + case Static: + ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args); + break; + case Constructor: + ret = newClass(mClass); + call(getStatic(mClass, name), ret, args); + break; + default: + NOT_REACHED("Bad lvalue kind"); + } } break; default: @@ -865,7 +887,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: } -TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args) +TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args) { ASSERT(b->getKind() == ExprNode::dot); @@ -1095,10 +1117,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::New: { InvokeExprNode *i = static_cast(p); - RegisterList args; + ArgumentList args; ExprPairList *p = i->pairs; while (p) { - args.push_back(genExpr(p->value)); + if (p->field && (p->field->getKind() == ExprNode::identifier)) + args.push_back(Argument(genExpr(p->value), &(static_cast(p->field))->name)); + else + args.push_back(Argument(genExpr(p->value), NULL )); p = p->next; } if (i->op->getKind() == ExprNode::identifier) { @@ -1145,10 +1170,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::call : { InvokeExprNode *i = static_cast(p); - RegisterList args; + ArgumentList args; ExprPairList *p = i->pairs; while (p) { - args.push_back(genExpr(p->value)); + if (p->field && (p->field->getKind() == ExprNode::identifier)) + args.push_back(Argument(genExpr(p->value), &(static_cast(p->field))->name)); + else + args.push_back(Argument(genExpr(p->value), NULL )); p = p->next; } @@ -1498,7 +1526,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, icg.genStmt(f->function.body); //stdOut << icg; ICodeModule *icm = icg.complete(); - ret = newFunction(icm); + ret = newFunction(icm, &f->function); } break; @@ -1555,6 +1583,17 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin return false; } +JSType *ICodeGenerator::extractType(ExprNode *t) +{ + JSType* type = &Any_Type; + // FIXME: need to do code generation for type expressions. + if (t && (t->getKind() == ExprNode::identifier)) { + IdentifierExprNode* typeExpr = static_cast(t); + type = findType(typeExpr->name); + } + return type; +} + ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass) { bool isStatic = hasAttribute(f->attributes, Token::Static); @@ -1564,13 +1603,47 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor icg.allocateParameter(mWorld->identifiers["this"], (mClass) ? mClass : &Any_Type); // always parameter #0 VariableBinding *v = f->function.parameters; while (v) { - if (v->name && (v->name->getKind() == ExprNode::identifier)) - icg.allocateParameter((static_cast(v->name))->name); + if (v->name && (v->name->getKind() == ExprNode::identifier)) { + JSType *pType; + if ((v == f->function.restParameter) && (v->type == NULL)) + pType = &Array_Type; + else + pType = extractType(v->type); + icg.allocateParameter((static_cast(v->name))->name, pType); + } + else + NOT_REACHED("qualified or un-named parameters not handled; bugger off."); v = v->next; } + v = f->function.optParameters; + if (v) { + while (v) { // include the rest parameter, as it may have an initializer + if (v->name && (v->name->getKind() == ExprNode::identifier)) { + icg.addParameterLabel(icg.setLabel(icg.getLabel())); + if (v->initializer) { // might be NULL when we get to the restParameter + TypedRegister p = icg.genExpr(v->name); + icg.move(p, icg.genExpr(v->initializer)); + } + } + v = v->next; + } + icg.addParameterLabel(icg.setLabel(icg.getLabel())); // to provide the entry-point for the default case + } + v = f->function.restParameter; + if (v) { + icg.mHasRestParameter = true; + if (v->name && (v->name->getKind() == ExprNode::identifier)) { + icg.mHasNamedRestParameter = true; + } + } if (isConstructor) { + /* + See if the first statement is an expression statement consisting + of a call to super(). If not we need to add a call to the default + superclass constructor ourselves. + */ TypedRegister thisValue = TypedRegister(0, mClass); - RegisterList args; + ArgumentList args; if (superclass) { bool foundSuperCall = false; BlockStmtNode *b = f->function.body; @@ -1664,12 +1737,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (v->name) { ASSERT(v->name->getKind() == ExprNode::identifier); IdentifierExprNode* idExpr = static_cast(v->name); - JSType* type = &Any_Type; - // FIXME: need to do code generation for type expressions. - if (v->type && v->type->getKind() == ExprNode::identifier) { - IdentifierExprNode* typeExpr = static_cast(v->type); - type = findType(typeExpr->name); - } + JSType* type = extractType(v->type); if (isStatic) { thisClass->defineStatic(idExpr->name, type); if (v->initializer) { @@ -1705,15 +1773,15 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (name == nameExpr->name) hasDefaultConstructor = true; thisClass->defineConstructor(name); - scg.setStatic(thisClass, name, scg.newFunction(icm)); + scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function)); } else if (isStatic) { thisClass->defineStatic(name, &Function_Type); - scg.setStatic(thisClass, name, scg.newFunction(icm)); + scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function)); } else - thisClass->defineMethod(name, new JSFunction(icm)); + thisClass->defineMethod(name, new JSFunction(icm, &f->function)); } } break; @@ -1725,12 +1793,12 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } // add the instance initializer - scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete())); + scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(), NULL)); // 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; + ArgumentList args; ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod); icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0 if (superclass) @@ -1738,7 +1806,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) icg.call(icg.getStatic(thisClass, initName), thisValue, &args); icg.returnStmt(thisValue); thisClass->defineConstructor(nameExpr->name); - scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete())); + scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(), NULL)); } // freeze the class. thisClass->complete(); @@ -1760,7 +1828,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) 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); + mGlobal->defineFunction(name, icm, &f->function); } } break; diff --git a/mozilla/js/js2/icodegenerator.h b/mozilla/js/js2/icodegenerator.h index 6415dee318b..229df639530 100644 --- a/mozilla/js/js2/icodegenerator.h +++ b/mozilla/js/js2/icodegenerator.h @@ -58,15 +58,25 @@ namespace ICG { public: ICodeModule(InstructionStream *iCode, VariableList *variables, uint32 maxRegister, uint32 maxParameter, - InstructionMap *instructionMap) : + InstructionMap *instructionMap, + bool hasRestParameter, bool hasNamedRestParameter) : its_iCode(iCode), itsVariables(variables), - itsParameterCount(maxParameter), itsMaxRegister(maxRegister), - mID(++sMaxID), mInstructionMap(instructionMap) { } + mParameterCount(maxParameter), itsMaxRegister(maxRegister), + mID(++sMaxID), mInstructionMap(instructionMap), + mParameterInit(NULL), + mNonOptionalParameterCount(maxParameter), + mEntryPoint(0), + mHasRestParameter(hasRestParameter), + mHasNamedRestParameter(hasNamedRestParameter) + { + } + ~ICodeModule() { delete its_iCode; delete itsVariables; delete mInstructionMap; + if (mParameterInit) delete mParameterInit; } Formatter& print(Formatter& f); @@ -75,11 +85,16 @@ namespace ICG { InstructionStream *its_iCode; VariableList *itsVariables; - uint32 itsParameterCount; + uint32 mParameterCount; uint32 itsMaxRegister; uint32 mID; InstructionMap *mInstructionMap; String mFileName; + uint32 *mParameterInit; + uint32 mNonOptionalParameterCount; + uint32 mEntryPoint; + bool mHasRestParameter; + bool mHasNamedRestParameter; static uint32 sMaxID; @@ -132,6 +147,9 @@ namespace ICG { JSClass *mClass; // enclosing class when generating code for methods ICodeGeneratorFlags mFlags; // assorted flags + LabelList *pLabels; // label for each parameter initialization entry point + bool mHasRestParameter; // true if this function has a ... parameter + bool mHasNamedRestParameter; // true if this function has a named ... parameter std::vector mPermanentRegister; @@ -155,13 +173,14 @@ namespace ICG { void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; } JSType *findType(const StringAtom& typeName); + JSType *extractType(ExprNode *t); + void addParameterLabel(Label *label) { if (pLabels == NULL) pLabels = new LabelList(); pLabels->push_back(label); } - - void setLabel(Label *label); + Label *setLabel(Label *label); void jsr(Label *label) { iCode->push_back(new Jsr(label)); } void rts() { iCode->push_back(new Rts()); } @@ -193,8 +212,8 @@ namespace ICG { typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind; LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex); - 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); + TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args); + TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args); ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass); public: @@ -206,6 +225,7 @@ namespace ICG { if (iCodeOwner) { delete iCode; delete mInstructionMap; + if (pLabels) delete pLabels; } } @@ -242,8 +262,8 @@ 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 base, TypedRegister target, RegisterList *args); - TypedRegister directCall(JSFunction *target, RegisterList *args); + TypedRegister call(TypedRegister base, TypedRegister target, ArgumentList *args); + TypedRegister directCall(JSFunction *target, ArgumentList *args); TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex); void move(TypedRegister destination, TypedRegister source); @@ -257,7 +277,7 @@ namespace ICG { TypedRegister newObject(TypedRegister constructor); TypedRegister newArray(); - TypedRegister newFunction(ICodeModule *icm); + TypedRegister newFunction(ICodeModule *icm, FunctionDefinition *def); TypedRegister newClass(JSClass *clazz); TypedRegister cast(TypedRegister arg, JSType *toType); diff --git a/mozilla/js/js2/interpreter.cpp b/mozilla/js/js2/interpreter.cpp index 1a045316cfe..8d3eea8fde8 100644 --- a/mozilla/js/js2/interpreter.cpp +++ b/mozilla/js/js2/interpreter.cpp @@ -96,16 +96,16 @@ struct Activation : public gc_base { } Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg, - const RegisterList& list) + const ArgumentList& list) : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) { // copy caller's parameter list to initial registers. JSValues::iterator dest = mRegisters.begin(); *dest++ = thisArg; const JSValues& params = caller->mRegisters; - for (RegisterList::const_iterator src = list.begin(), + for (ArgumentList::const_iterator src = list.begin(), end = list.end(); src != end; ++src, ++dest) { - *dest = params[(*src).first]; + *dest = params[(*src).first.first]; } } @@ -593,6 +593,16 @@ const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, return JSValue((*candidate)->function); } + +bool Context::hasNamedArguments(ArgumentList &args) +{ + Argument* e = args.end(); + for (ArgumentList::iterator r = args.begin(); r != e; r++) { + if ((*r).second) return true; + } + return false; +} + JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) { assert(mActivation == 0); /* recursion == bad */ @@ -666,13 +676,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (!target) throw new JSException("Call to non callable object"); if (target->isNative()) { - RegisterList ¶ms = op4(call); + ArgumentList ¶ms = op4(call); JSValues argv(params.size() + 1); argv[0] = (*registers)[op3(call).first]; JSValues::size_type i = 1; - for (RegisterList::const_iterator src = params.begin(), end = params.end(); + for (ArgumentList::const_iterator src = params.begin(), end = params.end(); src != end; ++src, ++i) { - argv[i] = (*registers)[src->first]; + argv[i] = (*registers)[src->first.first]; } JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) @@ -680,11 +690,56 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) break; } else { - mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, op1(call)); - mActivation = new Activation(target->getICode(), mActivation, (*registers)[op3(call).first], op4(call)); + ICodeModule *icm = target->getICode(); + ArgumentList &args = op4(call); + ArgumentList newArgs(args.size()); + uint32 argCount = args.size() + 1; // the 'this' arg is travelling separately + + if (hasNamedArguments(args)) { + // find argument names that match parameter names + for (uint32 a = 0; a < args.size(); a++) { + if (args[a].second) { + VariableList::iterator i = icm->itsVariables->find(*(args[a].second)); + if (i != icm->itsVariables->end()) { + TypedRegister r = (*i).second; + if (r.first < icm->mParameterCount) { // make sure we didn't match a local var + // the named argument is arriving in slot a, but needs to be r instead + newArgs[r.first - 1] = Argument(args[a].first, NULL); + } + + } + } + } + args = newArgs; + } + uint32 pOffset = icm->mEntryPoint; + if (argCount < icm->mNonOptionalParameterCount) + throw new JSException("Too few arguments in call"); + if (argCount >= icm->mParameterCount) { + if (icm->mHasRestParameter) { + if (icm->mHasNamedRestParameter) { + uint32 restArgsCount = argCount - icm->mParameterCount + 1; + uint32 restArgsStart = icm->mParameterCount - 2; // 1 for 'this', 1 for 0-based + JSArray *r = new JSArray(restArgsCount); + for (uint32 i = 0; i < restArgsCount; i++) + (*r)[i] = (*registers)[args[i + restArgsStart].first.first]; + (*registers)[args[restArgsStart].first.first] = r; + } + // else, we just ignore the other arguments + } + else { + if (argCount > icm->mParameterCount) + throw new JSException("Too many arguments in call"); + } + } + else { + if (argCount < icm->mParameterCount) + pOffset = icm->mParameterInit[argCount - icm->mNonOptionalParameterCount]; + } + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call)); + mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], args); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); + mPC = mActivation->mICode->its_iCode->begin() + pOffset; endPC = mActivation->mICode->its_iCode->end(); continue; } @@ -695,12 +750,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) DirectCall* call = static_cast(instruction); JSFunction *target = op2(call); if (target->isNative()) { - RegisterList ¶ms = op3(call); + ArgumentList ¶ms = op3(call); JSValues argv(params.size() + 1); JSValues::size_type i = 1; - for (RegisterList::const_iterator src = params.begin(), end = params.end(); + for (ArgumentList::const_iterator src = params.begin(), end = params.end(); src != end; ++src, ++i) { - argv[i] = (*registers)[src->first]; + argv[i] = (*registers)[src->first.first]; } JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) @@ -799,7 +854,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case NEW_FUNCTION: { NewFunction* nf = static_cast(instruction); - (*registers)[dst(nf).first] = new JSFunction(src1(nf)); + (*registers)[dst(nf).first] = new JSFunction(src1(nf), src2(nf)); } break; case NEW_ARRAY: @@ -1380,7 +1435,7 @@ using JSString throughout. } } - + mActivation = 0; return rv; } /* interpret */ diff --git a/mozilla/js/js2/interpreter.h b/mozilla/js/js2/interpreter.h index 11c0b50954d..a9a085b7dbf 100644 --- a/mozilla/js/js2/interpreter.h +++ b/mozilla/js/js2/interpreter.h @@ -90,6 +90,7 @@ namespace Interpreter { private: void broadcast(Event event); void initOperatorsPackage(); + bool hasNamedArguments(ArgumentList &args); private: World& mWorld; diff --git a/mozilla/js/js2/jstypes.cpp b/mozilla/js/js2/jstypes.cpp index b7ca507f3d0..7127819f98b 100644 --- a/mozilla/js/js2/jstypes.cpp +++ b/mozilla/js/js2/jstypes.cpp @@ -125,7 +125,7 @@ static JSValue function_constructor(Context *cx, const JSValues& argv) source.append(JSValue::valueToString(argv[argv.size() - 1]).string); source.append("}"); - JSFunction *f = new JSFunction(cx->compileFunction(source)); + JSFunction *f = new JSFunction(cx->compileFunction(source), NULL); f->setProperty(widenCString("length"), JSValue(parameterCount)); JSObject *obj = new JSObject(); f->setProperty(widenCString("prototype"), JSValue(obj)); @@ -496,11 +496,20 @@ Formatter& operator<<(Formatter& f, const JSValue& value) printFormat(f, "Object @ 0x%08X\n", value.object); f << *value.object; break; - case JSValue::array_tag: - printFormat(f, "Array @ 0x%08X", value.object); + case JSValue::array_tag: { + JSArray *a = value.array; + f << "["; + for (uint32 i = 0; i < a->length(); i++) { + f << (*a)[i]; + if (i < (a->length() - 1)) + f << ", "; + } + f << "]"; +// printFormat(f, "Array @ 0x%08X", value.array); + } break; case JSValue::function_tag: - printFormat(f, "Function @ 0x%08X", value.object); + printFormat(f, "Function @ 0x%08X", value.function); break; case JSValue::string_tag: f << "\"" << *value.string << "\""; diff --git a/mozilla/js/js2/jstypes.h b/mozilla/js/js2/jstypes.h index ea3142056cf..1b1333378a0 100644 --- a/mozilla/js/js2/jstypes.h +++ b/mozilla/js/js2/jstypes.h @@ -36,6 +36,7 @@ #include "utilities.h" #include "gc_allocator.h" +#include "parser.h" #include #include #include @@ -205,18 +206,18 @@ namespace JSTypes { extern const JSValue kPositiveInfinity; // JS2 predefined types: - extern JSType Any_Type; - extern JSType Integer_Type; - extern JSType Number_Type; - extern JSType Character_Type; - extern JSType String_Type; - extern JSType Function_Type; - extern JSType Array_Type; - extern JSType Type_Type; - extern JSType Boolean_Type; - extern JSType Null_Type; - extern JSType Void_Type; - extern JSType None_Type; + extern JSType Any_Type; + extern JSType Integer_Type; + extern JSType Number_Type; + extern JSType Character_Type; + extern JSType String_Type; + extern JSType Function_Type; + extern JSType Array_Type; + extern JSType Type_Type; + extern JSType Boolean_Type; + extern JSType Null_Type; + extern JSType Void_Type; + extern JSType None_Type; // JS1X heritage classes as types: extern JSType Object_Type; @@ -423,8 +424,12 @@ namespace JSTypes { static JSString* FunctionString; static JSObject* FunctionPrototypeObject; ICodeModule* mICode; + + uint32 mParameterCount; + bool mParameterInfo; + protected: - JSFunction() : mICode(0) {} + JSFunction() : mICode(0), mParameterCount(0) {} typedef JavaScript::gc_traits_finalizable traits; typedef gc_allocator allocator; @@ -432,13 +437,21 @@ namespace JSTypes { public: static void initFunctionObject(JSScope *g); - JSFunction(ICodeModule* iCode) + JSFunction(ICodeModule* iCode, FunctionDefinition *def) : JSObject(FunctionPrototypeObject), - mICode(iCode) + mICode(iCode), mParameterCount(0), mParameterInfo(false) { setClass(FunctionString); + if (def) { + mParameterInfo = true; + VariableBinding *p = def->parameters; + while (p) { mParameterCount++; p = p->next; } + } } + uint32 getParameterCount() { return mParameterCount; } + bool hasParameterInfo() { return mParameterInfo; } + ~JSFunction(); void* operator new(size_t) { return allocator::allocate(1); } @@ -547,9 +560,9 @@ namespace JSTypes { return result; } - JSValue& defineFunction(const String& name, ICodeModule* iCode) + JSValue& defineFunction(const String& name, ICodeModule* iCode, FunctionDefinition *def) { - JSValue value(new JSFunction(iCode)); + JSValue value(new JSFunction(iCode, def)); return defineVariable(name, &Function_Type, value); } diff --git a/mozilla/js/js2/vmtypes.cpp b/mozilla/js/js2/vmtypes.cpp index b0fa2a92e6d..f40659417e2 100644 --- a/mozilla/js/js2/vmtypes.cpp +++ b/mozilla/js/js2/vmtypes.cpp @@ -47,13 +47,13 @@ Formatter& operator<< (Formatter& f, Instruction& i) return i.print(f); } -Formatter& operator<< (Formatter& f, RegisterList& rl) +Formatter& operator<< (Formatter& f, ArgumentList& rl) { - TypedRegister* e = rl.end(); + Argument* e = rl.end(); f << "("; - for (RegisterList::iterator r = rl.begin(); r != e; r++) { - f << "R" << r->first; + for (ArgumentList::iterator r = rl.begin(); r != e; r++) { + f << "R" << r->first.first; if ((r + 1) != e) f << ", "; } @@ -64,16 +64,16 @@ Formatter& operator<< (Formatter& f, RegisterList& rl) Formatter& operator<< (Formatter& f, const ArgList& al) { - const RegisterList& rl = al.mList; + const ArgumentList& rl = al.mList; const JSValues& registers = al.mRegisters; f << "("; - RegisterList::const_iterator i = rl.begin(), e = rl.end(); + ArgumentList::const_iterator i = rl.begin(), e = rl.end(); if (i != e) { - TypedRegister r = *i++; - f << "R" << r.first << '=' << registers[r.first]; + Argument r = *i++; + f << "R" << r.first.first << '=' << registers[r.first.first]; while (i != e) { r = *i++; - f << ", R" << r.first << '=' << registers[r.first]; + f << ", R" << r.first << '=' << registers[r.first.first]; } } f << ")"; diff --git a/mozilla/js/js2/vmtypes.h b/mozilla/js/js2/vmtypes.h index 43dac818849..68f1bc63cb5 100644 --- a/mozilla/js/js2/vmtypes.h +++ b/mozilla/js/js2/vmtypes.h @@ -86,7 +86,8 @@ namespace VM { /********************************************************************/ typedef std::pair TypedRegister; - typedef std::vector RegisterList; + typedef std::pair Argument; + typedef std::vector ArgumentList; typedef std::vector InstructionStream; typedef InstructionStream::iterator InstructionIterator; typedef std::map > VariableMap; @@ -96,16 +97,16 @@ namespace VM { * Helper to print Call operands. */ struct ArgList { - const RegisterList& mList; + const ArgumentList& mList; const JSValues& mRegisters; - ArgList(const RegisterList& rl, const JSValues& registers) + ArgList(const ArgumentList& rl, const JSValues& registers) : mList(rl), mRegisters(registers) {} }; /********************************************************************/ Formatter& operator<< (Formatter& f, Instruction& i); - Formatter& operator<< (Formatter& f, RegisterList& rl); + Formatter& operator<< (Formatter& f, ArgumentList& rl); Formatter& operator<< (Formatter& f, const ArgList& al); Formatter& operator<< (Formatter& f, InstructionStream& is); Formatter& operator<< (Formatter& f, TypedRegister& r); diff --git a/mozilla/js2/src/icode.h b/mozilla/js2/src/icode.h index eb934525239..ad34f49c45a 100644 --- a/mozilla/js2/src/icode.h +++ b/mozilla/js2/src/icode.h @@ -41,7 +41,7 @@ NEGATE, /* dest, source */ NEW_ARRAY, /* dest */ NEW_CLASS, /* dest, class */ - NEW_FUNCTION, /* dest, ICodeModule */ + NEW_FUNCTION, /* dest, ICodeModule, Function Definition */ NEW_OBJECT, /* dest, constructor */ NOP, /* do nothing and like it */ NOT, /* dest, source */ @@ -143,11 +143,11 @@ /* print() and printOperands() inherited from GenericBranch */ }; - class Call : public Instruction_4 { + class Call : public Instruction_4 { public: /* result, target, this, args */ - Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, RegisterList aOp4) : - Instruction_4 + Call (TypedRegister aOp1, TypedRegister aOp2, TypedRegister aOp3, ArgumentList aOp4) : + Instruction_4 (CALL, aOp1, aOp2, aOp3, aOp4) {}; virtual Formatter& print(Formatter& f) { f << opcodeNames[CALL] << "\t" << mOp1 << ", " << mOp2 << ", " << mOp3 << ", " << mOp4; @@ -269,11 +269,11 @@ } }; - class DirectCall : public Instruction_3 { + class DirectCall : public Instruction_3 { public: /* result, target, args */ - DirectCall (TypedRegister aOp1, JSFunction * aOp2, RegisterList aOp3) : - Instruction_3 + DirectCall (TypedRegister aOp1, JSFunction * aOp2, ArgumentList aOp3) : + Instruction_3 (DIRECT_CALL, aOp1, aOp2, aOp3) {}; virtual Formatter& print(Formatter& f) { f << opcodeNames[DIRECT_CALL] << "\t" << mOp1 << ", " << "JSFunction" << ", " << mOp3; @@ -583,14 +583,14 @@ } }; - class NewFunction : public Instruction_2 { + class NewFunction : public Instruction_3 { public: - /* dest, ICodeModule */ - NewFunction (TypedRegister aOp1, ICodeModule* aOp2) : - Instruction_2 - (NEW_FUNCTION, aOp1, aOp2) {}; + /* dest, ICodeModule, Function Definition */ + NewFunction (TypedRegister aOp1, ICodeModule* aOp2, FunctionDefinition* aOp3) : + Instruction_3 + (NEW_FUNCTION, aOp1, aOp2, aOp3) {}; virtual Formatter& print(Formatter& f) { - f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule"; + f << opcodeNames[NEW_FUNCTION] << "\t" << mOp1 << ", " << "ICodeModule" << ", " << "FunctionDefinition"; return f; } virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { diff --git a/mozilla/js2/src/icodegenerator.cpp b/mozilla/js2/src/icodegenerator.cpp index 4ec254d82b9..ceec514d1dc 100644 --- a/mozilla/js2/src/icodegenerator.cpp +++ b/mozilla/js2/src/icodegenerator.cpp @@ -79,7 +79,10 @@ ICodeGenerator::ICodeGenerator(World *world, JSScope *global, JSClass *aClass, I mGlobal(global), mInstructionMap(new InstructionMap()), mClass(aClass), - mFlags(flags) + mFlags(flags), + pLabels(NULL), + mHasRestParameter(false), + mHasNamedRestParameter(false) { iCode = new InstructionStream(); iCodeOwner = true; @@ -171,7 +174,23 @@ ICodeModule *ICodeGenerator::complete() } } */ - ICodeModule* module = new ICodeModule(iCode, variableList, mPermanentRegister.size(), 0, mInstructionMap); + ICodeModule* module = new ICodeModule(iCode, + variableList, + mPermanentRegister.size(), + mParameterCount, + mInstructionMap, + mHasRestParameter, + mHasNamedRestParameter); + if (pLabels) { + uint32 i; + uint32 parameterInits = pLabels->size() - 1; // there's an extra label at the end for the actual entryPoint + module->mNonOptionalParameterCount -= parameterInits; + module->mParameterInit = new uint32[parameterInits]; + for (i = 0; i < parameterInits; i++) { + module->mParameterInit[i] = (*pLabels)[i]->mOffset; + } + module->mEntryPoint = (*pLabels)[i]->mOffset; + } iCodeOwner = false; // give ownership to the module. return module; } @@ -227,10 +246,10 @@ TypedRegister ICodeGenerator::newClass(JSClass *clazz) return dest; } -TypedRegister ICodeGenerator::newFunction(ICodeModule *icm) +TypedRegister ICodeGenerator::newFunction(ICodeModule *icm, FunctionDefinition *def) { TypedRegister dest(getTempRegister(), &Function_Type); - NewFunction *instr = new NewFunction(dest, icm); + NewFunction *instr = new NewFunction(dest, icm, def); iCode->push_back(instr); return dest; } @@ -458,7 +477,7 @@ TypedRegister ICodeGenerator::binaryOp(ICodeOp op, TypedRegister source1, return dest; } -TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, RegisterList *args) +TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, ArgumentList *args) { TypedRegister dest(getTempRegister(), &Any_Type); Call *instr = new Call(dest, target, thisArg, *args); @@ -466,7 +485,7 @@ TypedRegister ICodeGenerator::call(TypedRegister target, TypedRegister thisArg, return dest; } -TypedRegister ICodeGenerator::directCall(JSFunction *target, RegisterList *args) +TypedRegister ICodeGenerator::directCall(JSFunction *target, ArgumentList *args) { TypedRegister dest(getTempRegister(), &Any_Type); DirectCall *instr = new DirectCall(dest, target, *args); @@ -537,10 +556,11 @@ Label *ICodeGenerator::getLabel() return labels.back(); } -void ICodeGenerator::setLabel(Label *l) +Label *ICodeGenerator::setLabel(Label *l) { l->mBase = iCode; l->mOffset = iCode->size(); + return l; } /************************************************************************/ @@ -711,7 +731,7 @@ ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &n return Name; } -TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args) +TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args) { ASSERT(p->getKind() == ExprNode::identifier); @@ -836,26 +856,28 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: NOT_REACHED("Bad lvalue kind"); } break; - case ExprNode::call: - switch (lValueKind) { - case Var: - ret = call(v, TypedRegister(NotARegister, &Null_Type), args); - break; - case Name: - ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args); - break; - case Method: - ret = call(getMethod(thisBase, slotIndex), thisBase, args); - break; - case Static: - ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args); - break; - case Constructor: - ret = newClass(mClass); - call(getStatic(mClass, name), ret, args); - break; - default: - NOT_REACHED("Bad lvalue kind"); + case ExprNode::call: + { + switch (lValueKind) { + case Var: + ret = call(v, TypedRegister(NotARegister, &Null_Type), args); + break; + case Name: + ret = call(loadName(name), TypedRegister(NotARegister, &Null_Type), args); + break; + case Method: + ret = call(getMethod(thisBase, slotIndex), thisBase, args); + break; + case Static: + ret = call(getStatic(mClass, name), TypedRegister(NotARegister, &Null_Type), args); + break; + case Constructor: + ret = newClass(mClass); + call(getStatic(mClass, name), ret, args); + break; + default: + NOT_REACHED("Bad lvalue kind"); + } } break; default: @@ -865,7 +887,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: } -TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, RegisterList *args) +TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args) { ASSERT(b->getKind() == ExprNode::dot); @@ -1095,10 +1117,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::New: { InvokeExprNode *i = static_cast(p); - RegisterList args; + ArgumentList args; ExprPairList *p = i->pairs; while (p) { - args.push_back(genExpr(p->value)); + if (p->field && (p->field->getKind() == ExprNode::identifier)) + args.push_back(Argument(genExpr(p->value), &(static_cast(p->field))->name)); + else + args.push_back(Argument(genExpr(p->value), NULL )); p = p->next; } if (i->op->getKind() == ExprNode::identifier) { @@ -1145,10 +1170,13 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, case ExprNode::call : { InvokeExprNode *i = static_cast(p); - RegisterList args; + ArgumentList args; ExprPairList *p = i->pairs; while (p) { - args.push_back(genExpr(p->value)); + if (p->field && (p->field->getKind() == ExprNode::identifier)) + args.push_back(Argument(genExpr(p->value), &(static_cast(p->field))->name)); + else + args.push_back(Argument(genExpr(p->value), NULL )); p = p->next; } @@ -1498,7 +1526,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, icg.genStmt(f->function.body); //stdOut << icg; ICodeModule *icm = icg.complete(); - ret = newFunction(icm); + ret = newFunction(icm, &f->function); } break; @@ -1555,6 +1583,17 @@ static bool hasAttribute(const IdentifierList* identifiers, Token::Kind tokenKin return false; } +JSType *ICodeGenerator::extractType(ExprNode *t) +{ + JSType* type = &Any_Type; + // FIXME: need to do code generation for type expressions. + if (t && (t->getKind() == ExprNode::identifier)) { + IdentifierExprNode* typeExpr = static_cast(t); + type = findType(typeExpr->name); + } + return type; +} + ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass) { bool isStatic = hasAttribute(f->attributes, Token::Static); @@ -1564,13 +1603,47 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor icg.allocateParameter(mWorld->identifiers["this"], (mClass) ? mClass : &Any_Type); // always parameter #0 VariableBinding *v = f->function.parameters; while (v) { - if (v->name && (v->name->getKind() == ExprNode::identifier)) - icg.allocateParameter((static_cast(v->name))->name); + if (v->name && (v->name->getKind() == ExprNode::identifier)) { + JSType *pType; + if ((v == f->function.restParameter) && (v->type == NULL)) + pType = &Array_Type; + else + pType = extractType(v->type); + icg.allocateParameter((static_cast(v->name))->name, pType); + } + else + NOT_REACHED("qualified or un-named parameters not handled; bugger off."); v = v->next; } + v = f->function.optParameters; + if (v) { + while (v) { // include the rest parameter, as it may have an initializer + if (v->name && (v->name->getKind() == ExprNode::identifier)) { + icg.addParameterLabel(icg.setLabel(icg.getLabel())); + if (v->initializer) { // might be NULL when we get to the restParameter + TypedRegister p = icg.genExpr(v->name); + icg.move(p, icg.genExpr(v->initializer)); + } + } + v = v->next; + } + icg.addParameterLabel(icg.setLabel(icg.getLabel())); // to provide the entry-point for the default case + } + v = f->function.restParameter; + if (v) { + icg.mHasRestParameter = true; + if (v->name && (v->name->getKind() == ExprNode::identifier)) { + icg.mHasNamedRestParameter = true; + } + } if (isConstructor) { + /* + See if the first statement is an expression statement consisting + of a call to super(). If not we need to add a call to the default + superclass constructor ourselves. + */ TypedRegister thisValue = TypedRegister(0, mClass); - RegisterList args; + ArgumentList args; if (superclass) { bool foundSuperCall = false; BlockStmtNode *b = f->function.body; @@ -1664,12 +1737,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (v->name) { ASSERT(v->name->getKind() == ExprNode::identifier); IdentifierExprNode* idExpr = static_cast(v->name); - JSType* type = &Any_Type; - // FIXME: need to do code generation for type expressions. - if (v->type && v->type->getKind() == ExprNode::identifier) { - IdentifierExprNode* typeExpr = static_cast(v->type); - type = findType(typeExpr->name); - } + JSType* type = extractType(v->type); if (isStatic) { thisClass->defineStatic(idExpr->name, type); if (v->initializer) { @@ -1705,15 +1773,15 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (name == nameExpr->name) hasDefaultConstructor = true; thisClass->defineConstructor(name); - scg.setStatic(thisClass, name, scg.newFunction(icm)); + scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function)); } else if (isStatic) { thisClass->defineStatic(name, &Function_Type); - scg.setStatic(thisClass, name, scg.newFunction(icm)); + scg.setStatic(thisClass, name, scg.newFunction(icm, &f->function)); } else - thisClass->defineMethod(name, new JSFunction(icm)); + thisClass->defineMethod(name, new JSFunction(icm, &f->function)); } } break; @@ -1725,12 +1793,12 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) } // add the instance initializer - scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete())); + scg.setStatic(thisClass, initName, scg.newFunction(ccg.complete(), NULL)); // 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; + ArgumentList args; ICodeGenerator icg(mWorld, thisScope, thisClass, kIsStaticMethod); icg.allocateParameter(mWorld->identifiers["this"], thisClass); // always parameter #0 if (superclass) @@ -1738,7 +1806,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) icg.call(icg.getStatic(thisClass, initName), thisValue, &args); icg.returnStmt(thisValue); thisClass->defineConstructor(nameExpr->name); - scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete())); + scg.setStatic(thisClass, nameExpr->name, scg.newFunction(icg.complete(), NULL)); } // freeze the class. thisClass->complete(); @@ -1760,7 +1828,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) 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); + mGlobal->defineFunction(name, icm, &f->function); } } break; diff --git a/mozilla/js2/src/icodegenerator.h b/mozilla/js2/src/icodegenerator.h index 6415dee318b..229df639530 100644 --- a/mozilla/js2/src/icodegenerator.h +++ b/mozilla/js2/src/icodegenerator.h @@ -58,15 +58,25 @@ namespace ICG { public: ICodeModule(InstructionStream *iCode, VariableList *variables, uint32 maxRegister, uint32 maxParameter, - InstructionMap *instructionMap) : + InstructionMap *instructionMap, + bool hasRestParameter, bool hasNamedRestParameter) : its_iCode(iCode), itsVariables(variables), - itsParameterCount(maxParameter), itsMaxRegister(maxRegister), - mID(++sMaxID), mInstructionMap(instructionMap) { } + mParameterCount(maxParameter), itsMaxRegister(maxRegister), + mID(++sMaxID), mInstructionMap(instructionMap), + mParameterInit(NULL), + mNonOptionalParameterCount(maxParameter), + mEntryPoint(0), + mHasRestParameter(hasRestParameter), + mHasNamedRestParameter(hasNamedRestParameter) + { + } + ~ICodeModule() { delete its_iCode; delete itsVariables; delete mInstructionMap; + if (mParameterInit) delete mParameterInit; } Formatter& print(Formatter& f); @@ -75,11 +85,16 @@ namespace ICG { InstructionStream *its_iCode; VariableList *itsVariables; - uint32 itsParameterCount; + uint32 mParameterCount; uint32 itsMaxRegister; uint32 mID; InstructionMap *mInstructionMap; String mFileName; + uint32 *mParameterInit; + uint32 mNonOptionalParameterCount; + uint32 mEntryPoint; + bool mHasRestParameter; + bool mHasNamedRestParameter; static uint32 sMaxID; @@ -132,6 +147,9 @@ namespace ICG { JSClass *mClass; // enclosing class when generating code for methods ICodeGeneratorFlags mFlags; // assorted flags + LabelList *pLabels; // label for each parameter initialization entry point + bool mHasRestParameter; // true if this function has a ... parameter + bool mHasNamedRestParameter; // true if this function has a named ... parameter std::vector mPermanentRegister; @@ -155,13 +173,14 @@ namespace ICG { void setRegisterForVariable(const StringAtom& name, TypedRegister r) { (*variableList)[name] = r; } JSType *findType(const StringAtom& typeName); + JSType *extractType(ExprNode *t); + void addParameterLabel(Label *label) { if (pLabels == NULL) pLabels = new LabelList(); pLabels->push_back(label); } - - void setLabel(Label *label); + Label *setLabel(Label *label); void jsr(Label *label) { iCode->push_back(new Jsr(label)); } void rts() { iCode->push_back(new Rts()); } @@ -193,8 +212,8 @@ namespace ICG { typedef enum {Var, Property, Slot, Static, Constructor, Name, Method} LValueKind; LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex); - 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); + TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args); + TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args); ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass); public: @@ -206,6 +225,7 @@ namespace ICG { if (iCodeOwner) { delete iCode; delete mInstructionMap; + if (pLabels) delete pLabels; } } @@ -242,8 +262,8 @@ 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 base, TypedRegister target, RegisterList *args); - TypedRegister directCall(JSFunction *target, RegisterList *args); + TypedRegister call(TypedRegister base, TypedRegister target, ArgumentList *args); + TypedRegister directCall(JSFunction *target, ArgumentList *args); TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex); void move(TypedRegister destination, TypedRegister source); @@ -257,7 +277,7 @@ namespace ICG { TypedRegister newObject(TypedRegister constructor); TypedRegister newArray(); - TypedRegister newFunction(ICodeModule *icm); + TypedRegister newFunction(ICodeModule *icm, FunctionDefinition *def); TypedRegister newClass(JSClass *clazz); TypedRegister cast(TypedRegister arg, JSType *toType); diff --git a/mozilla/js2/src/interpreter.cpp b/mozilla/js2/src/interpreter.cpp index 1a045316cfe..8d3eea8fde8 100644 --- a/mozilla/js2/src/interpreter.cpp +++ b/mozilla/js2/src/interpreter.cpp @@ -96,16 +96,16 @@ struct Activation : public gc_base { } Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg, - const RegisterList& list) + const ArgumentList& list) : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) { // copy caller's parameter list to initial registers. JSValues::iterator dest = mRegisters.begin(); *dest++ = thisArg; const JSValues& params = caller->mRegisters; - for (RegisterList::const_iterator src = list.begin(), + for (ArgumentList::const_iterator src = list.begin(), end = list.end(); src != end; ++src, ++dest) { - *dest = params[(*src).first]; + *dest = params[(*src).first.first]; } } @@ -593,6 +593,16 @@ const JSValue Context::findBinaryOverride(JSValue &operand1, JSValue &operand2, return JSValue((*candidate)->function); } + +bool Context::hasNamedArguments(ArgumentList &args) +{ + Argument* e = args.end(); + for (ArgumentList::iterator r = args.begin(); r != e; r++) { + if ((*r).second) return true; + } + return false; +} + JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) { assert(mActivation == 0); /* recursion == bad */ @@ -666,13 +676,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (!target) throw new JSException("Call to non callable object"); if (target->isNative()) { - RegisterList ¶ms = op4(call); + ArgumentList ¶ms = op4(call); JSValues argv(params.size() + 1); argv[0] = (*registers)[op3(call).first]; JSValues::size_type i = 1; - for (RegisterList::const_iterator src = params.begin(), end = params.end(); + for (ArgumentList::const_iterator src = params.begin(), end = params.end(); src != end; ++src, ++i) { - argv[i] = (*registers)[src->first]; + argv[i] = (*registers)[src->first.first]; } JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) @@ -680,11 +690,56 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) break; } else { - mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, op1(call)); - mActivation = new Activation(target->getICode(), mActivation, (*registers)[op3(call).first], op4(call)); + ICodeModule *icm = target->getICode(); + ArgumentList &args = op4(call); + ArgumentList newArgs(args.size()); + uint32 argCount = args.size() + 1; // the 'this' arg is travelling separately + + if (hasNamedArguments(args)) { + // find argument names that match parameter names + for (uint32 a = 0; a < args.size(); a++) { + if (args[a].second) { + VariableList::iterator i = icm->itsVariables->find(*(args[a].second)); + if (i != icm->itsVariables->end()) { + TypedRegister r = (*i).second; + if (r.first < icm->mParameterCount) { // make sure we didn't match a local var + // the named argument is arriving in slot a, but needs to be r instead + newArgs[r.first - 1] = Argument(args[a].first, NULL); + } + + } + } + } + args = newArgs; + } + uint32 pOffset = icm->mEntryPoint; + if (argCount < icm->mNonOptionalParameterCount) + throw new JSException("Too few arguments in call"); + if (argCount >= icm->mParameterCount) { + if (icm->mHasRestParameter) { + if (icm->mHasNamedRestParameter) { + uint32 restArgsCount = argCount - icm->mParameterCount + 1; + uint32 restArgsStart = icm->mParameterCount - 2; // 1 for 'this', 1 for 0-based + JSArray *r = new JSArray(restArgsCount); + for (uint32 i = 0; i < restArgsCount; i++) + (*r)[i] = (*registers)[args[i + restArgsStart].first.first]; + (*registers)[args[restArgsStart].first.first] = r; + } + // else, we just ignore the other arguments + } + else { + if (argCount > icm->mParameterCount) + throw new JSException("Too many arguments in call"); + } + } + else { + if (argCount < icm->mParameterCount) + pOffset = icm->mParameterInit[argCount - icm->mNonOptionalParameterCount]; + } + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call)); + mActivation = new Activation(icm, mActivation, (*registers)[op3(call).first], args); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); + mPC = mActivation->mICode->its_iCode->begin() + pOffset; endPC = mActivation->mICode->its_iCode->end(); continue; } @@ -695,12 +750,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) DirectCall* call = static_cast(instruction); JSFunction *target = op2(call); if (target->isNative()) { - RegisterList ¶ms = op3(call); + ArgumentList ¶ms = op3(call); JSValues argv(params.size() + 1); JSValues::size_type i = 1; - for (RegisterList::const_iterator src = params.begin(), end = params.end(); + for (ArgumentList::const_iterator src = params.begin(), end = params.end(); src != end; ++src, ++i) { - argv[i] = (*registers)[src->first]; + argv[i] = (*registers)[src->first.first]; } JSValue result = static_cast(target)->mCode(this, argv); if (op1(call).first != NotARegister) @@ -799,7 +854,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) case NEW_FUNCTION: { NewFunction* nf = static_cast(instruction); - (*registers)[dst(nf).first] = new JSFunction(src1(nf)); + (*registers)[dst(nf).first] = new JSFunction(src1(nf), src2(nf)); } break; case NEW_ARRAY: @@ -1380,7 +1435,7 @@ using JSString throughout. } } - + mActivation = 0; return rv; } /* interpret */ diff --git a/mozilla/js2/src/interpreter.h b/mozilla/js2/src/interpreter.h index 11c0b50954d..a9a085b7dbf 100644 --- a/mozilla/js2/src/interpreter.h +++ b/mozilla/js2/src/interpreter.h @@ -90,6 +90,7 @@ namespace Interpreter { private: void broadcast(Event event); void initOperatorsPackage(); + bool hasNamedArguments(ArgumentList &args); private: World& mWorld; diff --git a/mozilla/js2/src/jstypes.cpp b/mozilla/js2/src/jstypes.cpp index b7ca507f3d0..7127819f98b 100644 --- a/mozilla/js2/src/jstypes.cpp +++ b/mozilla/js2/src/jstypes.cpp @@ -125,7 +125,7 @@ static JSValue function_constructor(Context *cx, const JSValues& argv) source.append(JSValue::valueToString(argv[argv.size() - 1]).string); source.append("}"); - JSFunction *f = new JSFunction(cx->compileFunction(source)); + JSFunction *f = new JSFunction(cx->compileFunction(source), NULL); f->setProperty(widenCString("length"), JSValue(parameterCount)); JSObject *obj = new JSObject(); f->setProperty(widenCString("prototype"), JSValue(obj)); @@ -496,11 +496,20 @@ Formatter& operator<<(Formatter& f, const JSValue& value) printFormat(f, "Object @ 0x%08X\n", value.object); f << *value.object; break; - case JSValue::array_tag: - printFormat(f, "Array @ 0x%08X", value.object); + case JSValue::array_tag: { + JSArray *a = value.array; + f << "["; + for (uint32 i = 0; i < a->length(); i++) { + f << (*a)[i]; + if (i < (a->length() - 1)) + f << ", "; + } + f << "]"; +// printFormat(f, "Array @ 0x%08X", value.array); + } break; case JSValue::function_tag: - printFormat(f, "Function @ 0x%08X", value.object); + printFormat(f, "Function @ 0x%08X", value.function); break; case JSValue::string_tag: f << "\"" << *value.string << "\""; diff --git a/mozilla/js2/src/jstypes.h b/mozilla/js2/src/jstypes.h index ea3142056cf..1b1333378a0 100644 --- a/mozilla/js2/src/jstypes.h +++ b/mozilla/js2/src/jstypes.h @@ -36,6 +36,7 @@ #include "utilities.h" #include "gc_allocator.h" +#include "parser.h" #include #include #include @@ -205,18 +206,18 @@ namespace JSTypes { extern const JSValue kPositiveInfinity; // JS2 predefined types: - extern JSType Any_Type; - extern JSType Integer_Type; - extern JSType Number_Type; - extern JSType Character_Type; - extern JSType String_Type; - extern JSType Function_Type; - extern JSType Array_Type; - extern JSType Type_Type; - extern JSType Boolean_Type; - extern JSType Null_Type; - extern JSType Void_Type; - extern JSType None_Type; + extern JSType Any_Type; + extern JSType Integer_Type; + extern JSType Number_Type; + extern JSType Character_Type; + extern JSType String_Type; + extern JSType Function_Type; + extern JSType Array_Type; + extern JSType Type_Type; + extern JSType Boolean_Type; + extern JSType Null_Type; + extern JSType Void_Type; + extern JSType None_Type; // JS1X heritage classes as types: extern JSType Object_Type; @@ -423,8 +424,12 @@ namespace JSTypes { static JSString* FunctionString; static JSObject* FunctionPrototypeObject; ICodeModule* mICode; + + uint32 mParameterCount; + bool mParameterInfo; + protected: - JSFunction() : mICode(0) {} + JSFunction() : mICode(0), mParameterCount(0) {} typedef JavaScript::gc_traits_finalizable traits; typedef gc_allocator allocator; @@ -432,13 +437,21 @@ namespace JSTypes { public: static void initFunctionObject(JSScope *g); - JSFunction(ICodeModule* iCode) + JSFunction(ICodeModule* iCode, FunctionDefinition *def) : JSObject(FunctionPrototypeObject), - mICode(iCode) + mICode(iCode), mParameterCount(0), mParameterInfo(false) { setClass(FunctionString); + if (def) { + mParameterInfo = true; + VariableBinding *p = def->parameters; + while (p) { mParameterCount++; p = p->next; } + } } + uint32 getParameterCount() { return mParameterCount; } + bool hasParameterInfo() { return mParameterInfo; } + ~JSFunction(); void* operator new(size_t) { return allocator::allocate(1); } @@ -547,9 +560,9 @@ namespace JSTypes { return result; } - JSValue& defineFunction(const String& name, ICodeModule* iCode) + JSValue& defineFunction(const String& name, ICodeModule* iCode, FunctionDefinition *def) { - JSValue value(new JSFunction(iCode)); + JSValue value(new JSFunction(iCode, def)); return defineVariable(name, &Function_Type, value); } diff --git a/mozilla/js2/src/vmtypes.cpp b/mozilla/js2/src/vmtypes.cpp index b0fa2a92e6d..f40659417e2 100644 --- a/mozilla/js2/src/vmtypes.cpp +++ b/mozilla/js2/src/vmtypes.cpp @@ -47,13 +47,13 @@ Formatter& operator<< (Formatter& f, Instruction& i) return i.print(f); } -Formatter& operator<< (Formatter& f, RegisterList& rl) +Formatter& operator<< (Formatter& f, ArgumentList& rl) { - TypedRegister* e = rl.end(); + Argument* e = rl.end(); f << "("; - for (RegisterList::iterator r = rl.begin(); r != e; r++) { - f << "R" << r->first; + for (ArgumentList::iterator r = rl.begin(); r != e; r++) { + f << "R" << r->first.first; if ((r + 1) != e) f << ", "; } @@ -64,16 +64,16 @@ Formatter& operator<< (Formatter& f, RegisterList& rl) Formatter& operator<< (Formatter& f, const ArgList& al) { - const RegisterList& rl = al.mList; + const ArgumentList& rl = al.mList; const JSValues& registers = al.mRegisters; f << "("; - RegisterList::const_iterator i = rl.begin(), e = rl.end(); + ArgumentList::const_iterator i = rl.begin(), e = rl.end(); if (i != e) { - TypedRegister r = *i++; - f << "R" << r.first << '=' << registers[r.first]; + Argument r = *i++; + f << "R" << r.first.first << '=' << registers[r.first.first]; while (i != e) { r = *i++; - f << ", R" << r.first << '=' << registers[r.first]; + f << ", R" << r.first << '=' << registers[r.first.first]; } } f << ")"; diff --git a/mozilla/js2/src/vmtypes.h b/mozilla/js2/src/vmtypes.h index 43dac818849..68f1bc63cb5 100644 --- a/mozilla/js2/src/vmtypes.h +++ b/mozilla/js2/src/vmtypes.h @@ -86,7 +86,8 @@ namespace VM { /********************************************************************/ typedef std::pair TypedRegister; - typedef std::vector RegisterList; + typedef std::pair Argument; + typedef std::vector ArgumentList; typedef std::vector InstructionStream; typedef InstructionStream::iterator InstructionIterator; typedef std::map > VariableMap; @@ -96,16 +97,16 @@ namespace VM { * Helper to print Call operands. */ struct ArgList { - const RegisterList& mList; + const ArgumentList& mList; const JSValues& mRegisters; - ArgList(const RegisterList& rl, const JSValues& registers) + ArgList(const ArgumentList& rl, const JSValues& registers) : mList(rl), mRegisters(registers) {} }; /********************************************************************/ Formatter& operator<< (Formatter& f, Instruction& i); - Formatter& operator<< (Formatter& f, RegisterList& rl); + Formatter& operator<< (Formatter& f, ArgumentList& rl); Formatter& operator<< (Formatter& f, const ArgList& al); Formatter& operator<< (Formatter& f, InstructionStream& is); Formatter& operator<< (Formatter& f, TypedRegister& r);