diff --git a/mozilla/js2/src/bytecodecontainer.h b/mozilla/js2/src/bytecodecontainer.h index 673487b0e8f..0f9259ae3e2 100644 --- a/mozilla/js2/src/bytecodecontainer.h +++ b/mozilla/js2/src/bytecodecontainer.h @@ -49,6 +49,7 @@ namespace MetaData { class Multiname; +class Frame; class BytecodeContainer { public: @@ -85,8 +86,10 @@ public: static uint16 getShort(void *pc) { return *((uint16 *)pc); } void addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addShort(mMultinameList.size() - 1); } - static Multiname *getMultiname(void *pc){ return (Multiname *)getLong(pc); } + void addFrame(Frame *f) { mFrameList.push_back(f); addShort(mFrameList.size() - 1); } + + void addString(const StringAtom &x, size_t pos) { emitOp(eString, pos); addPointer(&x); } void addString(String &x, size_t pos) { emitOp(eString, pos); addPointer(&x); } void addString(String *x, size_t pos) { emitOp(eString, pos); addPointer(x); } @@ -97,6 +100,7 @@ public: CodeBuffer mBuffer; std::vector mMultinameList; // gc tracking + std::vector mFrameList; // gc tracking int32 mStackTop; // keep these as signed so as to int32 mStackMax; // track if they go negative. diff --git a/mozilla/js2/src/epimetheus.cpp b/mozilla/js2/src/epimetheus.cpp index 965c1649da7..c65ac311fb7 100644 --- a/mozilla/js2/src/epimetheus.cpp +++ b/mozilla/js2/src/epimetheus.cpp @@ -147,7 +147,7 @@ static int readEvalPrint(FILE *in) metadata->setCurrentParser(&p); // for error reporting metadata->ValidateStmtList(parsedStatements); - js2val rval = metadata->EvalStmtList(RunPhase, parsedStatements); + js2val rval = metadata->ExecuteStmtList(RunPhase, parsedStatements); if (!JS2VAL_IS_VOID(rval)) stdOut << *metadata->engine->toString(rval) << '\n'; } diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index 094841ed827..51e610ee270 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -209,6 +209,7 @@ JS2Engine::JS2Engine(World &world) INIT_STRINGATOM(null), INIT_STRINGATOM(undefined), INIT_STRINGATOM(public), + INIT_STRINGATOM(private), INIT_STRINGATOM(object) { nanValue = (float64 *)gc_alloc_8(); @@ -245,8 +246,9 @@ int JS2Engine::getStackEffect(JS2Op op) case eMultiname: return 1; // push the multiname object - case eUse: - return -1; // consume a namespace object + case ePushFrame: + case ePopFrame: + return 0; default: ASSERT(false); diff --git a/mozilla/js2/src/js2engine.h b/mozilla/js2/src/js2engine.h index f9844b6a401..a15f15dc6b0 100644 --- a/mozilla/js2/src/js2engine.h +++ b/mozilla/js2/src/js2engine.h @@ -61,7 +61,8 @@ enum JS2Op { eReturnVoid, eNewObject, // eMultiname, // - eUse, + ePushFrame, // + ePopFrame }; @@ -111,6 +112,7 @@ public: StringAtom &null_StringAtom; StringAtom &undefined_StringAtom; StringAtom &public_StringAtom; + StringAtom &private_StringAtom; StringAtom &object_StringAtom; js2val *execStack; diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index d1d2cd0ef8b..cef8f92d987 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -71,8 +71,6 @@ namespace MetaData { * Validate the linked list of statement nodes beginning at 'p' */ void JS2Metadata::ValidateStmtList(StmtNode *p) { - cxt.openNamespaces.clear(); - cxt.openNamespaces.push_back(publicNamespace); while (p) { ValidateStmt(&cxt, &env, p); p = p->next; @@ -192,14 +190,67 @@ namespace MetaData { } } break; + case StmtNode::Class: + { + ClassStmtNode *classStmt = checked_cast(p); + JS2Class *superClass = objectClass; + if (classStmt->superclass) { + ValidateExpression(cxt, env, classStmt->superclass); + js2val av = EvalExpression(env, CompilePhase, classStmt->superclass); + if (JS2VAL_IS_NULL(av) || !JS2VAL_IS_OBJECT(av)) + reportError(Exception::badValueError, "Class expected in inheritance", p->pos); + JS2Object *obj = JS2VAL_TO_OBJECT(av); + if (obj->kind != ClassKind) + reportError(Exception::badValueError, "Class expected in inheritance", p->pos); + superClass = checked_cast(obj); + } + Attribute *attr = NULL; + if (classStmt->attributes) { + ValidateAttributeExpression(cxt, env, classStmt->attributes); + attr = EvalAttributeExpression(env, CompilePhase, classStmt->attributes); + } + CompoundAttribute *a = Attribute::toCompoundAttribute(attr); + if (!superClass->complete || superClass->final) + reportError(Exception::definitionError, "Illegal inheritance", p->pos); + JS2Object *proto = NULL; + bool final; + switch (a->memberMod) { + case Attribute::NoModifier: + final = false; + break; + case Attribute::Static: + if (env->getTopFrame()->kind != ClassKind) + reportError(Exception::definitionError, "Illegal use of static modifier", p->pos); + final = false; + break; + case Attribute::Final: + final = true; + break; + default: + reportError(Exception::definitionError, "Illegal modifier for class definition", p->pos); + break; + } + JS2Class *c = new JS2Class(superClass, proto, new Namespace(engine->public_StringAtom), (a->dynamic || superClass->dynamic), final); + classStmt->c = c; + Variable *v = new Variable(classClass, OBJECT_TO_JS2VAL(c), true); + defineStaticMember(env, classStmt->name, a->namespaces, a->overrideMod, a->xplicit, ReadWriteAccess, v, p->pos); + if (classStmt->body) { + env->addFrame(c); + ValidateStmtList(cxt, env, classStmt->body->statements); + ASSERT(env->getTopFrame() == c); + env->removeTopFrame(); + } + c->complete = true; + } } // switch (p->getKind()) } + /* - * Evaluate the linked list of statement nodes beginning at 'p' (generate bytecode) - * and then execute that bytecode + * Evaluate the linked list of statement nodes beginning at 'p' + * (generate bytecode and then execute that bytecode */ - js2val JS2Metadata::EvalStmtList(Phase phase, StmtNode *p) + js2val JS2Metadata::ExecuteStmtList(Phase phase, StmtNode *p) { BytecodeContainer *saveBacon = bCon; bCon = new BytecodeContainer(); @@ -267,6 +318,25 @@ namespace MetaData { { } break; + case StmtNode::Class: + { + ClassStmtNode *classStmt = checked_cast(p); + JS2Class *c = classStmt->c; + if (classStmt->body) { + env->addFrame(c); + bCon->emitOp(ePushFrame, p->pos); + bCon->addFrame(c); + StmtNode *bp = classStmt->body->statements; + while (bp) { + EvalStmt(env, phase, bp); + bp = bp->next; + } + ASSERT(env->getTopFrame() == c); + env->removeTopFrame(); + bCon->emitOp(ePopFrame, p->pos); + } + } + break; default: NOT_REACHED("Not Yet Implemented"); } // switch (p->getKind()) @@ -970,6 +1040,8 @@ namespace MetaData { glob(world), env(new MetaData::SystemFrame(), &glob) { + cxt.openNamespaces.clear(); + cxt.openNamespaces.push_back(publicNamespace); } // objectType(o) returns an OBJECT o's most specific type. @@ -1365,6 +1437,27 @@ namespace MetaData { nextPond->moveUnmarkedToFreeList(); } + + /************************************************************************************ + * + * JS2Class + * + ************************************************************************************/ + + JS2Class::JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final) + : Frame(ClassKind), + instanceInitOrder(NULL), + complete(false), + super(super), + prototype(proto), + privateNamespace(privateNamespace), + dynamic(dynamic), + primitive(false), + final(final), + call(NULL), + construct(NULL) + { } + /************************************************************************************ * * JS2Object diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 3c45e06d413..856aaac4389 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -353,7 +353,7 @@ public: class JS2Class : public Frame { public: - JS2Class() : Frame(ClassKind) { } + JS2Class(JS2Class *super, JS2Object *proto, Namespace *privateNamespace, bool dynamic, bool final); StringAtom &getName(); @@ -559,6 +559,9 @@ public: Frame *getTopFrame() { return firstFrame; } Frame *getPackageOrGlobalFrame(); + void addFrame(Frame *f) { f->nextFrame = firstFrame; firstFrame = f; } + void removeTopFrame() { firstFrame = firstFrame->nextFrame; } + js2val findThis(bool allowPrototypeThis); js2val lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase); void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing, Phase phase); @@ -629,7 +632,7 @@ public: void ValidateExpression(Context *cxt, Environment *env, ExprNode *p); void ValidateAttributeExpression(Context *cxt, Environment *env, ExprNode *p); - js2val EvalStmtList(Environment *env, Phase phase, StmtNode *p); + js2val ExecuteStmtList(Phase phase, StmtNode *p); js2val EvalExpression(Environment *env, Phase phase, ExprNode *p); Reference *EvalExprNode(Environment *env, Phase phase, ExprNode *p); Attribute *EvalAttributeExpression(Environment *env, Phase phase, ExprNode *p); @@ -680,6 +683,7 @@ public: JS2Class *stringClass; JS2Class *objectClass; JS2Class *namespaceClass; + JS2Class *classClass; Parser *mParser; // used for error reporting diff --git a/mozilla/js2/src/js2op_access.cpp b/mozilla/js2/src/js2op_access.cpp index 4994844a850..9da4336c0d9 100644 --- a/mozilla/js2/src/js2op_access.cpp +++ b/mozilla/js2/src/js2op_access.cpp @@ -33,62 +33,49 @@ // Get a multiname literal and add the currently open namespaces from the context // Push the resulting multiname object - case eMultiname: { - Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; - pc += sizeof(short); - mn->addNamespace(meta->cxt); - push(OBJECT_TO_JS2VAL(mn)); - } - break; -#if 0 - // Get a multiname literal and pop a namespace value to add to it - // Push the resulting multiname object - case eQMultiname: { - js2val nsVal = pop(); - if (!JS2VAL_IS_OBJECT(nsVal)) - meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos); - JS2Object *obj = JS2VAL_TO_OBJECT(nsVal); - if ((obj->kind != AttributeObjectKind) || ((checked_cast(obj))->attrKind != Attribute::NamespaceAttr)) - meta->reportError(Exception::badValueError, "Expected a namespace", meta->errorPos); - Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; - pc += sizeof(short); - mn->addNamespace(checked_cast(obj)); - push(OBJECT_TO_JS2VAL(mn)); - } - break; -#endif + case eMultiname: + { + Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; + pc += sizeof(short); + mn->addNamespace(meta->cxt); + push(OBJECT_TO_JS2VAL(mn)); + } + break; + // Pop a multiname object and read it's value from the environment on to the stack. - case eLexicalRead: { - js2val mnVal = pop(); - ASSERT(JS2VAL_IS_OBJECT(mnVal)); - JS2Object *obj = JS2VAL_TO_OBJECT(mnVal); - Multiname *mn = checked_cast(obj); - retval = meta->env.lexicalRead(meta, mn, phase); - push(retval); - } - break; + case eLexicalRead: + { + js2val mnVal = pop(); + ASSERT(JS2VAL_IS_OBJECT(mnVal)); + JS2Object *obj = JS2VAL_TO_OBJECT(mnVal); + Multiname *mn = checked_cast(obj); + retval = meta->env.lexicalRead(meta, mn, phase); + push(retval); + } + break; // Pop a value and a multiname. Write the value to the multiname in the environment, leave // the value on the stack top. - case eLexicalWrite: { - retval = pop(); - js2val mnVal = pop(); - ASSERT(JS2VAL_IS_OBJECT(mnVal)); - JS2Object *obj = JS2VAL_TO_OBJECT(mnVal); - Multiname *mn = checked_cast(obj); - meta->env.lexicalWrite(meta, mn, retval, true, phase); - push(retval); - } - break; + case eLexicalWrite: + { + retval = pop(); + js2val mnVal = pop(); + ASSERT(JS2VAL_IS_OBJECT(mnVal)); + JS2Object *obj = JS2VAL_TO_OBJECT(mnVal); + Multiname *mn = checked_cast(obj); + meta->env.lexicalWrite(meta, mn, retval, true, phase); + push(retval); + } + break; - // Pop a namespace object and add it to the list of currently open namespaces in the context - case eUse: { - js2val nsVal = pop(); - if (!JS2VAL_IS_OBJECT(nsVal)) - meta->reportError(Exception::badValueError, "Expected a namespace", meta->engine->errorPos()); - JS2Object *obj = JS2VAL_TO_OBJECT(nsVal); - if ((obj->kind != AttributeObjectKind) || ((checked_cast(obj))->attrKind != Attribute::NamespaceAttr)) - meta->reportError(Exception::badValueError, "Expected a namespace", meta->engine->errorPos()); + case ePushFrame: + { + Frame *f = bCon->mFrameList[BytecodeContainer::getShort(pc)]; + pc += sizeof(short); + } + break; - } - break; \ No newline at end of file + case ePopFrame: + { + } + break; \ No newline at end of file diff --git a/mozilla/js2/src/parser.h b/mozilla/js2/src/parser.h index 6a12f73824b..8163e623ac9 100644 --- a/mozilla/js2/src/parser.h +++ b/mozilla/js2/src/parser.h @@ -59,6 +59,7 @@ namespace JavaScript { #ifdef EPIMETHEUS namespace MetaData { class Context; + class JS2Class; } #endif @@ -678,7 +679,9 @@ namespace JavaScript { #ifdef DIKDIK JS2Runtime::JSType *mType; // used by backend #endif - +#ifdef EPIMETHEUS + MetaData::JS2Class *c; +#endif ClassStmtNode(size_t pos, ExprNode *attributes, const StringAtom &name, ExprNode *superclass, BlockStmtNode *body): NamespaceStmtNode(pos, Class, attributes, name), superclass(superclass), body(body) {}