/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */ /* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "hm-main.h" #ifdef VMCFG_HALFMOON namespace halfmoon { using namespace avmplus; // // global Type values // const Type* TOP = &TopType::INSTANCE; const Type* BOT = &BottomType::INSTANCE; const Type* TOPDATA = &TopDataType::INSTANCE; const Type* EFFECT = &EffectType::INSTANCE; const Type* STATE = &StateType::INSTANCE; const Type* TRAITS = &TraitsType::BASE; const Type* ORDINAL = &OrdinalType::BASE; const Type* NAME = &NameType::BASE; const Type* METHOD = &MethodType::BASE; const Type* ENV = &EnvType::BASE; // ---------------------------------------------------------------------- // Type /** * buildName - prints type name into AVM StringBuffer, * then makes an Allocated copy. * NOTE: currently printName() may not print anything, * in which case we return the empty (not NULL) string. */ const char* Type::buildName(Lattice& lat) const { StringBuffer buf(lat.core()); printName(buf, lat.core()); const char* vmstr = buf.c_str(); if (vmstr != NULL) { char* name = new (lat.alloc) char[VMPI_strlen(buf.c_str()) + 1]; VMPI_strcpy(name, buf.c_str()); for(int i = 0; name[i]; ++i) if(name[i] == '\"') name[i] = '\''; return name; } else { return ""; } } // ---------------------------------------------------------------------- // Base types const TopType TopType::INSTANCE; const BottomType BottomType::INSTANCE; const TopDataType TopDataType::INSTANCE; const EffectType EffectType::INSTANCE; const StateType StateType::INSTANCE; // ---------------------------------------------------------------------- // VM types template const Type* VMType::copy(Lattice& lat) const { if (!is_const) return &SELF_CLASS::BASE; Type* t = new (lat.alloc) SELF_CLASS(const_value); assert(t->name == NULL); t->name = buildName(lat); return t; } const TraitsType TraitsType::BASE; const OrdinalType OrdinalType::BASE; const NameType NameType::BASE; const MethodType MethodType::BASE; const EnvType EnvType::BASE; const Type* EnvType::copy(Lattice& lat) const { if (method == NULL) return &BASE; EnvType* t = new (lat.alloc) EnvType(method); assert(t->name == NULL); t->name = buildName(lat); return t; } // ------------------------------------------------------------------- // DataType /** * */ PrintWriter& DataType::printConstQual(PrintWriter& console, AvmCore* core) const { return console << '=' << asAtom(getAtomConst(core)); } /** * true if value set includes null, but we exclude it by constraint */ bool DataType::excludesNull() const { return Lattice::isNullable(traits) && !is_nullable; } /** * for most but not all data types, the default model is determined by the traits. */ ModelKind DataType::defaultModelKind() const { return halfmoon::defaultModelKind(traits); } // -------------------------------------------------------------------- // SimpleDataType template PrintWriter& SimpleDataType ::printName(PrintWriter& console, AvmCore* core) const { #ifdef AVMPLUS_VERBOSE console << traits; if (is_const) printConstQual(console, core); else if (excludesNull()) console << "~"; if (model != defaultModelKind()) console << "[" << modelDesc(model) << "]"; #else (void)core; #endif return console; } template const Type* SimpleDataType ::copy(Lattice& lat) const { Type *t = new (lat.alloc) SELF_CLASS(model, traits, is_nullable, is_const, const_value); assert(t->name == NULL); t->name = buildName(lat); return t; } template const DataType* SimpleDataType ::changeModel(Lattice &lat, ModelKind m) const { if (model == m) { return this; } else if (isCompatibleModel(m)) { return (DataType*)lat.makeType(SELF_CLASS(m, traits, is_nullable, is_const, const_value)); } else if (isNull() && isPointer(m)) { switch (m) { case kModelString: return (DataType*)lat.makeType(StringType(lat, m, (String*)NULL)); case kModelNamespace: return (DataType*)lat.makeType(NamespaceType(lat, m, (Namespace*)NULL)); case kModelScriptObject: return lat.null_type; default: assert(false && "non-nullable model"); return this; // fail } } else { assert(false && "incompatible model"); return this; // fail } } template const Type* SimpleDataType ::makeNotNull(Lattice &lat) const { if (!is_nullable) return this; if (is_const && AvmCore::isNullOrUndefined(atomVal(this, 0))) return BOT; // once you take null out of the set {null}, you have {} assert(!is_const); // is_const && !isNull should imply !is_nullable return lat.makeType( SELF_CLASS(model, traits, false, is_const, const_value)); } template const SELF_CLASS* SimpleDataType ::makeUnion(const SELF_CLASS& t, Lattice& lat) const { ModelKind union_model = model == t.model ? model : kModelAtom; if (is_const && t.is_const && const_value == t.const_value) return (SELF_CLASS*)lat.makeType( SELF_CLASS(union_model, traits, is_nullable, true, const_value)); Traits* union_traits = Verifier::findCommonBase(traits, t.traits); bool union_nullable = is_nullable || t.is_nullable; return (SELF_CLASS*)lat.makeType( SELF_CLASS(union_model, union_traits, union_nullable, false, (VALUE_REP)0)); } template const Type* SimpleDataType ::makeUnion(const Type& t, Lattice& lat) const { if (isSubtypeOf(t) && submodelof(this, &t)) return &t; if (t.isSubtypeOf(*this) && submodelof(&t, this)) return this; if (t.kind == TYPE_KIND) return makeUnion((SELF_CLASS&)t, lat); if (isDataType(t)) { // if we're null, reverse the test so we only need to handle the other-is-null case if (isNull() && halfmoon::kind(this) != kTypeVoid) { return t.makeUnion(*this, lat); } bool union_nullable = is_nullable || t.is_nullable; Traits* union_traits = Verifier::findCommonBase(traits, getTraits(&t)); switch (builtinType(union_traits)) { case BUILTIN_any: if (union_traits == NULL) { // null unioned with t just returns a nullable t, except for void if (builtinType(getTraits(&t)) == BUILTIN_null && builtinType(traits) != BUILTIN_void) { return lat.makeType(SELF_CLASS(model, traits, true, false, (VALUE_REP)0)); } } return lat.makeType(AnyType(union_traits, union_nullable)); case BUILTIN_object: return lat.makeType(ObjectType(union_traits, union_nullable)); default: if (union_traits == traits) { assert(builtinType(getTraits(&t)) == BUILTIN_null); return lat.makeType(SELF_CLASS(model, traits, true, false, (VALUE_REP)0)); } else { assert(halfmoon::defaultModelKind(union_traits) == kModelScriptObject); return lat.makeType(ScriptObjectType(kModelScriptObject, union_traits, union_nullable)); } } } return t.makeUnion(*this, lat); } // -------------------------------------------------------------------- // AnyType AnyType::AnyType(Traits* traits, bool is_nullable) : SimpleDataType (traits, kModelAtom, is_nullable, false, Atom(0)) { assert(builtinType(traits) == BUILTIN_any); } // -------------------------------------------------------------------- // ObjectType ObjectType::ObjectType(Traits* traits, bool is_nullable) : SimpleDataType (traits, kModelAtom, is_nullable, false, Atom(0)) { assert(builtinType(traits) == BUILTIN_object); } // -------------------------------------------------------------------- // VoidType VoidType::VoidType(Traits* traits) : SimpleDataType (traits, kModelAtom, true, true, undefinedAtom) { assert(builtinType(traits) == BUILTIN_void); } // -------------------------------------------------------------------- // ScriptObjectType ScriptObjectType::ScriptObjectType(ModelKind model, Traits* traits, bool is_nullable) : SimpleDataType (traits, model, is_nullable, false, NULL) { assert(isCompatibleModel(model)); } ScriptObjectType::ScriptObjectType(ModelKind model, Traits* traits, ScriptObject* const_value) : SimpleDataType (traits, model, const_value == NULL, true, const_value) { assert(isCompatibleModel(model)); } ScriptObjectType::ScriptObjectType(ModelKind model, Traits* traits, bool is_nullable, bool is_const, ScriptObject* const_value) : SimpleDataType (traits, model, is_nullable, is_const, const_value) { assert(isCompatibleModel(model)); } PrintWriter& ScriptObjectType::printName(PrintWriter& console, AvmCore* core) const { #ifdef AVMPLUS_VERBOSE if (builtinType(traits) == BUILTIN_any) console << "ScriptObject"; else console << traits; if (is_const) printConstQual(console, core); else if (excludesNull()) console << "~"; if (model != defaultModelKind()) console << "[" << modelDesc(model) << "]"; #else (void)core; #endif return console; } // -------------------------------------------------------------------- // NamespaceType NamespaceType::NamespaceType(Lattice& lat, ModelKind model, bool is_nullable) : SimpleDataType (lat.namespace_traits, model, is_nullable, false, NULL) { assert(isCompatibleModel(model)); } NamespaceType::NamespaceType(Lattice& lat, ModelKind model, Namespace* const_value) : SimpleDataType (lat.namespace_traits, model, const_value == NULL, true, const_value) { assert(isCompatibleModel(model)); } NamespaceType::NamespaceType(ModelKind model, Traits* traits, bool is_nullable, bool is_const, Namespace* const_value) : SimpleDataType (traits, model, is_nullable, is_const, const_value) { assert(isCompatibleModel(model)); } // -------------------------------------------------------------------- // StringType StringType::StringType(Lattice& lat, ModelKind model, bool is_nullable) : SimpleDataType (lat.string_traits, model, is_nullable, false, NULL) { assert(isCompatibleModel(model)); } StringType::StringType(Lattice& lat, ModelKind model, String* const_value) : SimpleDataType (lat.string_traits, model, const_value == NULL, true, const_value) { assert(isCompatibleModel(model)); } StringType::StringType(ModelKind model, Traits* traits, bool is_nullable, bool is_const, String* const_value) : SimpleDataType (traits, model, is_nullable, is_const, const_value) { assert(isCompatibleModel(model)); } // -------------------------------------------------------------------- // BooleanType BooleanType::BooleanType(Lattice& lat, ModelKind model) : SimpleDataType (lat.boolean_traits, model, false, false, false) { assert(isCompatibleModel(model)); } BooleanType::BooleanType(Lattice& lat, bool const_value, ModelKind model) : SimpleDataType (lat.boolean_traits, model, false, true, const_value) { assert(isCompatibleModel(model)); } BooleanType::BooleanType(ModelKind model, Traits* traits, bool is_nullable, bool is_const, bool const_value) : SimpleDataType (traits, model, is_nullable, is_const, const_value) { assert(isCompatibleModel(model)); } // -------------------------------------------------------------------- // NumberType const NumberConstraint NumberType::TRIV; NumberType::NumberType(Lattice& lat, ModelKind model) : DataType(kTypeNumber, model, lat.number_traits, false, false), constraint(TRIV) { assert(isCompatibleModel(model)); } NumberType::NumberType(Lattice& lat, ModelKind model, bool is_int, bool is_uint) : DataType(kTypeNumber, model, lat.number_traits, false, false), constraint(is_int, is_uint) { assert(isCompatibleModel(model)); } NumberType::NumberType(Lattice& lat, double d, ModelKind model) : DataType(kTypeNumber, model, lat.number_traits, false, true), constraint(d) { assert(isCompatibleModel(model)); } NumberType::NumberType(ModelKind model, Traits* traits, NumberConstraint constraint) : DataType(kTypeNumber, model, traits, false, constraint.isConst()), constraint(constraint) { assert(isCompatibleModel(model)); } const Type* NumberType::copy(Lattice& lat) const { Type *t = new (lat.alloc) NumberType(model, traits, constraint); assert(t->name == NULL); t->name = buildName(lat); return t; } const NumberType* NumberType::changeModel(Lattice &lat, ModelKind m) const { assert(isCompatibleModel(m)); return model == m ? this : (NumberType*)lat.makeType(NumberType(m, traits, constraint)); } const NumberType* NumberType::makeUnion(const NumberType& t, Lattice& lat) const { NumberConstraint union_constraint = constraint.makeUnion(t.constraint); ModelKind union_model = (model == kModelAtom || t.model == kModelAtom) ? kModelAtom : (union_constraint.isInt() || union_constraint.isUInt()) ? kModelInt : kModelDouble; return (NumberType*)lat.makeType(NumberType(union_model, traits, union_constraint)); } const Type* NumberType::makeUnion(const Type& t, Lattice& lat) const { if (isSubtypeOf(t) && submodelof(this, &t)) return &t; if (t.isSubtypeOf(*this) && submodelof(&t, this)) return this; if (t.kind == kTypeNumber) return makeUnion((NumberType&)t, lat); if (isDataType(t)) { Traits* union_traits = Verifier::findCommonBase(traits, getTraits(&t)); BuiltinType bt = builtinType(union_traits); if (bt == BUILTIN_any) { return lat.makeType(AnyType(union_traits, t.is_nullable)); } else { assert(bt == BUILTIN_object); return lat.makeType(ObjectType(union_traits, t.is_nullable)); } } return t.makeUnion(*this, lat); } // ------------------------------------------------------------------- /// /// type functions /// /** * Return true iff value_set(t1) is a subset of value_set(t2) */ bool subtypeof(const Type* t1, const Type* t2) { return t1->isSubtypeOf(*t2); } bool subtypeof(const Type& t1, const Type& t2) { return t1.isSubtypeOf(t2); } // CAUTION: wiggly, will change bool submodelof(const Type* t1, const Type* t2) { return model(t1) == model(t2) || isBottom(t1) || isTop(t2) || (isTopData(t2) && isDataType(*t1)); } // -------------------------------------------------------------------- bool maybeIndex(const Type* name_type, const Type* index_type) { if (isConst(name_type) && isNumber(index_type)) { const Multiname* name = nameVal(name_type); return !name->isAttr() && name->isRuntime() && name->containsAnyPublicNamespace(); } return false; } /** * Lattice */ Lattice::Lattice(AvmCore* core, Allocator& alloc) : alloc(alloc), core_(core), types(alloc) { BuiltinTraits& builtin = core->traits; int_traits = builtin.int_itraits; uint_traits = builtin.uint_itraits; number_traits = builtin.number_itraits; boolean_traits = builtin.boolean_itraits; namespace_traits = builtin.namespace_itraits; string_traits = builtin.string_itraits; object_traits = builtin.object_itraits; class_traits = builtin.class_itraits; void_traits = builtin.void_itraits; null_type = makeAtomConst(builtin.null_itraits, nullObjectAtom); void_type = makeAtomConst(void_traits, undefinedAtom); boolean_type = makeType(boolean_traits); double_type = makeType(number_traits); int_type = (NumberType*)makeType(NumberType(*this, kModelInt, true, false)); uint_type = (NumberType*)makeType(NumberType(*this, kModelInt, false, true)); makeNullableTypes(object_traits, object_type); makeNullableTypes(string_traits, string_type); makeNullableTypes(namespace_traits, namespace_type); makeNullableTypes(builtin.error_itraits, error_type); makeNullableTypes(builtin.array_itraits, array_type); makeNullableTypes(builtin.vectorint_itraits, vectorint_type); makeNullableTypes(builtin.vectoruint_itraits, vectoruint_type); makeNullableTypes(builtin.vectordouble_itraits, vectordouble_type); makeNullableTypes(builtin.vectorobj_itraits, vectorobject_type); makeNullableTypes(class_traits, class_type); makeNullableTypes(builtin.function_itraits, function_type); atom_type[kTypeNullable] = makeType(NULL, true, kModelAtom); atom_type[kTypeNotNull] = makeType(NULL, false, kModelAtom); method_type = METHOD; // TODO remove scriptobject_type[kTypeNullable] = (ScriptObjectType*)makeType(ScriptObjectType(kModelScriptObject, NULL, true)); scriptobject_type[kTypeNotNull] = (ScriptObjectType*)makeType(ScriptObjectType(kModelScriptObject, NULL, false)); } /** * */ void Lattice::makeNullableTypes(Traits* traits, const DataType* types[2]) { types[kTypeNullable] = makeType(traits, true); types[kTypeNotNull] = makeType(traits, false); } /** * canBeNull() is true if the given type allows null or undefined. * False for primitives and true for String, Namespace, Object, user class * and interface types, and activation object types. */ bool Lattice::isNullable(Traits* t) { switch (Traits::getBuiltinType(t)) { case BUILTIN_number: case BUILTIN_int: case BUILTIN_uint: case BUILTIN_boolean: return false; default: return true; } } const Type* Lattice::makeParamType(int p, MethodSignaturep signature) { if (p == 0) return makeType(signature->paramTraits(0), false); if (p <= signature->param_count()) return makeType(signature->paramTraits(p)); return atom_type[kTypeNullable]; } /** * Look up the given type in the hashtable, add it if necessary, then * return the canonical type. This function always returns a pointer to * an arena allocated Type. */ const Type* Lattice::makeType(const Type& type) { // TODO figure this out, then remove assert(!type.is_const || !isDataType(type) || model(&type) != kModelInvalid); const Type* interned = types.get(TypeKey(&type)); if (interned == NULL) { const Type* fresh = type.copy(*this); types.put(TypeKey(fresh), fresh); interned = fresh; } return interned; } /** * Create a type value for the given traits and nullable hint. * TODO final param */ const DataType* Lattice::makeType(Traits* traits, bool nullable, ModelKind model) { assert(isNullable(traits) || !nullable); switch (builtinType(traits)) { case BUILTIN_int: return int_type; case BUILTIN_uint: return uint_type; case BUILTIN_null: return null_type; case BUILTIN_void: return void_type; case BUILTIN_string: return (DataType*)makeType(StringType(*this, model, nullable)); case BUILTIN_boolean: return (DataType*)makeType(BooleanType(*this, model)); case BUILTIN_namespace: return (DataType*)makeType(NamespaceType(*this, model, nullable)); case BUILTIN_number: return (DataType*)makeType(NumberType(*this, model)); case BUILTIN_object: assert(model == kModelAtom); return (DataType*)makeType(ObjectType(traits, nullable)); case BUILTIN_any: assert(model == kModelAtom); return (DataType*)makeType(AnyType(traits, nullable)); default: return (DataType*)makeType(ScriptObjectType(model, traits, nullable)); } } /** * Second guess the verifier. If the verifier derived the type int * or uint, it really means Number with an int32 or uint32 representation. */ const Type* Lattice::makeType(const FrameValue& value) { return makeType(value.traits, isNullable(value.traits) ? !value.notNull : false); } /** * Create a non-null type value given a type-value that might be null. */ const Type* Lattice::makeNotNull(const Type* type) { assert(isDataType(*type)); return ((DataType*)type)->makeNotNull(*this); } /** * Create a constant of the given type and value. * TODO API with just Atom, figure out traits using * chunk of toplevel toTraits (TODO should factor w/that) */ const DataType* Lattice::makeAtomConst(Traits* traits, Atom val) { bool nullOrUndefined = AvmCore::isNullOrUndefined(val); (void)nullOrUndefined; // used only in asserts switch (builtinType(traits)) { case BUILTIN_int: case BUILTIN_uint: { assert(false); // should have been mapped to number break; } case BUILTIN_number: { assert(AvmCore::isNumber(val)); return makeNumberConst(AvmCore::number_d(val), kModelAtom); } case BUILTIN_any: { assert(nullOrUndefined); return AvmCore::isNull(val) ? makeObjectConst(traits, (ScriptObject*)atomPtr(val), kModelAtom) : (DataType*)makeType(VoidType(void_traits)); } case BUILTIN_void: { assert(val == undefinedAtom); return (DataType*)makeType(VoidType(traits)); } case BUILTIN_string: { assert(AvmCore::isString(val)); return makeStringConst((String*)atomPtr(val), kModelAtom); } case BUILTIN_boolean: { assert(AvmCore::isBoolean(val)); return makeBoolConst(val == trueAtom, kModelAtom); } case BUILTIN_namespace: { assert(AvmCore::isNamespace(val)); return makeNamespaceConst((Namespace*)atomPtr(val), kModelAtom); } case BUILTIN_null: { assert(AvmCore::isNull(val)); return makeObjectConst(traits, (ScriptObject*)atomPtr(val), kModelAtom); } case BUILTIN_object: default: { assert(AvmCore::isNull(val) || AvmCore::isObject(val)); return makeObjectConst(traits, (ScriptObject*)atomPtr(val), kModelAtom); } } assert(false); return NULL; } // // TODO // /** Create an int32 constant in -2^31..2^31-1 */ const DataType* Lattice::makeIntConst(int32_t val, bool boxed) { ModelKind m = boxed ? kModelAtom : kModelInt; return (DataType*)makeType(NumberType(*this, val, m)); } /** Create a uint32 in 0..2^32-1 */ const DataType* Lattice::makeUIntConst(uint32_t val, bool boxed) { ModelKind m = boxed ? kModelAtom : kModelInt; return (DataType*)makeType(NumberType(*this, val, m)); } /** Create a double constant. */ const DataType* Lattice::makeDoubleConst(double val, bool boxed) { ModelKind m = boxed ? kModelAtom : kModelDouble; return (DataType*)makeType(NumberType(*this, val, m)); } const DataType* Lattice::makeNumberConst(double val, bool boxed) { if (isWhole(val)) { if (int32_t(val) == val) return makeIntConst(int32_t(val), boxed); if (uint32_t(val) == val) return makeUIntConst(uint32_t(val), boxed); } return makeDoubleConst(val, boxed); } const BooleanType* Lattice::makeBoolConst(bool val, ModelKind m) { return (BooleanType*)makeType(BooleanType(*this, val, m)); } const StringType* Lattice::makeStringConst(PoolObject* pool, uint32_t index) { return (StringType*)makeType( StringType(*this, StringType::NATIVE_MODEL, pool->getString(index))); } const StringType* Lattice::makeStringConst(String* str, ModelKind m) { return (StringType*)makeType(StringType(*this, m, str)); } const NamespaceType* Lattice::makeNamespaceConst(Namespace* val, ModelKind m) { return (NamespaceType*)makeType(NamespaceType(*this, m, val)); } const ScriptObjectType* Lattice::makeObjectConst(Traits* traits, ScriptObject* val, ModelKind m) { return (ScriptObjectType*)makeType(ScriptObjectType(m, traits, val)); } avmplus::Binding Lattice::toBinding(const Type* obj_type, const Type* name_type) const { // fixme - should isDataType(bottom) = true? if so, remove this early // return and keep assert. if (isBottom(obj_type)) return BIND_NONE; return toBinding(getTraits(obj_type), name_type); } avmplus::Binding Lattice::toBinding(Traits* traits, const Type* name_type) const { // This code is based on getBinding() in instr.cpp, but without the need // for Toplevel* or the possibility to throw any exceptions. const Multiname* name; if (!traits || !isConst(name_type) || !(name = nameVal(name_type))->isBinding()) return BIND_NONE; TraitsBindingsp tb = traits->getTraitsBindings(); return name->isNsset() ? tb->findBinding(name->getName(), name->getNsset()) : tb->findBinding(name->getName(), name->getNamespace()); } /** Return a type for an outer scope */ const Type* Lattice::getOuterScopeType(MethodInfo* method, int scope_index) { Traits* scope_type = method->declaringScope()->getScopeTraitsAt(scope_index); return makeType(scope_type, false, kModelAtom); } const Type* Lattice::getSlotType(const Type* obj_type, int slot) { return makeType(getSlotTraits(obj_type, slot)); } uint32_t Lattice::getSlotOffset(const Type* obj_type, int slot) { Traits* obj_traits = getTraits(obj_type); assert(obj_traits && "getSlotType requires a type with slots"); TraitsBindingsp tb = obj_traits->getTraitsBindings(); return tb->getSlotOffset(slot); } Traits* Lattice::getSlotTraits(const Type* obj_type, int slot) { Traits* obj_traits = getTraits(obj_type); assert(obj_traits && "getSlotType requires a type with slots"); TraitsBindingsp tb = obj_traits->getTraitsBindings(); return tb->getSlotTraits(slot); } bool Lattice::isResolved(const Type* obj_type) { return getTraits(obj_type)->isResolved(); } /** * obj_type is the Type of an object * disp_id is the vtable slot corresponding to a method * returns the MethodInfo for the given slot of a vtable */ MethodInfo* Lattice::getSlotMethod(const Type* obj_type, int slot) { TraitsBindingsp tb = getTraits(obj_type)->getTraitsBindings(); return tb->getMethod(slot); } MethodInfo* Lattice::getInitializer(const Type* obj_type) { return getTraits(obj_type)->init; } const Type* Lattice::finddefType(PoolObject* pool, const Type* name_type) { const Multiname* name = nameVal(name_type); DomainMgr* domainMgr = core()->domainMgr(); MethodInfo* script = domainMgr->findScriptInPoolByMultiname(pool, *name); if (isValidBinding((avmplus::Binding) script)) return makeType(script->declaringTraits(), false); return object_type[kTypeNotNull]; } /** * at the moment, we don't correctly handle interfaces * eg class A impl I, class B impl I, a and b's union should be the type I * However, verifier::findCommonBase, given the traits of a and b, * does not correctly find I, and so makeUnion currently * loosens the type to object. Thus, we have to forcibly keep * coercions from a -> I by stating nothing is a sub type of t if t is an interface * see check halfmoon/test/functionscripts/classes/interfaceMerge.as */ const Type* Lattice::makeUnion(const Type* t1, const Type* t2) { return t1->makeUnion(*t2, *this); } const DataType* Lattice::getInstanceType(const Type* class_type) { // TODO should we be asserting? if (!isDataType(*class_type)) return NULL; Traits* class_traits = getTraits(class_type); return class_traits && class_traits->itraits ? makeType(class_traits->itraits) : NULL; } } // namespace avmplus #endif // VMCFG_HALFMOON