ArrayType.cpp revision bd33e3854555589f312c4d6d89491e2f5cc2f782
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 <hidl-util/Formatter.h>
20#include <android-base/logging.h>
21
22#include "ConstantExpression.h"
23
24namespace android {
25
26ArrayType::ArrayType(ArrayType *srcArray, ConstantExpression *size)
27    : mElementType(srcArray->mElementType),
28      mSizes(srcArray->mSizes),
29      mSizeComments(srcArray->mSizeComments) {
30    prependDimension(size);
31}
32
33ArrayType::ArrayType(Type *elementType, ConstantExpression *size)
34    : mElementType(elementType) {
35    prependDimension(size);
36}
37
38void ArrayType::prependDimension(ConstantExpression *size) {
39    mSizes.insert(mSizes.begin(), size->castSizeT());
40    mSizeComments.insert(mSizeComments.begin(), size->description());
41}
42
43void ArrayType::appendDimension(ConstantExpression *size) {
44    mSizes.push_back(size->castSizeT());
45    mSizeComments.push_back(size->description());
46}
47
48size_t ArrayType::countDimensions() const {
49    return mSizes.size();
50}
51
52void ArrayType::addNamedTypesToSet(std::set<const FQName> &set) const {
53    mElementType->addNamedTypesToSet(set);
54}
55
56bool ArrayType::isArray() const {
57    return true;
58}
59
60Type *ArrayType::getElementType() const {
61    return mElementType;
62}
63
64std::string ArrayType::getCppType(StorageMode mode,
65                                  std::string *extra,
66                                  bool specifyNamespaces) const {
67    const std::string base = mElementType->getCppType(extra, specifyNamespaces);
68    CHECK(extra->empty());
69
70    std::string space = specifyNamespaces ? "::android::hardware::" : "";
71    std::string arrayType = space + "hidl_array<" + base;
72
73    for (size_t i = 0; i < mSizes.size(); ++i) {
74        arrayType += ", ";
75        arrayType += std::to_string(mSizes[i]);
76
77        arrayType += " /* ";
78        arrayType += mSizeComments[i];
79        arrayType += " */";
80    }
81
82    arrayType += ">";
83
84    switch (mode) {
85        case StorageMode_Stack:
86            return arrayType;
87
88        case StorageMode_Argument:
89            return "const " + arrayType + "&";
90
91        case StorageMode_Result:
92            return "const " + arrayType + "*";
93    }
94
95    CHECK(!"Should not be here");
96}
97
98std::string ArrayType::getJavaType(
99        std::string *extra, bool forInitializer) const {
100    std::string baseExtra;
101    const std::string base =
102        mElementType->getJavaType(&baseExtra, forInitializer);
103
104    CHECK(baseExtra.empty());
105
106    extra->clear();
107
108    CHECK(mSizes.size() == mSizeComments.size());
109    for (size_t i = 0; i < mSizes.size(); ++i) {
110        *extra += "[";
111
112        if (forInitializer) {
113            *extra += std::to_string(mSizes[i]);
114            *extra += " ";
115        }
116
117        *extra += "/* " + mSizeComments[i] + " */";
118
119        *extra += "]";
120    }
121
122    return base;
123}
124
125std::string ArrayType::getJavaWrapperType() const {
126    return mElementType->getJavaWrapperType();
127}
128
129std::string ArrayType::getVtsType() const {
130    return "TYPE_ARRAY";
131}
132
133void ArrayType::emitReaderWriter(
134        Formatter &out,
135        const std::string &name,
136        const std::string &parcelObj,
137        bool parcelObjIsPointer,
138        bool isReader,
139        ErrorMode mode) const {
140    std::string baseExtra;
141    std::string baseType = mElementType->getCppType(&baseExtra);
142    CHECK(baseExtra.empty());
143
144    const std::string parentName = "_hidl_" + name + "_parent";
145
146    out << "size_t " << parentName << ";\n\n";
147
148    const std::string parcelObjDeref =
149        parcelObj + (parcelObjIsPointer ? "->" : ".");
150
151    if (isReader) {
152        std::string extra;
153
154        out << name
155            << " = ("
156            << getCppResultType(&extra)
157            << ")"
158            << parcelObjDeref
159            << "readBuffer(&"
160            << parentName
161            << ");\n\n";
162
163        out << "if (" << name << " == nullptr) {\n";
164
165        out.indent();
166
167        out << "_hidl_err = ::android::UNKNOWN_ERROR;\n";
168        handleError2(out, mode);
169
170        out.unindent();
171        out << "}\n\n";
172    } else {
173        size_t numArrayElements = 1;
174        for (auto size : mSizes) {
175            numArrayElements *= size;
176        }
177
178        out << "_hidl_err = "
179            << parcelObjDeref
180            << "writeBuffer("
181            << name
182            << ".data(), "
183            << numArrayElements
184            << " * sizeof("
185            << baseType
186            << "), &"
187            << parentName
188            << ");\n";
189
190        handleError(out, mode);
191    }
192
193    emitReaderWriterEmbedded(
194            out,
195            0 /* depth */,
196            name,
197            name /* sanitizedName */,
198            isReader /* nameIsPointer */,
199            parcelObj,
200            parcelObjIsPointer,
201            isReader,
202            mode,
203            parentName,
204            "0 /* parentOffset */");
205}
206
207void ArrayType::emitReaderWriterEmbedded(
208        Formatter &out,
209        size_t depth,
210        const std::string &name,
211        const std::string &sanitizedName,
212        bool nameIsPointer,
213        const std::string &parcelObj,
214        bool parcelObjIsPointer,
215        bool isReader,
216        ErrorMode mode,
217        const std::string &parentName,
218        const std::string &offsetText) const {
219    if (!mElementType->needsEmbeddedReadWrite()) {
220        return;
221    }
222
223    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
224
225    std::string baseExtra;
226    std::string baseType = mElementType->getCppType(&baseExtra);
227    CHECK(baseExtra.empty());
228
229    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
230
231    out << "for (size_t "
232        << iteratorName
233        << " = 0; "
234        << iteratorName
235        << " < "
236        << dimension()
237        << "; ++"
238        << iteratorName
239        << ") {\n";
240
241    out.indent();
242
243    mElementType->emitReaderWriterEmbedded(
244            out,
245            depth + 1,
246            nameDeref + "data()[" + iteratorName + "]",
247            sanitizedName + "_indexed",
248            false /* nameIsPointer */,
249            parcelObj,
250            parcelObjIsPointer,
251            isReader,
252            mode,
253            parentName,
254            offsetText
255                + " + " + iteratorName + " * sizeof("
256                + baseType
257                + ")");
258
259    out.unindent();
260
261    out << "}\n\n";
262}
263
264void ArrayType::emitResolveReferences(
265            Formatter &out,
266            const std::string &name,
267            bool nameIsPointer,
268            const std::string &parcelObj,
269            bool parcelObjIsPointer,
270            bool isReader,
271            ErrorMode mode) const {
272    emitResolveReferencesEmbedded(
273        out,
274        0 /* depth */,
275        name,
276        name /* sanitizedName */,
277        nameIsPointer,
278        parcelObj,
279        parcelObjIsPointer,
280        isReader,
281        mode,
282        "_hidl_" + name + "_parent",
283        "0 /* parentOffset */");
284}
285
286void ArrayType::emitResolveReferencesEmbedded(
287            Formatter &out,
288            size_t depth,
289            const std::string &name,
290            const std::string &sanitizedName,
291            bool nameIsPointer,
292            const std::string &parcelObj,
293            bool parcelObjIsPointer,
294            bool isReader,
295            ErrorMode mode,
296            const std::string &parentName,
297            const std::string &offsetText) const {
298    CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
299
300    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
301
302    std::string baseExtra;
303    std::string baseType = mElementType->getCppType(&baseExtra);
304
305    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
306
307    out << "for (size_t "
308        << iteratorName
309        << " = 0; "
310        << iteratorName
311        << " < "
312        << dimension()
313        << "; ++"
314        << iteratorName
315        << ") {\n";
316
317    out.indent();
318
319    mElementType->emitResolveReferencesEmbedded(
320        out,
321        depth + 1,
322        nameDeref + "data()[" + iteratorName + "]",
323        sanitizedName + "_indexed",
324        false /* nameIsPointer */,
325        parcelObj,
326        parcelObjIsPointer,
327        isReader,
328        mode,
329        parentName,
330        offsetText + " + " + iteratorName + " * sizeof("
331        + baseType
332        + ")");
333
334    out.unindent();
335
336    out << "}\n\n";
337}
338
339
340bool ArrayType::needsEmbeddedReadWrite() const {
341    return mElementType->needsEmbeddedReadWrite();
342}
343
344bool ArrayType::needsResolveReferences() const {
345    return mElementType->needsResolveReferences();
346}
347
348bool ArrayType::resultNeedsDeref() const {
349    return true;
350}
351
352void ArrayType::emitJavaReaderWriter(
353        Formatter &out,
354        const std::string &parcelObj,
355        const std::string &argName,
356        bool isReader) const {
357    if (isReader) {
358        std::string extra;
359        out << "new "
360            << getJavaType(&extra, true /* forInitializer */)
361            << extra
362            << ";\n";
363    }
364
365    out << "{\n";
366    out.indent();
367
368    out << "HwBlob _hidl_blob = ";
369
370    if (isReader) {
371        out << parcelObj
372            << ".readBuffer();\n";
373    } else {
374        size_t align, size;
375        getAlignmentAndSize(&align, &size);
376
377        out << "new HwBlob("
378            << size
379            << " /* size */);\n";
380    }
381
382    emitJavaFieldReaderWriter(
383            out,
384            0 /* depth */,
385            parcelObj,
386            "_hidl_blob",
387            argName,
388            "0 /* offset */",
389            isReader);
390
391    if (!isReader) {
392        out << parcelObj << ".writeBuffer(_hidl_blob);\n";
393    }
394
395    out.unindent();
396    out << "}\n";
397}
398
399void ArrayType::emitJavaFieldInitializer(
400        Formatter &out, const std::string &fieldName) const {
401    std::string extra;
402    std::string typeName = getJavaType(&extra, false /* forInitializer */);
403
404    std::string extraInit;
405    getJavaType(&extraInit, true /* forInitializer */);
406
407    out << "final "
408        << typeName
409        << extra
410        << " "
411        << fieldName
412        << " = new "
413        << typeName
414        << extraInit
415        << ";\n";
416}
417
418void ArrayType::emitJavaFieldReaderWriter(
419        Formatter &out,
420        size_t depth,
421        const std::string &parcelName,
422        const std::string &blobName,
423        const std::string &fieldName,
424        const std::string &offset,
425        bool isReader) const {
426    out << "{\n";
427    out.indent();
428
429    std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
430    out << "long " << offsetName << " = " << offset << ";\n";
431
432    std::string indexString;
433    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
434        std::string iteratorName =
435            "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
436
437        out << "for (int "
438            << iteratorName
439            << " = 0; "
440            << iteratorName
441            << " < "
442            << mSizes[dim]
443            << "; ++"
444            << iteratorName
445            << ") {\n";
446
447        out.indent();
448
449        indexString += "[" + iteratorName + "]";
450    }
451
452    if (isReader && mElementType->isCompoundType()) {
453        std::string extra;
454        std::string typeName =
455            mElementType->getJavaType(&extra, false /* forInitializer */);
456
457        CHECK(extra.empty());
458
459        out << fieldName
460            << indexString
461            << " = new "
462            << typeName
463            << "();\n";
464    }
465
466    mElementType->emitJavaFieldReaderWriter(
467            out,
468            depth + 1,
469            parcelName,
470            blobName,
471            fieldName + indexString,
472            offsetName,
473            isReader);
474
475    size_t elementAlign, elementSize;
476    mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
477
478    out << offsetName << " += " << std::to_string(elementSize) << ";\n";
479
480    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
481        out.unindent();
482        out << "}\n";
483    }
484
485    out.unindent();
486    out << "}\n";
487}
488
489status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
490    out << "type: " << getVtsType() << "\n";
491    out << "vector_value: {\n";
492    out.indent();
493    out << "vector_size: " << mSizes[0] << "\n";
494    // Simple array case.
495    if (mSizes.size() == 1) {
496        status_t err = mElementType->emitVtsTypeDeclarations(out);
497        if (err != OK) {
498            return err;
499        }
500    } else {  // Multi-dimension array case.
501        for (size_t index = 1; index < mSizes.size(); index++) {
502            out << "type: " << getVtsType() << "\n";
503            out << "vector_value: {\n";
504            out.indent();
505            out << "vector_size: " << mSizes[index] << "\n";
506            if (index == mSizes.size() - 1) {
507                status_t err = mElementType->emitVtsTypeDeclarations(out);
508                if (err != OK) {
509                    return err;
510                }
511            }
512        }
513    }
514    for (size_t index = 0; index < mSizes.size(); index++) {
515        out.unindent();
516        out << "}\n";
517    }
518    return OK;
519}
520
521bool ArrayType::isJavaCompatible() const {
522    return mElementType->isJavaCompatible();
523}
524
525void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
526    mElementType->getAlignmentAndSize(align, size);
527
528    for (auto sizeInDimension : mSizes) {
529        (*size) *= sizeInDimension;
530    }
531}
532
533size_t ArrayType::dimension() const {
534    size_t numArrayElements = 1;
535    for (auto size : mSizes) {
536        numArrayElements *= size;
537    }
538    return numArrayElements;
539}
540
541}  // namespace android
542
543