From ec190a145c26fb823e87eb7074f0b23c76dbc5df Mon Sep 17 00:00:00 2001 From: water Date: Sat, 9 Mar 2024 13:02:53 -0500 Subject: [PATCH] avoid too much field copy --- common/type_system/Type.cpp | 19 +++---- common/type_system/Type.h | 4 +- common/type_system/TypeSystem.cpp | 51 ++++++++++--------- common/type_system/TypeSystem.h | 5 +- common/type_system/deftype.cpp | 49 +++++++++--------- decompiler/IR2/bitfields.cpp | 12 ++--- .../analysis/analyze_inspect_method.cpp | 23 ++++----- decompiler/analysis/find_skelgroups.cpp | 2 +- decompiler/level_extractor/MercData.cpp | 5 +- decompiler/util/goal_data_reader.cpp | 38 +++++++------- goalc/compiler/compilation/Static.cpp | 37 +++++++------- goalc/compiler/compilation/Type.cpp | 4 +- test/test_type_system.cpp | 2 +- 13 files changed, 123 insertions(+), 128 deletions(-) diff --git a/common/type_system/Type.cpp b/common/type_system/Type.cpp index 5eec0cb1ae..fcd49828c0 100644 --- a/common/type_system/Type.cpp +++ b/common/type_system/Type.cpp @@ -901,18 +901,14 @@ int StructureType::get_inline_array_start_alignment() const { } } -bool StructureType::lookup_field(const std::string& name, Field* out) { +const Field* StructureType::lookup_field(const std::string& name) const { for (auto& x : m_fields) { if (x.name() == name) { - if (out) { - *out = x; - } - - return true; + return &x; } } - return false; + return nullptr; } void StructureType::override_field_type(const std::string& field_name, const TypeSpec& new_type) { @@ -1045,16 +1041,13 @@ std::string BitField::diff(const BitField& other) const { BitFieldType::BitFieldType(std::string parent, std::string name, int size, bool sign_extend) : ValueType(std::move(parent), std::move(name), false, size, sign_extend, RegClass::GPR_64) {} -bool BitFieldType::lookup_field(const std::string& name, BitField* out) const { +const BitField* BitFieldType::lookup_field(const std::string& name) const { for (auto& field : m_fields) { if (field.name() == name) { - if (out) { - *out = field; - } - return true; + return &field; } } - return false; + return nullptr; } std::string BitField::print() const { diff --git a/common/type_system/Type.h b/common/type_system/Type.h index 8527640079..9b345746af 100644 --- a/common/type_system/Type.h +++ b/common/type_system/Type.h @@ -305,7 +305,7 @@ class StructureType : public ReferenceType { int get_in_memory_alignment() const override; int get_inline_array_stride_alignment() const override; int get_inline_array_start_alignment() const override; - bool lookup_field(const std::string& name, Field* out); + const Field* lookup_field(const std::string& name) const; bool is_dynamic() const { return m_dynamic; } ~StructureType() = default; void set_pack(bool pack) { m_pack = pack; } @@ -384,7 +384,7 @@ class BitField { class BitFieldType : public ValueType { public: BitFieldType(std::string parent, std::string name, int size, bool sign_extend); - bool lookup_field(const std::string& name, BitField* out) const; + const BitField* lookup_field(const std::string& name) const; std::string print() const override; bool operator==(const Type& other) const override; const std::vector& fields() const { return m_fields; } diff --git a/common/type_system/TypeSystem.cpp b/common/type_system/TypeSystem.cpp index 9171ed1361..5ebfade740 100644 --- a/common/type_system/TypeSystem.cpp +++ b/common/type_system/TypeSystem.cpp @@ -952,42 +952,42 @@ void TypeSystem::assert_method_id(const std::string& type_name, FieldLookupInfo TypeSystem::lookup_field_info(const std::string& type_name, const std::string& field_name) const { FieldLookupInfo info; - info.field = lookup_field(type_name, field_name); + info.field = &lookup_field(type_name, field_name); // get array size, for bounds checking (when possible) - if (info.field.is_array() && !info.field.is_dynamic()) { - info.array_size = info.field.array_size(); + if (info.field->is_array() && !info.field->is_dynamic()) { + info.array_size = info.field->array_size(); } - auto base_type = lookup_type_allow_partial_def(info.field.type()); + auto base_type = lookup_type_allow_partial_def(info.field->type()); if (base_type->is_reference()) { - if (info.field.is_inline()) { - if (info.field.is_array()) { + if (info.field->is_inline()) { + if (info.field->is_array()) { // inline array of reference types info.needs_deref = false; - info.type = make_inline_array_typespec(info.field.type()); + info.type = make_inline_array_typespec(info.field->type()); } else { // inline object info.needs_deref = false; - info.type = info.field.type(); + info.type = info.field->type(); } } else { - if (info.field.is_array()) { + if (info.field->is_array()) { info.needs_deref = false; - info.type = make_pointer_typespec(info.field.type()); + info.type = make_pointer_typespec(info.field->type()); } else { info.needs_deref = true; - info.type = info.field.type(); + info.type = info.field->type(); } } } else { - if (info.field.is_array()) { + if (info.field->is_array()) { info.needs_deref = false; - info.type = make_pointer_typespec(info.field.type()); + info.type = make_pointer_typespec(info.field->type()); } else { // not array info.needs_deref = true; - info.type = info.field.type(); + info.type = info.field->type(); } } return info; @@ -999,7 +999,7 @@ FieldLookupInfo TypeSystem::lookup_field_info(const std::string& type_name, void TypeSystem::assert_field_offset(const std::string& type_name, const std::string& field_name, int offset) { - Field field = lookup_field(type_name, field_name); + const Field& field = lookup_field(type_name, field_name); if (field.offset() != offset) { throw_typesystem_error("assert_field_offset({}, {}, {}) failed - got {}\n", type_name, field_name, offset); @@ -1020,7 +1020,7 @@ int TypeSystem::add_field_to_type(StructureType* type, bool skip_in_static_decomp, double score, const std::optional decomp_as_ts) { - if (type->lookup_field(field_name, nullptr)) { + if (type->lookup_field(field_name)) { throw_typesystem_error("Type {} already has a field named {}\n", type->get_name(), field_name); } @@ -1304,13 +1304,14 @@ int TypeSystem::get_next_method_id(const Type* type) const { /*! * Lookup a field of a type by name */ -Field TypeSystem::lookup_field(const std::string& type_name, const std::string& field_name) const { +const Field& TypeSystem::lookup_field(const std::string& type_name, + const std::string& field_name) const { auto type = get_type_of_type(type_name); - Field field; - if (!type->lookup_field(field_name, &field)) { + auto field = type->lookup_field(field_name); + if (!field) { throw_typesystem_error("Type {} has no field named {}\n", type_name, field_name); } - return field; + return *field; } /*! @@ -1876,16 +1877,16 @@ bool TypeSystem::is_bitfield_type(const std::string& type_name) const { BitfieldLookupInfo TypeSystem::lookup_bitfield_info(const std::string& type_name, const std::string& field_name) const { auto type = get_type_of_type(type_name); - BitField f; - if (!type->lookup_field(field_name, &f)) { + const BitField* f = type->lookup_field(field_name); + if (!f) { throw_typesystem_error("Type {} has no bitfield named {}\n", type_name, field_name); } BitfieldLookupInfo result; - result.result_type = f.type(); - result.offset = f.offset(); + result.result_type = f->type(); + result.offset = f->offset(); result.sign_extend = lookup_type(result.result_type)->get_load_signed(); - result.size = f.size(); + result.size = f->size(); return result; } diff --git a/common/type_system/TypeSystem.h b/common/type_system/TypeSystem.h index f28cb9a693..33e039609e 100644 --- a/common/type_system/TypeSystem.h +++ b/common/type_system/TypeSystem.h @@ -17,6 +17,7 @@ #include "Type.h" #include "TypeSpec.h" +#include "common/util/StringHashTable.h" struct TypeFlags { union { @@ -31,7 +32,7 @@ struct TypeFlags { }; struct FieldLookupInfo { - Field field; + const Field* field = nullptr; TypeSpec type; bool needs_deref = true; int array_size = -1; @@ -303,7 +304,7 @@ class TypeSystem { const std::string& actual, bool allow_alias) const; int get_alignment_in_type(const Field& field); - Field lookup_field(const std::string& type_name, const std::string& field_name) const; + const Field& lookup_field(const std::string& type_name, const std::string& field_name) const; StructureType* add_builtin_structure(const std::string& parent, const std::string& type_name, bool boxed = false); diff --git a/common/type_system/deftype.cpp b/common/type_system/deftype.cpp index 513dd99405..f91398c7b6 100644 --- a/common/type_system/deftype.cpp +++ b/common/type_system/deftype.cpp @@ -106,8 +106,7 @@ void add_field( double score = 0; bool skip_in_decomp = false; std::optional decomp_as_ts = std::nullopt; - Field override_field; - bool override = false; + const Field* override_field = nullptr; if (!rest->is_empty_list()) { if (car(rest).is_int()) { @@ -131,21 +130,22 @@ void add_field( offset_override = get_int(car(rest)); rest = cdr(rest); } else if (opt_name == ":override") { - override = true; - if (!structure->lookup_field(name, &override_field)) { + override_field = structure->lookup_field(name); + if (!override_field) { throw std::runtime_error(fmt::format("Field {} not found to override", name)); } } else if (opt_name == ":overlay-at") { const auto& param = car(rest); rest = cdr(rest); - Field overlay_field; + const Field* overlay_field = nullptr; if (param.is_symbol()) { auto field_name = symbol_string(param); - if (!structure->lookup_field(field_name, &overlay_field)) { + overlay_field = structure->lookup_field(field_name); + if (!overlay_field) { throw std::runtime_error( - fmt::format("Field {} not found to overlay for {}", field_name, name)); + fmt::format("Field {} not found to overlay for {} (1)", field_name, name)); } - offset_override = overlay_field.offset(); + offset_override = overlay_field->offset(); } else if (param.is_pair() && car(¶m).is_symbol("->")) { auto name_it = cdr(¶m); if (name_it->is_empty_list()) { @@ -157,17 +157,17 @@ void add_field( while (!name_it->is_empty_list()) { const auto& deref_field = car(name_it); if (deref_field.is_int()) { - auto ref_array_field = !type_to_use && !overlay_field.is_inline() - ? ts->lookup_type_allow_partial_def(overlay_field.type()) + auto ref_array_field = !type_to_use && !overlay_field->is_inline() + ? ts->lookup_type_allow_partial_def(overlay_field->type()) : nullptr; if (ref_array_field) { // we can have an array of references (non-inline) to a forward-declared type offset_override += ref_array_field->get_load_size() * deref_field.as_int(); } else { - auto type_to_deref = type_to_use && overlay_field.is_inline() + auto type_to_deref = type_to_use && overlay_field->is_inline() ? TypeSpec("inline-array") : TypeSpec("pointer"); - type_to_deref.add_arg(overlay_field.type()); + type_to_deref.add_arg(overlay_field->type()); auto deref_info = ts->get_deref_info(type_to_deref); if (!deref_info.can_deref) { throw std::runtime_error( @@ -180,16 +180,17 @@ void add_field( if (!type_to_use) { throw std::runtime_error( fmt::format("Field {} not inside a structure for overlay-at in {}", - overlay_field.name(), name)); + overlay_field->name(), name)); } auto field_name = symbol_string(car(name_it)); - if (!type_to_use->lookup_field(field_name, &overlay_field)) { + overlay_field = type_to_use->lookup_field(field_name); + if (!overlay_field) { throw std::runtime_error( - fmt::format("Field {} not found to overlay for {}", field_name, name)); + fmt::format("Field {} not found to overlay for {} (2)", field_name, name)); } type_to_use = - dynamic_cast(ts->lookup_type_no_throw(overlay_field.type())); - offset_override += overlay_field.offset(); + dynamic_cast(ts->lookup_type_no_throw(overlay_field->type())); + offset_override += overlay_field->offset(); } name_it = cdr(name_it); } @@ -216,21 +217,21 @@ void add_field( } } - if (override && name == override_field.name()) { + if (override_field && name == override_field->name()) { // override field, e.g. (root collide-shape :overlay-at root) // does not add new field, merely rewrites inherited one - if (!ts->tc(override_field.type(), type)) { + if (!ts->tc(override_field->type(), type)) { throw std::runtime_error( fmt::format("Wanted to override field {}, but type {} isn't child of {}", - override_field.name(), type.print(), override_field.type().print())); + override_field->name(), type.print(), override_field->type().print())); } - if (override_field.is_inline() != is_inline || override_field.is_dynamic() != is_dynamic || - (array_size != -1 && override_field.array_size() != array_size)) { + if (override_field->is_inline() != is_inline || override_field->is_dynamic() != is_dynamic || + (array_size != -1 && override_field->array_size() != array_size)) { throw std::runtime_error( fmt::format("Wanted to override field {}, but some parameters were different", - override_field.name())); + override_field->name())); } - structure->override_field_type(override_field.name(), type); + structure->override_field_type(override_field->name(), type); } else { // new unique field int actual_offset = diff --git a/decompiler/IR2/bitfields.cpp b/decompiler/IR2/bitfields.cpp index 2199b6bd88..00939c2084 100644 --- a/decompiler/IR2/bitfields.cpp +++ b/decompiler/IR2/bitfields.cpp @@ -825,15 +825,15 @@ std::optional> get_field_defs_from_expr(const BitFieldT return std::nullopt; } - BitField field_info; - if (!type_info->lookup_field(maybe_field->field_name, &field_info)) { + const BitField* field_info = type_info->lookup_field(maybe_field->field_name); + if (!field_info) { ASSERT(false); } - if (field_info.type() == TypeSpec("symbol") || field_info.type() == TypeSpec("type")) { + if (field_info->type() == TypeSpec("symbol") || field_info->type() == TypeSpec("type")) { maybe_field->value = strip_int_or_uint_cast(maybe_field->value); } - if (field_info.type() == TypeSpec("float")) { + if (field_info->type() == TypeSpec("float")) { auto stripped = strip_int_or_uint_cast(maybe_field->value); auto integer = get_goal_integer_constant(stripped, env); if (integer) { @@ -845,9 +845,9 @@ std::optional> get_field_defs_from_expr(const BitFieldT } auto field_type_as_bitfield = - dynamic_cast(env.dts->ts.lookup_type(field_info.type())); + dynamic_cast(env.dts->ts.lookup_type(field_info->type())); if (field_type_as_bitfield) { - maybe_field->value = cast_to_bitfield(field_type_as_bitfield, field_info.type(), pool, env, + maybe_field->value = cast_to_bitfield(field_type_as_bitfield, field_info->type(), pool, env, maybe_field->value); } diff --git a/decompiler/analysis/analyze_inspect_method.cpp b/decompiler/analysis/analyze_inspect_method.cpp index 3039df2ec1..dba293d25b 100644 --- a/decompiler/analysis/analyze_inspect_method.cpp +++ b/decompiler/analysis/analyze_inspect_method.cpp @@ -1522,10 +1522,9 @@ std::string TypeInspectorResult::print_as_deftype( continue; } if (old_game_type) { - Field old_field; - if (old_game_type->lookup_field(field.name(), &old_field) && - field.type() != old_field.type()) { - field.type() = old_field.type(); + const Field* old_field = old_game_type->lookup_field(field.name()); + if (old_field && field.type() != old_field->type()) { + field.type() = old_field->type(); was_guess.push_back(true); } else { was_guess.push_back(false); @@ -1608,17 +1607,17 @@ std::string TypeInspectorResult::print_as_deftype( result.append(std::to_string(field.offset())); result.append(")"); if (old_game_type) { - Field old_field; - if (old_game_type->lookup_field(field.name(), &old_field)) { - if (old_field.type() != field.type()) { - result += fmt::format(" ;; {}", old_field.type().print()); - if (old_field.is_array() && !old_field.is_dynamic()) { - result += fmt::format(" {}", old_field.array_size()); + const Field* old_field = old_game_type->lookup_field(field.name()); + if (old_field) { + if (old_field->type() != field.type()) { + result += fmt::format(" ;; {}", old_field->type().print()); + if (old_field->is_array() && !old_field->is_dynamic()) { + result += fmt::format(" {}", old_field->array_size()); } - if (old_field.is_inline()) { + if (old_field->is_inline()) { result += " :inline"; } - if (old_field.is_dynamic()) { + if (old_field->is_dynamic()) { result += " :dynamic"; } } diff --git a/decompiler/analysis/find_skelgroups.cpp b/decompiler/analysis/find_skelgroups.cpp index 869374a8b4..a4d8e5f962 100644 --- a/decompiler/analysis/find_skelgroups.cpp +++ b/decompiler/analysis/find_skelgroups.cpp @@ -571,7 +571,7 @@ void inspect_cloth_data_jak3(LetElement* let, DefskelgroupElement::StaticInfo& i if (array_set) { // get elements auto elts = when_body->elts().size() - 2; - for (int i = 0; i < elts; i++) { + for (size_t i = 0; i < elts; i++) { auto parms_form = dynamic_cast(when_body->at(i + 1)); if (parms_form) { auto parms_data = dynamic_cast(parms_form->src()->at(0)); diff --git a/decompiler/level_extractor/MercData.cpp b/decompiler/level_extractor/MercData.cpp index 8709262830..69678029f4 100644 --- a/decompiler/level_extractor/MercData.cpp +++ b/decompiler/level_extractor/MercData.cpp @@ -362,14 +362,13 @@ void MercEffect::from_ref(TypedRef tr, tri_count = read_plain_data_field(tr, "tri-count", dts); dvert_count = read_plain_data_field(tr, "dvert-count", dts); auto* type = dynamic_cast(dts.ts.lookup_type("merc-effect")); - Field temp; - if (type->lookup_field("envmap-usage", &temp)) { + if (type->lookup_field("envmap-usage")) { envmap_or_effect_usage = read_plain_data_field(tr, "envmap-usage", dts); } else { envmap_or_effect_usage = read_plain_data_field(tr, "effect-usage", dts); } - if (type->lookup_field("texture-index", &temp)) { + if (type->lookup_field("texture-index")) { texture_index = read_plain_data_field(tr, "texture-index", dts); } diff --git a/decompiler/util/goal_data_reader.cpp b/decompiler/util/goal_data_reader.cpp index 12777b8495..7d26d57936 100644 --- a/decompiler/util/goal_data_reader.cpp +++ b/decompiler/util/goal_data_reader.cpp @@ -11,8 +11,8 @@ void read_plain_data_field(const TypedRef& object, u8* out) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); - if (field_info.field.is_dynamic() || field_info.field.is_array() || - field_info.field.is_inline()) { + if (field_info.field->is_dynamic() || field_info.field->is_array() || + field_info.field->is_inline()) { throw Error("Field {} is dynamic/array/inline and can't be used with read_plain_data_field", field_name); } @@ -36,7 +36,7 @@ void read_plain_data_field(const TypedRef& object, const auto& words = object.ref.data->words_by_seg.at(object.ref.seg); for (int byte = 0; byte < size_bytes; byte++) { - int byte_in_words = byte + object.ref.byte_offset + field_info.field.offset(); + int byte_in_words = byte + object.ref.byte_offset + field_info.field->offset(); int word_idx = byte_in_words / 4; int byte_in_word = byte_in_words % 4; @@ -80,13 +80,13 @@ decompiler::LinkedWord::Kind get_word_kind_for_field(const TypedRef& object, const decompiler::DecompilerTypeSystem& dts) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); - if (field_info.field.is_dynamic() || field_info.field.is_array() || - field_info.field.is_inline()) { + if (field_info.field->is_dynamic() || field_info.field->is_array() || + field_info.field->is_inline()) { throw Error("Field {} is dynamic/array/inline and can't be used with get_word_kind_for_field", field_name); } - int byte_in_words = object.ref.byte_offset + field_info.field.offset(); + int byte_in_words = object.ref.byte_offset + field_info.field->offset(); if ((byte_in_words % 4) != 0) { throw Error("Field {} was misaligned.", field_name); } @@ -100,8 +100,8 @@ TypedRef get_and_check_ref_to_basic(const TypedRef& object, const decompiler::DecompilerTypeSystem& dts) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); - if (field_info.field.is_dynamic() || field_info.field.is_array() || - field_info.field.is_inline()) { + if (field_info.field->is_dynamic() || field_info.field->is_array() || + field_info.field->is_inline()) { throw Error( "Field {} is dynamic/array/inline and can't be used with get_and_check_ref_to_basic", field_name); @@ -113,7 +113,7 @@ TypedRef get_and_check_ref_to_basic(const TypedRef& object, throw Error("Field {} is not a basic and can't be used with read_plain_data_field", field_name); } - int byte_in_words = object.ref.byte_offset + field_info.field.offset(); + int byte_in_words = object.ref.byte_offset + field_info.field->offset(); if ((byte_in_words % 4) != 0) { throw Error("Field {} was misaligned.", field_name); } @@ -156,8 +156,8 @@ std::string read_symbol_field(const TypedRef& object, const decompiler::DecompilerTypeSystem& dts) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); - if (field_info.field.is_dynamic() || field_info.field.is_array() || - field_info.field.is_inline()) { + if (field_info.field->is_dynamic() || field_info.field->is_array() || + field_info.field->is_inline()) { throw Error("Field {} is dynamic/array/inline and can't be used with read_symbol_field", field_name); } @@ -167,7 +167,7 @@ std::string read_symbol_field(const TypedRef& object, field_info.type.print()); } - int byte_in_words = object.ref.byte_offset + field_info.field.offset(); + int byte_in_words = object.ref.byte_offset + field_info.field->offset(); if ((byte_in_words % 4) != 0) { throw Error("Field {} was misaligned.", field_name); } @@ -187,8 +187,8 @@ std::string read_type_field(const TypedRef& object, bool ignore_field_type) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); - if (field_info.field.is_dynamic() || field_info.field.is_array() || - field_info.field.is_inline()) { + if (field_info.field->is_dynamic() || field_info.field->is_array() || + field_info.field->is_inline()) { throw Error("Field {} is dynamic/array/inline and can't be used with read_type_field", field_name); } @@ -198,7 +198,7 @@ std::string read_type_field(const TypedRef& object, field_info.type.print()); } - int byte_in_words = object.ref.byte_offset + field_info.field.offset(); + int byte_in_words = object.ref.byte_offset + field_info.field->offset(); if ((byte_in_words % 4) != 0) { throw Error("Field {} was misaligned.", field_name); } @@ -243,8 +243,8 @@ std::string read_string_field(const TypedRef& object, bool ignore_field_type) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); - if (field_info.field.is_dynamic() || field_info.field.is_array() || - field_info.field.is_inline()) { + if (field_info.field->is_dynamic() || field_info.field->is_array() || + field_info.field->is_inline()) { throw Error("Field {} is dynamic/array/inline and can't be used with read_string_field", field_name); } @@ -254,7 +254,7 @@ std::string read_string_field(const TypedRef& object, field_info.type.print()); } - int byte_in_words = object.ref.byte_offset + field_info.field.offset(); + int byte_in_words = object.ref.byte_offset + field_info.field->offset(); if ((byte_in_words % 4) != 0) { throw Error("Field {} was misaligned.", field_name); } @@ -273,7 +273,7 @@ Ref get_field_ref(const TypedRef& object, const decompiler::DecompilerTypeSystem& dts) { FieldLookupInfo field_info = dts.ts.lookup_field_info(object.type->get_name(), field_name); Ref result = object.ref; - result.byte_offset += field_info.field.offset(); + result.byte_offset += field_info.field->offset(); return result; } diff --git a/goalc/compiler/compilation/Static.cpp b/goalc/compiler/compilation/Static.cpp index 57f1e42341..2908fc3640 100644 --- a/goalc/compiler/compilation/Static.cpp +++ b/goalc/compiler/compilation/Static.cpp @@ -46,10 +46,10 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, field_name_def = field_name_def.substr(1); auto field_info = m_ts.lookup_field_info(type_info->get_name(), field_name_def); - auto field_offset = field_info.field.offset() + offset; + auto field_offset = field_info.field->offset() + offset; - if (field_info.field.is_array()) { - bool is_inline = field_info.field.is_inline(); + if (field_info.field->is_array()) { + bool is_inline = field_info.field->is_inline(); // for an array field, we only accept (new 'static 'array ...) if (!field_value.is_list()) { @@ -85,20 +85,21 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, auto array_content_type = parse_typespec(new_form.at(3), env); if (is_inline) { - if (field_info.field.type() != array_content_type) { + if (field_info.field->type() != array_content_type) { throw_compiler_error(field_value, "Inline array field must have the correct type"); } } else { // allow more specific types. // TODO make this better. - m_ts.typecheck_and_throw(field_info.field.type(), array_content_type, "Array content type"); + m_ts.typecheck_and_throw(field_info.field->type(), array_content_type, + "Array content type"); } s64 elt_array_len = get_constant_integer_or_error(new_form.at(4), env); - if (!field_info.field.is_dynamic() && elt_array_len != field_info.field.array_size()) { + if (!field_info.field->is_dynamic() && elt_array_len != field_info.field->array_size()) { throw_compiler_error(field_value, "Array field had an expected size of {} but got {}", - field_info.field.array_size(), elt_array_len); + field_info.field->array_size(), elt_array_len); } auto arg_list = get_list_as_vector(field_value.as_pair()->cdr); @@ -107,14 +108,14 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, } if (is_inline) { - if (field_info.field.is_dynamic()) { + if (field_info.field->is_dynamic()) { throw_compiler_error(form, "Dynamic fields are not supported for inline"); } - fill_static_inline_array_inline(field_value, field_info.field.type(), arg_list, structure, + fill_static_inline_array_inline(field_value, field_info.field->type(), arg_list, structure, field_offset, env); } else { int num_elts = arg_list.size() - 4; - if (field_info.field.is_dynamic()) { + if (field_info.field->is_dynamic()) { // need to resize data // first, expected original size int expected_data_size = type_info->get_size_in_memory(); @@ -124,7 +125,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, int increase_by = stride * num_elts; structure->data.resize(expected_data_size + increase_by); } - fill_static_array_inline(field_value, field_info.field.type(), arg_list.data() + 4, + fill_static_array_inline(field_value, field_info.field->type(), arg_list.data() + 4, num_elts, structure, field_offset, env); } @@ -132,7 +133,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, ASSERT(field_info.needs_deref); // for now... auto deref_info = m_ts.get_deref_info(m_ts.make_pointer_typespec(field_info.type)); ASSERT(field_offset + deref_info.load_size <= int(structure->data.size())); - ASSERT(!field_info.field.is_inline()); + ASSERT(!field_info.field->is_inline()); auto sr = compile_static(field_value, env); if (!sr.is_constant_data()) { throw_compiler_error(form, "Could not use {} for an integer field", field_value.print()); @@ -153,10 +154,10 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, } else if (is_structure(field_info.type) || is_pair(field_info.type) || is_symbol(field_info.type) || field_info.type == TypeSpec("object")) { if (is_pair(field_info.type)) { - ASSERT(!field_info.field.is_inline()); + ASSERT(!field_info.field->is_inline()); } - if (field_info.field.is_inline()) { + if (field_info.field->is_inline()) { // for an inline field, we only accept (new 'static ' ...) if (!field_value.is_list()) { throw_compiler_error(field_value, "Inline field was not properly specified"); @@ -200,7 +201,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, if (sr.is_symbol()) { if (sr.symbol_name() != "#f" && sr.symbol_name() != "_empty_") { typecheck(form, field_info.type, sr.typespec(), - fmt::format("Field {}, containing symbol {}", field_info.field.name(), + fmt::format("Field {}, containing symbol {}", field_info.field->name(), sr.symbol_name())); } structure->add_symbol_record(sr.symbol_name(), field_offset); @@ -232,7 +233,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, auto deref_info = m_ts.get_deref_info(m_ts.make_pointer_typespec(field_info.type)); auto field_size = deref_info.load_size; ASSERT(field_offset + field_size <= int(structure->data.size())); - ASSERT(!field_info.field.is_inline()); + ASSERT(!field_info.field->is_inline()); auto sr = compile_static(field_value, env); if (!sr.is_constant_data()) { throw_compiler_error(form, "Could not use {} for a float field", field_value.print()); @@ -254,7 +255,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, u32 linker_val = 0xffffffff; memcpy(structure->data.data() + field_offset, &linker_val, 4); } else if (!sr.is_reference()) { - throw_compiler_error(form, "Invalid definition of field {}", field_info.field.name()); + throw_compiler_error(form, "Invalid definition of field {}", field_info.field->name()); } else { typecheck(form, field_info.type, sr.typespec()); ASSERT(sr.reference()->get_addr_offset() == 0); @@ -276,7 +277,7 @@ void Compiler::compile_static_structure_inline(const goos::Object& form, memcpy(structure->data.data() + field_offset, &linker_val, 4); } else { if (!sr.is_reference()) { - throw_compiler_error(form, "Invalid definition of field {}", field_info.field.name()); + throw_compiler_error(form, "Invalid definition of field {}", field_info.field->name()); } typecheck(form, field_info.type, sr.typespec()); ASSERT(sr.reference()->get_addr_offset() == 0); diff --git a/goalc/compiler/compilation/Type.cpp b/goalc/compiler/compilation/Type.cpp index 6f8bbaa287..f905d9287d 100644 --- a/goalc/compiler/compilation/Type.cpp +++ b/goalc/compiler/compilation/Type.cpp @@ -658,7 +658,7 @@ Val* Compiler::get_field_of_structure(const StructureType* type, if (field.needs_deref) { TypeSpec loc_type = m_ts.make_pointer_typespec(field.type); auto loc = - fe->alloc_val(loc_type, object, field.field.offset() + offset); + fe->alloc_val(loc_type, object, field.field->offset() + offset); auto di = m_ts.get_deref_info(loc_type); ASSERT(di.can_deref); ASSERT(di.mem_deref); @@ -669,7 +669,7 @@ Val* Compiler::get_field_of_structure(const StructureType* type, field.type.base_type() == "inline-array" ? field.type.get_single_arg() : field.type; auto field_type_info = m_ts.lookup_type(type_for_offset); result = fe->alloc_val( - field.type, object, field.field.offset() + offset + field_type_info->get_offset()); + field.type, object, field.field->offset() + offset + field_type_info->get_offset()); result->mark_as_settable(); } return result; diff --git a/test/test_type_system.cpp b/test/test_type_system.cpp index 7a6541b9da..84694039d1 100644 --- a/test/test_type_system.cpp +++ b/test/test_type_system.cpp @@ -352,7 +352,7 @@ TEST(TypeSystem, FieldLookup) { TypeSystem ts; ts.add_builtin_types(GameVersion::Jak1); - EXPECT_EQ(ts.lookup_field_info("type", "parent").field.offset(), 8); + EXPECT_EQ(ts.lookup_field_info("type", "parent").field->offset(), 8); EXPECT_EQ(ts.lookup_field_info("string", "data").type.print(), "(pointer uint8)"); EXPECT_ANY_THROW(ts.lookup_field_info("type", "not-a-real-field"));