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