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