diff --git a/common/util/CopyOnWrite.h b/common/util/CopyOnWrite.h index 227c3dba3a..29959124fb 100644 --- a/common/util/CopyOnWrite.h +++ b/common/util/CopyOnWrite.h @@ -1,3 +1,5 @@ +#pragma once + #include #include "common/util/assert.h" @@ -46,9 +48,11 @@ class CopyOnWrite { * Construct a new object. */ template - explicit CopyOnWrite(Args&&... args) { + static CopyOnWrite make_cow(Args&&... args) { + CopyOnWrite result; auto obj = new ObjectAndCount(std::forward(args)...); - acquire_object(obj); + result.acquire_object(obj); + return result; } /*! @@ -112,3 +116,8 @@ class CopyOnWrite { ObjectAndCount* m_data = nullptr; }; + +template +CopyOnWrite make_cow(Args&&... args) { + return CopyOnWrite::make_cow(std::forward(args)...); +} \ No newline at end of file diff --git a/decompiler/IR2/MultiTypeAnalysis.cpp b/decompiler/IR2/MultiTypeAnalysis.cpp index feeb6f7e1d..e13fab789d 100644 --- a/decompiler/IR2/MultiTypeAnalysis.cpp +++ b/decompiler/IR2/MultiTypeAnalysis.cpp @@ -189,16 +189,17 @@ namespace { * Create a register type state with no parent and the given typespec. */ RegState make_typespec_parent_regstate(const TypeSpec& typespec) { - RegState result = make_cow + return make_cow(TP_Type::make_from_ts(typespec)); } /*! * Create an instruction type state for the first instruction of a function. */ InstrTypeState construct_initial_typestate(const TypeSpec& function_type, + const TypeSpec& behavior_type, const Env& env, const RegState& uninitialized) { - // start with everything unintialized + // start with everything uninitialized InstrTypeState result(uninitialized); assert(function_type.base_type() == "function"); assert(function_type.arg_count() >= 1); // must know the function type. @@ -207,9 +208,20 @@ InstrTypeState construct_initial_typestate(const TypeSpec& function_type, for (int i = 0; i < int(function_type.arg_count()) - 1; i++) { auto reg_id = Register::get_arg_reg(i); const auto& reg_type = function_type.get_arg(i); - result.get(Register(Reg::GPR, reg_id)) = TP_Type::make_from_ts(reg_type); + result.get(reg_id) = make_cow(TP_Type::make_from_ts(reg_type)); } + if (behavior_type != TypeSpec("none")) { + result.get(Register(Reg::GPR, Reg::S6)) = + make_cow(TP_Type::make_from_ts(behavior_type)); + } + + // set stack slots as uninitialized too. + for (auto slot_info : env.stack_spills().map()) { + result.add_stack_slot(slot_info.first, uninitialized); + } + + return result; } } // namespace diff --git a/decompiler/IR2/MultiTypeAnalysis.h b/decompiler/IR2/MultiTypeAnalysis.h index e5bc32d64a..78c0284ed1 100644 --- a/decompiler/IR2/MultiTypeAnalysis.h +++ b/decompiler/IR2/MultiTypeAnalysis.h @@ -15,16 +15,14 @@ struct PossibleType; struct DerefHint { struct Token { - enum class Kind { - INTEGER, FIELD, VAR, INVALID - } kind = Kind::INVALID; + enum class Kind { INTEGER, FIELD, VAR, INVALID } kind = Kind::INVALID; int integer = 0; std::string name; - bool matches(const FieldReverseLookupOutput::Token& other)const ; + bool matches(const FieldReverseLookupOutput::Token& other) const; }; std::vector tokens; - bool matches(const FieldReverseLookupOutput& value)const ; + bool matches(const FieldReverseLookupOutput& value) const; }; /*! @@ -47,10 +45,12 @@ struct PossibleType { TP_Type type; // the actual type. std::optional deref_path; // the field accessed to get here double deref_score = 0.; - TypeDecisionParent parent; // the decision we made to allow this. + TypeDecisionParent parent; // the decision we made to allow this. void eliminate() { m_valid_cache = false; } bool is_valid() const; // true, unless we were eliminated. + PossibleType(const TP_Type& tp_type) : type(tp_type) {} + private: mutable bool m_valid_cache = true; }; @@ -59,8 +59,12 @@ struct PossibleType { * The set of all possible types in a register. */ struct RegisterTypeState { + std::optional override_type; // this is just for printing errors. std::optional single_type_cache; std::vector possible_types; + + RegisterTypeState() = delete; + RegisterTypeState(const PossibleType& single_type) : possible_types({single_type}) {} void reduce_to_single_type(DecompWarnings* warnings, int op_idx, const DerefHint* hint); const PossibleType& get_single_type_decision() const; const TP_Type& get_single_tp_type() const; @@ -83,7 +87,30 @@ class InstrTypeState { return m_regs[reg.reg_id()]; } + CopyOnWrite& get_stack_slot(int offset) { + for (auto& slot : m_stack_slots) { + if (slot.first == offset) { + return slot.second; + } + } + assert(false); + } + + const RegisterTypeState& get_stack_slot_const(int offset) const { + for (auto& slot : m_stack_slots) { + if (slot.first == offset) { + return *slot.second; + } + } + assert(false); + } + + void add_stack_slot(int offset, const CopyOnWrite& value) { + m_stack_slots.emplace_back(offset, value); + } + private: std::array, Reg::MAX_VAR_REG_ID> m_regs; + std::vector>> m_stack_slots; }; } // namespace decompiler \ No newline at end of file diff --git a/test/test_common_util.cpp b/test/test_common_util.cpp index b9683a605f..7ed220454a 100644 --- a/test/test_common_util.cpp +++ b/test/test_common_util.cpp @@ -144,7 +144,7 @@ TEST(CommonUtil, PowerOfTwo) { } TEST(CommonUtil, CopyOnWrite) { - CopyOnWrite x(2); + CopyOnWrite x = make_cow(2); EXPECT_EQ(*x, 2); *x.mut() = 3;