Skip to content

Commit

Permalink
Support dir tpages (#671)
Browse files Browse the repository at this point in the history
* support dir tpages

* fix warnings and bad return

* one more try

* revive the offline test script

* fix this null bug
  • Loading branch information
water111 authored Jul 2, 2021
1 parent b96d865 commit 6366068
Show file tree
Hide file tree
Showing 36 changed files with 476 additions and 114 deletions.
24 changes: 18 additions & 6 deletions common/type_system/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ std::string reg_kind_to_string(RegClass kind) {
*/
bool MethodInfo::operator==(const MethodInfo& other) const {
return id == other.id && name == other.name && type == other.type &&
defined_in_type == other.defined_in_type && other.no_virtual == no_virtual;
defined_in_type == other.defined_in_type && other.no_virtual == no_virtual &&
other.overrides_method_type_of_parent == overrides_method_type_of_parent;
}

std::string MethodInfo::diff(const MethodInfo& other) const {
Expand All @@ -56,6 +57,11 @@ std::string MethodInfo::diff(const MethodInfo& other) const {
if (no_virtual != other.no_virtual) {
result += fmt::format("no_virtual: {} vs. {}\n", no_virtual, other.no_virtual);
}

if (overrides_method_type_of_parent != other.overrides_method_type_of_parent) {
result += fmt::format("overrides_method_type_of_parent: {} vs. {}\n",
overrides_method_type_of_parent, other.overrides_method_type_of_parent);
}
return result;
}

Expand Down Expand Up @@ -311,9 +317,11 @@ bool Type::get_my_method(int id, MethodInfo* out) const {
* defined specifically for this type or not.
*/
bool Type::get_my_last_method(MethodInfo* out) const {
if (!m_methods.empty()) {
*out = m_methods.back();
return true;
for (auto it = m_methods.rbegin(); it != m_methods.rend(); it++) {
if (!it->overrides_method_type_of_parent) {
*out = *it;
return true;
}
}
return false;
}
Expand All @@ -334,9 +342,13 @@ bool Type::get_my_new_method(MethodInfo* out) const {
* Add a method defined specifically for this type.
*/
const MethodInfo& Type::add_method(const MethodInfo& info) {
if (!m_methods.empty()) {
assert(m_methods.back().id + 1 == info.id);
for (auto it = m_methods.rbegin(); it != m_methods.rend(); it++) {
if (!it->overrides_method_type_of_parent) {
assert(it->id + 1 == info.id);
break;
}
}

m_methods.push_back(info);
return m_methods.back();
}
Expand Down
1 change: 1 addition & 0 deletions common/type_system/Type.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ struct MethodInfo {
TypeSpec type;
std::string defined_in_type;
bool no_virtual = false;
bool overrides_method_type_of_parent = false;

bool operator==(const MethodInfo& other) const;
bool operator!=(const MethodInfo& other) const { return !((*this) == other); }
Expand Down
15 changes: 11 additions & 4 deletions common/type_system/TypeFieldLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,13 @@ void try_reverse_lookup_other(const FieldReverseLookupInput& input,
FieldReverseMultiLookupOutput* output,
int max_count);

std::vector<FieldReverseLookupOutput::Token> parent_to_vector(const ReverseLookupNode* parent) {
if (!parent) {
return {};
}
return parent->to_vector();
}

/*!
* Handle a dereference of a pointer/boxed array. This can be:
* - just dereferencing a pointer
Expand Down Expand Up @@ -188,15 +195,15 @@ void try_reverse_lookup_array_like(const FieldReverseLookupInput& input,
// also just return the array
if (elt_idx == 0) {
if (boxed_array) {
auto vec = parent->to_vector();
auto vec = parent_to_vector(parent);
FieldReverseLookupOutput::Token tok;
tok.kind = FieldReverseLookupOutput::Token::Kind::FIELD;
tok.field_score = 0.0; // don't bother
tok.name = "data";
vec.push_back(tok);
output->results.emplace_back(false, array_data_type, vec);
} else {
auto parent_vector = parent->to_vector();
auto parent_vector = parent_to_vector(parent);
if (!parent_vector.empty()) {
output->results.emplace_back(false, input.base_type, parent_vector);
}
Expand Down Expand Up @@ -280,9 +287,9 @@ void try_reverse_lookup_inline_array(const FieldReverseLookupInput& input,

// can we just return the array?
if (expected_offset_into_elt == offset_into_elt && !input.deref.has_value() && elt_idx == 0) {
auto parent_vec = parent->to_vector();
auto parent_vec = parent_to_vector(parent);
if (!parent_vec.empty()) {
output->results.emplace_back(false, input.base_type, parent->to_vector());
output->results.emplace_back(false, input.base_type, parent_to_vector(parent));
}

if ((int)output->results.size() >= max_count) {
Expand Down
117 changes: 72 additions & 45 deletions common/type_system/TypeSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -477,8 +477,10 @@ int TypeSystem::get_load_size_allow_partial_def(const TypeSpec& ts) const {
MethodInfo TypeSystem::declare_method(const std::string& type_name,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts) {
return declare_method(lookup_type(make_typespec(type_name)), method_name, no_virtual, ts);
const TypeSpec& ts,
bool override_type) {
return declare_method(lookup_type(make_typespec(type_name)), method_name, no_virtual, ts,
override_type);
}

/*!
Expand All @@ -493,43 +495,61 @@ MethodInfo TypeSystem::declare_method(const std::string& type_name,
MethodInfo TypeSystem::declare_method(Type* type,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts) {
const TypeSpec& ts,
bool override_type) {
if (method_name == "new") {
if (override_type) {
throw_typesystem_error("Cannot use :replace option with a new method.");
}
return add_new_method(type, ts);
}

// look up the method
MethodInfo existing_info;
bool got_existing = try_lookup_method(type, method_name, &existing_info);

if (got_existing) {
// make sure we aren't changing anything.
if (!existing_info.type.is_compatible_child_method(ts, type->get_name())) {
if (override_type) {
if (!got_existing) {
throw_typesystem_error(
"The method {} of type {} was originally declared as {}, but has been "
"redeclared as {}\n",
method_name, type->get_name(), existing_info.type.print(), ts.print());
"Cannot use :replace on method {} of {} because this method was not previously declared "
"in a parent.",
method_name, type->get_name());
}

if ((existing_info.no_virtual || no_virtual) &&
existing_info.defined_in_type != type->get_name()) {
throw_typesystem_error(
"Cannot define method {} in type {} when it was defined as no_virtual in parent type {}",
method_name, type->get_name(), existing_info.defined_in_type);
}
// use the existing ID.
return type->add_method(
{existing_info.id, method_name, ts, type->get_name(), no_virtual, true});
} else {
if (got_existing) {
// make sure we aren't changing anything.
if (!existing_info.type.is_compatible_child_method(ts, type->get_name())) {
throw_typesystem_error(
"The method {} of type {} was originally declared as {}, but has been "
"redeclared as {}\n",
method_name, type->get_name(), existing_info.type.print(), ts.print());
}

if (no_virtual != existing_info.no_virtual) {
throw_typesystem_error(
"The method {} of type {} was originally declared with no_virtual = {}, but has been "
"redeclared as {}",
method_name, type->get_name(), existing_info.no_virtual, no_virtual);
}
if ((existing_info.no_virtual || no_virtual) &&
existing_info.defined_in_type != type->get_name()) {
throw_typesystem_error(
"Cannot define method {} in type {} when it was defined as no_virtual in parent type "
"{}",
method_name, type->get_name(), existing_info.defined_in_type);
}

return existing_info;
} else {
// add a new method!
return type->add_method(
{get_next_method_id(type), method_name, ts, type->get_name(), no_virtual});
if (no_virtual != existing_info.no_virtual) {
throw_typesystem_error(
"The method {} of type {} was originally declared with no_virtual = {}, but has been "
"redeclared as {}",
method_name, type->get_name(), existing_info.no_virtual, no_virtual);
}

return existing_info;
} else {
// add a new method!
return type->add_method(
{get_next_method_id(type), method_name, ts, type->get_name(), no_virtual, false});
}
}
}

Expand Down Expand Up @@ -955,23 +975,25 @@ void TypeSystem::add_builtin_types() {

// OBJECT
declare_method(obj_type, "new", false,
make_function_typespec({"symbol", "type", "int"}, "_type_"));
declare_method(obj_type, "delete", false, make_function_typespec({"_type_"}, "none"));
declare_method(obj_type, "print", false, make_function_typespec({"_type_"}, "_type_"));
declare_method(obj_type, "inspect", false, make_function_typespec({"_type_"}, "_type_"));
declare_method(obj_type, "length", false,
make_function_typespec({"_type_"}, "int")); // todo - this integer type?
declare_method(obj_type, "asize-of", false, make_function_typespec({"_type_"}, "int"));
declare_method(obj_type, "copy", false, make_function_typespec({"_type_", "symbol"}, "_type_"));
declare_method(obj_type, "relocate", false, make_function_typespec({"_type_", "int"}, "_type_"));
make_function_typespec({"symbol", "type", "int"}, "_type_"), false);
declare_method(obj_type, "delete", false, make_function_typespec({"_type_"}, "none"), false);
declare_method(obj_type, "print", false, make_function_typespec({"_type_"}, "_type_"), false);
declare_method(obj_type, "inspect", false, make_function_typespec({"_type_"}, "_type_"), false);
declare_method(obj_type, "length", false, make_function_typespec({"_type_"}, "int"),
false); // todo - this integer type?
declare_method(obj_type, "asize-of", false, make_function_typespec({"_type_"}, "int"), false);
declare_method(obj_type, "copy", false, make_function_typespec({"_type_", "symbol"}, "_type_"),
false);
declare_method(obj_type, "relocate", false, make_function_typespec({"_type_", "int"}, "_type_"),
false);
declare_method(obj_type, "mem-usage", false,
make_function_typespec({"_type_", "memory-usage-block", "int"}, "_type_"));
make_function_typespec({"_type_", "memory-usage-block", "int"}, "_type_"), false);

// STRUCTURE
// structure new doesn't support dynamic sizing, which is kinda weird - it grabs the size from
// the type. Dynamic structures use new-dynamic-structure, which is used exactly once ever.
declare_method(structure_type, "new", false,
make_function_typespec({"symbol", "type"}, "_type_"));
declare_method(structure_type, "new", false, make_function_typespec({"symbol", "type"}, "_type_"),
false);
// structure_type is a field-less StructureType, so we have to do this to match the runtime.
// structure_type->override_size_in_memory(4);

Expand All @@ -980,18 +1002,19 @@ void TypeSystem::add_builtin_types() {
add_field_to_type(basic_type, "type", make_typespec("type"));
// the default new basic doesn't support dynamic sizing. anything dynamic will override this
// and then call (method object new) to do the dynamically-sized allocation.
declare_method(basic_type, "new", false, make_function_typespec({"symbol", "type"}, "_type_"));
declare_method(basic_type, "new", false, make_function_typespec({"symbol", "type"}, "_type_"),
false);

// SYMBOL
builtin_structure_inherit(symbol_type);
add_field_to_type(symbol_type, "value", make_typespec("object"));
// a new method which returns type none means new is illegal.
declare_method(symbol_type, "new", false, make_function_typespec({}, "none"));
declare_method(symbol_type, "new", false, make_function_typespec({}, "none"), false);

// TYPE
builtin_structure_inherit(type_type);
declare_method(type_type, "new", false,
make_function_typespec({"symbol", "type", "int"}, "_type_"));
make_function_typespec({"symbol", "type", "int"}, "_type_"), false);
add_field_to_type(type_type, "symbol", make_typespec("symbol"));
add_field_to_type(type_type, "parent", make_typespec("type"));
add_field_to_type(type_type, "size", make_typespec("uint16")); // actually u16
Expand All @@ -1008,7 +1031,7 @@ void TypeSystem::add_builtin_types() {
// string is never deftype'd for the decompiler, so we need to manually give the constructor
// type here.
declare_method(string_type, "new", false,
make_function_typespec({"symbol", "type", "int", "string"}, "_type_"));
make_function_typespec({"symbol", "type", "int", "string"}, "_type_"), false);

// FUNCTION
builtin_structure_inherit(function_type);
Expand Down Expand Up @@ -1037,7 +1060,7 @@ void TypeSystem::add_builtin_types() {
// todo
builtin_structure_inherit(array_type);
declare_method(array_type, "new", false,
make_function_typespec({"symbol", "type", "type", "int"}, "_type_"));
make_function_typespec({"symbol", "type", "type", "int"}, "_type_"), false);
// array has: number, number, type
add_field_to_type(array_type, "length", make_typespec("int32"));
add_field_to_type(array_type, "allocated-length", make_typespec("int32"));
Expand All @@ -1047,7 +1070,7 @@ void TypeSystem::add_builtin_types() {
// pair
pair_type->override_offset(2);
declare_method(pair_type, "new", false,
make_function_typespec({"symbol", "type", "object", "object"}, "_type_"));
make_function_typespec({"symbol", "type", "object", "object"}, "_type_"), false);
add_field_to_type(pair_type, "car", make_typespec("object"));
add_field_to_type(pair_type, "cdr", make_typespec("object"));

Expand All @@ -1065,7 +1088,7 @@ void TypeSystem::add_builtin_types() {
add_field_to_type(file_stream_type, "name", make_typespec("string"));
add_field_to_type(file_stream_type, "file", make_typespec("uint32"));
declare_method(file_stream_type, "new", false,
make_function_typespec({"symbol", "type", "string", "basic"}, "_type_"));
make_function_typespec({"symbol", "type", "string", "basic"}, "_type_"), false);
}

/*!
Expand Down Expand Up @@ -1590,6 +1613,10 @@ std::string TypeSystem::generate_deftype_footer(const Type* type) const {
methods_string.append(":no-virtual ");
}

if (info.overrides_method_type_of_parent) {
methods_string.append(":replace ");
}

methods_string.append(fmt::format("{})\n ", info.id));
}

Expand Down
7 changes: 4 additions & 3 deletions common/type_system/TypeSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,13 @@ class TypeSystem {
MethodInfo declare_method(const std::string& type_name,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts);
const TypeSpec& ts,
bool override_type);
MethodInfo declare_method(Type* type,
const std::string& method_name,
bool no_virtual,
const TypeSpec& ts);

const TypeSpec& ts,
bool override_type);
MethodInfo define_method(const std::string& type_name,
const std::string& method_name,
const TypeSpec& ts);
Expand Down
9 changes: 8 additions & 1 deletion common/type_system/deftype.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -188,12 +188,18 @@ void declare_method(Type* type, TypeSystem* type_system, const goos::Object& def
obj = cdr(obj);

bool no_virtual = false;
bool replace_method = false;

if (!obj->is_empty_list() && car(obj).is_symbol(":no-virtual")) {
obj = cdr(obj);
no_virtual = true;
}

if (!obj->is_empty_list() && car(obj).is_symbol(":replace")) {
obj = cdr(obj);
replace_method = true;
}

int id = -1;
if (!obj->is_empty_list() && car(obj).is_int()) {
auto& id_obj = car(obj);
Expand All @@ -212,7 +218,8 @@ void declare_method(Type* type, TypeSystem* type_system, const goos::Object& def
});
function_typespec.add_arg(parse_typespec(type_system, return_type));

auto info = type_system->declare_method(type, method_name, no_virtual, function_typespec);
auto info = type_system->declare_method(type, method_name, no_virtual, function_typespec,
replace_method);

// check the method assert
if (id != -1) {
Expand Down
1 change: 1 addition & 0 deletions decompiler/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ add_library(
analysis/type_analysis.cpp
analysis/variable_naming.cpp

data/dir_tpages.cpp
data/game_count.cpp
data/game_text.cpp
data/StrFileReader.cpp
Expand Down
Loading

0 comments on commit 6366068

Please sign in to comment.