root/core/AbcParser.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. decodeAbc
  2. addAOTDebugInfo
  3. canParse
  4. domain
  5. computeInstanceSizeAndSlotsOffset
  6. parseNsRef
  7. parseTypeName
  8. resolveQName
  9. resolveMethodInfo
  10. resolveUtf8
  11. parseName
  12. parse
  13. parseTraits
  14. parseMethodInfos
  15. parseMetadataInfos
  16. parseMethodBodies
  17. parseCpool
  18. addNamedTraits
  19. addNamedTraits
  20. addNamedScript
  21. parseScriptInfos
  22. parseInstanceInfos
  23. parseClassInfos
  24. readU30
  25. readDouble

/* ***** BEGIN LICENSE BLOCK *****
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 *
 * The Original Code is [Open Source Virtual Machine.].
 *
 * The Initial Developer of the Original Code is
 * Adobe System Incorporated.
 * Portions created by the Initial Developer are Copyright (C) 1993-2006
 * the Initial Developer. All Rights Reserved.
 *
 * Contributor(s):
 *   Adobe AS3 Team
 *
 * Alternatively, the contents of this file may be used under the terms of
 * either the GNU General Public License Version 2 or later (the "GPL"), or
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 * in which case the provisions of the GPL or the LGPL are applicable instead
 * of those above. If you wish to allow use of your version of this file only
 * under the terms of either the GPL or the LGPL, and not to allow others to
 * use your version of this file under the terms of the MPL, indicate your
 * decision by deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL or the LGPL. If you do not delete
 * the provisions above, a recipient may use your version of this file under
 * the terms of any one of the MPL, the GPL or the LGPL.
 *
 * ***** END LICENSE BLOCK ***** */

#include "avmplus.h"

#ifdef VMCFG_AOT
#include "AOTCompiler.h"
#endif

namespace avmplus
{
    /**
     * parse a .abc file completely
     * @param code
     * @return
     */
    PoolObject* AbcParser::decodeAbc(AvmCore* core, ScriptBuffer code, 
                Toplevel* toplevel,
                Domain* domain,
                const NativeInitializer* natives,
                API api)
    {
                int version;
                int result = canParse(code, &version);
                
#ifdef AVMPLUS_VERBOSE
                if (core->isVerbose(VB_parse))
                        core->console << "major=" << (version&0xFFFF) << " minor=" << (version>>16) << "\n";
#endif
                
                if (result != 0) {
                        switch (result) {
                                case kInvalidMagicError:
                                        toplevel->throwVerifyError(kInvalidMagicError, core->toErrorString(version>>16), core->toErrorString(version&0xFFFF));
                                case kCorruptABCError:
                                default:
                                        toplevel->throwVerifyError(kCorruptABCError);
                        }
                }

#ifdef VMCFG_AOT
                if(!natives) // no natives -- runtime-loaded script
                {
                        if(version == 0 && code.getSize() == 24) // only ABC "references" -- these are 0.0 version followed by SHA1
                        {
                                void *sha1 = (void *)(code.getBuffer() + 4);
                                for(int i = 0; i < nAOTInfos; i++)
                                {
                                        const AOTInfo *aotInfo = &aotInfos[i];
                                        AvmAssert(aotInfo != NULL);
                                        
                                        MMGC_STATIC_ASSERT(sizeof(aotInfo->origABCSHA1) == 20);
                                        if(!memcmp(aotInfo->origABCSHA1, sha1, 20))
                                        {
                                                ReadOnlyScriptBufferImpl scriptBufferImpl(aotInfo->abcBytes, aotInfo->nABCBytes);
                                                ScriptBuffer code(&scriptBufferImpl);
                                                
                                                NativeInitializer ninit(core, aotInfo, 0, 0);
                                                PoolObject *pool = decodeAbc(core, code, toplevel, domain, &ninit, api);
                                                AvmAssert(pool != NULL);
                                                AvmAssert(!pool->isBuiltin);
                                                AvmAssert(pool->aotInfo == aotInfo);
#ifdef DEBUGGER
                                                // TODO: is there a better pace to do this for both builtins and user scripts?
                                                addAOTDebugInfo(pool);
#endif
                                                return pool;
                                        }
                                }
                        }
                        toplevel->throwVerifyError( kCorruptABCError ); // not a reference or not found 
                        return NULL;
                }
#endif
                
                AbcParser parser(core, code, toplevel, domain, natives);
                PoolObject *pObject = parser.parse(api);
                if ( !pObject ) {
                        toplevel->throwVerifyError( kCorruptABCError );
                        /*NOTREACHED*/
                        return NULL;
                }
                else
                        return pObject;
        }

#if defined(VMCFG_AOT) && defined(DEBUGGER)
        void AbcParser::addAOTDebugInfo(PoolObject *pool)
        {
                AvmCore *core = pool->core;
                const AOTInfo *aotInfo = pool->aotInfo;
                Debugger *debugger = core->debugger();
                
                if(debugger)
                {
                        const MethodDebugInfo* methodDebugInfos = aotInfo->methodDebugInfos;
                
                        if(methodDebugInfos != NULL)
                        {                               
                                // create the structure representing the ABC
                                AbcFile* abc = new (core->GetGC()) AbcFile(core, 0);
                                
                                for(int n = 0; n < aotInfo->nABCMethods; n++)
                                {
                                        MethodInfo *f = pool->getMethodInfo(n);
                                        
                                        // create DMIs
                                        const MethodDebugInfo &info = methodDebugInfos[n];
                                        DebuggerMethodInfo* dmi = DebuggerMethodInfo::create(core, info.local_count, -1, info.scope_count);
                                        pool->_method_dmi.set(n, dmi);
                                        
                                        // set the file in the MethodInfo
                                        f->setFile(abc);
                                        
                                        // get a SourceFile
                                        SourceFile *src = NULL;
                                        
                                        if(info.file_name)
                                        {
                                                Stringp fileName = pool->getString(info.file_name);
                                                src = abc->sourceNamed(fileName);
                                                if(!src)
                                                {
                                                        src = new (core->GetGC()) SourceFile(core->GetGC(), fileName);
                                                        abc->sourceAdd(src);
                                                }
                                        }
                                        
                                        // set register names
                                        for(int i = 0; i < info.local_count; i++)
                                        {
                                                int name = info.local_names[i];
                                                
                                                if(name)
                                                        f->setRegName(i, pool->getString(name));
                                        }
                                        
                                        // add line info
                                        if(src)
                                                for(int i = 0; i < info.line_count; i++)
                                                        src->addLine(info.lines[i], f, 0);
                                }
                                // hook the ABC in
                                debugger->pool2abcIndex.add(pool, (const void *)debugger->abcList.size());
                                debugger->abcList.add(abc);
                        }
                }
    }
#endif

        int AbcParser::canParse(ScriptBuffer code, int* version)
        {
                if (version != NULL)
                        *version = 0;
                
                if (code.getSize() < 4)
                        return kCorruptABCError;
                
                int v = AvmCore::readU16(&code[0]) | AvmCore::readU16(&code[2])<<16;
                if (version != NULL)
                        *version = v;
                
                switch (v) {
#ifdef VMCFG_AOT
                        case 0: // just a "reference" to an AOT-ed ABC!
#endif
                        case (46<<16|16):
                                return 0;
                        default:
                                return kInvalidMagicError;
                }
        }
        
        AbcParser::AbcParser(AvmCore* core, ScriptBuffer code, 
                Toplevel* toplevel,
                Domain* domain,
                const NativeInitializer* natives)
                : instances(core->GetGC(), 0),
                  toplevel(toplevel),
                  domain(domain)
        {
                this->core = core;
                this->code = code;
                this->pool = NULL;
                this->version = AvmCore::readU16(&code[0]) | AvmCore::readU16(&code[2])<<16;
                this->pos = &code[4];
                this->natives = natives;

                abcStart = &code[0];
                abcEnd = &code[(int)code.getSize()];

                classCount = 0;
                metaNames = NULL;
        }

