Files
dmcallis 65a0592776 Initial source code drop
Source code drop for the Actionscript virtual machine in the Adobe
Flash Player for December 2013
2013-12-02 16:04:04 -08:00

882 lines
28 KiB
C++

/* -*- 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<class SELF_CLASS, TypeKind TYPE_KIND, typename VALUE_REP>
const Type* VMType<SELF_CLASS, TYPE_KIND, VALUE_REP>::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<class SELF_CLASS, TypeKind TYPE_KIND, ModelKind MODEL_KIND, typename VALUE_REP>
PrintWriter& SimpleDataType<SELF_CLASS, TYPE_KIND, MODEL_KIND, VALUE_REP>
::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<class SELF_CLASS, TypeKind TYPE_KIND, ModelKind MODEL_KIND, typename VALUE_REP>
const Type* SimpleDataType<SELF_CLASS, TYPE_KIND, MODEL_KIND, VALUE_REP>
::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<class SELF_CLASS, TypeKind TYPE_KIND, ModelKind MODEL_KIND, typename VALUE_REP>
const DataType* SimpleDataType<SELF_CLASS, TYPE_KIND, MODEL_KIND, VALUE_REP>
::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<class SELF_CLASS, TypeKind TYPE_KIND, ModelKind MODEL_KIND, typename VALUE_REP>
const Type* SimpleDataType<SELF_CLASS, TYPE_KIND, MODEL_KIND, VALUE_REP>
::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<class SELF_CLASS, TypeKind TYPE_KIND, ModelKind MODEL_KIND, typename VALUE_REP>
const SELF_CLASS* SimpleDataType<SELF_CLASS, TYPE_KIND, MODEL_KIND, VALUE_REP>
::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<class SELF_CLASS, TypeKind TYPE_KIND, ModelKind MODEL_KIND, typename VALUE_REP>
const Type* SimpleDataType<SELF_CLASS, TYPE_KIND, MODEL_KIND, VALUE_REP>
::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<AnyType, kTypeAny, kModelAtom, Atom>
(traits, kModelAtom, is_nullable, false, Atom(0)) {
assert(builtinType(traits) == BUILTIN_any);
}
// --------------------------------------------------------------------
// ObjectType
ObjectType::ObjectType(Traits* traits, bool is_nullable) :
SimpleDataType<ObjectType, kTypeObject, kModelAtom, Atom>
(traits, kModelAtom, is_nullable, false, Atom(0)) {
assert(builtinType(traits) == BUILTIN_object);
}
// --------------------------------------------------------------------
// VoidType
VoidType::VoidType(Traits* traits) :
SimpleDataType<VoidType, kTypeVoid, kModelAtom, Atom>
(traits, kModelAtom, true, true, undefinedAtom) {
assert(builtinType(traits) == BUILTIN_void);
}
// --------------------------------------------------------------------
// ScriptObjectType
ScriptObjectType::ScriptObjectType(ModelKind model, Traits* traits,
bool is_nullable) :
SimpleDataType<ScriptObjectType, kTypeScriptObject, kModelScriptObject, ScriptObject*>
(traits, model, is_nullable, false, NULL) {
assert(isCompatibleModel(model));
}
ScriptObjectType::ScriptObjectType(ModelKind model, Traits* traits,
ScriptObject* const_value) :
SimpleDataType<ScriptObjectType, kTypeScriptObject, kModelScriptObject, ScriptObject*>
(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<ScriptObjectType, kTypeScriptObject, kModelScriptObject, ScriptObject*>
(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<NamespaceType, kTypeNamespace, kModelNamespace, Namespace*>
(lat.namespace_traits, model, is_nullable, false, NULL) {
assert(isCompatibleModel(model));
}
NamespaceType::NamespaceType(Lattice& lat, ModelKind model, Namespace* const_value) :
SimpleDataType<NamespaceType, kTypeNamespace, kModelNamespace, Namespace*>
(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<NamespaceType, kTypeNamespace, kModelNamespace, Namespace*>
(traits, model, is_nullable, is_const, const_value) {
assert(isCompatibleModel(model));
}
// --------------------------------------------------------------------
// StringType
StringType::StringType(Lattice& lat, ModelKind model, bool is_nullable) :
SimpleDataType<StringType, kTypeString, kModelString, String*>
(lat.string_traits, model, is_nullable, false, NULL) {
assert(isCompatibleModel(model));
}
StringType::StringType(Lattice& lat, ModelKind model, String* const_value) :
SimpleDataType<StringType, kTypeString, kModelString, String*>
(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<StringType, kTypeString, kModelString, String*>
(traits, model, is_nullable, is_const, const_value) {
assert(isCompatibleModel(model));
}
// --------------------------------------------------------------------
// BooleanType
BooleanType::BooleanType(Lattice& lat, ModelKind model) :
SimpleDataType<BooleanType, kTypeBoolean, kModelInt, bool>
(lat.boolean_traits, model, false, false, false) {
assert(isCompatibleModel(model));
}
BooleanType::BooleanType(Lattice& lat, bool const_value, ModelKind model) :
SimpleDataType<BooleanType, kTypeBoolean, kModelInt, bool>
(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<BooleanType, kTypeBoolean, kModelInt, bool>
(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