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