diff --git a/decompiler/config/jak1_ntsc_black_label.jsonc b/decompiler/config/jak1_ntsc_black_label.jsonc index 8ea050f7c6..7bfdb7cde2 100644 --- a/decompiler/config/jak1_ntsc_black_label.jsonc +++ b/decompiler/config/jak1_ntsc_black_label.jsonc @@ -4,7 +4,7 @@ // if you want to filter to only some object names. // it will make the decompiler much faster. "allowed_objects": [], - "banned_objects": [], + "banned_objects": ["collide-mesh"], //////////////////////////// // CODE ANALYSIS OPTIONS diff --git a/docs/markdown/progress-notes/changelog.md b/docs/markdown/progress-notes/changelog.md index a936cab78d..7f40b69cc6 100644 --- a/docs/markdown/progress-notes/changelog.md +++ b/docs/markdown/progress-notes/changelog.md @@ -206,4 +206,5 @@ - Using `->` on a plain `pointer` or `inline-array` now generates an error instead of crashing the compiler - It is now possible to use a macro to provide a static inline array element definition - It is now possible to have symbol names that have a `#` in the middle of them -- `go-hook` now returns the return value of the `enter-state` function it calls \ No newline at end of file +- `go-hook` now returns the return value of the `enter-state` function it calls +- Added a `(declare-file (debug))` to put things in the debug segment by default. This only changes _static_ objects. Dynamic allocation with forms like `cons` will continue to use the main segment like before. \ No newline at end of file diff --git a/goal_src/engine/camera/cam-layout.gc b/goal_src/engine/camera/cam-layout.gc index c1d993ab76..9cd3b60f01 100644 --- a/goal_src/engine/camera/cam-layout.gc +++ b/goal_src/engine/camera/cam-layout.gc @@ -5,6 +5,8 @@ ;; name in dgo: cam-layout ;; dgos: GAME, ENGINE +(declare-file (debug)) + ;; DECOMP BEGINS ;; this file is debug only diff --git a/goal_src/engine/debug/anim-tester.gc b/goal_src/engine/debug/anim-tester.gc index 9fca89c41e..380474a7be 100644 --- a/goal_src/engine/debug/anim-tester.gc +++ b/goal_src/engine/debug/anim-tester.gc @@ -8,6 +8,8 @@ ;; NOTES - removed one of the 2 inspects ;; - also fixed up a basic file-stream constructor on the stack +(declare-file (debug)) + (declare-type list-control structure) (define-extern anim-test-anim-list-handler (function int list-control symbol)) (define-extern anim-test-edit-sequence-list-handler (function int list-control symbol)) diff --git a/goal_src/engine/debug/default-menu.gc b/goal_src/engine/debug/default-menu.gc index a7752867cf..640c9f12f4 100644 --- a/goal_src/engine/debug/default-menu.gc +++ b/goal_src/engine/debug/default-menu.gc @@ -5,6 +5,8 @@ ;; name in dgo: default-menu ;; dgos: GAME, ENGINE +(declare-file (debug)) + ;; Forward declarations for stuff we haven't written yet: (define-extern *edit-instance* string) diff --git a/goalc/compiler/Compiler.h b/goalc/compiler/Compiler.h index dbd38a48b7..56fc95d145 100644 --- a/goalc/compiler/Compiler.h +++ b/goalc/compiler/Compiler.h @@ -125,7 +125,7 @@ class Compiler { Val* compile_float(float value, Env* env, int seg); Val* compile_symbol(const goos::Object& form, Env* env); Val* compile_string(const goos::Object& form, Env* env); - Val* compile_string(const std::string& str, Env* env, int seg = MAIN_SEGMENT); + Val* compile_string(const std::string& str, Env* env, int seg); Val* compile_get_symbol_value(const goos::Object& form, const std::string& name, Env* env); Val* compile_function_or_method_call(const goos::Object& form, Env* env); @@ -233,15 +233,20 @@ class Compiler { Env* env, bool call_constructor); - StaticResult fill_static_array(const goos::Object& form, const goos::Object& rest, Env* env); + StaticResult fill_static_array(const goos::Object& form, + const goos::Object& rest, + Env* env, + int seg); StaticResult fill_static_boxed_array(const goos::Object& form, const goos::Object& rest, - Env* env); + Env* env, + int seg); StaticResult fill_static_inline_array(const goos::Object& form, const goos::Object& rest, - Env* env); + Env* env, + int seg); void fill_static_inline_array_inline(const goos::Object& form, const TypeSpec& content_type, @@ -330,10 +335,11 @@ class Compiler { Val* compile_new_static_structure_or_basic(const goos::Object& form, const TypeSpec& type, const goos::Object& field_defs, - Env* env); - Val* compile_static_pair(const goos::Object& form, Env* env); + Env* env, + int seg); + Val* compile_static_pair(const goos::Object& form, Env* env, int seg); StaticResult compile_static(const goos::Object& form, Env* env); - StaticResult compile_static_no_eval_for_pairs(const goos::Object& form, Env* env); + StaticResult compile_static_no_eval_for_pairs(const goos::Object& form, Env* env, int seg); Val* compile_bitfield_definition(const goos::Object& form, const TypeSpec& type, @@ -343,7 +349,8 @@ class Compiler { StaticResult compile_new_static_structure(const goos::Object& form, const TypeSpec& type, const goos::Object& _field_defs, - Env* env); + Env* env, + int seg); void compile_static_structure_inline(const goos::Object& form, const TypeSpec& type, @@ -606,6 +613,7 @@ class Compiler { Val* compile_inline(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_declare(const goos::Object& form, const goos::Object& rest, Env* env); Val* compile_local_vars(const goos::Object& form, const goos::Object& rest, Env* env); + Val* compile_declare_file(const goos::Object& form, const goos::Object& rest, Env* env); // Type Val* compile_deftype(const goos::Object& form, const goos::Object& rest, Env* env); diff --git a/goalc/compiler/Env.h b/goalc/compiler/Env.h index fae453fe50..0f85af8c80 100644 --- a/goalc/compiler/Env.h +++ b/goalc/compiler/Env.h @@ -118,12 +118,16 @@ class FileEnv : public Env { return (T*)m_vals.back().get(); } + int default_segment() const { return m_default_segment; } + void set_debug_file() { m_default_segment = DEBUG_SEGMENT; } + protected: std::string m_name; std::vector> m_functions; std::vector> m_statics; int m_anon_func_counter = 0; std::vector> m_vals; + int m_default_segment = MAIN_SEGMENT; // statics FunctionEnv* m_top_level_func = nullptr; @@ -192,6 +196,14 @@ class FunctionEnv : public DeclareEnv { int align_bytes); int stack_slots_used_for_stack_vars() const { return m_stack_var_slots_used; } + int segment_for_static_data() { + if (segment == TOP_LEVEL_SEGMENT) { + return file_env()->default_segment(); + } else { + return segment; + } + } + int idx_in_file = -1; template diff --git a/goalc/compiler/compilation/Atoms.cpp b/goalc/compiler/compilation/Atoms.cpp index ce2c71015e..96ce9a1209 100644 --- a/goalc/compiler/compilation/Atoms.cpp +++ b/goalc/compiler/compilation/Atoms.cpp @@ -208,6 +208,7 @@ const std::unordered_map< {"declare", &Compiler::compile_declare}, {"inline", &Compiler::compile_inline}, {"local-vars", &Compiler::compile_local_vars}, + {"declare-file", &Compiler::compile_declare_file}, // {"with-inline", &Compiler::compile_with_inline}, // {"get-ra-ptr", &Compiler::compile_get_ra_ptr}, @@ -428,14 +429,12 @@ Val* Compiler::compile_symbol(const goos::Object& form, Env* env) { } /*! - * Compile a string constant. The constant is placed in the same segment as the parent function. + * Compile a string constant. The constant is placed in the same segment as the parent function. For + * top-level functions, the string is placed in the file's default segment. */ Val* Compiler::compile_string(const goos::Object& form, Env* env) { - auto segment = env->function_env()->segment; - if (segment == TOP_LEVEL_SEGMENT) { - segment = MAIN_SEGMENT; - } - return compile_string(form.as_string()->data, env, segment); + return compile_string(form.as_string()->data, env, + env->function_env()->segment_for_static_data()); } /*! @@ -456,12 +455,10 @@ Val* Compiler::compile_string(const std::string& str, Env* env, int seg) { * of the code, at least in Jak 1. */ Val* Compiler::compile_float(const goos::Object& code, Env* env) { - auto segment = env->function_env()->segment; - if (segment == TOP_LEVEL_SEGMENT) { - segment = MAIN_SEGMENT; - } assert(code.is_float()); - return compile_float(code.float_obj.value, env, segment); + // TODO: this will put top-level only floats in main. Which is conservative because I + // don't think we can take the address of a float constant. + return compile_float(code.float_obj.value, env, env->function_env()->segment_for_static_data()); } /*! diff --git a/goalc/compiler/compilation/Function.cpp b/goalc/compiler/compilation/Function.cpp index c5c7ac3fef..8387842a29 100644 --- a/goalc/compiler/compilation/Function.cpp +++ b/goalc/compiler/compilation/Function.cpp @@ -149,11 +149,7 @@ Val* Compiler::compile_lambda(const goos::Object& form, const goos::Object& rest args.has_named("inline-only") && symbol_string(args.get_named("inline-only")) != "#f"; // pick default segment to store function in. - int segment = MAIN_SEGMENT; - if (fe->segment == DEBUG_SEGMENT) { - // make anonymous lambdas in debug functions also go to debug - segment = DEBUG_SEGMENT; - } + int segment = fe->segment_for_static_data(); // override default segment. if (args.has_named("segment")) { @@ -714,3 +710,34 @@ Val* Compiler::compile_declare(const goos::Object& form, const goos::Object& res }); return get_none(); } + +Val* Compiler::compile_declare_file(const goos::Object& /*form*/, + const goos::Object& rest, + Env* env) { + for_each_in_list(rest, [&](const goos::Object& o) { + if (!o.is_pair()) { + throw_compiler_error(o, "Invalid declare-file specification."); + } + + auto first = o.as_pair()->car; + auto rrest = &o.as_pair()->cdr; + + if (!first.is_symbol()) { + throw_compiler_error( + first, "Invalid declare option specification, expected a symbol, but got {} instead.", + first.print()); + } + + if (first.as_symbol()->name == "debug") { + if (!rrest->is_empty_list()) { + throw_compiler_error(first, "Invalid debug declare"); + } + env->file_env()->set_debug_file(); + + } else { + throw_compiler_error(first, "Unrecognized declare-file option {}.", first.print()); + } + }); + + return get_none(); +} \ No newline at end of file diff --git a/goalc/compiler/compilation/Macro.cpp b/goalc/compiler/compilation/Macro.cpp index f44332cd83..f0774ae408 100644 --- a/goalc/compiler/compilation/Macro.cpp +++ b/goalc/compiler/compilation/Macro.cpp @@ -146,7 +146,7 @@ Val* Compiler::compile_quote(const goos::Object& form, const goos::Object& rest, return empty_pair; } case goos::ObjectType::PAIR: - return compile_static_pair(thing, env); + return compile_static_pair(thing, env, env->function_env()->segment_for_static_data()); default: throw_compiler_error(form, "Quote is not yet implemented for {}.", thing.print()); } diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index fafa134499..7aab3f6e7f 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -264,14 +264,15 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, StaticResult Compiler::compile_new_static_structure(const goos::Object& form, const TypeSpec& type, const goos::Object& _field_defs, - Env* env) { + Env* env, + int seg) { std::unique_ptr obj; if (is_basic(type)) { - obj = std::make_unique(MAIN_SEGMENT, type.base_type()); + obj = std::make_unique(seg, type.base_type()); } else { // if we ever find this type of static data outside of MAIN_SEGMENT, we can create an option // in the new form to pick the segment. - obj = std::make_unique(MAIN_SEGMENT); + obj = std::make_unique(seg); } auto type_info = dynamic_cast(m_ts.lookup_type(type)); @@ -554,22 +555,19 @@ Val* Compiler::compile_bitfield_definition(const goos::Object& form, * - Integers * - Strings */ -StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form, Env* env) { +StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form, + Env* env, + int seg) { auto fie = env->file_env(); - auto fe = env->function_env(); - auto segment = fe->segment; - if (segment == TOP_LEVEL_SEGMENT) { - segment = MAIN_SEGMENT; - } if (form.is_pair()) { if (form.as_pair()->car.is_symbol() && (form.as_pair()->car.as_symbol()->name == "new" || form.as_pair()->car.as_symbol()->name == "the" || form.as_pair()->car.as_symbol()->name == "lambda")) { return compile_static(form, env); } - auto car = compile_static_no_eval_for_pairs(form.as_pair()->car, env); - auto cdr = compile_static_no_eval_for_pairs(form.as_pair()->cdr, env); - auto pair_structure = std::make_unique(car, cdr, segment); + auto car = compile_static_no_eval_for_pairs(form.as_pair()->car, env, seg); + auto cdr = compile_static_no_eval_for_pairs(form.as_pair()->cdr, env, seg); + auto pair_structure = std::make_unique(car, cdr, seg); auto result = StaticResult::make_structure_reference(pair_structure.get(), m_ts.make_typespec("pair")); fie->add_static(std::move(pair_structure)); @@ -588,7 +586,7 @@ StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form return StaticResult::make_symbol("_empty_"); } else if (form.is_string()) { // todo - this should eventually work with a string pool - auto obj = std::make_unique(form.as_string()->data, segment); + auto obj = std::make_unique(form.as_string()->data, seg); auto result = StaticResult::make_structure_reference(obj.get(), m_ts.make_typespec("string")); fie->add_static(std::move(obj)); return result; @@ -599,7 +597,7 @@ StaticResult Compiler::compile_static_no_eval_for_pairs(const goos::Object& form } /*! - * Generic copmilation function to handle: + * Generic compilation function to handle: * - (new 'static ), a reference * * - (new 'static '), an integer constant @@ -616,10 +614,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env auto form = expand_macro_completely(form_before_macro, env); auto fie = env->file_env(); auto fe = env->function_env(); - auto segment = fe->segment; - if (segment == TOP_LEVEL_SEGMENT) { - segment = MAIN_SEGMENT; - } + auto segment = fe->segment_for_static_data(); if (form.is_symbol()) { // constant, #t, or #f @@ -660,7 +655,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env throw_compiler_error(form, "The form {} is an invalid quoted form.", form.print()); } if (second.is_pair() || second.is_empty_list()) { - return compile_static_no_eval_for_pairs(second, env); + return compile_static_no_eval_for_pairs(second, env, segment); } else { throw_compiler_error(form, "Could not evaluate the quoted form {} at compile time.", second.print()); @@ -685,11 +680,11 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env } if (unquote(args.at(1)).as_symbol()->name == "boxed-array") { - return fill_static_boxed_array(form, rest, env); + return fill_static_boxed_array(form, rest, env, segment); } else if (unquote(args.at(1)).as_symbol()->name == "array") { - return fill_static_array(form, rest, env); + return fill_static_array(form, rest, env, segment); } else if (unquote(args.at(1)).as_symbol()->name == "inline-array") { - return fill_static_inline_array(form, rest, env); + return fill_static_inline_array(form, rest, env, segment); } else { auto ts = parse_typespec(unquote(args.at(1))); if (ts == TypeSpec("string")) { @@ -710,7 +705,7 @@ StaticResult Compiler::compile_static(const goos::Object& form_before_macro, Env compile_bitfield_definition(form, ts, constructor_args, false, env)); return StaticResult::make_constant_data(val->value(), val->type()); } else if (is_structure(ts)) { - return compile_new_static_structure(form, ts, constructor_args, env); + return compile_new_static_structure(form, ts, constructor_args, env, segment); } else { throw_compiler_error(form, "Cannot construct a static {}.", ts.print()); } @@ -831,7 +826,8 @@ void Compiler::fill_static_array_inline(const goos::Object& form, StaticResult Compiler::fill_static_array(const goos::Object& form, const goos::Object& rest, - Env* env) { + Env* env, + int seg) { auto fie = env->file_env(); // (new 'static 'boxed-array ...) // get all arguments now @@ -851,10 +847,9 @@ StaticResult Compiler::fill_static_array(const goos::Object& form, assert(deref_info.can_deref); assert(deref_info.mem_deref); auto array_data_size_bytes = length * deref_info.stride; - // todo, segments std::unique_ptr obj; - obj = std::make_unique(MAIN_SEGMENT); + obj = std::make_unique(seg); obj->data.resize(array_data_size_bytes); @@ -870,7 +865,8 @@ StaticResult Compiler::fill_static_array(const goos::Object& form, StaticResult Compiler::fill_static_boxed_array(const goos::Object& form, const goos::Object& rest, - Env* env) { + Env* env, + int seg) { auto fie = env->file_env(); // (new 'static 'boxed-array ...) // get all arguments now @@ -923,7 +919,7 @@ StaticResult Compiler::fill_static_boxed_array(const goos::Object& form, auto array_data_size_bytes = allocated_length * deref_info.stride; // todo, segments std::unique_ptr obj; - obj = std::make_unique(MAIN_SEGMENT, "array"); + obj = std::make_unique(seg, "array"); int array_header_size = 16; obj->data.resize(array_header_size + array_data_size_bytes); @@ -1002,7 +998,8 @@ void Compiler::fill_static_inline_array_inline(const goos::Object& form, StaticResult Compiler::fill_static_inline_array(const goos::Object& form, const goos::Object& rest, - Env* env) { + Env* env, + int seg) { auto fie = env->file_env(); // (new 'static 'inline-array ...) // get all arguments now @@ -1021,8 +1018,7 @@ StaticResult Compiler::fill_static_inline_array(const goos::Object& form, auto deref_info = m_ts.get_deref_info(inline_array_type); assert(deref_info.can_deref); assert(!deref_info.mem_deref); - // todo - auto obj = std::make_unique(MAIN_SEGMENT); + auto obj = std::make_unique(seg); obj->set_offset(is_basic(content_type) ? 4 : 0); obj->data.resize(length * deref_info.stride); @@ -1035,9 +1031,9 @@ StaticResult Compiler::fill_static_inline_array(const goos::Object& form, return result; } -Val* Compiler::compile_static_pair(const goos::Object& form, Env* env) { +Val* Compiler::compile_static_pair(const goos::Object& form, Env* env, int seg) { assert(form.is_pair()); // (quote PAIR) - auto result = compile_static_no_eval_for_pairs(form, env); + auto result = compile_static_no_eval_for_pairs(form, env, seg); assert(result.is_reference()); auto fe = env->function_env(); auto static_result = fe->alloc_val(result.reference(), result.typespec()); @@ -1047,9 +1043,10 @@ Val* Compiler::compile_static_pair(const goos::Object& form, Env* env) { Val* Compiler::compile_new_static_structure_or_basic(const goos::Object& form, const TypeSpec& type, const goos::Object& field_defs, - Env* env) { + Env* env, + int seg) { auto fe = env->function_env(); - auto sr = compile_new_static_structure(form, type, field_defs, env); + auto sr = compile_new_static_structure(form, type, field_defs, env, seg); auto result = fe->alloc_val(sr.reference(), type); return result; } diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 59edfdcb5d..e79af5f9da 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -485,7 +485,7 @@ Val* Compiler::compile_defmethod(const goos::Object& form, const goos::Object& _ place->func = nullptr; auto new_func_env = std::make_unique(env, lambda.debug_name, &m_goos.reader); - new_func_env->set_segment(MAIN_SEGMENT); // todo, how do we set debug? + new_func_env->set_segment(env->function_env()->segment_for_static_data()); new_func_env->method_of_type_name = symbol_string(type_name); // set up arguments @@ -1060,7 +1060,8 @@ Val* Compiler::compile_static_new(const goos::Object& form, } else { auto type_of_object = parse_typespec(unquote(type)); if (is_structure(type_of_object)) { - return compile_new_static_structure_or_basic(form, type_of_object, *rest, env); + return compile_new_static_structure_or_basic(form, type_of_object, *rest, env, + env->function_env()->segment_for_static_data()); } if (is_bitfield(type_of_object)) {