Esempio n. 1
0
	// this = argv[0] (ignored)
	// arg1 = argv[1]
	// argN = argv[argc]
	Atom RegExpClass::construct(int argc, Atom* argv)
	{
		AvmCore* core = this->core();
		Stringp pattern;

		Atom patternAtom = (argc>0) ? argv[1] : undefinedAtom;
		Atom optionsAtom = (argc>1) ? argv[2] : undefinedAtom;

		if (AvmCore::istype(patternAtom, traits()->itraits)) {
			// Pattern is a RegExp object
			if (optionsAtom != undefinedAtom) {
				// ECMA 15.10.4.1 says to throw an error if flags specified
				toplevel()->throwTypeError(kRegExpFlagsArgumentError);
			}
			// Return a clone of the RegExp object
			RegExpObject* regExpObject = (RegExpObject*)AvmCore::atomToScriptObject(patternAtom);
			return (new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(regExpObject))->atom();
		} else {
			if (patternAtom != undefinedAtom) {
				pattern = core->string(argv[1]);
			} else {
				// cn:  disable this, breaking ecma3 tests.   was: todo look into this. it's what SpiderMonkey does.
				pattern = core->kEmptyString; //core->newConstantStringLatin1("(?:)");
			}
		}

		Stringp options = NULL;
		if (optionsAtom != undefinedAtom) {
			options = core->string(optionsAtom);
		}

		RegExpObject* inst = new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(this, pattern, options);
		return inst->atom();
	}
Esempio n. 2
0
File: VTable.cpp Progetto: bsdf/trx
    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;
    }
Esempio n. 3
0
	// E4X 13.3.2, page 67
	Atom QNameClass::construct(int argc, Atom* argv)
	{
		AvmCore* core = this->core();

		if (argc == 0)
			return (new (core->GetGC(), ivtable()->getExtraSize()) QNameObject(this, undefinedAtom))->atom();

		if (argc == 1)
		{
			if (core->isObject(argv[1]) && AvmCore::istype(argv[1], core->traits.qName_itraits))
				return argv[1];

			return (new (core->GetGC(), ivtable()->getExtraSize()) QNameObject(this, argv[1]))->atom();
		}
		else
		{
			Atom a = argv[1];
			if (a == undefinedAtom)
			{
				// ns undefined same as unspecified
				return (new (core->GetGC(), ivtable()->getExtraSize()) QNameObject(this, argv[2]))->atom();
			}
			else
			{
				Namespace* ns;
				if (AvmCore::isNull(a))
					ns = NULL;
				// It's important to preserve the incoming namespace because it's type
				// may not be public.  I.E...
				// namespace ns;
				// q = new QName(ns, "name"); // ns is a NS_PackageInternal ns
				// If we ever use this QName as a multiname, we need to preserve the exact ns
				else if (core->isNamespace(a))
					ns = core->atomToNamespace(a);				
				else
					ns = core->newNamespace (a);
				return (new (core->GetGC(), ivtable()->getExtraSize()) QNameObject(this, ns, argv[2]))->atom();
			}
		}
	}
Esempio n. 4
0
	RegExpClass::RegExpClass(VTable* cvtable)
		: ClassClosure(cvtable)
	{
		AvmAssert(traits()->getSizeOfInstance() == sizeof(RegExpClass));

		AvmCore* core = this->core();

		ScriptObject* object_prototype = toplevel()->objectClass->prototype;
		prototype = new (core->GetGC(), ivtable()->getExtraSize()) RegExpObject(this,object_prototype);

		kindex = core->internConstantStringLatin1("index");
		kinput = core->internConstantStringLatin1("input");
	}
