support for record extensions when using -O gen-standalone-C++

This commit is contained in:
Vern Paxson 2025-01-09 16:11:37 -08:00 committed by Arne Welzel
parent 300b3788e2
commit 960931ba5c
7 changed files with 64 additions and 9 deletions

View file

@ -618,11 +618,16 @@ public:
const detail::AttrPtr& GetAttr(detail::AttrTag a) const { return attrs ? attrs->Find(a) : detail::Attr::nil; }
const detail::Location* GetLocationInfo() const { return &loc; }
void DescribeReST(ODesc* d, bool roles_only = false) const;
TypePtr type;
detail::AttributesPtr attrs;
const char* id = nullptr;
private:
detail::Location loc = detail::GetCurrentLocation();
};
using type_decl_list = PList<TypeDecl>;

View file

@ -544,7 +544,8 @@ void FuncTypeInfo::AddInitializerVals(std::vector<std::string>& ivs) const {
ivs.emplace_back(Fmt(static_cast<int>(expressionless_return_okay)));
}
RecordTypeInfo::RecordTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c, std::move(_t)) {
RecordTypeInfo::RecordTypeInfo(CPPCompile* _c, TypePtr _t, int _addl_fields)
: AbstractTypeInfo(_c, std::move(_t)), addl_fields(_addl_fields) {
// Note, we leave init_cohort at 0 because the skeleton of this type
// is built in the first cohort.
auto r = t->AsRecordType()->Types();
@ -574,6 +575,7 @@ RecordTypeInfo::RecordTypeInfo(CPPCompile* _c, TypePtr _t) : AbstractTypeInfo(_c
void RecordTypeInfo::AddInitializerVals(std::vector<std::string>& ivs) const {
ivs.emplace_back(Fmt(c->TrackString(t->GetName())));
ivs.emplace_back(Fmt(addl_fields));
auto n = field_names.size();

View file

@ -644,11 +644,15 @@ private:
class RecordTypeInfo : public AbstractTypeInfo {
public:
RecordTypeInfo(CPPCompile* c, TypePtr _t);
RecordTypeInfo(CPPCompile* c, TypePtr _t, int _addl_fields);
void AddInitializerVals(std::vector<std::string>& ivs) const override;
private:
// If non-zero, where additional fields begin. Only used for standalone
// compilation.
int addl_fields;
std::vector<std::string> field_names;
std::vector<TypePtr> field_types;
std::vector<int> field_attrs;

View file

@ -383,11 +383,18 @@ TypePtr CPP_TypeInits::BuildRecordType(InitsManager* im, ValElemVec& init_vals,
auto r = cast_intrusive<RecordType>(inits_vec[offset]);
ASSERT(r);
if ( r->NumFields() == 0 ) {
auto addl_fields = init_vals[2];
if ( addl_fields > 0 || r->NumFields() == 0 ) {
// We shouldn't be adding fields if the record doesn't have any
// existing fields - that would reflect an initialization botch.
if ( addl_fields > 0 && r->NumFields() == 0 )
reporter->InternalError("record unexpectedly empty when adding fields");
type_decl_list tl;
auto n = init_vals.size();
auto i = 2U;
auto i = 3U + addl_fields * 3;
while ( i < n ) {
auto s = im->Strings(init_vals[i++]);

View file

@ -189,9 +189,43 @@ shared_ptr<CPP_InitInfo> CPPCompile::RegisterType(const TypePtr& tp) {
processed_types[t] = nullptr;
// When doing standalone compilation, if the type is a record *and*
// (1) it's not one that we're fully generating (i.e., it's not solely
// defined in the scripts that we're compiling-to-standalone), and (2) the
// scripts we're compiling extend the record using "redef += record ...",
// then we need to track the offset where those record extensions start,
// so that when initializing the standalone code, we can add in those
// record fields.
//
// If any of those conditions don't hold, then this variable will remain 0.
int addl_fields = 0;
bool type_init_needed = standalone && obj_matches_opt_files(tp);
if ( standalone && ! type_init_needed ) {
if ( tp->Tag() == TYPE_RECORD ) {
auto tr = tp->AsRecordType();
for ( auto i = tr->NumOrigFields(); i < tr->NumFields(); ++i ) {
auto fd = tr->FieldDecl(i);
if ( filename_matches_opt_files(fd->GetLocationInfo()->filename) ) {
if ( addl_fields == 0 )
addl_fields = i;
}
else if ( addl_fields > 0 )
reporter->FatalError(
"can't compile standalone-C++ with field \"%s\" in record \"%s\" added after those introduced "
"by compiled script",
fd->id, t->GetName().c_str());
}
if ( addl_fields > 0 )
type_init_needed = true;
}
}
shared_ptr<CPP_InitInfo> gi;
if ( (standalone && obj_matches_opt_files(tp)) || t->GetName().empty() ) {
if ( type_init_needed || t->GetName().empty() ) {
switch ( t->Tag() ) {
case TYPE_ADDR:
case TYPE_ANY:
@ -221,7 +255,7 @@ shared_ptr<CPP_InitInfo> CPPCompile::RegisterType(const TypePtr& tp) {
case TYPE_TABLE: gi = make_shared<TableTypeInfo>(this, tp); break;
case TYPE_RECORD: gi = make_shared<RecordTypeInfo>(this, tp); break;
case TYPE_RECORD: gi = make_shared<RecordTypeInfo>(this, tp, addl_fields); break;
case TYPE_FUNC: gi = make_shared<FuncTypeInfo>(this, tp); break;

View file

@ -125,13 +125,13 @@ bool should_analyze(const ScriptFuncPtr& f, const StmtPtr& body) {
return false;
}
bool obj_matches_opt_files(const Obj* obj) {
bool filename_matches_opt_files(const char* filename) {
auto& ofiles = analysis_options.only_files;
if ( ofiles.empty() )
return false;
auto fin = util::detail::normalize_path(obj->GetLocationInfo()->filename);
auto fin = util::detail::normalize_path(filename);
for ( auto& o : ofiles )
if ( std::regex_match(fin, o) )
@ -140,6 +140,8 @@ bool obj_matches_opt_files(const Obj* obj) {
return false;
}
bool obj_matches_opt_files(const Obj* obj) { return filename_matches_opt_files(obj->GetLocationInfo()->filename); }
static bool optimize_AST(ScriptFuncPtr f, std::shared_ptr<ProfileFunc>& pf, std::shared_ptr<Reducer>& rc,
ScopePtr scope, StmtPtr& body) {
pf = std::make_shared<ProfileFunc>(f.get(), body, true);

View file

@ -254,8 +254,9 @@ extern void add_file_analysis_pattern(AnalyOpt& opts, const char* pat);
// it should be skipped.
extern bool should_analyze(const ScriptFuncPtr& f, const StmtPtr& body);
// True if the given object's location matches one specified by
// True if the given filename or object location matches one specified by
// --optimize-files=...
extern bool filename_matches_opt_files(const char* filename);
extern bool obj_matches_opt_files(const Obj* obj);
inline bool obj_matches_opt_files(const ObjPtr& obj) { return obj_matches_opt_files(obj.get()); }