ArrayType.cpp revision be2a3737675b83dd61b52c11f0d7549fa1276739
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
123void ArrayType::emitReaderWriter(
124        Formatter &out,
125        const std::string &name,
126        const std::string &parcelObj,
127        bool parcelObjIsPointer,
128        bool isReader,
129        ErrorMode mode) const {
130    std::string baseExtra;
131    std::string baseType = mElementType->getCppType(&baseExtra);
132    CHECK(baseExtra.empty());
133
134    const std::string parentName = "_hidl_" + name + "_parent";
135
136    out << "size_t " << parentName << ";\n\n";
137
138    const std::string parcelObjDeref =
139        parcelObj + (parcelObjIsPointer ? "->" : ".");
140
141    if (isReader) {
142        std::string extra;
143
144        out << name
145            << " = ("
146            << getCppResultType(&extra)
147            << ")"
148            << parcelObjDeref
149            << "readBuffer(&"
150            << parentName
151            << ");\n\n";
152
153        out << "if (" << name << " == nullptr) {\n";
154
155        out.indent();
156
157        out << "_hidl_err = ::android::UNKNOWN_ERROR;\n";
158        handleError2(out, mode);
159
160        out.unindent();
161        out << "}\n\n";
162    } else {
163        size_t numArrayElements = 1;
164        for (auto size : mSizes) {
165            numArrayElements *= size;
166        }
167
168        out << "_hidl_err = "
169            << parcelObjDeref
170            << "writeBuffer("
171            << name
172            << ".data(), "
173            << numArrayElements
174            << " * sizeof("
175            << baseType
176            << "), &"
177            << parentName
178            << ");\n";
179
180        handleError(out, mode);
181    }
182
183    emitReaderWriterEmbedded(
184            out,
185            0 /* depth */,
186            name,
187            name /* sanitizedName */,
188            isReader /* nameIsPointer */,
189            parcelObj,
190            parcelObjIsPointer,
191            isReader,
192            mode,
193            parentName,
194            "0 /* parentOffset */");
195}
196
197void ArrayType::emitReaderWriterEmbedded(
198        Formatter &out,
199        size_t depth,
200        const std::string &name,
201        const std::string &sanitizedName,
202        bool nameIsPointer,
203        const std::string &parcelObj,
204        bool parcelObjIsPointer,
205        bool isReader,
206        ErrorMode mode,
207        const std::string &parentName,
208        const std::string &offsetText) const {
209    if (!mElementType->needsEmbeddedReadWrite()) {
210        return;
211    }
212
213    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
214
215    std::string baseExtra;
216    std::string baseType = mElementType->getCppType(&baseExtra);
217    CHECK(baseExtra.empty());
218
219    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
220
221    out << "for (size_t "
222        << iteratorName
223        << " = 0; "
224        << iteratorName
225        << " < "
226        << dimension()
227        << "; ++"
228        << iteratorName
229        << ") {\n";
230
231    out.indent();
232
233    mElementType->emitReaderWriterEmbedded(
234            out,
235            depth + 1,
236            nameDeref + "data()[" + iteratorName + "]",
237            sanitizedName + "_indexed",
238            false /* nameIsPointer */,
239            parcelObj,
240            parcelObjIsPointer,
241            isReader,
242            mode,
243            parentName,
244            offsetText
245                + " + " + iteratorName + " * sizeof("
246                + baseType
247                + ")");
248
249    out.unindent();
250
251    out << "}\n\n";
252}
253
254void ArrayType::emitResolveReferences(
255            Formatter &out,
256            const std::string &name,
257            bool nameIsPointer,
258            const std::string &parcelObj,
259            bool parcelObjIsPointer,
260            bool isReader,
261            ErrorMode mode) const {
262    emitResolveReferencesEmbedded(
263        out,
264        0 /* depth */,
265        name,
266        name /* sanitizedName */,
267        nameIsPointer,
268        parcelObj,
269        parcelObjIsPointer,
270        isReader,
271        mode,
272        "_hidl_" + name + "_parent",
273        "0 /* parentOffset */");
274}
275
276void ArrayType::emitResolveReferencesEmbedded(
277            Formatter &out,
278            size_t depth,
279            const std::string &name,
280            const std::string &sanitizedName,
281            bool nameIsPointer,
282            const std::string &parcelObj,
283            bool parcelObjIsPointer,
284            bool isReader,
285            ErrorMode mode,
286            const std::string &parentName,
287            const std::string &offsetText) const {
288    CHECK(needsResolveReferences() && mElementType->needsResolveReferences());
289
290    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
291
292    std::string baseExtra;
293    std::string baseType = mElementType->getCppType(&baseExtra);
294
295    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
296
297    out << "for (size_t "
298        << iteratorName
299        << " = 0; "
300        << iteratorName
301        << " < "
302        << dimension()
303        << "; ++"
304        << iteratorName
305        << ") {\n";
306
307    out.indent();
308
309    mElementType->emitResolveReferencesEmbedded(
310        out,
311        depth + 1,
312        nameDeref + "data()[" + iteratorName + "]",
313        sanitizedName + "_indexed",
314        false /* nameIsPointer */,
315        parcelObj,
316        parcelObjIsPointer,
317        isReader,
318        mode,
319        parentName,
320        offsetText + " + " + iteratorName + " * sizeof("
321        + baseType
322        + ")");
323
324    out.unindent();
325
326    out << "}\n\n";
327}
328
329
330bool ArrayType::needsEmbeddedReadWrite() const {
331    return mElementType->needsEmbeddedReadWrite();
332}
333
334bool ArrayType::needsResolveReferences() const {
335    return mElementType->needsResolveReferences();
336}
337
338bool ArrayType::resultNeedsDeref() const {
339    return true;
340}
341
342void ArrayType::emitJavaReaderWriter(
343        Formatter &out,
344        const std::string &parcelObj,
345        const std::string &argName,
346        bool isReader) const {
347    if (isReader) {
348        std::string extra;
349        out << "new "
350            << getJavaType(&extra, true /* forInitializer */)
351            << extra
352            << ";\n";
353    }
354
355    out << "{\n";
356    out.indent();
357
358    out << "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 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 extra;
392    std::string typeName = getJavaType(&extra, false /* forInitializer */);
393
394    std::string extraInit;
395    getJavaType(&extraInit, true /* forInitializer */);
396
397    out << "final "
398        << typeName
399        << extra
400        << " "
401        << fieldName
402        << " = new "
403        << typeName
404        << extraInit
405        << ";\n";
406}
407
408void ArrayType::emitJavaFieldReaderWriter(
409        Formatter &out,
410        size_t depth,
411        const std::string &parcelName,
412        const std::string &blobName,
413        const std::string &fieldName,
414        const std::string &offset,
415        bool isReader) const {
416    out << "{\n";
417    out.indent();
418
419    std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
420    out << "long " << offsetName << " = " << offset << ";\n";
421
422    std::string indexString;
423    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
424        std::string iteratorName =
425            "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
426
427        out << "for (int "
428            << iteratorName
429            << " = 0; "
430            << iteratorName
431            << " < "
432            << mSizes[dim]
433            << "; ++"
434            << iteratorName
435            << ") {\n";
436
437        out.indent();
438
439        indexString += "[" + iteratorName + "]";
440    }
441
442    if (isReader && mElementType->isCompoundType()) {
443        std::string extra;
444        std::string typeName =
445            mElementType->getJavaType(&extra, false /* forInitializer */);
446
447        CHECK(extra.empty());
448
449        out << fieldName
450            << indexString
451            << " = new "
452            << typeName
453            << "();\n";
454    }
455
456    mElementType->emitJavaFieldReaderWriter(
457            out,
458            depth + 1,
459            parcelName,
460            blobName,
461            fieldName + indexString,
462            offsetName,
463            isReader);
464
465    size_t elementAlign, elementSize;
466    mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
467
468    out << offsetName << " += " << std::to_string(elementSize) << ";\n";
469
470    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
471        out.unindent();
472        out << "}\n";
473    }
474
475    out.unindent();
476    out << "}\n";
477}
478
479status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
480    if (mSizes.size() > 1) {
481        // Multi-dimensional arrays are yet to be supported in VTS.
482        return UNKNOWN_ERROR;
483    }
484
485    out << "type: TYPE_ARRAY\n" << "vector_value: {\n";
486    out.indent();
487    out << "size: " << mSizes[0] << "\n";
488    status_t err = mElementType->emitVtsTypeDeclarations(out);
489    if (err != OK) {
490        return err;
491    }
492    out.unindent();
493    out << "}\n";
494    return OK;
495}
496
497bool ArrayType::isJavaCompatible() const {
498    return mElementType->isJavaCompatible();
499}
500
501void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
502    mElementType->getAlignmentAndSize(align, size);
503
504    for (auto sizeInDimension : mSizes) {
505        (*size) *= sizeInDimension;
506    }
507}
508
509size_t ArrayType::dimension() const {
510    size_t numArrayElements = 1;
511    for (auto size : mSizes) {
512        numArrayElements *= size;
513    }
514    return numArrayElements;
515}
516
517}  // namespace android
518
519