Skip linkloader, use shared object files

Bug: 18322681

- In rsCpuScript, if property rs.skip.linkloader is set, look for a .so
  file in the cache directory and load it.  If it is not available, use
  bcc to generate relocatable object file and link it to a .so using
  ld.mc.  Use the embedded symbols in .rs.info and follow steps similar
  to the compatibility library to invoke script functions or access
  script variables.
- Add rs* symbols like rsGetAllocation to libRSCpuRef (ala
  libRSSupport).  Do necessary changes to argument types to get mangled
  names correct.
- Make 64-bit version of rsSetObject take two pointers instead of a
  pointer and a large object.  rsIsObject takes a pointer instead of a
  large object.  Otherwise, we get failures in x86_64 due to calling
  convention mismatch.  To match the function names in the shared object
  path, define these functions as 'extern "C"' with their mangled names.
- Add stubbed Math functions from rsCpuRuntimeMath and
  rsCpuRuntimeMathFuncs into libRSCpuRef.so.
- Coalesce separate #ifdef paths in libRSCpuRef.  Function parameters
  for runtime callbacks and bcc plugin are needed in the
  non-compatibilty path, but take default NULL arguments.  This patch
  introduces these parameters into the compatibility path as well, and
  passes default NULL arguments.

Change-Id: I8a853350e39d30b4d852c30e4b5da5a75a2f2820
diff --git a/cpu_ref/Android.mk b/cpu_ref/Android.mk
index e267fe9..6599932 100644
--- a/cpu_ref/Android.mk
+++ b/cpu_ref/Android.mk
@@ -22,6 +22,7 @@
 	rsCpuCore.cpp \
 	rsCpuScript.cpp \
 	rsCpuRuntimeMath.cpp \
+	rsCpuRuntimeMathFuncs.cpp \
 	rsCpuRuntimeStubs.cpp \
 	rsCpuScriptGroup.cpp \
 	rsCpuScriptGroup2.cpp \
@@ -79,7 +80,7 @@
     rsCpuIntrinsics_x86.cpp
 endif
 
-LOCAL_SHARED_LIBRARIES += libRS libcutils libutils liblog libsync libc++
+LOCAL_SHARED_LIBRARIES += libRS libcutils libutils liblog libsync libc++ libdl
 
 # these are not supported in 64-bit yet
 LOCAL_SHARED_LIBRARIES += libbcc libbcinfo
diff --git a/cpu_ref/rsCpuCore.cpp b/cpu_ref/rsCpuCore.cpp
index 84c2416..738eb84 100644
--- a/cpu_ref/rsCpuCore.cpp
+++ b/cpu_ref/rsCpuCore.cpp
@@ -64,11 +64,9 @@
 
 RsdCpuReference * RsdCpuReference::create(Context *rsc, uint32_t version_major,
         uint32_t version_minor, sym_lookup_t lfn, script_lookup_t slfn
-#ifndef RS_COMPATIBILITY_LIB
         , bcc::RSLinkRuntimeCallback pLinkRuntimeCallback,
         RSSelectRTCallback pSelectRTCallback,
         const char *pBccPluginName
-#endif
         ) {
 
     RsdCpuReferenceImpl *cpu = new RsdCpuReferenceImpl(rsc);
@@ -80,13 +78,11 @@
         return nullptr;
     }
 
-#ifndef RS_COMPATIBILITY_LIB
     cpu->setLinkRuntimeCallback(pLinkRuntimeCallback);
     cpu->setSelectRTCallback(pSelectRTCallback);
     if (pBccPluginName) {
         cpu->setBccPluginName(pBccPluginName);
     }
-#endif
 
     return cpu;
 }
@@ -116,11 +112,9 @@
     memset(&mWorkers, 0, sizeof(mWorkers));
     memset(&mTlsStruct, 0, sizeof(mTlsStruct));
     mExit = false;
-#ifndef RS_COMPATIBILITY_LIB
     mLinkRuntimeCallback = nullptr;
     mSelectRTCallback = nullptr;
     mSetupCompilerCallback = nullptr;
-#endif
 }
 
 
@@ -587,9 +581,7 @@
 
     RsdCpuScriptImpl *i = new RsdCpuScriptImpl(this, s);
     if (!i->init(resName, cacheDir, bitcode, bitcodeSize, flags
-#ifndef RS_COMPATIBILITY_LIB
         , getBccPluginName()
-#endif
         )) {
         delete i;
         return nullptr;
diff --git a/cpu_ref/rsCpuCore.h b/cpu_ref/rsCpuCore.h
index e069658..8060826 100644
--- a/cpu_ref/rsCpuCore.h
+++ b/cpu_ref/rsCpuCore.h
@@ -190,7 +190,6 @@
         return mScriptLookupFn(mRSC, s);
     }
 
-#ifndef RS_COMPATIBILITY_LIB
     void setLinkRuntimeCallback(
             bcc::RSLinkRuntimeCallback pLinkRuntimeCallback) {
         mLinkRuntimeCallback = pLinkRuntimeCallback;
@@ -220,7 +219,6 @@
     virtual const char *getBccPluginName() const {
         return mBccPluginName.c_str();
     }
-#endif
     virtual bool getInForEach() { return mInForEach; }
 
 protected:
@@ -248,12 +246,10 @@
 
     ScriptTLSStruct mTlsStruct;
 
-#ifndef RS_COMPATIBILITY_LIB
     bcc::RSLinkRuntimeCallback mLinkRuntimeCallback;
     RSSelectRTCallback mSelectRTCallback;
     RSSetupCompilerCallback mSetupCompilerCallback;
     std::string mBccPluginName;
-#endif
 };
 
 
diff --git a/cpu_ref/rsCpuRuntimeMath.cpp b/cpu_ref/rsCpuRuntimeMath.cpp
index 7dac921..55887fa 100644
--- a/cpu_ref/rsCpuRuntimeMath.cpp
+++ b/cpu_ref/rsCpuRuntimeMath.cpp
@@ -112,7 +112,6 @@
     return fmin(v - i, 0x1.fffffep-1f);
 }
 
