slang_rs_reflection_cpp.cpp revision 7dd6da2077ad17ea59f4239f5275074bf5642859
1/*
2 * Copyright 2012, The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <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::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::sp<android::RSC::RS> rs," +
184          " const char *cacheDir, size_t cacheDirLength);");
185  write("virtual ~" + mClassName + "();");
186  write("");
187
188
189  // Reflect export variable
190  slot = 0;
191  for (RSContext::const_export_var_iterator I = mRSContext->export_vars_begin(),
192         E = mRSContext->export_vars_end(); I != E; I++, slot++) {
193    genExportVariable(*I);
194  }
195
196  // Reflect export for each functions
197  for (RSContext::const_export_foreach_iterator
198           I = mRSContext->export_foreach_begin(),
199           E = mRSContext->export_foreach_end(); I != E; I++) {
200    const RSExportForEach *ef = *I;
201    if (ef->isDummyRoot()) {
202      write("// No forEach_root(...)");
203      continue;
204    }
205
206    ArgTy Args;
207    stringstream ss;
208    ss << "void forEach_" << ef->getName() << "(";
209
210    if (ef->hasIn()) {
211      Args.push_back(std::make_pair(
212          "android::sp<const android::RSC::Allocation>", "ain"));
213    }
214
215    if (ef->hasOut() || ef->hasReturn()) {
216      Args.push_back(std::make_pair(
217          "android::sp<const android::RSC::Allocation>", "aout"));
218    }
219
220    const RSExportRecordType *ERT = ef->getParamPacketType();
221    if (ERT) {
222      for (RSExportForEach::const_param_iterator i = ef->params_begin(),
223           e = ef->params_end(); i != e; i++) {
224        RSReflectionTypeData rtd;
225        (*i)->getType()->convertToRTD(&rtd);
226        Args.push_back(std::make_pair(rtd.type->c_name, (*i)->getName()));
227      }
228    }
229    makeArgs(ss, Args);
230    ss << ");";
231    write(ss);
232  }
233
234
235  // Reflect export function
236  for (RSContext::const_export_func_iterator
237        I = mRSContext->export_funcs_begin(),
238        E = mRSContext->export_funcs_end(); I != E; I++) {
239    const RSExportFunc *ef = *I;
240
241    stringstream ss;
242    makeFunctionSignature(ss, false, ef);
243    write(ss);
244  }
245
246  decIndent();
247  write("};");
248  return true;
249}
250
251bool RSReflectionCpp::writeBC() {
252  FILE *pfin = fopen(mOutputBCFileName.c_str(), "rb");
253  if (pfin == NULL) {
254    fprintf(stderr, "Error: could not read file %s\n",
255            mOutputBCFileName.c_str());
256    return false;
257  }
258
259  unsigned char buf[16];
260  int read_length;
261  write("static const unsigned char __txt[] = {");
262  incIndent();
263  while ((read_length = fread(buf, 1, sizeof(buf), pfin)) > 0) {
264    string s;
265    for (int i = 0; i < read_length; i++) {
266      char buf2[16];
267      snprintf(buf2, sizeof(buf2), "0x%02x,", buf[i]);
268      s += buf2;
269    }
270    write(s);
271  }
272  decIndent();
273  write("};");
274  write("");
275  return true;
276}
277
278bool RSReflectionCpp::makeImpl(const std::string &baseClass) {
279  startFile(mClassName + ".cpp");
280
281  write("");
282  write("#include \"" + mClassName + ".h\"");
283  write("");
284
285  writeBC();
286
287  // Imports
288  //for(unsigned i = 0; i < (sizeof(Import) / sizeof(const char*)); i++)
289      //out() << "import " << Import[i] << ";" << std::endl;
290  //out() << std::endl;
291
292  write("\n");
293  stringstream ss;
294  ss << mClassName << "::" << mClassName
295     << "(android::sp<android::RSC::RS> rs, const char *cacheDir, "
296        "size_t cacheDirLength) :\n"
297        "        ScriptC(rs, __txt, sizeof(__txt), \""
298     << mClassName << "\", " << mClassName.length()
299     << ", cacheDir, cacheDirLength) {";
300  write(ss);
301  incIndent();
302  //...
303  decIndent();
304  write("}");
305  write("");
306
307  write(mClassName + "::~" + mClassName + "() {");
308  write("}");
309  write("");
310
311  // Reflect export for each functions
312  uint32_t slot = 0;
313  for (RSContext::const_export_foreach_iterator
314       I = mRSContext->export_foreach_begin(),
315       E = mRSContext->export_foreach_end(); I != E; I++, slot++) {
316    const RSExportForEach *ef = *I;
317    if (ef->isDummyRoot()) {
318      write("// No forEach_root(...)");
319      continue;
320    }
321
322    stringstream tmp;
323    ArgTy Args;
324    tmp << "void " << mClassName << "::forEach_" << ef->getName() << "(";
325
326    if (ef->hasIn()) {
327      Args.push_back(std::make_pair(
328          "android::sp<const android::RSC::Allocation>", "ain"));
329    }
330
331    if (ef->hasOut() || ef->hasReturn()) {
332      Args.push_back(std::make_pair(
333          "android::sp<const android::RSC::Allocation>", "aout"));
334    }
335
336    const RSExportRecordType *ERT = ef->getParamPacketType();
337    if (ERT) {
338      for (RSExportForEach::const_param_iterator i = ef->params_begin(),
339           e = ef->params_end(); i != e; i++) {
340        RSReflectionTypeData rtd;
341        (*i)->getType()->convertToRTD(&rtd);
342        Args.push_back(std::make_pair(rtd.type->c_name, (*i)->getName()));
343      }
344    }
345    makeArgs(tmp, Args);
346
347    tmp << ") {";
348    write(tmp);
349    tmp.str("");
350
351    std::string FieldPackerName = ef->getName() + "_fp";
352    if (ERT) {
353      if (genCreateFieldPacker(ERT, FieldPackerName.c_str())) {
354        genPackVarOfType(ERT, NULL, FieldPackerName.c_str());
355      }
356    }
357    tmp << "    forEach(" << slot << ", ";
358
359    if (ef->hasIn()) {
360      tmp << "ain, ";
361    } else {
362      tmp << "NULL, ";
363    }
364
365    if (ef->hasOut() || ef->hasReturn()) {
366      tmp << "aout, ";
367    } else {
368      tmp << "NULL, ";
369    }
370
371    tmp << "NULL, 0);";
372    write(tmp);
373
374    write("}");
375    write("");
376  }
377
378  slot = 0;
379  // Reflect export function
380  for (RSContext::const_export_func_iterator
381       I = mRSContext->export_funcs_begin(),
382       E = mRSContext->export_funcs_end(); I != E; I++) {
383    const RSExportFunc *ef = *I;
384
385    stringstream ss;
386    makeFunctionSignature(ss, true, ef);
387    write(ss);
388    ss.str("");
389    const RSExportRecordType *params = ef->getParamPacketType();
390    size_t param_len = 0;
391    if (params) {
392      param_len = RSExportType::GetTypeAllocSize(params);
393      if (genCreateFieldPacker(params, "__fp")) {
394        genPackVarOfType(params, NULL, "__fp");
395      }
396    }
397
398    ss.str("");
399    ss << "    invoke(" << slot;
400    if (params) {
401      ss << ", __fp.getData(), " << param_len << ");";
402    } else {
403      ss << ", NULL, 0);";
404    }
405    write(ss);
406
407    write("}");
408    write("");
409
410    slot++;
411  }
412
413  decIndent();
414  return true;
415}
416
417void RSReflectionCpp::genExportVariable(const RSExportVar *EV) {
418  const RSExportType *ET = EV->getType();
419
420  switch (ET->getClass()) {
421    case RSExportType::ExportClassPrimitive: {
422      genPrimitiveTypeExportVariable(EV);
423      break;
424    }
425    case RSExportType::ExportClassPointer: {
426      genPointerTypeExportVariable(EV);
427      break;
428    }
429    case RSExportType::ExportClassVector: {
430      genVectorTypeExportVariable(EV);
431      break;
432    }
433    case RSExportType::ExportClassMatrix: {
434      genMatrixTypeExportVariable(EV);
435      break;
436    }
437    case RSExportType::ExportClassConstantArray: {
438      genConstantArrayTypeExportVariable(EV);
439      break;
440    }
441    case RSExportType::ExportClassRecord: {
442      genRecordTypeExportVariable(EV);
443      break;
444    }
445    default: {
446      slangAssert(false && "Unknown class of type");
447    }
448  }
449}
450
451
452void RSReflectionCpp::genPrimitiveTypeExportVariable(const RSExportVar *EV) {
453  RSReflectionTypeData rtd;
454  EV->getType()->convertToRTD(&rtd);
455
456  if (!EV->isConst()) {
457    write(string("void set_") + EV->getName() + "(" + rtd.type->c_name +
458          " v) {");
459    stringstream tmp;
460    tmp << getNextExportVarSlot();
461    write(string("    setVar(") + tmp.str() + ", &v, sizeof(v));");
462    write(string("    __") + EV->getName() + " = v;");
463    write("}");
464  }
465  write(string(rtd.type->c_name) + " get_" + EV->getName() + "() const {");
466  if (EV->isConst()) {
467    const clang::APValue &val = EV->getInit();
468    bool isBool = !strcmp(rtd.type->c_name, "bool");
469    write(string("    return ") + genInitValue(val, isBool) + ";");
470  } else {
471    write(string("    return __") + EV->getName() + ";");
472  }
473  write("}");
474  write("");
475}
476
477void RSReflectionCpp::genPointerTypeExportVariable(const RSExportVar *EV) {
478  const RSExportType *ET = EV->getType();
479
480  slangAssert((ET->getClass() == RSExportType::ExportClassPointer) &&
481              "Variable should be type of pointer here");
482
483  std::string TypeName = GetTypeName(ET);
484  std::string VarName = EV->getName();
485
486  RSReflectionTypeData rtd;
487  EV->getType()->convertToRTD(&rtd);
488  uint32_t slot = getNextExportVarSlot();
489
490  if (!EV->isConst()) {
491    write(string("void bind_") + VarName + "(" + TypeName +
492          " v) {");
493    stringstream tmp;
494    tmp << slot;
495    write(string("    bindAllocation(v, ") + tmp.str() + ");");
496    write(string("    __") + VarName + " = v;");
497    write("}");
498  }
499  write(TypeName + " get_" + VarName + "() const {");
500  if (EV->isConst()) {
501    const clang::APValue &val = EV->getInit();
502    bool isBool = !strcmp(TypeName.c_str(), "bool");
503    write(string("    return ") + genInitValue(val, isBool) + ";");
504  } else {
505    write(string("    return __") + VarName + ";");
506  }
507  write("}");
508  write("");
509
510}
511
512void RSReflectionCpp::genVectorTypeExportVariable(const RSExportVar *EV) {
513  slangAssert(false);
514}
515
516void RSReflectionCpp::genMatrixTypeExportVariable(const RSExportVar *EV) {
517  slangAssert(false);
518}
519
520void RSReflectionCpp::genConstantArrayTypeExportVariable(
521    const RSExportVar *EV) {
522  slangAssert(false);
523}
524
525void RSReflectionCpp::genRecordTypeExportVariable(const RSExportVar *EV) {
526  slangAssert(false);
527}
528
529
530void RSReflectionCpp::makeFunctionSignature(
531    std::stringstream &ss,
532    bool isDefinition,
533    const RSExportFunc *ef) {
534  ss << "void ";
535  if (isDefinition) {
536    ss << mClassName << "::";
537  }
538  ss << "invoke_" << ef->getName() << "(";
539
540  if (ef->getParamPacketType()) {
541    bool FirstArg = true;
542    for (RSExportFunc::const_param_iterator i = ef->params_begin(),
543         e = ef->params_end(); i != e; i++) {
544      RSReflectionTypeData rtd;
545      (*i)->getType()->convertToRTD(&rtd);
546      if (!FirstArg) {
547        ss << ", ";
548      } else {
549        FirstArg = false;
550      }
551      ss << rtd.type->c_name << " " << (*i)->getName();
552    }
553  }
554
555  if (isDefinition) {
556    ss << ") {";
557  } else {
558    ss << ");";
559  }
560}
561
562void RSReflectionCpp::makeArgs(std::stringstream &ss, const ArgTy& Args) {
563  bool FirstArg = true;
564
565  for (ArgTy::const_iterator I = Args.begin(), E = Args.end(); I != E; I++) {
566    if (!FirstArg) {
567      ss << ", ";
568    } else {
569      FirstArg = false;
570    }
571
572    ss << I->first << " " << I->second;
573  }
574}
575
576bool RSReflectionCpp::genCreateFieldPacker(const RSExportType *ET,
577                                           const char *FieldPackerName) {
578  size_t AllocSize = RSExportType::GetTypeAllocSize(ET);
579
580  if (AllocSize > 0) {
581    std::stringstream ss;
582    ss << "    FieldPacker " << FieldPackerName << "("
583       << AllocSize << ");";
584    write(ss);
585    return true;
586  }
587
588  return false;
589}
590
591void RSReflectionCpp::genPackVarOfType(const RSExportType *ET,
592                                       const char *VarName,
593                                       const char *FieldPackerName) {
594  std::stringstream ss;
595  switch (ET->getClass()) {
596    case RSExportType::ExportClassPrimitive:
597    case RSExportType::ExportClassVector:
598    case RSExportType::ExportClassPointer:
599    case RSExportType::ExportClassMatrix: {
600      RSReflectionTypeData rtd;
601      ET->convertToRTD(&rtd);
602      ss << "    " << FieldPackerName << ".add(" << VarName << ");";
603      write(ss);
604      break;
605    }
606    case RSExportType::ExportClassConstantArray: {
607      /*const RSExportConstantArrayType *ECAT =
608          static_cast<const RSExportConstantArrayType *>(ET);
609
610      // TODO(zonr): more elegant way. Currently, we obtain the unique index
611      //             variable (this method involves recursive call which means
612      //             we may have more than one level loop, therefore we can't
613      //             always use the same index variable name here) name given
614      //             in the for-loop from counting the '.' in @VarName.
615      unsigned Level = 0;
616      size_t LastDotPos = 0;
617      std::string ElementVarName(VarName);
618
619      while (LastDotPos != std::string::npos) {
620        LastDotPos = ElementVarName.find_first_of('.', LastDotPos + 1);
621        Level++;
622      }
623      std::string IndexVarName("ct");
624      IndexVarName.append(llvm::utostr_32(Level));
625
626      C.indent() << "for (int " << IndexVarName << " = 0; " <<
627                          IndexVarName << " < " << ECAT->getSize() << "; " <<
628                          IndexVarName << "++)";
629      C.startBlock();
630
631      ElementVarName.append("[" + IndexVarName + "]");
632      genPackVarOfType(C, ECAT->getElementType(), ElementVarName.c_str(),
633                       FieldPackerName);
634
635      C.endBlock();*/
636      break;
637    }
638    case RSExportType::ExportClassRecord: {
639      const RSExportRecordType *ERT =
640          static_cast<const RSExportRecordType*>(ET);
641      // Relative pos from now on in field packer
642      unsigned Pos = 0;
643
644      for (RSExportRecordType::const_field_iterator I = ERT->fields_begin(),
645               E = ERT->fields_end();
646           I != E;
647           I++) {
648        const RSExportRecordType::Field *F = *I;
649        std::string FieldName;
650        size_t FieldOffset = F->getOffsetInParent();
651        size_t FieldStoreSize = RSExportType::GetTypeStoreSize(F->getType());
652        size_t FieldAllocSize = RSExportType::GetTypeAllocSize(F->getType());
653
654        if (VarName != NULL)
655          FieldName = VarName + ("." + F->getName());
656        else
657          FieldName = F->getName();
658
659        if (FieldOffset > Pos) {
660          ss.str("");
661          ss << "    " << FieldPackerName << ".skip("
662             << (FieldOffset - Pos) << ");";
663          write(ss);
664        }
665
666        genPackVarOfType(F->getType(), FieldName.c_str(), FieldPackerName);
667
668        // There is padding in the field type
669        if (FieldAllocSize > FieldStoreSize) {
670          ss.str("");
671          ss << "    " << FieldPackerName << ".skip("
672             << (FieldAllocSize - FieldStoreSize) << ");";
673          write(ss);
674        }
675
676        Pos = FieldOffset + FieldAllocSize;
677      }
678
679      // There maybe some padding after the struct
680      if (RSExportType::GetTypeAllocSize(ERT) > Pos) {
681        ss.str("");
682        ss << "    " << FieldPackerName << ".skip("
683           << RSExportType::GetTypeAllocSize(ERT) - Pos << ");";
684        write(ss);
685      }
686      break;
687    }
688    default: {
689      slangAssert(false && "Unknown class of type");
690    }
691  }
692}
693
694}  // namespace slang
695