1 /* 2 * Copyright 2010-2014, 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 "slang_rs_reflection.h" 18 19 #include <sys/stat.h> 20 21 #include <cstdarg> 22 #include <cctype> 23 24 #include <algorithm> 25 #include <sstream> 26 #include <string> 27 #include <utility> 28 29 #include "llvm/ADT/APFloat.h" 30 #include "llvm/ADT/StringExtras.h" 31 32 #include "os_sep.h" 33 #include "slang_rs_context.h" 34 #include "slang_rs_export_var.h" 35 #include "slang_rs_export_foreach.h" 36 #include "slang_rs_export_func.h" 37 #include "slang_rs_export_reduce.h" 38 #include "slang_rs_reflect_utils.h" 39 #include "slang_rs_reflection_state.h" 40 #include "slang_version.h" 41 42 #define RS_SCRIPT_CLASS_NAME_PREFIX "ScriptC_" 43 #define RS_SCRIPT_CLASS_SUPER_CLASS_NAME "ScriptC" 44 45 #define RS_TYPE_CLASS_SUPER_CLASS_NAME ".Script.FieldBase" 46 47 #define RS_TYPE_ITEM_CLASS_NAME "Item" 48 49 #define RS_TYPE_ITEM_SIZEOF_LEGACY "Item.sizeof" 50 #define RS_TYPE_ITEM_SIZEOF_CURRENT "mElement.getBytesSize()" 51 52 #define RS_TYPE_ITEM_BUFFER_NAME "mItemArray" 53 #define RS_TYPE_ITEM_BUFFER_PACKER_NAME "mIOBuffer" 54 #define RS_TYPE_ELEMENT_REF_NAME "mElementCache" 55 56 #define RS_EXPORT_VAR_INDEX_PREFIX "mExportVarIdx_" 57 #define RS_EXPORT_VAR_PREFIX "mExportVar_" 58 #define RS_EXPORT_VAR_ELEM_PREFIX "mExportVarElem_" 59 #define RS_EXPORT_VAR_DIM_PREFIX "mExportVarDim_" 60 #define RS_EXPORT_VAR_CONST_PREFIX "const_" 61 62 #define RS_ELEM_PREFIX "__" 63 64 #define RS_FP_PREFIX "__rs_fp_" 65 66 #define RS_RESOURCE_NAME "__rs_resource_name" 67 68 #define RS_EXPORT_FUNC_INDEX_PREFIX "mExportFuncIdx_" 69 #define RS_EXPORT_FOREACH_INDEX_PREFIX "mExportForEachIdx_" 70 #define RS_EXPORT_REDUCE_INDEX_PREFIX "mExportReduceIdx_" 71 72 #define RS_EXPORT_VAR_ALLOCATION_PREFIX "mAlloction_" 73 #define RS_EXPORT_VAR_DATA_STORAGE_PREFIX "mData_" 74 75 #define SAVED_RS_REFERENCE "mRSLocal" 76 77 namespace slang { 78 79 static void genCheck64BitInternal(const RSContext *Context, ReflectionState *State, 80 GeneratedFile &Out, bool Parens); 81 82 class RSReflectionJavaElementBuilder { 83 public: 84 RSReflectionJavaElementBuilder(const char *ElementBuilderName, 85 const RSExportRecordType *ERT, 86 const char *RenderScriptVar, 87 GeneratedFile *Out, const RSContext *RSContext, 88 RSReflectionJava *Reflection, 89 ReflectionState *RState); 90 void generate(); 91 92 private: 93 void genAddElement(const RSExportType *ET, const std::string &VarName, 94 unsigned ArraySize); 95 void genAddStatementStart(); 96 void genAddStatementEnd(const std::string &VarName, unsigned ArraySize, 97 unsigned Which = RSReflectionJava::FieldIndex | RSReflectionJava::Field32Index); 98 void genAddPadding(int PaddingSize, unsigned Which); // Which: See RSReflectionJava::incFieldIndex() 99 void genAddPadding(int PaddingSize, ReflectionState::Val32 Field32PaddingSize); 100 // TODO Will remove later due to field name information is not necessary for 101 // C-reflect-to-Java 102 std::string createPaddingField() { 103 return mPaddingPrefix + llvm::itostr(mPaddingFieldIndex++); 104 } 105 106 void genCheck64Bit(bool Parens) { 107 genCheck64BitInternal(mRSContext, mState, *mOut, Parens); 108 } 109 110 const char *mElementBuilderName; 111 const RSExportRecordType *mERT; 112 const char *mRenderScriptVar; 113 GeneratedFile *mOut; 114 std::string mPaddingPrefix; 115 int mPaddingFieldIndex; 116 const RSContext *mRSContext; 117 RSReflectionJava *mReflection; 118 ReflectionState *mState; 119 }; 120 121 enum MatrixLanguage { ML_Java, ML_Script }; 122 static const char *GetMatrixTypeName(const RSExportMatrixType *EMT, MatrixLanguage lang) { 123 static const char *MatrixTypeJavaNameMap[3][2] = {/* 2x2 */ { "Matrix2f", "rs_matrix2x2" }, 124 /* 3x3 */ { "Matrix3f", "rs_matrix3x3" }, 125 /* 4x4 */ { "Matrix4f", "rs_matrix4x4" } 126 }; 127 unsigned Dim = EMT->getDim(); 128 129 if ((Dim - 2) < (sizeof(MatrixTypeJavaNameMap) / sizeof(const char *))) 130 return MatrixTypeJavaNameMap[EMT->getDim() - 2][lang]; 131 132 slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension"); 133 return nullptr; 134 } 135 136 static const char *GetVectorAccessor(unsigned Index) { 137 static const char *VectorAccessorMap[] = {/* 0 */ "x", 138 /* 1 */ "y", 139 /* 2 */ "z", 140 /* 3 */ "w", 141 }; 142 143 slangAssert((Index < (sizeof(VectorAccessorMap) / sizeof(const char *))) && 144 "Out-of-bound index to access vector member"); 145 146 return VectorAccessorMap[Index]; 147 } 148 149 static const char *GetPackerAPIName(const RSExportPrimitiveType *EPT) { 150 static const char *PrimitiveTypePackerAPINameMap[] = { 151 "addI16", // DataTypeFloat16 152 "addF32", // DataTypeFloat32 153 "addF64", // DataTypeFloat64 154 "addI8", // DataTypeSigned8 155 "addI16", // DataTypeSigned16 156 "addI32", // DataTypeSigned32 157 "addI64", // DataTypeSigned64 158 "addU8", // DataTypeUnsigned8 159 "addU16", // DataTypeUnsigned16 160 "addU32", // DataTypeUnsigned32 161 "addU64", // DataTypeUnsigned64 162 "addBoolean", // DataTypeBoolean 163 "addU16", // DataTypeUnsigned565 164 "addU16", // DataTypeUnsigned5551 165 "addU16", // DataTypeUnsigned4444 166 "addMatrix", // DataTypeRSMatrix2x2 167 "addMatrix", // DataTypeRSMatrix3x3 168 "addMatrix", // DataTypeRSMatrix4x4 169 "addObj", // DataTypeRSElement 170 "addObj", // DataTypeRSType 171 "addObj", // DataTypeRSAllocation 172 "addObj", // DataTypeRSSampler 173 "addObj", // DataTypeRSScript 174 "addObj", // DataTypeRSMesh 175 "addObj", // DataTypeRSPath 176 "addObj", // DataTypeRSProgramFragment 177 "addObj", // DataTypeRSProgramVertex 178 "addObj", // DataTypeRSProgramRaster 179 "addObj", // DataTypeRSProgramStore 180 "addObj", // DataTypeRSFont 181 }; 182 unsigned TypeId = EPT->getType(); 183 184 if (TypeId < (sizeof(PrimitiveTypePackerAPINameMap) / sizeof(const char *))) 185 return PrimitiveTypePackerAPINameMap[EPT->getType()]; 186 187 slangAssert(false && "GetPackerAPIName : Unknown primitive data type"); 188 return nullptr; 189 } 190 191 namespace { 192 193 std::string GetReduceResultTypeName(const RSExportType *ET) { 194 switch (ET->getClass()) { 195 case RSExportType::ExportClassConstantArray: { 196 const RSExportConstantArrayType *const CAT = static_cast<const RSExportConstantArrayType *>(ET); 197 return "resultArray" + std::to_string(CAT->getNumElement()) + "_" + 198 RSReflectionJava::GetTypeName( 199 CAT->getElementType(), 200 (RSReflectionJava::TypeNameDefault & ~RSReflectionJava::TypeNameWithRecordElementName) | 201 RSReflectionJava::TypeNameC); 202 } 203 case RSExportType::ExportClassRecord: 204 return "resultStruct_" + 205 RSReflectionJava::GetTypeName( 206 ET, 207 (RSReflectionJava::TypeNameDefault & ~RSReflectionJava::TypeNameWithRecordElementName) | 208 RSReflectionJava::TypeNameC); 209 default: 210 return "result_" + 211 RSReflectionJava::GetTypeName(ET, RSReflectionJava::TypeNameDefault | RSReflectionJava::TypeNameC); 212 } 213 } 214 215 std::string GetReduceResultTypeName(const RSExportReduce *ER) { 216 return GetReduceResultTypeName(ER->getResultType()); 217 } 218 219 } // end anonymous namespace 220 221 static const char *GetTypeNullValue(const RSExportType *ET) { 222 switch (ET->getClass()) { 223 case RSExportType::ExportClassPrimitive: { 224 const RSExportPrimitiveType *EPT = 225 static_cast<const RSExportPrimitiveType *>(ET); 226 if (EPT->isRSObjectType()) 227 return "null"; 228 else if (EPT->getType() == DataTypeBoolean) 229 return "false"; 230 else 231 return "0"; 232 break; 233 } 234 case RSExportType::ExportClassPointer: 235 case RSExportType::ExportClassVector: 236 case RSExportType::ExportClassMatrix: 237 case RSExportType::ExportClassConstantArray: 238 case RSExportType::ExportClassRecord: { 239 return "null"; 240 break; 241 } 242 default: { slangAssert(false && "Unknown class of type"); } 243 } 244 return ""; 245 } 246 247 static std::string GetBuiltinElementConstruct(const RSExportType *ET) { 248 if (ET->getClass() == RSExportType::ExportClassPrimitive) { 249 return std::string("Element.") + ET->getElementName(); 250 } else if (ET->getClass() == RSExportType::ExportClassVector) { 251 const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET); 252 if (EVT->getType() == DataTypeFloat32) { 253 if (EVT->getNumElement() == 2) { 254 return "Element.F32_2"; 255 } else if (EVT->getNumElement() == 3) { 256 return "Element.F32_3"; 257 } else if (EVT->getNumElement() == 4) { 258 return "Element.F32_4"; 259 } else { 260 slangAssert(false && "Vectors should be size 2, 3, 4"); 261 } 262 } else if (EVT->getType() == DataTypeUnsigned8) { 263 if (EVT->getNumElement() == 4) 264 return "Element.U8_4"; 265 } 266 } else if (ET->getClass() == RSExportType::ExportClassMatrix) { 267 const RSExportMatrixType *EMT = static_cast<const RSExportMatrixType *>(ET); 268 switch (EMT->getDim()) { 269 case 2: 270 return "Element.MATRIX_2X2"; 271 case 3: 272 return "Element.MATRIX_3X3"; 273 case 4: 274 return "Element.MATRIX_4X4"; 275 default: 276 slangAssert(false && "Unsupported dimension of matrix"); 277 } 278 } 279 // RSExportType::ExportClassPointer can't be generated in a struct. 280 281 return ""; 282 } 283 284 // If FromIntegerType == DestIntegerType, then Value is returned. 285 // Otherwise, return a Java expression that zero-extends the value 286 // Value, assumed to be of type FromIntegerType, to the integer type 287 // DestIntegerType. 288 // 289 // Intended operations: 290 // byte -> {byte,int,short,long} 291 // short -> {short,int,long} 292 // int -> {int,long} 293 // long -> long 294 static std::string ZeroExtendValue(const std::string &Value, 295 const std::string &FromIntegerType, 296 const std::string &DestIntegerType) { 297 #ifndef __DISABLE_ASSERTS 298 // Integer types arranged in increasing order by width 299 const std::vector<std::string> ValidTypes{"byte", "short", "int", "long"}; 300 auto FromTypeLoc = std::find(ValidTypes.begin(), ValidTypes.end(), FromIntegerType); 301 auto DestTypeLoc = std::find(ValidTypes.begin(), ValidTypes.end(), DestIntegerType); 302 // Check that both types are valid. 303 slangAssert(FromTypeLoc != ValidTypes.end()); 304 slangAssert(DestTypeLoc != ValidTypes.end()); 305 // Check that DestIntegerType is at least as wide as FromIntegerType. 306 slangAssert(FromTypeLoc - ValidTypes.begin() <= DestTypeLoc - ValidTypes.begin()); 307 #endif 308 309 if (FromIntegerType == DestIntegerType) { 310 return Value; 311 } 312 313 std::string Mask, MaskLiteralType; 314 if (FromIntegerType == "byte") { 315 Mask = "0xff"; 316 MaskLiteralType = "int"; 317 } else if (FromIntegerType == "short") { 318 Mask = "0xffff"; 319 MaskLiteralType = "int"; 320 } else if (FromIntegerType == "int") { 321 Mask = "0xffffffffL"; 322 MaskLiteralType = "long"; 323 } else { 324 // long -> long casts should have already been handled. 325 slangAssert(false && "Unknown integer type"); 326 } 327 328 // Cast the mask to the appropriate type. 329 if (MaskLiteralType != DestIntegerType) { 330 Mask = "(" + DestIntegerType + ") " + Mask; 331 } 332 return "((" + DestIntegerType + ") ((" + Value + ") & " + Mask + "))"; 333 } 334 335 std::string RSReflectionJava::GetTypeName(const RSExportType *ET, unsigned Style) { 336 slangAssert((Style & (TypeNameC|TypeNamePseudoC)) != (TypeNameC|TypeNamePseudoC)); 337 slangAssert(!(Style & TypeNamePseudoC) || (Style == TypeNamePseudoC)); 338 339 const bool CLike = Style & (TypeNameC|TypeNamePseudoC); 340 341 switch (ET->getClass()) { 342 case RSExportType::ExportClassPrimitive: { 343 const auto ReflectionType = 344 RSExportPrimitiveType::getRSReflectionType(static_cast<const RSExportPrimitiveType *>(ET)); 345 return (CLike ? ReflectionType->s_name : ReflectionType->java_name); 346 } 347 case RSExportType::ExportClassPointer: { 348 slangAssert(!(Style & TypeNameC) && 349 "No need to support C type names for pointer types yet"); 350 const RSExportType *PointeeType = 351 static_cast<const RSExportPointerType *>(ET)->getPointeeType(); 352 353 if (Style & TypeNamePseudoC) 354 return GetTypeName(PointeeType, Style) + "*"; 355 else if (PointeeType->getClass() != RSExportType::ExportClassRecord) 356 return "Allocation"; 357 else 358 return PointeeType->getElementName(); 359 } 360 case RSExportType::ExportClassVector: { 361 const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET); 362 const auto ReflectionType = EVT->getRSReflectionType(EVT); 363 std::stringstream VecName; 364 VecName << (CLike ? ReflectionType->s_name : ReflectionType->rs_java_vector_prefix) 365 << EVT->getNumElement(); 366 return VecName.str(); 367 } 368 case RSExportType::ExportClassMatrix: { 369 return GetMatrixTypeName(static_cast<const RSExportMatrixType *>(ET), CLike ? ML_Script : ML_Java); 370 } 371 case RSExportType::ExportClassConstantArray: { 372 const RSExportConstantArrayType *CAT = 373 static_cast<const RSExportConstantArrayType *>(ET); 374 std::string ElementTypeName = GetTypeName(CAT->getElementType(), Style); 375 if (Style & TypeNamePseudoC) { 376 std::stringstream ArrayName; 377 ArrayName << ElementTypeName << '[' << CAT->getNumElement() << ']'; 378 return ArrayName.str(); 379 } 380 else if (Style & TypeNameWithConstantArrayBrackets) { 381 slangAssert(!(Style & TypeNameC) && 382 "No need to support C type names for array types with brackets yet"); 383 ElementTypeName.append("[]"); 384 } 385 return ElementTypeName; 386 } 387 case RSExportType::ExportClassRecord: { 388 slangAssert(!(Style & TypeNameC) && 389 "No need to support C type names for record types yet"); 390 if (Style & TypeNamePseudoC) 391 return "struct " + ET->getName(); 392 else if (Style & TypeNameWithRecordElementName) 393 return ET->getElementName() + "." RS_TYPE_ITEM_CLASS_NAME; 394 else 395 return ET->getName(); 396 } 397 default: { slangAssert(false && "Unknown class of type"); } 398 } 399 400 return ""; 401 } 402 403 void RSReflectionJava::genConditionalVal(const std::string &Prefix, bool Parens, 404 size_t Val, ReflectionState::Val32 Val32) { 405 if (Prefix.empty() || (Val != 0) || (Val32.first && (Val32.second != 0 ))) { 406 mOut << Prefix; 407 408 if (!Val32.first || (Val == Val32.second)) { 409 // Either we're ignoring the 32-bit case, or 32-bit and 64-bit 410 // values are the same. 411 mOut << Val; 412 } else { 413 // We cannot ignore the 32-bit case, and 32-bit and 64-bit 414 // values differ. 415 if (Parens) 416 mOut << '('; 417 genCheck64Bit(true); 418 mOut << " ? " << Val << " : " << Val32.second; 419 if (Parens) 420 mOut << ')'; 421 } 422 } 423 } 424 425 static void genCheck64BitInternal(const RSContext *Context, ReflectionState *State, 426 GeneratedFile &Out, bool Parens) { 427 State->setOutputClassDivergent(); 428 if (Context->isCompatLib()) { 429 if (Parens) 430 Out << '('; 431 Out << "RenderScript.getPointerSize() == 8"; 432 if (Parens) 433 Out << ')'; 434 } 435 else 436 Out << "sIs64Bit"; 437 } 438 439 void RSReflectionJava::genCheck64Bit(bool Parens) { 440 genCheck64BitInternal(mRSContext, mState, mOut, Parens); 441 } 442 443 void RSReflectionJava::genCompute64Bit() { 444 if (mRSContext->isCompatLib()) { 445 // We can rely on RenderScript class in lockstep with llvm-rs-cc 446 // and hence in lockstep with the generated code, so we don't need 447 // any complicated logic to determine pointer size. 448 return; 449 } 450 451 // Note that Android L is the first release to support 64-bit 452 // targets. When RenderScript is compiled with "-target-api $v" 453 // with "$v < 21" (L is API level 21), we only compile for 32-bit, 454 // and we reflect during that compile, so there are no divergent 455 // structs, and we will not get here. 456 457 slangAssert(mRSContext->getTargetAPI() >= SLANG_L_TARGET_API); 458 459 mOut.indent() << "private static boolean sIs64Bit;\n\n"; 460 mOut.indent() << "static"; 461 mOut.startBlock(); 462 mOut.indent() << "if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)"; 463 mOut.startBlock(); 464 mOut.indent() << "sIs64Bit = Process.is64Bit();\n"; 465 mOut.endBlock(); 466 mOut.indent() << "else"; 467 mOut.startBlock(); 468 mOut.indent() << "try"; 469 mOut.startBlock(); 470 mOut.indent() << "Field f = RenderScript.class.getDeclaredField(\"sPointerSize\");\n"; 471 mOut.indent() << "f.setAccessible(true);\n"; 472 mOut.indent() << "sIs64Bit = (f.getInt(null) == 8);\n"; 473 mOut.endBlock(); 474 475 // If reflection fails, assume we're on a 32-bit-only device 476 // (64-bit-only is not allowed). This should only happen if the 477 // device is L-or-later but has been customized in some way so that 478 // the field "sPointerSize" -- introduced in L -- is not present. 479 // 480 // Alternatively, we could treat this as 64-bit (reverting to the 481 // behavior prior to the fix for http://b/32780232) or we could 482 // decide we have no idea what's going on and throw an exception. 483 mOut.indent() << "catch (Throwable e)"; 484 mOut.startBlock(); 485 mOut.indent() << "sIs64Bit = false;\n"; 486 mOut.endBlock(); 487 488 mOut.endBlock(); 489 mOut.endBlock(); 490 } 491 492 /********************** Methods to generate script class **********************/ 493 RSReflectionJava::RSReflectionJava(const RSContext *Context, 494 std::vector<std::string> *GeneratedFileNames, 495 const std::string &OutputBaseDirectory, 496 const std::string &RSSourceFileName, 497 const std::string &BitCodeFileName, 498 bool EmbedBitcodeInJava, 499 ReflectionState *RState) 500 : mRSContext(Context), mState(RState), mCollecting(RState->isCollecting()), 501 mPackageName(Context->getReflectJavaPackageName()), 502 mRSPackageName(Context->getRSPackageName()), 503 mOutputBaseDirectory(OutputBaseDirectory), 504 mRSSourceFileName(RSSourceFileName), mBitCodeFileName(BitCodeFileName), 505 mResourceId(RSSlangReflectUtils::JavaClassNameFromRSFileName( 506 mBitCodeFileName.c_str())), 507 mScriptClassName(RS_SCRIPT_CLASS_NAME_PREFIX + 508 RSSlangReflectUtils::JavaClassNameFromRSFileName( 509 mRSSourceFileName.c_str())), 510 mEmbedBitcodeInJava(EmbedBitcodeInJava), mNextExportVarSlot(0), 511 mNextExportFuncSlot(0), mNextExportForEachSlot(0), 512 mNextExportReduceSlot(0), mLastError(""), 513 mGeneratedFileNames(GeneratedFileNames), mFieldIndex(0), mField32Index(0) { 514 slangAssert(mGeneratedFileNames && "Must supply GeneratedFileNames"); 515 slangAssert(!mPackageName.empty() && mPackageName != "-"); 516 517 mOutputDirectory = RSSlangReflectUtils::ComputePackagedPath( 518 OutputBaseDirectory.c_str(), mPackageName.c_str()) + 519 OS_PATH_SEPARATOR_STR; 520 521 // mElement.getBytesSize only exists on JB+ 522 if (mRSContext->getTargetAPI() >= SLANG_JB_TARGET_API) { 523 mItemSizeof = RS_TYPE_ITEM_SIZEOF_CURRENT; 524 } else { 525 mItemSizeof = RS_TYPE_ITEM_SIZEOF_LEGACY; 526 } 527 528 mState->nextFile(mRSContext, mPackageName, mRSSourceFileName); 529 } 530 531 bool RSReflectionJava::genScriptClass(const std::string &ClassName, 532 std::string &ErrorMsg) { 533 if (!mCollecting) { 534 if (!startClass(AM_Public, false, ClassName, RS_SCRIPT_CLASS_SUPER_CLASS_NAME, 535 ErrorMsg)) 536 return false; 537 538 mState->beginOutputClass(); 539 genScriptClassConstructor(); 540 } 541 542 // Reflect exported variables 543 mState->beginVariables(mRSContext->export_vars_size()); 544 for (auto I = mRSContext->export_vars_begin(), 545 E = mRSContext->export_vars_end(); 546 I != E; I++) 547 genExportVariable(*I); 548 mState->endVariables(); 549 550 // Reflect exported forEach functions (only available on ICS+) 551 if (mRSContext->getTargetAPI() >= SLANG_ICS_TARGET_API) { 552 mState->beginForEaches(mRSContext->getNumAssignedForEachOrdinals()); 553 for (auto I = mRSContext->export_foreach_begin(), 554 E = mRSContext->export_foreach_end(); 555 I != E; I++) { 556 genExportForEach(*I); 557 } 558 mState->endForEaches(); 559 } 560 561 // Reflect exported reduce functions 562 if (!mCollecting) { 563 for (const RSExportType *ResultType : mRSContext->getReduceResultTypes( 564 // FilterIn 565 exportableReduce, 566 567 // Compare 568 [](const RSExportType *A, const RSExportType *B) 569 { return GetReduceResultTypeName(A) < GetReduceResultTypeName(B); })) 570 genExportReduceResultType(ResultType); 571 } 572 mState->beginReduces(mRSContext->export_reduce_size()); 573 for (auto I = mRSContext->export_reduce_begin(), 574 E = mRSContext->export_reduce_end(); 575 I != E; ++I) 576 genExportReduce(*I); 577 mState->endReduces(); 578 579 // Reflect exported functions (invokable) 580 mState->beginInvokables(mRSContext->export_funcs_size()); 581 for (auto I = mRSContext->export_funcs_begin(), 582 E = mRSContext->export_funcs_end(); 583 I != E; ++I) 584 genExportFunction(*I); 585 mState->endInvokables(); 586 587 if (!mCollecting) { 588 if (mState->endOutputClass()) 589 genCompute64Bit(); 590 591 endClass(); 592 593 mGeneratedFileNames->push_back(mScriptClassName); 594 } 595 596 return true; 597 } 598 599 void RSReflectionJava::genScriptClassConstructor() { 600 std::string className(RSSlangReflectUtils::JavaBitcodeClassNameFromRSFileName( 601 mRSSourceFileName.c_str())); 602 // Provide a simple way to reference this object. 603 mOut.indent() << "private static final String " RS_RESOURCE_NAME " = \"" 604 << getResourceId() << "\";\n"; 605 606 // Generate a simple constructor with only a single parameter (the rest 607 // can be inferred from information we already have). 608 mOut.indent() << "// Constructor\n"; 609 startFunction(AM_Public, false, nullptr, getClassName(), 1, "RenderScript", 610 "rs"); 611 612 const bool haveReduceExportables = 613 mRSContext->export_reduce_begin() != mRSContext->export_reduce_end(); 614 615 if (getEmbedBitcodeInJava()) { 616 // Call new single argument Java-only constructor 617 mOut.indent() << "super(rs,\n"; 618 mOut.indent() << " " << RS_RESOURCE_NAME ",\n"; 619 mOut.indent() << " " << className << ".getBitCode32(),\n"; 620 mOut.indent() << " " << className << ".getBitCode64());\n"; 621 } else { 622 // Call alternate constructor with required parameters. 623 // Look up the proper raw bitcode resource id via the context. 624 mOut.indent() << "this(rs,\n"; 625 mOut.indent() << " rs.getApplicationContext().getResources(),\n"; 626 mOut.indent() << " rs.getApplicationContext().getResources()." 627 "getIdentifier(\n"; 628 mOut.indent() << " " RS_RESOURCE_NAME ", \"raw\",\n"; 629 mOut.indent() 630 << " rs.getApplicationContext().getPackageName()));\n"; 631 endFunction(); 632 633 // Alternate constructor (legacy) with 3 original parameters. 634 startFunction(AM_Public, false, nullptr, getClassName(), 3, "RenderScript", 635 "rs", "Resources", "resources", "int", "id"); 636 // Call constructor of super class 637 mOut.indent() << "super(rs, resources, id);\n"; 638 } 639 640 // If an exported variable has initial value, reflect it. 641 // Keep this in sync with initialization handling in ReflectionState::declareVariable(). 642 643 for (auto I = mRSContext->export_vars_begin(), 644 E = mRSContext->export_vars_end(); 645 I != E; I++) { 646 const RSExportVar *EV = *I; 647 if (!EV->getInit().isUninit()) { 648 genInitExportVariable(EV->getType(), EV->getName(), EV->getInit()); 649 } else if (EV->getArraySize()) { 650 // Always create an initial zero-init array object. 651 mOut.indent() << RS_EXPORT_VAR_PREFIX << EV->getName() << " = new " 652 << GetTypeName(EV->getType(), TypeNameDefault & ~TypeNameWithConstantArrayBrackets) << "[" 653 << EV->getArraySize() << "];\n"; 654 size_t NumInits = EV->getNumInits(); 655 const RSExportConstantArrayType *ECAT = 656 static_cast<const RSExportConstantArrayType *>(EV->getType()); 657 const RSExportType *ET = ECAT->getElementType(); 658 for (size_t i = 0; i < NumInits; i++) { 659 std::stringstream Name; 660 Name << EV->getName() << "[" << i << "]"; 661 genInitExportVariable(ET, Name.str(), EV->getInitArray(i)); 662 } 663 } 664 if (mRSContext->getTargetAPI() >= SLANG_JB_TARGET_API) { 665 genTypeInstance(EV->getType()); 666 } 667 genFieldPackerInstance(EV->getType()); 668 } 669 670 if (haveReduceExportables) { 671 mOut.indent() << SAVED_RS_REFERENCE << " = rs;\n"; 672 } 673 674 // Reflect argument / return types in kernels 675 676 for (auto I = mRSContext->export_foreach_begin(), 677 E = mRSContext->export_foreach_end(); 678 I != E; I++) { 679 const RSExportForEach *EF = *I; 680 681 const RSExportForEach::InTypeVec &InTypes = EF->getInTypes(); 682 for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end(); 683 BI != EI; BI++) { 684 if (*BI != nullptr) { 685 genTypeInstanceFromPointer(*BI); 686 } 687 } 688 689 const RSExportType *OET = EF->getOutType(); 690 if (OET) { 691 genTypeInstanceFromPointer(OET); 692 } 693 } 694 695 for (auto I = mRSContext->export_reduce_begin(), 696 E = mRSContext->export_reduce_end(); 697 I != E; I++) { 698 const RSExportReduce *ER = *I; 699 700 const RSExportType *RT = ER->getResultType(); 701 slangAssert(RT != nullptr); 702 if (!exportableReduce(RT)) 703 continue; 704 705 genTypeInstance(RT); 706 707 const RSExportReduce::InTypeVec &InTypes = ER->getAccumulatorInTypes(); 708 for (RSExportReduce::InTypeIter BI = InTypes.begin(), EI = InTypes.end(); 709 BI != EI; BI++) { 710 slangAssert(*BI != nullptr); 711 genTypeInstance(*BI); 712 } 713 } 714 715 endFunction(); 716 717 for (std::set<std::string>::iterator I = mTypesToCheck.begin(), 718 E = mTypesToCheck.end(); 719 I != E; I++) { 720 mOut.indent() << "private Element " RS_ELEM_PREFIX << *I << ";\n"; 721 } 722 723 for (std::set<std::string>::iterator I = mFieldPackerTypes.begin(), 724 E = mFieldPackerTypes.end(); 725 I != E; I++) { 726 mOut.indent() << "private FieldPacker " RS_FP_PREFIX << *I << ";\n"; 727 } 728 729 if (haveReduceExportables) { 730 // We save a private copy of rs in order to create temporary 731 // allocations in the reduce_* entry points. 732 mOut.indent() << "private RenderScript " << SAVED_RS_REFERENCE << ";\n"; 733 } 734 } 735 736 void RSReflectionJava::genInitBoolExportVariable(const std::string &VarName, 737 const clang::APValue &Val) { 738 slangAssert(!Val.isUninit() && "Not a valid initializer"); 739 slangAssert((Val.getKind() == clang::APValue::Int) && 740 "Bool type has wrong initial APValue"); 741 742 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = "; 743 744 mOut << ((Val.getInt().getSExtValue() == 0) ? "false" : "true") << ";\n"; 745 } 746 747 void 748 RSReflectionJava::genInitPrimitiveExportVariable(const std::string &VarName, 749 const clang::APValue &Val) { 750 slangAssert(!Val.isUninit() && "Not a valid initializer"); 751 752 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = "; 753 genInitValue(Val, false); 754 mOut << ";\n"; 755 } 756 757 void RSReflectionJava::genInitExportVariable(const RSExportType *ET, 758 const std::string &VarName, 759 const clang::APValue &Val) { 760 slangAssert(!Val.isUninit() && "Not a valid initializer"); 761 762 switch (ET->getClass()) { 763 case RSExportType::ExportClassPrimitive: { 764 const RSExportPrimitiveType *EPT = 765 static_cast<const RSExportPrimitiveType *>(ET); 766 if (EPT->getType() == DataTypeBoolean) { 767 genInitBoolExportVariable(VarName, Val); 768 } else { 769 genInitPrimitiveExportVariable(VarName, Val); 770 } 771 break; 772 } 773 case RSExportType::ExportClassPointer: { 774 if (!Val.isInt() || Val.getInt().getSExtValue() != 0) 775 std::cout << "Initializer which is non-NULL to pointer type variable " 776 "will be ignored\n"; 777 break; 778 } 779 case RSExportType::ExportClassVector: { 780 const RSExportVectorType *EVT = static_cast<const RSExportVectorType *>(ET); 781 switch (Val.getKind()) { 782 case clang::APValue::Int: 783 case clang::APValue::Float: { 784 for (unsigned i = 0; i < EVT->getNumElement(); i++) { 785 std::string Name = VarName + "." + GetVectorAccessor(i); 786 genInitPrimitiveExportVariable(Name, Val); 787 } 788 break; 789 } 790 case clang::APValue::Vector: { 791 std::stringstream VecName; 792 VecName << EVT->getRSReflectionType(EVT)->rs_java_vector_prefix 793 << EVT->getNumElement(); 794 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = new " 795 << VecName.str() << "();\n"; 796 797 unsigned NumElements = std::min( 798 static_cast<unsigned>(EVT->getNumElement()), Val.getVectorLength()); 799 for (unsigned i = 0; i < NumElements; i++) { 800 const clang::APValue &ElementVal = Val.getVectorElt(i); 801 std::string Name = VarName + "." + GetVectorAccessor(i); 802 genInitPrimitiveExportVariable(Name, ElementVal); 803 } 804 break; 805 } 806 case clang::APValue::MemberPointer: 807 case clang::APValue::Uninitialized: 808 case clang::APValue::ComplexInt: 809 case clang::APValue::ComplexFloat: 810 case clang::APValue::LValue: 811 case clang::APValue::Array: 812 case clang::APValue::Struct: 813 case clang::APValue::Union: 814 case clang::APValue::AddrLabelDiff: { 815 slangAssert(false && "Unexpected type of value of initializer."); 816 } 817 } 818 break; 819 } 820 // TODO(zonr): Resolving initializer of a record (and matrix) type variable 821 // is complex. It cannot obtain by just simply evaluating the initializer 822 // expression. 823 case RSExportType::ExportClassMatrix: 824 case RSExportType::ExportClassConstantArray: 825 case RSExportType::ExportClassRecord: { 826 #if 0 827 unsigned InitIndex = 0; 828 const RSExportRecordType *ERT = 829 static_cast<const RSExportRecordType*>(ET); 830 831 slangAssert((Val.getKind() == clang::APValue::Vector) && 832 "Unexpected type of initializer for record type variable"); 833 834 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName 835 << " = new " << ERT->getElementName() 836 << "." RS_TYPE_ITEM_CLASS_NAME"();\n"; 837 838 for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), 839 E = ERT->fields_end(); 840 I != E; 841 I++) { 842 const RSExportRecordType::Field *F = *I; 843 std::string FieldName = VarName + "." + F->getName(); 844 845 if (InitIndex > Val.getVectorLength()) 846 break; 847 848 genInitPrimitiveExportVariable(FieldName, 849 Val.getVectorElt(InitIndex++)); 850 } 851 #endif 852 slangAssert(false && "Unsupported initializer for record/matrix/constant " 853 "array type variable currently"); 854 break; 855 } 856 default: { slangAssert(false && "Unknown class of type"); } 857 } 858 } 859 860 void RSReflectionJava::genExportVariable(const RSExportVar *EV) { 861 const RSExportType *ET = EV->getType(); 862 863 const ReflectionState::Val32 864 AllocSize32 = mState->declareVariable(EV); 865 866 if (mCollecting) 867 return; 868 869 mOut.indent() << "private final static int " << RS_EXPORT_VAR_INDEX_PREFIX 870 << EV->getName() << " = " << getNextExportVarSlot() << ";\n"; 871 872 switch (ET->getClass()) { 873 case RSExportType::ExportClassPrimitive: { 874 genPrimitiveTypeExportVariable(EV); 875 break; 876 } 877 case RSExportType::ExportClassPointer: { 878 genPointerTypeExportVariable(EV); 879 break; 880 } 881 case RSExportType::ExportClassVector: { 882 genVectorTypeExportVariable(EV); 883 break; 884 } 885 case RSExportType::ExportClassMatrix: { 886 genMatrixTypeExportVariable(EV); 887 break; 888 } 889 case RSExportType::ExportClassConstantArray: { 890 genConstantArrayTypeExportVariable(EV, AllocSize32); 891 break; 892 } 893 case RSExportType::ExportClassRecord: { 894 genRecordTypeExportVariable(EV, AllocSize32); 895 break; 896 } 897 default: { slangAssert(false && "Unknown class of type"); } 898 } 899 } 900 901 // Keep this in sync with Invokable analysis in ReflectionState::declareInvokable(). 902 void RSReflectionJava::genExportFunction(const RSExportFunc *EF) { 903 mState->declareInvokable(EF); 904 905 if (!mCollecting) { 906 mOut.indent() << "private final static int " << RS_EXPORT_FUNC_INDEX_PREFIX 907 << EF->getName() << " = " << getNextExportFuncSlot() << ";\n"; 908 } 909 910 // invoke_*() 911 ArgTy Args; 912 913 if (!mCollecting) { 914 if (EF->hasParam()) { 915 for (RSExportFunc::const_param_iterator I = EF->params_begin(), 916 E = EF->params_end(); 917 I != E; I++) { 918 Args.push_back( 919 std::make_pair(GetTypeName((*I)->getType()), (*I)->getName())); 920 } 921 } 922 923 if (mRSContext->getTargetAPI() >= SLANG_M_TARGET_API) { 924 startFunction(AM_Public, false, "Script.InvokeID", 925 "getInvokeID_" + EF->getName(), 0); 926 927 mOut.indent() << "return createInvokeID(" << RS_EXPORT_FUNC_INDEX_PREFIX 928 << EF->getName() << ");\n"; 929 930 endFunction(); 931 } 932 933 startFunction(AM_Public, false, "void", 934 "invoke_" + EF->getName(/*Mangle=*/false), 935 // We are using un-mangled name since Java 936 // supports method overloading. 937 Args); 938 } 939 940 if (!EF->hasParam()) { 941 if (!mCollecting) 942 mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName() 943 << ");\n"; 944 } else { 945 const RSExportRecordType *ERT = EF->getParamPacketType(); 946 947 // NOTE: This type isn't on the RSContext::export_types* list. 948 mState->declareRecord(ERT, false); 949 950 std::string FieldPackerName = EF->getName() + "_fp"; 951 952 if (genCreateFieldPacker(ERT, FieldPackerName.c_str(), 953 mState->getRecord32(ERT).getRecordAllocSize())) 954 genPackVarOfType(ERT, nullptr, FieldPackerName.c_str()); 955 956 if (!mCollecting) 957 mOut.indent() << "invoke(" << RS_EXPORT_FUNC_INDEX_PREFIX << EF->getName() 958 << ", " << FieldPackerName << ");\n"; 959 } 960 961 if (!mCollecting) 962 endFunction(); 963 } 964 965 void RSReflectionJava::genPairwiseDimCheck(const std::string &name0, 966 const std::string &name1) { 967 mOut.indent() << "// Verify dimensions\n"; 968 mOut.indent() << "t0 = " << name0 << ".getType();\n"; 969 mOut.indent() << "t1 = " << name1 << ".getType();\n"; 970 mOut.indent() << "if ((t0.getCount() != t1.getCount()) ||\n"; 971 mOut.indent() << " (t0.getX() != t1.getX()) ||\n"; 972 mOut.indent() << " (t0.getY() != t1.getY()) ||\n"; 973 mOut.indent() << " (t0.getZ() != t1.getZ()) ||\n"; 974 mOut.indent() << " (t0.hasFaces() != t1.hasFaces()) ||\n"; 975 mOut.indent() << " (t0.hasMipmaps() != t1.hasMipmaps())) {\n"; 976 mOut.indent() << " throw new RSRuntimeException(\"Dimension mismatch " 977 << "between parameters " << name0 << " and " << name1 978 << "!\");\n"; 979 mOut.indent() << "}\n\n"; 980 } 981 982 void RSReflectionJava::genNullArrayCheck(const std::string &ArrayName) { 983 mOut.indent() << "// Verify that \"" << ArrayName << "\" is non-null.\n"; 984 mOut.indent() << "if (" << ArrayName << " == null) {\n"; 985 mOut.indent() << " throw new RSIllegalArgumentException(\"Array \\\"" 986 << ArrayName << "\\\" is null!\");\n"; 987 mOut.indent() << "}\n"; 988 } 989 990 void RSReflectionJava::genVectorLengthCompatibilityCheck(const std::string &ArrayName, 991 unsigned VecSize) { 992 mOut.indent() << "// Verify that the array length is a multiple of the vector size.\n"; 993 mOut.indent() << "if (" << ArrayName << ".length % " << std::to_string(VecSize) 994 << " != 0) {\n"; 995 mOut.indent() << " throw new RSIllegalArgumentException(\"Array \\\"" << ArrayName 996 << "\\\" is not a multiple of " << std::to_string(VecSize) 997 << " in length!\");\n"; 998 mOut.indent() << "}\n"; 999 } 1000 1001 // Keep this in sync with ForEach analysis in ReflectionState::beginForEach() 1002 // and other ReflectionState::*ForEach*() methods. 1003 void RSReflectionJava::genExportForEach(const RSExportForEach *EF) { 1004 if (EF->isDummyRoot()) { 1005 mState->declareForEachDummyRoot(EF); 1006 1007 if (!mCollecting) { 1008 // Skip reflection for dummy root() kernels. Note that we have to 1009 // advance the next slot number for ForEach, however. 1010 mOut.indent() << "//private final static int " 1011 << RS_EXPORT_FOREACH_INDEX_PREFIX << EF->getName() << " = " 1012 << getNextExportForEachSlot() << ";\n"; 1013 } 1014 1015 return; 1016 } 1017 1018 if (!mCollecting) { 1019 mOut.indent() << "private final static int " << RS_EXPORT_FOREACH_INDEX_PREFIX 1020 << EF->getName() << " = " << getNextExportForEachSlot() 1021 << ";\n"; 1022 } 1023 1024 // forEach_*() 1025 ArgTy Args; 1026 bool HasAllocation = false; // at least one in/out allocation? 1027 1028 const RSExportForEach::InVec &Ins = EF->getIns(); 1029 const RSExportForEach::InTypeVec &InTypes = EF->getInTypes(); 1030 const RSExportType *OET = EF->getOutType(); 1031 const RSExportRecordType *ERT = EF->getParamPacketType(); 1032 1033 mState->beginForEach(EF); 1034 1035 for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end(); 1036 BI != EI; BI++) { 1037 mState->addForEachIn(EF, *BI); 1038 } 1039 1040 if (Ins.size() == 1) { 1041 HasAllocation = true; 1042 if (!mCollecting) 1043 Args.push_back(std::make_pair("Allocation", "ain")); 1044 } else if (Ins.size() > 1) { 1045 HasAllocation = true; 1046 if (!mCollecting) { 1047 for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI; 1048 BI++) { 1049 Args.push_back(std::make_pair("Allocation", 1050 "ain_" + (*BI)->getName().str())); 1051 } 1052 } 1053 } 1054 1055 if (EF->hasOut() || EF->hasReturn()) { 1056 HasAllocation = true; 1057 if (!mCollecting) 1058 Args.push_back(std::make_pair("Allocation", "aout")); 1059 } 1060 1061 if (ERT) { 1062 for (RSExportForEach::const_param_iterator I = EF->params_begin(), 1063 E = EF->params_end(); 1064 I != E; I++) { 1065 mState->addForEachParam(EF, (*I)->getType()); 1066 if (!mCollecting) 1067 Args.push_back( 1068 std::make_pair(GetTypeName((*I)->getType()), (*I)->getName())); 1069 } 1070 } 1071 1072 if (mRSContext->getTargetAPI() >= SLANG_JB_MR1_TARGET_API) { 1073 mState->addForEachSignatureMetadata(EF, EF->getSignatureMetadata()); 1074 1075 if (!mCollecting) { 1076 startFunction(AM_Public, false, "Script.KernelID", 1077 "getKernelID_" + EF->getName(), 0); 1078 1079 // TODO: add element checking 1080 mOut.indent() << "return createKernelID(" << RS_EXPORT_FOREACH_INDEX_PREFIX 1081 << EF->getName() << ", " << EF->getSignatureMetadata() 1082 << ", null, null);\n"; 1083 1084 endFunction(); 1085 } 1086 } 1087 1088 if (!mCollecting) { 1089 if (mRSContext->getTargetAPI() >= SLANG_JB_MR2_TARGET_API) { 1090 if (HasAllocation) { 1091 startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args); 1092 1093 mOut.indent() << "forEach_" << EF->getName(); 1094 mOut << "("; 1095 1096 if (Ins.size() == 1) { 1097 mOut << "ain, "; 1098 1099 } else if (Ins.size() > 1) { 1100 for (RSExportForEach::InIter BI = Ins.begin(), EI = Ins.end(); BI != EI; 1101 BI++) { 1102 1103 mOut << "ain_" << (*BI)->getName().str() << ", "; 1104 } 1105 } 1106 1107 if (EF->hasOut() || EF->hasReturn()) { 1108 mOut << "aout, "; 1109 } 1110 1111 if (EF->hasUsrData()) { 1112 mOut << Args.back().second << ", "; 1113 } 1114 1115 // No clipped bounds to pass in. 1116 mOut << "null);\n"; 1117 1118 endFunction(); 1119 } 1120 1121 // Add the clipped kernel parameters to the Args list. 1122 Args.push_back(std::make_pair("Script.LaunchOptions", "sc")); 1123 } 1124 } 1125 1126 if (!mCollecting) { 1127 startFunction(AM_Public, false, "void", "forEach_" + EF->getName(), Args); 1128 1129 if (InTypes.size() == 1) { 1130 if (InTypes.front() != nullptr) { 1131 genTypeCheck(InTypes.front(), "ain"); 1132 } 1133 1134 } else if (InTypes.size() > 1) { 1135 size_t Index = 0; 1136 for (RSExportForEach::InTypeIter BI = InTypes.begin(), EI = InTypes.end(); 1137 BI != EI; BI++, ++Index) { 1138 1139 if (*BI != nullptr) { 1140 genTypeCheck(*BI, ("ain_" + Ins[Index]->getName()).str().c_str()); 1141 } 1142 } 1143 } 1144 1145 if (OET) { 1146 genTypeCheck(OET, "aout"); 1147 } 1148 1149 if (Ins.size() == 1 && (EF->hasOut() || EF->hasReturn())) { 1150 mOut.indent() << "Type t0, t1;"; 1151 genPairwiseDimCheck("ain", "aout"); 1152 1153 } else if (Ins.size() > 1) { 1154 mOut.indent() << "Type t0, t1;"; 1155 1156 std::string In0Name = "ain_" + Ins[0]->getName().str(); 1157 1158 for (size_t index = 1; index < Ins.size(); ++index) { 1159 genPairwiseDimCheck(In0Name, "ain_" + Ins[index]->getName().str()); 1160 } 1161 1162 if (EF->hasOut() || EF->hasReturn()) { 1163 genPairwiseDimCheck(In0Name, "aout"); 1164 } 1165 } 1166 } 1167 1168 std::string FieldPackerName = EF->getName() + "_fp"; 1169 if (ERT) { 1170 // NOTE: This type isn't on the RSContext::export_types* list. 1171 mState->declareRecord(ERT, false); 1172 1173 if (genCreateFieldPacker(ERT, FieldPackerName.c_str(), 1174 mState->getRecord32(ERT).getRecordAllocSize())) { 1175 genPackVarOfType(ERT, nullptr, FieldPackerName.c_str()); 1176 } 1177 } 1178 1179 mState->endForEach(); 1180 1181 if (mCollecting) 1182 return; 1183 1184 mOut.indent() << "forEach(" << RS_EXPORT_FOREACH_INDEX_PREFIX 1185 << EF->getName(); 1186 1187 if (Ins.size() == 1) { 1188 mOut << ", ain"; 1189 } else if (Ins.size() > 1) { 1190 mOut << ", new Allocation[]{ain_" << Ins[0]->getName().str(); 1191 1192 for (size_t index = 1; index < Ins.size(); ++index) { 1193 mOut << ", ain_" << Ins[index]->getName().str(); 1194 } 1195 1196 mOut << "}"; 1197 1198 } else { 1199 mOut << ", (Allocation) null"; 1200 } 1201 1202 if (EF->hasOut() || EF->hasReturn()) 1203 mOut << ", aout"; 1204 else 1205 mOut << ", null"; 1206 1207 if (EF->hasUsrData()) 1208 mOut << ", " << FieldPackerName; 1209 else 1210 mOut << ", null"; 1211 1212 if (mRSContext->getTargetAPI() >= SLANG_JB_MR2_TARGET_API) { 1213 mOut << ", sc);\n"; 1214 } else { 1215 mOut << ");\n"; 1216 } 1217 1218 endFunction(); 1219 } 1220 1221 ////////////////////////////////////////////////////////////////////////////////////////////////////// 1222 1223 // Reductions with certain legal result types can only be reflected for NDK, not for Java. 1224 bool RSReflectionJava::exportableReduce(const RSExportType *ResultType) { 1225 const RSExportType *CheckType = ResultType; 1226 if (ResultType->getClass() == RSExportType::ExportClassConstantArray) 1227 CheckType = static_cast<const RSExportConstantArrayType *>(ResultType)->getElementType(); 1228 if (CheckType->getClass() == RSExportType::ExportClassRecord) { 1229 // No Java reflection for struct until http://b/22236498 is resolved. 1230 return false; 1231 } 1232 1233 return true; 1234 } 1235 1236 namespace { 1237 enum MappingComment { MappingCommentWithoutType, MappingCommentWithCType }; 1238 1239 // OUTPUTS 1240 // InputParamName = name to use for input parameter 1241 // InputMappingComment = text showing the mapping from InputParamName to the corresponding 1242 // accumulator function parameter name (and possibly type) 1243 // INPUTS 1244 // NamePrefix = beginning of parameter name (e.g., "in") 1245 // MappingComment = whether or not InputMappingComment should contain type 1246 // ER = description of the reduction 1247 // InIdx = which input (numbered from zero) 1248 void getReduceInputStrings(std::string &InputParamName, std::string &InputMappingComment, 1249 const std::string &NamePrefix, MappingComment Mapping, 1250 const RSExportReduce *ER, size_t InIdx) { 1251 InputParamName = NamePrefix + std::to_string(InIdx+1); 1252 std::string TypeString; 1253 if (Mapping == MappingCommentWithCType) { 1254 const RSExportType *InType = ER->getAccumulatorInTypes()[InIdx]; 1255 if (InType->getClass() == RSExportType::ExportClassRecord) { 1256 // convertToRTD doesn't understand this type 1257 TypeString = "/* struct <> */ "; 1258 } else { 1259 RSReflectionTypeData InTypeData; 1260 ER->getAccumulatorInTypes()[InIdx]->convertToRTD(&InTypeData); 1261 slangAssert(InTypeData.type->s_name != nullptr); 1262 if (InTypeData.vecSize > 1) { 1263 TypeString = InTypeData.type->s_name + std::to_string(InTypeData.vecSize) + " "; 1264 } else { 1265 TypeString = InTypeData.type->s_name + std::string(" "); 1266 } 1267 } 1268 } 1269 InputMappingComment = InputParamName + " = \"" + TypeString + std::string(ER->getAccumulatorIns()[InIdx]->getName()) + "\""; 1270 } 1271 1272 } // end anonymous namespace 1273 1274 // Keep this in sync with Reduce analysis in ReflectionState::declareReduce(). 1275 void RSReflectionJava::genExportReduce(const RSExportReduce *ER) { 1276 const bool IsExportable = exportableReduce(ER->getResultType()); 1277 1278 // Need to track even a non-exportable reduce, both so that we get 1279 // the count of reduction kernels correct, and so that we can 1280 // intelligently diagnose cases where 32-bit and 64-bit compiles 1281 // disagree as to whether a reduction kernel is exportable. 1282 mState->declareReduce(ER, IsExportable); 1283 1284 if (!IsExportable || mCollecting) 1285 return; 1286 1287 // Generate the reflected function index. 1288 mOut.indent() << "private final static int " << RS_EXPORT_REDUCE_INDEX_PREFIX 1289 << ER->getNameReduce() << " = " << getNextExportReduceSlot() 1290 << ";\n"; 1291 1292 /****** remember resultSvType generation **********************************************************/ 1293 1294 // Two variants of reduce_* entry points get generated. 1295 // Array variant: 1296 // result_<resultSvType> reduce_<name>(<devecSiIn1Type>[] in1, ..., <devecSiInNType>[] inN) 1297 // Allocation variant: 1298 // result_<resultSvType> reduce_<name>(Allocation in1, ..., Allocation inN) 1299 // result_<resultSvType> reduce_<name>(Allocation in1, ..., Allocation inN, Script.LaunchOptions sc) 1300 1301 genExportReduceArrayVariant(ER); 1302 genExportReduceAllocationVariant(ER); 1303 } 1304 1305 void RSReflectionJava::genExportReduceArrayVariant(const RSExportReduce *ER) { 1306 // Analysis of result type. Returns early if result type is not 1307 // suitable for array method reflection. 1308 const RSExportType *const ResultType = ER->getResultType(); 1309 auto ResultTypeClass = ResultType->getClass(); 1310 switch (ResultTypeClass) { 1311 case RSExportType::ExportClassConstantArray: 1312 case RSExportType::ExportClassMatrix: 1313 case RSExportType::ExportClassPrimitive: 1314 case RSExportType::ExportClassVector: 1315 // Ok 1316 break; 1317 1318 case RSExportType::ExportClassPointer: 1319 slangAssert(!"Should not get here with pointer type"); 1320 return; 1321 1322 case RSExportType::ExportClassRecord: 1323 // TODO: convertToRTD() cannot handle this. Why not? 1324 return; 1325 1326 default: 1327 slangAssert(!"Unknown export class"); 1328 return; 1329 } 1330 RSReflectionTypeData ResultTypeData; 1331 ResultType->convertToRTD(&ResultTypeData); 1332 if (!ResultTypeData.type->java_name || !ResultTypeData.type->java_array_element_name || 1333 (ResultTypeData.vecSize > 1 && !ResultTypeData.type->rs_java_vector_prefix)) { 1334 slangAssert(false); 1335 return; 1336 } 1337 const std::string ResultTypeName = GetReduceResultTypeName(ER); 1338 1339 // Analysis of inputs. Returns early if some input type is not 1340 // suitable for array method reflection. 1341 llvm::SmallVector<RSReflectionTypeData, 1> InsTypeData; 1342 ArgTy Args; 1343 const auto &Ins = ER->getAccumulatorIns(); 1344 const auto &InTypes = ER->getAccumulatorInTypes(); 1345 slangAssert(Ins.size() == InTypes.size()); 1346 InsTypeData.resize(Ins.size()); 1347 llvm::SmallVector<std::string, 1> InComments; 1348 for (size_t InIdx = 0, InEnd = Ins.size(); InIdx < InEnd; ++InIdx) { 1349 const RSExportType *const InType = InTypes[InIdx]; 1350 switch (InType->getClass()) { 1351 case RSExportType::ExportClassMatrix: 1352 case RSExportType::ExportClassPrimitive: 1353 case RSExportType::ExportClassVector: 1354 // Ok 1355 break; 1356 1357 case RSExportType::ExportClassConstantArray: 1358 // No 1359 return; 1360 1361 case RSExportType::ExportClassPointer: 1362 slangAssert(!"Should not get here with pointer type"); 1363 return; 1364 1365 case RSExportType::ExportClassRecord: 1366 // TODO: convertToRTD() cannot handle this. Why not? 1367 return; 1368 1369 default: 1370 slangAssert(!"Unknown export class"); 1371 return; 1372 } 1373 1374 RSReflectionTypeData &InTypeData = InsTypeData[InIdx]; 1375 InType->convertToRTD(&InTypeData); 1376 if (!InTypeData.type->java_name || !InTypeData.type->java_array_element_name || 1377 (InTypeData.vecSize > 1 && !InTypeData.type->rs_java_vector_prefix)) { 1378 return; 1379 } 1380 1381 std::string InputParamName, InputComment; 1382 getReduceInputStrings(InputParamName, InputComment, "in", MappingCommentWithoutType, ER, InIdx); 1383 if (InTypeData.vecSize > 1) 1384 InputComment += (", flattened " + std::to_string(InTypeData.vecSize) + "-vectors"); 1385 InComments.push_back(InputComment); 1386 1387 const std::string InputTypeName = std::string(InTypeData.type->java_array_element_name) + "[]"; 1388 Args.push_back(std::make_pair(InputTypeName, InputParamName)); 1389 } 1390 1391 const std::string MethodName = "reduce_" + ER->getNameReduce(); 1392 1393 // result_<resultSvType> reduce_<name>(<devecSiIn1Type>[] in1, ..., <devecSiInNType>[] inN) 1394 1395 for (const std::string &InComment : InComments) 1396 mOut.indent() << "// " << InComment << "\n"; 1397 startFunction(AM_Public, false, ResultTypeName.c_str(), MethodName, Args); 1398 slangAssert(Ins.size() == InTypes.size()); 1399 slangAssert(Ins.size() == InsTypeData.size()); 1400 slangAssert(Ins.size() == Args.size()); 1401 std::string In1Length; 1402 std::string InputAllocationOutgoingArgumentList; 1403 std::vector<std::string> InputAllocationNames; 1404 for (size_t InIdx = 0, InEnd = Ins.size(); InIdx < InEnd; ++InIdx) { 1405 const std::string &ArgName = Args[InIdx].second; 1406 genNullArrayCheck(ArgName); 1407 std::string InLength = ArgName + ".length"; 1408 const uint32_t VecSize = InsTypeData[InIdx].vecSize; 1409 if (VecSize > 1) { 1410 InLength += " / " + std::to_string(VecSize); 1411 genVectorLengthCompatibilityCheck(ArgName, VecSize); 1412 } 1413 if (InIdx == 0) { 1414 In1Length = InLength; 1415 } else { 1416 mOut.indent() << "// Verify that input array lengths are the same.\n"; 1417 mOut.indent() << "if (" << In1Length << " != " << InLength << ") {\n"; 1418 mOut.indent() << " throw new RSRuntimeException(\"Array length mismatch " 1419 << "between parameters \\\"" << Args[0].second << "\\\" and \\\"" << ArgName 1420 << "\\\"!\");\n"; 1421 mOut.indent() << "}\n"; 1422 } 1423 // Create a temporary input allocation 1424 const std::string TempName = "a" + ArgName; 1425 mOut.indent() << "Allocation " << TempName << " = Allocation.createSized(" 1426 << SAVED_RS_REFERENCE << ", " 1427 << RS_ELEM_PREFIX << InTypes[InIdx]->getElementName() << ", " 1428 << InLength << ");\n"; 1429 mOut.indent() << TempName << ".setAutoPadding(true);\n"; 1430 mOut.indent() << TempName << ".copyFrom(" << ArgName << ");\n"; 1431 // ... and put that input allocation on the outgoing argument list 1432 if (!InputAllocationOutgoingArgumentList.empty()) 1433 InputAllocationOutgoingArgumentList += ", "; 1434 InputAllocationOutgoingArgumentList += TempName; 1435 // ... and keep track of it for setting result.mTempIns 1436 InputAllocationNames.push_back(TempName); 1437 } 1438 1439 mOut << "\n"; 1440 mOut.indent() << ResultTypeName << " result = " << MethodName << "(" << InputAllocationOutgoingArgumentList << ", null);\n"; 1441 if (!InputAllocationNames.empty()) { 1442 mOut.indent() << "result.mTempIns = new Allocation[]{"; 1443 bool EmittedFirst = false; 1444 for (const std::string &InputAllocationName : InputAllocationNames) { 1445 if (!EmittedFirst) { 1446 EmittedFirst = true; 1447 } else { 1448 mOut << ", "; 1449 } 1450 mOut << InputAllocationName; 1451 } 1452 mOut << "};\n"; 1453 } 1454 mOut.indent() << "return result;\n"; 1455 endFunction(); 1456 } 1457 1458 void RSReflectionJava::genExportReduceAllocationVariant(const RSExportReduce *ER) { 1459 const auto &Ins = ER->getAccumulatorIns(); 1460 const auto &InTypes = ER->getAccumulatorInTypes(); 1461 const RSExportType *ResultType = ER->getResultType(); 1462 1463 llvm::SmallVector<std::string, 1> InComments; 1464 ArgTy Args; 1465 for (size_t InIdx = 0, InEnd = Ins.size(); InIdx < InEnd; ++InIdx) { 1466 std::string InputParamName, InputComment; 1467 getReduceInputStrings(InputParamName, InputComment, "ain", MappingCommentWithCType, ER, InIdx); 1468 InComments.push_back(InputComment); 1469 Args.push_back(std::make_pair("Allocation", InputParamName)); 1470 } 1471 1472 const std::string MethodName = "reduce_" + ER->getNameReduce(); 1473 const std::string ResultTypeName = GetReduceResultTypeName(ER); 1474 1475 // result_<resultSvType> reduce_<name>(Allocation in1, ..., Allocation inN) 1476 1477 for (const std::string &InComment : InComments) 1478 mOut.indent() << "// " << InComment << "\n"; 1479 startFunction(AM_Public, false, ResultTypeName.c_str(), MethodName, Args); 1480 mOut.indent() << "return " << MethodName << "("; 1481 bool EmittedFirstArg = false; 1482 for (const auto &Arg : Args) { 1483 if (!EmittedFirstArg) { 1484 EmittedFirstArg = true; 1485 } else { 1486 mOut << ", "; 1487 } 1488 mOut << Arg.second; 1489 } 1490 mOut << ", null);\n"; 1491 endFunction(); 1492 1493 // result_<resultSvType> reduce_<name>(Allocation in1, ..., Allocation inN, Script.LaunchOptions sc) 1494 1495 static const char FormalOptionsName[] = "sc"; 1496 Args.push_back(std::make_pair("Script.LaunchOptions", FormalOptionsName)); 1497 for (const std::string &InComment : InComments) 1498 mOut.indent() << "// " << InComment << "\n"; 1499 startFunction(AM_Public, false, ResultTypeName.c_str(), MethodName, Args); 1500 const std::string &In0Name = Args[0].second; 1501 // Sanity-check inputs 1502 if (Ins.size() > 1) 1503 mOut.indent() << "Type t0, t1;\n"; 1504 for (size_t InIdx = 0, InEnd = Ins.size(); InIdx < InEnd; ++InIdx) { 1505 const std::string &InName = Args[InIdx].second; 1506 genTypeCheck(InTypes[InIdx], InName.c_str()); 1507 if (InIdx > 0) 1508 genPairwiseDimCheck(In0Name, InName); 1509 } 1510 // Create a temporary output allocation 1511 const char OutputAllocName[] = "aout"; 1512 const size_t OutputAllocLength = 1513 ResultType->getClass() == RSExportType::ExportClassConstantArray 1514 ? static_cast<const RSExportConstantArrayType *>(ResultType)->getNumElement() 1515 : 1; 1516 mOut.indent() << "Allocation " << OutputAllocName << " = Allocation.createSized(" 1517 << SAVED_RS_REFERENCE << ", " 1518 << RS_ELEM_PREFIX << ResultType->getElementName() << ", " 1519 << OutputAllocLength << ");\n"; 1520 mOut.indent() << OutputAllocName << ".setAutoPadding(true);\n"; 1521 // Call the underlying reduce entry point 1522 mOut.indent() << "reduce(" << RS_EXPORT_REDUCE_INDEX_PREFIX << ER->getNameReduce() 1523 << ", new Allocation[]{" << In0Name; 1524 for (size_t InIdx = 1, InEnd = Ins.size(); InIdx < InEnd; ++InIdx) 1525 mOut << ", " << Args[InIdx].second; 1526 mOut << "}, " << OutputAllocName << ", " << FormalOptionsName << ");\n"; 1527 mOut.indent() << "return new " << ResultTypeName << "(" << OutputAllocName << ");\n"; 1528 endFunction(); 1529 } 1530 1531 namespace { 1532 1533 // When we've copied the Allocation to a Java array, how do we 1534 // further process the elements of that array? 1535 enum MapFromAllocation { 1536 MapFromAllocationTrivial, // no further processing 1537 MapFromAllocationPositive, // need to ensure elements are positive (range check) 1538 MapFromAllocationBoolean, // need to convert elements from byte to boolean 1539 MapFromAllocationPromote // need to zero extend elements 1540 }; 1541 1542 // Return Java expression that maps from an Allocation element to a Java non-vector result. 1543 // 1544 // MFA = mapping kind 1545 // ArrayElementTypeName = type of InVal (having been copied out of Allocation to Java array) 1546 // ReflectedScalarTypeName = type of mapped value 1547 // InVal = input value that must be mapped 1548 // 1549 std::string genReduceResultMapping(MapFromAllocation MFA, 1550 const std::string &ArrayElementTypeName, 1551 const std::string &ReflectedScalarTypeName, 1552 const char *InVal) { 1553 switch (MFA) { 1554 default: 1555 slangAssert(!"Unknown MapFromAllocation"); 1556 // and fall through 1557 case MapFromAllocationPositive: // range checking must be done separately 1558 case MapFromAllocationTrivial: 1559 return InVal; 1560 case MapFromAllocationBoolean: 1561 return std::string(InVal) + std::string(" != 0"); 1562 case MapFromAllocationPromote: 1563 return ZeroExtendValue(InVal, 1564 ArrayElementTypeName, 1565 ReflectedScalarTypeName); 1566 } 1567 } 1568 1569 // Return Java expression that maps from an Allocation element to a Java vector result. 1570 // 1571 // MFA = mapping kind 1572 // ArrayElementTypeName = type of InVal (having been copied out of Allocation to Java array) 1573 // ReflectedScalarTypeName = type of mapped value 1574 // VectorTypeName = type of vector 1575 // VectorElementCount = number of elements in the vector 1576 // InArray = input array containing vector elements 1577 // InIdx = index of first vector element within InArray (or nullptr, if 0) 1578 // 1579 std::string genReduceResultVectorMapping(MapFromAllocation MFA, 1580 const std::string &ArrayElementTypeName, 1581 const std::string &ReflectedScalarTypeName, 1582 const std::string &VectorTypeName, 1583 unsigned VectorElementCount, 1584 const char *InArray, const char *InIdx = nullptr) { 1585 std::string result = "new " + VectorTypeName + "("; 1586 for (unsigned VectorElementIdx = 0; VectorElementIdx < VectorElementCount; ++VectorElementIdx) { 1587 if (VectorElementIdx) 1588 result += ", "; 1589 1590 std::string ArrayElementName = std::string(InArray) + "["; 1591 if (InIdx) 1592 ArrayElementName += std::string(InIdx) + "+"; 1593 ArrayElementName += std::to_string(VectorElementIdx) + "]"; 1594 1595 result += genReduceResultMapping(MFA, ArrayElementTypeName, ReflectedScalarTypeName, 1596 ArrayElementName.c_str()); 1597 } 1598 result += ")"; 1599 return result; 1600 } 1601 1602 void genReduceResultRangeCheck(GeneratedFile &Out, const char *InVal) { 1603 Out.indent() << "if (" << InVal << " < 0)\n"; 1604 Out.indent() << " throw new RSRuntimeException(\"Result is not representible in Java\");\n"; 1605 } 1606 1607 } // end anonymous namespace 1608 1609 void RSReflectionJava::genExportReduceResultType(const RSExportType *ResultType) { 1610 if (!exportableReduce(ResultType)) 1611 return; 1612 1613 const std::string ClassName = GetReduceResultTypeName(ResultType); 1614 const std::string GetMethodReturnTypeName = GetTypeName(ResultType); 1615 mOut.indent() << "// To obtain the result, invoke get(), which blocks\n"; 1616 mOut.indent() << "// until the asynchronously-launched operation has completed.\n"; 1617 mOut.indent() << "public static class " << ClassName; 1618 mOut.startBlock(); 1619 startFunction(AM_Public, false, GetMethodReturnTypeName.c_str(), "get", 0); 1620 1621 RSReflectionTypeData TypeData; 1622 ResultType->convertToRTD(&TypeData); 1623 1624 const std::string UnbracketedResultTypeName = 1625 GetTypeName(ResultType, TypeNameDefault & ~TypeNameWithConstantArrayBrackets); 1626 const std::string ReflectedScalarTypeName = TypeData.type->java_name; 1627 // Note: MATRIX* types do not have a java_array_element_name 1628 const std::string ArrayElementTypeName = 1629 TypeData.type->java_array_element_name 1630 ? std::string(TypeData.type->java_array_element_name) 1631 : ReflectedScalarTypeName; 1632 1633 MapFromAllocation MFA = MapFromAllocationTrivial; 1634 if (std::string(TypeData.type->rs_type) == "UNSIGNED_64") 1635 MFA = MapFromAllocationPositive; 1636 else if (ReflectedScalarTypeName == "boolean") 1637 MFA = MapFromAllocationBoolean; 1638 else if (ReflectedScalarTypeName != ArrayElementTypeName) 1639 MFA = MapFromAllocationPromote; 1640 1641 mOut.indent() << "if (!mGotResult)"; 1642 mOut.startBlock(); 1643 1644 if (TypeData.vecSize == 1) { // result type is non-vector 1645 // <ArrayElementType>[] outArray = new <ArrayElementType>[1]; 1646 // mOut.copyTo(outArray); 1647 mOut.indent() << ArrayElementTypeName << "[] outArray = new " << ArrayElementTypeName 1648 << "[" << std::max(TypeData.arraySize, 1U) << "];\n"; 1649 mOut.indent() << "mOut.copyTo(outArray);\n"; 1650 if (TypeData.arraySize == 0) { // result type is non-array non-vector 1651 // mResult = outArray[0]; // but there are several special cases 1652 if (MFA == MapFromAllocationPositive) 1653 genReduceResultRangeCheck(mOut, "outArray[0]"); 1654 mOut.indent() << "mResult = " 1655 << genReduceResultMapping(MFA, ArrayElementTypeName, ReflectedScalarTypeName, 1656 "outArray[0]") 1657 << ";\n"; 1658 } else { // result type is array of non-vector 1659 if (MFA == MapFromAllocationTrivial) { 1660 // mResult = outArray; 1661 mOut.indent() << "mResult = outArray;\n"; 1662 } else { 1663 // <ResultType> result = new <UnbracketedResultType>[<ArrayElementCount>]; 1664 // for (unsigned Idx = 0; Idx < <ArrayElementCount>; ++Idx) 1665 // result[Idx] = <Transform>(outArray[Idx]); 1666 // mResult = result; // but there are several special cases 1667 if (MFA != MapFromAllocationPositive) { 1668 mOut.indent() << GetTypeName(ResultType) << " result = new " 1669 << UnbracketedResultTypeName 1670 << "[" << TypeData.arraySize << "];\n"; 1671 } 1672 mOut.indent() << "for (int Idx = 0; Idx < " << TypeData.arraySize << "; ++Idx)"; 1673 mOut.startBlock(); 1674 if (MFA == MapFromAllocationPositive) { 1675 genReduceResultRangeCheck(mOut, "outArray[Idx]"); 1676 } else { 1677 mOut.indent() << "result[Idx] = " 1678 << genReduceResultMapping(MFA, ArrayElementTypeName, ReflectedScalarTypeName, 1679 "outArray[Idx]") 1680 << ";\n"; 1681 } 1682 mOut.endBlock(); 1683 mOut.indent() << "mResult = " << (MFA == MapFromAllocationPositive ? "outArray" : "result") << ";\n"; 1684 } 1685 } 1686 } else { // result type is vector or array of vector 1687 // <ArrayElementType>[] outArray = new <ArrayElementType>[<VectorElementCount> * <ArrayElementCount>]; 1688 // mOut.copyTo(outArray); 1689 const unsigned VectorElementCount = TypeData.vecSize; 1690 const unsigned OutArrayElementCount = VectorElementCount * std::max(TypeData.arraySize, 1U); 1691 mOut.indent() << ArrayElementTypeName << "[] outArray = new " << ArrayElementTypeName 1692 << "[" << OutArrayElementCount << "];\n"; 1693 mOut.indent() << "mOut.copyTo(outArray);\n"; 1694 if (MFA == MapFromAllocationPositive) { 1695 mOut.indent() << "for (int Idx = 0; Idx < " << OutArrayElementCount << "; ++Idx)"; 1696 mOut.startBlock(); 1697 genReduceResultRangeCheck(mOut, "outArray[Idx]"); 1698 mOut.endBlock(); 1699 } 1700 if (TypeData.arraySize == 0) { // result type is vector 1701 // mResult = new <ResultType>(outArray[0], outArray[1] ...); // but there are several special cases 1702 mOut.indent() << "mResult = " 1703 << genReduceResultVectorMapping(MFA, 1704 ArrayElementTypeName, ReflectedScalarTypeName, 1705 GetTypeName(ResultType), VectorElementCount, 1706 "outArray") 1707 << ";\n"; 1708 } else { // result type is array of vector 1709 // <ResultType> result = new <UnbracketedResultType>[<ArrayElementCount>]; 1710 // for (unsigned Idx = 0; Idx < <ArrayElementCount>; ++Idx) 1711 // result[Idx] = new <UnbracketedResultType>(outArray[<ArrayElementCount>*Idx+0], 1712 // outArray[<ArrayElementCount>*Idx+1]...); 1713 // mResult = result; // but there are several special cases 1714 mOut.indent() << GetTypeName(ResultType) << " result = new " 1715 << UnbracketedResultTypeName 1716 << "[" << TypeData.arraySize << "];\n"; 1717 mOut.indent() << "for (int Idx = 0; Idx < " << TypeData.arraySize << "; ++Idx)"; 1718 mOut.startBlock(); 1719 mOut.indent() << "result[Idx] = " 1720 << genReduceResultVectorMapping(MFA, 1721 ArrayElementTypeName, ReflectedScalarTypeName, 1722 UnbracketedResultTypeName, VectorElementCount, 1723 "outArray", (std::to_string(VectorElementCount) + "*Idx").c_str()) 1724 << ";\n"; 1725 mOut.endBlock(); 1726 mOut.indent() << "mResult = result;\n"; 1727 } 1728 } 1729 1730 mOut.indent() << "mOut.destroy();\n"; 1731 mOut.indent() << "mOut = null; // make Java object eligible for garbage collection\n"; 1732 mOut.indent() << "if (mTempIns != null)"; 1733 mOut.startBlock(); 1734 mOut.indent() << "for (Allocation tempIn : mTempIns)"; 1735 mOut.startBlock(); 1736 mOut.indent() << "tempIn.destroy();\n"; 1737 mOut.endBlock(); 1738 mOut.indent() << "mTempIns = null; // make Java objects eligible for garbage collection\n"; 1739 mOut.endBlock(); 1740 mOut.indent() << "mGotResult = true;\n"; 1741 mOut.endBlock(); 1742 1743 mOut.indent() << "return mResult;\n"; 1744 endFunction(); 1745 1746 startFunction(AM_Private, false, nullptr, ClassName, 1, "Allocation", "out"); 1747 // TODO: Generate allocation type check and size check? Or move 1748 // responsibility for instantiating the Allocation here, instead of 1749 // the reduce_* method? 1750 mOut.indent() << "mTempIns = null;\n"; 1751 mOut.indent() << "mOut = out;\n"; 1752 mOut.indent() << "mGotResult = false;\n"; 1753 endFunction(); 1754 mOut.indent() << "private Allocation[] mTempIns;\n"; 1755 mOut.indent() << "private Allocation mOut;\n"; 1756 // TODO: If result is reference type rather than primitive type, we 1757 // could omit mGotResult and use mResult==null to indicate that we 1758 // haven't obtained the result yet. 1759 mOut.indent() << "private boolean mGotResult;\n"; 1760 mOut.indent() << "private " << GetMethodReturnTypeName << " mResult;\n"; 1761 mOut.endBlock(); 1762 } 1763 1764 ////////////////////////////////////////////////////////////////////////////////////////////////////// 1765 1766 void RSReflectionJava::genTypeInstanceFromPointer(const RSExportType *ET) { 1767 if (ET->getClass() == RSExportType::ExportClassPointer) { 1768 // For pointer parameters to original forEach kernels. 1769 const RSExportPointerType *EPT = 1770 static_cast<const RSExportPointerType *>(ET); 1771 genTypeInstance(EPT->getPointeeType()); 1772 } else { 1773 // For handling pass-by-value kernel parameters. 1774 genTypeInstance(ET); 1775 } 1776 } 1777 1778 void RSReflectionJava::genTypeInstance(const RSExportType *ET) { 1779 switch (ET->getClass()) { 1780 case RSExportType::ExportClassPrimitive: 1781 case RSExportType::ExportClassVector: 1782 case RSExportType::ExportClassConstantArray: { 1783 std::string TypeName = ET->getElementName(); 1784 if (addTypeNameForElement(TypeName)) { 1785 mOut.indent() << RS_ELEM_PREFIX << TypeName << " = Element." << TypeName 1786 << "(rs);\n"; 1787 } 1788 break; 1789 } 1790 1791 case RSExportType::ExportClassRecord: { 1792 std::string ClassName = ET->getElementName(); 1793 if (addTypeNameForElement(ClassName)) { 1794 mOut.indent() << RS_ELEM_PREFIX << ClassName << " = " << ClassName 1795 << ".createElement(rs);\n"; 1796 } 1797 break; 1798 } 1799 1800 default: 1801 break; 1802 } 1803 } 1804 1805 void RSReflectionJava::genFieldPackerInstance(const RSExportType *ET) { 1806 switch (ET->getClass()) { 1807 case RSExportType::ExportClassPrimitive: 1808 case RSExportType::ExportClassVector: 1809 case RSExportType::ExportClassConstantArray: 1810 case RSExportType::ExportClassRecord: { 1811 std::string TypeName = ET->getElementName(); 1812 addTypeNameForFieldPacker(TypeName); 1813 break; 1814 } 1815 1816 default: 1817 break; 1818 } 1819 } 1820 1821 void RSReflectionJava::genTypeCheck(const RSExportType *ET, 1822 const char *VarName) { 1823 mOut.indent() << "// check " << VarName << "\n"; 1824 1825 if (ET->getClass() == RSExportType::ExportClassPointer) { 1826 const RSExportPointerType *EPT = 1827 static_cast<const RSExportPointerType *>(ET); 1828 ET = EPT->getPointeeType(); 1829 } 1830 1831 std::string TypeName; 1832 1833 switch (ET->getClass()) { 1834 case RSExportType::ExportClassPrimitive: 1835 case RSExportType::ExportClassVector: 1836 case RSExportType::ExportClassRecord: { 1837 TypeName = ET->getElementName(); 1838 break; 1839 } 1840 1841 default: 1842 break; 1843 } 1844 1845 if (!TypeName.empty()) { 1846 mOut.indent() << "if (!" << VarName 1847 << ".getType().getElement().isCompatible(" RS_ELEM_PREFIX 1848 << TypeName << ")) {\n"; 1849 mOut.indent() << " throw new RSRuntimeException(\"Type mismatch with " 1850 << TypeName << "!\");\n"; 1851 mOut.indent() << "}\n"; 1852 } 1853 } 1854 1855 void RSReflectionJava::genPrimitiveTypeExportVariable(const RSExportVar *EV) { 1856 slangAssert( 1857 (EV->getType()->getClass() == RSExportType::ExportClassPrimitive) && 1858 "Variable should be type of primitive here"); 1859 1860 const RSExportPrimitiveType *EPT = 1861 static_cast<const RSExportPrimitiveType *>(EV->getType()); 1862 std::string TypeName = GetTypeName(EPT); 1863 const std::string &VarName = EV->getName(); 1864 1865 genPrivateExportVariable(TypeName, EV->getName()); 1866 1867 if (EV->isConst()) { 1868 mOut.indent() << "public final static " << TypeName 1869 << " " RS_EXPORT_VAR_CONST_PREFIX << VarName << " = "; 1870 const clang::APValue &Val = EV->getInit(); 1871 genInitValue(Val, EPT->getType() == DataTypeBoolean); 1872 mOut << ";\n"; 1873 } else { 1874 // set_*() 1875 // This must remain synchronized, since multiple Dalvik threads may 1876 // be calling setters. 1877 startFunction(AM_PublicSynchronized, false, "void", "set_" + VarName, 1, 1878 TypeName.c_str(), "v"); 1879 if ((EPT->getElementSizeInBytes() < 4) || EV->isUnsigned()) { 1880 // We create/cache a per-type FieldPacker. This allows us to reuse the 1881 // validation logic (for catching negative inputs from Dalvik, as well 1882 // as inputs that are too large to be represented in the unsigned type). 1883 // Sub-integer types are also handled specially here, so that we don't 1884 // overwrite bytes accidentally. 1885 std::string ElemName = EPT->getElementName(); 1886 std::string FPName; 1887 FPName = RS_FP_PREFIX + ElemName; 1888 mOut.indent() << "if (" << FPName << "!= null) {\n"; 1889 mOut.increaseIndent(); 1890 mOut.indent() << FPName << ".reset();\n"; 1891 mOut.decreaseIndent(); 1892 mOut.indent() << "} else {\n"; 1893 mOut.increaseIndent(); 1894 mOut.indent() << FPName << " = new FieldPacker(" << EPT->getElementSizeInBytes() 1895 << ");\n"; 1896 mOut.decreaseIndent(); 1897 mOut.indent() << "}\n"; 1898 1899 genPackVarOfType(EPT, "v", FPName.c_str()); 1900 mOut.indent() << "setVar(" << RS_EXPORT_VAR_INDEX_PREFIX << VarName 1901 << ", " << FPName << ");\n"; 1902 } else { 1903 mOut.indent() << "setVar(" << RS_EXPORT_VAR_INDEX_PREFIX << VarName 1904 << ", v);\n"; 1905 } 1906 1907 // Dalvik update comes last, since the input may be invalid (and hence 1908 // throw an exception). 1909 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n"; 1910 1911 endFunction(); 1912 } 1913 1914 genGetExportVariable(TypeName, VarName); 1915 genGetFieldID(VarName); 1916 } 1917 1918 void RSReflectionJava::genInitValue(const clang::APValue &Val, bool asBool) { 1919 switch (Val.getKind()) { 1920 case clang::APValue::Int: { 1921 const llvm::APInt &api = Val.getInt(); 1922 if (asBool) { 1923 mOut << ((api.getSExtValue() == 0) ? "false" : "true"); 1924 } else { 1925 // TODO: Handle unsigned correctly 1926 mOut << api.getSExtValue(); 1927 if (api.getBitWidth() > 32) { 1928 mOut << "L"; 1929 } 1930 } 1931 break; 1932 } 1933 1934 case clang::APValue::Float: { 1935 const llvm::APFloat &apf = Val.getFloat(); 1936 llvm::SmallString<30> s; 1937 apf.toString(s); 1938 mOut << s.c_str(); 1939 if (&apf.getSemantics() == &llvm::APFloat::IEEEsingle) { 1940 if (s.count('.') == 0) { 1941 mOut << ".f"; 1942 } else { 1943 mOut << "f"; 1944 } 1945 } 1946 break; 1947 } 1948 1949 case clang::APValue::ComplexInt: 1950 case clang::APValue::ComplexFloat: 1951 case clang::APValue::LValue: 1952 case clang::APValue::Vector: { 1953 slangAssert(false && "Primitive type cannot have such kind of initializer"); 1954 break; 1955 } 1956 1957 default: { slangAssert(false && "Unknown kind of initializer"); } 1958 } 1959 } 1960 1961 void RSReflectionJava::genPointerTypeExportVariable(const RSExportVar *EV) { 1962 const RSExportType *ET = EV->getType(); 1963 const RSExportType *PointeeType; 1964 1965 slangAssert((ET->getClass() == RSExportType::ExportClassPointer) && 1966 "Variable should be type of pointer here"); 1967 1968 PointeeType = static_cast<const RSExportPointerType *>(ET)->getPointeeType(); 1969 std::string TypeName = GetTypeName(ET); 1970 const std::string &VarName = EV->getName(); 1971 1972 genPrivateExportVariable(TypeName, VarName); 1973 1974 // bind_*() 1975 startFunction(AM_Public, false, "void", "bind_" + VarName, 1, 1976 TypeName.c_str(), "v"); 1977 1978 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n"; 1979 mOut.indent() << "if (v == null) bindAllocation(null, " 1980 << RS_EXPORT_VAR_INDEX_PREFIX << VarName << ");\n"; 1981 1982 if (PointeeType->getClass() == RSExportType::ExportClassRecord) { 1983 mOut.indent() << "else bindAllocation(v.getAllocation(), " 1984 << RS_EXPORT_VAR_INDEX_PREFIX << VarName << ");\n"; 1985 } else { 1986 mOut.indent() << "else bindAllocation(v, " << RS_EXPORT_VAR_INDEX_PREFIX 1987 << VarName << ");\n"; 1988 } 1989 1990 endFunction(); 1991 1992 genGetExportVariable(TypeName, VarName); 1993 } 1994 1995 void RSReflectionJava::genVectorTypeExportVariable(const RSExportVar *EV) { 1996 slangAssert((EV->getType()->getClass() == RSExportType::ExportClassVector) && 1997 "Variable should be type of vector here"); 1998 1999 std::string TypeName = GetTypeName(EV->getType()); 2000 std::string VarName = EV->getName(); 2001 2002 genPrivateExportVariable(TypeName, VarName); 2003 genSetExportVariable(TypeName, EV, 1); 2004 genGetExportVariable(TypeName, VarName); 2005 genGetFieldID(VarName); 2006 } 2007 2008 void RSReflectionJava::genMatrixTypeExportVariable(const RSExportVar *EV) { 2009 slangAssert((EV->getType()->getClass() == RSExportType::ExportClassMatrix) && 2010 "Variable should be type of matrix here"); 2011 2012 const RSExportType *ET = EV->getType(); 2013 std::string TypeName = GetTypeName(ET); 2014 const std::string &VarName = EV->getName(); 2015 2016 genPrivateExportVariable(TypeName, VarName); 2017 2018 // set_*() 2019 if (!EV->isConst()) { 2020 const char *FieldPackerName = "fp"; 2021 startFunction(AM_PublicSynchronized, false, "void", "set_" + VarName, 1, 2022 TypeName.c_str(), "v"); 2023 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n"; 2024 2025 if (genCreateFieldPacker(ET, FieldPackerName, ReflectionState::NoVal32())) 2026 genPackVarOfType(ET, "v", FieldPackerName); 2027 mOut.indent() << "setVar(" RS_EXPORT_VAR_INDEX_PREFIX << VarName << ", " 2028 << FieldPackerName << ");\n"; 2029 2030 endFunction(); 2031 } 2032 2033 genGetExportVariable(TypeName, VarName); 2034 genGetFieldID(VarName); 2035 } 2036 2037 void 2038 RSReflectionJava::genConstantArrayTypeExportVariable(const RSExportVar *EV, 2039 ReflectionState::Val32 AllocSize32) { 2040 const RSExportType *const ET = EV->getType(); 2041 slangAssert( 2042 (ET->getClass() == RSExportType::ExportClassConstantArray) && 2043 "Variable should be type of constant array here"); 2044 2045 std::string TypeName = GetTypeName(EV->getType()); 2046 std::string VarName = EV->getName(); 2047 2048 genPrivateExportVariable(TypeName, VarName); 2049 genSetExportVariable(TypeName, EV, 2050 static_cast<const RSExportConstantArrayType *>(ET)->getNumElement(), 2051 AllocSize32); 2052 genGetExportVariable(TypeName, VarName); 2053 genGetFieldID(VarName); 2054 } 2055 2056 void RSReflectionJava::genRecordTypeExportVariable(const RSExportVar *EV, 2057 ReflectionState::Val32 AllocSize32) { 2058 slangAssert((EV->getType()->getClass() == RSExportType::ExportClassRecord) && 2059 "Variable should be type of struct here"); 2060 2061 std::string TypeName = GetTypeName(EV->getType()); 2062 std::string VarName = EV->getName(); 2063 2064 genPrivateExportVariable(TypeName, VarName); 2065 genSetExportVariable(TypeName, EV, 1, AllocSize32); 2066 genGetExportVariable(TypeName, VarName); 2067 genGetFieldID(VarName); 2068 } 2069 2070 void RSReflectionJava::genPrivateExportVariable(const std::string &TypeName, 2071 const std::string &VarName) { 2072 mOut.indent() << "private " << TypeName << " " << RS_EXPORT_VAR_PREFIX 2073 << VarName << ";\n"; 2074 } 2075 2076 // Dimension = array element count; otherwise, 1. 2077 void RSReflectionJava::genSetExportVariable(const std::string &TypeName, 2078 const RSExportVar *EV, 2079 unsigned Dimension, 2080 ReflectionState::Val32 AllocSize32) { 2081 if (!EV->isConst()) { 2082 const char *FieldPackerName = "fp"; 2083 const std::string &VarName = EV->getName(); 2084 const RSExportType *ET = EV->getType(); 2085 startFunction(AM_PublicSynchronized, false, "void", "set_" + VarName, 1, 2086 TypeName.c_str(), "v"); 2087 mOut.indent() << RS_EXPORT_VAR_PREFIX << VarName << " = v;\n"; 2088 2089 if (genCreateFieldPacker(ET, FieldPackerName, AllocSize32)) 2090 genPackVarOfType(ET, "v", FieldPackerName); 2091 2092 if (mRSContext->getTargetAPI() < SLANG_JB_TARGET_API) { 2093 // Legacy apps must use the old setVar() without Element/dim components. 2094 mOut.indent() << "setVar(" << RS_EXPORT_VAR_INDEX_PREFIX << VarName 2095 << ", " << FieldPackerName << ");\n"; 2096 } else { 2097 // We only have support for one-dimensional array reflection today, 2098 // but the entry point (i.e. setVar()) takes an array of dimensions. 2099 mOut.indent() << "int []__dimArr = new int[1];\n"; 2100 mOut.indent() << "__dimArr[0] = " << Dimension << ";\n"; 2101 mOut.indent() << "setVar(" << RS_EXPORT_VAR_INDEX_PREFIX << VarName 2102 << ", " << FieldPackerName << ", " << RS_ELEM_PREFIX 2103 << ET->getElementName() << ", __dimArr);\n"; 2104 } 2105 2106 endFunction(); 2107 } 2108 } 2109 2110 void RSReflectionJava::genGetExportVariable(const std::string &TypeName, 2111 const std::string &VarName) { 2112 startFunction(AM_Public, false, TypeName.c_str(), "get_" + VarName, 0); 2113 2114 mOut.indent() << "return " << RS_EXPORT_VAR_PREFIX << VarName << ";\n"; 2115 2116 endFunction(); 2117 } 2118 2119 void RSReflectionJava::genGetFieldID(const std::string &VarName) { 2120 // We only generate getFieldID_*() for non-Pointer (bind) types. 2121 if (mRSContext->getTargetAPI() >= SLANG_JB_MR1_TARGET_API) { 2122 startFunction(AM_Public, false, "Script.FieldID", "getFieldID_" + VarName, 2123 0); 2124 2125 mOut.indent() << "return createFieldID(" << RS_EXPORT_VAR_INDEX_PREFIX 2126 << VarName << ", null);\n"; 2127 2128 endFunction(); 2129 } 2130 } 2131 2132 /******************* Methods to generate script class /end *******************/ 2133 2134 bool RSReflectionJava::genCreateFieldPacker(const RSExportType *ET, 2135 const char *FieldPackerName, 2136 ReflectionState::Val32 AllocSize32) { 2137 size_t AllocSize = ET->getAllocSize(); 2138 slangAssert(!AllocSize32.first || ((AllocSize == 0) == (AllocSize32.second == 0))); 2139 if (AllocSize > 0) { 2140 if (!mCollecting) { 2141 mOut.indent() << "FieldPacker " << FieldPackerName << " = new FieldPacker("; 2142 genConditionalVal("", false, AllocSize, AllocSize32); 2143 mOut << ");\n"; 2144 } 2145 } 2146 else 2147 return false; 2148 return true; 2149 } 2150 2151 void RSReflectionJava::genPackVarOfType(const RSExportType *ET, 2152 const char *VarName, 2153 const char *FieldPackerName) { 2154 if (mCollecting) 2155 return; 2156 2157 switch (ET->getClass()) { 2158 case RSExportType::ExportClassPrimitive: 2159 case RSExportType::ExportClassVector: { 2160 mOut.indent() << FieldPackerName << "." 2161 << GetPackerAPIName( 2162 static_cast<const RSExportPrimitiveType *>(ET)) << "(" 2163 << VarName << ");\n"; 2164 break; 2165 } 2166 case RSExportType::ExportClassPointer: { 2167 // Must reflect as type Allocation in Java 2168 const RSExportType *PointeeType = 2169 static_cast<const RSExportPointerType *>(ET)->getPointeeType(); 2170 2171 if (PointeeType->getClass() != RSExportType::ExportClassRecord) { 2172 mOut.indent() << FieldPackerName << ".addI32(" << VarName 2173 << ".getPtr());\n"; 2174 } else { 2175 mOut.indent() << FieldPackerName << ".addI32(" << VarName 2176 << ".getAllocation().getPtr());\n"; 2177 } 2178 break; 2179 } 2180 case RSExportType::ExportClassMatrix: { 2181 mOut.indent() << FieldPackerName << ".addMatrix(" << VarName << ");\n"; 2182 break; 2183 } 2184 case RSExportType::ExportClassConstantArray: { 2185 const RSExportConstantArrayType *ECAT = 2186 static_cast<const RSExportConstantArrayType *>(ET); 2187 2188 // TODO(zonr): more elegant way. Currently, we obtain the unique index 2189 // variable (this method involves recursive call which means 2190 // we may have more than one level loop, therefore we can't 2191 // always use the same index variable name here) name given 2192 // in the for-loop from counting the '.' in @VarName. 2193 unsigned Level = 0; 2194 size_t LastDotPos = 0; 2195 std::string ElementVarName(VarName); 2196 2197 while (LastDotPos != std::string::npos) { 2198 LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1); 2199 Level++; 2200 } 2201 std::string IndexVarName("ct"); 2202 IndexVarName.append(llvm::utostr(Level)); 2203 2204 mOut.indent() << "for (int " << IndexVarName << " = 0; " << IndexVarName 2205 << " < " << ECAT->getNumElement() << "; " << IndexVarName << "++)"; 2206 mOut.startBlock(); 2207 2208 ElementVarName.append("[" + IndexVarName + "]"); 2209 genPackVarOfType(ECAT->getElementType(), ElementVarName.c_str(), 2210 FieldPackerName); 2211 2212 mOut.endBlock(); 2213 break; 2214 } 2215 case RSExportType::ExportClassRecord: { 2216 // Keep struct/field layout in sync with ReflectionState::declareRecord() 2217 2218 const RSExportRecordType *ERT = static_cast<const RSExportRecordType *>(ET); 2219 const ReflectionState::Record32 Record32 = mState->getRecord32(ERT); 2220 2221 auto emitSkip = [this, &FieldPackerName](size_t At, size_t Need, 2222 ReflectionState::Val32 Padding32) { 2223 if ((Need > At) || (Padding32.first && (Padding32.second != 0))) { 2224 size_t Padding = Need - At; 2225 mOut.indent() << FieldPackerName << ".skip("; 2226 if (!Padding32.first || (Padding == Padding32.second)) 2227 mOut << Padding; 2228 else { 2229 genCheck64Bit(true); 2230 mOut << " ? " << Padding << " : " << Padding32.second; 2231 } 2232 mOut << ");\n"; 2233 } 2234 }; 2235 2236 // Relative pos from now on in field packer 2237 unsigned Pos = 0; 2238 2239 unsigned FieldNum = 0; 2240 for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), 2241 E = ERT->fields_end(); 2242 I != E; I++, FieldNum++) { 2243 const RSExportRecordType::Field *F = *I; 2244 std::string FieldName; 2245 size_t FieldOffset = F->getOffsetInParent(); 2246 const RSExportType *T = F->getType(); 2247 size_t FieldStoreSize = T->getStoreSize(); 2248 size_t FieldAllocSize = T->getAllocSize(); 2249 2250 const auto Field32PreAndPostPadding = Record32.getFieldPreAndPostPadding(FieldNum); 2251 2252 if (VarName != nullptr) 2253 FieldName = VarName + ("." + F->getName()); 2254 else 2255 FieldName = F->getName(); 2256 2257 emitSkip(Pos, FieldOffset, Field32PreAndPostPadding.first /* pre */); 2258 2259 genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName); 2260 2261 // There is padding in the field type? 2262 emitSkip(FieldStoreSize, FieldAllocSize, Field32PreAndPostPadding.second /* post */); 2263 2264 Pos = FieldOffset + FieldAllocSize; 2265 } 2266 2267 // There maybe some padding after the struct 2268 emitSkip(Pos, ERT->getAllocSize(), Record32.getRecordPostPadding()); 2269 break; 2270 } 2271 default: { slangAssert(false && "Unknown class of type"); } 2272 } 2273 } 2274 2275 void RSReflectionJava::genAllocateVarOfType(const RSExportType *T, 2276 const std::string &VarName) { 2277 switch (T->getClass()) { 2278 case RSExportType::ExportClassPrimitive: { 2279 // Primitive type like int in Java has its own storage once it's declared. 2280 // 2281 // FIXME: Should we allocate storage for RS object? 2282 // if (static_cast<const RSExportPrimitiveType *>(T)->isRSObjectType()) 2283 // mOut.indent() << VarName << " = new " << GetTypeName(T) << "();\n"; 2284 break; 2285 } 2286 case RSExportType::ExportClassPointer: { 2287 // Pointer type is an instance of Allocation or a TypeClass whose value is 2288 // expected to be assigned by programmer later in Java program. Therefore 2289 // we don't reflect things like [VarName] = new Allocation(); 2290 mOut.indent() << VarName << " = null;\n"; 2291 break; 2292 } 2293 case RSExportType::ExportClassConstantArray: { 2294 const RSExportConstantArrayType *ECAT = 2295 static_cast<const RSExportConstantArrayType *>(T); 2296 const RSExportType *ElementType = ECAT->getElementType(); 2297 2298 mOut.indent() << VarName << " = new " << GetTypeName(ElementType) << "[" 2299 << ECAT->getNumElement() << "];\n"; 2300 2301 // Primitive type element doesn't need allocation code. 2302 if (ElementType->getClass() != RSExportType::ExportClassPrimitive) { 2303 mOut.indent() << "for (int $ct = 0; $ct < " << ECAT->getNumElement() 2304 << "; $ct++)"; 2305 mOut.startBlock(); 2306 2307 std::string ElementVarName(VarName); 2308 ElementVarName.append("[$ct]"); 2309 genAllocateVarOfType(ElementType, ElementVarName); 2310 2311 mOut.endBlock(); 2312 } 2313 break; 2314 } 2315 case RSExportType::ExportClassVector: 2316 case RSExportType::ExportClassMatrix: 2317 case RSExportType::ExportClassRecord: { 2318 mOut.indent() << VarName << " = new " << GetTypeName(T) << "();\n"; 2319 break; 2320 } 2321 } 2322 } 2323 2324 void RSReflectionJava::genNewItemBufferIfNull(const char *Index) { 2325 mOut.indent() << "if (" << RS_TYPE_ITEM_BUFFER_NAME " == null) "; 2326 mOut << RS_TYPE_ITEM_BUFFER_NAME << " = new " << RS_TYPE_ITEM_CLASS_NAME 2327 << "[getType().getX() /* count */];\n"; 2328 if (Index != nullptr) { 2329 mOut.indent() << "if (" << RS_TYPE_ITEM_BUFFER_NAME << "[" << Index 2330 << "] == null) "; 2331 mOut << RS_TYPE_ITEM_BUFFER_NAME << "[" << Index << "] = new " 2332 << RS_TYPE_ITEM_CLASS_NAME << "();\n"; 2333 } 2334 } 2335 2336 void RSReflectionJava::genNewItemBufferPackerIfNull() { 2337 mOut.indent() << "if (" << RS_TYPE_ITEM_BUFFER_PACKER_NAME << " == null) "; 2338 mOut << RS_TYPE_ITEM_BUFFER_PACKER_NAME " = new FieldPacker(" 2339 << mItemSizeof << " * getType().getX()/* count */);\n"; 2340 } 2341 2342 /********************** Methods to generate type class **********************/ 2343 bool RSReflectionJava::genTypeClass(const RSExportRecordType *ERT, 2344 std::string &ErrorMsg) { 2345 mState->declareRecord(ERT); 2346 if (mCollecting) 2347 return true; 2348 2349 std::string ClassName = ERT->getElementName(); 2350 std::string superClassName = getRSPackageName(); 2351 superClassName += RS_TYPE_CLASS_SUPER_CLASS_NAME; 2352 2353 if (!startClass(AM_Public, false, ClassName, superClassName.c_str(), 2354 ErrorMsg)) 2355 return false; 2356 2357 mGeneratedFileNames->push_back(ClassName); 2358 2359 mState->beginOutputClass(); 2360 2361 genTypeItemClass(ERT); 2362 2363 // Declare item buffer and item buffer packer 2364 mOut.indent() << "private " << RS_TYPE_ITEM_CLASS_NAME << " " 2365 << RS_TYPE_ITEM_BUFFER_NAME << "[];\n"; 2366 mOut.indent() << "private FieldPacker " << RS_TYPE_ITEM_BUFFER_PACKER_NAME 2367 << ";\n"; 2368 mOut.indent() << "private static java.lang.ref.WeakReference<Element> " 2369 << RS_TYPE_ELEMENT_REF_NAME 2370 << " = new java.lang.ref.WeakReference<Element>(null);\n"; 2371 2372 genTypeClassConstructor(ERT); 2373 genTypeClassCopyToArrayLocal(ERT); 2374 genTypeClassCopyToArray(ERT); 2375 genTypeClassItemSetter(ERT); 2376 genTypeClassItemGetter(ERT); 2377 genTypeClassComponentSetter(ERT); 2378 genTypeClassComponentGetter(ERT); 2379 genTypeClassCopyAll(ERT); 2380 if (!mRSContext->isCompatLib()) { 2381 // Skip the resize method if we are targeting a compatibility library. 2382 genTypeClassResize(); 2383 } 2384 2385 if (mState->endOutputClass()) 2386 genCompute64Bit(); 2387 2388 endClass(); 2389 2390 resetFieldIndex(); 2391 clearFieldIndexMap(); 2392 2393 return true; 2394 } 2395 2396 void RSReflectionJava::genTypeItemClass(const RSExportRecordType *ERT) { 2397 mOut.indent() << "static public class " RS_TYPE_ITEM_CLASS_NAME; 2398 mOut.startBlock(); 2399 2400 // Sizeof should not be exposed for 64-bit; it is not accurate 2401 if (mRSContext->getTargetAPI() < 21) { 2402 mOut.indent() << "public static final int sizeof = " << ERT->getAllocSize() 2403 << ";\n"; 2404 } 2405 2406 // Member elements 2407 mOut << "\n"; 2408 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 2409 FE = ERT->fields_end(); 2410 FI != FE; FI++) { 2411 mOut.indent() << GetTypeName((*FI)->getType()) << " " << (*FI)->getName() 2412 << ";\n"; 2413 } 2414 2415 // Constructor 2416 mOut << "\n"; 2417 mOut.indent() << RS_TYPE_ITEM_CLASS_NAME << "()"; 2418 mOut.startBlock(); 2419 2420 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 2421 FE = ERT->fields_end(); 2422 FI != FE; FI++) { 2423 const RSExportRecordType::Field *F = *FI; 2424 genAllocateVarOfType(F->getType(), F->getName()); 2425 } 2426 2427 // end Constructor 2428 mOut.endBlock(); 2429 2430 // end Item class 2431 mOut.endBlock(); 2432 } 2433 2434 void RSReflectionJava::genTypeClassConstructor(const RSExportRecordType *ERT) { 2435 const char *RenderScriptVar = "rs"; 2436 2437 startFunction(AM_Public, true, "Element", "createElement", 1, "RenderScript", 2438 RenderScriptVar); 2439 2440 // TODO(all): Fix weak-refs + multi-context issue. 2441 // mOut.indent() << "Element e = " << RS_TYPE_ELEMENT_REF_NAME 2442 // << ".get();\n"; 2443 // mOut.indent() << "if (e != null) return e;\n"; 2444 RSReflectionJavaElementBuilder builder("eb", ERT, RenderScriptVar, &mOut, 2445 mRSContext, this, mState); 2446 builder.generate(); 2447 2448 mOut.indent() << "return eb.create();\n"; 2449 // mOut.indent() << "e = eb.create();\n"; 2450 // mOut.indent() << RS_TYPE_ELEMENT_REF_NAME 2451 // << " = new java.lang.ref.WeakReference<Element>(e);\n"; 2452 // mOut.indent() << "return e;\n"; 2453 endFunction(); 2454 2455 // private with element 2456 startFunction(AM_Private, false, nullptr, getClassName(), 1, "RenderScript", 2457 RenderScriptVar); 2458 mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << " = null;\n"; 2459 mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << " = null;\n"; 2460 mOut.indent() << "mElement = createElement(" << RenderScriptVar << ");\n"; 2461 endFunction(); 2462 2463 // 1D without usage 2464 startFunction(AM_Public, false, nullptr, getClassName(), 2, "RenderScript", 2465 RenderScriptVar, "int", "count"); 2466 2467 mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << " = null;\n"; 2468 mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << " = null;\n"; 2469 mOut.indent() << "mElement = createElement(" << RenderScriptVar << ");\n"; 2470 // Call init() in super class 2471 mOut.indent() << "init(" << RenderScriptVar << ", count);\n"; 2472 endFunction(); 2473 2474 // 1D with usage 2475 startFunction(AM_Public, false, nullptr, getClassName(), 3, "RenderScript", 2476 RenderScriptVar, "int", "count", "int", "usages"); 2477 2478 mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << " = null;\n"; 2479 mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << " = null;\n"; 2480 mOut.indent() << "mElement = createElement(" << RenderScriptVar << ");\n"; 2481 // Call init() in super class 2482 mOut.indent() << "init(" << RenderScriptVar << ", count, usages);\n"; 2483 endFunction(); 2484 2485 // create1D with usage 2486 startFunction(AM_Public, true, getClassName().c_str(), "create1D", 3, 2487 "RenderScript", RenderScriptVar, "int", "dimX", "int", 2488 "usages"); 2489 mOut.indent() << getClassName() << " obj = new " << getClassName() << "(" 2490 << RenderScriptVar << ");\n"; 2491 mOut.indent() << "obj.mAllocation = Allocation.createSized(" 2492 "rs, obj.mElement, dimX, usages);\n"; 2493 mOut.indent() << "return obj;\n"; 2494 endFunction(); 2495 2496 // create1D without usage 2497 startFunction(AM_Public, true, getClassName().c_str(), "create1D", 2, 2498 "RenderScript", RenderScriptVar, "int", "dimX"); 2499 mOut.indent() << "return create1D(" << RenderScriptVar 2500 << ", dimX, Allocation.USAGE_SCRIPT);\n"; 2501 endFunction(); 2502 2503 // create2D without usage 2504 startFunction(AM_Public, true, getClassName().c_str(), "create2D", 3, 2505 "RenderScript", RenderScriptVar, "int", "dimX", "int", "dimY"); 2506 mOut.indent() << "return create2D(" << RenderScriptVar 2507 << ", dimX, dimY, Allocation.USAGE_SCRIPT);\n"; 2508 endFunction(); 2509 2510 // create2D with usage 2511 startFunction(AM_Public, true, getClassName().c_str(), "create2D", 4, 2512 "RenderScript", RenderScriptVar, "int", "dimX", "int", "dimY", 2513 "int", "usages"); 2514 2515 mOut.indent() << getClassName() << " obj = new " << getClassName() << "(" 2516 << RenderScriptVar << ");\n"; 2517 mOut.indent() << "Type.Builder b = new Type.Builder(rs, obj.mElement);\n"; 2518 mOut.indent() << "b.setX(dimX);\n"; 2519 mOut.indent() << "b.setY(dimY);\n"; 2520 mOut.indent() << "Type t = b.create();\n"; 2521 mOut.indent() << "obj.mAllocation = Allocation.createTyped(rs, t, usages);\n"; 2522 mOut.indent() << "return obj;\n"; 2523 endFunction(); 2524 2525 // createTypeBuilder 2526 startFunction(AM_Public, true, "Type.Builder", "createTypeBuilder", 1, 2527 "RenderScript", RenderScriptVar); 2528 mOut.indent() << "Element e = createElement(" << RenderScriptVar << ");\n"; 2529 mOut.indent() << "return new Type.Builder(rs, e);\n"; 2530 endFunction(); 2531 2532 // createCustom with usage 2533 startFunction(AM_Public, true, getClassName().c_str(), "createCustom", 3, 2534 "RenderScript", RenderScriptVar, "Type.Builder", "tb", "int", 2535 "usages"); 2536 mOut.indent() << getClassName() << " obj = new " << getClassName() << "(" 2537 << RenderScriptVar << ");\n"; 2538 mOut.indent() << "Type t = tb.create();\n"; 2539 mOut.indent() << "if (t.getElement() != obj.mElement) {\n"; 2540 mOut.indent() << " throw new RSIllegalArgumentException(" 2541 "\"Type.Builder did not match expected element type.\");\n"; 2542 mOut.indent() << "}\n"; 2543 mOut.indent() << "obj.mAllocation = Allocation.createTyped(rs, t, usages);\n"; 2544 mOut.indent() << "return obj;\n"; 2545 endFunction(); 2546 } 2547 2548 void RSReflectionJava::genTypeClassCopyToArray(const RSExportRecordType *ERT) { 2549 startFunction(AM_Private, false, "void", "copyToArray", 2, 2550 RS_TYPE_ITEM_CLASS_NAME, "i", "int", "index"); 2551 2552 genNewItemBufferPackerIfNull(); 2553 mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << ".reset(index * " 2554 << mItemSizeof << ");\n"; 2555 2556 mOut.indent() << "copyToArrayLocal(i, " RS_TYPE_ITEM_BUFFER_PACKER_NAME 2557 ");\n"; 2558 2559 endFunction(); 2560 } 2561 2562 void 2563 RSReflectionJava::genTypeClassCopyToArrayLocal(const RSExportRecordType *ERT) { 2564 startFunction(AM_Private, false, "void", "copyToArrayLocal", 2, 2565 RS_TYPE_ITEM_CLASS_NAME, "i", "FieldPacker", "fp"); 2566 2567 genPackVarOfType(ERT, "i", "fp"); 2568 2569 endFunction(); 2570 } 2571 2572 void RSReflectionJava::genTypeClassItemSetter(const RSExportRecordType *ERT) { 2573 startFunction(AM_PublicSynchronized, false, "void", "set", 3, 2574 RS_TYPE_ITEM_CLASS_NAME, "i", "int", "index", "boolean", 2575 "copyNow"); 2576 genNewItemBufferIfNull(nullptr); 2577 mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << "[index] = i;\n"; 2578 2579 mOut.indent() << "if (copyNow) "; 2580 mOut.startBlock(); 2581 2582 mOut.indent() << "copyToArray(i, index);\n"; 2583 mOut.indent() << "FieldPacker fp = new FieldPacker(" << mItemSizeof << ");\n"; 2584 mOut.indent() << "copyToArrayLocal(i, fp);\n"; 2585 mOut.indent() << "mAllocation.setFromFieldPacker(index, fp);\n"; 2586 2587 // End of if (copyNow) 2588 mOut.endBlock(); 2589 2590 endFunction(); 2591 } 2592 2593 void RSReflectionJava::genTypeClassItemGetter(const RSExportRecordType *ERT) { 2594 startFunction(AM_PublicSynchronized, false, RS_TYPE_ITEM_CLASS_NAME, "get", 1, 2595 "int", "index"); 2596 mOut.indent() << "if (" << RS_TYPE_ITEM_BUFFER_NAME 2597 << " == null) return null;\n"; 2598 mOut.indent() << "return " << RS_TYPE_ITEM_BUFFER_NAME << "[index];\n"; 2599 endFunction(); 2600 } 2601 2602 void 2603 RSReflectionJava::genTypeClassComponentSetter(const RSExportRecordType *ERT) { 2604 const ReflectionState::Record32 Record32 = mState->getRecord32(ERT); 2605 2606 unsigned FieldNum = 0; 2607 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 2608 FE = ERT->fields_end(); 2609 FI != FE; FI++, FieldNum++) { 2610 const RSExportRecordType::Field *F = *FI; 2611 size_t FieldOffset = F->getOffsetInParent(); 2612 size_t FieldStoreSize = F->getType()->getStoreSize(); 2613 std::pair<unsigned, unsigned> FieldIndex = getFieldIndex(F); 2614 2615 const auto Field32OffsetAndStoreSize = Record32.getFieldOffsetAndStoreSize(FieldNum); 2616 2617 startFunction(AM_PublicSynchronized, false, "void", "set_" + F->getName(), 2618 3, "int", "index", GetTypeName(F->getType()).c_str(), "v", 2619 "boolean", "copyNow"); 2620 genNewItemBufferPackerIfNull(); 2621 genNewItemBufferIfNull("index"); 2622 mOut.indent() << RS_TYPE_ITEM_BUFFER_NAME << "[index]." << F->getName() 2623 << " = v;\n"; 2624 2625 mOut.indent() << "if (copyNow) "; 2626 mOut.startBlock(); 2627 2628 mOut.indent() << RS_TYPE_ITEM_BUFFER_PACKER_NAME << ".reset(index * " 2629 << mItemSizeof; 2630 genConditionalVal(" + ", true, FieldOffset, Field32OffsetAndStoreSize.first /* offset */); 2631 mOut << ");\n"; 2632 2633 genPackVarOfType(F->getType(), "v", RS_TYPE_ITEM_BUFFER_PACKER_NAME); 2634 2635 mOut.indent() << "FieldPacker fp = new FieldPacker("; 2636 genConditionalVal("", false, FieldStoreSize, Field32OffsetAndStoreSize.second /* size */); 2637 mOut << ");\n"; 2638 2639 genPackVarOfType(F->getType(), "v", "fp"); 2640 mOut.indent() << "mAllocation.setFromFieldPacker(index, "; 2641 genConditionalVal("", false, FieldIndex.first, 2642 ReflectionState::Val32(Field32OffsetAndStoreSize.first.first, FieldIndex.second)); 2643 mOut << ", fp);\n"; 2644 2645 // End of if (copyNow) 2646 mOut.endBlock(); 2647 2648 endFunction(); 2649 } 2650 } 2651 2652 void 2653 RSReflectionJava::genTypeClassComponentGetter(const RSExportRecordType *ERT) { 2654 for (RSExportRecordType::const_field_iterator FI = ERT->fields_begin(), 2655 FE = ERT->fields_end(); 2656 FI != FE; FI++) { 2657 const RSExportRecordType::Field *F = *FI; 2658 startFunction(AM_PublicSynchronized, false, 2659 GetTypeName(F->getType()).c_str(), "get_" + F->getName(), 1, 2660 "int", "index"); 2661 mOut.indent() << "if (" RS_TYPE_ITEM_BUFFER_NAME << " == null) return " 2662 << GetTypeNullValue(F->getType()) << ";\n"; 2663 mOut.indent() << "return " RS_TYPE_ITEM_BUFFER_NAME << "[index]." 2664 << F->getName() << ";\n"; 2665 endFunction(); 2666 } 2667 } 2668 2669 void RSReflectionJava::genTypeClassCopyAll(const RSExportRecordType *ERT) { 2670 startFunction(AM_PublicSynchronized, false, "void", "copyAll", 0); 2671 2672 mOut.indent() << "for (int ct = 0; ct < " << RS_TYPE_ITEM_BUFFER_NAME 2673 << ".length; ct++)" 2674 << " copyToArray(" << RS_TYPE_ITEM_BUFFER_NAME 2675 << "[ct], ct);\n"; 2676 mOut.indent() << "mAllocation.setFromFieldPacker(0, " 2677 << RS_TYPE_ITEM_BUFFER_PACKER_NAME ");\n"; 2678 2679 endFunction(); 2680 } 2681 2682 void RSReflectionJava::genTypeClassResize() { 2683 startFunction(AM_PublicSynchronized, false, "void", "resize", 1, "int", 2684 "newSize"); 2685 2686 mOut.indent() << "if (mItemArray != null) "; 2687 mOut.startBlock(); 2688 mOut.indent() << "int oldSize = mItemArray.length;\n"; 2689 mOut.indent() << "int copySize = Math.min(oldSize, newSize);\n"; 2690 mOut.indent() << "if (newSize == oldSize) return;\n"; 2691 mOut.indent() << "Item ni[] = new Item[newSize];\n"; 2692 mOut.indent() << "System.arraycopy(mItemArray, 0, ni, 0, copySize);\n"; 2693 mOut.indent() << "mItemArray = ni;\n"; 2694 mOut.endBlock(); 2695 mOut.indent() << "mAllocation.resize(newSize);\n"; 2696 2697 mOut.indent() << "if (" RS_TYPE_ITEM_BUFFER_PACKER_NAME 2698 " != null) " RS_TYPE_ITEM_BUFFER_PACKER_NAME " = " 2699 "new FieldPacker(" << mItemSizeof << " * getType().getX()/* count */);\n"; 2700 2701 endFunction(); 2702 } 2703 2704 /******************** Methods to generate type class /end ********************/ 2705 2706 /********** Methods to create Element in Java of given record type ***********/ 2707 2708 RSReflectionJavaElementBuilder::RSReflectionJavaElementBuilder( 2709 const char *ElementBuilderName, const RSExportRecordType *ERT, 2710 const char *RenderScriptVar, GeneratedFile *Out, const RSContext *RSContext, 2711 RSReflectionJava *Reflection, ReflectionState *RState) 2712 : mElementBuilderName(ElementBuilderName), mERT(ERT), 2713 mRenderScriptVar(RenderScriptVar), mOut(Out), mPaddingFieldIndex(1), 2714 mRSContext(RSContext), mReflection(Reflection), mState(RState) { 2715 if (mRSContext->getTargetAPI() < SLANG_ICS_TARGET_API) { 2716 mPaddingPrefix = "#padding_"; 2717 } else { 2718 mPaddingPrefix = "#rs_padding_"; 2719 } 2720 } 2721 2722 void RSReflectionJavaElementBuilder::generate() { 2723 mOut->indent() << "Element.Builder " << mElementBuilderName 2724 << " = new Element.Builder(" << mRenderScriptVar << ");\n"; 2725 genAddElement(mERT, "", /* ArraySize = */ 0); 2726 } 2727 2728 void RSReflectionJavaElementBuilder::genAddElement(const RSExportType *ET, 2729 const std::string &VarName, 2730 unsigned ArraySize) { 2731 std::string ElementConstruct = GetBuiltinElementConstruct(ET); 2732 2733 if (ElementConstruct != "") { 2734 genAddStatementStart(); 2735 *mOut << ElementConstruct << "(" << mRenderScriptVar << ")"; 2736 genAddStatementEnd(VarName, ArraySize); 2737 } else { 2738 2739 switch (ET->getClass()) { 2740 case RSExportType::ExportClassPrimitive: { 2741 const RSExportPrimitiveType *EPT = 2742 static_cast<const RSExportPrimitiveType *>(ET); 2743 const char *DataTypeName = 2744 RSExportPrimitiveType::getRSReflectionType(EPT)->rs_type; 2745 genAddStatementStart(); 2746 *mOut << "Element.createUser(" << mRenderScriptVar 2747 << ", Element.DataType." << DataTypeName << ")"; 2748 genAddStatementEnd(VarName, ArraySize); 2749 break; 2750 } 2751 case RSExportType::ExportClassVector: { 2752 const RSExportVectorType *EVT = 2753 static_cast<const RSExportVectorType *>(ET); 2754 const char *DataTypeName = 2755 RSExportPrimitiveType::getRSReflectionType(EVT)->rs_type; 2756 genAddStatementStart(); 2757 *mOut << "Element.createVector(" << mRenderScriptVar 2758 << ", Element.DataType." << DataTypeName << ", " 2759 << EVT->getNumElement() << ")"; 2760 genAddStatementEnd(VarName, ArraySize); 2761 break; 2762 } 2763 case RSExportType::ExportClassPointer: 2764 // Pointer type variable should be resolved in 2765 // GetBuiltinElementConstruct() 2766 slangAssert(false && "??"); 2767 break; 2768 case RSExportType::ExportClassMatrix: 2769 // Matrix type variable should be resolved 2770 // in GetBuiltinElementConstruct() 2771 slangAssert(false && "??"); 2772 break; 2773 case RSExportType::ExportClassConstantArray: { 2774 const RSExportConstantArrayType *ECAT = 2775 static_cast<const RSExportConstantArrayType *>(ET); 2776 2777 const RSExportType *ElementType = ECAT->getElementType(); 2778 if (ElementType->getClass() != RSExportType::ExportClassRecord) { 2779 genAddElement(ECAT->getElementType(), VarName, ECAT->getNumElement()); 2780 } else { 2781 slangAssert((ArraySize == 0) && "Cannot reflect multidimensional array types"); 2782 ArraySize = ECAT->getNumElement(); 2783 genAddStatementStart(); 2784 *mOut << ElementType->getElementName() << ".createElement(" << mRenderScriptVar << ")"; 2785 genAddStatementEnd(VarName, ArraySize); 2786 } 2787 break; 2788 } 2789 case RSExportType::ExportClassRecord: { 2790 // Simalar to case of RSExportType::ExportClassRecord in genPackVarOfType. 2791 // 2792 // TODO(zonr): Generalize these two function such that there's no 2793 // duplicated codes. 2794 2795 // Keep struct/field layout in sync with ReflectionState::declareRecord() 2796 2797 const RSExportRecordType *ERT = 2798 static_cast<const RSExportRecordType *>(ET); 2799 const ReflectionState::Record32 Record32 = mState->getRecord32(ERT); 2800 2801 int Pos = 0; // relative pos from now on 2802 2803 unsigned FieldNum = 0; 2804 for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(), 2805 E = ERT->fields_end(); 2806 I != E; I++, FieldNum++) { 2807 const RSExportRecordType::Field *F = *I; 2808 size_t FieldOffset = F->getOffsetInParent(); 2809 const RSExportType *T = F->getType(); 2810 size_t FieldStoreSize = T->getStoreSize(); 2811 size_t FieldAllocSize = T->getAllocSize(); 2812 2813 const auto Field32PreAndPostPadding = Record32.getFieldPreAndPostPadding(FieldNum); 2814 2815 std::string FieldName; 2816 if (!VarName.empty()) 2817 FieldName = VarName + "." + F->getName(); 2818 else 2819 FieldName = F->getName(); 2820 2821 // Alignment 2822 genAddPadding(FieldOffset - Pos, Field32PreAndPostPadding.first /* pre */); 2823 2824 // eb.add(...) 2825 mReflection->addFieldIndexMapping(F); 2826 if (F->getType()->getClass() != RSExportType::ExportClassRecord) { 2827 genAddElement(F->getType(), FieldName, 0); 2828 } else { 2829 genAddStatementStart(); 2830 *mOut << F->getType()->getElementName() << ".createElement(" << mRenderScriptVar << ")"; 2831 genAddStatementEnd(FieldName, ArraySize); 2832 } 2833 2834 if (mRSContext->getTargetAPI() < SLANG_ICS_TARGET_API) { 2835 // There is padding within the field type. This is only necessary 2836 // for HC-targeted APIs. 2837 genAddPadding(FieldAllocSize - FieldStoreSize, Field32PreAndPostPadding.second /* post */); 2838 } 2839 2840 Pos = FieldOffset + FieldAllocSize; 2841 } 2842 2843 // There maybe some padding after the struct 2844 size_t RecordAllocSize = ERT->getAllocSize(); 2845 genAddPadding(RecordAllocSize - Pos, Record32.getRecordPostPadding()); 2846 break; 2847 } 2848 default: 2849 slangAssert(false && "Unknown class of type"); 2850 break; 2851 } 2852 } 2853 } 2854 2855 void RSReflectionJavaElementBuilder::genAddPadding(int PaddingSize, unsigned Which) { 2856 while (PaddingSize > 0) { 2857 const std::string &VarName = createPaddingField(); 2858 genAddStatementStart(); 2859 if (PaddingSize >= 4) { 2860 *mOut << "Element.U32(" << mRenderScriptVar << ")"; 2861 PaddingSize -= 4; 2862 } else if (PaddingSize >= 2) { 2863 *mOut << "Element.U16(" << mRenderScriptVar << ")"; 2864 PaddingSize -= 2; 2865 } else if (PaddingSize >= 1) { 2866 *mOut << "Element.U8(" << mRenderScriptVar << ")"; 2867 PaddingSize -= 1; 2868 } 2869 genAddStatementEnd(VarName, 0, Which); 2870 } 2871 } 2872 2873 void RSReflectionJavaElementBuilder::genAddPadding(int PaddingSize, 2874 ReflectionState::Val32 Field32PaddingSize) { 2875 if (!Field32PaddingSize.first || (PaddingSize == Field32PaddingSize.second)) { 2876 // Either we're ignoring the 32-bit case, or 32-bit and 64-bit 2877 // padding are the same. 2878 genAddPadding(PaddingSize, RSReflectionJava::FieldIndex | RSReflectionJava::Field32Index); 2879 return; 2880 } 2881 2882 // We cannot ignore the 32-bit case, and 32-bit and 64-bit padding differ. 2883 2884 if ((PaddingSize == 0) != (Field32PaddingSize.second == 0)) { 2885 // Only pad one of the two cases. 2886 2887 mOut->indent() << "if ("; 2888 if (PaddingSize == 0) 2889 *mOut << '!'; 2890 genCheck64Bit(PaddingSize == 0); 2891 *mOut << ')'; 2892 2893 mOut->startBlock(); 2894 if (PaddingSize != 0) 2895 genAddPadding(PaddingSize, RSReflectionJava::FieldIndex); 2896 else 2897 genAddPadding(Field32PaddingSize.second, RSReflectionJava::Field32Index); 2898 mOut->endBlock(); 2899 return; 2900 } 2901 2902 // Pad both of the two cases, differently. 2903 mOut->indent() << "if ("; 2904 genCheck64Bit(false); 2905 *mOut << ')'; 2906 mOut->startBlock(); 2907 genAddPadding(PaddingSize, RSReflectionJava::FieldIndex); 2908 mOut->endBlock(); 2909 mOut->indent() << "else"; 2910 mOut->startBlock(); 2911 genAddPadding(Field32PaddingSize.second, RSReflectionJava::Field32Index); 2912 mOut->endBlock(); 2913 } 2914 2915 void RSReflectionJavaElementBuilder::genAddStatementStart() { 2916 mOut->indent() << mElementBuilderName << ".add("; 2917 } 2918 2919 void 2920 RSReflectionJavaElementBuilder::genAddStatementEnd(const std::string &VarName, 2921 unsigned ArraySize, 2922 unsigned Which) { 2923 *mOut << ", \"" << VarName << "\""; 2924 if (ArraySize > 0) { 2925 *mOut << ", " << ArraySize; 2926 } 2927 *mOut << ");\n"; 2928 // TODO Review incFieldIndex. It's probably better to assign the numbers at 2929 // the start rather 2930 // than as we're generating the code. 2931 mReflection->incFieldIndex(Which); 2932 } 2933 2934 /******** Methods to create Element in Java of given record type /end ********/ 2935 2936 bool RSReflectionJava::reflect() { 2937 // Note that we may issue declareRecord() in many places during the 2938 // reflection process. 2939 mState->beginRecords(); 2940 2941 std::string ErrorMsg; 2942 if (!genScriptClass(mScriptClassName, ErrorMsg)) { 2943 std::cerr << "Failed to generate class " << mScriptClassName << " (" 2944 << ErrorMsg << ")\n"; 2945 return false; 2946 } 2947 2948 // class ScriptField_<TypeName> 2949 for (RSContext::const_export_type_iterator 2950 TI = mRSContext->export_types_begin(), 2951 TE = mRSContext->export_types_end(); 2952 TI != TE; TI++) { 2953 const RSExportType *ET = TI->getValue(); 2954 2955 if (ET->getClass() == RSExportType::ExportClassRecord) { 2956 const RSExportRecordType *ERT = 2957 static_cast<const RSExportRecordType *>(ET); 2958 2959 if (!ERT->isArtificial() && !genTypeClass(ERT, ErrorMsg)) { 2960 std::cerr << "Failed to generate type class for struct '" 2961 << ERT->getName() << "' (" << ErrorMsg << ")\n"; 2962 return false; 2963 } 2964 } 2965 } 2966 2967 mState->endRecords(); 2968 2969 return true; 2970 } 2971 2972 const char *RSReflectionJava::AccessModifierStr(AccessModifier AM) { 2973 switch (AM) { 2974 case AM_Public: 2975 return "public"; 2976 break; 2977 case AM_Protected: 2978 return "protected"; 2979 break; 2980 case AM_Private: 2981 return "private"; 2982 break; 2983 case AM_PublicSynchronized: 2984 return "public synchronized"; 2985 break; 2986 default: 2987 return ""; 2988 break; 2989 } 2990 } 2991 2992 bool RSReflectionJava::startClass(AccessModifier AM, bool IsStatic, 2993 const std::string &ClassName, 2994 const char *SuperClassName, 2995 std::string &ErrorMsg) { 2996 // Open file for class 2997 std::string FileName = ClassName + ".java"; 2998 if (!mOut.startFile(mOutputDirectory, FileName, mRSSourceFileName, 2999 mRSContext->getLicenseNote(), true, 3000 mRSContext->getVerbose())) { 3001 return false; 3002 } 3003 3004 // Package 3005 if (!mPackageName.empty()) { 3006 mOut << "package " << mPackageName << ";\n"; 3007 } 3008 mOut << "\n"; 3009 3010 // Imports 3011 // 3012 // The first few imports are only needed for divergent classes, but 3013 // at this point we don't know whether we are emitting a divergent 3014 // class. 3015 // 3016 if (!mRSContext->isCompatLib()) { 3017 mOut << "import android.os.Build;\n"; 3018 mOut << "import android.os.Process;\n"; 3019 mOut << "import java.lang.reflect.Field;\n"; 3020 } 3021 // (End of imports needed for divergent classes.) 3022 mOut << "import " << mRSPackageName << ".*;\n"; 3023 if (getEmbedBitcodeInJava()) { 3024 mOut << "import " << mPackageName << "." 3025 << RSSlangReflectUtils::JavaBitcodeClassNameFromRSFileName( 3026 mRSSourceFileName.c_str()) << ";\n"; 3027 } else { 3028 mOut << "import android.content.res.Resources;\n"; 3029 } 3030 mOut << "\n"; 3031 3032 // All reflected classes should be annotated as hidden, so that they won't 3033 // be exposed in SDK. 3034 mOut << "/**\n"; 3035 mOut << " * @hide\n"; 3036 mOut << " */\n"; 3037 3038 mOut << AccessModifierStr(AM) << ((IsStatic) ? " static" : "") << " class " 3039 << ClassName; 3040 if (SuperClassName != nullptr) 3041 mOut << " extends " << SuperClassName; 3042 3043 mOut.startBlock(); 3044 3045 mClassName = ClassName; 3046 3047 return true; 3048 } 3049 3050 void RSReflectionJava::endClass() { 3051 mOut.endBlock(); 3052 mOut.closeFile(); 3053 clear(); 3054 } 3055 3056 void RSReflectionJava::startTypeClass(const std::string &ClassName) { 3057 mOut.indent() << "public static class " << ClassName; 3058 mOut.startBlock(); 3059 } 3060 3061 void RSReflectionJava::endTypeClass() { mOut.endBlock(); } 3062 3063 void RSReflectionJava::startFunction(AccessModifier AM, bool IsStatic, 3064 const char *ReturnType, 3065 const std::string &FunctionName, int Argc, 3066 ...) { 3067 ArgTy Args; 3068 va_list vl; 3069 va_start(vl, Argc); 3070 3071 for (int i = 0; i < Argc; i++) { 3072 const char *ArgType = va_arg(vl, const char *); 3073 const char *ArgName = va_arg(vl, const char *); 3074 3075 Args.push_back(std::make_pair(ArgType, ArgName)); 3076 } 3077 va_end(vl); 3078 3079 startFunction(AM, IsStatic, ReturnType, FunctionName, Args); 3080 } 3081 3082 void RSReflectionJava::startFunction(AccessModifier AM, bool IsStatic, 3083 const char *ReturnType, 3084 const std::string &FunctionName, 3085 const ArgTy &Args) { 3086 mOut.indent() << AccessModifierStr(AM) << ((IsStatic) ? " static " : " ") 3087 << ((ReturnType) ? ReturnType : "") << " " << FunctionName 3088 << "("; 3089 3090 bool FirstArg = true; 3091 for (ArgTy::const_iterator I = Args.begin(), E = Args.end(); I != E; I++) { 3092 if (!FirstArg) 3093 mOut << ", "; 3094 else 3095 FirstArg = false; 3096 3097 mOut << I->first << " " << I->second; 3098 } 3099 3100 mOut << ")"; 3101 mOut.startBlock(); 3102 } 3103 3104 void RSReflectionJava::endFunction() { mOut.endBlock(); } 3105 3106 bool RSReflectionJava::addTypeNameForElement(const std::string &TypeName) { 3107 if (mTypesToCheck.find(TypeName) == mTypesToCheck.end()) { 3108 mTypesToCheck.insert(TypeName); 3109 return true; 3110 } else { 3111 return false; 3112 } 3113 } 3114 3115 bool RSReflectionJava::addTypeNameForFieldPacker(const std::string &TypeName) { 3116 if (mFieldPackerTypes.find(TypeName) == mFieldPackerTypes.end()) { 3117 mFieldPackerTypes.insert(TypeName); 3118 return true; 3119 } else { 3120 return false; 3121 } 3122 } 3123 3124 } // namespace slang 3125