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