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