From 98393c6f4c37aa05f1817df72a90087fb0d44b8f Mon Sep 17 00:00:00 2001 From: Tyler Wilding Date: Sat, 21 Jan 2023 21:40:39 -0500 Subject: [PATCH] goalc: support static arrays of `type`s (#2140) draft because using the array is a little weird still, don't feel like dealing with window's slow debugging builds today. I get the following weird error: ```clj (define test-array (new 'static 'boxed-array :type type vector)) gr> (-> test-array 0) 1538004 #x1777d4 0.0000 vector gr> (type? (-> test-array 0) type) 1342757 #x147d25 0.0000 #t gr> (new 'static (-> test-array 0)) -- Compilation Error! -- Got 3 arguments, but expected 2 Form: (-> test-array 0) Location: Program string:1 (new 'static (-> test-array 0)) ^ Code: (new 'static (-> test-array 0)) ``` Maybe this is expected though and the `new` method wants a symbol, not a type? Fixes #2060 Co-authored-by: water --- decompiler/config/jak2/all-types.gc | 2 - goalc/compiler/compilation/Static.cpp | 21 +- .../jak2/engine/target/target-h_REF.gc | 230 ++++++++++++++++++ test/decompiler/test_FormExpressionBuild2.cpp | 2 +- .../with_game/test-static-array-of-types.gc | 13 + test/goalc/test_with_game.cpp | 5 + 6 files changed, 267 insertions(+), 6 deletions(-) create mode 100644 test/decompiler/reference/jak2/engine/target/target-h_REF.gc create mode 100644 test/goalc/source_templates/with_game/test-static-array-of-types.gc diff --git a/decompiler/config/jak2/all-types.gc b/decompiler/config/jak2/all-types.gc index f0e72e8e9..7c864aa11 100644 --- a/decompiler/config/jak2/all-types.gc +++ b/decompiler/config/jak2/all-types.gc @@ -37282,7 +37282,6 @@ ) |# -#| (deftype turret-info (basic) ((process uint32 :offset-assert 4) (handle uint64 :offset-assert 8) @@ -37295,7 +37294,6 @@ :size-assert #x40 :flag-assert #x900000040 ) -|# #| (deftype turret-path-event (structure) diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index 0d0d2d976..7a585de34 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -856,7 +856,20 @@ void Compiler::fill_static_array_inline(const goos::Object& form, ASSERT(deref_info.mem_deref); for (int arg_idx = 0; arg_idx < args_array_length; arg_idx++) { int elt_offset = offset + arg_idx * deref_info.stride; - auto sr = compile_static(args_array[arg_idx], env); + const auto& arg = args_array[arg_idx]; + // Special case for symbols that refer to types + StaticResult sr; + if (content_type == TypeSpec("type") && arg.is_symbol()) { + const auto& type_name = arg.as_symbol()->name; + std::optional expected_method_count = m_ts.try_get_type_method_count(type_name); + if (!expected_method_count) { + throw_compiler_error(form, "Undeclared type used in inline-array - {}", type_name); + } + sr = StaticResult::make_type_ref(type_name, expected_method_count.value()); + } else { + sr = compile_static(arg, env); + } + if (is_integer(content_type)) { typecheck(form, TypeSpec("integer"), sr.typespec()); } else { @@ -883,8 +896,10 @@ void Compiler::fill_static_array_inline(const goos::Object& form, throw_compiler_error(form, "The integer {} doesn't fit in element {} of array of {}", sr.constant().print(), arg_idx, content_type.print()); } - } // TODO - handle type case here as well - else if (sr.is_func()) { + } else if (sr.is_type()) { + ASSERT(deref_info.stride == 4); + structure->add_type_record(sr.symbol_name(), elt_offset); + } else if (sr.is_func()) { ASSERT(deref_info.stride == 4); structure->add_function_record(sr.function(), elt_offset); } else { diff --git a/test/decompiler/reference/jak2/engine/target/target-h_REF.gc b/test/decompiler/reference/jak2/engine/target/target-h_REF.gc new file mode 100644 index 000000000..ab4af5e09 --- /dev/null +++ b/test/decompiler/reference/jak2/engine/target/target-h_REF.gc @@ -0,0 +1,230 @@ +;;-*-Lisp-*- +(in-package goal) + +;; definition of type target +(deftype target (process-focusable) + ((self-override target :offset 32) + (control control-info :offset 128) + (fact-override fact-info-target :offset 160) + (skel2 joint-control :offset-assert 204) + (shadow-backup shadow-geo :offset-assert 208) + (target-flags uint32 :offset 188) + (game game-info :offset-assert 212) + (neck joint-mod :offset-assert 216) + (head joint-mod :offset-assert 220) + (upper-body joint-mod :offset-assert 224) + (horns joint-mod :offset-assert 228) + (hair joint-mod 2 :offset-assert 232) + (darkjak-interp float :offset-assert 240) + (darkjak-giant-interp float :offset-assert 244) + (arm-ik joint-mod-ik 2 :offset-assert 248) + (leg-ik joint-mod-ik 2 :offset-assert 256) + (foot joint-mod 2 :offset-assert 264) + (mech-ik joint-mod-ik 2 :offset-assert 272) + (init-time time-frame :offset 272) + (teleport-time time-frame :offset-assert 280) + (state-hook-time time-frame :offset-assert 288) + (state-hook (function none :behavior target) :offset-assert 296) + (cam-user-mode symbol :offset-assert 300) + (sidekick (pointer sidekick) :offset-assert 304) + (manipy (pointer manipy) :offset-assert 308) + (mirror (pointer process-drawable) :offset-assert 312) + (attack-info attack-info :inline :offset-assert 320) + (attack-info-rec attack-info :inline :offset-assert 480) + (attack-info-old attack-info 8 :inline :offset-assert 640) + (anim-seed uint64 :offset-assert 1920) + (alt-cam-pos vector :inline :offset-assert 1936) + (current-level level :offset-assert 1952) + (saved-pos transformq :inline :offset-assert 1968) + (saved-owner uint64 :offset-assert 2016) + (alt-neck-pos vector :inline :offset-assert 2032) + (focus-search (array collide-shape) :offset-assert 2048) + (excitement float :offset-assert 2052) + (shock-effect-time time-frame :offset-assert 2056) + (beard? symbol :offset-assert 2064) + (spool-anim spool-anim :offset-assert 2068) + (ambient-time time-frame :offset-assert 2072) + (fp-hud handle :offset-assert 2080) + (no-load-wait uint64 :offset-assert 2088) + (no-look-around-wait uint64 :offset-assert 2096) + (burn-proc handle :offset-assert 2104) + (pre-joint-hook (function none :behavior target) :offset-assert 2112) + (notify handle :offset-assert 2120) + (mode-cache basic :offset-assert 2128) + (mode-param1 handle :offset-assert 2136) + (mode-param2 uint64 :offset-assert 2144) + (mode-param3 uint64 :offset-assert 2152) + (tobot-state state :offset-assert 2160) + (tobot? symbol :offset-assert 2164) + (tobot-recorder basic :offset-assert 2168) + (color-effect basic :offset-assert 2172) + (color-effect-start-time time-frame :offset-assert 2176) + (color-effect-duration uint64 :offset-assert 2184) + (racer racer-info :offset-assert 2192) + (tube tube-info :offset-assert 2196) + (flut flut-info :offset-assert 2200) + (board board-info :offset-assert 2204) + (pilot pilot-info :offset-assert 2208) + (gun gun-info :offset-assert 2212) + (mech mech-info :offset-assert 2216) + (turret basic :offset-assert 2220) + (darkjak darkjak-info :offset-assert 2224) + (indax indax-info :offset-assert 2228) + ) + :heap-base #x840 + :method-count-assert 29 + :size-assert #x8b8 + :flag-assert #x1d084008b8 + (:methods + (do-edge-grabs (_type_ collide-cache collide-edge-spec) none 27) + (init-target (_type_ continue-point symbol) none :behavior target 28) + ) + (:states + target-carry-drop + target-carry-falling + (target-carry-hit-ground symbol) + (target-carry-jump float float) + target-carry-stance + target-carry-throw + target-carry-walk + (target-flut-start handle) + target-indax-start + (target-racing-start handle) + (target-tube-start handle) + (target-warp-in vector vector target) + (target-warp-out vector vector target) + ) + ) + +;; definition for method 3 of type target +(defmethod inspect target ((obj target)) + (when (not obj) + (set! obj obj) + (goto cfg-4) + ) + (let ((t9-0 (method-of-type process-focusable inspect))) + (t9-0 obj) + ) + (format #t "~2Tcontrol: ~A~%" (-> obj control)) + (format #t "~2Tskel2: ~A~%" (-> obj skel2)) + (format #t "~2Tshadow-backup: ~A~%" (-> obj shadow-backup)) + (format #t "~2Ttarget-flags: ~D~%" (-> obj state-flags)) + (format #t "~2Tgame: ~A~%" (-> obj game)) + (format #t "~2Tneck: ~A~%" (-> obj neck)) + (format #t "~2Thead: ~A~%" (-> obj head)) + (format #t "~2Tupper-body: ~A~%" (-> obj upper-body)) + (format #t "~2Thorns: ~A~%" (-> obj horns)) + (format #t "~2Thair[2] @ #x~X~%" (-> obj hair)) + (format #t "~2Tdarkjak-interp: ~f~%" (-> obj darkjak-interp)) + (format #t "~2Tdarkjak-giant-interp: ~f~%" (-> obj darkjak-giant-interp)) + (format #t "~2Tarm-ik[2] @ #x~X~%" (-> obj arm-ik)) + (format #t "~2Tleg-ik[2] @ #x~X~%" (-> obj leg-ik)) + (format #t "~2Tfoot[2] @ #x~X~%" (-> obj foot)) + (format #t "~2Tinit-time: ~D~%" (-> obj init-time)) + (format #t "~2Tteleport-time: ~D~%" (-> obj teleport-time)) + (format #t "~2Tstate-hook-time: ~D~%" (-> obj state-hook-time)) + (format #t "~2Tstate-hook: ~A~%" (-> obj state-hook)) + (format #t "~2Tcam-user-mode: ~A~%" (-> obj cam-user-mode)) + (format #t "~2Tsidekick: #x~X~%" (-> obj sidekick)) + (format #t "~2Tmanipy: #x~X~%" (-> obj manipy)) + (format #t "~2Tmirror: #x~X~%" (-> obj mirror)) + (format #t "~2Tattack-info: #~%" (-> obj attack-info)) + (format #t "~2Tattack-info-rec: #~%" (-> obj attack-info-rec)) + (format #t "~2Tattack-info-old[8] @ #x~X~%" (-> obj attack-info-old)) + (format #t "~2Tanim-seed: ~D~%" (-> obj anim-seed)) + (format #t "~2Talt-cam-pos: ~`vector`P~%" (-> obj alt-cam-pos)) + (format #t "~2Tcurrent-level: ~A~%" (-> obj current-level)) + (format #t "~2Tsaved-pos: #~%" (-> obj saved-pos)) + (format #t "~2Tsaved-owner: ~D~%" (-> obj saved-owner)) + (format #t "~2Talt-neck-pos: ~`vector`P~%" (-> obj alt-neck-pos)) + (format #t "~2Tfocus-search: ~A~%" (-> obj focus-search)) + (format #t "~2Texcitement: ~f~%" (-> obj excitement)) + (format #t "~2Tshock-effect-time: ~D~%" (-> obj shock-effect-time)) + (format #t "~2Tbeard?: ~A~%" (-> obj beard?)) + (format #t "~2Tspool-anim: ~A~%" (-> obj spool-anim)) + (format #t "~2Tambient-time: ~D~%" (-> obj ambient-time)) + (format #t "~2Tfp-hud: ~D~%" (-> obj fp-hud)) + (format #t "~2Tno-load-wait: ~D~%" (-> obj no-load-wait)) + (format #t "~2Tno-look-around-wait: ~D~%" (-> obj no-look-around-wait)) + (format #t "~2Tburn-proc: ~D~%" (-> obj burn-proc)) + (format #t "~2Tpre-joint-hook: ~A~%" (-> obj pre-joint-hook)) + (format #t "~2Tnotify: ~D~%" (-> obj notify)) + (format #t "~2Tmode-cache: ~A~%" (-> obj mode-cache)) + (format #t "~2Tmode-param1: ~D~%" (-> obj mode-param1)) + (format #t "~2Tmode-param2: ~A~%" (-> obj mode-param2)) + (format #t "~2Tmode-param3: ~A~%" (-> obj mode-param3)) + (format #t "~2Ttobot-state: ~A~%" (-> obj tobot-state)) + (format #t "~2Ttobot?: ~A~%" (-> obj tobot?)) + (format #t "~2Ttobot-recorder: ~A~%" (-> obj tobot-recorder)) + (format #t "~2Tcolor-effect: ~A~%" (-> obj color-effect)) + (format #t "~2Tcolor-effect-start-time: ~D~%" (-> obj color-effect-start-time)) + (format #t "~2Tcolor-effect-duration: ~D~%" (-> obj color-effect-duration)) + (format #t "~2Tracer: ~A~%" (-> obj racer)) + (format #t "~2Ttube: ~A~%" (-> obj tube)) + (format #t "~2Tflut: ~A~%" (-> obj flut)) + (format #t "~2Tboard: ~A~%" (-> obj board)) + (format #t "~2Tpilot: ~A~%" (-> obj pilot)) + (format #t "~2Tgun: ~A~%" (-> obj gun)) + (format #t "~2Tmech: ~A~%" (-> obj mech)) + (format #t "~2Tturret: ~A~%" (-> obj turret)) + (format #t "~2Tdarkjak: ~A~%" (-> obj darkjak)) + (format #t "~2Tindax: ~A~%" (-> obj indax)) + (label cfg-4) + obj + ) + +;; definition (perm) for symbol *target*, type target +(define-perm *target* target #f) + +;; definition of type sidekick +(deftype sidekick (process-drawable) + ((parent-override (pointer target) :offset 16) + (control control-info :offset 128) + (anim-seed uint64 :offset 208) + (shadow-in-movie? symbol :offset-assert 216) + (special-anim-time time-frame :offset-assert 224) + (special-anim-interp float :offset-assert 232) + (special-anim-frame float :offset-assert 236) + (offset transformq :inline :offset-assert 240) + (mirror (pointer process-drawable) :offset-assert 288) + ) + :heap-base #xb0 + :method-count-assert 20 + :size-assert #x124 + :flag-assert #x1400b00124 + (:states + sidekick-clone + ) + ) + +;; definition for method 3 of type sidekick +(defmethod inspect sidekick ((obj sidekick)) + (when (not obj) + (set! obj obj) + (goto cfg-4) + ) + (let ((t9-0 (method-of-type process-drawable inspect))) + (t9-0 obj) + ) + (format #t "~2Tcontrol: ~A~%" (-> obj root)) + (format #t "~2Tstate-time: ~D~%" (-> obj state-time)) + (format #t "~2Tanim-seed: ~D~%" (-> obj anim-seed)) + (format #t "~2Tshadow-in-movie?: ~A~%" (-> obj shadow-in-movie?)) + (format #t "~2Tspecial-anim-time: ~D~%" (-> obj special-anim-time)) + (format #t "~2Tspecial-anim-interp: ~f~%" (-> obj special-anim-interp)) + (format #t "~2Tspecial-anim-frame: ~f~%" (-> obj special-anim-frame)) + (format #t "~2Toffset: #~%" (-> obj offset)) + (format #t "~2Tmirror: #x~X~%" (-> obj mirror)) + (label cfg-4) + obj + ) + +;; definition (perm) for symbol *sidekick*, type sidekick +(define-perm *sidekick* sidekick #f) + +;; failed to figure out what this is: +(new 'static 'boxed-array :type type pilot-info mech-info turret-info indax-info tube-info) + + + + diff --git a/test/decompiler/test_FormExpressionBuild2.cpp b/test/decompiler/test_FormExpressionBuild2.cpp index 845d8719f..fb36820ee 100644 --- a/test/decompiler/test_FormExpressionBuild2.cpp +++ b/test/decompiler/test_FormExpressionBuild2.cpp @@ -664,7 +664,7 @@ TEST_F(FormRegressionTestJak1, DmaSyncCrash) { test_with_expr(func, type, expected); } -TEST_F(FormRegressionTestJak1, DmaSendDraft) { +TEST_F(FormRegressionTestJak1, DmaSend) { std::string func = "sll r0, r0, 0\n" " daddiu sp, sp, -64\n" diff --git a/test/goalc/source_templates/with_game/test-static-array-of-types.gc b/test/goalc/source_templates/with_game/test-static-array-of-types.gc new file mode 100644 index 000000000..6f98af133 --- /dev/null +++ b/test/goalc/source_templates/with_game/test-static-array-of-types.gc @@ -0,0 +1,13 @@ +;; make a type +(deftype test-basic (basic) + ((num int32))) + +;; declare an array that stores these types +(define test-array (new 'static 'boxed-array :type type test-basic)) + +;; use the array to make something +(define test-instance-basic + (new 'static 'test-basic :num 1234)) + +(when (basic-type? test-instance-basic (-> test-array 0)) + (format #t "matched!~%")) diff --git a/test/goalc/test_with_game.cpp b/test/goalc/test_with_game.cpp index 104d9af8b..6a026673a 100644 --- a/test/goalc/test_with_game.cpp +++ b/test/goalc/test_with_game.cpp @@ -771,6 +771,11 @@ TEST_F(WithGameTests, StaticLambdaArray) { {"2\n1\n0\n"}); } +TEST_F(WithGameTests, StaticTypeArray) { + shared_compiler->runner.run_static_test(testCategory, "test-static-array-of-types.gc", + {"matched!\n0\n"}); +} + TEST_F(WithGameTests, MethodReplace) { shared_compiler->runner.run_static_test(testCategory, "test-method-replace.gc", {"relocate! foo: 123 heap: 1 name: 2\n0\n"});