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