Skip to content

Commit 56e9d9b

Browse files
committed
Generate getters for fields of big structs
1 parent ce84116 commit 56e9d9b

File tree

5 files changed

+150
-23
lines changed

5 files changed

+150
-23
lines changed

bindgen/ir/IR.cpp

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

175175
for (const auto &u : ir.unions) {
176-
if (ir.shouldOutput(u)) {
176+
if (ir.shouldOutput(u) && u->hasHelperMethods()) {
177177
s << "\n" << u->generateHelperClass();
178178
}
179179
}
@@ -193,9 +193,10 @@ void IR::generate(const std::string &excludePrefix) {
193193
}
194194

195195
bool IR::hasHelperMethods() const {
196-
if (hasOutputtedDeclaration(unions)) {
197-
/* all unions have helper methods */
198-
return true;
196+
for (const auto &u : unions) {
197+
if (shouldOutput(u) && u->hasHelperMethods()) {
198+
return true;
199+
}
199200
}
200201

201202
for (const auto &s : structs) {

bindgen/ir/Struct.cpp

Lines changed: 76 additions & 12 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
bool isPacked)
@@ -65,19 +73,15 @@ std::shared_ptr<TypeDef> Struct::generateTypeDef() {
6573

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

@@ -96,6 +100,28 @@ bool Struct::hasHelperMethods() const {
96100
return !isPacked && !fields.empty();
97101
}
98102

103+
std::string Struct::generateHelperClassMethodsForStructRepresentation() const {
104+
std::stringstream s;
105+
for (unsigned fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) {
106+
if (!fields[fieldIndex]->getName().empty()) {
107+
s << generateGetterForStructRepresentation(fieldIndex);
108+
s << generateSetterForStructRepresentation(fieldIndex);
109+
}
110+
}
111+
return s.str();
112+
}
113+
114+
std::string Struct::generateHelperClassMethodsForArrayRepresentation() const {
115+
std::stringstream s;
116+
for (unsigned fieldIndex = 0; fieldIndex < fields.size(); fieldIndex++) {
117+
if (!fields[fieldIndex]->getName().empty()) {
118+
s << generateGetterForArrayRepresentation(fieldIndex);
119+
s << generateSetterForArrayRepresentation(fieldIndex);
120+
}
121+
}
122+
return s.str();
123+
}
124+
99125
std::string Struct::getTypeAlias() const { return "struct_" + name; }
100126

101127
std::string Struct::str() const {
@@ -131,7 +157,8 @@ bool Struct::operator==(const Type &other) const {
131157
return false;
132158
}
133159

134-
std::string Struct::generateSetter(unsigned fieldIndex) const {
160+
std::string
161+
Struct::generateSetterForStructRepresentation(unsigned fieldIndex) const {
135162
std::shared_ptr<Field> field = fields[fieldIndex];
136163
std::string setter = handleReservedWords(field->getName(), "_=");
137164
std::string parameterType = field->getType()->str();
@@ -143,11 +170,12 @@ std::string Struct::generateSetter(unsigned fieldIndex) const {
143170
}
144171
std::stringstream s;
145172
s << " def " << setter << "(value: " + parameterType + "): Unit = !p._"
146-
<< std::to_string(fieldIndex + 1) << " = " << value;
173+
<< std::to_string(fieldIndex + 1) << " = " << value << "\n";
147174
return s.str();
148175
}
149176

150-
std::string Struct::generateGetter(unsigned fieldIndex) const {
177+
std::string
178+
Struct::generateGetterForStructRepresentation(unsigned fieldIndex) const {
151179
std::shared_ptr<Field> field = fields[fieldIndex];
152180
std::string getter = handleReservedWords(field->getName());
153181
std::string returnType = field->getType()->str();
@@ -160,14 +188,49 @@ std::string Struct::generateGetter(unsigned fieldIndex) const {
160188
methodBody = "!p._" + std::to_string(fieldIndex + 1);
161189
}
162190
std::stringstream s;
163-
s << " def " << getter << ": " << returnType << " = " << methodBody;
191+
s << " def " << getter << ": " << returnType << " = " << methodBody
192+
<< "\n";
164193
return s.str();
165194
}
166195

167196
bool Struct::isRepresentedAsStruct() const {
168197
return fields.size() <= SCALA_NATIVE_MAX_STRUCT_FIELDS;
169198
}
170199

200+
std::string
201+
Struct::generateSetterForArrayRepresentation(unsigned int fieldIndex) const {
202+
return std::string();
203+
}
204+
205+
std::string
206+
Struct::generateGetterForArrayRepresentation(unsigned fieldIndex) const {
207+
std::shared_ptr<Field> field = fields[fieldIndex];
208+
std::string getter = handleReservedWords(field->getName());
209+
std::string returnType;
210+
std::string methodBody;
211+
212+
PointerType pointerToFieldType = PointerType(field->getType());
213+
if (field->getOffset() != 0) {
214+
methodBody = "(p._1 + " + std::to_string(field->getOffset()) + ")";
215+
} else {
216+
methodBody = "p._1";
217+
}
218+
methodBody = methodBody + ".cast[" + pointerToFieldType.str() + "]";
219+
220+
if (isAliasForType<ArrayType>(field->getType().get()) ||
221+
isAliasForType<Struct>(field->getType().get())) {
222+
returnType = pointerToFieldType.str();
223+
} else {
224+
methodBody = "!" + methodBody;
225+
returnType = field->getType()->str();
226+
}
227+
std::stringstream s;
228+
s << " def " << getter << ": " << returnType << " = " << methodBody
229+
<< "\n";
230+
return s.str();
231+
return "";
232+
}
233+
171234
Union::Union(std::string name, std::vector<std::shared_ptr<Field>> fields,
172235
uint64_t maxSize, std::shared_ptr<Location> location)
173236
: StructOrUnion(std::move(name), std::move(fields), std::move(location)),
@@ -179,6 +242,7 @@ std::shared_ptr<TypeDef> Union::generateTypeDef() {
179242
}
180243

181244
std::string Union::generateHelperClass() const {
245+
assert(hasHelperMethods());
182246
std::stringstream s;
183247
std::string type = getTypeAlias();
184248
s << " implicit class " << type << "_pos"

bindgen/ir/Struct.h

Lines changed: 33 additions & 5 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+
virtual bool hasHelperMethods() const;
45+
3446
protected:
3547
std::string name;
3648
std::vector<std::shared_ptr<Field>> fields;
@@ -54,7 +66,7 @@ class Struct : public StructOrUnion,
5466
/**
5567
* @return true if helper methods will be generated for this struct
5668
*/
57-
bool hasHelperMethods() const;
69+
bool hasHelperMethods() const override;
5870

5971
bool usesType(const std::shared_ptr<Type> &type,
6072
bool stopOnTypeDefs) const override;
@@ -63,16 +75,32 @@ class Struct : public StructOrUnion,
6375

6476
bool operator==(const Type &other) const override;
6577

66-
std::string generateSetter(unsigned fieldIndex) const;
67-
68-
std::string generateGetter(unsigned fieldIndex) const;
69-
7078
private:
7179
/* type size is needed if number of fields is bigger than 22 */
7280
uint64_t typeSize;
7381
bool isPacked;
7482

7583
bool isRepresentedAsStruct() const;
84+
85+
/**
86+
* @return implicit helper class for struct that is represented as CStruct.
87+
*/
88+
std::string generateHelperClassMethodsForStructRepresentation() const;
89+
90+
/**
91+
* @return implicit helper class for struct that is represented as CArray.
92+
*/
93+
std::string generateHelperClassMethodsForArrayRepresentation() const;
94+
95+
std::string
96+
generateSetterForStructRepresentation(unsigned fieldIndex) const;
97+
98+
std::string
99+
generateGetterForStructRepresentation(unsigned fieldIndex) const;
100+
101+
std::string generateSetterForArrayRepresentation(unsigned fieldIndex) const;
102+
103+
std::string generateGetterForArrayRepresentation(unsigned fieldIndex) const;
76104
};
77105

78106
class Union : public StructOrUnion,

bindgen/visitor/TreeVisitor.cpp

Lines changed: 8 additions & 2 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) {
@@ -126,12 +127,17 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) {
126127
}
127128

128129
std::vector<std::shared_ptr<Field>> fields;
130+
const clang::ASTRecordLayout &recordLayout =
131+
astContext->getASTRecordLayout(record);
129132

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

136142
cycleDetection.AddDependency(newName, field->getType());
137143
}

tests/samples/Struct.scala

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,34 @@ object StructHelpers {
5151

5252
def struct_points()(implicit z: native.Zone): native.Ptr[struct_points] = native.alloc[struct_points]
5353

54+
implicit class struct_bigStruct_ops(val p: native.Ptr[struct_bigStruct]) extends AnyVal {
55+
def one: native.CLong = !p._1.cast[native.Ptr[native.CLong]]
56+
def two: native.CChar = !(p._1 + 8).cast[native.Ptr[native.CChar]]
57+
def three: native.CInt = !(p._1 + 12).cast[native.Ptr[native.CInt]]
58+
def four: native.CFloat = !(p._1 + 16).cast[native.Ptr[native.CFloat]]
59+
def five: native.CDouble = !(p._1 + 24).cast[native.Ptr[native.CDouble]]
60+
def six: native.Ptr[struct_point] = !(p._1 + 32).cast[native.Ptr[native.Ptr[struct_point]]]
61+
def seven: native.CInt = !(p._1 + 40).cast[native.Ptr[native.CInt]]
62+
def eight: native.CInt = !(p._1 + 44).cast[native.Ptr[native.CInt]]
63+
def nine: native.CInt = !(p._1 + 48).cast[native.Ptr[native.CInt]]
64+
def ten: native.CInt = !(p._1 + 52).cast[native.Ptr[native.CInt]]
65+
def eleven: native.CInt = !(p._1 + 56).cast[native.Ptr[native.CInt]]
66+
def twelve: native.CInt = !(p._1 + 60).cast[native.Ptr[native.CInt]]
67+
def thirteen: native.CInt = !(p._1 + 64).cast[native.Ptr[native.CInt]]
68+
def fourteen: native.CInt = !(p._1 + 68).cast[native.Ptr[native.CInt]]
69+
def fifteen: native.CInt = !(p._1 + 72).cast[native.Ptr[native.CInt]]
70+
def sixteen: native.CInt = !(p._1 + 76).cast[native.Ptr[native.CInt]]
71+
def seventeen: native.CInt = !(p._1 + 80).cast[native.Ptr[native.CInt]]
72+
def eighteen: native.CInt = !(p._1 + 84).cast[native.Ptr[native.CInt]]
73+
def nineteen: native.CInt = !(p._1 + 88).cast[native.Ptr[native.CInt]]
74+
def twenty: native.CInt = !(p._1 + 92).cast[native.Ptr[native.CInt]]
75+
def twentyOne: native.CInt = !(p._1 + 96).cast[native.Ptr[native.CInt]]
76+
def twentyTwo: native.CInt = !(p._1 + 100).cast[native.Ptr[native.CInt]]
77+
def twentyThree: native.CInt = !(p._1 + 104).cast[native.Ptr[native.CInt]]
78+
}
79+
80+
def struct_bigStruct()(implicit z: native.Zone): native.Ptr[struct_bigStruct] = native.alloc[struct_bigStruct]
81+
5482
implicit class struct_structWithAnonymousStruct_ops(val p: native.Ptr[struct_structWithAnonymousStruct]) extends AnyVal {
5583
def a: native.CInt = !p._1
5684
def a_=(value: native.CInt): Unit = !p._1 = value

0 commit comments

Comments
 (0)