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