SuperConstructor call sequence.
git-svn-id: svn://10.0.0.236/trunk@142196 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
parent
832cb868ca
commit
8db2da07db
@ -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.
|
||||
|
||||
@ -65,7 +65,9 @@ namespace JavaScript
|
||||
propertyAccessError,
|
||||
uninitializedError,
|
||||
argumentMismatchError,
|
||||
attributeError
|
||||
attributeError,
|
||||
constantError,
|
||||
argumentsError
|
||||
};
|
||||
|
||||
Kind kind; // The exception's kind
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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<JS2Class *>(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);
|
||||
}
|
||||
|
||||
|
||||
@ -231,7 +231,7 @@ namespace MetaData {
|
||||
JS2Object *fnObj = JS2VAL_TO_OBJECT(fnVal);
|
||||
if ((fnObj->kind == SimpleInstanceKind)
|
||||
&& ((checked_cast<SimpleInstance *>(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);
|
||||
|
||||
@ -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<ExprStmtNode *>(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<FunctionExprNode *>(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<InvokeExprNode *>(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<InstanceGetter *>(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<InstanceSetter *>(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<Getter *>(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<Setter *>(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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user