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