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