From 2f57db1c9bc271c08fdfcdcb6fae259e6e5235ef Mon Sep 17 00:00:00 2001 From: kornilova-l Date: Mon, 2 Jul 2018 09:38:40 +0400 Subject: [PATCH 1/5] Convert size in bits to size in bytes --- bindgen/TypeTranslator.cpp | 5 +++-- bindgen/visitor/TreeVisitor.cpp | 10 ++++++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/bindgen/TypeTranslator.cpp b/bindgen/TypeTranslator.cpp index d93f441..df569cc 100644 --- a/bindgen/TypeTranslator.cpp +++ b/bindgen/TypeTranslator.cpp @@ -132,9 +132,10 @@ std::shared_ptr TypeTranslator::translate(const clang::QualType &qtpe, if (typeEquals(tpe, avoid)) { // This is a type that we want to avoid the usage. // Êxample: A struct that has a pointer to itself - uint64_t size = ctx->getTypeSize(tpe); + uint64_t sizeInBits = ctx->getTypeSize(tpe); + assert(sizeInBits % 8 == 0); return std::make_shared( - std::make_shared("Byte"), size); + std::make_shared("Byte"), sizeInBits / 8); } if (tpe->isFunctionPointerType()) { diff --git a/bindgen/visitor/TreeVisitor.cpp b/bindgen/visitor/TreeVisitor.cpp index 9ea4770..8c8ce95 100644 --- a/bindgen/visitor/TreeVisitor.cpp +++ b/bindgen/visitor/TreeVisitor.cpp @@ -105,8 +105,9 @@ void TreeVisitor::handleUnion(clang::RecordDecl *record, std::string name) { std::vector fields; for (const clang::FieldDecl *field : record->fields()) { - uint64_t sizeInBytes = astContext->getTypeSize(field->getType()) / 8; - maxSize = std::max(maxSize, sizeInBytes); + uint64_t sizeInBits = astContext->getTypeSize(field->getType()); + assert(sizeInBits % 8 == 0); + maxSize = std::max(maxSize, sizeInBits / 8); std::string fname = field->getNameAsString(); std::shared_ptr ftype = typeTranslator.translate(field->getType(), &name); @@ -152,9 +153,10 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) { llvm::errs().flush(); } + uint64_t sizeInBits = astContext->getTypeSize(record->getTypeForDecl()); + assert(sizeInBits % 8 == 0); std::shared_ptr alias = - ir.addStruct(name, std::move(fields), - astContext->getTypeSize(record->getTypeForDecl())); + ir.addStruct(name, std::move(fields), sizeInBits / 8); typeTranslator.addAlias("struct " + name, alias); } From b8bad83b205bed1ba71da2b820226970fb227adb Mon Sep 17 00:00:00 2001 From: kornilova-l Date: Mon, 2 Jul 2018 09:51:06 +0400 Subject: [PATCH 2/5] Add tests for types that use native.CArray --- bindgen/ir/IR.cpp | 4 ++- bindgen/ir/Struct.cpp | 6 ++-- tests/samples/Struct.c | 2 ++ tests/samples/Struct.h | 28 +++++++++++++++++++ tests/samples/Struct.scala | 2 ++ tests/samples/Union.c | 2 ++ tests/samples/Union.h | 2 ++ tests/samples/Union.scala | 1 + .../bindgen/samples/StructTests.scala | 5 ++++ .../bindgen/samples/UnionTests.scala | 2 ++ 10 files changed, 49 insertions(+), 5 deletions(-) diff --git a/bindgen/ir/IR.cpp b/bindgen/ir/IR.cpp index 8c8b400..170de1c 100644 --- a/bindgen/ir/IR.cpp +++ b/bindgen/ir/IR.cpp @@ -141,7 +141,9 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) { s << "object " << ir.libName << "Helpers {\n"; for (const auto &st : ir.structs) { - s << "\n" << st->generateHelperClass(); + if (st->hasHelperMethods()) { + s << "\n" << st->generateHelperClass(); + } } for (const auto &u : ir.unions) { diff --git a/bindgen/ir/Struct.cpp b/bindgen/ir/Struct.cpp index 5943aac..7283831 100644 --- a/bindgen/ir/Struct.cpp +++ b/bindgen/ir/Struct.cpp @@ -37,10 +37,8 @@ std::shared_ptr Struct::generateTypeDef() { } std::string Struct::generateHelperClass() const { - if (!hasHelperMethods()) { - /* struct is empty or represented as an array */ - return ""; - } + assert(hasHelperMethods()); + /* struct is not empty and not represented as an array */ std::stringstream s; std::string type = getAliasType(); s << " implicit class " << type << "_ops(val p: native.Ptr[" << type diff --git a/tests/samples/Struct.c b/tests/samples/Struct.c index fb53ee9..9406945 100644 --- a/tests/samples/Struct.c +++ b/tests/samples/Struct.c @@ -7,3 +7,5 @@ point_s getPoint() { point->y = 20; return point; } + +int getBigStructSize() { return sizeof(struct bigStruct); } diff --git a/tests/samples/Struct.h b/tests/samples/Struct.h index 2e5d9d9..47f2a8c 100644 --- a/tests/samples/Struct.h +++ b/tests/samples/Struct.h @@ -6,3 +6,31 @@ struct point { typedef struct point *point_s; point_s getPoint(); + +struct bigStruct { + long one; + char two; + int three; + float four; + double five; + point_s six; + int seven; + int eight; + int nine; + int ten; + int eleven; + int twelve; + int thirteen; + int fourteen; + int fifteen; + int sixteen; + int seventeen; + int eighteen; + int nineteen; + int twenty; + int twentyOne; + int twentyTwo; + int twentyThree; +}; + +int getBigStructSize(); diff --git a/tests/samples/Struct.scala b/tests/samples/Struct.scala index f466d78..6148a0e 100644 --- a/tests/samples/Struct.scala +++ b/tests/samples/Struct.scala @@ -8,7 +8,9 @@ import scala.scalanative.native._ object Struct { type struct_point = native.CStruct2[native.CInt, native.CInt] type point_s = native.Ptr[struct_point] + type struct_bigStruct = native.CArray[Byte, native.Nat.Digit[native.Nat._1, native.Nat.Digit[native.Nat._1, native.Nat._2]]] def getPoint(): native.Ptr[struct_point] = native.extern + def getBigStructSize(): native.CInt = native.extern } import Struct._ diff --git a/tests/samples/Union.c b/tests/samples/Union.c index 8cb4d02..8071061 100644 --- a/tests/samples/Union.c +++ b/tests/samples/Union.c @@ -4,3 +4,5 @@ void setIntValue(union values *v) { v->i = 10; } void setLongValue(union values *v) { v->l = 10000000000; } + +int getUnionSize() { return sizeof(union values); } diff --git a/tests/samples/Union.h b/tests/samples/Union.h index e3a8f95..a2746fa 100644 --- a/tests/samples/Union.h +++ b/tests/samples/Union.h @@ -7,3 +7,5 @@ union values { void setIntValue(union values *v); void setLongValue(union values *v); + +int getUnionSize(); diff --git a/tests/samples/Union.scala b/tests/samples/Union.scala index c9d9b6d..cf72bae 100644 --- a/tests/samples/Union.scala +++ b/tests/samples/Union.scala @@ -9,6 +9,7 @@ object Union { type union_values = native.CArray[Byte, native.Nat._8] def setIntValue(v: native.Ptr[union_values]): Unit = native.extern def setLongValue(v: native.Ptr[union_values]): Unit = native.extern + def getUnionSize(): native.CInt = native.extern } import Union._ diff --git a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala index caa4e6d..3ee3fef 100644 --- a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala +++ b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala @@ -1,6 +1,7 @@ package org.scalanative.bindgen.samples import utest._ +import scala.scalanative.native.sizeof import org.scalanative.bindgen.samples.StructHelpers._ object StructTests extends TestSuite { @@ -10,5 +11,9 @@ object StructTests extends TestSuite { assert(point.x == 10) assert(point.y == 20) } + + 'bigStructSize - { + assert(Struct.getBigStructSize() == sizeof[Struct.struct_bigStruct]) + } } } diff --git a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala index 80d6b5e..97b11c6 100644 --- a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala +++ b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala @@ -13,6 +13,8 @@ object UnionTests extends TestSuite { assert(!structPtr.i == 10) Union.setLongValue(structPtr) assert(!structPtr.l == 10000000000L) + + assert(Union.getUnionSize() == sizeof[Union.union_values]) } } } From 5d35f1b0eb93b10f24082b86f0b4eae5f0e37ad3 Mon Sep 17 00:00:00 2001 From: kornilova-l Date: Mon, 2 Jul 2018 11:00:41 +0400 Subject: [PATCH 3/5] Test helper methods for inner anonymous struct --- tests/samples/Struct.c | 8 +++++++ tests/samples/Struct.h | 12 ++++++++++ tests/samples/Struct.scala | 12 ++++++++++ .../bindgen/samples/StructTests.scala | 23 ++++++++++++++++++- 4 files changed, 54 insertions(+), 1 deletion(-) diff --git a/tests/samples/Struct.c b/tests/samples/Struct.c index 9406945..d721854 100644 --- a/tests/samples/Struct.c +++ b/tests/samples/Struct.c @@ -9,3 +9,11 @@ point_s getPoint() { } int getBigStructSize() { return sizeof(struct bigStruct); } + +char getCharFromAnonymousStruct(struct structWithAnonymousStruct *s) { + return s->anonymousStruct.c; +} + +char getIntFromAnonymousStruct(struct structWithAnonymousStruct *s) { + return s->anonymousStruct.i; +} diff --git a/tests/samples/Struct.h b/tests/samples/Struct.h index 47f2a8c..42dda09 100644 --- a/tests/samples/Struct.h +++ b/tests/samples/Struct.h @@ -34,3 +34,15 @@ struct bigStruct { }; int getBigStructSize(); + +struct structWithAnonymousStruct { + int a; + struct { + char c; + int i; + } anonymousStruct; +}; + +char getCharFromAnonymousStruct(struct structWithAnonymousStruct *s); + +char getIntFromAnonymousStruct(struct structWithAnonymousStruct *s); diff --git a/tests/samples/Struct.scala b/tests/samples/Struct.scala index 6148a0e..5ef17ec 100644 --- a/tests/samples/Struct.scala +++ b/tests/samples/Struct.scala @@ -9,8 +9,11 @@ object Struct { type struct_point = native.CStruct2[native.CInt, native.CInt] type point_s = native.Ptr[struct_point] type struct_bigStruct = native.CArray[Byte, native.Nat.Digit[native.Nat._1, native.Nat.Digit[native.Nat._1, native.Nat._2]]] + type struct_structWithAnonymousStruct = native.CStruct2[native.CInt, native.CArray[Byte, native.Nat._8]] def getPoint(): native.Ptr[struct_point] = native.extern def getBigStructSize(): native.CInt = native.extern + def getCharFromAnonymousStruct(s: native.Ptr[struct_structWithAnonymousStruct]): native.CChar = native.extern + def getIntFromAnonymousStruct(s: native.Ptr[struct_structWithAnonymousStruct]): native.CChar = native.extern } import Struct._ @@ -25,4 +28,13 @@ object StructHelpers { } def struct_point()(implicit z: native.Zone): native.Ptr[struct_point] = native.alloc[struct_point] + + implicit class struct_structWithAnonymousStruct_ops(val p: native.Ptr[struct_structWithAnonymousStruct]) extends AnyVal { + def a: native.CInt = !p._1 + def a_=(value: native.CInt):Unit = !p._1 = value + def anonymousStruct: native.CArray[Byte, native.Nat._8] = !p._2 + def anonymousStruct_=(value: native.CArray[Byte, native.Nat._8]):Unit = !p._2 = value + } + + def struct_structWithAnonymousStruct()(implicit z: native.Zone): native.Ptr[struct_structWithAnonymousStruct] = native.alloc[struct_structWithAnonymousStruct] } diff --git a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala index 3ee3fef..2907318 100644 --- a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala +++ b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala @@ -1,7 +1,7 @@ package org.scalanative.bindgen.samples import utest._ -import scala.scalanative.native.sizeof +import scala.scalanative.native._ import org.scalanative.bindgen.samples.StructHelpers._ object StructTests extends TestSuite { @@ -10,10 +10,31 @@ object StructTests extends TestSuite { val point = Struct.getPoint() assert(point.x == 10) assert(point.y == 20) + + point.x_=(11) + assert(point.x == 11) } 'bigStructSize - { assert(Struct.getBigStructSize() == sizeof[Struct.struct_bigStruct]) } + + 'innerAnonymousStruct - { + type struct_anonymousStruct = CStruct2[CChar, CInt] + Zone { implicit zone => + val anonymousStruct: Ptr[struct_anonymousStruct] = alloc[struct_anonymousStruct] + !anonymousStruct._1 = 'a' + !anonymousStruct._2 = 42 + + val structWithAnonymousStruct = struct_structWithAnonymousStruct() + val array: Ptr[CArray[Byte, Nat._8]] = anonymousStruct.cast[Ptr[CArray[Byte, Nat._8]]] + !structWithAnonymousStruct._2 = !array // works + // structWithAnonymousStruct.anonymousStruct_=(!array) // fixme: fails + // val s = structWithAnonymousStruct.anonymousStruct // fixme: fails + + assert('a' == Struct.getCharFromAnonymousStruct(structWithAnonymousStruct)) + assert(42 == Struct.getIntFromAnonymousStruct(structWithAnonymousStruct)) + } + } } } From 28cfe2230dfce465664148b3700270cdc543944a Mon Sep 17 00:00:00 2001 From: kornilova-l Date: Mon, 2 Jul 2018 11:19:40 +0400 Subject: [PATCH 4/5] Move union size test to separate test case --- .../scalanative/bindgen/samples/UnionTests.scala | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala index 97b11c6..fb028bc 100644 --- a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala +++ b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/UnionTests.scala @@ -8,14 +8,16 @@ object UnionTests extends TestSuite { val tests = Tests { 'getValues - { Zone {implicit zone => - val structPtr = alloc[Union.union_values] - Union.setIntValue(structPtr) - assert(!structPtr.i == 10) - Union.setLongValue(structPtr) - assert(!structPtr.l == 10000000000L) - - assert(Union.getUnionSize() == sizeof[Union.union_values]) + val unionPtr = alloc[Union.union_values] + Union.setIntValue(unionPtr) + assert(!unionPtr.i == 10) + Union.setLongValue(unionPtr) + assert(!unionPtr.l == 10000000000L) } } + + 'unionSize - { + assert(Union.getUnionSize() == sizeof[Union.union_values]) + } } } From 11a0a59716e529015ec9cf31e92640b5f21d203a Mon Sep 17 00:00:00 2001 From: kornilova-l Date: Mon, 2 Jul 2018 11:46:18 +0400 Subject: [PATCH 5/5] Do not use getter for field of type CArray --- .../scala/org/scalanative/bindgen/samples/StructTests.scala | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala index 2907318..a721c52 100644 --- a/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala +++ b/tests/samples/src/test/scala/org/scalanative/bindgen/samples/StructTests.scala @@ -27,10 +27,8 @@ object StructTests extends TestSuite { !anonymousStruct._2 = 42 val structWithAnonymousStruct = struct_structWithAnonymousStruct() - val array: Ptr[CArray[Byte, Nat._8]] = anonymousStruct.cast[Ptr[CArray[Byte, Nat._8]]] - !structWithAnonymousStruct._2 = !array // works - // structWithAnonymousStruct.anonymousStruct_=(!array) // fixme: fails - // val s = structWithAnonymousStruct.anonymousStruct // fixme: fails + val array = anonymousStruct.cast[Ptr[CArray[Byte, Nat._8]]] + !structWithAnonymousStruct._2 = !array assert('a' == Struct.getCharFromAnonymousStruct(structWithAnonymousStruct)) assert(42 == Struct.getIntFromAnonymousStruct(structWithAnonymousStruct))