rsCpuExecutable.cpp revision ca451c3280b6265a9b79273b4bf89e121a050cab
1#include "rsCpuExecutable.h"
2#include "rsCppUtils.h"
3
4#include <fstream>
5#include <set>
6#include <memory>
7
8#include <sys/stat.h>
9
10#ifdef RS_COMPATIBILITY_LIB
11#include <stdio.h>
12#include <unistd.h>
13#else
14#include "bcc/Config.h"
15#endif
16
17#include <dlfcn.h>
18#include <sys/stat.h>
19
20namespace android {
21namespace renderscript {
22
23namespace {
24
25// Check if a path exists and attempt to create it if it doesn't.
26static bool ensureCacheDirExists(const char *path) {
27    if (access(path, R_OK | W_OK | X_OK) == 0) {
28        // Done if we can rwx the directory
29        return true;
30    }
31    if (mkdir(path, 0700) == 0) {
32        return true;
33    }
34    return false;
35}
36
37// Copy the file named \p srcFile to \p dstFile.
38// Return 0 on success and -1 if anything wasn't copied.
39static int copyFile(const char *dstFile, const char *srcFile) {
40    std::ifstream srcStream(srcFile);
41    if (!srcStream) {
42        ALOGE("Could not verify or read source file: %s", srcFile);
43        return -1;
44    }
45    std::ofstream dstStream(dstFile);
46    if (!dstStream) {
47        ALOGE("Could not verify or write destination file: %s", dstFile);
48        return -1;
49    }
50    dstStream << srcStream.rdbuf();
51    if (!dstStream) {
52        ALOGE("Could not write destination file: %s", dstFile);
53        return -1;
54    }
55
56    srcStream.close();
57    dstStream.close();
58
59    return 0;
60}
61
62static std::string findSharedObjectName(const char *cacheDir,
63                                        const char *resName) {
64    std::string scriptSOName(cacheDir);
65#if defined(RS_COMPATIBILITY_LIB) && !defined(__LP64__)
66    size_t cutPos = scriptSOName.rfind("cache");
67    if (cutPos != std::string::npos) {
68        scriptSOName.erase(cutPos);
69    } else {
70        ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
71    }
72    scriptSOName.append("/lib/librs.");
73#else
74    scriptSOName.append("/librs.");
75#endif // RS_COMPATIBILITY_LIB
76    scriptSOName.append(resName);
77    scriptSOName.append(".so");
78
79    return scriptSOName;
80}
81
82}  // anonymous namespace
83
84const char* SharedLibraryUtils::LD_EXE_PATH = "/system/bin/ld.mc";
85const char* SharedLibraryUtils::RS_CACHE_DIR = "com.android.renderscript.cache";
86
87#ifndef RS_COMPATIBILITY_LIB
88
89bool SharedLibraryUtils::createSharedLibrary(const char *driverName,
90                                             const char *cacheDir,
91                                             const char *resName) {
92    std::string sharedLibName = findSharedObjectName(cacheDir, resName);
93    std::string objFileName = cacheDir;
94    objFileName.append("/");
95    objFileName.append(resName);
96    objFileName.append(".o");
97    // Should be something like "libRSDriver.so".
98    std::string linkDriverName = driverName;
99    // Remove ".so" and replace "lib" with "-l".
100    // This will leave us with "-lRSDriver" instead.
101    linkDriverName.erase(linkDriverName.length() - 3);
102    linkDriverName.replace(0, 3, "-l");
103
104    const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so";
105    const char *mTriple = "-mtriple=" DEFAULT_TARGET_TRIPLE_STRING;
106    const char *libPath = "--library-path=" SYSLIBPATH;
107    const char *vendorLibPath = "--library-path=" SYSLIBPATH_VENDOR;
108
109    std::vector<const char *> args = {
110        LD_EXE_PATH,
111        "-shared",
112        "-nostdlib",
113        compiler_rt, mTriple, vendorLibPath, libPath,
114        linkDriverName.c_str(), "-lm", "-lc",
115        objFileName.c_str(),
116        "-o", sharedLibName.c_str(),
117        nullptr
118    };
119
120    return rsuExecuteCommand(LD_EXE_PATH, args.size()-1, args.data());
121
122}
123
124#endif  // RS_COMPATIBILITY_LIB
125
126const char* RsdCpuScriptImpl::BCC_EXE_PATH = "/system/bin/bcc";
127
128void* SharedLibraryUtils::loadSharedLibrary(const char *cacheDir,
129                                            const char *resName,
130                                            const char *nativeLibDir,
131                                            bool* alreadyLoaded) {
132    void *loaded = nullptr;
133
134#if defined(RS_COMPATIBILITY_LIB) && defined(__LP64__)
135    std::string scriptSOName = findSharedObjectName(nativeLibDir, resName);
136#else
137    std::string scriptSOName = findSharedObjectName(cacheDir, resName);
138#endif
139
140    // We should check if we can load the library from the standard app
141    // location for shared libraries first.
142    loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName, alreadyLoaded);
143
144    if (loaded == nullptr) {
145        ALOGE("Unable to open shared library (%s): %s",
146              scriptSOName.c_str(), dlerror());
147
148#ifdef RS_COMPATIBILITY_LIB
149        // One final attempt to find the library in "/system/lib".
150        // We do this to allow bundled applications to use the compatibility
151        // library fallback path. Those applications don't have a private
152        // library path, so they need to install to the system directly.
153        // Note that this is really just a testing path.
154        std::string scriptSONameSystem("/system/lib/librs.");
155        scriptSONameSystem.append(resName);
156        scriptSONameSystem.append(".so");
157        loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
158                              resName);
159        if (loaded == nullptr) {
160            ALOGE("Unable to open system shared library (%s): %s",
161                  scriptSONameSystem.c_str(), dlerror());
162        }
163#endif
164    }
165
166    return loaded;
167}
168
169std::string SharedLibraryUtils::getRandomString(size_t len) {
170    char buf[len + 1];
171    for (size_t i = 0; i < len; i++) {
172        uint32_t r = arc4random() & 0xffff;
173        r %= 62;
174        if (r < 26) {
175            // lowercase
176            buf[i] = 'a' + r;
177        } else if (r < 52) {
178            // uppercase
179            buf[i] = 'A' + (r - 26);
180        } else {
181            // Use a number
182            buf[i] = '0' + (r - 52);
183        }
184    }
185    buf[len] = '\0';
186    return std::string(buf);
187}
188
189void* SharedLibraryUtils::loadSOHelper(const char *origName, const char *cacheDir,
190                                       const char *resName, bool *alreadyLoaded) {
191    // Keep track of which .so libraries have been loaded. Once a library is
192    // in the set (per-process granularity), we must instead make a copy of
193    // the original shared object (randomly named .so file) and load that one
194    // instead. If we don't do this, we end up aliasing global data between
195    // the various Script instances (which are supposed to be completely
196    // independent).
197    static std::set<std::string> LoadedLibraries;
198
199    void *loaded = nullptr;
200
201    // Skip everything if we don't even have the original library available.
202    if (access(origName, F_OK) != 0) {
203        return nullptr;
204    }
205
206    // Common path is that we have not loaded this Script/library before.
207    if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
208        if (alreadyLoaded != nullptr) {
209            *alreadyLoaded = false;
210        }
211        loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
212        if (loaded) {
213            LoadedLibraries.insert(origName);
214        }
215        return loaded;
216    }
217
218    if (alreadyLoaded != nullptr) {
219        *alreadyLoaded = true;
220    }
221
222    std::string newName(cacheDir);
223
224    // Append RS_CACHE_DIR only if it is not found in cacheDir
225    // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
226    if (newName.find(RS_CACHE_DIR) == std::string::npos) {
227        newName.append("/");
228        newName.append(RS_CACHE_DIR);
229        newName.append("/");
230    }
231
232    if (!ensureCacheDirExists(newName.c_str())) {
233        ALOGE("Could not verify or create cache dir: %s", cacheDir);
234        return nullptr;
235    }
236
237    // Construct an appropriately randomized filename for the copy.
238    newName.append("librs.");
239    newName.append(resName);
240    newName.append("#");
241    newName.append(getRandomString(6).c_str());  // 62^6 potential filename variants.
242    newName.append(".so");
243
244    int r = copyFile(newName.c_str(), origName);
245    if (r != 0) {
246        ALOGE("Could not create copy %s -> %s", origName, newName.c_str());
247        return nullptr;
248    }
249    loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
250    r = unlink(newName.c_str());
251    if (r != 0) {
252        ALOGE("Could not unlink copy %s", newName.c_str());
253    }
254    if (loaded) {
255        LoadedLibraries.insert(newName.c_str());
256    }
257
258    return loaded;
259}
260
261// MAXLINESTR must be compatible with operator '#' in C macro.
262#define MAXLINESTR 499
263// MAXLINE must be (MAXLINESTR + 1), representing the size of a C string
264// containing MAXLINESTR non-null chars plus a null.
265#define MAXLINE (MAXLINESTR + 1)
266#define MAKE_STR_HELPER(S) #S
267#define MAKE_STR(S) MAKE_STR_HELPER(S)
268#define EXPORT_VAR_STR "exportVarCount: "
269#define EXPORT_FUNC_STR "exportFuncCount: "
270#define EXPORT_FOREACH_STR "exportForEachCount: "
271#define EXPORT_REDUCE_STR "exportReduceCount: "
272#define OBJECT_SLOT_STR "objectSlotCount: "
273#define PRAGMA_STR "pragmaCount: "
274#define THREADABLE_STR "isThreadable: "
275#define CHECKSUM_STR "buildChecksum: "
276
277// Copy up to a newline or size chars from str -> s, updating str
278// Returns s when successful and nullptr when '\0' is finally reached.
279static char* strgets(char *s, int size, const char **ppstr) {
280    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
281        return nullptr;
282    }
283
284    int i;
285    for (i = 0; i < (size - 1); i++) {
286        s[i] = **ppstr;
287        (*ppstr)++;
288        if (s[i] == '\0') {
289            return s;
290        } else if (s[i] == '\n') {
291            s[i+1] = '\0';
292            return s;
293        }
294    }
295
296    // size has been exceeded.
297    s[i] = '\0';
298
299    return s;
300}
301
302// Creates a duplicate of a string. The new string is as small as possible,
303// only including characters up to and including the first null-terminator;
304// otherwise, the new string will be the same size as the input string.
305// The code that calls duplicateString is responsible for the new string's
306// lifetime, and is responsible for freeing it when it is no longer needed.
307static char* duplicateString(const char *str, size_t length) {
308    const size_t newLen = strnlen(str, length-1) + 1;
309    char *newStr = new char[newLen];
310    strlcpy(newStr, str, newLen);
311    return newStr;
312}
313
314ScriptExecutable* ScriptExecutable::createFromSharedObject(
315    void* sharedObj, uint32_t expectedChecksum) {
316    char line[MAXLINE];
317
318    size_t varCount = 0;
319    size_t funcCount = 0;
320    size_t forEachCount = 0;
321    size_t reduceCount = 0;
322    size_t objectSlotCount = 0;
323    size_t pragmaCount = 0;
324    bool isThreadable = true;
325
326    void** fieldAddress = nullptr;
327    bool* fieldIsObject = nullptr;
328    char** fieldName = nullptr;
329    InvokeFunc_t* invokeFunctions = nullptr;
330    ForEachFunc_t* forEachFunctions = nullptr;
331    uint32_t* forEachSignatures = nullptr;
332    ReduceDescription* reduceDescriptions = nullptr;
333    const char ** pragmaKeys = nullptr;
334    const char ** pragmaValues = nullptr;
335    uint32_t checksum = 0;
336
337    const char *rsInfo = (const char *) dlsym(sharedObj, kRsInfo);
338    int numEntries = 0;
339    const int *rsGlobalEntries = (const int *) dlsym(sharedObj, kRsGlobalEntries);
340    const char **rsGlobalNames = (const char **) dlsym(sharedObj, kRsGlobalNames);
341    const void **rsGlobalAddresses = (const void **) dlsym(sharedObj, kRsGlobalAddresses);
342    const size_t *rsGlobalSizes = (const size_t *) dlsym(sharedObj, kRsGlobalSizes);
343    const uint32_t *rsGlobalProperties = (const uint32_t *) dlsym(sharedObj, kRsGlobalProperties);
344
345    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
346        return nullptr;
347    }
348    if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
349        ALOGE("Invalid export var count!: %s", line);
350        return nullptr;
351    }
352
353    fieldAddress = new void*[varCount];
354    if (fieldAddress == nullptr) {
355        return nullptr;
356    }
357
358    fieldIsObject = new bool[varCount];
359    if (fieldIsObject == nullptr) {
360        goto error;
361    }
362
363    fieldName = new char*[varCount];
364    if (fieldName == nullptr) {
365        goto error;
366    }
367
368    for (size_t i = 0; i < varCount; ++i) {
369        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
370            goto error;
371        }
372        char *c = strrchr(line, '\n');
373        if (c) {
374            *c = '\0';
375        }
376        void* addr = dlsym(sharedObj, line);
377        if (addr == nullptr) {
378            ALOGE("Failed to find variable address for %s: %s",
379                  line, dlerror());
380            // Not a critical error if we don't find a global variable.
381        }
382        fieldAddress[i] = addr;
383        fieldIsObject[i] = false;
384        fieldName[i] = duplicateString(line, sizeof(line));
385    }
386
387    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
388        goto error;
389    }
390    if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
391        ALOGE("Invalid export func count!: %s", line);
392        goto error;
393    }
394
395    invokeFunctions = new InvokeFunc_t[funcCount];
396    if (invokeFunctions == nullptr) {
397        goto error;
398    }
399
400    for (size_t i = 0; i < funcCount; ++i) {
401        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
402            goto error;
403        }
404        char *c = strrchr(line, '\n');
405        if (c) {
406            *c = '\0';
407        }
408
409        invokeFunctions[i] = (InvokeFunc_t) dlsym(sharedObj, line);
410        if (invokeFunctions[i] == nullptr) {
411            ALOGE("Failed to get function address for %s(): %s",
412                  line, dlerror());
413            goto error;
414        }
415    }
416
417    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
418        goto error;
419    }
420    if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
421        ALOGE("Invalid export forEach count!: %s", line);
422        goto error;
423    }
424
425    forEachFunctions = new ForEachFunc_t[forEachCount];
426    if (forEachFunctions == nullptr) {
427        goto error;
428    }
429
430    forEachSignatures = new uint32_t[forEachCount];
431    if (forEachSignatures == nullptr) {
432        goto error;
433    }
434
435    for (size_t i = 0; i < forEachCount; ++i) {
436        unsigned int tmpSig = 0;
437        char tmpName[MAXLINE];
438
439        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
440            goto error;
441        }
442        if (sscanf(line, "%u - %" MAKE_STR(MAXLINESTR) "s",
443                   &tmpSig, tmpName) != 2) {
444          ALOGE("Invalid export forEach!: %s", line);
445          goto error;
446        }
447
448        // Lookup the expanded ForEach kernel.
449        strncat(tmpName, ".expand", MAXLINESTR-strlen(tmpName));
450        forEachSignatures[i] = tmpSig;
451        forEachFunctions[i] =
452            (ForEachFunc_t) dlsym(sharedObj, tmpName);
453        if (i != 0 && forEachFunctions[i] == nullptr &&
454            strcmp(tmpName, "root.expand")) {
455            // Ignore missing root.expand functions.
456            // root() is always specified at location 0.
457            ALOGE("Failed to find forEach function address for %s(): %s",
458                  tmpName, dlerror());
459            goto error;
460        }
461    }
462
463    // Read general reduce kernels
464    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
465        goto error;
466    }
467    if (sscanf(line, EXPORT_REDUCE_STR "%zu", &reduceCount) != 1) {
468        ALOGE("Invalid export reduce new count!: %s", line);
469        goto error;
470    }
471
472    reduceDescriptions = new ReduceDescription[reduceCount];
473    if (reduceDescriptions == nullptr) {
474        goto error;
475    }
476
477    for (size_t i = 0; i < reduceCount; ++i) {
478        static const char kNoName[] = ".";
479
480        unsigned int tmpSig = 0;
481        size_t tmpSize = 0;
482        char tmpNameReduce[MAXLINE];
483        char tmpNameInitializer[MAXLINE];
484        char tmpNameAccumulator[MAXLINE];
485        char tmpNameCombiner[MAXLINE];
486        char tmpNameOutConverter[MAXLINE];
487        char tmpNameHalter[MAXLINE];
488
489        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
490            goto error;
491        }
492#define DELIMNAME " - %" MAKE_STR(MAXLINESTR) "s"
493        if (sscanf(line, "%u - %zu" DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME DELIMNAME,
494                   &tmpSig, &tmpSize, tmpNameReduce, tmpNameInitializer, tmpNameAccumulator,
495                   tmpNameCombiner, tmpNameOutConverter, tmpNameHalter) != 8) {
496            ALOGE("Invalid export reduce new!: %s", line);
497            goto error;
498        }
499#undef DELIMNAME
500
501        // For now, we expect
502        // - Reduce and Accumulator names
503        // - optional Initializer, Combiner, and OutConverter name
504        // - no Halter name
505        if (!strcmp(tmpNameReduce, kNoName) ||
506            !strcmp(tmpNameAccumulator, kNoName)) {
507            ALOGE("Expected reduce and accumulator names!: %s", line);
508            goto error;
509        }
510        if (strcmp(tmpNameHalter, kNoName)) {
511            ALOGE("Did not expect halter name!: %s", line);
512            goto error;
513        }
514
515        // The current implementation does not use the signature
516        // or reduce name.
517
518        reduceDescriptions[i].accumSize = tmpSize;
519
520        // Process the (optional) initializer.
521        if (strcmp(tmpNameInitializer, kNoName)) {
522          // Lookup the original user-written initializer.
523          if (!(reduceDescriptions[i].initFunc =
524                (ReduceInitializerFunc_t) dlsym(sharedObj, tmpNameInitializer))) {
525            ALOGE("Failed to find initializer function address for %s(): %s",
526                  tmpNameInitializer, dlerror());
527            goto error;
528          }
529        } else {
530          reduceDescriptions[i].initFunc = nullptr;
531        }
532
533        // Lookup the expanded accumulator.
534        strncat(tmpNameAccumulator, ".expand", MAXLINESTR-strlen(tmpNameAccumulator));
535        if (!(reduceDescriptions[i].accumFunc =
536              (ReduceAccumulatorFunc_t) dlsym(sharedObj, tmpNameAccumulator))) {
537            ALOGE("Failed to find accumulator function address for %s(): %s",
538                  tmpNameAccumulator, dlerror());
539            goto error;
540        }
541
542        // Process the (optional) combiner.
543        if (strcmp(tmpNameCombiner, kNoName)) {
544          // Lookup the original user-written combiner.
545          if (!(reduceDescriptions[i].combFunc =
546                (ReduceCombinerFunc_t) dlsym(sharedObj, tmpNameCombiner))) {
547            ALOGE("Failed to find combiner function address for %s(): %s",
548                  tmpNameCombiner, dlerror());
549            goto error;
550          }
551        } else {
552          reduceDescriptions[i].combFunc = nullptr;
553        }
554
555        // Process the (optional) outconverter.
556        if (strcmp(tmpNameOutConverter, kNoName)) {
557          // Lookup the original user-written outconverter.
558          if (!(reduceDescriptions[i].outFunc =
559                (ReduceOutConverterFunc_t) dlsym(sharedObj, tmpNameOutConverter))) {
560            ALOGE("Failed to find outconverter function address for %s(): %s",
561                  tmpNameOutConverter, dlerror());
562            goto error;
563          }
564        } else {
565          reduceDescriptions[i].outFunc = nullptr;
566        }
567    }
568
569    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
570        goto error;
571    }
572    if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
573        ALOGE("Invalid object slot count!: %s", line);
574        goto error;
575    }
576
577    for (size_t i = 0; i < objectSlotCount; ++i) {
578        uint32_t varNum = 0;
579        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
580            goto error;
581        }
582        if (sscanf(line, "%u", &varNum) != 1) {
583            ALOGE("Invalid object slot!: %s", line);
584            goto error;
585        }
586
587        if (varNum < varCount) {
588            fieldIsObject[varNum] = true;
589        }
590    }
591
592#ifndef RS_COMPATIBILITY_LIB
593    // Do not attempt to read pragmas or isThreadable flag in compat lib path.
594    // Neither is applicable for compat lib
595
596    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
597        goto error;
598    }
599
600    if (sscanf(line, PRAGMA_STR "%zu", &pragmaCount) != 1) {
601        ALOGE("Invalid pragma count!: %s", line);
602        goto error;
603    }
604
605    pragmaKeys = new const char*[pragmaCount];
606    if (pragmaKeys == nullptr) {
607        goto error;
608    }
609
610    pragmaValues = new const char*[pragmaCount];
611    if (pragmaValues == nullptr) {
612        goto error;
613    }
614
615    bzero(pragmaKeys, sizeof(char*) * pragmaCount);
616    bzero(pragmaValues, sizeof(char*) * pragmaCount);
617
618    for (size_t i = 0; i < pragmaCount; ++i) {
619        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
620            ALOGE("Unable to read pragma at index %zu!", i);
621            goto error;
622        }
623        char key[MAXLINE];
624        char value[MAXLINE] = ""; // initialize in case value is empty
625
626        // pragmas can just have a key and no value.  Only check to make sure
627        // that the key is not empty
628        if (sscanf(line, "%" MAKE_STR(MAXLINESTR) "s - %" MAKE_STR(MAXLINESTR) "s",
629                   key, value) == 0 ||
630            strlen(key) == 0)
631        {
632            ALOGE("Invalid pragma value!: %s", line);
633
634            goto error;
635        }
636
637        pragmaKeys[i] = duplicateString(key, sizeof(key));
638        pragmaValues[i] = duplicateString(value, sizeof(value));
639        //ALOGE("Pragma %zu: Key: '%s' Value: '%s'", i, pKey, pValue);
640    }
641
642    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
643        goto error;
644    }
645
646    char tmpFlag[4];
647    if (sscanf(line, THREADABLE_STR "%3s", tmpFlag) != 1) {
648        ALOGE("Invalid threadable flag!: %s", line);
649        goto error;
650    }
651    if (strcmp(tmpFlag, "yes") == 0) {
652        isThreadable = true;
653    } else if (strcmp(tmpFlag, "no") == 0) {
654        isThreadable = false;
655    } else {
656        ALOGE("Invalid threadable flag!: %s", tmpFlag);
657        goto error;
658    }
659
660    if (strgets(line, MAXLINE, &rsInfo) != nullptr) {
661        if (sscanf(line, CHECKSUM_STR "%08x", &checksum) != 1) {
662            ALOGE("Invalid checksum flag!: %s", line);
663            goto error;
664        }
665    } else {
666        ALOGE("Missing checksum in shared obj file");
667        goto error;
668    }
669
670    if (expectedChecksum != 0 && checksum != expectedChecksum) {
671        ALOGE("Found invalid checksum.  Expected %08x, got %08x\n",
672              expectedChecksum, checksum);
673        goto error;
674    }
675
676#endif  // RS_COMPATIBILITY_LIB
677
678    // Read in information about mutable global variables provided by bcc's
679    // RSGlobalInfoPass
680    if (rsGlobalEntries) {
681        numEntries = *rsGlobalEntries;
682        if (numEntries > 0) {
683            rsAssert(rsGlobalNames);
684            rsAssert(rsGlobalAddresses);
685            rsAssert(rsGlobalSizes);
686            rsAssert(rsGlobalProperties);
687        }
688    }
689
690    return new ScriptExecutable(
691        fieldAddress, fieldIsObject, fieldName, varCount,
692        invokeFunctions, funcCount,
693        forEachFunctions, forEachSignatures, forEachCount,
694        reduceDescriptions, reduceCount,
695        pragmaKeys, pragmaValues, pragmaCount,
696        rsGlobalNames, rsGlobalAddresses, rsGlobalSizes, rsGlobalProperties,
697        numEntries, isThreadable, checksum);
698
699error:
700
701#ifndef RS_COMPATIBILITY_LIB
702
703    if (pragmaKeys) {
704        for (size_t idx = 0; idx < pragmaCount; ++idx) {
705            delete [] pragmaKeys[idx];
706        }
707    }
708
709    if (pragmaValues) {
710        for (size_t idx = 0; idx < pragmaCount; ++idx) {
711            delete [] pragmaValues[idx];
712        }
713    }
714
715    delete[] pragmaValues;
716    delete[] pragmaKeys;
717#endif  // RS_COMPATIBILITY_LIB
718
719    delete[] reduceDescriptions;
720
721    delete[] forEachSignatures;
722    delete[] forEachFunctions;
723
724    delete[] invokeFunctions;
725
726    for (size_t i = 0; i < varCount; i++) {
727        delete[] fieldName[i];
728    }
729    delete[] fieldName;
730    delete[] fieldIsObject;
731    delete[] fieldAddress;
732
733    return nullptr;
734}
735
736void* ScriptExecutable::getFieldAddress(const char* name) const {
737    // TODO: improve this by using a hash map.
738    for (size_t i = 0; i < mExportedVarCount; i++) {
739        if (strcmp(name, mFieldName[i]) == 0) {
740            return mFieldAddress[i];
741        }
742    }
743    return nullptr;
744}
745
746bool ScriptExecutable::dumpGlobalInfo() const {
747    ALOGE("Globals: %p %p %p", mGlobalAddresses, mGlobalSizes, mGlobalNames);
748    ALOGE("P   - Pointer");
749    ALOGE(" C  - Constant");
750    ALOGE("  S - Static");
751    for (int i = 0; i < mGlobalEntries; i++) {
752        ALOGE("Global[%d]: %p %zu %s", i, mGlobalAddresses[i], mGlobalSizes[i],
753              mGlobalNames[i]);
754        uint32_t properties = mGlobalProperties[i];
755        ALOGE("%c%c%c Type: %u",
756              isGlobalPointer(properties)  ? 'P' : ' ',
757              isGlobalConstant(properties) ? 'C' : ' ',
758              isGlobalStatic(properties)   ? 'S' : ' ',
759              getGlobalRsType(properties));
760    }
761    return true;
762}
763
764}  // namespace renderscript
765}  // namespace android
766