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