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