rsCpuScript.cpp revision 4b3c34e6833e39bc89c2128002806b654b8e623d
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    // Execute the bcc compiler.
234    if (useRSDebugContext) {
235        args->push_back("-rs-debug-ctx");
236    } else {
237        // Only load additional libraries for compiles that don't use
238        // the debug context.
239        if (bccPluginName && strlen(bccPluginName) > 0) {
240            args->push_back("-load");
241            args->push_back(bccPluginName);
242        }
243    }
244
245    args->push_back(bcFileName.string());
246    args->push_back(NULL);
247}
248
249static bool compileBitcode(const android::String8& bcFileName,
250                           const char *bitcode,
251                           size_t bitcodeSize,
252                           const char** compileArguments,
253                           const std::string& compileCommandLine) {
254    rsAssert(bitcode && bitcodeSize);
255
256    FILE *bcfile = fopen(bcFileName.string(), "w");
257    if (!bcfile) {
258        ALOGE("Could not write to %s", bcFileName.string());
259        return false;
260    }
261    size_t nwritten = fwrite(bitcode, 1, bitcodeSize, bcfile);
262    fclose(bcfile);
263    if (nwritten != bitcodeSize) {
264        ALOGE("Could not write %zu bytes to %s", bitcodeSize,
265              bcFileName.string());
266        return false;
267    }
268
269    pid_t pid = fork();
270
271    switch (pid) {
272    case -1: {  // Error occurred (we attempt no recovery)
273        ALOGE("Couldn't fork for bcc compiler execution");
274        return false;
275    }
276    case 0: {  // Child process
277        ALOGV("Invoking BCC with: %s", compileCommandLine.c_str());
278        execv(BCC_EXE_PATH, (char* const*)compileArguments);
279
280        ALOGE("execv() failed: %s", strerror(errno));
281        abort();
282        return false;
283    }
284    default: {  // Parent process (actual driver)
285        // Wait on child process to finish compiling the source.
286        int status = 0;
287        pid_t w = waitpid(pid, &status, 0);
288        if (w == -1) {
289            ALOGE("Could not wait for bcc compiler");
290            return false;
291        }
292
293        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
294            return true;
295        }
296
297        ALOGE("bcc compiler terminated unexpectedly");
298        return false;
299    }
300    }
301}
302
303#endif  // !defined(RS_COMPATIBILITY_LIB)
304}  // namespace
305
306namespace android {
307namespace renderscript {
308
309#ifdef RS_COMPATIBILITY_LIB
310#define MAXLINE 500
311#define MAKE_STR_HELPER(S) #S
312#define MAKE_STR(S) MAKE_STR_HELPER(S)
313#define EXPORT_VAR_STR "exportVarCount: "
314#define EXPORT_FUNC_STR "exportFuncCount: "
315#define EXPORT_FOREACH_STR "exportForEachCount: "
316#define OBJECT_SLOT_STR "objectSlotCount: "
317
318// Copy up to a newline or size chars from str -> s, updating str
319// Returns s when successful and NULL when '\0' is finally reached.
320static char* strgets(char *s, int size, const char **ppstr) {
321    if (!ppstr || !*ppstr || **ppstr == '\0' || size < 1) {
322        return NULL;
323    }
324
325    int i;
326    for (i = 0; i < (size - 1); i++) {
327        s[i] = **ppstr;
328        (*ppstr)++;
329        if (s[i] == '\0') {
330            return s;
331        } else if (s[i] == '\n') {
332            s[i+1] = '\0';
333            return s;
334        }
335    }
336
337    // size has been exceeded.
338    s[i] = '\0';
339
340    return s;
341}
342#endif
343
344RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
345    mCtx = ctx;
346    mScript = s;
347
348#ifdef RS_COMPATIBILITY_LIB
349    mScriptSO = NULL;
350    mInvokeFunctions = NULL;
351    mForEachFunctions = NULL;
352    mFieldAddress = NULL;
353    mFieldIsObject = NULL;
354    mForEachSignatures = NULL;
355#else
356    mCompilerContext = NULL;
357    mCompilerDriver = NULL;
358    mExecutable = NULL;
359#endif
360
361
362    mRoot = NULL;
363    mRootExpand = NULL;
364    mInit = NULL;
365    mFreeChildren = NULL;
366
367
368    mBoundAllocs = NULL;
369    mIntrinsicData = NULL;
370    mIsThreadable = true;
371}
372
373
374bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
375                            uint8_t const *bitcode, size_t bitcodeSize,
376                            uint32_t flags, char const *bccPluginName) {
377    //ALOGE("rsdScriptCreate %p %p %p %p %i %i %p", rsc, resName, cacheDir, bitcode, bitcodeSize, flags, lookupFunc);
378    //ALOGE("rsdScriptInit %p %p", rsc, script);
379
380    mCtx->lockMutex();
381#ifndef RS_COMPATIBILITY_LIB
382    bool useRSDebugContext = false;
383
384    mCompilerContext = NULL;
385    mCompilerDriver = NULL;
386    mExecutable = NULL;
387
388    mCompilerContext = new bcc::BCCContext();
389    if (mCompilerContext == NULL) {
390        ALOGE("bcc: FAILS to create compiler context (out of memory)");
391        mCtx->unlockMutex();
392        return false;
393    }
394
395    mCompilerDriver = new bcc::RSCompilerDriver();
396    if (mCompilerDriver == NULL) {
397        ALOGE("bcc: FAILS to create compiler driver (out of memory)");
398        mCtx->unlockMutex();
399        return false;
400    }
401
402    // Configure symbol resolvers (via compiler-rt and the RS runtime).
403    mRSRuntime.setLookupFunction(lookupRuntimeStub);
404    mRSRuntime.setContext(this);
405    mResolver.chainResolver(mCompilerRuntime);
406    mResolver.chainResolver(mRSRuntime);
407
408    // Run any compiler setup functions we have been provided with.
409    RSSetupCompilerCallback setupCompilerCallback =
410            mCtx->getSetupCompilerCallback();
411    if (setupCompilerCallback != NULL) {
412        setupCompilerCallback(mCompilerDriver);
413    }
414
415    bcinfo::MetadataExtractor bitcodeMetadata((const char *) bitcode, bitcodeSize);
416    if (!bitcodeMetadata.extract()) {
417        ALOGE("Could not extract metadata from bitcode");
418        mCtx->unlockMutex();
419        return false;
420    }
421
422    const char* core_lib = findCoreLib(bitcodeMetadata, (const char*)bitcode, bitcodeSize);
423
424    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
425        mCompilerDriver->setDebugContext(true);
426        useRSDebugContext = true;
427    }
428
429    android::String8 bcFileName(cacheDir);
430    bcFileName.append("/");
431    bcFileName.append(resName);
432    bcFileName.append(".bc");
433
434    std::vector<const char*> compileArguments;
435    setCompileArguments(&compileArguments, bcFileName, cacheDir, resName, core_lib,
436                        useRSDebugContext, bccPluginName);
437    // The last argument of compileArguments ia a NULL, so remove 1 from the size.
438    std::string compileCommandLine =
439                bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
440
441    if (!is_force_recompile()) {
442        // Load the compiled script that's in the cache, if any.
443        mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
444                                                        bitcodeSize, compileCommandLine.c_str(),
445                                                        mResolver);
446    }
447
448    // If we can't, it's either not there or out of date.  We compile the bit code and try loading
449    // again.
450    if (mExecutable == NULL) {
451        if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(),
452                            compileCommandLine)) {
453            ALOGE("bcc: FAILS to compile '%s'", resName);
454            mCtx->unlockMutex();
455            return false;
456        }
457        mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
458                                                        bitcodeSize, compileCommandLine.c_str(),
459                                                        mResolver);
460        if (mExecutable == NULL) {
461            ALOGE("bcc: FAILS to load freshly compiled executable for '%s'", resName);
462            mCtx->unlockMutex();
463            return false;
464        }
465    }
466
467    mExecutable->setThreadable(mIsThreadable);
468    if (!mExecutable->syncInfo()) {
469        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
470    }
471
472    mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
473    mRootExpand =
474        reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
475    mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
476    mFreeChildren =
477        reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
478
479
480    if (bitcodeMetadata.getExportVarCount()) {
481        mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
482        memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
483    }
484
485    for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
486        char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
487        mExportedForEachFuncList.push_back(
488                    std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
489    }
490
491#else  // RS_COMPATIBILITY_LIB is defined
492
493    mScriptSO = loadSharedLibrary(cacheDir, resName);
494
495    if (mScriptSO) {
496        char line[MAXLINE];
497        mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
498        if (mRoot) {
499            //ALOGE("Found root(): %p", mRoot);
500        }
501        mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
502        if (mRootExpand) {
503            //ALOGE("Found root.expand(): %p", mRootExpand);
504        }
505        mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
506        if (mInit) {
507            //ALOGE("Found init(): %p", mInit);
508        }
509        mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
510        if (mFreeChildren) {
511            //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
512        }
513
514        const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
515        if (rsInfo) {
516            //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
517        }
518
519        size_t varCount = 0;
520        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
521            goto error;
522        }
523        if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
524            ALOGE("Invalid export var count!: %s", line);
525            goto error;
526        }
527
528        mExportedVariableCount = varCount;
529        //ALOGE("varCount: %zu", varCount);
530        if (varCount > 0) {
531            // Start by creating/zeroing this member, since we don't want to
532            // accidentally clean up invalid pointers later (if we error out).
533            mFieldIsObject = new bool[varCount];
534            if (mFieldIsObject == NULL) {
535                goto error;
536            }
537            memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
538            mFieldAddress = new void*[varCount];
539            if (mFieldAddress == NULL) {
540                goto error;
541            }
542            for (size_t i = 0; i < varCount; ++i) {
543                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
544                    goto error;
545                }
546                char *c = strrchr(line, '\n');
547                if (c) {
548                    *c = '\0';
549                }
550                mFieldAddress[i] = dlsym(mScriptSO, line);
551                if (mFieldAddress[i] == NULL) {
552                    ALOGE("Failed to find variable address for %s: %s",
553                          line, dlerror());
554                    // Not a critical error if we don't find a global variable.
555                }
556                else {
557                    //ALOGE("Found variable %s at %p", line,
558                    //mFieldAddress[i]);
559                }
560            }
561        }
562
563        size_t funcCount = 0;
564        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
565            goto error;
566        }
567        if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
568            ALOGE("Invalid export func count!: %s", line);
569            goto error;
570        }
571
572        mExportedFunctionCount = funcCount;
573        //ALOGE("funcCount: %zu", funcCount);
574
575        if (funcCount > 0) {
576            mInvokeFunctions = new InvokeFunc_t[funcCount];
577            if (mInvokeFunctions == NULL) {
578                goto error;
579            }
580            for (size_t i = 0; i < funcCount; ++i) {
581                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
582                    goto error;
583                }
584                char *c = strrchr(line, '\n');
585                if (c) {
586                    *c = '\0';
587                }
588
589                mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
590                if (mInvokeFunctions[i] == NULL) {
591                    ALOGE("Failed to get function address for %s(): %s",
592                          line, dlerror());
593                    goto error;
594                }
595                else {
596                    //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
597                }
598            }
599        }
600
601        size_t forEachCount = 0;
602        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
603            goto error;
604        }
605        if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
606            ALOGE("Invalid export forEach count!: %s", line);
607            goto error;
608        }
609
610        if (forEachCount > 0) {
611
612            mForEachSignatures = new uint32_t[forEachCount];
613            if (mForEachSignatures == NULL) {
614                goto error;
615            }
616            mForEachFunctions = new ForEachFunc_t[forEachCount];
617            if (mForEachFunctions == NULL) {
618                goto error;
619            }
620            for (size_t i = 0; i < forEachCount; ++i) {
621                unsigned int tmpSig = 0;
622                char tmpName[MAXLINE];
623
624                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
625                    goto error;
626                }
627                if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
628                           &tmpSig, tmpName) != 2) {
629                    ALOGE("Invalid export forEach!: %s", line);
630                    goto error;
631                }
632
633                // Lookup the expanded ForEach kernel.
634                strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
635                mForEachSignatures[i] = tmpSig;
636                mForEachFunctions[i] =
637                        (ForEachFunc_t) dlsym(mScriptSO, tmpName);
638                if (i != 0 && mForEachFunctions[i] == NULL) {
639                    // Ignore missing root.expand functions.
640                    // root() is always specified at location 0.
641                    ALOGE("Failed to find forEach function address for %s: %s",
642                          tmpName, dlerror());
643                    goto error;
644                }
645                else {
646                    //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
647                }
648            }
649        }
650
651        size_t objectSlotCount = 0;
652        if (strgets(line, MAXLINE, &rsInfo) == NULL) {
653            goto error;
654        }
655        if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
656            ALOGE("Invalid object slot count!: %s", line);
657            goto error;
658        }
659
660        if (objectSlotCount > 0) {
661            rsAssert(varCount > 0);
662            for (size_t i = 0; i < objectSlotCount; ++i) {
663                uint32_t varNum = 0;
664                if (strgets(line, MAXLINE, &rsInfo) == NULL) {
665                    goto error;
666                }
667                if (sscanf(line, "%u", &varNum) != 1) {
668                    ALOGE("Invalid object slot!: %s", line);
669                    goto error;
670                }
671
672                if (varNum < varCount) {
673                    mFieldIsObject[varNum] = true;
674                }
675            }
676        }
677
678        if (varCount > 0) {
679            mBoundAllocs = new Allocation *[varCount];
680            memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
681        }
682
683        if (mScriptSO == (void*)1) {
684            //rsdLookupRuntimeStub(script, "acos");
685        }
686    } else {
687        goto error;
688    }
689#endif
690    mCtx->unlockMutex();
691    return true;
692
693#ifdef RS_COMPATIBILITY_LIB
694error:
695
696    mCtx->unlockMutex();
697    delete[] mInvokeFunctions;
698    delete[] mForEachFunctions;
699    delete[] mFieldAddress;
700    delete[] mFieldIsObject;
701    delete[] mForEachSignatures;
702    delete[] mBoundAllocs;
703    if (mScriptSO) {
704        dlclose(mScriptSO);
705    }
706    return false;
707#endif
708}
709
710#ifndef RS_COMPATIBILITY_LIB
711
712#ifdef __LP64__
713#define SYSLIBPATH "/system/lib64"
714#else
715#define SYSLIBPATH "/system/lib"
716#endif
717
718const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
719                                          size_t bitcodeSize) {
720    const char* defaultLib = SYSLIBPATH"/libclcore.bc";
721
722    // If we're debugging, use the debug library.
723    if (mCtx->getContext()->getContextType() == RS_CONTEXT_TYPE_DEBUG) {
724        return SYSLIBPATH"/libclcore_debug.bc";
725    }
726
727    // If a callback has been registered to specify a library, use that.
728    RSSelectRTCallback selectRTCallback = mCtx->getSelectRTCallback();
729    if (selectRTCallback != NULL) {
730        return selectRTCallback((const char*)bitcode, bitcodeSize);
731    }
732
733    // Check for a platform specific library
734#if defined(ARCH_ARM_HAVE_NEON) && !defined(DISABLE_CLCORE_NEON)
735    enum bcinfo::RSFloatPrecision prec = ME.getRSFloatPrecision();
736    if (prec == bcinfo::RS_FP_Imprecise || prec == bcinfo::RS_FP_Relaxed) {
737        // NEON-capable ARMv7a devices can use an accelerated math library
738        // for all reduced precision scripts.
739        // ARMv8 does not use NEON, as ASIMD can be used with all precision
740        // levels.
741        return SYSLIBPATH"/libclcore_neon.bc";
742    } else {
743        return defaultLib;
744    }
745#elif defined(__i386__) || defined(__x86_64__)
746    // x86 devices will use an optimized library.
747    return SYSLIBPATH"/libclcore_x86.bc";
748#else
749    return defaultLib;
750#endif
751}
752
753#endif
754
755void RsdCpuScriptImpl::populateScript(Script *script) {
756#ifndef RS_COMPATIBILITY_LIB
757    // Copy info over to runtime
758    script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
759    script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
760    script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
761    script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
762    script->mHal.info.exportedPragmaKeyList =
763        const_cast<const char**>(mExecutable->getPragmaKeys().array());
764    script->mHal.info.exportedPragmaValueList =
765        const_cast<const char**>(mExecutable->getPragmaValues().array());
766
767    if (mRootExpand) {
768        script->mHal.info.root = mRootExpand;
769    } else {
770        script->mHal.info.root = mRoot;
771    }
772#else
773    // Copy info over to runtime
774    script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
775    script->mHal.info.exportedVariableCount = mExportedVariableCount;
776    script->mHal.info.exportedPragmaCount = 0;
777    script->mHal.info.exportedPragmaKeyList = 0;
778    script->mHal.info.exportedPragmaValueList = 0;
779
780    // Bug, need to stash in metadata
781    if (mRootExpand) {
782        script->mHal.info.root = mRootExpand;
783    } else {
784        script->mHal.info.root = mRoot;
785    }
786#endif
787}
788
789
790typedef void (*rs_t)(const void *, void *, const void *, uint32_t, uint32_t, uint32_t, uint32_t);
791
792void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation * ain, Allocation * aout,
793                                        const void * usr, uint32_t usrLen,
794                                        const RsScriptCall *sc,
795                                        MTLaunchStruct *mtls) {
796
797    memset(mtls, 0, sizeof(MTLaunchStruct));
798
799    // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
800    if (ain && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
801        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
802        return;
803    }
804    if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
805        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
806        return;
807    }
808
809    if (ain != NULL) {
810        const Type *inType = ain->getType();
811
812        mtls->fep.dimX = inType->getDimX();
813        mtls->fep.dimY = inType->getDimY();
814        mtls->fep.dimZ = inType->getDimZ();
815
816    } else if (aout != NULL) {
817        const Type *outType = aout->getType();
818
819        mtls->fep.dimX = outType->getDimX();
820        mtls->fep.dimY = outType->getDimY();
821        mtls->fep.dimZ = outType->getDimZ();
822
823    } else {
824        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
825        return;
826    }
827
828    if (ain != NULL && aout != NULL) {
829        if (!ain->hasSameDims(aout)) {
830            mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
831              "Failed to launch kernel; dimensions of input and output allocations do not match.");
832
833            return;
834        }
835    }
836
837    if (!sc || (sc->xEnd == 0)) {
838        mtls->xEnd = mtls->fep.dimX;
839    } else {
840        rsAssert(sc->xStart < mtls->fep.dimX);
841        rsAssert(sc->xEnd <= mtls->fep.dimX);
842        rsAssert(sc->xStart < sc->xEnd);
843        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
844        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
845        if (mtls->xStart >= mtls->xEnd) return;
846    }
847
848    if (!sc || (sc->yEnd == 0)) {
849        mtls->yEnd = mtls->fep.dimY;
850    } else {
851        rsAssert(sc->yStart < mtls->fep.dimY);
852        rsAssert(sc->yEnd <= mtls->fep.dimY);
853        rsAssert(sc->yStart < sc->yEnd);
854        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
855        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
856        if (mtls->yStart >= mtls->yEnd) return;
857    }
858
859    if (!sc || (sc->zEnd == 0)) {
860        mtls->zEnd = mtls->fep.dimZ;
861    } else {
862        rsAssert(sc->zStart < mtls->fep.dimZ);
863        rsAssert(sc->zEnd <= mtls->fep.dimZ);
864        rsAssert(sc->zStart < sc->zEnd);
865        mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
866        mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
867        if (mtls->zStart >= mtls->zEnd) return;
868    }
869
870    mtls->xEnd = rsMax((uint32_t)1, mtls->xEnd);
871    mtls->yEnd = rsMax((uint32_t)1, mtls->yEnd);
872    mtls->zEnd = rsMax((uint32_t)1, mtls->zEnd);
873    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
874
875    rsAssert(!ain || (ain->getType()->getDimZ() == 0));
876
877    mtls->rsc = mCtx;
878    mtls->ain = ain;
879    mtls->aout = aout;
880    mtls->fep.usr = usr;
881    mtls->fep.usrLen = usrLen;
882    mtls->mSliceSize = 1;
883    mtls->mSliceNum = 0;
884
885    mtls->fep.ptrIn = NULL;
886    mtls->fep.eStrideIn = 0;
887    mtls->isThreadable = mIsThreadable;
888
889    if (ain) {
890        mtls->fep.ptrIn = (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr;
891        mtls->fep.eStrideIn = ain->getType()->getElementSizeBytes();
892        mtls->fep.yStrideIn = ain->mHal.drvState.lod[0].stride;
893    }
894
895    mtls->fep.ptrOut = NULL;
896    mtls->fep.eStrideOut = 0;
897    if (aout) {
898        mtls->fep.ptrOut = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
899        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
900        mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
901    }
902}
903
904void RsdCpuScriptImpl::forEachMtlsSetup(const Allocation ** ains, uint32_t inLen,
905                                        Allocation * aout,
906                                        const void * usr, uint32_t usrLen,
907                                        const RsScriptCall *sc,
908                                        MTLaunchStruct *mtls) {
909
910    memset(mtls, 0, sizeof(MTLaunchStruct));
911
912    // possible for this to occur if IO_OUTPUT/IO_INPUT with no bound surface
913    if (ains != NULL) {
914        for (int index = inLen; --index >= 0;) {
915            const Allocation* ain = ains[index];
916
917            if (ain != NULL && (const uint8_t *)ain->mHal.drvState.lod[0].mallocPtr == NULL) {
918                mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null in allocations");
919                return;
920            }
921        }
922    }
923
924    if (aout && (const uint8_t *)aout->mHal.drvState.lod[0].mallocPtr == NULL) {
925        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null out allocations");
926        return;
927    }
928
929    if (ains != NULL) {
930        const Allocation *ain0   = ains[0];
931        const Type       *inType = ain0->getType();
932
933        mtls->fep.dimX = inType->getDimX();
934        mtls->fep.dimY = inType->getDimY();
935        mtls->fep.dimZ = inType->getDimZ();
936
937        for (int Index = inLen; --Index >= 1;) {
938            if (!ain0->hasSameDims(ains[Index])) {
939                mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
940                  "Failed to launch kernel; dimensions of input and output allocations do not match.");
941
942                return;
943            }
944        }
945
946    } else if (aout != NULL) {
947        const Type *outType = aout->getType();
948
949        mtls->fep.dimX = outType->getDimX();
950        mtls->fep.dimY = outType->getDimY();
951        mtls->fep.dimZ = outType->getDimZ();
952
953    } else {
954        mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT, "rsForEach called with null allocations");
955        return;
956    }
957
958    if (ains != NULL && aout != NULL) {
959        if (!ains[0]->hasSameDims(aout)) {
960            mCtx->getContext()->setError(RS_ERROR_BAD_SCRIPT,
961              "Failed to launch kernel; dimensions of input and output allocations do not match.");
962
963            return;
964        }
965    }
966
967    if (!sc || (sc->xEnd == 0)) {
968        mtls->xEnd = mtls->fep.dimX;
969    } else {
970        rsAssert(sc->xStart < mtls->fep.dimX);
971        rsAssert(sc->xEnd <= mtls->fep.dimX);
972        rsAssert(sc->xStart < sc->xEnd);
973        mtls->xStart = rsMin(mtls->fep.dimX, sc->xStart);
974        mtls->xEnd = rsMin(mtls->fep.dimX, sc->xEnd);
975        if (mtls->xStart >= mtls->xEnd) return;
976    }
977
978    if (!sc || (sc->yEnd == 0)) {
979        mtls->yEnd = mtls->fep.dimY;
980    } else {
981        rsAssert(sc->yStart < mtls->fep.dimY);
982        rsAssert(sc->yEnd <= mtls->fep.dimY);
983        rsAssert(sc->yStart < sc->yEnd);
984        mtls->yStart = rsMin(mtls->fep.dimY, sc->yStart);
985        mtls->yEnd = rsMin(mtls->fep.dimY, sc->yEnd);
986        if (mtls->yStart >= mtls->yEnd) return;
987    }
988
989    if (!sc || (sc->zEnd == 0)) {
990        mtls->zEnd = mtls->fep.dimZ;
991    } else {
992        rsAssert(sc->zStart < mtls->fep.dimZ);
993        rsAssert(sc->zEnd <= mtls->fep.dimZ);
994        rsAssert(sc->zStart < sc->zEnd);
995        mtls->zStart = rsMin(mtls->fep.dimZ, sc->zStart);
996        mtls->zEnd = rsMin(mtls->fep.dimZ, sc->zEnd);
997        if (mtls->zStart >= mtls->zEnd) return;
998    }
999
1000    mtls->xEnd     = rsMax((uint32_t)1, mtls->xEnd);
1001    mtls->yEnd     = rsMax((uint32_t)1, mtls->yEnd);
1002    mtls->zEnd     = rsMax((uint32_t)1, mtls->zEnd);
1003    mtls->arrayEnd = rsMax((uint32_t)1, mtls->arrayEnd);
1004
1005    rsAssert(!ains || (ains[0]->getType()->getDimZ() == 0));
1006
1007    mtls->rsc        = mCtx;
1008    mtls->ains       = ains;
1009    mtls->aout       = aout;
1010    mtls->fep.usr    = usr;
1011    mtls->fep.usrLen = usrLen;
1012    mtls->mSliceSize = 1;
1013    mtls->mSliceNum  = 0;
1014
1015    mtls->fep.ptrIns    = NULL;
1016    mtls->fep.eStrideIn = 0;
1017    mtls->isThreadable  = mIsThreadable;
1018
1019    if (ains) {
1020        mtls->fep.ptrIns    = new const uint8_t*[inLen];
1021        mtls->fep.inStrides = new StridePair[inLen];
1022
1023        for (int index = inLen; --index >= 0;) {
1024            const Allocation *ain = ains[index];
1025
1026            mtls->fep.ptrIns[index] =
1027              (const uint8_t*)ain->mHal.drvState.lod[0].mallocPtr;
1028
1029            mtls->fep.inStrides[index].eStride =
1030              ain->getType()->getElementSizeBytes();
1031            mtls->fep.inStrides[index].yStride =
1032              ain->mHal.drvState.lod[0].stride;
1033        }
1034    }
1035
1036    mtls->fep.ptrOut = NULL;
1037    mtls->fep.eStrideOut = 0;
1038    if (aout) {
1039        mtls->fep.ptrOut     = (uint8_t *)aout->mHal.drvState.lod[0].mallocPtr;
1040        mtls->fep.eStrideOut = aout->getType()->getElementSizeBytes();
1041        mtls->fep.yStrideOut = aout->mHal.drvState.lod[0].stride;
1042    }
1043}
1044
1045
1046void RsdCpuScriptImpl::invokeForEach(uint32_t slot,
1047                                     const Allocation * ain,
1048                                     Allocation * aout,
1049                                     const void * usr,
1050                                     uint32_t usrLen,
1051                                     const RsScriptCall *sc) {
1052
1053    MTLaunchStruct mtls;
1054    forEachMtlsSetup(ain, aout, usr, usrLen, sc, &mtls);
1055    forEachKernelSetup(slot, &mtls);
1056
1057    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1058    mCtx->launchThreads(ain, aout, sc, &mtls);
1059    mCtx->setTLS(oldTLS);
1060}
1061
1062void RsdCpuScriptImpl::invokeForEachMulti(uint32_t slot,
1063                                          const Allocation ** ains,
1064                                          uint32_t inLen,
1065                                          Allocation * aout,
1066                                          const void * usr,
1067                                          uint32_t usrLen,
1068                                          const RsScriptCall *sc) {
1069
1070    MTLaunchStruct mtls;
1071
1072    forEachMtlsSetup(ains, inLen, aout, usr, usrLen, sc, &mtls);
1073    forEachKernelSetup(slot, &mtls);
1074
1075    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1076    mCtx->launchThreads(ains, inLen, aout, sc, &mtls);
1077    mCtx->setTLS(oldTLS);
1078}
1079
1080void RsdCpuScriptImpl::forEachKernelSetup(uint32_t slot, MTLaunchStruct *mtls) {
1081    mtls->script = this;
1082    mtls->fep.slot = slot;
1083#ifndef RS_COMPATIBILITY_LIB
1084    rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
1085    mtls->kernel = reinterpret_cast<ForEachFunc_t>(
1086                      mExecutable->getExportForeachFuncAddrs()[slot]);
1087    rsAssert(mtls->kernel != NULL);
1088    mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
1089#else
1090    mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
1091    rsAssert(mtls->kernel != NULL);
1092    mtls->sig = mForEachSignatures[slot];
1093#endif
1094}
1095
1096int RsdCpuScriptImpl::invokeRoot() {
1097    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1098    int ret = mRoot();
1099    mCtx->setTLS(oldTLS);
1100    return ret;
1101}
1102
1103void RsdCpuScriptImpl::invokeInit() {
1104    if (mInit) {
1105        mInit();
1106    }
1107}
1108
1109void RsdCpuScriptImpl::invokeFreeChildren() {
1110    if (mFreeChildren) {
1111        mFreeChildren();
1112    }
1113}
1114
1115void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
1116                                      size_t paramLength) {
1117    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
1118
1119    RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
1120    reinterpret_cast<void (*)(const void *, uint32_t)>(
1121#ifndef RS_COMPATIBILITY_LIB
1122        mExecutable->getExportFuncAddrs()[slot])(params, paramLength);
1123#else
1124        mInvokeFunctions[slot])(params, paramLength);
1125#endif
1126    mCtx->setTLS(oldTLS);
1127}
1128
1129void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
1130    //rsAssert(!script->mFieldIsObject[slot]);
1131    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1132
1133    //if (mIntrinsicID) {
1134        //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
1135        //return;
1136    //}
1137
1138#ifndef RS_COMPATIBILITY_LIB
1139    int32_t *destPtr = reinterpret_cast<int32_t *>(
1140                          mExecutable->getExportVarAddrs()[slot]);
1141#else
1142    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1143#endif
1144    if (!destPtr) {
1145        //ALOGV("Calling setVar on slot = %i which is null", slot);
1146        return;
1147    }
1148
1149    memcpy(destPtr, data, dataLength);
1150}
1151
1152void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
1153    //rsAssert(!script->mFieldIsObject[slot]);
1154    //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
1155
1156#ifndef RS_COMPATIBILITY_LIB
1157    int32_t *srcPtr = reinterpret_cast<int32_t *>(
1158                          mExecutable->getExportVarAddrs()[slot]);
1159#else
1160    int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1161#endif
1162    if (!srcPtr) {
1163        //ALOGV("Calling setVar on slot = %i which is null", slot);
1164        return;
1165    }
1166    memcpy(data, srcPtr, dataLength);
1167}
1168
1169
1170void RsdCpuScriptImpl::setGlobalVarWithElemDims(uint32_t slot, const void *data, size_t dataLength,
1171                                                const Element *elem,
1172                                                const uint32_t *dims, size_t dimLength) {
1173
1174#ifndef RS_COMPATIBILITY_LIB
1175    int32_t *destPtr = reinterpret_cast<int32_t *>(
1176        mExecutable->getExportVarAddrs()[slot]);
1177#else
1178    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1179#endif
1180    if (!destPtr) {
1181        //ALOGV("Calling setVar on slot = %i which is null", slot);
1182        return;
1183    }
1184
1185    // We want to look at dimension in terms of integer components,
1186    // but dimLength is given in terms of bytes.
1187    dimLength /= sizeof(int);
1188
1189    // Only a single dimension is currently supported.
1190    rsAssert(dimLength == 1);
1191    if (dimLength == 1) {
1192        // First do the increment loop.
1193        size_t stride = elem->getSizeBytes();
1194        const char *cVal = reinterpret_cast<const char *>(data);
1195        for (uint32_t i = 0; i < dims[0]; i++) {
1196            elem->incRefs(cVal);
1197            cVal += stride;
1198        }
1199
1200        // Decrement loop comes after (to prevent race conditions).
1201        char *oldVal = reinterpret_cast<char *>(destPtr);
1202        for (uint32_t i = 0; i < dims[0]; i++) {
1203            elem->decRefs(oldVal);
1204            oldVal += stride;
1205        }
1206    }
1207
1208    memcpy(destPtr, data, dataLength);
1209}
1210
1211void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
1212
1213    //rsAssert(!script->mFieldIsObject[slot]);
1214    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
1215
1216#ifndef RS_COMPATIBILITY_LIB
1217    int32_t *destPtr = reinterpret_cast<int32_t *>(
1218                          mExecutable->getExportVarAddrs()[slot]);
1219#else
1220    int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
1221#endif
1222    if (!destPtr) {
1223        //ALOGV("Calling setVar on slot = %i which is null", slot);
1224        return;
1225    }
1226
1227    void *ptr = NULL;
1228    mBoundAllocs[slot] = data;
1229    if(data) {
1230        ptr = data->mHal.drvState.lod[0].mallocPtr;
1231    }
1232    memcpy(destPtr, &ptr, sizeof(void *));
1233}
1234
1235void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
1236
1237    //rsAssert(script->mFieldIsObject[slot]);
1238    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
1239
1240    //if (mIntrinsicID) {
1241        //mIntrinsicFuncs.setVarObj(dc, script, drv->mIntrinsicData, slot, alloc);
1242        //return;
1243    //}
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(), (ObjectBase **)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            ObjectBase **obj_addr =
1278                reinterpret_cast<ObjectBase **>(*var_addr_iter);
1279            if (*is_object_iter) {
1280                if (*var_addr_iter != 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                    ObjectBase **obj_addr =
1311                        reinterpret_cast<ObjectBase **>(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