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