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