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