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