ArrayType.cpp revision 709b62dbda6184770bb34470ff550e02c1643e67
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
22namespace android {
23
24ArrayType::ArrayType(ArrayType *srcArray, size_t size)
25    : mElementType(srcArray->mElementType),
26      mSizes(srcArray->mSizes) {
27    addDimension(size);
28}
29
30ArrayType::ArrayType(Type *elementType, size_t size)
31    : mElementType(elementType) {
32    addDimension(size);
33}
34
35void ArrayType::addDimension(size_t size) {
36    mSizes.insert(mSizes.begin(), size);
37}
38
39void ArrayType::addNamedTypesToSet(std::set<const FQName> &set) const {
40    mElementType->addNamedTypesToSet(set);
41}
42
43bool ArrayType::isArray() const {
44    return true;
45}
46
47std::string ArrayType::getCppType(StorageMode mode,
48                                  std::string *extra,
49                                  bool specifyNamespaces) const {
50    const std::string base = mElementType->getCppType(extra, specifyNamespaces);
51    CHECK(extra->empty());
52
53    size_t numArrayElements = 1;
54    for (auto size : mSizes) {
55        numArrayElements *= size;
56    }
57
58    *extra += "[";
59    *extra += std::to_string(numArrayElements);
60    *extra += "]";
61
62    switch (mode) {
63        case StorageMode_Stack:
64            return base;
65
66        case StorageMode_Argument:
67        case StorageMode_Result:
68        {
69            *extra = " /* " + base;
70            for (auto size : mSizes) {
71                *extra += "[" + std::to_string(size) + "]";
72            }
73            *extra += " */";
74
75            return "const " + base + "*";
76        }
77    }
78}
79
80std::string ArrayType::getJavaType(
81        std::string *extra, bool forInitializer) const {
82    std::string baseExtra;
83    const std::string base =
84        mElementType->getJavaType(&baseExtra, forInitializer);
85
86    CHECK(baseExtra.empty());
87
88    extra->clear();
89
90    for (auto size : mSizes) {
91        *extra += "[";
92
93        if (forInitializer) {
94            *extra += std::to_string(size);
95        }
96
97        *extra += "]";
98    }
99
100    return base;
101}
102
103void ArrayType::emitReaderWriter(
104        Formatter &out,
105        const std::string &name,
106        const std::string &parcelObj,
107        bool parcelObjIsPointer,
108        bool isReader,
109        ErrorMode mode) const {
110    std::string baseExtra;
111    std::string baseType = mElementType->getCppType(&baseExtra);
112    CHECK(baseExtra.empty());
113
114    const std::string parentName = "_hidl_" + name + "_parent";
115
116    out << "size_t " << parentName << ";\n\n";
117
118    const std::string parcelObjDeref =
119        parcelObj + (parcelObjIsPointer ? "->" : ".");
120
121    if (isReader) {
122        out << name
123            << " = (const "
124            << baseType
125            << " *)"
126            << parcelObjDeref
127            << "readBuffer(&"
128            << parentName
129            << ");\n\n";
130
131        out << "if (" << name << " == nullptr) {\n";
132
133        out.indent();
134
135        out << "_hidl_err = ::android::UNKNOWN_ERROR;\n";
136        handleError2(out, mode);
137
138        out.unindent();
139        out << "}\n\n";
140    } else {
141        out << "_hidl_err = "
142            << parcelObjDeref
143            << "writeBuffer("
144            << name
145            << ", ";
146
147        for (auto size : mSizes) {
148            out << size << " * ";
149        }
150
151        out << "sizeof("
152            << baseType
153            << "), &"
154            << parentName
155            << ");\n";
156
157        handleError(out, mode);
158    }
159
160    emitReaderWriterEmbedded(
161            out,
162            0 /* depth */,
163            name,
164            isReader /* nameIsPointer */,
165            parcelObj,
166            parcelObjIsPointer,
167            isReader,
168            mode,
169            parentName,
170            "0 /* parentOffset */");
171}
172
173void ArrayType::emitReaderWriterEmbedded(
174        Formatter &out,
175        size_t depth,
176        const std::string &name,
177        bool nameIsPointer,
178        const std::string &parcelObj,
179        bool parcelObjIsPointer,
180        bool isReader,
181        ErrorMode mode,
182        const std::string &parentName,
183        const std::string &offsetText) const {
184    if (!mElementType->needsEmbeddedReadWrite()) {
185        return;
186    }
187
188    const std::string nameDeref = name + (nameIsPointer ? "->" : ".");
189
190    std::string baseExtra;
191    std::string baseType = mElementType->getCppType(&baseExtra);
192    CHECK(baseExtra.empty());
193
194    std::string iteratorName = "_hidl_index_" + std::to_string(depth);
195
196    size_t numArrayElements = 1;
197    for (auto size : mSizes) {
198        numArrayElements *= size;
199    }
200
201    out << "for (size_t "
202        << iteratorName
203        << " = 0; "
204        << iteratorName
205        << " < "
206        << numArrayElements
207        << "; ++"
208        << iteratorName
209        << ") {\n";
210
211    out.indent();
212
213    mElementType->emitReaderWriterEmbedded(
214            out,
215            depth + 1,
216            name + "[" + iteratorName + "]",
217            false /* nameIsPointer */,
218            parcelObj,
219            parcelObjIsPointer,
220            isReader,
221            mode,
222            parentName,
223            offsetText
224                + " + " + iteratorName + " * sizeof("
225                + baseType
226                + ")");
227
228    out.unindent();
229
230    out << "}\n\n";
231}
232
233bool ArrayType::needsEmbeddedReadWrite() const {
234    return mElementType->needsEmbeddedReadWrite();
235}
236
237void ArrayType::emitJavaReaderWriter(
238        Formatter &out,
239        const std::string &parcelObj,
240        const std::string &argName,
241        bool isReader) const {
242    if (isReader) {
243        std::string extra;
244        out << "new "
245            << getJavaType(&extra, true /* forInitializer */)
246            << extra
247            << ";\n";
248    }
249
250    out << "{\n";
251    out.indent();
252
253    out << "HwBlob _hidl_blob = ";
254
255    if (isReader) {
256        out << parcelObj
257            << ".readBuffer();\n";
258    } else {
259        size_t align, size;
260        getAlignmentAndSize(&align, &size);
261
262        out << "new HwBlob("
263            << size
264            << " /* size */);\n";
265    }
266
267    emitJavaFieldReaderWriter(
268            out,
269            0 /* depth */,
270            parcelObj,
271            "_hidl_blob",
272            argName,
273            "0 /* offset */",
274            isReader);
275
276    if (!isReader) {
277        out << parcelObj << ".writeBuffer(_hidl_blob);\n";
278    }
279
280    out.unindent();
281    out << "}\n";
282}
283
284void ArrayType::emitJavaFieldInitializer(
285        Formatter &out, const std::string &fieldName) const {
286    std::string extra;
287    std::string typeName = getJavaType(&extra, false /* forInitializer */);
288
289    std::string extraInit;
290    getJavaType(&extraInit, true /* forInitializer */);
291
292    out << "final "
293        << typeName
294        << extra
295        << " "
296        << fieldName
297        << " = new "
298        << typeName
299        << extraInit
300        << ";\n";
301}
302
303void ArrayType::emitJavaFieldReaderWriter(
304        Formatter &out,
305        size_t depth,
306        const std::string &parcelName,
307        const std::string &blobName,
308        const std::string &fieldName,
309        const std::string &offset,
310        bool isReader) const {
311    std::string offsetName = "_hidl_array_offset_" + std::to_string(depth);
312    out << "long " << offsetName << " = " << offset << ";\n";
313
314    std::string indexString;
315    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
316        std::string iteratorName =
317            "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim);
318
319        out << "for (int "
320            << iteratorName
321            << " = 0; "
322            << iteratorName
323            << " < "
324            << mSizes[dim]
325            << "; ++"
326            << iteratorName
327            << ") {\n";
328
329        out.indent();
330
331        indexString += "[" + iteratorName + "]";
332    }
333
334    if (isReader && mElementType->isCompoundType()) {
335        std::string extra;
336        std::string typeName =
337            mElementType->getJavaType(&extra, false /* forInitializer */);
338
339        CHECK(extra.empty());
340
341        out << fieldName
342            << indexString
343            << " = new "
344            << typeName
345            << "();\n";
346    }
347
348    mElementType->emitJavaFieldReaderWriter(
349            out,
350            depth + 1,
351            parcelName,
352            blobName,
353            fieldName + indexString,
354            offsetName,
355            isReader);
356
357    size_t elementAlign, elementSize;
358    mElementType->getAlignmentAndSize(&elementAlign, &elementSize);
359
360    out << offsetName << " += " << std::to_string(elementSize) << ";\n";
361
362    for (size_t dim = 0; dim < mSizes.size(); ++dim) {
363        out.unindent();
364        out << "}\n";
365    }
366}
367
368status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const {
369    if (mSizes.size() > 1) {
370        // Multi-dimensional arrays are yet to be supported in VTS.
371        return UNKNOWN_ERROR;
372    }
373
374    out << "type: TYPE_ARRAY\n" << "vector_value: {\n";
375    out.indent();
376    out << "size: " << mSizes[0] << "\n";
377    status_t err = mElementType->emitVtsTypeDeclarations(out);
378    if (err != OK) {
379        return err;
380    }
381    out.unindent();
382    out << "}\n";
383    return OK;
384}
385
386bool ArrayType::isJavaCompatible() const {
387    return mElementType->isJavaCompatible();
388}
389
390void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const {
391    mElementType->getAlignmentAndSize(align, size);
392
393    for (auto sizeInDimension : mSizes) {
394        (*size) *= sizeInDimension;
395    }
396}
397
398}  // namespace android
399
400