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