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