Super constructor call sequence and super statement.

git-svn-id: svn://10.0.0.236/trunk@142187 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
rogerl%netscape.com
2003-05-07 22:59:25 +00:00
parent 52ecce675e
commit ba3c57bef0
6 changed files with 103 additions and 11 deletions

View File

@@ -595,12 +595,13 @@ namespace MetaData {
{ ePopFrame, "PopFrame", 0 },
{ eWithin, "With", 0 },
{ eWithout, "EndWith", 0 },
{ eBranchFalse, "BranchFalse", BRANCH_OFFSET }, // <branch displacement:s32> XXX save space with short and long versions instead ?
{ eBranchTrue, "BranchTrue", BRANCH_OFFSET }, // <branch displacement:s32>
{ eBranch, "Branch", BRANCH_OFFSET }, // <branch displacement:s32>
{ eBreak, "Break", BREAK_OFFSET_AND_COUNT }, // <branch displacement:s32> <blockCount:u16>
{ eNew, "New", U16 }, // <argCount:u16>
{ eBranchFalse, "BranchFalse", BRANCH_OFFSET }, // <branch displacement:s32> XXX save space with short and long versions instead ?
{ eBranchTrue, "BranchTrue", BRANCH_OFFSET }, // <branch displacement:s32>
{ eBranch, "Branch", BRANCH_OFFSET }, // <branch displacement:s32>
{ eBreak, "Break", BREAK_OFFSET_AND_COUNT }, // <branch displacement:s32> <blockCount:u16>
{ eNew, "New", U16 }, // <argCount:u16>
{ eCall, "Call", U16 }, // <argCount:u16>
{ eSuperCall, "SuperCall", U16 }, // <argCount:u16>
{ eTypeof, "Typeof", 0 },
{ eInstanceof, "Instanceof", 0 },
{ eIs, "Is", 0 },
@@ -968,9 +969,7 @@ namespace MetaData {
JS2Class *c = checked_cast<JS2Class *>(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);
}

View File

@@ -159,6 +159,7 @@ enum JS2Op {
eBreak, // <branch displacement:s32> <blockCount:u16>
eNew, // <argCount:u16>
eCall, // <argCount:u16>
eSuperCall, // <argCount:u16>
eTypeof,
eInstanceof,
eIs,

View File

@@ -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;

View File

@@ -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<InvokeExprNode *>(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<InvokeExprNode *>(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<ParameterFrame *>(*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

View File

@@ -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);

View File

@@ -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();