Esempio n. 5
0
	Stringp FileClass::read(Stringp filename)
	{
		Toplevel* toplevel = this->toplevel();
		AvmCore* core = this->core();

		if (!filename) {
			toplevel->throwArgumentError(kNullArgumentError, "filename");
		}
		UTF8String* filenameUTF8 = filename->toUTF8String();
		FILE *fp = fopen(filenameUTF8->c_str(), "r");
		if (fp == NULL) {
			toplevel->throwError(kFileOpenError, filename);
		}
		fseek(fp, 0L, SEEK_END);
		long len = ftell(fp);
		#ifdef UNDER_CE
		fseek (fp, 0L, SEEK_SET);
		#else
		rewind(fp);
		#endif

		unsigned char *c = new unsigned char[len+1];
		len = (long)fread(c, 1, len, fp);
		c[len] = 0;
		
		fclose(fp);

		if (len >= 3)
		{
			// UTF8 BOM
			if ((c[0] == 0xef) && (c[1] == 0xbb) && (c[2] == 0xbf))
			{
				return core->newString(((char *)c) + 3, len - 3);
			}
			else if ((c[0] == 0xfe) && (c[1] == 0xff))
			{
				//UTF-16 big endian
				c += 2;
				len = (len - 2) >> 1;
				Stringp out = new (core->GetGC()) String(len);
				wchar *buffer = out->lockBuffer();
				for (long i = 0; i < len; i++)
				{
					buffer[i] = (c[0] << 8) + c[1];
					c += 2;
				}
				out->unlockBuffer();

				return out;
			}
			else if ((c[0] == 0xff) && (c[1] == 0xfe))
	ScriptObject* TypeDescriber::describeMetadataInfo(PoolObject* pool, uint32_t metadata_index)
	{
		AvmCore* core = m_toplevel->core();
		const uint8_t* metadata_pos = pool->metadata_infos[metadata_index];

		const uint32_t name_index = (metadata_pos) ? AvmCore::readU30(metadata_pos) : 0;
		// A bit of a hack: if the pool is builtin, always omit metadata chunks with names of "Version"
		// or "native", since these are used for reserved purposes internally.
		Stringp name = poolstr(pool, name_index);
		AvmAssert(name->isInterned() && core->kVersion->isInterned() && str(kstrid_native)->isInterned());
		if (pool->isBuiltin && (name == core->kVersion || name == str(kstrid_native))) 
			return NULL;

		const uint32_t val_count = (metadata_pos) ? AvmCore::readU30(metadata_pos) : 0;

		ScriptObject* o = new_object();
		ArrayObject* a = new_array();

		if (val_count > 0)
		{
			GC* gc = core->GetGC();
			List<uint32_t> key_indexes(gc);
			List<uint32_t> val_indexes(gc);
			
			read_u30_list(key_indexes, val_count, metadata_pos);
			read_u30_list(val_indexes, val_count, metadata_pos);

			for (uint32_t i = 0; i < val_count; ++i)
			{
				ScriptObject* v = new_object();
				const KVPair props[] = {
					{ kstrid_key, strAtom(poolstr(pool, key_indexes.get(i))) },
					{ kstrid_value, strAtom(poolstr(pool, val_indexes.get(i))) },
				};
				setpropmulti(v, props, elem_count(props));
				pushobj(a, v);
			}
		}

		const KVPair props[] = {
			{ kstrid_name, strAtom(name) },
			{ kstrid_value, objAtom(a) },
		};
		setpropmulti(o, props, elem_count(props));

		return o;
	}
Esempio n. 7
0
    // E4X 13.5.2, pg 87
    // this = argv[0] (ignored)
    // arg1 = argv[1]
    // argN = argv[argc]
    Atom XMLListClass::construct(int argc, Atom* argv)
    {
        AvmCore* core = this->core();
        if ((!argc) || AvmCore::isNullOrUndefined(argv[1]))
        {
            return ToXMLList (core->kEmptyString->atom());
        }

        // if args[0] is xmllist, create new list and call append
        if (AvmCore::isXMLList(argv[1]))
        {
            XMLListObject *l = XMLListObject::create(core->GetGC(), toplevel()->xmlListClass());
            l->_append (argv[1]);
            return l->atom();
        }

        return ToXMLList(argv[1]);
    }
	Atom DomainObject::loadBytes(ByteArrayObject *b)
	{
		AvmCore* core = this->core();
		if (!b)
			toplevel()->throwTypeError(kNullArgumentError, core->toErrorString("bytes"));

		ShellCodeContext* codeContext = new (core->GetGC()) ShellCodeContext();
		codeContext->m_domainEnv = domainEnv;

		// parse new bytecode
		size_t len = b->get_length();
		ScriptBuffer code = core->newScriptBuffer(len);
		VMPI_memcpy(code.getBuffer(), &b->GetByteArray()[0], len);
		Toplevel *toplevel = domainToplevel;
		return core->handleActionBlock(code, 0,
								  domainEnv,
								  toplevel,
								  NULL, codeContext);
	}
Esempio n. 9
0
File: VTable.cpp Progetto: bsdf/trx
 MethodEnv* VTable::makeMethodEnv(MethodInfo* func, ScopeChain* scope)
 {
     AvmCore* core = this->core();
     AbcEnv* abcEnv = scope->abcEnv();
     MethodEnv* methodEnv = MethodEnv::create(core->GetGC(), func, scope);
     // register this env in the callstatic method table
     int method_id = func->method_id();
     if (method_id != -1)
     {
         AvmAssert(abcEnv->pool() == func->pool());
         if (abcEnv->getMethod(method_id) == NULL)
         {
             abcEnv->setMethod(method_id, methodEnv);
         }
         #ifdef AVMPLUS_VERBOSE
         else if (func->pool()->isVerbose(VB_traits))
         {
             core->console << "WARNING: tried to re-register global MethodEnv for " << func << "\n";
         }
         #endif
     }
     return methodEnv;
 }
Esempio n. 10
0
    Atom SamplerScript::getMemberNames(ScriptObject* self, Atom o, bool instanceNames)
    {
#ifdef DEBUGGER
        AvmCore* core = self->core();
        MMgc::GC* gc = core->GetGC();
        Sampler* s = core->get_sampler();
        if (!s || !trusted(self))
            return undefinedAtom;

        if (AvmCore::isObject(o))
        {
            Traits *t = AvmCore::atomToScriptObject(o)->traits();
            if(AvmCore::istype(o, CLASS_TYPE) && instanceNames && t->itraits)
                t = t->itraits;
            if (s->slotIteratorVTable == NULL)
                s->slotIteratorVTable = _newVT(self->toplevel(), self->traits()->pool, sizeof(SlotIterator));
            return (new (gc) SlotIterator(t, s->slotIteratorVTable))->atom();
        }
#else
        (void)self;
        (void)o; (void)instanceNames;
#endif
        return undefinedAtom;
    }
Esempio n. 11
0
    // E4X 10.4, pg 36
    Atom XMLListClass::ToXMLList(Atom arg)
    {
        AvmCore* core = this->core();

        if (AvmCore::isNullOrUndefined(arg))
        {
            toplevel()->throwTypeError(
                       (arg == undefinedAtom) ? kConvertUndefinedToObjectError :
                                            kConvertNullToObjectError);
            return arg;
        }

        if (AvmCore::isXMLList(arg))
        {
            return arg;
        }
        else if (AvmCore::isXML(arg))
        {
            XMLObject *x = AvmCore::atomToXMLObject(arg);
            Multiname m;
            bool bFound = x->getQName (&m);
            Atom parent = x->parent();
            if (parent == undefinedAtom)
                parent = nullObjectAtom;
            XMLListObject *xl = XMLListObject::create(core->GetGC(), toplevel()->xmlListClass(), parent, bFound ? &m : 0);

            xl->_append (arg);
            return xl->atom();
        }
        else
        {
            Toplevel* toplevel = this->toplevel();

            Stringp s = core->string(arg);

            if (s->matchesLatin1("<>", 2, 0) && s->matchesLatin1("</>", 3, s->length()-3))
                s = s->substr(2, s->length() - 5);

            Namespace *defaultNamespace = toplevel->getDefaultNamespace();
            // We handle this step in the XMLObject constructor to avoid concatenation huge strings together
            // parentString = <parent xnlns=defaultNamespace> s </parent>
            // 3. Parse parentString as a W3C element information info e
            // 4. If the parse fails, throw a SyntaxError exception
            // 5. x = toXML(e);
            //StringBuffer parentString (core);
            //parentString << "<parent xmlns=\"";
            //parentString << defaultNamespace->getURI();
            //parentString << "\">";
            //parentString << s;
            //parentString << "</parent>";
            XMLObject *x = XMLObject::create(core->GetGC(), toplevel->xmlClass(), s, defaultNamespace);

            XMLListObject *xl = XMLListObject::create(core->GetGC(), toplevel->xmlListClass());
            for (uint32_t i = 0; i < x->getNode()->_length(); i++)
            {
                E4XNode *c = x->getNode()->_getAt (i);
                c->setParent (NULL);

                // !!@ trying to emulate rhino behavior here
                // Add the default namespace to our top element.
                Namespace *ns = toplevel->getDefaultNamespace();
                c->_addInScopeNamespace (core, ns, core->findPublicNamespace());
                xl->_appendNode (c);
            }
            return xl->atom();
        }
    }
Esempio n. 12
0
	// E4X 10.3, page 32
	Atom XMLClass::ToXML(Atom arg)
	{
		Toplevel* toplevel = this->toplevel();
		AvmCore* core = this->core();

		if (AvmCore::isNullOrUndefined(arg))
		{
			toplevel->throwTypeError(
					   (arg == undefinedAtom) ? kConvertUndefinedToObjectError :
											kConvertNullToObjectError);
			return arg;
		}
		else if (AvmCore::isXML(arg))
		{
			return arg;
		}
		else if (AvmCore::isXMLList(arg))
		{
			XMLListObject *xl = AvmCore::atomToXMLList(arg);
			if (xl->_length() == 1)
			{
				return xl->_getAt(0)->atom();
			}
			else
			{
				toplevel->throwTypeError(kXMLMarkupMustBeWellFormed);
				return 0;//notreached
			}
		}
		else
		{
			Namespace *defaultNamespace = toplevel->getDefaultNamespace();

			// 2. Parse parentString as a W3C element information info e
			// 3. If the parse fails, throw a SyntaxError exception
			XMLObject *x = new (core->GetGC()) XMLObject(toplevel->xmlClass(), core->string(arg), defaultNamespace);

			// 4. x = toXML(e);
			// 5. if x.length == 0
			//       return new xml object
			if (!x->getNode()->_length())
			{
				x->setNode( new (core->GetGC()) TextE4XNode(0, core->kEmptyString) );
			}
			// 6. else if x.length == 1
			//       x[0].parent = null
			//		return x[0]
			else if (x->getNode()->_length() == 1)
			{
				x->setNode( x->getNode()->_getAt (0)); // discard parent node
				x->getNode()->setParent (0);
			}
			// 7. else throw a syntaxError
			else
			{
				// check for multiple nodes where the first n-1 are PI/comment nodes and the 
				// last one is an element node.  Just ignore the PI/comment nodes and return
				// the element node.  (bug 148526).
				// Will also now ignore any text nodes that just contain whitespace (leading
				// or trailing) the one valid element node.  If multiple element nodes are found,
				// that is a failing case as well. (bug 192355)
				E4XNode *node = x->getNode();
				E4XNode *validNode = NULL;

				for (uint32 i = 0; i < node->_length(); i++)
				{
					E4XNode *n = node->_getAt (i);
					if (n->getClass() == E4XNode::kElement)
					{
						if (validNode != NULL)
							toplevel->throwTypeError(kXMLMarkupMustBeWellFormed);

						validNode = n;
					}
					else if (n->getClass() == E4XNode::kText)
					{
						if (!n->getValue()->isWhitespace())
						{
							toplevel->throwTypeError(kXMLMarkupMustBeWellFormed);
						}
					}
				}

				// No valid nodes found
				if (!validNode)
					toplevel->throwTypeError(kXMLMarkupMustBeWellFormed);

				x->setNode( validNode ); // discard parent node
				validNode->setParent (0);
			}
			return x->atom();
		}
	}
Esempio n. 13
0
File: VTable.cpp Progetto: bsdf/trx
    void VTable::resolveSignatures(ScopeChain* scope)
    {
        AvmAssert(scope != NULL);

        if( this->linked )
            return;
        // don't mark as resolved until the end of the function:
        // if traits->resolveSignatures() throws, we end up with the VTable as
        // "resolved" but the Traits not, which makes us crash in unpredictable ways.
        if (!traits->isResolved())
        {
            traits->resolveSignatures(toplevel());
            traits->setDeclaringScopes(scope->scopeTraits());
        }

#if defined(DEBUG) || defined(_DEBUG)
        // have to use local variables for CodeWarrior
        Traits* traitsBase = traits->base;
        Traits* baseTraits = base ? base->traits : 0;
        // make sure the traits of the base vtable matches the base traits
        AvmAssert((base == NULL && traits->base == NULL) || (base != NULL && traitsBase == baseTraits));
#endif // DEBUG

        AvmCore* core = traits->core;
        MMgc::GC* gc = core->GetGC();

        if (traits->init && !this->init)
        {
            this->init = makeMethodEnv(traits->init, scope);
        }

        // populate method table
        const TraitsBindingsp td = traits->getTraitsBindings();
        const TraitsBindingsp btd = td->base;
        for (uint32_t i = 0, n = td->methodCount; i < n; i++)
        {
            MethodInfo* method = td->getMethod(i);

            if (btd && i < btd->methodCount && method == btd->getMethod(i))
            {
                // inherited method
                // this->methods[i] = base->methods[i];
                WB(gc, this, &methods[i], base->methods[i]);
                continue;
            }

            // new definition
            if (method != NULL)
            {
                //this->methods[i] = new (gc) MethodEnv(method, this);
                WB(gc, this, &methods[i], makeMethodEnv(method, scope));
                continue;
            }
            #ifdef AVMPLUS_VERBOSE
            if (traits->pool->isVerbose(VB_traits))
            {
                // why would the compiler assign sparse disp_id's?
                traits->core->console << "WARNING: empty disp_id " << i << " on " << traits << "\n";
            }
            #endif
        }

        // this is done here b/c this property of the traits isn't set until the
        // Dictionary's ClassClosure is called
        if (base && base->traits->isDictionary())
            traits->set_isDictionary();

        traits->core->exec->notifyVTableResolved(this);

        linked = true;
    }
Esempio n. 14
0
	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
	}
	ScriptObject* TypeDescriber::describeTraits(Traitsp traits, uint32_t flags)
	{
		if (!(flags & INCLUDE_TRAITS))
			return NULL;
			
		AvmCore* core = m_toplevel->core();
		GC* gc = core->GetGC();
		TraitsBindingsp tb = traits->getTraitsBindings();
		TraitsMetadatap tm = traits->getTraitsMetadata();

		ScriptObject* o = new_object();

		ArrayObject* bases = NULL;
		ArrayObject* metadata = NULL;
		ArrayObject* interfaces = NULL;
		ArrayObject* methods = NULL;
		ArrayObject* accessors = NULL;
		ArrayObject* variables = NULL;
		ScriptObject* constructor = NULL;

		if (flags & INCLUDE_BASES)
		{
			metadata = new_array();
			PoolObject* class_mdpool;
			const uint8_t* class_md = tm->getMetadataPos(class_mdpool);
			if (class_md)
				addDescribeMetadata(metadata, class_mdpool, class_md);
		}
		
		if (flags & INCLUDE_BASES)
		{
			bases = new_array();
			for (Traitsp b = traits->base; b; b = b->base) 
				pushstr(bases, describeClassName(b));
		}
		
		if (flags & INCLUDE_INTERFACES)
		{
			interfaces = new_array();
			// our TraitsBindings only includes our own interfaces, not any we might have inherited, 
			// so walk the tree. there might be redundant interfaces listed in the inheritance, 
			// so use a list to remove dupes
			List<Traitsp> unique(gc);
			for (Traitsp b = traits; b; b = b->base) 
			{
				TraitsBindingsp tbi = b->getTraitsBindings();
				for (uint32_t i = 0; i < tbi->interfaceCapacity; ++i)
				{
					Traitsp ti = tbi->getInterface(i);
					if (ti && ti->isInterface && unique.indexOf(ti) < 0)
					{
						unique.add(ti);
						pushstr(interfaces, describeClassName(ti));
					}
				}
			}
		}

		// constructor
		if (flags & INCLUDE_CONSTRUCTOR)
		{
			AbstractFunction* initMethod = traits->init;
			if (initMethod && initMethod->param_count)
			{
				constructor = describeParams(initMethod);
			}
		}
		
		if (flags & (INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_VARIABLES))
		{
			// recover slot/method metadata and method-declarer information.
			
			// make a flattened set of bindings so we don't have to check for overrides as we go.
			// This is not terribly efficient, but doesn't need to be.
			MultinameHashtable* mybind = new (gc) MultinameHashtable();
			addBindings(mybind, tb, flags);

			// Don't want interface methods, so post-process and wipe out any
			// bindings that were added
			for (uint32_t i = 0; i < tb->interfaceCapacity; ++i)
			{
				Traitsp ti = tb->getInterface(i);
				if (ti && ti->isInterface)
				{
					TraitsBindingsp tbi = ti->getTraitsBindings();
					for (int32_t index = 0; (index = tbi->next(index)) != 0; )
					{
						Stringp name = tbi->keyAt(index);
						Namespacep ns = tbi->nsAt(index);
						mybind->add(name, ns, BIND_NONE);
					}
				}
			}
			
			// yuck, replicate buggy behavior in FP9/10
			List<Namespacep> nsremoval(gc);
			if (flags & HIDE_NSURI_METHODS)
			{
				for (uint32_t i = 0; i < tb->interfaceCapacity; ++i)
				{
					Traitsp ti = tb->getInterface(i);
					// already did interfaces, don't need to do them again
					if (ti && !ti->isInterface)
					{
						TraitsBindingsp tbi = ti->getTraitsBindings();
						for (int32_t index = 0; (index = tbi->next(index)) != 0; )
						{
							Namespacep ns = tbi->nsAt(index);
							if (ns->getURI()->length() > 0 && nsremoval.indexOf(ns) < 0)
								nsremoval.add(ns);
						}
					}
				}
			}

			for (int32_t index = 0; (index = mybind->next(index)) != 0; )
			{
				Binding binding = mybind->valueAt(index);
				Stringp name = mybind->keyAt(index);
				Namespacep ns = mybind->nsAt(index);
				Stringp nsuri = ns->getURI();
				TraitsMetadata::MetadataPtr md1 = NULL;
				TraitsMetadata::MetadataPtr md2 = NULL;
				PoolObject* md1pool = NULL;
				PoolObject* md2pool = NULL;

				// We only display public members -- exposing private namespaces could compromise security.
				if (ns->getType() != Namespace::NS_Public) 
					continue;
				
				if ((flags & HIDE_NSURI_METHODS) && nsremoval.indexOf(ns) >= 0)
					continue;
			
				ScriptObject* v = new_object();

				const BindingKind bk = AvmCore::bindingKind(binding);
				switch (bk)
				{
					case BKIND_CONST:
					case BKIND_VAR:
					{
						if (!(flags & INCLUDE_VARIABLES))
							continue;

						const uint32_t slotID = AvmCore::bindingToSlotId(binding);
						const KVPair props[] = {
							{ kstrid_access, strAtom(str(bk == BKIND_CONST ? kstrid_readonly : kstrid_readwrite)) },
							{ kstrid_type, strAtom(describeClassName(tb->getSlotTraits(slotID))) },
						};
						setpropmulti(v, props, elem_count(props));
						if (!variables) variables = new_array();
						pushobj(variables, v);
						md1 = tm->getSlotMetadataPos(slotID, md1pool);
						break;
					}

					case BKIND_METHOD:
					{
						if (!(flags & INCLUDE_METHODS))
							continue;

						const uint32_t methodID = AvmCore::bindingToMethodId(binding);
						const AbstractFunction* af = tb->getMethod(methodID);

						Traitsp declaringTraits = af->declaringTraits;

						const KVPair props[] = {
							{ kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) },
							{ kstrid_returnType, strAtom(describeClassName(af->returnTraits())) },
							{ kstrid_parameters, objAtom(describeParams(af)) },
						};
						setpropmulti(v, props, elem_count(props));
						if (!methods) methods = new_array();
						pushobj(methods, v);
						md1 = tm->getMethodMetadataPos(methodID, md1pool);
						break;
					}
					
					case BKIND_GET:
					case BKIND_SET:
					case BKIND_GETSET:
					{
						if (!(flags & INCLUDE_ACCESSORS))
							continue;
							
						const uint32_t methodID = AvmCore::hasGetterBinding(binding) ?
													AvmCore::bindingToGetterId(binding) :
													AvmCore::bindingToSetterId(binding);

						const AbstractFunction* af = tb->getMethod(methodID);

						Traitsp declaringTraits = af->declaringTraits;

						Traitsp accessorType = AvmCore::hasGetterBinding(binding) ?
													af->returnTraits() :
													af->paramTraits(1);

						static const uint8_t bk2str[8] = 
						{
							uint8_t(kstrid_emptyString),	// BKIND_NONE
							uint8_t(kstrid_emptyString),	// BKIND_METHOD
							uint8_t(kstrid_emptyString),	// BKIND_VAR
							uint8_t(kstrid_emptyString),	// BKIND_CONST
							uint8_t(kstrid_emptyString),	// BKIND_ITRAMP
							uint8_t(kstrid_readonly),		// BKIND_GET
							uint8_t(kstrid_writeonly),		// BKIND_SET
							uint8_t(kstrid_readwrite)		// BKIND_GETSET
						};
						const KVPair props[] = {
							{ kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) },
							{ kstrid_access, strAtom(str(StringId(bk2str[bk]))) },
							{ kstrid_type, strAtom(describeClassName(accessorType)) },
						};
						setpropmulti(v, props, elem_count(props));
						if (AvmCore::hasGetterBinding(binding))
							md1 = tm->getMethodMetadataPos(AvmCore::bindingToGetterId(binding), md1pool);
						if (AvmCore::hasSetterBinding(binding))
							md2 = tm->getMethodMetadataPos(AvmCore::bindingToSetterId(binding), md2pool);
						if (!accessors) accessors = new_array();
						pushobj(accessors, v);
						break;
					}
					case BKIND_NONE:
						break;
				}

				ArrayObject* vm = NULL;
				if ((flags & INCLUDE_METADATA) && (md1 || md2))
				{
					vm = new_array();
					addDescribeMetadata(vm, md1pool, md1);
					addDescribeMetadata(vm, md2pool, md2);
				}
				const KVPair props[] = {
					{ kstrid_name, strAtom(name) },
					{ kstrid_uri, strAtom(nsuri->length() == 0 ? NULL : nsuri) },
					{ kstrid_metadata, objAtom(vm) },
				};
				setpropmulti(v, props, elem_count(props));
			}
		}

		const KVPair props[] = {
			{ kstrid_bases, objAtom(bases) },
			{ kstrid_interfaces, objAtom(interfaces) },
			{ kstrid_metadata, objAtom(metadata) },
			{ kstrid_accessors, objAtom(accessors) },
			{ kstrid_methods, objAtom(methods) },
			{ kstrid_variables, objAtom(variables) },
			{ kstrid_constructor, objAtom(constructor) },
		};
		setpropmulti(o, props, elem_count(props));

		return o;
	}