        AbcParser::~AbcParser()
        {
                if (metaNames)
                        core->GetGC()->Free(metaNames);
        }

        REALLY_INLINE void AbcParser::computeInstanceSizeAndSlotsOffset(int class_id, 
                                                                                                                                        Traits* base,
                                                                                                                                        uint16_t& sizeofInstance,
                                                                                                                                        uint16_t& offsetofSlots) const
        {
                // If this is a native class, use the stated instance size and offset to slot area.
                const NativeClassInfo* nativeEntry;
                if (natives && (nativeEntry = natives->get_class(class_id)) != NULL && nativeEntry->sizeofInstance)
                {
                        sizeofInstance = nativeEntry->sizeofInstance;
                        offsetofSlots = nativeEntry->offsetofSlotsInstance;
                        return;
                }

                // Search the inheritance chain for any native classes.
                while (base)
                {
                        if (base->getSizeOfInstance() > sizeof(ScriptObject))
                        {
                                // non-Object base class uses a subclass of ScriptObject, so use that size.
                                sizeofInstance = base->getSizeOfInstance();
                                // non-native class so slots start after end of C++ data.
                                offsetofSlots = sizeofInstance;
                                return;
                        }
                        base = base->base;
                }

                // no derived native classes found
                sizeofInstance = uint16_t(sizeof(ScriptObject));
                offsetofSlots = uint16_t(sizeof(ScriptObject));
        }

        Namespacep AbcParser::parseNsRef(const byte* &pc) const
        {
                uint32 index = readU30(pc);
                if (index == 0)
                {
                        return NULL; // AnyNamespace
                }

                if (index >= pool->constantNsCount)
                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(pool->constantNsCount));
                return pool->cpool_ns[index];
        }

