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