Esempio n. 16
0
	void MethodInfo::verify(Toplevel *toplevel, AbcEnv* abc_env)
	{
		AvmAssert(declaringTraits()->isResolved());
		resolveSignature(toplevel);
		AvmCore* core = this->pool()->core;
		if (isNative())
		{
			union {
				GprMethodProc implGPR;
				AvmThunkNativeThunker thunker;
				AvmThunkNativeThunkerN thunkerN;
			} u;
	#ifdef DEBUGGER
			if (core->debugger())
			{
				MethodSignaturep ms = getMethodSignature();
				if (ms->returnTraitsBT() == BUILTIN_number)
					u.thunkerN = MethodInfo::debugEnterExitWrapperN;
				else
					u.thunker = MethodInfo::debugEnterExitWrapper32;
			}
			else
	#endif
			{
				u.thunker = this->thunker();
			}
			this->setNativeImpl(u.implGPR);
		}
		else
		{
			#ifdef DEBUGGER
			// just a fake CallStackNode here, so that if we throw a verify error, 
			// we get a stack trace with the method being verified as its top entry.
			CallStackNode callStackNode(this);
			#endif /* DEBUGGER */

			PERFM_NTPROF("verify-ticks");

			CodeWriter* coder = NULL;
			Verifier verifier(this, toplevel, abc_env);

			/*
				These "buf" declarations are an unfortunate but expedient hack:
				the existing CodeWriter classes (eg CodegenLIR, etc) have historically
				always been stack-allocated, thus they have no WB protection on member
				fields. Recent changes were made to allow for explicit cleanup() of them
				in the event of exception, but there was a latent bug waiting to happen:
				the actual automatic var was going out of scope, but still being referenced
				(via the 'coder' pointer) in the exception handler, but the area being 
				pointed to may or may not still be valid. The ideal fix for this would 
				simply be to heap-allocate the CodeWriters, but that would require going
				thru the existing code carefully and inserting WB where appropriate.
				Instead, this "expedient" hack uses placement new to ensure the memory
				stays valid into the exception handler. 
				
				Note: the lack of a call to the dtor of the CodeWriter(s) is not an oversight.
				Calling cleanup() on coder is equivalent to running the dtor for all
				of the CodeWriters here.
				
				Note: allocated using arrays of intptr_t (rather than char) to ensure alignment is acceptable.
			*/
		#define MAKE_BUF(name, type) \
			intptr_t name[(sizeof(type)+sizeof(intptr_t)-1)/sizeof(intptr_t)]

		#if defined FEATURE_NANOJIT
			MAKE_BUF(jit_buf, CodegenLIR);
			#if defined AVMPLUS_WORD_CODE
			MAKE_BUF(teeWriter_buf, TeeWriter);
			#endif
			#ifdef FEATURE_CFGWRITER
			MAKE_BUF(cfg_buf, CFGWriter);
			#endif
		#endif
			#if defined AVMPLUS_WORD_CODE
			MAKE_BUF(translator_buf, WordcodeEmitter);
			#else
			MAKE_BUF(stubWriter_buf, CodeWriter);
			#endif

			TRY(core, kCatchAction_Rethrow)
			{
#if defined FEATURE_NANOJIT
				if ((core->IsJITEnabled()) && !suggestInterp())
				{
					PERFM_NTPROF("verify & IR gen");
					
					// note placement-new usage!
					CodegenLIR* jit = new(jit_buf) CodegenLIR(this);
					#if defined AVMPLUS_WORD_CODE
					WordcodeEmitter* translator = new(translator_buf) WordcodeEmitter(this, toplevel);
					TeeWriter* teeWriter = new(teeWriter_buf) TeeWriter(translator, jit);
					coder = teeWriter;
					#else
					coder = jit;
					#endif

				#ifdef FEATURE_CFGWRITER
					// analyze code and generate LIR
					CFGWriter* cfg = new(cfg_buf) CFGWriter(this, coder); 
					coder = cfg;
				#endif

				    verifier.verify(coder);
					PERFM_TPROF_END();
			
					if (!jit->overflow) {
						// assembler LIR into native code
						jit->emitMD();
					}

					// the MD buffer can overflow so we need to re-iterate
					// over the whole thing, since we aren't yet robust enough
					// to just rebuild the MD code.

					// mark it as interpreted and try to limp along
					if (jit->overflow) {
						if (core->JITMustSucceed()) {
							Exception* e = new (core->GetGC()) Exception(core, core->newStringLatin1("JIT failed")->atom());
							e->flags |= Exception::EXIT_EXCEPTION;
							core->throwException(e);
						}
						setInterpImpl();
					}
	                #ifdef AVMPLUS_WORD_CODE
					else {
						if (_abc.word_code.translated_code) 
						{
							set_word_code(core->GetGC(), NULL);
						}
						if (_abc.word_code.exceptions) 
						{
							_abc.word_code.exceptions = NULL;
						}
					}
                    #endif
				}
				else
				{
					// NOTE copied below
					#if defined AVMPLUS_WORD_CODE
					WordcodeEmitter* translator = new(translator_buf) WordcodeEmitter(this, toplevel);
					coder = translator;
					#else
					CodeWriter* stubWriter = new(stubWriter_buf) CodeWriter();
					coder = stubWriter;
					#endif
					verifier.verify(coder); // pass2 dataflow
					setInterpImpl();
					// NOTE end copy
				}
#else // FEATURE_NANOJIT

				// NOTE copied from above
				#if defined AVMPLUS_WORD_CODE
				WordcodeEmitter* translator = new(translator_buf) WordcodeEmitter(this, toplevel);
				coder = translator;
				#else
				CodeWriter* stubWriter = new(stubWriter_buf) CodeWriter();
				coder = stubWriter;
				#endif
				verifier.verify(coder); // pass2 dataflow
				setInterpImpl();
				// NOTE end copy

#endif // FEATURE_NANOJIT
				
				if (coder)
				{
					coder->cleanup();
					coder = NULL;
				}
			}
			CATCH (Exception *exception) 
			{
				// clean up verifier
				verifier.~Verifier();

				// call cleanup all the way down the chain
				// each stage calls cleanup on the next one
				if (coder)
					coder->cleanup();

				// re-throw exception
				core->throwException(exception);
			}
			END_CATCH
			END_TRY
			PERFM_TPROF_END();
		}
Esempio n. 17
0
    ScriptObject* TypeDescriber::describeTraits(Traitsp traits, uint32_t flags, Toplevel* toplevel)
    {
        if (!(flags & INCLUDE_TRAITS))
            return NULL;

        AvmCore* core = m_toplevel->core();
        GC* gc = core->GetGC();
        TraitsBindingsp tb = traits->getTraitsBindings();
        TraitsMetadatap tm = traits->getTraitsMetadata();

        ScriptObject* o = new_object();

        ArrayObject* bases = NULL;
        ArrayObject* metadata = NULL;
        ArrayObject* interfaces = NULL;
        ArrayObject* methods = NULL;
        ArrayObject* accessors = NULL;
        ArrayObject* variables = NULL;
        ScriptObject* constructor = NULL;

        if (flags & INCLUDE_METADATA)
        {
            metadata = new_array();
            PoolObject* class_mdpool;
            const uint8_t* class_md = tm->getMetadataPos(class_mdpool);
            if (class_md)
                addDescribeMetadata(metadata, class_mdpool, class_md);
        }

        if (flags & INCLUDE_BASES)
        {
            bases = new_array();
            for (Traitsp b = traits->base; b; b = b->base)
                pushstr(bases, describeClassName(b));
        }

        if (flags & INCLUDE_INTERFACES)
        {
            interfaces = new_array();
            for (InterfaceIterator iter(traits); iter.hasNext();)
            {
                Traits* ti = iter.next();
                pushstr(interfaces, describeClassName(ti));
            }
        }

        // constructor
        if (flags & INCLUDE_CONSTRUCTOR)
        {
            MethodInfo* initMethod = traits->init;
            if (initMethod)
            {
                initMethod->resolveSignature(toplevel);
                MethodSignaturep ms = initMethod->getMethodSignature();
                if (ms->param_count() > 0)
                {
                    constructor = describeParams(initMethod, ms);
                }
            }
        }

        if (flags & (INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_VARIABLES))
        {
            // recover slot/method metadata and method-declarer information.

            // make a flattened set of bindings so we don't have to check for overrides as we go.
            // This is not terribly efficient, but doesn't need to be.
            MultinameBindingHashtable* mybind = MultinameBindingHashtable::create(gc);
            addBindings(m_toplevel->core(), mybind, tb, flags);

            // Don't want interface methods, so post-process and wipe out any
            // bindings that were added.
            for (InterfaceIterator ifc_iter(traits); ifc_iter.hasNext();)
            {
                Traitsp ti = ifc_iter.next();
                TraitsBindingsp tbi = ti->getTraitsBindings();
                StTraitsBindingsIterator iter(tbi);
                while (iter.next())
                {
                    if (!iter.key()) continue;
                    mybind->add(iter.key(), iter.ns(), BIND_NONE);
                }
            }

            // yuck, replicate buggy behavior in FP9/10
            RCList<Namespace> nsremoval(gc, kListInitialCapacity);
            if (flags & HIDE_NSURI_METHODS)
            {
                for (TraitsBindingsp tbi = tb->base; tbi; tbi = tbi->base)
                {
                    StTraitsBindingsIterator iter(tbi);
                    while (iter.next())
                    {
                        if (!iter.key()) continue;
                        Namespacep ns = iter.ns();
                        if (ns->getURI()->length() > 0 && nsremoval.indexOf(ns) < 0)
                        {
                            nsremoval.add(ns);
                        }
                    }
                }
            }

            StMNHTBindingIterator iter(mybind);
            while (iter.next())
            {
                if (!iter.key()) continue;
                Stringp name = iter.key();
                Namespacep ns = iter.ns();
                Binding binding = iter.value();
                Stringp nsuri = ns->getURI();
                TraitsMetadata::MetadataPtr md1 = NULL;
                TraitsMetadata::MetadataPtr md2 = NULL;
                PoolObject* md1pool = NULL;
                PoolObject* md2pool = NULL;

                // We only display public members -- exposing private namespaces could compromise security.
                if (ns->getType() != Namespace::NS_Public) {
                    continue;
                }

                if ((flags & HIDE_NSURI_METHODS) && nsremoval.indexOf(ns) >= 0) {
                    continue;
                }
                ScriptObject* v = new_object();

                const BindingKind bk = AvmCore::bindingKind(binding);
                switch (bk)
                {
                    case BKIND_CONST:
                    case BKIND_VAR:
                    {
                        if (!(flags & INCLUDE_VARIABLES))
                            continue;

                        const uint32_t slotID = AvmCore::bindingToSlotId(binding);
                        const KVPair props[] = {
                            { kstrid_access, strAtom(str(bk == BKIND_CONST ? kstrid_readonly : kstrid_readwrite)) },
                            { kstrid_type, strAtom(describeClassName(tb->getSlotTraits(slotID))) },
                        };
                        setpropmulti(v, props, elem_count(props));
                        if (!variables) variables = new_array();
                        pushobj(variables, v);
                        md1 = tm->getSlotMetadataPos(slotID, md1pool);
                        break;
                    }

                    case BKIND_METHOD:
                    {
                        if (!(flags & INCLUDE_METHODS))
                            continue;

                        const uint32_t methodID = AvmCore::bindingToMethodId(binding);
                        MethodInfo* mi = tb->getMethod(methodID);
                        mi->resolveSignature(toplevel);
                        MethodSignaturep ms = mi->getMethodSignature();

                        Traitsp declaringTraits = mi->declaringTraits();

                        const KVPair props[] = {
                            { kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) },
                            { kstrid_returnType, strAtom(describeClassName(ms->returnTraits())) },
                            { kstrid_parameters, objAtom(describeParams(mi, ms)) },
                        };
                        setpropmulti(v, props, elem_count(props));
                        if (!methods) methods = new_array();
                        pushobj(methods, v);
                        md1 = tm->getMethodMetadataPos(methodID, md1pool);
                        break;
                    }

                    case BKIND_GET:
                    case BKIND_SET:
                    case BKIND_GETSET:
                    {
                        if (!(flags & INCLUDE_ACCESSORS))
                            continue;

                        const uint32_t methodID = AvmCore::hasGetterBinding(binding) ?
                                                    AvmCore::bindingToGetterId(binding) :
                                                    AvmCore::bindingToSetterId(binding);

                        MethodInfo* mi = tb->getMethod(methodID);
                        mi->resolveSignature(toplevel);
                        MethodSignaturep ms = mi->getMethodSignature();

                        Traitsp declaringTraits = mi->declaringTraits();

                        // The verifier does not check the signature of a setter
                        // except when it is invoked.  We must be prepared for the
                        // case in which it has no arguments.
                        Traitsp accessorType;

                        if (AvmCore::hasGetterBinding(binding)) {
                            accessorType = ms->returnTraits();
                        } else {
                            // If setter is malformed, just use '*' as a placeholder.
                            accessorType = (ms->param_count() < 1) ? NULL : ms->paramTraits(1);
                        }

                        static const uint8_t bk2str[8] =
                        {
                            uint8_t(kstrid_emptyString),    // BKIND_NONE
                            uint8_t(kstrid_emptyString),    // BKIND_METHOD
                            uint8_t(kstrid_emptyString),    // BKIND_VAR
                            uint8_t(kstrid_emptyString),    // BKIND_CONST
                            uint8_t(kstrid_emptyString),    // unused
                            uint8_t(kstrid_readonly),       // BKIND_GET
                            uint8_t(kstrid_writeonly),      // BKIND_SET
                            uint8_t(kstrid_readwrite)       // BKIND_GETSET
                        };
                        const KVPair props[] = {
                            { kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) },
                            { kstrid_access, strAtom(str(StringId(bk2str[bk]))) },
                            { kstrid_type, strAtom(describeClassName(accessorType)) },
                        };
                        setpropmulti(v, props, elem_count(props));
                        if (AvmCore::hasGetterBinding(binding))
                            md1 = tm->getMethodMetadataPos(AvmCore::bindingToGetterId(binding), md1pool);
                        if (AvmCore::hasSetterBinding(binding))
                            md2 = tm->getMethodMetadataPos(AvmCore::bindingToSetterId(binding), md2pool);
                        if (!accessors) accessors = new_array();
                        pushobj(accessors, v);
                        break;
                    }
                    case BKIND_NONE:
                        break;
                    default:
                        break;
                }

                ArrayObject* vm = NULL;
                if ((flags & INCLUDE_METADATA) && (md1 || md2))
                {
                    vm = new_array();
                    addDescribeMetadata(vm, md1pool, md1);
                    addDescribeMetadata(vm, md2pool, md2);
                }
                const KVPair props[] = {
                    { kstrid_name, strAtom(name) },
                    { kstrid_uri, strAtom(nsuri->length() == 0 ? NULL : nsuri) },
                    { kstrid_metadata, objAtom(vm) },
                };
                setpropmulti(v, props, elem_count(props));
            }
        }

        const KVPair props[] = {
            { kstrid_bases, objAtom(bases) },
            { kstrid_interfaces, objAtom(interfaces) },
            { kstrid_metadata, objAtom(metadata) },
            { kstrid_accessors, objAtom(accessors) },
            { kstrid_methods, objAtom(methods) },
            { kstrid_variables, objAtom(variables) },
            { kstrid_constructor, objAtom(constructor) },
        };
        setpropmulti(o, props, elem_count(props));

        return o;
    }