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