Skip to content

Commit

Permalink
Replace ConstNullnessDomain with Simply NullnessDomain
Browse files Browse the repository at this point in the history
Summary:
- Retire `ConstNullnessDomain`
- Simplify the analysis logic
- Behavior preserving change

Reviewed By: ssj933

Differential Revision: D51728882

fbshipit-source-id: 98beacc7ce7cb79f2eca87a632f08f2f5c50dcb7
  • Loading branch information
Wei Zhang (Devinfra) authored and facebook-github-bot committed Dec 4, 2023
1 parent b099839 commit 372b817
Show file tree
Hide file tree
Showing 7 changed files with 14 additions and 395 deletions.
30 changes: 10 additions & 20 deletions libredex/DexTypeEnvironment.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <boost/optional.hpp>

#include <sparta/AbstractDomain.h>
#include <sparta/ConstantAbstractDomain.h>
#include <sparta/FiniteAbstractDomain.h>
#include <sparta/PatriciaTreeMapAbstractEnvironment.h>
#include <sparta/PatriciaTreeSet.h>
Expand Down Expand Up @@ -255,15 +256,15 @@ using TypedefAnnotationDomain = SingletonDexTypeDomain;

/*
*
* ConstNullnessDomain X SingletonDexTypeDomain X SmallSetDexTypeDomain
* NullnessDomain X SingletonDexTypeDomain X SmallSetDexTypeDomain
*
*
* When the SmallSetDexTypeDomain has elements, then they represent an exact set
* of non-interface classes (including arrays), or possibly java.lang.Throwable.
*/
class DexTypeDomain final
: public sparta::ReducedProductAbstractDomain<DexTypeDomain,
ConstNullnessDomain,
NullnessDomain,
SingletonDexTypeDomain,
SmallSetDexTypeDomain,
TypedefAnnotationDomain> {
Expand All @@ -272,7 +273,7 @@ class DexTypeDomain final

using BaseType =
sparta::ReducedProductAbstractDomain<DexTypeDomain,
ConstNullnessDomain,
NullnessDomain,
SingletonDexTypeDomain,
SmallSetDexTypeDomain,
TypedefAnnotationDomain>;
Expand All @@ -283,17 +284,10 @@ class DexTypeDomain final
// catch this. So we insert a redundant '= default'.
DexTypeDomain() = default;

explicit DexTypeDomain(int64_t v)
: ReducedProductAbstractDomain(
std::make_tuple(ConstNullnessDomain(v),
SingletonDexTypeDomain(),
SmallSetDexTypeDomain::top(),
TypedefAnnotationDomain())) {}

explicit DexTypeDomain(const DexType* dex_type,
const DexAnnoType* annotation = nullptr)
: ReducedProductAbstractDomain(
std::make_tuple(ConstNullnessDomain(NOT_NULL),
std::make_tuple(NullnessDomain(NOT_NULL),
SingletonDexTypeDomain(dex_type),
SmallSetDexTypeDomain(dex_type),
(annotation && annotation->m_type)
Expand All @@ -305,7 +299,7 @@ class DexTypeDomain final
bool is_dex_type_exact,
const DexAnnoType* annotation = nullptr)
: ReducedProductAbstractDomain(
std::make_tuple(ConstNullnessDomain(nullness),
std::make_tuple(NullnessDomain(nullness),
SingletonDexTypeDomain(dex_type),
is_dex_type_exact ? SmallSetDexTypeDomain(dex_type)
: SmallSetDexTypeDomain::top(),
Expand All @@ -315,32 +309,28 @@ class DexTypeDomain final

explicit DexTypeDomain(const DexAnnoType* annotation)
: ReducedProductAbstractDomain(std::make_tuple(
ConstNullnessDomain(),
NullnessDomain(),
SingletonDexTypeDomain(),
SmallSetDexTypeDomain::top(),
annotation->m_type ? TypedefAnnotationDomain(annotation->m_type)
: TypedefAnnotationDomain())) {}

static void reduce_product(
std::tuple<ConstNullnessDomain,
std::tuple<NullnessDomain,
SingletonDexTypeDomain,
SmallSetDexTypeDomain,
TypedefAnnotationDomain>& /* product */) {}

static DexTypeDomain null() { return DexTypeDomain(IS_NULL); }

NullnessDomain get_nullness() const { return get<0>().get_nullness(); }
NullnessDomain get_nullness() const { return get<0>(); }

bool is_null() const { return get_nullness().element() == IS_NULL; }

bool is_not_null() const { return get_nullness().element() == NOT_NULL; }

bool is_nullable() const { return get_nullness().is_top(); }

boost::optional<ConstantDomain::ConstantType> get_constant() const {
return get<0>().const_domain().get_constant();
}

const SingletonDexTypeDomain& get_single_domain() const { return get<1>(); }

const TypedefAnnotationDomain& get_annotation_domain() const {
Expand Down Expand Up @@ -373,7 +363,7 @@ class DexTypeDomain final
private:
explicit DexTypeDomain(const Nullness nullness)
: ReducedProductAbstractDomain(
std::make_tuple(ConstNullnessDomain(nullness),
std::make_tuple(NullnessDomain(nullness),
SingletonDexTypeDomain::none(),
SmallSetDexTypeDomain(),
TypedefAnnotationDomain::none())) {}
Expand Down
166 changes: 0 additions & 166 deletions libredex/NullnessDomain.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,7 @@

#pragma once

#include <sparta/ConstantAbstractDomain.h>
#include <sparta/DisjointUnionAbstractDomain.h>
#include <sparta/FiniteAbstractDomain.h>
#include <sparta/PatriciaTreeMapAbstractEnvironment.h>
#include <sparta/ReducedProductAbstractDomain.h>

#include "DexUtil.h"

Expand Down Expand Up @@ -50,165 +46,3 @@ using NullnessDomain = sparta::FiniteAbstractDomain<Nullness,
&lattice>;

std::ostream& operator<<(std::ostream& output, const Nullness& nullness);

/*
* Constant domain
*
* Simple domain that tracks the value of integer constants.
*/
using ConstantDomain = sparta::ConstantAbstractDomain<int64_t>;

/*
* ConstNullness domain
*
* A const integer value can have nullness. E.g., const 0 -> NULL.
*/
class ConstNullnessDomain final
: public sparta::ReducedProductAbstractDomain<ConstNullnessDomain,
ConstantDomain,
NullnessDomain> {
public:
using ReducedProductAbstractDomain::ReducedProductAbstractDomain;

// Some older compilers complain that the class is not default
// constructible. We intended to use the default constructors of the base
// class (via the `using` declaration above), but some compilers fail to
// catch this. So we insert a redundant '= default'.
ConstNullnessDomain() = default;

explicit ConstNullnessDomain(Nullness nullness)
: ConstNullnessDomain(std::make_tuple(
nullness == IS_NULL ? ConstantDomain(0) : ConstantDomain::top(),
NullnessDomain(nullness))) {}

explicit ConstNullnessDomain(int64_t v)
: ConstNullnessDomain(std::make_tuple(
ConstantDomain(v), NullnessDomain(v == 0 ? IS_NULL : NOT_NULL))) {}

ConstNullnessDomain null() { return ConstNullnessDomain(IS_NULL); }

static void reduce_product(
std::tuple<ConstantDomain, NullnessDomain>& /* domains */) {}

ConstantDomain const_domain() const { return get<0>(); }

boost::optional<ConstantDomain::ConstantType> get_constant() const {
return const_domain().get_constant();
}

NullnessDomain get_nullness() const { return get<1>(); }
};

/*
* Spec wise the max size of a Java array is
* std::numeric_limits<int32_t>::max() - 8. Reference:
* http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/ec45423a4700#l5.12
*
* However, for performance reasons, we don't want to allocate a Domain this
* large. We cap the size of the array elements at 1000.
*/
constexpr int64_t JAVA_ARRAY_SIZE_MAX = 1000;

class ArrayNullnessDomain final
: public sparta::ReducedProductAbstractDomain<
ArrayNullnessDomain,
NullnessDomain /* nullness of the array object */,
sparta::ConstantAbstractDomain<uint32_t> /* array length */,
sparta::PatriciaTreeMapAbstractEnvironment<
uint32_t,
NullnessDomain> /* array elements */> {

public:
using ArrayLengthDomain = sparta::ConstantAbstractDomain<uint32_t>;
using ElementsNullness =
sparta::PatriciaTreeMapAbstractEnvironment<uint32_t, NullnessDomain>;
using BaseType = sparta::ReducedProductAbstractDomain<ArrayNullnessDomain,
NullnessDomain,
ArrayLengthDomain,
ElementsNullness>;
using ReducedProductAbstractDomain::ReducedProductAbstractDomain;

// Some older compilers complain that the class is not default constructible.
// We intended to use the default constructors of the base class (via the
// `using` declaration above), but some compilers fail to catch this. So we
// insert a redundant '= default'.
ArrayNullnessDomain() = default;

static void reduce_product(
std::tuple<NullnessDomain, ArrayLengthDomain, ElementsNullness>&
product) {
if (std::get<1>(product).is_top()) {
std::get<2>(product).set_to_top();
}
}

explicit ArrayNullnessDomain(uint32_t length)
: ReducedProductAbstractDomain(std::make_tuple(NullnessDomain(NOT_NULL),
ArrayLengthDomain(length),
ElementsNullness())) {
mutate_elements([length](ElementsNullness* elements) {
for (size_t i = 0; i < length; ++i) {
elements->set(i, NullnessDomain(UNINITIALIZED));
}
});
reduce();
}

NullnessDomain get_nullness() const { return get<0>(); }

boost::optional<uint32_t> get_length() const {
return get<1>().get_constant();
}

ElementsNullness get_elements() const { return get<2>(); }

void reset_elements() {
apply<2>([](auto elements) { elements->set_to_top(); });
}

NullnessDomain get_element(uint32_t idx) const {
return get_elements().get(idx);
}

ArrayNullnessDomain& set_element(uint32_t idx, const NullnessDomain& domain) {
if (is_top() || is_bottom()) {
return *this;
}
auto length = get_length();
if (!length || idx >= *length) {
return *this;
}
return this->mutate_elements([idx, domain](ElementsNullness* elements) {
elements->set(idx, domain);
});
}

void join_with(const ArrayNullnessDomain& other) {
BaseType::join_with(other);
reduce();
}

void widen_with(const ArrayNullnessDomain& other) {
BaseType::widen_with(other);
reduce();
}

static bool is_valid_array_size(boost::optional<int64_t>& val) {
return val && *val >= 0 && *val <= JAVA_ARRAY_SIZE_MAX;
}

static bool is_valid_array_idx(boost::optional<int64_t>& val) {
return val && *val >= 0 && *val < JAVA_ARRAY_SIZE_MAX;
}

private:
ArrayNullnessDomain& mutate_elements(
std::function<void(ElementsNullness*)> f) {
this->template apply<2>(std::move(f));
return *this;
}
};

using ArrayConstNullnessDomain =
sparta::DisjointUnionAbstractDomain<ConstNullnessDomain,
ArrayNullnessDomain>;
Loading

0 comments on commit 372b817

Please sign in to comment.