From ba3c57bef0fafe2269f83758272d50abb614f2ef Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Wed, 7 May 2003 22:59:25 +0000 Subject: [PATCH] Super constructor call sequence and super statement. git-svn-id: svn://10.0.0.236/trunk@142187 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/src/js2engine.cpp | 15 ++++---- mozilla/js2/src/js2engine.h | 1 + mozilla/js2/src/js2eval.cpp | 9 +++++ mozilla/js2/src/js2metadata.cpp | 56 +++++++++++++++++++++++++++- mozilla/js2/src/js2metadata.h | 18 ++++++++- mozilla/js2/src/js2op_invocation.cpp | 15 ++++++++ 6 files changed, 103 insertions(+), 11 deletions(-) diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index 1126f03f68e..2206ffdaaf9 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -595,12 +595,13 @@ namespace MetaData { { ePopFrame, "PopFrame", 0 }, { eWithin, "With", 0 }, { eWithout, "EndWith", 0 }, - { eBranchFalse, "BranchFalse", BRANCH_OFFSET }, // XXX save space with short and long versions instead ? - { eBranchTrue, "BranchTrue", BRANCH_OFFSET }, // - { eBranch, "Branch", BRANCH_OFFSET }, // - { eBreak, "Break", BREAK_OFFSET_AND_COUNT }, // - { eNew, "New", U16 }, // + { eBranchFalse, "BranchFalse", BRANCH_OFFSET }, // XXX save space with short and long versions instead ? + { eBranchTrue, "BranchTrue", BRANCH_OFFSET }, // + { eBranch, "Branch", BRANCH_OFFSET }, // + { eBreak, "Break", BREAK_OFFSET_AND_COUNT }, // + { eNew, "New", U16 }, // { eCall, "Call", U16 }, // + { eSuperCall, "SuperCall", U16 }, // { eTypeof, "Typeof", 0 }, { eInstanceof, "Instanceof", 0 }, { eIs, "Is", 0 }, @@ -968,9 +969,7 @@ namespace MetaData { JS2Class *c = checked_cast(obj); SimpleInstance *result = new SimpleInstance(meta, c->prototype, c); DEFINE_ROOTKEEPER(rk, result); - if (c->init) { - meta->invokeFunction(c->init, OBJECT_TO_JS2VAL(result), NULL, 0); - } + meta->invokeInit(c, OBJECT_TO_JS2VAL(result), NULL, 0); return OBJECT_TO_JS2VAL(result); } diff --git a/mozilla/js2/src/js2engine.h b/mozilla/js2/src/js2engine.h index c278b79d2eb..a49878c154a 100644 --- a/mozilla/js2/src/js2engine.h +++ b/mozilla/js2/src/js2engine.h @@ -159,6 +159,7 @@ enum JS2Op { eBreak, // eNew, // eCall, // + eSuperCall, // eTypeof, eInstanceof, eIs, diff --git a/mozilla/js2/src/js2eval.cpp b/mozilla/js2/src/js2eval.cpp index 0ed20535b6b..39ceaa7e663 100644 --- a/mozilla/js2/src/js2eval.cpp +++ b/mozilla/js2/src/js2eval.cpp @@ -268,6 +268,15 @@ namespace MetaData { return retval; } + // Invoke the constructor function for a class, calling the super constructor as necessary + void JS2Metadata::invokeInit(JS2Class *c, js2val thisValue, js2val *argv, uint32 argc) + { + if (c->init) { + invokeFunction(c->init, thisValue, argv, argc); + } + + } + js2val JS2Metadata::invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc) { js2val result = JS2VAL_UNDEFINED; diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index fb608da5034..0c80e72279b 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -175,6 +175,7 @@ namespace MetaData { reportError(Exception::syntaxError, "A class constructor cannot be a getter or a setter", pos); // XXX shouldn't be using validateStaticFunction c->init = validateStaticFunction(cxt, env, fnDef, false, false, pos); + c->init->fWrap->compileFrame->isConstructor = true; } void JS2Metadata::validateInstance(Context *cxt, Environment *env, FunctionDefinition *fnDef, JS2Class *c, CompoundAttribute *a, bool final, size_t pos) @@ -1914,6 +1915,22 @@ namespace MetaData { f->obj = validateStaticFunction(cxt, env, &f->function, true, true, p->pos); } break; + case ExprNode::superStmt: + { + ParameterFrame *pFrame = env->getEnclosingParameterFrame(); + if ((pFrame == NULL) || !pFrame->isConstructor) + reportError(Exception::syntaxError, "A super statement is meaningful only inside a constructor", p->pos); + + InvokeExprNode *i = checked_cast(p); + ValidateExpression(cxt, env, i->op); + ExprPairList *args = i->pairs; + while (args) { + ValidateExpression(cxt, env, args->value); + args = args->next; + } + pFrame->callsSuperConstructor = true; + } + break; default: NOT_REACHED("Not Yet Implemented"); } // switch (p->getKind()) @@ -2638,7 +2655,7 @@ doUnary: argCount++; args = args->next; } - bCon->emitOp(eNew, p->pos, -(argCount + 1) + 1); // pop argCount args, the type/function, and push a result + bCon->emitOp(eNew, p->pos, -(argCount + 1) + 1); // pop argCount args, the type or function, and push a result bCon->addShort(argCount); } break; @@ -2675,6 +2692,21 @@ doUnary: bCon->addObject(f->obj); } break; + case ExprNode::superStmt: + { + InvokeExprNode *i = checked_cast(p); + ExprPairList *args = i->pairs; + uint16 argCount = 0; + while (args) { + Reference *r = SetupExprNode(env, phase, args->value, exprType); + if (r) r->emitReadBytecode(bCon, p->pos); + argCount++; + args = args->next; + } + bCon->emitOp(eSuperCall, p->pos, -argCount); // pop argCount args, no result + bCon->addShort(argCount); + } + break; default: NOT_REACHED("Not Yet Implemented"); } @@ -2700,6 +2732,28 @@ doUnary: return NULL; } + // If env is from with a function's body, return the innermost ParameterFrame for + // the innermost such function, otherwise return NULL + ParameterFrame *Environment::getEnclosingParameterFrame() + { + FrameListIterator fi = getBegin(); + while (fi != getEnd()) { + switch ((*fi)->kind) { + case ClassKind: + case PackageKind: + case SystemKind: + return NULL; + case ParameterFrameKind: + return checked_cast(*fi); + case BlockFrameKind: + case WithFrameKind: + break; + } + fi++; + } + return NULL; + } + // getRegionalEnvironment(env) returns all frames in env up to and including the first // regional frame. A regional frame is either any frame other than a with frame or local // block frame, a local block frame directly enclosed in a class, or a local block frame diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 4e87131e597..dcabb8ede53 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -699,6 +699,7 @@ public: Environment(Environment *e) : JS2Object(EnvironmentKind), frameList(e->frameList) { } JS2Class *getEnclosingClass(); + ParameterFrame *Environment::getEnclosingParameterFrame(); FrameListIterator getRegionalFrame(); FrameListIterator getRegionalEnvironment(); Frame *getTopFrame() { return frameList.front(); } @@ -1211,12 +1212,21 @@ public: : NonWithFrame(ParameterFrameKind), thisObject(thisObject), prototype(prototype), - buildArguments(false) { } + buildArguments(false), + isConstructor(false), + callsSuperConstructor(false), + superConstructorCalled(true) + { } ParameterFrame(ParameterFrame *pluralFrame) : NonWithFrame(ParameterFrameKind, pluralFrame), thisObject(JS2VAL_UNDEFINED), prototype(pluralFrame->prototype), - buildArguments(pluralFrame->buildArguments) { } + buildArguments(pluralFrame->buildArguments), + isConstructor(pluralFrame->isConstructor), + callsSuperConstructor(pluralFrame->callsSuperConstructor), + superConstructorCalled(false) // initialized to false for each construction of a singular frame + // and then set true when/if the call occurs + { } // Plurality plurality; js2val thisObject; // The value of this; none if this function doesn't define this; @@ -1225,6 +1235,9 @@ public: bool prototype; // true if this function is not an instance method but defines this anyway bool buildArguments; + bool isConstructor; + bool callsSuperConstructor; + bool superConstructorCalled; // Variable **positional; // list of positional parameters, in order // uint32 positionalCount; @@ -1388,6 +1401,7 @@ public: js2val invokeFunction(const char *fname); bool invokeFunctionOnObject(js2val thisValue, const String *fnName, js2val &result); js2val invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc); + void invokeInit(JS2Class *c, js2val thisValue, js2val* argv, uint32 argc); void createDynamicProperty(JS2Object *obj, QualifiedName *qName, js2val initVal, Access access, bool sealed, bool enumerable); void createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable); diff --git a/mozilla/js2/src/js2op_invocation.cpp b/mozilla/js2/src/js2op_invocation.cpp index 5cd315f5e6a..0dc9b648372 100644 --- a/mozilla/js2/src/js2op_invocation.cpp +++ b/mozilla/js2/src/js2op_invocation.cpp @@ -177,6 +177,21 @@ } break; + case eSuperCall: + { + uint16 argCount = BytecodeContainer::getShort(pc); + pc += sizeof(uint16); + ParameterFrame *pFrame = meta->env->getEnclosingParameterFrame(); + ASSERT(pFrame && (pFrame->isConstructor)); + if (pFrame->superConstructorCalled) + meta->reportError(Exception::referenceError, "The superconstructor cannot be called twice", errorPos()); + JS2Class *c = meta->env->getEnclosingClass(); + ASSERT(c); + ASSERT(!JS2VAL_IS_VOID(pFrame->thisObject)); + meta->invokeInit(c->super, pFrame->thisObject, base(argCount), argCount); + } + break; + case ePopv: { retval = pop();