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