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