Home | History | Annotate | Download | only in hidl
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "ArrayType.h"
     18 
     19 #include <android-base/logging.h>
     20 #include <hidl-util/Formatter.h>
     21 #include <iostream>
     22 
     23 #include "ConstantExpression.h"
     24 
     25 namespace android {
     26 
     27 ArrayType::ArrayType(const Reference<Type>& elementType, ConstantExpression* size, Scope* parent)
     28     : Type(parent), mElementType(elementType), mSizes{size} {
     29     CHECK(!elementType.isEmptyReference());
     30 }
     31 
     32 void ArrayType::appendDimension(ConstantExpression *size) {
     33     mSizes.push_back(size);
     34 }
     35 
     36 size_t ArrayType::countDimensions() const {
     37     return mSizes.size();
     38 }
     39 
     40 bool ArrayType::isArray() const {
     41     return true;
     42 }
     43 
     44 bool ArrayType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const {
     45     return mElementType->canCheckEquality(visited);
     46 }
     47 
     48 const Type* ArrayType::getElementType() const {
     49     return mElementType.get();
     50 }
     51 
     52 std::string ArrayType::typeName() const {
     53     if (dimension() == 1) {
     54         return "array of " + mElementType->typeName();
     55     }
     56 
     57     return std::to_string(dimension()) + "d array of " + mElementType->typeName();
     58 }
     59 
     60 std::vector<const Reference<Type>*> ArrayType::getReferences() const {
     61     return {&mElementType};
     62 }
     63 
     64 std::vector<const ConstantExpression*> ArrayType::getConstantExpressions() const {
     65     std::vector<const ConstantExpression*> ret;
     66     ret.insert(ret.end(), mSizes.begin(), mSizes.end());
     67     return ret;
     68 }
     69 
     70 status_t ArrayType::resolveInheritance() {
     71     // Resolve for typedefs
     72     while (mElementType->isArray()) {
     73         ArrayType* innerArray = static_cast<ArrayType*>(mElementType.get());
     74         mSizes.insert(mSizes.end(), innerArray->mSizes.begin(), innerArray->mSizes.end());
     75         mElementType = innerArray->mElementType;
     76     }
     77     return Type::resolveInheritance();
     78 }
     79 
     80 status_t ArrayType::validate() const {
     81     CHECK(!mElementType->isArray());
     82 
     83     if (mElementType->isBinder()) {
     84         std::cerr << "ERROR: Arrays of interface types are not supported"
     85                   << " at " << mElementType.location() << "\n";
     86 
     87         return UNKNOWN_ERROR;
     88     }
     89     return Type::validate();
     90 }
     91 
     92 std::string ArrayType::getCppType(StorageMode mode,
     93                                   bool specifyNamespaces) const {
     94     const std::string base = mElementType->getCppStackType(specifyNamespaces);
     95 
     96     std::string space = specifyNamespaces ? "::android::hardware::" : "";
     97     std::string arrayType = space + "hidl_array<" + base;
     98 
     99     for (size_t i = 0; i < mSizes.size(); ++i) {
    100         arrayType += ", ";
    101         arrayType += mSizes[i]->cppValue();
    102 
    103         if (!mSizes[i]->descriptionIsTrivial()) {
    104             arrayType += " /* ";
    105             arrayType += mSizes[i]->description();
    106             arrayType += " */";
    107         }
    108     }
    109 
    110     arrayType += ">";
    111 
    112     switch (mode) {
    113         case StorageMode_Stack:
    114             return arrayType;
    115 
    116         case StorageMode_Argument:
    117             return "const " + arrayType + "&";
    118 
    119         case StorageMode_Result:
    120             return "const " + arrayType + "*";
    121     }
    122 
    123     CHECK(!"Should not be here");
    124 }
    125 
    126 std::string ArrayType::getInternalDataCppType() const {
    127     std::string result = mElementType->getCppStackType();
    128     for (size_t i = 0; i < mSizes.size(); ++i) {
    129         result += "[";
    130         result += mSizes[i]->cppValue();
    131         result += "]";
    132     }
    133     return result;
    134 }
    135 
    136 std::string ArrayType::getJavaType(bool forInitializer) const {
    137     std::string base =
    138         mElementType->getJavaType(forInitializer);
    139 
    140     for (size_t i = 0; i < mSizes.size(); ++i) {
    141         base += "[";
    142 
    143         if (forInitializer) {
    144             base += mSizes[i]->javaValue();
    145         }
    146 
    147         if (!forInitializer || !mSizes[i]->descriptionIsTrivial()) {
    148             if (forInitializer)
    149                 base += " ";
    150             base += "/* " + mSizes[i]->description() + " */";
    151         }
    152 
    153         base += "]";
    154     }
    155 
    156     return base;
    157 }
    158 
    159 std::string ArrayType::getJavaWrapperType() const {
    160     return mElementType->getJavaWrapperType();
    161 }
    162 
    163 std::string ArrayType::getVtsType() const {
    164     return "TYPE_ARRAY";
    165 }
    166 
    167 void ArrayType::emitReaderWriter(
    168         Formatter &out,
    169         const std::string &name,
    170         const std::string &parcelObj,
    171         bool parcelObjIsPointer,
    172         bool isReader,
    173         ErrorMode mode) const {
    174     std::string baseType = mElementType->getCppStackType();
    175 
    176     const std::string parentName = "_hidl_" + name + "_parent";
    177 
    178     out << "size_t " << parentName << ";\n\n";
    179 
    180     const std::string parcelObjDeref =
    181         parcelObj + (parcelObjIsPointer ? "->" : ".");
    182 
    183     size_t numArrayElements = 1;
    184     for (auto size : mSizes) {
    185         numArrayElements *= size->castSizeT();
    186     }
    187     if (isReader) {
    188         out << "_hidl_err = "
    189             << parcelObjDeref
    190             << "readBuffer("
    191             << numArrayElements
    192             << " * sizeof("
    193             << baseType
    194             << "), &"
    195             << parentName
    196             << ", "
    197             << " reinterpret_cast<const void **>("
    198             << "&" << name
    199             << "));\n\n";
    200 
    201         handleError(out, mode);
    202     } else {
    203 
    204         out << "_hidl_err = "
    205             << parcelObjDeref
    206             << "writeBuffer("
    207             << name
    208             << ".data(), "
    209             << numArrayElements
    210             << " * sizeof("
    211             << baseType
    212             << "), &"
    213             << parentName
    214             << ");\n";
    215 
    216         handleError(out, mode);
    217     }
    218 
    219     emitReaderWriterEmbedded(
    220             out,
    221             0 /* depth */,
    222             name,
    223             name /* sanitizedName */,
    224             isReader /* nameIsPointer */,
    225             parcelObj,
    226             parcelObjIsPointer,
    227             isReader,
    228             mode,
    229             parentName,
    230             "0 /* parentOffset */");
    231 }
    232 
    233 void ArrayType::emitReaderWriterEmbedded(
    234         Formatter &out,
    235         size_t depth,
    236         const std::string &name,
    237         const std::string &sanitizedName,
    238         bool nameIsPointer,
    239         const std::string &parcelObj,
    240         bool parcelObjIsPointer,
    241         bool isReader,
    242         ErrorMode mode,
    243         const std::string &parentName,
    244         const std::string &offsetText) const {
    245     if (!mElementType->needsEmbeddedReadWrite()) {
    246         return;
    247     }
    248 
    249     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
    250 
    251     std::string baseType = mElementType->getCppStackType();
    252 
    253     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
    254 
    255     out << "for (size_t "
    256         << iteratorName
    257         << " = 0; "
    258         << iteratorName
    259         << " < "
    260         << dimension()
    261         << "; ++"
    262         << iteratorName
    263         << ") {\n";
    264 
    265     out.indent();
    266 
    267     mElementType->emitReaderWriterEmbedded(
    268             out,
    269             depth + 1,
    270             nameDeref + "data()[" + iteratorName + "]",
    271             sanitizedName + "_indexed",
    272             false /* nameIsPointer */,
    273             parcelObj,
    274             parcelObjIsPointer,
    275             isReader,
    276             mode,
    277             parentName,
    278             offsetText
    279                 + " + " + iteratorName + " * sizeof("
    280                 + baseType
    281                 + ")");
    282 
    283     out.unindent();
    284 
    285     out << "}\n\n";
    286 }
    287 
    288 void ArrayType::emitResolveReferences(
    289             Formatter &out,
    290             const std::string &name,
    291             bool nameIsPointer,
    292             const std::string &parcelObj,
    293             bool parcelObjIsPointer,
    294             bool isReader,
    295             ErrorMode mode) const {
    296     emitResolveReferencesEmbedded(
    297         out,
    298         0 /* depth */,
    299         name,
    300         name /* sanitizedName */,
    301         nameIsPointer,
    302         parcelObj,
    303         parcelObjIsPointer,
    304         isReader,
    305         mode,
    306         "_hidl_" + name + "_parent",
    307         "0 /* parentOffset */");
    308 }
    309 
    310 void ArrayType::emitResolveReferencesEmbedded(
    311             Formatter &out,
    312             size_t depth,
    313             const std::string &name,
    314             const std::string &sanitizedName,
    315             bool nameIsPointer,
    316             const std::string &parcelObj,
    317             bool parcelObjIsPointer,
    318             bool isReader,
    319             ErrorMode mode,
    320             const std::string &parentName,
    321             const std::string &offsetText) const {
    322     CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
    323 
    324     const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
    325 
    326     std::string baseType = mElementType->getCppStackType();
    327 
    328     std::string iteratorName = "_hidl_index_" + std::to_string(depth);
    329 
    330     out << "for (size_t "
    331         << iteratorName
    332         << " = 0; "
    333         << iteratorName
    334         << " < "
    335         << dimension()
    336         << "; ++"
    337         << iteratorName
    338         << ") {\n";
    339 
    340     out.indent();
    341 
    342     mElementType->emitResolveReferencesEmbedded(
    343         out,
    344         depth + 1,
    345         nameDeref + "data()[" + iteratorName + "]",
    346         sanitizedName + "_indexed",
    347         false /* nameIsPointer */,
    348         parcelObj,
    349         parcelObjIsPointer,
    350         isReader,
    351         mode,
    352         parentName,
    353         offsetText + " + " + iteratorName + " * sizeof("
    354         + baseType
    355         + ")");
    356 
    357     out.unindent();
    358 
    359     out << "}\n\n";
    360 }
    361 
    362 void ArrayType::emitJavaDump(
    363         Formatter &out,
    364         const std::string &streamName,
    365         const std::string &name) const {
    366     out << streamName << ".append(java.util.Arrays."
    367         << (countDimensions() > 1 ? "deepToString" : "toString")
    368         << "("
    369         << name << "));\n";
    370 }
    371 
    372 
    373 bool ArrayType::needsEmbeddedReadWrite() const {
    374     return mElementType->needsEmbeddedReadWrite();
    375 }
    376 
    377 bool ArrayType::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const {
    378     if (mElementType->needsResolveReferences(visited)) {
    379         return true;
    380     }
    381     return Type::deepNeedsResolveReferences(visited);
    382 }
    383 
    384 bool ArrayType::resultNeedsDeref() const {
    385     return true;
    386 }
    387 
    388 void ArrayType::emitJavaReaderWriter(
    389         Formatter &out,
    390         const std::string &parcelObj,
    391         const std::string &argName,
    392         bool isReader) const {
    393     size_t align, size;
    394     getAlignmentAndSize(&align, &size);
    395 
    396     if (isReader) {
    397         out << "new "
    398             << getJavaType(true /* forInitializer */)
    399             << ";\n";
    400     }
    401 
    402     out << "{\n";
    403     out.indent();
    404 
    405     out << "android.os.HwBlob _hidl_blob = ";
    406 
    407     if (isReader) {
    408         out << parcelObj
    409             << ".readBuffer("
    410             << size
    411             << " /* size */);\n";
    412     } else {
    413         out << "new android.os.HwBlob("
    414             << size
    415             << " /* size */);\n";
    416     }
    417 
    418     emitJavaFieldReaderWriter(
    419             out,
    420             0 /* depth */,
    421             parcelObj,
    422             "_hidl_blob",
    423             argName,
    424             "0 /* offset */",
    425             isReader);
    426 
    427     if (!isReader) {
    428         out << parcelObj << ".writeBuffer(_hidl_blob);\n";
    429     }
    430 
    431     out.unindent();
    432     out << "}\n";
    433 }
    434 
    435 void ArrayType::emitJavaFieldInitializer(
    436         Formatter &out, const std::string &fieldName) const {
    437     std::string typeName = getJavaType(false /* forInitializer */);
    438     std::string initName = getJavaType(true /* forInitializer */);
    439 
    440     out << "final "
    441         << typeName
    442         << " "
    443         << fieldName
    444         << " = new "
    445         << initName
    446         << ";\n";
    447 }
    448 
    449 void ArrayType::emitJavaFieldReaderWriter(
    450         Formatter &out,
    451         size_t depth,
    452         const std::string &parcelName,
    453         const std::string &blobName,
    454         const std::string &fieldName,
    455         const std::string &offset,
    456         bool isReader) const {
    457     out << "{\n";
    458     out.indent();
    459 
    460     std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
    461     out << "long " << offsetName << " = " << offset << ";\n";
    462 
    463     const bool isPrimitiveArray = mElementType->isScalar();
    464 
    465     /* If the element type corresponds to a Java primitive type we can optimize
    466        the innermost loop by copying a linear range of memory instead of doing
    467        a per-element copy. As a result the outer nested loop does not include
    468        the final dimension. */
    469     const size_t loopDimensions = mSizes.size() - (isPrimitiveArray ? 1 : 0);
    470 
    471     std::string indexString;
    472     for (size_t dim = 0; dim < loopDimensions; ++dim) {
    473         std::string iteratorName =
    474             "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
    475 
    476         out << "for (int "
    477             << iteratorName
    478             << " = 0; "
    479             << iteratorName
    480             << " < "
    481             << mSizes[dim]->javaValue()
    482             << "; ++"
    483             << iteratorName
    484             << ") {\n";
    485 
    486         out.indent();
    487 
    488         indexString += "[" + iteratorName + "]";
    489     }
    490 
    491     if (isReader && mElementType->isCompoundType()) {
    492         std::string typeName =
    493             mElementType->getJavaType(false /* forInitializer */);
    494 
    495         out << fieldName
    496             << indexString
    497             << " = new "
    498             << typeName
    499             << "();\n";
    500     }
    501 
    502     if (!isPrimitiveArray) {
    503         mElementType->emitJavaFieldReaderWriter(
    504                 out,
    505                 depth + 1,
    506                 parcelName,
    507                 blobName,
    508                 fieldName + indexString,
    509                 offsetName,
    510                 isReader);
    511 
    512         size_t elementAlign, elementSize;
    513         mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
    514 
    515         out << offsetName << " += " << std::to_string(elementSize) << ";\n";
    516     } else {
    517         if (isReader) {
    518             out << blobName
    519                 << ".copyTo"
    520                 << mElementType->getJavaSuffix()
    521                 << "Array("
    522                 << offsetName
    523                 << ", "
    524                 << fieldName
    525                 << indexString
    526                 << ", "
    527                 << mSizes.back()->javaValue()
    528                 << " /* size */);\n";
    529         } else {
    530             out << blobName
    531                 << ".put"
    532                 << mElementType->getJavaSuffix()
    533                 << "Array("
    534                 << offsetName
    535                 << ", "
    536                 << fieldName
    537                 << indexString
    538                 << ");\n";
    539         }
    540 
    541         size_t elementAlign, elementSize;
    542         mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
    543 
    544         out << offsetName
    545             << " += "
    546             << mSizes.back()->javaValue()
    547             << " * "
    548             << elementSize
    549             << ";\n";
    550     }
    551 
    552     for (size_t dim = 0; dim < loopDimensions; ++dim) {
    553         out.unindent();
    554         out << "}\n";
    555     }
    556 
    557     out.unindent();
    558     out << "}\n";
    559 }
    560 
    561 void ArrayType::emitVtsTypeDeclarations(Formatter& out) const {
    562     out << "type: " << getVtsType() << "\n";
    563     out << "vector_size: " << mSizes[0]->value() << "\n";
    564     out << "vector_value: {\n";
    565     out.indent();
    566     // Simple array case.
    567     if (mSizes.size() == 1) {
    568         mElementType->emitVtsTypeDeclarations(out);
    569     } else {  // Multi-dimension array case.
    570         for (size_t index = 1; index < mSizes.size(); index++) {
    571             out << "type: " << getVtsType() << "\n";
    572             out << "vector_size: " << mSizes[index]->value() << "\n";
    573             out << "vector_value: {\n";
    574             out.indent();
    575             if (index == mSizes.size() - 1) {
    576                 mElementType->emitVtsTypeDeclarations(out);
    577             }
    578         }
    579     }
    580     for (size_t index = 0; index < mSizes.size(); index++) {
    581         out.unindent();
    582         out << "}\n";
    583     }
    584 }
    585 
    586 bool ArrayType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const {
    587     if (!mElementType->isJavaCompatible(visited)) {
    588         return false;
    589     }
    590     return Type::deepIsJavaCompatible(visited);
    591 }
    592 
    593 bool ArrayType::deepContainsPointer(std::unordered_set<const Type*>* visited) const {
    594     if (mElementType->containsPointer(visited)) {
    595         return true;
    596     }
    597     return Type::deepContainsPointer(visited);
    598 }
    599 
    600 void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
    601     mElementType->getAlignmentAndSize(align, size);
    602 
    603     for (auto sizeInDimension : mSizes) {
    604         (*size) *= sizeInDimension->castSizeT();
    605     }
    606 }
    607 
    608 size_t ArrayType::dimension() const {
    609     size_t numArrayElements = 1;
    610     for (auto size : mSizes) {
    611         numArrayElements *= size->castSizeT();
    612     }
    613     return numArrayElements;
    614 }
    615 
    616 }  // namespace android
    617 
    618