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