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