#if defined(VMCFG_AOT) || defined(AVMPLUS_VERBOSE)
        void AbcParser::parseTypeName(const byte* &pc, Multiname& m) const
        {
                // only save the type name for now.  verifier will resolve to traits
                uint32 index = readU30(pc);
                if (index == 0)
                {
                        // type is *
                        m.setNamespace(core->getPublicNamespace(pool));
                        m.setName(core->kAsterisk);
                        return;
                }

                if (index >= pool->cpool_mn_offsets.size())
                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(pool->cpool_mn_offsets.size()));

                pool->parseMultiname(m, index);
        }
        #endif

        uint32_t AbcParser::resolveQName(const byte* &p, Multiname &m) const
        {
                uint32 index = readU30(p);
                if (index == 0 || index >= pool->cpool_mn_offsets.size())
                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(pool->constantCount));

                pool->parseMultiname(m, index);

                if (!pool->isBuiltin && !m.isQName())
                        toplevel->throwVerifyError(kCpoolEntryWrongTypeError, core->toErrorString(index));
                return index;
        }

        MethodInfo* AbcParser::resolveMethodInfo(uint32 index) const
        {
                const uint32_t c = pool->methodCount();
                if (index >= c)
                        toplevel->throwVerifyError(kMethodInfoExceedsCountError, core->toErrorString(index), core->toErrorString(c));

                MethodInfo* f = pool->getMethodInfo(index);
                if (!f)
                        toplevel->throwVerifyError(kMethodInfoOrderError, core->toErrorString(index));

                return f;
        }

        Stringp AbcParser::resolveUtf8(uint32 index) const
        {
                if (index > 0 && index < pool->constantStringCount)
                {
                        return pool->getString(index);
                }
                toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(pool->constantStringCount));
                return NULL;
        }

        Stringp AbcParser::parseName(const byte* &pc) const
        {
                uint32 index = readU30(pc);
                if (index == 0)
                        return NULL;
                return resolveUtf8(index);
        }

        PoolObject* AbcParser::parse(API api)
        {
#ifdef VMCFG_LOOKUP_CACHE
                // Loading a new ABC file always invalidates the lookup cache
                core->invalidateLookupCache();
#endif
                // Loading a new ABC file always invalidates the traits cache(s)
                core->tbCache()->flush();
                core->tmCache()->flush();

                // constant pool
                parseCpool(api);

                // parse all methodInfos in one pass.  Nested functions must come before outer functions
                parseMethodInfos();

                // parse all metadataInfos - AVM+ doesn't care about this, so we are really just skipping them
                parseMetadataInfos();

                // parse classes.  base classes must come first.
                if (!parseInstanceInfos()) return NULL;

                bool first = false;
                if (CLASS_TYPE == NULL)
                {
                        // if we haven't got types from the builtin file yet, do it now.
                        first = true;
                        core->traits.initInstanceTypes(pool);

                        // register "void"
                        addNamedTraits(core->getPublicNamespace(ApiUtils::getSmallestAPI()), VOID_TYPE->name(), VOID_TYPE);
                }

                // type information about class objects
                parseClassInfos();

                if (first)
                {
                        core->traits.initClassTypes(pool);
                }

                // scripts
                if( !parseScriptInfos() ) return NULL;

                // method bodies: code, exception info, and activation traits
                parseMethodBodies();

        return pool;
        }

        // check to see if we are trying to read past the file end or the beginning.
        #define CHECK_POS(pos) do { if ((pos) < abcStart || (pos) >= abcEnd ) toplevel->throwVerifyError(kCorruptABCError); } while (0)

        /**
         * setting up a traits that extends another one.  Two parser passes are required,
         * one for sizing the traits object and the other for allocating it and filling
         * it in.
         */
        Traits* AbcParser::parseTraits(uint16_t sizeofInstance,
                                                                        uint16_t offsetofSlots,
                                                                        Traits* base, 
                                                                        Namespacep ns, 
                                                                        Stringp name, 
                                                                        MethodInfo* script, 
                                                                        TraitsPosPtr traitsPos,
                                                                        TraitsPosType posType, 
                                                                        Namespacep protectedNamespace)
        {
                uint32_t nameCount = readU30(pos);

                // Very generous check for nameCount being way too large.
                if (nameCount > (uint32_t)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                #ifdef AVMPLUS_VERBOSE
                if (pool->isVerbose(VB_parse))
                        core->console << "        trait_count=" << nameCount << "\n";
                #endif

                Traits* traits = Traits::newTraits(pool, base, sizeofInstance,offsetofSlots , traitsPos, posType);
                traits->set_names(ns, name);
                traits->protectedNamespace = protectedNamespace;
                
                for (uint32_t i=0; i < nameCount; i++)
        {
                        Multiname mn;
                        const uint32_t qn_index = resolveQName(pos, mn);
                        Namespacep ns;
                        const NamespaceSet* nss;
                        if (mn.namespaceCount() > 1) {
                                nss = (NamespaceSet*) mn.getNsset();
                                ns = nss->nsAt(0);
                        }
                        else {
                                ns = mn.getNamespace();
                                nss = NamespaceSet::create(core->GetGC(), ns);
                        }
                        // TODO name can come out null and fire all kinds of asserts from a broken compiler
                        // and crash a release build, not sure if null is valid in any cases but there's definitely
                        // a missing verify error here somewhere
                        Stringp name = mn.getName();
                        CHECK_POS(pos);
            int tag = *pos++;
            TraitKind kind = (TraitKind) (tag & 0x0f);
                        
                        uint32_t class_index = 0;
                        uint32_t method_index = 0;
                        uint32_t slot_id = 0;
                        uint32_t value_index = 0;
                        uint32_t earlyDispId = 0;
                        bool needsDxns = false;
#ifdef AVMPLUS_VERBOSE
                        Multiname typeName;
#endif

                        // Read in the trait entry.
                        switch (kind)
                        {
                        case TRAIT_Slot:
                        case TRAIT_Const:
                                slot_id = readU30(pos);                                                 // slot id
#ifdef AVMPLUS_VERBOSE
                                parseTypeName(pos, typeName);
#else
                                readU30(pos);
#endif
                                value_index = readU30(pos);     // value index
                                if (value_index)
                                {
                                        CHECK_POS(pos);
                                        pos += 1;                               // value_kind
                                }
                                break;
                        case TRAIT_Class:
                                readU30(pos); // slot id
                                class_index = readU30(pos);
                                break;
                        case TRAIT_Getter:
                        case TRAIT_Setter:
                        case TRAIT_Method:
                                earlyDispId = readU30(pos);                     // disp id
                                method_index = readU30(pos);    
                                break;
                        default:
                                // unsupported traits type
                                toplevel->throwVerifyError(kUnsupportedTraitsKindError, core->toErrorString(kind));
                        }

                        const byte* meta_pos = pos;
                        if (tag & ATTR_metadata)
                        {
                                const uint32_t metadataCount = readU30(pos);
                                for (uint32_t metadata = 0; metadata < metadataCount; ++metadata)
                                {
                                        const uint32_t index = readU30(pos);
                                        if (index >= pool->metadataCount || !metaNames)
                                                toplevel->throwVerifyError(kCorruptABCError);
                                        Stringp name = metaNames[index];
                                        if (name == core->kNeedsDxns)
                                                needsDxns = true;
                                }
                        }

                        switch (kind)
            {
            case TRAIT_Slot:
            case TRAIT_Const:
            case TRAIT_Class:
                        {
                                if (script)
                                        addNamedScript(nss, name, script);

                                if (kind == TRAIT_Class)
                                {
                                        // get the class type
                                        if (class_index >= classCount)
                                                toplevel->throwVerifyError(kClassInfoExceedsCountError, core->toErrorString(class_index), core->toErrorString(classCount));

                                        Traits* ctraits = pool->getClassTraits(class_index);
                                        if (!ctraits) 
                                                toplevel->throwVerifyError(kClassInfoOrderError, core->toErrorString(class_index));

                                        #ifdef AVMPLUS_VERBOSE
                                        if (pool->isVerbose(VB_parse))
                                        {
                                                core->console << "            " << traitNames[kind]
                                                        << " name=" << Multiname::format(core, ns, name)
                                                        << " slot_id=" << slot_id
                                                        << " type=" << ctraits
                                                        << "\n";
                                        }
                                        #endif

                                        if (script)
                                        {
                                                // promote instance type to the vm-wide type table.
                                                // map type name to traits
                                                addNamedTraits(nss, name, ctraits->itraits);
                                                if (tag & ATTR_metadata)
                                                {
                                                        ctraits->itraits->setMetadataPos(meta_pos);
                                                }
                                        }
                                        else
                                        {
                                                if (tag & ATTR_metadata)
                                                {
                                                        ctraits->setMetadataPos(meta_pos);
                                                }
                                        }
                                }
                                else
                                {
                                        #ifdef AVMPLUS_VERBOSE
                                        if (pool->isVerbose(VB_parse))
                                        {
                                                core->console << "            " << traitNames[kind]
                                                        << " name=" << Multiname::format(core,ns,name)
                                                        << " slot_id=" << slot_id
                                                        << " value_index=" << value_index
                                                        << " type=" << typeName
                                                        << "\n";
                                        }
                                        #endif
                                }
                    break;
                        }
                        case TRAIT_Getter:
                        case TRAIT_Setter:
            case TRAIT_Method:
                        {
                                #ifdef AVMPLUS_VERBOSE
                                if (pool->isVerbose(VB_parse))
                                {
                                        core->console << "            " << traitNames[kind]
                                                << " name=" << Multiname::format(core, ns, name)
                                                << " disp_id=" << earlyDispId << " (ignored)"
                                            << " method_index=" << method_index
                                                << " attr=" << ((tag&ATTR_final)?"final":"virtual");
                                        if (tag&ATTR_override)
                                                core->console << "|override";
                                        core->console << "\n";
                                }
                                #endif

                                // id is unused here
                                MethodInfo* f = resolveMethodInfo(method_index);

                                #if VMCFG_METHOD_NAMES
                                if (core->config.methodNames)
                                {
                                        pool->_method_name_indices.set(method_index, -int32_t(qn_index));
                                }
                                #else
                                (void)qn_index;
                                #endif

                                // since this function is ref'ed here, we know the receiver type.
                                if (!f->makeMethodOf(traits))
                                        toplevel->throwVerifyError(kCorruptABCError);
                                
                                f->setKind(kind); // sets the IS_GETTER/IS_SETTER flags
                                if (tag & ATTR_final)
                                        f->setFinal();
                                if (tag & ATTR_override)
                                        f->setOverride();
                                if (needsDxns)
                                        f->setNeedsDxns();
                                
                                // only export one name for an accessor 
                                if (script && !domain->getNamedScript(name,ns))
                                        addNamedScript(nss, name, script);

                break;
                        }

                        default:
                                // unsupported traits type
                                toplevel->throwVerifyError(kUnsupportedTraitsKindError, core->toErrorString(kind));
            }

#ifdef AVMPLUS_VERBOSE
            if (tag & ATTR_metadata)
            {
                uint32_t metadataCount = readU30(meta_pos);
                                for (uint32_t metadata = 0; metadata < metadataCount; ++metadata)
                                {
                                        uint32_t index = readU30(meta_pos);
                                        if (pool->isVerbose(VB_parse))
                                                core->console << "            [" << metaNames[index] << "]\n";
                                }
            }
#endif
        }

                return traits;
        }

        void AbcParser::parseMethodInfos()
    {
        int methodCount = readU30(pos);

                #ifdef AVMPLUS_VERBOSE
                if(pool->isVerbose(VB_parse)) {
                        core->console << "method_count=" << methodCount << "\n";
                }
                #endif

                int size = methodCount == 0 ? 1 : methodCount;

                if (size > (abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                MMGC_MEM_TYPE(pool);
                pool->_methods.ensureCapacity(size);
#ifdef DEBUGGER
                if (core->debugger())
                {
                        pool->_method_dmi.ensureCapacity(size);
                        for (int i = 0; i < size; ++i)
                                pool->_method_dmi.set(i, NULL);
                }
#endif
#if VMCFG_METHOD_NAMES
                if (core->config.methodNames)
                {
                        pool->_method_name_indices.ensureCapacity(size);
                }
#endif

#ifdef AVMPLUS_VERBOSE
                const byte* startpos = pos;
#endif

                for (int i=0; i < methodCount; i++)
        {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        const byte* info_pos = pos;
                
                        // MethodInfo
                        const int param_count = readU30(pos);

#ifdef VMCFG_AOT
                        const byte* ret_type_pos = pos;
#endif

                // @todo -- we should add an AbcParser equivalent of skipU30;
                // then the next two clauses would be                   
                //              skipU30(pos, param_count+1);
                // in non-verbose builds
                        #ifdef AVMPLUS_VERBOSE
                        Multiname returnTypeName;
                        parseTypeName(pos, returnTypeName);
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":method["<<i<<"]\n"
                                        << "        returnType=" << returnTypeName << "\n"
                                        << "        param_count=" << param_count 
                                    << "\n";
                        }
                        #else
                        readU30(pos);// return type name
                        #endif

                        for( int j = 1; j <= param_count; ++j)
                        {
                                #ifdef AVMPLUS_VERBOSE
                                Multiname multiname;
                                parseTypeName(pos, multiname);
                                if(pool->isVerbose(VB_parse)) {
                                        core->console << "            paramType["<<j<<"]="<< multiname << "\n";
                                }
                                #else
                                readU30(pos);
                                #endif
                        }

            uint32_t name_index = readU30(pos);
            (void)name_index;
                        CHECK_POS(pos);
                        uint8_t abcFlags = *pos++;

                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "        name_index=" << name_index;
                                if (name_index > 0 && name_index < pool->constantStringCount)
                                        core->console << " \"" << pool->getString(name_index) << "\"";
                                core->console << "\n        flags=" << (uint32_t)abcFlags << "\n";
                        }
                        #endif

                        const NativeMethodInfo* ni = NULL;
                        if (abcFlags & MethodInfo::NATIVE)
                        {
                                ni = natives ? natives->getNativeInfo(i) : NULL;
                                if (!ni)
                                {
                                        // If this assert hits, you're missing a native method.  Method "i"
                                        // corresponds to the function of the same number in 
                                        // source\avmglue\avmglue.h if you're running the Flash player.
                                        AvmAssertMsg(0, "missing native method decl");
                                        toplevel->throwVerifyError(kIllegalNativeMethodError);
                                }
                        }

#ifdef VMCFG_AOT
                        bool isCompiled = false;
                        {
                                Multiname returnTypeName;
                                parseTypeName(ret_type_pos, returnTypeName);

                                NativeMethodInfo compiledMethodInfo;

                                if (!ni && natives->getCompiledInfo(&compiledMethodInfo, returnTypeName, i))
                                {
                                        ni = &compiledMethodInfo;
                                        abcFlags |= MethodInfo::compiledMethodFlags();
                                        isCompiled = true;
                                }
                        }
#endif

                        const int optional_count = (abcFlags & MethodInfo::HAS_OPTIONAL) ? readU30(pos) : 0;

                        MethodInfo* info = new (core->GetGC()) MethodInfo(i, pool, info_pos, abcFlags, ni);
                        
#ifdef VMCFG_AOT
                        if(isCompiled)
                                info->setCompiledMethod();
#endif
                        
                        #if VMCFG_METHOD_NAMES
                        if (core->config.methodNames)
                        {
                                pool->_method_name_indices.set(i, int32_t(name_index));
                        }
                        #endif

                        if (abcFlags & MethodInfo::HAS_OPTIONAL)
                        {
                                for( int j = 0; j < optional_count; ++j)
                                {
                                        readU30(pos);
                                        ++pos; // Kind bytes for each default value
                                }

                                if (!optional_count || (optional_count > param_count))
                                {
                                        // cannot have more optional params than total params
                                        toplevel->throwVerifyError(kCorruptABCError);
                                }
                        }

                        if (abcFlags & MethodInfo::HAS_PARAM_NAMES)
                        {
                                // AVMPlus doesn't care about the param names, just skip past them
                                for( int j = 0; j < param_count; ++j )
                                {
                                        readU30(pos);
                                }
                        }

                        // save method info pointer.  we will verify code later.
                        pool->_methods.set(i, info);
#ifdef DEBUGGER
                        // don't create the corresponding DebuggerMethodInfo yet, we'll do that in parseMethodBodies
#endif
                }
    }
        

        void AbcParser::parseMetadataInfos()
    {
        uint32_t metadataCount = readU30(pos);

                #ifdef AVMPLUS_VERBOSE
                if(pool->isVerbose(VB_parse)) {
                        core->console << "metadata_count=" << metadataCount << "\n";
                }
                #endif

                if (metadataCount > uint32_t(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                pool->metadata_infos.ensureCapacity(metadataCount);
                pool->metadataCount = metadataCount;

                if (metadataCount > 0)
                {
                        metaNames = (Stringp*) core->GetGC()->Calloc(metadataCount, sizeof(Stringp), MMgc::GC::kContainsPointers);

#ifdef AVMPLUS_VERBOSE
                        kVerboseVerify = core->internConstantStringLatin1("VerboseVerify");
#endif

                        for (uint32_t i=0; i < metadataCount; i++)
                        {
                                pool->metadata_infos.set(i, pos);
                                // MetadataInfo
                                uint32_t index = readU30(pos);
                                Stringp name = resolveUtf8(index);
                                // constant pool names are stuck and always reachable via PoolObject, DRC or WB
                                metaNames[i] = name;

                                #ifdef AVMPLUS_VERBOSE
                                if(pool->isVerbose(VB_parse)) {
                                        core->console << "    " << name;
                                }
                                #endif

                                int values_count = readU30(pos);
                                if (values_count > 0)
                                {
                                        #ifdef AVMPLUS_VERBOSE
                                        if(pool->isVerbose(VB_parse)) {
                                                core->console << "(";
                                        }
                                        #endif
                                        for(int q = 0; q < values_count; ++q)
                                        {
                                                uint32_t a = readU30(pos);
                                                uint32_t b = readU30(pos);
                                                #ifdef AVMPLUS_VERBOSE
                                                if(pool->isVerbose(VB_parse)) {
                                                        core->console << a << "," << b;
                                                        if (q+1 < values_count)
                                                                core->console << " ";
                                                }
                                                #else
                                                (void)a;
                                                (void)b;
                                                #endif
                                        }
                                        #ifdef AVMPLUS_VERBOSE
                                        if(pool->isVerbose(VB_parse)) {
                                                core->console << ")";
                                        }
                                #endif
                                }
                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                        core->console << "\n";
                        }
                        #endif
                        }
                }
    }

    void AbcParser::parseMethodBodies()
    {
        int bodyCount = readU30(pos);

                #ifdef AVMPLUS_VERBOSE
                if(pool->isVerbose(VB_parse)) {
                        core->console << "bodies_count=" << bodyCount << "\n";
                }
                #endif

#ifdef AVMPLUS_VERBOSE
                const byte* startpos = pos;
#endif

                for (int i=0; i < bodyCount; i++)
        {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif

                        uint32_t method_index = readU30(pos);
                        MethodInfo* info = resolveMethodInfo(method_index);

                        const byte *body_pos = pos;

            int max_stack = readU30(pos);
            (void)max_stack;
            
            int local_count = readU30(pos);
                        (void)local_count;

                        // can't do this check here because param_count isn't available
                        // until the method is resolved. (we could do some tricks to extract
                        // it, but we just defer this check to Verifier::verify instead.)
                        //if (local_count < info->param_count()+1)
                        //{
                        //      // must have enough locals to hold all parameters including this
                        //      toplevel->throwVerifyError(kCorruptABCError);
                        //}

                        // TODO change file format, just want local max_scope
                        int init_scope_depth = readU30(pos);
                        (void)init_scope_depth;
                        
                        int max_scope_depth = readU30(pos);
                        (void)max_scope_depth;

                        int code_length = readU30(pos);

                        if (code_length <= 0
#ifdef VMCFG_AOT
                                && !info->needActivation() // AOT allows a dummy body so that it can represent activation traits
#endif
                                ) 
                        {
                                toplevel->throwVerifyError(kInvalidCodeLengthError, core->toErrorString(code_length));
                        }

                        // check to see if we are trying to jump past the file end or the beginning.
                        if ( pos < abcStart || pos+code_length >= abcEnd )
                                toplevel->throwVerifyError(kCorruptABCError);
            pos += code_length;

            int exception_count = readU30(pos);

                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":method["<<method_index<<"] max_stack=" << max_stack
                                        << " local_count=" << local_count 
                                        << " init_scope_depth=" << init_scope_depth 
                                        << " max_scope_depth=" << max_scope_depth
                                        << " code_length=" << code_length
                                        << " exception_count=" << exception_count
                                    << "\n";
                        }
                        #endif

                        if (exception_count != 0) 
                        {
                                info->setHasExceptions();
                                for (int i=0; i<exception_count; i++) 
                                {
                                        // this will be parsed when method is verified.
                                        // see MethodInfo::resolveSignature

                                        #ifdef AVMPLUS_VERBOSE
                                        int from = readU30(pos);
                                        int to = readU30(pos);
                                        int target = readU30(pos);
                                        Multiname typeName;
                                        parseTypeName(pos, typeName);

                                        Multiname qn;
                                        uint32 name_index = (version != (46<<16|15)) ? readU30(pos) : 0;
                                        if (name_index != 0)
                                        {
                                                if (name_index >= pool->cpool_mn_offsets.size())
                                                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(name_index), core->toErrorString(pool->constantCount));
                                                pool->parseMultiname(qn, name_index);
                                        }

                                        if (pool->isVerbose(VB_parse))
                                        {
                                                core->console << "            exception["<<i<<"] from="<< from
                                                        << " to=" << to
                                                        << " target=" << target 
                                                        << " type=" << typeName
                                                        << " name=";
                                                if (name_index)
                                                {
                                                        core->console << qn;
                                                }
                                                else
                                                {
                                                        core->console << "(none)";
                                                }
                                                core->console << "\n";
                                        }
                                        #else
                                        readU30(pos); // from
                                        readU30(pos); // to
                                        readU30(pos); // target
                                        readU30(pos); // type name
                                        if (version != (46<<16|15))
                                        {
                                                const uint32 name_index = readU30(pos); // variable name
                                                if (name_index >= pool->cpool_mn_offsets.size())
                                                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(name_index), core->toErrorString(pool->constantCount));
                                        }
                                        #endif
                                }
                        }

                        if (info->hasMethodBody())
                        {
                                // Interface methods should not have bodies
                                Traits* declaringTraits = info->declaringTraits();
                                if (declaringTraits && declaringTraits->isInterface())
                                {
                                        toplevel->throwVerifyError(kIllegalInterfaceMethodBodyError, core->toErrorString(info));
                                }

#ifdef DEBUGGER
                                if (core->debugger())
                                {
                                        DebuggerMethodInfo* dmi = DebuggerMethodInfo::create(core, local_count, code_length, max_scope_depth - init_scope_depth);
                                        pool->_method_dmi.set(method_index, dmi);
                                }
#endif

                                // if non-zero, we have a duplicate method body - throw a verify error
                                if (info->abc_body_pos())
                                {
                                        toplevel->throwVerifyError(kDuplicateMethodBodyError, core->toErrorString(info));
                                }
                                
                                AvmAssert(!info->isResolved());
                                info->set_abc_body_pos(body_pos);

                                // there will be a traits_count here, even if NEED_ACTIVATION is not
                                // set.  So we parse the same way all the time.  We could reduce file size and
                                // memory by omitting the count + traits completely.

                                const byte* traits_pos = pos;
                                int nameCount = readU30(pos);
                                if (info->needActivation() || nameCount > 0)
                                {
                                        pos = traits_pos;
                                        Namespacep ns = NULL;
                                        Stringp name = NULL;
                                        #ifdef AVMPLUS_VERBOSE
                                        if (core->config.methodNames)
                                        {
                                                ns = core->getPublicNamespace(pool);
                                                name = core->internString(info->getMethodNameWithTraits(declaringTraits));
                                        }
                                        #endif
                                        // activation traits are raw types, not subclasses of object.  this is
                                        // okay because they aren't accessable to the programming model.
                                        Traits* act = parseTraits(sizeof(ScriptObject),
                                                                                                                                sizeof(ScriptObject), 
                                                                                                                                NULL, 
                                                                                                                                ns, 
                                                                                                                                name, 
                                                                                                                                NULL, 
                                                                                                                                traits_pos,
                                                                                                                                TRAITSTYPE_ACTIVATION, 
                                                                                                                                NULL);
                                        act->final = true;
                                        info->init_activationTraits(act);
                                }
                                else
                                {
                                        // TODO remove this assert once abc format is adjusted
                                        AvmAssert(nameCount == 0);
                                }
                        }
                        else
                        {
#ifdef VMCFG_AOT
                                if (info->needActivation())
                                {
                                        Namespacep ns = NULL;
                                        Stringp name = NULL;
                                        #ifdef AVMPLUS_VERBOSE
                                        if (core->config.methodNames)
                                        {
                                                ns = core->getPublicNamespace(pool);
                                                name = core->internString(info->getMethodNameWithTraits(info->declaringTraits()));
                                        }
                                        #endif
                                        // activation traits are raw types, not subclasses of object.  this is
                                        // okay because they aren't accessable to the programming model.
                                        Traits* act = parseTraits(sizeof(ScriptObject), 
                                                                                          sizeof(ScriptObject),
                                                                                          NULL, 
                                                                                          ns, 
                                                                                          name, 
                                                                                          NULL, 
                                                                                          pos,
                                                                                          TRAITSTYPE_ACTIVATION, 
                                                                                          NULL);
                                                act->final = true;
                                                info->init_activationTraits(act);
                                                pool->aotInfo->activationTraits[method_index] = act;
                                } else
#endif
                                {
                                        // native methods should not have bodies!
                                        toplevel->throwVerifyError(kIllegalNativeMethodBodyError, core->toErrorString(info));
                                }
                        }
        }
    }

    void AbcParser::parseCpool(API api)
    {
                pool = new (core->GetGC()) PoolObject(core, code, pos, api);
                pool->domain = domain;
                
#ifdef VMCFG_AOT
                AvmAssert(natives != 0);
                pool->isBuiltin = natives->hasBuiltins();
                pool->aotInfo = natives->get_aotInfo();
#else
                pool->isBuiltin = (natives != NULL);
#endif

                uint32 int_count = readU30(pos);
                // sanity check to prevent huge allocations
                if (int_count > (uint32)(abcEnd - pos)) 
                        toplevel->throwVerifyError(kCorruptABCError);

                List<int>& cpool_int = pool->cpool_int;
                cpool_int.ensureCapacity(int_count);
                pool->constantIntCount = int_count;

#ifdef AVMPLUS_VERBOSE
                pool->verbose_vb = core->config.verbose_vb; // pool picks up global settings
#endif

#ifdef AVMPLUS_VERBOSE
                const byte* startpos = pos;
#endif

                for(uint32_t i = 1; i < int_count; ++i)
                {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        // S32 value
                        cpool_int.set(i, readS32(pos));
                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_int["<<(uint32_t)i<<"]="
                                        <<constantNames[CONSTANT_Int] << " ";
                                core->console << cpool_int[i] << "\n";
                        }
                        #endif
                }

                uint32 uint_count = readU30(pos);
                if (uint_count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                List<uint32>& cpool_uint = pool->cpool_uint;
                cpool_uint.ensureCapacity(uint_count);
                pool->constantUIntCount = uint_count;

#ifdef AVMPLUS_VERBOSE
                startpos = pos;
#endif

                for(uint32_t i = 1; i < uint_count; ++i)
                {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        // U32 value
                        cpool_uint.set(i, (unsigned)readS32(pos));

                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_uint["<<i<<"]="
                                        <<constantNames[CONSTANT_UInt] << " ";
                                core->console << (double)cpool_uint[i];
                                core->console << "\n";
                        }
                        #endif
                }

                uint32 double_count = readU30(pos);
                if (double_count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                List<double*, LIST_GCObjects>& cpool_double = pool->cpool_double;
                cpool_double.ensureCapacity(double_count);
                pool->constantDoubleCount = double_count;

#ifdef AVMPLUS_VERBOSE
                startpos = pos;
#endif

                for(uint32_t i = 1; i < double_count; ++i)
                {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        double value = readDouble(pos);
                        cpool_double.set(i, (double*)(core->allocDouble(value)&~7));
                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_double["<<i<<"]="
                                        <<constantNames[CONSTANT_Double] << " ";
                                core->console << *cpool_double[i];
                                core->console << "\n";
                        }
                        #endif
                }

                uint32 string_count = readU30(pos);
                if (string_count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                MMGC_MEM_TYPE(pool);
                pool->setupConstantStrings(string_count);

#ifdef AVMPLUS_VERBOSE
                startpos = pos;
#endif

                pool->_abcStringStart = pos;

                PoolObject::ConstantStringData* dataP = pool->_abcStrings.data;
                AvmAssert(core->kEmptyString != NULL);
                dataP->str = core->kEmptyString;
                for(uint32_t i = 1; i < string_count; ++i)
                {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        // save the byte position into the cpool array
                        (++dataP)->abcPtr = pos;
                        // number of characters
                        // todo - is compiler emitting no. of chars or no. of bytes?
                        int len = readU30(pos);

                        // check to see if we are trying to read past the file end or the beginning.
            // Also check for valid UTF8.
                        if (pos < abcStart || pos+len >= abcEnd || 
                UnicodeUtils::Utf8ToUtf16((const uint8*) pos, len, NULL, 0, true) < 0)
            {
                // if we throw a verify error here, _abcStringEnd will never be set, and _abcStrings
                // will be left in an inconsistent state. having _abcStringStart set but not _abcStringEnd
                // can cause dynamicizeStrings to make poor decisions. So clean up before throwing.
                pool->_abcStringStart = NULL;
                pool->_abcStringEnd = NULL;
                VMPI_memset(pool->_abcStrings.data, 0, string_count*sizeof(PoolObject::ConstantStringData*));
                                toplevel->throwVerifyError(kCorruptABCError);
            }

#ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_string["<<i<<"]="
                                        << constantNames[CONSTANT_Utf8] << " ";
                                core->console.write(pos, len);
                                core->console << "\n";
                        }
#endif
                        // skip the UTF-8 string
                        pos += len;
                }
                pool->_abcStringEnd = pos;

                uint32 ns_count = readU30(pos);
                if (ns_count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                List<Namespacep> &cpool_ns = pool->cpool_ns;

                MMGC_MEM_TYPE(pool);
                cpool_ns.ensureCapacity(ns_count);
                pool->constantNsCount = ns_count;

#ifdef AVMPLUS_VERBOSE
                startpos = pos;
#endif
                for( uint32_t i = 1; i < ns_count; ++i )
                {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        CHECK_POS(pos);
                        CPoolKind kind = (CPoolKind) *(pos++);
                        switch(kind)
                        {
                                case CONSTANT_Namespace:
                case CONSTANT_PackageNamespace:
                case CONSTANT_PackageInternalNs:
                case CONSTANT_ProtectedNamespace:
                            case CONSTANT_ExplicitNamespace:
                case CONSTANT_StaticProtectedNs:
                                {
                                        uint32 index = readU30(pos);
                    Namespace::NamespaceType type = Namespace::NS_Public;
                    switch(kind)
                    {
                    case CONSTANT_PackageInternalNs:
                        type = Namespace::NS_PackageInternal;
                        break;
                    case CONSTANT_ProtectedNamespace:
                        type = Namespace::NS_Protected;
                        break;
                    case CONSTANT_ExplicitNamespace:
                        type = Namespace::NS_Explicit;
                                                break;
                    case CONSTANT_StaticProtectedNs:
                        type = Namespace::NS_StaticProtected;
                        break;
                    }

                    if (index)
                                        {
                                                Stringp uri = resolveUtf8(index);
                                                API api = ApiUtils::getURIAPI(core, uri);
                                                if (api) {
                                                        uri = ApiUtils::getBaseURI(core, uri);
                                                }
                                                else {
                                                        if (pool->isBuiltin) {
                                                                // builtins are by default in the largest version
                                                                api = ApiUtils::getLargestAPI(core);
                                                        }
                                                        else {
                                                                api = pool->getAPI();
                                                        }

                                                        // finally, if it has as version mark then strip it. this only happens
                                                        // when asc and avm are out of sync, which is a contingency we support
                                                        if (ApiUtils::hasVersionMark(uri))
                                                                uri = ApiUtils::getBaseURI(core, uri);
                                                }
                                                Namespacep ns = core->internNamespace(core->newNamespace(uri, type, api));
                                                cpool_ns.set(i, ns);
                                        }
                                        else
                                        {
                                                // issue this looks wrong.  should uri be ""?
                                                Atom uri = undefinedAtom;
                                                cpool_ns.set(i, core->internNamespace(core->newNamespace(uri, type)));
                                        }
                                        break;
                                }

                                case CONSTANT_PrivateNs: 
                                {
                                        uint32 index =  readU30(pos);
                                        Stringp uri = index ? resolveUtf8(index) : (Stringp)core->kEmptyString;
                    Namespacep ns = new (core->GetGC()) Namespace(nullStringAtom, uri, Namespace::NS_Private);
                                        cpool_ns.set(i, ns);
                                        break;
                                }
                                default:
                                {
                                        toplevel->throwVerifyError(kCpoolEntryWrongTypeError, core->toErrorString(i));
                                }
                        }
                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_ns["<<i<<"]="
                                        <<constantNames[kind] << " ";
                                core->console << core->format(cpool_ns[i]->atom());
                                core->console << "\n";
                        }
                        #endif
                }

                uint32 ns_set_count = readU30(pos);
                if (ns_set_count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                List<NamespaceSetp>& cpool_ns_set = pool->cpool_ns_set;
                cpool_ns_set.ensureCapacity(ns_set_count);
                pool->constantNsSetCount = ns_set_count;

#ifdef AVMPLUS_VERBOSE
                startpos = pos;
#endif

                for( uint32_t i = 1; i < ns_set_count; ++i)
                {
#ifdef AVMPLUS_VERBOSE
                        int offset = (int)(pos-startpos);
#endif
                        uint32 ns_count = readU30(pos);
                        
                        if (ns_count > (uint32)(abcEnd - pos))
                                toplevel->throwVerifyError(kCorruptABCError);

                        NamespaceSet* namespace_set = NamespaceSet::_create(core->GetGC(), ns_count);
                        for(uint32 j=0; j < ns_count; ++j)
                        {
                                Namespacep ns = parseNsRef(pos);
                                if (!ns)
                                        toplevel->throwVerifyError(kIllegalNamespaceError);
                                namespace_set->_initNsAt(j, ns);
                        }
                        cpool_ns_set.set(i, namespace_set);

                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_ns_set["<<i<<"]="
                                        <<constantNames[CONSTANT_NamespaceSet] << " ";
                                core->console << cpool_ns_set[i]->format(core);
                                core->console << "\n";
                        }
                        #endif
                }

                uint32 mn_count = readU30(pos);
                if (mn_count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                List<uint32_t>& cpool_mn_offsets = pool->cpool_mn_offsets;

                MMGC_MEM_TYPE(pool);
                cpool_mn_offsets.ensureCapacity(mn_count);

                for(uint32_t i = 1; i < mn_count; ++i )
                {
                        CHECK_POS(pos);
                        uint32_t const offset = uint32_t(pos - pool->_abcStart);
                        cpool_mn_offsets.set(i, offset);
                        CPoolKind kind = (CPoolKind)*pos++;
                        switch(kind)
                        {
                        case CONSTANT_Qname: 
                        case CONSTANT_QnameA:
                        {
                                // U16 namespace_index
                                // U16 name_index
                                // parse a multiname with one namespace (aka qname)
                                parseNsRef(pos);
                                parseName(pos);
                                break;
                        }

                        case CONSTANT_RTQname:
                        case CONSTANT_RTQnameA: 
                        {
                                // U16 name_index
                                // parse a multiname with just a name; ns fetched at runtime
                                parseName(pos);
                                break;
                        }
                        case CONSTANT_RTQnameL:
                        case CONSTANT_RTQnameLA:
                        {
                                break;
                        }

                        case CONSTANT_Multiname:
                        case CONSTANT_MultinameA:
                        {
                                parseName(pos);
                                
                                uint32 index = readU30(pos);

                                if (!index || index >= pool->constantNsSetCount)
                                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(pool->constantNsSetCount));

                                // If it is in the range of Namespace Sets then it must be a namespace set/
                                break;
                        }

                        case CONSTANT_MultinameL:
                        case CONSTANT_MultinameLA:
                        {
                                uint32 index = readU30(pos);

                                if (!index || index >= pool->constantNsSetCount)
                                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(pool->constantNsSetCount));

                                // If it is in the range of Namespace Sets then it must be a namespace set.

                                break;
                        }
                        
                        case CONSTANT_TypeName:
                        {
                                uint32 index = readU30(pos);

                // compare index against mn_count, *not* cpool_mn_offsets.size(), as the latter is still being built...
                // it's ok to forward-reference here.
                                if(!index || index >= mn_count)
                                        toplevel->throwVerifyError(kCpoolIndexRangeError, core->toErrorString(index), core->toErrorString(mn_count));

                                index = readU30(pos);
                                if(index != 1)
                                        toplevel->throwVerifyError(kCorruptABCError);
                                readU30(pos);
                                break;
                        }
                        default:
                                toplevel->throwVerifyError(kCpoolEntryWrongTypeError, core->toErrorString(i));
                        }
                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << offset << ":" << "cpool_mn["<<i<<"]="
                                        <<constantNames[kind] << " ";
                                Multiname name;
                                pool->parseMultiname(name, i);
                                core->console << name;
                                core->console << "\n";
                        }
                        #endif
                }
    }

    void AbcParser::addNamedTraits(NamespaceSetp nss, Stringp name, Traits* itraits)
    {
        // check to see if the base namespace has been added, if so then
        // all versions have been added
        Namespace* ns = nss->nsAt(0);
        if (!ns->isPrivate()) {
                        // compute the compatible apis for all namespaces and construct a namespace
                        // with that composite api
                        API apis = 0;
            for (NamespaceSetIterator iter(nss); iter.hasNext();) 
            {
                Namespacep nsi = iter.next();
                                AvmAssert(pool->isBuiltin && ApiUtils::isVersionedNS(core, nsi->getType(), nsi->getURI()) ? nsi->getAPI() != 0 : true);
                                apis |= ApiUtils::getCompatibleAPIs(core, nsi->getAPI());
                        }
                        ns = ApiUtils::getVersionedNamespace(core, ns, apis);
                        if (!domain->getNamedTrait(name, ns)) {
                                domain->addNamedTrait(name, ns, itraits);
                        }
                }
        else {
            // duplicate class
            //Multiname qname(ns,name);
            //toplevel->definitionErrorClass()->throwError(kRedefinedError, core->toErrorString(&qname));
        }
    }

        void AbcParser::addNamedTraits(Namespacep ns, Stringp name, Traits* itraits)
        {
                addNamedTraits(NamespaceSet::create(core->GetGC(), ns), name, itraits);
        }

        void AbcParser::addNamedScript(NamespaceSetp nss, Stringp name, MethodInfo* script)
        {
                Namespacep ns = nss->nsAt(0); // just need one
                if (ns->isPrivate()) 
                {
                        pool->addPrivateNamedScript(name, ns, script);
                }
                else 
                {
                        // use the first namespace to see if its been added
                        MethodInfo* s = domain->getNamedScript(name, ns);
                        if (!s)
                        {
                                API apis = 0;
                for (NamespaceSetIterator iter(nss); iter.hasNext();) 
                {
                    Namespacep nsi = iter.next();
                                        AvmAssert(pool->isBuiltin && ApiUtils::isVersionedNS(core, nsi->getType(), nsi->getURI()) ? nsi->getAPI() != 0 : true);
                                        apis |= ApiUtils::getCompatibleAPIs(core, nsi->getAPI());
                                }
                                ns = ApiUtils::getVersionedNamespace(core, ns, apis);
                                domain->addNamedScript(name, ns, script);
                        }
                        else
                        {
                                // duplicate definition
                                //Multiname qname(ns, name);
                                //toplevel->definitionErrorClass()->throwError(kRedefinedError, core->toErrorString(&qname));
                        }
                }
        }

        bool AbcParser::parseScriptInfos()
        {
                /*
                        U16 script_count
                        ScriptInfo[script_count]
                        {
                                U16 init_index                  // method_info index of init function
                                Traits script_traits    // traits for the global object of this package
                        }
                */

                uint32_t count = readU30(pos);

                #ifdef AVMPLUS_VERBOSE
                if(pool->isVerbose(VB_parse)) {
                        core->console << "script_count=" << count << "\n";
                }
                #endif

#ifdef AVMPLUS_VERBOSE
                const byte* startpos = pos;
#endif

                if (count == 0)
                {
                        return true;
                }

                if (count > (uint32)(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                pool->_scripts.ensureCapacity(count);

                // make global objects subclasses of Object

                for (uint32_t i=0; i < count; i++)
                {
                        const byte* script_pos = pos;

                        int init_index = readU30(pos);

                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console << "    " << (int)(script_pos-startpos) << ":script[" << i << "]"
                                        << " init_index=" << init_index
                                        << "\n";
                        }
                        #endif
                        MethodInfo* script = resolveMethodInfo(init_index);
                        Traits* declaringTraits = script->declaringTraits();

                        if (declaringTraits != NULL)
                        {
                                // method has already been bound to a different type.  Can't bind it twice because
                                // it can only have one environment, for its scope chain and super references.
                                toplevel->throwVerifyError(kAlreadyBoundError, core->toErrorString(script), core->toErrorString(declaringTraits));
                        }

                        Traits* traits = parseTraits(sizeof(ScriptObject),
                                                                                        sizeof(ScriptObject),
                                                                                        core->traits.object_itraits, 
                                                                                        core->getPublicNamespace(pool), 
                                                                                        core->kglobal, 
                                                                                        script, 
                                                                                        script_pos,
                                                                                        TRAITSTYPE_SCRIPT,
                                                                                        NULL);

                        if( !traits ) return false; // parseTraits failed

                        
                        // global object, make it dynamic
                        traits->set_needsHashtable(true);
                        traits->final = true;

                        script->makeMethodOf(traits);
                        traits->init = script;

            #if defined FEATURE_NANOJIT
                        if (core->config.runmode == RM_mixed || core->config.runmode == RM_interp_all)
                        {
                                // suggest that we don't jit the $init methods
                                script->setSuggestInterp();
                        }
                        #endif

                        pool->_scripts.set(i, traits);
#ifdef VMCFG_AOT
                        pool->aotInfo->scriptTraits[i] = traits;
#endif
                }

                return true;
        }

        bool AbcParser::parseInstanceInfos()
        {
                classCount = readU30(pos);
#ifdef AVMPLUS_VERBOSE
                if(pool->isVerbose(VB_parse)) {
                        core->console << "class_count=" << classCount <<"\n";
                }
#endif

#ifdef AVMPLUS_VERBOSE
                const byte* startpos = pos;
#endif

                if (classCount == 0)
                {
                        return true;
                }

                if (classCount > uintptr_t(abcEnd - pos))
                        toplevel->throwVerifyError(kCorruptABCError);

                // allocate room for class infos early, to handle nested classes
                pool->_classes.ensureCapacity(classCount);

                instances.ensureCapacity(classCount);

                for (uint32_t i=0; i < classCount; i++)
                {
                        const byte* instancepos = pos;

                        // CONSTANT_QName name of this class

                        Multiname mn;
                        resolveQName(pos, mn);
                        Namespacep ns;
                        Stringp name;
                        name = mn.getName();
                        const NamespaceSet* nss;
                        if (mn.namespaceCount() > 1) 
                        {
                                nss = mn.getNsset();
                                ns = nss->nsAt(0);
                        }
                        else 
                        {
                                ns = mn.getNamespace();
                                nss = NamespaceSet::create(core->GetGC(), ns);
                        }

                        // resolving base class type means class heirarchy must be a Tree
                        Traits* baseTraits = pool->resolveTypeName(pos, toplevel);

                        if ((baseTraits && baseTraits->final) ||
                                (CLASS_TYPE != NULL && baseTraits == CLASS_TYPE) ||
                                // note, builtins are allowed to override Function
                                (FUNCTION_TYPE != NULL && baseTraits == FUNCTION_TYPE && !pool->isBuiltin))
                        {
                                // error - attempt to extend final class
                #ifdef AVMPLUS_VERBOSE
                                if(pool->isVerbose(VB_parse)) {
                                        core->console << mn << " can't extend final class " << baseTraits << "\n";
                                }
                #endif
                                toplevel->throwVerifyError(kCannotExtendFinalClass, core->toErrorString(&mn));
                        }

                        if (baseTraits && baseTraits->isInterface())
                        {
                                // error, can't extend interface
                                toplevel->throwVerifyError(kCannotExtendError, core->toErrorString(&mn), core->toErrorString(baseTraits));
                        }

                        // read flags:  bit 0: sealed
                        //                              bit 1: final
                        //                              bit 2: interface
                        //                              bit 3: protected
                        CHECK_POS(pos);
                        int flags = *pos++;

                        // read protected namespace
                        Namespacep protectedNamespace = NULL;
                        if (flags & 8)
                        {
                                protectedNamespace = parseNsRef(pos);
                        }
                        
                        int interfaceCount = readU30(pos);
                        const byte* interfacePos = pos;

                        if(interfaceCount)
                        {
                                if (interfaceCount >= 0x10000000)
                                        toplevel->throwVerifyError(kCorruptABCError);

                                for( int x = 0; x < interfaceCount; ++ x )
                                {
                                        Traits *t = pool->resolveTypeName(pos, toplevel);
                                        if (!t || !t->isInterface())
                                        {
                                                // error, can't implement non-interface type
                                                toplevel->throwVerifyError(kCannotImplementError, core->toErrorString(&mn), core->toErrorString(t));
                                        }
                                }
                        }

                        // TODO make sure the inheritance is legal.      
                        //      - can't override final members
                        //      - overrides agree with base class signature
                        
                        uint32_t iinit_index = readU30(pos);
                        MethodInfo* iinit = resolveMethodInfo(iinit_index);

#ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                // TODO:  fixup this math here, since the 2's are all wrong
                                core->console
                                        << "    " << (int)(instancepos-startpos) << ":instance[" << i << "]"
                                        << " " << mn;

                                if (baseTraits)
                                        core->console << " extends " << baseTraits;

                                core->console
                                        << " interface_count=" << interfaceCount
                                        << " iinit_index=" << iinit_index
                                        << "\n";
                        }
#endif
                        TraitsPosType postype = (flags & 4) ? TRAITSTYPE_INTERFACE : TRAITSTYPE_INSTANCE;
                        uint16_t sizeofInstance = 0;
                        uint16_t offsetofSlots = 0;
                        computeInstanceSizeAndSlotsOffset(i, baseTraits, sizeofInstance, offsetofSlots);
                        Traits* itraits = parseTraits(sizeofInstance, 
                                                                                  offsetofSlots,  
                                                                                  baseTraits, 
                                                                                  ns, 
                                                                                  name, 
                                                                                  0, 
                                                                                  instancepos,
                                                                                  postype, 
                                                                                  protectedNamespace);
                        if( !itraits ) return false;
                        if (!baseTraits && core->traits.object_itraits == NULL)
                        {
                                // save object traits
                                core->traits.object_itraits = itraits;
                                itraits->builtinType = BUILTIN_object;
                        }

                        // AS3 language decision: dynamic is not inherited.
                        itraits->set_needsHashtable((flags&1) == 0);
                        itraits->final   = (flags&2) != 0;

                        if (itraits->isInterface())
                        {
                                // check for slotCount != 0 now done at resolve time

                                // interface base must be *
                                if (baseTraits)
                                {
                                        // error, can't extend this type
                                        toplevel->throwVerifyError(kCannotExtendError, core->toErrorString(&mn), core->toErrorString(baseTraits));
                                }
                        }

                        Traits* declaringTraits = iinit->declaringTraits();
                        if (declaringTraits != NULL)
                        {
                                // method has already been bound to a different type.  Can't bind it twice because
                                // it can only have one environment, for its scope chain and super references.
                                toplevel->throwVerifyError(kAlreadyBoundError, core->toErrorString(iinit), core->toErrorString(declaringTraits));
                        }

                        iinit->makeMethodOf(itraits);
                        itraits->init = iinit;

#ifdef AVMPLUS_VERBOSE
                        // print the interfaces.  interfaces have been resolved above so any
                        // errors would have been reported earlier.
                        for (int j=0, n=interfaceCount; j < n; j++)
                        {
                                Traits *interfaceTraits = pool->resolveTypeName(interfacePos, toplevel);
                                if(pool->isVerbose(VB_parse)) {
                                        core->console << "                interface["<<j<<"]=" << interfaceTraits <<"\n";
                                }
                        }
#else
                        (void)interfacePos;
#endif
                                                
                        instances.set(i, itraits);

                        if (pool->getTraits(name, ns, false) == NULL)
                        {
                                pool->addNamedTraits(name, ns, itraits);
                        }
                        else
                        {
                                // error, can't redefine a class or interface
                                //toplevel->definitionErrorClass()->throwError(kRedefinedError, core->toErrorString(&mn));
                        }
                }

                return true;
    }

        void AbcParser::parseClassInfos()
    {
                if (classCount == 0)
                {
                        return;
                }

#ifdef AVMPLUS_VERBOSE
                const byte* startpos = pos;
#endif

        for (uint32_t i=0; i < classCount; i++)
        {
            // CONSTANT_Multiname name of this class
                        Traits* itraits = instances[i];
                        Namespacep ns = itraits->ns();
                        Stringp name = itraits->name();

                        const byte* class_pos = pos;

                        uint32_t cinit_index = readU30(pos);
            MethodInfo* cinit = resolveMethodInfo(cinit_index);

                        #ifdef AVMPLUS_VERBOSE
                        if(pool->isVerbose(VB_parse)) {
                                core->console
                                        << "    " << (int)(class_pos-startpos) << ":class[" << i << "]"
                                        << " " << ns << "::" << name;

                                core->console
                                        << " cinit_index=" << cinit_index
                                        << "\n";
                        }
                        #endif

                        const NativeClassInfo* nativeEntry = natives ? natives->get_class(i) : NULL;
                        bool haveClassNativeInfo = nativeEntry && nativeEntry->sizeofClass;
                        Traits* ctraits = parseTraits(haveClassNativeInfo ? nativeEntry->sizeofClass : sizeof(ClassClosure),
                                                                                        haveClassNativeInfo ? nativeEntry->offsetofSlotsClass : sizeof(ClassClosure), 
                                                                                        CLASS_TYPE, 
                                                                                        ns, 
                                                                                        core->internString(core->concatStrings(name, core->newConstantStringLatin1("$"))), 
                                                                                        NULL, 
                                                                                        class_pos,
                                                                                        TRAITSTYPE_CLASS, 
                                                                                        itraits->protectedNamespace);

                        ctraits->setCreateClassClosureProc(nativeEntry ? nativeEntry->createClassClosure : NULL);

                        Traits* declaringTraits = cinit->declaringTraits();
                        if (declaringTraits != NULL)
                        {
                                // method has already been bound to a different type.  Can't bind it twice because
                                // it can only have one environment, for its scope chain and super references.
                                toplevel->throwVerifyError(kAlreadyBoundError, core->toErrorString(cinit), core->toErrorString(declaringTraits));
                        }
                        
                        cinit->makeMethodOf(ctraits);
                        ctraits->init = cinit;
                        ctraits->itraits = itraits;
                        ctraits->final = true;
                        ctraits->set_needsHashtable(true);

            #if defined FEATURE_NANOJIT
                        if (core->config.runmode == RM_mixed || core->config.runmode == RM_interp_all)
                        {
                                // suggest that we don't jit the class initializer
                                cinit->setSuggestInterp();
                        }
                        #endif

                        pool->_classes.set(i, ctraits);
        }
    }

        uint32_t AbcParser::readU30(const byte*& p) const
        {
                // We have added kBufferPadding bytes to the end of the main swf buffer.
                // Why?  Here we can read from 1 to 5 bytes.  If we were to
                // put the required safety checks at each byte read, we would slow
                // parsing of the file down.  With this buffer, only one check at the
                // top of this function is necessary. (we will read on into our own memory)
                CHECK_POS(p);
                return toplevel->readU30(p);
        }

        double AbcParser::readDouble(const byte* &p) const
        {
                // check to see if we are trying to read past the file end.
                if (p < abcStart || p+7 >= abcEnd )
                        toplevel->throwVerifyError(kCorruptABCError);

                union {
                        double value;
                        #if defined AVMPLUS_BIG_ENDIAN || defined VMCFG_DOUBLE_MSW_FIRST
                                struct { uint32_t hi, lo; } words;
                        #else
                                struct { uint32_t lo, hi; } words;
                        #endif
                };
                // the bytes in the abc are little endian but the words
                // in memory can be little endian or big endian.
                words.lo = p[0] | p[1]<<8 | p[2]<<16 | p[3]<<24;
                words.hi = p[4] | p[5]<<8 | p[6]<<16 | p[7]<<24;
                p += 8;
                return value;
        }
}

/* [<][>][^][v][top][bottom][index][help] */