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