From 8db2da07db99396c10e97bef780e1e65f3ebed16 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Thu, 8 May 2003 07:07:55 +0000 Subject: [PATCH] SuperConstructor call sequence. git-svn-id: svn://10.0.0.236/trunk@142196 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/src/exception.cpp | 3 +++ mozilla/js2/src/exception.h | 4 +++- mozilla/js2/src/js2array.cpp | 2 +- mozilla/js2/src/js2engine.cpp | 6 +++-- mozilla/js2/src/js2eval.cpp | 28 +++++++++++++++++------ mozilla/js2/src/js2metadata.cpp | 33 ++++++++++++++++------------ mozilla/js2/src/js2metadata.h | 4 ++-- mozilla/js2/src/js2op_invocation.cpp | 1 + 8 files changed, 54 insertions(+), 27 deletions(-) diff --git a/mozilla/js2/src/exception.cpp b/mozilla/js2/src/exception.cpp index 9d60cf813f1..4c5cc1ffc94 100644 --- a/mozilla/js2/src/exception.cpp +++ b/mozilla/js2/src/exception.cpp @@ -58,6 +58,9 @@ static const char *const kindStrings[] = { "Property access error", // you're at the wrong house "Uninitialized error", // read before write "Argument mismatch error", // bad argument type/number + "Attribute error", // illegal attribute error + "Constant error", // it just won't go away + "Arguments error" // an error in the arguments }; // Return a null-terminated string describing the exception's kind. diff --git a/mozilla/js2/src/exception.h b/mozilla/js2/src/exception.h index e74e35d0d11..3aff475535d 100644 --- a/mozilla/js2/src/exception.h +++ b/mozilla/js2/src/exception.h @@ -65,7 +65,9 @@ namespace JavaScript propertyAccessError, uninitializedError, argumentMismatchError, - attributeError + attributeError, + constantError, + argumentsError }; Kind kind; // The exception's kind diff --git a/mozilla/js2/src/js2array.cpp b/mozilla/js2/src/js2array.cpp index 27131a3ff13..1714b1f0646 100644 --- a/mozilla/js2/src/js2array.cpp +++ b/mozilla/js2/src/js2array.cpp @@ -549,7 +549,7 @@ static int32 sort_compare(js2val *a, js2val *b, CompareArgs *arg) js2val argv[2]; argv[0] = av; argv[1] = bv; - js2val v = meta->invokeFunction(ca->target, JS2VAL_NULL, argv, 2); + js2val v = meta->invokeFunction(ca->target, JS2VAL_NULL, argv, 2, NULL); float64 f = meta->toFloat64(v); if (JSDOUBLE_IS_NaN(f) || (f == 0)) result = 0; diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index 2206ffdaaf9..577d21c807a 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -961,15 +961,17 @@ namespace MetaData { // XXX Default construction of an instance of the class // that is the value of the passed in 'this' - js2val JS2Engine::defaultConstructor(JS2Metadata *meta, const js2val thisValue, js2val /* argv */ [], uint32 /* argc */) + js2val JS2Engine::defaultConstructor(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc) { ASSERT(JS2VAL_IS_OBJECT(thisValue) && !JS2VAL_IS_NULL(thisValue)); JS2Object *obj = JS2VAL_TO_OBJECT(thisValue); ASSERT(obj->kind == ClassKind); JS2Class *c = checked_cast(obj); + if (!c->complete) + meta->reportError(Exception::constantError, "Cannot construct an instance of a class before its definition has been compiled", meta->engine->errorPos()); SimpleInstance *result = new SimpleInstance(meta, c->prototype, c); DEFINE_ROOTKEEPER(rk, result); - meta->invokeInit(c, OBJECT_TO_JS2VAL(result), NULL, 0); + meta->invokeInit(c, OBJECT_TO_JS2VAL(result), argv, argc); return OBJECT_TO_JS2VAL(result); } diff --git a/mozilla/js2/src/js2eval.cpp b/mozilla/js2/src/js2eval.cpp index 39ceaa7e663..762e23585ae 100644 --- a/mozilla/js2/src/js2eval.cpp +++ b/mozilla/js2/src/js2eval.cpp @@ -231,7 +231,7 @@ namespace MetaData { JS2Object *fnObj = JS2VAL_TO_OBJECT(fnVal); if ((fnObj->kind == SimpleInstanceKind) && ((checked_cast(fnObj))->type == functionClass)) { - result = invokeFunction(fnObj, thisValue, NULL, 0); + result = invokeFunction(fnObj, thisValue, NULL, 0, NULL); return true; } } @@ -268,16 +268,29 @@ namespace MetaData { return retval; } - // Invoke the constructor function for a class, calling the super constructor as necessary + // Invoke the constructor function for a class void JS2Metadata::invokeInit(JS2Class *c, js2val thisValue, js2val *argv, uint32 argc) { - if (c->init) { - invokeFunction(c->init, thisValue, argv, argc); + FunctionInstance *init = NULL; + if (c) init = c->init; + if (init) { + ParameterFrame *runtimeFrame; + DEFINE_ROOTKEEPER(rk, runtimeFrame); + runtimeFrame = new ParameterFrame(init->fWrap->compileFrame); + if (!init->fWrap->compileFrame->callsSuperConstructor) { + invokeInit(c->super, thisValue, NULL, 0); + runtimeFrame->superConstructorCalled = true; + } + invokeFunction(init, thisValue, argv, argc, runtimeFrame); + if (!runtimeFrame->superConstructorCalled) + reportError(Exception::uninitializedError, "The superconstuctor must be called before returning normally from a constructor", engine->errorPos()); } - + else + if (argc) + reportError(Exception::argumentsError, "The default constructor does not take any arguments", engine->errorPos()); } - js2val JS2Metadata::invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc) + js2val JS2Metadata::invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc, ParameterFrame *runtimeFrame) { js2val result = JS2VAL_UNDEFINED; @@ -297,8 +310,9 @@ namespace MetaData { BytecodeContainer *bCon = fWrap->bCon; CompilationData *oldData = startCompilationUnit(bCon, bCon->mSource, bCon->mSourceLocation); - ParameterFrame *runtimeFrame = new ParameterFrame(fWrap->compileFrame); DEFINE_ROOTKEEPER(rk, runtimeFrame); + if (runtimeFrame == NULL) + runtimeFrame = new ParameterFrame(fWrap->compileFrame); runtimeFrame->instantiate(fWrap->env); runtimeFrame->thisObject = thisValue; runtimeFrame->assignArguments(this, fnObj, argv, argc, argc); diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 0c80e72279b..891712b8463 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -85,7 +85,7 @@ namespace MetaData { } } - FunctionInstance *JS2Metadata::validateStaticFunction(Context *cxt, Environment *env, FunctionDefinition *fnDef, bool prototype, bool unchecked, size_t pos) + FunctionInstance *JS2Metadata::validateStaticFunction(Context *cxt, Environment *env, FunctionDefinition *fnDef, bool prototype, bool unchecked, bool isConstructor, size_t pos) { js2val compileThis = JS2VAL_VOID; ParameterFrame *compileFrame = new ParameterFrame(compileThis, prototype); @@ -116,6 +116,7 @@ namespace MetaData { } createDynamicProperty(result, engine->length_StringAtom, INT_TO_JS2VAL(pCount), ReadAccess, true, false); result->fWrap->length = pCount; + compileFrame->isConstructor = isConstructor; ValidateStmt(cxt, env, Plural, fnDef->body); env->removeTopFrame(); } @@ -134,7 +135,7 @@ namespace MetaData { DEFINE_ROOTKEEPER(rk1, fnInst); switch (fnDef->prefix) { case FunctionName::normal: - fnInst = validateStaticFunction(cxt, env, fnDef, a->prototype, unchecked, pos); + fnInst = validateStaticFunction(cxt, env, fnDef, a->prototype, unchecked, false, pos); if (hoisted) defineHoistedVar(env, fnDef->name, OBJECT_TO_JS2VAL(fnInst), false, pos); else { @@ -148,7 +149,7 @@ namespace MetaData { reportError(Exception::attributeError, "A getter cannot have the prototype attribute", pos); ASSERT(!(unchecked || hoisted)); // XXX shouldn't be using validateStaticFunction - fnInst = validateStaticFunction(cxt, env, fnDef, false, false, pos); + fnInst = validateStaticFunction(cxt, env, fnDef, false, false, false, pos); Getter *g = new Getter(fnInst); defineLocalMember(env, fnDef->name, &a->namespaces, a->overrideMod, a->xplicit, ReadAccess, g, pos, true); } @@ -159,7 +160,7 @@ namespace MetaData { reportError(Exception::attributeError, "A setter cannot have the prototype attribute", pos); ASSERT(!(unchecked || hoisted)); // XXX shouldn't be using validateStaticFunction - fnInst = validateStaticFunction(cxt, env, fnDef, false, false, pos); + fnInst = validateStaticFunction(cxt, env, fnDef, false, false, false, pos); Setter *s = new Setter(fnInst); defineLocalMember(env, fnDef->name, &a->namespaces, a->overrideMod, a->xplicit, WriteAccess, s, pos, true); } @@ -174,8 +175,7 @@ namespace MetaData { if (fnDef->prefix != FunctionName::normal) 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; + c->init = validateStaticFunction(cxt, env, fnDef, false, false, true, pos); } void JS2Metadata::validateInstance(Context *cxt, Environment *env, FunctionDefinition *fnDef, JS2Class *c, CompoundAttribute *a, bool final, size_t pos) @@ -185,7 +185,7 @@ namespace MetaData { // XXX shouldn't be using validateStaticFunction FunctionInstance *fnInst = NULL; DEFINE_ROOTKEEPER(rk1, fnInst); - fnInst = validateStaticFunction(cxt, env, fnDef, false, false, pos); + fnInst = validateStaticFunction(cxt, env, fnDef, false, false, false, pos); Multiname *mn = new Multiname(fnDef->name, a->namespaces); InstanceMember *m; switch (fnDef->prefix) { @@ -695,6 +695,8 @@ namespace MetaData { ASSERT(env->getTopFrame() == c); env->removeTopFrame(); } + if (c->init == NULL) + c->init = superClass->init; c->complete = true; } break; @@ -1421,7 +1423,9 @@ namespace MetaData { ExprStmtNode *e = checked_cast(p); Reference *r = SetupExprNode(env, phase, e->expr, &exprType); if (r) r->emitReadBytecode(bCon, p->pos); - bCon->emitOp(ePopv, p->pos); + // superStmt expressions don't produce any result value + if (e->expr->getKind() != ExprNode::superStmt) + bCon->emitOp(ePopv, p->pos); } break; case StmtNode::Namespace: @@ -1912,7 +1916,7 @@ namespace MetaData { case ExprNode::functionLiteral: { FunctionExprNode *f = checked_cast(p); - f->obj = validateStaticFunction(cxt, env, &f->function, true, true, p->pos); + f->obj = validateStaticFunction(cxt, env, &f->function, true, true, false, p->pos); } break; case ExprNode::superStmt: @@ -1922,7 +1926,6 @@ namespace MetaData { 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); @@ -4161,7 +4164,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... case Member::InstanceGetterMember: { InstanceGetter *ig = checked_cast(m); - *rval = invokeFunction(ig->fInst, containerVal, NULL, 0); + *rval = invokeFunction(ig->fInst, containerVal, NULL, 0, NULL); return true; } default: @@ -4186,7 +4189,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... case Member::InstanceSetterMember: { InstanceSetter *is = checked_cast(m); - invokeFunction(is->fInst, containerVal, &newValue, 1); + invokeFunction(is->fInst, containerVal, &newValue, 1, NULL); return true; } default: @@ -4248,7 +4251,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... case LocalMember::GetterMember: { Getter *g = checked_cast(m); - *rval = invokeFunction(g->code, JS2VAL_VOID, NULL, 0); + *rval = invokeFunction(g->code, JS2VAL_VOID, NULL, 0, NULL); } return true; case LocalMember::SetterMember: @@ -4313,7 +4316,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... case LocalMember::SetterMember: { Setter *s = checked_cast(m); - invokeFunction(s->code, JS2VAL_VOID, &newValue, 1); + invokeFunction(s->code, JS2VAL_VOID, &newValue, 1, NULL); } return true; } @@ -4585,7 +4588,9 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... GCMARKOBJECT(super) GCMARKVALUE(prototype); GCMARKOBJECT(privateNamespace) + GCMARKOBJECT(init) if (typeofString) JS2Object::mark(typeofString); + if (name) JS2Object::mark(name); GCMARKVALUE(defaultValue); for (InstanceBindingIterator rib = instanceBindings.begin(), riend = instanceBindings.end(); (rib != riend); rib++) { InstanceBindingEntry *ibe = *rib; diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index dcabb8ede53..9878a1f40a4 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -1360,7 +1360,7 @@ public: void ValidateStmt(Context *cxt, Environment *env, Plurality pl, StmtNode *p); void ValidateExpression(Context *cxt, Environment *env, ExprNode *p); void ValidateAttributeExpression(Context *cxt, Environment *env, ExprNode *p); - FunctionInstance *validateStaticFunction(Context *cxt, Environment *env, FunctionDefinition *fnDef, bool prototype, bool unchecked, size_t pos); + FunctionInstance *validateStaticFunction(Context *cxt, Environment *env, FunctionDefinition *fnDef, bool prototype, bool unchecked, bool isConstructor, size_t pos); void validateStatic(Context *cxt, Environment *env, FunctionDefinition *fnDef, CompoundAttribute *a, bool unchecked, bool hoisted, size_t pos); void validateConstructor(Context *cxt, Environment *env, FunctionDefinition *fnDef, JS2Class *c, CompoundAttribute *a, size_t pos); @@ -1400,7 +1400,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); + js2val invokeFunction(JS2Object *fnObj, js2val thisValue, js2val *argv, uint32 argc, ParameterFrame *runtimeFrame); void invokeInit(JS2Class *c, js2val thisValue, js2val* argv, uint32 argc); void createDynamicProperty(JS2Object *obj, QualifiedName *qName, 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 0dc9b648372..545363c3af0 100644 --- a/mozilla/js2/src/js2op_invocation.cpp +++ b/mozilla/js2/src/js2op_invocation.cpp @@ -189,6 +189,7 @@ ASSERT(c); ASSERT(!JS2VAL_IS_VOID(pFrame->thisObject)); meta->invokeInit(c->super, pFrame->thisObject, base(argCount), argCount); + pFrame->superConstructorCalled = true; } break;