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