// After loading an ABC and inserting scripts into the verify queue, // process the work queues until they are empty. void BaseExecMgr::verifyEarly(Toplevel* toplevel, AbcEnv* abc_env) { GCList<MethodInfo> verifyQueue2(core->GetGC(), kListInitialCapacity); int verified; do { verified = 0; while (!verifyTraitsQueue.isEmpty()) { Traits* t = verifyTraitsQueue.removeFirst(); t->resolveSignatures(toplevel); TraitsBindingsp td = t->getTraitsBindings(); enqFunction(t->init); for (int i=0, n=td->methodCount; i < n; i++) enqFunction(td->getMethod(i)); } while (!verifyFunctionQueue.isEmpty()) { MethodInfo* f = verifyFunctionQueue.removeLast(); if (!isVerified(f)) { if (f->declaringTraits()->init != f && f->declaringScope() == NULL) { verifyQueue2.add(f); continue; } verified++; //console << "pre verify " << f << "\n"; verifyMethod(f, toplevel, abc_env); setVerified(f); if (config.verifyonly) f->_invoker = verifyOnlyInvoker; } } while (!verifyQueue2.isEmpty()) verifyFunctionQueue.add(verifyQueue2.removeLast()); } while (verified > 0); }
uint64_t VTable::bytesUsed() const { uint64_t bytesUsed = sizeof(VTable); if(ivtable != NULL) bytesUsed += ivtable->bytesUsed(); const TraitsBindingsp td = traits->getTraitsBindings(); const uint32_t n = td->methodCount; const uint32_t baseMethodCount = base ? td->base->methodCount : 0; bytesUsed += td->methodCount*sizeof(MethodInfo*); for (uint32_t i=0; i < n; i++) { MethodInfo* method = td->getMethod(i); if (i < baseMethodCount && td->base && method == td->base->getMethod(i)) { continue; } else if(method != NULL) { bytesUsed += method->bytesUsed(); } } return bytesUsed; }
void VTable::resolveSignatures(ScopeChain* scope) { AvmAssert(scope != NULL); if( this->linked ) return; // don't mark as resolved until the end of the function: // if traits->resolveSignatures() throws, we end up with the VTable as // "resolved" but the Traits not, which makes us crash in unpredictable ways. if (!traits->isResolved()) { traits->resolveSignatures(toplevel()); traits->setDeclaringScopes(scope->scopeTraits()); } #if defined(DEBUG) || defined(_DEBUG) // have to use local variables for CodeWarrior Traits* traitsBase = traits->base; Traits* baseTraits = base ? base->traits : 0; // make sure the traits of the base vtable matches the base traits AvmAssert((base == NULL && traits->base == NULL) || (base != NULL && traitsBase == baseTraits)); #endif // DEBUG AvmCore* core = traits->core; MMgc::GC* gc = core->GetGC(); if (traits->init && !this->init) { this->init = makeMethodEnv(traits->init, scope); } // populate method table const TraitsBindingsp td = traits->getTraitsBindings(); const TraitsBindingsp btd = td->base; for (uint32_t i = 0, n = td->methodCount; i < n; i++) { MethodInfo* method = td->getMethod(i); if (btd && i < btd->methodCount && method == btd->getMethod(i)) { // inherited method // this->methods[i] = base->methods[i]; WB(gc, this, &methods[i], base->methods[i]); continue; } // new definition if (method != NULL) { //this->methods[i] = new (gc) MethodEnv(method, this); WB(gc, this, &methods[i], makeMethodEnv(method, scope)); continue; } #ifdef AVMPLUS_VERBOSE if (traits->pool->isVerbose(VB_traits)) { // why would the compiler assign sparse disp_id's? traits->core->console << "WARNING: empty disp_id " << i << " on " << traits << "\n"; } #endif } // this is done here b/c this property of the traits isn't set until the // Dictionary's ClassClosure is called if (base && base->traits->isDictionary()) traits->set_isDictionary(); traits->core->exec->notifyVTableResolved(this); linked = true; }
ScriptObject* TypeDescriber::describeTraits(Traitsp traits, uint32_t flags) { if (!(flags & INCLUDE_TRAITS)) return NULL; AvmCore* core = m_toplevel->core(); GC* gc = core->GetGC(); TraitsBindingsp tb = traits->getTraitsBindings(); TraitsMetadatap tm = traits->getTraitsMetadata(); ScriptObject* o = new_object(); ArrayObject* bases = NULL; ArrayObject* metadata = NULL; ArrayObject* interfaces = NULL; ArrayObject* methods = NULL; ArrayObject* accessors = NULL; ArrayObject* variables = NULL; ScriptObject* constructor = NULL; if (flags & INCLUDE_BASES) { metadata = new_array(); PoolObject* class_mdpool; const uint8_t* class_md = tm->getMetadataPos(class_mdpool); if (class_md) addDescribeMetadata(metadata, class_mdpool, class_md); } if (flags & INCLUDE_BASES) { bases = new_array(); for (Traitsp b = traits->base; b; b = b->base) pushstr(bases, describeClassName(b)); } if (flags & INCLUDE_INTERFACES) { interfaces = new_array(); // our TraitsBindings only includes our own interfaces, not any we might have inherited, // so walk the tree. there might be redundant interfaces listed in the inheritance, // so use a list to remove dupes List<Traitsp> unique(gc); for (Traitsp b = traits; b; b = b->base) { TraitsBindingsp tbi = b->getTraitsBindings(); for (uint32_t i = 0; i < tbi->interfaceCapacity; ++i) { Traitsp ti = tbi->getInterface(i); if (ti && ti->isInterface && unique.indexOf(ti) < 0) { unique.add(ti); pushstr(interfaces, describeClassName(ti)); } } } } // constructor if (flags & INCLUDE_CONSTRUCTOR) { AbstractFunction* initMethod = traits->init; if (initMethod && initMethod->param_count) { constructor = describeParams(initMethod); } } if (flags & (INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_VARIABLES)) { // recover slot/method metadata and method-declarer information. // make a flattened set of bindings so we don't have to check for overrides as we go. // This is not terribly efficient, but doesn't need to be. MultinameHashtable* mybind = new (gc) MultinameHashtable(); addBindings(mybind, tb, flags); // Don't want interface methods, so post-process and wipe out any // bindings that were added for (uint32_t i = 0; i < tb->interfaceCapacity; ++i) { Traitsp ti = tb->getInterface(i); if (ti && ti->isInterface) { TraitsBindingsp tbi = ti->getTraitsBindings(); for (int32_t index = 0; (index = tbi->next(index)) != 0; ) { Stringp name = tbi->keyAt(index); Namespacep ns = tbi->nsAt(index); mybind->add(name, ns, BIND_NONE); } } } // yuck, replicate buggy behavior in FP9/10 List<Namespacep> nsremoval(gc); if (flags & HIDE_NSURI_METHODS) { for (uint32_t i = 0; i < tb->interfaceCapacity; ++i) { Traitsp ti = tb->getInterface(i); // already did interfaces, don't need to do them again if (ti && !ti->isInterface) { TraitsBindingsp tbi = ti->getTraitsBindings(); for (int32_t index = 0; (index = tbi->next(index)) != 0; ) { Namespacep ns = tbi->nsAt(index); if (ns->getURI()->length() > 0 && nsremoval.indexOf(ns) < 0) nsremoval.add(ns); } } } } for (int32_t index = 0; (index = mybind->next(index)) != 0; ) { Binding binding = mybind->valueAt(index); Stringp name = mybind->keyAt(index); Namespacep ns = mybind->nsAt(index); Stringp nsuri = ns->getURI(); TraitsMetadata::MetadataPtr md1 = NULL; TraitsMetadata::MetadataPtr md2 = NULL; PoolObject* md1pool = NULL; PoolObject* md2pool = NULL; // We only display public members -- exposing private namespaces could compromise security. if (ns->getType() != Namespace::NS_Public) continue; if ((flags & HIDE_NSURI_METHODS) && nsremoval.indexOf(ns) >= 0) continue; ScriptObject* v = new_object(); const BindingKind bk = AvmCore::bindingKind(binding); switch (bk) { case BKIND_CONST: case BKIND_VAR: { if (!(flags & INCLUDE_VARIABLES)) continue; const uint32_t slotID = AvmCore::bindingToSlotId(binding); const KVPair props[] = { { kstrid_access, strAtom(str(bk == BKIND_CONST ? kstrid_readonly : kstrid_readwrite)) }, { kstrid_type, strAtom(describeClassName(tb->getSlotTraits(slotID))) }, }; setpropmulti(v, props, elem_count(props)); if (!variables) variables = new_array(); pushobj(variables, v); md1 = tm->getSlotMetadataPos(slotID, md1pool); break; } case BKIND_METHOD: { if (!(flags & INCLUDE_METHODS)) continue; const uint32_t methodID = AvmCore::bindingToMethodId(binding); const AbstractFunction* af = tb->getMethod(methodID); Traitsp declaringTraits = af->declaringTraits; const KVPair props[] = { { kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) }, { kstrid_returnType, strAtom(describeClassName(af->returnTraits())) }, { kstrid_parameters, objAtom(describeParams(af)) }, }; setpropmulti(v, props, elem_count(props)); if (!methods) methods = new_array(); pushobj(methods, v); md1 = tm->getMethodMetadataPos(methodID, md1pool); break; } case BKIND_GET: case BKIND_SET: case BKIND_GETSET: { if (!(flags & INCLUDE_ACCESSORS)) continue; const uint32_t methodID = AvmCore::hasGetterBinding(binding) ? AvmCore::bindingToGetterId(binding) : AvmCore::bindingToSetterId(binding); const AbstractFunction* af = tb->getMethod(methodID); Traitsp declaringTraits = af->declaringTraits; Traitsp accessorType = AvmCore::hasGetterBinding(binding) ? af->returnTraits() : af->paramTraits(1); static const uint8_t bk2str[8] = { uint8_t(kstrid_emptyString), // BKIND_NONE uint8_t(kstrid_emptyString), // BKIND_METHOD uint8_t(kstrid_emptyString), // BKIND_VAR uint8_t(kstrid_emptyString), // BKIND_CONST uint8_t(kstrid_emptyString), // BKIND_ITRAMP uint8_t(kstrid_readonly), // BKIND_GET uint8_t(kstrid_writeonly), // BKIND_SET uint8_t(kstrid_readwrite) // BKIND_GETSET }; const KVPair props[] = { { kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) }, { kstrid_access, strAtom(str(StringId(bk2str[bk]))) }, { kstrid_type, strAtom(describeClassName(accessorType)) }, }; setpropmulti(v, props, elem_count(props)); if (AvmCore::hasGetterBinding(binding)) md1 = tm->getMethodMetadataPos(AvmCore::bindingToGetterId(binding), md1pool); if (AvmCore::hasSetterBinding(binding)) md2 = tm->getMethodMetadataPos(AvmCore::bindingToSetterId(binding), md2pool); if (!accessors) accessors = new_array(); pushobj(accessors, v); break; } case BKIND_NONE: break; } ArrayObject* vm = NULL; if ((flags & INCLUDE_METADATA) && (md1 || md2)) { vm = new_array(); addDescribeMetadata(vm, md1pool, md1); addDescribeMetadata(vm, md2pool, md2); } const KVPair props[] = { { kstrid_name, strAtom(name) }, { kstrid_uri, strAtom(nsuri->length() == 0 ? NULL : nsuri) }, { kstrid_metadata, objAtom(vm) }, }; setpropmulti(v, props, elem_count(props)); } } const KVPair props[] = { { kstrid_bases, objAtom(bases) }, { kstrid_interfaces, objAtom(interfaces) }, { kstrid_metadata, objAtom(metadata) }, { kstrid_accessors, objAtom(accessors) }, { kstrid_methods, objAtom(methods) }, { kstrid_variables, objAtom(variables) }, { kstrid_constructor, objAtom(constructor) }, }; setpropmulti(o, props, elem_count(props)); return o; }
ScriptObject* TypeDescriber::describeTraits(Traitsp traits, uint32_t flags, Toplevel* toplevel) { if (!(flags & INCLUDE_TRAITS)) return NULL; AvmCore* core = m_toplevel->core(); GC* gc = core->GetGC(); TraitsBindingsp tb = traits->getTraitsBindings(); TraitsMetadatap tm = traits->getTraitsMetadata(); ScriptObject* o = new_object(); ArrayObject* bases = NULL; ArrayObject* metadata = NULL; ArrayObject* interfaces = NULL; ArrayObject* methods = NULL; ArrayObject* accessors = NULL; ArrayObject* variables = NULL; ScriptObject* constructor = NULL; if (flags & INCLUDE_METADATA) { metadata = new_array(); PoolObject* class_mdpool; const uint8_t* class_md = tm->getMetadataPos(class_mdpool); if (class_md) addDescribeMetadata(metadata, class_mdpool, class_md); } if (flags & INCLUDE_BASES) { bases = new_array(); for (Traitsp b = traits->base; b; b = b->base) pushstr(bases, describeClassName(b)); } if (flags & INCLUDE_INTERFACES) { interfaces = new_array(); for (InterfaceIterator iter(traits); iter.hasNext();) { Traits* ti = iter.next(); pushstr(interfaces, describeClassName(ti)); } } // constructor if (flags & INCLUDE_CONSTRUCTOR) { MethodInfo* initMethod = traits->init; if (initMethod) { initMethod->resolveSignature(toplevel); MethodSignaturep ms = initMethod->getMethodSignature(); if (ms->param_count() > 0) { constructor = describeParams(initMethod, ms); } } } if (flags & (INCLUDE_ACCESSORS | INCLUDE_METHODS | INCLUDE_VARIABLES)) { // recover slot/method metadata and method-declarer information. // make a flattened set of bindings so we don't have to check for overrides as we go. // This is not terribly efficient, but doesn't need to be. MultinameBindingHashtable* mybind = MultinameBindingHashtable::create(gc); addBindings(m_toplevel->core(), mybind, tb, flags); // Don't want interface methods, so post-process and wipe out any // bindings that were added. for (InterfaceIterator ifc_iter(traits); ifc_iter.hasNext();) { Traitsp ti = ifc_iter.next(); TraitsBindingsp tbi = ti->getTraitsBindings(); StTraitsBindingsIterator iter(tbi); while (iter.next()) { if (!iter.key()) continue; mybind->add(iter.key(), iter.ns(), BIND_NONE); } } // yuck, replicate buggy behavior in FP9/10 RCList<Namespace> nsremoval(gc, kListInitialCapacity); if (flags & HIDE_NSURI_METHODS) { for (TraitsBindingsp tbi = tb->base; tbi; tbi = tbi->base) { StTraitsBindingsIterator iter(tbi); while (iter.next()) { if (!iter.key()) continue; Namespacep ns = iter.ns(); if (ns->getURI()->length() > 0 && nsremoval.indexOf(ns) < 0) { nsremoval.add(ns); } } } } StMNHTBindingIterator iter(mybind); while (iter.next()) { if (!iter.key()) continue; Stringp name = iter.key(); Namespacep ns = iter.ns(); Binding binding = iter.value(); Stringp nsuri = ns->getURI(); TraitsMetadata::MetadataPtr md1 = NULL; TraitsMetadata::MetadataPtr md2 = NULL; PoolObject* md1pool = NULL; PoolObject* md2pool = NULL; // We only display public members -- exposing private namespaces could compromise security. if (ns->getType() != Namespace::NS_Public) { continue; } if ((flags & HIDE_NSURI_METHODS) && nsremoval.indexOf(ns) >= 0) { continue; } ScriptObject* v = new_object(); const BindingKind bk = AvmCore::bindingKind(binding); switch (bk) { case BKIND_CONST: case BKIND_VAR: { if (!(flags & INCLUDE_VARIABLES)) continue; const uint32_t slotID = AvmCore::bindingToSlotId(binding); const KVPair props[] = { { kstrid_access, strAtom(str(bk == BKIND_CONST ? kstrid_readonly : kstrid_readwrite)) }, { kstrid_type, strAtom(describeClassName(tb->getSlotTraits(slotID))) }, }; setpropmulti(v, props, elem_count(props)); if (!variables) variables = new_array(); pushobj(variables, v); md1 = tm->getSlotMetadataPos(slotID, md1pool); break; } case BKIND_METHOD: { if (!(flags & INCLUDE_METHODS)) continue; const uint32_t methodID = AvmCore::bindingToMethodId(binding); MethodInfo* mi = tb->getMethod(methodID); mi->resolveSignature(toplevel); MethodSignaturep ms = mi->getMethodSignature(); Traitsp declaringTraits = mi->declaringTraits(); const KVPair props[] = { { kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) }, { kstrid_returnType, strAtom(describeClassName(ms->returnTraits())) }, { kstrid_parameters, objAtom(describeParams(mi, ms)) }, }; setpropmulti(v, props, elem_count(props)); if (!methods) methods = new_array(); pushobj(methods, v); md1 = tm->getMethodMetadataPos(methodID, md1pool); break; } case BKIND_GET: case BKIND_SET: case BKIND_GETSET: { if (!(flags & INCLUDE_ACCESSORS)) continue; const uint32_t methodID = AvmCore::hasGetterBinding(binding) ? AvmCore::bindingToGetterId(binding) : AvmCore::bindingToSetterId(binding); MethodInfo* mi = tb->getMethod(methodID); mi->resolveSignature(toplevel); MethodSignaturep ms = mi->getMethodSignature(); Traitsp declaringTraits = mi->declaringTraits(); // The verifier does not check the signature of a setter // except when it is invoked. We must be prepared for the // case in which it has no arguments. Traitsp accessorType; if (AvmCore::hasGetterBinding(binding)) { accessorType = ms->returnTraits(); } else { // If setter is malformed, just use '*' as a placeholder. accessorType = (ms->param_count() < 1) ? NULL : ms->paramTraits(1); } static const uint8_t bk2str[8] = { uint8_t(kstrid_emptyString), // BKIND_NONE uint8_t(kstrid_emptyString), // BKIND_METHOD uint8_t(kstrid_emptyString), // BKIND_VAR uint8_t(kstrid_emptyString), // BKIND_CONST uint8_t(kstrid_emptyString), // unused uint8_t(kstrid_readonly), // BKIND_GET uint8_t(kstrid_writeonly), // BKIND_SET uint8_t(kstrid_readwrite) // BKIND_GETSET }; const KVPair props[] = { { kstrid_declaredBy, strAtom(describeClassName(declaringTraits)) }, { kstrid_access, strAtom(str(StringId(bk2str[bk]))) }, { kstrid_type, strAtom(describeClassName(accessorType)) }, }; setpropmulti(v, props, elem_count(props)); if (AvmCore::hasGetterBinding(binding)) md1 = tm->getMethodMetadataPos(AvmCore::bindingToGetterId(binding), md1pool); if (AvmCore::hasSetterBinding(binding)) md2 = tm->getMethodMetadataPos(AvmCore::bindingToSetterId(binding), md2pool); if (!accessors) accessors = new_array(); pushobj(accessors, v); break; } case BKIND_NONE: break; default: break; } ArrayObject* vm = NULL; if ((flags & INCLUDE_METADATA) && (md1 || md2)) { vm = new_array(); addDescribeMetadata(vm, md1pool, md1); addDescribeMetadata(vm, md2pool, md2); } const KVPair props[] = { { kstrid_name, strAtom(name) }, { kstrid_uri, strAtom(nsuri->length() == 0 ? NULL : nsuri) }, { kstrid_metadata, objAtom(vm) }, }; setpropmulti(v, props, elem_count(props)); } } const KVPair props[] = { { kstrid_bases, objAtom(bases) }, { kstrid_interfaces, objAtom(interfaces) }, { kstrid_metadata, objAtom(metadata) }, { kstrid_accessors, objAtom(accessors) }, { kstrid_methods, objAtom(methods) }, { kstrid_variables, objAtom(variables) }, { kstrid_constructor, objAtom(constructor) }, }; setpropmulti(o, props, elem_count(props)); return o; }