#include "third-party/fmt/core.h" #include "StaticObject.h" #include "common/goal_constants.h" #include "goalc/compiler/Env.h" namespace { template uint32_t push_data_to_byte_vector(T data, std::vector& v) { auto* ptr = (uint8_t*)(&data); for (std::size_t i = 0; i < sizeof(T); i++) { v.push_back(ptr[i]); } return sizeof(T); } } // namespace //////////////// // StaticString //////////////// StaticString::StaticString(std::string text_data, int _seg) : StaticBasic(_seg, "string"), text(std::move(text_data)) {} std::string StaticString::print() const { return fmt::format("static-string \"{}\"", text); } void StaticString::generate(emitter::ObjectGenerator* gen) { rec = gen->add_static_to_seg(seg, 16); auto& d = gen->get_static_data(rec); // add "string" type tag: gen->link_static_type_ptr(rec, d.size(), "string"); for (int i = 0; i < POINTER_SIZE; i++) { d.push_back(0xbe); } // add allocated size push_data_to_byte_vector(text.size(), d); // add chars for (auto c : text) { d.push_back(c); } d.push_back(0); } //////////////// // StaticFloat //////////////// StaticFloat::StaticFloat(float _value, int _seg) : value(_value), seg(_seg) {} StaticObject::LoadInfo StaticFloat::get_load_info() const { LoadInfo info; info.requires_load = true; info.load_size = 4; info.load_signed = false; info.prefer_xmm = true; return info; } void StaticFloat::generate(emitter::ObjectGenerator* gen) { rec = gen->add_static_to_seg(seg, 4); auto& d = gen->get_static_data(rec); push_data_to_byte_vector(value, d); } int StaticFloat::get_addr_offset() const { return 0; } std::string StaticFloat::print() const { return fmt::format("(sf {})", value); } /////////////////// // StaticStructure /////////////////// StaticStructure::StaticStructure(int _seg) : seg(_seg) {} std::string StaticStructure::print() const { return "static-structure"; } StaticObject::LoadInfo StaticStructure::get_load_info() const { LoadInfo info; info.requires_load = false; info.prefer_xmm = false; return info; } int StaticStructure::get_addr_offset() const { return m_offset; } void StaticStructure::generate_structure(emitter::ObjectGenerator* gen) { rec = gen->add_static_to_seg(seg, 16); auto& d = gen->get_static_data(rec); d.insert(d.end(), data.begin(), data.end()); for (auto& sym : symbols) { gen->link_static_symbol_ptr(rec, sym.offset, sym.name); } for (auto& ptr : pointers) { gen->link_static_pointer_to_data(rec, ptr.offset_in_this, ptr.dest->rec, ptr.offset_in_dest); } for (auto& type : types) { gen->link_static_type_ptr(rec, type.offset, type.name); } for (auto& func : functions) { gen->link_static_pointer_to_function(rec, func.offset_in_this, gen->get_existing_function_record(func.func->idx_in_file)); } } void StaticStructure::generate(emitter::ObjectGenerator* gen) { generate_structure(gen); } void StaticStructure::add_symbol_record(std::string name, int offset) { SymbolRecord srec; srec.name = std::move(name); srec.offset = offset; symbols.push_back(srec); } void StaticStructure::add_pointer_record(int offset_in_this, StaticStructure* dest, int offset_in_dest) { PointerRecord prec; prec.offset_in_this = offset_in_this; prec.dest = dest; prec.offset_in_dest = offset_in_dest; pointers.push_back(prec); } void StaticStructure::add_type_record(std::string name, int offset) { SymbolRecord srec; srec.name = std::move(name); srec.offset = offset; types.push_back(srec); } void StaticStructure::add_function_record(const FunctionEnv* function, int offset) { FunctionRecord frec; frec.func = function; frec.offset_in_this = offset; functions.push_back(frec); } /////////////////// // StaticBasic /////////////////// StaticBasic::StaticBasic(int _seg, std::string _type_name) : StaticStructure(_seg), type_name(std::move(_type_name)) { add_type_record(type_name, 0); } int StaticBasic::get_addr_offset() const { return BASIC_OFFSET; } /////////////////// // StaticPair /////////////////// StaticPair::StaticPair(StaticResult car, StaticResult cdr, int _seg) : StaticStructure(_seg), m_car(std::move(car)), m_cdr(std::move(cdr)) {} int StaticPair::get_addr_offset() const { return PAIR_OFFSET; } void StaticPair::generate(emitter::ObjectGenerator* gen) { data.resize(2 * POINTER_SIZE); // size of pair generate_item(m_car, 0); generate_item(m_cdr, 4); generate_structure(gen); } void StaticPair::generate_item(const StaticResult& item, int offset) { if (item.is_reference()) { add_pointer_record(offset, item.reference(), item.reference()->get_addr_offset()); } else if (item.is_symbol()) { add_symbol_record(item.symbol_name(), offset); u32 symbol_placeholder = 0xffffffff; memcpy(data.data() + offset, &symbol_placeholder, POINTER_SIZE); } else if (item.is_constant_data()) { // if it's a constant data, it should always be a boxed integer for a pair. // or I guess you could put a normal integer too. Either way, we assume signed here, // though we may need to allow overflow so you can store either signed/unsigned things in pairs s32 value = item.constant_s32(); memcpy(data.data() + offset, &value, POINTER_SIZE); } else if (item.is_func()) { add_function_record(item.function(), offset); } else { throw std::runtime_error("Unsupported item kind in StaticPair::generate_item"); } } /////////////////// // StaticResult /////////////////// StaticResult StaticResult::make_structure_reference(StaticStructure* structure, TypeSpec ts) { StaticResult result; result.m_kind = Kind::STRUCTURE_REFERENCE; result.m_struct = structure; result.m_ts = std::move(ts); return result; } StaticResult StaticResult::make_constant_data(const ConstantValue& data, TypeSpec ts) { StaticResult result; result.m_kind = Kind::CONSTANT_DATA; result.m_constant_data = data; result.m_ts = std::move(ts); return result; } StaticResult StaticResult::make_constant_data(u64 data, const TypeSpec& ts) { return make_constant_data(ConstantValue((void*)&data, sizeof(u64)), ts); } StaticResult StaticResult::make_symbol(const std::string& name) { StaticResult result; result.m_kind = Kind::SYMBOL; result.m_symbol = name; result.m_ts = TypeSpec("symbol"); return result; } StaticResult StaticResult::make_type_ref(const std::string& type_name, int method_count) { StaticResult result; result.m_kind = Kind::TYPE; result.m_symbol = type_name; result.m_method_count = method_count; result.m_ts = TypeSpec("type"); return result; } StaticResult StaticResult::make_func_ref(const FunctionEnv* func, const TypeSpec& type) { StaticResult result; result.m_kind = Kind::FUNCTION_REFERENCE; result.m_func = func; result.m_ts = type; return result; }