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