Skip to content

Commit 01ef112

Browse files
committed
Generate getters for fields of big structs
1 parent 0e5ac3e commit 01ef112

File tree

4 files changed

+119
-32
lines changed

4 files changed

+119
-32
lines changed

bindgen/ir/IR.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) {
164164
}
165165

166166
for (const auto &u : ir.unions) {
167-
if (ir.shouldOutput(u)) {
167+
if (ir.shouldOutput(u) && u->hasHelperMethods()) {
168168
s << "\n" << u->generateHelperClass();
169169
}
170170
}
@@ -184,9 +184,10 @@ void IR::generate(const std::string &excludePrefix) {
184184
}
185185

186186
bool IR::hasHelperMethods() const {
187-
if (hasOutputtedDeclaration(unions)) {
188-
/* all unions have helper methods */
189-
return true;
187+
for (const auto &u : unions) {
188+
if (shouldOutput(u) && u->hasHelperMethods()) {
189+
return true;
190+
}
190191
}
191192

192193
for (const auto &s : structs) {

bindgen/ir/Struct.cpp

Lines changed: 74 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
#include "Struct.h"
22
#include "../Utils.h"
33
#include "types/ArrayType.h"
4+
#include "types/PointerType.h"
45
#include "types/PrimitiveType.h"
56
#include <sstream>
67

78
Field::Field(std::string name, std::shared_ptr<Type> type)
89
: TypeAndName(std::move(name), std::move(type)) {}
910

11+
Field::Field(std::string name, std::shared_ptr<Type> type, uint64_t offset)
12+
: TypeAndName(std::move(name), std::move(type)), offset(offset) {}
13+
14+
uint64_t Field::getOffset() const { return offset; }
15+
1016
StructOrUnion::StructOrUnion(std::string name,
1117
std::vector<std::shared_ptr<Field>> fields,
1218
std::shared_ptr<Location> location)
@@ -41,6 +47,8 @@ std::shared_ptr<Location> StructOrUnion::getLocation() const {
4147
return location;
4248
}
4349

50+
bool StructOrUnion::hasHelperMethods() const { return !fields.empty(); }
51+
4452
Struct::Struct(std::string name, std::vector<std::shared_ptr<Field>> fields,
4553
uint64_t typeSize, std::shared_ptr<Location> location)
4654
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),
@@ -64,19 +72,15 @@ std::shared_ptr<TypeDef> Struct::generateTypeDef() {
6472

6573
std::string Struct::generateHelperClass() const {
6674
assert(hasHelperMethods());
67-
/* struct is not empty and not represented as an array */
6875
std::stringstream s;
6976
std::string type = getTypeAlias();
7077
s << " implicit class " << type << "_ops(val p: native.Ptr[" << type
7178
<< "])"
7279
<< " extends AnyVal {\n";
73-
unsigned fieldIndex = 0;
74-
for (const auto &field : fields) {
75-
if (!field->getName().empty()) {
76-
s << generateGetter(fieldIndex) << "\n";
77-
s << generateSetter(fieldIndex) << "\n";
78-
}
79-
fieldIndex++;
80+
if (fields.size() <= SCALA_NATIVE_MAX_STRUCT_FIELDS) {
81+
s << generateHelperClassMethodsForStructRepresentation();
82+
} else {
83+
s << generateHelperClassMethodsForArrayRepresentation();
8084
}
8185
s << " }\n\n";
8286

@@ -88,8 +92,26 @@ std::string Struct::generateHelperClass() const {
8892
return s.str();
8993
}
9094

91-
bool Struct::hasHelperMethods() const {
92-
return !fields.empty() && fields.size() < SCALA_NATIVE_MAX_STRUCT_FIELDS;
95+
std::string Struct::generateHelperClassMethodsForStructRepresentation() const {
96+
std::stringstream s;
97+
for (unsigned fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) {
98+
if (!fields[fieldIndex]->getName().empty()) {
99+
s << generateGetterForStructRepresentation(fieldIndex);
100+
s << generateSetterForStructRepresentation(fieldIndex);
101+
}
102+
}
103+
return s.str();
104+
}
105+
106+
std::string Struct::generateHelperClassMethodsForArrayRepresentation() const {
107+
std::stringstream s;
108+
for (unsigned fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) {
109+
if (!fields[fieldIndex]->getName().empty()) {
110+
s << generateGetterForArrayRepresentation(fieldIndex);
111+
s << generateSetterForArrayRepresentation(fieldIndex);
112+
}
113+
}
114+
return s.str();
93115
}
94116

95117
std::string Struct::getTypeAlias() const { return "struct_" + name; }
@@ -127,7 +149,8 @@ bool Struct::operator==(const Type &other) const {
127149
return false;
128150
}
129151

130-
std::string Struct::generateSetter(unsigned fieldIndex) const {
152+
std::string
153+
Struct::generateSetterForStructRepresentation(unsigned fieldIndex) const {
131154
std::shared_ptr<Field> field = fields[fieldIndex];
132155
std::string setter = handleReservedWords(field->getName(), "_=");
133156
std::string parameterType = field->getType()->str();
@@ -139,11 +162,12 @@ std::string Struct::generateSetter(unsigned fieldIndex) const {
139162
}
140163
std::stringstream s;
141164
s << " def " << setter << "(value: " + parameterType + "): Unit = !p._"
142-
<< std::to_string(fieldIndex + 1) << " = " << value;
165+
<< std::to_string(fieldIndex + 1) << " = " << value << "\n";
143166
return s.str();
144167
}
145168

146-
std::string Struct::generateGetter(unsigned fieldIndex) const {
169+
std::string
170+
Struct::generateGetterForStructRepresentation(unsigned fieldIndex) const {
147171
std::shared_ptr<Field> field = fields[fieldIndex];
148172
std::string getter = handleReservedWords(field->getName());
149173
std::string returnType = field->getType()->str();
@@ -156,10 +180,45 @@ std::string Struct::generateGetter(unsigned fieldIndex) const {
156180
methodBody = "!p._" + std::to_string(fieldIndex + 1);
157181
}
158182
std::stringstream s;
159-
s << " def " << getter << ": " << returnType << " = " << methodBody;
183+
s << " def " << getter << ": " << returnType << " = " << methodBody
184+
<< "\n";
160185
return s.str();
161186
}
162187

188+
std::string
189+
Struct::generateSetterForArrayRepresentation(unsigned int fieldIndex) const {
190+
return std::string();
191+
}
192+
193+
std::string
194+
Struct::generateGetterForArrayRepresentation(unsigned fieldIndex) const {
195+
std::shared_ptr<Field> field = fields[fieldIndex];
196+
std::string getter = handleReservedWords(field->getName());
197+
std::string returnType;
198+
std::string methodBody;
199+
200+
PointerType pointerToFieldType = PointerType(field->getType());
201+
if (field->getOffset() != 0) {
202+
methodBody = "(p._1 + " + std::to_string(field->getOffset()) + ")";
203+
} else {
204+
methodBody = "p._1";
205+
}
206+
methodBody = methodBody + ".cast[" + pointerToFieldType.str() + "]";
207+
208+
if (isAliasForType<ArrayType>(field->getType().get()) ||
209+
isAliasForType<Struct>(field->getType().get())) {
210+
returnType = pointerToFieldType.str();
211+
} else {
212+
methodBody = "!" + methodBody;
213+
returnType = field->getType()->str();
214+
}
215+
std::stringstream s;
216+
s << " def " << getter << ": " << returnType << " = " << methodBody
217+
<< "\n";
218+
return s.str();
219+
return "";
220+
}
221+
163222
Union::Union(std::string name, std::vector<std::shared_ptr<Field>> fields,
164223
uint64_t maxSize, std::shared_ptr<Location> location)
165224
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),
@@ -171,6 +230,7 @@ std::shared_ptr<TypeDef> Union::generateTypeDef() {
171230
}
172231

173232
std::string Union::generateHelperClass() const {
233+
assert(hasHelperMethods());
174234
std::stringstream s;
175235
std::string type = getTypeAlias();
176236
s << " implicit class " << type << "_pos"

bindgen/ir/Struct.h

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@
1212
class Field : public TypeAndName {
1313
public:
1414
Field(std::string name, std::shared_ptr<Type> type);
15+
16+
Field(std::string name, std::shared_ptr<Type> type, uint64_t offset);
17+
18+
uint64_t getOffset() const;
19+
20+
protected:
21+
/**
22+
* Offset in bytes from address of struct/union.
23+
*/
24+
uint64_t offset = 0;
1525
};
1626

1727
class StructOrUnion {
@@ -31,6 +41,8 @@ class StructOrUnion {
3141

3242
virtual std::string getTypeAlias() const = 0;
3343

44+
bool hasHelperMethods() const;
45+
3446
protected:
3547
std::string name;
3648
std::vector<std::shared_ptr<Field>> fields;
@@ -50,25 +62,36 @@ class Struct : public StructOrUnion,
5062

5163
std::string getTypeAlias() const override;
5264

53-
/**
54-
* @return true if helper methods will be generated for this struct
55-
*/
56-
bool hasHelperMethods() const;
57-
5865
bool usesType(const std::shared_ptr<Type> &type,
5966
bool stopOnTypeDefs) const override;
6067

6168
std::string str() const override;
6269

6370
bool operator==(const Type &other) const override;
6471

65-
std::string generateSetter(unsigned fieldIndex) const;
66-
67-
std::string generateGetter(unsigned fieldIndex) const;
68-
6972
private:
7073
/* type size is needed if number of fields is bigger than 22 */
7174
uint64_t typeSize;
75+
76+
/**
77+
* @return implicit helper class for struct that is represented as CStruct.
78+
*/
79+
std::string generateHelperClassMethodsForStructRepresentation() const;
80+
81+
/**
82+
* @return implicit helper class for struct that is represented as CArray.
83+
*/
84+
std::string generateHelperClassMethodsForArrayRepresentation() const;
85+
86+
std::string
87+
generateSetterForStructRepresentation(unsigned fieldIndex) const;
88+
89+
std::string
90+
generateGetterForStructRepresentation(unsigned fieldIndex) const;
91+
92+
std::string generateSetterForArrayRepresentation(unsigned fieldIndex) const;
93+
94+
std::string generateGetterForArrayRepresentation(unsigned fieldIndex) const;
7295
};
7396

7497
class Union : public StructOrUnion,

bindgen/visitor/TreeVisitor.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "TreeVisitor.h"
2+
#include "clang/AST/RecordLayout.h"
23
#include <stdio.h>
34

45
bool TreeVisitor::VisitFunctionDecl(clang::FunctionDecl *func) {
@@ -127,18 +128,20 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) {
127128
llvm::errs().flush();
128129
}
129130

130-
int fieldCnt = 0;
131131
std::vector<std::shared_ptr<Field>> fields;
132+
const clang::ASTRecordLayout &recordLayout =
133+
astContext->getASTRecordLayout(record);
132134

133135
for (const clang::FieldDecl *field : record->fields()) {
134136
std::shared_ptr<Type> ftype =
135137
typeTranslator.translate(field->getType(), &name);
136-
fields.push_back(
137-
std::make_shared<Field>(field->getNameAsString(), ftype));
138+
uint64_t recordOffsetInBits =
139+
recordLayout.getFieldOffset(field->getFieldIndex());
140+
assert(recordOffsetInBits % 8 == 0);
141+
fields.push_back(std::make_shared<Field>(
142+
field->getNameAsString(), ftype, recordOffsetInBits / 8));
138143

139144
cycleDetection.AddDependency(newName, field->getType());
140-
141-
fieldCnt++;
142145
}
143146

144147
if (cycleDetection.isCyclic(newName)) {

0 commit comments

Comments
 (0)