From 36ebbbe9b24573c9aa41e4e6b412b7b08a93e656 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Sat, 24 Aug 2002 04:10:42 +0000 Subject: [PATCH] Disneyland progress. --- js2/src/bytecodecontainer.cpp | 8 ++ js2/src/bytecodecontainer.h | 21 +++- js2/src/js2engine.cpp | 15 ++- js2/src/js2engine.h | 13 ++- js2/src/js2metadata.cpp | 212 ++++++++++++++++++++++++++++++---- js2/src/js2metadata.h | 87 ++++++++++---- js2/src/js2op_access.cpp | 10 +- js2/src/js2op_invocation.cpp | 17 ++- js2/src/js2op_literal.cpp | 6 + 9 files changed, 327 insertions(+), 62 deletions(-) diff --git a/js2/src/bytecodecontainer.cpp b/js2/src/bytecodecontainer.cpp index 31b92fcab7a0..70d8a7e36367 100644 --- a/js2/src/bytecodecontainer.cpp +++ b/js2/src/bytecodecontainer.cpp @@ -32,6 +32,14 @@ * file under either the NPL or the GPL. */ +#ifdef _WIN32 + // Turn off warnings about identifiers too long in browser information +#pragma warning(disable: 4786) +#pragma warning(disable: 4711) +#pragma warning(disable: 4710) +#endif + + #include #include diff --git a/js2/src/bytecodecontainer.h b/js2/src/bytecodecontainer.h index b2435029c980..86a232fcf329 100644 --- a/js2/src/bytecodecontainer.h +++ b/js2/src/bytecodecontainer.h @@ -60,20 +60,33 @@ public: void emitOp(JS2Op op) { adjustStack(op); addByte((uint8)op); } - void adjustStack(JS2Op op) { mStackTop += JS2Engine::getStackEffect(op); if (mStackTop > mStackMax) mStackMax = mStackTop; ASSERT(mStackTop >= 0); } + void emitOp(JS2Op op, int32 effect) { adjustStack(op, effect); addByte((uint8)op); } + + void adjustStack(JS2Op op) { adjustStack(op, JS2Engine::getStackEffect(op)); } + void adjustStack(JS2Op op, int32 effect){ mStackTop += effect; if (mStackTop > mStackMax) mStackMax = mStackTop; ASSERT(mStackTop >= 0); } void addByte(uint8 v) { mBuffer->push_back(v); } - void addPointer(void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); } + void addPointer(const void *v) { ASSERT(sizeof(void *) == sizeof(uint32)); addLong((uint32)(v)); } + static void *getPointer(void *pc) { return (void *)getLong(pc); } void addFloat64(float64 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(float64)); } static float64 getFloat64(void *pc) { return *((float64 *)pc); } - void addLong(uint32 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); } + void addLong(const uint32 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint32)); } static uint32 getLong(void *pc) { return *((uint32 *)pc); } - void addMultiname(Multiname *mn) { mMultinameList.push_back(mn); addPointer(mn); } + void addShort(uint16 v) { mBuffer->insert(mBuffer->end(), (uint8 *)&v, (uint8 *)(&v) + sizeof(uint16)); } + 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 addString(const StringAtom &x) { emitOp(eString); addPointer(&x); } + void addString(String &x) { emitOp(eString); addPointer(&x); } + void addString(String *x) { emitOp(eString); addPointer(x); } + static String *getString(void *pc) { return (String *)getPointer(pc); } + // XXX We lose StringAtom here - is there anyway of stashing these in a bytecodecontainer? typedef std::vector CodeBuffer; diff --git a/js2/src/js2engine.cpp b/js2/src/js2engine.cpp index ac534757e9c4..4895f951964c 100644 --- a/js2/src/js2engine.cpp +++ b/js2/src/js2engine.cpp @@ -61,9 +61,10 @@ namespace JavaScript { namespace MetaData { -js2val JS2Engine::interpret(JS2Metadata *metadata, Phase execPhase, uint8 *start) +js2val JS2Engine::interpret(JS2Metadata *metadata, Phase execPhase, BytecodeContainer *targetbCon) { - pc = start; + bCon = targetbCon; + pc = bCon->getCodeStart(); meta = metadata; phase = execPhase; return interpreterLoop(); @@ -171,6 +172,9 @@ js2val JS2Engine::convertValueToPrimitive(js2val x) // return [[DefaultValue]] --> get property 'toString' and invoke it, // if not available or result is not primitive then try property 'valueOf' // if that's not available or returns a non primitive, throw a TypeError + + return STRING_TO_JS2VAL(&object_StringAtom); + ASSERT(false); return JS2VAL_VOID; } @@ -196,11 +200,13 @@ float64 JS2Engine::convertValueToDouble(js2val x) #define INIT_STRINGATOM(n) n##_StringAtom(world.identifiers[#n]) JS2Engine::JS2Engine(World &world) - : INIT_STRINGATOM(true), + : world(world), + INIT_STRINGATOM(true), INIT_STRINGATOM(false), INIT_STRINGATOM(null), INIT_STRINGATOM(undefined), - INIT_STRINGATOM(public) + INIT_STRINGATOM(public), + INIT_STRINGATOM(object) { nanValue = (float64 *)gc_alloc_8(); *nanValue = nan; @@ -218,6 +224,7 @@ int JS2Engine::getStackEffect(JS2Op op) case eReturn: case ePlus: return -1; + case eString: case eTrue: case eFalse: case eNumber: diff --git a/js2/src/js2engine.h b/js2/src/js2engine.h index 024a1324c679..94d1eb606c48 100644 --- a/js2/src/js2engine.h +++ b/js2/src/js2engine.h @@ -53,22 +53,25 @@ enum JS2Op { eTrue, eFalse, eNumber, + eString, // + eObject, // eLexicalRead, // eLexicalWrite, // eReturn, - eReturnVoid + eReturnVoid, + eNewObject // }; class JS2Metadata; - +class BytecodeContainer; class JS2Engine { public: JS2Engine(World &world); - js2val interpret(JS2Metadata *metadata, Phase execPhase, uint8 *start); + js2val interpret(JS2Metadata *metadata, Phase execPhase, BytecodeContainer *targetbCon); js2val interpreterLoop(); @@ -91,8 +94,10 @@ public: float64 toNumber(js2val x) { if (JS2VAL_IS_INT(x)) return JS2VAL_TO_INT(x); else if (JS2VAL_IS_DOUBLE(x)) return *JS2VAL_TO_DOUBLE(x); else return convertValueToDouble(x); } uint8 *pc; + BytecodeContainer *bCon; JS2Metadata *meta; Phase phase; + World &world; float64 *nanValue; float64 *float64Table[256]; @@ -102,6 +107,7 @@ public: StringAtom &null_StringAtom; StringAtom &undefined_StringAtom; StringAtom &public_StringAtom; + StringAtom &object_StringAtom; js2val *execStack; js2val *sp; @@ -113,6 +119,7 @@ public: }; +String *numberToString(float64 *number); diff --git a/js2/src/js2metadata.cpp b/js2/src/js2metadata.cpp index 65b86c80cd2a..302caef9c504 100644 --- a/js2/src/js2metadata.cpp +++ b/js2/src/js2metadata.cpp @@ -120,8 +120,8 @@ namespace MetaData { while (v) { ValidateTypeExpression(v->type); - if (cxt->strict && ((regionalFrame->kind == Frame::GlobalObject) - || (regionalFrame->kind == Frame::Function)) + if (cxt->strict && ((regionalFrame->kind == GlobalObjectKind) + || (regionalFrame->kind == FunctionKind)) && (p->getKind() == StmtNode::Var) // !immutable && (vs->attributes == NULL) && (v->type == NULL)) { @@ -132,7 +132,7 @@ namespace MetaData { if (a->dynamic || a->prototype) reportError(Exception::definitionError, "Illegal attribute", p->pos); Attribute::MemberModifier memberMod = a->memberMod; - if ((env->getTopFrame()->kind == Frame::Class) + if ((env->getTopFrame()->kind == ClassKind) && (memberMod == Attribute::NoModifier)) memberMod = Attribute::Final; switch (memberMod) { @@ -168,7 +168,7 @@ namespace MetaData { p = p->next; } bCon->emitOp(eReturnVoid); - return engine->interpret(this, phase, bCon->getCodeStart()); + return engine->interpret(this, phase, bCon); } /* @@ -458,6 +458,16 @@ namespace MetaData { void JS2Metadata::ValidateExpression(Context *cxt, Environment *env, ExprNode *p) { switch (p->getKind()) { + case ExprNode::number: + case ExprNode::boolean: + break; + case ExprNode::objectLiteral: + break; + case ExprNode::dot: + { + } + break; + case ExprNode::assignment: case ExprNode::add: { @@ -471,6 +481,8 @@ namespace MetaData { // IdentifierExprNode *i = checked_cast(p); } break; + default: + NOT_REACHED("Not Yet Implemented"); } // switch (p->getKind()) } @@ -483,7 +495,7 @@ namespace MetaData { { EvalExprNode(env, phase, p); bCon->emitOp(eReturnVoid); - return engine->interpret(this, phase, bCon->getCodeStart()); + return engine->interpret(this, phase, bCon); } /* @@ -494,10 +506,6 @@ namespace MetaData { Reference *returnRef = NULL; switch (p->getKind()) { - case ExprNode::index: - { - } - break; case ExprNode::assignment: { @@ -542,7 +550,7 @@ namespace MetaData { case ExprNode::identifier: { IdentifierExprNode *i = checked_cast(p); - returnRef = new LexicalReference(new Multiname(i->name, cxt), env, cxt.strict); + returnRef = new LexicalReference(i->name, cxt.strict); } break; case ExprNode::boolean: @@ -552,6 +560,38 @@ namespace MetaData { bCon->emitOp(eFalse); break; case ExprNode::objectLiteral: + { + uint32 argCount = 0; + PairListExprNode *plen = checked_cast(p); + ExprPairList *e = plen->pairs; + while (e) { + ASSERT(e->field && e->value); + Reference *rVal = EvalExprNode(env, phase, e->value); + if (rVal) rVal->emitReadBytecode(bCon); + switch (e->field->getKind()) { + case ExprNode::identifier: + bCon->addString(checked_cast(e->field)->name); + break; + case ExprNode::string: + bCon->addString(checked_cast(e->field)->str); + break; + case ExprNode::number: + bCon->addString(numberToString(&(checked_cast(e->field))->value)); + break; + default: + NOT_REACHED("bad field name"); + } + argCount++; + e = e->next; + } + bCon->emitOp(eNewObject, -argCount + 1); + bCon->addShort(argCount); + } + break; + case ExprNode::dot: + { + BinaryExprNode *b = checked_cast(p); + } break; default: NOT_REACHED("Not Yet Implemented"); @@ -574,7 +614,7 @@ namespace MetaData { JS2Class *Environment::getEnclosingClass() { Frame *pf = firstFrame; - while (pf && (pf->kind != Frame::Class)) + while (pf && (pf->kind != ClassKind)) pf = pf->nextFrame; return checked_cast(pf); } @@ -584,11 +624,11 @@ namespace MetaData { { Frame *pf = firstFrame; Frame *prev = NULL; - while (pf->kind == Frame::Block) { + while (pf->kind == BlockKind) { prev = pf; pf = pf->nextFrame; } - if (pf->nextFrame && (pf->kind == Frame::Class)) + if (pf->nextFrame && (pf->kind == ClassKind)) pf = prev; return pf; } @@ -610,7 +650,7 @@ namespace MetaData { { Frame *pf = firstFrame; while (pf) { - if ((pf->kind == Frame::Function) + if ((pf->kind == FunctionKind) && !JS2VAL_IS_NULL(checked_cast(pf)->thisObject)) if (allowPrototypeThis || !checked_cast(pf)->prototype) return checked_cast(pf)->thisObject; @@ -651,7 +691,7 @@ namespace MetaData { } if (createIfMissing) { pf = getPackageOrGlobalFrame(); - if (pf->kind == Frame::GlobalObject) { + if (pf->kind == GlobalObjectKind) { if (meta->writeProperty(pf, multiname, &lookup, true, newValue, phase)) return; } @@ -705,7 +745,7 @@ namespace MetaData { { QualifiedName qName(publicNamespace, id); Frame *regionalFrame = env->getRegionalFrame(); - ASSERT((env->getTopFrame()->kind == Frame::GlobalObject) || (env->getTopFrame()->kind == Frame::Function)); + ASSERT((env->getTopFrame()->kind == GlobalObjectKind) || (env->getTopFrame()->kind == FunctionKind)); // run through all the existing bindings, both read and write, to see if this // variable already exists. @@ -734,7 +774,7 @@ namespace MetaData { } } if (!existing) { - if (regionalFrame->kind == Frame::GlobalObject) { + if (regionalFrame->kind == GlobalObjectKind) { GlobalObject *gObj = checked_cast(regionalFrame); DynamicPropertyIterator dp = gObj->dynamicProperties.find(id); if (dp != gObj->dynamicProperties.end()) @@ -791,14 +831,98 @@ namespace MetaData { */ } - bool JS2Metadata::readDynamicProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval) + // Read the property from the container given by the public id in multiname - if that exists + // + bool JS2Metadata::readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval) { - return true; + ASSERT(container && ((container->kind == DynamicInstanceKind) + || (container->kind == GlobalObjectKind) + || (container->kind == PrototypeInstanceKind))); + if (!multiname->onList(publicNamespace)) + return false; + const StringAtom &name = multiname->name; + if (phase == CompilePhase) reportError(Exception::compileExpressionError, "Inappropriate compile time expression", errorPos); + DynamicPropertyMap *dMap = NULL; + bool isPrototypeInstance = false; + if (container->kind == DynamicInstanceKind) + dMap = &(checked_cast(container))->dynamicProperties; + else + if (container->kind == GlobalObjectKind) + dMap = &(checked_cast(container))->dynamicProperties; + else { + isPrototypeInstance = true; + dMap = &(checked_cast(container))->dynamicProperties; + } + for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) { + if (i->first == name) { + *rval = i->second; + return true; + } + } + if (isPrototypeInstance) { + PrototypeInstance *pInst = (checked_cast(container))->parent; + while (pInst) { + for (DynamicPropertyIterator i = pInst->dynamicProperties.begin(), end = pInst->dynamicProperties.end(); (i != end); i++) { + if (i->first == name) { + *rval = i->second; + return true; + } + } + pInst = pInst->parent; + } + } + if (lookupKind->isPropertyLookup()) { + *rval = JS2VAL_UNDEFINED; + return true; + } + return false; // 'None' } bool JS2Metadata::writeDynamicProperty(Frame *container, Multiname *multiname, bool createIfMissing, js2val newValue, Phase phase) { - return true; + ASSERT(container && ((container->kind == DynamicInstanceKind) + || (container->kind == GlobalObjectKind) + || (container->kind == PrototypeInstanceKind))); + if (!multiname->onList(publicNamespace)) + return false; + const StringAtom &name = multiname->name; + DynamicPropertyMap *dMap = NULL; + if (container->kind == DynamicInstanceKind) + dMap = &(checked_cast(container))->dynamicProperties; + else + if (container->kind == GlobalObjectKind) + dMap = &(checked_cast(container))->dynamicProperties; + else + dMap = &(checked_cast(container))->dynamicProperties; + for (DynamicPropertyIterator i = dMap->begin(), end = dMap->end(); (i != end); i++) { + if (i->first == name) { + i->second = newValue; + return true; + } + } + if (!createIfMissing) + return false; + if (container->kind == DynamicInstanceKind) { + DynamicInstance *dynInst = checked_cast(container); + InstanceBinding *ib = resolveInstanceMemberName(dynInst->type, multiname, ReadAccess, phase); + if (ib == NULL) { + const DynamicPropertyMap::value_type e(name, newValue); + dynInst->dynamicProperties.insert(e); + return true; + } + } + else { + if (container->kind == GlobalObjectKind) { + GlobalObject *glob = checked_cast(container); + StaticMember *m = findFlatMember(glob, multiname, ReadAccess, phase); + if (m == NULL) { + const DynamicPropertyMap::value_type e(name, newValue); + glob->dynamicProperties.insert(e); + return true; + } + } + } + return false; // 'None' } bool JS2Metadata::readStaticMember(StaticMember *m, Phase phase, js2val *rval) @@ -856,7 +980,7 @@ namespace MetaData { bool JS2Metadata::readProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval) { StaticMember *m = findFlatMember(container, multiname, ReadAccess, phase); - if (!m && (container->kind == Frame::GlobalObject)) + if (!m && (container->kind == GlobalObjectKind)) return readDynamicProperty(container, multiname, lookupKind, phase, rval); else return readStaticMember(m, phase, rval); @@ -867,7 +991,7 @@ namespace MetaData { bool JS2Metadata::writeProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, bool createIfMissing, js2val newValue, Phase phase) { StaticMember *m = findFlatMember(container, multiname, WriteAccess, phase); - if (!m && (container->kind == Frame::GlobalObject)) + if (!m && (container->kind == GlobalObjectKind)) return writeDynamicProperty(container, multiname, createIfMissing, newValue, phase); else return writeStaticMember(m, newValue, phase); @@ -898,7 +1022,7 @@ namespace MetaData { break; } if (multiname->matches(b->second->qname)) { - if (found) + if (found && (b->second->content != found)) reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", errorPos, multiname->name); else found = b->second->content; @@ -908,6 +1032,48 @@ namespace MetaData { return found; } + /* + * Start from the root class (Object) and proceed through more specific classes that are ancestors of c. + * Find the binding that matches the given access and multiname, it's an error if more than one such exists. + * + */ + InstanceBinding *JS2Metadata::resolveInstanceMemberName(JS2Class *c, Multiname *multiname, Access access, Phase phase) + { + InstanceBinding *result = NULL; + if (c->super) { + result = resolveInstanceMemberName(c->super, multiname, access, phase); + if (result) return result; + } + InstanceBindingIterator b, end; + if ((access == ReadAccess) || (access == ReadWriteAccess)) { + b = c->instanceReadBindings.lower_bound(multiname->name); + end = c->instanceReadBindings.upper_bound(multiname->name); + } + else { + b = c->instanceWriteBindings.lower_bound(multiname->name); + end = c->instanceWriteBindings.upper_bound(multiname->name); + } + while (true) { + if (b == end) { + if (access == ReadWriteAccess) { + access = WriteAccess; + b = c->instanceWriteBindings.lower_bound(multiname->name); + end = c->instanceWriteBindings.upper_bound(multiname->name); + } + else + break; + } + if (multiname->matches(b->second->qname)) { + if (result && (b->second->content != result->content)) + reportError(Exception::propertyAccessError, "Ambiguous reference to {0}", errorPos, multiname->name); + else + result = b->second; + } + b++; + } + return result; + } + /* * Throw an exception of the specified kind, indicating the position 'pos' and * attaching the given message. If 'arg' is specified, replace {0} in the message diff --git a/js2/src/js2metadata.h b/js2/src/js2metadata.h index 0c03dc0344c4..5cf29e3f6981 100644 --- a/js2/src/js2metadata.h +++ b/js2/src/js2metadata.h @@ -54,14 +54,35 @@ typedef void (Invokable)(); typedef Invokable Callor; typedef JS2Object *(Constructor)(); - +enum ObjectKind { + AttributeObjectKind, + SystemKind, + GlobalObjectKind, + PackageKind, + FunctionKind, + ClassKind, + BlockKind, + PrototypeInstanceKind, + FixedInstanceKind, + DynamicInstanceKind }; class JS2Object { // Every object is either undefined, null, a Boolean, // a number, a string, a namespace, a compound attribute, a class, a method closure, // a prototype instance, a class instance, a package object, or the global object. public: + + JS2Object(ObjectKind kind) : kind(kind) { } + + ObjectKind kind; + + void *operator new(size_t s); + + +#ifdef DEBUG + virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function +#endif }; class Attribute : public JS2Object { @@ -71,7 +92,7 @@ public: enum OverrideModifier { NoOverride, DoOverride, DontOverride, OverrideUndefined }; - Attribute(AttributeKind kind) : kind(kind) { } + Attribute(AttributeKind kind) : JS2Object(AttributeObjectKind), kind(kind) { } static Attribute *combineAttributes(Attribute *a, Attribute *b); static CompoundAttribute *toCompoundAttribute(Attribute *a); @@ -102,7 +123,9 @@ public: }; // MULTINAME is the semantic domain of sets of qualified names. Multinames are used internally in property lookup. -// We keep Multinames as a basename and a list of namespace qualifiers +// We keep Multinames as a basename and a list of namespace qualifiers (XXX is that right - would the basename +// ever be different for the same multiname?) +// Pointers to Multiname instances get embedded in the bytecode. typedef std::vector NamespaceList; typedef NamespaceList::iterator NamespaceListIterator; class Multiname { @@ -257,33 +280,28 @@ public: typedef std::multimap StaticBindingMap; typedef StaticBindingMap::iterator StaticBindingIterator; -class InstanceBindingMap { -public: -}; +typedef std::multimap InstanceBindingMap; +typedef InstanceBindingMap::iterator InstanceBindingIterator; + // A frame contains bindings defined at a particular scope in a program. A frame is either the top-level system frame, // a global object, a package, a function frame, a class, or a block frame -class Frame { +class Frame : public JS2Object { public: enum Plurality { Singular, Plural }; - enum FrameKind { System, GlobalObject, Package, Function, Class, Block }; - Frame(FrameKind kind) : kind(kind), nextFrame(NULL) { } + Frame(ObjectKind kind) : JS2Object(kind), nextFrame(NULL) { } StaticBindingMap staticReadBindings; // Map of qualified names to readable static members defined in this frame StaticBindingMap staticWriteBindings; // Map of qualified names to writable static members defined in this frame - FrameKind kind; // [rather than use RTTI (in general)] Frame *nextFrame; -#ifdef DEBUG - virtual void uselessVirtual() { } // want the checked_cast stuff to work, so need a virtual function -#endif }; class JS2Class : public Frame { public: - JS2Class() : Frame(Class) { } + JS2Class() : Frame(ClassKind) { } StringAtom &getName(); @@ -310,7 +328,7 @@ public: class GlobalObject : public Frame { public: - GlobalObject(World &world) : Frame(Frame::GlobalObject), internalNamespace(new Namespace(world.identifiers["internal"])) { } + GlobalObject(World &world) : Frame(GlobalObjectKind), internalNamespace(new Namespace(world.identifiers["internal"])) { } Namespace *internalNamespace; // This global object's internal namespace DynamicPropertyMap dynamicProperties; // A set of this global object's dynamic properties @@ -325,8 +343,10 @@ public: }; // Instances of non-dynamic classes are represented as FIXEDINSTANCE records. These instances can contain only fixed properties. -class FixedInstance { +class FixedInstance : public JS2Object { public: + FixedInstance() : JS2Object(FixedInstanceKind), typeofString(type->getName()) { } + JS2Class *type; // This instance's type Invokable *call; // A procedure to call when this instance is used in a call expression Invokable *construct; // A procedure to call when this instance is used in a new expression @@ -336,9 +356,9 @@ public: }; // Instances of dynamic classes are represented as DYNAMICINSTANCE records. These instances can contain fixed and dynamic properties. -class DynamicInstance { +class DynamicInstance : public JS2Object { public: - DynamicInstance(JS2Class *type) : type(type), call(NULL), construct(NULL), env(NULL), typeofString(type->getName()) { } + DynamicInstance(JS2Class *type) : JS2Object(DynamicInstanceKind), type(type), call(NULL), construct(NULL), env(NULL), typeofString(type->getName()) { } JS2Class *type; // This instance's type Invokable *call; // A procedure to call when this instance is used in a call expression @@ -349,7 +369,24 @@ public: DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties }; +// Prototype instances are represented as PROTOTYPE records. Prototype instances +// contain no fixed properties. +class PrototypeInstance : public JS2Object { +public: + PrototypeInstance(PrototypeInstance *parent) : JS2Object(PrototypeInstanceKind), parent(parent) { } + + + PrototypeInstance *parent; // If this instance was created by calling new on a prototype function, + // the value of the function’s prototype property at the time of the call; + // none otherwise. + DynamicPropertyMap dynamicProperties; // A set of this instance's dynamic properties +}; + + + + // Base class for all references (lvalues) +// References are generated during the eval stage (bytecode generation) class Reference { public: virtual void emitReadBytecode(BytecodeContainer *bCon) { ASSERT(false); } @@ -363,6 +400,7 @@ class LexicalReference : public Reference { // of a given set of qualified names. LEXICALREFERENCE tuples arise from evaluating identifiers a and qualified identifiers // q::a. public: + LexicalReference(const StringAtom &name, bool strict) : variableMultiname(new Multiname(name)), env(NULL), strict(strict) { } LexicalReference(Multiname *vm, Environment *env, bool strict) : variableMultiname(vm), env(env), strict(strict) { } Multiname *variableMultiname; // A nonempty set of qualified names to which this reference can refer @@ -419,13 +457,13 @@ public: // The top-level frame containing predefined constants, functions, and classes. class SystemFrame : public Frame { public: - SystemFrame() : Frame(System) { } + SystemFrame() : Frame(SystemKind) { } }; // Frames holding bindings for invoked functions class FunctionFrame : public Frame { public: - FunctionFrame() : Frame(Function) { } + FunctionFrame() : Frame(FunctionKind) { } Plurality plurality; js2val thisObject; // The value of this; none if this function doesn't define this; @@ -439,7 +477,7 @@ public: class BlockFrame : public Frame { public: - BlockFrame() : Frame(Block) { } + BlockFrame() : Frame(BlockKind) { } Plurality plurality; }; @@ -448,6 +486,9 @@ public: class LookupKind { public: LookupKind(bool isLexical, js2val thisObject) : isLexical(isLexical), thisObject(thisObject) { } + + bool isPropertyLookup() { return !isLexical; } + bool isLexical; // if isLexical, use the 'this' below. Otherwise it's a propertyLookup js2val thisObject; }; @@ -547,11 +588,12 @@ public: JS2Class *objectType(js2val obj); StaticMember *findFlatMember(Frame *container, Multiname *multiname, Access access, Phase phase); + InstanceBinding *resolveInstanceMemberName(JS2Class *js2class, Multiname *multiname, Access access, Phase phase); bool readProperty(js2val container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); bool readProperty(Frame *pf, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); - bool readDynamicProperty(Frame *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); + bool readDynamicProperty(JS2Object *container, Multiname *multiname, LookupKind *lookupKind, Phase phase, js2val *rval); bool readStaticMember(StaticMember *m, Phase phase, js2val *rval); @@ -594,7 +636,6 @@ public: }; - }; // namespace MetaData }; // namespace Javascript diff --git a/js2/src/js2op_access.cpp b/js2/src/js2op_access.cpp index 83304699bc0d..af740657e8c9 100644 --- a/js2/src/js2op_access.cpp +++ b/js2/src/js2op_access.cpp @@ -33,15 +33,17 @@ case eLexicalRead: { - Multiname *mn = BytecodeContainer::getMultiname(pc); - pc += sizeof(Multiname *); + Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; + pc += sizeof(short); + mn->addNamespace(meta->cxt); meta->env.lexicalRead(meta, mn, phase); } break; case eLexicalWrite: { - Multiname *mn = BytecodeContainer::getMultiname(pc); - pc += sizeof(Multiname *); + Multiname *mn = bCon->mMultinameList[BytecodeContainer::getShort(pc)]; + pc += sizeof(short); + mn->addNamespace(meta->cxt); retval = pop(); meta->env.lexicalWrite(meta, mn, retval, true, phase); } diff --git a/js2/src/js2op_invocation.cpp b/js2/src/js2op_invocation.cpp index b5aee65c09a0..ff0b673dfc8b 100644 --- a/js2/src/js2op_invocation.cpp +++ b/js2/src/js2op_invocation.cpp @@ -44,4 +44,19 @@ } break; - + case eNewObject: { + uint16 argCount = BytecodeContainer::getShort(pc); + pc += sizeof(uint16); + PrototypeInstance *pInst = new PrototypeInstance(NULL); // XXX Object prototype object + for (uint16 i = 0; i < argCount; i++) { + js2val nameVal = pop(); + ASSERT(JS2VAL_IS_STRING(nameVal)); + String *name = JS2VAL_TO_STRING(nameVal); + const StringAtom &nameAtom = world.identifiers[*name]; + js2val fieldVal = pop(); + const DynamicPropertyMap::value_type e(nameAtom, fieldVal); + pInst->dynamicProperties.insert(e); + } + push(OBJECT_TO_JS2VAL(pInst)); + } + break; diff --git a/js2/src/js2op_literal.cpp b/js2/src/js2op_literal.cpp index c56cffc06209..d605d523eb03 100644 --- a/js2/src/js2op_literal.cpp +++ b/js2/src/js2op_literal.cpp @@ -48,3 +48,9 @@ push(JS2VAL_TRUE); } break; + + case eString: { + push(STRING_TO_JS2VAL(BytecodeContainer::getString(pc))); + pc += sizeof(String *); + } + break;