[decompiler] small fixes for methods and more reference tests (#419)

* clean up method stuff, fix a few small bugs, and add references for easy -h files

* more small fixes and reference tests
This commit is contained in:
water111
2021-05-06 00:42:49 -04:00
committed by GitHub
parent 0a6602e320
commit 21fefa0aaa
41 changed files with 3427 additions and 220 deletions
+2 -6
View File
@@ -457,12 +457,8 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const {
auto method_id = (ro.offset - 16) / 4;
auto method_info = env.dts->ts.lookup_method(type_name, method_id);
std::vector<DerefToken> tokens;
tokens.push_back(DerefToken::make_field_name("methods-by-name"));
tokens.push_back(DerefToken::make_field_name(method_info.name));
auto source = pool.alloc_single_element_form<SimpleExpressionElement>(
nullptr, SimpleAtom::make_var(ro.var).as_expr(), m_my_idx);
return pool.alloc_single_element_form<DerefElement>(nullptr, source, false, tokens);
return pool.alloc_single_element_form<MethodOfTypeElement>(
nullptr, ro.var, input_type.get_type_objects_typespec(), method_info);
}
// todo structure method
+27
View File
@@ -1497,6 +1497,8 @@ std::string fixed_operator_to_string(FixedOperatorKind kind) {
return "!=";
case FixedOperatorKind::METHOD_OF_OBJECT:
return "method-of-object";
case FixedOperatorKind::METHOD_OF_TYPE:
return "method-of-type";
case FixedOperatorKind::NULLP:
return "null?";
case FixedOperatorKind::PAIRP:
@@ -2346,6 +2348,31 @@ void StackSpillValueElement::apply_form(const std::function<void(Form*)>&) {}
void StackSpillValueElement::collect_vars(RegAccessSet&, bool) const {}
void StackSpillValueElement::get_modified_regs(RegSet&) const {}
////////////////////////////////
// MethodOfTypeElement
///////////////////////////////
MethodOfTypeElement::MethodOfTypeElement(RegisterAccess type_reg,
const TypeSpec& type_at_decompile,
const MethodInfo& method_info)
: m_type_reg(type_reg), m_type_at_decompile(type_at_decompile), m_method_info(method_info) {}
goos::Object MethodOfTypeElement::to_form_internal(const Env& env) const {
return pretty_print::build_list("method-of-type", m_type_reg.to_form(env), m_method_info.name);
}
void MethodOfTypeElement::apply(const std::function<void(FormElement*)>& f) {
f(this);
}
void MethodOfTypeElement::apply_form(const std::function<void(Form*)>&) {}
void MethodOfTypeElement::collect_vars(RegAccessSet& vars, bool) const {
vars.insert(m_type_reg);
}
void MethodOfTypeElement::get_modified_regs(RegSet&) const {}
////////////////////////////////
// Utilities
////////////////////////////////
+28
View File
@@ -997,6 +997,10 @@ class DerefToken {
void apply_form(const std::function<void(Form*)>& f);
void get_modified_regs(RegSet& regs) const;
bool is_field_name(const std::string& name) const {
return m_kind == Kind::FIELD_NAME && m_name == name;
}
Kind kind() const { return m_kind; }
const std::string& field_name() const {
assert(m_kind == Kind::FIELD_NAME);
@@ -1038,6 +1042,7 @@ class DerefElement : public FormElement {
const Form* base() const { return m_base; }
Form* base() { return m_base; }
const std::vector<DerefToken>& tokens() const { return m_tokens; }
std::vector<DerefToken>& tokens() { return m_tokens; }
void set_base(Form* new_base);
void set_addr_of(bool is_addr_of) { m_is_addr_of = is_addr_of; }
@@ -1146,6 +1151,7 @@ class ConstantTokenElement : public FormElement {
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
const std::string& value() const { return m_value; }
private:
std::string m_value;
@@ -1365,6 +1371,28 @@ class StackSpillValueElement : public FormElement {
bool m_is_signed = false;
};
class MethodOfTypeElement : public FormElement {
public:
MethodOfTypeElement(RegisterAccess type_reg,
const TypeSpec& type_at_decompile,
const MethodInfo& method_info);
goos::Object to_form_internal(const Env& env) const override;
void apply(const std::function<void(FormElement*)>& f) override;
void apply_form(const std::function<void(Form*)>& f) override;
void collect_vars(RegAccessSet& vars, bool recursive) const override;
void update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) override;
void get_modified_regs(RegSet& regs) const override;
private:
RegisterAccess m_type_reg;
TypeSpec m_type_at_decompile;
MethodInfo m_method_info;
};
/*!
* A Form is a wrapper around one or more FormElements.
* This is done for two reasons:
+46 -58
View File
@@ -1677,8 +1677,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto actual_arg_type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto desired_arg_type = function_type.get_arg(arg_id + 1);
if (!env.dts->ts.tc(desired_arg_type, actual_arg_type)) {
arg_forms.push_back(
pool.alloc_single_element_form<CastElement>(nullptr, desired_arg_type, val));
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env));
} else {
arg_forms.push_back(val);
}
@@ -1694,8 +1693,7 @@ void FunctionCallElement::update_from_stack(const Env& env,
auto actual_arg_type = env.get_types_before_op(var.idx()).get(var.reg()).typespec();
auto desired_arg_type = function_type.get_arg(arg_id);
if (!env.dts->ts.tc(desired_arg_type, actual_arg_type)) {
arg_forms.push_back(
pool.alloc_single_element_form<CastElement>(nullptr, desired_arg_type, val));
arg_forms.push_back(cast_form(val, desired_arg_type, pool, env));
} else {
arg_forms.push_back(val);
}
@@ -1791,13 +1789,13 @@ void FunctionCallElement::update_from_stack(const Env& env,
{
// detect method calls:
// ex: ((-> pair methods-by-name new) (quote global) pair gp-0 a3-0)
// ex: ((method-of-type pair new) (quote global) pair gp-0 a3-0)
constexpr int type_for_method = 0;
constexpr int method_name = 1;
auto deref_matcher = Matcher::deref(
Matcher::any_symbol(type_for_method), false,
{DerefTokenMatcher::string("methods-by-name"), DerefTokenMatcher::any_string(method_name)});
auto deref_matcher = Matcher::op(
GenericOpMatcher::fixed(FixedOperatorKind::METHOD_OF_TYPE),
{Matcher::any_symbol(type_for_method), Matcher::any_constant_token(method_name)});
auto matcher = Matcher::op_with_rest(GenericOpMatcher::func(deref_matcher), {});
auto temp_form = pool.alloc_single_form(nullptr, new_form);
@@ -1893,13 +1891,13 @@ void FunctionCallElement::update_from_stack(const Env& env,
{
// detect method calls:
// ex: ((-> XXX methods-by-name new) (quote global) pair gp-0 a3-0)
// ex: ((method-of-type x new) (quote global) pair gp-0 a3-0)
constexpr int method_name = 0;
constexpr int type_source = 1;
auto deref_matcher = Matcher::deref(
Matcher::any(type_source), false,
{DerefTokenMatcher::string("methods-by-name"), DerefTokenMatcher::any_string(method_name)});
auto deref_matcher =
Matcher::op(GenericOpMatcher::fixed(FixedOperatorKind::METHOD_OF_TYPE),
{Matcher::any(type_source), Matcher::any_constant_token(method_name)});
auto matcher = Matcher::op_with_rest(GenericOpMatcher::func(deref_matcher), {});
auto temp_form = pool.alloc_single_form(nullptr, new_form);
@@ -1942,52 +1940,7 @@ void DerefElement::update_from_stack(const Env& env,
// merge nested ->'s
inline_nested();
if (m_tokens.size() >= 3) {
auto& method_name = m_tokens.at(m_tokens.size() - 1);
auto& mbn = m_tokens.at(m_tokens.size() - 2);
auto& type = m_tokens.at(m_tokens.size() - 3);
if (method_name.kind() == DerefToken::Kind::FIELD_NAME &&
mbn.kind() == DerefToken::Kind::FIELD_NAME && mbn.field_name() == "methods-by-name" &&
type.kind() == DerefToken::Kind::FIELD_NAME && type.field_name() == "type") {
std::string name = method_name.field_name();
m_tokens.pop_back();
m_tokens.pop_back();
m_tokens.pop_back();
if (m_tokens.empty()) {
auto method_op = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::METHOD_OF_OBJECT), m_base,
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, name));
result->push_back(method_op);
} else {
auto method_op = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::METHOD_OF_OBJECT),
pool.alloc_single_form(nullptr, this),
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, name));
result->push_back(method_op);
}
return;
}
}
// rewrite access to the method table to use method-of-object
// (-> <some-object> type methods-by-name <method-name>)
// (method-of-object <some-object> <method-name>)
auto get_method_matcher = Matcher::deref(
Matcher::any(0), false,
{DerefTokenMatcher::string("type"), DerefTokenMatcher::string("methods-by-name"),
DerefTokenMatcher::any_string(1)});
Form hack_form;
hack_form.elts() = {this};
auto mr = match(get_method_matcher, &hack_form);
if (mr.matched) {
auto method_op = pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::METHOD_OF_OBJECT), mr.maps.forms.at(0),
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, mr.maps.strings.at(1)));
result->push_back(method_op);
} else {
result->push_back(this);
}
result->push_back(this);
}
void DerefElement::inline_nested() {
@@ -3187,6 +3140,41 @@ void VectorFloatLoadStoreElement::push_to_stack(const Env&, FormPool&, FormStack
stack.push_form_element(this, true);
}
void MethodOfTypeElement::update_from_stack(const Env& env,
FormPool& pool,
FormStack& stack,
std::vector<FormElement*>* result,
bool allow_side_effects) {
mark_popped();
auto type = pop_to_forms({m_type_reg}, env, pool, stack, allow_side_effects).at(0);
auto type_as_deref = type->try_as_element<DerefElement>();
if (type_as_deref) {
if (type_as_deref->tokens().size() > 1 &&
type_as_deref->tokens().back().is_field_name("type")) {
type_as_deref->tokens().pop_back();
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::METHOD_OF_OBJECT),
std::vector<Form*>{type, pool.alloc_single_element_form<ConstantTokenElement>(
nullptr, m_method_info.name)}));
return;
} else if (type_as_deref->tokens().size() == 1 &&
type_as_deref->tokens().back().is_field_name("type")) {
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::METHOD_OF_OBJECT),
std::vector<Form*>{
type_as_deref->base(),
pool.alloc_single_element_form<ConstantTokenElement>(nullptr, m_method_info.name)}));
return;
}
}
result->push_back(pool.alloc_element<GenericElement>(
GenericOperator::make_fixed(FixedOperatorKind::METHOD_OF_TYPE),
std::vector<Form*>{type, pool.alloc_single_element_form<ConstantTokenElement>(
nullptr, m_method_info.name)}));
}
void SimpleAtomElement::update_from_stack(const Env&,
FormPool&,
FormStack&,
+19
View File
@@ -130,6 +130,13 @@ Matcher Matcher::while_loop(const Matcher& condition, const Matcher& body) {
return m;
}
Matcher Matcher::any_constant_token(int match_id) {
Matcher m;
m.m_kind = Kind::ANY_CONSTANT_TOKEN;
m.m_string_out_id = match_id;
return m;
}
bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out) const {
switch (m_kind) {
case Kind::ANY:
@@ -251,6 +258,18 @@ bool Matcher::do_match(Form* input, MatchResult::Maps* maps_out) const {
return false;
} break;
case Kind::ANY_CONSTANT_TOKEN: {
auto as_ct = input->try_as_element<ConstantTokenElement>();
if (as_ct) {
if (m_string_out_id != -1) {
maps_out->strings[m_string_out_id] = as_ct->value();
}
return true;
} else {
return false;
}
} break;
case Kind::CAST: {
auto as_cast = dynamic_cast<CastElement*>(input->try_as_single_element());
if (as_cast) {
+2
View File
@@ -46,6 +46,7 @@ class Matcher {
const Matcher& true_case,
const Matcher& false_case);
static Matcher while_loop(const Matcher& condition, const Matcher& body);
static Matcher any_constant_token(int match_id = -1);
enum class Kind {
ANY_REG, // matching any register
@@ -64,6 +65,7 @@ class Matcher {
SYMBOL,
IF_WITH_ELSE,
WHILE_LOOP,
ANY_CONSTANT_TOKEN,
INVALID
};
+1
View File
@@ -138,6 +138,7 @@ enum class FixedOperatorKind {
NEQ,
CONS,
METHOD_OF_OBJECT,
METHOD_OF_TYPE,
NULLP,
PAIRP,
NONE,
+16 -14
View File
@@ -5218,7 +5218,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -5238,7 +5238,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -5272,7 +5272,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -5299,7 +5299,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -5342,7 +5342,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -5376,7 +5376,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
(dummy-18 () none 18)
)
@@ -5470,7 +5470,6 @@
;; generic-h
;;;;;;;;;;;;;;;;
;; todo
(deftype gsf-vertex (structure)
((data uint32 8 :offset-assert 0)
(byte uint8 32 :offset 0)
@@ -5729,6 +5728,8 @@
:flag-assert #x900000100
)
(define-extern *gsf-buffer* gsf-buffer)
;;;;;;;;;;;;;
;; lights-h
;;;;;;;;;;;;;
@@ -6042,7 +6043,7 @@
(corner-count int32 :offset-assert 2080)
(temp-vecs vector 4 :inline :offset-assert 2096)
(mid-mask-ptrs pointer 36 :offset-assert 2160)
(mid-camera-masks ocean-mid-masks 36 :inline :offset-assert 2304)
(mid-camera-masks uint64 36 :offset-assert 2304)
(trans-mask-ptrs pointer 64 :offset-assert 2592)
(trans-camera-masks ocean-trans-mask 16 :inline :offset-assert 2848)
(trans-temp-masks ocean-trans-mask 16 :inline :offset-assert 2976)
@@ -6259,6 +6260,8 @@
:flag-assert #x900000110
)
(define-extern *ocean-wave-frames* (pointer uint32))
;;;;;;;;;;
;; sky-h
;;;;;;;;;;
@@ -8363,7 +8366,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -10924,7 +10927,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -10973,7 +10976,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -10995,7 +10998,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -11024,7 +11027,7 @@
(dummy-13 () none 13)
(dummy-14 () none 14)
(dummy-15 () none 15)
(dummy-16 () none 16)
(dummy-16 (_type_ object object) object 16)
(dummy-17 () none 17)
)
)
@@ -33730,7 +33733,6 @@
(define-extern *ocean-mid-masks-sunken* ocean-mid-masks) ;; unknown type
(define-extern *ocean-map-village1* ocean-map) ;; unknown type
(define-extern *ocean-spheres-village1* ocean-spheres) ;; unknown type
;;(define-extern *ocean-wave-frames* object) ;; unknown type
;;(define-extern sky-color-hour object) ;; unknown type
;;(define-extern sky-circle-data object) ;; unknown type
(define-extern *sky-drawn* symbol) ;; unknown type
@@ -270,28 +270,29 @@
],
"ocean-tables": [
["L26", "ocean-spheres", true],
["L18", "ocean-spheres", true],
// see comment in ocean-tables.gc
// ["L26", "ocean-spheres", true],
// ["L18", "ocean-spheres", true],
["L25", "ocean-colors", true],
["L17", "ocean-colors", true],
// ["L25", "ocean-colors", true],
// ["L17", "ocean-colors", true],
["L23", "ocean-near-indices", true],
["L15", "ocean-near-indices", true],
["L9", "ocean-near-indices", true],
["L22", "ocean-trans-indices", true],
["L14", "ocean-trans-indices", true],
["L8", "ocean-trans-indices", true],
["L21", "ocean-mid-indices", true],
["L13", "ocean-mid-indices", true],
["L7", "ocean-mid-indices", true],
["L19", "ocean-mid-masks", true],
["L11", "ocean-mid-masks", true],
["L5", "ocean-mid-masks", true],
// ["L23", "ocean-near-indices", true],
// ["L15", "ocean-near-indices", true],
// ["L9", "ocean-near-indices", true],
// ["L22", "ocean-trans-indices", true],
// ["L14", "ocean-trans-indices", true],
// ["L8", "ocean-trans-indices", true],
// ["L21", "ocean-mid-indices", true],
// ["L13", "ocean-mid-indices", true],
// ["L7", "ocean-mid-indices", true],
// ["L19", "ocean-mid-masks", true],
// ["L11", "ocean-mid-masks", true],
// ["L5", "ocean-mid-masks", true],
["L4", "ocean-map", true],
["L3", "ocean-map", true],
["L2", "ocean-map", true]
// ["L4", "ocean-map", true],
// ["L3", "ocean-map", true],
// ["L2", "ocean-map", true]
],
"ocean-frames": [["L1", "(pointer uint32)", true, 16384]],