slang_rs_reflection_cpp.cpp revision ee9d7b0e0cb74a592cef718d72b589b64997bd21
1/*
2 * Copyright 2013, 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 <sys/stat.h>
18#include <stdio.h>
19#include <stdlib.h>
20
21#include <cstdarg>
22#include <cctype>
23
24#include <algorithm>
25#include <sstream>
26#include <string>
27#include <utility>
28
29#include "os_sep.h"
30#include "slang_rs_context.h"
31#include "slang_rs_export_var.h"
32#include "slang_rs_export_foreach.h"
33#include "slang_rs_export_func.h"
34#include "slang_rs_reflect_utils.h"
35#include "slang_version.h"
36#include "slang_utils.h"
37
38#include "slang_rs_reflection_cpp.h"
39
40using namespace std;
41
42namespace slang {
43
44#define RS_TYPE_ITEM_CLASS_NAME          "Item"
45
46static const char *GetMatrixTypeName(const RSExportMatrixType *EMT) {
47  static const char *MatrixTypeCNameMap[] = {
48    "rs_matrix2x2",
49    "rs_matrix3x3",
50    "rs_matrix4x4",
51  };
52  unsigned Dim = EMT->getDim();
53
54  if ((Dim - 2) < (sizeof(MatrixTypeCNameMap) / sizeof(const char*)))
55    return MatrixTypeCNameMap[ EMT->getDim() - 2 ];
56
57  slangAssert(false && "GetMatrixTypeName : Unsupported matrix dimension");
58  return NULL;
59}
60
61
62static std::string GetTypeName(const RSExportType *ET, bool Brackets = true) {
63  switch (ET->getClass()) {
64    case RSExportType::ExportClassPrimitive: {
65      return RSExportPrimitiveType::getRSReflectionType(
66          static_cast<const RSExportPrimitiveType*>(ET))->c_name;
67    }
68    case RSExportType::ExportClassPointer: {
69      const RSExportType *PointeeType =
70          static_cast<const RSExportPointerType*>(ET)->getPointeeType();
71
72      if (PointeeType->getClass() != RSExportType::ExportClassRecord)
73        return "android::RSC::sp<android::RSC::Allocation>";
74      else
75        return PointeeType->getElementName();
76    }
77    case RSExportType::ExportClassVector: {
78      const RSExportVectorType *EVT =
79          static_cast<const RSExportVectorType*>(ET);
80      std::stringstream VecName;
81      VecName << EVT->getRSReflectionType(EVT)->rs_c_vector_prefix
82              << EVT->getNumElement();
83      return VecName.str();
84    }
85    case RSExportType::ExportClassMatrix: {
86      return GetMatrixTypeName(static_cast<const RSExportMatrixType*>(ET));
87    }
88    case RSExportType::ExportClassConstantArray: {
89      // TODO: Fix this for C arrays!
90      const RSExportConstantArrayType* CAT =
91          static_cast<const RSExportConstantArrayType*>(ET);
92      std::string ElementTypeName = GetTypeName(CAT->getElementType());
93      if (Brackets) {
94        ElementTypeName.append("[]");
95      }
96      return ElementTypeName;
97    }
98    case RSExportType::ExportClassRecord: {
99      // TODO: Fix for C structs!
100      return ET->getElementName() + "." RS_TYPE_ITEM_CLASS_NAME;
101    }
102    default: {
103      slangAssert(false && "Unknown class of type");
104    }
105  }
106
107  return "";
108}
109
110
111RSReflectionCpp::RSReflectionCpp(const RSContext *con)
112    : RSReflectionBase(con) {
113  clear();
114}
115
116RSReflectionCpp::~RSReflectionCpp() {
117}
118
119bool RSReflectionCpp::reflect(const string &OutputPathBase,
120                              const string &InputFileName,
121                              const string &OutputBCFileName) {
122  mInputFileName = InputFileName;
123  mOutputPath = OutputPathBase;
124  mOutputBCFileName = OutputBCFileName;
125  mClassName = string("ScriptC_") + stripRS(InputFileName);
126
127  makeHeader("android::RSC::ScriptC");
128  std::vector< std::string > header(mText);
129  mText.clear();
130
131  makeImpl("android::RSC::ScriptC");
132  std::vector< std::string > cpp(mText);
133  mText.clear();
134
135
136  writeFile(mClassName + ".h", header);
137  writeFile(mClassName + ".cpp", cpp);
138
139
140  return true;
141}
142
143
144#define RS_TYPE_CLASS_NAME_PREFIX        "ScriptField_"
145
146
147
148bool RSReflectionCpp::makeHeader(const std::string &baseClass) {
149  startFile(mClassName + ".h");
150
151  write("");
152  write("#include \"RenderScript.h\"");
153  write("using namespace android::RSC;");
154  write("");
155
156  // Imports
157  //for(unsigned i = 0; i < (sizeof(Import) / sizeof(const char*)); i++)
158      //out() << "import " << Import[i] << ";" << std::endl;
159  //out() << std::endl;
160
161  if (!baseClass.empty()) {
162    write("class " + mClassName + " : public " + baseClass + " {");
163  } else {
164    write("class " + mClassName + " {");
165  }
166
167  write("private:");
168  uint32_t slot = 0;
169  incIndent();
170  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
171         E = mRSContext->export_vars_end(); I != E; I++, slot++) {
172    const RSExportVar *ev = *I;
173    RSReflectionTypeData rtd;
174    ev->getType()->convertToRTD(&rtd);
175    if (!ev->isConst()) {
176      write(GetTypeName(ev->getType()) + " __" + ev->getName() + ";");
177    }
178  }
179  decIndent();
180
181  write("public:");
182  incIndent();
183  write(mClassName + "(android::RSC::sp<android::RSC::RS> rs);");
184  write("virtual ~" + mClassName + "();");
185  write("");
186
187
188  // Reflect export variable
189  slot = 0;
190  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
191         E = mRSContext->export_vars_end(); I != E; I++, slot++) {
192    genExportVariable(*I);
193  }
194
195  // Reflect export for each functions
196  for (RSContext::const_export_foreach_iterator
197           I = mRSContext->export_foreach_begin(),
198           E = mRSContext->export_foreach_end(); I != E; I++) {
199    const RSExportForEach *ef = *I;
200    if (ef->isDummyRoot()) {
201      write("// No forEach_root(...)");
202      continue;
203    }
204
205    ArgTy Args;
206    stringstream ss;
207    ss << "void forEach_" << ef->getName() << "(";
208
209    if (ef->hasIn()) {
210      Args.push_back(std::make_pair(
211          "android::RSC::sp<const android::RSC::Allocation>", "ain"));
212    }
213
214    if (ef->hasOut() || ef->hasReturn()) {
215      Args.push_back(std::make_pair(
216          "android::RSC::sp<const android::RSC::Allocation>", "aout"));
217    }
218
219    const RSExportRecordType *ERT = ef->getParamPacketType();
220    if (ERT) {
221      for (RSExportForEach::const_param_iterator i = ef->params_begin(),
222           e = ef->params_end(); i != e; i++) {
223        RSReflectionTypeData rtd;
224        (*i)->getType()->convertToRTD(&rtd);
225        Args.push_back(std::make_pair(rtd.type->c_name, (*i)->getName()));
226      }
227    }
228    makeArgs(ss, Args);
229    ss << ");";
230    write(ss);
231  }
232
233
234  // Reflect export function
235  for (RSContext::const_export_func_iterator
236        I = mRSContext->export_funcs_begin(),
237        E = mRSContext->export_funcs_end(); I != E; I++) {
238    const RSExportFunc *ef = *I;
239
240    stringstream ss;
241    makeFunctionSignature(ss, false, ef);
242    write(ss);
243  }
244
245  decIndent();
246  write("};");
247  return true;
248}
249
250bool RSReflectionCpp::writeBC() {
251  FILE *pfin = fopen(mOutputBCFileName.c_str(), "rb");
252  if (pfin == NULL) {
253    fprintf(stderr, "Error: could not read file %s\n",
254            mOutputBCFileName.c_str());
255    return false;
256  }
257
258  unsigned char buf[16];
259  int read_length;
260  write("static const unsigned char __txt[] = {");
261  incIndent();
262  while ((read_length = fread(buf, 1, sizeof(buf), pfin)) > 0) {
263    string s;
264    for (int i = 0; i < read_length; i++) {
265      char buf2[16];
266      snprintf(buf2, sizeof(buf2), "0x%02x,", buf[i]);
267      s += buf2;
268    }
269    write(s);
270  }
271  decIndent();
272  write("};");
273  write("");
274  return true;
275}
276
277bool RSReflectionCpp::makeImpl(const std::string &baseClass) {
278  startFile(mClassName + ".cpp");
279
280  write("");
281  write("#include \"" + mClassName + ".h\"");
282  write("");
283
284  writeBC();
285
286  // Imports
287  //for(unsigned i = 0; i < (sizeof(Import) / sizeof(const char*)); i++)
288      //out() << "import " << Import[i] << ";" << std::endl;
289  //out() << std::endl;
290
291  write("\n");
292  stringstream ss;
293  const std::string &packageName = mRSContext->getReflectJavaPackageName();
294  ss << mClassName << "::" << mClassName
295     << "(android::RSC::sp<android::RSC::RS> rs):\n"
296        "        ScriptC(rs, __txt, sizeof(__txt), \""
297     << stripRS(mInputFileName) << "\", " << stripRS(mInputFileName).length()
298     << ", \"/data/data/" << packageName << "/app\", sizeof(\"" << packageName << "\")) {";
299  write(ss);
300  incIndent();
301  //...
302  decIndent();
303  write("}");
304  write("");
305
306  write(mClassName + "::~" + mClassName + "() {");
307  write("}");
308  write("");
309
310  // Reflect export for each functions
311  uint32_t slot = 0;
312  for (RSContext::const_export_foreach_iterator
313       I = mRSContext->export_foreach_begin(),
314       E = mRSContext->export_foreach_end(); I != E; I++, slot++) {
315    const RSExportForEach *ef = *I;
316    if (ef->isDummyRoot()) {
317      write("// No forEach_root(...)");
318      continue;
319    }
320
321    stringstream tmp;
322    ArgTy Args;
323    tmp << "void " << mClassName << "::forEach_" << ef->getName() << "(";
324
325    if (ef->hasIn()) {
326      Args.push_back(std::make_pair(
327          "android::RSC::sp<const android::RSC::Allocation>", "ain"));
328    }
329
330    if (ef->hasOut() || ef->hasReturn()) {
331      Args.push_back(std::make_pair(
332          "android::RSC::sp<const android::RSC::Allocation>", "aout"));
333    }
334
335    const RSExportRecordType *ERT = ef->getParamPacketType();
336    if (ERT) {
337      for (RSExportForEach::const_param_iterator i = ef->params_begin(),
338           e = ef->params_end(); i != e; i++) {
339        RSReflectionTypeData rtd;
340        (*i)->getType()->convertToRTD(&rtd);
341        Args.push_back(std::make_pair(rtd.type->c_name, (*i)->getName()));
342      }
343    }
344    makeArgs(tmp, Args);
345
346    tmp << ") {";
347    write(tmp);
348    tmp.str("");
349
350    std::string FieldPackerName = ef->getName() + "_fp";
351    if (ERT) {
352      if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
353        genPackVarOfType(ERT, NULL, FieldPackerName.c_str());
354      }
355    }
356    tmp << "    forEach(" << slot << ", ";
357
358    if (ef->hasIn()) {
359      tmp << "ain, ";
360    } else {
361      tmp << "NULL, ";
362    }
363
364    if (ef->hasOut() || ef->hasReturn()) {
365      tmp << "aout, ";
366    } else {
367      tmp << "NULL, ";
368    }
369
370    tmp << "NULL, 0);";
371    write(tmp);
372
373    write("}");
374    write("");
375  }
376
377  slot = 0;
378  // Reflect export function
379  for (RSContext::const_export_func_iterator
380       I = mRSContext->export_funcs_begin(),
381       E = mRSContext->export_funcs_end(); I != E; I++) {
382    const RSExportFunc *ef = *I;
383
384    stringstream ss;
385    makeFunctionSignature(ss, true, ef);
386    write(ss);
387    ss.str("");
388    const RSExportRecordType *params = ef->getParamPacketType();
389    size_t param_len = 0;
390    if (params) {
391      param_len = RSExportType::GetTypeAllocSize(params);
392      if (genCreateFieldPacker(params, "__fp")) {
393        genPackVarOfType(params, NULL, "__fp");
394      }
395    }
396
397    ss.str("");
398    ss << "    invoke(" << slot;
399    if (params) {
400      ss << ", __fp.getData(), " << param_len << ");";
401    } else {
402      ss << ", NULL, 0);";
403    }
404    write(ss);
405
406    write("}");
407    write("");
408
409    slot++;
410  }
411
412  decIndent();
413  return true;
414}
415
416void RSReflectionCpp::genExportVariable(const RSExportVar *EV) {
417  const RSExportType *ET = EV->getType();
418
419  switch (ET->getClass()) {
420    case RSExportType::ExportClassPrimitive: {
421      genPrimitiveTypeExportVariable(EV);
422      break;
423    }
424    case RSExportType::ExportClassPointer: {
425      genPointerTypeExportVariable(EV);
426      break;
427    }
428    case RSExportType::ExportClassVector: {
429      genVectorTypeExportVariable(EV);
430      break;
431    }
432    case RSExportType::ExportClassMatrix: {
433      genMatrixTypeExportVariable(EV);
434      break;
435    }
436    case RSExportType::ExportClassConstantArray: {
437      genConstantArrayTypeExportVariable(EV);
438      break;
439    }
440    case RSExportType::ExportClassRecord: {
441      genRecordTypeExportVariable(EV);
442      break;
443    }
444    default: {
445      slangAssert(false && "Unknown class of type");
446    }
447  }
448}
449
450
451void RSReflectionCpp::genPrimitiveTypeExportVariable(const RSExportVar *EV) {
452  RSReflectionTypeData rtd;
453  EV->getType()->convertToRTD(&rtd);
454
455  if (!EV->isConst()) {
456    write(string("void set_") + EV->getName() + "(" + rtd.type->c_name +
457          " v) {");
458    stringstream tmp;
459    tmp << getNextExportVarSlot();
460    write(string("    setVar(") + tmp.str() + ", &v, sizeof(v));");
461    write(string("    __") + EV->getName() + " = v;");
462    write("}");
463  }
464  write(string(rtd.type->c_name) + " get_" + EV->getName() + "() const {");
465  if (EV->isConst()) {
466    const clang::APValue &val = EV->getInit();
467    bool isBool = !strcmp(rtd.type->c_name, "bool");
468    write(string("    return ") + genInitValue(val, isBool) + ";");
469  } else {
470    write(string("    return __") + EV->getName() + ";");
471  }
472  write("}");
473  write("");
474}
475
476void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) {
477  const RSExportType *ET = EV->getType();
478
479  slangAssert((ET->getClass() == RSExportType::ExportClassPointer) &&
480              "Variable should be type of pointer here");
481
482  std::string TypeName = GetTypeName(ET);
483  std::string VarName = EV->getName();
484
485  RSReflectionTypeData rtd;
486  EV->getType()->convertToRTD(&rtd);
487  uint32_t slot = getNextExportVarSlot();
488
489  if (!EV->isConst()) {
490    write(string("void bind_") + VarName + "(" + TypeName +
491          " v) {");
492    stringstream tmp;
493    tmp << slot;
494    write(string("    bindAllocation(v, ") + tmp.str() + ");");
495    write(string("    __") + VarName + " = v;");
496    write("}");
497  }
498  write(TypeName + " get_" + VarName + "() const {");
499  if (EV->isConst()) {
500    const clang::APValue &val = EV->getInit();
501    bool isBool = !strcmp(TypeName.c_str(), "bool");
502    write(string("    return ") + genInitValue(val, isBool) + ";");
503  } else {
504    write(string("    return __") + VarName + ";");
505  }
506  write("}");
507  write("");
508
509}
510
511void RSReflectionCpp::genVectorTypeExportVariable(const RSExportVar *EV) {
512  slangAssert(false);
513}
514
515void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
516  slangAssert(false);
517}
518
519void RSReflectionCpp::genConstantArrayTypeExportVariable(
520    const RSExportVar *EV) {
521  slangAssert(false);
522}
523
524void RSReflectionCpp::genRecordTypeExportVariable(const RSExportVar *EV) {
525  slangAssert(false);
526}
527
528
529void RSReflectionCpp::makeFunctionSignature(
530    std::stringstream &ss,
531    bool isDefinition,
532    const RSExportFunc *ef) {
533  ss << "void ";
534  if (isDefinition) {
535    ss << mClassName << "::";
536  }
537  ss << "invoke_" << ef->getName() << "(";
538
539  if (ef->getParamPacketType()) {
540    bool FirstArg = true;
541    for (RSExportFunc::const_param_iterator i = ef->params_begin(),
542         e = ef->params_end(); i != e; i++) {
543      RSReflectionTypeData rtd;
544      (*i)->getType()->convertToRTD(&rtd);
545      if (!FirstArg) {
546        ss << ", ";
547      } else {
548        FirstArg = false;
549      }
550      ss << rtd.type->c_name << " " << (*i)->getName();
551    }
552  }
553
554  if (isDefinition) {
555    ss << ") {";
556  } else {
557    ss << ");";
558  }
559}
560
561void RSReflectionCpp::makeArgs(std::stringstream &ss, const ArgTy& Args) {
562  bool FirstArg = true;
563
564  for (ArgTy::const_iterator I = Args.begin(), E = Args.end(); I != E; I++) {
565    if (!FirstArg) {
566      ss << ", ";
567    } else {
568      FirstArg = false;
569    }
570
571    ss << I->first << " " << I->second;
572  }
573}
574
575bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET,
576                                           const char *FieldPackerName) {
577  size_t AllocSize = RSExportType::GetTypeAllocSize(ET);
578
579  if (AllocSize > 0) {
580    std::stringstream ss;
581    ss << "    FieldPacker " << FieldPackerName << "("
582       << AllocSize << ");";
583    write(ss);
584    return true;
585  }
586
587  return false;
588}
589
590void RSReflectionCpp::genPackVarOfType(const RSExportType *ET,
591                                       const char *VarName,
592                                       const char *FieldPackerName) {
593  std::stringstream ss;
594  switch (ET->getClass()) {
595    case RSExportType::ExportClassPrimitive:
596    case RSExportType::ExportClassVector:
597    case RSExportType::ExportClassPointer:
598    case RSExportType::ExportClassMatrix: {
599      RSReflectionTypeData rtd;
600      ET->convertToRTD(&rtd);
601      ss << "    " << FieldPackerName << ".add(" << VarName << ");";
602      write(ss);
603      break;
604    }
605    case RSExportType::ExportClassConstantArray: {
606      /*const RSExportConstantArrayType *ECAT =
607          static_cast<const RSExportConstantArrayType *>(ET);
608
609      // TODO(zonr): more elegant way. Currently, we obtain the unique index
610      //             variable (this method involves recursive call which means
611      //             we may have more than one level loop, therefore we can't
612      //             always use the same index variable name here) name given
613      //             in the for-loop from counting the '.' in @VarName.
614      unsigned Level = 0;
615      size_t LastDotPos = 0;
616      std::string ElementVarName(VarName);
617
618      while (LastDotPos != std::string::npos) {
619        LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1);
620        Level++;
621      }
622      std::string IndexVarName("ct");
623      IndexVarName.append(llvm::utostr_32(Level));
624
625      C.indent() << "for (int " << IndexVarName << " = 0; " <<
626                          IndexVarName << " < " << ECAT->getSize() << "; " <<
627                          IndexVarName << "++)";
628      C.startBlock();
629
630      ElementVarName.append("[" + IndexVarName + "]");
631      genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(),
632                       FieldPackerName);
633
634      C.endBlock();*/
635      break;
636    }
637    case RSExportType::ExportClassRecord: {
638      const RSExportRecordType *ERT =
639          static_cast<const RSExportRecordType*>(ET);
640      // Relative pos from now on in field packer
641      unsigned Pos = 0;
642
643      for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
644               E = ERT->fields_end();
645           I != E;
646           I++) {
647        const RSExportRecordType::Field *F = *I;
648        std::string FieldName;
649        size_t FieldOffset = F->getOffsetInParent();
650        size_t FieldStoreSize = RSExportType::GetTypeStoreSize(F->getType());
651        size_t FieldAllocSize = RSExportType::GetTypeAllocSize(F->getType());
652
653        if (VarName != NULL)
654          FieldName = VarName + ("." + F->getName());
655        else
656          FieldName = F->getName();
657
658        if (FieldOffset > Pos) {
659          ss.str("");
660          ss << "    " << FieldPackerName << ".skip("
661             << (FieldOffset - Pos) << ");";
662          write(ss);
663        }
664
665        genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
666
667        // There is padding in the field type
668        if (FieldAllocSize > FieldStoreSize) {
669          ss.str("");
670          ss << "    " << FieldPackerName << ".skip("
671             << (FieldAllocSize - FieldStoreSize) << ");";
672          write(ss);
673        }
674
675        Pos = FieldOffset + FieldAllocSize;
676      }
677
678      // There maybe some padding after the struct
679      if (RSExportType::GetTypeAllocSize(ERT) > Pos) {
680        ss.str("");
681        ss << "    " << FieldPackerName << ".skip("
682           << RSExportType::GetTypeAllocSize(ERT) - Pos << ");";
683        write(ss);
684      }
685      break;
686    }
687    default: {
688      slangAssert(false && "Unknown class of type");
689    }
690  }
691}
692
693}  // namespace slang
694