-#ifdef RS_COMPATIBILITY_LIB
 EXPORT_F32_FN_F32(acosf)
 EXPORT_F32_FN_F32(acoshf)
 EXPORT_F32_FN_F32(asinf)
@@ -213,7 +212,6 @@
 void __attribute__((overloadable)) rsMatrixTranspose(rs_matrix2x2 *m) {
     SC_MatrixTranspose_2x2((Matrix2x2 *) m);
 }
-#endif
 
 //////////////////////////////////////////////////////////////////////////////
 // Class implementation
diff --git a/cpu_ref/rsCpuRuntimeMathFuncs.cpp b/cpu_ref/rsCpuRuntimeMathFuncs.cpp
index 6eb7063..0a16935 100644
--- a/cpu_ref/rsCpuRuntimeMathFuncs.cpp
+++ b/cpu_ref/rsCpuRuntimeMathFuncs.cpp
@@ -16,7 +16,6 @@
 
 // exports unavailable mathlib functions to compat lib
 
-#ifdef RS_COMPATIBILITY_LIB
 
 typedef unsigned int uint32_t;
 typedef int int32_t;
@@ -92,6 +91,7 @@
   return SC_randf2(min, max);
 }
 
+#ifdef RS_COMPATIBILITY_LIB
 
 // !!! DANGER !!!
 // These functions are potentially missing on older Android versions.
diff --git a/cpu_ref/rsCpuScript.cpp b/cpu_ref/rsCpuScript.cpp
index f38c898..462c161 100644
--- a/cpu_ref/rsCpuScript.cpp
+++ b/cpu_ref/rsCpuScript.cpp
@@ -18,16 +18,9 @@
 #include "rsCpuScript.h"
 
 #ifdef RS_COMPATIBILITY_LIB
-    #include <set>
-    #include <string>
-    #include <dlfcn.h>
     #include <stdio.h>
-    #include <stdlib.h>
-    #include <string.h>
     #include <sys/stat.h>
     #include <unistd.h>
-    #include <fstream>
-    #include <iostream>
 #else
     #include <bcc/BCCContext.h>
     #include <bcc/Config/Config.h>
@@ -45,8 +38,21 @@
     #include <vector>
 #endif
 
+#include <set>
+#include <string>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fstream>
+#include <iostream>
+
+#ifdef __LP64__
+#define SYSLIBPATH "/system/lib64"
+#else
+#define SYSLIBPATH "/system/lib"
+#endif
+
 namespace {
-#ifdef RS_COMPATIBILITY_LIB
 
 // Create a len length string containing random characters from [A-Za-z0-9].
 static std::string getRandomString(size_t len) {
@@ -106,6 +112,8 @@
     return 0;
 }
 
+#define RS_CACHE_DIR "com.android.renderscript.cache"
+
 // Attempt to load the shared library from origName, but then fall back to
 // creating a copy of the shared library if necessary (to ensure instancing).
 // This function returns the dlopen()-ed handle if successful.
@@ -136,7 +144,12 @@
     }
 
     std::string newName(cacheDir);
-    newName.append("/com.android.renderscript.cache/");
+
+    // Append RS_CACHE_DIR only if it is not found in cacheDir
+    // In driver mode, RS_CACHE_DIR is already appended to cacheDir.
+    if (newName.find(RS_CACHE_DIR) == std::string::npos) {
+        newName.append("/" RS_CACHE_DIR "/");
+    }
 
     if (!ensureCacheDirExists(newName.c_str())) {
         ALOGE("Could not verify or create cache dir: %s", cacheDir);
@@ -167,15 +180,12 @@
     return loaded;
 }
 
-// Load the shared library referred to by cacheDir and resName. If we have
-// already loaded this library, we instead create a new copy (in the
-// cache dir) and then load that. We then immediately destroy the copy.
-// This is required behavior to implement script instancing for the support
-// library, since shared objects are loaded and de-duped by name only.
-static void *loadSharedLibrary(const char *cacheDir, const char *resName) {
-    void *loaded = nullptr;
+static std::string findSharedObjectName(const char *cacheDir,
+                                        const char *resName) {
+
 #ifndef RS_SERVER
     std::string scriptSOName(cacheDir);
+#ifdef RS_COMPATIBILITY_LIB
     size_t cutPos = scriptSOName.rfind("cache");
     if (cutPos != std::string::npos) {
         scriptSOName.erase(cutPos);
@@ -184,11 +194,28 @@
     }
     scriptSOName.append("/lib/librs.");
 #else
+    scriptSOName.append("/librs.");
+#endif
+
+#else
     std::string scriptSOName("lib");
 #endif
     scriptSOName.append(resName);
     scriptSOName.append(".so");
 
+    return scriptSOName;
+}
+
+// Load the shared library referred to by cacheDir and resName. If we have
+// already loaded this library, we instead create a new copy (in the
+// cache dir) and then load that. We then immediately destroy the copy.
+// This is required behavior to implement script instancing for the support
+// library, since shared objects are loaded and de-duped by name only.
+static void *loadSharedLibrary(const char *cacheDir, const char *resName) {
+    void *loaded = nullptr;
+
+    std::string scriptSOName = findSharedObjectName(cacheDir, resName);
+
     // We should check if we can load the library from the standard app
     // location for shared libraries first.
     loaded = loadSOHelper(scriptSOName.c_str(), cacheDir, resName);
@@ -216,7 +243,29 @@
     return loaded;
 }
 
-#else  // RS_COMPATIBILITY_LIB is not defined
+#ifndef RS_COMPATIBILITY_LIB
+
+static bool is_skip_linkloader() {
+    char buf[PROPERTY_VALUE_MAX];
+    static bool initialized = false;
+    static bool prop = false;
+
+    if (initialized) {
+        return prop;
+    }
+
+    property_get("rs.skip.linkloader", buf, "");
+    prop = (buf[0] != '\0');
+    initialized = true;
+
+    if (prop) {
+        ALOGV("Skipping linkloader");
+    }
+    else {
+        ALOGV("Default path: using linkloader");
+    }
+    return prop;
+}
 
 static bool is_force_recompile() {
 #ifdef RS_SERVER
@@ -277,6 +326,11 @@
         }
     }
 
