diff --git a/decompiler/IR2/AtomicOp.cpp b/decompiler/IR2/AtomicOp.cpp index d513743ebe..1990be6b57 100644 --- a/decompiler/IR2/AtomicOp.cpp +++ b/decompiler/IR2/AtomicOp.cpp @@ -428,7 +428,7 @@ AsmOp::AsmOp(Instruction instr, int my_idx) : AtomicOp(my_idx), m_instr(std::mov } } - assert(m_instr.n_src <= 3); + assert(m_instr.n_src <= 4); for (int i = 0; i < m_instr.n_src; i++) { auto& src = m_instr.get_src(i); if (src.is_reg()) { @@ -455,7 +455,7 @@ goos::Object AsmOp::to_form(const std::vector& labels, const En } } - assert(m_instr.n_src <= 3); + assert(m_instr.n_src <= 4); for (int i = 0; i < m_instr.n_src; i++) { if (m_src[i].has_value()) { forms.push_back(m_src[i].value().to_form(env)); diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index 6a43e21de4..e75eb0ebc6 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -303,7 +303,7 @@ class AsmOp : public AtomicOp { private: Instruction m_instr; std::optional m_dst; - std::optional m_src[3]; + std::optional m_src[4]; }; /*! @@ -585,10 +585,12 @@ class CallOp : public AtomicOp { void collect_vars(VariableSet& vars) const override; const std::vector& arg_vars() const { return m_arg_vars; } Variable function_var() const { return m_function_var; } + bool is_method() const { return m_is_virtual_method; } protected: TypeSpec m_call_type; bool m_call_type_set = false; + bool m_is_virtual_method = false; std::vector m_arg_vars; Variable m_function_var; diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index decbdbf49d..714ac0bbf5 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -237,8 +237,9 @@ FormElement* LoadVarOp::get_as_form(FormPool& pool, const Env& env) const { if (get_as_reg_offset(m_src, &ro)) { auto& input_type = env.get_types_before_op(m_my_idx).get(ro.reg); - if (input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD && ro.offset >= 16 && - (ro.offset & 3) == 0 && m_size == 4 && m_kind == Kind::UNSIGNED) { + if ((input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL || + input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD) && + ro.offset >= 16 && (ro.offset & 3) == 0 && m_size == 4 && m_kind == Kind::UNSIGNED) { // method get of fixed type auto type_name = input_type.get_type_objects_typespec().base_type(); auto method_id = (ro.offset - 16) / 4; diff --git a/decompiler/IR2/AtomicOpTypeAnalysis.cpp b/decompiler/IR2/AtomicOpTypeAnalysis.cpp index 9eec09bba5..e8e0943e1b 100644 --- a/decompiler/IR2/AtomicOpTypeAnalysis.cpp +++ b/decompiler/IR2/AtomicOpTypeAnalysis.cpp @@ -88,7 +88,7 @@ TP_Type SimpleAtom::get_type(const TypeState& input, if (type->second == TypeSpec("type")) { // if we get a type by symbol, we should remember which type we got it from. - return TP_Type::make_type_object(TypeSpec(m_string)); + return TP_Type::make_type_no_virtual_object(TypeSpec(m_string)); } if (type->second == TypeSpec("function")) { @@ -396,10 +396,10 @@ TypeState IR2_BranchDelay::propagate_types(const TypeState& input, output.get(m_var[0]->reg()) = TP_Type::make_from_ts(TypeSpec("symbol")); break; case Kind::SET_BINTEGER: - output.get(m_var[0]->reg()) = TP_Type::make_type_object(TypeSpec("binteger")); + output.get(m_var[0]->reg()) = TP_Type::make_type_no_virtual_object(TypeSpec("binteger")); break; case Kind::SET_PAIR: - output.get(m_var[0]->reg()) = TP_Type::make_type_object(TypeSpec("pair")); + output.get(m_var[0]->reg()) = TP_Type::make_type_no_virtual_object(TypeSpec("pair")); break; case Kind::NOP: case Kind::NO_DELAY: @@ -500,8 +500,9 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input, if (get_as_reg_offset(m_src, &ro)) { auto& input_type = input.get(ro.reg); - if (input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD && ro.offset >= 16 && - (ro.offset & 3) == 0 && m_size == 4 && m_kind == Kind::UNSIGNED) { + if ((input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD || + input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL) && + ro.offset >= 16 && (ro.offset & 3) == 0 && m_size == 4 && m_kind == Kind::UNSIGNED) { // method get of fixed type auto type_name = input_type.get_type_objects_typespec().base_type(); auto method_id = (ro.offset - 16) / 4; @@ -511,7 +512,12 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input, // remember that we're an object new. return TP_Type::make_object_new(method_type); } - return TP_Type::make_from_ts(method_type); + if (method_id == GOAL_NEW_METHOD || + input_type.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL) { + return TP_Type::make_from_ts(method_type); + } else { + return TP_Type::make_method(method_type); + } } if (input_type.kind == TP_Type::Kind::TYPESPEC && input_type.typespec() == TypeSpec("type") && @@ -594,7 +600,7 @@ TP_Type LoadVarOp::get_src_type(const TypeState& input, // load_path.push_back("type"); // load_path_set = true; - return TP_Type::make_type_object(input_type.typespec().base_type()); + return TP_Type::make_type_allow_virtual_object(input_type.typespec().base_type()); } if (input_type.kind == TP_Type::Kind::DYNAMIC_METHOD_ACCESS && ro.offset == 16) { @@ -699,6 +705,7 @@ TypeState CallOp::propagate_types_internal(const TypeState& input, const Reg::Gpr arg_regs[8] = {Reg::A0, Reg::A1, Reg::A2, Reg::A3, Reg::T0, Reg::T1, Reg::T2, Reg::T3}; + m_is_virtual_method = false; TypeState end_types = input; auto in_tp = input.get(Register(Reg::GPR, Reg::T9)); @@ -789,6 +796,11 @@ TypeState CallOp::propagate_types_internal(const TypeState& input, for (uint32_t i = 0; i < in_type.arg_count() - 1; i++) { m_read_regs.emplace_back(Reg::GPR, arg_regs[i]); m_arg_vars.push_back(Variable(VariableMode::READ, m_read_regs.back(), m_my_idx)); + if (i == 0 && in_tp.kind == TP_Type::Kind::METHOD) { + m_read_regs.pop_back(); + m_arg_vars.pop_back(); + m_is_virtual_method = true; + } } m_write_regs.clear(); diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 795e8f38cb..64134e932f 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -622,6 +622,11 @@ class CondNoElseElement : public FormElement { void collect_vars(VariableSet& vars) const override; void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; void get_modified_regs(RegSet& regs) const override; + void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) override; }; /*! @@ -940,6 +945,11 @@ class GetMethodElement : public FormElement { void apply_form(const std::function& f) override; void collect_vars(VariableSet& vars) const override; void get_modified_regs(RegSet& regs) const override; + void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) override; private: Form* m_in = nullptr; @@ -973,6 +983,11 @@ class ConstantTokenElement : public FormElement { void apply_form(const std::function& f) override; void collect_vars(VariableSet& vars) const override; void get_modified_regs(RegSet& regs) const override; + void update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) override; private: std::string m_value; diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index e804530a08..c50d2f857e 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -904,13 +904,28 @@ void FunctionCallElement::update_from_stack(const Env& env, for (size_t i = 0; i < nargs; i++) { all_pop_vars.push_back(m_op->arg_vars().at(i)); } + + TypeSpec function_type; + bool is_method = false; + auto& tp_type = env.get_types_before_op(all_pop_vars.at(0).idx()).get(all_pop_vars.at(0).reg()); + if (env.has_type_analysis()) { + if (tp_type.kind == TP_Type::Kind::METHOD && all_pop_vars.size() >= 1) { + is_method = true; + } + function_type = tp_type.typespec(); + } + + assert(is_method == m_op->is_method()); + + // if method, don't pop the obj arg. + // Variable method_obj_var; + // if (is_method) { + // method_obj_var = all_pop_vars.at(1); + // all_pop_vars.erase(all_pop_vars.begin() + 1); + // } + auto unstacked = pop_to_forms(all_pop_vars, env, pool, stack, allow_side_effects); std::vector arg_forms; - TypeSpec function_type; - if (env.has_type_analysis()) { - function_type = - env.get_types_before_op(all_pop_vars.at(0).idx()).get(all_pop_vars.at(0).reg()).typespec(); - } for (size_t arg_id = 0; arg_id < nargs; arg_id++) { auto val = unstacked.at(arg_id + 1); // first is the function itself. @@ -929,8 +944,39 @@ void FunctionCallElement::update_from_stack(const Env& env, } } - auto new_form = pool.alloc_element( - GenericOperator::make_function(unstacked.at(0)), arg_forms); + FormElement* new_form = nullptr; + if (is_method) { + auto matcher = Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::METHOD_OF_OBJECT), + {Matcher::any(0), Matcher::any(1)}); + auto mr = match(matcher, unstacked.at(0)); + if (!mr.matched) { + throw std::runtime_error("Failed to match method call. Got " + + unstacked.at(0)->to_string(env)); + } + + auto unsafe = stack.unsafe_peek(Register(Reg::GPR, Reg::A0)); + if (unsafe) { + if (!unsafe->try_as_single_element()) { + throw std::runtime_error( + fmt::format("Peek got something weird: {}\n", unsafe->to_string(env))); + } + if (unsafe->try_as_single_element() != mr.maps.forms.at(0)->try_as_single_element()) { + throw std::runtime_error(fmt::format("Invalid method call. {} vs {}.", + unsafe->to_string(env), + mr.maps.forms.at(0)->to_string(env))); + } + } else { + throw std::runtime_error("Failed to peek for arg0"); + } + + arg_forms.insert(arg_forms.begin(), unsafe); + new_form = pool.alloc_element( + GenericOperator::make_function(mr.maps.forms.at(1)), arg_forms); + + } else { + new_form = pool.alloc_element(GenericOperator::make_function(unstacked.at(0)), + arg_forms); + } { // detect method calls: @@ -1021,7 +1067,10 @@ void FunctionCallElement::update_from_stack(const Env& env, return; } } else { - throw std::runtime_error("Failed to match new method"); + lg::warn("Got a suspicious new method. This may be fine, but should be uncommon: {}", + temp_form->to_string(env)); + // throw std::runtime_error("Failed to match new method: " + + // temp_form->to_string(env)); } } else { throw std::runtime_error("Method call detected, not yet implemented"); @@ -1713,7 +1762,8 @@ void ArrayFieldAccess::update_from_stack(const Env& env, // reg1 is idx auto reg0_matcher = - Matcher::match_or({Matcher::cast("uint", Matcher::any(0)), Matcher::any(0)}); + Matcher::match_or({Matcher::cast("int", Matcher::any(0)), + Matcher::cast("uint", Matcher::any(0)), Matcher::any(0)}); auto reg1_matcher = Matcher::match_or({Matcher::cast("uint", Matcher::any(1)), Matcher::any(1)}); auto sll_matcher = @@ -1722,10 +1772,14 @@ void ArrayFieldAccess::update_from_stack(const Env& env, auto matcher = Matcher::fixed_op(FixedOperatorKind::ADDITION, {reg0_matcher, sll_matcher}); auto match_result = match(matcher, new_val); if (!match_result.matched) { - fmt::print("power {}\n", power_of_two); - throw std::runtime_error( - "Couldn't match ArrayFieldAccess (stride power of 2, 0 offset) values: " + - new_val->to_string(env)); + matcher = Matcher::fixed_op(FixedOperatorKind::ADDITION, {sll_matcher, reg0_matcher}); + match_result = match(matcher, new_val); + if (!match_result.matched) { + fmt::print("power {}\n", power_of_two); + throw std::runtime_error( + "Couldn't match ArrayFieldAccess (stride power of 2, 0 offset) values: " + + new_val->to_string(env)); + } } auto idx = match_result.maps.forms.at(1); @@ -1878,4 +1932,28 @@ void StringConstantElement::update_from_stack(const Env&, result->push_back(this); } +void GetMethodElement::update_from_stack(const Env&, + FormPool&, + FormStack&, + std::vector* result, + bool) { + result->push_back(this); +} + +void CondNoElseElement::update_from_stack(const Env&, + FormPool&, + FormStack&, + std::vector* result, + bool) { + result->push_back(this); +} + +void ConstantTokenElement::update_from_stack(const Env&, + FormPool&, + FormStack&, + std::vector* result, + bool) { + result->push_back(this); +} + } // namespace decompiler diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index 9230f426c8..ee59b63c94 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -146,6 +146,26 @@ Form* FormStack::pop_reg(Register reg, return nullptr; } +Form* FormStack::unsafe_peek(Register reg) { + RegSet modified; + for (size_t i = m_stack.size(); i-- > 0;) { + auto& entry = m_stack.at(i); + if (entry.active) { + return nullptr; + } + + entry.source->get_modified_regs(modified); + if (modified.find(reg) != modified.end()) { + return nullptr; + } + + if (entry.destination.has_value() && entry.destination->reg() == reg) { + return entry.source; + } + } + return nullptr; +} + std::vector FormStack::rewrite(FormPool& pool) { std::vector result; diff --git a/decompiler/IR2/FormStack.h b/decompiler/IR2/FormStack.h index bdf51f45fc..cfa7482a67 100644 --- a/decompiler/IR2/FormStack.h +++ b/decompiler/IR2/FormStack.h @@ -27,6 +27,7 @@ class FormStack { const Env& env, bool allow_side_effects); Form* pop_reg(Register reg, const RegSet& barrier, const Env& env, bool allow_side_effects); + Form* unsafe_peek(Register reg); bool is_single_expression(); std::vector rewrite(FormPool& pool); std::vector rewrite_to_get_var(FormPool& pool, const Variable& var, const Env& env); diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 841e114deb..f6cffe66b9 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -1375,6 +1375,131 @@ (define-extern box-vector-inside? (function bounding-box vector symbol)) (define-extern box-vector-enside? (function bounding-box vector symbol)) +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; MATRIX ;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; + +(define-extern matrix-identity! (function matrix matrix)) +(define-extern matrix+! (function matrix matrix matrix matrix)) +(define-extern matrix-! (function matrix matrix matrix matrix)) +(define-extern matrix*! (function matrix matrix matrix matrix)) +(define-extern matrixp*! (function matrix matrix matrix matrix)) +(define-extern vector-matrix*! (function vector vector matrix vector)) +(define-extern vector-rotate*! (function vector vector matrix vector)) +(define-extern vector3s-matrix*! function) +(define-extern vector3s-rotate*! function) + +(define-extern matrix-inverse-of-rot-trans! function) +(define-extern matrix-3x3-determinant function) +(define-extern matrix-3x3-inverse-transpose! function) + +(define-extern matrix-scale! function) +(define-extern column-scale-matrix! function) +(define-extern matrix-rotate-yx! function) +(define-extern matrix-y-angle function) +(define-extern matrix-3x3-inverse! function) +(define-extern matrix-rotate-z! function) +;;(define-extern *identity-matrix* object) ;; unknown type +(define-extern matrix-axis-angle! function) +(define-extern matrix-rotate-zyx! function) +(define-extern matrix-rotate-x! function) + +(define-extern matrix-rotate-yxy! function) + +(define-extern matrix-4x4-determinant function) +(define-extern matrix-inv-scale! function) +(define-extern matrix-rotate-yzx! function) +(define-extern matrix-axis-sin-cos! function) +(define-extern matrix-lerp! function) +(define-extern matrix-rotate-y! function) + +(define-extern matrix-rotate-xyz! function) +(define-extern scale-matrix! function) +(define-extern matrix-rotate-yxz! function) +(define-extern matrix-rotate-zxy! function) + +(define-extern matrix3-determinant function) +(define-extern matrix3-inverse-transpose! function) +(define-extern matrix-translate+! function) +(define-extern matrix-transpose! function) +(define-extern matrix-4x4-inverse-transpose! function) + +(define-extern matrix-axis-sin-cos-vu! function) +(define-extern matrix-translate! function) +(define-extern matrix-4x4-inverse! function) + +(define-extern vector-sincos! function) +(define-extern trs-matrix-calc! function) +(define-extern transform-matrix-parent-calc! function) +(define-extern transform-matrix-calc! function) + +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;;; EULER ;;;;;;;;;;;;;;;;;;;;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; + +(define-extern set-eul! (function euler-angles float float float int euler-angles)) +(define-extern eul->matrix function) +(define-extern quat->eul function) + + +(define-extern eul->quat function) +(define-extern matrix->eul function) + + +;(define-extern sound-rpc-set-falloff-curve object) ;; unknown type +;;(define-extern *sound-bank-2* object) ;; unknown type +;;(define-extern sound-rpc-reload-info object) ;; unknown type +;;(define-extern sound-rpc-stop-sound object) ;; unknown type +;;(define-extern sound-rpc-list-sounds object) ;; unknown type +;;(define-extern *current-sound-id* object) ;; unknown type +;;(define-extern sound-bank-id object) ;; unknown type +;;(define-extern sound-rpc-get-irx-version object) ;; unknown type +;;(define-extern sound-rpc-load-music object) ;; unknown type +;;(define-extern sound-rpc-set-ear-trans object) ;; unknown type +;;(define-extern ambient-sound object) ;; unknown type +;;(define-extern sound-rpc-pause-group object) ;; unknown type +;;(define-extern sound-rpc-shutdown object) ;; unknown type +;;(define-extern sound-rpc-unload-bank object) ;; unknown type +;;(define-extern sound-rpc-pause-sound object) ;; unknown type +;;(define-extern sound-id object) ;; unknown type +(deftype sound-id (uint32) + () + ) + +(deftype sound-bank-id (uint32) + () + ) + +(deftype sound-name (uint128) + () + ) +;;(define-extern sound-play-parms object) ;; unknown type +;;(define-extern sound-rpc-load-bank object) ;; unknown type +;;(define-extern sound-rpc-set-master-volume object) ;; unknown type +;;(define-extern sound-rpc-set-param object) ;; unknown type +;;(define-extern *sound-bank-1* object) ;; unknown type +;;(define-extern sound-rpc-stop-group object) ;; unknown type +;;(define-extern sound-rpc-play object) ;; unknown type +;;(define-extern sound-rpc-cmd object) ;; unknown type +(define-extern sound-spec type) +;;(define-extern sound-rpc-set-sound-falloff object) ;; unknown type +;;(define-extern sound-rpc-union object) ;; unknown type +;;(define-extern sound-rpc-unload-music object) ;; unknown type +;;(define-extern sound-rpc-set-language object) ;; unknown type +;;(define-extern sound-rpc-set-reverb object) ;; unknown type +;;(define-extern sound-rpc-sound-cmd object) ;; unknown type +;;(define-extern sound-rpc-group-cmd object) ;; unknown type +;;(define-extern sound-rpc-bank-cmd object) ;; unknown type +;;(define-extern sound-rpc-continue-sound object) ;; unknown type +;;(define-extern sound-rpc-set-flava object) ;; unknown type +;;(define-extern sound-name object) ;; unknown type +;;(define-extern sound-rpc-continue-group object) ;; unknown type + + (deftype sound-rpc-cmd (structure) ((rsvd1 uint16 :offset-assert 0) (command uint16 :offset-assert 2) @@ -1803,13 +1928,29 @@ ;;;;;;;;;;;;; ; ;; vif-h -; (deftype vif-stat (uint32) -; () -; :method-count-assert 9 -; :size-assert #x4 -; :flag-assert #x900000004 -; ;; likely a bitfield type -; ) +(deftype vif-stat (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ;; likely a bitfield type + ) + +(deftype vif-fbrst (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ;; likely a bitfield type + ) + +(deftype vif-err (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ;; likely a bitfield type + ) ;; vif-h (deftype vif-bank (structure) @@ -1842,13 +1983,21 @@ :flag-assert #x900000174 ) ; ;; dma-h -; (deftype dma-chcr (uint32) -; () -; :method-count-assert 9 -; :size-assert #x4 -; :flag-assert #x900000004 -; ;; likely a bitfield type -; ) +(deftype dma-chcr (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ;; likely a bitfield type + ) + +(deftype dma-ctrl (uint32) + () + :method-count-assert 9 + :size-assert #x4 + :flag-assert #x900000004 + ;; likely a bitfield type + ) (deftype dma-bank (structure) ((chcr uint32 :offset 0) @@ -1913,13 +2062,13 @@ ) ; ;; dma-h -; (deftype dma-tag (uint64) -; () -; :method-count-assert 9 -; :size-assert #x8 -; :flag-assert #x900000008 -; ;; likely a bitfield type -; ) +(deftype dma-tag (uint64) + () + :method-count-assert 9 + :size-assert #x8 + :flag-assert #x900000008 + ;; likely a bitfield type + ) ; ;; dma-h @@ -31574,51 +31723,6 @@ (define-extern deg-diff function) (define-extern vector-y-angle function) -(define-extern vector3s-rotate*! function) -(define-extern matrix-inverse-of-rot-trans! function) -(define-extern matrix-3x3-determinant function) -(define-extern matrix-3x3-inverse-transpose! function) -(define-extern vector-matrix*! function) -(define-extern matrix-scale! function) -(define-extern column-scale-matrix! function) -(define-extern matrix-rotate-yx! function) -(define-extern matrix-y-angle function) -(define-extern matrix-3x3-inverse! function) -(define-extern matrix-rotate-z! function) -;;(define-extern *identity-matrix* object) ;; unknown type -(define-extern matrix-axis-angle! function) -(define-extern matrix-rotate-zyx! function) -(define-extern matrix-rotate-x! function) -(define-extern matrix+! function) -(define-extern matrix-rotate-yxy! function) -(define-extern matrix-identity! function) -(define-extern vector3s-matrix*! function) -(define-extern matrix-4x4-determinant function) -(define-extern matrix-inv-scale! function) -(define-extern matrix-rotate-yzx! function) -(define-extern matrix-axis-sin-cos! function) -(define-extern matrix-lerp! function) -(define-extern matrix-rotate-y! function) -(define-extern matrix*! function) -(define-extern matrix-rotate-xyz! function) -(define-extern scale-matrix! function) -(define-extern matrix-rotate-yxz! function) -(define-extern matrix-rotate-zxy! function) -(define-extern vector-rotate*! function) -(define-extern matrix3-determinant function) -(define-extern matrix3-inverse-transpose! function) -(define-extern matrix-translate+! function) -(define-extern matrix-transpose! function) -(define-extern matrix-4x4-inverse-transpose! function) -(define-extern matrixp*! function) -(define-extern matrix-axis-sin-cos-vu! function) -(define-extern matrix-translate! function) -(define-extern matrix-4x4-inverse! function) -(define-extern matrix-! function) -(define-extern vector-sincos! function) -(define-extern trs-matrix-calc! function) -(define-extern transform-matrix-parent-calc! function) -(define-extern transform-matrix-calc! function) (define-extern quaternion-zero! function) (define-extern quaternion-set! function) @@ -31683,11 +31787,6 @@ (define-extern acos-rad function) (define-extern acos function) -(define-extern quat->eul function) -(define-extern set-eul! function) -(define-extern eul->matrix function) -(define-extern eul->quat function) -(define-extern matrix->eul function) (define-extern vector-reflect-flat! function) (define-extern forward-down->inv-matrix function) (define-extern circle-test function) @@ -31763,43 +31862,7 @@ (define-extern sincos! function) (define-extern vector-rad<-vector-deg! function) (define-extern radmod function) -;;(define-extern sound-rpc-set-falloff-curve object) ;; unknown type -;;(define-extern *sound-bank-2* object) ;; unknown type -;;(define-extern sound-rpc-reload-info object) ;; unknown type -;;(define-extern sound-rpc-stop-sound object) ;; unknown type -;;(define-extern sound-rpc-list-sounds object) ;; unknown type -;;(define-extern *current-sound-id* object) ;; unknown type -;;(define-extern sound-bank-id object) ;; unknown type -;;(define-extern sound-rpc-get-irx-version object) ;; unknown type -;;(define-extern sound-rpc-load-music object) ;; unknown type -;;(define-extern sound-rpc-set-ear-trans object) ;; unknown type -;;(define-extern ambient-sound object) ;; unknown type -;;(define-extern sound-rpc-pause-group object) ;; unknown type -;;(define-extern sound-rpc-shutdown object) ;; unknown type -;;(define-extern sound-rpc-unload-bank object) ;; unknown type -;;(define-extern sound-rpc-pause-sound object) ;; unknown type -;;(define-extern sound-id object) ;; unknown type -;;(define-extern sound-play-parms object) ;; unknown type -;;(define-extern sound-rpc-load-bank object) ;; unknown type -;;(define-extern sound-rpc-set-master-volume object) ;; unknown type -;;(define-extern sound-rpc-set-param object) ;; unknown type -;;(define-extern *sound-bank-1* object) ;; unknown type -;;(define-extern sound-rpc-stop-group object) ;; unknown type -;;(define-extern sound-rpc-play object) ;; unknown type -;;(define-extern sound-rpc-cmd object) ;; unknown type -(define-extern sound-spec type) -;;(define-extern sound-rpc-set-sound-falloff object) ;; unknown type -;;(define-extern sound-rpc-union object) ;; unknown type -;;(define-extern sound-rpc-unload-music object) ;; unknown type -;;(define-extern sound-rpc-set-language object) ;; unknown type -;;(define-extern sound-rpc-set-reverb object) ;; unknown type -;;(define-extern sound-rpc-sound-cmd object) ;; unknown type -;;(define-extern sound-rpc-group-cmd object) ;; unknown type -;;(define-extern sound-rpc-bank-cmd object) ;; unknown type -;;(define-extern sound-rpc-continue-sound object) ;; unknown type -;;(define-extern sound-rpc-set-flava object) ;; unknown type -;;(define-extern sound-name object) ;; unknown type -;;(define-extern sound-rpc-continue-group object) ;; unknown type +; ;;(define-extern vif-stat object) ;; unknown type ;;(define-extern vif-fbrst object) ;; unknown type ;;(define-extern vif-err object) ;; unknown type diff --git a/decompiler/util/DecompilerTypeSystem.cpp b/decompiler/util/DecompilerTypeSystem.cpp index e83b0dbf40..c2d991806e 100644 --- a/decompiler/util/DecompilerTypeSystem.cpp +++ b/decompiler/util/DecompilerTypeSystem.cpp @@ -213,7 +213,14 @@ TP_Type DecompilerTypeSystem::tp_lca(const TP_Type& existing, return new_result; } case TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD: { - auto new_result = TP_Type::make_type_object(ts.lowest_common_ancestor( + auto new_result = TP_Type::make_type_allow_virtual_object(ts.lowest_common_ancestor( + existing.get_type_objects_typespec(), add.get_type_objects_typespec())); + *changed = (new_result != existing); + return new_result; + } + + case TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL: { + auto new_result = TP_Type::make_type_no_virtual_object(ts.lowest_common_ancestor( existing.get_type_objects_typespec(), add.get_type_objects_typespec())); *changed = (new_result != existing); return new_result; @@ -265,6 +272,12 @@ TP_Type DecompilerTypeSystem::tp_lca(const TP_Type& existing, return TP_Type::make_from_ts("int"); } + case TP_Type::Kind::METHOD: + // never allow this to remain method + *changed = true; + return TP_Type::make_from_ts( + ts.lowest_common_ancestor(existing.typespec(), add.typespec())); + case TP_Type::Kind::FALSE_AS_NULL: case TP_Type::Kind::UNINITIALIZED: case TP_Type::Kind::DYNAMIC_METHOD_ACCESS: @@ -288,6 +301,22 @@ TP_Type DecompilerTypeSystem::tp_lca(const TP_Type& existing, return result_type; } + if (existing.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL && + add.kind == TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD) { + auto result_type = TP_Type::make_type_no_virtual_object(ts.lowest_common_ancestor( + existing.get_type_objects_typespec(), add.get_type_objects_typespec())); + *changed = (result_type != existing); + return result_type; + } + + if (existing.kind == TP_Type::Kind::TYPE_OF_TYPE_OR_CHILD && + add.kind == TP_Type::Kind::TYPE_OF_TYPE_NO_VIRTUAL) { + auto result_type = TP_Type::make_type_no_virtual_object(ts.lowest_common_ancestor( + existing.get_type_objects_typespec(), add.get_type_objects_typespec())); + *changed = (result_type != existing); + return result_type; + } + // otherwise, as an absolute fallback, convert both to TypeSpecs and do TypeSpec LCA auto new_result = TP_Type::make_from_ts( coerce_to_reg_type(ts.lowest_common_ancestor(existing.typespec(), add.typespec()))); diff --git a/decompiler/util/TP_Type.cpp b/decompiler/util/TP_Type.cpp index bfdf122d9d..c4c28aa237 100644 --- a/decompiler/util/TP_Type.cpp +++ b/decompiler/util/TP_Type.cpp @@ -31,6 +31,8 @@ std::string TP_Type::print() const { return m_ts.print(); case Kind::TYPE_OF_TYPE_OR_CHILD: return fmt::format("", m_ts.print()); + case Kind::TYPE_OF_TYPE_NO_VIRTUAL: + return fmt::format("", m_ts.print()); case Kind::FALSE_AS_NULL: return fmt::format("'#f"); case Kind::UNINITIALIZED: @@ -51,6 +53,8 @@ std::string TP_Type::print() const { return fmt::format("", m_int, m_ts.print()); case Kind::DYNAMIC_METHOD_ACCESS: return fmt::format(""); + case Kind::METHOD: + return fmt::format("", m_ts.print()); case Kind::INVALID: default: assert(false); @@ -67,6 +71,10 @@ bool TP_Type::operator==(const TP_Type& other) const { return m_ts == other.m_ts; case Kind::TYPE_OF_TYPE_OR_CHILD: return m_ts == other.m_ts; + case Kind::TYPE_OF_TYPE_NO_VIRTUAL: + return m_ts == other.m_ts; + case Kind::METHOD: + return m_ts == other.m_ts; case Kind::FALSE_AS_NULL: return true; case Kind::UNINITIALIZED: @@ -102,6 +110,7 @@ TypeSpec TP_Type::typespec() const { case Kind::TYPESPEC: return m_ts; case Kind::TYPE_OF_TYPE_OR_CHILD: + case Kind::TYPE_OF_TYPE_NO_VIRTUAL: return TypeSpec("type"); case Kind::FALSE_AS_NULL: return TypeSpec("symbol"); @@ -129,6 +138,8 @@ TypeSpec TP_Type::typespec() const { return TypeSpec("object"); case Kind::FORMAT_STRING: return TypeSpec("string"); + case Kind::METHOD: + return m_ts; case Kind::INVALID: default: assert(false); diff --git a/decompiler/util/TP_Type.h b/decompiler/util/TP_Type.h index 8ee9c65104..5fbe223a96 100644 --- a/decompiler/util/TP_Type.h +++ b/decompiler/util/TP_Type.h @@ -15,8 +15,9 @@ namespace decompiler { class TP_Type { public: enum class Kind { - TYPESPEC, // just a normal typespec - TYPE_OF_TYPE_OR_CHILD, // a type object, of the given type of a child type. + TYPESPEC, // just a normal typespec + TYPE_OF_TYPE_OR_CHILD, // a type object, of the given type of a child type. + TYPE_OF_TYPE_NO_VIRTUAL, FALSE_AS_NULL, // the GOAL "false" object, possibly used as a null. UNINITIALIZED, // representing data which is uninitialized. PRODUCT_WITH_CONSTANT, // representing: (val * multiplier) @@ -28,6 +29,7 @@ class TP_Type { INTEGER_CONSTANT_PLUS_VAR, // constant + variable. used in stuff like (&-> obj inline-val-arr // x) DYNAMIC_METHOD_ACCESS, // partial access into a + METHOD, INVALID } kind = Kind::UNINITIALIZED; TP_Type() = default; @@ -73,6 +75,13 @@ class TP_Type { static TP_Type make_from_ts(const std::string& ts) { return make_from_ts(TypeSpec(ts)); } + static TP_Type make_method(const TypeSpec& method_type) { + TP_Type result; + result.kind = Kind::METHOD; + result.m_ts = method_type; + return result; + } + static TP_Type make_from_string(const std::string& str) { TP_Type result; result.kind = Kind::STRING_CONSTANT; @@ -80,13 +89,20 @@ class TP_Type { return result; } - static TP_Type make_type_object(const TypeSpec& type) { + static TP_Type make_type_allow_virtual_object(const TypeSpec& type) { TP_Type result; result.kind = Kind::TYPE_OF_TYPE_OR_CHILD; result.m_ts = type; return result; } + static TP_Type make_type_no_virtual_object(const TypeSpec& type) { + TP_Type result; + result.kind = Kind::TYPE_OF_TYPE_NO_VIRTUAL; + result.m_ts = type; + return result; + } + static TP_Type make_false() { TP_Type result; result.kind = Kind::FALSE_AS_NULL; @@ -149,7 +165,7 @@ class TP_Type { } const TypeSpec& get_type_objects_typespec() const { - assert(kind == Kind::TYPE_OF_TYPE_OR_CHILD); + assert(kind == Kind::TYPE_OF_TYPE_OR_CHILD || kind == Kind::TYPE_OF_TYPE_NO_VIRTUAL); return m_ts; } diff --git a/test/decompiler/test_FormExpressionBuild.cpp b/test/decompiler/test_FormExpressionBuild.cpp index e50a7e360a..33d71b5d79 100644 --- a/test/decompiler/test_FormExpressionBuild.cpp +++ b/test/decompiler/test_FormExpressionBuild.cpp @@ -2053,7 +2053,7 @@ TEST_F(FormRegressionTest, ExprPrintl) { " bgtzl v1, L62\n" " lw v1, pair(s7)\n" "\n" - " lwu v1, -4(a0)\n" + " lwu v1, -4(a0)\n" // want to cheat this read. "L62:\n" " lwu t9, 24(v1)\n" " jalr ra, t9\n" diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index 102d1ad329..b5ffb91d0f 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -660,93 +660,434 @@ TEST_F(FormRegressionTest, ExprMethod0Process) { "\t\t[13, [\"v0\", \"process\"]]]")); } -// TEST_F(FormRegressionTest, ExprInspectProcessHeap) { +TEST_F(FormRegressionTest, ExprInspectProcessHeap) { + std::string func = + " sll r0, r0, 0\n" + "L251:\n" + " daddiu sp, sp, -64\n" + " sd ra, 0(sp)\n" + " sq s4, 16(sp)\n" + " sq s5, 32(sp)\n" + " sq gp, 48(sp)\n" + + " or gp, a0, r0\n" + " lwu v1, 76(gp)\n" + " daddiu s5, v1, 4\n" + " beq r0, r0, L253\n" + " sll r0, r0, 0\n" + + "L252:\n" + " or a0, s5, r0\n" + " lwu v1, -4(a0)\n" + " lwu t9, 28(v1)\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " addiu s4, r0, -16\n" + " or a0, s5, r0\n" + " lwu v1, -4(a0)\n" + " lwu t9, 36(v1)\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " daddiu v1, v1, 15\n" + " and v1, s4, v1\n" + " daddu s5, s5, v1\n" + + "L253:\n" + " lwu v1, 84(gp)\n" + " slt v1, s5, v1\n" + " bne v1, r0, L252\n" + " sll r0, r0, 0\n" + + " or v0, s7, r0\n" + " ld ra, 0(sp)\n" + " lq gp, 48(sp)\n" + " lq s5, 32(sp)\n" + " lq s4, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 64"; + std::string type = "(function process symbol)"; + std::string expected = + "(begin\n" + " (set! s5-0 (+ (-> arg0 heap-base) (the-as uint 4)))\n" + " (while\n" + " (< (the-as int s5-0) (the-as int (-> arg0 heap-cur)))\n" + " (inspect (the-as basic s5-0))\n" + " (set!\n" + " (the-as int s5-0)\n" + " (+ (the-as int s5-0) (logand -16 (+ (asize-of s5-0) 15)))\n" + " )\n" + " )\n" + " (quote #f)\n" + " )\n" + ""; + test_with_expr(func, type, expected, false, "", {}, + parse_hint_json("[\t\t[4, [\"s5\", \"basic\"]],\n" + "\t\t[17, [\"s5\", \"int\"]]]")); +} + +// note: skipped method 3 process + +TEST_F(FormRegressionTest, ExprMethod5Process) { + std::string func = + " sll r0, r0, 0\n" + " lw v1, process(s7)\n" + " lhu v1, 8(v1)\n" + " lw a0, 68(a0)\n" + " daddu v0, v1, a0\n" + " jr ra\n" + " daddu sp, sp, r0"; + std::string type = "(function process int)"; + std::string expected = + "(the-as int (+ (-> process size) (the-as uint (-> arg0 allocated-length))))"; + test_with_expr(func, type, expected); +} + +TEST_F(FormRegressionTest, ExprMethod2Process) { + std::string func = + " sll r0, r0, 0\n" + " daddiu sp, sp, -32\n" + " sd ra, 0(sp)\n" + " sd fp, 8(sp)\n" + " or fp, t9, r0\n" + " sq gp, 16(sp)\n" + + " or gp, a0, r0\n" + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L317\n" + " lwu a2, -4(gp)\n" + " lwu a3, 0(gp)\n" + " lwu t0, 32(gp)\n" + " lwu v1, 52(gp)\n" + " beq s7, v1, L245\n" + " or t1, s7, r0\n" + + " lwu v1, 52(gp)\n" + " lwu t1, 0(v1)\n" + + "L245:\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " lw t9, format(s7)\n" + " daddiu a0, s7, #t\n" + " daddiu a1, fp, L316\n" + " lwu v1, 44(gp)\n" + " lwu v1, 28(v1)\n" + " lwu a2, 44(gp)\n" + " lwu a2, 24(a2)\n" + " dsubu a2, v1, a2\n" + " lwu v1, 40(gp)\n" + " lw a3, 32(v1)\n" + " lw v1, 68(gp)\n" + " lwu t0, 80(gp)\n" + " lwu t1, 84(gp)\n" + " dsubu t0, t0, t1\n" + " dsubu t0, v1, t0\n" + " lw t1, 68(gp)\n" + " or t2, gp, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v0, gp, r0\n" + " ld ra, 0(sp)\n" + " ld fp, 8(sp)\n" + " lq gp, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 32"; + std::string type = "(function process process)"; + std::string expected = + "(begin\n" + " (format\n" + " (quote #t)\n" + " \"#<~A ~S ~A :state ~S \"\n" + " (-> arg0 type)\n" + " (-> arg0 name)\n" + " (-> arg0 status)\n" + " (if (-> arg0 state) (-> arg0 state name))\n" + " )\n" + " (format\n" + " (quote #t)\n" + " \":stack ~D/~D :heap ~D/~D @ #x~X>\"\n" + " (- (-> arg0 top-thread stack-top) (the-as uint (-> arg0 top-thread sp)))\n" + " (-> arg0 main-thread stack-size)\n" + " (-\n" + " (-> arg0 allocated-length)\n" + " (- (-> arg0 heap-top) (the-as uint (-> arg0 heap-cur)))\n" + " )\n" + " (-> arg0 allocated-length)\n" + " arg0\n" + " )\n" + " arg0\n" + " )"; + test_with_expr(func, type, expected, false, "", + {{"L317", "#<~A ~S ~A :state ~S "}, {"L316", ":stack ~D/~D :heap ~D/~D @ #x~X>"}}); +} + +TEST_F(FormRegressionTest, ExprMethod0DeadPool) { + std::string func = + " sll r0, r0, 0\n" + " daddiu sp, sp, -112\n" + " sd ra, 0(sp)\n" + " sq s1, 16(sp)\n" + " sq s2, 32(sp)\n" + " sq s3, 48(sp)\n" + " sq s4, 64(sp)\n" + " sq s5, 80(sp)\n" + " sq gp, 96(sp)\n" + + " or gp, a0, r0\n" + " or s5, a2, r0\n" + " or s4, a3, r0\n" + " or s2, t0, r0\n" + " lw v1, object(s7)\n" + " lwu t9, 16(v1)\n" + " or a0, gp, r0\n" + " or v1, a1, r0\n" + " lhu a2, 8(a1)\n" + " or a1, v1, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or s3, v0, r0\n" + " sw s2, 0(s3)\n" + " addiu v1, r0, 256\n" + " sw v1, 4(s3)\n" + " sw s7, 8(s3)\n" + " sw s7, 12(s3)\n" + " sw s7, 16(s3)\n" + " sw s3, 24(s3)\n" + " daddiu v1, s3, 24\n" + " sw v1, 20(s3)\n" + " addiu s2, r0, 0\n" + " beq r0, r0, L233\n" + " sll r0, r0, 0\n" + + "L230:\n" + " lwu s1, 16(s3)\n" + " lw v1, process(s7)\n" + " lwu t9, 16(v1)\n" + " or a0, gp, r0\n" + " lw a1, process(s7)\n" + " daddiu a2, s7, dead\n" + " or a3, s4, r0\n" + " jalr ra, t9\n" + " sll v0, ra, 0\n" + + " or v1, v0, r0\n" + " or a0, v1, r0\n" + " beq s7, a0, L231\n" + " or a1, s7, r0\n" + + " lwu a1, 20(a0)\n" + + "L231:\n" + " sw a1, 16(s3)\n" + " or a0, s3, r0\n" + " beq s7, a0, L232\n" + " or a1, s7, r0\n" + + " lwu a1, 20(a0)\n" + + "L232:\n" + " sw a1, 8(v1)\n" + " sw s3, 28(v1)\n" + " sw s1, 12(v1)\n" + " daddiu s2, s2, 1\n" + + "L233:\n" + " slt v1, s2, s5\n" + " bne v1, r0, L230\n" + " sll r0, r0, 0\n" + + " or v1, s7, r0\n" + " or v1, s7, r0\n" + " or v0, s3, r0\n" + " ld ra, 0(sp)\n" + " lq gp, 96(sp)\n" + " lq s5, 80(sp)\n" + " lq s4, 64(sp)\n" + " lq s3, 48(sp)\n" + " lq s2, 32(sp)\n" + " lq s1, 16(sp)\n" + " jr ra\n" + " daddiu sp, sp, 112"; + std::string type = "(function symbol type int int basic dead-pool)"; + std::string expected = + "(begin\n" + " (set! s3-0 (object-new arg0 arg1 (the-as int (-> arg1 size))))\n" + " (set! (-> s3-0 name) arg4)\n" + " (set! (-> s3-0 mask) 256)\n" + " (set! (-> s3-0 parent) (quote #f))\n" + " (set! (-> s3-0 brother) (quote #f))\n" + " (set! (-> s3-0 child) (quote #f))\n" + " (set! (-> s3-0 self) s3-0)\n" + " (set! (-> s3-0 ppointer) (&-> s3-0 self))\n" + " (set! s2-1 0)\n" + " (while\n" + " (< s2-1 arg2)\n" + " (set! s1-0 (-> s3-0 child))\n" + " (set! v1-5 ((method-of-type process new) arg0 process (quote dead) arg3))\n" + " (set! a0-3 v1-5)\n" + " (set! (-> s3-0 child) (if a0-3 (-> a0-3 ppointer)))\n" + " (set! a0-4 s3-0)\n" + " (set! (-> v1-5 parent) (if a0-4 (-> a0-4 ppointer)))\n" + " (set! (-> v1-5 pool) s3-0)\n" + " (set! (-> v1-5 brother) s1-0)\n" + " (set! s2-1 (+ s2-1 1))\n" + " )\n" + " s3-0\n" + " )"; + test_with_expr(func, type, expected, false, "dead-pool"); +} + +// TODO - sketchy types, and likely a bug in the game. +// TEST_F(FormRegressionTest, ExprMethod14DeadPool) { // std::string func = // " sll r0, r0, 0\n" -// "L251:\n" // " daddiu sp, sp, -64\n" // " sd ra, 0(sp)\n" +// " sd fp, 8(sp)\n" +// " or fp, t9, r0\n" // " sq s4, 16(sp)\n" // " sq s5, 32(sp)\n" // " sq gp, 48(sp)\n" // -// " or gp, a0, r0\n" -// " lwu v1, 76(gp)\n" -// " daddiu s5, v1, 4\n" -// " beq r0, r0, L253\n" -// " sll r0, r0, 0\n" +// " or s5, a0, r0\n" +// " or gp, a1, r0\n" +// " lwu s4, 16(s5)\n" +// " bnel s7, s4, L223\n" // -// "L252:\n" -// " or a0, s5, r0\n" +// " or v1, s7, r0\n" +// +// " lw v1, *debug-segment*(s7)\n" +// " beql s7, v1, L223\n" +// +// " or v1, v1, r0\n" +// +// " lw v1, *debug-dead-pool*(s7)\n" +// " dsubu a0, s5, v1\n" +// " daddiu v1, s7, 8\n" +// " movz v1, s7, a0\n" +// +// "L223:\n" +// " beq s7, v1, L225\n" +// " or v1, s7, r0\n" +// +// " lw a0, *debug-dead-pool*(s7)\n" // " lwu v1, -4(a0)\n" -// " lwu t9, 28(v1)\n" +// " lwu t9, 72(v1)\n" +// " or a1, gp, r0\n" // " jalr ra, t9\n" // " sll v0, ra, 0\n" // -// " or v1, v0, r0\n" -// " addiu s4, r0, -16\n" -// " or a0, s5, r0\n" -// " lwu v1, -4(a0)\n" -// " lwu t9, 36(v1)\n" +// " or s4, v0, r0\n" +// " beq s7, s4, L225\n" +// " or v1, s7, r0\n" +// +// " lw t9, format(s7)\n" +// " addiu a0, r0, 0\n" +// " daddiu a1, fp, L315\n" +// " or a2, gp, r0\n" +// " or v1, s4, r0\n" +// " beq s7, v1, L224\n" +// " or a3, s7, r0\n" +// +// " lwu v1, 0(v1)\n" +// " lwu a3, 24(v1)\n" +// +// "L224:\n" +// " lwu t0, 0(s5)\n" // " jalr ra, t9\n" // " sll v0, ra, 0\n" -// +// "\n" // " or v1, v0, r0\n" -// " daddiu v1, v1, 15\n" -// " and v1, s4, v1\n" -// " daddu s5, s5, v1\n" // -// "L253:\n" -// " lwu v1, 84(gp)\n" -// " slt v1, s5, v1\n" -// " bne v1, r0, L252\n" +// "L225:\n" +// " beq s7, s4, L226\n" // " sll r0, r0, 0\n" // +// " lwu v1, 0(s4)\n" +// " sw gp, -4(v1)\n" +// " lwu v0, 0(s4)\n" +// " beq r0, r0, L228\n" +// " sll r0, r0, 0\n" +// +// "L226:\n" +// " lw t9, format(s7)\n" +// " addiu a0, r0, 0\n" +// " daddiu a1, fp, L314\n" +// " beq s7, s4, L227\n" +// " or a3, s7, r0\n" +// +// " lwu v1, 0(s4)\n" +// " lwu a3, 24(v1)\n" +// +// "L227:\n" +// " lwu t0, 0(s5)\n" +// " or a2, gp, r0\n" +// " jalr ra, t9\n" +// " sll v0, ra, 0\n" +// // " or v0, s7, r0\n" +// +// "L228:\n" // " ld ra, 0(sp)\n" +// " ld fp, 8(sp)\n" // " lq gp, 48(sp)\n" // " lq s5, 32(sp)\n" // " lq s4, 16(sp)\n" // " jr ra\n" // " daddiu sp, sp, 64"; -// std::string type = "(function process symbol)"; +// std::string type = "(function dead-pool type int process)"; // std::string expected = // "(begin\n" -// " (set!\n" -// " v0-0\n" -// " (if\n" -// " (= (-> arg0 type) symbol)\n" -// " (object-new arg0 arg1 (the-as int (+ (-> process size) (the-as uint arg3))))\n" -// " (+ (the-as int arg0) 4)\n" +// " (set! s4-0 (-> arg0 child))\n" +// " (when\n" +// " (and (not s4-0) *debug-segment* (!= arg0 *debug-dead-pool*))\n" +// " (set! s4-0 (get-process *debug-dead-pool* arg1 arg2))\n" +// " (when\n" +// " s4-0\n" +// " (set! t9-1 format)\n" +// " (set! a0-2 0)\n" +// " (set!\n" +// " a1-2\n" +// " \"WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%\"\n" +// " )\n" +// " (set! a2-1 arg1)\n" +// " (set! v1-6 s4-0)\n" +// " (t9-1 a0-2 a1-2 a2-1 (if v1-6 (-> v1-6 name 6)) (-> arg0 name))\n" +// " )\n" +// " )\n" +// " (the-as\n" +// " process\n" +// " (cond\n" +// " (s4-0\n" +// " (set! (-> (the-as (pointer process-tree) s4-0) 0 type) arg1)\n" +// " (-> s4-0 0)\n" +// " )\n" +// " (else\n" +// " (format\n" +// " 0\n" +// " \"WARNING: ~A ~A could not be allocated, because ~A was empty.~%\"\n" +// " arg1\n" +// " (if s4-0 (-> s4-0 0 self))\n" +// " (-> arg0 name)\n" +// " )\n" +// " (quote #f)\n" +// " )\n" // " )\n" // " )\n" -// " (set! (-> (the-as process v0-0) name) arg2)\n" -// " (set! (-> v0-0 status) (quote dead))\n" -// " (set! (-> v0-0 pid) 0)\n" -// " (set! (-> v0-0 pool) (quote #f))\n" -// " (set! (-> v0-0 allocated-length) arg3)\n" -// " (set! (-> v0-0 top-thread) (quote #f))\n" -// " (set! (-> v0-0 main-thread) (quote #f))\n" -// " (set! v1-5 (-> v0-0 stack))\n" -// " (set! (-> v0-0 heap-cur) v1-5)\n" -// " (set! (-> v0-0 heap-base) v1-5)\n" -// " (set! (-> v0-0 heap-top) (&-> v0-0 stack (-> v0-0 allocated-length)))\n" -// " (set! (-> v0-0 stack-frame-top) (-> v0-0 heap-top))\n" -// " (set! (-> v0-0 stack-frame-top) (quote #f))\n" -// " (set! (-> v0-0 state) (quote #f))\n" -// " (set! (-> v0-0 next-state) (quote #f))\n" -// " (set! (-> v0-0 entity) (quote #f))\n" -// " (set! (-> v0-0 trans-hook) (quote #f))\n" -// " (set! (-> v0-0 post-hook) (quote #f))\n" -// " (set! (-> v0-0 event-hook) (quote #f))\n" -// " (set! (-> v0-0 parent) (quote #f))\n" -// " (set! (-> v0-0 brother) (quote #f))\n" -// " (set! (-> v0-0 child) (quote #f))\n" -// " (set! (-> v0-0 self) v0-0)\n" -// " (set! (-> v0-0 ppointer) (&-> v0-0 self))\n" -// " v0-0\n" // " )"; -// test_with_expr(func, type, expected, false, "", {}, -// parse_hint_json("[\t\t[4, [\"s5\", \"basic\"]],\n" -// "\t\t[17, [\"s5\", \"int\"]]]")); +// test_with_expr( +// func, type, expected, false, "dead-pool", +// {{"L315", "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was +// empty.~%"}, +// {"L314", "WARNING: ~A ~A could not be allocated, because ~A was empty.~%"}}, +// parse_hint_json("[\t\t[25, [\"v1\", \"(pointer process-tree)\"]],\n" +// "\t\t[30, [\"s4\", \"(pointer process-tree)\"]]]")); //} \ No newline at end of file