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