// Function called as constructor ... not supported from user code // this = argv[0] (ignored) // arg1 = argv[1] // argN = argv[argc] MethodClosure* MethodClosureClass::create(MethodEnv* m, Atom obj) { WeakKeyHashtable* mcTable = m->getMethodClosureTable(); Atom mcWeakAtom = mcTable->get(obj); GCWeakRef* ref = (GCWeakRef*)AvmCore::atomToGCObject(mcWeakAtom); MethodClosure* mc; if (!ref || !ref->get()) { VTable* ivtable = this->ivtable(); mc = (new (core()->GetGC(), ivtable->getExtraSize()) MethodClosure(ivtable, m, obj)); // since MC inherits from CC, we must explicitly set the prototype and delegate since the // ctor will leave those null (and without delegate set, apply() and friends won't be found // in pure ES3 code) mc->prototype = prototype; mc->setDelegate(prototype); mcWeakAtom = AvmCore::gcObjectToAtom(mc->GetWeakRef()); mcTable->add(obj, mcWeakAtom); } else { mc = (MethodClosure*)ref->get(); } return mc; }
DoubleVectorObject* DoubleVectorClass::newVector(uint32 length) { VTable* ivtable = this->ivtable(); DoubleVectorObject *v = new (core()->GetGC(), ivtable->getExtraSize()) DoubleVectorObject(ivtable, prototype); v->set_length(length); return v; }
ObjectVectorObject* ObjectVectorClass::newVector(uint32 length) { VTable* ivtable = this->ivtable(); ObjectVectorObject *v = new (core()->GetGC(), ivtable->getExtraSize()) ObjectVectorObject(ivtable, prototype); v->set_type(this->index_type->atom()); v->set_length(length); return v; }
Atom VectorClass::applyTypeArgs(int argc, Atom* argv) { //Vector only takes 1 type argument AvmAssert(argc==1); if (argc != 1) { toplevel()->typeErrorClass()->throwError(kWrongTypeArgCountError, traits()->formatClassName(), core()->toErrorString(1), core()->toErrorString(argc)); } Atom type = argv[0]; AvmCore* core = this->core(); if (ISNULL(type)) return toplevel()->objectVectorClass->atom(); if (atomKind(type) != kObjectType) toplevel()->throwVerifyError(kCorruptABCError); ScriptObject* so = AvmCore::atomToScriptObject(type); if (so == toplevel()->intClass) return toplevel()->intVectorClass->atom(); else if (so == toplevel()->numberClass) return toplevel()->doubleVectorClass->atom(); else if (so == toplevel()->uintClass) return toplevel()->uintVectorClass->atom(); Traits* param_traits = so->vtable->ivtable->traits; Stringp fullname = VectorClass::makeVectorClassName(core, param_traits); if (!instantiated_types->contains(fullname->atom())) { VTable* vtab = this->vtable->newParameterizedVTable(param_traits, fullname); ObjectVectorClass* new_type = new (vtab->gc(), vtab->getExtraSize()) ObjectVectorClass(vtab); new_type->index_type = (ClassClosure*)AvmCore::atomToScriptObject(type); new_type->setDelegate(toplevel()->classClass->prototype); // Is this right? Should each instantiation get its own prototype? new_type->prototype = toplevel()->objectVectorClass->prototype; instantiated_types->add(fullname->atom(), new_type->atom()); } return (Atom)instantiated_types->get(fullname->atom()); }
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; }
Atom VectorClass::applyTypeArgs(int argc, Atom* argv) { Toplevel* toplevel = this->toplevel(); //Vector only takes 1 type argument AvmAssert(argc==1); if (argc != 1) { toplevel->typeErrorClass()->throwError(kWrongTypeArgCountError, traits()->formatClassName(), core()->toErrorString(1), core()->toErrorString(argc)); } Atom const typeAtom = argv[0]; ClassClosure* parameterizedType; if (ISNULL(typeAtom)) { parameterizedType = toplevel->objectVectorClass; } else { if (atomKind(typeAtom) != kObjectType) toplevel->throwVerifyError(kCorruptABCError); ScriptObject* typeObj = AvmCore::atomToScriptObject(typeAtom); if (typeObj == toplevel->intClass) { parameterizedType = toplevel->intVectorClass; } else if (typeObj == toplevel->uintClass) { parameterizedType = toplevel->uintVectorClass; } else if (typeObj == toplevel->numberClass) { parameterizedType = toplevel->doubleVectorClass; } else { // if we have an object, we must have an itraits (otherwise the typearg is not a Class) Traits* typeTraits = typeObj->vtable->traits->itraits; if (!typeTraits) toplevel->throwVerifyError(kCorruptABCError); ClassClosure* typeClass = (ClassClosure*)typeObj; Domain* typeDomain = typeObj->traits()->pool->domain; if ((parameterizedType = typeDomain->getParameterizedType(typeClass)) == NULL) { Stringp fullname = VectorClass::makeVectorClassName(core(), typeTraits); VTable* vt = this->vtable->newParameterizedVTable(typeTraits, fullname); ObjectVectorClass* parameterizedVector = new (vt->gc(), vt->getExtraSize()) ObjectVectorClass(vt); parameterizedVector->index_type = typeClass; parameterizedVector->setDelegate(toplevel->classClass->prototypePtr()); // Is this right? Should each instantiation get its own prototype? parameterizedVector->setPrototypePtr(toplevel->objectVectorClass->prototypePtr()); typeDomain->addParameterizedType(typeClass, parameterizedVector); parameterizedType = parameterizedVector; } } } return parameterizedType->atom(); }
ClassClosure *SamplerScript::getType(Toplevel* ss_toplevel, SamplerObjectType sot, const void *ptr) { Toplevel* tl; switch (sotGetKind(sot)) { case kSOT_String: { // toplevel can be null here if there was no CodeContext active // when the sample was taken (ie, string was allocated from C++ code). // in that case, use the TL from the SamplerScript itself... it isn't // technically the right one to use, but is adequate for our purposes here // (it will return a stringClass or namespaceClass that will be valid // for the sampler) tl = sotGetToplevel(sot); if (!tl) tl = ss_toplevel; return tl->stringClass(); } case kSOT_Namespace: { tl = sotGetToplevel(sot); if (!tl) tl = ss_toplevel; return tl->namespaceClass(); } default: AvmAssert(0); case kSOT_Object: break; } VTable* vt = sotGetVTable(sot); tl = vt->toplevel(); AvmCore* core = tl->core(); ClassClosure *type; ScriptObject* obj = (ScriptObject*)ptr; if (obj && AvmCore::istype(obj->atom(), core->traits.class_itraits)) { type = tl->classClass(); } else if (obj && AvmCore::istype(obj->atom(), core->traits.function_itraits)) { type = tl->functionClass(); } else if (obj && obj->traits()->isActivationTraits()) { type = tl->objectClass; } else { // fallback answer type = tl->objectClass; // note that note all types will have an init method, // so those types may get reported as "objectClass" rather // than something more specific. However, it's not clear // that the Sampler ever really cared about reporting those // objects well in the first place (eg activation or catch objects), // so it doesn't seem we're a lot worse off than before. ScopeChain* sc = NULL; if (vt->init) sc = vt->init->scope(); if (sc && sc->getSize() <= 1) { if(sc->getSize() == 1) type = tl->classClass(); } else if (sc) { Atom ccAtom = sc->getScope(sc->getSize()-1); if(AvmCore::isObject(ccAtom)) { type = (ClassClosure*) AvmCore::atomToScriptObject(ccAtom); if(!AvmCore::istype(type->atom(), core->traits.class_itraits)) { // obj is a ClassClosure type = tl->classClass(); } } } } AvmAssert(AvmCore::istype(type->atom(), core->traits.class_itraits)); return type; }
ArrayClass::ArrayClass(VTable* cvtable) : ClassClosure(cvtable), kComma(core()->internConstantStringLatin1(",")) { AvmCore* core = this->core(); Toplevel* toplevel = this->toplevel(); toplevel->arrayClass = this; AvmAssert(traits()->getSizeOfInstance() == sizeof(ArrayClass)); VTable* ivtable = this->ivtable(); ScriptObject* objectPrototype = toplevel->objectClass->prototype; prototype = new (core->GetGC(), ivtable->getExtraSize()) ArrayObject(ivtable, objectPrototype, 0); // According to ECMAscript spec (ECMA-262.pdf) // generic support: concat, join, pop, push, reverse, shift, slice, sort, splice, unshift // NOT generic: toString, toLocaleString // unknown: sortOn (our own extension) #if defined(_DEBUG) // AtomArray DRC unit tests, put here b/c this always runs once, has a GC * and // this class has to do with arrays. this is more convienent that trying to test // through actionscript // create an atom Stringp s = core->newConstantStringLatin1("foo"); Atom a = s->atom(); AvmAssert(s->RefCount()==0); AtomArray *ar = new (gc()) AtomArray(); // test push/pop ar->push(a); AvmAssert(s->RefCount()==1); ar->push(a); AvmAssert(s->RefCount()==2); ar->pop(); AvmAssert(s->RefCount()==1); // reverse ar->push(a); AvmAssert(s->RefCount()==2); ar->reverse(); AvmAssert(s->RefCount()==2); // shift ar->shift(); AvmAssert(s->RefCount()==1); // splice AtomArray *ar2 = new (gc()) AtomArray(); ar->push(a); ar2->push(ar); AvmAssert(s->RefCount()==4); ar->splice(1, 2, 1, ar2, 0); // [a,a,a] AvmAssert(s->RefCount()==5); // unshift Atom as[4] = {a,a,a,a}; ar->unshift(as, 4); AvmAssert(s->RefCount()==9); // removeAt ar->removeAt(1); AvmAssert(s->RefCount()==8); // setAt ar->setAt(2, a); AvmAssert(s->RefCount()==8); // insert ar->insert(2, a); AvmAssert(s->RefCount()==9); // clear ar->clear(); AvmAssert(s->RefCount() == 2); ar2->clear(); AvmAssert(s->RefCount() == 0); gc()->Free(ar); gc()->Free(ar2); #endif }
MSIDispatchConsumer* MSIDispatchConsumerClass::create(IDispatch* p) { VTable* ivtable = this->ivtable(); MSIDispatchConsumer *o = new (core()->GetGC(), ivtable->getExtraSize()) MSIDispatchConsumer(ivtable, prototype, p); return o; }
// Function called as constructor ... not supported from user code MSIUnknownConsumer* MSIUnknownConsumerClass::create(IUnknown* p, const IID &iid) { VTable* ivtable = this->ivtable(); MSIUnknownConsumer *o = new (core()->GetGC(), ivtable->getExtraSize()) MSIUnknownConsumer(ivtable, prototype, p, iid); return o; }