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