Skip to content

Commit

Permalink
Support breaking cycles on complex types
Browse files Browse the repository at this point in the history
  • Loading branch information
kornilova203 committed Jul 26, 2018
1 parent e7d4728 commit 6833e33
Show file tree
Hide file tree
Showing 19 changed files with 545 additions and 233 deletions.
2 changes: 0 additions & 2 deletions bindgen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,6 @@ add_executable(bindgen
ir/Location.cpp
ir/LocationManager.h
ir/LocationManager.cpp
ir/CycleNode.cpp
ir/CycleNode.h
)

if (STATIC_LINKING)
Expand Down
4 changes: 0 additions & 4 deletions bindgen/ir/CycleNode.cpp

This file was deleted.

17 changes: 0 additions & 17 deletions bindgen/ir/CycleNode.h

This file was deleted.

245 changes: 130 additions & 115 deletions bindgen/ir/Struct.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "Struct.h"
#include "../Utils.h"
#include "types/ArrayType.h"
#include "types/FunctionPointerType.h"
#include "types/PointerType.h"
#include "types/PrimitiveType.h"
#include <sstream>
Expand Down Expand Up @@ -38,74 +39,19 @@ Struct::Struct(std::string name, std::vector<std::shared_ptr<Field>> fields,
bool StructOrUnion::usesType(
const std::shared_ptr<const Type> &type, bool stopOnTypeDefs,
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
for (const auto &field : fields) {
if (*field->getType() == *type ||
field->getType()->usesType(type, stopOnTypeDefs, visitedTypes)) {
return true;
}
}
return false;
}

bool StructOrUnion::findAllCycles(
const StructOrUnion *startStructOrUnion, CycleNode &cycleNode,
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
if (this == startStructOrUnion) {
return true;
}
/* visitedTypes check is ignored because it is not necessary to save Struct
* and Union types in visitedTypes if it is done for TypeDefs (Struct and
* Union types can be references only through TypeDefs) */
bool belongsToCycle = false;
for (const auto &field : fields) {
CycleNode newCycleNode(this, field.get());
if (field->getType()->findAllCycles(startStructOrUnion, newCycleNode,
visitedTypes)) {
if (isAliasForType<Struct>(field->getType().get()) ||
isAliasForType<Union>(field->getType().get())) {
/* cycles cannot be broken on value type fields */
newCycleNode.isValueType = true;
}
belongsToCycle = true;
cycleNode.cycleNodes.push_back(newCycleNode);
}
if (contains(this, visitedTypes)) {
return false;
}
return belongsToCycle;
}
visitedTypes.push_back(shared_from_this());

bool StructOrUnion::hasBiggestName(
const CycleNode &node, std::vector<std::string> namesInCycle) const {
if (!node.isValueType) {
namesInCycle.push_back(node.structOrUnion->getTypeAlias());
}
if (node.cycleNodes.empty()) {
std::sort(namesInCycle.begin(), namesInCycle.end());
return getTypeAlias() == namesInCycle.back();
}
for (const auto &cycleNode : node.cycleNodes) {
if (hasBiggestName(cycleNode, namesInCycle)) {
for (const auto &field : fields) {
if (*field->getType() == *type ||
field->getType()->usesType(type, stopOnTypeDefs, visitedTypes)) {
return true;
}
}
return false;
}

bool StructOrUnion::shouldFieldBreakCycle(
const std::shared_ptr<Field> &field) const {
if (isAliasForType<Struct>(field->getType().get()) ||
isAliasForType<Union>(field->getType().get())) {
return false;
}
CycleNode baseNode(this, field.get());
std::vector<std::shared_ptr<const Type>> visitedTypes;
if (field->getType()->findAllCycles(this, baseNode, visitedTypes)) {
/* one or more cycles were found but type of the filed should be changed
* if this struct/union has the biggest name compared to other
* structs/unions in cycle that have fields of non-value type. */
std::vector<std::string> namesInCycle;
bool res = hasBiggestName(baseNode, namesInCycle);
return res;
}
visitedTypes.pop_back();
return false;
}

Expand Down Expand Up @@ -188,12 +134,14 @@ std::string Struct::str() const {
std::string sep = "";
for (const auto &field : fields) {
ss << sep;
if (!isInstanceOf<PointerType>(field->getType().get()) ||
!shouldFieldBreakCycle(field)) {

std::vector<std::shared_ptr<const StructOrUnion>>
recordTypesThatShouldBeReplaced = shouldFieldBreakCycle(field);
if (recordTypesThatShouldBeReplaced.empty()) {
ss << field->getType()->str();
} else {
ss << PointerType(std::make_shared<PrimitiveType>("Byte")).str();
std::shared_ptr<const Type> typeReplacement = getTypeReplacement(
field->getType(), recordTypesThatShouldBeReplaced);
ss << typeReplacement->str();
}
sep = ", ";
}
Expand All @@ -202,24 +150,6 @@ std::string Struct::str() const {
return ss.str();
}

bool Struct::usesType(
const std::shared_ptr<const Type> &type, bool stopOnTypeDefs,
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {

if (contains(this, visitedTypes)) {
return false;
}
visitedTypes.push_back(shared_from_this());

bool result = StructOrUnion::usesType(type, stopOnTypeDefs, visitedTypes);
if (!result) {
/* current Struct instance should not be in the path to search
* type */
visitedTypes.pop_back();
}
return result;
}

bool Struct::operator==(const Type &other) const {
if (this == &other) {
return true;
Expand All @@ -238,13 +168,16 @@ Struct::generateSetterForStructRepresentation(unsigned fieldIndex) const {
std::string setter = handleReservedWords(field->getName(), "_=");
std::string parameterType = field->getType()->str();
std::string value = "value";
if (isAliasForType<ArrayType>(field->getType().get()) ||
isAliasForType<Struct>(field->getType().get())) {
std::vector<std::shared_ptr<const StructOrUnion>>
recordTypesThatShouldBeReplaced = shouldFieldBreakCycle(field);
if (!recordTypesThatShouldBeReplaced.empty()) {
std::shared_ptr<const Type> typeReplacement = getTypeReplacement(
field->getType(), recordTypesThatShouldBeReplaced);
value = value + ".cast[" + typeReplacement->str() + "]";
} else if (isAliasForType<ArrayType>(field->getType().get()) ||
isAliasForType<Struct>(field->getType().get())) {
parameterType = "native.Ptr[" + parameterType + "]";
value = "!" + value;
} else if (isInstanceOf<PointerType>(field->getType().get()) &&
shouldFieldBreakCycle(field)) {
value = value + ".cast[native.Ptr[Byte]]";
}
std::stringstream s;
s << " def " << setter << "(value: " + parameterType + "): Unit = !p._"
Expand All @@ -261,8 +194,7 @@ Struct::generateGetterForStructRepresentation(unsigned fieldIndex) const {
if (isAliasForType<ArrayType>(field->getType().get()) ||
isAliasForType<Struct>(field->getType().get())) {
returnType = "native.Ptr[" + returnType + "]";
} else if (isInstanceOf<PointerType>(field->getType().get()) &&
shouldFieldBreakCycle(field)) {
} else if (!shouldFieldBreakCycle(field).empty()) {
methodBody =
"(!" + methodBody + ").cast[" + field->getType()->str() + "]";
} else {
Expand Down Expand Up @@ -293,13 +225,16 @@ Struct::generateSetterForArrayRepresentation(unsigned int fieldIndex) const {
"(" + castedField + " + " + std::to_string(offsetInBytes) + ")";
}
castedField = "!" + castedField + ".cast[" + pointerToFieldType.str() + "]";
if (isAliasForType<ArrayType>(field->getType().get()) ||
isAliasForType<Struct>(field->getType().get())) {
std::vector<std::shared_ptr<const StructOrUnion>>
recordTypesThatShouldBeReplaced = shouldFieldBreakCycle(field);
if (!recordTypesThatShouldBeReplaced.empty()) {
std::shared_ptr<const Type> typeReplacement = getTypeReplacement(
field->getType(), recordTypesThatShouldBeReplaced);
value = value + ".cast[" + typeReplacement->str() + "]";
} else if (isAliasForType<ArrayType>(field->getType().get()) ||
isAliasForType<Struct>(field->getType().get())) {
parameterType = pointerToFieldType.str();
value = "!" + value;
} else if (isInstanceOf<PointerType>(field->getType().get()) &&
shouldFieldBreakCycle(field)) {
value = value + ".cast[native.Ptr[Byte]]";
}
std::stringstream s;
s << " def " << setter
Expand Down Expand Up @@ -327,8 +262,7 @@ Struct::generateGetterForArrayRepresentation(unsigned fieldIndex) const {
if (isAliasForType<ArrayType>(field->getType().get()) ||
isAliasForType<Struct>(field->getType().get())) {
returnType = pointerToFieldType.str();
} else if (isInstanceOf<PointerType>(field->getType().get()) &&
shouldFieldBreakCycle(field)) {
} else if (!shouldFieldBreakCycle(field).empty()) {
methodBody =
"(!" + methodBody + ").cast[" + field->getType()->str() + "]";
returnType = field->getType()->str();
Expand All @@ -342,11 +276,104 @@ Struct::generateGetterForArrayRepresentation(unsigned fieldIndex) const {
return s.str();
}

std::shared_ptr<const Type>
Struct::getTypeReplacement(std::shared_ptr<const Type> type,
std::vector<std::shared_ptr<const StructOrUnion>>
recordTypesThatShouldBeReplaced) const {
std::shared_ptr<const Type> replacementType = type->unrollTypedefs();
std::shared_ptr<PointerType> pointerToByte =
std::make_shared<PointerType>(std::make_shared<PrimitiveType>("Byte"));
for (const auto &recordType : recordTypesThatShouldBeReplaced) {
std::shared_ptr<TypeDef> recordTypeDef = std::make_shared<TypeDef>(
recordType->getTypeAlias(), recordType, nullptr);
std::shared_ptr<Type> pointerToRecord =
std::make_shared<PointerType>(recordTypeDef);
if (*replacementType == *pointerToRecord) {
replacementType = pointerToByte;
} else {
replacementType =
replacementType->replaceType(pointerToRecord, pointerToByte);
}
std::vector<std::shared_ptr<const Type>> visitedTypes;
if (replacementType->usesType(recordType, false, visitedTypes)) {
assert(isInstanceOf<FunctionPointerType>(replacementType.get()));
/* function pointer types may have return value or a parameter of
* value type */
replacementType = replacementType->replaceType(
recordTypeDef,
std::make_shared<PrimitiveType>("native.CStruct0"));
}
}
return replacementType;
}

std::vector<std::shared_ptr<const StructOrUnion>>
Struct::shouldFieldBreakCycle(const std::shared_ptr<Field> &field) const {
std::vector<std::shared_ptr<const StructOrUnion>>
recordTypesThatShouldBeReplaced;
if (isAliasForType<Struct>(field->getType().get()) ||
isAliasForType<Union>(field->getType().get())) {
return recordTypesThatShouldBeReplaced;
}
CycleNode baseNode(shared_from_base<Struct>(), field.get());
std::vector<std::shared_ptr<const Type>> visitedTypes;
if (field->getType()->findAllCycles(shared_from_base<Struct>(), baseNode,
visitedTypes)) {
/* one or more cycles were found but type of the filed should be
* changed if this struct/union has the biggest name compared to
* other structs/unions in cycle that have fields of non-value type.
*/
for (const auto &nextCycleNode : baseNode.cycleNodes) {
std::vector<std::string> namesInCycle;
if (hasBiggestName(nextCycleNode, namesInCycle)) {
recordTypesThatShouldBeReplaced.push_back(nextCycleNode.s);
}
}
}
return recordTypesThatShouldBeReplaced;
}

bool Struct::findAllCycles(
const StructOrUnion *startStructOrUnion, CycleNode &cycleNode,
const std::shared_ptr<const Struct> &startStruct, CycleNode &cycleNode,
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
return StructOrUnion::findAllCycles(startStructOrUnion, cycleNode,
visitedTypes);
if (this == startStruct.get()) {
return true;
}
/* visitedTypes check is ignored because it is not necessary to save Struct
* and Union types in visitedTypes if it is done for TypeDefs (Struct and
* Union types can be references only through TypeDefs) */
bool belongsToCycle = false;
for (const auto &field : fields) {
CycleNode newCycleNode(shared_from_base<Struct>(), field.get());
if (field->getType()->findAllCycles(startStruct, newCycleNode,
visitedTypes)) {
if (isAliasForType<Struct>(field->getType().get()) ||
isAliasForType<Union>(field->getType().get())) {
/* cycles cannot be broken on value type fields */
newCycleNode.isValueType = true;
}
belongsToCycle = true;
cycleNode.cycleNodes.push_back(newCycleNode);
}
}
return belongsToCycle;
}

bool Struct::hasBiggestName(const CycleNode &node,
std::vector<std::string> namesInCycle) const {
if (!node.isValueType) {
namesInCycle.push_back(node.s->getTypeAlias());
}
if (node.cycleNodes.empty()) {
std::sort(namesInCycle.begin(), namesInCycle.end());
return getTypeAlias() >= namesInCycle.back();
}
for (const auto &cycleNode : node.cycleNodes) {
if (hasBiggestName(cycleNode, namesInCycle)) {
return true;
}
}
return false;
}

Union::Union(std::string name, std::vector<std::shared_ptr<Field>> fields,
Expand Down Expand Up @@ -408,19 +435,7 @@ bool Union::usesType(
if (ArrayType::usesType(type, stopOnTypeDefs, visitedTypes)) {
return true;
}
visitedTypes.pop_back();

bool result = StructOrUnion::usesType(type, stopOnTypeDefs, visitedTypes);
if (!result) {
/* current Union instance should not be in the path to search
* type */
visitedTypes.pop_back();
}
return result;
}

bool Union::findAllCycles(
const StructOrUnion *startStructOrUnion, CycleNode &cycleNode,
std::vector<std::shared_ptr<const Type>> &visitedTypes) const {
return StructOrUnion::findAllCycles(startStructOrUnion, cycleNode,
visitedTypes);
return StructOrUnion::usesType(type, stopOnTypeDefs, visitedTypes);
}
Loading

0 comments on commit 6833e33

Please sign in to comment.