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