1/*
2 * Copyright (C) 2011-2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "rsCpuCore.h"
18#include "rsCpuScript.h"
19
20#ifdef RS_COMPATIBILITY_LIB
21    #include <set>
22    #include <string>
23    #include <dlfcn.h>
24    #include <stdio.h>
25    #include <stdlib.h>
26    #include <string.h>
27    #include <sys/stat.h>
28    #include <unistd.h>
29#else
30    #include <bcc/BCCContext.h>
31    #include <bcc/Config/Config.h>
32    #include <bcc/Renderscript/RSCompilerDriver.h>
33    #include <bcc/Renderscript/RSExecutable.h>
34    #include <bcc/Renderscript/RSInfo.h>
35    #include <bcinfo/MetadataExtractor.h>
36    #include <cutils/properties.h>
37
38    #include <sys/types.h>
39    #include <sys/wait.h>
40    #include <unistd.h>
41
42    #include <string>
43    #include <vector>
44#endif
45
46namespace {
47#ifdef RS_COMPATIBILITY_LIB
48
49// Create a len length string containing random characters from [A-Za-z0-9].
50static std::string getRandomString(size_t len) {
51    char buf[len + 1];
52    for (size_t i = 0; i < len; i++) {
53        uint32_t r = arc4random() & 0xffff;
54        r %= 62;
55        if (r < 26) {
56            // lowercase
57            buf[i] = 'a' + r;
58        } else if (r < 52) {
59            // uppercase
60            buf[i] = 'A' + (r - 26);
61        } else {
62            // Use a number
63            buf[i] = '0' + (r - 52);
64        }
65    }
66    buf[len] = '\0';
67    return std::string(buf);
68}
69
70// Check if a path exists and attempt to create it if it doesn't.
71static bool ensureCacheDirExists(const char *path) {
72    if (access(path, R_OK | W_OK | X_OK) == 0) {
73        // Done if we can rwx the directory
74        return true;
75    }
76    if (mkdir(path, 0700) == 0) {
77        return true;
78    }
79    return false;
80}
81
82// Attempt to load the shared library from origName, but then fall back to
83// creating the symlinked shared library if necessary (to ensure instancing).
84// This function returns the dlopen()-ed handle if successful.
85static void *loadSOHelper(const char *origName, const char *cacheDir,
86                          const char *resName) {
87    // Keep track of which .so libraries have been loaded. Once a library is
88    // in the set (per-process granularity), we must instead make a symlink to
89    // the original shared object (randomly named .so file) and load that one
90    // instead. If we don't do this, we end up aliasing global data between
91    // the various Script instances (which are supposed to be completely
92    // independent).
93    static std::set<std::string> LoadedLibraries;
94
95    void *loaded = NULL;
96
97    // Skip everything if we don't even have the original library available.
98    if (access(origName, F_OK) != 0) {
99        return NULL;
100    }
101
102    // Common path is that we have not loaded this Script/library before.
103    if (LoadedLibraries.find(origName) == LoadedLibraries.end()) {
104        loaded = dlopen(origName, RTLD_NOW | RTLD_LOCAL);
105        if (loaded) {
106            LoadedLibraries.insert(origName);
107        }
108        return loaded;
109    }
110
111    std::string newName(cacheDir);
112    newName.append("/com.android.renderscript.cache/");
113
114    if (!ensureCacheDirExists(newName.c_str())) {
115        ALOGE("Could not verify or create cache dir: %s", cacheDir);
116        return NULL;
117    }
118
119    // Construct an appropriately randomized filename for the symlink.
120    newName.append("librs.");
121    newName.append(resName);
122    newName.append("#");
123    newName.append(getRandomString(6));  // 62^6 potential filename variants.
124    newName.append(".so");
125
126    int r = symlink(origName, newName.c_str());
127    if (r != 0) {
128        ALOGE("Could not create symlink %s -> %s", newName.c_str(), origName);
129        return NULL;
130    }
131    loaded = dlopen(newName.c_str(), RTLD_NOW | RTLD_LOCAL);
132    r = unlink(newName.c_str());
133    if (r != 0) {
134        ALOGE("Could not unlink symlink %s", newName.c_str());
135    }
136    if (loaded) {
137        LoadedLibraries.insert(newName.c_str());
138    }
139
140    return loaded;
141}
142
143// Load the shared library referred to by cacheDir and resName. If we have
144// already loaded this library, we instead create a new symlink (in the
145// cache dir) and then load that. We then immediately destroy the symlink.
146// This is required behavior to implement script instancing for the support
147// library, since shared objects are loaded and de-duped by name only.
148static void *loadSharedLibrary(const char *cacheDir, const char *resName) {
149    void *loaded = NULL;
150    //arc4random_stir();
151#ifndef RS_SERVER
152    std::string scriptSOName(cacheDir);
153    size_t cutPos = scriptSOName.rfind("cache");
154    if (cutPos != std::string::npos) {
155        scriptSOName.erase(cutPos);
156    } else {
157        ALOGE("Found peculiar cacheDir (missing \"cache\"): %s", cacheDir);
158    }
159    scriptSOName.append("/lib/librs.");
160#else
161    std::string scriptSOName("lib");
162#endif
163    scriptSOName.append(resName);
164    scriptSOName.append(".so");
165
166    // We should check if we can load the library from the standard app
167    // location for shared libraries first.
168    loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
169
170    if (loaded == NULL) {
171        ALOGE("Unable to open shared library (%s): %s",
172              scriptSOName.c_str(), dlerror());
173
174        // One final attempt to find the library in "/system/lib".
175        // We do this to allow bundled applications to use the compatibility
176        // library fallback path. Those applications don't have a private
177        // library path, so they need to install to the system directly.
178        // Note that this is really just a testing path.
179        android::String8 scriptSONameSystem("/system/lib/librs.");
180        scriptSONameSystem.append(resName);
181        scriptSONameSystem.append(".so");
182        loaded = loadSOHelper(scriptSONameSystem.c_str(), cacheDir,
183                              resName);
184        if (loaded == NULL) {
185            ALOGE("Unable to open system shared library (%s): %s",
186                  scriptSONameSystem.c_str(), dlerror());
187        }
188    }
189
190    return loaded;
191}
192
193#else  // RS_COMPATIBILITY_LIB is not defined
194
195static bool is_force_recompile() {
196#ifdef RS_SERVER
197  return false;
198#else
199  char buf[PROPERTY_VALUE_MAX];
200
201  // Re-compile if floating point precision has been overridden.
202  property_get("debug.rs.precision", buf, "");
203  if (buf[0] != '\0') {
204    return true;
205  }
206
207  // Re-compile if debug.rs.forcerecompile is set.
208  property_get("debug.rs.forcerecompile", buf, "0");
209  if ((::strcmp(buf, "1") == 0) || (::strcmp(buf, "true") == 0)) {
210    return true;
211  } else {
212    return false;
213  }
214#endif  // RS_SERVER
215}
216
217const static char *BCC_EXE_PATH = "/system/bin/bcc";
218
219static void setCompileArguments(std::vector<const char*>* args, const android::String8& bcFileName,
220                                const char* cacheDir, const char* resName, const char* core_lib,
221                                bool useRSDebugContext, const char* bccPluginName) {
222    rsAssert(cacheDir && resName && core_lib);
223    args->push_back(BCC_EXE_PATH);
224    args->push_back("-o");
225    args->push_back(resName);
226    args->push_back("-output_path");
227    args->push_back(cacheDir);
228    args->push_back("-bclib");
229    args->push_back(core_lib);
230    args->push_back("-mtriple");
231    args->push_back(DEFAULT_TARGET_TRIPLE_STRING);
232
233    // Enable workaround for A53 codegen by default.
234#if defined(__aarch64__) && !defined(DISABLE_A53_WORKAROUND)
235    args->push_back("-aarch64-fix-cortex-a53-835769");
236#endif
237
238    // Execute the bcc compiler.
239    if (useRSDebugContext) {
240        args->push_back("-rs-debug-ctx");
241    } else {
242        // Only load additional libraries for compiles that don't use
243        // the debug context.
244        if (bccPluginName && strlen(bccPluginName) > 0) {
245            args->push_back("-load");
246            args->push_back(bccPluginName);
247        }
248    }
249
250    args->push_back(bcFileName.string());
251    args->push_back(NULL);
252}
253
254static bool compileBitcode(const android::String8& bcFileName,
255                           const char *bitcode,
256                           size_t bitcodeSize,
257                           const char** compileArguments,
258                           const std::string& compileCommandLine) {
259    rsAssert(bitcode && bitcodeSize);
260
261    FILE *bcfile = fopen(bcFileName.string(), "w");
262    if (!bcfile) {
263        ALOGE("Could not write to %s", bcFileName.string());
264        return false;
265    }
266    size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
267    fclose(bcfile);
268    if (nwritten != bitcodeSize) {
269        ALOGE("Could not write %zu bytes to %s", bitcodeSize,
270              bcFileName.string());
271        return false;
272    }
273
274    pid_t pid = fork();
275
276    switch (pid) {
277    case -1: {  // Error occurred (we attempt no recovery)
278        ALOGE("Couldn't fork for bcc compiler execution");
279        return false;
280    }
281    case 0: {  // Child process
282        ALOGV("Invoking BCC with: %s", compileCommandLine.c_str());
283        execv(BCC_EXE_PATH, (char* const*)compileArguments);
284
285        ALOGE("execv() failed: %s", strerror(errno));
286        abort();
287        return false;
288    }
289    default: {  // Parent process (actual driver)
290        // Wait on child process to finish compiling the source.
291        int status = 0;
292        pid_t w = waitpid(pid, &status, 0);
293        if (w == -1) {
294            ALOGE("Could not wait for bcc compiler");
295            return false;
296        }
297
298        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
299            return true;
300        }
301
302        ALOGE("bcc compiler terminated unexpectedly");
303        return false;
304    }
305    }
306}
307
308#endif  // !defined(RS_COMPATIBILITY_LIB)
309}  // namespace
310
311namespace android {
312namespace renderscript {
313
314#ifdef RS_COMPATIBILITY_LIB
315#define MAXLINE 500
316#define MAKE_STR_HELPER(S) #S
317#define MAKE_STR(S) MAKE_STR_HELPER(S)
318#define EXPORT_VAR_STR "exportVarCount: "
319#define EXPORT_FUNC_STR "exportFuncCount: "
320#define EXPORT_FOREACH_STR "exportForEachCount: "
321#define OBJECT_SLOT_STR "objectSlotCount: "
322
323// Copy up to a newline or size chars from str -> s, updating str
324// Returns s when successful and NULL when '\0' is finally reached.
325static char* strgets(char *s, int size, const char **ppstr) {
326    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
327        return NULL;
328    }
329
330    int i;
331    for (i = 0; i < (size - 1); i++) {
332        s[i] = **ppstr;
333        (*ppstr)++;
334        if (s[i] == '\0') {
335            return s;
336        } else if (s[i] == '\n') {
337            s[i+1] = '\0';
338            return s;
339        }
340    }
341
342    // size has been exceeded.
343    s[i] = '\0';
344
345    return s;
346}
347#endif
348
349RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
350    mCtx = ctx;
351    mScript = s;
352
353#ifdef RS_COMPATIBILITY_LIB
354    mScriptSO = NULL;
355    mInvokeFunctions = NULL;
356    mForEachFunctions = NULL;
357    mFieldAddress = NULL;
358    mFieldIsObject = NULL;
359    mForEachSignatures = NULL;
360#else
361    mCompilerContext = NULL;
362    mCompilerDriver = NULL;
363    mExecutable = NULL;
364#endif
365
366
367    mRoot = NULL;
368    mRootExpand = NULL;
369    mInit = NULL;
370    mFreeChildren = NULL;
371
372
373    mBoundAllocs = NULL;
374    mIntrinsicData = NULL;
375    mIsThreadable = true;
376}
377
378
379bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
380                            uint8_t const *bitcode, size_t bitcodeSize,
381                            uint32_t flags, char const *bccPluginName) {
382    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
383    //ALOGE("rsdScriptInit %p %p", rsc, script);
384
385    mCtx->lockMutex();
386#ifndef RS_COMPATIBILITY_LIB
387    bool useRSDebugContext = false;
388
389    mCompilerContext = NULL;
390    mCompilerDriver = NULL;
391    mExecutable = NULL;
392
393    mCompilerContext = new bcc::BCCContext();
394    if (mCompilerContext == NULL) {
395        ALOGE("bcc: FAILS to create compiler context (out of memory)");
396        mCtx->unlockMutex();
397        return false;
398    }
399
400    mCompilerDriver = new bcc::RSCompilerDriver();
401    if (mCompilerDriver == NULL) {
402        ALOGE("bcc: FAILS to create compiler driver (out of memory)");
403        mCtx->unlockMutex();
404        return false;
405    }
406
407    // Configure symbol resolvers (via compiler-rt and the RS runtime).
408    mRSRuntime.setLookupFunction(lookupRuntimeStub);
409    mRSRuntime.setContext(this);
410    mResolver.chainResolver(mCompilerRuntime);
411    mResolver.chainResolver(mRSRuntime);
412
413    // Run any compiler setup functions we have been provided with.
414    RSSetupCompilerCallback setupCompilerCallback =
415            mCtx->getSetupCompilerCallback();
416    if (setupCompilerCallback != NULL) {
417        setupCompilerCallback(mCompilerDriver);
418    }
419
420    bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
421    if (!bitcodeMetadata.extract()) {
422        ALOGE("Could not extract metadata from bitcode");
423        mCtx->unlockMutex();
424        return false;
425    }
426
427    const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
428
429    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
430        mCompilerDriver->setDebugContext(true);
431        useRSDebugContext = true;
432    }
433
434    android::String8 bcFileName(cacheDir);
435    bcFileName.append("/");
436    bcFileName.append(resName);
437    bcFileName.append(".bc");
438
439    std::vector<const char*> compileArguments;
440    setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
441                        useRSDebugContext, bccPluginName);
442    // The last argument of compileArguments ia a NULL, so remove 1 from the size.
443    std::string compileCommandLine =
444                bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
445
446    if (!is_force_recompile()) {
447        // Load the compiled script that's in the cache, if any.
448        mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
449                                                        bitcodeSize, compileCommandLine.c_str(),
450                                                        mResolver);
451    }
452
453    // If we can't, it's either not there or out of date.  We compile the bit code and try loading
454    // again.
455    if (mExecutable == NULL) {
456        if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(),
457                            compileCommandLine)) {
458            ALOGE("bcc: FAILS to compile '%s'", resName);
459            mCtx->unlockMutex();
460            return false;
461        }
462        mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
463                                                        bitcodeSize, compileCommandLine.c_str(),
464                                                        mResolver);
465        if (mExecutable == NULL) {
466            ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName);
467            mCtx->unlockMutex();
468            return false;
469        }
470    }
471
472    mExecutable->setThreadable(mIsThreadable);
473    if (!mExecutable->syncInfo()) {
474        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
475    }
476
477    mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
478    mRootExpand =
479        reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
480    mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
481    mFreeChildren =
482        reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
483
484
485    if (bitcodeMetadata.getExportVarCount()) {
486        mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
487        memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
488    }
489
490    for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
491        char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
492        mExportedForEachFuncList.push_back(
493                    std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
494    }
495
496#else  // RS_COMPATIBILITY_LIB is defined
497
498    mScriptSO = loadSharedLibrary(cacheDir, resName);
499
500    if (mScriptSO) {
501        char line[MAXLINE];
502        mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
503        if (mRoot) {
504            //ALOGE("Found root(): %p", mRoot);
505        }
506        mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
507        if (mRootExpand) {
508            //ALOGE("Found root.expand(): %p", mRootExpand);
509        }
510        mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
511        if (mInit) {
512            //ALOGE("Found init(): %p", mInit);
513        }
514        mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
515        if (mFreeChildren) {
516            //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
517        }
518
519        const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
520        if (rsInfo) {
521            //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
522        }
523
524        size_t varCount = 0;
525        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
526            goto error;
527        }
528        if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
529            ALOGE("Invalid export var count!: %s", line);
530            goto error;
531        }
532
533        mExportedVariableCount = varCount;
534        //ALOGE("varCount: %zu", varCount);
535        if (varCount > 0) {
536            // Start by creating/zeroing this member, since we don't want to
537            // accidentally clean up invalid pointers later (if we error out).
538            mFieldIsObject = new bool[varCount];
539            if (mFieldIsObject == NULL) {
540                goto error;
541            }
542            memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
543            mFieldAddress = new void*[varCount];
544            if (mFieldAddress == NULL) {
545                goto error;
546            }
547            for (size_t i = 0; i < varCount; ++i) {
548                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
549                    goto error;
550                }
551                char *c = strrchr(line, '\n');
552                if (c) {
553                    *c = '\0';
554                }
555                mFieldAddress[i] = dlsym(mScriptSO, line);
556                if (mFieldAddress[i] == NULL) {
557                    ALOGE("Failed to find variable address for %s: %s",
558                          line, dlerror());
559                    // Not a critical error if we don't find a global variable.
560                }
561                else {
562                    //ALOGE("Found variable %s at %p", line,
563                    //mFieldAddress[i]);
564                }
565            }
566        }
567
568        size_t funcCount = 0;
569        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
570            goto error;
571        }
572        if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
573            ALOGE("Invalid export func count!: %s", line);
574            goto error;
575        }
576
577        mExportedFunctionCount = funcCount;
578        //ALOGE("funcCount: %zu", funcCount);
579
580        if (funcCount > 0) {
581            mInvokeFunctions = new InvokeFunc_t[funcCount];
582            if (mInvokeFunctions == NULL) {
583                goto error;
584            }
585            for (size_t i = 0; i < funcCount; ++i) {
586                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
587                    goto error;
588                }
589                char *c = strrchr(line, '\n');
590                if (c) {
591                    *c = '\0';
592                }
593
594                mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
595                if (mInvokeFunctions[i] == NULL) {
596                    ALOGE("Failed to get function address for %s(): %s",
597                          line, dlerror());
598                    goto error;
599                }
600                else {
601                    //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
602                }
603            }
604        }
605
606        size_t forEachCount = 0;
607        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
608            goto error;
609        }
610        if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
611            ALOGE("Invalid export forEach count!: %s", line);
612            goto error;
613        }
614
615        if (forEachCount > 0) {
616
617            mForEachSignatures = new uint32_t[forEachCount];
618            if (mForEachSignatures == NULL) {
619                goto error;
620            }
621            mForEachFunctions = new ForEachFunc_t[forEachCount];
622            if (mForEachFunctions == NULL) {
623                goto error;
624            }
625            for (size_t i = 0; i < forEachCount; ++i) {
626                unsigned int tmpSig = 0;
627                char tmpName[MAXLINE];
628
629                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
630                    goto error;
631                }
632                if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
633                           &tmpSig, tmpName) != 2) {
634                    ALOGE("Invalid export forEach!: %s", line);
635                    goto error;
636                }
637
638                // Lookup the expanded ForEach kernel.
639                strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
640                mForEachSignatures[i] = tmpSig;
641                mForEachFunctions[i] =
642                        (ForEachFunc_t) dlsym(mScriptSO, tmpName);
643                if (i != 0 && mForEachFunctions[i] == NULL) {
644                    // Ignore missing root.expand functions.
645                    // root() is always specified at location 0.
646                    ALOGE("Failed to find forEach function address for %s: %s",
647                          tmpName, dlerror());
648                    goto error;
649                }
650                else {
651                    //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
652                }
653            }
654        }
655
656        size_t objectSlotCount = 0;
657        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
658            goto error;
659        }
660        if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
661            ALOGE("Invalid object slot count!: %s", line);
662            goto error;
663        }
664
665        if (objectSlotCount > 0) {
666            rsAssert(varCount > 0);
667            for (size_t i = 0; i < objectSlotCount; ++i) {
668                uint32_t varNum = 0;
669                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
670                    goto error;
671                }
672                if (sscanf(line, "%u", &varNum) != 1) {
673                    ALOGE("Invalid object slot!: %s", line);
674                    goto error;
675                }
676
677                if (varNum < varCount) {
678                    mFieldIsObject[varNum] = true;
679                }
680            }
681        }
682
683        if (varCount > 0) {
684            mBoundAllocs = new Allocation *[varCount];
685            memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
686        }
687
688        if (mScriptSO == (void*)1) {
689            //rsdLookupRuntimeStub(script, "acos");
690        }
691    } else {
692        goto error;
693    }
694#endif
695    mCtx->unlockMutex();
696    return true;
697
698#ifdef RS_COMPATIBILITY_LIB
699error:
700
701    mCtx->unlockMutex();
702    delete[] mInvokeFunctions;
703    delete[] mForEachFunctions;
704    delete[] mFieldAddress;
705    delete[] mFieldIsObject;
706    delete[] mForEachSignatures;
707    delete[] mBoundAllocs;
708    if (mScriptSO) {
709        dlclose(mScriptSO);
710    }
711    return false;
712#endif
713}
714
715#ifndef RS_COMPATIBILITY_LIB
716
717#ifdef __LP64__
718#define SYSLIBPATH "/system/lib64"
719#else
720#define SYSLIBPATH "/system/lib"
721#endif
722
723const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
724                                          size_t bitcodeSize) {
725    const char* defaultLib = SYSLIBPATH"/libclcore.bc";
726
727    // If we're debugging, use the debug library.
728    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
729        return SYSLIBPATH"/libclcore_debug.bc";
730    }
731
732    // If a callback has been registered to specify a library, use that.
733    RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
734    if (selectRTCallback != NULL) {
735        return selectRTCallback((const char*)bitcode, bitcodeSize);
736    }
737
738    // Check for a platform specific library
739#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
740    enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
741    if (prec == bcinfo::RS_FP_Relaxed) {
742        // NEON-capable ARMv7a devices can use an accelerated math library
743        // for all reduced precision scripts.
744        // ARMv8 does not use NEON, as ASIMD can be used with all precision
745        // levels.
746        return SYSLIBPATH"/libclcore_neon.bc";
747    } else {
748        return defaultLib;
749    }
750#elif defined(__i386__) || defined(__x86_64__)
751    // x86 devices will use an optimized library.
752    return SYSLIBPATH"/libclcore_x86.bc";
753#else
754    return defaultLib;
755#endif
756}
757
758#endif
759
760void RsdCpuScriptImpl::populateScript(Script *script) {
761#ifndef RS_COMPATIBILITY_LIB
762    // Copy info over to runtime
763    script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
764    script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
765    script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
766    script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
767    script->mHal.info.exportedPragmaKeyList =
768        const_cast<const char**>(mExecutable->getPragmaKeys().array());
769    script->mHal.info.exportedPragmaValueList =
770        const_cast<const char**>(mExecutable->getPragmaValues().array());
771
772    if (mRootExpand) {
773        script->mHal.info.root = mRootExpand;
774    } else {
775        script->mHal.info.root = mRoot;
776    }
777#else
778    // Copy info over to runtime
779    script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
780    script->mHal.info.exportedVariableCount = mExportedVariableCount;
781    script->mHal.info.exportedPragmaCount = 0;
782    script->mHal.info.exportedPragmaKeyList = 0;
783    script->mHal.info.exportedPragmaValueList = 0;
784
785    // Bug, need to stash in metadata
786    if (mRootExpand) {
787        script->mHal.info.root = mRootExpand;
788    } else {
789        script->mHal.info.root = mRoot;
790    }
791#endif
792}
793
794
795typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
796
797void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout,
798                                        const void * usr, uint32_t usrLen,
799                                        const RsScriptCall *sc,
800                                        MTLaunchStruct *mtls) {
801
802    memset(mtls, 0, sizeof(MTLaunchStruct));
803
804    // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
805    if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
806        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
807        return;
808    }
809    if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
810        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
811        return;
812    }
813
814    if (ain != NULL) {
815        const Type *inType = ain->getType();
816
817        mtls->fep.dimX = inType->getDimX();
818        mtls->fep.dimY = inType->getDimY();
819        mtls->fep.dimZ = inType->getDimZ();
820
821    } else if (aout != NULL) {
822        const Type *outType = aout->getType();
823
824        mtls->fep.dimX = outType->getDimX();
825        mtls->fep.dimY = outType->getDimY();
826        mtls->fep.dimZ = outType->getDimZ();
827
828    } else {
829        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
830        return;
831    }
832
833    if (ain != NULL && aout != NULL) {
834        if (!ain->hasSameDims(aout)) {
835            mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
836              "Failed to launch kernel; dimensions of input and output allocations do not match.");
837
838            return;
839        }
840    }
841
842    if (!sc || (sc->xEnd == 0)) {
843        mtls->xEnd = mtls->fep.dimX;
844    } else {
845        rsAssert(sc->xStart < mtls->fep.dimX);
846        rsAssert(sc->xEnd <= mtls->fep.dimX);
847        rsAssert(sc->xStart < sc->xEnd);
848        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
849        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
850        if (mtls->xStart >= mtls->xEnd) return;
851    }
852
853    if (!sc || (sc->yEnd == 0)) {
854        mtls->yEnd = mtls->fep.dimY;
855    } else {
856        rsAssert(sc->yStart < mtls->fep.dimY);
857        rsAssert(sc->yEnd <= mtls->fep.dimY);
858        rsAssert(sc->yStart < sc->yEnd);
859        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
860        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
861        if (mtls->yStart >= mtls->yEnd) return;
862    }
863
864    if (!sc || (sc->zEnd == 0)) {
865        mtls->zEnd = mtls->fep.dimZ;
866    } else {
867        rsAssert(sc->zStart < mtls->fep.dimZ);
868        rsAssert(sc->zEnd <= mtls->fep.dimZ);
869        rsAssert(sc->zStart < sc->zEnd);
870        mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
871        mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
872        if (mtls->zStart >= mtls->zEnd) return;
873    }
874
875    mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
876    mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
877    mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
878    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
879
880    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
881
882    mtls->rsc = mCtx;
883    mtls->ain = ain;
884    mtls->aout = aout;
885    mtls->fep.usr = usr;
886    mtls->fep.usrLen = usrLen;
887    mtls->mSliceSize = 1;
888    mtls->mSliceNum = 0;
889
890    mtls->fep.ptrIn = NULL;
891    mtls->fep.eStrideIn = 0;
892    mtls->isThreadable = mIsThreadable;
893
894    if (ain) {
895        mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr;
896        mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
897        mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride;
898    }
899
900    mtls->fep.ptrOut = NULL;
901    mtls->fep.eStrideOut = 0;
902    if (aout) {
903        mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
904        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
905        mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
906    }
907}
908
909void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains, uint32_t inLen,
910                                        Allocation * aout,
911                                        const void * usr, uint32_t usrLen,
912                                        const RsScriptCall *sc,
913                                        MTLaunchStruct *mtls) {
914
915    memset(mtls, 0, sizeof(MTLaunchStruct));
916
917    // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
918    if (ains != NULL) {
919        for (int index = inLen; --index >= 0;) {
920            const Allocation* ain = ains[index];
921
922            if (ain != NULL && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
923                mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
924                return;
925            }
926        }
927    }
928
929    if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
930        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
931        return;
932    }
933
934    if (ains != NULL) {
935        const Allocation *ain0   = ains[0];
936        const Type       *inType = ain0->getType();
937
938        mtls->fep.dimX = inType->getDimX();
939        mtls->fep.dimY = inType->getDimY();
940        mtls->fep.dimZ = inType->getDimZ();
941
942        for (int Index = inLen; --Index >= 1;) {
943            if (!ain0->hasSameDims(ains[Index])) {
944                mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
945                  "Failed to launch kernel; dimensions of input and output allocations do not match.");
946
947                return;
948            }
949        }
950
951    } else if (aout != NULL) {
952        const Type *outType = aout->getType();
953
954        mtls->fep.dimX = outType->getDimX();
955        mtls->fep.dimY = outType->getDimY();
956        mtls->fep.dimZ = outType->getDimZ();
957
958    } else {
959        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
960        return;
961    }
962
963    if (ains != NULL && aout != NULL) {
964        if (!ains[0]->hasSameDims(aout)) {
965            mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
966              "Failed to launch kernel; dimensions of input and output allocations do not match.");
967
968            return;
969        }
970    }
971
972    if (!sc || (sc->xEnd == 0)) {
973        mtls->xEnd = mtls->fep.dimX;
974    } else {
975        rsAssert(sc->xStart < mtls->fep.dimX);
976        rsAssert(sc->xEnd <= mtls->fep.dimX);
977        rsAssert(sc->xStart < sc->xEnd);
978        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
979        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
980        if (mtls->xStart >= mtls->xEnd) return;
981    }
982
983    if (!sc || (sc->yEnd == 0)) {
984        mtls->yEnd = mtls->fep.dimY;
985    } else {
986        rsAssert(sc->yStart < mtls->fep.dimY);
987        rsAssert(sc->yEnd <= mtls->fep.dimY);
988        rsAssert(sc->yStart < sc->yEnd);
989        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
990        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
991        if (mtls->yStart >= mtls->yEnd) return;
992    }
993
994    if (!sc || (sc->zEnd == 0)) {
995        mtls->zEnd = mtls->fep.dimZ;
996    } else {
997        rsAssert(sc->zStart < mtls->fep.dimZ);
998        rsAssert(sc->zEnd <= mtls->fep.dimZ);
999        rsAssert(sc->zStart < sc->zEnd);
1000        mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
1001        mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
1002        if (mtls->zStart >= mtls->zEnd) return;
1003    }
1004
1005    mtls->xEnd     = rsMax((uint32_t)1, mtls->xEnd);
1006    mtls->yEnd     = rsMax((uint32_t)1, mtls->yEnd);
1007    mtls->zEnd     = rsMax((uint32_t)1, mtls->zEnd);
1008    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
1009
1010    rsAssert(!ains || (ains[0]->getType()->getDimZ() == 0));
1011
1012    mtls->rsc        = mCtx;
1013    mtls->ains       = ains;
1014    mtls->aout       = aout;
1015    mtls->fep.usr    = usr;
1016    mtls->fep.usrLen = usrLen;
1017    mtls->mSliceSize = 1;
1018    mtls->mSliceNum  = 0;
1019
1020    mtls->fep.ptrIns    = NULL;
1021    mtls->fep.eStrideIn = 0;
1022    mtls->isThreadable  = mIsThreadable;
1023
1024    if (ains) {
1025        mtls->fep.ptrIns    = new const uint8_t*[inLen];
1026        mtls->fep.inStrides = new StridePair[inLen];
1027
1028        for (int index = inLen; --index >= 0;) {
1029            const Allocation *ain = ains[index];
1030
1031            mtls->fep.ptrIns[index] =
1032              (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr;
1033
1034            mtls->fep.inStrides[index].eStride =
1035              ain->getType()->getElementSizeBytes();
1036            mtls->fep.inStrides[index].yStride =
1037              ain->mHal.drvState.lod[0].stride;
1038        }
1039    }
1040
1041    mtls->fep.ptrOut = NULL;
1042    mtls->fep.eStrideOut = 0;
1043    if (aout) {
1044        mtls->fep.ptrOut     = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
1045        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
1046        mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
1047    }
1048}
1049
1050
1051void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
1052                                     const Allocation * ain,
1053                                     Allocation * aout,
1054                                     const void * usr,
1055                                     uint32_t usrLen,
1056                                     const RsScriptCall *sc) {
1057
1058    MTLaunchStruct mtls;
1059    forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls);
1060    forEachKernelSetup(slot, &mtls);
1061
1062    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1063    mCtx->launchThreads(ain, aout, sc, &mtls);
1064    mCtx->setTLS(oldTLS);
1065}
1066
1067void RsdCpuScriptImpl::invokeForEachMulti(uint32_t slot,
1068                                          const Allocation ** ains,
1069                                          uint32_t inLen,
1070                                          Allocation * aout,
1071                                          const void * usr,
1072                                          uint32_t usrLen,
1073                                          const RsScriptCall *sc) {
1074
1075    MTLaunchStruct mtls;
1076
1077    forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls);
1078    forEachKernelSetup(slot, &mtls);
1079
1080    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1081    mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
1082    mCtx->setTLS(oldTLS);
1083}
1084
1085void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
1086    mtls->script = this;
1087    mtls->fep.slot = slot;
1088#ifndef RS_COMPATIBILITY_LIB
1089    rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
1090    mtls->kernel = reinterpret_cast<ForEachFunc_t>(
1091                      mExecutable->getExportForeachFuncAddrs()[slot]);
1092    rsAssert(mtls->kernel != NULL);
1093    mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
1094#else
1095    mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
1096    rsAssert(mtls->kernel != NULL);
1097    mtls->sig = mForEachSignatures[slot];
1098#endif
1099}
1100
1101int RsdCpuScriptImpl::invokeRoot() {
1102    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1103    int ret = mRoot();
1104    mCtx->setTLS(oldTLS);
1105    return ret;
1106}
1107
1108void RsdCpuScriptImpl::invokeInit() {
1109    if (mInit) {
1110        mInit();
1111    }
1112}
1113
1114void RsdCpuScriptImpl::invokeFreeChildren() {
1115    if (mFreeChildren) {
1116        mFreeChildren();
1117    }
1118}
1119
1120void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
1121                                      size_t paramLength) {
1122    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
1123
1124    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1125    reinterpret_cast<void (*)(const void *, uint32_t)>(
1126#ifndef RS_COMPATIBILITY_LIB
1127        mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
1128#else
1129        mInvokeFunctions[slot])(params, paramLength);
1130#endif
1131    mCtx->setTLS(oldTLS);
1132}
1133
1134void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
1135    //rsAssert(!script->mFieldIsObject[slot]);
1136    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1137
1138    //if (mIntrinsicID) {
1139        //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
1140        //return;
1141    //}
1142
1143#ifndef RS_COMPATIBILITY_LIB
1144    int32_t *destPtr = reinterpret_cast<int32_t *>(
1145                          mExecutable->getExportVarAddrs()[slot]);
1146#else
1147    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1148#endif
1149    if (!destPtr) {
1150        //ALOGV("Calling setVar on slot = %i which is null", slot);
1151        return;
1152    }
1153
1154    memcpy(destPtr, data, dataLength);
1155}
1156
1157void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
1158    //rsAssert(!script->mFieldIsObject[slot]);
1159    //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1160
1161#ifndef RS_COMPATIBILITY_LIB
1162    int32_t *srcPtr = reinterpret_cast<int32_t *>(
1163                          mExecutable->getExportVarAddrs()[slot]);
1164#else
1165    int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1166#endif
1167    if (!srcPtr) {
1168        //ALOGV("Calling setVar on slot = %i which is null", slot);
1169        return;
1170    }
1171    memcpy(data, srcPtr, dataLength);
1172}
1173
1174
1175void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1176                                                const Element *elem,
1177                                                const uint32_t *dims, size_t dimLength) {
1178
1179#ifndef RS_COMPATIBILITY_LIB
1180    int32_t *destPtr = reinterpret_cast<int32_t *>(
1181        mExecutable->getExportVarAddrs()[slot]);
1182#else
1183    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1184#endif
1185    if (!destPtr) {
1186        //ALOGV("Calling setVar on slot = %i which is null", slot);
1187        return;
1188    }
1189
1190    // We want to look at dimension in terms of integer components,
1191    // but dimLength is given in terms of bytes.
1192    dimLength /= sizeof(int);
1193
1194    // Only a single dimension is currently supported.
1195    rsAssert(dimLength == 1);
1196    if (dimLength == 1) {
1197        // First do the increment loop.
1198        size_t stride = elem->getSizeBytes();
1199        const char *cVal = reinterpret_cast<const char *>(data);
1200        for (uint32_t i = 0; i < dims[0]; i++) {
1201            elem->incRefs(cVal);
1202            cVal += stride;
1203        }
1204
1205        // Decrement loop comes after (to prevent race conditions).
1206        char *oldVal = reinterpret_cast<char *>(destPtr);
1207        for (uint32_t i = 0; i < dims[0]; i++) {
1208            elem->decRefs(oldVal);
1209            oldVal += stride;
1210        }
1211    }
1212
1213    memcpy(destPtr, data, dataLength);
1214}
1215
1216void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1217
1218    //rsAssert(!script->mFieldIsObject[slot]);
1219    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
1220
1221#ifndef RS_COMPATIBILITY_LIB
1222    int32_t *destPtr = reinterpret_cast<int32_t *>(
1223                          mExecutable->getExportVarAddrs()[slot]);
1224#else
1225    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1226#endif
1227    if (!destPtr) {
1228        //ALOGV("Calling setVar on slot = %i which is null", slot);
1229        return;
1230    }
1231
1232    void *ptr = NULL;
1233    mBoundAllocs[slot] = data;
1234    if(data) {
1235        ptr = data->mHal.drvState.lod[0].mallocPtr;
1236    }
1237    memcpy(destPtr, &ptr, sizeof(void *));
1238}
1239
1240void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1241
1242    //rsAssert(script->mFieldIsObject[slot]);
1243    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
1244
1245#ifndef RS_COMPATIBILITY_LIB
1246    int32_t *destPtr = reinterpret_cast<int32_t *>(
1247                          mExecutable->getExportVarAddrs()[slot]);
1248#else
1249    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1250#endif
1251
1252    if (!destPtr) {
1253        //ALOGV("Calling setVar on slot = %i which is null", slot);
1254        return;
1255    }
1256
1257    rsrSetObject(mCtx->getContext(), (rs_object_base *)destPtr, data);
1258}
1259
1260RsdCpuScriptImpl::~RsdCpuScriptImpl() {
1261#ifndef RS_COMPATIBILITY_LIB
1262    if (mExecutable) {
1263        Vector<void *>::const_iterator var_addr_iter =
1264            mExecutable->getExportVarAddrs().begin();
1265        Vector<void *>::const_iterator var_addr_end =
1266            mExecutable->getExportVarAddrs().end();
1267
1268        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_iter =
1269            mExecutable->getInfo().getObjectSlots().begin();
1270        bcc::RSInfo::ObjectSlotListTy::const_iterator is_object_end =
1271            mExecutable->getInfo().getObjectSlots().end();
1272
1273        while ((var_addr_iter != var_addr_end) &&
1274               (is_object_iter != is_object_end)) {
1275            // The field address can be NULL if the script-side has optimized
1276            // the corresponding global variable away.
1277            rs_object_base *obj_addr =
1278                reinterpret_cast<rs_object_base *>(*var_addr_iter);
1279            if (*is_object_iter) {
1280                if (*var_addr_iter != NULL && mCtx->getContext() != NULL) {
1281                    rsrClearObject(mCtx->getContext(), obj_addr);
1282                }
1283            }
1284            var_addr_iter++;
1285            is_object_iter++;
1286        }
1287    }
1288
1289    if (mCompilerContext) {
1290        delete mCompilerContext;
1291    }
1292    if (mCompilerDriver) {
1293        delete mCompilerDriver;
1294    }
1295    if (mExecutable) {
1296        delete mExecutable;
1297    }
1298    if (mBoundAllocs) {
1299        delete[] mBoundAllocs;
1300    }
1301
1302    for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) {
1303        delete[] mExportedForEachFuncList[i].first;
1304    }
1305#else
1306    if (mFieldIsObject) {
1307        for (size_t i = 0; i < mExportedVariableCount; ++i) {
1308            if (mFieldIsObject[i]) {
1309                if (mFieldAddress[i] != NULL) {
1310                    rs_object_base *obj_addr =
1311                        reinterpret_cast<rs_object_base *>(mFieldAddress[i]);
1312                    rsrClearObject(mCtx->getContext(), obj_addr);
1313                }
1314            }
1315        }
1316    }
1317
1318    if (mInvokeFunctions) delete[] mInvokeFunctions;
1319    if (mForEachFunctions) delete[] mForEachFunctions;
1320    if (mFieldAddress) delete[] mFieldAddress;
1321    if (mFieldIsObject) delete[] mFieldIsObject;
1322    if (mForEachSignatures) delete[] mForEachSignatures;
1323    if (mBoundAllocs) delete[] mBoundAllocs;
1324    if (mScriptSO) {
1325        dlclose(mScriptSO);
1326    }
1327#endif
1328}
1329
1330Allocation * RsdCpuScriptImpl::getAllocationForPointer(const void *ptr) const {
1331    if (!ptr) {
1332        return NULL;
1333    }
1334
1335    for (uint32_t ct=0; ct < mScript->mHal.info.exportedVariableCount; ct++) {
1336        Allocation *a = mBoundAllocs[ct];
1337        if (!a) continue;
1338        if (a->mHal.drvState.lod[0].mallocPtr == ptr) {
1339            return a;
1340        }
1341    }
1342    ALOGE("rsGetAllocation, failed to find %p", ptr);
1343    return NULL;
1344}
1345
1346void RsdCpuScriptImpl::preLaunch(uint32_t slot, const Allocation * ain,
1347                       Allocation * aout, const void * usr,
1348                       uint32_t usrLen, const RsScriptCall *sc)
1349{
1350}
1351
1352void RsdCpuScriptImpl::postLaunch(uint32_t slot, const Allocation * ain,
1353                        Allocation * aout, const void * usr,
1354                        uint32_t usrLen, const RsScriptCall *sc)
1355{
1356}
1357
1358
1359}
1360}
1361