+    if (is_skip_linkloader()) {
+        args->push_back("-fPIC");
+        args->push_back("-embedRSInfo");
+    }
+
     args->push_back(bcFileName.c_str());
     args->push_back(nullptr);
 }
@@ -335,13 +389,70 @@
     }
 }
 
+const static char *LD_EXE_PATH = "/system/bin/ld.mc";
+
+static bool createSharedLib(const char *cacheDir, const char *resName) {
+    std::string sharedLibName = findSharedObjectName(cacheDir, resName);
+    std::string objFileName = cacheDir;
+    objFileName.append("/");
+    objFileName.append(resName);
+    objFileName.append(".o");
+
+    const char *compiler_rt = SYSLIBPATH"/libcompiler_rt.so";
+    std::vector<const char *> args = {
+        LD_EXE_PATH,
+        "-shared",
+        "-nostdlib",
+        compiler_rt,
+        "-mtriple", DEFAULT_TARGET_TRIPLE_STRING,
+        "-L", SYSLIBPATH,
+        "-lRSDriver", "-lm", "-lc",
+        objFileName.c_str(),
+        "-o", sharedLibName.c_str(),
+        nullptr
+    };
+
+    std::string cmdLineStr = bcc::getCommandLine(args.size()-1, args.data());
+
+    pid_t pid = fork();
+
+    switch (pid) {
+    case -1: {  // Error occurred (we attempt no recovery)
+        ALOGE("Couldn't fork for linker (%s) execution", LD_EXE_PATH);
+        return false;
+    }
+    case 0: {  // Child process
+        ALOGV("Invoking ld.mc with args '%s'", cmdLineStr.c_str());
+        execv(LD_EXE_PATH, (char* const*) args.data());
+
+        ALOGE("execv() failed: %s", strerror(errno));
+        abort();
+        return false;
+    }
+    default: {  // Parent process (actual driver)
+        // Wait on child process to finish compiling the source.
+        int status = 0;
+        pid_t w = waitpid(pid, &status, 0);
+        if (w == -1) {
+            ALOGE("Could not wait for linker (%s)", LD_EXE_PATH);
+            return false;
+        }
+
+        if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+            return true;
+        }
+
+        ALOGE("Linker (%s) terminated unexpectedly", LD_EXE_PATH);
+        return false;
+    }
+    }
+}
 #endif  // !defined(RS_COMPATIBILITY_LIB)
 }  // namespace
 
 namespace android {
 namespace renderscript {
 
-#ifdef RS_COMPATIBILITY_LIB
 #define MAXLINE 500
 #define MAKE_STR_HELPER(S) #S
 #define MAKE_STR(S) MAKE_STR_HELPER(S)
@@ -374,20 +485,20 @@
 
     return s;
 }
-#endif
 
 RsdCpuScriptImpl::RsdCpuScriptImpl(RsdCpuReferenceImpl *ctx, const Script *s) {
     mCtx = ctx;
     mScript = s;
 
-#ifdef RS_COMPATIBILITY_LIB
     mScriptSO = nullptr;
+
     mInvokeFunctions = nullptr;
     mForEachFunctions = nullptr;
     mFieldAddress = nullptr;
     mFieldIsObject = nullptr;
     mForEachSignatures = nullptr;
-#else
+
+#ifndef RS_COMPATIBILITY_LIB
     mCompilerDriver = nullptr;
     mExecutable = nullptr;
 #endif
@@ -404,6 +515,242 @@
     mIsThreadable = true;
 }
 
+bool RsdCpuScriptImpl::storeRSInfoFromSO() {
+    char line[MAXLINE];
+    size_t varCount = 0;
+    size_t funcCount = 0;
+    size_t forEachCount = 0;
+    size_t objectSlotCount = 0;
+
+    mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
+    if (mRoot) {
+        //ALOGE("Found root(): %p", mRoot);
+    }
+    mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
+    if (mRootExpand) {
+        //ALOGE("Found root.expand(): %p", mRootExpand);
+    }
+    mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
+    if (mInit) {
+        //ALOGE("Found init(): %p", mInit);
+    }
+    mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
+    if (mFreeChildren) {
+        //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
+    }
+
+    const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
+    if (rsInfo) {
+        //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
+    }
+
+    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+        goto error;
+    }
+    if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
+        ALOGE("Invalid export var count!: %s", line);
+        goto error;
+    }
+
+    mExportedVariableCount = varCount;
+    //ALOGE("varCount: %zu", varCount);
+    if (varCount > 0) {
+        // Start by creating/zeroing this member, since we don't want to
+        // accidentally clean up invalid pointers later (if we error out).
+        mFieldIsObject = new bool[varCount];
+        if (mFieldIsObject == nullptr) {
+            goto error;
+        }
+        memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
+        mFieldAddress = new void*[varCount];
+        if (mFieldAddress == nullptr) {
+            goto error;
+        }
+        for (size_t i = 0; i < varCount; ++i) {
+            if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+                goto error;
+            }
+            char *c = strrchr(line, '\n');
+            if (c) {
+                *c = '\0';
+            }
+            mFieldAddress[i] = dlsym(mScriptSO, line);
+            if (mFieldAddress[i] == nullptr) {
+                ALOGE("Failed to find variable address for %s: %s",
+                      line, dlerror());
+                // Not a critical error if we don't find a global variable.
+            }
+            else {
+                //ALOGE("Found variable %s at %p", line,
+                //mFieldAddress[i]);
+            }
+        }
+    }
+
+    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+        goto error;
+    }
+    if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
+        ALOGE("Invalid export func count!: %s", line);
+        goto error;
+    }
+
+    mExportedFunctionCount = funcCount;
+    //ALOGE("funcCount: %zu", funcCount);
+
+    if (funcCount > 0) {
+        mInvokeFunctions = new InvokeFunc_t[funcCount];
+        if (mInvokeFunctions == nullptr) {
+            goto error;
+        }
+        for (size_t i = 0; i < funcCount; ++i) {
+            if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+                goto error;
+            }
+            char *c = strrchr(line, '\n');
+            if (c) {
+                *c = '\0';
+            }
+
+            mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
+            if (mInvokeFunctions[i] == nullptr) {
+                ALOGE("Failed to get function address for %s(): %s",
+                      line, dlerror());
+                goto error;
+            }
+            else {
+                //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
+            }
+        }
+    }
+
+    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+        goto error;
+    }
+    if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
+        ALOGE("Invalid export forEach count!: %s", line);
+        goto error;
+    }
+
+    if (forEachCount > 0) {
+
+        mForEachSignatures = new uint32_t[forEachCount];
+        if (mForEachSignatures == nullptr) {
+            goto error;
+        }
+        mForEachFunctions = new ForEachFunc_t[forEachCount];
+        if (mForEachFunctions == nullptr) {
+            goto error;
+        }
+        for (size_t i = 0; i < forEachCount; ++i) {
+            unsigned int tmpSig = 0;
+            char tmpName[MAXLINE];
+
+            if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+                goto error;
+            }
+            if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
+                       &tmpSig, tmpName) != 2) {
+                ALOGE("Invalid export forEach!: %s", line);
+                goto error;
+            }
+
+            // Lookup the expanded ForEach kernel.
+            strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
+            mForEachSignatures[i] = tmpSig;
+            mForEachFunctions[i] =
+                    (ForEachFunc_t) dlsym(mScriptSO, tmpName);
+            if (i != 0 && mForEachFunctions[i] == nullptr) {
+                // Ignore missing root.expand functions.
+                // root() is always specified at location 0.
+                ALOGE("Failed to find forEach function address for %s: %s",
+                      tmpName, dlerror());
+                goto error;
+            }
+            else {
+                //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
+            }
+        }
+    }
+
+    if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+        goto error;
+    }
+    if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
+        ALOGE("Invalid object slot count!: %s", line);
+        goto error;
+    }
+
+    if (objectSlotCount > 0) {
+        rsAssert(varCount > 0);
+        for (size_t i = 0; i < objectSlotCount; ++i) {
+            uint32_t varNum = 0;
+            if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
+                goto error;
+            }
+            if (sscanf(line, "%u", &varNum) != 1) {
+                ALOGE("Invalid object slot!: %s", line);
+                goto error;
+            }
+
+            if (varNum < varCount) {
+                mFieldIsObject[varNum] = true;
+            }
+        }
+    }
+
+    if (varCount > 0) {
+        mBoundAllocs = new Allocation *[varCount];
+        memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
+    }
+
+    if (mScriptSO == (void*)1) {
+        //rsdLookupRuntimeStub(script, "acos");
+    }
+
+    return true;
+
+error:
+    delete[] mInvokeFunctions;
+    delete[] mForEachFunctions;
+    delete[] mFieldAddress;
+    delete[] mFieldIsObject;
+    delete[] mForEachSignatures;
+    delete[] mBoundAllocs;
+
+    return false;
+}
+
+#ifndef RS_COMPATIBILITY_LIB
+bool RsdCpuScriptImpl::storeRSInfoFromObj(bcinfo::MetadataExtractor &bitcodeMetadata) {
+
+    mExecutable->setThreadable(mIsThreadable);
+    if (!mExecutable->syncInfo()) {
+        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
+    }
+
+    mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
+    mRootExpand =
+        reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
+    mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
+    mFreeChildren =
+        reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
+
+
+    if (bitcodeMetadata.getExportVarCount()) {
+        mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
+        memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
+    }
+
+    for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
+        char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
+        mExportedForEachFuncList.push_back(
+                    std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
+    }
+
+    return true;
+}
+#endif
 
 bool RsdCpuScriptImpl::init(char const *resName, char const *cacheDir,
                             uint8_t const *bitcode, size_t bitcodeSize,
@@ -464,7 +811,12 @@
     std::string compileCommandLine =
                 bcc::getCommandLine(compileArguments.size() - 1, compileArguments.data());
 
-    if (!is_force_recompile()) {
+    if (is_skip_linkloader()) {
+        if (!is_force_recompile()) {
+            mScriptSO = loadSharedLibrary(cacheDir, resName);
+        }
+    }
+    else if (!is_force_recompile()) {
         // Load the compiled script that's in the cache, if any.
         mExecutable = bcc::RSCompilerDriver::loadScript(cacheDir, resName, (const char*)bitcode,
                                                         bitcodeSize, compileCommandLine.c_str(),
@@ -473,7 +825,31 @@
 
     // If we can't, it's either not there or out of date.  We compile the bit code and try loading
     // again.
-    if (mExecutable == nullptr) {
+    if (is_skip_linkloader()) {
+        if (mScriptSO == nullptr) {
+            if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize,
+                                compileArguments.data(), compileCommandLine))
+            {
+                ALOGE("bcc: FAILS to compile '%s'", resName);
+                mCtx->unlockMutex();
+                return false;
+            }
+
+            if (!createSharedLib(cacheDir, resName)) {
+                ALOGE("Linker: Failed to link object file '%s'", resName);
+                mCtx->unlockMutex();
+                return false;
+            }
+
+            mScriptSO = loadSharedLibrary(cacheDir, resName);
+            if (mScriptSO == nullptr) {
+                ALOGE("Unable to load '%s'", resName);
+                mCtx->unlockMutex();
+                return false;
+            }
+        }
+    }
+    else if (mExecutable == nullptr) {
         if (!compileBitcode(bcFileName, (const char*)bitcode, bitcodeSize, compileArguments.data(),
                             compileCommandLine)) {
             ALOGE("bcc: FAILS to compile '%s'", resName);
@@ -490,257 +866,46 @@
         }
     }
 
-    mExecutable->setThreadable(mIsThreadable);
-    if (!mExecutable->syncInfo()) {
-        ALOGW("bcc: FAILS to synchronize the RS info file to the disk");
+    // if using the shared object path, read RS symbol information
+    // from the .so.  Otherwise, read from the object files
+    if (!is_skip_linkloader()) {
+        storeRSInfoFromObj(bitcodeMetadata);
     }
+    else {
+        if ( !mScriptSO) {
+            goto error;
+        }
 
-    mRoot = reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root"));
-    mRootExpand =
-        reinterpret_cast<int (*)()>(mExecutable->getSymbolAddress("root.expand"));
-    mInit = reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress("init"));
-    mFreeChildren =
-        reinterpret_cast<void (*)()>(mExecutable->getSymbolAddress(".rs.dtor"));
-
-
-    if (bitcodeMetadata.getExportVarCount()) {
-        mBoundAllocs = new Allocation *[bitcodeMetadata.getExportVarCount()];
-        memset(mBoundAllocs, 0, sizeof(void *) * bitcodeMetadata.getExportVarCount());
+        if ( !storeRSInfoFromSO()) {
+          goto error;
+        }
     }
-
-    for (size_t i = 0; i < bitcodeMetadata.getExportForEachSignatureCount(); i++) {
-        char* name = new char[strlen(bitcodeMetadata.getExportForEachNameList()[i]) + 1];
-        mExportedForEachFuncList.push_back(
-                    std::make_pair(name, bitcodeMetadata.getExportForEachSignatureList()[i]));
-    }
-
 #else  // RS_COMPATIBILITY_LIB is defined
 
     mScriptSO = loadSharedLibrary(cacheDir, resName);
 
-    if (mScriptSO) {
-        char line[MAXLINE];
-        mRoot = (RootFunc_t) dlsym(mScriptSO, "root");
-        if (mRoot) {
-            //ALOGE("Found root(): %p", mRoot);
-        }
-        mRootExpand = (RootFunc_t) dlsym(mScriptSO, "root.expand");
-        if (mRootExpand) {
-            //ALOGE("Found root.expand(): %p", mRootExpand);
-        }
-        mInit = (InvokeFunc_t) dlsym(mScriptSO, "init");
-        if (mInit) {
-            //ALOGE("Found init(): %p", mInit);
-        }
-        mFreeChildren = (InvokeFunc_t) dlsym(mScriptSO, ".rs.dtor");
-        if (mFreeChildren) {
-            //ALOGE("Found .rs.dtor(): %p", mFreeChildren);
-        }
+    if (!mScriptSO) {
+        goto error;
+    }
 
-        const char *rsInfo = (const char *) dlsym(mScriptSO, ".rs.info");
-        if (rsInfo) {
-            //ALOGE("Found .rs.info(): %p - %s", rsInfo, rsInfo);
-        }
-
-        size_t varCount = 0;
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        if (sscanf(line, EXPORT_VAR_STR "%zu", &varCount) != 1) {
-            ALOGE("Invalid export var count!: %s", line);
-            goto error;
-        }
-
-        mExportedVariableCount = varCount;
-        //ALOGE("varCount: %zu", varCount);
-        if (varCount > 0) {
-            // Start by creating/zeroing this member, since we don't want to
-            // accidentally clean up invalid pointers later (if we error out).
-            mFieldIsObject = new bool[varCount];
-            if (mFieldIsObject == nullptr) {
-                goto error;
-            }
-            memset(mFieldIsObject, 0, varCount * sizeof(*mFieldIsObject));
-            mFieldAddress = new void*[varCount];
-            if (mFieldAddress == nullptr) {
-                goto error;
-            }
-            for (size_t i = 0; i < varCount; ++i) {
-                if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-                    goto error;
-                }
-                char *c = strrchr(line, '\n');
-                if (c) {
-                    *c = '\0';
-                }
-                mFieldAddress[i] = dlsym(mScriptSO, line);
-                if (mFieldAddress[i] == nullptr) {
-                    ALOGE("Failed to find variable address for %s: %s",
-                          line, dlerror());
-                    // Not a critical error if we don't find a global variable.
-                }
-                else {
-                    //ALOGE("Found variable %s at %p", line,
-                    //mFieldAddress[i]);
-                }
-            }
-        }
-
-        size_t funcCount = 0;
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        if (sscanf(line, EXPORT_FUNC_STR "%zu", &funcCount) != 1) {
-            ALOGE("Invalid export func count!: %s", line);
-            goto error;
-        }
-
-        mExportedFunctionCount = funcCount;
-        //ALOGE("funcCount: %zu", funcCount);
-
-        if (funcCount > 0) {
-            mInvokeFunctions = new InvokeFunc_t[funcCount];
-            if (mInvokeFunctions == nullptr) {
-                goto error;
-            }
-            for (size_t i = 0; i < funcCount; ++i) {
-                if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-                    goto error;
-                }
-                char *c = strrchr(line, '\n');
-                if (c) {
-                    *c = '\0';
-                }
-
-                mInvokeFunctions[i] = (InvokeFunc_t) dlsym(mScriptSO, line);
-                if (mInvokeFunctions[i] == nullptr) {
-                    ALOGE("Failed to get function address for %s(): %s",
-                          line, dlerror());
-                    goto error;
-                }
-                else {
-                    //ALOGE("Found InvokeFunc_t %s at %p", line, mInvokeFunctions[i]);
-                }
-            }
-        }
-
-        size_t forEachCount = 0;
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        if (sscanf(line, EXPORT_FOREACH_STR "%zu", &forEachCount) != 1) {
-            ALOGE("Invalid export forEach count!: %s", line);
-            goto error;
-        }
-
-        if (forEachCount > 0) {
-
-            mForEachSignatures = new uint32_t[forEachCount];
-            if (mForEachSignatures == nullptr) {
-                goto error;
-            }
-            mForEachFunctions = new ForEachFunc_t[forEachCount];
-            if (mForEachFunctions == nullptr) {
-                goto error;
-            }
-            for (size_t i = 0; i < forEachCount; ++i) {
-                unsigned int tmpSig = 0;
-                char tmpName[MAXLINE];
-
-                if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-                    goto error;
-                }
-                if (sscanf(line, "%u - %" MAKE_STR(MAXLINE) "s",
-                           &tmpSig, tmpName) != 2) {
-                    ALOGE("Invalid export forEach!: %s", line);
-                    goto error;
-                }
-
-                // Lookup the expanded ForEach kernel.
-                strncat(tmpName, ".expand", MAXLINE-1-strlen(tmpName));
-                mForEachSignatures[i] = tmpSig;
-                mForEachFunctions[i] =
-                        (ForEachFunc_t) dlsym(mScriptSO, tmpName);
-                if (i != 0 && mForEachFunctions[i] == nullptr) {
-                    // Ignore missing root.expand functions.
-                    // root() is always specified at location 0.
-                    ALOGE("Failed to find forEach function address for %s: %s",
-                          tmpName, dlerror());
-                    goto error;
-                }
-                else {
-                    //ALOGE("Found forEach %s at %p", tmpName, mForEachFunctions[i]);
-                }
-            }
-        }
-
-        size_t objectSlotCount = 0;
-        if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-            goto error;
-        }
-        if (sscanf(line, OBJECT_SLOT_STR "%zu", &objectSlotCount) != 1) {
-            ALOGE("Invalid object slot count!: %s", line);
-            goto error;
-        }
-
-        if (objectSlotCount > 0) {
-            rsAssert(varCount > 0);
-            for (size_t i = 0; i < objectSlotCount; ++i) {
-                uint32_t varNum = 0;
-                if (strgets(line, MAXLINE, &rsInfo) == nullptr) {
-                    goto error;
-                }
-                if (sscanf(line, "%u", &varNum) != 1) {
-                    ALOGE("Invalid object slot!: %s", line);
-                    goto error;
-                }
-
-                if (varNum < varCount) {
-                    mFieldIsObject[varNum] = true;
-                }
-            }
-        }
-
-        if (varCount > 0) {
-            mBoundAllocs = new Allocation *[varCount];
-            memset(mBoundAllocs, 0, varCount * sizeof(*mBoundAllocs));
-        }
-
-        if (mScriptSO == (void*)1) {
-            //rsdLookupRuntimeStub(script, "acos");
-        }
-    } else {
+    if (!storeRSInfoFromSO()) {
         goto error;
     }
 #endif
     mCtx->unlockMutex();
     return true;
 
-#ifdef RS_COMPATIBILITY_LIB
 error:
 
     mCtx->unlockMutex();
-    delete[] mInvokeFunctions;
-    delete[] mForEachFunctions;
-    delete[] mFieldAddress;
-    delete[] mFieldIsObject;
-    delete[] mForEachSignatures;
-    delete[] mBoundAllocs;
     if (mScriptSO) {
         dlclose(mScriptSO);
     }
     return false;
-#endif
 }
 
 #ifndef RS_COMPATIBILITY_LIB
 
