Handle big bitcode files.
Split the bitcode file into segments due to Java method size limitation.
Change-Id: I4c171c40a45067da63098deb2408449dab38b041
diff --git a/slang_rs_reflect_utils.cpp b/slang_rs_reflect_utils.cpp
index b718913..1c7cc4d 100644
--- a/slang_rs_reflect_utils.cpp
+++ b/slang_rs_reflect_utils.cpp
@@ -3,7 +3,6 @@
#include <cstdlib>
#include <cstdio>
#include <cstring>
-#include <fstream>
#include <sys/stat.h>
#include <sys/types.h>
@@ -13,9 +12,9 @@
using std::string;
string RSSlangReflectUtils::ComputePackagedPath(
- const std::string& prefixPath, const std::string& packageName) {
+ const char* prefixPath, const char* packageName) {
string packaged_path(prefixPath);
- if (!prefixPath.empty() && (prefixPath[prefixPath.length() - 1] != '/')) {
+ if (!packaged_path.empty() && (packaged_path[packaged_path.length() - 1] != '/')) {
packaged_path += "/";
}
size_t s = packaged_path.length();
@@ -103,21 +102,146 @@
return true;
}
-bool RSSlangReflectUtils::EncodeBitcodeToJavaFile(
- const char* rsFileName, const char* inputBCFileName,
- const std::string& outputPath, const std::string& packageName) {
+static bool GenerateAccessorHeader(
+ const RSSlangReflectUtils::BitCodeAccessorContext& context, FILE* pfout) {
+ fprintf(pfout, "/*\n");
+ fprintf(pfout, " * This file is auto-generated. DO NOT MODIFY!\n");
+ fprintf(pfout, " * The source RenderScript file: %s\n", context.rsFileName);
+ fprintf(pfout, " */\n\n");
+ fprintf(pfout, "package %s;\n\n", context.packageName);
- FILE* pfin = fopen(inputBCFileName, "rb");
+ // add imports here.
+
+ return true;
+}
+
+static bool GenerateAccessorMethodSignature(
+ const RSSlangReflectUtils::BitCodeAccessorContext& context, FILE* pfout) {
+ // the prototype of the accessor method
+ fprintf(pfout, " // return byte array representation of the bitcode.\n");
+ fprintf(pfout, " public static byte[] getBitCode() {\n");
+ return true;
+}
+
+// Java method size must not exceed 64k,
+// so we have to split the bitcode into multiple segments.
+static bool GenerateSegmentMethod(
+ const char* buff, int blen, int seg_num, FILE* pfout) {
+
+ fprintf(pfout, " private static byte[] getSegment_%d() {\n", seg_num);
+ fprintf(pfout, " byte[] data = {\n");
+
+ const static int LINE_BYTE_NUM = 16;
+ char out_line[LINE_BYTE_NUM*6 + 10];
+ const char* out_line_end = out_line + sizeof(out_line);
+ char* p = out_line;
+
+ int write_length = 0;
+ while (write_length < blen) {
+ p += snprintf(p, out_line_end - p, " %4d,", (int)buff[write_length]);
+ ++write_length;
+ if (((write_length % LINE_BYTE_NUM) == 0)
+ || (write_length == blen)) {
+ fprintf(pfout, " ");
+ fprintf(pfout, out_line);
+ fprintf(pfout, "\n");
+ p = out_line;
+ }
+ }
+
+ fprintf(pfout, " };\n");
+ fprintf(pfout, " return data;\n");
+ fprintf(pfout, " }\n\n");
+
+ return true;
+}
+
+static bool GenerateJavaCodeAccessorMethod(
+ const RSSlangReflectUtils::BitCodeAccessorContext& context, FILE* pfout) {
+ FILE* pfin = fopen(context.bcFileName, "rb");
if (pfin == NULL) {
+ fprintf(stderr, "Error: could not read file %s\n", context.bcFileName);
return false;
}
- string output_path = ComputePackagedPath(outputPath, packageName);
- if (!mkdir_p(output_path.c_str())) {
- return false;
+ // start the accessor method
+ GenerateAccessorMethodSignature(context, pfout);
+ fprintf(pfout, " return getBitCodeInternal();\n");
+ // end the accessor method
+ fprintf(pfout, " };\n\n");
+
+ // output the data
+ // make sure the generated function for a segment won't break the Javac
+ // size limitation (64K).
+ const static int SEG_SIZE = 0x2000;
+ char* buff = new char[SEG_SIZE];
+ int read_length;
+ int seg_num = 0;
+ int total_length = 0;
+ while ((read_length = fread(buff, 1, SEG_SIZE, pfin)) > 0) {
+ GenerateSegmentMethod(buff, read_length, seg_num, pfout);
+ ++seg_num;
+ total_length += read_length;
+ }
+ delete []buff;
+ fclose(pfin);
+
+ // output the internal accessor method
+ fprintf(pfout, " private static int bitCodeLength = %d;\n\n", total_length);
+ fprintf(pfout, " private static byte[] getBitCodeInternal() {\n");
+ fprintf(pfout, " byte[] bc = new byte[bitCodeLength];\n");
+ fprintf(pfout, " int offset = 0;\n");
+ fprintf(pfout, " byte[] seg;\n");
+ for (int i = 0; i < seg_num; ++i) {
+ fprintf(pfout, " seg = getSegment_%d();\n", i);
+ fprintf(pfout, " System.arraycopy(seg, 0, bc, offset, seg.length);\n");
+ fprintf(pfout, " offset += seg.length;\n");
+ }
+ fprintf(pfout, " return bc;\n");
+ fprintf(pfout, " }\n\n");
+
+ return true;
+}
+
+static bool GenerateAccessorClass(
+ const RSSlangReflectUtils::BitCodeAccessorContext& context,
+ const char* clazz_name, FILE* pfout) {
+ // begin the class.
+ fprintf(pfout, "/**\n");
+ fprintf(pfout, " * @hide\n");
+ fprintf(pfout, " */\n");
+ fprintf(pfout, "public class %s {\n", clazz_name);
+ fprintf(pfout, "\n");
+
+ bool ret = true;
+ switch (context.bcStorage) {
+ case BCST_APK_RESOURCE:
+ break;
+ case BCST_JAVA_CODE:
+ ret = GenerateJavaCodeAccessorMethod(context, pfout);
+ break;
+ default:
+ ret = false;
}
- string clazz_name(JavaClassNameFromRSFileName(rsFileName));
+ // end the class.
+ fprintf(pfout, "}\n");
+
+ return ret;
+}
+
+
+bool RSSlangReflectUtils::GenerateBitCodeAccessor(
+ const BitCodeAccessorContext& context) {
+ string output_path = ComputePackagedPath(context.reflectPath,
+ context.packageName);
+ if (!mkdir_p(output_path.c_str())) {
+ fprintf(stderr, "Error: could not create dir %s\n",
+ output_path.c_str());
+ return false;
+ }
+
+ string clazz_name(JavaClassNameFromRSFileName(context.rsFileName));
clazz_name += "BitCode";
string filename(clazz_name);
filename += ".java";
@@ -128,63 +252,16 @@
printf("Generating %s ...\n", filename.c_str());
FILE* pfout = fopen(output_filename.c_str(), "w");
if (pfout == NULL) {
+ fprintf(stderr, "Error: could not write to file %s\n",
+ output_filename.c_str());
return false;
}
- // Output the header
- fprintf(pfout, "/*\n");
- fprintf(pfout, " * This file is auto-generated. DO NOT MODIFY!\n");
- fprintf(pfout, " * The source RenderScript file: %s\n", rsFileName);
- fprintf(pfout, " */\n\n");
- fprintf(pfout, "package %s;\n\n", packageName.c_str());
- fprintf(pfout, "/**\n");
- fprintf(pfout, " * @hide\n");
- fprintf(pfout, " */\n");
- fprintf(pfout, "public class %s {\n", clazz_name.c_str());
- fprintf(pfout, "\n");
- fprintf(pfout, " // return byte array representation of the bitcode file.\n");
- fprintf(pfout, " public static byte[] getBitCode() {\n");
- fprintf(pfout, " byte[] bc = new byte[data.length];\n");
- fprintf(pfout, " System.arraycopy(data, 0, bc, 0, data.length);\n");
- fprintf(pfout, " return bc;\n");
- fprintf(pfout, " }\n");
- fprintf(pfout, "\n");
- fprintf(pfout, " // byte array representation of the bitcode file.\n");
- fprintf(pfout, " private static final byte[] data = {\n");
+ bool ret = GenerateAccessorHeader(context, pfout)
+ && GenerateAccessorClass(context, clazz_name.c_str(), pfout);
- // output the data
- const static int BUFF_SIZE = 0x10000;
- char* buff = new char[BUFF_SIZE];
- int read_length;
- while ((read_length = fread(buff, 1, BUFF_SIZE, pfin)) > 0) {
- const static int LINE_BYTE_NUM = 16;
- char out_line[LINE_BYTE_NUM*6 + 10];
- const char* out_line_end = out_line + sizeof(out_line);
- char* p = out_line;
-
- int write_length = 0;
- while (write_length < read_length) {
- p += snprintf(p, out_line_end - p, " %4d,", (int)buff[write_length]);
- ++write_length;
- if (((write_length % LINE_BYTE_NUM) == 0)
- || (write_length == read_length)) {
- fprintf(pfout, " ");
- fprintf(pfout, out_line);
- fprintf(pfout, "\n");
- p = out_line;
- }
- }
-
- }
- delete []buff;
-
- // the rest of the java file.
- fprintf(pfout, " };\n");
- fprintf(pfout, "}\n");
-
- fclose(pfin);
fclose(pfout);
- return true;
+ return ret;
}
}