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