-#ifdef __LP64__
-#define SYSLIBPATH "/system/lib64"
-#else
-#define SYSLIBPATH "/system/lib"
-#endif
-
 const char* RsdCpuScriptImpl::findCoreLib(const bcinfo::MetadataExtractor& ME, const char* bitcode,
                                           size_t bitcodeSize) {
     const char* defaultLib = SYSLIBPATH"/libclcore.bc";
@@ -781,19 +946,36 @@
 void RsdCpuScriptImpl::populateScript(Script *script) {
 #ifndef RS_COMPATIBILITY_LIB
     // Copy info over to runtime
-    script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
-    script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
-    script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
-    script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
-    script->mHal.info.exportedPragmaKeyList =
-        const_cast<const char**>(&mExecutable->getPragmaKeys().front());
-    script->mHal.info.exportedPragmaValueList =
-        const_cast<const char**>(&mExecutable->getPragmaValues().front());
+    if (!is_skip_linkloader()) {
+        script->mHal.info.exportedFunctionCount = mExecutable->getExportFuncAddrs().size();
+        script->mHal.info.exportedVariableCount = mExecutable->getExportVarAddrs().size();
+        script->mHal.info.exportedForeachFuncList = &mExportedForEachFuncList[0];
+        script->mHal.info.exportedPragmaCount = mExecutable->getPragmaKeys().size();
+        script->mHal.info.exportedPragmaKeyList =
+            const_cast<const char**>(&mExecutable->getPragmaKeys().front());
+        script->mHal.info.exportedPragmaValueList =
+            const_cast<const char**>(&mExecutable->getPragmaValues().front());
 
-    if (mRootExpand) {
-        script->mHal.info.root = mRootExpand;
-    } else {
-        script->mHal.info.root = mRoot;
+        if (mRootExpand) {
+            script->mHal.info.root = mRootExpand;
+        } else {
+            script->mHal.info.root = mRoot;
+        }
+    }
+    else {
+        // Copy info over to runtime
+        script->mHal.info.exportedFunctionCount = mExportedFunctionCount;
+        script->mHal.info.exportedVariableCount = mExportedVariableCount;
+        script->mHal.info.exportedPragmaCount = 0;
+        script->mHal.info.exportedPragmaKeyList = 0;
+        script->mHal.info.exportedPragmaValueList = 0;
+
+        // Bug, need to stash in metadata
+        if (mRootExpand) {
+            script->mHal.info.root = mRootExpand;
+        } else {
+            script->mHal.info.root = mRoot;
+        }
     }
 #else
     // Copy info over to runtime
@@ -997,11 +1179,18 @@
     mtls->script = this;
     mtls->fep.slot = slot;
 #ifndef RS_COMPATIBILITY_LIB
-    rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
-    mtls->kernel = reinterpret_cast<ForEachFunc_t>(
-                      mExecutable->getExportForeachFuncAddrs()[slot]);
-    rsAssert(mtls->kernel != nullptr);
-    mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
+    if (!is_skip_linkloader()) {
+        rsAssert(slot < mExecutable->getExportForeachFuncAddrs().size());
+        mtls->kernel = reinterpret_cast<ForEachFunc_t>(
+                          mExecutable->getExportForeachFuncAddrs()[slot]);
+        rsAssert(mtls->kernel != nullptr);
+        mtls->sig = mExecutable->getInfo().getExportForeachFuncs()[slot].second;
+    }
+    else {
+        mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
+        rsAssert(mtls->kernel != nullptr);
+        mtls->sig = mForEachSignatures[slot];
+    }
 #else
     mtls->kernel = reinterpret_cast<ForEachFunc_t>(mForEachFunctions[slot]);
     rsAssert(mtls->kernel != nullptr);
@@ -1030,7 +1219,7 @@
 
 void RsdCpuScriptImpl::invokeFunction(uint32_t slot, const void *params,
                                       size_t paramLength) {
-    //ALOGE("invoke %p %p %i %p %i", dc, script, slot, params, paramLength);
+    //ALOGE("invoke %i %p %zu", slot, params, paramLength);
     void * ap = nullptr;
 
 #if defined(__x86_64__)
@@ -1048,15 +1237,19 @@
 #endif
 
     RsdCpuScriptImpl * oldTLS = mCtx->setTLS(this);
-    reinterpret_cast<void (*)(const void *, uint32_t)>(
 #ifndef RS_COMPATIBILITY_LIB
-        mExecutable->getExportFuncAddrs()[slot])(ap ? (const void *)ap : params, paramLength);
+    if (! is_skip_linkloader()) {
+        reinterpret_cast<void (*)(const void *, uint32_t)>(
+            mExecutable->getExportFuncAddrs()[slot])(
+                ap? (const void *) ap : params, paramLength);
+    }
+    else {
+        reinterpret_cast<void (*)(const void *, uint32_t)>(
+            mInvokeFunctions[slot])(ap? (const void *) ap: params, paramLength);
+    }
 #else
-        mInvokeFunctions[slot])(ap ? (const void *)ap : params, paramLength);
-#endif
-
-#if defined(__x86_64__)
-    if (ap) free(ap);
+    reinterpret_cast<void (*)(const void *, uint32_t)>(
+        mInvokeFunctions[slot])(ap? (const void *) ap: params, paramLength);
 #endif
 
     mCtx->setTLS(oldTLS);
@@ -1064,7 +1257,7 @@
 
 void RsdCpuScriptImpl::setGlobalVar(uint32_t slot, const void *data, size_t dataLength) {
     //rsAssert(!script->mFieldIsObject[slot]);
-    //ALOGE("setGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
+    //ALOGE("setGlobalVar %i %p %zu", slot, data, dataLength);
 
     //if (mIntrinsicID) {
         //mIntrinsicFuncs.setVar(dc, script, drv->mIntrinsicData, slot, data, dataLength);
@@ -1072,8 +1265,14 @@
     //}
 
 #ifndef RS_COMPATIBILITY_LIB
-    int32_t *destPtr = reinterpret_cast<int32_t *>(
-                          mExecutable->getExportVarAddrs()[slot]);
+    int32_t *destPtr = nullptr;
+    if (!is_skip_linkloader()) {
+        destPtr = reinterpret_cast<int32_t *>(
+                               mExecutable->getExportVarAddrs()[slot]);
+    }
+    else {
+        destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
+    }
 #else
     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
 #endif
@@ -1087,11 +1286,17 @@
 
 void RsdCpuScriptImpl::getGlobalVar(uint32_t slot, void *data, size_t dataLength) {
     //rsAssert(!script->mFieldIsObject[slot]);
-    //ALOGE("getGlobalVar %p %p %i %p %i", dc, script, slot, data, dataLength);
+    //ALOGE("getGlobalVar %i %p %zu", slot, data, dataLength);
 
 #ifndef RS_COMPATIBILITY_LIB
-    int32_t *srcPtr = reinterpret_cast<int32_t *>(
-                          mExecutable->getExportVarAddrs()[slot]);
+    int32_t *srcPtr = nullptr;
+    if (!is_skip_linkloader()) {
+        srcPtr = reinterpret_cast<int32_t *>(
+                              mExecutable->getExportVarAddrs()[slot]);
+    }
+    else {
+        srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
+    }
 #else
     int32_t *srcPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
 #endif
@@ -1108,8 +1313,14 @@
                                                 const uint32_t *dims, size_t dimLength) {
 
 #ifndef RS_COMPATIBILITY_LIB
-    int32_t *destPtr = reinterpret_cast<int32_t *>(
-        mExecutable->getExportVarAddrs()[slot]);
+    int32_t *destPtr = nullptr;
+    if (!is_skip_linkloader()) {
+        destPtr = reinterpret_cast<int32_t *>(
+                               mExecutable->getExportVarAddrs()[slot]);
+    }
+    else {
+        destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
+    }
 #else
     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
 #endif
@@ -1147,11 +1358,17 @@
 void RsdCpuScriptImpl::setGlobalBind(uint32_t slot, Allocation *data) {
 
     //rsAssert(!script->mFieldIsObject[slot]);
-    //ALOGE("setGlobalBind %p %p %i %p", dc, script, slot, data);
+    //ALOGE("setGlobalBind %i %p", slot, data);
 
 #ifndef RS_COMPATIBILITY_LIB
-    int32_t *destPtr = reinterpret_cast<int32_t *>(
-                          mExecutable->getExportVarAddrs()[slot]);
+    int32_t *destPtr = nullptr;
+    if (!is_skip_linkloader()) {
+        destPtr = reinterpret_cast<int32_t *>(
+                               mExecutable->getExportVarAddrs()[slot]);
+    }
+    else {
+        destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
+    }
 #else
     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
 #endif
@@ -1162,7 +1379,7 @@
 
     void *ptr = nullptr;
     mBoundAllocs[slot] = data;
-    if(data) {
+    if (data) {
         ptr = data->mHal.drvState.lod[0].mallocPtr;
     }
     memcpy(destPtr, &ptr, sizeof(void *));
@@ -1171,11 +1388,17 @@
 void RsdCpuScriptImpl::setGlobalObj(uint32_t slot, ObjectBase *data) {
 
     //rsAssert(script->mFieldIsObject[slot]);
-    //ALOGE("setGlobalObj %p %p %i %p", dc, script, slot, data);
+    //ALOGE("setGlobalObj %i %p", slot, data);
 
 #ifndef RS_COMPATIBILITY_LIB
-    int32_t *destPtr = reinterpret_cast<int32_t *>(
-                          mExecutable->getExportVarAddrs()[slot]);
+    int32_t *destPtr = nullptr;
+    if (!is_skip_linkloader()) {
+        destPtr = reinterpret_cast<int32_t *>(
+                               mExecutable->getExportVarAddrs()[slot]);
+    }
+    else {
+        destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
+    }
 #else
     int32_t *destPtr = reinterpret_cast<int32_t *>(mFieldAddress[slot]);
 #endif
@@ -1230,6 +1453,27 @@
     for (size_t i = 0; i < mExportedForEachFuncList.size(); i++) {
         delete[] mExportedForEachFuncList[i].first;
     }
+
+    if (mFieldIsObject) {
+        for (size_t i = 0; i < mExportedVariableCount; ++i) {
+            if (mFieldIsObject[i]) {
+                if (mFieldAddress[i] != nullptr) {
+                    rs_object_base *obj_addr =
+                        reinterpret_cast<rs_object_base *>(mFieldAddress[i]);
+                    rsrClearObject(mCtx->getContext(), obj_addr);
+                }
+            }
+        }
+    }
+
+    if (is_skip_linkloader()) {
+        if (mInvokeFunctions) delete[] mInvokeFunctions;
+        if (mForEachFunctions) delete[] mForEachFunctions;
+        if (mFieldAddress) delete[] mFieldAddress;
+        if (mFieldIsObject) delete[] mFieldIsObject;
+        if (mForEachSignatures) delete[] mForEachSignatures;
+    }
+
 #else
     if (mFieldIsObject) {
         for (size_t i = 0; i < mExportedVariableCount; ++i) {
diff --git a/cpu_ref/rsCpuScript.h b/cpu_ref/rsCpuScript.h
index a8a808b..324ee14 100644
--- a/cpu_ref/rsCpuScript.h
+++ b/cpu_ref/rsCpuScript.h
@@ -50,10 +50,11 @@
         const RsExpandKernelParams *,
         uint32_t x1, uint32_t x2,
         uint32_t outstep);
-#ifdef RS_COMPATIBILITY_LIB
+
     typedef void (* InvokeFunc_t)(void);
     typedef void (* ForEachFunc_t)(void);
     typedef int (* RootFunc_t)(void);
+#ifdef RS_COMPATIBILITY_LIB
     typedef void (*WorkerCallback_t)(void *usr, uint32_t idx);
 #endif
 
@@ -107,23 +108,34 @@
     static void * lookupRuntimeStub(void* pContext, char const* name);
 
     virtual Allocation * getAllocationForPointer(const void *ptr) const;
+    bool storeRSInfoFromSO();
 
 #ifndef RS_COMPATIBILITY_LIB
+    bool storeRSInfoFromObj(bcinfo::MetadataExtractor &bitcodeMetadata);
     virtual  void * getRSExecutable() { return mExecutable; }
 #endif
 
 protected:
     RsdCpuReferenceImpl *mCtx;
     const Script *mScript;
+    void *mScriptSO;
 
 #ifndef RS_COMPATIBILITY_LIB
     // Returns the path to the core library we'll use.
     const char* findCoreLib(const bcinfo::MetadataExtractor& bitCodeMetaData, const char* bitcode,
                             size_t bitcodeSize);
-    int (*mRoot)();
-    int (*mRootExpand)();
-    void (*mInit)();
-    void (*mFreeChildren)();
+    RootFunc_t mRoot;
+    RootFunc_t mRootExpand;
+    InvokeFunc_t mInit;
+    InvokeFunc_t mFreeChildren;
+
+    InvokeFunc_t *mInvokeFunctions;
+    ForEachFunc_t *mForEachFunctions;
+    void **mFieldAddress;
+    bool *mFieldIsObject;
+    uint32_t *mForEachSignatures;
+    size_t mExportedVariableCount;
+    size_t mExportedFunctionCount;
 
     std::vector<std::pair<const char *, uint32_t> > mExportedForEachFuncList;
 
@@ -133,7 +145,6 @@
     bcc::SymbolResolverProxy mResolver;
     bcc::RSExecutable *mExecutable;
 #else
-    void *mScriptSO;
     RootFunc_t mRoot;
     RootFunc_t mRootExpand;
     InvokeFunc_t mInit;
diff --git a/cpu_ref/rsd_cpu.h b/cpu_ref/rsd_cpu.h
index d886cef..d00425c 100644
--- a/cpu_ref/rsd_cpu.h
+++ b/cpu_ref/rsd_cpu.h
@@ -19,7 +19,6 @@
 
 #include "rsAllocation.h"
 
-#ifndef RS_COMPATIBILITY_LIB
 namespace llvm {
 
 class Module;
@@ -38,7 +37,6 @@
 typedef const char* (*RSSelectRTCallback) (const char*, size_t);
 
 typedef void (*RSSetupCompilerCallback) (bcc::RSCompilerDriver *);
-#endif
 
 namespace android {
 namespace renderscript {
@@ -123,11 +121,9 @@
 
     static RsdCpuReference * create(Context *c, uint32_t version_major,
                                     uint32_t version_minor, sym_lookup_t lfn, script_lookup_t slfn
-#ifndef RS_COMPATIBILITY_LIB
                                     , bcc::RSLinkRuntimeCallback pLinkRuntimeCallback = nullptr,
                                     RSSelectRTCallback pSelectRTCallback = nullptr,
                                     const char *pBccPluginName = nullptr
-#endif
                                     );
     virtual ~RsdCpuReference();
     virtual void setPriority(int32_t priority) = 0;