ArrayType.cpp revision a23f1ae530383d3a0d0e5178a0bf988da789e893
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 <android-base/logging.h> 20#include <hidl-util/Formatter.h> 21#include <iostream> 22 23#include "ConstantExpression.h" 24 25namespace android { 26 27ArrayType::ArrayType(const Reference<Type>& elementType, ConstantExpression* size, Scope* parent) 28 : Type(parent), mElementType(elementType), mSizes{size} { 29 CHECK(!elementType.isEmptyReference()); 30} 31 32void ArrayType::appendDimension(ConstantExpression *size) { 33 mSizes.push_back(size); 34} 35 36size_t ArrayType::countDimensions() const { 37 return mSizes.size(); 38} 39 40bool ArrayType::isArray() const { 41 return true; 42} 43 44bool ArrayType::deepCanCheckEquality(std::unordered_set<const Type*>* visited) const { 45 return mElementType->canCheckEquality(visited); 46} 47 48const Type* ArrayType::getElementType() const { 49 return mElementType.get(); 50} 51 52std::string ArrayType::typeName() const { 53 if (dimension() == 1) { 54 return "array of " + mElementType->typeName(); 55 } 56 57 return std::to_string(dimension()) + "d array of " + mElementType->typeName(); 58} 59 60std::vector<const Reference<Type>*> ArrayType::getReferences() const { 61 return {&mElementType}; 62} 63 64std::vector<const ConstantExpression*> ArrayType::getConstantExpressions() const { 65 std::vector<const ConstantExpression*> ret; 66 ret.insert(ret.end(), mSizes.begin(), mSizes.end()); 67 return ret; 68} 69 70status_t ArrayType::resolveInheritance() { 71 // Resolve for typedefs 72 while (mElementType->isArray()) { 73 ArrayType* innerArray = static_cast<ArrayType*>(mElementType.get()); 74 mSizes.insert(mSizes.end(), innerArray->mSizes.begin(), innerArray->mSizes.end()); 75 mElementType = innerArray->mElementType; 76 } 77 return Type::resolveInheritance(); 78} 79 80status_t ArrayType::validate() const { 81 CHECK(!mElementType->isArray()); 82 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::deepNeedsResolveReferences(std::unordered_set<const Type*>* visited) const { 378 if (mElementType->needsResolveReferences(visited)) { 379 return true; 380 } 381 return Type::deepNeedsResolveReferences(visited); 382} 383 384bool ArrayType::resultNeedsDeref() const { 385 return true; 386} 387 388void ArrayType::emitJavaReaderWriter( 389 Formatter &out, 390 const std::string &parcelObj, 391 const std::string &argName, 392 bool isReader) const { 393 size_t align, size; 394 getAlignmentAndSize(&align, &size); 395 396 if (isReader) { 397 out << "new " 398 << getJavaType(true /* forInitializer */) 399 << ";\n"; 400 } 401 402 out << "{\n"; 403 out.indent(); 404 405 out << "android.os.HwBlob _hidl_blob = "; 406 407 if (isReader) { 408 out << parcelObj 409 << ".readBuffer(" 410 << size 411 << " /* size */);\n"; 412 } else { 413 out << "new android.os.HwBlob(" 414 << size 415 << " /* size */);\n"; 416 } 417 418 emitJavaFieldReaderWriter( 419 out, 420 0 /* depth */, 421 parcelObj, 422 "_hidl_blob", 423 argName, 424 "0 /* offset */", 425 isReader); 426 427 if (!isReader) { 428 out << parcelObj << ".writeBuffer(_hidl_blob);\n"; 429 } 430 431 out.unindent(); 432 out << "}\n"; 433} 434 435void ArrayType::emitJavaFieldInitializer( 436 Formatter &out, const std::string &fieldName) const { 437 std::string typeName = getJavaType(false /* forInitializer */); 438 std::string initName = getJavaType(true /* forInitializer */); 439 440 out << "final " 441 << typeName 442 << " " 443 << fieldName 444 << " = new " 445 << initName 446 << ";\n"; 447} 448 449void ArrayType::emitJavaFieldReaderWriter( 450 Formatter &out, 451 size_t depth, 452 const std::string &parcelName, 453 const std::string &blobName, 454 const std::string &fieldName, 455 const std::string &offset, 456 bool isReader) const { 457 out << "{\n"; 458 out.indent(); 459 460 std::string offsetName = "_hidl_array_offset_" + std::to_string(depth); 461 out << "long " << offsetName << " = " << offset << ";\n"; 462 463 const bool isPrimitiveArray = mElementType->isScalar(); 464 465 /* If the element type corresponds to a Java primitive type we can optimize 466 the innermost loop by copying a linear range of memory instead of doing 467 a per-element copy. As a result the outer nested loop does not include 468 the final dimension. */ 469 const size_t loopDimensions = mSizes.size() - (isPrimitiveArray ? 1 : 0); 470 471 std::string indexString; 472 for (size_t dim = 0; dim < loopDimensions; ++dim) { 473 std::string iteratorName = 474 "_hidl_index_" + std::to_string(depth) + "_" + std::to_string(dim); 475 476 out << "for (int " 477 << iteratorName 478 << " = 0; " 479 << iteratorName 480 << " < " 481 << mSizes[dim]->javaValue() 482 << "; ++" 483 << iteratorName 484 << ") {\n"; 485 486 out.indent(); 487 488 indexString += "[" + iteratorName + "]"; 489 } 490 491 if (isReader && mElementType->isCompoundType()) { 492 std::string typeName = 493 mElementType->getJavaType(false /* forInitializer */); 494 495 out << fieldName 496 << indexString 497 << " = new " 498 << typeName 499 << "();\n"; 500 } 501 502 if (!isPrimitiveArray) { 503 mElementType->emitJavaFieldReaderWriter( 504 out, 505 depth + 1, 506 parcelName, 507 blobName, 508 fieldName + indexString, 509 offsetName, 510 isReader); 511 512 size_t elementAlign, elementSize; 513 mElementType->getAlignmentAndSize(&elementAlign, &elementSize); 514 515 out << offsetName << " += " << std::to_string(elementSize) << ";\n"; 516 } else { 517 if (isReader) { 518 out << blobName 519 << ".copyTo" 520 << mElementType->getJavaSuffix() 521 << "Array(" 522 << offsetName 523 << ", " 524 << fieldName 525 << indexString 526 << ", " 527 << mSizes.back()->javaValue() 528 << " /* size */);\n"; 529 } else { 530 out << blobName 531 << ".put" 532 << mElementType->getJavaSuffix() 533 << "Array(" 534 << offsetName 535 << ", " 536 << fieldName 537 << indexString 538 << ");\n"; 539 } 540 541 size_t elementAlign, elementSize; 542 mElementType->getAlignmentAndSize(&elementAlign, &elementSize); 543 544 out << offsetName 545 << " += " 546 << mSizes.back()->javaValue() 547 << " * " 548 << elementSize 549 << ";\n"; 550 } 551 552 for (size_t dim = 0; dim < loopDimensions; ++dim) { 553 out.unindent(); 554 out << "}\n"; 555 } 556 557 out.unindent(); 558 out << "}\n"; 559} 560 561status_t ArrayType::emitVtsTypeDeclarations(Formatter &out) const { 562 out << "type: " << getVtsType() << "\n"; 563 out << "vector_size: " << mSizes[0]->value() << "\n"; 564 out << "vector_value: {\n"; 565 out.indent(); 566 // Simple array case. 567 if (mSizes.size() == 1) { 568 status_t err = mElementType->emitVtsTypeDeclarations(out); 569 if (err != OK) { 570 return err; 571 } 572 } else { // Multi-dimension array case. 573 for (size_t index = 1; index < mSizes.size(); index++) { 574 out << "type: " << getVtsType() << "\n"; 575 out << "vector_size: " << mSizes[index]->value() << "\n"; 576 out << "vector_value: {\n"; 577 out.indent(); 578 if (index == mSizes.size() - 1) { 579 status_t err = mElementType->emitVtsTypeDeclarations(out); 580 if (err != OK) { 581 return err; 582 } 583 } 584 } 585 } 586 for (size_t index = 0; index < mSizes.size(); index++) { 587 out.unindent(); 588 out << "}\n"; 589 } 590 return OK; 591} 592 593bool ArrayType::deepIsJavaCompatible(std::unordered_set<const Type*>* visited) const { 594 if (!mElementType->isJavaCompatible(visited)) { 595 return false; 596 } 597 return Type::deepIsJavaCompatible(visited); 598} 599 600bool ArrayType::deepContainsPointer(std::unordered_set<const Type*>* visited) const { 601 if (mElementType->containsPointer(visited)) { 602 return true; 603 } 604 return Type::deepContainsPointer(visited); 605} 606 607void ArrayType::getAlignmentAndSize(size_t *align, size_t *size) const { 608 mElementType->getAlignmentAndSize(align, size); 609 610 for (auto sizeInDimension : mSizes) { 611 (*size) *= sizeInDimension->castSizeT(); 612 } 613} 614 615size_t ArrayType::dimension() const { 616 size_t numArrayElements = 1; 617 for (auto size : mSizes) { 618 numArrayElements *= size->castSizeT(); 619 } 620 return numArrayElements; 621} 622 623} // namespace android 624 625