diff --git a/common/log/log.cpp b/common/log/log.cpp index 0ef99fcd74..c560507fd4 100644 --- a/common/log/log.cpp +++ b/common/log/log.cpp @@ -103,20 +103,35 @@ void initialize() { assert(!gLogger.initialized); #ifdef _WIN32 - // Always enable VIRTUAL_TERMINAL_PROCESSING, this console mode allows the console (stdout) to - // support ANSI colors in the outputted text, which are used by the logging tool. - // This mode may not be enabled by default, and changing that involves modifying the registry, - // so it seems like a better solution would be enabling it ourselves. + // Enable some console terminal flags. Some of these may not be enabled by default, unless + // the user edits their registry. This is clearly unwanted, so we just set them here ourselves. + + // VIRTUAL_TERMINAL_PROCESSING enables support for ANSI colors in the stdout text, used by the + // logging tool. + // ENABLE_QUICK_EDIT_MODE enables various mouse-related stdin functions, such as right-click for + // copy-paste, scroll wheel to - shocker - scroll, etc. // Get handle to stdout HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE); // get current stdout mode DWORD modeStdOut; GetConsoleMode(hStdOut, &modeStdOut); - // enable VIRTUAL_TERMINAL_PROCESSING. As a bitwise OR it will not do anything if it is - // already set + // printf("stdout mode is: %08x", modeStdOut); + + // Get handle to stdin + HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE); + // get current stdin mode + DWORD modeStdIn; + GetConsoleMode(hStdIn, &modeStdIn); + // printf("stdin mode is: %08x", modeStdIn); + + // enable VIRTUAL_TERMINAL_PROCESSING on stdout modeStdOut |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; SetConsoleMode(hStdOut, modeStdOut); + + // enable ENABLE_QUICK_EDIT_MODE on stdin + modeStdIn |= ENABLE_QUICK_EDIT_MODE; + SetConsoleMode(hStdIn, modeStdIn); #endif gLogger.initialized = true; @@ -132,4 +147,4 @@ void finish() { } } -} // namespace lg \ No newline at end of file +} // namespace lg diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index 27268eac25..764db60043 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -38,6 +38,16 @@ TypeSystem::TypeSystem() { * throw_on_redefine is set. The type should be fully set up (fields, etc) before running this. */ Type* TypeSystem::add_type(const std::string& name, std::unique_ptr type) { + auto method_kv = m_forward_declared_method_counts.find(name); + if (method_kv != m_forward_declared_method_counts.end()) { + int method_count = get_next_method_id(type.get()); + if (method_count != method_kv->second) { + throw_typesystem_error( + "Type {} was defined with {} methods, but was forward declared with {}\n", name, + method_count, method_kv->second); + } + } + auto kv = m_types.find(name); if (kv != m_types.end()) { // exists already @@ -177,6 +187,53 @@ void TypeSystem::forward_declare_type_as(const std::string& new_type, } } +void TypeSystem::forward_declare_type_method_count(const std::string& name, int num_methods) { + auto existing_fwd = m_forward_declared_method_counts.find(name); + if (existing_fwd != m_forward_declared_method_counts.end() && + existing_fwd->second != num_methods) { + throw_typesystem_error( + "Type {} was originally forward declared with {} methods and is now being forward declared " + "with {} methods", + name, existing_fwd->second, num_methods); + } + + auto existing_type = m_types.find(name); + if (existing_type != m_types.end()) { + int existing_count = get_next_method_id(existing_type->second.get()); + if (existing_count != num_methods) { + throw_typesystem_error( + "Type {} was defined with {} methods and is now being forward declared with {} methods", + name, existing_fwd->second, num_methods); + } + } + + m_forward_declared_method_counts[name] = num_methods; +} + +int TypeSystem::get_type_method_count(const std::string& name) const { + auto result = try_get_type_method_count(name); + if (result) { + return *result; + } + throw_typesystem_error("Tried to find the number of methods on type {}, but it is not defined.", + name); + return -1; +} + +std::optional TypeSystem::try_get_type_method_count(const std::string& name) const { + auto type_it = m_types.find(name); + if (type_it != m_types.end()) { + return get_next_method_id(type_it->second.get()); + } + + auto fwd_it = m_forward_declared_method_counts.find(name); + if (fwd_it != m_forward_declared_method_counts.end()) { + return fwd_it->second; + } + + return {}; +} + /*! * Get the runtime type (as a name string) of a TypeSpec. Gets the runtime type of the primary * type of the TypeSpec. diff --git a/common/type_system/TypeSystem.h b/common/type_system/TypeSystem.h index 146014053a..269669377a 100644 --- a/common/type_system/TypeSystem.h +++ b/common/type_system/TypeSystem.h @@ -126,6 +126,9 @@ class TypeSystem { Type* add_type(const std::string& name, std::unique_ptr type); void forward_declare_type_as_type(const std::string& name); void forward_declare_type_as(const std::string& new_type, const std::string& parent_type); + void forward_declare_type_method_count(const std::string& name, int num_methods); + int get_type_method_count(const std::string& name) const; + std::optional try_get_type_method_count(const std::string& name) const; std::string get_runtime_type(const TypeSpec& ts); DerefInfo get_deref_info(const TypeSpec& ts) const; @@ -258,6 +261,8 @@ class TypeSystem { std::unordered_map> m_types; std::unordered_map m_forward_declared_types; + std::unordered_map m_forward_declared_method_counts; + std::vector> m_old_types; bool m_allow_redefinition = false; diff --git a/decompiler/IR2/AtomicOpForm.cpp b/decompiler/IR2/AtomicOpForm.cpp index d3051cb0ed..614cf37786 100644 --- a/decompiler/IR2/AtomicOpForm.cpp +++ b/decompiler/IR2/AtomicOpForm.cpp @@ -642,8 +642,10 @@ Form* LoadVarOp::get_load_src(FormPool& pool, const Env& env) const { u64 value; memcpy(&value, &word0.data, 4); memcpy(((u8*)&value) + 4, &word1.data, 4); - return pool.alloc_single_element_form( - nullptr, SimpleAtom::make_int_constant(value)); + return pool.alloc_single_element_form( + nullptr, TypeSpec("uint"), + pool.alloc_single_element_form( + nullptr, SimpleAtom::make_int_constant(value))); } // is it a constant bitfield? @@ -797,4 +799,4 @@ FormElement* StackSpillStoreOp::get_as_form(FormPool& pool, const Env& env) cons return pool.alloc_element(m_value, m_size, m_offset, cast_type); } -} // namespace decompiler \ No newline at end of file +} // namespace decompiler diff --git a/decompiler/IR2/bitfields.cpp b/decompiler/IR2/bitfields.cpp index 6459f81c1b..be354be131 100644 --- a/decompiler/IR2/bitfields.cpp +++ b/decompiler/IR2/bitfields.cpp @@ -547,7 +547,7 @@ std::vector compact_nested_logiors(GenericElement* input, const Env&) { while (next) { assert(next->elts().size() == 2); result.push_back(next->elts().at(1)); - auto next_next = next->elts().at(0); + auto next_next = strip_int_or_uint_cast(next->elts().at(0)); next = next_next->try_as_element(); if (!next || !next->op().is_fixed(FixedOperatorKind::LOGIOR)) { result.push_back(next_next); @@ -778,4 +778,4 @@ Form* cast_to_bitfield_enum(const EnumType* type_info, FormPool& pool, const Env return pool.alloc_single_element_form(nullptr, oper, form_elts); } -} // namespace decompiler \ No newline at end of file +} // namespace decompiler diff --git a/decompiler/ObjectFile/LinkedObjectFileCreation.cpp b/decompiler/ObjectFile/LinkedObjectFileCreation.cpp index 82f539ad3b..f8ce125c0f 100644 --- a/decompiler/ObjectFile/LinkedObjectFileCreation.cpp +++ b/decompiler/ObjectFile/LinkedObjectFileCreation.cpp @@ -760,10 +760,8 @@ static void link_v3(LinkedObjectFile& f, link_ptr--; s_name = (const char*)(&data.at(link_ptr)); } else { - // methods todo - s_name = (const char*)(&data.at(link_ptr)); - // get_type_info().inform_type_method_count(s_name, reloc & 0x7f); todo + dts.ts.forward_declare_type_method_count(s_name, reloc & 0x7f); kind = SymbolLinkKind::TYPE; } diff --git a/decompiler/config/all-types.gc b/decompiler/config/all-types.gc index 418b30059d..e3d30e4595 100644 --- a/decompiler/config/all-types.gc +++ b/decompiler/config/all-types.gc @@ -12736,7 +12736,7 @@ (deftype entity-actor (entity) ( (nav-mesh nav-mesh :offset-assert 52) - (etype basic :offset-assert 56) ;; probably type + (etype type :offset-assert 56) ;; probably type (task uint8 :offset-assert 60) (vis-id uint16 :offset-assert 62) (quat quaternion :inline :offset-assert 64) @@ -12754,9 +12754,9 @@ ) (deftype entity-info (basic) - ((ptype basic :offset-assert 4) + ((ptype type :offset-assert 4) (package basic :offset-assert 8) - (art-group basic :offset-assert 12) + (art-group pair :offset-assert 12) (pool basic :offset-assert 16) (heap-size int32 :offset-assert 20) ) @@ -15988,7 +15988,7 @@ ;; - Unknowns -;;(define-extern *entity-info* object) ;; unknown type +(define-extern *entity-info* (array entity-info)) ;; ---------------------- diff --git a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc index fe92c09ebe..79085b8dcb 100644 --- a/decompiler/config/jak1_ntsc_black_label/label_types.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/label_types.jsonc @@ -520,10 +520,6 @@ ["L10", "debug-sphere-table", true] ], - "generic": [ - ["L11", "(array generic-dma-foreground-sink)", true], - ["L12", "uint64", true] - ], "entity": [ ["L324", "float", true] ], @@ -581,5 +577,15 @@ ["L227", "uint64", true], ["L228", "uint64", true], ["L229", "uint64", true] + ], + + "generic": [ + ["L10", "generic-dma-foreground-sink", true], + ["L11", "(array generic-dma-foreground-sink)", true], + ["L12", "uint64", true] + ], + + "entity-table": [ + ["L8", "(array entity-info)", true] ] } diff --git a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc index e393299bb1..84a5d2a1d6 100644 --- a/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/type_casts.jsonc @@ -686,5 +686,8 @@ ], "drawable-frag-count": [ [[14, 20], "s5", "drawable-group"] + ], + "generic-init-buffers": [ + [[39, 44], "v1", "dma-packet"] ] } diff --git a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc index aa7ad695a3..b774e793a5 100644 --- a/decompiler/config/jak1_ntsc_black_label/var_names.jsonc +++ b/decompiler/config/jak1_ntsc_black_label/var_names.jsonc @@ -2033,7 +2033,11 @@ "v1-11":["v1-11", "dma-packet"] } }, - "add-debug-light": { "vars": { "s1-0":["s1-0", "rgba"]} } - - + "add-debug-light": { "vars": { "s1-0":["s1-0", "rgba"]} }, + + "generic-init-buffers": { + "vars": { + "v1-8": ["packet", "dma-packet"] + } + } } diff --git a/decompiler/util/data_decompile.cpp b/decompiler/util/data_decompile.cpp index 1656ea15da..3b9c7f4fd7 100644 --- a/decompiler/util/data_decompile.cpp +++ b/decompiler/util/data_decompile.cpp @@ -2,6 +2,7 @@ #include "data_decompile.h" #include "third-party/fmt/core.h" +#include "common/type_system/Type.h" #include "common/goos/PrettyPrinter.h" #include "common/util/math_util.h" #include "common/log/log.h" @@ -269,15 +270,12 @@ goos::Object decompile_structure(const TypeSpec& type, // check alignment auto offset_location = label.offset - type_info->get_offset(); - // if ((offset_location % 8) == 2) { - // // TEMP HACK - // lg::error("Data decompile was looking for a structure, but it looks like a pair instead."); - // return decompile_pair(label, labels, words, ts); - // } if (offset_location % 8) { - throw std::runtime_error( - fmt::format("Structure type {} (type offset {}) has alignment {}, which is not valid.", - type_info->get_name(), type_info->get_offset(), (offset_location % 8))); + throw std::runtime_error(fmt::format( + "Tried to decompile a structure with type type {} (type offset {}) at label {}, but it has " + "alignment {}, which is not valid. {}", + type_info->get_name(), type_info->get_offset(), label.name, (offset_location % 8), + (offset_location & 0b10) ? "Maybe it is actually a pair?" : "")); } // check enough room @@ -517,6 +515,17 @@ goos::Object decompile_structure(const TypeSpec& type, } } else if (word.kind == LinkedWord::EMPTY_PTR) { field_defs_out.emplace_back(field.name(), pretty_print::to_symbol("'()")); + } else if (word.kind == LinkedWord::TYPE_PTR) { + if (field.type() != TypeSpec("type")) { + throw std::runtime_error( + fmt::format("Field {} in type {} offset {} had a reference to type {}, but the " + "type of the field is not type.", + field.name(), actual_type.print(), field.offset(), word.symbol_name)); + } + int method_count = ts.get_type_method_count(word.symbol_name); + field_defs_out.emplace_back( + field.name(), pretty_print::to_symbol(fmt::format("(type-ref {} :method-count {})", + word.symbol_name, method_count))); } else { throw std::runtime_error( fmt::format("Field {} in type {} offset {} did not have a proper reference", diff --git a/docs/markdown/progress-notes/changelog.md b/docs/markdown/progress-notes/changelog.md index c8d8fe3eef..1ff8a89df9 100644 --- a/docs/markdown/progress-notes/changelog.md +++ b/docs/markdown/progress-notes/changelog.md @@ -164,4 +164,5 @@ - GOOS supports `string-ref`, `string-length`, `ash`, and characters can now be treated as a signed 8-bit number - Fixed a bug where saved xmm registers might be clobbered when calling a C++ function that wasn't `format`. - The `declare-type` form now supports any parent type. The type system will do a better job of trying to make things work out when only part of the type hierarchy is defined, and you can now chain type forward declarations. The compiler is stricter and will not accept forward declarations that are possibly incompatible. Instead, forward declare enough types and their parents for the compiler to be able to figure it out. -- The `deftype` form is more strict and will throw an error if the type definition is in any way incompatible with existing forward declarations of types. \ No newline at end of file +- The `deftype` form is more strict and will throw an error if the type definition is in any way incompatible with existing forward declarations of types. +- Added a `type-ref` form to insert a reference to a type into a static structure and optionally forward declare the number of methods \ No newline at end of file diff --git a/goal_src/engine/entity/entity-h.gc b/goal_src/engine/entity/entity-h.gc index f67892dad0..53e347fc32 100644 --- a/goal_src/engine/entity/entity-h.gc +++ b/goal_src/engine/entity/entity-h.gc @@ -160,7 +160,7 @@ (declare-type nav-mesh basic) (deftype entity-actor (entity) ((nav-mesh nav-mesh :offset-assert 52) - (etype basic :offset-assert 56) + (etype type :offset-assert 56) (task uint8 :offset-assert 60) (vis-id uint16 :offset-assert 62) (quat quaternion :inline :offset-assert 64) @@ -178,9 +178,9 @@ ;; definition of type entity-info (deftype entity-info (basic) - ((ptype basic :offset-assert 4) + ((ptype type :offset-assert 4) (package basic :offset-assert 8) - (art-group basic :offset-assert 12) + (art-group pair :offset-assert 12) (pool basic :offset-assert 16) (heap-size int32 :offset-assert 20) ) diff --git a/goal_src/engine/gfx/generic/generic.gc b/goal_src/engine/gfx/generic/generic.gc index 2411d84911..8f7c5727d4 100644 --- a/goal_src/engine/gfx/generic/generic.gc +++ b/goal_src/engine/gfx/generic/generic.gc @@ -5,3 +5,150 @@ ;; name in dgo: generic ;; dgos: GAME, ENGINE +; This is actually defined in generic-vu1.gc but this file builds first +(define-extern generic-init-buf (function dma-buffer int uint none)) + +;; definition for symbol *generic-foreground-sinks*, type (array generic-dma-foreground-sink) +(define + *generic-foreground-sinks* + (the-as (array generic-dma-foreground-sink) + (new + 'static + 'boxed-array + :type generic-dma-foreground-sink :length 0 :allocated-length 9 + ) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 0) + (the-as + generic-dma-foreground-sink + (-> *level* level0 foreground-sink-group 0 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 1) + (the-as + generic-dma-foreground-sink + (-> *level* level0 foreground-sink-group 1 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 2) + (the-as + generic-dma-foreground-sink + (-> *level* level1 foreground-sink-group 0 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 3) + (the-as + generic-dma-foreground-sink + (-> *level* level1 foreground-sink-group 1 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 4) + (the-as + generic-dma-foreground-sink + (-> *level* level-default foreground-sink-group 0 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 5) + (the-as + generic-dma-foreground-sink + (-> *level* level-default foreground-sink-group 1 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 6) + (new 'static 'generic-dma-foreground-sink :bucket 30) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 7) + (the-as + generic-dma-foreground-sink + (-> *level* level0 foreground-sink-group 2 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 8) + (the-as + generic-dma-foreground-sink + (-> *level* level1 foreground-sink-group 2 merc-sink) + ) + ) + +;; definition for function generic-dma-foreground-sink-init +;; INFO: Return type mismatch int vs none. +(defun generic-dma-foreground-sink-init ((arg0 generic-dma-foreground-sink)) + (set! (-> arg0 state gifbuf-adr) (the-as uint 837)) + (set! (-> arg0 state inbuf-adr) (the-as uint 9)) + (none) + ) + +;; definition for function generic-init-buffers +(defun generic-init-buffers () + (vu-lights-default! *default-lights*) + (let ((gp-0 #x10001c0) + (s5-0 (the-as uint #x1010001c0)) + ) + (dotimes (s4-0 9) + (let ((s1-0 (-> *generic-foreground-sinks* s4-0))) + (when s1-0 + (let* ((s3-0 (-> s1-0 bucket)) + (s0-0 + (-> *display* frames (-> *display* on-screen) frame global-buf) + ) + (s2-0 (-> s0-0 base)) + ) + (if (>= s4-0 7) + (generic-init-buf s0-0 1 s5-0) + (generic-init-buf s0-0 1 (the-as uint gp-0)) + ) + (generic-dma-foreground-sink-init s1-0) + (let ((a3-0 (-> s0-0 base))) + (let ((packet (the-as dma-packet (-> s0-0 base)))) + (set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id next))) + (set! (-> packet vif0) (new 'static 'vif-tag)) + (set! (-> packet vif1) (new 'static 'vif-tag)) + (set! (-> s0-0 base) (&+ (the-as pointer packet) 16)) + ) + (dma-bucket-insert-tag + (-> *display* frames (-> *display* on-screen) frame bucket-group) + s3-0 + s2-0 + (the-as (pointer dma-tag) a3-0) + ) + ) + ) + ) + ) + ) + ) + #f + ) + +;; definition for function generic-sink +(defun generic-sink ((arg0 int)) + (-> *generic-foreground-sinks* arg0) + ) diff --git a/goalc/compiler/StaticObject.cpp b/goalc/compiler/StaticObject.cpp index bed055f3db..5ab2bc0396 100644 --- a/goalc/compiler/StaticObject.cpp +++ b/goalc/compiler/StaticObject.cpp @@ -215,4 +215,13 @@ StaticResult StaticResult::make_symbol(const std::string& name) { result.m_symbol = name; result.m_ts = TypeSpec("symbol"); return result; +} + +StaticResult StaticResult::make_type_ref(const std::string& type_name, int method_count) { + StaticResult result; + result.m_kind = Kind::TYPE; + result.m_symbol = type_name; + result.m_method_count = method_count; + result.m_ts = TypeSpec("type"); + return result; } \ No newline at end of file diff --git a/goalc/compiler/StaticObject.h b/goalc/compiler/StaticObject.h index bd0910c3d9..c968e23acb 100644 --- a/goalc/compiler/StaticObject.h +++ b/goalc/compiler/StaticObject.h @@ -101,13 +101,13 @@ class StaticResult { static StaticResult make_constant_data(const ConstantValue& data, TypeSpec ts); static StaticResult make_constant_data(u64 data, const TypeSpec& ts); static StaticResult make_symbol(const std::string& name); - - std::string print() const; + static StaticResult make_type_ref(const std::string& type_name, int method_count); const TypeSpec& typespec() const { return m_ts; } bool is_reference() const { return m_kind == Kind::STRUCTURE_REFERENCE; } bool is_constant_data() const { return m_kind == Kind::CONSTANT_DATA; } bool is_symbol() const { return m_kind == Kind::SYMBOL; } + bool is_type() const { return m_kind == Kind::TYPE; } StaticStructure* reference() const { assert(is_reference()); @@ -121,10 +121,15 @@ class StaticResult { } const std::string& symbol_name() const { - assert(is_symbol()); + assert(is_symbol() || is_type()); return m_symbol; } + int method_count() const { + assert(is_type()); + return m_method_count; + } + u64 constant_u64() const { assert(is_constant_data() && m_constant_data && m_constant_data->size() == 8); return m_constant_data->value_64(); @@ -145,10 +150,19 @@ class StaticResult { // used for only constant data std::optional m_constant_data; - // used for only symbol + // used for only symbol and type std::string m_symbol; - enum class Kind { STRUCTURE_REFERENCE, CONSTANT_DATA, SYMBOL, INVALID } m_kind = Kind::INVALID; + // used only for type + int m_method_count = -1; + + enum class Kind { + STRUCTURE_REFERENCE, + CONSTANT_DATA, + SYMBOL, + TYPE, + INVALID + } m_kind = Kind::INVALID; }; class StaticPair : public StaticStructure { diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index 82ab063672..a4a77c9162 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -205,6 +205,12 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, typecheck(form, field_info.type, sr.typespec()); structure->add_pointer_record(field_offset, sr.reference(), sr.reference()->get_addr_offset()); + } else if (sr.is_type()) { + if (field_info.type != TypeSpec("type")) { + throw_compiler_error(form, "Cannot put a type reference in a field with type {}", + field_info.type.print()); + } + structure->add_type_record(sr.symbol_name(), field_offset); } else { throw_compiler_error(form, "Unsupported field value {}.", field_value.print()); } @@ -669,6 +675,37 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env } } } + } else if (first.is_symbol("type-ref")) { + auto args = get_va(form, rest); + va_check(form, args, {goos::ObjectType::SYMBOL}, + {{{"method-count", {false, goos::ObjectType::INTEGER}}}}); + + auto type_name = args.unnamed.at(0).as_symbol()->name; + + std::optional expected_method_count = m_ts.try_get_type_method_count(type_name); + int method_count = -1; + + if (args.has_named("method-count")) { + method_count = args.get_named("method-count").as_int(); + if (expected_method_count && (method_count != *expected_method_count)) { + throw_compiler_error( + form, "type-ref wanted {} methods for type {}, but the type system thinks it has {}", + method_count, type_name, *expected_method_count); + } + } else { + if (!expected_method_count) { + throw_compiler_error( + form, + "Cannot create a static type reference for type {}. The type-ref form did not have a " + ":method-count argument and the type system does not know how many methods it has.", + type_name); + } + method_count = *expected_method_count; + } + + m_ts.forward_declare_type_method_count(type_name, method_count); + + return StaticResult::make_type_ref(type_name, method_count); } else { // maybe an enum s64 int_out; diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index c90c6b71e6..93b49e65a9 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -124,7 +124,7 @@ void Compiler::generate_field_description(const goos::Object& form, const Field& f) { std::string str_template; std::vector format_args = {}; - if (m_ts.tc(m_ts.make_typespec("type"), f.type())) { + if (f.name() == "type" && f.offset() == 0) { // type return; } else if (f.is_array() && !f.is_dynamic()) { diff --git a/goalc/emitter/ObjectGenerator.cpp b/goalc/emitter/ObjectGenerator.cpp index 0442188f69..6480e061e5 100644 --- a/goalc/emitter/ObjectGenerator.cpp +++ b/goalc/emitter/ObjectGenerator.cpp @@ -458,7 +458,7 @@ void ObjectGenerator::emit_link_type_pointer(int seg, const TypeSystem* ts) { out.push_back(0); // method count - out.push_back(ts->get_next_method_id(ts->lookup_type(rec.first))); + out.push_back(ts->get_type_method_count(rec.first)); // number of links push_data(size, out); diff --git a/test/decompiler/reference/engine/dma/dma_REF.gc b/test/decompiler/reference/engine/dma/dma_REF.gc index 9f1d535890..949f5a3c16 100644 --- a/test/decompiler/reference/engine/dma/dma_REF.gc +++ b/test/decompiler/reference/engine/dma/dma_REF.gc @@ -264,7 +264,7 @@ (defun clear-vu0-mem () (let ((v1-0 (the-as (pointer uint32) #x11004000))) (dotimes (a0-0 1024) - (set! (-> v1-0 a0-0) #xabadbeef) + (set! (-> v1-0 a0-0) (the-as uint #xabadbeef)) ) ) (let ((v0-0 0)) @@ -277,7 +277,7 @@ (defun clear-vu1-mem () (let ((v1-0 (the-as (pointer uint32) #x1100c000))) (dotimes (a0-0 4096) - (set! (-> v1-0 a0-0) #xabadbeef) + (set! (-> v1-0 a0-0) (the-as uint #xabadbeef)) ) ) (let ((v0-0 0)) diff --git a/test/decompiler/reference/engine/entity/entity-h_REF.gc b/test/decompiler/reference/engine/entity/entity-h_REF.gc index 25ca0c6094..7f5cf4f99c 100644 --- a/test/decompiler/reference/engine/entity/entity-h_REF.gc +++ b/test/decompiler/reference/engine/entity/entity-h_REF.gc @@ -234,7 +234,7 @@ ;; definition of type entity-actor (deftype entity-actor (entity) ((nav-mesh nav-mesh :offset-assert 52) - (etype basic :offset-assert 56) + (etype type :offset-assert 56) (task uint8 :offset-assert 60) (vis-id uint16 :offset-assert 62) (quat quaternion :inline :offset-assert 64) @@ -252,9 +252,9 @@ ;; definition of type entity-info (deftype entity-info (basic) - ((ptype basic :offset-assert 4) + ((ptype type :offset-assert 4) (package basic :offset-assert 8) - (art-group basic :offset-assert 12) + (art-group pair :offset-assert 12) (pool basic :offset-assert 16) (heap-size int32 :offset-assert 20) ) diff --git a/test/decompiler/reference/engine/game/video_REF.gc b/test/decompiler/reference/engine/game/video_REF.gc index 4fd9c78f0c..97ef7d18ae 100644 --- a/test/decompiler/reference/engine/game/video_REF.gc +++ b/test/decompiler/reference/engine/game/video_REF.gc @@ -100,7 +100,3 @@ (defun get-aspect-ratio () (-> *setting-control* current aspect-ratio) ) - - - - diff --git a/test/decompiler/reference/engine/gfx/generic/generic_REF.gc b/test/decompiler/reference/engine/gfx/generic/generic_REF.gc new file mode 100644 index 0000000000..71b2b1e13d --- /dev/null +++ b/test/decompiler/reference/engine/gfx/generic/generic_REF.gc @@ -0,0 +1,151 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition for symbol *generic-foreground-sinks*, type (array generic-dma-foreground-sink) +(define + *generic-foreground-sinks* + (the-as (array generic-dma-foreground-sink) + (new + 'static + 'boxed-array + :type generic-dma-foreground-sink :length 0 :allocated-length 9 + ) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 0) + (the-as + generic-dma-foreground-sink + (-> *level* level0 foreground-sink-group 0 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 1) + (the-as + generic-dma-foreground-sink + (-> *level* level0 foreground-sink-group 1 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 2) + (the-as + generic-dma-foreground-sink + (-> *level* level1 foreground-sink-group 0 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 3) + (the-as + generic-dma-foreground-sink + (-> *level* level1 foreground-sink-group 1 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 4) + (the-as + generic-dma-foreground-sink + (-> *level* level-default foreground-sink-group 0 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 5) + (the-as + generic-dma-foreground-sink + (-> *level* level-default foreground-sink-group 1 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 6) + (new 'static 'generic-dma-foreground-sink :bucket 30) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 7) + (the-as + generic-dma-foreground-sink + (-> *level* level0 foreground-sink-group 2 merc-sink) + ) + ) + +;; failed to figure out what this is: +(set! + (-> *generic-foreground-sinks* 8) + (the-as + generic-dma-foreground-sink + (-> *level* level1 foreground-sink-group 2 merc-sink) + ) + ) + +;; definition for function generic-dma-foreground-sink-init +;; INFO: Return type mismatch int vs none. +(defun generic-dma-foreground-sink-init ((arg0 generic-dma-foreground-sink)) + (set! (-> arg0 state gifbuf-adr) (the-as uint 837)) + (set! (-> arg0 state inbuf-adr) (the-as uint 9)) + (none) + ) + +;; definition for function generic-init-buffers +(defun generic-init-buffers () + (vu-lights-default! *default-lights*) + (let ((gp-0 #x10001c0) + (s5-0 (the-as uint #x1010001c0)) + ) + (dotimes (s4-0 9) + (let ((s1-0 (-> *generic-foreground-sinks* s4-0))) + (when s1-0 + (let* ((s3-0 (-> s1-0 bucket)) + (s0-0 + (-> *display* frames (-> *display* on-screen) frame global-buf) + ) + (s2-0 (-> s0-0 base)) + ) + (if (>= s4-0 7) + (generic-init-buf s0-0 1 s5-0) + (generic-init-buf s0-0 1 (the-as uint gp-0)) + ) + (generic-dma-foreground-sink-init s1-0) + (let ((a3-0 (-> s0-0 base))) + (let ((packet (the-as dma-packet (-> s0-0 base)))) + (set! (-> packet dma) (new 'static 'dma-tag :id (dma-tag-id next))) + (set! (-> packet vif0) (new 'static 'vif-tag)) + (set! (-> packet vif1) (new 'static 'vif-tag)) + (set! (-> s0-0 base) (&+ (the-as pointer packet) 16)) + ) + (dma-bucket-insert-tag + (-> *display* frames (-> *display* on-screen) frame bucket-group) + s3-0 + s2-0 + (the-as (pointer dma-tag) a3-0) + ) + ) + ) + ) + ) + ) + ) + #f + ) + +;; definition for function generic-sink +(defun generic-sink ((arg0 int)) + (-> *generic-foreground-sinks* arg0) + ) + + + + diff --git a/test/decompiler/reference/engine/load/load-dgo_REF.gc b/test/decompiler/reference/engine/load/load-dgo_REF.gc index fe46d7ae7b..a2c32322aa 100644 --- a/test/decompiler/reference/engine/load/load-dgo_REF.gc +++ b/test/decompiler/reference/engine/load/load-dgo_REF.gc @@ -410,7 +410,7 @@ ;; INFO: Return type mismatch int vs none. (defun destroy-mem ((arg0 (pointer uint32)) (arg1 (pointer uint32))) (while (< (the-as int arg0) (the-as int arg1)) - (set! (-> arg0 0) #xffffffff) + (set! (-> arg0 0) (the-as uint #xffffffff)) (set! arg0 (&-> arg0 1)) ) (let ((v0-0 0)) diff --git a/test/decompiler/reference/kernel/gcommon_REF.gc b/test/decompiler/reference/kernel/gcommon_REF.gc index 40a5dc3277..7b528a0a2b 100644 --- a/test/decompiler/reference/kernel/gcommon_REF.gc +++ b/test/decompiler/reference/kernel/gcommon_REF.gc @@ -160,7 +160,10 @@ ;; definition for method 5 of type type ;; INFO: Return type mismatch uint vs int. (defmethod asize-of type ((obj type)) - (the-as int (logand #xfffffff0 (+ (* (-> obj allocated-length) 4) 43))) + (the-as + int + (logand (the-as uint #xfffffff0) (+ (* (-> obj allocated-length) 4) 43)) + ) ) ;; definition for function basic-type? diff --git a/test/goalc/source_templates/with_game/test-type-ref.gc b/test/goalc/source_templates/with_game/test-type-ref.gc new file mode 100644 index 0000000000..899c5c45a8 --- /dev/null +++ b/test/goalc/source_templates/with_game/test-type-ref.gc @@ -0,0 +1,24 @@ + +;; define a type with fields that hold a type. +(deftype test-type-with-type-field (basic) + ((name string) + (some-type-1 type) + (some-type-2 type)) + ) + +(let ((obj (new 'static 'test-type-with-type-field + :name "test" + :some-type-2 (type-ref some-unknown-type :method-count 20) + :some-type-1 (type-ref string :method-count 9))) + (old-string string)) + (format #t "~A ~A ~A ~A ~D ~D~%" + (-> obj some-type-1 symbol) + (= (-> obj some-type-1) old-string) ;; should not reallocate string + (-> obj some-type-1 parent) + (-> obj some-type-2 symbol) ;; should fill out type symbol + (-> obj some-type-2 allocated-length) ;; and method length + (-> obj some-type-2 parent) ;; but other stuff should be 0's + ) + ) + + diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index 023836b3c8..0cafc691c5 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -621,6 +621,12 @@ TEST_F(WithGameTests, StaticArrayField) { "0\n"}); } +TEST_F(WithGameTests, TypeReference) { + runner.run_static_test(env, testCategory, "test-type-ref.gc", + {"string #t basic some-unknown-type 20 0\n" + "0\n"}); +} + TEST_F(WithGameTests, StaticFieldInlineArray) { runner.run_static_test(env, testCategory, "test-static-field-inline-arrays.gc", {"\"second\" \"first\"\n"