From 42eba1cf234feac56d3aa79291517fe01e99e371 Mon Sep 17 00:00:00 2001 From: "rogerl%netscape.com" Date: Fri, 30 May 2003 22:47:57 +0000 Subject: [PATCH] Changes to arguments instance & class --- js2/src/js2eval.cpp | 44 ++++++++++++++++++++++- js2/src/js2metadata.cpp | 79 +++++++++++++++++++++++++++++++---------- js2/src/js2metadata.h | 39 ++++++++++++++++---- 3 files changed, 137 insertions(+), 25 deletions(-) diff --git a/js2/src/js2eval.cpp b/js2/src/js2eval.cpp index af29c91b8612..9d935ad80dcd 100644 --- a/js2/src/js2eval.cpp +++ b/js2/src/js2eval.cpp @@ -853,6 +853,48 @@ namespace MetaData { return Delete(meta, base, mn, NULL, result); } + bool JS2ArgumentsClass::Read(JS2Metadata *meta, js2val *base, Multiname *multiname, Environment *env, Phase phase, js2val *rval) + { + ASSERT(JS2VAL_IS_OBJECT(*base)); + JS2Object *obj = JS2VAL_TO_OBJECT(*base); + ArgumentsInstance *args = checked_cast(obj); + + uint32 index; + if ((multiname->nsList->size() == 1) + && (multiname->nsList->back() == meta->publicNamespace) + && isValidIndex(multiname->name, index) + && (index < args->mSlots->size())) { + *rval = (*args->mSlots)[index]; + return true; + } + else + return JS2Class::Read(meta, base, multiname, env, phase, rval); + } + + bool JS2ArgumentsClass::Write(JS2Metadata *meta, js2val base, Multiname *multiname, Environment *env, bool createIfMissing, js2val newValue, bool initFlag) + { + ASSERT(JS2VAL_IS_OBJECT(base)); + JS2Object *obj = JS2VAL_TO_OBJECT(base); + ArgumentsInstance *args = checked_cast(obj); + + uint32 index; + if ((multiname->nsList->size() == 1) + && (multiname->nsList->back() == meta->publicNamespace) + && isValidIndex(multiname->name, index) + && (index < args->mSlots->size())) { + (*args->mSlots)[index] = newValue; + return true; + } + else + return JS2Class::Write(meta, base, multiname, env, createIfMissing, newValue, false); + } + + bool JS2ArgumentsClass::Delete(JS2Metadata *meta, js2val base, Multiname *multiname, Environment *env, bool *result) + { + return JS2Class::Delete(meta, base, multiname, env, result); + } + + bool JS2Class::Write(JS2Metadata *meta, js2val base, Multiname *multiname, Environment *env, bool createIfMissing, js2val newValue, bool initFlag) { InstanceMember *mBase = meta->findBaseInstanceMember(this, multiname, WriteAccess); @@ -883,7 +925,7 @@ namespace MetaData { DEFINE_ROOTKEEPER(rk, mn); if ( (meta->findBaseInstanceMember(this, mn, ReadAccess) == NULL) && (meta->findCommonMember(&base, mn, ReadAccess, true) == NULL) ) { - meta->createDynamicProperty(baseObj, &qName, newValue, ReadWriteAccess, false, true); + meta->createDynamicProperty(baseObj, mn->name, newValue, ReadWriteAccess, false, true); return true; } } diff --git a/js2/src/js2metadata.cpp b/js2/src/js2metadata.cpp index 25a40f06c6a9..7d74f8754ba9 100644 --- a/js2/src/js2metadata.cpp +++ b/js2/src/js2metadata.cpp @@ -3106,7 +3106,7 @@ doUnary: } // Clone the pluralFrame bindings into the singularFrame, instantiating new members for each binding - void Environment::instantiateFrame(NonWithFrame *pluralFrame, NonWithFrame *singularFrame) + void Environment::instantiateFrame(NonWithFrame *pluralFrame, NonWithFrame *singularFrame, bool buildSlots) { singularFrame->localBindings.clear(); @@ -3118,7 +3118,7 @@ doUnary: LocalBindingEntry *lbe = *bi2; singularFrame->localBindings.insert(lbe->name, lbe->clone()); } - if (pluralFrame->slots) { + if (buildSlots && pluralFrame->slots) { size_t count = pluralFrame->slots->size(); singularFrame->slots = new std::vector(count); for (size_t i = 0; i < count; i++) @@ -4008,6 +4008,7 @@ static const uint8 urlCharType[256] = MAKEBUILTINCLASS(classClass, objectClass, false, true, engine->allocStringPtr(&world.identifiers["Class"]), JS2VAL_NULL); MAKEBUILTINCLASS(functionClass, objectClass, true, true, engine->Function_StringAtom, JS2VAL_NULL); MAKEBUILTINCLASS(packageClass, objectClass, true, true, engine->allocStringPtr(&world.identifiers["Package"]), JS2VAL_NULL); + MAKEBUILTINCLASS(argumentsClass, objectClass, true, true, engine->allocStringPtr(&world.identifiers["Arguments"]), JS2VAL_NULL); @@ -4581,22 +4582,34 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... DynamicVariable *JS2Metadata::createDynamicProperty(JS2Object *obj, const char *name, js2val initVal, Access access, bool sealed, bool enumerable) { - QualifiedName qName(publicNamespace, &world.identifiers[widenCString(name)]); - return createDynamicProperty(obj, &qName, initVal, access, sealed, enumerable); + return createDynamicProperty(obj, &world.identifiers[widenCString(name)], initVal, access, sealed, enumerable); } - +/* DynamicVariable *JS2Metadata::createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable) { DEFINE_ROOTKEEPER(rk, name); QualifiedName qName(publicNamespace, name); return createDynamicProperty(obj, &qName, initVal, access, sealed, enumerable); } +*/ + void JS2Metadata::addPublicVariableToLocalMap(LocalBindingMap *lMap, const String *name, LocalMember *v, Access access, bool enumerable) + { + LocalBinding *new_b = new LocalBinding(access, v, enumerable); + LocalBindingEntry **lbeP = (*lMap)[*name]; + LocalBindingEntry *lbe; + if (lbeP == NULL) { + lbe = new LocalBindingEntry(*name); + lMap->insert(*name, lbe); + } + else + lbe = *lbeP; + lbe->bindingList.push_back(LocalBindingEntry::NamespaceBinding(publicNamespace, new_b)); + } // The caller must make sure that the created property does not already exist and does not conflict with any other property. - DynamicVariable *JS2Metadata::createDynamicProperty(JS2Object *obj, QualifiedName *qName, js2val initVal, Access access, bool sealed, bool enumerable) + DynamicVariable *JS2Metadata::createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable) { DynamicVariable *dv = new DynamicVariable(initVal, sealed); - LocalBinding *new_b = new LocalBinding(access, dv, enumerable); LocalBindingMap *lMap; if (obj->kind == SimpleInstanceKind) lMap = &checked_cast(obj)->localBindings; @@ -4605,7 +4618,8 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... lMap = &checked_cast(obj)->localBindings; else ASSERT(false); - + addPublicVariableToLocalMap(lMap, name, dv, access, enumerable); +/* LocalBindingEntry **lbeP = (*lMap)[*qName->name]; LocalBindingEntry *lbe; if (lbeP == NULL) { @@ -4615,6 +4629,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... else lbe = *lbeP; lbe->bindingList.push_back(LocalBindingEntry::NamespaceBinding(qName->nameSpace, new_b)); +*/ return dv; } @@ -4662,6 +4677,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... GCMARKOBJECT(syntaxErrorClass); GCMARKOBJECT(typeErrorClass); GCMARKOBJECT(uriErrorClass); + GCMARKOBJECT(argumentsClass); for (BConListIterator i = bConList.begin(), end = bConList.end(); (i != end); i++) (*i)->mark(); @@ -5039,6 +5055,28 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... delete fWrap; } +/************************************************************************************ + * + * ArgumentsInstance + * + ************************************************************************************/ + + // gc-mark all contained JS2Objects and visit contained structures to do likewise + void ArgumentsInstance::markChildren() + { + SimpleInstance::markChildren(); + if (mSlots) { + for (uint32 i = 0; i < mSlots->size(); i++) + GCMARKVALUE((*mSlots)[i]); + } + } + + ArgumentsInstance::~ArgumentsInstance() + { + if (mSlots) + delete mSlots; + } + /************************************************************************************ * * InstanceMethod @@ -5129,7 +5167,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... void ParameterFrame::instantiate(Environment *env) { - env->instantiateFrame(pluralFrame, this); + env->instantiateFrame(pluralFrame, this, !buildArguments); } // Assume that instantiate has been called, the plural frame will contain @@ -5141,11 +5179,18 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... ASSERT(pluralFrame->kind == ParameterFrameKind); ParameterFrame *plural = checked_cast(pluralFrame); - SimpleInstance *argsObj = NULL; + ArgumentsInstance *argsObj = NULL; DEFINE_ROOTKEEPER(rk2, argsObj); + uint32 slotCount = (plural->slots) ? plural->slots->size() : 0; + if (plural->buildArguments) { - argsObj = new SimpleInstance(meta, meta->objectClass->prototype, meta->objectClass); + // If we're building an arguments object, the slots for the parameter frame are located + // there so that the arguments object itself can survive beyond the life of the function. + argsObj = new ArgumentsInstance(meta, meta->objectClass->prototype, meta->argumentsClass); + if (slotCount) + argsObj->mSlots = new std::vector(slotCount); + slots = argsObj->mSlots; // Add the 'arguments' property String name(widenCString("arguments")); ASSERT(localBindings[name] == NULL); @@ -5155,22 +5200,16 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... localBindings.insert(name, lbe); } - uint32 slotCount = (plural->slots) ? plural->slots->size() : 0; - uint32 i; for (i = 0; (i < argCount); i++) { if (i < slotCount) { (*slots)[i] = argBase[i]; } - if (plural->buildArguments) - meta->objectClass->WritePublic(meta, OBJECT_TO_JS2VAL(argsObj), meta->engine->numberToString(i), true, argBase[i]); } while (i++ < length) { if (i < slotCount) { (*slots)[i] = JS2VAL_UNDEFINED; } - if (plural->buildArguments) - meta->objectClass->WritePublic(meta, OBJECT_TO_JS2VAL(argsObj), meta->engine->numberToString(i), true, JS2VAL_UNDEFINED); } if (plural->buildArguments) { setLength(meta, argsObj, argCount); @@ -5188,6 +5227,9 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... ParameterFrame::~ParameterFrame() { + if (buildArguments) { + slots = NULL; // the slots are in the arguments object, let it do the delete + } } /************************************************************************************ @@ -5202,6 +5244,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... GCMARKOBJECT(type) } + /************************************************************************************ * * BlockFrame @@ -5211,7 +5254,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now... void BlockFrame::instantiate(Environment *env) { if (pluralFrame) - env->instantiateFrame(pluralFrame, this); + env->instantiateFrame(pluralFrame, this, true); } diff --git a/js2/src/js2metadata.h b/js2/src/js2metadata.h index 11504c5b5b12..299f847d0634 100644 --- a/js2/src/js2metadata.h +++ b/js2/src/js2metadata.h @@ -57,6 +57,7 @@ class FunctionInstance; class ArrayInstance; class RegExpInstance; class Package; +class ArgumentsInstance; typedef void (Invokable)(); typedef js2val (Callor)(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc); @@ -270,6 +271,7 @@ public: ROOTKEEPER_CONSTRUCTOR(SimpleInstance) ROOTKEEPER_CONSTRUCTOR(FunctionInstance) ROOTKEEPER_CONSTRUCTOR(DateInstance) + ROOTKEEPER_CONSTRUCTOR(ArgumentsInstance) #ifdef DEBUG RootKeeper(js2val *p, int line, char *pfile) : is_js2val(true), js2val_count(0), p(p) { init(line, pfile); } @@ -528,8 +530,6 @@ public: virtual void mark(); }; - - // A LOCALBINDING describes the member to which one qualified name is bound in a frame. Multiple // qualified names may be bound to the same member in a frame, but a qualified name may not be // bound to multiple members in a frame (except when one binding is for reading only and @@ -752,7 +752,7 @@ public: void lexicalInit(JS2Metadata *meta, Multiname *multiname, js2val newValue); bool lexicalDelete(JS2Metadata *meta, Multiname *multiname, Phase phase); - void instantiateFrame(NonWithFrame *pluralFrame, NonWithFrame *singularFrame); + void instantiateFrame(NonWithFrame *pluralFrame, NonWithFrame *singularFrame, bool buildSlots); void markChildren(); @@ -855,6 +855,16 @@ public: virtual bool BracketDelete(JS2Metadata *meta, js2val base, js2val indexVal, bool *result) { return false; } }; +class JS2ArgumentsClass : public JS2Class { +public: + JS2ArgumentsClass(JS2Class *super, js2val proto, Namespace *privateNamespace, bool dynamic, bool final, const String *name) + : JS2Class(super, proto, privateNamespace, dynamic, final, name) { } + + virtual bool Read(JS2Metadata *meta, js2val *base, Multiname *multiname, Environment *env, Phase phase, js2val *rval); + virtual bool Write(JS2Metadata *meta, js2val base, Multiname *multiname, Environment *env, bool createIfMissing, js2val newValue, bool initFlag); + virtual bool Delete(JS2Metadata *meta, js2val base, Multiname *multiname, Environment *env, bool *result); +}; + class Package : public NonWithFrame { public: typedef enum { InTransit, InHand } PackageStatus; @@ -1049,6 +1059,19 @@ public: virtual ~RegExpInstance() { } }; +class ArgumentsInstance : public SimpleInstance { +public: + ArgumentsInstance(JS2Metadata *meta, js2val parent, JS2Class *type) : SimpleInstance(meta, parent, type), mSlots(NULL) { } + + ValueList *mSlots; + + virtual void markChildren(); + virtual ~ArgumentsInstance(); +}; + + + + // A helper class for 'for..in' statements class ForIteratorObject : public JS2Object { public: @@ -1076,6 +1099,7 @@ private: // Base class for all references (lvalues) // References are generated during the eval stage (bytecode generation), but shouldn't live beyond that +// so they're allocated from an arena carried in the metadata class and cleared after each bytecode gen pass. class Reference : public ArenaObject { public: virtual ~Reference() { } @@ -1092,7 +1116,7 @@ public: virtual void emitDeleteBytecode(BytecodeContainer *, size_t) { ASSERT(false); } - // indicate whether building the reference generate any stack deposits + // indicate whether building the reference generates any stack deposits virtual int hasStackEffect() { ASSERT(false); return 0; } }; @@ -1329,7 +1353,8 @@ public: // available because this function hasn't been called yet. bool prototype; // true if this function is not an instance method but defines this anyway - bool buildArguments; + bool buildArguments; // true if the 'arguments' variable is referenced, it will be constructed + // by 'assignArguments' and contain the slots for this frame. bool isConstructor; bool isInstance; bool callsSuperConstructor; @@ -1489,8 +1514,9 @@ public: void invokeInit(JS2Class *c, js2val thisValue, js2val* argv, uint32 argc); DynamicVariable *createDynamicProperty(JS2Object *obj, const char *name, js2val initVal, Access access, bool sealed, bool enumerable); - DynamicVariable *createDynamicProperty(JS2Object *obj, QualifiedName *qName, js2val initVal, Access access, bool sealed, bool enumerable); +// DynamicVariable *createDynamicProperty(JS2Object *obj, QualifiedName *qName, js2val initVal, Access access, bool sealed, bool enumerable); DynamicVariable *createDynamicProperty(JS2Object *obj, const String *name, js2val initVal, Access access, bool sealed, bool enumerable); + void addPublicVariableToLocalMap(LocalBindingMap *lMap, const String *name, LocalMember *v, Access access, bool enumerable); FunctionInstance *createFunctionInstance(Environment *env, bool prototype, bool unchecked, NativeCode *code, uint32 length, DynamicVariable **lengthProperty); @@ -1582,6 +1608,7 @@ public: JS2Class *syntaxErrorClass; JS2Class *typeErrorClass; JS2Class *uriErrorClass; + JS2Class *argumentsClass; BytecodeContainer *bCon; // the current output container