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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -159,6 +159,7 @@ enum JS2Op {
|
||||
eBreak, // <branch displacement:s32> <blockCount:u16>
|
||||
eNew, // <argCount:u16>
|
||||
eCall, // <argCount:u16>
|
||||
eSuperCall, // <argCount:u16>
|
||||
eTypeof,
|
||||
eInstanceof,
|
||||
eIs,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user