mirror of
https://github.com/open-goal/jak-project
synced 2026-07-12 07:38:53 -04:00
avoid too much field copy
This commit is contained in:
@@ -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 {
|
||||
|
||||
@@ -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<BitField>& fields() const { return m_fields; }
|
||||
|
||||
@@ -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<TypeSpec> 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<StructureType>(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<BitFieldType>(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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -106,8 +106,7 @@ void add_field(
|
||||
double score = 0;
|
||||
bool skip_in_decomp = false;
|
||||
std::optional<TypeSpec> 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<StructureType*>(ts->lookup_type_no_throw(overlay_field.type()));
|
||||
offset_override += overlay_field.offset();
|
||||
dynamic_cast<StructureType*>(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 =
|
||||
|
||||
@@ -825,15 +825,15 @@ std::optional<std::vector<BitFieldDef>> 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<std::vector<BitFieldDef>> get_field_defs_from_expr(const BitFieldT
|
||||
}
|
||||
|
||||
auto field_type_as_bitfield =
|
||||
dynamic_cast<BitFieldType*>(env.dts->ts.lookup_type(field_info.type()));
|
||||
dynamic_cast<BitFieldType*>(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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<SetFormFormElement*>(when_body->at(i + 1));
|
||||
if (parms_form) {
|
||||
auto parms_data = dynamic_cast<DecompiledDataElement*>(parms_form->src()->at(0));
|
||||
|
||||
@@ -362,14 +362,13 @@ void MercEffect::from_ref(TypedRef tr,
|
||||
tri_count = read_plain_data_field<u16>(tr, "tri-count", dts);
|
||||
dvert_count = read_plain_data_field<u16>(tr, "dvert-count", dts);
|
||||
auto* type = dynamic_cast<StructureType*>(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<u8>(tr, "envmap-usage", dts);
|
||||
} else {
|
||||
envmap_or_effect_usage = read_plain_data_field<u8>(tr, "effect-usage", dts);
|
||||
}
|
||||
|
||||
if (type->lookup_field("texture-index", &temp)) {
|
||||
if (type->lookup_field("texture-index")) {
|
||||
texture_index = read_plain_data_field<u8>(tr, "texture-index", dts);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 <type> ...)
|
||||
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 '<type> ...)
|
||||
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);
|
||||
|
||||
@@ -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<MemoryOffsetConstantVal>(loc_type, object, field.field.offset() + offset);
|
||||
fe->alloc_val<MemoryOffsetConstantVal>(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<MemoryOffsetConstantVal>(
|
||||
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;
|
||||
|
||||
@@ -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"));
|
||||
|
||||
Reference in New Issue
Block a user