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