From d11b23802a15b6b305c56f3c343a604d3aed49e3 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Fri, 8 Dec 2000 23:55:39 +0000 Subject: [PATCH] Sweeping set of changes to implement closures. Also re-targetted entire front-end to Cobol and back-end now generates pdp11 assembly code in spanish. --- js/js2/icode.h | 36 +++++ js/js2/icodegenerator.cpp | 170 ++++++++++++++--------- js/js2/icodegenerator.h | 14 +- js/js2/icodemap.h | 108 ++++++++------- js/js2/interpreter.cpp | 268 +++++++++++++++++-------------------- js/js2/interpreter.h | 78 ++++++++++- js/js2/jsclasses.h | 17 +++ js/js2/jstypes.h | 18 ++- js/js2/tools/jsicodes.pm | 12 ++ js/js2/vmtypes.h | 4 +- js/js2/winbuild/js2.dsp | 20 +++ js2/src/icode.h | 36 +++++ js2/src/icodegenerator.cpp | 170 ++++++++++++++--------- js2/src/icodegenerator.h | 14 +- js2/src/icodemap.h | 108 ++++++++------- js2/src/interpreter.cpp | 268 +++++++++++++++++-------------------- js2/src/interpreter.h | 78 ++++++++++- js2/src/jsclasses.h | 17 +++ js2/src/jstypes.h | 18 ++- js2/src/vmtypes.h | 4 +- js2/src/winbuild/js2.dsp | 20 +++ js2/tools/jsicodes.pm | 12 ++ 22 files changed, 962 insertions(+), 528 deletions(-) diff --git a/js/js2/icode.h b/js/js2/icode.h index 02780cf1dc88..1f4f0240d42d 100644 --- a/js/js2/icode.h +++ b/js/js2/icode.h @@ -26,6 +26,7 @@ DIVIDE, /* dest, source1, source2 */ ELEM_XCR, /* dest, base, index, value */ GENERIC_BINARY_OP, /* dest, op, source1, source2 */ + GET_CLOSURE, /* dest, closure depth */ GET_ELEMENT, /* dest, base, index */ GET_METHOD, /* result, target base, index */ GET_PROP, /* dest, object, prop name */ @@ -43,6 +44,7 @@ NEGATE, /* dest, source */ NEW_ARRAY, /* dest */ NEW_CLASS, /* dest, class */ + NEW_CLOSURE, /* dest, ICodeModule */ NEW_FUNCTION, /* dest, ICodeModule */ NEW_OBJECT, /* dest, constructor */ NOP, /* do nothing and like it */ @@ -402,6 +404,22 @@ } }; + class GetClosure : public Instruction_2 { + public: + /* dest, closure depth */ + GetClosure (TypedRegister aOp1, uint32 aOp2) : + Instruction_2 + (GET_CLOSURE, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[GET_CLOSURE] << "\t" << mOp1 << ", " << mOp2; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << getRegisterValue(registers, mOp1.first); + return f; + } + }; + class GetElement : public Instruction_3 { public: /* dest, base, index */ @@ -666,6 +684,22 @@ } }; + class NewClosure : public Instruction_2 { + public: + /* dest, ICodeModule */ + NewClosure (TypedRegister aOp1, ICodeModule* aOp2) : + Instruction_2 + (NEW_CLOSURE, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[NEW_CLOSURE] << "\t" << mOp1 << ", " << "ICodeModule"; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << getRegisterValue(registers, mOp1.first); + return f; + } + }; + class NewFunction : public Instruction_2 { public: /* dest, ICodeModule */ @@ -1165,6 +1199,7 @@ "DIVIDE ", "ELEM_XCR ", "GENERIC_BINARY_OP ", + "GET_CLOSURE ", "GET_ELEMENT ", "GET_METHOD ", "GET_PROP ", @@ -1182,6 +1217,7 @@ "NEGATE ", "NEW_ARRAY ", "NEW_CLASS ", + "NEW_CLOSURE ", "NEW_FUNCTION ", "NEW_OBJECT ", "NOP ", diff --git a/js/js2/icodegenerator.cpp b/js/js2/icodegenerator.cpp index 7adcbbf4857f..73f585027a0a 100644 --- a/js/js2/icodegenerator.cpp +++ b/js/js2/icodegenerator.cpp @@ -73,7 +73,7 @@ Formatter& operator<<(Formatter &f, ICodeModule &i) // -ICodeGenerator::ICodeGenerator(Context *cx, JSClass *aClass, ICodeGeneratorFlags flags) +ICodeGenerator::ICodeGenerator(Context *cx, ICodeGenerator *containingFunction, JSClass *aClass, ICodeGeneratorFlags flags) : mTopRegister(0), mExceptionRegister(TypedRegister(NotARegister, &None_Type)), variableList(new VariableList()), @@ -83,7 +83,8 @@ ICodeGenerator::ICodeGenerator(Context *cx, JSClass *aClass, ICodeGeneratorFlags mClass(aClass), mFlags(flags), pLabels(NULL), - mInitName(cx->getWorld().identifiers["__init__"]) + mInitName(cx->getWorld().identifiers["__init__"]), + mContainingFunction(containingFunction) { iCode = new InstructionStream(); iCodeOwner = true; @@ -360,7 +361,6 @@ TypedRegister ICodeGenerator::staticXcr(JSClass *base, const StringAtom &name, I - TypedRegister ICodeGenerator::getSlot(TypedRegister base, uint32 slot) { TypedRegister dest(getTempRegister(), &Any_Type); @@ -498,6 +498,22 @@ TypedRegister ICodeGenerator::bindThis(TypedRegister thisArg, TypedRegister targ return dest; } + +TypedRegister ICodeGenerator::getClosure(uint32 count) +{ + TypedRegister dest(getTempRegister(), &Any_Type); + iCode->push_back(new GetClosure(dest, count)); + return dest; +} + +TypedRegister ICodeGenerator::newClosure(ICodeModule *icm) +{ + TypedRegister dest(getTempRegister(), &Function_Type); + iCode->push_back(new NewClosure(dest, icm)); + return dest; +} + + TypedRegister ICodeGenerator::getMethod(TypedRegister thisArg, uint32 slotIndex) { TypedRegister dest(getTempRegister(), &Any_Type); @@ -735,31 +751,70 @@ static bool isStaticName(JSClass *c, const StringAtom &name, JSType*& type, bool return false; } -ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue) +ICodeGenerator::LValueKind ICodeGenerator::getVariableByName(const StringAtom &name, TypedRegister &v) +{ + v = variableList->findVariable(name); + if (v.first == NotARegister) + v = parameterList->findVariable(name); + if (v.first != NotARegister) + return Var; + return NoKind; +} + +ICodeGenerator::LValueKind ICodeGenerator::scanForVariable(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base) +{ + LValueKind k = getVariableByName(name, v); + if (k == Var) return k; + + uint32 count = 0; + ICodeGenerator *upper = mContainingFunction; + while (upper) { + k = upper->getVariableByName(name, v); + if (k == Var) { + base = getClosure(count); + slotIndex = v.first; + return Slot; + } + count++; + upper = upper->mContainingFunction; + } + return NoKind; +} + +// find 'name' (unqualified) in the current context. +// for local variable, returns v.first = register number +// for slot/method, returns slotIndex and sets base appropriately +// (note closure vars also get handled this way) +// v.second is set to the type regardless +ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base, bool lvalue) { if (!isWithinWith()) { - v = variableList->findVariable(name); - if (v.first == NotARegister) - v = parameterList->findVariable(name); - if (v.first != NotARegister) - return Var; + LValueKind k = scanForVariable(name, v, slotIndex, base); + if (k != NoKind) + return k; else { if (mClass) { // we're compiling a method of a class if (!isStaticMethod()) { - if (isSlotName(mClass, name, slotIndex, v.second, lvalue)) + if (isSlotName(mClass, name, slotIndex, v.second, lvalue)) { + base = TypedRegister(0, mClass); return Slot; - if (isMethodName(mClass, name, slotIndex)) + } + if (isMethodName(mClass, name, slotIndex)) { + base = TypedRegister(0, mClass); return Method; + } } bool isConstructor = false; if (isStaticName(mClass, name, v.second, isConstructor)) { return (isConstructor) ? Constructor : Static; } } + // last chance - if it's a generic name in the global scope, try to get a type for it v.second = mContext->getGlobalObject()->getType(name); return Name; } } + // all bet's off, generic name & type v.second = &Any_Type; return Name; } @@ -771,13 +826,12 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: /*JSType *vType = &Any_Type;*/ uint32 slotIndex; TypedRegister v; + TypedRegister base; const StringAtom &name = (static_cast(p))->name; - LValueKind lValueKind = resolveIdentifier(name, v, slotIndex, lvalue); + LValueKind lValueKind = resolveIdentifier(name, v, slotIndex, base, lvalue); JSType *targetType = v.second; - TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type); - switch (use) { case ExprNode::addEquals: case ExprNode::subtractEquals: @@ -797,7 +851,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: v = loadName(name, v.second); break; case Slot: - v = getSlot(thisBase, slotIndex); + v = getSlot(base, slotIndex); break; case Static: case Constructor: @@ -818,7 +872,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: saveName(name, ret); break; case Slot: - setSlot(thisBase, slotIndex, ret); + setSlot(base, slotIndex, ret); break; case Static: case Constructor: @@ -837,7 +891,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = loadName(name, v.second); break; case Slot: - ret = getSlot(thisBase, slotIndex); + ret = getSlot(base, slotIndex); break; case Static: case Constructor: @@ -859,8 +913,8 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: saveName(name, ret); break; case Slot: - ret = binaryOp(xcrementOp, getSlot(thisBase, slotIndex), loadImmediate(1.0)); - setSlot(thisBase, slotIndex, ret); + ret = binaryOp(xcrementOp, getSlot(base, slotIndex), loadImmediate(1.0)); + setSlot(base, slotIndex, ret); break; case Static: case Constructor: @@ -881,7 +935,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = nameXcr(name, xcrementOp); break; case Slot: - ret = slotXcr(thisBase, slotIndex, xcrementOp); + ret = slotXcr(base, slotIndex, xcrementOp); break; case Static: case Constructor: @@ -901,7 +955,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = call(loadName(name), args); break; case Method: - ret = call(getMethod(thisBase, slotIndex), args); + ret = call(getMethod(base, slotIndex), args); break; case Static: ret = call(getStatic(mClass, name), args); @@ -932,15 +986,20 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I NOT_REACHED("Implement me"); // turns into a getProperty (but not via any overloaded [] ) } else { + // we have . const StringAtom &fieldName = static_cast(b->op2)->name; TypedRegister base; + TypedRegister baseBase; JSClass *clazz = NULL; JSType *fieldType = &Any_Type; uint32 slotIndex; if ((b->op1->getKind() == ExprNode::identifier) && !isWithinWith()) { + // handle . const StringAtom &baseName = (static_cast(b->op1))->name; - resolveIdentifier(baseName, base, slotIndex, false); - + LValueKind baseKind = resolveIdentifier(baseName, base, slotIndex, baseBase, false); + if (baseKind == Slot) { + base = getSlot(baseBase, slotIndex); + } // // handle . // @@ -1570,22 +1629,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } break; - case ExprNode::functionLiteral: // XXX FIXME!! This needs to handled by calling genFunction !!! - // - the parameter handling is all wrong + case ExprNode::functionLiteral: { FunctionExprNode *f = static_cast(p); - ICodeGenerator icg(mContext); - icg.allocateParameter(mContext->getWorld().identifiers["this"], false); // 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, false, &Any_Type); - v = v->next; - } - icg.genStmt(f->function.body); - //stdOut << icg; - ICodeModule *icm = icg.complete(extractType(f->function.resultType)); - ret = newFunction(icm); + ICodeModule *icm = genFunction(f->function, false, false, NULL); + ret = newClosure(icm); } break; @@ -1596,9 +1644,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, ret = genExpr(b->op1); if (b->op2->getKind() == ExprNode::identifier) { TypedRegister t; - /*uint32 slotIndex;*/ const StringAtom &name = (static_cast(b->op2))->name; - /*LValueKind lvk = resolveIdentifier(name, t, slotIndex);*/ ASSERT(t.second == &Type_Type); const JSValue &v = mContext->getGlobalObject()->getVariable(name); ASSERT(v.isType()); @@ -1663,26 +1709,25 @@ JSType *ICodeGenerator::extractType(ExprNode *t) return type; } -ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass) +ICodeModule *ICodeGenerator::genFunction(FunctionDefinition &function, bool isStatic, bool isConstructor, JSClass *superclass) { - bool isStatic = hasAttribute(f->attributes, Token::Static); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; - ICodeGenerator icg(mContext, mClass, flags); + ICodeGenerator icg(mContext, this, mClass, flags); icg.allocateParameter(mContext->getWorld().identifiers["this"], false, (mClass) ? mClass : &Any_Type); // always parameter #0 - VariableBinding *v = f->function.parameters; + VariableBinding *v = function.parameters; bool unnamed = true; uint32 positionalCount = 0; StringFormatter s; while (v) { - if (unnamed && (v == f->function.namedParameters)) { // Track when we hit the first named parameter. + if (unnamed && (v == function.namedParameters)) { // Track when we hit the first named parameter. icg.parameterList->setPositionalCount(positionalCount); unnamed = false; } // The rest parameter is ignored in this processing - we push it to the end of the list. // But we need to track whether it comes before or after the | - if (v == f->function.restParameter) { + if (v == function.restParameter) { icg.parameterList->setRestParameter( (unnamed) ? ParameterList::HasRestParameterBeforeBar : ParameterList::HasRestParameterAfterBar ); } else { @@ -1708,8 +1753,8 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor if (unnamed) icg.parameterList->setPositionalCount(positionalCount); // now allocate the rest parameter - if (f->function.restParameter) { - v = f->function.restParameter; + if (function.restParameter) { + v = function.restParameter; JSType *pType = (v->type == NULL) ? &Array_Type : extractType(v->type); if (v->name && (v->name->getKind() == ExprNode::identifier)) icg.allocateParameter((static_cast(v->name))->name, (v->initializer != NULL), pType); @@ -1718,7 +1763,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor } // generate the code for optional initializers - v = f->function.optParameters; + v = function.optParameters; if (v) { while (v) { // include the rest parameter, as it may have an initializer if (v->name && (v->name->getKind() == ExprNode::identifier)) { @@ -1731,7 +1776,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor icg.setLabel(l); } else { // an un-initialized rest parameter is still an empty array - if (v == f->function.restParameter) { + if (v == function.restParameter) { Label *l = icg.getLabel(); icg.branchInitialized(l, p); icg.move(p, icg.newArray()); @@ -1754,7 +1799,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor ArgumentList *args = new ArgumentList(); if (superclass) { bool foundSuperCall = false; - BlockStmtNode *b = f->function.body; + BlockStmtNode *b = function.body; if (b && b->statements && (b->statements->getKind() == StmtNode::expression)) { ExprStmtNode *e = static_cast(b->statements); if (e->expr->getKind() == ExprNode::call) { @@ -1779,13 +1824,13 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor icg.call(icg.bindThis(thisValue, icg.getStatic(mClass, mInitName)), args); // ok, so it's mis-named } - if (f->function.body) - icg.genStmt(f->function.body); + if (function.body) + icg.genStmt(function.body); if (isConstructor) { TypedRegister thisValue = TypedRegister(0, mClass); icg.returnStmt(thisValue); } - return icg.complete(extractType(f->function.resultType)); + return icg.complete(extractType(function.resultType)); } TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) @@ -1900,11 +1945,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (needsInstanceInitializer) { // constructor code generator. Slot variable // initializers get added to this function. - ccg = new ICodeGenerator(classContext, thisClass, kNoFlags); + ccg = new ICodeGenerator(classContext, NULL, thisClass, kNoFlags); ccg->allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0 } - ICodeGenerator scg(classContext, thisClass, kIsStaticMethod); // static initializer code generator. + ICodeGenerator scg(classContext, NULL, thisClass, kIsStaticMethod); // static initializer code generator. // static field inits, plus code to initialize // static method slots. StmtNode* s = classStmt->body->statements; @@ -1943,8 +1988,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) bool isConstructor = (s->getKind() == StmtNode::Constructor); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; - ICodeGenerator mcg(classContext, thisClass, flags); // method code generator. - ICodeModule *icm = mcg.genFunction(f, isConstructor, superclass); + ICodeGenerator mcg(classContext, NULL, thisClass, flags); // method code generator. + ICodeModule *icm = mcg.genFunction(f->function, isStatic, isConstructor, superclass); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; if (isConstructor) { @@ -1988,7 +2033,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (!hasDefaultConstructor) { TypedRegister thisValue = TypedRegister(0, thisClass); ArgumentList *args = new ArgumentList(); - ICodeGenerator icg(classContext, thisClass, kIsStaticMethod); + ICodeGenerator icg(classContext, NULL, thisClass, kIsStaticMethod); icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0 if (superclass) icg.call(icg.bindThis(thisValue, icg.getStatic(superclass, superclass->getName())), args); @@ -2015,7 +2060,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) case StmtNode::Function: { FunctionStmtNode *f = static_cast(p); - ICodeModule *icm = genFunction(f, false, NULL); + bool isStatic = hasAttribute(f->attributes, Token::Static); + ICodeModule *icm = genFunction(f->function, isStatic, false, NULL); JSType *resultType = extractType(f->function.resultType); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; @@ -2468,8 +2514,8 @@ void ICodeGenerator::readICode(const char *fileName) JSClass* thisClass = new JSClass(mContext->getGlobalObject(), className, superclass); JSScope* thisScope = thisClass->getScope(); Context *classContext = new Context(mContext->getWorld(), thisScope); - ICodeGenerator scg(classContext, thisClass, kIsStaticMethod); - ICodeGenerator ccg(classContext, thisClass, kNoFlags); + ICodeGenerator scg(classContext, NULL, thisClass, kIsStaticMethod); + ICodeGenerator ccg(classContext, NULL, thisClass, kNoFlags); ccg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); thisClass->defineStatic(mInitName, &Function_Type); @@ -2541,7 +2587,7 @@ void ICodeGenerator::readICode(const char *fileName) if (!hasDefaultConstructor) { TypedRegister thisValue = TypedRegister(0, thisClass); ArgumentList *args = new ArgumentList(0); - ICodeGenerator icg(mContext, thisClass, kIsStaticMethod); + ICodeGenerator icg(mContext, NULL, thisClass, kIsStaticMethod); icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0 if (superclass) icg.call(icg.bindThis(thisValue, icg.getStatic(superclass, superclass->getName())), args); diff --git a/js/js2/icodegenerator.h b/js/js2/icodegenerator.h index 957e508666ac..a9e2d8911e35 100644 --- a/js/js2/icodegenerator.h +++ b/js/js2/icodegenerator.h @@ -217,6 +217,7 @@ namespace ICG { LabelList *pLabels; // label for each parameter initialization entry point const StringAtom &mInitName; + ICodeGenerator *mContainingFunction;// outer function for nested functions std::vector mPermanentRegister; @@ -260,7 +261,6 @@ namespace ICG { void endWith() { iCode->push_back(new Without()); } - void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; } ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind); @@ -272,16 +272,18 @@ namespace ICG { void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); } - typedef enum { Var, Property, Slot, Static, Constructor, Name, Method } LValueKind; + typedef enum { NoKind, Var, Property, Slot, Static, Constructor, Name, Method } LValueKind; - LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue); + LValueKind ICodeGenerator::getVariableByName(const StringAtom &name, TypedRegister &v); + LValueKind ICodeGenerator::scanForVariable(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base); + LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base, bool lvalue); TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue); TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue); - ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass); + ICodeModule *genFunction(FunctionDefinition &function, bool isStatic, bool isConstructor, JSClass *superClass); public: - ICodeGenerator(Context *cx, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel); + ICodeGenerator(Context *cx, ICodeGenerator *containingFunction = NULL, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel); ~ICodeGenerator() { @@ -352,6 +354,8 @@ namespace ICG { TypedRegister directCall(JSFunction *target, ArgumentList *args); TypedRegister bindThis(TypedRegister thisArg, TypedRegister target); TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex); + TypedRegister getClosure(uint32 count); + TypedRegister newClosure(ICodeModule *icm); void move(TypedRegister destination, TypedRegister source); TypedRegister logicalNot(TypedRegister source); diff --git a/js/js2/icodemap.h b/js/js2/icodemap.h index 963a967ddd17..66b03fc0a861 100644 --- a/js/js2/icodemap.h +++ b/js/js2/icodemap.h @@ -45,7 +45,7 @@ namespace JavaScript { namespace ICodeASM { - static uint icodemap_size = 73; + static uint icodemap_size = 75; static struct { char *name; @@ -74,6 +74,7 @@ namespace ICodeASM { {"DIVIDE", {otRegister, otRegister, otRegister}}, {"ELEM_XCR", {otRegister, otRegister, otRegister, otDouble}}, {"GENERIC_BINARY_OP", {otRegister, otBinaryOp, otRegister, otRegister}}, + {"GET_CLOSURE", {otRegister, otUInt32}}, {"GET_ELEMENT", {otRegister, otRegister, otRegister}}, {"GET_METHOD", {otRegister, otRegister, otUInt32}}, {"GET_PROP", {otRegister, otRegister, otStringAtom}}, @@ -91,6 +92,7 @@ namespace ICodeASM { {"NEGATE", {otRegister, otRegister}}, {"NEW_ARRAY", {otRegister}}, {"NEW_CLASS", {otRegister, otJSClass}}, + {"NEW_CLOSURE", {otRegister, otICodeModule}}, {"NEW_FUNCTION", {otRegister, otICodeModule}}, {"NEW_OBJECT", {otRegister, otRegister}}, {"NOP", {otNone}}, @@ -204,153 +206,159 @@ namespace ICodeASM { i = new GenericBinaryOP (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0), TypedRegister(static_cast(node->operand[3].data), 0)); break; case 23: - i = new GetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new GetClosure (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); break; case 24: - i = new GetMethod (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); + i = new GetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 25: - i = new GetProp (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data)); + i = new GetMethod (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); break; case 26: - i = new GetSlot (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); + i = new GetProp (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data)); break; case 27: - i = new GetStatic (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); + i = new GetSlot (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); break; case 28: - i = new Instanceof (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new GetStatic (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); break; case 29: - i = new Jsr (reinterpret_cast(node->operand[0].data)); + i = new Instanceof (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 30: - i = new LoadBoolean (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); + i = new Jsr (reinterpret_cast(node->operand[0].data)); break; case 31: - i = new LoadImmediate (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); + i = new LoadBoolean (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); break; case 32: - i = new LoadName (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new LoadImmediate (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); break; case 33: - i = new LoadString (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new LoadName (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 34: - i = new Move (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new LoadString (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 35: - i = new Multiply (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Move (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 36: - i = new NameXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); + i = new Multiply (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 37: - i = new Negate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new NameXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); break; case 38: - i = new NewArray (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new Negate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 39: - i = new NewClass (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new NewArray (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 40: - i = new NewFunction (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new NewClass (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 41: - i = new NewObject (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new NewClosure (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 42: - i = new Nop (); + i = new NewFunction (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 43: - i = new Not (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new NewObject (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 44: - i = new Or (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Nop (); break; case 45: - i = new Posate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new Not (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 46: - i = new PropXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data), static_cast(node->operand[3].data)); + i = new Or (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 47: - i = new Remainder (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Posate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 48: - i = new Return (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new PropXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data), static_cast(node->operand[3].data)); break; case 49: - i = new ReturnVoid (); + i = new Remainder (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 50: - i = new Rts (); + i = new Return (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 51: - i = new SaveName (reinterpret_cast(node->operand[0].data), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new ReturnVoid (); break; case 52: - i = new SetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Rts (); break; case 53: - i = new SetProp (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SaveName (reinterpret_cast(node->operand[0].data), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 54: - i = new SetSlot (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 55: - i = new SetStatic (reinterpret_cast(node->operand[0].data), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetProp (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 56: - i = new Shiftleft (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetSlot (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 57: - i = new Shiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetStatic (reinterpret_cast(node->operand[0].data), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 58: - i = new SlotXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); + i = new Shiftleft (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 59: - i = new StaticXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); + i = new Shiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 60: - i = new StrictEQ (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SlotXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); break; case 61: - i = new StrictNE (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new StaticXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); break; case 62: - i = new Subtract (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new StrictEQ (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 63: - i = new Super (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new StrictNE (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 64: - i = new Test (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new Subtract (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 65: - i = new Throw (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new Super (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 66: - i = new Tryin (reinterpret_cast(node->operand[0].data), reinterpret_cast(node->operand[1].data)); + i = new Test (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 67: - i = new Tryout (); + i = new Throw (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 68: - i = new Ushiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Tryin (reinterpret_cast(node->operand[0].data), reinterpret_cast(node->operand[1].data)); break; case 69: - i = new VarXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); + i = new Tryout (); break; case 70: - i = new Within (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new Ushiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 71: - i = new Without (); + i = new VarXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); break; case 72: + i = new Within (TypedRegister(static_cast(node->operand[0].data), 0)); + break; + case 73: + i = new Without (); + break; + case 74: i = new Xor (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; diff --git a/js/js2/interpreter.cpp b/js/js2/interpreter.cpp index 62fd7f4d0b00..a761328927c0 100644 --- a/js/js2/interpreter.cpp +++ b/js/js2/interpreter.cpp @@ -64,81 +64,6 @@ using namespace JSMathClass; // These classes are private to the JS interpreter. -/** -* -*/ -struct Handler: public gc_base { - Handler(Label *catchLabel, Label *finallyLabel) - : catchTarget(catchLabel), finallyTarget(finallyLabel) {} - Label *catchTarget; - Label *finallyTarget; -}; -typedef std::vector CatchStack; - - -/** - * Represents the current function's invocation state. - */ -struct Activation : public gc_base { - JSValues mRegisters; - ICodeModule* mICode; - CatchStack catchStack; - - Activation(ICodeModule* iCode, const JSValues& args) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - // copy arg list to initial registers. - JSValues::iterator dest = mRegisters.begin(); - for (JSValues::const_iterator src = args.begin(), - end = args.end(); src != end; ++src, ++dest) { - *dest = *src; - } - } - - Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg, - 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 (ArgumentList::const_iterator src = list->begin(), - end = list->end(); src != end; ++src, ++dest) { - Register r = (*src).first.first; - if (r != NotARegister) - *dest = params[r]; - else - *dest = JSValue(JSValue::uninitialized_tag); - } - } - - // calling a binary operator, no 'this' - Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg1, const JSValue arg2) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - mRegisters[0] = thisArg; - mRegisters[1] = arg1; - mRegisters[2] = arg2; - } - - // calling a getter function, no arguments - Activation(ICodeModule* iCode, const JSValue thisArg) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - mRegisters[0] = thisArg; - } - - // calling a setter function, 1 argument - Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - mRegisters[0] = thisArg; - mRegisters[1] = arg; - } - -}; - /** * exception-safe class to save off values. */ @@ -244,7 +169,7 @@ void Context::loadClass(const char *fileName) } JSValues& Context::getRegisters() { return mActivation->mRegisters; } -ICodeModule* Context::getICode() { return mActivation->mICode; } +ICodeModule* Context::getICode() { return mICode; } /** * Stores saved state from the *previous* activation, the current @@ -256,11 +181,13 @@ struct Linkage : public Context::Frame, public gc_base { Activation* mActivation; // caller's activation. JSScope* mScope; TypedRegister mResult; // the desired target register for the return value + ICodeModule* mICode; // the caller function + JSClosure* mClosure; Linkage(Linkage* linkage, InstructionIterator returnPC, - Activation* activation, JSScope* scope, TypedRegister result) + Activation* activation, JSScope* scope, TypedRegister result, ICodeModule* iCode, JSClosure *closure) : mNext(linkage), mReturnPC(returnPC), - mActivation(activation), mScope(scope), mResult(result) + mActivation(activation), mScope(scope), mResult(result), mICode(iCode), mClosure(closure) { } @@ -270,7 +197,7 @@ struct Linkage : public Context::Frame, public gc_base { { pc = mReturnPC; registers = &mActivation->mRegisters; - iCode = mActivation->mICode; + iCode = mICode; } }; @@ -651,12 +578,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) // when invoked with empty args, make sure that 'this' is // going to be the global object. - mActivation = new Activation(iCode, args); + mICode = iCode; + mActivation = new Activation(mICode->itsMaxRegister, args); JSValues* registers = &mActivation->mRegisters; if (args.size() == 0) (*registers)[0] = mGlobal; - mPC = mActivation->mICode->its_iCode->begin(); - InstructionIterator endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + InstructionIterator endPC = mICode->its_iCode->end(); // stack of all catch/finally handlers available for the current activation // to implement jsr/rts for finally code @@ -727,7 +655,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (target->isNative()) { ArgumentList *params = op3(call); JSValues argv(params->size() + 1); - argv[0] = target->getThis(); //(*registers)[op3(call).first]; + argv[0] = target->getThis(); JSValues::size_type i = 1; for (ArgumentList::const_iterator src = params->begin(), end = params->end(); src != end; ++src, ++i) { @@ -786,9 +714,6 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) else { // shift the index value down by the number of positional parameters index = (int)d; index -= icm->itsParameters->mPositionalCount; -// StringFormatter s; -// s << ((int)d - icm->itsParameters->mPositionalCount); -// argName = &mWorld.identifiers[s]; } TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match @@ -834,15 +759,41 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call)); - mActivation = new Activation(icm, mActivation, target->getThis()/*(*registers)[op3(call).first]*/, callArgs); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call), mICode, mCurrentClosure); + mICode = icm; + mActivation = new Activation(mICode->itsMaxRegister, mActivation, target->getThis(), callArgs); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); + JSClosure *cl = dynamic_cast(target); + if (cl) + mCurrentClosure = cl; continue; } } + + case NEW_CLOSURE: + { + NewClosure* nc = static_cast(instruction); + JSClosure* cl = new JSClosure(src1(nc), mActivation, mCurrentClosure); + (*registers)[dst(nc).first] = cl; + } + break; + + case GET_CLOSURE: + { + GetClosure* gc = static_cast(instruction); + uint32 count = src1(gc); + JSClosure* cl = mCurrentClosure; + while (count-- > 0) { + ASSERT(cl); + cl = cl->getPrevious(); + } + (*registers)[dst(gc).first] = cl->getActivation(); + } + break; + case DIRECT_CALL: { DirectCall* call = static_cast(instruction); @@ -862,11 +813,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } else { mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, op1(call)); - mActivation = new Activation(target->getICode(), mActivation, kNullValue, op3(call)); + mActivation, mGlobal, op1(call), mICode, mCurrentClosure); + mICode = target->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, mActivation, kNullValue, op3(call)); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } } @@ -887,7 +839,9 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (linkage->mResult.first != NotARegister) (*registers)[linkage->mResult.first] = kUndefinedValue; mPC = linkage->mReturnPC; - endPC = mActivation->mICode->its_iCode->end(); + mICode = linkage->mICode; + mCurrentClosure = linkage->mClosure; + endPC = mICode->its_iCode->end(); } continue; @@ -911,7 +865,9 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (linkage->mResult.first != NotARegister) (*registers)[linkage->mResult.first] = result; mPC = linkage->mReturnPC; - endPC = mActivation->mICode->its_iCode->end(); + mICode = linkage->mICode; + mCurrentClosure = linkage->mClosure; + endPC = mICode->its_iCode->end(); } continue; case MOVE: @@ -926,11 +882,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSFunction *getter = mGlobal->getter(*src1(ln)); if (getter) { ASSERT(!getter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln)); - mActivation = new Activation(getter->getICode(), kNullValue); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln), mICode, mCurrentClosure); + mICode = getter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, kNullValue); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } else @@ -943,11 +900,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSFunction *setter = mGlobal->setter(*dst(sn)); if (setter) { ASSERT(!setter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type)); - mActivation = new Activation(setter->getICode(), (*registers)[src1(sn).first], kNullValue); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type), mICode, mCurrentClosure); + mICode = setter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, (*registers)[src1(sn).first], kNullValue); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } else @@ -1093,21 +1051,33 @@ using JSString throughout. GetSlot* gs = static_cast(instruction); JSValue& value = (*registers)[src1(gs).first]; if (value.isObject()) { - JSInstance* inst = static_cast(value.object); - if (inst->hasGetter(src2(gs))) { - JSFunction* getter = inst->getter(src2(gs)); - ASSERT(!getter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(gs)); - mActivation = new Activation(getter->getICode(), value); - registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); - continue; + JSInstance* inst = dynamic_cast(value.object); + if (inst) { + if (inst->hasGetter(src2(gs))) { + JSFunction* getter = inst->getter(src2(gs)); + ASSERT(!getter->isNative()); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(gs), mICode, mCurrentClosure); + mICode = getter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, value); + registers = &mActivation->mRegisters; + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); + continue; + } + else + (*registers)[dst(gs).first] = (*inst)[src2(gs)]; + } + else { + Activation* act = dynamic_cast(value.object); + if (act) { + (*registers)[dst(gs).first] = act->mRegisters[src2(gs)]; + } + else + NOT_REACHED("runtime error"); } - else - (*registers)[dst(gs).first] = (*inst)[src2(gs)]; } - // XXX runtime error + else + NOT_REACHED("runtime error"); } break; case SET_SLOT: @@ -1115,20 +1085,33 @@ using JSString throughout. SetSlot* ss = static_cast(instruction); JSValue& value = (*registers)[dst(ss).first]; if (value.isObject()) { - JSInstance* inst = static_cast(value.object); - if (inst->hasSetter(src1(ss))) { - JSFunction* setter = inst->setter(src1(ss)); - ASSERT(!setter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type)); - mActivation = new Activation(setter->getICode(), value, (*registers)[src2(ss).first]); - registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); - continue; + JSInstance* inst = dynamic_cast(value.object); + if (inst) { + if (inst->hasSetter(src1(ss))) { + JSFunction* setter = inst->setter(src1(ss)); + ASSERT(!setter->isNative()); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type), mICode, mCurrentClosure); + mICode = setter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, value, (*registers)[src2(ss).first]); + registers = &mActivation->mRegisters; + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); + continue; + } + else + (*inst)[src1(ss)] = (*registers)[src2(ss).first]; + } + else { + Activation* act = dynamic_cast(value.object); + if (act) { + act->mRegisters[src1(ss)] = (*registers)[src2(ss).first]; + } + else + NOT_REACHED("runtime error"); } - else - (*inst)[src1(ss)] = (*registers)[src2(ss).first]; } + else + NOT_REACHED("runtime error"); } break; @@ -1154,7 +1137,7 @@ using JSString throughout. { GenericBranch* bra = static_cast(instruction); - mPC = mActivation->mICode->its_iCode->begin() + ofs(bra); + mPC = mICode->its_iCode->begin() + ofs(bra); continue; } break; @@ -1164,7 +1147,7 @@ using JSString throughout. static_cast(instruction); ASSERT((*registers)[src1(bc).first].isBoolean()); if ((*registers)[src1(bc).first].boolean) { - mPC = mActivation->mICode->its_iCode->begin() + ofs(bc); + mPC = mICode->its_iCode->begin() + ofs(bc); continue; } } @@ -1175,7 +1158,7 @@ using JSString throughout. static_cast(instruction); ASSERT((*registers)[src1(bc).first].isBoolean()); if (!(*registers)[src1(bc).first].boolean) { - mPC = mActivation->mICode->its_iCode->begin() + ofs(bc); + mPC = mICode->its_iCode->begin() + ofs(bc); continue; } } @@ -1185,7 +1168,7 @@ using JSString throughout. GenericBranch* bc = static_cast(instruction); if ((*registers)[src1(bc).first].isInitialized()) { - mPC = mActivation->mICode->its_iCode->begin() + ofs(bc); + mPC = mICode->its_iCode->begin() + ofs(bc); continue; } } @@ -1207,11 +1190,12 @@ using JSString throughout. } else { mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, dst(gbo)); - mActivation = new Activation(target->getICode(), kNullValue, r1, r2); + mActivation, mGlobal, dst(gbo), mICode, mCurrentClosure); + mICode = target->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, kNullValue, r1, r2); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } } @@ -1513,7 +1497,7 @@ using JSString throughout. subroutineStack.push(++mPC); Jsr* jsr = static_cast(instruction); uint32 offset = ofs(jsr); - mPC = mActivation->mICode->its_iCode->begin() + offset; + mPC = mICode->its_iCode->begin() + offset; continue; } case RTS: @@ -1561,11 +1545,11 @@ using JSString throughout. Handler *h = mActivation->catchStack.back(); registers = &mActivation->mRegisters; if (h->catchTarget) { - mPC = mActivation->mICode->its_iCode->begin() + h->catchTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->catchTarget->mOffset; } else { ASSERT(h->finallyTarget); - mPC = mActivation->mICode->its_iCode->begin() + h->finallyTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->finallyTarget->mOffset; } mLinkage = pLinkage; break; @@ -1577,11 +1561,11 @@ using JSString throughout. else { Handler *h = mActivation->catchStack.back(); if (h->catchTarget) { - mPC = mActivation->mICode->its_iCode->begin() + h->catchTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->catchTarget->mOffset; } else { ASSERT(h->finallyTarget); - mPC = mActivation->mICode->its_iCode->begin() + h->finallyTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->finallyTarget->mOffset; } continue; } diff --git a/js/js2/interpreter.h b/js/js2/interpreter.h index a7cbf1a59a6a..da3862b04477 100644 --- a/js/js2/interpreter.h +++ b/js/js2/interpreter.h @@ -40,7 +40,7 @@ namespace Interpreter { void initContext(); public: explicit Context(World& world, JSScope* aGlobal) - : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); } + : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false), mCurrentClosure(0) { initContext(); } World& getWorld() { return mWorld; } JSScope* getGlobalObject() { return mGlobal; } @@ -102,6 +102,8 @@ namespace Interpreter { typedef ListenerList::iterator ListenerIterator; ListenerList mListeners; Activation* mActivation; + ICodeModule* mICode; + JSClosure* mCurrentClosure; bool mHasOperatorsPackageLoaded; InstructionIterator mPC; @@ -110,6 +112,80 @@ namespace Interpreter { }; /* class Context */ + /** + * + */ + struct Handler: public gc_base { + Handler(Label *catchLabel, Label *finallyLabel) + : catchTarget(catchLabel), finallyTarget(finallyLabel) {} + Label *catchTarget; + Label *finallyTarget; + }; + typedef std::vector CatchStack; + + + /** + * Represents the current function's invocation state. + */ + struct Activation : public JSObject { + JSValues mRegisters; + CatchStack catchStack; + + Activation(uint32 highRegister, const JSValues& args) + : mRegisters(highRegister + 1) + { + // copy arg list to initial registers. + JSValues::iterator dest = mRegisters.begin(); + for (JSValues::const_iterator src = args.begin(), + end = args.end(); src != end; ++src, ++dest) { + *dest = *src; + } + } + + Activation(uint32 highRegister, Activation* caller, const JSValue thisArg, + const ArgumentList* list) + : mRegisters(highRegister + 1) + { + // copy caller's parameter list to initial registers. + JSValues::iterator dest = mRegisters.begin(); + *dest++ = thisArg; + const JSValues& params = caller->mRegisters; + for (ArgumentList::const_iterator src = list->begin(), + end = list->end(); src != end; ++src, ++dest) { + Register r = (*src).first.first; + if (r != NotARegister) + *dest = params[r]; + else + *dest = JSValue(JSValue::uninitialized_tag); + } + } + + // calling a binary operator, no 'this' + Activation(uint32 highRegister, const JSValue thisArg, const JSValue arg1, const JSValue arg2) + : mRegisters(highRegister + 1) + { + mRegisters[0] = thisArg; + mRegisters[1] = arg1; + mRegisters[2] = arg2; + } + + // calling a getter function, no arguments + Activation(uint32 highRegister, const JSValue thisArg) + : mRegisters(highRegister + 1) + { + mRegisters[0] = thisArg; + } + + // calling a setter function, 1 argument + Activation(uint32 highRegister, const JSValue thisArg, const JSValue arg) + : mRegisters(highRegister + 1) + { + mRegisters[0] = thisArg; + mRegisters[1] = arg; + } + + }; /* struct Activation */ + } /* namespace Interpreter */ } /* namespace JavaScript */ diff --git a/js/js2/jsclasses.h b/js/js2/jsclasses.h index c98eff8a66e0..2edd7ea8adf0 100644 --- a/js/js2/jsclasses.h +++ b/js/js2/jsclasses.h @@ -347,11 +347,28 @@ namespace JSClasses { return gc_base::operator new(n); } + void* operator new(size_t n, uint32 slotCount) + { + if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1); + return gc_base::operator new(n); + } + #if !defined(XP_MAC) void operator delete(void* /*ptr*/) {} void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {} + void operator delete(void* /*ptr*/, uint32 /*slotCount*/) {} #endif + JSInstance(uint32 slotCount) + { + mType = NULL; + // initialize extra slots with undefined. + if (slotCount > 0) { + std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1), + JSTypes::kUndefinedValue); + } + } + JSInstance(JSClass* thisClass) { mType = thisClass; diff --git a/js/js2/jstypes.h b/js/js2/jstypes.h index 60af2fd0106a..71e63d4f1e34 100644 --- a/js/js2/jstypes.h +++ b/js/js2/jstypes.h @@ -49,6 +49,7 @@ namespace ICG { } /* namespace ICG */ namespace Interpreter { class Context; + struct Activation; } /* namespace Interpreter */ } /* namespace JavaScript */ @@ -504,7 +505,6 @@ namespace JSTypes { static JSObject* FunctionPrototypeObject; ICodeModule* mICode; - typedef JavaScript::gc_traits_finalizable traits; typedef gc_allocator allocator; @@ -519,7 +519,6 @@ namespace JSTypes { { setClass(FunctionString); } - virtual ~JSFunction(); virtual JSValue getThis() { return kNullValue; } @@ -563,6 +562,21 @@ namespace JSTypes { void* operator new(size_t) { return allocator::allocate(1); } }; + class JSClosure : public JSFunction { + Interpreter::Activation *mActivation; + JSClosure *mPrevious; + typedef JavaScript::gc_traits_finalizable traits; + typedef gc_allocator allocator; + public: + JSClosure(ICodeModule* iCode, Interpreter::Activation *activation, JSClosure *previous) + : JSFunction(iCode), mActivation(activation), mPrevious(previous) {} + + JSClosure* getPrevious() { return mPrevious; } + Interpreter::Activation* getActivation() { return mActivation; } + + void* operator new(size_t) { return allocator::allocate(1); } + }; + /** * Provides a set of nested scopes. */ diff --git a/js/js2/tools/jsicodes.pm b/js/js2/tools/jsicodes.pm index 0b0885748184..755769642838 100644 --- a/js/js2/tools/jsicodes.pm +++ b/js/js2/tools/jsicodes.pm @@ -289,6 +289,18 @@ $ops{"SET_ELEMENT"} = rem => "base, index, value", params => [ ("TypedRegister", "TypedRegister", "TypedRegister") ] }; +$ops{"NEW_CLOSURE"} = + { + super => "Instruction_2", + rem => "dest, ICodeModule", + params => [ ("TypedRegister", "ICodeModule*") ] + }; +$ops{"GET_CLOSURE"} = + { + super => "Instruction_2", + rem => "dest, closure depth", + params => [ ("TypedRegister", "uint32") ] + }; $ops{"ADD"} = $math_op; $ops{"SUBTRACT"} = $math_op; $ops{"MULTIPLY"} = $math_op; diff --git a/js/js2/vmtypes.h b/js/js2/vmtypes.h index 974b527863f8..612e07f4609f 100644 --- a/js/js2/vmtypes.h +++ b/js/js2/vmtypes.h @@ -213,7 +213,7 @@ namespace VM { virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { - f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first) << ", " << getRegisterValue(registers, mOp3.first); + f /* << getRegisterValue(registers, mOp1.first) << ", " */ << getRegisterValue(registers, mOp2.first) << ", " << getRegisterValue(registers, mOp3.first); return f; } }; @@ -229,7 +229,7 @@ namespace VM { virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { - f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first); + f /* << getRegisterValue(registers, mOp1.first) << ", " */ << getRegisterValue(registers, mOp2.first); return f; } }; diff --git a/js/js2/winbuild/js2.dsp b/js/js2/winbuild/js2.dsp index a5d2ee91b6a5..6399740eed17 100644 --- a/js/js2/winbuild/js2.dsp +++ b/js/js2/winbuild/js2.dsp @@ -119,6 +119,14 @@ SOURCE=..\debugger.cpp # End Source File # Begin Source File +SOURCE=..\exception.cpp +# End Source File +# Begin Source File + +SOURCE=..\exception_msgs.cpp +# End Source File +# Begin Source File + SOURCE=..\hash.cpp # End Source File # Begin Source File @@ -147,6 +155,10 @@ SOURCE=..\jstypes.cpp # End Source File # Begin Source File +SOURCE=..\lexutils.cpp +# End Source File +# Begin Source File + SOURCE=..\numerics.cpp # End Source File # Begin Source File @@ -179,6 +191,10 @@ SOURCE=..\cpucfg.h # End Source File # Begin Source File +SOURCE=..\exception.h +# End Source File +# Begin Source File + SOURCE=..\gc_allocator.h # End Source File # Begin Source File @@ -219,6 +235,10 @@ SOURCE=..\jstypes.h # End Source File # Begin Source File +SOURCE=..\lexutils.h +# End Source File +# Begin Source File + SOURCE=..\nodefactory.h # End Source File # Begin Source File diff --git a/js2/src/icode.h b/js2/src/icode.h index 02780cf1dc88..1f4f0240d42d 100644 --- a/js2/src/icode.h +++ b/js2/src/icode.h @@ -26,6 +26,7 @@ DIVIDE, /* dest, source1, source2 */ ELEM_XCR, /* dest, base, index, value */ GENERIC_BINARY_OP, /* dest, op, source1, source2 */ + GET_CLOSURE, /* dest, closure depth */ GET_ELEMENT, /* dest, base, index */ GET_METHOD, /* result, target base, index */ GET_PROP, /* dest, object, prop name */ @@ -43,6 +44,7 @@ NEGATE, /* dest, source */ NEW_ARRAY, /* dest */ NEW_CLASS, /* dest, class */ + NEW_CLOSURE, /* dest, ICodeModule */ NEW_FUNCTION, /* dest, ICodeModule */ NEW_OBJECT, /* dest, constructor */ NOP, /* do nothing and like it */ @@ -402,6 +404,22 @@ } }; + class GetClosure : public Instruction_2 { + public: + /* dest, closure depth */ + GetClosure (TypedRegister aOp1, uint32 aOp2) : + Instruction_2 + (GET_CLOSURE, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[GET_CLOSURE] << "\t" << mOp1 << ", " << mOp2; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << getRegisterValue(registers, mOp1.first); + return f; + } + }; + class GetElement : public Instruction_3 { public: /* dest, base, index */ @@ -666,6 +684,22 @@ } }; + class NewClosure : public Instruction_2 { + public: + /* dest, ICodeModule */ + NewClosure (TypedRegister aOp1, ICodeModule* aOp2) : + Instruction_2 + (NEW_CLOSURE, aOp1, aOp2) {}; + virtual Formatter& print(Formatter& f) { + f << opcodeNames[NEW_CLOSURE] << "\t" << mOp1 << ", " << "ICodeModule"; + return f; + } + virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { + f << getRegisterValue(registers, mOp1.first); + return f; + } + }; + class NewFunction : public Instruction_2 { public: /* dest, ICodeModule */ @@ -1165,6 +1199,7 @@ "DIVIDE ", "ELEM_XCR ", "GENERIC_BINARY_OP ", + "GET_CLOSURE ", "GET_ELEMENT ", "GET_METHOD ", "GET_PROP ", @@ -1182,6 +1217,7 @@ "NEGATE ", "NEW_ARRAY ", "NEW_CLASS ", + "NEW_CLOSURE ", "NEW_FUNCTION ", "NEW_OBJECT ", "NOP ", diff --git a/js2/src/icodegenerator.cpp b/js2/src/icodegenerator.cpp index 7adcbbf4857f..73f585027a0a 100644 --- a/js2/src/icodegenerator.cpp +++ b/js2/src/icodegenerator.cpp @@ -73,7 +73,7 @@ Formatter& operator<<(Formatter &f, ICodeModule &i) // -ICodeGenerator::ICodeGenerator(Context *cx, JSClass *aClass, ICodeGeneratorFlags flags) +ICodeGenerator::ICodeGenerator(Context *cx, ICodeGenerator *containingFunction, JSClass *aClass, ICodeGeneratorFlags flags) : mTopRegister(0), mExceptionRegister(TypedRegister(NotARegister, &None_Type)), variableList(new VariableList()), @@ -83,7 +83,8 @@ ICodeGenerator::ICodeGenerator(Context *cx, JSClass *aClass, ICodeGeneratorFlags mClass(aClass), mFlags(flags), pLabels(NULL), - mInitName(cx->getWorld().identifiers["__init__"]) + mInitName(cx->getWorld().identifiers["__init__"]), + mContainingFunction(containingFunction) { iCode = new InstructionStream(); iCodeOwner = true; @@ -360,7 +361,6 @@ TypedRegister ICodeGenerator::staticXcr(JSClass *base, const StringAtom &name, I - TypedRegister ICodeGenerator::getSlot(TypedRegister base, uint32 slot) { TypedRegister dest(getTempRegister(), &Any_Type); @@ -498,6 +498,22 @@ TypedRegister ICodeGenerator::bindThis(TypedRegister thisArg, TypedRegister targ return dest; } + +TypedRegister ICodeGenerator::getClosure(uint32 count) +{ + TypedRegister dest(getTempRegister(), &Any_Type); + iCode->push_back(new GetClosure(dest, count)); + return dest; +} + +TypedRegister ICodeGenerator::newClosure(ICodeModule *icm) +{ + TypedRegister dest(getTempRegister(), &Function_Type); + iCode->push_back(new NewClosure(dest, icm)); + return dest; +} + + TypedRegister ICodeGenerator::getMethod(TypedRegister thisArg, uint32 slotIndex) { TypedRegister dest(getTempRegister(), &Any_Type); @@ -735,31 +751,70 @@ static bool isStaticName(JSClass *c, const StringAtom &name, JSType*& type, bool return false; } -ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue) +ICodeGenerator::LValueKind ICodeGenerator::getVariableByName(const StringAtom &name, TypedRegister &v) +{ + v = variableList->findVariable(name); + if (v.first == NotARegister) + v = parameterList->findVariable(name); + if (v.first != NotARegister) + return Var; + return NoKind; +} + +ICodeGenerator::LValueKind ICodeGenerator::scanForVariable(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base) +{ + LValueKind k = getVariableByName(name, v); + if (k == Var) return k; + + uint32 count = 0; + ICodeGenerator *upper = mContainingFunction; + while (upper) { + k = upper->getVariableByName(name, v); + if (k == Var) { + base = getClosure(count); + slotIndex = v.first; + return Slot; + } + count++; + upper = upper->mContainingFunction; + } + return NoKind; +} + +// find 'name' (unqualified) in the current context. +// for local variable, returns v.first = register number +// for slot/method, returns slotIndex and sets base appropriately +// (note closure vars also get handled this way) +// v.second is set to the type regardless +ICodeGenerator::LValueKind ICodeGenerator::resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base, bool lvalue) { if (!isWithinWith()) { - v = variableList->findVariable(name); - if (v.first == NotARegister) - v = parameterList->findVariable(name); - if (v.first != NotARegister) - return Var; + LValueKind k = scanForVariable(name, v, slotIndex, base); + if (k != NoKind) + return k; else { if (mClass) { // we're compiling a method of a class if (!isStaticMethod()) { - if (isSlotName(mClass, name, slotIndex, v.second, lvalue)) + if (isSlotName(mClass, name, slotIndex, v.second, lvalue)) { + base = TypedRegister(0, mClass); return Slot; - if (isMethodName(mClass, name, slotIndex)) + } + if (isMethodName(mClass, name, slotIndex)) { + base = TypedRegister(0, mClass); return Method; + } } bool isConstructor = false; if (isStaticName(mClass, name, v.second, isConstructor)) { return (isConstructor) ? Constructor : Static; } } + // last chance - if it's a generic name in the global scope, try to get a type for it v.second = mContext->getGlobalObject()->getType(name); return Name; } } + // all bet's off, generic name & type v.second = &Any_Type; return Name; } @@ -771,13 +826,12 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: /*JSType *vType = &Any_Type;*/ uint32 slotIndex; TypedRegister v; + TypedRegister base; const StringAtom &name = (static_cast(p))->name; - LValueKind lValueKind = resolveIdentifier(name, v, slotIndex, lvalue); + LValueKind lValueKind = resolveIdentifier(name, v, slotIndex, base, lvalue); JSType *targetType = v.second; - TypedRegister thisBase = TypedRegister(0, mClass ? mClass : &Any_Type); - switch (use) { case ExprNode::addEquals: case ExprNode::subtractEquals: @@ -797,7 +851,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: v = loadName(name, v.second); break; case Slot: - v = getSlot(thisBase, slotIndex); + v = getSlot(base, slotIndex); break; case Static: case Constructor: @@ -818,7 +872,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: saveName(name, ret); break; case Slot: - setSlot(thisBase, slotIndex, ret); + setSlot(base, slotIndex, ret); break; case Static: case Constructor: @@ -837,7 +891,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = loadName(name, v.second); break; case Slot: - ret = getSlot(thisBase, slotIndex); + ret = getSlot(base, slotIndex); break; case Static: case Constructor: @@ -859,8 +913,8 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: saveName(name, ret); break; case Slot: - ret = binaryOp(xcrementOp, getSlot(thisBase, slotIndex), loadImmediate(1.0)); - setSlot(thisBase, slotIndex, ret); + ret = binaryOp(xcrementOp, getSlot(base, slotIndex), loadImmediate(1.0)); + setSlot(base, slotIndex, ret); break; case Static: case Constructor: @@ -881,7 +935,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = nameXcr(name, xcrementOp); break; case Slot: - ret = slotXcr(thisBase, slotIndex, xcrementOp); + ret = slotXcr(base, slotIndex, xcrementOp); break; case Static: case Constructor: @@ -901,7 +955,7 @@ TypedRegister ICodeGenerator::handleIdentifier(IdentifierExprNode *p, ExprNode:: ret = call(loadName(name), args); break; case Method: - ret = call(getMethod(thisBase, slotIndex), args); + ret = call(getMethod(base, slotIndex), args); break; case Static: ret = call(getStatic(mClass, name), args); @@ -932,15 +986,20 @@ TypedRegister ICodeGenerator::handleDot(BinaryExprNode *b, ExprNode::Kind use, I NOT_REACHED("Implement me"); // turns into a getProperty (but not via any overloaded [] ) } else { + // we have . const StringAtom &fieldName = static_cast(b->op2)->name; TypedRegister base; + TypedRegister baseBase; JSClass *clazz = NULL; JSType *fieldType = &Any_Type; uint32 slotIndex; if ((b->op1->getKind() == ExprNode::identifier) && !isWithinWith()) { + // handle . const StringAtom &baseName = (static_cast(b->op1))->name; - resolveIdentifier(baseName, base, slotIndex, false); - + LValueKind baseKind = resolveIdentifier(baseName, base, slotIndex, baseBase, false); + if (baseKind == Slot) { + base = getSlot(baseBase, slotIndex); + } // // handle . // @@ -1570,22 +1629,11 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, } break; - case ExprNode::functionLiteral: // XXX FIXME!! This needs to handled by calling genFunction !!! - // - the parameter handling is all wrong + case ExprNode::functionLiteral: { FunctionExprNode *f = static_cast(p); - ICodeGenerator icg(mContext); - icg.allocateParameter(mContext->getWorld().identifiers["this"], false); // 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, false, &Any_Type); - v = v->next; - } - icg.genStmt(f->function.body); - //stdOut << icg; - ICodeModule *icm = icg.complete(extractType(f->function.resultType)); - ret = newFunction(icm); + ICodeModule *icm = genFunction(f->function, false, false, NULL); + ret = newClosure(icm); } break; @@ -1596,9 +1644,7 @@ TypedRegister ICodeGenerator::genExpr(ExprNode *p, ret = genExpr(b->op1); if (b->op2->getKind() == ExprNode::identifier) { TypedRegister t; - /*uint32 slotIndex;*/ const StringAtom &name = (static_cast(b->op2))->name; - /*LValueKind lvk = resolveIdentifier(name, t, slotIndex);*/ ASSERT(t.second == &Type_Type); const JSValue &v = mContext->getGlobalObject()->getVariable(name); ASSERT(v.isType()); @@ -1663,26 +1709,25 @@ JSType *ICodeGenerator::extractType(ExprNode *t) return type; } -ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superclass) +ICodeModule *ICodeGenerator::genFunction(FunctionDefinition &function, bool isStatic, bool isConstructor, JSClass *superclass) { - bool isStatic = hasAttribute(f->attributes, Token::Static); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; - ICodeGenerator icg(mContext, mClass, flags); + ICodeGenerator icg(mContext, this, mClass, flags); icg.allocateParameter(mContext->getWorld().identifiers["this"], false, (mClass) ? mClass : &Any_Type); // always parameter #0 - VariableBinding *v = f->function.parameters; + VariableBinding *v = function.parameters; bool unnamed = true; uint32 positionalCount = 0; StringFormatter s; while (v) { - if (unnamed && (v == f->function.namedParameters)) { // Track when we hit the first named parameter. + if (unnamed && (v == function.namedParameters)) { // Track when we hit the first named parameter. icg.parameterList->setPositionalCount(positionalCount); unnamed = false; } // The rest parameter is ignored in this processing - we push it to the end of the list. // But we need to track whether it comes before or after the | - if (v == f->function.restParameter) { + if (v == function.restParameter) { icg.parameterList->setRestParameter( (unnamed) ? ParameterList::HasRestParameterBeforeBar : ParameterList::HasRestParameterAfterBar ); } else { @@ -1708,8 +1753,8 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor if (unnamed) icg.parameterList->setPositionalCount(positionalCount); // now allocate the rest parameter - if (f->function.restParameter) { - v = f->function.restParameter; + if (function.restParameter) { + v = function.restParameter; JSType *pType = (v->type == NULL) ? &Array_Type : extractType(v->type); if (v->name && (v->name->getKind() == ExprNode::identifier)) icg.allocateParameter((static_cast(v->name))->name, (v->initializer != NULL), pType); @@ -1718,7 +1763,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor } // generate the code for optional initializers - v = f->function.optParameters; + v = function.optParameters; if (v) { while (v) { // include the rest parameter, as it may have an initializer if (v->name && (v->name->getKind() == ExprNode::identifier)) { @@ -1731,7 +1776,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor icg.setLabel(l); } else { // an un-initialized rest parameter is still an empty array - if (v == f->function.restParameter) { + if (v == function.restParameter) { Label *l = icg.getLabel(); icg.branchInitialized(l, p); icg.move(p, icg.newArray()); @@ -1754,7 +1799,7 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor ArgumentList *args = new ArgumentList(); if (superclass) { bool foundSuperCall = false; - BlockStmtNode *b = f->function.body; + BlockStmtNode *b = function.body; if (b && b->statements && (b->statements->getKind() == StmtNode::expression)) { ExprStmtNode *e = static_cast(b->statements); if (e->expr->getKind() == ExprNode::call) { @@ -1779,13 +1824,13 @@ ICodeModule *ICodeGenerator::genFunction(FunctionStmtNode *f, bool isConstructor icg.call(icg.bindThis(thisValue, icg.getStatic(mClass, mInitName)), args); // ok, so it's mis-named } - if (f->function.body) - icg.genStmt(f->function.body); + if (function.body) + icg.genStmt(function.body); if (isConstructor) { TypedRegister thisValue = TypedRegister(0, mClass); icg.returnStmt(thisValue); } - return icg.complete(extractType(f->function.resultType)); + return icg.complete(extractType(function.resultType)); } TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) @@ -1900,11 +1945,11 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (needsInstanceInitializer) { // constructor code generator. Slot variable // initializers get added to this function. - ccg = new ICodeGenerator(classContext, thisClass, kNoFlags); + ccg = new ICodeGenerator(classContext, NULL, thisClass, kNoFlags); ccg->allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0 } - ICodeGenerator scg(classContext, thisClass, kIsStaticMethod); // static initializer code generator. + ICodeGenerator scg(classContext, NULL, thisClass, kIsStaticMethod); // static initializer code generator. // static field inits, plus code to initialize // static method slots. StmtNode* s = classStmt->body->statements; @@ -1943,8 +1988,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) bool isConstructor = (s->getKind() == StmtNode::Constructor); ICodeGeneratorFlags flags = (isStatic) ? kIsStaticMethod : kNoFlags; - ICodeGenerator mcg(classContext, thisClass, flags); // method code generator. - ICodeModule *icm = mcg.genFunction(f, isConstructor, superclass); + ICodeGenerator mcg(classContext, NULL, thisClass, flags); // method code generator. + ICodeModule *icm = mcg.genFunction(f->function, isStatic, isConstructor, superclass); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; if (isConstructor) { @@ -1988,7 +2033,7 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) if (!hasDefaultConstructor) { TypedRegister thisValue = TypedRegister(0, thisClass); ArgumentList *args = new ArgumentList(); - ICodeGenerator icg(classContext, thisClass, kIsStaticMethod); + ICodeGenerator icg(classContext, NULL, thisClass, kIsStaticMethod); icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0 if (superclass) icg.call(icg.bindThis(thisValue, icg.getStatic(superclass, superclass->getName())), args); @@ -2015,7 +2060,8 @@ TypedRegister ICodeGenerator::genStmt(StmtNode *p, LabelSet *currentLabelSet) case StmtNode::Function: { FunctionStmtNode *f = static_cast(p); - ICodeModule *icm = genFunction(f, false, NULL); + bool isStatic = hasAttribute(f->attributes, Token::Static); + ICodeModule *icm = genFunction(f->function, isStatic, false, NULL); JSType *resultType = extractType(f->function.resultType); if (f->function.name->getKind() == ExprNode::identifier) { const StringAtom& name = (static_cast(f->function.name))->name; @@ -2468,8 +2514,8 @@ void ICodeGenerator::readICode(const char *fileName) JSClass* thisClass = new JSClass(mContext->getGlobalObject(), className, superclass); JSScope* thisScope = thisClass->getScope(); Context *classContext = new Context(mContext->getWorld(), thisScope); - ICodeGenerator scg(classContext, thisClass, kIsStaticMethod); - ICodeGenerator ccg(classContext, thisClass, kNoFlags); + ICodeGenerator scg(classContext, NULL, thisClass, kIsStaticMethod); + ICodeGenerator ccg(classContext, NULL, thisClass, kNoFlags); ccg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); thisClass->defineStatic(mInitName, &Function_Type); @@ -2541,7 +2587,7 @@ void ICodeGenerator::readICode(const char *fileName) if (!hasDefaultConstructor) { TypedRegister thisValue = TypedRegister(0, thisClass); ArgumentList *args = new ArgumentList(0); - ICodeGenerator icg(mContext, thisClass, kIsStaticMethod); + ICodeGenerator icg(mContext, NULL, thisClass, kIsStaticMethod); icg.allocateParameter(mContext->getWorld().identifiers["this"], false, thisClass); // always parameter #0 if (superclass) icg.call(icg.bindThis(thisValue, icg.getStatic(superclass, superclass->getName())), args); diff --git a/js2/src/icodegenerator.h b/js2/src/icodegenerator.h index 957e508666ac..a9e2d8911e35 100644 --- a/js2/src/icodegenerator.h +++ b/js2/src/icodegenerator.h @@ -217,6 +217,7 @@ namespace ICG { LabelList *pLabels; // label for each parameter initialization entry point const StringAtom &mInitName; + ICodeGenerator *mContainingFunction;// outer function for nested functions std::vector mPermanentRegister; @@ -260,7 +261,6 @@ namespace ICG { void endWith() { iCode->push_back(new Without()); } - void startStatement(uint32 pos) { (*mInstructionMap)[iCode->size()] = pos; } ICodeOp mapExprNodeToICodeOp(ExprNode::Kind kind); @@ -272,16 +272,18 @@ namespace ICG { void setFlag(uint32 flag, bool v) { mFlags = (ICodeGeneratorFlags)((v) ? mFlags | flag : mFlags & ~flag); } - typedef enum { Var, Property, Slot, Static, Constructor, Name, Method } LValueKind; + typedef enum { NoKind, Var, Property, Slot, Static, Constructor, Name, Method } LValueKind; - LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, bool lvalue); + LValueKind ICodeGenerator::getVariableByName(const StringAtom &name, TypedRegister &v); + LValueKind ICodeGenerator::scanForVariable(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base); + LValueKind resolveIdentifier(const StringAtom &name, TypedRegister &v, uint32 &slotIndex, TypedRegister &base, bool lvalue); TypedRegister handleIdentifier(IdentifierExprNode *p, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue); TypedRegister handleDot(BinaryExprNode *b, ExprNode::Kind use, ICodeOp xcrementOp, TypedRegister ret, ArgumentList *args, bool lvalue); - ICodeModule *genFunction(FunctionStmtNode *f, bool isConstructor, JSClass *superClass); + ICodeModule *genFunction(FunctionDefinition &function, bool isStatic, bool isConstructor, JSClass *superClass); public: - ICodeGenerator(Context *cx, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel); + ICodeGenerator(Context *cx, ICodeGenerator *containingFunction = NULL, JSClass *aClass = NULL, ICodeGeneratorFlags flags = kIsTopLevel); ~ICodeGenerator() { @@ -352,6 +354,8 @@ namespace ICG { TypedRegister directCall(JSFunction *target, ArgumentList *args); TypedRegister bindThis(TypedRegister thisArg, TypedRegister target); TypedRegister getMethod(TypedRegister thisArg, uint32 slotIndex); + TypedRegister getClosure(uint32 count); + TypedRegister newClosure(ICodeModule *icm); void move(TypedRegister destination, TypedRegister source); TypedRegister logicalNot(TypedRegister source); diff --git a/js2/src/icodemap.h b/js2/src/icodemap.h index 963a967ddd17..66b03fc0a861 100644 --- a/js2/src/icodemap.h +++ b/js2/src/icodemap.h @@ -45,7 +45,7 @@ namespace JavaScript { namespace ICodeASM { - static uint icodemap_size = 73; + static uint icodemap_size = 75; static struct { char *name; @@ -74,6 +74,7 @@ namespace ICodeASM { {"DIVIDE", {otRegister, otRegister, otRegister}}, {"ELEM_XCR", {otRegister, otRegister, otRegister, otDouble}}, {"GENERIC_BINARY_OP", {otRegister, otBinaryOp, otRegister, otRegister}}, + {"GET_CLOSURE", {otRegister, otUInt32}}, {"GET_ELEMENT", {otRegister, otRegister, otRegister}}, {"GET_METHOD", {otRegister, otRegister, otUInt32}}, {"GET_PROP", {otRegister, otRegister, otStringAtom}}, @@ -91,6 +92,7 @@ namespace ICodeASM { {"NEGATE", {otRegister, otRegister}}, {"NEW_ARRAY", {otRegister}}, {"NEW_CLASS", {otRegister, otJSClass}}, + {"NEW_CLOSURE", {otRegister, otICodeModule}}, {"NEW_FUNCTION", {otRegister, otICodeModule}}, {"NEW_OBJECT", {otRegister, otRegister}}, {"NOP", {otNone}}, @@ -204,153 +206,159 @@ namespace ICodeASM { i = new GenericBinaryOP (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0), TypedRegister(static_cast(node->operand[3].data), 0)); break; case 23: - i = new GetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new GetClosure (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); break; case 24: - i = new GetMethod (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); + i = new GetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 25: - i = new GetProp (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data)); + i = new GetMethod (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); break; case 26: - i = new GetSlot (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); + i = new GetProp (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data)); break; case 27: - i = new GetStatic (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); + i = new GetSlot (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); break; case 28: - i = new Instanceof (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new GetStatic (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); break; case 29: - i = new Jsr (reinterpret_cast(node->operand[0].data)); + i = new Instanceof (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 30: - i = new LoadBoolean (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); + i = new Jsr (reinterpret_cast(node->operand[0].data)); break; case 31: - i = new LoadImmediate (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); + i = new LoadBoolean (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); break; case 32: - i = new LoadName (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new LoadImmediate (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data)); break; case 33: - i = new LoadString (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new LoadName (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 34: - i = new Move (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new LoadString (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 35: - i = new Multiply (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Move (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 36: - i = new NameXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); + i = new Multiply (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 37: - i = new Negate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new NameXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data)); break; case 38: - i = new NewArray (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new Negate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 39: - i = new NewClass (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new NewArray (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 40: - i = new NewFunction (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); + i = new NewClass (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 41: - i = new NewObject (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new NewClosure (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 42: - i = new Nop (); + i = new NewFunction (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data)); break; case 43: - i = new Not (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new NewObject (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 44: - i = new Or (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Nop (); break; case 45: - i = new Posate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new Not (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 46: - i = new PropXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data), static_cast(node->operand[3].data)); + i = new Or (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 47: - i = new Remainder (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Posate (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 48: - i = new Return (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new PropXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), reinterpret_cast(node->operand[2].data), static_cast(node->operand[3].data)); break; case 49: - i = new ReturnVoid (); + i = new Remainder (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 50: - i = new Rts (); + i = new Return (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 51: - i = new SaveName (reinterpret_cast(node->operand[0].data), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new ReturnVoid (); break; case 52: - i = new SetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Rts (); break; case 53: - i = new SetProp (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SaveName (reinterpret_cast(node->operand[0].data), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 54: - i = new SetSlot (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetElement (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 55: - i = new SetStatic (reinterpret_cast(node->operand[0].data), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetProp (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 56: - i = new Shiftleft (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetSlot (TypedRegister(static_cast(node->operand[0].data), 0), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 57: - i = new Shiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SetStatic (reinterpret_cast(node->operand[0].data), static_cast(node->operand[1].data), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 58: - i = new SlotXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); + i = new Shiftleft (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 59: - i = new StaticXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); + i = new Shiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 60: - i = new StrictEQ (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new SlotXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); break; case 61: - i = new StrictNE (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new StaticXcr (TypedRegister(static_cast(node->operand[0].data), 0), reinterpret_cast(node->operand[1].data), static_cast(node->operand[2].data), static_cast(node->operand[3].data)); break; case 62: - i = new Subtract (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new StrictEQ (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 63: - i = new Super (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new StrictNE (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 64: - i = new Test (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); + i = new Subtract (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 65: - i = new Throw (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new Super (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 66: - i = new Tryin (reinterpret_cast(node->operand[0].data), reinterpret_cast(node->operand[1].data)); + i = new Test (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0)); break; case 67: - i = new Tryout (); + i = new Throw (TypedRegister(static_cast(node->operand[0].data), 0)); break; case 68: - i = new Ushiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); + i = new Tryin (reinterpret_cast(node->operand[0].data), reinterpret_cast(node->operand[1].data)); break; case 69: - i = new VarXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); + i = new Tryout (); break; case 70: - i = new Within (TypedRegister(static_cast(node->operand[0].data), 0)); + i = new Ushiftright (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; case 71: - i = new Without (); + i = new VarXcr (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), static_cast(node->operand[2].data)); break; case 72: + i = new Within (TypedRegister(static_cast(node->operand[0].data), 0)); + break; + case 73: + i = new Without (); + break; + case 74: i = new Xor (TypedRegister(static_cast(node->operand[0].data), 0), TypedRegister(static_cast(node->operand[1].data), 0), TypedRegister(static_cast(node->operand[2].data), 0)); break; diff --git a/js2/src/interpreter.cpp b/js2/src/interpreter.cpp index 62fd7f4d0b00..a761328927c0 100644 --- a/js2/src/interpreter.cpp +++ b/js2/src/interpreter.cpp @@ -64,81 +64,6 @@ using namespace JSMathClass; // These classes are private to the JS interpreter. -/** -* -*/ -struct Handler: public gc_base { - Handler(Label *catchLabel, Label *finallyLabel) - : catchTarget(catchLabel), finallyTarget(finallyLabel) {} - Label *catchTarget; - Label *finallyTarget; -}; -typedef std::vector CatchStack; - - -/** - * Represents the current function's invocation state. - */ -struct Activation : public gc_base { - JSValues mRegisters; - ICodeModule* mICode; - CatchStack catchStack; - - Activation(ICodeModule* iCode, const JSValues& args) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - // copy arg list to initial registers. - JSValues::iterator dest = mRegisters.begin(); - for (JSValues::const_iterator src = args.begin(), - end = args.end(); src != end; ++src, ++dest) { - *dest = *src; - } - } - - Activation(ICodeModule* iCode, Activation* caller, const JSValue thisArg, - 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 (ArgumentList::const_iterator src = list->begin(), - end = list->end(); src != end; ++src, ++dest) { - Register r = (*src).first.first; - if (r != NotARegister) - *dest = params[r]; - else - *dest = JSValue(JSValue::uninitialized_tag); - } - } - - // calling a binary operator, no 'this' - Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg1, const JSValue arg2) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - mRegisters[0] = thisArg; - mRegisters[1] = arg1; - mRegisters[2] = arg2; - } - - // calling a getter function, no arguments - Activation(ICodeModule* iCode, const JSValue thisArg) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - mRegisters[0] = thisArg; - } - - // calling a setter function, 1 argument - Activation(ICodeModule* iCode, const JSValue thisArg, const JSValue arg) - : mRegisters(iCode->itsMaxRegister + 1), mICode(iCode) - { - mRegisters[0] = thisArg; - mRegisters[1] = arg; - } - -}; - /** * exception-safe class to save off values. */ @@ -244,7 +169,7 @@ void Context::loadClass(const char *fileName) } JSValues& Context::getRegisters() { return mActivation->mRegisters; } -ICodeModule* Context::getICode() { return mActivation->mICode; } +ICodeModule* Context::getICode() { return mICode; } /** * Stores saved state from the *previous* activation, the current @@ -256,11 +181,13 @@ struct Linkage : public Context::Frame, public gc_base { Activation* mActivation; // caller's activation. JSScope* mScope; TypedRegister mResult; // the desired target register for the return value + ICodeModule* mICode; // the caller function + JSClosure* mClosure; Linkage(Linkage* linkage, InstructionIterator returnPC, - Activation* activation, JSScope* scope, TypedRegister result) + Activation* activation, JSScope* scope, TypedRegister result, ICodeModule* iCode, JSClosure *closure) : mNext(linkage), mReturnPC(returnPC), - mActivation(activation), mScope(scope), mResult(result) + mActivation(activation), mScope(scope), mResult(result), mICode(iCode), mClosure(closure) { } @@ -270,7 +197,7 @@ struct Linkage : public Context::Frame, public gc_base { { pc = mReturnPC; registers = &mActivation->mRegisters; - iCode = mActivation->mICode; + iCode = mICode; } }; @@ -651,12 +578,13 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) // when invoked with empty args, make sure that 'this' is // going to be the global object. - mActivation = new Activation(iCode, args); + mICode = iCode; + mActivation = new Activation(mICode->itsMaxRegister, args); JSValues* registers = &mActivation->mRegisters; if (args.size() == 0) (*registers)[0] = mGlobal; - mPC = mActivation->mICode->its_iCode->begin(); - InstructionIterator endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + InstructionIterator endPC = mICode->its_iCode->end(); // stack of all catch/finally handlers available for the current activation // to implement jsr/rts for finally code @@ -727,7 +655,7 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (target->isNative()) { ArgumentList *params = op3(call); JSValues argv(params->size() + 1); - argv[0] = target->getThis(); //(*registers)[op3(call).first]; + argv[0] = target->getThis(); JSValues::size_type i = 1; for (ArgumentList::const_iterator src = params->begin(), end = params->end(); src != end; ++src, ++i) { @@ -786,9 +714,6 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) else { // shift the index value down by the number of positional parameters index = (int)d; index -= icm->itsParameters->mPositionalCount; -// StringFormatter s; -// s << ((int)d - icm->itsParameters->mPositionalCount); -// argName = &mWorld.identifiers[s]; } TypedRegister argument = (*args)[i].first; // this is the argument whose name didn't match @@ -834,15 +759,41 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } } - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call)); - mActivation = new Activation(icm, mActivation, target->getThis()/*(*registers)[op3(call).first]*/, callArgs); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, op1(call), mICode, mCurrentClosure); + mICode = icm; + mActivation = new Activation(mICode->itsMaxRegister, mActivation, target->getThis(), callArgs); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); + JSClosure *cl = dynamic_cast(target); + if (cl) + mCurrentClosure = cl; continue; } } + + case NEW_CLOSURE: + { + NewClosure* nc = static_cast(instruction); + JSClosure* cl = new JSClosure(src1(nc), mActivation, mCurrentClosure); + (*registers)[dst(nc).first] = cl; + } + break; + + case GET_CLOSURE: + { + GetClosure* gc = static_cast(instruction); + uint32 count = src1(gc); + JSClosure* cl = mCurrentClosure; + while (count-- > 0) { + ASSERT(cl); + cl = cl->getPrevious(); + } + (*registers)[dst(gc).first] = cl->getActivation(); + } + break; + case DIRECT_CALL: { DirectCall* call = static_cast(instruction); @@ -862,11 +813,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) } else { mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, op1(call)); - mActivation = new Activation(target->getICode(), mActivation, kNullValue, op3(call)); + mActivation, mGlobal, op1(call), mICode, mCurrentClosure); + mICode = target->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, mActivation, kNullValue, op3(call)); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } } @@ -887,7 +839,9 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (linkage->mResult.first != NotARegister) (*registers)[linkage->mResult.first] = kUndefinedValue; mPC = linkage->mReturnPC; - endPC = mActivation->mICode->its_iCode->end(); + mICode = linkage->mICode; + mCurrentClosure = linkage->mClosure; + endPC = mICode->its_iCode->end(); } continue; @@ -911,7 +865,9 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) if (linkage->mResult.first != NotARegister) (*registers)[linkage->mResult.first] = result; mPC = linkage->mReturnPC; - endPC = mActivation->mICode->its_iCode->end(); + mICode = linkage->mICode; + mCurrentClosure = linkage->mClosure; + endPC = mICode->its_iCode->end(); } continue; case MOVE: @@ -926,11 +882,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSFunction *getter = mGlobal->getter(*src1(ln)); if (getter) { ASSERT(!getter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln)); - mActivation = new Activation(getter->getICode(), kNullValue); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(ln), mICode, mCurrentClosure); + mICode = getter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, kNullValue); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } else @@ -943,11 +900,12 @@ JSValue Context::interpret(ICodeModule* iCode, const JSValues& args) JSFunction *setter = mGlobal->setter(*dst(sn)); if (setter) { ASSERT(!setter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type)); - mActivation = new Activation(setter->getICode(), (*registers)[src1(sn).first], kNullValue); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type), mICode, mCurrentClosure); + mICode = setter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, (*registers)[src1(sn).first], kNullValue); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } else @@ -1093,21 +1051,33 @@ using JSString throughout. GetSlot* gs = static_cast(instruction); JSValue& value = (*registers)[src1(gs).first]; if (value.isObject()) { - JSInstance* inst = static_cast(value.object); - if (inst->hasGetter(src2(gs))) { - JSFunction* getter = inst->getter(src2(gs)); - ASSERT(!getter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(gs)); - mActivation = new Activation(getter->getICode(), value); - registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); - continue; + JSInstance* inst = dynamic_cast(value.object); + if (inst) { + if (inst->hasGetter(src2(gs))) { + JSFunction* getter = inst->getter(src2(gs)); + ASSERT(!getter->isNative()); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, dst(gs), mICode, mCurrentClosure); + mICode = getter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, value); + registers = &mActivation->mRegisters; + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); + continue; + } + else + (*registers)[dst(gs).first] = (*inst)[src2(gs)]; + } + else { + Activation* act = dynamic_cast(value.object); + if (act) { + (*registers)[dst(gs).first] = act->mRegisters[src2(gs)]; + } + else + NOT_REACHED("runtime error"); } - else - (*registers)[dst(gs).first] = (*inst)[src2(gs)]; } - // XXX runtime error + else + NOT_REACHED("runtime error"); } break; case SET_SLOT: @@ -1115,20 +1085,33 @@ using JSString throughout. SetSlot* ss = static_cast(instruction); JSValue& value = (*registers)[dst(ss).first]; if (value.isObject()) { - JSInstance* inst = static_cast(value.object); - if (inst->hasSetter(src1(ss))) { - JSFunction* setter = inst->setter(src1(ss)); - ASSERT(!setter->isNative()); - mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type)); - mActivation = new Activation(setter->getICode(), value, (*registers)[src2(ss).first]); - registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); - continue; + JSInstance* inst = dynamic_cast(value.object); + if (inst) { + if (inst->hasSetter(src1(ss))) { + JSFunction* setter = inst->setter(src1(ss)); + ASSERT(!setter->isNative()); + mLinkage = new Linkage(mLinkage, ++mPC, mActivation, mGlobal, TypedRegister(NotARegister, &Null_Type), mICode, mCurrentClosure); + mICode = setter->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, value, (*registers)[src2(ss).first]); + registers = &mActivation->mRegisters; + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); + continue; + } + else + (*inst)[src1(ss)] = (*registers)[src2(ss).first]; + } + else { + Activation* act = dynamic_cast(value.object); + if (act) { + act->mRegisters[src1(ss)] = (*registers)[src2(ss).first]; + } + else + NOT_REACHED("runtime error"); } - else - (*inst)[src1(ss)] = (*registers)[src2(ss).first]; } + else + NOT_REACHED("runtime error"); } break; @@ -1154,7 +1137,7 @@ using JSString throughout. { GenericBranch* bra = static_cast(instruction); - mPC = mActivation->mICode->its_iCode->begin() + ofs(bra); + mPC = mICode->its_iCode->begin() + ofs(bra); continue; } break; @@ -1164,7 +1147,7 @@ using JSString throughout. static_cast(instruction); ASSERT((*registers)[src1(bc).first].isBoolean()); if ((*registers)[src1(bc).first].boolean) { - mPC = mActivation->mICode->its_iCode->begin() + ofs(bc); + mPC = mICode->its_iCode->begin() + ofs(bc); continue; } } @@ -1175,7 +1158,7 @@ using JSString throughout. static_cast(instruction); ASSERT((*registers)[src1(bc).first].isBoolean()); if (!(*registers)[src1(bc).first].boolean) { - mPC = mActivation->mICode->its_iCode->begin() + ofs(bc); + mPC = mICode->its_iCode->begin() + ofs(bc); continue; } } @@ -1185,7 +1168,7 @@ using JSString throughout. GenericBranch* bc = static_cast(instruction); if ((*registers)[src1(bc).first].isInitialized()) { - mPC = mActivation->mICode->its_iCode->begin() + ofs(bc); + mPC = mICode->its_iCode->begin() + ofs(bc); continue; } } @@ -1207,11 +1190,12 @@ using JSString throughout. } else { mLinkage = new Linkage(mLinkage, ++mPC, - mActivation, mGlobal, dst(gbo)); - mActivation = new Activation(target->getICode(), kNullValue, r1, r2); + mActivation, mGlobal, dst(gbo), mICode, mCurrentClosure); + mICode = target->getICode(); + mActivation = new Activation(mICode->itsMaxRegister, kNullValue, r1, r2); registers = &mActivation->mRegisters; - mPC = mActivation->mICode->its_iCode->begin(); - endPC = mActivation->mICode->its_iCode->end(); + mPC = mICode->its_iCode->begin(); + endPC = mICode->its_iCode->end(); continue; } } @@ -1513,7 +1497,7 @@ using JSString throughout. subroutineStack.push(++mPC); Jsr* jsr = static_cast(instruction); uint32 offset = ofs(jsr); - mPC = mActivation->mICode->its_iCode->begin() + offset; + mPC = mICode->its_iCode->begin() + offset; continue; } case RTS: @@ -1561,11 +1545,11 @@ using JSString throughout. Handler *h = mActivation->catchStack.back(); registers = &mActivation->mRegisters; if (h->catchTarget) { - mPC = mActivation->mICode->its_iCode->begin() + h->catchTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->catchTarget->mOffset; } else { ASSERT(h->finallyTarget); - mPC = mActivation->mICode->its_iCode->begin() + h->finallyTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->finallyTarget->mOffset; } mLinkage = pLinkage; break; @@ -1577,11 +1561,11 @@ using JSString throughout. else { Handler *h = mActivation->catchStack.back(); if (h->catchTarget) { - mPC = mActivation->mICode->its_iCode->begin() + h->catchTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->catchTarget->mOffset; } else { ASSERT(h->finallyTarget); - mPC = mActivation->mICode->its_iCode->begin() + h->finallyTarget->mOffset; + mPC = mICode->its_iCode->begin() + h->finallyTarget->mOffset; } continue; } diff --git a/js2/src/interpreter.h b/js2/src/interpreter.h index a7cbf1a59a6a..da3862b04477 100644 --- a/js2/src/interpreter.h +++ b/js2/src/interpreter.h @@ -40,7 +40,7 @@ namespace Interpreter { void initContext(); public: explicit Context(World& world, JSScope* aGlobal) - : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false) { initContext(); } + : mWorld(world), mGlobal(aGlobal), mLinkage(0), mActivation(0), mHasOperatorsPackageLoaded(false), mCurrentClosure(0) { initContext(); } World& getWorld() { return mWorld; } JSScope* getGlobalObject() { return mGlobal; } @@ -102,6 +102,8 @@ namespace Interpreter { typedef ListenerList::iterator ListenerIterator; ListenerList mListeners; Activation* mActivation; + ICodeModule* mICode; + JSClosure* mCurrentClosure; bool mHasOperatorsPackageLoaded; InstructionIterator mPC; @@ -110,6 +112,80 @@ namespace Interpreter { }; /* class Context */ + /** + * + */ + struct Handler: public gc_base { + Handler(Label *catchLabel, Label *finallyLabel) + : catchTarget(catchLabel), finallyTarget(finallyLabel) {} + Label *catchTarget; + Label *finallyTarget; + }; + typedef std::vector CatchStack; + + + /** + * Represents the current function's invocation state. + */ + struct Activation : public JSObject { + JSValues mRegisters; + CatchStack catchStack; + + Activation(uint32 highRegister, const JSValues& args) + : mRegisters(highRegister + 1) + { + // copy arg list to initial registers. + JSValues::iterator dest = mRegisters.begin(); + for (JSValues::const_iterator src = args.begin(), + end = args.end(); src != end; ++src, ++dest) { + *dest = *src; + } + } + + Activation(uint32 highRegister, Activation* caller, const JSValue thisArg, + const ArgumentList* list) + : mRegisters(highRegister + 1) + { + // copy caller's parameter list to initial registers. + JSValues::iterator dest = mRegisters.begin(); + *dest++ = thisArg; + const JSValues& params = caller->mRegisters; + for (ArgumentList::const_iterator src = list->begin(), + end = list->end(); src != end; ++src, ++dest) { + Register r = (*src).first.first; + if (r != NotARegister) + *dest = params[r]; + else + *dest = JSValue(JSValue::uninitialized_tag); + } + } + + // calling a binary operator, no 'this' + Activation(uint32 highRegister, const JSValue thisArg, const JSValue arg1, const JSValue arg2) + : mRegisters(highRegister + 1) + { + mRegisters[0] = thisArg; + mRegisters[1] = arg1; + mRegisters[2] = arg2; + } + + // calling a getter function, no arguments + Activation(uint32 highRegister, const JSValue thisArg) + : mRegisters(highRegister + 1) + { + mRegisters[0] = thisArg; + } + + // calling a setter function, 1 argument + Activation(uint32 highRegister, const JSValue thisArg, const JSValue arg) + : mRegisters(highRegister + 1) + { + mRegisters[0] = thisArg; + mRegisters[1] = arg; + } + + }; /* struct Activation */ + } /* namespace Interpreter */ } /* namespace JavaScript */ diff --git a/js2/src/jsclasses.h b/js2/src/jsclasses.h index c98eff8a66e0..2edd7ea8adf0 100644 --- a/js2/src/jsclasses.h +++ b/js2/src/jsclasses.h @@ -347,11 +347,28 @@ namespace JSClasses { return gc_base::operator new(n); } + void* operator new(size_t n, uint32 slotCount) + { + if (slotCount > 0) n += sizeof(JSValue) * (slotCount - 1); + return gc_base::operator new(n); + } + #if !defined(XP_MAC) void operator delete(void* /*ptr*/) {} void operator delete(void* /*ptr*/, JSClass* /*thisClass*/) {} + void operator delete(void* /*ptr*/, uint32 /*slotCount*/) {} #endif + JSInstance(uint32 slotCount) + { + mType = NULL; + // initialize extra slots with undefined. + if (slotCount > 0) { + std::uninitialized_fill(&mSlots[1], &mSlots[1] + (slotCount - 1), + JSTypes::kUndefinedValue); + } + } + JSInstance(JSClass* thisClass) { mType = thisClass; diff --git a/js2/src/jstypes.h b/js2/src/jstypes.h index 60af2fd0106a..71e63d4f1e34 100644 --- a/js2/src/jstypes.h +++ b/js2/src/jstypes.h @@ -49,6 +49,7 @@ namespace ICG { } /* namespace ICG */ namespace Interpreter { class Context; + struct Activation; } /* namespace Interpreter */ } /* namespace JavaScript */ @@ -504,7 +505,6 @@ namespace JSTypes { static JSObject* FunctionPrototypeObject; ICodeModule* mICode; - typedef JavaScript::gc_traits_finalizable traits; typedef gc_allocator allocator; @@ -519,7 +519,6 @@ namespace JSTypes { { setClass(FunctionString); } - virtual ~JSFunction(); virtual JSValue getThis() { return kNullValue; } @@ -563,6 +562,21 @@ namespace JSTypes { void* operator new(size_t) { return allocator::allocate(1); } }; + class JSClosure : public JSFunction { + Interpreter::Activation *mActivation; + JSClosure *mPrevious; + typedef JavaScript::gc_traits_finalizable traits; + typedef gc_allocator allocator; + public: + JSClosure(ICodeModule* iCode, Interpreter::Activation *activation, JSClosure *previous) + : JSFunction(iCode), mActivation(activation), mPrevious(previous) {} + + JSClosure* getPrevious() { return mPrevious; } + Interpreter::Activation* getActivation() { return mActivation; } + + void* operator new(size_t) { return allocator::allocate(1); } + }; + /** * Provides a set of nested scopes. */ diff --git a/js2/src/vmtypes.h b/js2/src/vmtypes.h index 974b527863f8..612e07f4609f 100644 --- a/js2/src/vmtypes.h +++ b/js2/src/vmtypes.h @@ -213,7 +213,7 @@ namespace VM { virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { - f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first) << ", " << getRegisterValue(registers, mOp3.first); + f /* << getRegisterValue(registers, mOp1.first) << ", " */ << getRegisterValue(registers, mOp2.first) << ", " << getRegisterValue(registers, mOp3.first); return f; } }; @@ -229,7 +229,7 @@ namespace VM { virtual Formatter& printOperands(Formatter& f, const JSValues& registers) { - f << getRegisterValue(registers, mOp1.first) << ", " << getRegisterValue(registers, mOp2.first); + f /* << getRegisterValue(registers, mOp1.first) << ", " */ << getRegisterValue(registers, mOp2.first); return f; } }; diff --git a/js2/src/winbuild/js2.dsp b/js2/src/winbuild/js2.dsp index a5d2ee91b6a5..6399740eed17 100644 --- a/js2/src/winbuild/js2.dsp +++ b/js2/src/winbuild/js2.dsp @@ -119,6 +119,14 @@ SOURCE=..\debugger.cpp # End Source File # Begin Source File +SOURCE=..\exception.cpp +# End Source File +# Begin Source File + +SOURCE=..\exception_msgs.cpp +# End Source File +# Begin Source File + SOURCE=..\hash.cpp # End Source File # Begin Source File @@ -147,6 +155,10 @@ SOURCE=..\jstypes.cpp # End Source File # Begin Source File +SOURCE=..\lexutils.cpp +# End Source File +# Begin Source File + SOURCE=..\numerics.cpp # End Source File # Begin Source File @@ -179,6 +191,10 @@ SOURCE=..\cpucfg.h # End Source File # Begin Source File +SOURCE=..\exception.h +# End Source File +# Begin Source File + SOURCE=..\gc_allocator.h # End Source File # Begin Source File @@ -219,6 +235,10 @@ SOURCE=..\jstypes.h # End Source File # Begin Source File +SOURCE=..\lexutils.h +# End Source File +# Begin Source File + SOURCE=..\nodefactory.h # End Source File # Begin Source File diff --git a/js2/tools/jsicodes.pm b/js2/tools/jsicodes.pm index 0b0885748184..755769642838 100644 --- a/js2/tools/jsicodes.pm +++ b/js2/tools/jsicodes.pm @@ -289,6 +289,18 @@ $ops{"SET_ELEMENT"} = rem => "base, index, value", params => [ ("TypedRegister", "TypedRegister", "TypedRegister") ] }; +$ops{"NEW_CLOSURE"} = + { + super => "Instruction_2", + rem => "dest, ICodeModule", + params => [ ("TypedRegister", "ICodeModule*") ] + }; +$ops{"GET_CLOSURE"} = + { + super => "Instruction_2", + rem => "dest, closure depth", + params => [ ("TypedRegister", "uint32") ] + }; $ops{"ADD"} = $math_op; $ops{"SUBTRACT"} = $math_op; $ops{"MULTIPLY"} = $math_op;