/** 15.2.4.5 Object.prototype.hasOwnProperty (V) When the hasOwnProperty method is called with argument V, the following steps are taken: 1. Let O be this object. 2. Call ToString(V). 3. If O doesnt have a property with the name given by Result(2), return false. 4. Return true. NOTE Unlike [[HasProperty]] (section 8.6.2.4), this method does not consider objects in the prototype chain. */ bool ObjectClass::_hasOwnProperty(Atom thisAtom, Stringp name) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; Traitsp t = NULL; switch (atomKind(thisAtom)) { case kObjectType: { // ISSUE should this look in traits and dynamic vars, or just dynamic vars. ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); if (obj->hasStringProperty(name)) return true; t = obj->traits(); break; } case kNamespaceType: case kStringType: case kBooleanType: case kDoubleType: case kIntegerType: t = toplevel()->toTraits(thisAtom); break; default: return false; } return t->getTraitsBindings()->findBinding(name, core->publicNamespace) != BIND_NONE; }
VTable* VTable::newParameterizedVTable(Traits* param_traits, Stringp fullname) { Toplevel* toplevel = this->toplevel(); AvmCore* core = toplevel->core(); Namespacep traitsNs = this->traits->ns(); GCRef<builtinClassManifest> builtinClasses = toplevel->builtinClasses(); GCRef<ObjectVectorClass> vectorobj_cls = builtinClasses->get_Vector_objectClass(); GCRef<ScopeChain> vectorobj_cscope = vectorobj_cls->vtable->init->scope(); GCRef<ScopeChain> vectorobj_iscope = vectorobj_cls->ivtable()->init->scope(); VTable* objVecVTable = vectorobj_cls->vtable; AbcEnv* objVecAbcEnv = vectorobj_cscope->abcEnv(); Toplevel* objVecToplevel = objVecVTable->toplevel(); VTable* objVecIVTable = objVecVTable->ivtable; // these cases should all be filtered out by the caller; // we only want to handle Vector<SomeObject> here AvmAssert(param_traits != NULL && param_traits != toplevel->intClass()->vtable->traits->itraits && param_traits != toplevel->uintClass()->vtable->traits->itraits && param_traits != toplevel->numberClass()->vtable->traits->itraits); PoolObject* traitsPool = this->traits->pool; Stringp classname = core->internString(fullname->appendLatin1("$")); Traits* ctraits = core->domainMgr()->findTraitsInPoolByNameAndNS(traitsPool, classname, traitsNs); Traits* itraits; if (!ctraits) { // important: base the new ctraits on objVecVTable->traits, *not* this->traits; // we want the result to be based off ObjectVectorClass, not VectorClass // (otherwise sizeofInstance would be too small and we'd be crashy) ctraits = objVecVTable->traits->newParameterizedCTraits(classname, traitsNs); ctraits->verifyBindings(toplevel); itraits = traitsPool->resolveParameterizedType(toplevel, this->ivtable->traits, param_traits); ctraits->itraits = itraits; } else { itraits = ctraits->itraits; } AvmAssert(itraits != NULL); VTable* class_ivtable = builtinClasses->get_ClassClass()->ivtable(); VTable* cvtab = core->newVTable(ctraits, class_ivtable, objVecToplevel); ScopeChain* cvtab_cscope = vectorobj_cscope->cloneWithNewVTable(core->GetGC(), cvtab, objVecAbcEnv); VTable* ivtab = core->newVTable(itraits, objVecIVTable, objVecToplevel); ScopeChain* ivtab_iscope = vectorobj_iscope->cloneWithNewVTable(core->GetGC(), ivtab, objVecAbcEnv); cvtab->ivtable = ivtab; ivtab->init = objVecIVTable->init; cvtab->resolveSignatures(cvtab_cscope); ivtab->resolveSignatures(ivtab_iscope); return cvtab; }
/** 15.2.4.5 Object.prototype.hasOwnProperty (V) When the hasOwnProperty method is called with argument V, the following steps are taken: 1. Let O be this object. 2. Call ToString(V). 3. If O doesn't have a property with the name given by Result(2), return false. 4. Return true. NOTE Unlike [[HasProperty]] (section 8.6.2.4), this method does not consider objects in the prototype chain. */ bool ObjectClass::_hasOwnProperty(Atom thisAtom, Stringp name) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; Traitsp t = NULL; switch (atomKind(thisAtom)) { case kObjectType: { // ISSUE should this look in traits and dynamic vars, or just dynamic vars. ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); // TODO // The change below is important as otherwise we will throw error in a call to hasAtomProperty for ByteArrayObject. // This gets us back to the behaviour which we had in Marlin. // A bugzilla bug [ 562224 ] has been created to address this issue more cleanly in near future return obj->traits()->getTraitsBindings()->findBinding(name, core->findPublicNamespace()) != BIND_NONE || obj->hasStringProperty(name); } case kNamespaceType: case kStringType: case kBooleanType: case kDoubleType: case kIntptrType: t = toplevel()->toTraits(thisAtom); break; default: return false; } // NOTE use caller's public namespace return t->getTraitsBindings()->findBinding(name, core->findPublicNamespace()) != BIND_NONE; }
ClassClosure* DomainObject::getClass(Stringp name) { AvmCore *core = this->core(); if (name == NULL) { toplevel()->throwArgumentError(kNullArgumentError, core->toErrorString("name")); } // Search for a dot from the end. int dot = name->lastIndexOf(core->cachedChars[(int)'.']); // If there is a '.', this is a fully-qualified // class name in a package. Must turn it into // a namespace-qualified multiname. Namespace* ns; Stringp className; if (dot >= 0) { Stringp uri = core->internString(name->substring(0, dot)); ns = core->internNamespace(core->newNamespace(uri)); className = core->internString(name->substring(dot+1, name->length())); } else { ns = core->publicNamespace; className = core->internString(name); } Multiname multiname(ns, className); // OOO: In the distribution, we search core->codeContext()->domainEnv rather than // our own domainEnv, which is surely a bug? ScriptObject *container = finddef(multiname, domainEnv); if (!container) { toplevel()->throwTypeError(kClassNotFoundError, core->toErrorString(&multiname)); } Atom atom = toplevel()->getproperty(container->atom(), &multiname, container->vtable); if (!AvmCore::istype(atom, core->traits.class_itraits)) { toplevel()->throwTypeError(kClassNotFoundError, core->toErrorString(&multiname)); } return (ClassClosure*)AvmCore::atomToScriptObject(atom); }
void ObjectClass::_setPropertyIsEnumerable(Atom thisAtom, Stringp name, bool enumerable) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; if ((thisAtom&7) == kObjectType) { ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); obj->setStringPropertyIsEnumerable(name, enumerable); } else { // cannot create properties on a sealed object. Multiname multiname(core->publicNamespace, name); toplevel()->throwReferenceError(kWriteSealedError, &multiname, traits()); } }
void ObjectClass::_setPropertyIsEnumerable(Atom thisAtom, Stringp name, bool enumerable) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; if (atomKind(thisAtom) == kObjectType) { ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); obj->setStringPropertyIsEnumerable(name, enumerable); } else { // cannot create properties on a sealed object. // NOTE just use the unmarked version Multiname multiname(core->getAnyPublicNamespace(), name); // NOTE use default public toplevel()->throwReferenceError(kWriteSealedError, &multiname, traits()); } }
bool ObjectClass::_propertyIsEnumerable(Atom thisAtom, Stringp name) { AvmCore* core = this->core(); name = name ? core->internString(name) : (Stringp)core->knull; if ((thisAtom&7) == kObjectType) { ScriptObject* obj = AvmCore::atomToScriptObject(thisAtom); return obj->getStringPropertyIsEnumerable(name); } else if ((thisAtom&7) == kNamespaceType) { // Special case: // E4X 13.2.5.1, 13.2.5.2 specifies that prefix and uri // are not DontEnum. return name == core->kuri || name == core->kprefix; } else { return false; } }
ArrayObject* RegExpObject::_exec(Stringp subject, UTF8String *utf8Subject, int startIndex, int& matchIndex, int& matchLen) { AvmAssert(subject != NULL); AvmAssert(utf8Subject != NULL); int ovector[OVECTOR_SIZE]; int results; int subjectLength = utf8Subject->length(); if( startIndex < 0 || startIndex > subjectLength || (results = pcre_exec((pcre*)m_pcreInst, NULL, utf8Subject->c_str(), subjectLength, startIndex, PCRE_NO_UTF8_CHECK, ovector, OVECTOR_SIZE)) < 0) { matchIndex = 0; matchLen = 0; return NULL; } AvmCore *core = this->core(); ArrayObject *a = toplevel()->arrayClass->newArray(results); a->setAtomProperty(toplevel()->regexpClass()->kindex, core->intToAtom(Utf8ToUtf16Index(subject, utf8Subject, ovector[0]))); a->setAtomProperty(toplevel()->regexpClass()->kinput, subject->atom()); a->setLength(results); // set array slots for (int i=0; i<results; i++) { if (ovector[i*2] > -1) { int length = ovector[i*2 + 1] - ovector[i*2]; Atom match = stringFromUTF8(utf8Subject->c_str()+ovector[i*2], length); a->setUintProperty(i, match); } else { a->setUintProperty(i, undefinedAtom); } } // handle named groups if (m_hasNamedGroups) { int entrySize; pcre_fullinfo((pcre*)m_pcreInst, NULL, PCRE_INFO_NAMEENTRYSIZE, &entrySize); int nameCount; pcre_fullinfo((pcre*)m_pcreInst, NULL, PCRE_INFO_NAMECOUNT, &nameCount); // this space is freed when (pcre*)m_pcreInst is freed char *nameTable; pcre_fullinfo((pcre*)m_pcreInst, NULL, PCRE_INFO_NAMETABLE, &nameTable); /* nameTable is a series of fixed length entries (entrySize) the first two bytes are the index into the ovector and the result is a null terminated string (the subgroup name) */ for (int i = 0; i < nameCount; i++) { int nameIndex, length; nameIndex = (nameTable[0] << 8) + nameTable[1]; length = ovector[nameIndex * 2 + 1] - ovector[ nameIndex * 2 ]; Atom name = stringFromUTF8((char*)(nameTable+2), (uint32)strlen(nameTable+2)); name = core->internString(name)->atom(); Atom value = stringFromUTF8(utf8Subject->c_str()+ovector[nameIndex*2], length); a->setAtomProperty(name, value); nameTable += entrySize; } } matchIndex = ovector[0]; matchLen = ovector[1]-ovector[0]; return a; }