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