From bbfe54bd1e44081c1a28a297458a3c05ab51bfca Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Fri, 4 Apr 2003 23:24:57 +0000 Subject: [PATCH] Fixing for..in, runaway string allocation, array.length initialization. git-svn-id: svn://10.0.0.236/trunk@140728 18797224-902f-48f8-a5cc-f745e15eee43 --- mozilla/js2/src/epimetheus.cpp | 31 ++++++++----- mozilla/js2/src/js2array.cpp | 2 + mozilla/js2/src/js2engine.cpp | 65 +++++++++++++-------------- mozilla/js2/src/js2eval.cpp | 4 ++ mozilla/js2/src/js2metadata.cpp | 24 +++++----- mozilla/js2/src/js2metadata.h | 9 ++-- mozilla/js2/src/js2op_access.cpp | 18 +++++--- mozilla/js2/src/js2op_flowcontrol.cpp | 2 +- mozilla/js2/src/js2op_literal.cpp | 2 +- 9 files changed, 89 insertions(+), 68 deletions(-) diff --git a/mozilla/js2/src/epimetheus.cpp b/mozilla/js2/src/epimetheus.cpp index 890e506a5b1..ac7b4ee370e 100644 --- a/mozilla/js2/src/epimetheus.cpp +++ b/mozilla/js2/src/epimetheus.cpp @@ -233,11 +233,11 @@ js2val trace(JS2Metadata *meta, const js2val /* thisValue */, js2val /* argv */ return JS2VAL_UNDEFINED; } -void printFrameBindings(NonWithFrame *f) +void printLocalBindings(LocalBindingMap *lMap) { stdOut << " Local Bindings:\n"; - for (LocalBindingIterator bi = f->localBindings.begin(), bend = f->localBindings.end(); (bi != bend); bi++) { + for (LocalBindingIterator bi = lMap->begin(), bend = lMap->end(); (bi != bend); bi++) { LocalBindingEntry *lbe = *bi; for (LocalBindingEntry::NS_Iterator i = lbe->begin(), end = lbe->end(); (i != end); i++) { LocalBindingEntry::NamespaceBinding ns = *i; @@ -261,14 +261,25 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint else if (JS2VAL_IS_OBJECT(argv[0])) { JS2Object *fObj = JS2VAL_TO_OBJECT(argv[0]); - if (((fObj->kind == SimpleInstanceKind) - && (meta->objectType(argv[0]) == meta->functionClass))) { - FunctionWrapper *fWrap; - fWrap = (checked_cast(fObj))->fWrap; - if (fWrap->code) - stdOut << "\n"; + if (fObj->kind == SimpleInstanceKind) { + + SimpleInstance *s = checked_cast(fObj); + stdOut << "SimpleInstance\n"; + if (JS2VAL_IS_OBJECT(s->super)) + printFormat(stdOut, "super = 0x%08X\n", s->super); else - dumpBytecode(fWrap->bCon); + stdOut << "super = " << *metadata->toString(s->super) << '\n'; + stdOut << ((s->sealed) ? "sealed " : "not-sealed ") << '\n'; + stdOut << "type = " << *s->type->getName() << '\n'; + printLocalBindings(&s->localBindings); + if (meta->objectType(argv[0]) == meta->functionClass) { + FunctionWrapper *fWrap; + fWrap = (checked_cast(fObj))->fWrap; + if (fWrap->code) + stdOut << "\n"; + else + dumpBytecode(fWrap->bCon); + } } else { if (fObj->kind == ClassKind) { @@ -280,7 +291,7 @@ js2val dump(JS2Metadata *meta, const js2val /* thisValue */, js2val argv[], uint stdOut << ((c->dynamic) ? " dynamic, " : " non-dynamic, ") << ((c->final) ? "final" : "non-final") << "\n"; stdOut << " slotCount = " << c->slotCount << "\n"; - printFrameBindings(c); + printLocalBindings(&c->localBindings); stdOut << " Instance Bindings:\n"; for (InstanceBindingIterator rib = c->instanceBindings.begin(), riend = c->instanceBindings.end(); (rib != riend); rib++) { diff --git a/mozilla/js2/src/js2array.cpp b/mozilla/js2/src/js2array.cpp index c752c6dd954..6df41199923 100644 --- a/mozilla/js2/src/js2array.cpp +++ b/mozilla/js2/src/js2array.cpp @@ -121,6 +121,8 @@ js2val Array_Constructor(JS2Metadata *meta, const js2val /*thisValue*/, js2val * setLength(meta, arrInst, i); } } + else + setLength(meta, arrInst, 0); return thatValue; } diff --git a/mozilla/js2/src/js2engine.cpp b/mozilla/js2/src/js2engine.cpp index de63ec89a11..d619ededfa6 100644 --- a/mozilla/js2/src/js2engine.cpp +++ b/mozilla/js2/src/js2engine.cpp @@ -211,7 +211,11 @@ namespace MetaData { String *JS2Engine::allocStringPtr(const char *s) { - return allocStringPtr(&meta->world.identifiers[widenCString(s)]); + String *p = (String *)(JS2Object::alloc(sizeof(String), false)); + size_t len = strlen(s); + String *result = new (p) String(len, uni::null); + std::transform(s, s+len, result->begin(), widen); + return result; } String *JS2Engine::allocStringPtr(const String *s) @@ -274,7 +278,7 @@ namespace MetaData { { char buf[dtosStandardBufferSize]; const char *chrp = doubleToStr(buf, dtosStandardBufferSize, i, dtosStandard, 0); - return allocStringPtr(&meta->world.identifiers[chrp]); + return allocStringPtr(chrp); } // Convert a double to a string @@ -282,7 +286,7 @@ namespace MetaData { { char buf[dtosStandardBufferSize]; const char *chrp = doubleToStr(buf, dtosStandardBufferSize, *number, dtosStandard, 0); - return allocStringPtr(&meta->world.identifiers[chrp]); + return allocStringPtr(chrp); } // x is a Number, validate that it has no fractional component @@ -1012,47 +1016,40 @@ namespace MetaData { // // Initialize and build a list of names of properties in the object. // - bool ForIteratorObject::first() + bool ForIteratorObject::first(JS2Engine *engine) { if (obj == NULL) return false; originalObj = obj; - return buildNameList(); + return buildNameList(engine->meta); } // Iterate over LocalBindings - bool ForIteratorObject::buildNameList() + bool ForIteratorObject::buildNameList(JS2Metadata *meta) { - if (obj->kind == ClassKind) { - JS2Class *c = checked_cast(obj); - nameList = new const String *[c->localBindings.size()]; - length = 0; - for (LocalBindingIterator bi = c->localBindings.begin(), bend = c->localBindings.end(); (bi != bend); bi++) { - LocalBindingEntry *lbe = *bi; - nameList[length++] = &lbe->name; - } - } - else { - LocalBindingMap *lMap = NULL; - if (obj->kind == SimpleInstanceKind) - lMap = &(checked_cast(obj))->localBindings; - else - if (obj->kind == PackageKind) - lMap = &(checked_cast(obj))->localBindings; - else - if (obj->kind == ClassKind) - lMap = &(checked_cast(obj))->localBindings; + LocalBindingMap *lMap = NULL; + if (obj->kind == SimpleInstanceKind) + lMap = &(checked_cast(obj))->localBindings; + else + if (obj->kind == PackageKind) + lMap = &(checked_cast(obj))->localBindings; + else + if (obj->kind == ClassKind) + lMap = &(checked_cast(obj))->localBindings; - if (lMap) { - nameList = new const String *[lMap->size()]; - length = 0; - for (LocalBindingIterator bi = lMap->begin(), bend = lMap->end(); (bi != bend); bi++) { - LocalBindingEntry *lbe = *bi; - nameList[length++] = &lbe->name; + if (lMap) { + nameList = new const String *[lMap->size()]; + length = 0; + for (LocalBindingIterator bi = lMap->begin(), bend = lMap->end(); (bi != bend); bi++) { + LocalBindingEntry *lbe = *bi; + for (LocalBindingEntry::NS_Iterator i = lbe->begin(), end = lbe->end(); (i != end); i++) { + LocalBindingEntry::NamespaceBinding ns = *i; + if ((ns.first == meta->publicNamespace) && ns.second->enumerable) + nameList[length++] = &lbe->name; } - it = 0; - return (length != 0); } + it = 0; + return (length != 0); } return false; } @@ -1086,7 +1083,7 @@ namespace MetaData { if (!JS2VAL_IS_NULL(protoval)) { if (JS2VAL_IS_OBJECT(protoval)) { obj = JS2VAL_TO_OBJECT(protoval); - return buildNameList(); + return buildNameList(engine->meta); } } } diff --git a/mozilla/js2/src/js2eval.cpp b/mozilla/js2/src/js2eval.cpp index 850d48de697..522f09a17a8 100644 --- a/mozilla/js2/src/js2eval.cpp +++ b/mozilla/js2/src/js2eval.cpp @@ -362,6 +362,10 @@ namespace MetaData { // 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 + JS2Object *obj = JS2VAL_TO_OBJECT(x); + if (obj->kind != SimpleInstanceKind) // therefore, not an E3 object, so just return + return engine->typeofString(x); // the 'typeof' string + if (hint == StringHint) { js2val result; if (invokeFunctionOnObject(x, engine->toString_StringAtom, result)) { diff --git a/mozilla/js2/src/js2metadata.cpp b/mozilla/js2/src/js2metadata.cpp index 79c572448e6..989c0854c88 100644 --- a/mozilla/js2/src/js2metadata.cpp +++ b/mozilla/js2/src/js2metadata.cpp @@ -1544,7 +1544,7 @@ namespace MetaData { break; case ExprNode::This: { - if (env->findThis(true) == JS2VAL_VOID) + if (env->findThis(this, true) == JS2VAL_VOID) reportError(Exception::syntaxError, "No 'this' available", p->pos); } break; @@ -2402,7 +2402,7 @@ doUnary: // findThis returns the value of this. If allowPrototypeThis is true, allow this to be defined // by either an instance member of a class or a prototype function. If allowPrototypeThis is // false, allow this to be defined only by an instance member of a class. - js2val Environment::findThis(bool allowPrototypeThis) + js2val Environment::findThis(JS2Metadata *meta, bool allowPrototypeThis) { FrameListIterator fi = getBegin(); while (fi != getEnd()) { @@ -2412,8 +2412,7 @@ doUnary: if (allowPrototypeThis || !checked_cast(pf)->prototype) return checked_cast(pf)->thisObject; // XXX for ECMA3, when we hit a package (read GlobalObject) return that as the 'this' - // XXX should have 'ECMA3' compatibility flag in Environment? - if (pf->kind == PackageKind) + if ((pf->kind == PackageKind) && meta->cxt.E3compatibility) return OBJECT_TO_JS2VAL(pf); fi++; } @@ -2427,7 +2426,7 @@ doUnary: // an error. void Environment::lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase, js2val *rval) { - LookupKind lookup(true, findThis(false)); + LookupKind lookup(true, findThis(meta, false)); FrameListIterator fi = getBegin(); bool result = false; while (fi != getEnd()) { @@ -2470,7 +2469,7 @@ doUnary: // exists, then fine. Otherwise create the property there. void Environment::lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing) { - LookupKind lookup(true, findThis(false)); + LookupKind lookup(true, findThis(meta, false)); FrameListIterator fi = getBegin(); bool result = false; while (fi != getEnd()) { @@ -2513,7 +2512,8 @@ doUnary: if (result) return; } - meta->reportError(Exception::referenceError, "{0} is undefined", meta->engine->errorPos(), multiname->name); + if (!meta->cxt.E3compatibility) + meta->reportError(Exception::referenceError, "{0} is undefined", meta->engine->errorPos(), multiname->name); } @@ -2521,7 +2521,7 @@ doUnary: // but it had darn well better be in the environment somewhere. void Environment::lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue) { - LookupKind lookup(true, findThis(false)); + LookupKind lookup(true, findThis(meta, false)); FrameListIterator fi = getBegin(); bool result = false; while (fi != getEnd()) { @@ -2570,7 +2570,7 @@ doUnary: // can't be found, or the result of the deleteProperty call if it was found. bool Environment::lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase) { - LookupKind lookup(true, findThis(false)); + LookupKind lookup(true, findThis(meta, false)); FrameListIterator fi = getBegin(); bool result = false; while (fi != getEnd()) { @@ -2643,7 +2643,7 @@ doUnary: ************************************************************************************/ // clone a context - Context::Context(Context *cxt) : strict(cxt->strict), openNamespaces(cxt->openNamespaces) + Context::Context(Context *cxt) : strict(cxt->strict), E3compatibility(cxt->E3compatibility), openNamespaces(cxt->openNamespaces) { ASSERT(false); // ?? used ?? } @@ -3218,7 +3218,7 @@ static const uint8 urlCharType[256] = { ASSERT(JS2VAL_IS_OBJECT(thisValue)); JS2Object *obj = JS2VAL_TO_OBJECT(thisValue); - if (obj->kind == PackageKind) { + if ((obj->kind == PackageKind) && meta->cxt.E3compatibility) { // special case this for now, ECMA3 test sanity... return GlobalObject_toString(meta, thisValue, NULL, 0); } @@ -3570,7 +3570,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... Member *JS2Metadata::findCommonMember(js2val *base, Multiname *multiname, Access access, bool flat) { Member *m = NULL; - if (JS2VAL_IS_PRIMITIVE(*base)) { + if (JS2VAL_IS_PRIMITIVE(*base) && cxt.E3compatibility) { *base = toObject(*base); // XXX E3 compatibility... } JS2Object *baseObj = JS2VAL_TO_OBJECT(*base); diff --git a/mozilla/js2/src/js2metadata.h b/mozilla/js2/src/js2metadata.h index 0409c14e481..1f9d48ab62c 100644 --- a/mozilla/js2/src/js2metadata.h +++ b/mozilla/js2/src/js2metadata.h @@ -647,7 +647,7 @@ public: void addFrame(Frame *f) { frameList.push_front(f); } void removeTopFrame() { frameList.pop_front(); } - js2val findThis(bool allowPrototypeThis); + js2val findThis(JS2Metadata *meta, bool allowPrototypeThis); void lexicalRead(JS2Metadata *meta, Multiname *multiname, Phase phase, js2val *rval); void lexicalWrite(JS2Metadata *meta, Multiname *multiname, js2val newValue, bool createIfMissing); void lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue); @@ -867,7 +867,7 @@ class ForIteratorObject : public JS2Object { public: ForIteratorObject(JS2Object *obj) : JS2Object(ForIteratorKind), obj(obj), nameList(NULL) { } - bool first(); + bool first(JS2Engine *engine); bool next(JS2Engine *engine); js2val value(JS2Engine *engine); @@ -880,7 +880,7 @@ public: private: - bool buildNameList(); + bool buildNameList(JS2Metadata *meta); const String **nameList; uint32 it; @@ -1101,9 +1101,10 @@ typedef NamespaceList::iterator NamespaceListIterator; // A CONTEXT carries static information about a particular point in the source program. class Context { public: - Context() : strict(false) { } + Context() : strict(false), E3compatibility(true) { } Context(Context *cxt); bool strict; // true if strict mode is in effect + bool E3compatibility; NamespaceList openNamespaces; // The set of namespaces that are open at this point. // The public namespace is always a member of this set. }; diff --git a/mozilla/js2/src/js2op_access.cpp b/mozilla/js2/src/js2op_access.cpp index c7d674e4189..f7c4b168deb 100644 --- a/mozilla/js2/src/js2op_access.cpp +++ b/mozilla/js2/src/js2op_access.cpp @@ -71,8 +71,10 @@ pc += sizeof(short); b = pop(); JS2Class *limit = meta->objectType(b); - if (!limit->write(meta, b, limit, mn, &lookup, true, a)) - meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name); + if (!limit->write(meta, b, limit, mn, &lookup, true, a)) { + if (!meta->cxt.E3compatibility) + meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn->name); + } push(a); } break; @@ -190,8 +192,10 @@ astr = meta->toString(indexVal); Multiname mn(&meta->world.identifiers[*astr], meta->publicNamespace); JS2Class *limit = meta->objectType(b); - if (!limit->bracketWrite(meta, b, limit, &mn, a)) - meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); + if (!limit->bracketWrite(meta, b, limit, &mn, a)) { + if (!meta->cxt.E3compatibility) + meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); + } push(a); indexVal = JS2VAL_VOID; astr = NULL; @@ -243,8 +247,10 @@ b = pop(); Multiname mn(&meta->world.identifiers[*JS2VAL_TO_STRING(indexVal)], meta->publicNamespace); JS2Class *limit = meta->objectType(b); - if (!limit->bracketWrite(meta, b, limit, &mn, a)) - meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); + if (!limit->bracketWrite(meta, b, limit, &mn, a)) { + if (!meta->cxt.E3compatibility) + meta->reportError(Exception::propertyAccessError, "No property named {0}", errorPos(), mn.name); + } push(a); indexVal = JS2VAL_VOID; } diff --git a/mozilla/js2/src/js2op_flowcontrol.cpp b/mozilla/js2/src/js2op_flowcontrol.cpp index 20165b3d336..a477f8d85ff 100644 --- a/mozilla/js2/src/js2op_flowcontrol.cpp +++ b/mozilla/js2/src/js2op_flowcontrol.cpp @@ -116,7 +116,7 @@ b = meta->toObject(a); ForIteratorObject *fi = new ForIteratorObject(JS2VAL_TO_OBJECT(b)); push(OBJECT_TO_JS2VAL(fi)); - push(BOOLEAN_TO_JS2VAL(fi->first())); + push(BOOLEAN_TO_JS2VAL(fi->first(this))); } break; diff --git a/mozilla/js2/src/js2op_literal.cpp b/mozilla/js2/src/js2op_literal.cpp index 3ce32fc8e6b..43e14b332e7 100644 --- a/mozilla/js2/src/js2op_literal.cpp +++ b/mozilla/js2/src/js2op_literal.cpp @@ -104,7 +104,7 @@ case eThis: // XXX literal? { - a = meta->env->findThis(true); + a = meta->env->findThis(meta, true); if (JS2VAL_IS_INACCESSIBLE(a)) meta->reportError(Exception::compileExpressionError, "'this' not available", errorPos()); push(a);