ArrayType.cpp revision c46e9842bd82d9c70e08b37a4507b448b285d6c6
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 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 += std::to_string(mSizes[i]);
71
72        arrayType += " /* ";
73        arrayType += mSizeComments[i];
74        arrayType += " */";
75    }
76
77    arrayType += ">";
78
79    switch (mode) {
80        case StorageMode_Stack:
81            return arrayType;
82
83        case StorageMode_Argument:
84            return "const " + arrayType + "&";
85
86        case StorageMode_Result:
87            return "const " + arrayType + "*";
88    }
89
90    CHECK(!"Should not be here");
91}
92
93std::string ArrayType::getJavaType(
94        std::string *extra, bool forInitializer) const {
95    std::string baseExtra;
96    const std::string base =
97        mElementType->getJavaType(&baseExtra, forInitializer);
98
99    CHECK(baseExtra.empty());
100
101    extra->clear();
102
103    CHECK(mSizes.size() == mSizeComments.size());
104    for (size_t i = 0; i < mSizes.size(); ++i) {
105        *extra += "[";
106
107        if (forInitializer) {
108            *extra += std::to_string(mSizes[i]);
109            *extra += " ";
110        }
111
112        *extra += "/* " + mSizeComments[i] + " */";
113
114        *extra += "]";
115    }
116
117    return base;
118}
119
120std::string ArrayType::getJavaWrapperType() const {
121    return mElementType->getJavaWrapperType();
122}
123
124std::string ArrayType::getVtsType() const {
125    return "TYPE_ARRAY";
126}
127
128void ArrayType::emitReaderWriter(
129        Formatter &out,
130        const std::string &name,
131        const std::string &parcelObj,
132        bool parcelObjIsPointer,
133        bool isReader,
134        ErrorMode mode) const {
135    std::string baseExtra;
136    std::string baseType = mElementType->getCppType(&baseExtra);
137    CHECK(baseExtra.empty());
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        std::string extra;
148
149        out << name
150            << " = ("
151            << getCppResultType(&extra)
152            << ")"
153            << parcelObjDeref
154            << "readBuffer(&"
155            << parentName
156            << ");\n\n";
157
158        out << "if (" << name << " == nullptr) {\n";
159
160        out.indent();
161
162        out << "_hidl_err = ::android::UNKNOWN_ERROR;\n";
163        handleError2(out, mode);
164
165        out.unindent();
166        out << "}\n\n";
167    } else {
168        size_t numArrayElements = 1;
169        for (auto size : mSizes) {
170            numArrayElements *= size;
171        }
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 baseExtra;
221    std::string baseType = mElementType->getCppType(&baseExtra);
222    CHECK(baseExtra.empty());
223
224    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
225
226    out << "for (size_t "
227        << iteratorName
228        << " = 0; "
229        << iteratorName
230        << " < "
231        << dimension()
232        << "; ++"
233        << iteratorName
234        << ") {\n";
235
236    out.indent();
237
238    mElementType->emitReaderWriterEmbedded(
239            out,
240            depth + 1,
241            nameDeref + "data()[" + iteratorName + "]",
242            sanitizedName + "_indexed",
243            false /* nameIsPointer */,
244            parcelObj,
245            parcelObjIsPointer,
246            isReader,
247            mode,
248            parentName,
249            offsetText
250                + " + " + iteratorName + " * sizeof("
251                + baseType
252                + ")");
253
254    out.unindent();
255
256    out << "}\n\n";
257}
258
259void ArrayType::emitResolveReferences(
260            Formatter &out,
261            const std::string &name,
262            bool nameIsPointer,
263            const std::string &parcelObj,
264            bool parcelObjIsPointer,
265            bool isReader,
266            ErrorMode mode) const {
267    emitResolveReferencesEmbedded(
268        out,
269        0 /* depth */,
270        name,
271        name /* sanitizedName */,
272        nameIsPointer,
273        parcelObj,
274        parcelObjIsPointer,
275        isReader,
276        mode,
277        "_hidl_" + name + "_parent",
278        "0 /* parentOffset */");
279}
280
281void ArrayType::emitResolveReferencesEmbedded(
282            Formatter &out,
283            size_t depth,
284            const std::string &name,
285            const std::string &sanitizedName,
286            bool nameIsPointer,
287            const std::string &parcelObj,
288            bool parcelObjIsPointer,
289            bool isReader,
290            ErrorMode mode,
291            const std::string &parentName,
292            const std::string &offsetText) const {
293    CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
294
295    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
296
297    std::string baseExtra;
298    std::string baseType = mElementType->getCppType(&baseExtra);
299
300    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
301
302    out << "for (size_t "
303        << iteratorName
304        << " = 0; "
305        << iteratorName
306        << " < "
307        << dimension()
308        << "; ++"
309        << iteratorName
310        << ") {\n";
311
312    out.indent();
313
314    mElementType->emitResolveReferencesEmbedded(
315        out,
316        depth + 1,
317        nameDeref + "data()[" + iteratorName + "]",
318        sanitizedName + "_indexed",
319        false /* nameIsPointer */,
320        parcelObj,
321        parcelObjIsPointer,
322        isReader,
323        mode,
324        parentName,
325        offsetText + " + " + iteratorName + " * sizeof("
326        + baseType
327        + ")");
328
329    out.unindent();
330
331    out << "}\n\n";
332}
333
334
335bool ArrayType::needsEmbeddedReadWrite() const {
336    return mElementType->needsEmbeddedReadWrite();
337}
338
339bool ArrayType::needsResolveReferences() const {
340    return mElementType->needsResolveReferences();
341}
342
343bool ArrayType::resultNeedsDeref() const {
344    return true;
345}
346
347void ArrayType::emitJavaReaderWriter(
348        Formatter &out,
349        const std::string &parcelObj,
350        const std::string &argName,
351        bool isReader) const {
352    if (isReader) {
353        std::string extra;
354        out << "new "
355            << getJavaType(&extra, true /* forInitializer */)
356            << extra
357            << ";\n";
358    }
359
360    out << "{\n";
361    out.indent();
362
363    out << "HwBlob _hidl_blob = ";
364
365    if (isReader) {
366        out << parcelObj
367            << ".readBuffer();\n";
368    } else {
369        size_t align, size;
370        getAlignmentAndSize(&align, &size);
371
372        out << "new HwBlob("
373            << size
374            << " /* size */);\n";
375    }
376
377    emitJavaFieldReaderWriter(
378            out,
379            0 /* depth */,
380            parcelObj,
381            "_hidl_blob",
382            argName,
383            "0 /* offset */",
384            isReader);
385
386    if (!isReader) {
387        out << parcelObj << ".writeBuffer(_hidl_blob);\n";
388    }
389
390    out.unindent();
391    out << "}\n";
392}
393
394void ArrayType::emitJavaFieldInitializer(
395        Formatter &out, const std::string &fieldName) const {
396    std::string extra;
397    std::string typeName = getJavaType(&extra, false /* forInitializer */);
398
399    std::string extraInit;
400    getJavaType(&extraInit, true /* forInitializer */);
401
402    out << "final "
403        << typeName
404        << extra
405        << " "
406        << fieldName
407        << " = new "
408        << typeName
409        << extraInit
410        << ";\n";
411}
412
413void ArrayType::emitJavaFieldReaderWriter(
414        Formatter &out,
415        size_t depth,
416        const std::string &parcelName,
417        const std::string &blobName,
418        const std::string &fieldName,
419        const std::string &offset,
420        bool isReader) const {
421    out << "{\n";
422    out.indent();
423
424    std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
425    out << "long " << offsetName << " = " << offset << ";\n";
426
427    std::string indexString;
428    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
429        std::string iteratorName =
430            "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
431
432        out << "for (int "
433            << iteratorName
434            << " = 0; "
435            << iteratorName
436            << " < "
437            << mSizes[dim]
438            << "; ++"
439            << iteratorName
440            << ") {\n";
441
442        out.indent();
443
444        indexString += "[" + iteratorName + "]";
445    }
446
447    if (isReader && mElementType->isCompoundType()) {
448        std::string extra;
449        std::string typeName =
450            mElementType->getJavaType(&extra, false /* forInitializer */);
451
452        CHECK(extra.empty());
453
454        out << fieldName
455            << indexString
456            << " = new "
457            << typeName
458            << "();\n";
459    }
460
461    mElementType->emitJavaFieldReaderWriter(
462            out,
463            depth + 1,
464            parcelName,
465            blobName,
466            fieldName + indexString,
467            offsetName,
468            isReader);
469
470    size_t elementAlign, elementSize;
471    mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
472
473    out << offsetName << " += " << std::to_string(elementSize) << ";\n";
474
475    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
476        out.unindent();
477        out << "}\n";
478    }
479
480    out.unindent();
481    out << "}\n";
482}
483
484status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
485    out << "type: " << getVtsType() << "\n";
486    out << "vector_value: {\n";
487    out.indent();
488    out << "vector_size: " << mSizes[0] << "\n";
489    // Simple array case.
490    if (mSizes.size() == 1) {
491        status_t err = mElementType->emitVtsTypeDeclarations(out);
492        if (err != OK) {
493            return err;
494        }
495    } else {  // Multi-dimension array case.
496        for (size_t index = 1; index < mSizes.size(); index++) {
497            out << "type: " << getVtsType() << "\n";
498            out << "vector_value: {\n";
499            out.indent();
500            out << "vector_size: " << mSizes[index] << "\n";
501            if (index == mSizes.size() - 1) {
502                status_t err = mElementType->emitVtsTypeDeclarations(out);
503                if (err != OK) {
504                    return err;
505                }
506            }
507        }
508    }
509    for (size_t index = 0; index < mSizes.size(); index++) {
510        out.unindent();
511        out << "}\n";
512    }
513    return OK;
514}
515
516bool ArrayType::isJavaCompatible() const {
517    return mElementType->isJavaCompatible();
518}
519
520void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
521    mElementType->getAlignmentAndSize(align, size);
522
523    for (auto sizeInDimension : mSizes) {
524        (*size) *= sizeInDimension;
525    }
526}
527
528size_t ArrayType::dimension() const {
529    size_t numArrayElements = 1;
530    for (auto size : mSizes) {
531        numArrayElements *= size;
532    }
533    return numArrayElements;
534}
535
536}  // namespace android
537
538