From db48d94270381e61b7226b52866ec0d96135ddc4 Mon Sep 17 00:00:00 2001 From: water111 <48171810+water111@users.noreply.github.com> Date: Thu, 18 Feb 2021 11:35:45 -0500 Subject: [PATCH] [Decompiler] Clean Up (#271) * clean up * fix up until generic ops * finish kernel * documentation * types * add missing file --- decompiler/IR2/AtomicOp.h | 5 + decompiler/IR2/AtomicOpForm.cpp | 52 +- decompiler/IR2/Form.cpp | 110 ++ decompiler/IR2/Form.h | 110 +- decompiler/IR2/FormExpressionAnalysis.cpp | 359 ++++-- decompiler/IR2/FormStack.cpp | 15 + decompiler/IR2/FormStack.h | 1 + decompiler/config/all-types.gc | 238 ++-- .../jak1_ntsc_black_label/var_names.jsonc | 5 + doc/code_status.md | 4 +- doc/emacs_config.el | 24 + goal_src/kernel/gkernel.gc | 1050 +++++++++-------- goalc/compiler/compilation/Type.cpp | 2 +- .../test_FormExpressionBuildLong.cpp | 33 +- test/decompiler/test_gkernel_decomp.cpp | 6 +- 15 files changed, 1230 insertions(+), 784 deletions(-) create mode 100644 doc/emacs_config.el diff --git a/decompiler/IR2/AtomicOp.h b/decompiler/IR2/AtomicOp.h index 4623571b0..9c5191c9c 100644 --- a/decompiler/IR2/AtomicOp.h +++ b/decompiler/IR2/AtomicOp.h @@ -232,6 +232,11 @@ class SimpleExpression { goos::Object to_form(const std::vector& labels, const Env& env) const; bool operator==(const SimpleExpression& other) const; bool is_identity() const { return m_kind == Kind::IDENTITY; } + bool is_var() const { return is_identity() && get_arg(0).is_var(); } + const Variable& var() const { + assert(is_var()); + return get_arg(0).var(); + } void get_regs(std::vector* out) const; TP_Type get_type(const TypeState& input, const Env& env, const DecompilerTypeSystem& dts) const; TP_Type get_type_int2(const TypeState& input, diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index 905cd3ab0..e4276738a 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -106,10 +106,8 @@ FormElement* SetVarConditionOp::get_as_form(FormPool& pool, const Env& env) cons FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { if (env.has_type_analysis()) { if (m_addr.is_identity() && m_addr.get_arg(0).is_sym_val()) { - auto val = pool.alloc_single_element_form(nullptr, m_value.as_expr(), - m_my_idx); - auto src = pool.alloc_single_element_form(nullptr, m_addr, m_my_idx); - return pool.alloc_element(src, val); + return pool.alloc_element(m_addr.get_arg(0).get_str(), + m_value.as_expr(), m_my_idx); } IR2_RegOffset ro; @@ -120,22 +118,9 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { (input_type.typespec() == TypeSpec("object") || input_type.typespec() == TypeSpec("pair"))) { if (ro.offset == 2) { - auto base = pool.alloc_single_element_form( - nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); - auto val = pool.alloc_single_element_form( - nullptr, m_value.as_expr(), m_my_idx); - auto addr = pool.alloc_single_element_form( - nullptr, GenericOperator::make_fixed(FixedOperatorKind::CDR), base); - auto fr = pool.alloc_element(addr, val); - return fr; + return pool.alloc_element(false, ro.var, m_value.as_expr(), m_my_idx); } else if (ro.offset == -2) { - auto base = pool.alloc_single_element_form( - nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); - auto val = pool.alloc_single_element_form( - nullptr, m_value.as_expr(), m_my_idx); - auto addr = pool.alloc_single_element_form( - nullptr, GenericOperator::make_fixed(FixedOperatorKind::CAR), base); - return pool.alloc_element(addr, val); + return pool.alloc_element(true, ro.var, m_value.as_expr(), m_my_idx); } } @@ -160,14 +145,14 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { // we pass along the register offset because code generation seems to be a bit // different in different cases. - auto source = pool.alloc_single_element_form( - nullptr, ro.var, tokens, input_type.get_multiplier(), ro.offset); + auto source = pool.alloc_element( + ro.var, tokens, input_type.get_multiplier(), ro.offset); - auto val = pool.alloc_single_element_form( - nullptr, m_value.as_expr(), m_my_idx); + // auto val = pool.alloc_single_element_form( + // nullptr, m_value.as_expr(), m_my_idx); assert(!rd.addr_of); - return pool.alloc_element(source, val); + return pool.alloc_element(source, m_value.as_expr(), m_my_idx, ro.var); } } @@ -183,8 +168,6 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { auto rd = env.dts->ts.reverse_field_lookup(rd_in); if (rd.success) { - auto val = pool.alloc_single_element_form( - nullptr, m_value.as_expr(), m_my_idx); auto source = pool.alloc_single_element_form( nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); std::vector tokens; @@ -192,13 +175,13 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { tokens.push_back(to_token(x)); } assert(!rd.addr_of); - auto addr = - pool.alloc_single_element_form(nullptr, source, rd.addr_of, tokens); - return pool.alloc_element(addr, val); + auto addr = pool.alloc_element(source, rd.addr_of, tokens); + return pool.alloc_element(addr, m_value.as_expr(), m_my_idx, ro.var, + std::nullopt); } + std::string cast_type; if (input_type.typespec() == TypeSpec("pointer") && ro.offset == 0) { - std::string cast_type; switch (m_size) { case 1: cast_type = "int8"; @@ -220,11 +203,10 @@ FormElement* StoreOp::get_as_form(FormPool& pool, const Env& env) const { nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx); auto cast_source = pool.alloc_single_element_form( nullptr, TypeSpec("pointer", {TypeSpec(cast_type)}), source); - auto deref = pool.alloc_single_element_form(nullptr, cast_source, false, - std::vector()); - auto val = pool.alloc_single_element_form( - nullptr, m_value.as_expr(), m_my_idx); - return pool.alloc_element(deref, val); + auto deref = + pool.alloc_element(cast_source, false, std::vector()); + return pool.alloc_element(deref, m_value.as_expr(), m_my_idx, ro.var, + TypeSpec("pointer", {TypeSpec(cast_type)})); } } } diff --git a/decompiler/IR2/Form.cpp b/decompiler/IR2/Form.cpp index a102f5c49..d2322ed4f 100644 --- a/decompiler/IR2/Form.cpp +++ b/decompiler/IR2/Form.cpp @@ -319,6 +319,50 @@ bool SetVarElement::active() const { } } +StoreInSymbolElement::StoreInSymbolElement(std::string sym_name, SimpleExpression value, int my_idx) + : m_sym_name(std::move(sym_name)), m_value(std::move(value)), m_my_idx(my_idx) {} + +goos::Object StoreInSymbolElement::to_form_internal(const Env& env) const { + return pretty_print::build_list("set!", m_sym_name, m_value.to_form(env.file->labels, env)); +} + +void StoreInSymbolElement::apply(const std::function& f) { + f(this); +} + +void StoreInSymbolElement::apply_form(const std::function&) {} + +void StoreInSymbolElement::collect_vars(VariableSet& vars) const { + m_value.collect_vars(vars); +} + +void StoreInSymbolElement::get_modified_regs(RegSet&) const {} + +StoreInPairElement::StoreInPairElement(bool is_car, + Variable pair, + SimpleExpression value, + int my_idx) + : m_is_car(is_car), m_pair(pair), m_value(value), m_my_idx(my_idx) {} + +goos::Object StoreInPairElement::to_form_internal(const Env& env) const { + return pretty_print::build_list( + "set!", pretty_print::build_list(m_is_car ? "car" : "cdr", m_pair.to_form(env)), + m_value.to_form(env.file->labels, env)); +} + +void StoreInPairElement::apply(const std::function& f) { + f(this); +} + +void StoreInPairElement::apply_form(const std::function&) {} + +void StoreInPairElement::collect_vars(VariableSet& vars) const { + m_value.collect_vars(vars); + vars.insert(m_pair); +} + +void StoreInPairElement::get_modified_regs(RegSet&) const {} + ///////////////////////////// // SetFormFormElement ///////////////////////////// @@ -335,6 +379,7 @@ goos::Object SetFormFormElement::to_form_internal(const Env& env) const { } void SetFormFormElement::apply(const std::function& f) { + f(this); m_src->apply(f); m_dst->apply(f); } @@ -1598,4 +1643,69 @@ void ConstantTokenElement::apply_form(const std::function&) {} void ConstantTokenElement::collect_vars(VariableSet&) const {} void ConstantTokenElement::get_modified_regs(RegSet&) const {} +StorePlainDeref::StorePlainDeref(DerefElement* dst, + SimpleExpression expr, + int my_idx, + Variable base_var, + std::optional cast_type) + : m_dst(dst), + m_expr(std::move(expr)), + m_my_idx(my_idx), + m_base_var(std::move(base_var)), + m_cast_type(cast_type) {} +goos::Object StorePlainDeref::to_form_internal(const Env& env) const { + if (!m_cast_type.has_value()) { + return pretty_print::build_list("set!", m_dst->to_form(env), + m_expr.to_form(env.file->labels, env)); + } else { + return pretty_print::build_list( + "set!", pretty_print::build_list("the-as", m_cast_type->print(), m_dst->to_form(env)), + m_expr.to_form(env.file->labels, env)); + } +} +void StorePlainDeref::apply(const std::function& f) { + f(this); + m_dst->apply(f); +} + +void StorePlainDeref::apply_form(const std::function&) {} + +void StorePlainDeref::collect_vars(VariableSet& vars) const { + m_expr.collect_vars(vars); + m_dst->collect_vars(vars); +} + +void StorePlainDeref::get_modified_regs(RegSet& regs) const { + m_dst->get_modified_regs(regs); +} + +StoreArrayAccess::StoreArrayAccess(ArrayFieldAccess* dst, + SimpleExpression expr, + int my_idx, + Variable array_src) + : m_dst(dst), m_expr(expr), m_my_idx(my_idx), m_base_var(array_src) {} + +goos::Object StoreArrayAccess::to_form_internal(const Env& env) const { + return pretty_print::build_list("set!", m_dst->to_form(env), + m_expr.to_form(env.file->labels, env)); +} + +void StoreArrayAccess::apply(const std::function& f) { + f(this); + m_dst->apply(f); +} + +void StoreArrayAccess::apply_form(const std::function& f) { + m_dst->apply_form(f); +} + +void StoreArrayAccess::collect_vars(VariableSet& vars) const { + m_expr.collect_vars(vars); + m_dst->collect_vars(vars); +} + +void StoreArrayAccess::get_modified_regs(RegSet& regs) const { + m_dst->get_modified_regs(regs); +} + } // namespace decompiler diff --git a/decompiler/IR2/Form.h b/decompiler/IR2/Form.h index 61e78b3b1..7485f54ab 100644 --- a/decompiler/IR2/Form.h +++ b/decompiler/IR2/Form.h @@ -43,9 +43,16 @@ class FormElement { FormStack& stack, std::vector* result, bool allow_side_effects); + bool is_popped() const { return m_popped; } + + void mark_popped() { + assert(!m_popped); + m_popped = true; + } protected: friend class Form; + bool m_popped = false; }; /*! @@ -61,8 +68,6 @@ class SimpleExpressionElement : public FormElement { void apply_form(const std::function& f) override; bool is_sequence_point() const override; void collect_vars(VariableSet& vars) const override; - void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; - // void push_to_stack(const Env& env, FormStack& stack) override; void update_from_stack(const Env& env, FormPool& pool, FormStack& stack, @@ -219,13 +224,11 @@ class SimpleAtomElement : public FormElement { void collect_vars(VariableSet& vars) const override; void get_modified_regs(RegSet& regs) const override; const SimpleAtom& atom() const { return m_atom; } - void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; void update_from_stack(const Env& env, FormPool& pool, FormStack& stack, std::vector* result, bool allow_side_effects) override; - // void push_to_stack(const Env& env, FormStack& stack) override; private: SimpleAtom m_atom; @@ -246,11 +249,6 @@ class SetVarElement : public FormElement { bool is_sequence_point() const override; void collect_vars(VariableSet& vars) const override; void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; - void update_from_stack(const Env& env, - FormPool& pool, - FormStack& stack, - std::vector* result, - bool allow_side_effects) override; void get_modified_regs(RegSet& regs) const override; bool active() const override; @@ -276,6 +274,39 @@ class SetVarElement : public FormElement { SetVarInfo m_var_info; }; +class StoreInSymbolElement : public FormElement { + public: + StoreInSymbolElement(std::string sym_name, SimpleExpression value, int my_idx); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + 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; + + private: + std::string m_sym_name; + SimpleExpression m_value; + int m_my_idx = -1; +}; + +class StoreInPairElement : public FormElement { + public: + StoreInPairElement(bool is_car, Variable pair, SimpleExpression value, int my_idx); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + 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; + + private: + bool m_is_car = false; + Variable m_pair; + SimpleExpression m_value; + int m_my_idx = -1; +}; + /*! * Like SetVar, but sets a form to another form. * This is intended to be used with stores. @@ -298,6 +329,7 @@ class SetFormFormElement : public FormElement { Form* dst() { return m_dst; } private: + int m_real_push_count = 0; Form* m_dst = nullptr; Form* m_src = nullptr; }; @@ -341,7 +373,8 @@ class AsmOpElement : public FormElement { /*! * A "condition" like (< a b). This can be used as a boolean value directly: (set! a (< b c)) - * or it can be used as a branch condition: (if (< a b)). + * or it can be used as a branch condition: (if (< a b)). As a result, it implements both push + * and update. * * In the first case, it can be either a conditional move or actually branching. GOAL seems to use * the branching when sometimes it could have used the conditional move, and for now, we don't @@ -892,10 +925,13 @@ class DerefElement : public FormElement { bool allow_side_effects) override; void get_modified_regs(RegSet& regs) const override; + void inline_nested(); + bool is_addr_of() const { return m_is_addr_of; } const Form* base() const { return m_base; } Form* base() { return m_base; } const std::vector& tokens() const { return m_tokens; } + void set_base(Form* new_base) { m_base = new_base; } private: Form* m_base = nullptr; @@ -938,6 +974,12 @@ class ArrayFieldAccess : public FormElement { bool allow_side_effects) override; void get_modified_regs(RegSet& regs) const override; + void update_with_val(Form* new_val, + const Env& env, + FormPool& pool, + std::vector* result, + bool allow_side_effects); + private: Variable m_source; std::vector m_deref_tokens; @@ -1001,6 +1043,46 @@ class ConstantTokenElement : public FormElement { std::string m_value; }; +class StorePlainDeref : public FormElement { + public: + StorePlainDeref(DerefElement* dst, + SimpleExpression expr, + int my_idx, + Variable base_var, + std::optional cast_type); + + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(VariableSet& vars) const override; + void get_modified_regs(RegSet& regs) const override; + void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; + + private: + DerefElement* m_dst = nullptr; + SimpleExpression m_expr; + int m_my_idx = -1; + Variable m_base_var; + std::optional m_cast_type; +}; + +class StoreArrayAccess : public FormElement { + public: + StoreArrayAccess(ArrayFieldAccess* dst, SimpleExpression expr, int my_idx, Variable array_src); + goos::Object to_form_internal(const Env& env) const override; + void apply(const std::function& f) override; + void apply_form(const std::function& f) override; + void collect_vars(VariableSet& vars) const override; + void get_modified_regs(RegSet& regs) const override; + void push_to_stack(const Env& env, FormPool& pool, FormStack& stack) override; + + private: + ArrayFieldAccess* m_dst = nullptr; + SimpleExpression m_expr; + int m_my_idx = -1; + Variable m_base_var; +}; + /*! * A Form is a wrapper around one or more FormElements. * This is done for two reasons: @@ -1073,6 +1155,14 @@ class Form { bool has_side_effects(); void get_modified_regs(RegSet& regs) const; + bool is_popped() const { return m_elements.at(0)->is_popped(); } + + void mark_popped() { + for (auto x : m_elements) { + x->mark_popped(); + } + } + FormElement* parent_element = nullptr; private: diff --git a/decompiler/IR2/FormExpressionAnalysis.cpp b/decompiler/IR2/FormExpressionAnalysis.cpp index 04ef2b2d7..8e07a4f77 100644 --- a/decompiler/IR2/FormExpressionAnalysis.cpp +++ b/decompiler/IR2/FormExpressionAnalysis.cpp @@ -233,7 +233,12 @@ void Form::update_children_from_stack(const Env& env, for (size_t i = 0; i < m_elements.size(); i++) { if (i == 0) { // only bother doing the first one. - m_elements[i]->update_from_stack(env, pool, stack, &new_elts, allow_side_effects); + if (!m_elements[i]->is_popped()) { + m_elements[i]->update_from_stack(env, pool, stack, &new_elts, allow_side_effects); + } else { + new_elts.push_back(m_elements[i]); + } + } else { new_elts.push_back(m_elements[i]); } @@ -286,6 +291,7 @@ void LoadSourceElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); m_addr->update_children_from_stack(env, pool, stack, allow_side_effects); result->push_back(this); } @@ -356,6 +362,8 @@ void SimpleExpressionElement::update_from_stack_fpr_to_gpr(const Env& env, // set ourself to identity. m_expr = src.as_expr(); // then go again. + assert(m_popped); + m_popped = false; update_from_stack(env, pool, stack, result, allow_side_effects); } else { throw std::runtime_error( @@ -756,6 +764,7 @@ void SimpleExpressionElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); switch (m_expr.kind()) { case SimpleExpression::Kind::IDENTITY: update_from_stack_identity(env, pool, stack, result, allow_side_effects); @@ -883,6 +892,7 @@ void SimpleExpressionElement::update_from_stack(const Env& env, /////////////////// void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); for (auto x : m_src->elts()) { assert(x->parent_form == m_src); } @@ -894,6 +904,7 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta } m_src->update_children_from_stack(env, pool, stack, true); + for (auto x : m_src->elts()) { assert(x->parent_form == m_src); } @@ -926,23 +937,110 @@ void SetVarElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta } } -void SetVarElement::update_from_stack(const Env& env, - FormPool& pool, - FormStack& stack, - std::vector* result, - bool allow_side_effects) { - m_src->update_children_from_stack(env, pool, stack, allow_side_effects); - for (auto x : m_src->elts()) { - assert(x->parent_form == m_src); - } - result->push_back(this); +void SetFormFormElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { + // todo - is the order here right? + assert(m_popped); + assert(m_real_push_count == 0); + m_real_push_count++; + stack.push_form_element(this, true); } -void SetFormFormElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { - // todo - is the order here right? - m_dst->update_children_from_stack(env, pool, stack, false); - m_src->update_children_from_stack(env, pool, stack, false); - stack.push_form_element(this, true); +void StoreInSymbolElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + auto sym = pool.alloc_single_element_form(nullptr, m_sym_name); + auto val = pool.alloc_single_element_form(nullptr, m_value, m_my_idx); + val->update_children_from_stack(env, pool, stack, true); + + auto elt = pool.alloc_element(sym, val); + elt->mark_popped(); + stack.push_form_element(elt, true); +} + +void StoreInPairElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + auto op = m_is_car ? FixedOperatorKind::CAR : FixedOperatorKind::CDR; + if (m_value.is_var()) { + auto vars = std::vector({m_value.var(), m_pair}); + auto popped = pop_to_forms(vars, env, pool, stack, true); + auto addr = pool.alloc_single_element_form( + nullptr, GenericOperator::make_fixed(op), popped.at(1)); + addr->mark_popped(); + auto fr = pool.alloc_element(addr, popped.at(0)); + fr->mark_popped(); + stack.push_form_element(fr, true); + } else { + auto val = pool.alloc_single_element_form(nullptr, m_value, m_my_idx); + val->mark_popped(); + auto addr = pool.alloc_single_element_form( + nullptr, GenericOperator::make_fixed(op), + pop_to_forms({m_pair}, env, pool, stack, true).at(0)); + addr->mark_popped(); + auto fr = pool.alloc_element(addr, val); + fr->mark_popped(); + stack.push_form_element(fr, true); + } +} + +void StorePlainDeref::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); + if (m_expr.is_var()) { + auto vars = std::vector({m_expr.var(), m_base_var}); + auto popped = pop_to_forms(vars, env, pool, stack, true); + if (m_cast_type.has_value()) { + m_dst->set_base( + pool.alloc_single_element_form(nullptr, *m_cast_type, popped.at(1))); + } else { + m_dst->set_base(popped.at(1)); + } + + m_dst->mark_popped(); + m_dst->inline_nested(); + auto fr = pool.alloc_element(pool.alloc_single_form(nullptr, m_dst), + popped.at(0)); + fr->mark_popped(); + stack.push_form_element(fr, true); + } else { + auto vars = std::vector({m_base_var}); + auto popped = pop_to_forms(vars, env, pool, stack, true); + if (m_cast_type.has_value()) { + m_dst->set_base( + pool.alloc_single_element_form(nullptr, *m_cast_type, popped.at(1))); + } else { + m_dst->set_base(popped.at(0)); + } + m_dst->mark_popped(); + m_dst->inline_nested(); + auto val = pool.alloc_single_element_form(nullptr, m_expr, m_my_idx); + val->mark_popped(); + auto fr = pool.alloc_element(pool.alloc_single_form(nullptr, m_dst), val); + fr->mark_popped(); + stack.push_form_element(fr, true); + } +} + +void StoreArrayAccess::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); + Form* expr_form = nullptr; + Form* array_form = nullptr; + if (m_expr.is_var()) { + auto vars = std::vector({m_expr.var(), m_base_var}); + auto popped = pop_to_forms(vars, env, pool, stack, true); + m_dst->mark_popped(); + expr_form = popped.at(0); + array_form = popped.at(1); + } else { + auto vars = std::vector({m_base_var}); + auto popped = pop_to_forms(vars, env, pool, stack, true); + m_dst->mark_popped(); + expr_form = pool.alloc_single_element_form(nullptr, m_expr, m_my_idx); + array_form = popped.at(0); + } + + std::vector forms_out; + m_dst->update_with_val(array_form, env, pool, &forms_out, true); + auto form_out = pool.alloc_sequence_form(nullptr, forms_out); + + auto fr = pool.alloc_element(form_out, expr_form); + fr->mark_popped(); + stack.push_form_element(fr, true); } /////////////////// @@ -954,6 +1052,7 @@ void AshElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); auto forms = pop_to_forms({value, shift_amount}, env, pool, stack, allow_side_effects, consumed); auto new_form = pool.alloc_element( GenericOperator::make_fixed(FixedOperatorKind::ARITH_SHIFT), forms.at(0), forms.at(1)); @@ -969,6 +1068,7 @@ void AbsElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); auto forms = pop_to_forms({source}, env, pool, stack, allow_side_effects, consumed); auto new_form = pool.alloc_element( GenericOperator::make_fixed(FixedOperatorKind::ABS), forms.at(0)); @@ -984,6 +1084,7 @@ void FunctionCallElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); std::vector args; auto nargs = m_op->arg_vars().size(); args.resize(nargs, nullptr); @@ -1272,17 +1373,12 @@ void DerefElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); // todo - update var tokens from stack? m_base->update_children_from_stack(env, pool, stack, allow_side_effects); // merge nested ->'s - auto as_deref = dynamic_cast(m_base->try_as_single_element()); - if (as_deref) { - if (!m_is_addr_of && !as_deref->is_addr_of()) { - m_tokens.insert(m_tokens.begin(), as_deref->tokens().begin(), as_deref->tokens().end()); - m_base = as_deref->m_base; - } - } + inline_nested(); if (m_tokens.size() >= 3) { auto& method_name = m_tokens.at(m_tokens.size() - 1); @@ -1332,11 +1428,22 @@ void DerefElement::update_from_stack(const Env& env, } } +void DerefElement::inline_nested() { + auto as_deref = dynamic_cast(m_base->try_as_single_element()); + if (as_deref) { + if (!m_is_addr_of && !as_deref->is_addr_of()) { + m_tokens.insert(m_tokens.begin(), as_deref->tokens().begin(), as_deref->tokens().end()); + m_base = as_deref->m_base; + } + } +} + /////////////////// // UntilElement /////////////////// void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); for (auto form : {condition, body}) { FormStack temp_stack(false); for (auto& entry : form->elts()) { @@ -1353,6 +1460,7 @@ void UntilElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac } void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); bool first = true; for (auto form : {body, condition}) { FormStack temp_stack(first && stack.is_root()); @@ -1373,40 +1481,43 @@ void WhileElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stac // CondNoElseElement /////////////////// void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); if (already_rewritten) { stack.push_form_element(this, true); return; } - for (auto& entry : entries) { - for (auto form : {entry.condition, entry.body}) { - FormStack temp_stack(false); - for (auto& elt : form->elts()) { - elt->push_to_stack(env, pool, temp_stack); - } - std::vector new_entries; - if (form == entry.body && used_as_value) { - new_entries = rewrite_to_get_var(temp_stack, pool, final_destination); - } else { - new_entries = temp_stack.rewrite(pool); - } - - form->clear(); - for (auto e : new_entries) { - form->push_back(e); - } - } + // the first condition is special + auto first_condition = entries.front().condition; + // lets evaluate in on the parent stack... + for (auto x : first_condition->elts()) { + x->push_to_stack(env, pool, stack); } - // raise expression. - auto top_condition = entries.front().condition; - if (!top_condition->is_single_element()) { - auto real_condition = top_condition->back(); - top_condition->pop_back(); - for (auto x : top_condition->elts()) { - x->push_to_stack(env, pool, stack); + for (auto& entry : entries) { + for (auto form : {entry.condition, entry.body}) { + if (form == first_condition) { + form->clear(); + form->push_back(stack.pop_back(pool)); + } else { + FormStack temp_stack(false); + for (auto& elt : form->elts()) { + elt->push_to_stack(env, pool, temp_stack); + } + + std::vector new_entries; + if (form == entry.body && used_as_value) { + new_entries = rewrite_to_get_var(temp_stack, pool, final_destination); + } else { + new_entries = temp_stack.rewrite(pool); + } + + form->clear(); + for (auto e : new_entries) { + form->push_back(e); + } + } } - top_condition->elts() = {real_condition}; } if (used_as_value) { @@ -1418,6 +1529,7 @@ void CondNoElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& } void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); if (already_rewritten) { stack.push_form_element(this, true); return; @@ -1426,20 +1538,32 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac std::optional last_var; bool rewrite_as_set = true; + // the first condition is special + auto first_condition = entries.front().condition; + // lets evaluate in on the parent stack... + for (auto x : first_condition->elts()) { + x->push_to_stack(env, pool, stack); + } + // process conditions and bodies for (auto& entry : entries) { for (auto form : {entry.condition, entry.body}) { - FormStack temp_stack(false); - for (auto& elt : form->elts()) { - elt->push_to_stack(env, pool, temp_stack); - } + if (form == first_condition) { + form->clear(); + form->push_back(stack.pop_back(pool)); + } else { + FormStack temp_stack(false); + for (auto& elt : form->elts()) { + elt->push_to_stack(env, pool, temp_stack); + } - std::vector new_entries; - new_entries = temp_stack.rewrite(pool); + std::vector new_entries; + new_entries = temp_stack.rewrite(pool); - form->clear(); - for (auto e : new_entries) { - form->push_back(e); + form->clear(); + for (auto e : new_entries) { + form->push_back(e); + } } } } @@ -1500,17 +1624,6 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac rewrite_to_get_var(else_ir->elts(), pool, *last_var); } - // raise expression. - auto top_condition = entries.front().condition; - if (!top_condition->is_single_element()) { - auto real_condition = top_condition->back(); - top_condition->pop_back(); - for (auto x : top_condition->elts()) { - x->push_to_stack(env, pool, stack); - } - top_condition->elts() = {real_condition}; - } - if (rewrite_as_set) { if (set_unused) { stack.push_form_element(this, true); @@ -1528,6 +1641,7 @@ void CondWithElseElement::push_to_stack(const Env& env, FormPool& pool, FormStac /////////////////// void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); if (!used_as_value.value_or(false)) { throw std::runtime_error( "ShortCircuitElement::push_to_stack not implemented for result not used case."); @@ -1538,34 +1652,37 @@ void ShortCircuitElement::push_to_stack(const Env& env, FormPool& pool, FormStac stack.push_form_element(this, true); return; } - for (int i = 0; i < int(entries.size()); i++) { - auto& entry = entries.at(i); - FormStack temp_stack(false); - for (auto& elt : entry.condition->elts()) { - elt->push_to_stack(env, pool, temp_stack); - } - std::vector new_entries; - if (i == int(entries.size()) - 1) { - new_entries = rewrite_to_get_var(temp_stack, pool, final_result); - } else { - new_entries = temp_stack.rewrite(pool); - } - - entry.condition->clear(); - for (auto e : new_entries) { - entry.condition->push_back(e); - } + // the first condition is special + auto first_condition = entries.front().condition; + // lets evaluate in on the parent stack... + for (auto x : first_condition->elts()) { + x->push_to_stack(env, pool, stack); } - auto top_condition = entries.front().condition; - if (!top_condition->is_single_element()) { - auto real_condition = top_condition->back(); - top_condition->pop_back(); - for (auto x : top_condition->elts()) { - x->push_to_stack(env, pool, stack); + for (int i = 0; i < int(entries.size()); i++) { + auto& entry = entries.at(i); + if (entry.condition == first_condition) { + entry.condition->clear(); + entry.condition->push_back(stack.pop_back(pool)); + } else { + FormStack temp_stack(false); + for (auto& elt : entry.condition->elts()) { + elt->push_to_stack(env, pool, temp_stack); + } + + std::vector new_entries; + if (i == int(entries.size()) - 1) { + new_entries = rewrite_to_get_var(temp_stack, pool, final_result); + } else { + new_entries = temp_stack.rewrite(pool); + } + + entry.condition->clear(); + for (auto e : new_entries) { + entry.condition->push_back(e); + } } - top_condition->elts() = {real_condition}; } assert(used_as_value.has_value()); @@ -1579,6 +1696,7 @@ void ShortCircuitElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool) { + mark_popped(); (void)stack; if (already_rewritten) { result->push_back(this); @@ -1717,6 +1835,7 @@ FormElement* ConditionElement::make_generic(const Env&, } void ConditionElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); std::vector source_forms, popped_forms; std::vector source_types; std::vector vars; @@ -1766,6 +1885,7 @@ void ConditionElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); std::vector source_forms, popped_forms; std::vector source_types; std::vector vars; @@ -1811,6 +1931,7 @@ void ConditionElement::update_from_stack(const Env& env, } void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); FormStack temp_stack(false); for (auto& elt : return_code->elts()) { elt->push_to_stack(env, pool, temp_stack); @@ -1827,6 +1948,7 @@ void ReturnElement::push_to_stack(const Env& env, FormPool& pool, FormStack& sta } void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) { + mark_popped(); auto as_end = dynamic_cast(m_op); if (as_end) { // we don't want to push this to the stack (for now at least) @@ -1851,6 +1973,7 @@ void AtomicOpElement::push_to_stack(const Env& env, FormPool&, FormStack& stack) } void AsmOpElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { + mark_popped(); stack.push_form_element(this, true); } @@ -1859,11 +1982,11 @@ void GenericElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool) { - // TODO improve. - if (m_head.m_kind == GenericOperator::Kind::FUNCTION_EXPR) { - m_head.m_function->update_children_from_stack(env, pool, stack, false); - } else { - m_elts.back()->update_children_from_stack(env, pool, stack, false); + mark_popped(); + if (m_elts.size() == 1) { + // a bit of a hack, but AtomicOpForm uses this for loading car/cdr + // this is safe to do. + m_elts.front()->update_children_from_stack(env, pool, stack, true); } result->push_back(this); } @@ -1871,6 +1994,7 @@ void GenericElement::update_from_stack(const Env& env, void GenericElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { (void)env; (void)pool; + mark_popped(); stack.push_form_element(this, true); } @@ -1883,6 +2007,7 @@ void DynamicMethodAccess::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); auto reg0_matcher = Matcher::match_or({Matcher::any_reg(0), Matcher::cast("uint", Matcher::any_reg(0))}); @@ -1927,12 +2052,11 @@ bool is_power_of_two(int in, int* out) { } } // namespace -void ArrayFieldAccess::update_from_stack(const Env& env, - FormPool& pool, - FormStack& stack, - std::vector* result, - bool allow_side_effects) { - auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); +void ArrayFieldAccess::update_with_val(Form* new_val, + const Env& env, + FormPool& pool, + std::vector* result, + bool) { int power_of_two = 0; if (m_constant_offset == 0) { @@ -2077,6 +2201,16 @@ void ArrayFieldAccess::update_from_stack(const Env& env, } } +void ArrayFieldAccess::update_from_stack(const Env& env, + FormPool& pool, + FormStack& stack, + std::vector* result, + bool allow_side_effects) { + mark_popped(); + auto new_val = stack.pop_reg(m_source, {}, env, allow_side_effects); + update_with_val(new_val, env, pool, result, allow_side_effects); +} + //////////////////////// // CastElement //////////////////////// @@ -2086,6 +2220,7 @@ void CastElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); m_source->update_children_from_stack(env, pool, stack, allow_side_effects); result->push_back(this); } @@ -2099,6 +2234,7 @@ void TypeOfElement::update_from_stack(const Env& env, FormStack& stack, std::vector* result, bool allow_side_effects) { + mark_popped(); value->update_children_from_stack(env, pool, stack, allow_side_effects); result->push_back(this); } @@ -2108,6 +2244,7 @@ void TypeOfElement::update_from_stack(const Env& env, //////////////////////// void EmptyElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { + mark_popped(); stack.push_form_element(this, true); } @@ -2121,6 +2258,7 @@ bool is_symbol_true(const Form* form) { } void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool, FormStack& stack) { + mark_popped(); // pop the value and the original auto popped = pop_to_forms({old_value, source}, env, pool, stack, true); if (!is_symbol_true(popped.at(0))) { @@ -2136,27 +2274,21 @@ void ConditionalMoveFalseElement::push_to_stack(const Env& env, FormPool& pool, true); } -void SimpleAtomElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { - stack.push_form_element(this, true); -} - void SimpleAtomElement::update_from_stack(const Env&, FormPool&, FormStack&, std::vector* result, bool) { + mark_popped(); result->push_back(this); } -void SimpleExpressionElement::push_to_stack(const Env&, FormPool&, FormStack& stack) { - stack.push_form_element(this, true); -} - void StringConstantElement::update_from_stack(const Env&, FormPool&, FormStack&, std::vector* result, bool) { + mark_popped(); result->push_back(this); } @@ -2165,6 +2297,7 @@ void GetMethodElement::update_from_stack(const Env&, FormStack&, std::vector* result, bool) { + mark_popped(); result->push_back(this); } @@ -2173,6 +2306,7 @@ void CondNoElseElement::update_from_stack(const Env&, FormStack&, std::vector* result, bool) { + mark_popped(); result->push_back(this); } @@ -2181,6 +2315,7 @@ void ConstantTokenElement::update_from_stack(const Env&, FormStack&, std::vector* result, bool) { + mark_popped(); result->push_back(this); } diff --git a/decompiler/IR2/FormStack.cpp b/decompiler/IR2/FormStack.cpp index 6033e10ac..b694795be 100644 --- a/decompiler/IR2/FormStack.cpp +++ b/decompiler/IR2/FormStack.cpp @@ -191,6 +191,21 @@ Form* FormStack::unsafe_peek(Register reg, const Env& env) { return nullptr; } +FormElement* FormStack::pop_back(FormPool& pool) { + auto& back = m_stack.back(); + assert(back.active); + back.active = false; + if (back.elt) { + return back.elt; + } else { + assert(back.destination.has_value()); + auto elt = pool.alloc_element(*back.destination, back.source, + back.sequence_point, back.set_info); + back.source->parent_element = elt; + return elt; + } +} + std::vector FormStack::rewrite(FormPool& pool) { std::vector result; diff --git a/decompiler/IR2/FormStack.h b/decompiler/IR2/FormStack.h index 64256454a..0fbe8b812 100644 --- a/decompiler/IR2/FormStack.h +++ b/decompiler/IR2/FormStack.h @@ -36,6 +36,7 @@ class FormStack { const Env& env, bool allow_side_effects, int begin_idx = -1); + FormElement* pop_back(FormPool& pool); Form* unsafe_peek(Register reg, const Env& env); bool is_single_expression(); std::vector rewrite(FormPool& pool); diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 5a0dd06cd..a0c8cf7be 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -502,13 +502,13 @@ (define-extern search-process-tree (function process-tree (function process-tree object) process)) (define-extern execute-process-tree (function process-tree (function object object) kernel-context object)) -(define-extern previous-brother (function process-tree process-tree)) +(define-extern previous-brother (function process-tree object)) (define-extern change-parent (function process-tree process-tree process-tree)) -(define-extern change-brother (function process-tree process-tree process-tree)) +(define-extern change-brother (function process-tree process-tree object)) (define-extern change-to-last-brother (function process-tree process-tree)) (define-extern *active-pool* process-tree) -(define-extern kernel-dispatcher (function (function object))) +(define-extern kernel-dispatcher (function object)) (define-extern inspect-process-tree (function process-tree int int symbol process-tree)) (define-extern throw-dispatch (function catch-frame object none)) @@ -11014,120 +11014,116 @@ :flag-assert #x900000028 ) -; ;; progress-h -; (deftype progress (process) -; ((~Tcurrent-debug-string int32 :offset-assert 112) -; (~Tcurrent-debug-language int32 :offset-assert 116) -; (~Tcurrent-debug-group int32 :offset-assert 120) -; (~Tin-out-position int32 :offset-assert 124) -; (~Tdisplay-state uint64 :offset-assert 128) -; (~Tnext-display-state uint64 :offset-assert 136) -; (~Toption-index int32 :offset-assert 144) -; (~Tselected-option basic :offset-assert 148) -; (~Tcompletion-percentage float :offset-assert 152) -; (~Tready-to-run basic :offset-assert 156) -; (~Tdisplay-level-index int32 :offset-assert 160) -; (~Tnext-level-index int32 :offset-assert 164) -; (~Ttask-index int32 :offset-assert 168) -; (~Tin-transition basic :offset-assert 172) -; (~Tlast-in-transition basic :offset-assert 176) -; (~Tforce-transition basic :offset-assert 180) -; (~Tstat-transition basic :offset-assert 184) -; (~Tlevel-transition int32 :offset-assert 188) -; (~Tlanguage-selection uint64 :offset-assert 192) -; (~Tlanguage-direction basic :offset-assert 200) -; (~Tlanguage-transition basic :offset-assert 204) -; (~Tlanguage-x-offset int32 :offset-assert 208) -; (~Tsides-x-scale float :offset-assert 212) -; (~Tsides-y-scale float :offset-assert 216) -; (~Tleft-x-offset int32 :offset-assert 220) -; (~Tright-x-offset int32 :offset-assert 224) -; (~Tbutton-scale float :offset-assert 228) -; (~Tslot-scale float :offset-assert 232) -; (~Tleft-side-x-scale float :offset-assert 236) -; (~Tleft-side-y-scale float :offset-assert 240) -; (~Tright-side-x-scale float :offset-assert 244) -; (~Tright-side-y-scale float :offset-assert 248) -; (~Tsmall-orb-y-offset int32 :offset-assert 252) -; (~Tbig-orb-y-offset int32 :offset-assert 256) -; (~Ttransition-offset int32 :offset-assert 260) -; (~Ttransition-offset-invert int32 :offset-assert 264) -; (~Ttransition-percentage float :offset-assert 268) -; (~Ttransition-percentage-invert float :offset-assert 272) -; (~Ttransition-speed float :offset-assert 276) -; (~Ttotal-nb-of-power-cells int32 :offset-assert 280) -; (~Ttotal-nb-of-orbs int32 :offset-assert 284) -; (~Ttotal-nb-of-buzzers int32 :offset-assert 288) -; (~Tcard-info mc-slot-info :offset-assert 292) -; (~Tlast-option-index-change uint64 :offset-assert 296) -; (~Tvideo-mode-timeout uint64 :offset-assert 304) -; (~Tdisplay-state-stack UNKNOWN 5 :offset-assert 312) -; (~Toption-index-stack UNKNOWN 5 :offset-assert 352) -; (~Tdisplay-state-pos int32 :offset-assert 372) -; (~Tnb-of-icons int32 :offset-assert 376) -; (~Ticons UNKNOWN 6 :offset-assert 380) -; (~Tmax-nb-of-particles int32 :offset-assert 404) -; (~Tnb-of-particles int32 :offset-assert 408) -; (~Tparticles UNKNOWN 40 :offset-assert 412) -; (~Tparticle-state UNKNOWN 40 :offset-assert 572) -; ) -; :method-count-assert 59 -; :size-assert #x2dc -; :flag-assert #x3b027002dc -; ;; inherited inspect of process -; (:methods -; (dummy-9 () none 9) -; (dummy-10 () none 10) -; (dummy-11 () none 11) -; (dummy-12 () none 12) -; (dummy-13 () none 13) -; (dummy-14 () none 14) -; (dummy-15 () none 15) -; (dummy-16 () none 16) -; (dummy-17 () none 17) -; (dummy-18 () none 18) -; (dummy-19 () none 19) -; (dummy-20 () none 20) -; (dummy-21 () none 21) -; (dummy-22 () none 22) -; (dummy-23 () none 23) -; (dummy-24 () none 24) -; (dummy-25 () none 25) -; (dummy-26 () none 26) -; (dummy-27 () none 27) -; (dummy-28 () none 28) -; (dummy-29 () none 29) -; (dummy-30 () none 30) -; (dummy-31 () none 31) -; (dummy-32 () none 32) -; (dummy-33 () none 33) -; (dummy-34 () none 34) -; (dummy-35 () none 35) -; (dummy-36 () none 36) -; (dummy-37 () none 37) -; (dummy-38 () none 38) -; (dummy-39 () none 39) -; (dummy-40 () none 40) -; (dummy-41 () none 41) -; (dummy-42 () none 42) -; (dummy-43 () none 43) -; (dummy-44 () none 44) -; (dummy-45 () none 45) -; (dummy-46 () none 46) -; (dummy-47 () none 47) -; (dummy-48 () none 48) -; (dummy-49 () none 49) -; (dummy-50 () none 50) -; (dummy-51 () none 51) -; (dummy-52 () none 52) -; (dummy-53 () none 53) -; (dummy-54 () none 54) -; (dummy-55 () none 55) -; (dummy-56 () none 56) -; (dummy-57 () none 57) -; (dummy-58 () none 58) -; ) -; ) +;; progress-h +(deftype progress (process) + ((~Tcurrent-debug-string int32 :offset-assert 112) + (~Tcurrent-debug-language int32 :offset-assert 116) + (~Tcurrent-debug-group int32 :offset-assert 120) + (~Tin-out-position int32 :offset-assert 124) + (~Tdisplay-state uint64 :offset-assert 128) + (~Tnext-display-state uint64 :offset-assert 136) + (~Toption-index int32 :offset-assert 144) + (~Tselected-option basic :offset-assert 148) + (~Tcompletion-percentage float :offset-assert 152) + (~Tready-to-run basic :offset-assert 156) + (~Tdisplay-level-index int32 :offset-assert 160) + (~Tnext-level-index int32 :offset-assert 164) + (~Ttask-index int32 :offset-assert 168) + (~Tin-transition basic :offset-assert 172) + (~Tlast-in-transition basic :offset-assert 176) + (~Tforce-transition basic :offset-assert 180) + (~Tstat-transition basic :offset-assert 184) + (~Tlevel-transition int32 :offset-assert 188) + (~Tlanguage-selection uint64 :offset-assert 192) + (~Tlanguage-direction basic :offset-assert 200) + (~Tlanguage-transition basic :offset-assert 204) + (~Tlanguage-x-offset int32 :offset-assert 208) + (~Tsides-x-scale float :offset-assert 212) + (~Tsides-y-scale float :offset-assert 216) + (~Tleft-x-offset int32 :offset-assert 220) + (~Tright-x-offset int32 :offset-assert 224) + (~Tbutton-scale float :offset-assert 228) + (~Tslot-scale float :offset-assert 232) + (~Tleft-side-x-scale float :offset-assert 236) + (~Tleft-side-y-scale float :offset-assert 240) + (~Tright-side-x-scale float :offset-assert 244) + (~Tright-side-y-scale float :offset-assert 248) + (~Tsmall-orb-y-offset int32 :offset-assert 252) + (~Tbig-orb-y-offset int32 :offset-assert 256) + (~Ttransition-offset int32 :offset-assert 260) + (~Ttransition-offset-invert int32 :offset-assert 264) + (~Ttransition-percentage float :offset-assert 268) + (~Ttransition-percentage-invert float :offset-assert 272) + (~Ttransition-speed float :offset-assert 276) + (~Ttotal-nb-of-power-cells int32 :offset-assert 280) + (~Ttotal-nb-of-orbs int32 :offset-assert 284) + (~Ttotal-nb-of-buzzers int32 :offset-assert 288) + (~Tcard-info mc-slot-info :offset-assert 292) + (~Tlast-option-index-change uint64 :offset-assert 296) + (~Tvideo-mode-timeout uint64 :offset-assert 304) + (pad uint8 :offset 731) + ; (~Tdisplay-state-stack UNKNOWN 5 :offset-assert 312) + ; (~Toption-index-stack UNKNOWN 5 :offset-assert 352) + ; (~Tdisplay-state-pos int32 :offset-assert 372) + ; (~Tnb-of-icons int32 :offset-assert 376) + ; (~Ticons UNKNOWN 6 :offset-assert 380) + ; (~Tmax-nb-of-particles int32 :offset-assert 404) + ; (~Tnb-of-particles int32 :offset-assert 408) + ; (~Tparticles UNKNOWN 40 :offset-assert 412) + ; (~Tparticle-state UNKNOWN 40 :offset-assert 572) + ) + :method-count-assert 59 + :size-assert #x2dc + :flag-assert #x3b000002dc + ;; inherited inspect of process + (:methods + (dummy-14 () none 14) + (dummy-15 () none 15) + (dummy-16 () none 16) + (dummy-17 () none 17) + (dummy-18 () none 18) + (dummy-19 () none 19) + (dummy-20 () none 20) + (dummy-21 () none 21) + (dummy-22 () none 22) + (dummy-23 () none 23) + (dummy-24 () none 24) + (dummy-25 () none 25) + (dummy-26 () none 26) + (dummy-27 () none 27) + (dummy-28 () none 28) + (dummy-29 () none 29) + (dummy-30 () none 30) + (dummy-31 () none 31) + (dummy-32 () none 32) + (dummy-33 () none 33) + (dummy-34 () none 34) + (dummy-35 () none 35) + (dummy-36 () none 36) + (dummy-37 () none 37) + (dummy-38 () none 38) + (dummy-39 () none 39) + (dummy-40 () none 40) + (dummy-41 () none 41) + (dummy-42 () none 42) + (dummy-43 () none 43) + (dummy-44 () none 44) + (dummy-45 () none 45) + (dummy-46 () none 46) + (dummy-47 () none 47) + (dummy-48 () none 48) + (dummy-49 () none 49) + (dummy-50 () none 50) + (dummy-51 () none 51) + (dummy-52 () none 52) + (dummy-53 () none 53) + (dummy-54 () none 54) + (dummy-55 () none 55) + (dummy-56 () none 56) + (dummy-57 () none 57) + (dummy-58 () none 58) + ) + ) ;; rpc-h (deftype rpc-buffer (basic) @@ -33078,7 +33074,7 @@ ;;(define-extern *hud-parts* object) ;; unknown type (define-extern game-option type) ;;(define-extern progress object) ;; unknown type -;;(define-extern *progress-process* object) ;; unknown type +(define-extern *progress-process* process) ;; unknown type ;;(define-extern count-info object) ;; unknown type (define-extern task-info-data type) (define-extern game-count-info type) @@ -35375,13 +35371,13 @@ (define-extern main-cheats function) ;;(define-extern *progress-cheat* object) ;; unknown type (define-extern display-loop function) -(define-extern letterbox function) +(define-extern letterbox (function none)) ;;(define-extern *cheat-temp* object) ;; unknown type ;;(define-extern *master-exit* object) ;; unknown type ;;(define-extern *last-master-mode* object) ;; unknown type (define-extern off function) ;;(define-extern *screen-filter* object) ;; unknown type -(define-extern set-letterbox-frames function) +(define-extern set-letterbox-frames (function int none)) (define-extern entity-by-type function) ;;(define-extern scf-get-timeout object) ;; unknown type (define-extern pause-allowed? function) @@ -35767,7 +35763,7 @@ ;;(define-extern iron object) ;; unknown type ;;(define-extern wood object) ;; unknown type ;;(define-extern crate-type object) ;; unknown type -;;(define-extern hud-arriving object) ;; unknown type +(define-extern hud-arriving state) ;; unknown type ;;(define-extern hud-leaving object) ;; unknown type ;;(define-extern hud-hidden object) ;; unknown type ;;(define-extern hud-in object) ;; unknown type diff --git a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc index d00b480ce..2272db782 100644 --- a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc @@ -340,6 +340,11 @@ "(method 0 state)":{ "args":["allocation", "type-to-make", "name", "code", "trans", "enter", "exit", "event"], "vars":{"v0-0":"obj"} + }, + + "previous-brother":{ + "args":["proc"], + "vars":{"v1-0":"parent", "v1-2":"child"} } diff --git a/doc/code_status.md b/doc/code_status.md index 2f3e63ece..0ffaadeb3 100644 --- a/doc/code_status.md +++ b/doc/code_status.md @@ -14,7 +14,9 @@ - The types `cpu-thread` and `catch-frame` have a slightly different layout in OpenGOAL to back up x86-64 registers ## `gkernel`: -- In progress +- Many changes for x86-64/OpenGOAL +- A few bugs in the game related to `process-tree` vs `(pointer process-tree)`. +- `change-brother` is totally wrong, unused, and left out. ## `pskernel`: **Done** - Unimplemented in OpenGOAL. Seems to be debugging hooks into the PS2's kernel. Error strings indicate that there should have been a second related file included that actually contained the debugging handlers, but this file is not present. diff --git a/doc/emacs_config.el b/doc/emacs_config.el new file mode 100644 index 000000000..29c10ae5c --- /dev/null +++ b/doc/emacs_config.el @@ -0,0 +1,24 @@ +;; make gc files use lisp-mode +(add-to-list 'auto-mode-alist '("\\.gc\\'" . lisp-mode)) +;; run setup-goal when we enter lisp mode +(add-hook 'lisp-mode-hook 'setup-goal) + +(defun setup-goal () + ;; if we are in a gc file, change indent settings for GOAL + (when (and (stringp buffer-file-name) + (string-match "\\.gc\\'" buffer-file-name)) + (put 'with-pp 'common-lisp-indent-function 0) + (put 'while 'common-lisp-indent-function 1) + (put 'rlet 'common-lisp-indent-function 1) + (put 'until 'common-lisp-indent-function 1) + (put 'countdown 'common-lisp-indent-function 1) + (put 'defun-debug 'common-lisp-indent-function 2) + (put 'defenum 'common-lisp-indent-function 2) + + ;; indent for common lisp, this makes if's look nicer + (custom-set-variables '(lisp-indent-function 'common-lisp-indent-function)) + (autoload 'common-lisp-indent-function "cl-indent" "Common Lisp indent.") + ;; use spaces, not tabs + (setq-default indent-tabs-mode nil) + ) + ) diff --git a/goal_src/kernel/gkernel.gc b/goal_src/kernel/gkernel.gc index eb2813581..bdda17f7a 100644 --- a/goal_src/kernel/gkernel.gc +++ b/goal_src/kernel/gkernel.gc @@ -92,7 +92,7 @@ :relocating-process #f :low-memory-message #t ) - ) + ) ;; the main stack for running GOAL code! ;; all user code (that I know of) runs using *dram-stack* @@ -113,21 +113,21 @@ ;; Thread and CPU Thread ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; A GOAL thread represents the execution of code in a process. -; Each process has a "main thread", which is suspended and resumed. -; A process may also execute various temporary threads which always run until completion. -; A "temporary thread" cannot suspend and resume, but a "main thread" can. -; The currently executing thread of a process is the "top-thread". +;; A GOAL thread represents the execution of code in a process. +;; Each process has a "main thread", which is suspended and resumed. +;; A process may also execute various temporary threads which always run until completion. +;; A "temporary thread" cannot suspend and resume, but a "main thread" can. +;; The currently executing thread of a process is the "top-thread". -; Threads that suspend do so by saving their saved registers and their stack. -; All threads run on a single large stack and have small "backup" stacks that are much smaller than the main stack. -; as a result, suspending can fail if you are using more stack than the size of your backup stack. -; This "backup stack" can be different sizes for different threads and makes the thread type dynamic. -; The main thread is stored on the process heap, as they need the same lifetime as the process. -; The temporary threads are stored on the stack. There can be only one temporary thread at a time. +;; Threads that suspend do so by saving their saved registers and their stack. +;; All threads run on a single large stack and have small "backup" stacks that are much smaller than the main stack. +;; as a result, suspending can fail if you are using more stack than the size of your backup stack. +;; This "backup stack" can be different sizes for different threads and makes the thread type dynamic. +;; The main thread is stored on the process heap, as they need the same lifetime as the process. +;; The temporary threads are stored on the stack. There can be only one temporary thread at a time. -; All threads are actually cpu-threads. It's not clear why there are two separate types. -; Perhaps the thread was the public interface and cpu-thread is internal to the kernel? +;; All threads are actually cpu-threads. It's not clear why there are two separate types. +;; Perhaps the thread was the public interface and cpu-thread is internal to the kernel? (defmethod delete thread ((obj thread)) "Clean up a temporary thread after it is done being used. @@ -169,8 +169,8 @@ (set! (-> this stack-size) stack-size) ) (else - (msg-err "illegal attempt change stack size of ~A after more heap allocation has occured.~%" proc) - ) + (msg-err "illegal attempt change stack size of ~A after more heap allocation has occured.~%" proc) + ) ) ) (none) @@ -196,14 +196,14 @@ )) ) (else - ;; the main thread. We need the main thread's cpu-thread to stick around, so we put it in the - ;; process heap. - (let ((alloc (align16 (-> parent-process heap-cur)))) ;; start at heap cur, aligned - ;; bump heap to include our thread + its stack - (set! (-> parent-process heap-cur) (the pointer (+ alloc (-> type-to-make size) stack-size))) - (the cpu-thread (+ alloc *gtype-basic-offset*)) - ) - ) + ;; the main thread. We need the main thread's cpu-thread to stick around, so we put it in the + ;; process heap. + (let ((alloc (align16 (-> parent-process heap-cur)))) ;; start at heap cur, aligned + ;; bump heap to include our thread + its stack + (set! (-> parent-process heap-cur) (the pointer (+ alloc (-> type-to-make size) stack-size))) + (the cpu-thread (+ alloc *gtype-basic-offset*)) + ) + ) ))) ;; set up the type manually, as we allocated the memory manually @@ -246,10 +246,10 @@ "This is likely a defbehavior for process. Pops a single stack frame, if there is one." (rlet ((self :reg r13 :type process)) - (when (-> self stack-frame-top) - (set! (-> self stack-frame-top) (-> self stack-frame-top next)) - ) - ) + (when (-> self stack-frame-top) + (set! (-> self stack-frame-top) (-> self stack-frame-top next)) + ) + ) ) @@ -263,79 +263,79 @@ (defun-debug stream<-process-mask (stream (mask int)) "Print out a process mask. This function may have been auto-generated?" - ; 24 + ; 24 (if (not (eq? 0 (logand mask (process-mask death)))) (format stream "death ")) - ; 23 + ; 23 (if (not (eq? 0 (logand mask (process-mask attackable)))) (format stream "attackable ")) - ; 22 + ; 22 (if (not (eq? 0 (logand mask (process-mask projectile)))) (format stream "projectile ")) - ; 21 + ; 21 (if (not (eq? 0 (logand mask (process-mask entity)))) (format stream "entity ")) - ; 20 + ; 20 (if (not (eq? 0 (logand mask (process-mask ambient)))) (format stream "ambient ")) - ; 19 + ; 19 (if (not (eq? 0 (logand mask (process-mask platform)))) (format stream "platform ")) - ; 18 + ; 18 (if (not (eq? 0 (logand mask (process-mask camera)))) (format stream "camera ")) - ; 17 + ; 17 (if (not (eq? 0 (logand mask (process-mask enemy)))) (format stream "enemy ")) - ; 16 + ; 16 (if (not (eq? 0 (logand mask (process-mask collectable)))) (format stream "collectable ")) - ; 15 + ; 15 (if (not (eq? 0 (logand mask (process-mask crate)))) (format stream "crate ")) - ; 14 + ; 14 (if (not (eq? 0 (logand mask (process-mask sidekick)))) (format stream "sidekick ")) - ; 13 + ; 13 (if (not (eq? 0 (logand mask (process-mask target)))) (format stream "target ")) - ; 12 + ; 12 (if (not (eq? 0 (logand mask (process-mask movie-subject)))) (format stream "movie-subject ")) - ; 11 + ; 11 (if (not (eq? 0 (logand mask (process-mask movie)))) (format stream "movie ")) - ; 10 + ; 10 (if (not (eq? 0 (logand mask (process-mask going)))) (format stream "going ")) - ; 9 + ; 9 (if (not (eq? 0 (logand mask (process-mask heap-shrunk)))) (format stream "heap-shrunk ")) - ; 8 + ; 8 (if (not (eq? 0 (logand mask (process-mask process-tree)))) (format stream "process-tree ")) - ; 7 + ; 7 (if (not (eq? 0 (logand mask (process-mask sleep-code)))) (format stream "sleep-code ")) - ; 6 + ; 6 (if (not (eq? 0 (logand mask (process-mask sleep)))) (format stream "sleep ")) - ; 5 + ; 5 (if (not (eq? 0 (logand mask (process-mask actor-pause)))) (format stream "actor-pause ")) - ; 4 + ; 4 (if (not (eq? 0 (logand mask (process-mask progress)))) (format stream "progress ")) - ; 3 + ; 3 (if (not (eq? 0 (logand mask (process-mask menu)))) (format stream "menu ")) - ; 2 + ; 2 (if (not (eq? 0 (logand mask (process-mask pause)))) (format stream "pause ")) - ; 1 + ; 1 (if (not (eq? 0 (logand mask (process-mask draw)))) (format stream "draw ")) - ; 0 + ; 0 (if (not (eq? 0 (logand mask (process-mask execute)))) (format stream "execute ")) ) @@ -462,11 +462,11 @@ ;; print all objects on the process heap (protect (*print-column*) - (+! *print-column* *tab-size*) - (format #t "----~%") - (inspect-process-heap obj) - (format #t "----~%") - ) + (+! *print-column* *tab-size*) + (format #t "----~%") + (inspect-process-heap obj) + (format #t "----~%") + ) (format #t "~Tallocated-length: ~D~%" (-> obj allocated-length)) (format #t "~Tstack[~D] @ #x~X~%" (-> obj allocated-length) (-> obj stack)) @@ -515,7 +515,7 @@ To make sure this happens, all ops should be asm ops and we should have no GOAL expressions." (declare (asm-func none) - ;(print-asm) + ;(print-asm) ) (rlet ((sp :reg rsp :type uint) (off :reg r15 :type uint) @@ -525,29 +525,29 @@ (s3 :reg r11 :type uint) (s4 :reg r12 :type uint) ) - ;; get the kernel stack pointer as a GOAL pointer (won't use a temp reg) - (.load-sym :sext #f sp *kernel-sp*) - ;; convert it back to a real pointer - (.add sp off) - - ;; restore saved registers... - ;; without coloring system because this is "cheating" and modifying saved registers without backing up. - (.pop :color #f s4) - (.pop :color #f s3) - (.pop :color #f s2) - (.pop :color #f s1) - (.pop :color #f s0) - ;; return to the kernel function that called the user code - ;; rax should still contain the return value. - (.ret) - ) + ;; get the kernel stack pointer as a GOAL pointer (won't use a temp reg) + (.load-sym :sext #f sp *kernel-sp*) + ;; convert it back to a real pointer + (.add sp off) + + ;; restore saved registers... + ;; without coloring system because this is "cheating" and modifying saved registers without backing up. + (.pop :color #f s4) + (.pop :color #f s3) + (.pop :color #f s2) + (.pop :color #f s1) + (.pop :color #f s0) + ;; return to the kernel function that called the user code + ;; rax should still contain the return value. + (.ret) + ) ) (defun return-from-thread-dead () "Like return from thread, but we clean up our process with deactivate first. The return register is not preserved here, instead we return the value of deactivate" (declare (asm-func none) - ;(print-asm) + ;(print-asm) ) (rlet ((pp :reg r13 :type process) (sp :reg rsp :type uint) @@ -558,24 +558,24 @@ (s3 :reg r11 :type uint) (s4 :reg r12 :type uint) ) - - ;; first call the deactivate method. (todo - is the stack properly aligned for this?) - (deactivate pp) - ;; get the kernel stack pointer as a GOAL pointer - (.load-sym :sext #f sp *kernel-sp*) - ;; convert it back to a real pointer - (.add sp off) - - ;; restore saved registers... - ;; without coloring system because this is "cheating". - (.pop :color #f s4) - (.pop :color #f s3) - (.pop :color #f s2) - (.pop :color #f s1) - (.pop :color #f s0) - ;; return to the kernel function that called the user code - (.ret) - ) + + ;; first call the deactivate method. (todo - is the stack properly aligned for this?) + (deactivate pp) + ;; get the kernel stack pointer as a GOAL pointer + (.load-sym :sext #f sp *kernel-sp*) + ;; convert it back to a real pointer + (.add sp off) + + ;; restore saved registers... + ;; without coloring system because this is "cheating". + (.pop :color #f s4) + (.pop :color #f s3) + (.pop :color #f s2) + (.pop :color #f s1) + (.pop :color #f s0) + ;; return to the kernel function that called the user code + (.ret) + ) ) (defun reset-and-call ((obj thread) (func function)) @@ -585,7 +585,7 @@ NOTE: this should only be done from the kernel, running on the kernel's stack." (declare (asm-func object) - ;(print-asm) + ;(print-asm) ) (rlet ((pp :reg r13 :type process) @@ -598,37 +598,37 @@ (s4 :reg r12 :type uint) (temp :reg rax :type uint) ) - - ;; set up the process pointer - (set! pp (-> obj process)) - ;; mark the process as running and set its top thread - (set! (-> pp status) 'running) - (set! (-> pp top-thread) obj) - - ;; save the current kernel regs - (.push :color #f s0) - (.push :color #f s1) - (.push :color #f s2) - (.push :color #f s3) - (.push :color #f s4) - - ;; make rsp a GOAL pointer - (.sub sp off) - ;; and store it - (set! *kernel-sp* (the pointer sp)) ;; todo, asm form here? - - ;; setup the rsp for the new thread - (set! sp (the uint (-> obj stack-top))) - (.add sp off) - - ;; push the return trampoline to the stack for the user code to return to - (set! temp (the uint return-from-thread)) - (.add temp off) - (.push temp) ;; stack now 16 + 8 aligned - ;; and call the function! - (.add func off) - (.jr func) - ) + + ;; set up the process pointer + (set! pp (-> obj process)) + ;; mark the process as running and set its top thread + (set! (-> pp status) 'running) + (set! (-> pp top-thread) obj) + + ;; save the current kernel regs + (.push :color #f s0) + (.push :color #f s1) + (.push :color #f s2) + (.push :color #f s3) + (.push :color #f s4) + + ;; make rsp a GOAL pointer + (.sub sp off) + ;; and store it + (set! *kernel-sp* (the pointer sp)) ;; todo, asm form here? + + ;; setup the rsp for the new thread + (set! sp (the uint (-> obj stack-top))) + (.add sp off) + + ;; push the return trampoline to the stack for the user code to return to + (set! temp (the uint return-from-thread)) + (.add temp off) + (.push temp) ;; stack now 16 + 8 aligned + ;; and call the function! + (.add func off) + (.jr func) + ) ) @@ -665,19 +665,19 @@ (xmm14 :reg xmm14 :class fpr) (xmm15 :reg xmm15 :class fpr) ) - + ;; get the return address pushed by "call" in the suspend. (.pop temp) ;; convert to a GOAL address (.sub temp off) ;; store return address in thread (set! (-> obj pc) (the pointer temp)) - + ;; convert our stack pointer to a GOAL address (.sub sp off) ;; store in thread. (set! (-> obj sp) (the pointer sp)) - + ;; back up registers (.mov :color #f temp s0) (set! (-> obj rreg 0) temp) @@ -689,7 +689,7 @@ (set! (-> obj rreg 3) temp) (.mov :color #f temp s4) (set! (-> obj rreg 4) temp) - + ;; back up fprs (.mov :color #f temp xmm8) (set! (-> obj freg 0) (the-as float temp)) @@ -708,14 +708,14 @@ (.mov :color #f temp xmm15) (set! (-> obj freg 7) (the-as float temp)) - - + + ;; get our process (let ((proc (-> obj process))) (when (> (process-stack-used proc) (-> obj stack-size)) (break) ;; too much stack has been used and we can't suspend! ) - + ;; mark the process as suspended and copy the stack (set! (-> proc status) 'suspended) (let ((cur (the (pointer uint64) (-> obj stack-top))) @@ -728,15 +728,15 @@ ) ) ) - + ;; actually setting pp to 0 (set! obj (the cpu-thread 0)) - + ;; get the kernel stack pointer as a GOAL pointer (.load-sym :sext #f sp *kernel-sp*) ;; convert it back to a real pointer (.add sp off) - + ;; restore saved registers... ;; without coloring system because this is "cheating". (.pop :color #f s4) @@ -781,25 +781,25 @@ (xmm14 :reg xmm14 :class fpr) (xmm15 :reg xmm15 :class fpr) ) - + ;; save the current kernel regs (.push :color #f s0) (.push :color #f s1) (.push :color #f s2) (.push :color #f s3) (.push :color #f s4) - + ;; make rsp a GOAL pointer (.sub sp off) ;; and store it (set! *kernel-sp* (the pointer sp)) ;; todo, asm form here? - + ;; temp, stash thread in process-pointer (set! obj thread-to-resume) - + ;; set stack pointer for the thread. leave it as a GOAL pointer for now.. (set! sp (the uint (-> obj sp))) - + ;; restore the stack (sp is a GOAL pointer) (let ((cur (the (pointer uint64) (-> obj stack-top))) (restore (&+ (the (pointer uint64) (-> obj stack)) (-> obj stack-size))) @@ -810,14 +810,14 @@ (set! (-> cur) (-> restore)) ) ) - + ;; offset sp after we're done using it as a GOAL pointer. (.add sp off) - + ;; setup process (set! (-> (-> obj process) top-thread) obj) (set! (-> (-> obj process) status) 'running) - + ;; restore reg (set! temp (-> obj rreg 0)) (.mov :color #f s0 temp) @@ -850,7 +850,7 @@ ;; expects to receive 7 values from the cpu thread's rregs. ;; usually rreg holds saved registers, but on the first resume after ;; a set-to-run, they hold arguments, and set-to-run-bootstrap copies them. - + ;; We only have 5 saved regs, so we need to cheat and directly pass ;; two values in other registers ;; so we load the a4/a5 argument registers with rreg 5 and rreg 6 @@ -860,11 +860,11 @@ (.mov a4 temp) (set! temp (-> obj rreg 6)) (.mov a5 temp) - + ;; get the resume address (set! temp (the uint (-> obj pc))) (.add temp off) - + ;; setup the process (set! obj (the cpu-thread (-> obj process))) ;; resume! @@ -878,7 +878,7 @@ ;; Process Dead Pool ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -; a dead-pool is a collection of processes of fixed size that you can get processes from. + ; a dead-pool is a collection of processes of fixed size that you can get processes from. (define-extern *debug-dead-pool* dead-pool-heap) @@ -930,15 +930,15 @@ (cond (proc - ;; success! set our type and return. - (set! (-> (-> proc) type) type-to-make) - (the process (-> proc)) ;; cast from process-tree to process. - ) + ;; success! set our type and return. + (set! (-> (-> proc) type) type-to-make) + (the process (-> proc)) ;; cast from process-tree to process. + ) (else - (format 0 "WARNING: ~A ~A could not be allocated, because ~A was empty.~%" - type-to-make (as-process proc) (-> obj name)) - (the process #f) - ) + (format 0 "WARNING: ~A ~A could not be allocated, because ~A was empty.~%" + type-to-make (as-process proc) (-> obj name)) + (the process #f) + ) ) ) ) @@ -968,8 +968,8 @@ (defmethod new dead-pool-heap ((allocation symbol) (type-to-make type) (name basic) (allocated-length int) (heap-size int)) "Create a new dead pool heap. It will support allocated-length processes and have a total heap size of heap-size" (let ((obj (object-new allocation type-to-make (+ (the int (-> type-to-make size)) - (align16 (* allocated-length 12)) - heap-size)))) + (align16 (* allocated-length 12)) + heap-size)))) (set! (-> obj name) name) (set! (-> obj mask) (process-mask process-tree)) (set! (-> obj allocated-length) allocated-length) @@ -1020,8 +1020,8 @@ ;; start of proc end of type data process's heap basic offset ) (else - (-> obj heap base) - ) + (-> obj heap base) + ) ) ) @@ -1042,10 +1042,10 @@ ) ) (else - (if (-> rec next) - (&- (-> rec next process) (&+ (-> obj heap base) *gtype-basic-offset*)) - (&- (-> obj heap top) (-> obj heap base))) - ) + (if (-> rec next) + (&- (-> rec next process) (&+ (-> obj heap base) *gtype-basic-offset*)) + (&- (-> obj heap top) (-> obj heap base))) + ) ) ) ) @@ -1054,7 +1054,7 @@ "Start at the given record and find the closest gap after it. Returns the rec which has the gap after it. If no gaps, returns the last rec." (while (and (-> rec next) (zero? (gap-size obj rec))) - ; no gap here! + ; no gap here! (set! rec (-> rec next)) ) rec @@ -1116,9 +1116,9 @@ (defmethod memory-used dead-pool-heap ((obj dead-pool-heap)) "Get the amount of memory used. This includes gaps between processes." (if (-> obj last) - ; we have at least one process, get the not-last-gap memory + ; we have at least one process, get the not-last-gap memory (- (memory-total obj) (gap-size obj (-> obj last))) - ; no processes. + ; no processes. 0 ) ) @@ -1132,9 +1132,9 @@ "Get the total memory free." (let ((top (-> obj heap top))) (if (-> obj last) - ; get the last gap size + ; get the last gap size (gap-size obj (-> obj last)) - ; otherwise just the whole heap. + ; otherwise just the whole heap. (the int (&- top (-> obj heap base))) ) ) @@ -1148,7 +1148,7 @@ (defmethod find-gap-by-size dead-pool-heap ((obj dead-pool-heap) (size int)) "Find a gap which will fit at least size bytes. Returns the rec for the proc before the gap. Will return a #f rec if there's no gap big enough." - ; start our search at first-gap + ; start our search at first-gap (let ((rec (-> obj first-gap))) (while (and rec (< (gap-size obj rec) size)) ;; nope, not big enough. @@ -1228,25 +1228,25 @@ ) (else - ;; allocation failed! try again on the debug heap if we're debugging. - (when (and *debug-segment* (not (eq? obj *debug-dead-pool*))) - (set! proc (get-process *debug-dead-pool* type-to-make stack-size)) - (when (and proc *vis-boot*) - (format 0 "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%" type-to-make proc (-> obj name))) - ) - - ) + ;; allocation failed! try again on the debug heap if we're debugging. + (when (and *debug-segment* (not (eq? obj *debug-dead-pool*))) + (set! proc (get-process *debug-dead-pool* type-to-make stack-size)) + (when (and proc *vis-boot*) + (format 0 "WARNING: ~A ~A had to be allocated from the debug pool, because ~A was empty.~%" type-to-make proc (-> obj name))) + ) + + ) ) (cond (proc - ;; success! set type and return. - (set! (-> proc type) type-to-make) - ) + ;; success! set type and return. + (set! (-> proc type) type-to-make) + ) (else - ;; failure. complain. - (format 0 "WARNING: ~A ~A could not be allocated, because ~A was empty.~%" type-to-make proc (-> obj name)) - ) + ;; failure. complain. + (format 0 "WARNING: ~A ~A could not be allocated, because ~A was empty.~%" type-to-make proc (-> obj name)) + ) ) proc) @@ -1294,9 +1294,9 @@ (set! (-> rec next prev) (-> rec prev)) ) (else - ;; we were last, update that. - (set! (-> obj last) (-> rec prev)) - ) + ;; we were last, update that. + (set! (-> obj last) (-> rec prev)) + ) ) ;; insert at the front of the dead list. @@ -1376,7 +1376,7 @@ ;; and do compaction! (countdown (ii count) - + ;; first try to shrink a heap. (let ((shrink (-> obj first-shrink))) (when (not shrink) @@ -1388,7 +1388,7 @@ (shrink-heap obj (-> shrink process)) ) ) - + ;; now find the first gap (let ((gap (-> obj first-gap))) ;; and the thing after it @@ -1401,7 +1401,7 @@ ;; bug! (break) ) - + ;; try shrinking before relocating. (shrink-heap obj proc) ;; relocate! @@ -1429,34 +1429,34 @@ (< (the int (gap-location obj rec)) (the int (gap-location obj (-> obj first-gap)))) ) (set! (-> obj first-gap) (-> rec prev))) - + (when (eq? (-> obj first-shrink) rec) (set! (-> obj first-shrink) (-> rec prev)) (when (not (-> obj first-shrink process)) (set! (-> obj first-shrink) #f)) ) - + (set! (-> rec prev next) (-> rec next)) (cond ((-> rec next) (set! (-> rec next prev) (-> rec prev)) ) (else - (set! (-> obj last) (-> rec prev)) - ) + (set! (-> obj last) (-> rec prev)) + ) ) - + (let* ((insert (-> obj last)) (next (-> insert next)) ) - + (set! (-> insert next) rec) (set! (-> rec next) next) (when next (set! (-> next prev) rec)) (set! (-> rec prev) insert) - + (set! (-> obj last) rec) (set! (-> rec process) (relocate (-> rec process) (the int (&- (gap-location obj insert) (the int (&- (-> rec process) *gtype-basic-offset*)))))) @@ -1491,7 +1491,7 @@ "Look up a process with not the given name." (set! *global-search-name* (the basic name)) (the process (search-process-tree pool (lambda ((var process)) - (not (name= (-> var name) *global-search-name*))))) + (not (name= (-> var name) *global-search-name*))))) ) (defun process-count ((this process-tree)) @@ -1515,7 +1515,6 @@ (defun kill-by-type (type (pool process-tree)) "Call deactivate on all processes with the given type" - (break) ; this is sketchy. (set! *global-search-name* (the basic type)) (let ((proc (the process-tree #f))) (while (set! proc (search-process-tree pool (lambda ((var process)) @@ -1537,12 +1536,11 @@ (defun kill-not-type (type (pool process-tree)) "Call deactivate on all prcesses that don't match the given type" - (break) ;; this function is weird. (set! *global-search-name* (the basic type)) (let ((proc (the process-tree #f))) (while (set! proc (search-process-tree pool (lambda ((var process)) (!= (the type *global-search-name*) - (-> var type))))) + (-> var type))))) (deactivate proc) ) ) @@ -1568,17 +1566,17 @@ ;; stop. ) (else - ;; iterate through brothers - (let ((brother (-> obj child))) - (while brother - ;; kinda weird, we use the brother from _before_ recursing. - (let ((old-brother (-> (-> brother) brother))) - (iterate-process-tree (-> brother) func context) - (set! brother old-brother) - ) - ) - ) - ) + ;; iterate through brothers + (let ((brother (-> obj child))) + (while brother + ;; kinda weird, we use the brother from _before_ recursing. + (let ((old-brother (-> (-> brother) brother))) + (iterate-process-tree (-> brother) func context) + (set! brother old-brother) + ) + ) + ) + ) ) ret ) @@ -1663,101 +1661,96 @@ (execute-process-tree - *active-pool* - (lambda ((obj process)) - ;(format 0 "Call to dispatcher lambda!~%") - (let ((context *kernel-context*)) - (cond - ((or (eq? (-> obj status) 'waiting-to-run) - (eq? (-> obj status) 'suspended)) - - ;; we should run! - ;; set current process to us - (set! (-> context current-process) obj) - - ;; update pause junk for this run - (cond - ((process-mask? (-> obj mask) pause) - ;; we're paused. - (set! *stdcon* *stdcon1*) - (set! *debug-draw-pauseable* #t) - ) - (else - (set! *stdcon* *stdcon0*) - (set! *debug-draw-pauseable* #f) + *active-pool* + (lambda ((obj process)) + ;(format 0 "Call to dispatcher lambda!~%") + (let ((context *kernel-context*)) + (cond + ((or (eq? (-> obj status) 'waiting-to-run) + (eq? (-> obj status) 'suspended)) + + ;; we should run! + ;; set current process to us + (set! (-> context current-process) obj) + + ;; update pause junk for this run + (cond + ((process-mask? (-> obj mask) pause) + ;; we're paused. + (set! *stdcon* *stdcon1*) + (set! *debug-draw-pauseable* #t) + ) + (else + (set! *stdcon* *stdcon0*) + (set! *debug-draw-pauseable* #f) + ) + ) + + ;; TRANS + (cond + ((-> obj trans-hook) + ;; we have a trans hook defined. let's create a thread and run it. we can reuse the stack of the main-thread + ;; it is safe to do this because the main-thread is currently suspended or hasn't run yet. + (let ((trans (new 'process 'cpu-thread obj 'trans PROCESS_STACK_SAVE_SIZE (-> obj main-thread stack-top)))) + ;; call the function in the thread. + (reset-and-call trans (-> obj trans-hook)) + ;; remove the cpu-thread + (delete trans) + ;; check for deadness + (when (eq? (-> obj status) 'dead) + (set! (-> context current-process) #f) + (return-from #f 'dead) + ) ) ) - - ;; TRANS - (cond - ((-> obj trans-hook) - ;; we have a trans hook defined. let's create a thread and run it. we can reuse the stack of the main-thread - ;; it is safe to do this because the main-thread is currently suspended or hasn't run yet. - ;; hack process -> global new todo - (let ((trans (new 'global 'cpu-thread obj 'trans PROCESS_STACK_SAVE_SIZE (-> obj main-thread stack-top)))) - ;; call the function in the thread. - (reset-and-call trans (-> obj trans-hook)) - ;; remove the cpu-thread - (delete trans) - ;; check for deadness - (when (eq? (-> obj status) 'dead) - (set! (-> context current-process) #f) - (return-from #f 'dead) + ) + + ;; MAIN CODE + (if (process-mask? (-> obj mask) sleep-code) + ;; we're sleeping. Move us to suspended, in case we were in waiting to run. + (set! (-> obj status) 'suspended) + + ;; not sleeping. call resume hook + ((-> obj main-thread resume-hook) (-> obj main-thread)) + + ) + ;; check for deadness + (cond + ((eq? (-> obj status) 'dead) + ;; oops we died. return 'dead + (set! (-> context current-process) #f) + 'dead + ) + (else + ;; not dead. + ;; POST CODE + (cond + ((-> obj post-hook) + (let ((post (new 'process 'cpu-thread obj 'post PROCESS_STACK_SAVE_SIZE *kernel-dram-stack*))) + (reset-and-call post (-> obj post-hook)) + (delete post) + (when (eq? (-> obj status) 'dead) + ;; oops we died. + (set! (-> context current-process) #f) + (return-from #f 'dead) + ) + (set! (-> obj status) 'suspended) ) ) - ) - ) - - ;; MAIN CODE - (if (process-mask? (-> obj mask) sleep-code) - ;; we're sleeping. Move us to suspended, in case we were in waiting to run. - (set! (-> obj status) 'suspended) - - ;; not sleeping. call resume hook - ((-> obj main-thread resume-hook) (-> obj main-thread)) - - ) - ;; check for deadness - (cond - ((eq? (-> obj status) 'dead) - ;; oops we died. return 'dead - (set! (-> context current-process) #f) - 'dead - ) - (else - ;; not dead. - ;; POST CODE - (cond - ((-> obj post-hook) - ;; hack process -> global new todo - (let ((post (new 'global 'cpu-thread obj 'post PROCESS_STACK_SAVE_SIZE *kernel-dram-stack*))) - (reset-and-call post (-> obj post-hook)) - (delete post) - (when (eq? (-> obj status) 'dead) - ;; oops we died. - (set! (-> context current-process) #f) - (return-from #f 'dead) - ) - (set! (-> obj status) 'suspended) - ) - ) - ) - (set! (-> context current-process) #f) - #f ) + (set! (-> context current-process) #f) + #f ) - ) - - ((eq? (-> obj status) 'dead) - 'dead) + ) ) - ) - ) - *kernel-context* - ) - - ;; todo, remove this and replace it with the rest of the kernel dispatcher. - (set! *listener-function* (the (function object) #f)) + + ((eq? (-> obj status) 'dead) + 'dead) + ) + ) + ) + *kernel-context* + ) ) (define-extern inspect-process-tree (function process-tree int int symbol process-tree)) @@ -1768,17 +1761,17 @@ ;; print us (cond (detail - (format #t "__________________~%") - ;; this is here, but I removed it because it prints at the wrong indent and looks weird. - ;(format #t "~S~A~%" (if (zero? level) "" "+---") obj) - (protect (*print-column*) - (set! *print-column* (the binteger (* level 4))) - (inspect obj) - ) - ) + (format #t "__________________~%") + ;; this is here, but I removed it because it prints at the wrong indent and looks weird. + ;(format #t "~S~A~%" (if (zero? level) "" "+---") obj) + (protect (*print-column*) + (set! *print-column* (the binteger (* level 4))) + (inspect obj) + ) + ) (else - (format #t "~S~A~%" (if (zero? level) "" "+---") obj) - ) + (format #t "~S~A~%" (if (zero? level) "" "+---") obj) + ) ) ;; print our children @@ -1806,7 +1799,7 @@ ) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Stack Frame Stuff (TODO) +;; Stack Frame Stuff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; The GOAL kernel supports dynamic throw and catch. @@ -1841,7 +1834,7 @@ (xmm14 :reg xmm14 :class fpr) (xmm15 :reg xmm15 :class fpr) ) - + ;; we treat the allocation as an address. (let ((obj (the catch-frame (&+ allocation *gtype-basic-offset*)))) ;; setup catch frame @@ -1854,13 +1847,13 @@ (.sub temp off) ;; store it (set! (-> obj ra) (the int temp)) - + ;; todo, do we need a stack offset here? ;; remember the stack pointer (set! temp sp) (.sub temp off) (set! (-> obj sp) (the int temp)) - + ;; back up registers we care about (.mov :color #f temp s0) (set-u128-as-u64! (-> obj rreg 0) temp) @@ -1889,18 +1882,18 @@ (set! (-> obj freg 6) (the-as float temp)) (.mov :color #f temp xmm15) (set! (-> obj freg 7) (the-as float temp)) - + ;; push this stack frame (set! (-> obj next) (-> pp stack-frame-top)) (set! (-> pp stack-frame-top) obj) - + ;; help coloring, it isn't smart enough to realize it's "safe" to use these registers. (.push :color #f s3) (.push :color #f s2) (.push :color #f s2) (set! s3 (the uint func)) (set! s2 param-block) - + ;; todo - are we aligned correctly here? (let ((ret ((the-super-u64-fucntion s3) (-> s2 0) @@ -1948,10 +1941,10 @@ (xmm14 :reg xmm14 :class fpr) (xmm15 :reg xmm15 :class fpr) ) - + ;; pop everything we threw past (set! (-> pp stack-frame-top) (-> obj next)) - + ;; restore regs we care about. (set-u64-from-u128! temp (-> obj rreg 0)) (.mov :color #f s0 temp) @@ -1980,17 +1973,17 @@ (.mov :color #f xmm14 temp-float) (set! temp-float (-> obj freg 7)) (.mov :color #f xmm15 temp-float) - + ;; set stack pointer (set! sp (the uint (-> obj sp))) (.add sp off) - + ;; overwrite our return address (.pop temp) (set! temp (the uint (-> obj ra))) (.add temp off) (.push temp) - + ;; load the return register (.mov temp value) (.ret) @@ -2000,22 +1993,22 @@ (defun throw ((name symbol) value) "Dynamic throw." (rlet ((pp :reg r13 :type process)) - (let ((cur (-> pp stack-frame-top))) - (while cur - (when (and (eq? (-> cur name) name) (eq? (-> cur type) catch-frame)) - ;; match! - - (throw-dispatch (the catch-frame cur) value) - ) - - (if (eq? (-> cur type) protect-frame) - ;; call the cleanup function - ((-> (the protect-frame cur) exit)) - ) - (set! cur (-> cur next)) - ) + (let ((cur (-> pp stack-frame-top))) + (while cur + (when (and (eq? (-> cur name) name) (eq? (-> cur type) catch-frame)) + ;; match! + + (throw-dispatch (the catch-frame cur) value) ) + + (if (eq? (-> cur type) protect-frame) + ;; call the cleanup function + ((-> (the protect-frame cur) exit)) + ) + (set! cur (-> cur next)) ) + ) + ) (format 0 "ERROR: throw could not find tag ~A~%" name) (break) ) @@ -2027,9 +2020,9 @@ (set! (-> obj exit) func) (rlet ((pp :reg r13 :type process)) - (set! (-> obj next) (-> pp stack-frame-top)) - (set! (-> pp stack-frame-top) obj) - ) + (set! (-> obj next) (-> pp stack-frame-top)) + (set! (-> pp stack-frame-top) obj) + ) obj ) ) @@ -2038,7 +2031,29 @@ ;; Tree Stuff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; todo previous-brother +(defun previous-brother ((proc process-tree)) + "Get the process p where (-> p brother) is proc. Unused" + (local-vars (parent (pointer process-tree)) + (child (pointer process-tree)) + ) + ;; look up the tree to find our parent + (set! parent (-> proc parent)) + (the-as process-tree + (when parent + ;; make sure we aren't the only child. + (set! child (-> parent 0 child)) + (if (= child proc) (return '#f)) + ;; iterate, until we find the one. + (while child + (if (= (-> child 0 brother) proc) (return child)) + (set! child (-> child 0 brother)) + ) + ;; nope, didn't find it. bad tree. + '#f + ) + ) + ) + (defun change-parent ((obj process-tree) (new-parent process-tree)) "Make obj a child of new-parent" @@ -2053,12 +2068,12 @@ (set! (-> (-> parent) child) (-> obj brother)) ;; otherwise, look through brothers to find us. (begin - (while (not (eq? (as-process (-> (-> proc) brother)) obj)) - (set! proc (-> (-> proc) brother)) - ) - ;; ok, got us, splice out of list. - (set! (-> (-> proc) brother) (-> obj brother)) - ) + (while (not (eq? (as-process (-> (-> proc) brother)) obj)) + (set! proc (-> (-> proc) brother)) + ) + ;; ok, got us, splice out of list. + (set! (-> (-> proc) brother) (-> obj brother)) + ) ) ) ) @@ -2071,9 +2086,113 @@ ) ) -;; todo change-brother -;; todo change-to-last-brother - +(defun change-brother ((arg0 process-tree) (arg1 process-tree)) + "Unused, and wrong. + It seems like this was written when processes store process-trees, not (pointer process-tree)." + (local-vars + (v1-4 (pointer process-tree)) + (a1-1 symbol) + (a2-1 (pointer process-tree)) + (a3-1 (pointer process-tree)) + (t0-0 (pointer process-tree)) + (t1-0 (pointer process-tree)) + (t1-3 (pointer process-tree)) + (t1-4 (pointer process-tree)) + (t1-7 (pointer process-tree)) + (t1-8 (pointer process-tree)) + (t1-12 (pointer process-tree)) + (t1-13 (pointer process-tree)) + (t1-17 (pointer process-tree)) + ) + (when (and arg0 (!= (-> arg0 brother) arg1) (!= arg0 arg1)) + (set! a2-1 (-> arg0 parent)) + (when a2-1 + (set! t0-0 (-> a2-1 0 child)) + (set! a3-1 '#f) + (set! v1-4 '#f) + (set! t1-0 t0-0) + (when (= (if t1-0 (-> t1-0 0 self)) arg0) + (set! a3-1 a2-1) + (set! t1-3 a3-1) + ) + (set! t1-4 t0-0) + (when (= (if t1-4 (-> t1-4 0 self)) arg1) + (set! v1-4 a2-1) + (set! t1-7 v1-4) + ) + (while (and (-> t0-0 0 brother) (or (not a3-1) (not v1-4))) + (set! t1-8 t0-0) + (when (= (-> (if t1-8 (-> t1-8 0 self)) brother) arg1) + (set! v1-4 t0-0) + (set! t1-12 v1-4) + ) + (set! t1-13 t0-0) + (when (= (-> (if t1-13 (-> t1-13 0 self)) brother) arg0) + (set! a3-1 t0-0) + (set! t1-17 a3-1) + ) + (set! t0-0 (-> t0-0 0 brother)) + ) + (if (or (not a3-1) (not v1-4)) + (return 0) + (if (= a3-1 a2-1) + (set! (-> a3-1 4) (the process-tree (-> arg0 brother))) ;; wrong + (set! (-> a3-1 3) (the process-tree (-> arg0 brother))) ;; wrong + ) + ) + (cond + ((= v1-4 a2-1) + (set! (-> arg0 brother) (the (pointer process-tree) (-> v1-4 4))) ;; wrong + (set! (-> v1-4 4) (the process-tree (-> arg0 ppointer))) ;; wrong + ) + (else + (set! (-> arg0 brother) (the (pointer process-tree) (-> v1-4 3))) + (set! (-> v1-4 3) (the process-tree (-> arg0 ppointer))) + ) + ) + ) + ) + (the-as process-tree arg0) + ) + +(defun change-to-last-brother ((arg0 process-tree)) + (local-vars + (v1-4 (pointer process-tree)) + (v1-8 symbol) + (a1-0 (pointer process-tree)) + (a1-5 symbol) + (a1-9 symbol) + ) + (when (and (-> arg0 brother) (-> arg0 parent)) + (set! a1-0 (-> arg0 parent)) + (set! v1-4 (-> a1-0 0 child)) + (cond + ((= (-> v1-4 0) arg0) + (set! (-> a1-0 0 child) (-> arg0 brother))) + (else + (while (!= (-> v1-4 0 brother 0) arg0) + (nop!) + (nop!) + (nop!) + (nop!) + (set! v1-4 (-> v1-4 0 brother)) + ) + (set! (-> v1-4 0 brother) (-> arg0 brother)) + ) + ) + (while (-> v1-4 0 brother) + (nop!) + (nop!) + (nop!) + (nop!) + (set! v1-4 (-> v1-4 0 brother)) + ) + (set! (-> v1-4 0 brother) (-> arg0 ppointer)) + (set! (-> arg0 brother) '#f) + ) + arg0 + ) + ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Process Control @@ -2106,8 +2225,7 @@ (set! (-> obj connection-list next1) #f) (set! (-> obj connection-list prev1) #f) - ;; todo global -> process - (let ((thread (new 'global 'cpu-thread obj 'code PROCESS_STACK_SAVE_SIZE stack-top))) + (let ((thread (new 'process 'cpu-thread obj 'code PROCESS_STACK_SAVE_SIZE stack-top))) (set! (-> obj main-thread) thread) ) @@ -2120,55 +2238,55 @@ this function will return. The idea is that you use this when you want to initialize a process NOW. This will then return the value of the function you called!" (rlet ((pp :reg r13 :type process)) - - (let ((param-array (new 'stack 'array 'uint64 6)) - ) - ;; copy params to the stack. - - (set! (-> param-array 0) (the uint64 a0)) - (set! (-> param-array 1) (the uint64 a1)) - (set! (-> param-array 2) (the uint64 a2)) - (set! (-> param-array 3) (the uint64 a3)) - (set! (-> param-array 4) (the uint64 a4)) - (set! (-> param-array 5) (the uint64 a5)) - - (let* ((old-pp pp) - (func-val (begin - ;; set the process - (set! pp obj) - ;; set us as initializing - (set! (-> pp status) 'initialize) - ;; run! - (the object (new 'stack 'catch-frame 'initialize func param-array)) - ))) - ;; the function returned, either through a throw or through actually returning. - ;; the status will give us a clue of what happened. - (cond - ((= (-> pp status) 'initialize) - ;; we returned and didn't change status. - (set! (-> pp status) 'initialize-dead) - ;; this means we died, and we should be deactivated. - (deactivate pp) - ) - ((= (-> pp status) 'initialize-go) - ;; we returned with a (suspend) or (go) ? not sure - ;; either way, we're ready for next time! - (set! (-> pp status) 'waiting-to-run) - (when (eq? (-> pp pool type) dead-pool-heap) - ;; we can shrink the heap now. - (shrink-heap (the dead-pool-heap (-> pp pool)) pp) - ) - ) - (else - (format 0 "GOT UNKNOWN INIT: ~A~%" (-> pp status)) - ) - ) - ;; restore the old pp - (set! pp old-pp) - func-val - ) + + (let ((param-array (new 'stack 'array 'uint64 6)) ) + ;; copy params to the stack. + + (set! (-> param-array 0) (the uint64 a0)) + (set! (-> param-array 1) (the uint64 a1)) + (set! (-> param-array 2) (the uint64 a2)) + (set! (-> param-array 3) (the uint64 a3)) + (set! (-> param-array 4) (the uint64 a4)) + (set! (-> param-array 5) (the uint64 a5)) + + (let* ((old-pp pp) + (func-val (begin + ;; set the process + (set! pp obj) + ;; set us as initializing + (set! (-> pp status) 'initialize) + ;; run! + (the object (new 'stack 'catch-frame 'initialize func param-array)) + ))) + ;; the function returned, either through a throw or through actually returning. + ;; the status will give us a clue of what happened. + (cond + ((= (-> pp status) 'initialize) + ;; we returned and didn't change status. + (set! (-> pp status) 'initialize-dead) + ;; this means we died, and we should be deactivated. + (deactivate pp) + ) + ((= (-> pp status) 'initialize-go) + ;; we returned with a (suspend) or (go) ? not sure + ;; either way, we're ready for next time! + (set! (-> pp status) 'waiting-to-run) + (when (eq? (-> pp pool type) dead-pool-heap) + ;; we can shrink the heap now. + (shrink-heap (the dead-pool-heap (-> pp pool)) pp) + ) + ) + (else + (format 0 "GOT UNKNOWN INIT: ~A~%" (-> pp status)) + ) + ) + ;; restore the old pp + (set! pp old-pp) + func-val ) + ) + ) ) (defun set-to-run-bootstrap () @@ -2178,7 +2296,7 @@ This stub remaps these saved registers to argument registers. It also creates a return trampoline to return-from-thread-dead" (declare (asm-func none) - ;(print-asm) + ;(print-asm) ) (rlet ((s0 :reg rbx :type uint) @@ -2195,21 +2313,21 @@ ) - (.mov temp return-from-thread-dead) - (.add temp off) - (.push temp) - - ;; stack is 16 + 8 aligned now - - (.mov :color #f a0 s1) - (.mov :color #f a1 s2) - (.mov :color #f a2 s3) - (.mov :color #f a3 s4) - - (.add :color #f s0 off) - (.jr :color #f s0) - - ) + (.mov temp return-from-thread-dead) + (.add temp off) + (.push temp) + + ;; stack is 16 + 8 aligned now + + (.mov :color #f a0 s1) + (.mov :color #f a1 s2) + (.mov :color #f a2 s3) + (.mov :color #f a3 s4) + + (.add :color #f s0 off) + (.jr :color #f s0) + + ) ) @@ -2220,7 +2338,7 @@ Once the function returns, the process deactivates." (let ((proc (-> thread process))) (set! (-> proc status) 'waiting-to-run) - + ;; we store arguments and the function to call in saved registers (set! (-> thread rreg 0) (the uint func)) (set! (-> thread rreg 1) (the uint a0)) @@ -2244,28 +2362,28 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (defmethod deactivate process-tree ((obj process-tree)) - ;; todo - (format 0 "CALL TO DEACTIVATE~%") (none) ) -;; todo defstate +;; The defstate macro isn't defined yet, so we do it manually. (define dead-state - (new 'static 'state - :name #f - :next #f - :exit #f - :code #f - :trans #f - :post #f - :enter #f - :event #f)) + (new 'static 'state + :name #f + :next #f + :exit #f + :code #f + :trans #f + :post #f + :enter #f + :event #f)) (set! (-> dead-state code) nothing) -;; hack +;; this is not yet defined. (define-extern entity-deactivate-handler (function process object none)) +(define entity-deactivate-handler (the (function process object none) nothing)) + (define-extern process-disconnect (function object none)) (defmethod deactivate process ((obj process)) @@ -2290,23 +2408,23 @@ ;; clean up stack frames the process is in. ;; first, set pp so the cleanup code thinks its running in the right process. (rlet ((pp :reg r13 :type process)) - (let ((old-pp pp)) - (set! pp obj) - (let ((cur (-> pp stack-frame-top))) - (while cur - (when (or - (= (-> cur type) protect-frame) - (= (-> cur type) state) - ) - ;; we're a state or protect-frame, we can exit. - ((-> (the protect-frame cur) exit)) - ) - (set! cur (-> cur next)) - ) + (let ((old-pp pp)) + (set! pp obj) + (let ((cur (-> pp stack-frame-top))) + (while cur + (when (or + (= (-> cur type) protect-frame) + (= (-> cur type) state) + ) + ;; we're a state or protect-frame, we can exit. + ((-> (the protect-frame cur) exit)) ) - (set! pp old-pp) + (set! cur (-> cur next)) ) ) + (set! pp old-pp) + ) + ) ;; hack - if this isn't defined yet, don't try it. (if (!= 0 (the uint process-disconnect)) @@ -2341,27 +2459,27 @@ ;; and return (with no deactivate) (let ((temp (the uint return-from-thread))) (rlet ((off :reg r15 :type uint)) - (+! temp off) - (.push temp) - (.ret) - ) + (+! temp off) + (.push temp) + (.ret) + ) ) ) ;; second case - we deactivated while initializing. ((eq? (-> obj status) 'initialize) ;; added this - ; (if (!= pp obj) - ; (format 0 "ERROR: deactivated a non-current initializing process!") - ; (break) - ; ) + ; (if (!= pp obj) + ; (format 0 "ERROR: deactivated a non-current initializing process!") + ; (break) + ; ) (set! (-> obj status) 'dead) (throw 'initialize #f) ) ) (set! (-> obj status) 'dead) ) - (none) + (none) ) @@ -2372,8 +2490,7 @@ (let ((obj (define *listener-process* (new 'global 'process 'listener 2048)))) (set! (-> obj status) 'ready) (set! (-> obj pid) 1) - ;; allocation symbol is actually process, but it's ignored so this is ok for now. - (set! (-> obj main-thread) (new 'global 'cpu-thread obj 'main 256 *kernel-dram-stack*)) + (set! (-> obj main-thread) (new 'process 'cpu-thread obj 'main 256 *kernel-dram-stack*)) ) ;; these are unknown @@ -2391,8 +2508,8 @@ (define *camera-master-dead-pool* (new 'global 'dead-pool 1 (* 8 1024) '*camera-master-dead-pool*)) (if *debug-segment* - (define *debug-dead-pool* (new 'debug 'dead-pool-heap '*debug-dead-pool* 768 (* 1024 1024))) - ) + (define *debug-dead-pool* (new 'debug 'dead-pool-heap '*debug-dead-pool* 768 (* 1024 1024))) + ) (define *nk-dead-pool* (new 'global 'dead-pool-heap '*nk-dead-pool* 768 PROCESS_HEAP_SIZE)) (define *default-dead-pool* (the dead-pool *nk-dead-pool*)) @@ -2418,26 +2535,3 @@ (change-parent (define *default-pool* (new 'global 'process-tree 'default-pool)) *active-pool*) (set! (-> *default-pool* mask) (process-mask pause menu progress process-tree)) - -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Temp Hacks -;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - -; (defun kernel-dispatcher () -; "Kernel Dispatcher Function. This gets called from the main loop in kboot.cpp's KernelCheckAndDispatch" - -; ;; check if we have a new listener function to run -; (when *listener-function* -; ;; we do! enable method-set for debug purposes -; (+! *enable-method-set* 1) - -; ;; execute and print result -; (let ((result (*listener-function*))) -; (format #t "~D~%" result) -; ) -; (+! *enable-method-set* -1) - -; ;; clear the pending function. -; (set! *listener-function* (the (function object) #f)) -; ) -; ) diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 9668ec051..118953404 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -876,7 +876,7 @@ Val* Compiler::compile_new(const goos::Object& form, const goos::Object& _rest, auto type = pair_car(*rest); rest = &pair_cdr(*rest); - if (allocation == "global" || allocation == "debug") { + if (allocation == "global" || allocation == "debug" || allocation == "process") { // allocate on a named heap return compile_heap_new(form, allocation, type, rest, env); } else if (allocation == "static") { diff --git a/test/decompiler/test_FormExpressionBuildLong.cpp b/test/decompiler/test_FormExpressionBuildLong.cpp index 963884256..444e36750 100644 --- a/test/decompiler/test_FormExpressionBuildLong.cpp +++ b/test/decompiler/test_FormExpressionBuildLong.cpp @@ -640,10 +640,8 @@ TEST_F(FormRegressionTest, ExprArrayMethod2) { " )\n" " )\n" " (else\n" - // todo - why doesn't this merge? - " (set! v1-40 (or (= v1-1 (quote uint128)) (= v1-1 (quote int128))))\n" " (cond\n" - " (v1-40\n" + " ((or (= v1-1 (quote uint128)) (= v1-1 (quote int128)))\n" " (set! s5-8 0)\n" " (while\n" " (< s5-8 (-> arg0 length))\n" @@ -1309,9 +1307,8 @@ TEST_F(FormRegressionTest, ExprArrayMethod3) { " )\n" " )\n" " (else\n" - " (set! v1-40 (or (= v1-1 (quote int128)) (= v1-1 (quote uint128))))\n" " (cond\n" - " (v1-40\n" + " ((or (= v1-1 (quote int128)) (= v1-1 (quote uint128)))\n" " (set! s5-8 0)\n" " (while\n" " (< s5-8 (-> arg0 length))\n" @@ -2092,16 +2089,11 @@ TEST_F(FormRegressionTest, ExprValid) { " (quote #f)\n" " )\n" " (else\n" - // todo - why isn't this compacted? - " (set!\n" - " v1-33\n" - " (and\n" - " (!= arg1 type)\n" - " (not (valid? (rtype-of arg0) type (quote #f) (quote #t) 0))\n" - " )\n" - " )\n" " (cond\n" - " (v1-33\n" + " ((and\t\n" + " (!= arg1 type)\t\n" + " (not (valid? (rtype-of arg0) type (quote #f) (quote #t) 0))\t\n" + " )\n" " (if\n" " arg2\n" " (format\n" @@ -2483,7 +2475,6 @@ TEST_F(FormRegressionTest, ExprStringToInt) { " (a0-5 symbol)\n" " (a1-8 (pointer uint8))\n" " (a1-14 uint)\n" - " (a1-16 symbol)\n" " (a1-20 uint)\n" " (a1-23 uint)\n" " (a1-33 symbol)\n" @@ -2529,15 +2520,11 @@ TEST_F(FormRegressionTest, ExprStringToInt) { " (set! a1-14 v0-0)\n" " )\n" " (else\n" - " (set!\n" - " a1-16\n" - " (and\n" - " (>= (-> a0-3 0) (the-as uint 97))\n" - " (>= (the-as uint 102) (-> a0-3 0))\n" - " )\n" - " )\n" " (cond\n" - " (a1-16\n" + " ((and\t\n" + " (>= (-> a0-3 0) (the-as uint 97))\t\n" + " (>= (the-as uint 102) (-> a0-3 0))\t\n" + " )\n" " (set! v0-0 (+ (+ (-> a0-3 0) -87) (the-as uint (shl v0-0 4))))\n" " (set! a1-20 v0-0)\n" " )\n" diff --git a/test/decompiler/test_gkernel_decomp.cpp b/test/decompiler/test_gkernel_decomp.cpp index 07cec3a02..dbc4b4707 100644 --- a/test/decompiler/test_gkernel_decomp.cpp +++ b/test/decompiler/test_gkernel_decomp.cpp @@ -534,8 +534,7 @@ TEST_F(FormRegressionTest, RemoveMethod3ProcessTree) { " (set! a0-5 (quote #t))\n" " (set! a1-4 \"~Tbrother: ~A~%\")\n" " (set! v1-2 (-> arg0 brother))\n" - " (set! a2-4 (if v1-2 (-> v1-2 0 self)))\n" - " (t9-4 a0-5 a1-4 a2-4)\n" + " (t9-4 a0-5 a1-4 (if v1-2 (-> v1-2 0 self)))\n" " (set! t9-5 format)\n" " (set! a0-6 (quote #t))\n" " (set! a1-5 \"~Tchild: ~A~%\")\n" @@ -2533,7 +2532,8 @@ TEST_F(FormRegressionTest, ExprMethod16DeadPoolHeap) { std::string expected = "(begin\n" " (set! s4-0 (memory-free arg0))\n" - " (set! f0-2 (/ (the float s4-0) (the float (memory-total arg0))))\n" + " (set! v1-2 (memory-total arg0))\n" + " (set! f0-2 (/ (the float s4-0) (the float v1-2)))" " (cond\n" " ((< f0-2 (l.f L346))\n" " (set! arg1 1000)\n"